Skip to content

Commit 7aaf064

Browse files
authored
Merge pull request #34 from deepagent-ltd/dev
V3.8.2 fixbug
2 parents 61437d8 + 22a08d2 commit 7aaf064

71 files changed

Lines changed: 2288 additions & 164 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/app/src/components/review/dialog-review-contract.test.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, test } from "bun:test"
2-
import { listPending, setStatus } from "./dialog-review"
2+
import { listPending, setStatus, listEnvFacts, decideEnvFact, modifyEnvFact } from "./dialog-review.api"
33

44
// P1-C route contract: the V3.1 self-learning Review dialog talks to the raw-request escape-hatch
55
// routes (NOT the generated SDK). These assertions lock the exact method/url/body so a backend
@@ -70,4 +70,53 @@ describe("DeepAgent review dialog route contract", () => {
7070
},
7171
])
7272
})
73+
74+
// V3.8.1 §G use-gate route contract.
75+
test("listEnvFacts GETs /deepagent/env-facts and unwraps adopted/pending", async () => {
76+
const calls: Recorded[] = []
77+
const data = {
78+
adopted: [],
79+
pending: [{ fact_id: "f1", version: 1, description: "milvus", body: null, degraded: false }],
80+
}
81+
const result = await listEnvFacts(client(calls, data))
82+
expect(calls).toEqual([{ method: "GET", url: "/deepagent/env-facts" }])
83+
expect(result).toEqual(data)
84+
})
85+
86+
test("listEnvFacts tolerates missing fields", async () => {
87+
const calls: Recorded[] = []
88+
expect(await listEnvFacts(client(calls, {}))).toEqual({ adopted: [], pending: [] })
89+
})
90+
91+
test("decideEnvFact POSTs /deepagent/env-facts/decide with { factId, decision }", async () => {
92+
const calls: Recorded[] = []
93+
await decideEnvFact(client(calls, { ok: true }), "f1", "adopt")
94+
expect(calls).toEqual([
95+
{
96+
method: "POST",
97+
url: "/deepagent/env-facts/decide",
98+
body: { factId: "f1", decision: "adopt" },
99+
headers: { "Content-Type": "application/json" },
100+
},
101+
])
102+
})
103+
104+
test("modifyEnvFact POSTs /deepagent/env-facts/modify with the full edit payload", async () => {
105+
const calls: Recorded[] = []
106+
const input = {
107+
factId: "f1",
108+
description: "milvus test",
109+
body: { host: "10.0.0.5", port: 19530, last_confirmed_at: "2026-07-09T00:00:00Z" },
110+
mode: "global" as const,
111+
}
112+
await modifyEnvFact(client(calls, { ok: true, factId: "f1" }), input)
113+
expect(calls).toEqual([
114+
{
115+
method: "POST",
116+
url: "/deepagent/env-facts/modify",
117+
body: input,
118+
headers: { "Content-Type": "application/json" },
119+
},
120+
])
121+
})
73122
})
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Pure HTTP client functions + types for the DeepAgent Review dialog. Split out from the .tsx so it
2+
// carries NO UI imports (Kobalte/solid-web run client-only code at module eval, which crashes a
3+
// server-side unit test). The route contract test imports THIS module; the component re-exports these
4+
// for back-compat. Keep this file free of any solid-js/UI imports.
5+
6+
export type KnowledgeItem = {
7+
id: string
8+
type: "knowledge" | "strategy" | "methodology" | "memory" | "skill" | "failure_dossier"
9+
summary: string
10+
evidence_strength: "strong" | "medium" | "weak" | "none"
11+
evidence_refs: string[]
12+
approval_status: "pending" | "approved" | "rejected"
13+
}
14+
15+
type RawSdkClient = {
16+
client: {
17+
request<TData>(options: {
18+
method: string
19+
url: string
20+
body?: unknown
21+
headers?: Record<string, string>
22+
}): Promise<{ data?: TData }>
23+
}
24+
}
25+
26+
export type ReviewClient = RawSdkClient
27+
28+
export const listPending = async (client: ReviewClient): Promise<KnowledgeItem[]> => {
29+
const response = await client.client.request<{ items: KnowledgeItem[] }>({
30+
method: "GET",
31+
url: "/deepagent/knowledge/pending",
32+
})
33+
return response.data?.items ?? []
34+
}
35+
36+
export const setStatus = async (
37+
client: ReviewClient,
38+
action: "approve" | "reject-ids",
39+
ids: string[],
40+
): Promise<void> => {
41+
await client.client.request<{ updated: string[] }>({
42+
method: "POST",
43+
url: `/deepagent/knowledge/${action}`,
44+
body: { ids },
45+
headers: { "Content-Type": "application/json" },
46+
})
47+
}
48+
49+
// V3.8.1 §G environment-fact use-gate. Provisional user-global environment facts surface here so the
50+
// user decides, per project, whether to adopt them (§G.5). Credentials never appear — only secret_ref
51+
// pointers. `degraded` marks a fact whose last connection attempt failed (§G.6).
52+
export type EnvFactBody = {
53+
host?: string
54+
port?: number
55+
container?: string
56+
purpose?: string
57+
secret_refs?: string[]
58+
last_confirmed_at: string
59+
notes?: string
60+
}
61+
export type EnvFactItem = {
62+
fact_id: string
63+
version: number
64+
description: string
65+
body: EnvFactBody | null
66+
degraded: boolean
67+
}
68+
export type EnvFactList = { adopted: EnvFactItem[]; pending: EnvFactItem[] }
69+
70+
export const listEnvFacts = async (client: ReviewClient): Promise<EnvFactList> => {
71+
const response = await client.client.request<EnvFactList>({ method: "GET", url: "/deepagent/env-facts" })
72+
return { adopted: response.data?.adopted ?? [], pending: response.data?.pending ?? [] }
73+
}
74+
75+
export const decideEnvFact = async (
76+
client: ReviewClient,
77+
factId: string,
78+
decision: "adopt" | "reject",
79+
): Promise<void> => {
80+
await client.client.request<{ ok: boolean }>({
81+
method: "POST",
82+
url: "/deepagent/env-facts/decide",
83+
body: { factId, decision },
84+
headers: { "Content-Type": "application/json" },
85+
})
86+
}
87+
88+
// §G.5 modify: edit a fact then adopt it. mode=global corrects the shared fact for every project;
89+
// mode=project writes a project-local override, leaving the global fact untouched for others.
90+
export type EnvFactModifyInput = {
91+
factId: string
92+
description: string
93+
body: EnvFactBody
94+
domain?: string | null
95+
mode: "global" | "project"
96+
}
97+
export const modifyEnvFact = async (client: ReviewClient, input: EnvFactModifyInput): Promise<void> => {
98+
await client.client.request<{ ok: boolean; factId: string }>({
99+
method: "POST",
100+
url: "/deepagent/env-facts/modify",
101+
body: input,
102+
headers: { "Content-Type": "application/json" },
103+
})
104+
}

0 commit comments

Comments
 (0)