@koda-sl/baker-bridge 0.168.0-dev.d78500250 → 0.172.0-dev.b570aa3f2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -19
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +3 -1
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/agent.test.js +2 -0
- package/dist/hono/agent.test.js.map +1 -1
- package/dist/hono/bridge-job.d.ts +19 -11
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +125 -50
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +139 -7
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/model-capabilities.d.ts +1 -0
- package/dist/hono/model-capabilities.d.ts.map +1 -1
- package/dist/hono/model-capabilities.js +4 -0
- package/dist/hono/model-capabilities.js.map +1 -1
- package/dist/hono/openrouter-session.d.ts +3 -0
- package/dist/hono/openrouter-session.d.ts.map +1 -1
- package/dist/hono/openrouter-session.js +3 -0
- package/dist/hono/openrouter-session.js.map +1 -1
- package/dist/hono/relay.d.ts +4 -4
- package/dist/hono/relay.d.ts.map +1 -1
- package/dist/hono/relay.js +1 -1
- package/dist/hono/relay.js.map +1 -1
- package/dist/hono/relay.test.js +10 -4
- package/dist/hono/relay.test.js.map +1 -1
- package/dist/hono/served-model.d.ts +8 -0
- package/dist/hono/served-model.d.ts.map +1 -1
- package/dist/hono/served-model.js +41 -0
- package/dist/hono/served-model.js.map +1 -1
- package/dist/hono/served-model.test.js +19 -1
- package/dist/hono/served-model.test.js.map +1 -1
- package/dist/hono/session-continuity.integration.test.js +2 -0
- package/dist/hono/session-continuity.integration.test.js.map +1 -1
- package/dist/hono/subagent-route.d.ts +64 -0
- package/dist/hono/subagent-route.d.ts.map +1 -0
- package/dist/hono/subagent-route.js +147 -0
- package/dist/hono/subagent-route.js.map +1 -0
- package/dist/hono/subagent-route.test.d.ts +2 -0
- package/dist/hono/subagent-route.test.d.ts.map +1 -0
- package/dist/hono/subagent-route.test.js +68 -0
- package/dist/hono/subagent-route.test.js.map +1 -0
- package/dist/hono/tool-result-ledger.d.ts +2 -0
- package/dist/hono/tool-result-ledger.d.ts.map +1 -1
- package/dist/hono/tool-result-ledger.js +12 -8
- package/dist/hono/tool-result-ledger.js.map +1 -1
- package/dist/hono/turn-route.d.ts +84 -0
- package/dist/hono/turn-route.d.ts.map +1 -0
- package/dist/hono/turn-route.js +121 -0
- package/dist/hono/turn-route.js.map +1 -0
- package/dist/hono/turn-route.test.d.ts +2 -0
- package/dist/hono/turn-route.test.d.ts.map +1 -0
- package/dist/hono/turn-route.test.js +134 -0
- package/dist/hono/turn-route.test.js.map +1 -0
- package/package.json +2 -1
- package/dist/hono/effort-route.d.ts +0 -43
- package/dist/hono/effort-route.d.ts.map +0 -1
- package/dist/hono/effort-route.js +0 -36
- package/dist/hono/effort-route.js.map +0 -1
- package/dist/hono/effort-route.test.d.ts +0 -2
- package/dist/hono/effort-route.test.d.ts.map +0 -1
- package/dist/hono/effort-route.test.js +0 -54
- package/dist/hono/effort-route.test.js.map +0 -1
|
@@ -262,8 +262,9 @@ function createExecutor(options) {
|
|
|
262
262
|
...(options.catchUpWithMain ? { catchUpWithMain: options.catchUpWithMain } : {}),
|
|
263
263
|
...(options.keepCliInStep ? { keepCliInStep: options.keepCliInStep } : {}),
|
|
264
264
|
...(options.holdsNoWork ? { holdsNoWork: options.holdsNoWork } : {}),
|
|
265
|
-
// Never the network: a turn nobody judges runs
|
|
266
|
-
|
|
265
|
+
// Never the network: a turn nobody judges runs on the default model and effort.
|
|
266
|
+
routeJudge: options.routeJudge ?? (async () => null),
|
|
267
|
+
...(options.routeModels ? { routeModels: true } : {}),
|
|
267
268
|
});
|
|
268
269
|
}
|
|
269
270
|
function memoryInFlightTurns(initial) {
|
|
@@ -1345,6 +1346,17 @@ describe("BridgeJobExecutor", () => {
|
|
|
1345
1346
|
await executor.execute({ threadId: "thread_bedrock", turnId: "turn_bedrock", prompt: "Build a landing", history: history([]) }, activeControls());
|
|
1346
1347
|
expect(queryInputs[0]?.options.env).toMatchObject({ CLAUDE_CODE_MODEL_CAPABILITIES: "per_turn_effort" });
|
|
1347
1348
|
});
|
|
1349
|
+
// The CLI names each session with a structured-output request OpenRouter's Bedrock
|
|
1350
|
+
// cannot serve, so it went to Azure on OpenRouter credits; nothing reads the name.
|
|
1351
|
+
it("never sends the CLI's session-title request", async () => {
|
|
1352
|
+
const queryInputs = [];
|
|
1353
|
+
const executor = createExecutor({
|
|
1354
|
+
queryInputs,
|
|
1355
|
+
queryResults: [scriptedMessages(resultMessage(0, "session_untitled"))],
|
|
1356
|
+
});
|
|
1357
|
+
await executor.execute({ threadId: "thread_untitled", turnId: "turn_untitled", prompt: "Build a landing", history: history([]) }, activeControls());
|
|
1358
|
+
expect(queryInputs[0]?.options.env).toMatchObject({ CLAUDE_CODE_DISABLE_TERMINAL_TITLE: "1" });
|
|
1359
|
+
});
|
|
1348
1360
|
it("silences the CLI task reminders and ANSI colour in the agent subprocess", async () => {
|
|
1349
1361
|
const queryInputs = [];
|
|
1350
1362
|
const executor = createExecutor({
|
|
@@ -1483,6 +1495,78 @@ describe("BridgeJobExecutor", () => {
|
|
|
1483
1495
|
expect(options.env?.CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD).toBe("1");
|
|
1484
1496
|
expect(await readFile(join(instructionsDirMock.value, "CLAUDE.md"), "utf8")).toBe(`@${join(workspace, "COMPANY.md")}\n`);
|
|
1485
1497
|
});
|
|
1498
|
+
// Excluding CLAUDE.md from the memory files took it from every subagent that
|
|
1499
|
+
// loaded it there too; measured through the real CLI, `general-purpose` and
|
|
1500
|
+
// `research` lost it while still reading COMPANY.md.
|
|
1501
|
+
it("gives the shared instructions back to the subagents that loaded CLAUDE.md, and only to them", async () => {
|
|
1502
|
+
const workspace = await mkdtemp(join(tmpdir(), "baker-job-subagent-instructions-"));
|
|
1503
|
+
await writeFile(join(workspace, "CLAUDE.md"), "# Project Instructions\n\n## Client Context\n\nOne client per repo. Everything known about them:\n\n@COMPANY.md\n\n## Rules\n\nStage, don't ask.\n");
|
|
1504
|
+
await mkdir(join(workspace, ".claude", "agents"), { recursive: true });
|
|
1505
|
+
await writeFile(join(workspace, ".claude", "agents", "claim-checker.md"), "---\nname: claim-checker\nmodel: claude-sonnet-5-5\nomitClaudeMd: true\n---\nCheck claims.\n");
|
|
1506
|
+
projectRootMock.value = workspace;
|
|
1507
|
+
const queryInputs = [];
|
|
1508
|
+
const executor = createExecutor({
|
|
1509
|
+
queryInputs,
|
|
1510
|
+
queryResults: [scriptedMessages(resultMessage(0, "session_subagent_instructions"))],
|
|
1511
|
+
});
|
|
1512
|
+
await executor.execute({ threadId: "thread_sub_instr", turnId: "turn_sub_instr", prompt: "Build a landing", history: history([]) }, activeControls());
|
|
1513
|
+
const start = queryInputs[0]?.options.hooks?.SubagentStart?.[0]?.hooks[0];
|
|
1514
|
+
const contextFor = async (agentType) => (await start?.({
|
|
1515
|
+
hook_event_name: "SubagentStart",
|
|
1516
|
+
agent_type: agentType,
|
|
1517
|
+
agent_id: "a",
|
|
1518
|
+
session_id: "s",
|
|
1519
|
+
transcript_path: "",
|
|
1520
|
+
cwd: "",
|
|
1521
|
+
}, undefined, { signal: new AbortController().signal }))?.hookSpecificOutput?.additionalContext;
|
|
1522
|
+
expect(await contextFor("general-purpose")).toContain("Stage, don't ask.");
|
|
1523
|
+
expect(await contextFor("general-purpose")).not.toContain("@COMPANY.md");
|
|
1524
|
+
expect(await contextFor("claim-checker")).toBeUndefined();
|
|
1525
|
+
expect(await contextFor("fork")).toBeUndefined();
|
|
1526
|
+
});
|
|
1527
|
+
it("moves a built-in subagent that only reads to Sonnet, and records it with the turn", async () => {
|
|
1528
|
+
const queryInputs = [];
|
|
1529
|
+
let spawned;
|
|
1530
|
+
const executor = createExecutor({
|
|
1531
|
+
queryInputs,
|
|
1532
|
+
model: "claude-opus-5-5",
|
|
1533
|
+
routeModels: true,
|
|
1534
|
+
// The turn: finished work, so Opus. The spawn: only reading.
|
|
1535
|
+
routeJudge: (questions) => Promise.resolve(String(questions[0]?.instructions.message).includes("Check which step")
|
|
1536
|
+
? [0.2, 0.8, 0.9, 0.1]
|
|
1537
|
+
: [0.1, 0.9, 0.1, 0.9]),
|
|
1538
|
+
queryResults: [
|
|
1539
|
+
{
|
|
1540
|
+
async *[Symbol.asyncIterator]() {
|
|
1541
|
+
const preToolUse = queryInputs[0]?.options.hooks?.PreToolUse?.find((m) => m.matcher === "Agent")?.hooks[0];
|
|
1542
|
+
const result = (await preToolUse?.({
|
|
1543
|
+
hook_event_name: "PreToolUse",
|
|
1544
|
+
tool_name: "Agent",
|
|
1545
|
+
tool_input: {
|
|
1546
|
+
subagent_type: "general-purpose",
|
|
1547
|
+
description: "Walk the flow",
|
|
1548
|
+
prompt: "Check which step fires the conversion.",
|
|
1549
|
+
},
|
|
1550
|
+
tool_use_id: "toolu_1",
|
|
1551
|
+
session_id: "s",
|
|
1552
|
+
transcript_path: "",
|
|
1553
|
+
cwd: "",
|
|
1554
|
+
}, "toolu_1", { signal: new AbortController().signal }));
|
|
1555
|
+
spawned = result.hookSpecificOutput?.updatedInput;
|
|
1556
|
+
yield resultMessage(0, "session_subagent_route");
|
|
1557
|
+
},
|
|
1558
|
+
},
|
|
1559
|
+
],
|
|
1560
|
+
});
|
|
1561
|
+
const outcome = await executor.execute({ threadId: "thread_sub_route", turnId: "turn_sub_route", prompt: "Rebuild the landing", history: history([]) }, activeControls());
|
|
1562
|
+
expect(spawned).toMatchObject({ subagent_type: "general-purpose", model: "sonnet", effort: "high" });
|
|
1563
|
+
expect(outcome).toMatchObject({
|
|
1564
|
+
turnRoute: {
|
|
1565
|
+
model: "claude-opus-5-5",
|
|
1566
|
+
subagents: [{ agentType: "general-purpose", model: "sonnet", effort: "high", reason: "read_only" }],
|
|
1567
|
+
},
|
|
1568
|
+
});
|
|
1569
|
+
});
|
|
1486
1570
|
it("lets the CLI load a CLAUDE.md it cannot split, exactly as before", async () => {
|
|
1487
1571
|
const workspace = await mkdtemp(join(tmpdir(), "baker-job-instructions-old-"));
|
|
1488
1572
|
await writeFile(join(workspace, "CLAUDE.md"), "# Project Instructions\n\nNo company import.\n");
|
|
@@ -1700,9 +1784,11 @@ describe("BridgeJobExecutor", () => {
|
|
|
1700
1784
|
const asked = [];
|
|
1701
1785
|
const executor = createExecutor({
|
|
1702
1786
|
queryInputs,
|
|
1703
|
-
|
|
1787
|
+
model: "claude-opus-5-5",
|
|
1788
|
+
// small, complex, read-only, deliverable
|
|
1789
|
+
routeJudge: (questions) => {
|
|
1704
1790
|
asked.push(...questions);
|
|
1705
|
-
return [0.92, 0.05];
|
|
1791
|
+
return Promise.resolve([0.92, 0.05, 0.6, 0.1]);
|
|
1706
1792
|
},
|
|
1707
1793
|
queryResults: [scriptedMessages(resultMessage(0, "session_effort_low"))],
|
|
1708
1794
|
});
|
|
@@ -1721,17 +1807,63 @@ describe("BridgeJobExecutor", () => {
|
|
|
1721
1807
|
});
|
|
1722
1808
|
expect(outcome).toMatchObject({
|
|
1723
1809
|
kind: "completed",
|
|
1724
|
-
|
|
1810
|
+
turnRoute: { model: "claude-opus-5-5", modelReason: "fixed", effort: "low", reason: "small" },
|
|
1811
|
+
});
|
|
1812
|
+
});
|
|
1813
|
+
it("starts a chat that only reads on Sonnet, thinking harder, when the Runtime routes models", async () => {
|
|
1814
|
+
const queryInputs = [];
|
|
1815
|
+
const executor = createExecutor({
|
|
1816
|
+
queryInputs,
|
|
1817
|
+
model: "claude-opus-5-5",
|
|
1818
|
+
routeModels: true,
|
|
1819
|
+
routeJudge: () => Promise.resolve([0.2, 0.9, 0.85, 0.1]),
|
|
1820
|
+
queryResults: [scriptedMessages(resultMessage(0, "session_reading"))],
|
|
1725
1821
|
});
|
|
1822
|
+
const outcome = await executor.execute({ threadId: "thread_reading", turnId: "turn_reading", prompt: "¿Cómo van los anuncios?", history: history([]) }, activeControls());
|
|
1823
|
+
expect(queryInputs[0]?.options).toMatchObject({ model: "claude-sonnet-5-5", effort: "high" });
|
|
1824
|
+
expect(outcome).toMatchObject({
|
|
1825
|
+
model: "claude-sonnet-5-5",
|
|
1826
|
+
turnRoute: { model: "claude-sonnet-5-5", modelReason: "read_only", effort: "high" },
|
|
1827
|
+
});
|
|
1828
|
+
});
|
|
1829
|
+
it("moves a chat that ran on Sonnet to Opus once a turn asks for finished work", async () => {
|
|
1830
|
+
const configDir = await mkdtemp(join(tmpdir(), "bridge-turn-route-"));
|
|
1831
|
+
try {
|
|
1832
|
+
await mkdir(join(configDir, "projects", "-home-user-repo"), { recursive: true });
|
|
1833
|
+
await writeFile(join(configDir, "projects", "-home-user-repo", "session_sonnet.jsonl"), `${JSON.stringify({ type: "assistant", requestedModel: "claude-sonnet-5-5", message: { id: "m", model: "claude-sonnet-5-5", content: [] } })}\n`);
|
|
1834
|
+
vi.stubEnv("CLAUDE_CONFIG_DIR", configDir);
|
|
1835
|
+
const queryInputs = [];
|
|
1836
|
+
const executor = createExecutor({
|
|
1837
|
+
queryInputs,
|
|
1838
|
+
model: "claude-opus-5-5",
|
|
1839
|
+
routeModels: true,
|
|
1840
|
+
loadedBoundary: cleanBoundary("session_sonnet"),
|
|
1841
|
+
routeJudge: () => Promise.resolve([0.1, 0.95, 0.2, 0.9]),
|
|
1842
|
+
queryResults: [scriptedMessages(resultMessage(0, "session_sonnet"))],
|
|
1843
|
+
});
|
|
1844
|
+
await executor.execute({
|
|
1845
|
+
threadId: "thread_upgrade",
|
|
1846
|
+
turnId: "turn_upgrade",
|
|
1847
|
+
prompt: "Perfecto, créame una landing con esto",
|
|
1848
|
+
history: history([
|
|
1849
|
+
{ role: "user", text: "¿Cómo van los anuncios?", createdAt: 1 },
|
|
1850
|
+
{ role: "assistant", text: "Van bien: el CPL bajó un 12%.", createdAt: 2 },
|
|
1851
|
+
]),
|
|
1852
|
+
}, activeControls());
|
|
1853
|
+
expect(queryInputs[0]?.options).toMatchObject({ model: "claude-opus-5-5", effort: "medium" });
|
|
1854
|
+
}
|
|
1855
|
+
finally {
|
|
1856
|
+
await rm(configDir, { recursive: true, force: true });
|
|
1857
|
+
}
|
|
1726
1858
|
});
|
|
1727
1859
|
it("keeps a plan-mode turn at medium without asking Jev", async () => {
|
|
1728
1860
|
const queryInputs = [];
|
|
1729
1861
|
let asked = false;
|
|
1730
1862
|
const executor = createExecutor({
|
|
1731
1863
|
queryInputs,
|
|
1732
|
-
|
|
1864
|
+
routeJudge: () => {
|
|
1733
1865
|
asked = true;
|
|
1734
|
-
return [0.99, 0];
|
|
1866
|
+
return Promise.resolve([0.99, 0, 1, 0]);
|
|
1735
1867
|
},
|
|
1736
1868
|
queryResults: [scriptedMessages(resultMessage(0, "session_effort_plan"))],
|
|
1737
1869
|
});
|