diff --git a/apps/x/packages/core/docs/turn-runtime-design.md b/apps/x/packages/core/docs/turn-runtime-design.md index 620a0ad8..5f462bd1 100644 --- a/apps/x/packages/core/docs/turn-runtime-design.md +++ b/apps/x/packages/core/docs/turn-runtime-design.md @@ -409,6 +409,15 @@ in `config/context.json` (`elideHistoricToolResults`, default true; `elideHistoricImages`, default true; `elideHistoricMiddlePaneContent`, default true). The inspect CLI composes through the same decorated resolver. +Caveat: elision makes the composed payload a function of the durable log +PLUS the config in effect at compose time — the one deliberate exception to +"recomposition from durable state alone" (§8.3). Within a turn this is +harmless (policy is loaded once per execution, at resolve time), but +inspecting an old turn after a config change may show different prefix +bytes than were transmitted; the inspect CLI prints the active policy so +the divergence is visible. If exact-bytes replay ever becomes a hard +requirement, record the applied policy on the turn and compose from that. + ### 6.7 Agent snapshot inheritance Session turns whose resolved system prompt and tool set are byte-identical diff --git a/apps/x/packages/core/src/turns/inspect-cli.ts b/apps/x/packages/core/src/turns/inspect-cli.ts index 3140148f..9326a73c 100644 --- a/apps/x/packages/core/src/turns/inspect-cli.ts +++ b/apps/x/packages/core/src/turns/inspect-cli.ts @@ -8,6 +8,10 @@ // messages (user-message context, attachments, tool-result envelopes) are // visible; the file itself stores only structural facts and references. // +// Caveat: historic-context elision reads config/context.json at compose +// time, so recomposition is exact only while that config matches what was +// live when the call ran. The header prints the policy in effect NOW. +// // Session mode prints the session overview (title, turns, statuses, sizes); // pass --turns to cascade full turn inspection for every turn. // @@ -27,7 +31,7 @@ import { convertFromMessages } from "../agents/runtime.js"; import { WorkDir } from "../config/config.js"; import { FSSessionRepo } from "../sessions/fs-repo.js"; import { composeModelRequest } from "./compose-model-request.js"; -import { createContextResolver } from "./context-elision.js"; +import { createContextResolver, loadElisionPolicy } from "./context-elision.js"; import { FSTurnRepo } from "./fs-repo.js"; const turnRepo = new FSTurnRepo({ @@ -81,6 +85,17 @@ async function inspectTurn( console.log( `agent ${agent.agentId} model ${agent.model.provider}/${agent.model.model} calls ${state.modelCalls.length}${inherited}`, ); + const policy = loadElisionPolicy(); + console.log( + `context elision (per config/context.json NOW; transmitted bytes reflect the config live at call time): ` + + [ + policy.toolResults + ? `toolResults>${policy.toolResultThresholdChars}` + : "toolResults off", + policy.images ? "images" : "images off", + policy.middlePaneContent ? "notes" : "notes off", + ].join(", "), + ); for (const call of state.modelCalls) { if (onlyIndex !== undefined && call.index !== onlyIndex) continue;