@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
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
export { UnknownAdapterError, UnknownTierError } from "./errors.js";
|
|
2
2
|
export { createProviderRegistry } from "./registry.js";
|
|
3
|
-
export { resolveStepModel, resolveTierModel } from "./binding.js";
|
|
3
|
+
export { isZoneAwareBinding, parseTierBindingKey, resolveStepModel, resolveTierModel, resolveTierSpec, tierBindingKey, } from "./binding.js";
|
|
4
|
+
export { ANSWER_SHAPES, ZONES, answerShapeSchema, disclosurePolicySchema, parseDisclosurePolicy, parseTierBindingDocument, readTierBindingFile, TierBindingParseError, tierBindingDocumentSchema, zoneRolesSchema, zoneSchema, } from "./zone.js";
|
|
4
5
|
export { createMockAdapter, MOCK_ADAPTER_ID } from "./adapters/mock.js";
|
|
5
|
-
export { createOpenAICompatibleAdapter, OPENAI_COMPATIBLE_ADAPTER_ID, } from "./adapters/openai-compatible.js";
|
|
6
|
+
export { createOpenAICompatibleAdapter, mergeRequestBody, OPENAI_COMPATIBLE_ADAPTER_ID, } from "./adapters/openai-compatible.js";
|
|
6
7
|
export { ANTHROPIC_ADAPTER_ID, createAnthropicAdapter } from "./adapters/anthropic.js";
|
|
8
|
+
export { createOpenAIAdapter, OPENAI_ADAPTER_ID } from "./adapters/openai.js";
|
|
9
|
+
export { createPiAiAdapter, listPiAiCatalog, PI_AI_ADAPTER_ID } from "./adapters/pi-ai.js";
|
|
7
10
|
import { createAnthropicAdapter, ANTHROPIC_ADAPTER_ID } from "./adapters/anthropic.js";
|
|
8
11
|
import { createMockAdapter, MOCK_ADAPTER_ID } from "./adapters/mock.js";
|
|
12
|
+
import { createOpenAIAdapter, OPENAI_ADAPTER_ID } from "./adapters/openai.js";
|
|
9
13
|
import { createOpenAICompatibleAdapter, OPENAI_COMPATIBLE_ADAPTER_ID, } from "./adapters/openai-compatible.js";
|
|
14
|
+
import { createPiAiAdapter, PI_AI_ADAPTER_ID } from "./adapters/pi-ai.js";
|
|
10
15
|
import { createProviderRegistry } from "./registry.js";
|
|
11
16
|
/**
|
|
12
17
|
* A provider registry pre-populated with the built-in adapters
|
|
13
|
-
* (`mock`, `openai-compatible`, `anthropic`). Callers can still
|
|
18
|
+
* (`mock`, `openai-compatible`, `anthropic`, `openai`, `pi-ai`). Callers can still
|
|
14
19
|
* `register()` additional adapter ids onto the returned registry.
|
|
15
20
|
*/
|
|
16
21
|
export function createDefaultProviderRegistry() {
|
|
@@ -18,5 +23,7 @@ export function createDefaultProviderRegistry() {
|
|
|
18
23
|
registry.register(MOCK_ADAPTER_ID, createMockAdapter);
|
|
19
24
|
registry.register(OPENAI_COMPATIBLE_ADAPTER_ID, createOpenAICompatibleAdapter);
|
|
20
25
|
registry.register(ANTHROPIC_ADAPTER_ID, createAnthropicAdapter);
|
|
26
|
+
registry.register(OPENAI_ADAPTER_ID, createOpenAIAdapter);
|
|
27
|
+
registry.register(PI_AI_ADAPTER_ID, createPiAiAdapter);
|
|
21
28
|
return registry;
|
|
22
29
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { TierBinding } from "./binding.js";
|
|
3
|
+
/**
|
|
4
|
+
* Where a tier's model runs. `private` is a deployment the operator trusts
|
|
5
|
+
* with project data (rows, SQL, the semantic context); `public` is anything
|
|
6
|
+
* else, typically a cloud API. A deployment fact declared on the binding —
|
|
7
|
+
* never derived from an endpoint host, a model id or an adapter kind.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ZONES: readonly ["private", "public"];
|
|
10
|
+
export type Zone = (typeof ZONES)[number];
|
|
11
|
+
export declare const zoneSchema: z.ZodEnum<{
|
|
12
|
+
private: "private";
|
|
13
|
+
public: "public";
|
|
14
|
+
}>;
|
|
15
|
+
/** The answer shapes a planner may declare for a slot and the policy may allow. */
|
|
16
|
+
export declare const ANSWER_SHAPES: readonly ["scalar", "series", "table", "narrative"];
|
|
17
|
+
export type AnswerShape = (typeof ANSWER_SHAPES)[number];
|
|
18
|
+
export declare const answerShapeSchema: z.ZodEnum<{
|
|
19
|
+
narrative: "narrative";
|
|
20
|
+
scalar: "scalar";
|
|
21
|
+
series: "series";
|
|
22
|
+
table: "table";
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* The egress disclosure policy: what a verified callee answer may look like
|
|
26
|
+
* before it is disclosed to a public-zone caller. `max_rows` is required and
|
|
27
|
+
* must be a positive integer — a policy that forgets it would otherwise
|
|
28
|
+
* silently allow any table through, which is the wrong default for a gate.
|
|
29
|
+
*/
|
|
30
|
+
export declare const disclosurePolicySchema: z.ZodObject<{
|
|
31
|
+
allowed_shapes: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
32
|
+
narrative: "narrative";
|
|
33
|
+
scalar: "scalar";
|
|
34
|
+
series: "series";
|
|
35
|
+
table: "table";
|
|
36
|
+
}>>>;
|
|
37
|
+
max_rows: z.ZodNumber;
|
|
38
|
+
min_group_size: z.ZodDefault<z.ZodNumber>;
|
|
39
|
+
sensitive_column_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
40
|
+
pii_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
41
|
+
judge_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
|
42
|
+
}, z.core.$strict>;
|
|
43
|
+
export type DisclosurePolicy = z.infer<typeof disclosurePolicySchema>;
|
|
44
|
+
/**
|
|
45
|
+
* Non-step tiers the zone gate must check by role. Each value is a binding
|
|
46
|
+
* key (a bare tier or `<mount>/<tier>`) that must resolve in `tiers`.
|
|
47
|
+
*/
|
|
48
|
+
export declare const zoneRolesSchema: z.ZodObject<{
|
|
49
|
+
judge: z.ZodOptional<z.ZodString>;
|
|
50
|
+
render: z.ZodOptional<z.ZodString>;
|
|
51
|
+
}, z.core.$strict>;
|
|
52
|
+
export type ZoneRoles = z.infer<typeof zoneRolesSchema>;
|
|
53
|
+
/**
|
|
54
|
+
* The on-disk tier binding document (`--tier-binding <file>`), the file
|
|
55
|
+
* counterpart of the `--tier-adapter` flags. Keys of `tiers` are bare tier
|
|
56
|
+
* names or `<mount>/<tier>`; `disclosure_policy` and `roles` are the hybrid
|
|
57
|
+
* split's additions. Credentials belong in the adapter's environment, not in
|
|
58
|
+
* this file, but nothing here forbids `config.apiKey` for a local dev setup.
|
|
59
|
+
*/
|
|
60
|
+
export declare const tierBindingDocumentSchema: z.ZodObject<{
|
|
61
|
+
tiers: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
62
|
+
adapter: z.ZodString;
|
|
63
|
+
config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
64
|
+
zone: z.ZodOptional<z.ZodEnum<{
|
|
65
|
+
private: "private";
|
|
66
|
+
public: "public";
|
|
67
|
+
}>>;
|
|
68
|
+
}, z.core.$strict>>;
|
|
69
|
+
disclosure_policy: z.ZodOptional<z.ZodObject<{
|
|
70
|
+
allowed_shapes: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
71
|
+
narrative: "narrative";
|
|
72
|
+
scalar: "scalar";
|
|
73
|
+
series: "series";
|
|
74
|
+
table: "table";
|
|
75
|
+
}>>>;
|
|
76
|
+
max_rows: z.ZodNumber;
|
|
77
|
+
min_group_size: z.ZodDefault<z.ZodNumber>;
|
|
78
|
+
sensitive_column_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
79
|
+
pii_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
80
|
+
judge_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
|
81
|
+
}, z.core.$strict>>;
|
|
82
|
+
roles: z.ZodOptional<z.ZodObject<{
|
|
83
|
+
judge: z.ZodOptional<z.ZodString>;
|
|
84
|
+
render: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, z.core.$strict>>;
|
|
86
|
+
}, z.core.$strict>;
|
|
87
|
+
export type TierBindingDocument = z.infer<typeof tierBindingDocumentSchema>;
|
|
88
|
+
export declare class TierBindingParseError extends Error {
|
|
89
|
+
constructor(message: string);
|
|
90
|
+
}
|
|
91
|
+
/** Parses a tier binding document into the runtime `TierBinding`, loud-failing on any schema violation. */
|
|
92
|
+
export declare function parseTierBindingDocument(value: unknown): TierBinding;
|
|
93
|
+
/** Parses a disclosure policy on its own (the shape the egress verification step consumes). */
|
|
94
|
+
export declare function parseDisclosurePolicy(value: unknown): DisclosurePolicy;
|
|
95
|
+
/** Reads and parses a JSON tier binding file. */
|
|
96
|
+
export declare function readTierBindingFile(filePath: string): Promise<TierBinding>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Where a tier's model runs. `private` is a deployment the operator trusts
|
|
5
|
+
* with project data (rows, SQL, the semantic context); `public` is anything
|
|
6
|
+
* else, typically a cloud API. A deployment fact declared on the binding —
|
|
7
|
+
* never derived from an endpoint host, a model id or an adapter kind.
|
|
8
|
+
*/
|
|
9
|
+
export const ZONES = ["private", "public"];
|
|
10
|
+
export const zoneSchema = z.enum(ZONES);
|
|
11
|
+
/** The answer shapes a planner may declare for a slot and the policy may allow. */
|
|
12
|
+
export const ANSWER_SHAPES = ["scalar", "series", "table", "narrative"];
|
|
13
|
+
export const answerShapeSchema = z.enum(ANSWER_SHAPES);
|
|
14
|
+
/**
|
|
15
|
+
* The egress disclosure policy: what a verified callee answer may look like
|
|
16
|
+
* before it is disclosed to a public-zone caller. `max_rows` is required and
|
|
17
|
+
* must be a positive integer — a policy that forgets it would otherwise
|
|
18
|
+
* silently allow any table through, which is the wrong default for a gate.
|
|
19
|
+
*/
|
|
20
|
+
export const disclosurePolicySchema = z.object({
|
|
21
|
+
allowed_shapes: z.array(answerShapeSchema).min(1).default([...ANSWER_SHAPES]),
|
|
22
|
+
max_rows: z.number().int().positive(),
|
|
23
|
+
min_group_size: z.number().int().nonnegative().default(1),
|
|
24
|
+
sensitive_column_patterns: z.array(z.string().min(1)).default([]),
|
|
25
|
+
/** Regexes matched against string cells; the built-in PII set applies as well. */
|
|
26
|
+
pii_patterns: z.array(z.string().min(1)).default([]),
|
|
27
|
+
/** Judge wall-clock budget; a judge that exceeds it refuses the slot. */
|
|
28
|
+
judge_timeout_ms: z.number().int().positive().default(30_000),
|
|
29
|
+
}).strict();
|
|
30
|
+
/**
|
|
31
|
+
* Non-step tiers the zone gate must check by role. Each value is a binding
|
|
32
|
+
* key (a bare tier or `<mount>/<tier>`) that must resolve in `tiers`.
|
|
33
|
+
*/
|
|
34
|
+
export const zoneRolesSchema = z.object({
|
|
35
|
+
judge: z.string().min(1).optional(),
|
|
36
|
+
render: z.string().min(1).optional(),
|
|
37
|
+
}).strict();
|
|
38
|
+
const adapterSpecSchema = z.object({
|
|
39
|
+
adapter: z.string().min(1),
|
|
40
|
+
config: z.record(z.string(), z.unknown()).default({}),
|
|
41
|
+
zone: zoneSchema.optional(),
|
|
42
|
+
}).strict();
|
|
43
|
+
/**
|
|
44
|
+
* The on-disk tier binding document (`--tier-binding <file>`), the file
|
|
45
|
+
* counterpart of the `--tier-adapter` flags. Keys of `tiers` are bare tier
|
|
46
|
+
* names or `<mount>/<tier>`; `disclosure_policy` and `roles` are the hybrid
|
|
47
|
+
* split's additions. Credentials belong in the adapter's environment, not in
|
|
48
|
+
* this file, but nothing here forbids `config.apiKey` for a local dev setup.
|
|
49
|
+
*/
|
|
50
|
+
export const tierBindingDocumentSchema = z.object({
|
|
51
|
+
tiers: z.record(z.string().min(1), adapterSpecSchema),
|
|
52
|
+
disclosure_policy: disclosurePolicySchema.optional(),
|
|
53
|
+
roles: zoneRolesSchema.optional(),
|
|
54
|
+
}).strict();
|
|
55
|
+
export class TierBindingParseError extends Error {
|
|
56
|
+
constructor(message) {
|
|
57
|
+
super(message);
|
|
58
|
+
this.name = "TierBindingParseError";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function describeIssues(error) {
|
|
62
|
+
return error.issues.map((issue) => `${issue.path.map(String).join(".") || "<root>"}: ${issue.message}`).join("; ");
|
|
63
|
+
}
|
|
64
|
+
/** Parses a tier binding document into the runtime `TierBinding`, loud-failing on any schema violation. */
|
|
65
|
+
export function parseTierBindingDocument(value) {
|
|
66
|
+
const parsed = tierBindingDocumentSchema.safeParse(value);
|
|
67
|
+
if (!parsed.success)
|
|
68
|
+
throw new TierBindingParseError(`tier binding is invalid — ${describeIssues(parsed.error)}`);
|
|
69
|
+
const tiers = {};
|
|
70
|
+
for (const [key, spec] of Object.entries(parsed.data.tiers)) {
|
|
71
|
+
if (key.startsWith("/") || key.endsWith("/") || key.split("/").length > 2) {
|
|
72
|
+
throw new TierBindingParseError(`tier binding key "${key}" must be "<tier>" or "<mount>/<tier>"`);
|
|
73
|
+
}
|
|
74
|
+
tiers[key] = { adapter: spec.adapter, config: spec.config, ...(spec.zone !== undefined ? { zone: spec.zone } : {}) };
|
|
75
|
+
}
|
|
76
|
+
const binding = {
|
|
77
|
+
tiers,
|
|
78
|
+
...(parsed.data.disclosure_policy !== undefined ? { disclosurePolicy: parsed.data.disclosure_policy } : {}),
|
|
79
|
+
...(parsed.data.roles !== undefined ? { roles: parsed.data.roles } : {}),
|
|
80
|
+
};
|
|
81
|
+
for (const [role, key] of Object.entries(binding.roles ?? {})) {
|
|
82
|
+
if (key !== undefined && binding.tiers[key] === undefined) {
|
|
83
|
+
throw new TierBindingParseError(`roles.${role} names tier "${key}", which is not in tiers`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return binding;
|
|
87
|
+
}
|
|
88
|
+
/** Parses a disclosure policy on its own (the shape the egress verification step consumes). */
|
|
89
|
+
export function parseDisclosurePolicy(value) {
|
|
90
|
+
const parsed = disclosurePolicySchema.safeParse(value);
|
|
91
|
+
if (!parsed.success)
|
|
92
|
+
throw new TierBindingParseError(`disclosure_policy is invalid — ${describeIssues(parsed.error)}`);
|
|
93
|
+
return parsed.data;
|
|
94
|
+
}
|
|
95
|
+
/** Reads and parses a JSON tier binding file. */
|
|
96
|
+
export async function readTierBindingFile(filePath) {
|
|
97
|
+
let text;
|
|
98
|
+
try {
|
|
99
|
+
text = await readFile(filePath, "utf8");
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
throw new TierBindingParseError(`cannot read tier binding file "${filePath}": ${error instanceof Error ? error.message : String(error)}`);
|
|
103
|
+
}
|
|
104
|
+
let value;
|
|
105
|
+
try {
|
|
106
|
+
value = JSON.parse(text);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
throw new TierBindingParseError(`tier binding file "${filePath}" is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
|
+
}
|
|
111
|
+
return parseTierBindingDocument(value);
|
|
112
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which executed query answers the question. A step may run several successful
|
|
3
|
+
* queries (an exploratory count, then the real one, then a stray check), so
|
|
4
|
+
* "the last successful table" is not a safe choice: a chatty model produces a
|
|
5
|
+
* grounded but wrong answer. The model names the query it answered with in the
|
|
6
|
+
* terminal value's `definition`: by the `query_id` the host attached to the
|
|
7
|
+
* tool result, or by the exact SQL it ran; the host then selects that observed
|
|
8
|
+
* table, and never the model's own copy of the rows.
|
|
9
|
+
*/
|
|
10
|
+
/** Whitespace- and terminator-insensitive identity for one SQL text. */
|
|
11
|
+
export declare function sqlKey(sql: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* The host-assigned query id (`q<N>`) a terminal value cites as its answer, if any. An id is
|
|
14
|
+
* preferred over SQL: the model names the executed query instead of re-typing it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function namedAnswerQueryId(value: unknown): string | undefined;
|
|
17
|
+
/** The SQL a terminal value names as its answer, if it names exactly one. */
|
|
18
|
+
export declare function namedAnswerSql(value: unknown): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Picks the answering entry among candidates that each carry the SQL they ran.
|
|
21
|
+
* Named and observed: the last observation of that SQL. Named but never run:
|
|
22
|
+
* `undefined`, so the caller refuses rather than substitute another table.
|
|
23
|
+
* Unnamed: the last candidate, the historical rule, kept only for values that
|
|
24
|
+
* do not name a query at all.
|
|
25
|
+
*/
|
|
26
|
+
export declare function selectAnsweringCandidate<T extends {
|
|
27
|
+
readonly sql?: string | undefined;
|
|
28
|
+
readonly queryId?: string | undefined;
|
|
29
|
+
}>(candidates: readonly T[], terminalValue: unknown): T | undefined;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which executed query answers the question. A step may run several successful
|
|
3
|
+
* queries (an exploratory count, then the real one, then a stray check), so
|
|
4
|
+
* "the last successful table" is not a safe choice: a chatty model produces a
|
|
5
|
+
* grounded but wrong answer. The model names the query it answered with in the
|
|
6
|
+
* terminal value's `definition`: by the `query_id` the host attached to the
|
|
7
|
+
* tool result, or by the exact SQL it ran; the host then selects that observed
|
|
8
|
+
* table, and never the model's own copy of the rows.
|
|
9
|
+
*/
|
|
10
|
+
/** Whitespace- and terminator-insensitive identity for one SQL text. */
|
|
11
|
+
export function sqlKey(sql) {
|
|
12
|
+
return sql.replace(/\s+/g, " ").replace(/;\s*$/, "").trim();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The host-assigned query id (`q<N>`) a terminal value cites as its answer, if any. An id is
|
|
16
|
+
* preferred over SQL: the model names the executed query instead of re-typing it.
|
|
17
|
+
*/
|
|
18
|
+
export function namedAnswerQueryId(value) {
|
|
19
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
20
|
+
return undefined;
|
|
21
|
+
const record = value;
|
|
22
|
+
const definition = record.definition;
|
|
23
|
+
if (typeof definition === "object" && definition !== null && !Array.isArray(definition)) {
|
|
24
|
+
const id = definition.query_id;
|
|
25
|
+
if (typeof id === "string" && id.length > 0)
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
28
|
+
return typeof record.query_id === "string" && record.query_id.length > 0 ? record.query_id : undefined;
|
|
29
|
+
}
|
|
30
|
+
/** The SQL a terminal value names as its answer, if it names exactly one. */
|
|
31
|
+
export function namedAnswerSql(value) {
|
|
32
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
33
|
+
return undefined;
|
|
34
|
+
const record = value;
|
|
35
|
+
const definition = record.definition;
|
|
36
|
+
if (typeof definition === "object" && definition !== null && !Array.isArray(definition)) {
|
|
37
|
+
const sql = definition.sql;
|
|
38
|
+
if (typeof sql === "string" && sql.trim())
|
|
39
|
+
return sql;
|
|
40
|
+
}
|
|
41
|
+
return typeof record.sql === "string" && record.sql.trim() ? record.sql : undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Picks the answering entry among candidates that each carry the SQL they ran.
|
|
45
|
+
* Named and observed: the last observation of that SQL. Named but never run:
|
|
46
|
+
* `undefined`, so the caller refuses rather than substitute another table.
|
|
47
|
+
* Unnamed: the last candidate, the historical rule, kept only for values that
|
|
48
|
+
* do not name a query at all.
|
|
49
|
+
*/
|
|
50
|
+
export function selectAnsweringCandidate(candidates, terminalValue) {
|
|
51
|
+
// Cited by id among candidates that carry host ids: that candidate or none, never a fallback
|
|
52
|
+
// to the SQL text or the last table. Candidates with no ids at all (the session loop's seeds)
|
|
53
|
+
// cannot resolve an id, so the citation falls through to the SQL and last-table rules.
|
|
54
|
+
const id = namedAnswerQueryId(terminalValue);
|
|
55
|
+
if (id !== undefined && candidates.some((candidate) => candidate.queryId !== undefined))
|
|
56
|
+
return candidates.find((candidate) => candidate.queryId === id);
|
|
57
|
+
const named = namedAnswerSql(terminalValue);
|
|
58
|
+
if (named === undefined)
|
|
59
|
+
return candidates.at(-1);
|
|
60
|
+
const key = sqlKey(named);
|
|
61
|
+
return [...candidates].reverse().find((candidate) => candidate.sql !== undefined && sqlKey(candidate.sql) === key);
|
|
62
|
+
}
|
|
@@ -143,3 +143,9 @@ export declare function isTableOnlySchema(outputSchema: Record<string, unknown>)
|
|
|
143
143
|
* `form: "text"` instead of fabricating an envelope.
|
|
144
144
|
*/
|
|
145
145
|
export declare function extractEnvelopeFromText(text: string): RenderEnvelope | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* The raw JSON object a model's final text carries (fence- and prose-tolerant, see
|
|
148
|
+
* `extractJsonObjectText`), before any envelope normalization, else `undefined`. Fields the
|
|
149
|
+
* normalization drops, such as a cited `query_id`, are still present here.
|
|
150
|
+
*/
|
|
151
|
+
export declare function extractJsonCandidateFromText(text: string): unknown;
|
|
@@ -351,14 +351,21 @@ function extractJsonObjectText(text) {
|
|
|
351
351
|
* `form: "text"` instead of fabricating an envelope.
|
|
352
352
|
*/
|
|
353
353
|
export function extractEnvelopeFromText(text) {
|
|
354
|
-
|
|
354
|
+
const candidate = extractJsonCandidateFromText(text);
|
|
355
|
+
return candidate === undefined ? undefined : normalizeExtractedCandidate(candidate);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* The raw JSON object a model's final text carries (fence- and prose-tolerant, see
|
|
359
|
+
* `extractJsonObjectText`), before any envelope normalization, else `undefined`. Fields the
|
|
360
|
+
* normalization drops, such as a cited `query_id`, are still present here.
|
|
361
|
+
*/
|
|
362
|
+
export function extractJsonCandidateFromText(text) {
|
|
355
363
|
try {
|
|
356
|
-
|
|
364
|
+
return JSON.parse(extractJsonObjectText(text));
|
|
357
365
|
}
|
|
358
366
|
catch {
|
|
359
367
|
return undefined;
|
|
360
368
|
}
|
|
361
|
-
return normalizeExtractedCandidate(candidate);
|
|
362
369
|
}
|
|
363
370
|
/** Bounded: at most one MCP `CallToolResult` unwrap, so a pathological/self-referential payload can't recurse forever. */
|
|
364
371
|
const MAX_UNWRAP_DEPTH = 2;
|
|
@@ -25,15 +25,14 @@ export interface DeriveAdapterSpecOptions {
|
|
|
25
25
|
* exactly what that adapter targets. `endpoint` becomes `baseURL`; `model`
|
|
26
26
|
* comes from `options.model` (falling back to `DEFAULT_LOCAL_MODEL`) since
|
|
27
27
|
* `LocalAuthChoice` itself carries no model field.
|
|
28
|
-
* - `gateway` —
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* bare "Invalid URL" deep inside the adapter.
|
|
28
|
+
* - `gateway` — mapped onto the `pi-ai` adapter, pi-ai's unified client for
|
|
29
|
+
* an operator-chosen provider (a built-in pi-ai provider id such as
|
|
30
|
+
* `openrouter` or `amazon-bedrock`, or a custom OpenAI-compatible endpoint
|
|
31
|
+
* when `baseUrl` is set). `authChoice.config` must carry `provider` and
|
|
32
|
+
* `model`, and may carry `apiKey`, `baseUrl` and `headers`
|
|
33
|
+
* (`PiAiAdapterConfig`). `gateway` has no sensible default, so a
|
|
34
|
+
* missing/empty `provider`/`model` is a loud `wren-harness`-level error here
|
|
35
|
+
* rather than a failure deep inside the adapter on the first call.
|
|
37
36
|
*/
|
|
38
37
|
export declare function deriveAdapterSpec(authChoice: Extract<AuthChoice, {
|
|
39
38
|
mode: "api-key" | "local" | "gateway";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OPENAI_COMPATIBLE_ADAPTER_ID } from "../providers/index.js";
|
|
1
|
+
import { OPENAI_COMPATIBLE_ADAPTER_ID, PI_AI_ADAPTER_ID } from "../providers/index.js";
|
|
2
2
|
/** Default local endpoint used when a `LocalAuthChoice` omits `endpoint` (Ollama's default OpenAI-compatible port). */
|
|
3
3
|
export const DEFAULT_LOCAL_ENDPOINT = "http://localhost:11434/v1";
|
|
4
4
|
/**
|
|
@@ -20,15 +20,14 @@ export const DEFAULT_LOCAL_MODEL = "llama3.1";
|
|
|
20
20
|
* exactly what that adapter targets. `endpoint` becomes `baseURL`; `model`
|
|
21
21
|
* comes from `options.model` (falling back to `DEFAULT_LOCAL_MODEL`) since
|
|
22
22
|
* `LocalAuthChoice` itself carries no model field.
|
|
23
|
-
* - `gateway` —
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* bare "Invalid URL" deep inside the adapter.
|
|
23
|
+
* - `gateway` — mapped onto the `pi-ai` adapter, pi-ai's unified client for
|
|
24
|
+
* an operator-chosen provider (a built-in pi-ai provider id such as
|
|
25
|
+
* `openrouter` or `amazon-bedrock`, or a custom OpenAI-compatible endpoint
|
|
26
|
+
* when `baseUrl` is set). `authChoice.config` must carry `provider` and
|
|
27
|
+
* `model`, and may carry `apiKey`, `baseUrl` and `headers`
|
|
28
|
+
* (`PiAiAdapterConfig`). `gateway` has no sensible default, so a
|
|
29
|
+
* missing/empty `provider`/`model` is a loud `wren-harness`-level error here
|
|
30
|
+
* rather than a failure deep inside the adapter on the first call.
|
|
32
31
|
*/
|
|
33
32
|
export function deriveAdapterSpec(authChoice, options = {}) {
|
|
34
33
|
switch (authChoice.mode) {
|
|
@@ -45,14 +44,14 @@ export function deriveAdapterSpec(authChoice, options = {}) {
|
|
|
45
44
|
case "gateway": {
|
|
46
45
|
const config = authChoice.config ?? {};
|
|
47
46
|
const missing = [];
|
|
48
|
-
if (!isNonEmptyString(config["
|
|
49
|
-
missing.push("
|
|
47
|
+
if (!isNonEmptyString(config["provider"]))
|
|
48
|
+
missing.push("provider");
|
|
50
49
|
if (!isNonEmptyString(config["model"]))
|
|
51
50
|
missing.push("model");
|
|
52
51
|
if (missing.length > 0) {
|
|
53
|
-
throw new Error(`gateway mode requires ${missing.join(" and ")}
|
|
52
|
+
throw new Error(`gateway mode requires provider and model in config, missing ${missing.join(" and ")} (pass --provider and --model)`);
|
|
54
53
|
}
|
|
55
|
-
return { adapter:
|
|
54
|
+
return { adapter: PI_AI_ADAPTER_ID, config };
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const COMPONENT_STEPS = {
|
|
2
2
|
answer_query: [
|
|
3
|
-
{ name: "resolve_intent", tier: "cheap", tool:
|
|
3
|
+
{ name: "resolve_intent", tier: "cheap", tool: null },
|
|
4
4
|
{ name: "generate_sql", tier: "strong", tool: "run_sql" },
|
|
5
5
|
{ name: "repair_sql", tier: "strong", tool: "run_sql" },
|
|
6
6
|
],
|
|
@@ -115,6 +115,7 @@ export class CodexAskEventMapper {
|
|
|
115
115
|
reference.agentRole !== expectedRole(step.name) ||
|
|
116
116
|
reference.server !== "wren" ||
|
|
117
117
|
!reference.itemId ||
|
|
118
|
+
step.tool === null ||
|
|
118
119
|
reference.tool !== step.tool) {
|
|
119
120
|
throw new Error("warble-codex-local Ask artifact attribution did not match the allowed Wren MCP surface");
|
|
120
121
|
}
|
|
@@ -8,6 +8,10 @@ export declare function buildCodexAskArgs(cli: ResolvedCli, options: {
|
|
|
8
8
|
readonly codexHome: string;
|
|
9
9
|
readonly models: CodexManifestModels;
|
|
10
10
|
readonly mcpServer: ResolvedCli;
|
|
11
|
+
/** The genbi stdio proxy Codex starts as its `wren` MCP server (see `codex-wren-proxy.ts`). */
|
|
12
|
+
readonly proxy: ResolvedCli;
|
|
13
|
+
/** This turn's host query credential file; the proxy reads it, its path carries no secret. */
|
|
14
|
+
readonly credentialFile: string;
|
|
11
15
|
readonly codexBin?: string;
|
|
12
16
|
readonly timeoutMs: number;
|
|
13
17
|
readonly component?: CodexAskComponent;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { accessSync, constants as fsConstants } from "node:fs";
|
|
2
|
+
import { accessSync, existsSync, constants as fsConstants } from "node:fs";
|
|
3
3
|
import { createInterface } from "node:readline";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { hashDirectory } from "../compile/fingerprint.js";
|
|
7
|
+
import { openWrenComponentAccess } from "../components/wren-access.js";
|
|
5
8
|
import { enforceCompliance } from "../compliance/index.js";
|
|
6
9
|
import { compileProfile } from "../compile/pipeline.js";
|
|
7
10
|
import { createAgentEventEmitter } from "../events/index.js";
|
|
8
11
|
import { CodexAskEventMapper } from "./codex-ask-events.js";
|
|
12
|
+
import { openCodexHostQueryService } from "./codex-host-query.js";
|
|
9
13
|
import { resolveCodexLocalCli } from "./codex-local-cli.js";
|
|
10
|
-
import { CODEX_ASK_COMPONENTS, } from "./codex-local-manifest.js";
|
|
14
|
+
import { CODEX_ASK_COMPONENTS, codexAnalysisToolArgs, } from "./codex-local-manifest.js";
|
|
11
15
|
const CODEX_BILLING_ENV_KEYS = new Set([
|
|
12
16
|
"OPENAI_API_KEY",
|
|
13
17
|
"CODEX_API_KEY",
|
|
@@ -21,6 +25,19 @@ const DEFAULT_CODEX_ASK_TIMEOUT_MS = 10 * 60 * 1000;
|
|
|
21
25
|
export function buildCodexAskArgs(cli, options) {
|
|
22
26
|
if (!options.question.trim())
|
|
23
27
|
throw new Error("Codex Ask question must not be empty");
|
|
28
|
+
const serverArgs = [
|
|
29
|
+
...options.proxy.prefixArgs,
|
|
30
|
+
"--credential-file",
|
|
31
|
+
options.credentialFile,
|
|
32
|
+
"--",
|
|
33
|
+
options.mcpServer.command,
|
|
34
|
+
...options.mcpServer.prefixArgs,
|
|
35
|
+
"serve",
|
|
36
|
+
"mcp",
|
|
37
|
+
"--project",
|
|
38
|
+
options.userProject,
|
|
39
|
+
"--quiet",
|
|
40
|
+
];
|
|
24
41
|
return [
|
|
25
42
|
...cli.prefixArgs,
|
|
26
43
|
"dispatch",
|
|
@@ -41,20 +58,9 @@ export function buildCodexAskArgs(cli, options) {
|
|
|
41
58
|
"--server",
|
|
42
59
|
"wren",
|
|
43
60
|
"--server-command",
|
|
44
|
-
options.
|
|
45
|
-
...
|
|
46
|
-
"
|
|
47
|
-
"serve",
|
|
48
|
-
"--server-arg",
|
|
49
|
-
"mcp",
|
|
50
|
-
"--server-arg=--project",
|
|
51
|
-
"--server-arg",
|
|
52
|
-
options.userProject,
|
|
53
|
-
"--server-arg=--quiet",
|
|
54
|
-
"--inspect-tool",
|
|
55
|
-
"get_context",
|
|
56
|
-
"--query-tool",
|
|
57
|
-
"run_sql",
|
|
61
|
+
options.proxy.command,
|
|
62
|
+
...serverArgs.flatMap((arg) => arg.startsWith("-") ? [`--server-arg=${arg}`] : ["--server-arg", arg]),
|
|
63
|
+
...codexAnalysisToolArgs(options.component ?? "answer_query"),
|
|
58
64
|
"--timeout",
|
|
59
65
|
String(options.timeoutMs),
|
|
60
66
|
...(options.codexBin ? ["--codex-bin", options.codexBin] : []),
|
|
@@ -97,21 +103,42 @@ export async function runCodexAskDefault(options) {
|
|
|
97
103
|
if (options.signal?.aborted)
|
|
98
104
|
throw new Error("warble-codex-local Ask was cancelled during preparation");
|
|
99
105
|
const timeoutMs = options.timeoutMs ?? DEFAULT_CODEX_ASK_TIMEOUT_MS;
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
const userProject = options.userProject;
|
|
107
|
+
// This turn's host query service: the only place codex:local's run_sql executes and the
|
|
108
|
+
// only evidence its answer can be grounded on. Closed (and its observations discarded)
|
|
109
|
+
// when the turn ends, whatever the outcome.
|
|
110
|
+
const hostQueries = await openCodexHostQueryService({
|
|
111
|
+
openAccess: async (signal) => openWrenComponentAccess({
|
|
112
|
+
executable: singleExecutable(mcpServer),
|
|
113
|
+
project: userProject,
|
|
114
|
+
fingerprint: await hashDirectory(userProject),
|
|
115
|
+
signal,
|
|
116
|
+
}),
|
|
117
|
+
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
110
118
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
119
|
+
try {
|
|
120
|
+
const args = buildCodexAskArgs(cli, {
|
|
121
|
+
irPath,
|
|
122
|
+
question: options.question,
|
|
123
|
+
userProject,
|
|
124
|
+
codexHome,
|
|
125
|
+
models,
|
|
126
|
+
mcpServer,
|
|
127
|
+
proxy: defaultWrenProxy(),
|
|
128
|
+
credentialFile: hostQueries.credentialFile,
|
|
129
|
+
timeoutMs,
|
|
130
|
+
component,
|
|
131
|
+
...(options.codexBin !== undefined ? { codexBin: options.codexBin } : {}),
|
|
132
|
+
});
|
|
133
|
+
const mapper = new CodexAskEventMapper(models, component);
|
|
134
|
+
const finalText = await spawnCodexAsk(cli.command, args, mapper, emitter.emit, options.processTimeoutMs ?? timeoutMs + 5_000, options.signal);
|
|
135
|
+
const hostObservations = hostQueries.observations();
|
|
136
|
+
emitter.emit({ kind: "run.finish", status: "answer" });
|
|
137
|
+
return { finalText, hostObservations };
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
await hostQueries.close();
|
|
141
|
+
}
|
|
115
142
|
}
|
|
116
143
|
catch (error) {
|
|
117
144
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -127,6 +154,18 @@ function resolveModels(value) {
|
|
|
127
154
|
}
|
|
128
155
|
return models;
|
|
129
156
|
}
|
|
157
|
+
/** Governed access spawns one executable with fixed arguments; a prefixed command cannot be bound. */
|
|
158
|
+
function singleExecutable(cli) {
|
|
159
|
+
if (cli.prefixArgs.length > 0)
|
|
160
|
+
throw new Error("codex:local host queries need a standalone wren executable");
|
|
161
|
+
return cli.command;
|
|
162
|
+
}
|
|
163
|
+
/** The built proxy next to this module, else its source (Node strips its erasable types). */
|
|
164
|
+
function defaultWrenProxy() {
|
|
165
|
+
const built = fileURLToPath(new URL("./codex-wren-proxy.js", import.meta.url));
|
|
166
|
+
const script = existsSync(built) ? built : fileURLToPath(new URL("./codex-wren-proxy.ts", import.meta.url));
|
|
167
|
+
return { command: process.execPath, prefixArgs: [script] };
|
|
168
|
+
}
|
|
130
169
|
function resolveExecutableOnPath(name) {
|
|
131
170
|
for (const directory of (process.env.PATH ?? "").split(path.delimiter)) {
|
|
132
171
|
if (!directory)
|