@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.
Files changed (77) hide show
  1. package/README.md +47 -50
  2. package/dist/hono/agent.d.ts.map +1 -1
  3. package/dist/hono/agent.js +3 -3
  4. package/dist/hono/agent.js.map +1 -1
  5. package/dist/hono/agent.test.js +91 -175
  6. package/dist/hono/agent.test.js.map +1 -1
  7. package/dist/hono/attachments.d.ts.map +1 -1
  8. package/dist/hono/attachments.js +9 -1
  9. package/dist/hono/attachments.js.map +1 -1
  10. package/dist/hono/attachments.test.js +22 -1
  11. package/dist/hono/attachments.test.js.map +1 -1
  12. package/dist/hono/bridge-job.d.ts +7 -19
  13. package/dist/hono/bridge-job.d.ts.map +1 -1
  14. package/dist/hono/bridge-job.js +31 -110
  15. package/dist/hono/bridge-job.js.map +1 -1
  16. package/dist/hono/bridge-job.test.js +44 -184
  17. package/dist/hono/bridge-job.test.js.map +1 -1
  18. package/dist/hono/flow-input-card-fields.test.js +1 -1
  19. package/dist/hono/flow-input.d.ts +1 -1
  20. package/dist/hono/flow-input.js +1 -1
  21. package/dist/hono/main-sync.d.ts +22 -0
  22. package/dist/hono/main-sync.d.ts.map +1 -1
  23. package/dist/hono/main-sync.js +110 -2
  24. package/dist/hono/main-sync.js.map +1 -1
  25. package/dist/hono/main-sync.test.js +127 -1
  26. package/dist/hono/main-sync.test.js.map +1 -1
  27. package/dist/hono/openrouter-session.d.ts +13 -16
  28. package/dist/hono/openrouter-session.d.ts.map +1 -1
  29. package/dist/hono/openrouter-session.js +13 -16
  30. package/dist/hono/openrouter-session.js.map +1 -1
  31. package/dist/hono/publish-handoff.d.ts +0 -1
  32. package/dist/hono/publish-handoff.d.ts.map +1 -1
  33. package/dist/hono/publish-handoff.js +0 -53
  34. package/dist/hono/publish-handoff.js.map +1 -1
  35. package/dist/hono/publish-handoff.test.js +0 -48
  36. package/dist/hono/publish-handoff.test.js.map +1 -1
  37. package/dist/hono/relay.d.ts +0 -8
  38. package/dist/hono/relay.d.ts.map +1 -1
  39. package/dist/hono/relay.js +0 -2
  40. package/dist/hono/relay.js.map +1 -1
  41. package/dist/hono/relay.test.js +0 -24
  42. package/dist/hono/relay.test.js.map +1 -1
  43. package/dist/hono/runtime-files.d.ts +0 -1
  44. package/dist/hono/runtime-files.d.ts.map +1 -1
  45. package/dist/hono/runtime-files.js +0 -3
  46. package/dist/hono/runtime-files.js.map +1 -1
  47. package/dist/hono/types.d.ts +0 -12
  48. package/dist/hono/types.d.ts.map +1 -1
  49. package/dist/review/digest.d.ts +0 -13
  50. package/dist/review/digest.d.ts.map +1 -1
  51. package/dist/review/digest.js +1 -1
  52. package/dist/review/digest.js.map +1 -1
  53. package/package.json +1 -1
  54. package/dist/hono/effort-route.d.ts +0 -43
  55. package/dist/hono/effort-route.d.ts.map +0 -1
  56. package/dist/hono/effort-route.js +0 -36
  57. package/dist/hono/effort-route.js.map +0 -1
  58. package/dist/hono/effort-route.test.d.ts +0 -2
  59. package/dist/hono/effort-route.test.d.ts.map +0 -1
  60. package/dist/hono/effort-route.test.js +0 -54
  61. package/dist/hono/effort-route.test.js.map +0 -1
  62. package/dist/hono/tool-result-ledger.d.ts +0 -30
  63. package/dist/hono/tool-result-ledger.d.ts.map +0 -1
  64. package/dist/hono/tool-result-ledger.js +0 -63
  65. package/dist/hono/tool-result-ledger.js.map +0 -1
  66. package/dist/hono/tool-result-ledger.test.d.ts +0 -2
  67. package/dist/hono/tool-result-ledger.test.d.ts.map +0 -1
  68. package/dist/hono/tool-result-ledger.test.js +0 -61
  69. package/dist/hono/tool-result-ledger.test.js.map +0 -1
  70. package/dist/hono/workspace-instructions.d.ts +0 -43
  71. package/dist/hono/workspace-instructions.d.ts.map +0 -1
  72. package/dist/hono/workspace-instructions.js +0 -68
  73. package/dist/hono/workspace-instructions.js.map +0 -1
  74. package/dist/hono/workspace-instructions.test.d.ts +0 -2
  75. package/dist/hono/workspace-instructions.test.d.ts.map +0 -1
  76. package/dist/hono/workspace-instructions.test.js +0 -68
  77. package/dist/hono/workspace-instructions.test.js.map +0 -1
@@ -15,7 +15,6 @@ import { CONNECTION_INPUT_TOOL_NAME, CONNECTION_PLATFORMS, connectedButNotLoaded
15
15
  import { messageContextTokens, pickContextWindow, streamEventContextUsage, turnContextUsage, } from "./context-usage.js";
16
16
  import { CREDENTIAL_INPUT_TOOL_NAME, normalizeCredentialInputToolInput, } from "./credential-input.js";
17
17
  import { credentialScrubHooks } from "./credential-scrub.js";
18
- import { DEFAULT_TURN_EFFORT, decideTurnEffort } from "./effort-route.js";
19
18
  import { agentStatedFlowMessage, FLOW_INPUT_TOOL_NAME, nodeTargetRefusals, normalizeFlowInputToolInput, readRawFlowTree, sanitizeFlowRequests, unknownFlowPrefillMessage, } from "./flow-input.js";
20
19
  import { writesInventedLogo } from "./invented-logo.js";
21
20
  import { jevJudge } from "./jev.js";
@@ -24,7 +23,7 @@ import { composioScopesToInvalidate, failedCustomServers, reportMcpInvalid, serv
24
23
  import { agentModelOverride, autoCompactWindowForModel, betasForModel, contextWindowForModel, } from "./model-capabilities.js";
25
24
  import { agentShellPrefixEnv, killFirstWrapper } from "./oom-priority.js";
26
25
  import { anthropicCustomHeaders, runtimeOpenRouterTags } from "./openrouter-attribution.js";
27
- import { buildAgentExtraBody, EXTRA_BODY_ENV, MODEL_CAPABILITIES_ENV, PER_TURN_EFFORT_CAPABILITIES, } from "./openrouter-session.js";
26
+ import { BEDROCK_SERVABLE_CAPABILITIES, buildAgentExtraBody, EXTRA_BODY_ENV, MODEL_CAPABILITIES_ENV, } from "./openrouter-session.js";
28
27
  import { credentialReminder, currentReferenceReminder, kickoffBriefReminder } from "./prompt-context.js";
29
28
  import { publishLanguageReminder, publishRunReminder, publishStandingReminder } from "./publish-handoff.js";
30
29
  import { bridgeRuntimeFiles } from "./runtime-files.js";
@@ -36,10 +35,8 @@ import { skillLanguageHooks } from "./skill-language.js";
36
35
  import { BridgeSlashCommands, leadingSkillCommand, verbatimSlashCommand } from "./slash-commands.js";
37
36
  import { createBakerUiServer, normalizeTagInputToolInput, sanitizeTagChanges, TAG_INPUT_TOOL_NAME, unknownPrefillMessage, } from "./tag-input.js";
38
37
  import { blockingToolDelegated, toolRunAsCommand } from "./tool-in-shell.js";
39
- import { ToolResultLedger } from "./tool-result-ledger.js";
40
38
  import { recordTurnEvent } from "./turn-events.js";
41
39
  import { addQueryModelUsage, queryModelUsage, turnModelUsageList } from "./turn-model-usage.js";
42
- import { prepareSharedInstructions } from "./workspace-instructions.js";
43
40
  import { settleWorkspaceAfterTasks } from "./workspace-settle.js";
44
41
  export function parsePlanDecision(value) {
45
42
  if (!value || typeof value !== "object") {
@@ -220,13 +217,6 @@ const BASE_DISALLOWED_TOOLS = [
220
217
  // not asked to fund a research fleet. Ordinary fan-out is unaffected:
221
218
  // `Task` stays, so the scaffold's subagents still run.
222
219
  "Workflow",
223
- // Developer tools: design-system sync, code-review findings, Jupyter edits.
224
- // None was called once in 358 production chats (Oct 2026), and each
225
- // definition rides every request whenever the CLI does not defer it —
226
- // DesignSync's alone is ~9k characters.
227
- "DesignSync",
228
- "ReportFindings",
229
- "NotebookEdit",
230
220
  // NOT listed: `SendMessage`. It is how the model follows up with a
231
221
  // subagent it already ran, and the CLI tells it to on every Agent result.
232
222
  // The continued subagent runs in the background, but it announces itself
@@ -255,7 +245,7 @@ function disallowedToolsFor(job) {
255
245
  function modelForJob(job, sessionModel) {
256
246
  return job.review?.model ?? sessionModel;
257
247
  }
258
- export const REVIEW_DISALLOWED_TOOLS = ["Edit", "Write", "MultiEdit", "ExitPlanMode", "Skill"];
248
+ export const REVIEW_DISALLOWED_TOOLS = ["Edit", "Write", "MultiEdit", "NotebookEdit", "ExitPlanMode", "Skill"];
259
249
  /**
260
250
  * The findings contract, enforced by the SDK rather than parsed back out of
261
251
  * prose. `structured_output` on the result message is what reaches Convex, and
@@ -442,19 +432,6 @@ function createBridgeJobState() {
442
432
  detachedSession: false,
443
433
  modelUsageTotals: new Map(),
444
434
  queryModelUsage: new Map(),
445
- toolResults: new ToolResultLedger(),
446
- };
447
- }
448
- /** What a finished turn reports about its spend: per-model usage and per-tool result sizes. */
449
- function turnUsage(state) {
450
- const toolResults = state.toolResults.summary();
451
- return {
452
- modelUsage: turnModelUsageList(state.modelUsageTotals),
453
- ...(toolResults.length > 0 ? { toolResults } : {}),
454
- // An unjudged turn is left off: no decision on the record means Jev never answered.
455
- ...(state.effortDecision && state.effortDecision.reason !== "unjudged"
456
- ? { effortDecision: state.effortDecision }
457
- : {}),
458
435
  };
459
436
  }
460
437
  function errorMessage(error) {
@@ -531,21 +508,6 @@ function hookSettingsForJob(job) {
531
508
  }
532
509
  return {};
533
510
  }
534
- /**
535
- * Which instruction files a job loads as memory. A Session review loads none:
536
- * its brief has it read the rulebook as the Session had it (`git show
537
- * <sha>:CLAUDE.md`), since Publish may already have moved the working tree past
538
- * it, and the auto-loaded copy is ~24k tokens of the marketer's instructions
539
- * written cold and re-read on every review request. The client's agent loads
540
- * the workspace's `CLAUDE.md` itself only when it could not be split into the
541
- * shared system prompt (`prepareSharedInstructions`).
542
- */
543
- function instructionSettingsForJob(job, sharedInstructions) {
544
- if (job.review) {
545
- return { claudeMdExcludes: ["**/CLAUDE.md"] };
546
- }
547
- return sharedInstructions ? { claudeMdExcludes: [join(bridgeRuntimeFiles.projectRoot(), "CLAUDE.md")] } : {};
548
- }
549
511
  // Carry a Runtime-wide model override down to the fan-out workers.
550
512
  //
551
513
  // The shared subagents pin themselves to Sonnet 5.5 in their own frontmatter (see
@@ -1205,9 +1167,9 @@ export class BridgeJobExecutor {
1205
1167
  settleWorkspace;
1206
1168
  catchUpWithMain;
1207
1169
  holdsNoWork;
1170
+ settleAfterPublish;
1208
1171
  keepCliInStep;
1209
1172
  judge;
1210
- effortJudge;
1211
1173
  constructor(dependencies) {
1212
1174
  this.sdk = dependencies.sdk;
1213
1175
  this.relay = dependencies.relay;
@@ -1230,15 +1192,13 @@ export class BridgeJobExecutor {
1230
1192
  this.settleWorkspace = dependencies.settleWorkspace ?? (() => settleWorkspaceAfterTasks());
1231
1193
  this.catchUpWithMain = dependencies.catchUpWithMain;
1232
1194
  this.holdsNoWork = dependencies.holdsNoWork;
1195
+ this.settleAfterPublish = dependencies.settleAfterPublish;
1233
1196
  this.keepCliInStep = dependencies.keepCliInStep;
1234
1197
  this.readFlowTree =
1235
1198
  dependencies.readFlowTree ?? ((flowSlug) => readRawFlowTree(bridgeRuntimeFiles.flowsDir(), flowSlug));
1236
1199
  this.judge =
1237
1200
  dependencies.judge ??
1238
1201
  jevJudge(process.env.OPENROUTER_API_KEY, runtimeOpenRouterTags(process.env, { service: "bridge", feature: "bridge.toolCallGuard" }));
1239
- this.effortJudge =
1240
- dependencies.effortJudge ??
1241
- jevJudge(process.env.OPENROUTER_API_KEY, runtimeOpenRouterTags(process.env, { service: "bridge", feature: "bridge.effortRoute" }));
1242
1202
  }
1243
1203
  async execute(job, controls) {
1244
1204
  try {
@@ -1250,26 +1210,6 @@ export class BridgeJobExecutor {
1250
1210
  await this.inFlightTurns.clear(job.threadId, job.turnId).catch(() => undefined);
1251
1211
  }
1252
1212
  }
1253
- /**
1254
- * How hard the agent works on this turn (see `effort-route.ts`); null for a
1255
- * Session review, which keeps the default. Never throws: an unanswered judge
1256
- * is the default level.
1257
- */
1258
- async decideEffort(job, request) {
1259
- if (job.review) {
1260
- return null;
1261
- }
1262
- const lastReply = (job.history?.entries ?? []).filter((entry) => entry.role === "assistant").at(-1);
1263
- return await decideTurnEffort({
1264
- message: job.prompt,
1265
- previousReply: lastReply?.text ?? "",
1266
- judge: this.effortJudge,
1267
- planMode: job.planMode === true,
1268
- leadingCommand: request.leadingCommand,
1269
- unattended: job.unattended === true,
1270
- hasAttachments: (job.attachments?.length ?? 0) > 0,
1271
- }).catch(() => ({ effort: DEFAULT_TURN_EFFORT, reason: "unjudged" }));
1272
- }
1273
1213
  async executeTurn(job, controls) {
1274
1214
  const state = createBridgeJobState();
1275
1215
  let result = { costUsd: 0, attemptedRehydration: false };
@@ -1281,8 +1221,6 @@ export class BridgeJobExecutor {
1281
1221
  if (!request?.prompt || !controls.isActive()) {
1282
1222
  return { kind: "cancelled", costUsd: 0, model: state.model };
1283
1223
  }
1284
- // Asked while the boundary loads, so the answer (~0.3 s) costs the turn no time.
1285
- const effortDecision = this.decideEffort(job, request);
1286
1224
  const loaded = await this.loadTrustedBoundary(job, controls);
1287
1225
  if (loaded?.kind !== "clean") {
1288
1226
  request = await this.withContinuedAttachments(job, request);
@@ -1301,7 +1239,6 @@ export class BridgeJobExecutor {
1301
1239
  state.detachedSession = attempt.detachedSession === true;
1302
1240
  result.attemptedRehydration = attempt.attemptedRehydration;
1303
1241
  this.recordAttemptContextSource(job, attempt);
1304
- state.effortDecision = (await effortDecision) ?? undefined;
1305
1242
  result = await this.runAttempt(job, controls, state, attempt);
1306
1243
  return await this.finishSuccessfulAttempt(job, controls, state, result.costUsd);
1307
1244
  }
@@ -1310,8 +1247,6 @@ export class BridgeJobExecutor {
1310
1247
  if (repaired && controls.isActive()) {
1311
1248
  const repairState = createBridgeJobState();
1312
1249
  repairState.detachedSession = repaired.detachedSession === true;
1313
- // The same turn, so the same level: a changed one would re-write the cache.
1314
- repairState.effortDecision = state.effortDecision;
1315
1250
  let repairResult = { costUsd: 0, attemptedRehydration: repaired.attemptedRehydration };
1316
1251
  try {
1317
1252
  repairResult = await this.runAttempt(job, controls, repairState, repaired);
@@ -1514,22 +1449,22 @@ export class BridgeJobExecutor {
1514
1449
  return { costUsd, attemptedRehydration: attempt.attemptedRehydration };
1515
1450
  }
1516
1451
  async finishSuccessfulAttempt(job, controls, state, costUsd) {
1517
- const usage = turnUsage(state);
1452
+ const modelUsage = turnModelUsageList(state.modelUsageTotals);
1518
1453
  if (!controls.isActive()) {
1519
1454
  await this.clearIfDirty(job, controls, state, "abort");
1520
- return { kind: "cancelled", costUsd, model: state.model, ...usage };
1455
+ return { kind: "cancelled", costUsd, model: state.model, modelUsage };
1521
1456
  }
1522
1457
  // No boundary is handed back, so the refused exchange never becomes part of
1523
1458
  // the conversation the next message resumes.
1524
1459
  if (state.refusedWithoutFallback) {
1525
- return { kind: "errored", costUsd, model: state.model, ...usage, errors: [MODEL_REFUSAL_MESSAGE] };
1460
+ return { kind: "errored", costUsd, model: state.model, modelUsage, errors: [MODEL_REFUSAL_MESSAGE] };
1526
1461
  }
1527
1462
  if (!state.postedAssistantEvent && state.turnText.length > 0) {
1528
1463
  await this.postSyntheticAssistantEvent(job, state);
1529
1464
  }
1530
1465
  if (!controls.isActive()) {
1531
1466
  await this.clearIfDirty(job, controls, state, "abort");
1532
- return { kind: "cancelled", costUsd, model: state.model, ...usage };
1467
+ return { kind: "cancelled", costUsd, model: state.model, modelUsage };
1533
1468
  }
1534
1469
  // A detached turn (publish) ran in a session of its own. Handing that session
1535
1470
  // back as the thread's boundary would make the next chat message resume a
@@ -1542,11 +1477,17 @@ export class BridgeJobExecutor {
1542
1477
  // `closeRunThatChangedNothing`), and only the Runtime can vouch for its files.
1543
1478
  // Never after a publish turn: that one settles the chat itself.
1544
1479
  const workspaceUnchanged = !state.detachedSession && !job.review && this.holdsNoWork !== undefined && (await this.holdsNoWork());
1480
+ // A publish turn's push is settled before the chat goes on: its next turn starts from what went live.
1481
+ if (state.detachedSession) {
1482
+ await this.settleAfterPublish?.().catch((error) => {
1483
+ console.error(`[BridgeJob] could not settle the publish for ${job.threadId}`, error);
1484
+ });
1485
+ }
1545
1486
  return {
1546
1487
  kind: "completed",
1547
1488
  costUsd,
1548
1489
  model: state.model,
1549
- ...usage,
1490
+ modelUsage,
1550
1491
  ...(workspaceUnchanged ? { workspaceUnchanged: true } : {}),
1551
1492
  cleanBoundary,
1552
1493
  ...(state.structuredOutput === undefined ? {} : { structuredOutput: state.structuredOutput }),
@@ -1554,7 +1495,7 @@ export class BridgeJobExecutor {
1554
1495
  }
1555
1496
  errorOutcome(job, controls, state, result, error) {
1556
1497
  const model = state.model;
1557
- const usage = turnUsage(state);
1498
+ const modelUsage = turnModelUsageList(state.modelUsageTotals);
1558
1499
  if (result.attemptedRehydration) {
1559
1500
  void this.relay.contextSource({ threadId: job.threadId, turnId: job.turnId }, "rehydration_failed", {
1560
1501
  historyEntryCount: job.history?.entries.length ?? 0,
@@ -1564,7 +1505,7 @@ export class BridgeJobExecutor {
1564
1505
  });
1565
1506
  }
1566
1507
  if (!controls.isActive()) {
1567
- return { kind: "cancelled", costUsd: result.costUsd, model, ...usage };
1508
+ return { kind: "cancelled", costUsd: result.costUsd, model, modelUsage };
1568
1509
  }
1569
1510
  const shown = userFacingTurnError(error);
1570
1511
  if (shown !== errorMessage(error)) {
@@ -1574,7 +1515,7 @@ export class BridgeJobExecutor {
1574
1515
  kind: "errored",
1575
1516
  costUsd: result.costUsd,
1576
1517
  model,
1577
- ...usage,
1518
+ modelUsage,
1578
1519
  errors: [shown],
1579
1520
  };
1580
1521
  }
@@ -1849,12 +1790,6 @@ export class BridgeJobExecutor {
1849
1790
  await this.alignResumedTranscript(attempt);
1850
1791
  const mcpServers = await this.resolveMcpServers(job);
1851
1792
  const skills = await readSessionSkills(bridgeRuntimeFiles.projectRoot());
1852
- const sharedInstructions = job.review
1853
- ? null
1854
- : await prepareSharedInstructions({
1855
- projectRoot: bridgeRuntimeFiles.projectRoot(),
1856
- contextDir: bridgeRuntimeFiles.instructionsDir(),
1857
- });
1858
1793
  const autoCompactWindow = autoCompactWindowForModel(model);
1859
1794
  const betas = betasForModel(model);
1860
1795
  // No `outputStyle`: the built-in `Concise` style was pinned here against Opus 5's
@@ -1890,7 +1825,6 @@ export class BridgeJobExecutor {
1890
1825
  }
1891
1826
  : {}),
1892
1827
  ...hookSettingsForJob(job),
1893
- ...instructionSettingsForJob(job, sharedInstructions),
1894
1828
  };
1895
1829
  const agentTags = runtimeOpenRouterTags(process.env, {
1896
1830
  service: "agent",
@@ -1910,29 +1844,15 @@ export class BridgeJobExecutor {
1910
1844
  // more per level than Opus 5, so compare `low` on real Sessions before
1911
1845
  // treating this as tuned.
1912
1846
  //
1913
- // A changed top-level effort alone re-writes the cached conversation from
1914
- // its first tool exchange onward. It may differ between turns only because
1915
- // the CLI also restates it per message (`PER_TURN_EFFORT_CAPABILITIES`),
1916
- // which keeps the cache; prose is no substitute.
1917
- effort: state.effortDecision?.effort ?? DEFAULT_TURN_EFFORT,
1847
+ // MUST stay a single constant. The resolved effort is rendered into the
1848
+ // prompt, so changing it between requests invalidates every cache
1849
+ // breakpoint above it — on a session carrying hundreds of thousands of
1850
+ // tokens that re-write costs far more than any per-turn tuning saves.
1851
+ // Vary it per message only once the route accepts per-message effort
1852
+ // (see `BEDROCK_SERVABLE_CAPABILITIES`); prose is no substitute.
1853
+ effort: "medium",
1918
1854
  cwd: process.cwd(),
1919
1855
  settingSources: ["project"],
1920
- // The scaffold's CLAUDE.md, minus its `@COMPANY.md` import, as the system
1921
- // prompt, so every chat reads one cached copy instead of writing its own;
1922
- // the import loads from `instructionsDir` (see workspace-instructions.ts).
1923
- ...(sharedInstructions
1924
- ? {
1925
- systemPrompt: {
1926
- type: "preset",
1927
- preset: "claude_code",
1928
- append: sharedInstructions.shared,
1929
- // Recorded once per conversation, so a scaffold sync mid-chat cannot
1930
- // move the cached prefix under it; it lands at the next compaction.
1931
- snapshot: true,
1932
- },
1933
- additionalDirectories: [bridgeRuntimeFiles.instructionsDir()],
1934
- }
1935
- : {}),
1936
1856
  // `baker_ui` hosts in-process interactive dashboard tools (secure tag
1937
1857
  // form). Always present; HTTP (Composio) servers merge alongside it.
1938
1858
  mcpServers: { ...(mcpServers ?? {}), baker_ui: createBakerUiServer({ credentials: credentialsEnabled() }) },
@@ -1984,8 +1904,6 @@ export class BridgeJobExecutor {
1984
1904
  // they are never TTY-gated, so every help read the agent does inside
1985
1905
  // the sandbox pays ~5-10% of its tokens on colour codes it can't see.
1986
1906
  NO_COLOR: "1",
1987
- // Loads the `CLAUDE.md` in `instructionsDir`, which imports COMPANY.md.
1988
- ...(sharedInstructions ? { CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD: "1" } : {}),
1989
1907
  // Pin the conversation to one OpenRouter provider instance so the
1990
1908
  // instance-scoped prompt cache is actually re-read across the turn's
1991
1909
  // many tool-call requests. Merged into every model request body by the
@@ -1997,8 +1915,12 @@ export class BridgeJobExecutor {
1997
1915
  ANTHROPIC_CUSTOM_HEADERS: [process.env.ANTHROPIC_CUSTOM_HEADERS, anthropicCustomHeaders(agentTags.headers)]
1998
1916
  .filter(Boolean)
1999
1917
  .join("\n"),
2000
- // Lets a turn change effort without losing the prompt cache; see openrouter-session.ts.
2001
- [MODEL_CAPABILITIES_ENV]: PER_TURN_EFFORT_CAPABILITIES,
1918
+ // Without it no Opus 5.5 request can reach Bedrock; see openrouter-session.ts.
1919
+ [MODEL_CAPABILITIES_ENV]: BEDROCK_SERVABLE_CAPABILITIES,
1920
+ // The CLI names each session with a second, structured-output request on the
1921
+ // turn's model. OpenRouter's Bedrock cannot serve that, so it was billed to
1922
+ // OpenRouter credits on Azure or Vertex, and nothing in Baker reads the name.
1923
+ CLAUDE_CODE_DISABLE_TERMINAL_TITLE: "1",
2002
1924
  // The turn's message sender, so in-sandbox `baker` calls can scope to the acting user.
2003
1925
  ...(job.currentSender?.userId ? { BAKER_ACTING_USER_ID: job.currentSender.userId } : {}),
2004
1926
  ...subagentModelEnv(),
@@ -2076,7 +1998,6 @@ export class BridgeJobExecutor {
2076
1998
  for await (const msg of query) {
2077
1999
  stallDetector.observeMessage(msg);
2078
2000
  turnEnd.observeMessage(msg);
2079
- state.toolResults.observe(msg);
2080
2001
  controls.setWorkInFlight?.(stallDetector.hasPendingToolUses() || turnEnd.hasInFlightWork());
2081
2002
  try {
2082
2003
  costUsd = await this.consumeSdkMessage(job, controls, state, msg, costUsd);