@wrenai/genbi 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -2
- package/dist/assets/{echarts-LTFC-ysd.js → echarts-DYM4hjvk.js} +2 -2
- package/dist/assets/index-A_Wrq7Ey.css +1 -0
- package/dist/assets/{index-Bo--QMUN.js → index-DsH129tV.js} +18 -17
- package/dist/index.html +2 -2
- package/dist-server/harness/bundle/schema.d.ts +38 -0
- package/dist-server/harness/bundle/schema.js +18 -10
- package/dist-server/harness/bundle/version.js +1 -1
- package/dist-server/harness/cli-args.d.ts +10 -2
- package/dist-server/harness/cli-args.js +24 -8
- package/dist-server/harness/cli.js +75 -9
- package/dist-server/harness/compile/cache.js +4 -4
- package/dist-server/harness/compile/compose-profile.d.ts +51 -14
- package/dist-server/harness/compile/compose-profile.js +85 -19
- package/dist-server/harness/compile/context-loader.d.ts +56 -0
- package/dist-server/harness/compile/context-loader.js +237 -0
- package/dist-server/harness/compile/errors.d.ts +19 -0
- package/dist-server/harness/compile/errors.js +35 -0
- package/dist-server/harness/compile/index.d.ts +4 -3
- package/dist-server/harness/compile/index.js +4 -3
- package/dist-server/harness/compile/pipeline.d.ts +15 -7
- package/dist-server/harness/compile/pipeline.js +62 -14
- package/dist-server/harness/compile/resolve-binary.d.ts +2 -2
- package/dist-server/harness/compile/resolve-binary.js +3 -3
- package/dist-server/harness/compile/types.d.ts +29 -0
- package/dist-server/harness/compile/warble-identity.d.ts +11 -0
- package/dist-server/harness/compile/warble-identity.js +13 -0
- package/dist-server/harness/components/ai-step.d.ts +4 -0
- package/dist-server/harness/components/ai-step.js +40 -0
- package/dist-server/harness/components/broker.d.ts +60 -0
- package/dist-server/harness/components/broker.js +117 -0
- package/dist-server/harness/components/capability-card.d.ts +98 -0
- package/dist-server/harness/components/capability-card.js +169 -0
- package/dist-server/harness/components/context.d.ts +2 -0
- package/dist-server/harness/components/context.js +30 -0
- package/dist-server/harness/components/display.d.ts +6 -0
- package/dist-server/harness/components/display.js +29 -0
- package/dist-server/harness/components/egress-judge.d.ts +12 -0
- package/dist-server/harness/components/egress-judge.js +27 -0
- package/dist-server/harness/components/egress.d.ts +142 -0
- package/dist-server/harness/components/egress.js +469 -0
- package/dist-server/harness/components/in-process.d.ts +7 -0
- package/dist-server/harness/components/in-process.js +245 -0
- package/dist-server/harness/components/normalize.d.ts +35 -0
- package/dist-server/harness/components/normalize.js +245 -0
- package/dist-server/harness/components/plan.d.ts +31 -0
- package/dist-server/harness/components/plan.js +184 -0
- package/dist-server/harness/components/report.d.ts +207 -0
- package/dist-server/harness/components/report.js +309 -0
- package/dist-server/harness/components/runner.d.ts +193 -0
- package/dist-server/harness/components/runner.js +492 -0
- package/dist-server/harness/components/semantic-guards.d.ts +20 -0
- package/dist-server/harness/components/semantic-guards.js +42 -0
- package/dist-server/harness/components/terminal-json.d.ts +18 -0
- package/dist-server/harness/components/terminal-json.js +82 -0
- package/dist-server/harness/components/usage.d.ts +14 -0
- package/dist-server/harness/components/usage.js +19 -0
- package/dist-server/harness/components/wren-access.d.ts +29 -0
- package/dist-server/harness/components/wren-access.js +233 -0
- package/dist-server/harness/components/zone-dry-run.d.ts +43 -0
- package/dist-server/harness/components/zone-dry-run.js +107 -0
- package/dist-server/harness/components/zone-gate.d.ts +76 -0
- package/dist-server/harness/components/zone-gate.js +144 -0
- package/dist-server/harness/events/index.d.ts +1 -1
- package/dist-server/harness/events/types.d.ts +52 -0
- package/dist-server/harness/index.d.ts +9 -2
- package/dist-server/harness/index.js +5 -1
- package/dist-server/harness/loop/executor.d.ts +1 -0
- package/dist-server/harness/loop/executor.js +37 -15
- package/dist-server/harness/npm-package-resolve.d.ts +2 -0
- package/dist-server/harness/npm-package-resolve.js +16 -4
- package/dist-server/harness/providers/adapters/openai-compatible.d.ts +13 -0
- package/dist-server/harness/providers/adapters/openai-compatible.js +17 -0
- package/dist-server/harness/providers/adapters/openai.d.ts +7 -0
- package/dist-server/harness/providers/adapters/openai.js +6 -0
- package/dist-server/harness/providers/adapters/pi-ai.d.ts +48 -0
- package/dist-server/harness/providers/adapters/pi-ai.js +518 -0
- package/dist-server/harness/providers/binding.d.ts +45 -4
- package/dist-server/harness/providers/binding.js +44 -8
- package/dist-server/harness/providers/index.d.ts +9 -3
- package/dist-server/harness/providers/index.js +10 -3
- package/dist-server/harness/providers/zone.d.ts +96 -0
- package/dist-server/harness/providers/zone.js +112 -0
- package/dist-server/harness/render/answering-query.d.ts +29 -0
- package/dist-server/harness/render/answering-query.js +62 -0
- package/dist-server/harness/render/envelope.d.ts +6 -0
- package/dist-server/harness/render/envelope.js +10 -3
- package/dist-server/harness/route/adapter-spec.d.ts +8 -9
- package/dist-server/harness/route/adapter-spec.js +13 -14
- package/dist-server/harness/route/codex-ask-events.js +2 -1
- package/dist-server/harness/route/codex-ask.d.ts +4 -0
- package/dist-server/harness/route/codex-ask.js +69 -30
- package/dist-server/harness/route/codex-host-query.d.ts +52 -0
- package/dist-server/harness/route/codex-host-query.js +191 -0
- package/dist-server/harness/route/codex-local-manifest.d.ts +9 -1
- package/dist-server/harness/route/codex-local-manifest.js +96 -15
- package/dist-server/harness/route/codex-wren-proxy.d.ts +33 -0
- package/dist-server/harness/route/codex-wren-proxy.js +227 -0
- package/dist-server/harness/route/describe.js +45 -6
- package/dist-server/harness/route/in-process.d.ts +22 -1
- package/dist-server/harness/route/in-process.js +54 -4
- package/dist-server/harness/route/route.js +5 -2
- package/dist-server/harness/route/types.d.ts +30 -1
- package/dist-server/harness/session/run.js +30 -10
- package/dist-server/harness/setup/runner.d.ts +2 -0
- package/dist-server/harness/setup/runner.js +38 -17
- package/dist-server/harness/setup/yaml-scalar.d.ts +23 -0
- package/dist-server/harness/setup/yaml-scalar.js +62 -0
- package/dist-server/server/adopt.js +1 -17
- package/dist-server/server/app.d.ts +1 -0
- package/dist-server/server/app.js +163 -14
- package/dist-server/server/auth-choice.d.ts +13 -1
- package/dist-server/server/auth-choice.js +66 -1
- package/dist-server/server/bin.js +177 -25
- package/dist-server/server/codex-local-grounding.d.ts +18 -0
- package/dist-server/server/codex-local-grounding.js +92 -0
- package/dist-server/server/codex-native-session.d.ts +25 -0
- package/dist-server/server/codex-native-session.js +1 -0
- package/dist-server/server/codex-runtime-composition.d.ts +34 -0
- package/dist-server/server/codex-runtime-composition.js +250 -0
- package/dist-server/server/codex-structured-ask.d.ts +23 -0
- package/dist-server/server/codex-structured-ask.js +102 -0
- package/dist-server/server/conn-config.js +4 -16
- package/dist-server/server/conversation-socket.d.ts +16 -0
- package/dist-server/server/conversation-socket.js +65 -0
- package/dist-server/server/db.d.ts +46 -0
- package/dist-server/server/db.js +88 -9
- package/dist-server/server/env-detect.d.ts +6 -0
- package/dist-server/server/env-detect.js +7 -0
- package/dist-server/server/fold.d.ts +22 -4
- package/dist-server/server/fold.js +37 -5
- package/dist-server/server/harness.d.ts +2 -2
- package/dist-server/server/harness.js +33 -7
- package/dist-server/server/interactive-terminal.d.ts +10 -6
- package/dist-server/server/interactive-terminal.js +33 -8
- package/dist-server/server/managed-wren-runtime.d.ts +116 -0
- package/dist-server/server/managed-wren-runtime.js +670 -0
- package/dist-server/server/native-artifacts.d.ts +23 -7
- package/dist-server/server/native-artifacts.js +43 -12
- package/dist-server/server/native-component-context.d.ts +19 -0
- package/dist-server/server/native-component-context.js +76 -0
- package/dist-server/server/native-component-preparation.d.ts +20 -0
- package/dist-server/server/native-component-preparation.js +129 -0
- package/dist-server/server/native-component-runtime.d.ts +36 -0
- package/dist-server/server/native-component-runtime.js +92 -0
- package/dist-server/server/native-components.d.ts +84 -0
- package/dist-server/server/native-components.js +160 -0
- package/dist-server/server/native-dispatch-process.d.ts +8 -0
- package/dist-server/server/native-dispatch-process.js +65 -0
- package/dist-server/server/native-runtime-spec.d.ts +89 -0
- package/dist-server/server/native-runtime-spec.js +169 -0
- package/dist-server/server/native-sessions.d.ts +172 -19
- package/dist-server/server/native-sessions.js +839 -244
- package/dist-server/server/native-shutdown.d.ts +6 -0
- package/dist-server/server/native-shutdown.js +28 -0
- package/dist-server/server/native-wren-home.d.ts +18 -0
- package/dist-server/server/native-wren-home.js +262 -0
- package/dist-server/server/node-pty-host.d.ts +2 -1
- package/dist-server/server/node-pty-host.js +3 -2
- package/dist-server/server/profile-registry.d.ts +139 -0
- package/dist-server/server/profile-registry.js +620 -0
- package/dist-server/server/runtime-binding.d.ts +4 -1
- package/dist-server/server/runtime-binding.js +50 -2
- package/dist-server/server/runtime-host/claude-component-step.d.ts +25 -0
- package/dist-server/server/runtime-host/claude-component-step.js +186 -0
- package/dist-server/server/runtime-host/codex-app-server.d.ts +75 -0
- package/dist-server/server/runtime-host/codex-app-server.js +239 -0
- package/dist-server/server/runtime-host/codex-compatibility.d.ts +110 -0
- package/dist-server/server/runtime-host/codex-compatibility.js +162 -0
- package/dist-server/server/runtime-host/codex-component-step.d.ts +19 -0
- package/dist-server/server/runtime-host/codex-component-step.js +308 -0
- package/dist-server/server/runtime-host/codex-conversation.d.ts +109 -0
- package/dist-server/server/runtime-host/codex-conversation.js +295 -0
- package/dist-server/server/runtime-host/codex-direct-tools.d.ts +23 -0
- package/dist-server/server/runtime-host/codex-direct-tools.js +59 -0
- package/dist-server/server/runtime-host/codex-events.d.ts +647 -0
- package/dist-server/server/runtime-host/codex-events.js +66 -0
- package/dist-server/server/runtime-host/codex-policy.d.ts +16 -0
- package/dist-server/server/runtime-host/codex-policy.js +151 -0
- package/dist-server/server/runtime-host/codex-process.d.ts +8 -0
- package/dist-server/server/runtime-host/codex-process.js +96 -0
- package/dist-server/server/runtime-host/codex-rpc.d.ts +47 -0
- package/dist-server/server/runtime-host/codex-rpc.js +182 -0
- package/dist-server/server/runtime-host/codex-session.d.ts +74 -0
- package/dist-server/server/runtime-host/codex-session.js +492 -0
- package/dist-server/server/runtime-host/codex-terminal-protocol.d.ts +35 -0
- package/dist-server/server/runtime-host/codex-terminal-protocol.js +243 -0
- package/dist-server/server/runtime-host/codex-terminal.d.ts +16 -0
- package/dist-server/server/runtime-host/codex-terminal.js +120 -0
- package/dist-server/server/runtime-host/index.d.ts +5 -0
- package/dist-server/server/runtime-host/index.js +3 -0
- package/dist-server/server/runtime-host/local.d.ts +29 -0
- package/dist-server/server/runtime-host/local.js +90 -0
- package/dist-server/server/runtime-host/policy.d.ts +8 -0
- package/dist-server/server/runtime-host/policy.js +78 -0
- package/dist-server/server/runtime-host/types.d.ts +52 -0
- package/dist-server/server/runtime-host/types.js +62 -0
- package/dist-server/server/structured-query-evidence.d.ts +7 -0
- package/dist-server/server/structured-query-evidence.js +47 -0
- package/dist-server/server/structured-runtime.d.ts +52 -0
- package/dist-server/server/structured-runtime.js +130 -0
- package/dist-server/server/structured-scope.d.ts +4 -0
- package/dist-server/server/structured-scope.js +12 -0
- package/dist-server/server/turn.d.ts +6 -1
- package/dist-server/server/turn.js +82 -25
- package/dist-server/server/wire-types.d.ts +67 -3
- package/dist-server/server/wren-profiles.js +1 -1
- package/managed-wren/README.md +60 -0
- package/managed-wren/dependency-wheels.json +282 -0
- package/managed-wren/manifest.json +373 -0
- package/managed-wren/release-inputs.json +45 -0
- package/managed-wren/runtime-tree.cjs +115 -0
- package/managed-wren/source-inputs.json +40 -0
- package/package.json +15 -6
- package/profiles/genbi-default/context/binding.yml +17 -7
- package/profiles/genbi-default/context/context.json +146 -0
- package/profiles/genbi-default/ir.golden.json +39 -43
- package/profiles/genbi-default/profile.yml +31 -0
- package/profiles/genbi-enrich-context/context/binding.yml +14 -3
- package/profiles/genbi-enrich-context/context/context.json +146 -0
- package/profiles/genbi-enrich-context/ir.golden.json +4 -5
- package/profiles/genbi-monitor/context/binding.yml +13 -5
- package/profiles/genbi-monitor/context/context.json +146 -0
- package/profiles/genbi-monitor/ir.golden.json +13 -7
- package/profiles/genbi-report/context/binding.yml +19 -0
- package/profiles/genbi-report/context/context.json +223 -0
- package/profiles/genbi-report/ir.golden.json +328 -0
- package/profiles/genbi-report/profile.yml +38 -0
- package/profiles/genbi-setup/ir.golden.json +3 -1
- package/dist/assets/index-Xs4q7pNo.css +0 -1
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* codex:local's Wren MCP server: a stdio proxy in front of `wren serve mcp`.
|
|
4
|
+
*
|
|
5
|
+
* node codex-wren-proxy.js --credential-file <abs path> -- <wren> serve mcp --project <p> --quiet
|
|
6
|
+
*
|
|
7
|
+
* Every JSON-RPC line passes through to the child `wren serve mcp` unchanged, so the model sees
|
|
8
|
+
* the same tool names and schemas, except a `tools/call` of `run_sql`: that goes to this turn's
|
|
9
|
+
* host query service (see `codex-host-query.ts`), which executes it through governed access and
|
|
10
|
+
* records it as host evidence. The credential file (0600, owned by this user) names the turn's
|
|
11
|
+
* unix socket and token; without a valid one, `run_sql` is refused rather than run elsewhere.
|
|
12
|
+
*
|
|
13
|
+
* Node builtins only, and erasable TypeScript only, so it also runs from source.
|
|
14
|
+
*/
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync, realpathSync } from "node:fs";
|
|
17
|
+
import { connect } from "node:net";
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
import { createInterface } from "node:readline";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
const RUN_SQL = "run_sql";
|
|
22
|
+
const MAX_SQL_BYTES = 65_536;
|
|
23
|
+
/** The sentence the model sees per host error class; nothing from the host's wire is forwarded. */
|
|
24
|
+
const ERROR_TEXT = {
|
|
25
|
+
invalid_request: "The request did not match the governed run_sql contract: pass a non-empty sql string and an optional positive integer limit.",
|
|
26
|
+
model_not_found: "The query references a table that is not a model in the bound semantic context; query only the models it defines.",
|
|
27
|
+
policy_rejected: "The read-only analytical policy rejected the query: use one SELECT that reads at least one bound model.",
|
|
28
|
+
invalid_sql: "The SQL could not be parsed or planned against the semantic context.",
|
|
29
|
+
execution_failed: "The data source rejected the query at execution time, for example an unknown column or a type mismatch.",
|
|
30
|
+
timeout: "The query exceeded the statement time limit.",
|
|
31
|
+
datasource_unavailable: "The bound data source could not be reached.",
|
|
32
|
+
result_too_large: "The result exceeded the governed byte limit; narrow the query.",
|
|
33
|
+
budget_exhausted: "This turn's query budget is exhausted; answer from the results you already have.",
|
|
34
|
+
unauthorized: "run_sql is unavailable: the host query service rejected this session.",
|
|
35
|
+
internal: "The governed query failed for an unclassified reason.",
|
|
36
|
+
transport: "The host query service is unavailable.",
|
|
37
|
+
};
|
|
38
|
+
const NO_CREDENTIAL = "run_sql is unavailable: no valid host query credential was provided for this turn.";
|
|
39
|
+
/**
|
|
40
|
+
* Accepts only an absolute, regular, user-owned file no one else can read or write. The file is
|
|
41
|
+
* opened without following a symlink and checked and read through that one descriptor, so what
|
|
42
|
+
* is checked is what is read.
|
|
43
|
+
*/
|
|
44
|
+
export function readCredential(file) {
|
|
45
|
+
if (!file || !path.isAbsolute(file))
|
|
46
|
+
return undefined;
|
|
47
|
+
let fd;
|
|
48
|
+
try {
|
|
49
|
+
fd = openSync(file, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
|
|
50
|
+
const stat = fstatSync(fd);
|
|
51
|
+
if (!stat.isFile() || (stat.mode & 0o077) !== 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
if (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
54
|
+
return undefined;
|
|
55
|
+
const value = JSON.parse(readFileSync(fd, "utf8"));
|
|
56
|
+
if (typeof value.socket !== "string" || !path.isAbsolute(value.socket))
|
|
57
|
+
return undefined;
|
|
58
|
+
if (typeof value.token !== "string" || value.token.length < 32)
|
|
59
|
+
return undefined;
|
|
60
|
+
return { socket: value.socket, token: value.token };
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
if (fd !== undefined)
|
|
67
|
+
closeSync(fd);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* One connection at a time to the turn's host query service, reconnecting after a drop. Only
|
|
72
|
+
* the current socket's failure fails the pending requests (all of which were sent on it): a
|
|
73
|
+
* stale socket closing late never fails a request pending on its replacement. Each socket has
|
|
74
|
+
* its own read buffer.
|
|
75
|
+
*/
|
|
76
|
+
export class HostConnection {
|
|
77
|
+
credential;
|
|
78
|
+
open;
|
|
79
|
+
pending = new Map();
|
|
80
|
+
socket;
|
|
81
|
+
nextId = 1;
|
|
82
|
+
constructor(credential, open = connect) {
|
|
83
|
+
this.credential = credential;
|
|
84
|
+
this.open = open;
|
|
85
|
+
}
|
|
86
|
+
request(sql, limit) {
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
const id = this.nextId++;
|
|
89
|
+
try {
|
|
90
|
+
const socket = this.current();
|
|
91
|
+
this.pending.set(id, resolve);
|
|
92
|
+
socket.write(`${JSON.stringify({ token: this.credential.token, id, sql, ...(limit !== undefined ? { limit } : {}) })}\n`);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
this.pending.delete(id);
|
|
96
|
+
resolve({ error: "transport" });
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
close() {
|
|
101
|
+
this.socket?.end();
|
|
102
|
+
}
|
|
103
|
+
current() {
|
|
104
|
+
if (this.socket && !this.socket.destroyed)
|
|
105
|
+
return this.socket;
|
|
106
|
+
const socket = this.open(this.credential.socket);
|
|
107
|
+
let buffer = "";
|
|
108
|
+
const fail = () => {
|
|
109
|
+
if (this.socket !== socket)
|
|
110
|
+
return;
|
|
111
|
+
this.socket = undefined;
|
|
112
|
+
for (const waiter of this.pending.values())
|
|
113
|
+
waiter({ error: "transport" });
|
|
114
|
+
this.pending.clear();
|
|
115
|
+
};
|
|
116
|
+
socket.setEncoding("utf8");
|
|
117
|
+
socket.on("data", (chunk) => {
|
|
118
|
+
buffer += chunk;
|
|
119
|
+
let newline = buffer.indexOf("\n");
|
|
120
|
+
while (newline >= 0) {
|
|
121
|
+
const line = buffer.slice(0, newline);
|
|
122
|
+
buffer = buffer.slice(newline + 1);
|
|
123
|
+
newline = buffer.indexOf("\n");
|
|
124
|
+
try {
|
|
125
|
+
const frame = JSON.parse(line);
|
|
126
|
+
const waiter = typeof frame.id === "number" ? this.pending.get(frame.id) : undefined;
|
|
127
|
+
if (!waiter || typeof frame.id !== "number")
|
|
128
|
+
continue;
|
|
129
|
+
this.pending.delete(frame.id);
|
|
130
|
+
if (frame.error !== undefined)
|
|
131
|
+
waiter({ error: typeof frame.error?.class === "string" ? frame.error.class : "internal" });
|
|
132
|
+
else
|
|
133
|
+
waiter({ result: frame.result });
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
socket.destroy();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
socket.on("error", fail);
|
|
141
|
+
socket.on("close", fail);
|
|
142
|
+
this.socket = socket;
|
|
143
|
+
return socket;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function parseArgs(argv) {
|
|
147
|
+
const separator = argv.indexOf("--");
|
|
148
|
+
if (separator < 0 || separator === argv.length - 1) {
|
|
149
|
+
process.stderr.write("codex wren proxy: usage: --credential-file <path> -- <command> [args...]\n");
|
|
150
|
+
process.exit(2);
|
|
151
|
+
}
|
|
152
|
+
const own = argv.slice(0, separator);
|
|
153
|
+
const index = own.indexOf("--credential-file");
|
|
154
|
+
const credentialFile = index >= 0 ? own[index + 1] : undefined;
|
|
155
|
+
return { ...(credentialFile !== undefined ? { credentialFile } : {}), command: argv[separator + 1], args: argv.slice(separator + 2) };
|
|
156
|
+
}
|
|
157
|
+
function main() {
|
|
158
|
+
const options = parseArgs(process.argv.slice(2));
|
|
159
|
+
const credential = readCredential(options.credentialFile);
|
|
160
|
+
const host = credential ? new HostConnection(credential) : undefined;
|
|
161
|
+
const child = spawn(options.command, options.args, { stdio: ["pipe", "pipe", "inherit"] });
|
|
162
|
+
child.on("error", (error) => {
|
|
163
|
+
process.stderr.write(`codex wren proxy: could not start the Wren MCP server: ${error.message}\n`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
});
|
|
166
|
+
child.on("exit", (code, signal) => process.exit(code ?? (signal ? 1 : 0)));
|
|
167
|
+
const send = (line) => { process.stdout.write(`${line}\n`); };
|
|
168
|
+
createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", send);
|
|
169
|
+
const toolResult = (id, text, isError, structured) => {
|
|
170
|
+
send(JSON.stringify({ jsonrpc: "2.0", id, result: {
|
|
171
|
+
content: [{ type: "text", text }],
|
|
172
|
+
...(structured !== undefined ? { structuredContent: structured } : {}),
|
|
173
|
+
isError,
|
|
174
|
+
} }));
|
|
175
|
+
};
|
|
176
|
+
const runSql = async (id, input) => {
|
|
177
|
+
if (!host) {
|
|
178
|
+
toolResult(id, NO_CREDENTIAL, true);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const args = typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
|
|
182
|
+
const { sql, limit } = args;
|
|
183
|
+
if (typeof sql !== "string" || !sql.trim() || Buffer.byteLength(sql) > MAX_SQL_BYTES
|
|
184
|
+
|| (limit !== undefined && limit !== null && (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1))) {
|
|
185
|
+
toolResult(id, ERROR_TEXT.invalid_request, true);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const outcome = await host.request(sql, typeof limit === "number" ? limit : undefined);
|
|
189
|
+
if (outcome.error !== undefined) {
|
|
190
|
+
const known = outcome.error in ERROR_TEXT ? outcome.error : "internal";
|
|
191
|
+
toolResult(id, `Governed Wren query failed [${known}]: ${ERROR_TEXT[known]}`, true);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
toolResult(id, JSON.stringify(outcome.result), false, outcome.result);
|
|
195
|
+
};
|
|
196
|
+
createInterface({ input: process.stdin, crlfDelay: Infinity })
|
|
197
|
+
.on("line", (line) => {
|
|
198
|
+
let message;
|
|
199
|
+
try {
|
|
200
|
+
message = JSON.parse(line);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
message = undefined;
|
|
204
|
+
}
|
|
205
|
+
if (message && message.method === "tools/call" && message.id !== undefined && message.params?.name === RUN_SQL) {
|
|
206
|
+
void runSql(message.id, message.params.arguments);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
child.stdin.write(`${line}\n`);
|
|
210
|
+
})
|
|
211
|
+
.on("close", () => {
|
|
212
|
+
child.stdin.end();
|
|
213
|
+
host?.close();
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function invokedDirectly() {
|
|
217
|
+
if (process.argv[1] === undefined)
|
|
218
|
+
return false;
|
|
219
|
+
try {
|
|
220
|
+
return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (invokedDirectly())
|
|
227
|
+
main();
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
1
|
+
import { mkdtemp, readFile, realpath, rm } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { generatePreparedContext, resolveContextLoaderBinary } from "../compile/context-loader.js";
|
|
5
|
+
import { resolveWarbleBinary } from "../compile/resolve-binary.js";
|
|
2
6
|
import { loadBundleWithProvenance } from "../bundle/loader.js";
|
|
3
7
|
import { compileProfile, compileRawProfile } from "../compile/pipeline.js";
|
|
8
|
+
import { planDigest, readExecutionPlan } from "../components/plan.js";
|
|
9
|
+
import { describeComponentPlan } from "../components/display.js";
|
|
4
10
|
import { buildAgentSdkManifestArgs, runAgentSdkManifest } from "./agent-sdk-manifest.js";
|
|
5
11
|
import { resolveAgentSdkCli } from "./agent-sdk-cli.js";
|
|
6
12
|
import { resolveCodexLocalCli } from "./codex-local-cli.js";
|
|
@@ -45,14 +51,44 @@ async function describeCodexManifest(options) {
|
|
|
45
51
|
throw new Error("Codex manifest requires orchestrator, cheap, and strong model bindings");
|
|
46
52
|
}
|
|
47
53
|
const cli = await resolveCodexLocalCli(options.codexLocalBin);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
if (purpose === "context_enrichment")
|
|
55
|
+
return describeCodexEnrichmentManifest(cli, compiled.irPath, models);
|
|
56
|
+
const ir = JSON.parse(await readFile(compiled.irPath, "utf8"));
|
|
57
|
+
if (!ir.components.some((node) => node.llm_calls.some((step) => step.component_calls?.length))) {
|
|
58
|
+
return describeCodexAskManifest(cli, compiled.irPath, models);
|
|
59
|
+
}
|
|
60
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "genbi-manifest-context-"));
|
|
61
|
+
try {
|
|
62
|
+
if (options.context === "bootstrap")
|
|
63
|
+
throw new Error("Composed analysis requires a bound project");
|
|
64
|
+
const project = await realpath(options.userProject);
|
|
65
|
+
for (const id of ["answer_query", "generate_dashboard"]) {
|
|
66
|
+
const binding = ir.components.find((node) => node.id === id)?.context_binding;
|
|
67
|
+
if (!binding || typeof binding.project !== "string" || !path.isAbsolute(binding.project) || await realpath(binding.project) !== project) {
|
|
68
|
+
throw new Error(`Codex manifest cannot capture context for ${id} from a different project`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const file = path.join(dir, "context.json");
|
|
72
|
+
await generatePreparedContext(resolveContextLoaderBinary(), project, file);
|
|
73
|
+
const snapshot = JSON.parse(await readFile(file, "utf8"));
|
|
74
|
+
return await describeCodexAskManifest(cli, compiled.irPath, models, {
|
|
75
|
+
warbleBin: await resolveWarbleBinary(options.warbleBin),
|
|
76
|
+
contexts: Object.fromEntries(ir.components.map((node) => [node.id, { binding: node.context_binding, snapshot }])),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await rm(dir, { recursive: true, force: true });
|
|
81
|
+
}
|
|
51
82
|
}
|
|
52
83
|
async function describeVercelBundle(options) {
|
|
53
84
|
const compiled = await compileForDescription(options, "agnostic");
|
|
54
85
|
// `mode: "agnostic"` always produces a bundle — see `compileProfile`'s doc comment.
|
|
55
86
|
const bundleJson = JSON.parse(await readFile(compiled.bundlePath, "utf-8"));
|
|
87
|
+
if (bundleJson.vercel_bundle_version === "0.2") {
|
|
88
|
+
const ir = JSON.parse(await readFile(compiled.irPath, "utf8"));
|
|
89
|
+
const plan = readExecutionPlan(JSON.stringify(bundleJson), { digest: bundleJson.bundle_sha256, inputIrDigest: planDigest(ir), declarations: Object.fromEntries(ir.components.map((node) => [node.id, node])), contextBinding: ir.context_binding });
|
|
90
|
+
return describeComponentPlan(plan, bundleJson.profile);
|
|
91
|
+
}
|
|
56
92
|
return loadBundleWithProvenance(bundleJson, {
|
|
57
93
|
...(compiled.warbleBin !== undefined ? { warbleBin: compiled.warbleBin } : {}),
|
|
58
94
|
profileSource: options.profileSource,
|
|
@@ -66,10 +102,13 @@ async function describeAgentSdkManifest(options) {
|
|
|
66
102
|
...(options.context !== "bootstrap" ? { userProject: options.userProject } : {}),
|
|
67
103
|
});
|
|
68
104
|
const stdout = await runAgentSdkManifest(command, args);
|
|
69
|
-
|
|
105
|
+
const manifest = JSON.parse(stdout);
|
|
106
|
+
if (manifest.target !== "claude-agent-sdk:local")
|
|
107
|
+
throw new Error("Unexpected SDK manifest target");
|
|
108
|
+
return loadBundleWithProvenance(manifest, {
|
|
70
109
|
...(compiled.warbleBin !== undefined ? { warbleBin: compiled.warbleBin } : {}),
|
|
71
110
|
profileSource: options.profileSource,
|
|
72
|
-
});
|
|
111
|
+
}, { irVersion: "0.9", bundleVersions: ["0.1", "0.3"] });
|
|
73
112
|
}
|
|
74
113
|
function compileForDescription(options, mode) {
|
|
75
114
|
const shared = {
|
|
@@ -1,11 +1,32 @@
|
|
|
1
|
+
import { type TierBinding } from "../providers/index.js";
|
|
1
2
|
import type { RunAgentResult } from "../session/index.js";
|
|
2
3
|
import type { InProcessOptions } from "./types.js";
|
|
3
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Projects a bundle-wide validated map onto the component selected for one
|
|
6
|
+
* turn, keyed on (mount, tier): an `<agent.id>/<tier>` entry wins over the
|
|
7
|
+
* bare tier entry, so the same tier name can bind a different model per mount.
|
|
8
|
+
*/
|
|
4
9
|
export declare function filterTierBindingForAgent(agent: {
|
|
10
|
+
readonly id?: string;
|
|
5
11
|
readonly steps: readonly {
|
|
6
12
|
readonly tier: string;
|
|
7
13
|
}[];
|
|
8
14
|
}, tierBinding: Readonly<Record<string, import("../providers/index.js").AdapterSpec>>): Readonly<Record<string, import("../providers/index.js").AdapterSpec>>;
|
|
15
|
+
/**
|
|
16
|
+
* The legacy (single-agent, IR 0.6) path has no caller/callee split: every
|
|
17
|
+
* step, and the render stage, sees rows. So a zone-aware binding on this path
|
|
18
|
+
* must be all-private; a `public` or unset zone on any tier the agent (or its
|
|
19
|
+
* render stage) uses is a loud failure, the same posture as the composed gate.
|
|
20
|
+
*/
|
|
21
|
+
export declare function assertLegacyZoneBinding(agent: {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly steps: readonly {
|
|
24
|
+
readonly tier: string;
|
|
25
|
+
readonly realization: {
|
|
26
|
+
readonly kind: string;
|
|
27
|
+
};
|
|
28
|
+
}[];
|
|
29
|
+
}, binding: TierBinding, renderTier: string | undefined): void;
|
|
9
30
|
/**
|
|
10
31
|
* Resolves the `rootDir` the native `write_artifact` tool's
|
|
11
32
|
* `createLocalExecutionEnv` scope is rooted at. Precedence: an explicit
|
|
@@ -3,20 +3,57 @@ import path from "node:path";
|
|
|
3
3
|
import { createDefaultCapabilityRegistry } from "../capability/registry.js";
|
|
4
4
|
import { createLocalExecutionEnv } from "../exec/index.js";
|
|
5
5
|
import { deriveEnforcement } from "../guardrails/index.js";
|
|
6
|
-
import { createDefaultProviderRegistry } from "../providers/index.js";
|
|
6
|
+
import { createDefaultProviderRegistry, isZoneAwareBinding, resolveTierSpec } from "../providers/index.js";
|
|
7
|
+
import { ZoneGateError } from "../components/zone-gate.js";
|
|
7
8
|
import { runAgent } from "../session/index.js";
|
|
8
9
|
import { createWrenNativeToolRegistry, resolveWrenBinary } from "../tools/index.js";
|
|
9
10
|
import { deriveAdapterSpec } from "./adapter-spec.js";
|
|
10
11
|
import { describeBundle } from "./describe.js";
|
|
11
12
|
import { buildHybridTierBinding, buildUniformTierBinding } from "./tier-binding.js";
|
|
13
|
+
import { executionPlanFor } from "../components/display.js";
|
|
14
|
+
import { runInProcessComponents } from "../components/in-process.js";
|
|
12
15
|
const ANSWER_QUERY_AGENT_ID = "answer_query";
|
|
13
16
|
/** Operator-wide override for `resolveArtifactsDir`'s default, e.g. for a long-running BFF process. */
|
|
14
17
|
const ARTIFACTS_DIR_ENV_VAR = "WREN_HARNESS_ARTIFACTS_DIR";
|
|
15
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Projects a bundle-wide validated map onto the component selected for one
|
|
20
|
+
* turn, keyed on (mount, tier): an `<agent.id>/<tier>` entry wins over the
|
|
21
|
+
* bare tier entry, so the same tier name can bind a different model per mount.
|
|
22
|
+
*/
|
|
16
23
|
export function filterTierBindingForAgent(agent, tierBinding) {
|
|
24
|
+
const binding = { tiers: tierBinding };
|
|
17
25
|
return Object.fromEntries([...new Set(agent.steps.map((step) => step.tier))]
|
|
18
|
-
.
|
|
19
|
-
.
|
|
26
|
+
.map((tier) => [tier, resolveTierSpec(binding, tier, agent.id)?.spec])
|
|
27
|
+
.filter((entry) => entry[1] !== undefined));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The legacy (single-agent, IR 0.6) path has no caller/callee split: every
|
|
31
|
+
* step, and the render stage, sees rows. So a zone-aware binding on this path
|
|
32
|
+
* must be all-private; a `public` or unset zone on any tier the agent (or its
|
|
33
|
+
* render stage) uses is a loud failure, the same posture as the composed gate.
|
|
34
|
+
*/
|
|
35
|
+
export function assertLegacyZoneBinding(agent, binding, renderTier) {
|
|
36
|
+
if (!isZoneAwareBinding(binding))
|
|
37
|
+
return;
|
|
38
|
+
const violations = [];
|
|
39
|
+
const check = (tier, what) => {
|
|
40
|
+
const resolved = resolveTierSpec(binding, tier, agent.id);
|
|
41
|
+
const zone = resolved?.spec.zone ?? "unbound";
|
|
42
|
+
if (!resolved)
|
|
43
|
+
violations.push({ code: "unbound_tier", component: agent.id, tier, zone, message: `${what} (tier ${tier}) has no binding entry` });
|
|
44
|
+
else if (zone === "unbound")
|
|
45
|
+
violations.push({ code: "missing_zone", component: agent.id, tier, zone, message: `${what} (tier ${tier}) sees project data but binding entry "${resolved.key}" declares no zone` });
|
|
46
|
+
else if (zone !== "private")
|
|
47
|
+
violations.push({ code: "data_step_public", component: agent.id, tier, zone, message: `${what} (tier ${tier}) sees project data but binding entry "${resolved.key}" is zone: ${zone}; it must be private` });
|
|
48
|
+
};
|
|
49
|
+
for (const step of agent.steps)
|
|
50
|
+
check(step.tier, `step ${agent.id}.${step.tier}`);
|
|
51
|
+
const independent = agent.steps.filter((step) => step.realization.kind === "independent");
|
|
52
|
+
const render = renderTier ?? independent[independent.length - 1]?.tier;
|
|
53
|
+
if (render !== undefined)
|
|
54
|
+
check(render, `render stage of ${agent.id}`);
|
|
55
|
+
if (violations.length > 0)
|
|
56
|
+
throw new ZoneGateError(violations);
|
|
20
57
|
}
|
|
21
58
|
/**
|
|
22
59
|
* Resolves the `rootDir` the native `write_artifact` tool's
|
|
@@ -56,6 +93,12 @@ export function resolveArtifactsDir(outDir) {
|
|
|
56
93
|
*/
|
|
57
94
|
export async function runInProcessDefault(options) {
|
|
58
95
|
const bundle = options.bundle ?? (await describeBundle(options));
|
|
96
|
+
if (bundle.vercel_bundle_version === "0.2") {
|
|
97
|
+
const plan = executionPlanFor(bundle);
|
|
98
|
+
if (!plan)
|
|
99
|
+
throw new Error("Composed display has no trusted execution plan");
|
|
100
|
+
return runInProcessComponents(plan, options);
|
|
101
|
+
}
|
|
59
102
|
// Intent routing (server/turn.ts) picks the agent id when present; falls back to answer_query,
|
|
60
103
|
// the original default from before intent routing existed.
|
|
61
104
|
const agentId = options.agentId ?? ANSWER_QUERY_AGENT_ID;
|
|
@@ -69,6 +112,13 @@ export async function runInProcessDefault(options) {
|
|
|
69
112
|
// here; `buildHybridTierBinding` intentionally rejects tiers used solely by
|
|
70
113
|
// another component.
|
|
71
114
|
const agentTierBinding = options.tierBinding === undefined ? undefined : filterTierBindingForAgent(agent, options.tierBinding);
|
|
115
|
+
if (options.tierBinding !== undefined || options.disclosurePolicy !== undefined || options.zoneRoles !== undefined) {
|
|
116
|
+
assertLegacyZoneBinding(agent, {
|
|
117
|
+
tiers: options.tierBinding ?? {},
|
|
118
|
+
...(options.disclosurePolicy !== undefined ? { disclosurePolicy: options.disclosurePolicy } : {}),
|
|
119
|
+
...(options.zoneRoles !== undefined ? { roles: options.zoneRoles } : {}),
|
|
120
|
+
}, undefined);
|
|
121
|
+
}
|
|
72
122
|
const binding = options.tierBinding !== undefined
|
|
73
123
|
? buildHybridTierBinding(agent, agentTierBinding)
|
|
74
124
|
: buildUniformTierBinding(agent, deriveAdapterSpec(options.authChoice, options.model !== undefined ? { model: options.model } : {}));
|
|
@@ -41,8 +41,8 @@ export async function route(options) {
|
|
|
41
41
|
const deployment = options.deployment ?? "personal";
|
|
42
42
|
const { warnings } = enforceCompliance(authChoice, { deployment });
|
|
43
43
|
if (authChoice.mode === "subscription") {
|
|
44
|
-
if (options.tierBinding !== undefined) {
|
|
45
|
-
throw new Error("tierBinding (hybrid in-process per-tier routing) has no effect under a subscription " +
|
|
44
|
+
if (options.tierBinding !== undefined || options.disclosurePolicy !== undefined || options.zoneRoles !== undefined) {
|
|
45
|
+
throw new Error("tierBinding (with disclosurePolicy/zoneRoles: hybrid in-process per-tier routing) has no effect under a subscription " +
|
|
46
46
|
"authChoice — dispatched has no adapter/tier binding of its own; use modelsConfig instead " +
|
|
47
47
|
"(warble-agent-sdk's own --models-config per-step routing)");
|
|
48
48
|
}
|
|
@@ -96,6 +96,7 @@ export async function route(options) {
|
|
|
96
96
|
"per-tier adapter map)");
|
|
97
97
|
}
|
|
98
98
|
const result = await runInProcess({
|
|
99
|
+
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
99
100
|
authChoice,
|
|
100
101
|
profileSource: options.profileSource,
|
|
101
102
|
userProject: options.userProject,
|
|
@@ -107,6 +108,8 @@ export async function route(options) {
|
|
|
107
108
|
...(options.bundle !== undefined ? { bundle: options.bundle } : {}),
|
|
108
109
|
...(options.mcpServers !== undefined ? { mcpServers: options.mcpServers } : {}),
|
|
109
110
|
...(options.tierBinding !== undefined ? { tierBinding: options.tierBinding } : {}),
|
|
111
|
+
...(options.disclosurePolicy !== undefined ? { disclosurePolicy: options.disclosurePolicy } : {}),
|
|
112
|
+
...(options.zoneRoles !== undefined ? { zoneRoles: options.zoneRoles } : {}),
|
|
110
113
|
...(options.onEvent !== undefined ? { onEvent: options.onEvent } : {}),
|
|
111
114
|
...(options.agentId !== undefined ? { agentId: options.agentId } : {}),
|
|
112
115
|
});
|
|
@@ -2,7 +2,7 @@ import type { AuthChoice } from "../auth/index.js";
|
|
|
2
2
|
import type { Bundle } from "../bundle/schema.js";
|
|
3
3
|
import type { Deployment } from "../compliance/index.js";
|
|
4
4
|
import type { AgentEvent } from "../events/index.js";
|
|
5
|
-
import type { AdapterSpec } from "../providers/index.js";
|
|
5
|
+
import type { AdapterSpec, DisclosurePolicy, ZoneRoles } from "../providers/index.js";
|
|
6
6
|
import type { RunAgentResult } from "../session/index.js";
|
|
7
7
|
import type { McpServerConfigMap } from "../tools/index.js";
|
|
8
8
|
import type { ResolvedCli } from "./agent-sdk-cli.js";
|
|
@@ -15,6 +15,7 @@ import type { CodexManifestModels } from "./codex-local-manifest.js";
|
|
|
15
15
|
* tool through the real `wren` CLI (native tools) against `userProject`.
|
|
16
16
|
*/
|
|
17
17
|
export interface InProcessOptions {
|
|
18
|
+
readonly signal?: AbortSignal;
|
|
18
19
|
readonly authChoice: Extract<AuthChoice, {
|
|
19
20
|
mode: "api-key" | "local" | "gateway";
|
|
20
21
|
}>;
|
|
@@ -55,6 +56,19 @@ export interface InProcessOptions {
|
|
|
55
56
|
* coverage is total-or-loud-fail.
|
|
56
57
|
*/
|
|
57
58
|
readonly tierBinding?: Readonly<Record<string, AdapterSpec>>;
|
|
59
|
+
/**
|
|
60
|
+
* Hybrid privacy split: the egress disclosure policy the verification step
|
|
61
|
+
* enforces on every callee result before a caller sees it. Its presence
|
|
62
|
+
* arms the zone gate (see `components/zone-gate.ts`) and requires
|
|
63
|
+
* `zoneRoles.judge`.
|
|
64
|
+
*/
|
|
65
|
+
readonly disclosurePolicy?: DisclosurePolicy;
|
|
66
|
+
/** Hybrid privacy split: binding keys of the judge / render tiers the zone gate checks by role. */
|
|
67
|
+
readonly zoneRoles?: ZoneRoles;
|
|
68
|
+
/** Hybrid privacy split: size bound for the capability card handed to public-zone steps (default 32 KiB). */
|
|
69
|
+
readonly capabilityCard?: {
|
|
70
|
+
readonly maxBytes?: number;
|
|
71
|
+
};
|
|
58
72
|
/** Live-event layer: forwarded to `RunAgentContext.onEvent`. See that field's doc comment. */
|
|
59
73
|
readonly onEvent?: (event: AgentEvent) => void;
|
|
60
74
|
/**
|
|
@@ -209,6 +223,11 @@ export interface CodexAskOptions {
|
|
|
209
223
|
}
|
|
210
224
|
export interface CodexAskResult {
|
|
211
225
|
readonly finalText: string;
|
|
226
|
+
/**
|
|
227
|
+
* codex:local only: the queries this turn's host query service executed for the model's
|
|
228
|
+
* `run_sql`, the only evidence its answer may be grounded on. Never persisted.
|
|
229
|
+
*/
|
|
230
|
+
readonly hostObservations?: readonly import("./codex-host-query.js").HostQueryObservation[];
|
|
212
231
|
}
|
|
213
232
|
export type CodexAskExecutor = (options: CodexAskOptions) => Promise<CodexAskResult>;
|
|
214
233
|
/**
|
|
@@ -243,6 +262,10 @@ export interface RouteOptions {
|
|
|
243
262
|
readonly mcpServers?: McpServerConfigMap;
|
|
244
263
|
/** In-process only (hybrid mode); see `InProcessOptions.tierBinding`. `route()` rejects this alongside a `subscription` authChoice. */
|
|
245
264
|
readonly tierBinding?: Readonly<Record<string, AdapterSpec>>;
|
|
265
|
+
/** In-process only; see `InProcessOptions.disclosurePolicy`. */
|
|
266
|
+
readonly disclosurePolicy?: DisclosurePolicy;
|
|
267
|
+
/** In-process only; see `InProcessOptions.zoneRoles`. */
|
|
268
|
+
readonly zoneRoles?: ZoneRoles;
|
|
246
269
|
/** Dispatched only (hybrid mode); see `DispatchedOptions.modelsConfig`. `route()` rejects this alongside a non-`subscription` authChoice. */
|
|
247
270
|
readonly modelsConfig?: string;
|
|
248
271
|
/** Live-event layer: forwarded to whichever mode executor runs. See `InProcessOptions.onEvent`/`DispatchedOptions.onEvent`. */
|
|
@@ -283,4 +306,10 @@ export type RouteResult = ({
|
|
|
283
306
|
} & DispatchedResult) | ({
|
|
284
307
|
readonly backend: "codex-local";
|
|
285
308
|
readonly warnings: readonly string[];
|
|
309
|
+
} & CodexAskResult) | ({
|
|
310
|
+
readonly backend: "codex-app-server";
|
|
311
|
+
readonly warnings: readonly string[];
|
|
312
|
+
/** Host-captured normalized component evidence; never recovered from model prose. */
|
|
313
|
+
readonly envelope?: import("../render/envelope.js").RenderEnvelope;
|
|
314
|
+
readonly dataAttempted?: boolean;
|
|
286
315
|
} & CodexAskResult);
|
|
@@ -4,6 +4,7 @@ import { createLocalExecutionEnv } from "../exec/index.js";
|
|
|
4
4
|
import { deriveEnforcement } from "../guardrails/index.js";
|
|
5
5
|
import { executeAgent, summarizeToolOutput } from "../loop/index.js";
|
|
6
6
|
import { getAllowedBlockTypes, renderEnvelope } from "../render/index.js";
|
|
7
|
+
import { selectAnsweringCandidate } from "../render/answering-query.js";
|
|
7
8
|
import { BUILD_DASHBOARD_TOOL_NAME, WREN_QUERY_TOOL_NAME, withResolvedTools } from "../tools/index.js";
|
|
8
9
|
import { UnknownAgentError } from "./errors.js";
|
|
9
10
|
import { findLockedGatedCheck } from "./gate.js";
|
|
@@ -23,11 +24,16 @@ import { findLockedGatedCheck } from "./gate.js";
|
|
|
23
24
|
* becomes a `RefusalResult`.
|
|
24
25
|
*/
|
|
25
26
|
export async function runAgent(bundle, agentId, userInput, ctx) {
|
|
27
|
+
if (bundle.vercel_bundle_version === "0.2")
|
|
28
|
+
throw new Error("Composed plans require the component host runner");
|
|
26
29
|
assertCapabilities(bundle, ctx.capabilityRegistry);
|
|
27
30
|
const agent = bundle.agents.find((candidate) => candidate.id === agentId);
|
|
28
31
|
if (!agent) {
|
|
29
32
|
throw new UnknownAgentError(agentId);
|
|
30
33
|
}
|
|
34
|
+
if (agent.entrypoint === false || (agent.dependencies?.length ?? 0) > 0 || bundle.manifest_version === "0.3") {
|
|
35
|
+
throw new Error("This manifest requires its owning component runtime");
|
|
36
|
+
}
|
|
31
37
|
const emitter = createAgentEventEmitter(ctx.onEvent);
|
|
32
38
|
emitter.emit({ kind: "run.start", mode: "A", agentId });
|
|
33
39
|
try {
|
|
@@ -50,15 +56,16 @@ export async function runAgent(bundle, agentId, userInput, ctx) {
|
|
|
50
56
|
// forced to a refusal by this check.
|
|
51
57
|
let sawSuccessfulDataAccessCall = false;
|
|
52
58
|
const requiresDataAccess = agent.capabilities.some((entry) => entry.capability.startsWith("sql_execution:"));
|
|
53
|
-
// Deterministic table capture:
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
59
|
+
// Deterministic table capture: every *successful* `query` tool result,
|
|
60
|
+
// kept as a flat table payload (columns + positional rows + the SQL that
|
|
61
|
+
// produced it). This is the agent's real data — `renderEnvelope` builds
|
|
62
|
+
// the table/definition blocks straight from it instead of asking the
|
|
63
|
+
// render model to re-emit structure it tends to summarize away (leaving
|
|
64
|
+
// a bare `{type:"table"}`). Which capture is the answer is decided after
|
|
65
|
+
// the loop (see `selectAnsweringCandidate`): the one whose SQL the
|
|
66
|
+
// terminal artifact names, because a model that runs a stray check after
|
|
67
|
+
// the right query must not turn that check into a verified answer.
|
|
68
|
+
const toolTables = [];
|
|
62
69
|
// Deterministic dashboard-envelope capture: the most recent
|
|
63
70
|
// *successful* `build_dashboard` tool result, kept as-is (it's
|
|
64
71
|
// already a complete, ordered `{blocks}` envelope — see
|
|
@@ -110,7 +117,7 @@ export async function runAgent(bundle, agentId, userInput, ctx) {
|
|
|
110
117
|
sawSuccessfulDataAccessCall = true;
|
|
111
118
|
const seed = toToolTableSeed(outcome.output, outcome.input);
|
|
112
119
|
if (seed !== undefined)
|
|
113
|
-
|
|
120
|
+
toolTables.push(seed);
|
|
114
121
|
}
|
|
115
122
|
if (outcome.tool === BUILD_DASHBOARD_TOOL_NAME && outcome.outcome === "success") {
|
|
116
123
|
const seed = toDashboardSeed(outcome.output);
|
|
@@ -124,6 +131,7 @@ export async function runAgent(bundle, agentId, userInput, ctx) {
|
|
|
124
131
|
},
|
|
125
132
|
onEvent: emitter.emit,
|
|
126
133
|
});
|
|
134
|
+
const toolTable = selectAnsweringCandidate(toolTables, terminalArtifactValue(artifacts));
|
|
127
135
|
const envelope = await renderEnvelope(agent, artifacts, {
|
|
128
136
|
binding: ctx.binding,
|
|
129
137
|
registry: ctx.registry,
|
|
@@ -278,6 +286,18 @@ export async function runAgent(bundle, agentId, userInput, ctx) {
|
|
|
278
286
|
throw error;
|
|
279
287
|
}
|
|
280
288
|
}
|
|
289
|
+
/** The last dataflow artifact as a value: JSON text is parsed so a named `definition.sql` is visible. */
|
|
290
|
+
function terminalArtifactValue(artifacts) {
|
|
291
|
+
const last = [...artifacts.values()].at(-1);
|
|
292
|
+
if (typeof last !== "string")
|
|
293
|
+
return last;
|
|
294
|
+
try {
|
|
295
|
+
return JSON.parse(last);
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return last;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
281
301
|
function describeRunError(error) {
|
|
282
302
|
if (error instanceof Error)
|
|
283
303
|
return error.message;
|
|
@@ -18,6 +18,8 @@ export declare const BUILD_CONTEXT_AGENT_ID = "build_context";
|
|
|
18
18
|
*/
|
|
19
19
|
export declare const DEFAULT_SETUP_MAX_TURNS = 120;
|
|
20
20
|
export interface SetupStepRunOptions {
|
|
21
|
+
/** Owned turn cancellation, forwarded to the selected runtime. */
|
|
22
|
+
readonly signal?: AbortSignal;
|
|
21
23
|
/** The composed single-line prompt (see `composeSetupPrompt`). */
|
|
22
24
|
readonly prompt: string;
|
|
23
25
|
/** The workspace root the initial connect turn scaffolds `<name>/` into. */
|