@warble/claude-agent-sdk 0.10.0 → 0.12.0
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/dist/{chunk-Y5BDZDXF.js → chunk-7XQ5F6FM.js} +330 -53
- package/dist/chunk-7XQ5F6FM.js.map +1 -0
- package/dist/cli.js +24 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +238 -5
- package/dist/index.js +21 -1
- package/package.json +5 -4
- package/dist/chunk-Y5BDZDXF.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -9,10 +9,11 @@ import {
|
|
|
9
9
|
discoverClaudeModels,
|
|
10
10
|
emitAgentModule,
|
|
11
11
|
parseRenderFlavor,
|
|
12
|
+
parseSlotFlags,
|
|
12
13
|
prepareDispatch,
|
|
13
14
|
prepareDisplayManifest,
|
|
14
15
|
runDispatch
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-7XQ5F6FM.js";
|
|
16
17
|
|
|
17
18
|
// src/cli.ts
|
|
18
19
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -21,6 +22,13 @@ import { dirname, join, resolve } from "path";
|
|
|
21
22
|
import { createInterface } from "readline";
|
|
22
23
|
import { parseArgs } from "util";
|
|
23
24
|
import { fileURLToPath } from "url";
|
|
25
|
+
function parseSlotFlagsOrFail(flags) {
|
|
26
|
+
try {
|
|
27
|
+
return parseSlotFlags(flags);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
fail(e instanceof Error ? e.message : String(e));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
24
32
|
function fail(message) {
|
|
25
33
|
process.stderr.write(`error: ${message}
|
|
26
34
|
`);
|
|
@@ -90,7 +98,8 @@ async function main() {
|
|
|
90
98
|
"stream-json": { type: "boolean" },
|
|
91
99
|
resume: { type: "string" },
|
|
92
100
|
timeout: { type: "string" },
|
|
93
|
-
"include-unavailable": { type: "boolean" }
|
|
101
|
+
"include-unavailable": { type: "boolean" },
|
|
102
|
+
slot: { type: "string", multiple: true }
|
|
94
103
|
}
|
|
95
104
|
});
|
|
96
105
|
const [subcommand, irArg, question] = positionals;
|
|
@@ -116,7 +125,15 @@ async function main() {
|
|
|
116
125
|
const flavor = parseRenderFlavor(values["render-flavor"] ?? "programmatic");
|
|
117
126
|
const models = buildModels(values);
|
|
118
127
|
const raw = readFileSync(resolve(irArg), "utf8");
|
|
119
|
-
const common = {
|
|
128
|
+
const common = {
|
|
129
|
+
target,
|
|
130
|
+
flavor,
|
|
131
|
+
models,
|
|
132
|
+
raw,
|
|
133
|
+
irPath: irArg,
|
|
134
|
+
project: values.project,
|
|
135
|
+
slots: parseSlotFlagsOrFail(values.slot ?? [])
|
|
136
|
+
};
|
|
120
137
|
if (subcommand === "emit") {
|
|
121
138
|
return runEmit(common, values.out, Boolean(values.standalone));
|
|
122
139
|
}
|
|
@@ -130,6 +147,7 @@ async function main() {
|
|
|
130
147
|
}
|
|
131
148
|
function runEmit(common, outArg, standalone) {
|
|
132
149
|
const prepared = prepareDispatch({
|
|
150
|
+
slots: common.slots,
|
|
133
151
|
ir: common.raw,
|
|
134
152
|
target: common.target,
|
|
135
153
|
flavor: common.flavor,
|
|
@@ -155,7 +173,7 @@ function runManifest(common, outArg, includeUnavailable) {
|
|
|
155
173
|
irPath: common.irPath,
|
|
156
174
|
...common.project !== void 0 ? { project: common.project } : {}
|
|
157
175
|
};
|
|
158
|
-
const prepared = includeUnavailable ? prepareDisplayManifest(input) : prepareDispatch(input);
|
|
176
|
+
const prepared = includeUnavailable ? prepareDisplayManifest({ ...input, slots: common.slots }) : prepareDispatch({ ...input, slots: common.slots });
|
|
159
177
|
for (const c of prepared.components) {
|
|
160
178
|
if ("report" in c) printResolutionSummary(common.target, c.id, c.report);
|
|
161
179
|
}
|
|
@@ -184,6 +202,7 @@ async function runDispatchCmd(common, values, question) {
|
|
|
184
202
|
const warbleBin = values["warble-bin"] ?? defaultWarbleBin();
|
|
185
203
|
const title = values.title;
|
|
186
204
|
const prepared = prepareDispatch({
|
|
205
|
+
slots: common.slots,
|
|
187
206
|
ir: common.raw,
|
|
188
207
|
question: question ?? "",
|
|
189
208
|
target: common.target,
|
|
@@ -230,6 +249,7 @@ async function runChatCmd(common, values) {
|
|
|
230
249
|
const warbleBin = values["warble-bin"] ?? defaultWarbleBin();
|
|
231
250
|
const componentId = values.component ?? "answer_query";
|
|
232
251
|
const prepared = prepareDispatch({
|
|
252
|
+
slots: common.slots,
|
|
233
253
|
ir: common.raw,
|
|
234
254
|
target: common.target,
|
|
235
255
|
flavor: common.flavor,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `warble-agent-sdk` — the Claude Agent SDK back-end CLI.\n *\n * warble-agent-sdk dispatch <ir.json> \"<question>\" [--target …] [--models-config m.yml]\n * [--render-flavor programmatic|prompt] [--out ./run] [--project <dir>]\n * [--strong opus] [--cheap haiku] [--orchestrator sonnet]\n * [--warble-bin <path>] [--max-turns N] [--title <t>] [--dry-run]\n *\n * warble-agent-sdk emit <ir.json> [--out agent.ts] [--standalone] [--target …] [--models-config …]\n * [--render-flavor …] [--project <dir>] [--strong/--cheap/--orchestrator …]\n *\n * warble-agent-sdk manifest <ir.json> [--include-unavailable] [--out manifest.json] [--target …] [--models-config …]\n * [--render-flavor …] [--project <dir>] [--strong/--cheap/--orchestrator …]\n *\n * warble-agent-sdk chat <ir.json> [--project <dir>] [--component answer_query] [--out ./run]\n * [--target …] [--models-config m.yml] [--render-flavor programmatic|prompt] [--warble-bin <path>]\n * [--stream-json] [--resume <session-id>]\n *\n * `chat --stream-json` emits per-step/per-tool NDJSON events (one `WarbleChatEvent`, events.ts, per\n * line) to stdout as each turn runs, ending with a terminal `{\"t\":\"answer\",\"text\":…}` line, instead of\n * the default plain final-answer-text-per-turn output — for a consumer that wants to build a live,\n * expandable work log rather than just the finished text. Every turn also emits a\n * `{\"t\":\"session\",\"id\":…}` line (on success AND on a failed turn) carrying that turn's SDK session id.\n *\n * `--resume <session-id>` seeds a brand-new `chat` process's FIRST turn with a session id captured by\n * an earlier `chat` process (from its `{\"t\":\"session\",…}` line) — lets a caller resume a conversation\n * that a previous process started (e.g. one that ran out of turns), continuing the real SDK\n * conversation instead of re-dispatching a fresh prompt from scratch. Ignored after the first turn:\n * subsequent turns resume from this process's own prior turn, as usual.\n *\n * `dispatch` consumes the SAME `ir.json` a Rust `warble compile` emits and drives the SDK loop\n * in-process (`--dry-run` writes the assembled plan without calling `query()`). `emit` freezes the\n * resolved plan into an importable TS agent module (thin, or `--standalone`). `manifest` runs the\n * same preparation as `emit` (no `question`, no `query()` call) and instead serializes a display\n * manifest — the resolved agents/steps/tiers/capabilities/guardrails for THIS target, structurally\n * identical to the vercel back-end's bundle — so a consumer can source a display from whichever\n * back-end actually runs, instead of always reading the vercel bundle target's output. `chat` opens a\n * multi-turn session (session.ts, G1 — single profile, many turns) over one component, reading\n * questions from stdin line-by-line and resuming the SDK session turn over turn.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { parseArgs } from \"node:util\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { emitAgentModule } from \"./codegen.js\";\nimport { prepareDisplayManifest, prepareDispatch, type PreparedDispatch } from \"./dispatch.js\";\nimport { DispatchError } from \"./error.js\";\nimport type { WarbleChatEvent } from \"./events.js\";\nimport { buildManifest } from \"./manifest.js\";\nimport { ModelConfig } from \"./models.js\";\nimport { discoverClaudeModels } from \"./model_catalog.js\";\nimport { parseRenderFlavor, type RenderFlavor } from \"./options.js\";\nimport { DispatchSessionError, runDispatch } from \"./run.js\";\nimport { createChatSession } from \"./session.js\";\nimport { type ResolutionReport } from \"./resolve.js\";\nimport { DEFAULT_TARGET } from \"./targets.js\";\n\nfunction fail(message: string): never {\n process.stderr.write(`error: ${message}\\n`);\n process.exit(1);\n}\n\nconst USAGE =\n 'usage: warble-agent-sdk <dispatch|emit|manifest|chat> <ir.json> [\"<question>\"] [options]\\n' +\n \" warble-agent-sdk list-models [--project <dir>] [--timeout <ms>]\";\n\n// `require(\"../package.json\")` resolves relative to *this* file's own location, one directory up —\n// which is the package root in both the dev tree (src/cli.ts → ../package.json) and the published\n// layout (dist/cli.js → ../package.json; package.json ships in every npm package regardless of the\n// \"files\" allowlist). That keeps the reported version tied to the package's real `version` field\n// instead of a literal that could drift from it.\nconst requireFromHere = createRequire(import.meta.url);\n\nfunction packageVersion(): string {\n return (requireFromHere(\"../package.json\") as { version: string }).version;\n}\n\n/** Locate the reference `warble` binary: --warble-bin, else PATH, else this repo's release build. */\nfunction defaultWarbleBin(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n const repoBuilt = resolve(here, \"../../../target/release/warble\");\n return existsSync(repoBuilt) ? repoBuilt : \"warble\";\n}\n\nfunction printResolutionSummary(target: string, id: string, report: ResolutionReport): void {\n process.stderr.write(`warble-agent-sdk: capability resolution for '${target}' (component '${id}'):\\n`);\n for (const e of report) {\n const note = e.note ? ` — ${e.note}` : \"\";\n process.stderr.write(\n ` ${e.capability.padEnd(28)} ${e.outcome.padEnd(12)} (${e.provided_by}, ${e.criticality})${note}\\n`,\n );\n }\n}\n\ninterface CommonArgs {\n target: string;\n flavor: RenderFlavor;\n models: ModelConfig;\n raw: string;\n irPath: string;\n project: string | undefined;\n}\n\nfunction buildModels(values: Record<string, string | boolean | undefined>): ModelConfig {\n const cfgPath = values[\"models-config\"];\n if (typeof cfgPath === \"string\") {\n return ModelConfig.fromYaml(readFileSync(resolve(cfgPath), \"utf8\"));\n }\n return ModelConfig.fromFlags(\n (values.strong as string) ?? \"opus\",\n (values.cheap as string) ?? \"haiku\",\n (values.orchestrator as string) ?? \"sonnet\",\n );\n}\n\nasync function main(): Promise<void> {\n // Handle `--version`/`-V` and `--help`/`-h` up front, before the strict `parseArgs` below —\n // neither is a declared option there, so leaving them for `parseArgs` to see would throw\n // `ERR_PARSE_ARGS_UNKNOWN_OPTION` instead of doing what every other CLI does with them.\n const firstArg = process.argv[2];\n if (firstArg === \"--version\" || firstArg === \"-V\") {\n process.stdout.write(`${packageVersion()}\\n`);\n return;\n }\n if (firstArg === \"--help\" || firstArg === \"-h\") {\n process.stdout.write(`${USAGE}\\n`);\n return;\n }\n\n const { values, positionals } = parseArgs({\n allowPositionals: true,\n options: {\n target: { type: \"string\" },\n out: { type: \"string\" },\n \"models-config\": { type: \"string\" },\n \"render-flavor\": { type: \"string\" },\n strong: { type: \"string\" },\n cheap: { type: \"string\" },\n orchestrator: { type: \"string\" },\n project: { type: \"string\" },\n \"warble-bin\": { type: \"string\" },\n \"max-turns\": { type: \"string\" },\n title: { type: \"string\" },\n \"dry-run\": { type: \"boolean\" },\n standalone: { type: \"boolean\" },\n component: { type: \"string\" },\n \"stream-json\": { type: \"boolean\" },\n resume: { type: \"string\" },\n timeout: { type: \"string\" },\n \"include-unavailable\": { type: \"boolean\" },\n },\n });\n\n const [subcommand, irArg, question] = positionals;\n if (\n subcommand !== \"dispatch\" &&\n subcommand !== \"emit\" &&\n subcommand !== \"manifest\" &&\n subcommand !== \"chat\" &&\n subcommand !== \"list-models\"\n ) {\n fail(USAGE);\n }\n if (subcommand === \"list-models\") {\n if (irArg !== undefined || question !== undefined) fail(\"list-models does not take an <ir.json> or question\");\n const timeout = values.timeout === undefined ? undefined : Number(values.timeout);\n if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) fail(\"--timeout must be a positive number\");\n const catalog = await discoverClaudeModels({\n ...(values.project ? { cwd: values.project } : {}),\n ...(timeout !== undefined ? { timeoutMs: timeout } : {}),\n });\n process.stdout.write(`${JSON.stringify(catalog)}\\n`);\n return;\n }\n if (values.timeout !== undefined) fail(\"--timeout is only supported by list-models\");\n if (values[\"include-unavailable\"] && subcommand !== \"manifest\") fail(\"--include-unavailable is only supported by manifest\");\n if (!irArg) fail(\"missing <ir.json> argument\");\n\n const target = values.target ?? DEFAULT_TARGET;\n const flavor = parseRenderFlavor(values[\"render-flavor\"] ?? \"programmatic\");\n const models = buildModels(values);\n const raw = readFileSync(resolve(irArg), \"utf8\");\n\n const common: CommonArgs = { target, flavor, models, raw, irPath: irArg, project: values.project };\n\n if (subcommand === \"emit\") {\n return runEmit(common, values.out, Boolean(values.standalone));\n }\n if (subcommand === \"manifest\") {\n return runManifest(common, values.out, Boolean(values[\"include-unavailable\"]));\n }\n if (subcommand === \"chat\") {\n return runChatCmd(common, values);\n }\n return runDispatchCmd(common, values, question);\n}\n\nfunction runEmit(common: CommonArgs, outArg: string | undefined, standalone: boolean): void {\n const prepared: PreparedDispatch = prepareDispatch({\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n });\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n const outPath = resolve(outArg ?? \"agent.ts\");\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, emitAgentModule(prepared, { standalone }), \"utf8\");\n process.stderr.write(\n `warble-agent-sdk: emit — wrote ${outPath} (${prepared.components.length} component(s), ${standalone ? \"standalone\" : \"thin\"}).\\n`,\n );\n}\n\n/**\n * `manifest` — same preparation as `emit` (no `question`, `query()` never called), but instead of\n * freezing an importable agent module, serializes the display manifest (see `manifest.ts`) to stdout\n * or `--out`. Capability resolution summaries still go to stderr so stdout stays pure JSON.\n */\nfunction runManifest(common: CommonArgs, outArg: string | undefined, includeUnavailable: boolean): void {\n const input = {\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n } as const;\n const prepared = includeUnavailable ? prepareDisplayManifest(input) : prepareDispatch(input);\n for (const c of prepared.components) {\n if (\"report\" in c) printResolutionSummary(common.target, c.id, c.report);\n }\n\n const manifest = buildManifest(prepared, common.raw);\n const json = `${JSON.stringify(manifest, null, 2)}\\n`;\n\n if (outArg) {\n const outPath = resolve(outArg);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, json, \"utf8\");\n process.stderr.write(\n `warble-agent-sdk: manifest — wrote ${outPath} (${prepared.components.length} agent(s)).\\n`,\n );\n } else {\n process.stdout.write(json);\n }\n}\n\nasync function runDispatchCmd(\n common: CommonArgs,\n values: Record<string, string | boolean | undefined>,\n question: string | undefined,\n): Promise<void> {\n const dryRun = Boolean(values[\"dry-run\"]);\n if (!question && !dryRun) fail('missing \"<question>\" argument (or pass --dry-run)');\n\n const maxTurnsRaw = values[\"max-turns\"];\n const maxTurns = typeof maxTurnsRaw === \"string\" ? Number(maxTurnsRaw) : undefined;\n if (maxTurns !== undefined && !Number.isFinite(maxTurns)) fail(\"--max-turns must be a number\");\n\n const outDir = resolve((values.out as string) ?? \"./run\");\n const warbleBin = (values[\"warble-bin\"] as string) ?? defaultWarbleBin();\n const title = values.title as string | undefined;\n\n const prepared = prepareDispatch({\n ir: common.raw,\n question: question ?? \"\",\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n ...(maxTurns !== undefined ? { maxTurns } : {}),\n });\n\n mkdirSync(outDir, { recursive: true });\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n for (const c of prepared.components) {\n if (dryRun) {\n const planPath = join(outDir, `${c.node.verb}.plan.json`);\n writeFileSync(\n planPath,\n JSON.stringify({ prompt: c.plan.prompt, options: c.plan.options, meta: c.plan.meta }, null, 2) + \"\\n\",\n \"utf8\",\n );\n process.stderr.write(\n `warble-agent-sdk: dry-run — wrote plan ${planPath} (model=${c.plan.meta.model}, split=${c.plan.meta.split}, render=${c.plan.meta.render.kind}); query() not called.\\n`,\n );\n continue;\n }\n const result = await runDispatch(c.plan, { outDir, warbleBin, ...(title ? { title } : {}) });\n process.stderr.write(\n `warble-agent-sdk: ran '${c.node.verb}' → ${result.htmlPath ?? \"(no html)\"}; ` +\n `${result.denials.length} guardrail denial(s); trace at ${join(outDir, \"trace.json\")}\\n`,\n );\n }\n\n writeFileSync(\n join(outDir, \"capability-report.json\"),\n JSON.stringify(\n { target: common.target, components: prepared.components.map((c) => ({ id: c.id, capabilities: c.report })) },\n null,\n 2,\n ) + \"\\n\",\n \"utf8\",\n );\n}\n\n/**\n * `chat` — a multi-turn session (session.ts, G1) over ONE prepared component, reading questions from\n * stdin line-by-line. Each turn's answer is printed to stdout; the SDK session is resumed turn over\n * turn (`ChatSession` handles the `resume: session_id` plumbing). Manual/live use only — not exercised\n * by the offline test suite.\n *\n * `--stream-json` (opt-in): instead of printing the turn's plain final-answer text, stream one\n * `WarbleChatEvent` NDJSON line per event as the turn runs (via `session.ask`'s `onEvent`), followed\n * by a terminal `{\"t\":\"answer\",\"text\":…}` line. Without the flag, behavior is byte-for-byte unchanged\n * from before this option existed.\n */\nasync function runChatCmd(\n common: CommonArgs,\n values: Record<string, string | boolean | undefined>,\n): Promise<void> {\n const outDir = resolve((values.out as string) ?? \"./run\");\n const warbleBin = (values[\"warble-bin\"] as string) ?? defaultWarbleBin();\n const componentId = (values.component as string) ?? \"answer_query\";\n\n // Scoped to `componentId`: only its own required capabilities are resolved, so a *different*\n // component's unmet requirements (e.g. a sibling gated-tool with no approval channel wired on\n // this target) can never block dispatching this one. See `DispatchInput.componentId`.\n const prepared = prepareDispatch({\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n componentId,\n ...(common.project !== undefined ? { project: common.project } : {}),\n });\n\n // `prepareDispatch` with `componentId` set either returns exactly this one component or throws\n // (caught by `main().catch()` below) — this is a defensive invariant check, not a reachable\n // \"not found\" path; that path's error text now comes from `prepareDispatch` itself.\n const component = prepared.components[0];\n if (!component) fail(`internal error: no component prepared for '${componentId}'`);\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n mkdirSync(outDir, { recursive: true });\n const resumeSessionId = values.resume as string | undefined;\n const session = createChatSession(component.plan, { outDir, warbleBin }, resumeSessionId);\n\n process.stderr.write(\n `warble-agent-sdk: chat — component '${componentId}'; type a question per line (Ctrl-D to end).\\n`,\n );\n\n const streamJson = Boolean(values[\"stream-json\"]);\n const onEvent = streamJson\n ? (event: WarbleChatEvent): void => {\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n }\n : undefined;\n\n const emitSession = (id: string | null): void => {\n if (!streamJson) return;\n const sessionEvent: WarbleChatEvent = { t: \"session\", id };\n process.stdout.write(`${JSON.stringify(sessionEvent)}\\n`);\n };\n\n const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });\n for await (const line of rl) {\n const question = line.trim();\n if (!question) continue;\n let turn;\n try {\n turn = await session.ask(question, onEvent ? { onEvent } : {});\n } catch (err) {\n // A failed turn (e.g. error_max_turns) still surfaces its session id, when the SDK's result\n // message carried one, so a caller can resume this same conversation instead of starting over.\n emitSession(err instanceof DispatchSessionError ? err.sessionId : null);\n throw err;\n }\n emitSession(turn.sessionId);\n if (streamJson) {\n const answerEvent: WarbleChatEvent = { t: \"answer\", text: turn.finalText };\n process.stdout.write(`${JSON.stringify(answerEvent)}\\n`);\n } else {\n process.stdout.write(`${turn.finalText}\\n`);\n }\n }\n}\n\nmain().catch((e: unknown) => {\n if (e instanceof DispatchError) fail(e.message);\n fail(e instanceof Error ? (e.stack ?? e.message) : String(e));\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAyCA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,qBAAqB;AAC9B,SAAS,SAAS,MAAM,eAAe;AACvC,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAe9B,SAAS,KAAK,SAAwB;AACpC,UAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,QACJ;AAQF,IAAM,kBAAkB,cAAc,YAAY,GAAG;AAErD,SAAS,iBAAyB;AAChC,SAAQ,gBAAgB,iBAAiB,EAA0B;AACrE;AAGA,SAAS,mBAA2B;AAClC,QAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;AACnD,QAAM,YAAY,QAAQ,MAAM,gCAAgC;AAChE,SAAO,WAAW,SAAS,IAAI,YAAY;AAC7C;AAEA,SAAS,uBAAuB,QAAgB,IAAY,QAAgC;AAC1F,UAAQ,OAAO,MAAM,gDAAgD,MAAM,iBAAiB,EAAE;AAAA,CAAO;AACrG,aAAW,KAAK,QAAQ;AACtB,UAAM,OAAO,EAAE,OAAO,WAAM,EAAE,IAAI,KAAK;AACvC,YAAQ,OAAO;AAAA,MACb,KAAK,EAAE,WAAW,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,EAAE,WAAW,IAAI,IAAI;AAAA;AAAA,IAClG;AAAA,EACF;AACF;AAWA,SAAS,YAAY,QAAmE;AACtF,QAAM,UAAU,OAAO,eAAe;AACtC,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,YAAY,SAAS,aAAa,QAAQ,OAAO,GAAG,MAAM,CAAC;AAAA,EACpE;AACA,SAAO,YAAY;AAAA,IAChB,OAAO,UAAqB;AAAA,IAC5B,OAAO,SAAoB;AAAA,IAC3B,OAAO,gBAA2B;AAAA,EACrC;AACF;AAEA,eAAe,OAAsB;AAInC,QAAM,WAAW,QAAQ,KAAK,CAAC;AAC/B,MAAI,aAAa,eAAe,aAAa,MAAM;AACjD,YAAQ,OAAO,MAAM,GAAG,eAAe,CAAC;AAAA,CAAI;AAC5C;AAAA,EACF;AACA,MAAI,aAAa,YAAY,aAAa,MAAM;AAC9C,YAAQ,OAAO,MAAM,GAAG,KAAK;AAAA,CAAI;AACjC;AAAA,EACF;AAEA,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,IACxC,kBAAkB;AAAA,IAClB,SAAS;AAAA,MACP,QAAQ,EAAE,MAAM,SAAS;AAAA,MACzB,KAAK,EAAE,MAAM,SAAS;AAAA,MACtB,iBAAiB,EAAE,MAAM,SAAS;AAAA,MAClC,iBAAiB,EAAE,MAAM,SAAS;AAAA,MAClC,QAAQ,EAAE,MAAM,SAAS;AAAA,MACzB,OAAO,EAAE,MAAM,SAAS;AAAA,MACxB,cAAc,EAAE,MAAM,SAAS;AAAA,MAC/B,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,cAAc,EAAE,MAAM,SAAS;AAAA,MAC/B,aAAa,EAAE,MAAM,SAAS;AAAA,MAC9B,OAAO,EAAE,MAAM,SAAS;AAAA,MACxB,WAAW,EAAE,MAAM,UAAU;AAAA,MAC7B,YAAY,EAAE,MAAM,UAAU;AAAA,MAC9B,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5B,eAAe,EAAE,MAAM,UAAU;AAAA,MACjC,QAAQ,EAAE,MAAM,SAAS;AAAA,MACzB,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,uBAAuB,EAAE,MAAM,UAAU;AAAA,IAC3C;AAAA,EACF,CAAC;AAED,QAAM,CAAC,YAAY,OAAO,QAAQ,IAAI;AACtC,MACE,eAAe,cACf,eAAe,UACf,eAAe,cACf,eAAe,UACf,eAAe,eACf;AACA,SAAK,KAAK;AAAA,EACZ;AACA,MAAI,eAAe,eAAe;AAChC,QAAI,UAAU,UAAa,aAAa,OAAW,MAAK,oDAAoD;AAC5G,UAAM,UAAU,OAAO,YAAY,SAAY,SAAY,OAAO,OAAO,OAAO;AAChF,QAAI,YAAY,WAAc,CAAC,OAAO,SAAS,OAAO,KAAK,WAAW,GAAI,MAAK,qCAAqC;AACpH,UAAM,UAAU,MAAM,qBAAqB;AAAA,MACzC,GAAI,OAAO,UAAU,EAAE,KAAK,OAAO,QAAQ,IAAI,CAAC;AAAA,MAChD,GAAI,YAAY,SAAY,EAAE,WAAW,QAAQ,IAAI,CAAC;AAAA,IACxD,CAAC;AACD,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,OAAO,CAAC;AAAA,CAAI;AACnD;AAAA,EACF;AACA,MAAI,OAAO,YAAY,OAAW,MAAK,4CAA4C;AACnF,MAAI,OAAO,qBAAqB,KAAK,eAAe,WAAY,MAAK,qDAAqD;AAC1H,MAAI,CAAC,MAAO,MAAK,4BAA4B;AAE7C,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,SAAS,kBAAkB,OAAO,eAAe,KAAK,cAAc;AAC1E,QAAM,SAAS,YAAY,MAAM;AACjC,QAAM,MAAM,aAAa,QAAQ,KAAK,GAAG,MAAM;AAE/C,QAAM,SAAqB,EAAE,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,OAAO,SAAS,OAAO,QAAQ;AAEjG,MAAI,eAAe,QAAQ;AACzB,WAAO,QAAQ,QAAQ,OAAO,KAAK,QAAQ,OAAO,UAAU,CAAC;AAAA,EAC/D;AACA,MAAI,eAAe,YAAY;AAC7B,WAAO,YAAY,QAAQ,OAAO,KAAK,QAAQ,OAAO,qBAAqB,CAAC,CAAC;AAAA,EAC/E;AACA,MAAI,eAAe,QAAQ;AACzB,WAAO,WAAW,QAAQ,MAAM;AAAA,EAClC;AACA,SAAO,eAAe,QAAQ,QAAQ,QAAQ;AAChD;AAEA,SAAS,QAAQ,QAAoB,QAA4B,YAA2B;AAC1F,QAAM,WAA6B,gBAAgB;AAAA,IACjD,IAAI,OAAO;AAAA,IACX,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,EACpE,CAAC;AACD,aAAW,KAAK,SAAS,WAAY,wBAAuB,OAAO,QAAQ,EAAE,IAAI,EAAE,MAAM;AAEzF,QAAM,UAAU,QAAQ,UAAU,UAAU;AAC5C,YAAU,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C,gBAAc,SAAS,gBAAgB,UAAU,EAAE,WAAW,CAAC,GAAG,MAAM;AACxE,UAAQ,OAAO;AAAA,IACb,uCAAkC,OAAO,KAAK,SAAS,WAAW,MAAM,kBAAkB,aAAa,eAAe,MAAM;AAAA;AAAA,EAC9H;AACF;AAOA,SAAS,YAAY,QAAoB,QAA4B,oBAAmC;AACtG,QAAM,QAAQ;AAAA,IACZ,IAAI,OAAO;AAAA,IACX,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,EACpE;AACA,QAAM,WAAW,qBAAqB,uBAAuB,KAAK,IAAI,gBAAgB,KAAK;AAC3F,aAAW,KAAK,SAAS,YAAY;AACnC,QAAI,YAAY,EAAG,wBAAuB,OAAO,QAAQ,EAAE,IAAI,EAAE,MAAM;AAAA,EACzE;AAEA,QAAM,WAAW,cAAc,UAAU,OAAO,GAAG;AACnD,QAAM,OAAO,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA;AAEjD,MAAI,QAAQ;AACV,UAAM,UAAU,QAAQ,MAAM;AAC9B,cAAU,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C,kBAAc,SAAS,MAAM,MAAM;AACnC,YAAQ,OAAO;AAAA,MACb,2CAAsC,OAAO,KAAK,SAAS,WAAW,MAAM;AAAA;AAAA,IAC9E;AAAA,EACF,OAAO;AACL,YAAQ,OAAO,MAAM,IAAI;AAAA,EAC3B;AACF;AAEA,eAAe,eACb,QACA,QACA,UACe;AACf,QAAM,SAAS,QAAQ,OAAO,SAAS,CAAC;AACxC,MAAI,CAAC,YAAY,CAAC,OAAQ,MAAK,mDAAmD;AAElF,QAAM,cAAc,OAAO,WAAW;AACtC,QAAM,WAAW,OAAO,gBAAgB,WAAW,OAAO,WAAW,IAAI;AACzE,MAAI,aAAa,UAAa,CAAC,OAAO,SAAS,QAAQ,EAAG,MAAK,8BAA8B;AAE7F,QAAM,SAAS,QAAS,OAAO,OAAkB,OAAO;AACxD,QAAM,YAAa,OAAO,YAAY,KAAgB,iBAAiB;AACvE,QAAM,QAAQ,OAAO;AAErB,QAAM,WAAW,gBAAgB;AAAA,IAC/B,IAAI,OAAO;AAAA,IACX,UAAU,YAAY;AAAA,IACtB,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IAClE,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,EAC/C,CAAC;AAED,YAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,aAAW,KAAK,SAAS,WAAY,wBAAuB,OAAO,QAAQ,EAAE,IAAI,EAAE,MAAM;AAEzF,aAAW,KAAK,SAAS,YAAY;AACnC,QAAI,QAAQ;AACV,YAAM,WAAW,KAAK,QAAQ,GAAG,EAAE,KAAK,IAAI,YAAY;AACxD;AAAA,QACE;AAAA,QACA,KAAK,UAAU,EAAE,QAAQ,EAAE,KAAK,QAAQ,SAAS,EAAE,KAAK,SAAS,MAAM,EAAE,KAAK,KAAK,GAAG,MAAM,CAAC,IAAI;AAAA,QACjG;AAAA,MACF;AACA,cAAQ,OAAO;AAAA,QACb,+CAA0C,QAAQ,WAAW,EAAE,KAAK,KAAK,KAAK,WAAW,EAAE,KAAK,KAAK,KAAK,YAAY,EAAE,KAAK,KAAK,OAAO,IAAI;AAAA;AAAA,MAC/I;AACA;AAAA,IACF;AACA,UAAM,SAAS,MAAM,YAAY,EAAE,MAAM,EAAE,QAAQ,WAAW,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,EAAG,CAAC;AAC3F,YAAQ,OAAO;AAAA,MACb,0BAA0B,EAAE,KAAK,IAAI,YAAO,OAAO,YAAY,WAAW,KACrE,OAAO,QAAQ,MAAM,kCAAkC,KAAK,QAAQ,YAAY,CAAC;AAAA;AAAA,IACxF;AAAA,EACF;AAEA;AAAA,IACE,KAAK,QAAQ,wBAAwB;AAAA,IACrC,KAAK;AAAA,MACH,EAAE,QAAQ,OAAO,QAAQ,YAAY,SAAS,WAAW,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,cAAc,EAAE,OAAO,EAAE,EAAE;AAAA,MAC5G;AAAA,MACA;AAAA,IACF,IAAI;AAAA,IACJ;AAAA,EACF;AACF;AAaA,eAAe,WACb,QACA,QACe;AACf,QAAM,SAAS,QAAS,OAAO,OAAkB,OAAO;AACxD,QAAM,YAAa,OAAO,YAAY,KAAgB,iBAAiB;AACvE,QAAM,cAAe,OAAO,aAAwB;AAKpD,QAAM,WAAW,gBAAgB;AAAA,IAC/B,IAAI,OAAO;AAAA,IACX,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf;AAAA,IACA,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,EACpE,CAAC;AAKD,QAAM,YAAY,SAAS,WAAW,CAAC;AACvC,MAAI,CAAC,UAAW,MAAK,8CAA8C,WAAW,GAAG;AACjF,aAAW,KAAK,SAAS,WAAY,wBAAuB,OAAO,QAAQ,EAAE,IAAI,EAAE,MAAM;AAEzF,YAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,QAAM,kBAAkB,OAAO;AAC/B,QAAM,UAAU,kBAAkB,UAAU,MAAM,EAAE,QAAQ,UAAU,GAAG,eAAe;AAExF,UAAQ,OAAO;AAAA,IACb,4CAAuC,WAAW;AAAA;AAAA,EACpD;AAEA,QAAM,aAAa,QAAQ,OAAO,aAAa,CAAC;AAChD,QAAM,UAAU,aACZ,CAAC,UAAiC;AAChC,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,CAAI;AAAA,EACnD,IACA;AAEJ,QAAM,cAAc,CAAC,OAA4B;AAC/C,QAAI,CAAC,WAAY;AACjB,UAAM,eAAgC,EAAE,GAAG,WAAW,GAAG;AACzD,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,YAAY,CAAC;AAAA,CAAI;AAAA,EAC1D;AAEA,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,WAAW,SAAS,CAAC;AACxE,mBAAiB,QAAQ,IAAI;AAC3B,UAAM,WAAW,KAAK,KAAK;AAC3B,QAAI,CAAC,SAAU;AACf,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,QAAQ,IAAI,UAAU,UAAU,EAAE,QAAQ,IAAI,CAAC,CAAC;AAAA,IAC/D,SAAS,KAAK;AAGZ,kBAAY,eAAe,uBAAuB,IAAI,YAAY,IAAI;AACtE,YAAM;AAAA,IACR;AACA,gBAAY,KAAK,SAAS;AAC1B,QAAI,YAAY;AACd,YAAM,cAA+B,EAAE,GAAG,UAAU,MAAM,KAAK,UAAU;AACzE,cAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,WAAW,CAAC;AAAA,CAAI;AAAA,IACzD,OAAO;AACL,cAAQ,OAAO,MAAM,GAAG,KAAK,SAAS;AAAA,CAAI;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,MAAe;AAC3B,MAAI,aAAa,cAAe,MAAK,EAAE,OAAO;AAC9C,OAAK,aAAa,QAAS,EAAE,SAAS,EAAE,UAAW,OAAO,CAAC,CAAC;AAC9D,CAAC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `warble-agent-sdk` — the Claude Agent SDK back-end CLI.\n *\n * warble-agent-sdk dispatch <ir.json> \"<question>\" [--target …] [--models-config m.yml]\n * [--render-flavor programmatic|prompt] [--out ./run] [--project <dir>]\n * [--strong opus] [--cheap haiku] [--orchestrator sonnet]\n * [--warble-bin <path>] [--max-turns N] [--title <t>] [--dry-run]\n *\n * warble-agent-sdk emit <ir.json> [--out agent.ts] [--standalone] [--target …] [--models-config …]\n * [--render-flavor …] [--project <dir>] [--strong/--cheap/--orchestrator …]\n *\n * warble-agent-sdk manifest <ir.json> [--include-unavailable] [--out manifest.json] [--target …] [--models-config …]\n * [--render-flavor …] [--project <dir>] [--strong/--cheap/--orchestrator …]\n *\n * warble-agent-sdk chat <ir.json> [--project <dir>] [--component answer_query] [--out ./run]\n * [--target …] [--models-config m.yml] [--render-flavor programmatic|prompt] [--warble-bin <path>]\n * [--stream-json] [--resume <session-id>]\n *\n * `--slot NAME=VARIANT` fills a named prompt slot with that variant; `--slot NAME=` removes a slot\n * whose condition does not hold. Repeatable, accepted by every subcommand, and mirroring the `warble`\n * CLI's flag of the same name. A slot nobody names takes its declared default — except one carrying\n * a `present_when` condition, which is refused when unanswered on any path whose text reaches a\n * model, because shipping wording for something that may have been withheld is worse than shipping\n * none. `manifest` is a display and renders such a default instead of refusing.\n *\n * `chat --stream-json` emits per-step/per-tool NDJSON events (one `WarbleChatEvent`, events.ts, per\n * line) to stdout as each turn runs, ending with a terminal `{\"t\":\"answer\",\"text\":…}` line, instead of\n * the default plain final-answer-text-per-turn output — for a consumer that wants to build a live,\n * expandable work log rather than just the finished text. Every turn also emits a\n * `{\"t\":\"session\",\"id\":…}` line (on success AND on a failed turn) carrying that turn's SDK session id.\n *\n * `--resume <session-id>` seeds a brand-new `chat` process's FIRST turn with a session id captured by\n * an earlier `chat` process (from its `{\"t\":\"session\",…}` line) — lets a caller resume a conversation\n * that a previous process started (e.g. one that ran out of turns), continuing the real SDK\n * conversation instead of re-dispatching a fresh prompt from scratch. Ignored after the first turn:\n * subsequent turns resume from this process's own prior turn, as usual.\n *\n * `dispatch` consumes the SAME `ir.json` a Rust `warble compile` emits and drives the SDK loop\n * in-process (`--dry-run` writes the assembled plan without calling `query()`). `emit` freezes the\n * resolved plan into an importable TS agent module (thin, or `--standalone`). `manifest` runs the\n * same preparation as `emit` (no `question`, no `query()` call) and instead serializes a display\n * manifest — the resolved agents/steps/tiers/capabilities/guardrails for THIS target, structurally\n * identical to the vercel back-end's bundle — so a consumer can source a display from whichever\n * back-end actually runs, instead of always reading the vercel bundle target's output. `chat` opens a\n * multi-turn session (session.ts, G1 — single profile, many turns) over one component, reading\n * questions from stdin line-by-line and resuming the SDK session turn over turn.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { parseArgs } from \"node:util\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { emitAgentModule } from \"./codegen.js\";\nimport { prepareDisplayManifest, prepareDispatch, type PreparedDispatch } from \"./dispatch.js\";\nimport { parseSlotFlags } from \"./slots.js\";\nimport type { SlotSupply } from \"./slots.js\";\nimport { DispatchError } from \"./error.js\";\nimport type { WarbleChatEvent } from \"./events.js\";\nimport { buildManifest } from \"./manifest.js\";\nimport { ModelConfig } from \"./models.js\";\nimport { discoverClaudeModels } from \"./model_catalog.js\";\nimport { parseRenderFlavor, type RenderFlavor } from \"./options.js\";\nimport { DispatchSessionError, runDispatch } from \"./run.js\";\nimport { createChatSession } from \"./session.js\";\nimport { type ResolutionReport } from \"./resolve.js\";\nimport { DEFAULT_TARGET } from \"./targets.js\";\n\n/** `parseSlotFlags` throws; this CLI reports a bad flag as a usage failure instead. */\nfunction parseSlotFlagsOrFail(flags: readonly string[]): SlotSupply {\n try {\n return parseSlotFlags(flags);\n } catch (e) {\n fail(e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`error: ${message}\\n`);\n process.exit(1);\n}\n\nconst USAGE =\n 'usage: warble-agent-sdk <dispatch|emit|manifest|chat> <ir.json> [\"<question>\"] [options]\\n' +\n \" warble-agent-sdk list-models [--project <dir>] [--timeout <ms>]\";\n\n// `require(\"../package.json\")` resolves relative to *this* file's own location, one directory up —\n// which is the package root in both the dev tree (src/cli.ts → ../package.json) and the published\n// layout (dist/cli.js → ../package.json; package.json ships in every npm package regardless of the\n// \"files\" allowlist). That keeps the reported version tied to the package's real `version` field\n// instead of a literal that could drift from it.\nconst requireFromHere = createRequire(import.meta.url);\n\nfunction packageVersion(): string {\n return (requireFromHere(\"../package.json\") as { version: string }).version;\n}\n\n/** Locate the reference `warble` binary: --warble-bin, else PATH, else this repo's release build. */\nfunction defaultWarbleBin(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n const repoBuilt = resolve(here, \"../../../target/release/warble\");\n return existsSync(repoBuilt) ? repoBuilt : \"warble\";\n}\n\nfunction printResolutionSummary(target: string, id: string, report: ResolutionReport): void {\n process.stderr.write(`warble-agent-sdk: capability resolution for '${target}' (component '${id}'):\\n`);\n for (const e of report) {\n const note = e.note ? ` — ${e.note}` : \"\";\n process.stderr.write(\n ` ${e.capability.padEnd(28)} ${e.outcome.padEnd(12)} (${e.provided_by}, ${e.criticality})${note}\\n`,\n );\n }\n}\n\ninterface CommonArgs {\n target: string;\n flavor: RenderFlavor;\n models: ModelConfig;\n raw: string;\n irPath: string;\n project: string | undefined;\n /** The host's slot table, from `--slot`. Empty when none was given. */\n slots: SlotSupply;\n}\n\nfunction buildModels(values: Record<string, string | string[] | boolean | undefined>): ModelConfig {\n const cfgPath = values[\"models-config\"];\n if (typeof cfgPath === \"string\") {\n return ModelConfig.fromYaml(readFileSync(resolve(cfgPath), \"utf8\"));\n }\n return ModelConfig.fromFlags(\n (values.strong as string) ?? \"opus\",\n (values.cheap as string) ?? \"haiku\",\n (values.orchestrator as string) ?? \"sonnet\",\n );\n}\n\nasync function main(): Promise<void> {\n // Handle `--version`/`-V` and `--help`/`-h` up front, before the strict `parseArgs` below —\n // neither is a declared option there, so leaving them for `parseArgs` to see would throw\n // `ERR_PARSE_ARGS_UNKNOWN_OPTION` instead of doing what every other CLI does with them.\n const firstArg = process.argv[2];\n if (firstArg === \"--version\" || firstArg === \"-V\") {\n process.stdout.write(`${packageVersion()}\\n`);\n return;\n }\n if (firstArg === \"--help\" || firstArg === \"-h\") {\n process.stdout.write(`${USAGE}\\n`);\n return;\n }\n\n const { values, positionals } = parseArgs({\n allowPositionals: true,\n options: {\n target: { type: \"string\" },\n out: { type: \"string\" },\n \"models-config\": { type: \"string\" },\n \"render-flavor\": { type: \"string\" },\n strong: { type: \"string\" },\n cheap: { type: \"string\" },\n orchestrator: { type: \"string\" },\n project: { type: \"string\" },\n \"warble-bin\": { type: \"string\" },\n \"max-turns\": { type: \"string\" },\n title: { type: \"string\" },\n \"dry-run\": { type: \"boolean\" },\n standalone: { type: \"boolean\" },\n component: { type: \"string\" },\n \"stream-json\": { type: \"boolean\" },\n resume: { type: \"string\" },\n timeout: { type: \"string\" },\n \"include-unavailable\": { type: \"boolean\" },\n slot: { type: \"string\", multiple: true },\n },\n });\n\n\n\n const [subcommand, irArg, question] = positionals;\n if (\n subcommand !== \"dispatch\" &&\n subcommand !== \"emit\" &&\n subcommand !== \"manifest\" &&\n subcommand !== \"chat\" &&\n subcommand !== \"list-models\"\n ) {\n fail(USAGE);\n }\n if (subcommand === \"list-models\") {\n if (irArg !== undefined || question !== undefined) fail(\"list-models does not take an <ir.json> or question\");\n const timeout = values.timeout === undefined ? undefined : Number(values.timeout);\n if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) fail(\"--timeout must be a positive number\");\n const catalog = await discoverClaudeModels({\n ...(values.project ? { cwd: values.project } : {}),\n ...(timeout !== undefined ? { timeoutMs: timeout } : {}),\n });\n process.stdout.write(`${JSON.stringify(catalog)}\\n`);\n return;\n }\n if (values.timeout !== undefined) fail(\"--timeout is only supported by list-models\");\n if (values[\"include-unavailable\"] && subcommand !== \"manifest\") fail(\"--include-unavailable is only supported by manifest\");\n if (!irArg) fail(\"missing <ir.json> argument\");\n\n const target = values.target ?? DEFAULT_TARGET;\n const flavor = parseRenderFlavor(values[\"render-flavor\"] ?? \"programmatic\");\n const models = buildModels(values);\n const raw = readFileSync(resolve(irArg), \"utf8\");\n\n // Parsed once and carried on CommonArgs, so every subcommand that builds prompts gets the same\n // table. Without this the seam would be reachable only by importing the library, and a profile\n // with a conditional slot could not be run through this CLI at all — it would always refuse for\n // want of an answer.\n const common: CommonArgs = {\n target,\n flavor,\n models,\n raw,\n irPath: irArg,\n project: values.project,\n slots: parseSlotFlagsOrFail(values.slot ?? []),\n };\n\n if (subcommand === \"emit\") {\n return runEmit(common, values.out, Boolean(values.standalone));\n }\n if (subcommand === \"manifest\") {\n return runManifest(common, values.out, Boolean(values[\"include-unavailable\"]));\n }\n if (subcommand === \"chat\") {\n return runChatCmd(common, values);\n }\n return runDispatchCmd(common, values, question);\n}\n\nfunction runEmit(common: CommonArgs, outArg: string | undefined, standalone: boolean): void {\n const prepared: PreparedDispatch = prepareDispatch({\n slots: common.slots,\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n });\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n const outPath = resolve(outArg ?? \"agent.ts\");\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, emitAgentModule(prepared, { standalone }), \"utf8\");\n process.stderr.write(\n `warble-agent-sdk: emit — wrote ${outPath} (${prepared.components.length} component(s), ${standalone ? \"standalone\" : \"thin\"}).\\n`,\n );\n}\n\n/**\n * `manifest` — same preparation as `emit` (no `question`, `query()` never called), but instead of\n * freezing an importable agent module, serializes the display manifest (see `manifest.ts`) to stdout\n * or `--out`. Capability resolution summaries still go to stderr so stdout stays pure JSON.\n */\nfunction runManifest(common: CommonArgs, outArg: string | undefined, includeUnavailable: boolean): void {\n const input = {\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n } as const;\n const prepared = includeUnavailable ? prepareDisplayManifest({ ...input, slots: common.slots }) : prepareDispatch({ ...input, slots: common.slots });\n for (const c of prepared.components) {\n if (\"report\" in c) printResolutionSummary(common.target, c.id, c.report);\n }\n\n const manifest = buildManifest(prepared, common.raw);\n const json = `${JSON.stringify(manifest, null, 2)}\\n`;\n\n if (outArg) {\n const outPath = resolve(outArg);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, json, \"utf8\");\n process.stderr.write(\n `warble-agent-sdk: manifest — wrote ${outPath} (${prepared.components.length} agent(s)).\\n`,\n );\n } else {\n process.stdout.write(json);\n }\n}\n\nasync function runDispatchCmd(\n common: CommonArgs,\n values: Record<string, string | string[] | boolean | undefined>,\n question: string | undefined,\n): Promise<void> {\n const dryRun = Boolean(values[\"dry-run\"]);\n if (!question && !dryRun) fail('missing \"<question>\" argument (or pass --dry-run)');\n\n const maxTurnsRaw = values[\"max-turns\"];\n const maxTurns = typeof maxTurnsRaw === \"string\" ? Number(maxTurnsRaw) : undefined;\n if (maxTurns !== undefined && !Number.isFinite(maxTurns)) fail(\"--max-turns must be a number\");\n\n const outDir = resolve((values.out as string) ?? \"./run\");\n const warbleBin = (values[\"warble-bin\"] as string) ?? defaultWarbleBin();\n const title = values.title as string | undefined;\n\n const prepared = prepareDispatch({\n slots: common.slots,\n ir: common.raw,\n question: question ?? \"\",\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n ...(maxTurns !== undefined ? { maxTurns } : {}),\n });\n\n mkdirSync(outDir, { recursive: true });\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n for (const c of prepared.components) {\n if (dryRun) {\n const planPath = join(outDir, `${c.node.verb}.plan.json`);\n writeFileSync(\n planPath,\n JSON.stringify({ prompt: c.plan.prompt, options: c.plan.options, meta: c.plan.meta }, null, 2) + \"\\n\",\n \"utf8\",\n );\n process.stderr.write(\n `warble-agent-sdk: dry-run — wrote plan ${planPath} (model=${c.plan.meta.model}, split=${c.plan.meta.split}, render=${c.plan.meta.render.kind}); query() not called.\\n`,\n );\n continue;\n }\n const result = await runDispatch(c.plan, { outDir, warbleBin, ...(title ? { title } : {}) });\n process.stderr.write(\n `warble-agent-sdk: ran '${c.node.verb}' → ${result.htmlPath ?? \"(no html)\"}; ` +\n `${result.denials.length} guardrail denial(s); trace at ${join(outDir, \"trace.json\")}\\n`,\n );\n }\n\n writeFileSync(\n join(outDir, \"capability-report.json\"),\n JSON.stringify(\n { target: common.target, components: prepared.components.map((c) => ({ id: c.id, capabilities: c.report })) },\n null,\n 2,\n ) + \"\\n\",\n \"utf8\",\n );\n}\n\n/**\n * `chat` — a multi-turn session (session.ts, G1) over ONE prepared component, reading questions from\n * stdin line-by-line. Each turn's answer is printed to stdout; the SDK session is resumed turn over\n * turn (`ChatSession` handles the `resume: session_id` plumbing). Manual/live use only — not exercised\n * by the offline test suite.\n *\n * `--stream-json` (opt-in): instead of printing the turn's plain final-answer text, stream one\n * `WarbleChatEvent` NDJSON line per event as the turn runs (via `session.ask`'s `onEvent`), followed\n * by a terminal `{\"t\":\"answer\",\"text\":…}` line. Without the flag, behavior is byte-for-byte unchanged\n * from before this option existed.\n */\nasync function runChatCmd(\n common: CommonArgs,\n values: Record<string, string | string[] | boolean | undefined>,\n): Promise<void> {\n const outDir = resolve((values.out as string) ?? \"./run\");\n const warbleBin = (values[\"warble-bin\"] as string) ?? defaultWarbleBin();\n const componentId = (values.component as string) ?? \"answer_query\";\n\n // Scoped to `componentId`: only its own required capabilities are resolved, so a *different*\n // component's unmet requirements (e.g. a sibling gated-tool with no approval channel wired on\n // this target) can never block dispatching this one. See `DispatchInput.componentId`.\n const prepared = prepareDispatch({\n slots: common.slots,\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n componentId,\n ...(common.project !== undefined ? { project: common.project } : {}),\n });\n\n // `prepareDispatch` with `componentId` set either returns exactly this one component or throws\n // (caught by `main().catch()` below) — this is a defensive invariant check, not a reachable\n // \"not found\" path; that path's error text now comes from `prepareDispatch` itself.\n const component = prepared.components[0];\n if (!component) fail(`internal error: no component prepared for '${componentId}'`);\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n mkdirSync(outDir, { recursive: true });\n const resumeSessionId = values.resume as string | undefined;\n const session = createChatSession(component.plan, { outDir, warbleBin }, resumeSessionId);\n\n process.stderr.write(\n `warble-agent-sdk: chat — component '${componentId}'; type a question per line (Ctrl-D to end).\\n`,\n );\n\n const streamJson = Boolean(values[\"stream-json\"]);\n const onEvent = streamJson\n ? (event: WarbleChatEvent): void => {\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n }\n : undefined;\n\n const emitSession = (id: string | null): void => {\n if (!streamJson) return;\n const sessionEvent: WarbleChatEvent = { t: \"session\", id };\n process.stdout.write(`${JSON.stringify(sessionEvent)}\\n`);\n };\n\n const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });\n for await (const line of rl) {\n const question = line.trim();\n if (!question) continue;\n let turn;\n try {\n turn = await session.ask(question, onEvent ? { onEvent } : {});\n } catch (err) {\n // A failed turn (e.g. error_max_turns) still surfaces its session id, when the SDK's result\n // message carried one, so a caller can resume this same conversation instead of starting over.\n emitSession(err instanceof DispatchSessionError ? err.sessionId : null);\n throw err;\n }\n emitSession(turn.sessionId);\n if (streamJson) {\n const answerEvent: WarbleChatEvent = { t: \"answer\", text: turn.finalText };\n process.stdout.write(`${JSON.stringify(answerEvent)}\\n`);\n } else {\n process.stdout.write(`${turn.finalText}\\n`);\n }\n }\n}\n\nmain().catch((e: unknown) => {\n if (e instanceof DispatchError) fail(e.message);\n fail(e instanceof Error ? (e.stack ?? e.message) : String(e));\n});\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -172,6 +172,21 @@ interface PreconditionResult {
|
|
|
172
172
|
status: string;
|
|
173
173
|
checks: PreconditionCheck[];
|
|
174
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* A named position in prompt text, with the alternative wordings that may fill it (IR 0.7).
|
|
177
|
+
*
|
|
178
|
+
* `default` always names one of `variants` — compile refuses otherwise — so a consumer that has no
|
|
179
|
+
* opinion still has something to render. `present_when` is carried but never evaluated here: the
|
|
180
|
+
* spec assigns that to the host, and this back-end only asks the host for the answer.
|
|
181
|
+
*/
|
|
182
|
+
interface SlotDecl {
|
|
183
|
+
name: string;
|
|
184
|
+
/** Always a key of `variants`. */
|
|
185
|
+
default: string;
|
|
186
|
+
variants: Record<string, string>;
|
|
187
|
+
/** Present only when the author declared a condition. Carried verbatim; not interpreted here. */
|
|
188
|
+
present_when?: unknown;
|
|
189
|
+
}
|
|
175
190
|
interface ComponentNode {
|
|
176
191
|
id: string;
|
|
177
192
|
verb: string;
|
|
@@ -193,6 +208,9 @@ interface ComponentNode {
|
|
|
193
208
|
eval: EvalSpec | null;
|
|
194
209
|
/** Optional free-form framing shared by every step of this component (see `docs/spec/ir-schema.md`). */
|
|
195
210
|
brief?: string;
|
|
211
|
+
/** Slots belonging to THIS component's own prompt text (its steps and `brief`). Profile-level
|
|
212
|
+
* slots live on the IR root instead and are deliberately not copied here. */
|
|
213
|
+
slots?: SlotDecl[];
|
|
196
214
|
}
|
|
197
215
|
interface WarbleIr {
|
|
198
216
|
warble_ir_version: string;
|
|
@@ -200,6 +218,10 @@ interface WarbleIr {
|
|
|
200
218
|
context_binding: ContextBinding;
|
|
201
219
|
config: IrConfig;
|
|
202
220
|
components: ComponentNode[];
|
|
221
|
+
/** Profile-level slots, belonging to the profile's `system_prompt`. Names are unique across the
|
|
222
|
+
* whole project — compile refuses a collision with any component's — so a consumer resolves
|
|
223
|
+
* `{{ slot.<name> }}` against one flat namespace rather than a per-layer precedence rule. */
|
|
224
|
+
slots?: SlotDecl[];
|
|
203
225
|
}
|
|
204
226
|
/**
|
|
205
227
|
* IR versions this back-end understands. Older versions (0.1, 0.2) are no longer accepted now that
|
|
@@ -427,11 +449,11 @@ interface StepMessage {
|
|
|
427
449
|
}
|
|
428
450
|
/**
|
|
429
451
|
* Build the messages for one staged step: the step's own prompt as the system message, and the user
|
|
430
|
-
* message = the question plus each consumed
|
|
452
|
+
* message = the question plus each consumed artifact's value marshaled in by name (the `produces`→`consumes`
|
|
431
453
|
* hand-off). This is the same isolated-invocation contract the IR already carries for the file target's
|
|
432
454
|
* subagents (ir.ts `consumes`/`produces`), generalized here across providers.
|
|
433
455
|
*/
|
|
434
|
-
declare function buildStepMessages(step: StagedStep, question: string,
|
|
456
|
+
declare function buildStepMessages(step: StagedStep, question: string, artifacts: Readonly<Record<string, string>>): StepMessage[];
|
|
435
457
|
|
|
436
458
|
/**
|
|
437
459
|
* Minimal OpenAI-compatible chat client for the hybrid-staged path (see docs/spec/capability-model.md §7.2).
|
|
@@ -573,6 +595,9 @@ interface BuildConfig {
|
|
|
573
595
|
/**
|
|
574
596
|
* Build the `query({options})` for one resolved IR node. Loud-fails on any unsupported enum value
|
|
575
597
|
* before producing anything (wall-hit), mirroring `emit.rs`.
|
|
598
|
+
*
|
|
599
|
+
* The assembled prompts are checked for surviving slot references on the way out — see
|
|
600
|
+
* {@link assertPlanHasNoSlotReferences} for why that check lives here and not only at resolution.
|
|
576
601
|
*/
|
|
577
602
|
declare function buildDispatchPlan(node: ComponentNode, report: ResolutionReport, cfg: BuildConfig): DispatchPlan;
|
|
578
603
|
|
|
@@ -635,6 +660,97 @@ type WarbleChatEvent = {
|
|
|
635
660
|
readonly id: string | null;
|
|
636
661
|
};
|
|
637
662
|
|
|
663
|
+
/** Hash algorithm named in the output so a stored fingerprint stays readable if this ever changes. */
|
|
664
|
+
declare const ALGORITHM = "sha256";
|
|
665
|
+
/**
|
|
666
|
+
* One digest per surface, plus the total.
|
|
667
|
+
*
|
|
668
|
+
* **Per surface as well as in total, on purpose.** The total answers "did anything change"; only the
|
|
669
|
+
* per-surface digests answer "which prompt changed", and that is the question a trace disagreeing
|
|
670
|
+
* with its own hash actually raises. The cost is a few dozen bytes per run.
|
|
671
|
+
*/
|
|
672
|
+
interface PromptFingerprint {
|
|
673
|
+
algorithm: typeof ALGORITHM;
|
|
674
|
+
/** Digest over every surface: name-sorted, with each name hashed alongside its text. */
|
|
675
|
+
digest: string;
|
|
676
|
+
/** Per-surface digest, keyed by a stable surface name. */
|
|
677
|
+
surfaces: Record<string, string>;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Fingerprint an arbitrary surface map. The core; both helpers below funnel through it.
|
|
681
|
+
*
|
|
682
|
+
* The total digest hashes each surface's **name and text together**, name-sorted. Including the name
|
|
683
|
+
* is what stops two different arrangements of the same strings — a prompt moved from one subagent to
|
|
684
|
+
* another, say — from colliding; sorting is what makes the result independent of key order.
|
|
685
|
+
*/
|
|
686
|
+
declare function fingerprintSurfaces(surfaces: Record<string, string>): PromptFingerprint;
|
|
687
|
+
/**
|
|
688
|
+
* The prompt surfaces of the `query()` options a host is about to send.
|
|
689
|
+
*
|
|
690
|
+
* **This is the primitive, not {@link promptSurfaces}.** A host may assemble its own options from a
|
|
691
|
+
* plan rather than sending the plan's verbatim — the BIRD-Interact adapter does exactly that,
|
|
692
|
+
* replacing the system prompt with the component's `prompt_fragment` — and fingerprinting the plan
|
|
693
|
+
* in that case would record something other than what was sent. A fingerprint describing a prompt
|
|
694
|
+
* nobody received is worse than no fingerprint, because it reads as evidence.
|
|
695
|
+
*
|
|
696
|
+
* So take it as late as possible: over the options that actually reach `query()`.
|
|
697
|
+
*/
|
|
698
|
+
declare function promptSurfacesOf(options: Options): Record<string, string>;
|
|
699
|
+
/**
|
|
700
|
+
* The prompt surfaces a plan **itself** determines — what the single and split paths send verbatim.
|
|
701
|
+
*
|
|
702
|
+
* Surfaces are **named, not positional**, so a plan that gains or loses a subagent changes which
|
|
703
|
+
* keys exist rather than silently shifting every digest after the insertion point.
|
|
704
|
+
*
|
|
705
|
+
* **What this deliberately does NOT cover, and why it would be wrong to.** A staged step is not sent
|
|
706
|
+
* as its `prompt`: the executor prepends a runtime preamble built from the working directory, and
|
|
707
|
+
* the hybrid-tool path sends a driver prompt it composes from the step list, which appears nowhere in
|
|
708
|
+
* the plan's options. Recording a `step.<name>` digest of the bare `prompt` here would produce a
|
|
709
|
+
* fingerprint that does not match the bytes sent — the exact failure this module's header calls worse
|
|
710
|
+
* than no fingerprint, because it reads as evidence. Reproducing the assembly here instead would
|
|
711
|
+
* duplicate it and drift.
|
|
712
|
+
*
|
|
713
|
+
* So those paths are fingerprinted where the bytes exist: `runDispatch` reports one fingerprint per
|
|
714
|
+
* turn it sends, through `RunConfig.onPromptFingerprint`. Use that for anything staged or hybrid; use
|
|
715
|
+
* this for a plan whose options go out as built.
|
|
716
|
+
*
|
|
717
|
+
* One surface that looks missing and is not: on the single-tier (collapse) path a component's
|
|
718
|
+
* `prompt_fragment` is folded into `systemPrompt`, and `llm_calls[].prompt` is not read at all. So a
|
|
719
|
+
* one-step component's step text is covered through the driver surface rather than a step surface.
|
|
720
|
+
*/
|
|
721
|
+
declare function promptSurfaces(plan: DispatchPlan): Record<string, string>;
|
|
722
|
+
/** Fingerprint the prompts a plan assembled. See {@link promptSurfaces} on when this is the wrong one. */
|
|
723
|
+
declare function fingerprintPrompts(plan: DispatchPlan): PromptFingerprint;
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Compose an embedding host's `canUseTool` with a guardrail floor's, so a host can add its own
|
|
727
|
+
* enforcement instead of having to choose between the two. Without this an embedder's callback is
|
|
728
|
+
* silently replaced, which is the same failure whichever way round it happens.
|
|
729
|
+
*
|
|
730
|
+
* **The order is load-bearing: the embedder runs first, the floor runs last.** A `canUseTool` may
|
|
731
|
+
* rewrite a tool's input on the way through (`updatedInput`), so a floor that ran first would be
|
|
732
|
+
* inspecting an input the embedder could still change afterwards — the floor has to see what the
|
|
733
|
+
* tool will actually receive. Running it last is what makes composition one-directional: either side
|
|
734
|
+
* may deny, neither can turn the other's denial into an allow, and an allowed input has passed
|
|
735
|
+
* through both.
|
|
736
|
+
*
|
|
737
|
+
* An embedder denial returns immediately without consulting the floor, so the floor's `denials`
|
|
738
|
+
* ledger stays a record of guardrail enforcement rather than a mixed log of both parties.
|
|
739
|
+
*
|
|
740
|
+
* With no embedder callback the floor's own callback is returned unchanged, so a run without an
|
|
741
|
+
* embedder behaves exactly as it did before this seam existed.
|
|
742
|
+
*/
|
|
743
|
+
declare function composeCanUseTool(embedder: CanUseTool | undefined, floor: CanUseTool): CanUseTool;
|
|
744
|
+
/**
|
|
745
|
+
* Merge an embedding host's `hooks` with a guardrail's `PreToolUse` matchers, appending the
|
|
746
|
+
* guardrail's so the host's run first and neither set is dropped.
|
|
747
|
+
*
|
|
748
|
+
* This is the shape the main dispatch path already used inline; it is extracted here so the staged
|
|
749
|
+
* and hybrid-tool paths can stop discarding the host's hooks, and so there is one place to read
|
|
750
|
+
* rather than three to keep in step. `PreToolUse` is a separate control path from `canUseTool` (see
|
|
751
|
+
* `makeSetupReadDenyHook` below for the empirical note), which is why both have to compose.
|
|
752
|
+
*/
|
|
753
|
+
declare function composeHooks(embedder: Options["hooks"], guardHooks: HookCallbackMatcher[]): Options["hooks"];
|
|
638
754
|
/** A blocked tool call, recorded so the trace/report can prove enforcement actually fired. */
|
|
639
755
|
interface Denial {
|
|
640
756
|
tool: string;
|
|
@@ -757,6 +873,19 @@ interface RunConfig {
|
|
|
757
873
|
* message stream is consumed, not batched after the fact. Only wired on the main (single/split) SDK
|
|
758
874
|
* loop below — the hybrid-staged executor passes through with no events. */
|
|
759
875
|
onEvent?: (event: WarbleChatEvent) => void;
|
|
876
|
+
/**
|
|
877
|
+
* Called once per turn this run sends, with a fingerprint of the prompts THAT turn carried.
|
|
878
|
+
*
|
|
879
|
+
* Reported here rather than derived from the plan because the staged and hybrid paths do not send
|
|
880
|
+
* the plan's text as built: a step's options carry a runtime preamble ahead of its prompt, and the
|
|
881
|
+
* hybrid-tool driver composes a prompt that appears nowhere in the plan. A plan-derived digest
|
|
882
|
+
* would name bytes that were never sent, which is worse than none — it reads as evidence.
|
|
883
|
+
*
|
|
884
|
+
* Several turns therefore report several fingerprints. A consumer that wants one value per run
|
|
885
|
+
* should deduplicate by digest: one entry means the prompts held steady, more than one means they
|
|
886
|
+
* changed across the run, which is itself the finding.
|
|
887
|
+
*/
|
|
888
|
+
onPromptFingerprint?: (fingerprint: PromptFingerprint) => void;
|
|
760
889
|
}
|
|
761
890
|
/**
|
|
762
891
|
* A dispatch failure that still carries the SDK's session id, when the result message had one —
|
|
@@ -787,6 +916,78 @@ declare function buildToolDriverPrompt(steps: readonly StagedStep[]): string;
|
|
|
787
916
|
*/
|
|
788
917
|
declare function runHybridTool(plan: DispatchPlan, cfg: RunConfig): Promise<RunResult>;
|
|
789
918
|
|
|
919
|
+
/**
|
|
920
|
+
* What a host says about each slot, keyed by slot name:
|
|
921
|
+
*
|
|
922
|
+
* - a string — render this variant;
|
|
923
|
+
* - `null` — the slot's `present_when` does not hold, so remove it entirely;
|
|
924
|
+
* - absent — the host has no opinion, so render the declared `default`.
|
|
925
|
+
*
|
|
926
|
+
* A plain table rather than a callback, so what the model was told is decided before the run rather
|
|
927
|
+
* than during it: it can be recorded, compared and fingerprinted. A callback could not be.
|
|
928
|
+
*/
|
|
929
|
+
type SlotSupply = Readonly<Record<string, string | null>>;
|
|
930
|
+
/**
|
|
931
|
+
* What to do with a conditional slot the host did not answer.
|
|
932
|
+
*
|
|
933
|
+
* `"fail"` on any path whose text reaches a model: `default` covers "no opinion on the wording", and
|
|
934
|
+
* it cannot cover "no opinion on whether this exists at all" — defaulting there ships instructions
|
|
935
|
+
* for a capability that may have been withheld, which is the failure `present_when` exists to
|
|
936
|
+
* prevent.
|
|
937
|
+
*
|
|
938
|
+
* `"default"` on a display path. The rule above protects a model, not a reader, and a structural
|
|
939
|
+
* view that refuses to render a valid profile is worse than one showing the default wording. Note
|
|
940
|
+
* this is a real difference in meaning, not a relaxation for convenience: a display says "this is
|
|
941
|
+
* what the default binding would say", never "this is what will be sent".
|
|
942
|
+
*/
|
|
943
|
+
type UnansweredCondition = "fail" | "default";
|
|
944
|
+
/**
|
|
945
|
+
* Resolve each declared slot to the text that will replace its references, or to `null` when the
|
|
946
|
+
* host said it is not present.
|
|
947
|
+
*
|
|
948
|
+
* A slot's chosen variant may itself reference other slots — the compiler collects references from
|
|
949
|
+
* variant text and validates them, so this is authored-legal — hence the recursion, with a visiting
|
|
950
|
+
* set so a cycle is reported rather than spun on.
|
|
951
|
+
*
|
|
952
|
+
* @param decls every slot in scope for the text being resolved. That is the profile's slots PLUS
|
|
953
|
+
* the component's, together: compile checks the two layers separately, but it also folds the
|
|
954
|
+
* profile's `system_prompt` into each component's `brief` (`render_brief`), so by the time a
|
|
955
|
+
* consumer sees the IR one string carries references from both. Names are unique project-wide —
|
|
956
|
+
* compile refuses a collision — which is what makes one combined table unambiguous.
|
|
957
|
+
* @param supply the host's table.
|
|
958
|
+
* @param scope names the scope in errors ("component 'x'").
|
|
959
|
+
*/
|
|
960
|
+
declare function resolveSlots(decls: readonly SlotDecl[], supply: SlotSupply, scope: string, unanswered?: UnansweredCondition): ReadonlyMap<string, string | null>;
|
|
961
|
+
/**
|
|
962
|
+
* Apply a resolved scope to one piece of prompt text.
|
|
963
|
+
*
|
|
964
|
+
* A slot resolved to `null` leaves nothing behind — deliberately the empty string rather than any
|
|
965
|
+
* variant, since the point of a condition that does not hold is that the wording must not appear.
|
|
966
|
+
*/
|
|
967
|
+
declare function applySlots(raw: string, resolved: ReadonlyMap<string, string | null>, scope: string): string;
|
|
968
|
+
/**
|
|
969
|
+
* Refuse prompt text that still carries a slot reference.
|
|
970
|
+
*
|
|
971
|
+
* The guard, not a formality. Every other failure in this file is loud on its own; this one catches
|
|
972
|
+
* the case where a surface was never routed through {@link applySlots} at all — a new prompt-carrying
|
|
973
|
+
* field, a path that assembles text somewhere unexpected — which is exactly how the original defect
|
|
974
|
+
* arrived: the IR grew slots and nothing downstream was taught to consume them.
|
|
975
|
+
*/
|
|
976
|
+
declare function assertNoSlotReferences(raw: string, owner: string): void;
|
|
977
|
+
/**
|
|
978
|
+
* Parse repeated `--slot name=variant` / `--slot name=` flags into a {@link SlotSupply}.
|
|
979
|
+
*
|
|
980
|
+
* Lives here rather than in the CLI so it is reachable by a test and by any host that wants the same
|
|
981
|
+
* surface; the CLI turns the thrown error into its own usage failure. Mirrors the Rust CLI's flag of
|
|
982
|
+
* the same name — two user-facing surfaces that disagreed about what `name=` means would be worse
|
|
983
|
+
* than either one alone.
|
|
984
|
+
*
|
|
985
|
+
* An empty value is **not** an empty variant name: it is the host saying the slot's condition does
|
|
986
|
+
* not hold and the wording must not appear at all. That distinction is why the flag takes a trailing
|
|
987
|
+
* `=` rather than requiring a variant.
|
|
988
|
+
*/
|
|
989
|
+
declare function parseSlotFlags(flags: readonly string[]): SlotSupply;
|
|
990
|
+
|
|
790
991
|
interface RenderResult {
|
|
791
992
|
outPath: string;
|
|
792
993
|
/** stderr from `warble render` (it logs "wrote … (N block(s))"). */
|
|
@@ -910,6 +1111,16 @@ declare function createChatSession(plan: DispatchPlan, runCfg: RunConfig, initia
|
|
|
910
1111
|
interface DispatchInput {
|
|
911
1112
|
/** A parsed IR or a raw JSON string. */
|
|
912
1113
|
ir: WarbleIr | string;
|
|
1114
|
+
/**
|
|
1115
|
+
* What this host says about each declared slot: a variant name to render, `null` to remove the
|
|
1116
|
+
* slot because its `present_when` does not hold, or nothing at all to take the declared default.
|
|
1117
|
+
*
|
|
1118
|
+
* The IR carries every variant and picks none — picking is the host's job, and so is answering a
|
|
1119
|
+
* condition. Omit this entirely for an IR that declares no slots; supplying it then is harmless
|
|
1120
|
+
* but pointless. An IR that DOES declare a conditional slot and gets no answer for it is a loud
|
|
1121
|
+
* failure rather than a silent default (see `resolveSlots`).
|
|
1122
|
+
*/
|
|
1123
|
+
slots?: SlotSupply;
|
|
913
1124
|
/** The data question to answer (the `query()` prompt). Optional for prepare-only (dry-run/emit). */
|
|
914
1125
|
question?: string;
|
|
915
1126
|
target?: string;
|
|
@@ -962,7 +1173,24 @@ interface UnavailableDisplayComponent {
|
|
|
962
1173
|
reason: typeof UNAVAILABLE_COMPONENT_REASON;
|
|
963
1174
|
};
|
|
964
1175
|
}
|
|
965
|
-
|
|
1176
|
+
/**
|
|
1177
|
+
* A component in a display manifest that the target CAN run.
|
|
1178
|
+
*
|
|
1179
|
+
* Deliberately **not** a {@link PreparedComponent}: it carries no `plan`. A plan built for a display
|
|
1180
|
+
* is resolved under the lenient unanswered-condition policy, so handing one out would let a consumer
|
|
1181
|
+
* do the natural "preview it, then dispatch what was previewed" — `runDispatch(component.plan, cfg)`
|
|
1182
|
+
* type-checks with no cast — and send a model wording for a condition nobody ever answered. That is
|
|
1183
|
+
* exactly the failure the strict policy exists to prevent, arriving through the display door.
|
|
1184
|
+
*
|
|
1185
|
+
* A plan is still built during preparation, because that is what surfaces an unsupported enum as a
|
|
1186
|
+
* wall-hit; it is discarded rather than returned. Nothing in the manifest builders reads it.
|
|
1187
|
+
*/
|
|
1188
|
+
interface AvailableDisplayComponent {
|
|
1189
|
+
id: string;
|
|
1190
|
+
node: ComponentNode;
|
|
1191
|
+
report: ResolutionReport;
|
|
1192
|
+
}
|
|
1193
|
+
type DisplayComponent = AvailableDisplayComponent | UnavailableDisplayComponent;
|
|
966
1194
|
interface PreparedDisplayManifest {
|
|
967
1195
|
target: string;
|
|
968
1196
|
components: DisplayComponent[];
|
|
@@ -1132,7 +1360,12 @@ interface Manifest {
|
|
|
1132
1360
|
}
|
|
1133
1361
|
/** Port of `emit.rs::build_agent_bundle`, minus the tool-map parameter (this back-end's is fixed,
|
|
1134
1362
|
* see `LOCAL_TOOL_MAP`). */
|
|
1135
|
-
|
|
1363
|
+
/**
|
|
1364
|
+
* Takes the plan-less display shape deliberately. A {@link PreparedComponent} is still accepted —
|
|
1365
|
+
* it satisfies this structurally — but nothing here reads a plan, so nothing here should require
|
|
1366
|
+
* one; see `AvailableDisplayComponent` for why a display must not carry it.
|
|
1367
|
+
*/
|
|
1368
|
+
declare function buildAgentManifest(component: AvailableDisplayComponent): AvailableAgentManifest;
|
|
1136
1369
|
/** Never derives a plan, tool, or capability grant for an unavailable component. */
|
|
1137
1370
|
declare function buildUnavailableAgentManifest(component: UnavailableDisplayComponent): UnavailableAgentManifest;
|
|
1138
1371
|
/** Build the full display manifest for a `prepareDispatch` result. `raw` is the same IR the
|
|
@@ -1140,4 +1373,4 @@ declare function buildUnavailableAgentManifest(component: UnavailableDisplayComp
|
|
|
1140
1373
|
* `profile`, which `PreparedDispatch` does not itself carry. */
|
|
1141
1374
|
declare function buildManifest(prepared: PreparedDispatch | PreparedDisplayManifest, raw: string): Manifest;
|
|
1142
1375
|
|
|
1143
|
-
export { type AgentManifest, type AskOptions, type AvailableAgentManifest, type BuildConfig, COMPONENT_TYPES, type CallLocalOptions, type CapabilityEntry, type CapabilityOutcome, type CapabilityProfile, type ChatRequest, ChatSession, type ClarifyOutcome, type CompatibilityPolicy, type ComponentNode, type ComponentOutcome, type ComponentType, type ContextBinding, type Criticality, DEFAULT_CLARIFY_THRESHOLD, DEFAULT_RENDER_FLAVOR, DEFAULT_TARGET, DESTRUCTIVE_BASH_DENY, type Denial, type DiscoverClaudeModelsOptions, DispatchError, type DispatchInput, type DispatchMeta, type DispatchOutcome, type DispatchPlan, type DispatchRunConfig, DispatchSessionError, type DisplayComponent, type Effect, type EmitOptions, type GateFailureMode, type GateKind, type GuardConfig, type Guardrail, type GuardrailManifest, type IrConfig, type LlmCall, MODEL_CATALOG_VERSION, type Manifest, type ModelCatalogModel, type ModelCatalogResult, type ModelCatalogUnavailableCode, ModelConfig, OUTCOME_KINDS, type Outcome, type OutcomeKind, type PreconditionResult, type PreparedComponent, type PreparedDispatch, type PreparedDisplayManifest, type ProvidedBy, type Provider, REALIZATION_KINDS, type RealizationKind, type RenderBlock, type RenderFlavor, type RenderGate, type RenderResult, type ResolutionReport, type ResolvedCapability, type ResolvedIntent, type RoutingMode, type RoutingPlan, type RunConfig, type RunResult, SUPPORTED_IR_VERSIONS, type SessionState, type StagedStep, type StepManifest, type StepMessage, type StepRealization, type StepUsage, TRIGGER_KINDS, type TargetId, type TierBinding, type ToolPlan, type ToolRef, type Trace, type Trigger, type TriggerKind, type Turn, type TurnResult, UNAVAILABLE_COMPONENT_REASON, type UnavailableAgentManifest, type UnavailableDisplayComponent, type WarbleIr, type WhenGuardOut, aggregateTrace, appendTurn, buildAgentManifest, buildChatRequest, buildDispatchPlan, buildManifest, buildStepMessages, buildToolDriverPrompt, buildTurnPrompt, buildUnavailableAgentManifest, callOpenAiCompat, collectRequiredCapabilities, createChatSession, createSessionState, decideClarify, discoverClaudeModels, dispatch, distillFollowup, distinctProviders, distinctTiers, emitAgentModule, extractCompletionText, inspectNodeCapabilities, isKnownTarget, knownTargetNames, lastResolvedIntent, lastSessionId, localProfile, makeReadOnlyGuard, parseIr, parseRenderFlavor, planProviderRouting, prepareDispatch, prepareDisplayManifest, profileFor, renderEnvelope, resolveCapabilities, resolveNodeCapabilities, resolveProjectCwd, resolveStagedSteps, runDispatch, runHybridTool, shouldSplitPerStepTier, usesLocalProvider };
|
|
1376
|
+
export { type AgentManifest, type AskOptions, type AvailableAgentManifest, type AvailableDisplayComponent, type BuildConfig, COMPONENT_TYPES, type CallLocalOptions, type CapabilityEntry, type CapabilityOutcome, type CapabilityProfile, type ChatRequest, ChatSession, type ClarifyOutcome, type CompatibilityPolicy, type ComponentNode, type ComponentOutcome, type ComponentType, type ContextBinding, type Criticality, DEFAULT_CLARIFY_THRESHOLD, DEFAULT_RENDER_FLAVOR, DEFAULT_TARGET, DESTRUCTIVE_BASH_DENY, type Denial, type DiscoverClaudeModelsOptions, DispatchError, type DispatchInput, type DispatchMeta, type DispatchOutcome, type DispatchPlan, type DispatchRunConfig, DispatchSessionError, type DisplayComponent, type Effect, type EmitOptions, type GateFailureMode, type GateKind, type GuardConfig, type Guardrail, type GuardrailManifest, type IrConfig, type LlmCall, MODEL_CATALOG_VERSION, type Manifest, type ModelCatalogModel, type ModelCatalogResult, type ModelCatalogUnavailableCode, ModelConfig, OUTCOME_KINDS, type Outcome, type OutcomeKind, type PreconditionResult, type PreparedComponent, type PreparedDispatch, type PreparedDisplayManifest, type PromptFingerprint, type ProvidedBy, type Provider, REALIZATION_KINDS, type RealizationKind, type RenderBlock, type RenderFlavor, type RenderGate, type RenderResult, type ResolutionReport, type ResolvedCapability, type ResolvedIntent, type RoutingMode, type RoutingPlan, type RunConfig, type RunResult, SUPPORTED_IR_VERSIONS, type SessionState, type SlotSupply, type StagedStep, type StepManifest, type StepMessage, type StepRealization, type StepUsage, TRIGGER_KINDS, type TargetId, type TierBinding, type ToolPlan, type ToolRef, type Trace, type Trigger, type TriggerKind, type Turn, type TurnResult, UNAVAILABLE_COMPONENT_REASON, type UnansweredCondition, type UnavailableAgentManifest, type UnavailableDisplayComponent, type WarbleIr, type WhenGuardOut, aggregateTrace, appendTurn, applySlots, assertNoSlotReferences, buildAgentManifest, buildChatRequest, buildDispatchPlan, buildManifest, buildStepMessages, buildToolDriverPrompt, buildTurnPrompt, buildUnavailableAgentManifest, callOpenAiCompat, collectRequiredCapabilities, composeCanUseTool, composeHooks, createChatSession, createSessionState, decideClarify, discoverClaudeModels, dispatch, distillFollowup, distinctProviders, distinctTiers, emitAgentModule, extractCompletionText, fingerprintPrompts, fingerprintSurfaces, inspectNodeCapabilities, isKnownTarget, knownTargetNames, lastResolvedIntent, lastSessionId, localProfile, makeReadOnlyGuard, parseIr, parseRenderFlavor, parseSlotFlags, planProviderRouting, prepareDispatch, prepareDisplayManifest, profileFor, promptSurfaces, promptSurfacesOf, renderEnvelope, resolveCapabilities, resolveNodeCapabilities, resolveProjectCwd, resolveSlots, resolveStagedSteps, runDispatch, runHybridTool, shouldSplitPerStepTier, usesLocalProvider };
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
UNAVAILABLE_COMPONENT_REASON,
|
|
17
17
|
aggregateTrace,
|
|
18
18
|
appendTurn,
|
|
19
|
+
applySlots,
|
|
20
|
+
assertNoSlotReferences,
|
|
19
21
|
buildAgentManifest,
|
|
20
22
|
buildChatRequest,
|
|
21
23
|
buildDispatchPlan,
|
|
@@ -26,6 +28,8 @@ import {
|
|
|
26
28
|
buildUnavailableAgentManifest,
|
|
27
29
|
callOpenAiCompat,
|
|
28
30
|
collectRequiredCapabilities,
|
|
31
|
+
composeCanUseTool,
|
|
32
|
+
composeHooks,
|
|
29
33
|
createChatSession,
|
|
30
34
|
createSessionState,
|
|
31
35
|
decideClarify,
|
|
@@ -36,6 +40,8 @@ import {
|
|
|
36
40
|
distinctTiers,
|
|
37
41
|
emitAgentModule,
|
|
38
42
|
extractCompletionText,
|
|
43
|
+
fingerprintPrompts,
|
|
44
|
+
fingerprintSurfaces,
|
|
39
45
|
inspectNodeCapabilities,
|
|
40
46
|
isKnownTarget,
|
|
41
47
|
knownTargetNames,
|
|
@@ -45,20 +51,24 @@ import {
|
|
|
45
51
|
makeReadOnlyGuard,
|
|
46
52
|
parseIr,
|
|
47
53
|
parseRenderFlavor,
|
|
54
|
+
parseSlotFlags,
|
|
48
55
|
planProviderRouting,
|
|
49
56
|
prepareDispatch,
|
|
50
57
|
prepareDisplayManifest,
|
|
51
58
|
profileFor,
|
|
59
|
+
promptSurfaces,
|
|
60
|
+
promptSurfacesOf,
|
|
52
61
|
renderEnvelope,
|
|
53
62
|
resolveCapabilities,
|
|
54
63
|
resolveNodeCapabilities,
|
|
55
64
|
resolveProjectCwd,
|
|
65
|
+
resolveSlots,
|
|
56
66
|
resolveStagedSteps,
|
|
57
67
|
runDispatch,
|
|
58
68
|
runHybridTool,
|
|
59
69
|
shouldSplitPerStepTier,
|
|
60
70
|
usesLocalProvider
|
|
61
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-7XQ5F6FM.js";
|
|
62
72
|
export {
|
|
63
73
|
COMPONENT_TYPES,
|
|
64
74
|
ChatSession,
|
|
@@ -77,6 +87,8 @@ export {
|
|
|
77
87
|
UNAVAILABLE_COMPONENT_REASON,
|
|
78
88
|
aggregateTrace,
|
|
79
89
|
appendTurn,
|
|
90
|
+
applySlots,
|
|
91
|
+
assertNoSlotReferences,
|
|
80
92
|
buildAgentManifest,
|
|
81
93
|
buildChatRequest,
|
|
82
94
|
buildDispatchPlan,
|
|
@@ -87,6 +99,8 @@ export {
|
|
|
87
99
|
buildUnavailableAgentManifest,
|
|
88
100
|
callOpenAiCompat,
|
|
89
101
|
collectRequiredCapabilities,
|
|
102
|
+
composeCanUseTool,
|
|
103
|
+
composeHooks,
|
|
90
104
|
createChatSession,
|
|
91
105
|
createSessionState,
|
|
92
106
|
decideClarify,
|
|
@@ -97,6 +111,8 @@ export {
|
|
|
97
111
|
distinctTiers,
|
|
98
112
|
emitAgentModule,
|
|
99
113
|
extractCompletionText,
|
|
114
|
+
fingerprintPrompts,
|
|
115
|
+
fingerprintSurfaces,
|
|
100
116
|
inspectNodeCapabilities,
|
|
101
117
|
isKnownTarget,
|
|
102
118
|
knownTargetNames,
|
|
@@ -106,14 +122,18 @@ export {
|
|
|
106
122
|
makeReadOnlyGuard,
|
|
107
123
|
parseIr,
|
|
108
124
|
parseRenderFlavor,
|
|
125
|
+
parseSlotFlags,
|
|
109
126
|
planProviderRouting,
|
|
110
127
|
prepareDispatch,
|
|
111
128
|
prepareDisplayManifest,
|
|
112
129
|
profileFor,
|
|
130
|
+
promptSurfaces,
|
|
131
|
+
promptSurfacesOf,
|
|
113
132
|
renderEnvelope,
|
|
114
133
|
resolveCapabilities,
|
|
115
134
|
resolveNodeCapabilities,
|
|
116
135
|
resolveProjectCwd,
|
|
136
|
+
resolveSlots,
|
|
117
137
|
resolveStagedSteps,
|
|
118
138
|
runDispatch,
|
|
119
139
|
runHybridTool,
|