@koda-sl/baker-bridge 0.168.0-dev.d78500250 → 0.169.0-dev.e03ffd565
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 +47 -50
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +3 -3
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/agent.test.js +91 -175
- package/dist/hono/agent.test.js.map +1 -1
- package/dist/hono/attachments.d.ts.map +1 -1
- package/dist/hono/attachments.js +9 -1
- package/dist/hono/attachments.js.map +1 -1
- package/dist/hono/attachments.test.js +22 -1
- package/dist/hono/attachments.test.js.map +1 -1
- package/dist/hono/bridge-job.d.ts +7 -19
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +31 -110
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +44 -184
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/flow-input-card-fields.test.js +1 -1
- package/dist/hono/flow-input.d.ts +1 -1
- package/dist/hono/flow-input.js +1 -1
- package/dist/hono/main-sync.d.ts +22 -0
- package/dist/hono/main-sync.d.ts.map +1 -1
- package/dist/hono/main-sync.js +110 -2
- package/dist/hono/main-sync.js.map +1 -1
- package/dist/hono/main-sync.test.js +127 -1
- package/dist/hono/main-sync.test.js.map +1 -1
- package/dist/hono/openrouter-session.d.ts +13 -16
- package/dist/hono/openrouter-session.d.ts.map +1 -1
- package/dist/hono/openrouter-session.js +13 -16
- package/dist/hono/openrouter-session.js.map +1 -1
- package/dist/hono/publish-handoff.d.ts +0 -1
- package/dist/hono/publish-handoff.d.ts.map +1 -1
- package/dist/hono/publish-handoff.js +0 -53
- package/dist/hono/publish-handoff.js.map +1 -1
- package/dist/hono/publish-handoff.test.js +0 -48
- package/dist/hono/publish-handoff.test.js.map +1 -1
- package/dist/hono/relay.d.ts +0 -8
- package/dist/hono/relay.d.ts.map +1 -1
- package/dist/hono/relay.js +0 -2
- package/dist/hono/relay.js.map +1 -1
- package/dist/hono/relay.test.js +0 -24
- package/dist/hono/relay.test.js.map +1 -1
- package/dist/hono/runtime-files.d.ts +0 -1
- package/dist/hono/runtime-files.d.ts.map +1 -1
- package/dist/hono/runtime-files.js +0 -3
- package/dist/hono/runtime-files.js.map +1 -1
- package/dist/hono/types.d.ts +0 -12
- package/dist/hono/types.d.ts.map +1 -1
- package/dist/review/digest.d.ts +0 -13
- package/dist/review/digest.d.ts.map +1 -1
- package/dist/review/digest.js +1 -1
- package/dist/review/digest.js.map +1 -1
- package/package.json +1 -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
- package/dist/hono/tool-result-ledger.d.ts +0 -30
- package/dist/hono/tool-result-ledger.d.ts.map +0 -1
- package/dist/hono/tool-result-ledger.js +0 -63
- package/dist/hono/tool-result-ledger.js.map +0 -1
- package/dist/hono/tool-result-ledger.test.d.ts +0 -2
- package/dist/hono/tool-result-ledger.test.d.ts.map +0 -1
- package/dist/hono/tool-result-ledger.test.js +0 -61
- package/dist/hono/tool-result-ledger.test.js.map +0 -1
- package/dist/hono/workspace-instructions.d.ts +0 -43
- package/dist/hono/workspace-instructions.d.ts.map +0 -1
- package/dist/hono/workspace-instructions.js +0 -68
- package/dist/hono/workspace-instructions.js.map +0 -1
- package/dist/hono/workspace-instructions.test.d.ts +0 -2
- package/dist/hono/workspace-instructions.test.d.ts.map +0 -1
- package/dist/hono/workspace-instructions.test.js +0 -68
- package/dist/hono/workspace-instructions.test.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import { mkdir, mkdtemp,
|
|
2
|
+
import { mkdir, mkdtemp, rm, utimes, writeFile } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
@@ -9,19 +9,11 @@ vi.mock("./env.ts", () => ({
|
|
|
9
9
|
// The skills allowlist is read off the workspace, so the project root has to be
|
|
10
10
|
// steerable to a fixture directory. Defaults to the real root for every other test.
|
|
11
11
|
const projectRootMock = vi.hoisted(() => ({ value: process.cwd() }));
|
|
12
|
-
// Where the per-company instructions import is written; kept out of the real ~/.baker.
|
|
13
|
-
const instructionsDirMock = vi.hoisted(() => ({
|
|
14
|
-
value: `${process.env.TMPDIR ?? "/tmp"}/baker-job-instructions-${process.pid}`,
|
|
15
|
-
}));
|
|
16
12
|
vi.mock("./runtime-files.ts", async (importOriginal) => {
|
|
17
13
|
const actual = await importOriginal();
|
|
18
14
|
return {
|
|
19
15
|
...actual,
|
|
20
|
-
bridgeRuntimeFiles: {
|
|
21
|
-
...actual.bridgeRuntimeFiles,
|
|
22
|
-
projectRoot: () => projectRootMock.value,
|
|
23
|
-
instructionsDir: () => instructionsDirMock.value,
|
|
24
|
-
},
|
|
16
|
+
bridgeRuntimeFiles: { ...actual.bridgeRuntimeFiles, projectRoot: () => projectRootMock.value },
|
|
25
17
|
};
|
|
26
18
|
});
|
|
27
19
|
import { AVATAR_CASTING_TOOL_NAME } from "./avatar-casting.js";
|
|
@@ -262,8 +254,7 @@ function createExecutor(options) {
|
|
|
262
254
|
...(options.catchUpWithMain ? { catchUpWithMain: options.catchUpWithMain } : {}),
|
|
263
255
|
...(options.keepCliInStep ? { keepCliInStep: options.keepCliInStep } : {}),
|
|
264
256
|
...(options.holdsNoWork ? { holdsNoWork: options.holdsNoWork } : {}),
|
|
265
|
-
|
|
266
|
-
effortJudge: options.effortJudge ?? (async () => null),
|
|
257
|
+
...(options.settleAfterPublish ? { settleAfterPublish: options.settleAfterPublish } : {}),
|
|
267
258
|
});
|
|
268
259
|
}
|
|
269
260
|
function memoryInFlightTurns(initial) {
|
|
@@ -1016,39 +1007,6 @@ describe("BridgeJobExecutor", () => {
|
|
|
1016
1007
|
],
|
|
1017
1008
|
});
|
|
1018
1009
|
});
|
|
1019
|
-
// Tool results are most of what a turn writes to the prompt cache, and nothing
|
|
1020
|
-
// recorded their size: the turn now reports it next to its model usage.
|
|
1021
|
-
it("reports how much each tool's results put in the context this turn", async () => {
|
|
1022
|
-
const executor = createExecutor({
|
|
1023
|
-
queryResults: [
|
|
1024
|
-
scriptedMessages({
|
|
1025
|
-
type: "assistant",
|
|
1026
|
-
parent_tool_use_id: null,
|
|
1027
|
-
uuid: "assistant_tool",
|
|
1028
|
-
session_id: "session_tools_size",
|
|
1029
|
-
message: {
|
|
1030
|
-
id: "msg_tool",
|
|
1031
|
-
role: "assistant",
|
|
1032
|
-
content: [{ type: "tool_use", id: "tool_1", name: "Bash", input: { command: "baker ads meta ads" } }],
|
|
1033
|
-
},
|
|
1034
|
-
}, {
|
|
1035
|
-
type: "user",
|
|
1036
|
-
parent_tool_use_id: null,
|
|
1037
|
-
uuid: "user_tool_result",
|
|
1038
|
-
session_id: "session_tools_size",
|
|
1039
|
-
message: {
|
|
1040
|
-
role: "user",
|
|
1041
|
-
content: [{ type: "tool_result", tool_use_id: "tool_1", content: "r".repeat(800) }],
|
|
1042
|
-
},
|
|
1043
|
-
}, resultMessage(0.1, "session_tools_size")),
|
|
1044
|
-
],
|
|
1045
|
-
});
|
|
1046
|
-
const outcome = await executor.execute({ threadId: "thread_tools_size", turnId: "turn_tools_size", prompt: "How are the ads?", history: history([]) }, activeControls());
|
|
1047
|
-
expect(outcome).toMatchObject({
|
|
1048
|
-
kind: "completed",
|
|
1049
|
-
toolResults: [{ tool: "baker ads meta", agent: "main", calls: 1, bytes: 800, tokens: 200 }],
|
|
1050
|
-
});
|
|
1051
|
-
});
|
|
1052
1010
|
// OpenRouter answers under its own slug. A CLI resuming a transcript that names
|
|
1053
1011
|
// the slug drops every earlier thinking block from its first request, which
|
|
1054
1012
|
// breaks the prompt cache right after the system prompt (BAKER-331).
|
|
@@ -1103,6 +1061,25 @@ describe("BridgeJobExecutor", () => {
|
|
|
1103
1061
|
// would resume a transcript holding one `/publish` and nothing else.
|
|
1104
1062
|
expect(savedBoundaries).toEqual([]);
|
|
1105
1063
|
});
|
|
1064
|
+
it("settles the chat's Publish once a publish turn ends, and never after a chat turn", async () => {
|
|
1065
|
+
let settled = 0;
|
|
1066
|
+
const settleAfterPublish = () => {
|
|
1067
|
+
settled += 1;
|
|
1068
|
+
return Promise.resolve();
|
|
1069
|
+
};
|
|
1070
|
+
const publishing = createExecutor({
|
|
1071
|
+
queryResults: [scriptedMessages(resultMessage(0.3, "session_publish_own"))],
|
|
1072
|
+
settleAfterPublish,
|
|
1073
|
+
});
|
|
1074
|
+
const chatting = createExecutor({
|
|
1075
|
+
queryResults: [scriptedMessages(resultMessage(0.3, "session_chat"))],
|
|
1076
|
+
settleAfterPublish,
|
|
1077
|
+
});
|
|
1078
|
+
await publishing.execute({ threadId: "thread_publish", turnId: "turn_publish", prompt: "/publish", history: history([]) }, activeControls());
|
|
1079
|
+
const afterPublish = settled;
|
|
1080
|
+
await chatting.execute({ threadId: "thread_chat", turnId: "turn_chat", prompt: "hello" }, activeControls());
|
|
1081
|
+
expect([afterPublish, settled]).toEqual([1, 1]);
|
|
1082
|
+
});
|
|
1106
1083
|
it("leaves the chat's session alone when a publish fails", async () => {
|
|
1107
1084
|
const clearCalls = [];
|
|
1108
1085
|
const executor = createExecutor({
|
|
@@ -1331,19 +1308,27 @@ describe("BridgeJobExecutor", () => {
|
|
|
1331
1308
|
"x-session-id: thread_env",
|
|
1332
1309
|
].join("\n"));
|
|
1333
1310
|
});
|
|
1334
|
-
//
|
|
1335
|
-
//
|
|
1336
|
-
|
|
1337
|
-
// after the first tool exchange. Pinned on rather than left to the CLI's own
|
|
1338
|
-
// default, which a remote feature gate can switch off.
|
|
1339
|
-
it("turns on per-turn effort, so a turn on another effort level keeps the prompt cache", async () => {
|
|
1311
|
+
// OpenRouter has no Bedrock endpoint for a per-message effort, so while the CLI
|
|
1312
|
+
// sends one every Opus 5.5 request skips Bedrock and bills OpenRouter credits.
|
|
1313
|
+
it("keeps the agent's model requests servable by Bedrock", async () => {
|
|
1340
1314
|
const queryInputs = [];
|
|
1341
1315
|
const executor = createExecutor({
|
|
1342
1316
|
queryInputs,
|
|
1343
1317
|
queryResults: [scriptedMessages(resultMessage(0, "session_bedrock"))],
|
|
1344
1318
|
});
|
|
1345
1319
|
await executor.execute({ threadId: "thread_bedrock", turnId: "turn_bedrock", prompt: "Build a landing", history: history([]) }, activeControls());
|
|
1346
|
-
expect(queryInputs[0]?.options.env).toMatchObject({ CLAUDE_CODE_MODEL_CAPABILITIES: "per_turn_effort" });
|
|
1320
|
+
expect(queryInputs[0]?.options.env).toMatchObject({ CLAUDE_CODE_MODEL_CAPABILITIES: "-per_turn_effort" });
|
|
1321
|
+
});
|
|
1322
|
+
// The CLI names each session with a structured-output request OpenRouter's Bedrock
|
|
1323
|
+
// cannot serve, so it went to Azure on OpenRouter credits; nothing reads the name.
|
|
1324
|
+
it("never sends the CLI's session-title request", async () => {
|
|
1325
|
+
const queryInputs = [];
|
|
1326
|
+
const executor = createExecutor({
|
|
1327
|
+
queryInputs,
|
|
1328
|
+
queryResults: [scriptedMessages(resultMessage(0, "session_untitled"))],
|
|
1329
|
+
});
|
|
1330
|
+
await executor.execute({ threadId: "thread_untitled", turnId: "turn_untitled", prompt: "Build a landing", history: history([]) }, activeControls());
|
|
1331
|
+
expect(queryInputs[0]?.options.env).toMatchObject({ CLAUDE_CODE_DISABLE_TERMINAL_TITLE: "1" });
|
|
1347
1332
|
});
|
|
1348
1333
|
it("silences the CLI task reminders and ANSI colour in the agent subprocess", async () => {
|
|
1349
1334
|
const queryInputs = [];
|
|
@@ -1443,62 +1428,6 @@ describe("BridgeJobExecutor", () => {
|
|
|
1443
1428
|
expect(disallowed).not.toContain("Task");
|
|
1444
1429
|
expect(disallowed).not.toContain("SendMessage");
|
|
1445
1430
|
});
|
|
1446
|
-
// Developer tools a marketer's chat never calls (0 calls across 358
|
|
1447
|
-
// production chats, Oct 2026). Each definition rides every request a session
|
|
1448
|
-
// makes — DesignSync's alone is ~9k characters — whenever the CLI does not
|
|
1449
|
-
// defer it.
|
|
1450
|
-
it("removes the developer tools a marketer's chat never calls", async () => {
|
|
1451
|
-
const queryInputs = [];
|
|
1452
|
-
const executor = createExecutor({
|
|
1453
|
-
queryInputs,
|
|
1454
|
-
queryResults: [scriptedMessages(resultMessage(0, "session_dev_tools"))],
|
|
1455
|
-
});
|
|
1456
|
-
await executor.execute({ threadId: "thread_dev_tools", turnId: "turn_dev_tools", prompt: "Build a landing", history: history([]) }, activeControls());
|
|
1457
|
-
const disallowed = queryInputs[0]?.options.disallowedTools ?? [];
|
|
1458
|
-
expect(disallowed).toEqual(expect.arrayContaining(["DesignSync", "ReportFindings", "NotebookEdit"]));
|
|
1459
|
-
});
|
|
1460
|
-
// The scaffold's CLAUDE.md is the same text for every company on a scaffold
|
|
1461
|
-
// version, but loaded as a memory file it lands in the first user message with
|
|
1462
|
-
// no cache breakpoint after it, so every chat wrote its ~24k tokens cold. In the
|
|
1463
|
-
// system prompt it ends on a breakpoint and one chat reads another's copy.
|
|
1464
|
-
it("sends the workspace's shared instructions as the system prompt and loads COMPANY.md on its own", async () => {
|
|
1465
|
-
const workspace = await mkdtemp(join(tmpdir(), "baker-job-instructions-"));
|
|
1466
|
-
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");
|
|
1467
|
-
projectRootMock.value = workspace;
|
|
1468
|
-
const queryInputs = [];
|
|
1469
|
-
const executor = createExecutor({
|
|
1470
|
-
queryInputs,
|
|
1471
|
-
queryResults: [scriptedMessages(resultMessage(0, "session_instructions"))],
|
|
1472
|
-
});
|
|
1473
|
-
await executor.execute({ threadId: "thread_instructions", turnId: "turn_instructions", prompt: "Build a landing", history: history([]) }, activeControls());
|
|
1474
|
-
const options = queryInputs[0]?.options;
|
|
1475
|
-
expect(options.systemPrompt).toEqual({
|
|
1476
|
-
type: "preset",
|
|
1477
|
-
preset: "claude_code",
|
|
1478
|
-
append: "# Project Instructions\n\n## Rules\n\nStage, don't ask.\n",
|
|
1479
|
-
snapshot: true,
|
|
1480
|
-
});
|
|
1481
|
-
expect(options.settings).toMatchObject({ claudeMdExcludes: [join(workspace, "CLAUDE.md")] });
|
|
1482
|
-
expect(options.additionalDirectories).toEqual([instructionsDirMock.value]);
|
|
1483
|
-
expect(options.env?.CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD).toBe("1");
|
|
1484
|
-
expect(await readFile(join(instructionsDirMock.value, "CLAUDE.md"), "utf8")).toBe(`@${join(workspace, "COMPANY.md")}\n`);
|
|
1485
|
-
});
|
|
1486
|
-
it("lets the CLI load a CLAUDE.md it cannot split, exactly as before", async () => {
|
|
1487
|
-
const workspace = await mkdtemp(join(tmpdir(), "baker-job-instructions-old-"));
|
|
1488
|
-
await writeFile(join(workspace, "CLAUDE.md"), "# Project Instructions\n\nNo company import.\n");
|
|
1489
|
-
projectRootMock.value = workspace;
|
|
1490
|
-
const queryInputs = [];
|
|
1491
|
-
const executor = createExecutor({
|
|
1492
|
-
queryInputs,
|
|
1493
|
-
queryResults: [scriptedMessages(resultMessage(0, "session_instructions_old"))],
|
|
1494
|
-
});
|
|
1495
|
-
await executor.execute({ threadId: "thread_instructions_old", turnId: "turn_instructions_old", prompt: "Hi", history: history([]) }, activeControls());
|
|
1496
|
-
const options = queryInputs[0]?.options;
|
|
1497
|
-
expect(options.systemPrompt).toBeUndefined();
|
|
1498
|
-
expect(options.additionalDirectories).toBeUndefined();
|
|
1499
|
-
expect(options.settings ?? {}).not.toHaveProperty("claudeMdExcludes");
|
|
1500
|
-
expect(options.env?.CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD).toBeUndefined();
|
|
1501
|
-
});
|
|
1502
1431
|
it("allowlists the workspace's own skills so the CLI's built-in developer skills stay out of the session", async () => {
|
|
1503
1432
|
const workspace = await mkdtemp(join(tmpdir(), "baker-job-skills-"));
|
|
1504
1433
|
for (const skill of ["landing", "brand-build", "docx"]) {
|
|
@@ -1677,10 +1606,11 @@ describe("BridgeJobExecutor", () => {
|
|
|
1677
1606
|
await executor.execute({ threadId: "thread_nobeta", turnId: "turn_nobeta", prompt: "Hi", history: history([]) }, activeControls());
|
|
1678
1607
|
expect(queryInputs[0]?.options).not.toHaveProperty("betas");
|
|
1679
1608
|
});
|
|
1680
|
-
// Effort governs thinking depth, preamble and tool-call count
|
|
1681
|
-
//
|
|
1682
|
-
//
|
|
1683
|
-
|
|
1609
|
+
// Effort governs thinking depth, preamble and tool-call count, and the API
|
|
1610
|
+
// default is `high`. A silent drift back to the default costs money twice:
|
|
1611
|
+
// more tokens per turn, and — because the resolved effort is rendered into
|
|
1612
|
+
// the prompt — a cache-breakpoint invalidation on the turn it changes.
|
|
1613
|
+
it("sends a single constant effort so the prompt cache is never invalidated by it", async () => {
|
|
1684
1614
|
const queryInputs = [];
|
|
1685
1615
|
const executor = createExecutor({
|
|
1686
1616
|
queryInputs,
|
|
@@ -1693,57 +1623,8 @@ describe("BridgeJobExecutor", () => {
|
|
|
1693
1623
|
await executor.execute({ threadId: "thread_effort", turnId: "turn_effort_1", prompt: "Hi", history: history([]) }, activeControls());
|
|
1694
1624
|
await executor.execute({ threadId: "thread_effort", turnId: "turn_effort_2", prompt: "Again", history: history([]) }, activeControls());
|
|
1695
1625
|
expect(queryInputs[0]?.options.effort).toBe("medium");
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
it("runs a turn Jev clearly reads as small at low effort, and reports why", async () => {
|
|
1699
|
-
const queryInputs = [];
|
|
1700
|
-
const asked = [];
|
|
1701
|
-
const executor = createExecutor({
|
|
1702
|
-
queryInputs,
|
|
1703
|
-
effortJudge: async (questions) => {
|
|
1704
|
-
asked.push(...questions);
|
|
1705
|
-
return [0.92, 0.05];
|
|
1706
|
-
},
|
|
1707
|
-
queryResults: [scriptedMessages(resultMessage(0, "session_effort_low"))],
|
|
1708
|
-
});
|
|
1709
|
-
const outcome = await executor.execute({
|
|
1710
|
-
threadId: "thread_effort_low",
|
|
1711
|
-
turnId: "turn_effort_low",
|
|
1712
|
-
prompt: "¿Cuál fue el CPL de ayer?",
|
|
1713
|
-
history: history([
|
|
1714
|
-
{ role: "user", text: "Revisa la campaña de verano", createdAt: 1 },
|
|
1715
|
-
{ role: "assistant", text: "Listo: la campaña de verano va bien.", createdAt: 2 },
|
|
1716
|
-
]),
|
|
1717
|
-
}, activeControls());
|
|
1718
|
-
expect(queryInputs[0]?.options.effort).toBe("low");
|
|
1719
|
-
expect(asked[0]).toMatchObject({
|
|
1720
|
-
instructions: { message: "¿Cuál fue el CPL de ayer?", previous_reply: "Listo: la campaña de verano va bien." },
|
|
1721
|
-
});
|
|
1722
|
-
expect(outcome).toMatchObject({
|
|
1723
|
-
kind: "completed",
|
|
1724
|
-
effortDecision: { effort: "low", reason: "small", small: 0.92, complex: 0.05 },
|
|
1725
|
-
});
|
|
1726
|
-
});
|
|
1727
|
-
it("keeps a plan-mode turn at medium without asking Jev", async () => {
|
|
1728
|
-
const queryInputs = [];
|
|
1729
|
-
let asked = false;
|
|
1730
|
-
const executor = createExecutor({
|
|
1731
|
-
queryInputs,
|
|
1732
|
-
effortJudge: async () => {
|
|
1733
|
-
asked = true;
|
|
1734
|
-
return [0.99, 0];
|
|
1735
|
-
},
|
|
1736
|
-
queryResults: [scriptedMessages(resultMessage(0, "session_effort_plan"))],
|
|
1737
|
-
});
|
|
1738
|
-
await executor.execute({
|
|
1739
|
-
threadId: "thread_effort_plan",
|
|
1740
|
-
turnId: "turn_effort_plan",
|
|
1741
|
-
prompt: "Plan Q4",
|
|
1742
|
-
planMode: true,
|
|
1743
|
-
history: history([]),
|
|
1744
|
-
}, activeControls());
|
|
1745
|
-
expect(queryInputs[0]?.options.effort).toBe("medium");
|
|
1746
|
-
expect(asked).toBe(false);
|
|
1626
|
+
// Constant across turns — a per-turn value is what would break the cache.
|
|
1627
|
+
expect(queryInputs[1]?.options.effort).toBe(queryInputs[0]?.options.effort);
|
|
1747
1628
|
});
|
|
1748
1629
|
it("pins the auto-compact window to the context window it resolved for the model", async () => {
|
|
1749
1630
|
const queryInputs = [];
|
|
@@ -4030,8 +3911,6 @@ describe("BridgeJobExecutor stall recovery", () => {
|
|
|
4030
3911
|
kind: "completed",
|
|
4031
3912
|
costUsd: 0.05,
|
|
4032
3913
|
model: "claude-test",
|
|
4033
|
-
// The tool result the stalled query had already received still counts.
|
|
4034
|
-
toolResults: [expect.objectContaining({ calls: 1 })],
|
|
4035
3914
|
cleanBoundary: expect.objectContaining({ sessionId: "session_a" }),
|
|
4036
3915
|
});
|
|
4037
3916
|
expect(queryInputs).toHaveLength(2);
|
|
@@ -4770,9 +4649,6 @@ describe("BridgeJobExecutor turn end with background tasks", () => {
|
|
|
4770
4649
|
});
|
|
4771
4650
|
});
|
|
4772
4651
|
describe("BridgeJobExecutor review mode", () => {
|
|
4773
|
-
afterEach(() => {
|
|
4774
|
-
projectRootMock.value = process.cwd();
|
|
4775
|
-
});
|
|
4776
4652
|
const review = {
|
|
4777
4653
|
reviewId: "rev_1",
|
|
4778
4654
|
apiKey: "bk_review_key",
|
|
@@ -4830,21 +4706,6 @@ describe("BridgeJobExecutor review mode", () => {
|
|
|
4830
4706
|
await executor.execute(reviewJob(), activeControls());
|
|
4831
4707
|
expect(queryInputs[0]?.options.settings).toMatchObject({ permissions: { ask: ["Bash"] } });
|
|
4832
4708
|
});
|
|
4833
|
-
// The brief has the reviewer read the rulebook as the Session had it
|
|
4834
|
-
// (`git show <sha>:CLAUDE.md`); the working tree's copy may already be newer.
|
|
4835
|
-
// Auto-loading it put ~24k tokens of the marketer's instructions in front of
|
|
4836
|
-
// every review request, written cold and re-read on each one.
|
|
4837
|
-
it("does not load the workspace's CLAUDE.md into the reviewer, as a memory file or as the system prompt", async () => {
|
|
4838
|
-
const workspace = await mkdtemp(join(tmpdir(), "baker-review-instructions-"));
|
|
4839
|
-
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");
|
|
4840
|
-
projectRootMock.value = workspace;
|
|
4841
|
-
const queryInputs = [];
|
|
4842
|
-
const executor = createExecutor({ queryInputs });
|
|
4843
|
-
await executor.execute(reviewJob(), activeControls());
|
|
4844
|
-
expect(queryInputs[0]?.options.settings).toMatchObject({ claudeMdExcludes: ["**/CLAUDE.md"] });
|
|
4845
|
-
expect(queryInputs[0]?.options.systemPrompt).toBeUndefined();
|
|
4846
|
-
expect(queryInputs[0]?.options.additionalDirectories).toBeUndefined();
|
|
4847
|
-
});
|
|
4848
4709
|
it("removes every editing tool on top of the list an ordinary turn is denied", async () => {
|
|
4849
4710
|
const queryInputs = [];
|
|
4850
4711
|
const executor = createExecutor({ queryInputs });
|
|
@@ -4908,7 +4769,6 @@ describe("BridgeJobExecutor review mode", () => {
|
|
|
4908
4769
|
expect(options.env?.BAKER_DEBUG_LOG).toBeUndefined();
|
|
4909
4770
|
expect(options.settings ?? {}).not.toHaveProperty("disableAllHooks");
|
|
4910
4771
|
expect(options.settings ?? {}).not.toHaveProperty("permissions");
|
|
4911
|
-
expect(options.settings ?? {}).not.toHaveProperty("claudeMdExcludes");
|
|
4912
4772
|
});
|
|
4913
4773
|
// BAKER-3462: after an English skill body, the next line went out in English to a Spanish chat.
|
|
4914
4774
|
const spanishTurn = "Prepara cuatro anuncios nuevos para la campaña de verano y súbelos hoy mismo";
|