@wrenai/genbi 0.0.1
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/LICENSE +201 -0
- package/README.md +141 -0
- package/bin/genbi.mjs +31 -0
- package/dist/assets/echarts-LTFC-ysd.js +40 -0
- package/dist/assets/index-Bo--QMUN.js +441 -0
- package/dist/assets/index-Xs4q7pNo.css +1 -0
- package/dist/index.html +14 -0
- package/dist/wrenai_logo.png +0 -0
- package/dist/wrenai_logo_white.png +0 -0
- package/dist-server/harness/auth/detect.d.ts +18 -0
- package/dist-server/harness/auth/detect.js +37 -0
- package/dist-server/harness/auth/index.d.ts +4 -0
- package/dist-server/harness/auth/index.js +2 -0
- package/dist-server/harness/auth/probe.d.ts +18 -0
- package/dist-server/harness/auth/probe.js +52 -0
- package/dist-server/harness/auth/types.d.ts +42 -0
- package/dist-server/harness/auth/types.js +9 -0
- package/dist-server/harness/bundle/loader.d.ts +32 -0
- package/dist-server/harness/bundle/loader.js +43 -0
- package/dist-server/harness/bundle/schema.d.ts +199 -0
- package/dist-server/harness/bundle/schema.js +127 -0
- package/dist-server/harness/bundle/version.d.ts +10 -0
- package/dist-server/harness/bundle/version.js +43 -0
- package/dist-server/harness/capability/gate.d.ts +6 -0
- package/dist-server/harness/capability/gate.js +29 -0
- package/dist-server/harness/capability/registry.d.ts +6 -0
- package/dist-server/harness/capability/registry.js +17 -0
- package/dist-server/harness/cli-args.d.ts +123 -0
- package/dist-server/harness/cli-args.js +247 -0
- package/dist-server/harness/cli.d.ts +2 -0
- package/dist-server/harness/cli.js +151 -0
- package/dist-server/harness/compile/cache.d.ts +23 -0
- package/dist-server/harness/compile/cache.js +109 -0
- package/dist-server/harness/compile/compose-profile.d.ts +34 -0
- package/dist-server/harness/compile/compose-profile.js +95 -0
- package/dist-server/harness/compile/errors.d.ts +22 -0
- package/dist-server/harness/compile/errors.js +41 -0
- package/dist-server/harness/compile/fingerprint.d.ts +22 -0
- package/dist-server/harness/compile/fingerprint.js +84 -0
- package/dist-server/harness/compile/index.d.ts +8 -0
- package/dist-server/harness/compile/index.js +7 -0
- package/dist-server/harness/compile/pipeline.d.ts +66 -0
- package/dist-server/harness/compile/pipeline.js +176 -0
- package/dist-server/harness/compile/resolve-binary.d.ts +55 -0
- package/dist-server/harness/compile/resolve-binary.js +133 -0
- package/dist-server/harness/compile/types.d.ts +107 -0
- package/dist-server/harness/compile/types.js +1 -0
- package/dist-server/harness/compile/warble-identity.d.ts +12 -0
- package/dist-server/harness/compile/warble-identity.js +33 -0
- package/dist-server/harness/compliance/gate.d.ts +35 -0
- package/dist-server/harness/compliance/gate.js +48 -0
- package/dist-server/harness/compliance/index.d.ts +2 -0
- package/dist-server/harness/compliance/index.js +1 -0
- package/dist-server/harness/compliance/types.d.ts +16 -0
- package/dist-server/harness/compliance/types.js +1 -0
- package/dist-server/harness/events/emitter.d.ts +34 -0
- package/dist-server/harness/events/emitter.js +25 -0
- package/dist-server/harness/events/index.d.ts +4 -0
- package/dist-server/harness/events/index.js +2 -0
- package/dist-server/harness/events/sse.d.ts +20 -0
- package/dist-server/harness/events/sse.js +48 -0
- package/dist-server/harness/events/types.d.ts +131 -0
- package/dist-server/harness/events/types.js +1 -0
- package/dist-server/harness/exec/errors.d.ts +16 -0
- package/dist-server/harness/exec/errors.js +29 -0
- package/dist-server/harness/exec/index.d.ts +5 -0
- package/dist-server/harness/exec/index.js +2 -0
- package/dist-server/harness/exec/local.d.ts +32 -0
- package/dist-server/harness/exec/local.js +134 -0
- package/dist-server/harness/exec/policy.d.ts +12 -0
- package/dist-server/harness/exec/policy.js +1 -0
- package/dist-server/harness/exec/types.d.ts +63 -0
- package/dist-server/harness/exec/types.js +1 -0
- package/dist-server/harness/guardrails/index.d.ts +2 -0
- package/dist-server/harness/guardrails/index.js +1 -0
- package/dist-server/harness/guardrails/policy.d.ts +45 -0
- package/dist-server/harness/guardrails/policy.js +57 -0
- package/dist-server/harness/index.d.ts +37 -0
- package/dist-server/harness/index.js +19 -0
- package/dist-server/harness/loop/errors.d.ts +53 -0
- package/dist-server/harness/loop/errors.js +72 -0
- package/dist-server/harness/loop/executor.d.ts +123 -0
- package/dist-server/harness/loop/executor.js +380 -0
- package/dist-server/harness/loop/guard.d.ts +16 -0
- package/dist-server/harness/loop/guard.js +1 -0
- package/dist-server/harness/loop/index.d.ts +5 -0
- package/dist-server/harness/loop/index.js +3 -0
- package/dist-server/harness/native-producer/index.d.ts +109 -0
- package/dist-server/harness/native-producer/index.js +302 -0
- package/dist-server/harness/npm-package-resolve.d.ts +28 -0
- package/dist-server/harness/npm-package-resolve.js +47 -0
- package/dist-server/harness/providers/adapters/anthropic.d.ts +7 -0
- package/dist-server/harness/providers/adapters/anthropic.js +6 -0
- package/dist-server/harness/providers/adapters/mock.d.ts +4 -0
- package/dist-server/harness/providers/adapters/mock.js +5 -0
- package/dist-server/harness/providers/adapters/openai-compatible.d.ts +10 -0
- package/dist-server/harness/providers/adapters/openai-compatible.js +10 -0
- package/dist-server/harness/providers/binding.d.ts +23 -0
- package/dist-server/harness/providers/binding.js +13 -0
- package/dist-server/harness/providers/errors.d.ts +6 -0
- package/dist-server/harness/providers/errors.js +12 -0
- package/dist-server/harness/providers/index.d.ts +18 -0
- package/dist-server/harness/providers/index.js +22 -0
- package/dist-server/harness/providers/registry.d.ts +16 -0
- package/dist-server/harness/providers/registry.js +24 -0
- package/dist-server/harness/render/envelope.d.ts +145 -0
- package/dist-server/harness/render/envelope.js +428 -0
- package/dist-server/harness/render/errors.d.ts +33 -0
- package/dist-server/harness/render/errors.js +46 -0
- package/dist-server/harness/render/index.d.ts +5 -0
- package/dist-server/harness/render/index.js +3 -0
- package/dist-server/harness/render/validate.d.ts +13 -0
- package/dist-server/harness/render/validate.js +88 -0
- package/dist-server/harness/route/adapter-spec.d.ts +40 -0
- package/dist-server/harness/route/adapter-spec.js +61 -0
- package/dist-server/harness/route/agent-sdk-cli.d.ts +30 -0
- package/dist-server/harness/route/agent-sdk-cli.js +86 -0
- package/dist-server/harness/route/agent-sdk-manifest.d.ts +31 -0
- package/dist-server/harness/route/agent-sdk-manifest.js +56 -0
- package/dist-server/harness/route/artifact-content.d.ts +53 -0
- package/dist-server/harness/route/artifact-content.js +83 -0
- package/dist-server/harness/route/chat-event-mapper.d.ts +95 -0
- package/dist-server/harness/route/chat-event-mapper.js +164 -0
- package/dist-server/harness/route/codex-ask-events.d.ts +25 -0
- package/dist-server/harness/route/codex-ask-events.js +395 -0
- package/dist-server/harness/route/codex-ask.d.ts +15 -0
- package/dist-server/harness/route/codex-ask.js +242 -0
- package/dist-server/harness/route/codex-local-cli.d.ts +20 -0
- package/dist-server/harness/route/codex-local-cli.js +78 -0
- package/dist-server/harness/route/codex-local-manifest.d.ts +22 -0
- package/dist-server/harness/route/codex-local-manifest.js +180 -0
- package/dist-server/harness/route/describe.d.ts +54 -0
- package/dist-server/harness/route/describe.js +84 -0
- package/dist-server/harness/route/dispatched.d.ts +138 -0
- package/dist-server/harness/route/dispatched.js +339 -0
- package/dist-server/harness/route/in-process.d.ts +43 -0
- package/dist-server/harness/route/in-process.js +106 -0
- package/dist-server/harness/route/index.d.ts +19 -0
- package/dist-server/harness/route/index.js +12 -0
- package/dist-server/harness/route/profile-source.d.ts +37 -0
- package/dist-server/harness/route/profile-source.js +76 -0
- package/dist-server/harness/route/route.d.ts +33 -0
- package/dist-server/harness/route/route.js +114 -0
- package/dist-server/harness/route/tier-binding.d.ts +36 -0
- package/dist-server/harness/route/tier-binding.js +63 -0
- package/dist-server/harness/route/types.d.ts +286 -0
- package/dist-server/harness/route/types.js +1 -0
- package/dist-server/harness/session/errors.d.ts +4 -0
- package/dist-server/harness/session/errors.js +7 -0
- package/dist-server/harness/session/gate.d.ts +11 -0
- package/dist-server/harness/session/gate.js +13 -0
- package/dist-server/harness/session/index.d.ts +5 -0
- package/dist-server/harness/session/index.js +3 -0
- package/dist-server/harness/session/run.d.ts +60 -0
- package/dist-server/harness/session/run.js +333 -0
- package/dist-server/harness/session/types.d.ts +29 -0
- package/dist-server/harness/session/types.js +1 -0
- package/dist-server/harness/setup/codex-events.d.ts +12 -0
- package/dist-server/harness/setup/codex-events.js +108 -0
- package/dist-server/harness/setup/runner.d.ts +497 -0
- package/dist-server/harness/setup/runner.js +1314 -0
- package/dist-server/harness/tools/errors.d.ts +107 -0
- package/dist-server/harness/tools/errors.js +141 -0
- package/dist-server/harness/tools/index.d.ts +13 -0
- package/dist-server/harness/tools/index.js +8 -0
- package/dist-server/harness/tools/mcp.d.ts +26 -0
- package/dist-server/harness/tools/mcp.js +15 -0
- package/dist-server/harness/tools/native.d.ts +179 -0
- package/dist-server/harness/tools/native.js +322 -0
- package/dist-server/harness/tools/parse.d.ts +14 -0
- package/dist-server/harness/tools/parse.js +18 -0
- package/dist-server/harness/tools/resolve-wren-binary.d.ts +12 -0
- package/dist-server/harness/tools/resolve-wren-binary.js +21 -0
- package/dist-server/harness/tools/resolve.d.ts +51 -0
- package/dist-server/harness/tools/resolve.js +79 -0
- package/dist-server/harness/tools/setup-native.d.ts +84 -0
- package/dist-server/harness/tools/setup-native.js +353 -0
- package/dist-server/harness/tools/wiring.d.ts +10 -0
- package/dist-server/harness/tools/wiring.js +16 -0
- package/dist-server/providers/setup.provider.yaml +31 -0
- package/dist-server/providers/wren.provider.yaml +33 -0
- package/dist-server/server/adopt.d.ts +87 -0
- package/dist-server/server/adopt.js +263 -0
- package/dist-server/server/app.d.ts +6 -0
- package/dist-server/server/app.js +2521 -0
- package/dist-server/server/auth-choice.d.ts +16 -0
- package/dist-server/server/auth-choice.js +36 -0
- package/dist-server/server/bin.d.ts +2 -0
- package/dist-server/server/bin.js +601 -0
- package/dist-server/server/bootstrap-project-binding.d.ts +31 -0
- package/dist-server/server/bootstrap-project-binding.js +71 -0
- package/dist-server/server/clarify.d.ts +10 -0
- package/dist-server/server/clarify.js +17 -0
- package/dist-server/server/codex-setup-mcp.d.ts +2 -0
- package/dist-server/server/codex-setup-mcp.js +147 -0
- package/dist-server/server/compose.d.ts +89 -0
- package/dist-server/server/compose.js +271 -0
- package/dist-server/server/conn-config.d.ts +30 -0
- package/dist-server/server/conn-config.js +253 -0
- package/dist-server/server/context-files.d.ts +12 -0
- package/dist-server/server/context-files.js +117 -0
- package/dist-server/server/context-map.d.ts +30 -0
- package/dist-server/server/context-map.js +95 -0
- package/dist-server/server/context-source.d.ts +68 -0
- package/dist-server/server/context-source.js +85 -0
- package/dist-server/server/db.d.ts +862 -0
- package/dist-server/server/db.js +1839 -0
- package/dist-server/server/enrichment-runner.d.ts +184 -0
- package/dist-server/server/enrichment-runner.js +213 -0
- package/dist-server/server/enrichment-verify.d.ts +73 -0
- package/dist-server/server/enrichment-verify.js +290 -0
- package/dist-server/server/enrichment.d.ts +232 -0
- package/dist-server/server/enrichment.js +199 -0
- package/dist-server/server/env-detect.d.ts +8 -0
- package/dist-server/server/env-detect.js +17 -0
- package/dist-server/server/env-field-hints.d.ts +46 -0
- package/dist-server/server/env-field-hints.js +48 -0
- package/dist-server/server/fold.d.ts +133 -0
- package/dist-server/server/fold.js +407 -0
- package/dist-server/server/harness-profile-sources.d.ts +3 -0
- package/dist-server/server/harness-profile-sources.js +24 -0
- package/dist-server/server/harness.d.ts +19 -0
- package/dist-server/server/harness.js +439 -0
- package/dist-server/server/impact.d.ts +18 -0
- package/dist-server/server/impact.js +85 -0
- package/dist-server/server/interactive-terminal.d.ts +175 -0
- package/dist-server/server/interactive-terminal.js +336 -0
- package/dist-server/server/native-artifacts.d.ts +1004 -0
- package/dist-server/server/native-artifacts.js +564 -0
- package/dist-server/server/native-dispatch-registry.d.ts +42 -0
- package/dist-server/server/native-dispatch-registry.js +45 -0
- package/dist-server/server/native-producer-fence.d.ts +14 -0
- package/dist-server/server/native-producer-fence.js +48 -0
- package/dist-server/server/native-session-resume.d.ts +6 -0
- package/dist-server/server/native-session-resume.js +103 -0
- package/dist-server/server/native-session-workspace.d.ts +40 -0
- package/dist-server/server/native-session-workspace.js +175 -0
- package/dist-server/server/native-sessions.d.ts +374 -0
- package/dist-server/server/native-sessions.js +1517 -0
- package/dist-server/server/native-wren-runtime.d.ts +20 -0
- package/dist-server/server/native-wren-runtime.js +259 -0
- package/dist-server/server/node-pty-host.d.ts +31 -0
- package/dist-server/server/node-pty-host.js +100 -0
- package/dist-server/server/route-intent.d.ts +40 -0
- package/dist-server/server/route-intent.js +23 -0
- package/dist-server/server/runtime-binding.d.ts +52 -0
- package/dist-server/server/runtime-binding.js +258 -0
- package/dist-server/server/source-catalog.d.ts +84 -0
- package/dist-server/server/source-catalog.js +221 -0
- package/dist-server/server/source-driver.d.ts +35 -0
- package/dist-server/server/source-driver.js +124 -0
- package/dist-server/server/spa.d.ts +2 -0
- package/dist-server/server/spa.js +51 -0
- package/dist-server/server/subscription-model-catalog.d.ts +27 -0
- package/dist-server/server/subscription-model-catalog.js +203 -0
- package/dist-server/server/turn.d.ts +249 -0
- package/dist-server/server/turn.js +1074 -0
- package/dist-server/server/wire-types.d.ts +799 -0
- package/dist-server/server/wire-types.js +1 -0
- package/dist-server/server/wren-home.d.ts +19 -0
- package/dist-server/server/wren-home.js +33 -0
- package/dist-server/server/wren-profiles.d.ts +43 -0
- package/dist-server/server/wren-profiles.js +123 -0
- package/package.json +93 -0
- package/profiles/genbi-default/context/binding.yml +9 -0
- package/profiles/genbi-default/ir.golden.json +506 -0
- package/profiles/genbi-default/profile.yml +16 -0
- package/profiles/genbi-enrich-context/components/apply_enrichment/component.yml +42 -0
- package/profiles/genbi-enrich-context/components/draft_enrichment/component.yml +30 -0
- package/profiles/genbi-enrich-context/components/draft_enrichment/steps/draft.md +34 -0
- package/profiles/genbi-enrich-context/components/inspect_context/component.yml +32 -0
- package/profiles/genbi-enrich-context/components/inspect_context/steps/inspect.md +13 -0
- package/profiles/genbi-enrich-context/context/binding.yml +4 -0
- package/profiles/genbi-enrich-context/ir.golden.json +302 -0
- package/profiles/genbi-enrich-context/profile.yml +15 -0
- package/profiles/genbi-monitor/context/binding.yml +7 -0
- package/profiles/genbi-monitor/ir.golden.json +188 -0
- package/profiles/genbi-monitor/profile.yml +27 -0
- package/profiles/genbi-setup/components/build_context/component.yml +44 -0
- package/profiles/genbi-setup/components/build_context/steps/build.md +14 -0
- package/profiles/genbi-setup/components/connect_source/component.yml +51 -0
- package/profiles/genbi-setup/components/connect_source/steps/connect.md +23 -0
- package/profiles/genbi-setup/context/binding.yml +8 -0
- package/profiles/genbi-setup/ir.golden.json +140 -0
- package/profiles/genbi-setup/profile.yml +18 -0
- package/profiles/genbi-setup/raw/schema.json +5 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-owned contract for deterministic, noninteractive dispatch. This is
|
|
3
|
+
* intentionally not the interactive terminal protocol: it contains no bytes
|
|
4
|
+
* from a PTY, dispatcher stream, prompt, tool input/output, or credential.
|
|
5
|
+
*/
|
|
6
|
+
export const NATIVE_PRODUCER_VERSION = "1";
|
|
7
|
+
const MAX_RESULT_TEXT = 16 * 1024;
|
|
8
|
+
const MAX_CASSETTE_BYTES = 64 * 1024;
|
|
9
|
+
const SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
10
|
+
const SAFE_DIGEST = /^sha256:[a-f0-9]{64}$/;
|
|
11
|
+
/** Stable, prompt-free cassette selector for one host-owned idempotent run. */
|
|
12
|
+
export function nativeProducerCassetteKey(request) {
|
|
13
|
+
return `${request.vendor}__${request.agentId}__${request.idempotencyKey}`;
|
|
14
|
+
}
|
|
15
|
+
/** Runs one noninteractive dispatch and always returns a typed, fail-closed response. */
|
|
16
|
+
export async function produceNoninteractiveNative(request, options) {
|
|
17
|
+
const parsed = validateRequest(request);
|
|
18
|
+
if (parsed === undefined)
|
|
19
|
+
return failed("invalid_request");
|
|
20
|
+
if (parsed.version !== NATIVE_PRODUCER_VERSION)
|
|
21
|
+
return failed("unsupported_version");
|
|
22
|
+
if (parsed.scope.bindingDigest !== options.fence.bindingDigest || !options.fence.validateRun(parsed))
|
|
23
|
+
return failed("scope_mismatch");
|
|
24
|
+
if (options.signal?.aborted)
|
|
25
|
+
return failed("cancelled");
|
|
26
|
+
const controller = new AbortController();
|
|
27
|
+
const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;
|
|
28
|
+
let stop;
|
|
29
|
+
const timeout = setTimeout(() => {
|
|
30
|
+
stop = "timeout";
|
|
31
|
+
controller.abort();
|
|
32
|
+
}, timeoutMs);
|
|
33
|
+
const cancel = () => {
|
|
34
|
+
stop = "cancelled";
|
|
35
|
+
controller.abort();
|
|
36
|
+
};
|
|
37
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
38
|
+
const events = [];
|
|
39
|
+
try {
|
|
40
|
+
const dispatch = options.dispatch({
|
|
41
|
+
vendor: parsed.vendor,
|
|
42
|
+
agentId: parsed.agentId,
|
|
43
|
+
input: parsed.input,
|
|
44
|
+
scope: parsed.scope,
|
|
45
|
+
idempotencyKey: parsed.idempotencyKey,
|
|
46
|
+
signal: controller.signal,
|
|
47
|
+
fence: options.fence,
|
|
48
|
+
// Keep the private, potentially rich event stream inside the host. The
|
|
49
|
+
// bounded public lifecycle below is intentionally synthesized instead.
|
|
50
|
+
onEvent: (event) => events.push(event),
|
|
51
|
+
});
|
|
52
|
+
const result = await awaitWithAbort(dispatch, controller.signal);
|
|
53
|
+
if (stop === "timeout")
|
|
54
|
+
return failed("timeout");
|
|
55
|
+
if (!options.fence.validateRun(parsed))
|
|
56
|
+
return failed("scope_mismatch");
|
|
57
|
+
return complete(result, parsed, options.fence);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (stop === "timeout")
|
|
61
|
+
return failed("timeout");
|
|
62
|
+
if (isAbortError(error) || controller.signal.aborted)
|
|
63
|
+
return failed("cancelled");
|
|
64
|
+
return failed("producer_failed");
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
clearTimeout(timeout);
|
|
68
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
69
|
+
// The dispatcher callback is intentionally retained only until completion.
|
|
70
|
+
events.length = 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Replays a sanitized producer cassette; absence, drift, and scope changes fail closed. */
|
|
74
|
+
export function replayNoninteractiveNative(request, cassette, fence) {
|
|
75
|
+
const parsed = validateRequest(request);
|
|
76
|
+
if (parsed === undefined)
|
|
77
|
+
return failed("invalid_request");
|
|
78
|
+
if (parsed.version !== NATIVE_PRODUCER_VERSION)
|
|
79
|
+
return failed("unsupported_version");
|
|
80
|
+
const parsedCassette = validateCassette(cassette, parsed.input);
|
|
81
|
+
if (isRecord(cassette) && typeof cassette.version === "string" && cassette.version !== NATIVE_PRODUCER_VERSION) {
|
|
82
|
+
return failed("unsupported_version");
|
|
83
|
+
}
|
|
84
|
+
if (parsedCassette === undefined)
|
|
85
|
+
return failed("missing_replay");
|
|
86
|
+
if (parsed.scope.bindingDigest !== fence.bindingDigest || !fence.validateRun(parsed))
|
|
87
|
+
return failed("scope_mismatch");
|
|
88
|
+
if (parsedCassette.version !== NATIVE_PRODUCER_VERSION)
|
|
89
|
+
return failed("unsupported_version");
|
|
90
|
+
if (parsedCassette.vendor !== parsed.vendor ||
|
|
91
|
+
parsedCassette.agentId !== parsed.agentId ||
|
|
92
|
+
!sameScope(parsedCassette.scope, parsed.scope))
|
|
93
|
+
return failed("scope_mismatch");
|
|
94
|
+
if (parsedCassette.key !== nativeProducerCassetteKey(parsed))
|
|
95
|
+
return failed("missing_replay");
|
|
96
|
+
if (parsedCassette.response.status === "completed" && !parsedCassette.response.artifacts.every((artifact) => fence.validateArtifact(artifact, parsed))) {
|
|
97
|
+
return failed("scope_mismatch");
|
|
98
|
+
}
|
|
99
|
+
return parsedCassette.response;
|
|
100
|
+
}
|
|
101
|
+
/** Creates a checked-in/replayable record only from an already-safe response. */
|
|
102
|
+
export function createNativeProducerCassette(key, request, response, fence) {
|
|
103
|
+
const parsed = validateRequest(request);
|
|
104
|
+
const parsedResponse = validateResponse(response, parsed?.input);
|
|
105
|
+
if (!parsed || !parsedResponse || parsed.scope.bindingDigest !== fence.bindingDigest || !fence.validateRun(parsed) || !SAFE_ID.test(key) || (parsedResponse.status === "completed" && !parsedResponse.artifacts.every((artifact) => fence.validateArtifact(artifact, parsed)))) {
|
|
106
|
+
throw new Error("native producer cassette is invalid");
|
|
107
|
+
}
|
|
108
|
+
if (key !== nativeProducerCassetteKey(parsed)) {
|
|
109
|
+
throw new Error("native producer cassette key does not match its idempotent request");
|
|
110
|
+
}
|
|
111
|
+
const cassette = {
|
|
112
|
+
version: NATIVE_PRODUCER_VERSION,
|
|
113
|
+
key,
|
|
114
|
+
vendor: parsed.vendor,
|
|
115
|
+
agentId: parsed.agentId,
|
|
116
|
+
scope: parsed.scope,
|
|
117
|
+
response: parsedResponse,
|
|
118
|
+
};
|
|
119
|
+
if (Buffer.byteLength(JSON.stringify(cassette)) > MAX_CASSETTE_BYTES) {
|
|
120
|
+
throw new Error("native producer cassette exceeds its bounded contract");
|
|
121
|
+
}
|
|
122
|
+
return cassette;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Adapts existing subscription dispatchers without widening their protocol.
|
|
126
|
+
* The native producer only admits the vendor selected by the route options.
|
|
127
|
+
*/
|
|
128
|
+
export function createRouteNativeProducer(route, baseOptions) {
|
|
129
|
+
return async (input) => {
|
|
130
|
+
const choice = baseOptions.authChoice;
|
|
131
|
+
if (choice.mode !== "subscription" || choice.provider !== input.vendor) {
|
|
132
|
+
throw new Error("native producer vendor does not match the configured route");
|
|
133
|
+
}
|
|
134
|
+
const request = {
|
|
135
|
+
version: NATIVE_PRODUCER_VERSION,
|
|
136
|
+
vendor: input.vendor,
|
|
137
|
+
agentId: input.agentId,
|
|
138
|
+
input: input.input,
|
|
139
|
+
scope: input.scope,
|
|
140
|
+
idempotencyKey: input.idempotencyKey,
|
|
141
|
+
};
|
|
142
|
+
if (!input.fence.validateRoute(request, baseOptions.userProject)) {
|
|
143
|
+
throw new Error("native producer route fence rejected the request");
|
|
144
|
+
}
|
|
145
|
+
const result = await route({
|
|
146
|
+
...baseOptions,
|
|
147
|
+
question: input.input,
|
|
148
|
+
agentId: input.agentId,
|
|
149
|
+
onEvent: input.onEvent,
|
|
150
|
+
signal: input.signal,
|
|
151
|
+
});
|
|
152
|
+
return { text: resultText(result) };
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function resultText(result) {
|
|
156
|
+
if (result.backend === "agent") {
|
|
157
|
+
if (result.kind === "refusal")
|
|
158
|
+
throw new Error("producer refused result");
|
|
159
|
+
return JSON.stringify(result.envelope);
|
|
160
|
+
}
|
|
161
|
+
return result.finalText;
|
|
162
|
+
}
|
|
163
|
+
function complete(value, request, fence) {
|
|
164
|
+
if (!isRecord(value) || typeof value.text !== "string" || !value.text.trim())
|
|
165
|
+
return failed("malformed_output");
|
|
166
|
+
const text = sanitizeResultText(value.text, request.input);
|
|
167
|
+
if (text === undefined)
|
|
168
|
+
return failed("malformed_output");
|
|
169
|
+
const artifacts = value.artifacts === undefined ? [] : value.artifacts;
|
|
170
|
+
if (!Array.isArray(artifacts) || !artifacts.every((artifact) => validArtifact(artifact) && fence.validateArtifact(artifact, request))) {
|
|
171
|
+
return failed("malformed_output");
|
|
172
|
+
}
|
|
173
|
+
const rebuiltArtifacts = rebuildArtifacts(artifacts);
|
|
174
|
+
if (!rebuiltArtifacts)
|
|
175
|
+
return failed("malformed_output");
|
|
176
|
+
return {
|
|
177
|
+
version: NATIVE_PRODUCER_VERSION,
|
|
178
|
+
status: "completed",
|
|
179
|
+
lifecycle: [{ state: "accepted" }, { state: "running" }, { state: "completed" }],
|
|
180
|
+
result: { text },
|
|
181
|
+
artifacts: rebuiltArtifacts,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function failed(code) {
|
|
185
|
+
return {
|
|
186
|
+
version: NATIVE_PRODUCER_VERSION,
|
|
187
|
+
status: "failed",
|
|
188
|
+
lifecycle: [{ state: "accepted" }, { state: "running" }, { state: "failed" }],
|
|
189
|
+
error: { code },
|
|
190
|
+
artifacts: [],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function validateRequest(value) {
|
|
194
|
+
if (!isRecord(value) || !onlyKeys(value, ["version", "vendor", "agentId", "input", "scope", "idempotencyKey"]))
|
|
195
|
+
return undefined;
|
|
196
|
+
if (typeof value.version !== "string" || (value.vendor !== "claude" && value.vendor !== "codex") || typeof value.agentId !== "string" || typeof value.input !== "string" || typeof value.idempotencyKey !== "string")
|
|
197
|
+
return undefined;
|
|
198
|
+
if (!SAFE_ID.test(value.agentId) || !SAFE_ID.test(value.idempotencyKey) || value.input.length === 0 || value.input.length > MAX_RESULT_TEXT)
|
|
199
|
+
return undefined;
|
|
200
|
+
const scope = validateScope(value.scope);
|
|
201
|
+
if (!scope)
|
|
202
|
+
return undefined;
|
|
203
|
+
return { version: value.version, vendor: value.vendor, agentId: value.agentId, input: value.input, scope, idempotencyKey: value.idempotencyKey };
|
|
204
|
+
}
|
|
205
|
+
function validateCassette(value, prompt) {
|
|
206
|
+
if (!isRecord(value) || !onlyKeys(value, ["version", "key", "vendor", "agentId", "scope", "response"]))
|
|
207
|
+
return undefined;
|
|
208
|
+
if (value.version !== NATIVE_PRODUCER_VERSION || !SAFE_ID.test(String(value.key)) || (value.vendor !== "claude" && value.vendor !== "codex") || !SAFE_ID.test(String(value.agentId)))
|
|
209
|
+
return undefined;
|
|
210
|
+
const scope = validateScope(value.scope);
|
|
211
|
+
const response = validateResponse(value.response, prompt);
|
|
212
|
+
if (!scope || !response)
|
|
213
|
+
return undefined;
|
|
214
|
+
return { version: NATIVE_PRODUCER_VERSION, key: value.key, vendor: value.vendor, agentId: value.agentId, scope, response };
|
|
215
|
+
}
|
|
216
|
+
function validateResponse(value, prompt) {
|
|
217
|
+
if (!isRecord(value) || value.version !== NATIVE_PRODUCER_VERSION || !Array.isArray(value.lifecycle))
|
|
218
|
+
return undefined;
|
|
219
|
+
if (value.status === "completed" && isRecord(value.result) && typeof value.result.text === "string" && Array.isArray(value.artifacts)) {
|
|
220
|
+
if (!onlyKeys(value, ["version", "status", "lifecycle", "result", "artifacts"]))
|
|
221
|
+
return undefined;
|
|
222
|
+
const lifecycle = rebuildLifecycle(value.lifecycle, "completed");
|
|
223
|
+
const text = sanitizeResultText(value.result.text, prompt);
|
|
224
|
+
const artifacts = rebuildArtifacts(value.artifacts);
|
|
225
|
+
if (!lifecycle || text === undefined || !artifacts || !onlyKeys(value.result, ["text"]))
|
|
226
|
+
return undefined;
|
|
227
|
+
return { version: NATIVE_PRODUCER_VERSION, status: "completed", lifecycle, result: { text }, artifacts };
|
|
228
|
+
}
|
|
229
|
+
if (value.status === "failed" && isRecord(value.error) && typeof value.error.code === "string" && Array.isArray(value.artifacts) && value.artifacts.length === 0 && validErrorCode(value.error.code)) {
|
|
230
|
+
if (!onlyKeys(value, ["version", "status", "lifecycle", "error", "artifacts"]))
|
|
231
|
+
return undefined;
|
|
232
|
+
const lifecycle = rebuildLifecycle(value.lifecycle, "failed");
|
|
233
|
+
if (!lifecycle || !onlyKeys(value.error, ["code"]))
|
|
234
|
+
return undefined;
|
|
235
|
+
return { version: NATIVE_PRODUCER_VERSION, status: "failed", lifecycle, error: { code: value.error.code }, artifacts: [] };
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
function validateScope(value) {
|
|
240
|
+
if (!isRecord(value) || !onlyKeys(value, ["bindingDigest"]) || typeof value.bindingDigest !== "string" || !SAFE_DIGEST.test(value.bindingDigest))
|
|
241
|
+
return undefined;
|
|
242
|
+
return { bindingDigest: value.bindingDigest };
|
|
243
|
+
}
|
|
244
|
+
function validArtifact(value) {
|
|
245
|
+
return isRecord(value) && onlyKeys(value, ["id", "kind", "digest", "idempotencyKey"]) && SAFE_ID.test(String(value.id)) && SAFE_ID.test(String(value.idempotencyKey)) && SAFE_DIGEST.test(String(value.digest)) && ["dashboard", "report", "chart"].includes(String(value.kind));
|
|
246
|
+
}
|
|
247
|
+
function sanitizeResultText(text, prompt) {
|
|
248
|
+
if (Buffer.byteLength(text) > MAX_RESULT_TEXT ||
|
|
249
|
+
/[\u0000-\u001f\u007f-\u009f]/.test(text) ||
|
|
250
|
+
(prompt !== undefined && text.includes(prompt)) ||
|
|
251
|
+
/^\s*(?:\{|\[)/.test(text) ||
|
|
252
|
+
/\b(?:tool(?:[_ -]?(?:call|result|input|output))?|mcp(?:[_ -]?(?:tool|server|message))?|capability(?:[_ -]?(?:token|credential|grant))?|(?:api[_ -]?key|secret|token|password|authorization|credential))\b\s*[:=]|\bBearer\s+[A-Za-z0-9._-]+|\/(?:Users|home)\//i.test(text))
|
|
253
|
+
return undefined;
|
|
254
|
+
return text.replace(/\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/gi, "[redacted-id]");
|
|
255
|
+
}
|
|
256
|
+
function awaitWithAbort(promise, signal) {
|
|
257
|
+
if (signal.aborted)
|
|
258
|
+
return Promise.reject(new DOMException("cancelled", "AbortError"));
|
|
259
|
+
return new Promise((resolve, reject) => {
|
|
260
|
+
const abort = () => reject(new DOMException("cancelled", "AbortError"));
|
|
261
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
262
|
+
promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function isAbortError(error) {
|
|
266
|
+
return error instanceof DOMException && error.name === "AbortError";
|
|
267
|
+
}
|
|
268
|
+
function validErrorCode(value) {
|
|
269
|
+
return ["unsupported_version", "scope_mismatch", "invalid_request", "malformed_output", "missing_replay", "timeout", "cancelled", "producer_failed"].includes(value);
|
|
270
|
+
}
|
|
271
|
+
function rebuildLifecycle(value, terminal) {
|
|
272
|
+
if (value.length !== 3)
|
|
273
|
+
return undefined;
|
|
274
|
+
const states = ["accepted", "running", terminal];
|
|
275
|
+
const rebuilt = [];
|
|
276
|
+
for (let index = 0; index < states.length; index += 1) {
|
|
277
|
+
const entry = value[index];
|
|
278
|
+
if (!isRecord(entry) || !onlyKeys(entry, ["state"]) || entry.state !== states[index])
|
|
279
|
+
return undefined;
|
|
280
|
+
rebuilt.push({ state: states[index] });
|
|
281
|
+
}
|
|
282
|
+
return rebuilt;
|
|
283
|
+
}
|
|
284
|
+
function rebuildArtifacts(value) {
|
|
285
|
+
const rebuilt = [];
|
|
286
|
+
for (const artifact of value) {
|
|
287
|
+
if (!validArtifact(artifact))
|
|
288
|
+
return undefined;
|
|
289
|
+
const record = artifact;
|
|
290
|
+
rebuilt.push({ id: record.id, kind: record.kind, digest: record.digest, idempotencyKey: record.idempotencyKey });
|
|
291
|
+
}
|
|
292
|
+
return rebuilt;
|
|
293
|
+
}
|
|
294
|
+
function sameScope(a, b) {
|
|
295
|
+
return a.bindingDigest === b.bindingDigest;
|
|
296
|
+
}
|
|
297
|
+
function isRecord(value) {
|
|
298
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
299
|
+
}
|
|
300
|
+
function onlyKeys(value, allowed) {
|
|
301
|
+
return Object.keys(value).every((key) => allowed.includes(key));
|
|
302
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a binary shipped by an installed npm package's own `bin` field, using Node's module
|
|
3
|
+
* resolution rooted at this file — not `PATH`, and not a directory walk.
|
|
4
|
+
*
|
|
5
|
+
* This is what lets the `warble` binary and its dispatchers resolve to the exact pinned
|
|
6
|
+
* `@warble/*` version declared in `apps/genbi/package.json`, regardless of what else happens to be
|
|
7
|
+
* on `PATH` and regardless of how the current process was launched. `pnpm run <script>` prepends
|
|
8
|
+
* `node_modules/.bin` to `PATH`, so a bare `PATH` probe already tends to find a workspace-installed
|
|
9
|
+
* package when the process was started that way — but a process started directly (`node
|
|
10
|
+
* dist-server/server/bin.js`, a packaged deployment, a test runner) inherits no such `PATH`, and
|
|
11
|
+
* even when it does, `PATH` order rather than the pinned dependency version is what would decide
|
|
12
|
+
* the outcome. Resolving through `require.resolve` instead is deterministic in both cases: it
|
|
13
|
+
* always finds the version this package actually depends on.
|
|
14
|
+
*
|
|
15
|
+
* Returns `undefined` — never throws — when the package isn't installed, declares no matching
|
|
16
|
+
* `bin` entry, or the resolved file doesn't exist on disk, so callers can fall through to their
|
|
17
|
+
* next resolution tier.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveInstalledPackageBin(packageName: string, binName: string): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Named, explicit opt-in that re-enables the legacy "sibling `warble` git checkout"
|
|
22
|
+
* development-mode resolution tier in `resolveWarbleBinary`, `resolveAgentSdkCli`, and
|
|
23
|
+
* `resolveCodexLocalCli`. Off by default: once the pinned `@warble/*` packages are installed,
|
|
24
|
+
* silently preferring an ambient sibling checkout over them would make it easy to test against the
|
|
25
|
+
* wrong Warble version without noticing. Set to `"1"` only when deliberately developing GenBI
|
|
26
|
+
* against an uninstalled, unreleased Warble checkout.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isWarbleSiblingCheckoutDevModeEnabled(): boolean;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Resolves a binary shipped by an installed npm package's own `bin` field, using Node's module
|
|
6
|
+
* resolution rooted at this file — not `PATH`, and not a directory walk.
|
|
7
|
+
*
|
|
8
|
+
* This is what lets the `warble` binary and its dispatchers resolve to the exact pinned
|
|
9
|
+
* `@warble/*` version declared in `apps/genbi/package.json`, regardless of what else happens to be
|
|
10
|
+
* on `PATH` and regardless of how the current process was launched. `pnpm run <script>` prepends
|
|
11
|
+
* `node_modules/.bin` to `PATH`, so a bare `PATH` probe already tends to find a workspace-installed
|
|
12
|
+
* package when the process was started that way — but a process started directly (`node
|
|
13
|
+
* dist-server/server/bin.js`, a packaged deployment, a test runner) inherits no such `PATH`, and
|
|
14
|
+
* even when it does, `PATH` order rather than the pinned dependency version is what would decide
|
|
15
|
+
* the outcome. Resolving through `require.resolve` instead is deterministic in both cases: it
|
|
16
|
+
* always finds the version this package actually depends on.
|
|
17
|
+
*
|
|
18
|
+
* Returns `undefined` — never throws — when the package isn't installed, declares no matching
|
|
19
|
+
* `bin` entry, or the resolved file doesn't exist on disk, so callers can fall through to their
|
|
20
|
+
* next resolution tier.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveInstalledPackageBin(packageName, binName) {
|
|
23
|
+
try {
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
const pkgJsonPath = require.resolve(`${packageName}/package.json`);
|
|
26
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
|
|
27
|
+
const binField = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.[binName];
|
|
28
|
+
if (binField === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
const resolved = path.resolve(path.dirname(pkgJsonPath), binField);
|
|
31
|
+
return existsSync(resolved) ? resolved : undefined;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Named, explicit opt-in that re-enables the legacy "sibling `warble` git checkout"
|
|
39
|
+
* development-mode resolution tier in `resolveWarbleBinary`, `resolveAgentSdkCli`, and
|
|
40
|
+
* `resolveCodexLocalCli`. Off by default: once the pinned `@warble/*` packages are installed,
|
|
41
|
+
* silently preferring an ambient sibling checkout over them would make it easy to test against the
|
|
42
|
+
* wrong Warble version without noticing. Set to `"1"` only when deliberately developing GenBI
|
|
43
|
+
* against an uninstalled, unreleased Warble checkout.
|
|
44
|
+
*/
|
|
45
|
+
export function isWarbleSiblingCheckoutDevModeEnabled() {
|
|
46
|
+
return process.env.WREN_HARNESS_ALLOW_WARBLE_SIBLING_CHECKOUT === "1";
|
|
47
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
export declare const ANTHROPIC_ADAPTER_ID = "anthropic";
|
|
3
|
+
export interface AnthropicAdapterConfig {
|
|
4
|
+
readonly model: string;
|
|
5
|
+
readonly apiKey?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createAnthropicAdapter(config: AnthropicAdapterConfig): LanguageModel;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
2
|
+
export const ANTHROPIC_ADAPTER_ID = "anthropic";
|
|
3
|
+
export function createAnthropicAdapter(config) {
|
|
4
|
+
const provider = createAnthropic(config.apiKey !== undefined ? { apiKey: config.apiKey } : {});
|
|
5
|
+
return provider.languageModel(config.model);
|
|
6
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MockLanguageModelV4 } from "ai/test";
|
|
2
|
+
export declare const MOCK_ADAPTER_ID = "mock";
|
|
3
|
+
export type MockAdapterConfig = ConstructorParameters<typeof MockLanguageModelV4>[0];
|
|
4
|
+
export declare function createMockAdapter(config?: MockAdapterConfig): MockLanguageModelV4;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
export declare const OPENAI_COMPATIBLE_ADAPTER_ID = "openai-compatible";
|
|
3
|
+
export interface OpenAICompatibleAdapterConfig {
|
|
4
|
+
readonly baseURL: string;
|
|
5
|
+
readonly model: string;
|
|
6
|
+
readonly apiKey?: string;
|
|
7
|
+
/** Provider name reported in telemetry/errors. Defaults to the adapter id. */
|
|
8
|
+
readonly name?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function createOpenAICompatibleAdapter(config: OpenAICompatibleAdapterConfig): LanguageModel;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
2
|
+
export const OPENAI_COMPATIBLE_ADAPTER_ID = "openai-compatible";
|
|
3
|
+
export function createOpenAICompatibleAdapter(config) {
|
|
4
|
+
const provider = createOpenAICompatible({
|
|
5
|
+
name: config.name ?? OPENAI_COMPATIBLE_ADAPTER_ID,
|
|
6
|
+
baseURL: config.baseURL,
|
|
7
|
+
...(config.apiKey !== undefined ? { apiKey: config.apiKey } : {}),
|
|
8
|
+
});
|
|
9
|
+
return provider.languageModel(config.model);
|
|
10
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
import type { ProviderRegistry } from "./registry.js";
|
|
3
|
+
/** Names an adapter id + the config to realize it with. */
|
|
4
|
+
export interface AdapterSpec<Config = unknown> {
|
|
5
|
+
readonly adapter: string;
|
|
6
|
+
readonly config: Config;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Runtime-injected tier -> adapter binding. This is a plain object supplied
|
|
10
|
+
* by the caller at run time — it is never read from a bundle and must never
|
|
11
|
+
* be committed to a bundle fixture. `tier` names are open strings owned by
|
|
12
|
+
* the bundle's steps; the binding only needs to cover the tiers a given run
|
|
13
|
+
* actually uses.
|
|
14
|
+
*/
|
|
15
|
+
export interface TierBinding {
|
|
16
|
+
readonly tiers: Readonly<Record<string, AdapterSpec>>;
|
|
17
|
+
}
|
|
18
|
+
/** Resolve an open-string tier name to a concrete language model instance. */
|
|
19
|
+
export declare function resolveTierModel(binding: TierBinding, tier: string, registry: ProviderRegistry): LanguageModel;
|
|
20
|
+
/** Convenience: resolve the model for a bundle step via its `tier` field. */
|
|
21
|
+
export declare function resolveStepModel(step: {
|
|
22
|
+
readonly tier: string;
|
|
23
|
+
}, binding: TierBinding, registry: ProviderRegistry): LanguageModel;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { UnknownTierError } from "./errors.js";
|
|
2
|
+
/** Resolve an open-string tier name to a concrete language model instance. */
|
|
3
|
+
export function resolveTierModel(binding, tier, registry) {
|
|
4
|
+
const spec = binding.tiers[tier];
|
|
5
|
+
if (!spec) {
|
|
6
|
+
throw new UnknownTierError(tier);
|
|
7
|
+
}
|
|
8
|
+
return registry.create(spec.adapter, spec.config);
|
|
9
|
+
}
|
|
10
|
+
/** Convenience: resolve the model for a bundle step via its `tier` field. */
|
|
11
|
+
export function resolveStepModel(step, binding, registry) {
|
|
12
|
+
return resolveTierModel(binding, step.tier, registry);
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class UnknownAdapterError extends Error {
|
|
2
|
+
constructor(adapterId) {
|
|
3
|
+
super(`no provider adapter registered for id: "${adapterId}"`);
|
|
4
|
+
this.name = "UnknownAdapterError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export class UnknownTierError extends Error {
|
|
8
|
+
constructor(tier) {
|
|
9
|
+
super(`no binding entry for tier: "${tier}"`);
|
|
10
|
+
this.name = "UnknownTierError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { UnknownAdapterError, UnknownTierError } from "./errors.js";
|
|
2
|
+
export { createProviderRegistry } from "./registry.js";
|
|
3
|
+
export type { AdapterFactory, ProviderRegistry } from "./registry.js";
|
|
4
|
+
export { resolveStepModel, resolveTierModel } from "./binding.js";
|
|
5
|
+
export type { AdapterSpec, TierBinding } from "./binding.js";
|
|
6
|
+
export { createMockAdapter, MOCK_ADAPTER_ID } from "./adapters/mock.js";
|
|
7
|
+
export type { MockAdapterConfig } from "./adapters/mock.js";
|
|
8
|
+
export { createOpenAICompatibleAdapter, OPENAI_COMPATIBLE_ADAPTER_ID, } from "./adapters/openai-compatible.js";
|
|
9
|
+
export type { OpenAICompatibleAdapterConfig } from "./adapters/openai-compatible.js";
|
|
10
|
+
export { ANTHROPIC_ADAPTER_ID, createAnthropicAdapter } from "./adapters/anthropic.js";
|
|
11
|
+
export type { AnthropicAdapterConfig } from "./adapters/anthropic.js";
|
|
12
|
+
import { type ProviderRegistry } from "./registry.js";
|
|
13
|
+
/**
|
|
14
|
+
* A provider registry pre-populated with the built-in adapters
|
|
15
|
+
* (`mock`, `openai-compatible`, `anthropic`). Callers can still
|
|
16
|
+
* `register()` additional adapter ids onto the returned registry.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createDefaultProviderRegistry(): ProviderRegistry;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { UnknownAdapterError, UnknownTierError } from "./errors.js";
|
|
2
|
+
export { createProviderRegistry } from "./registry.js";
|
|
3
|
+
export { resolveStepModel, resolveTierModel } from "./binding.js";
|
|
4
|
+
export { createMockAdapter, MOCK_ADAPTER_ID } from "./adapters/mock.js";
|
|
5
|
+
export { createOpenAICompatibleAdapter, OPENAI_COMPATIBLE_ADAPTER_ID, } from "./adapters/openai-compatible.js";
|
|
6
|
+
export { ANTHROPIC_ADAPTER_ID, createAnthropicAdapter } from "./adapters/anthropic.js";
|
|
7
|
+
import { createAnthropicAdapter, ANTHROPIC_ADAPTER_ID } from "./adapters/anthropic.js";
|
|
8
|
+
import { createMockAdapter, MOCK_ADAPTER_ID } from "./adapters/mock.js";
|
|
9
|
+
import { createOpenAICompatibleAdapter, OPENAI_COMPATIBLE_ADAPTER_ID, } from "./adapters/openai-compatible.js";
|
|
10
|
+
import { createProviderRegistry } from "./registry.js";
|
|
11
|
+
/**
|
|
12
|
+
* A provider registry pre-populated with the built-in adapters
|
|
13
|
+
* (`mock`, `openai-compatible`, `anthropic`). Callers can still
|
|
14
|
+
* `register()` additional adapter ids onto the returned registry.
|
|
15
|
+
*/
|
|
16
|
+
export function createDefaultProviderRegistry() {
|
|
17
|
+
const registry = createProviderRegistry();
|
|
18
|
+
registry.register(MOCK_ADAPTER_ID, createMockAdapter);
|
|
19
|
+
registry.register(OPENAI_COMPATIBLE_ADAPTER_ID, createOpenAICompatibleAdapter);
|
|
20
|
+
registry.register(ANTHROPIC_ADAPTER_ID, createAnthropicAdapter);
|
|
21
|
+
return registry;
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
export type AdapterFactory<Config = unknown> = (config: Config) => LanguageModel;
|
|
3
|
+
export interface ProviderRegistry {
|
|
4
|
+
/** Register (or override) the adapter for an open-string adapter id. */
|
|
5
|
+
register<Config = unknown>(adapterId: string, factory: AdapterFactory<Config>): void;
|
|
6
|
+
/** Whether an adapter is registered for this id. */
|
|
7
|
+
has(adapterId: string): boolean;
|
|
8
|
+
/** Realize a language model instance for the given adapter id + config. */
|
|
9
|
+
create(adapterId: string, config: unknown): LanguageModel;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create an empty, injectable provider registry keyed on an open-string
|
|
13
|
+
* adapter id. Callers register built-in and/or custom adapters onto it;
|
|
14
|
+
* the registry itself has no opinion on what ids exist.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createProviderRegistry(): ProviderRegistry;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { UnknownAdapterError } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create an empty, injectable provider registry keyed on an open-string
|
|
4
|
+
* adapter id. Callers register built-in and/or custom adapters onto it;
|
|
5
|
+
* the registry itself has no opinion on what ids exist.
|
|
6
|
+
*/
|
|
7
|
+
export function createProviderRegistry() {
|
|
8
|
+
const adapters = new Map();
|
|
9
|
+
return {
|
|
10
|
+
register(adapterId, factory) {
|
|
11
|
+
adapters.set(adapterId, factory);
|
|
12
|
+
},
|
|
13
|
+
has(adapterId) {
|
|
14
|
+
return adapters.has(adapterId);
|
|
15
|
+
},
|
|
16
|
+
create(adapterId, config) {
|
|
17
|
+
const factory = adapters.get(adapterId);
|
|
18
|
+
if (!factory) {
|
|
19
|
+
throw new UnknownAdapterError(adapterId);
|
|
20
|
+
}
|
|
21
|
+
return factory(config);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|