Repository navigation
Conversation
Several prompts are only sent with one request: the goal reminder after a compaction, the reconciled Plan mode reminder, the keep-alive, goal review and /btw prompts, and the compaction summary prompt with its template reminder. The conversation-tail cache breakpoint landed on them, so each request wrote a cache entry that no later request could read. The goal and Plan reminders also sat where the next request has other content: before the user's prompt, or after the latest tool result. The next request diverged from the cached prefix there and wrote the rest of the conversation again. The goal reminder stays until a continuation restates the objective, so this repeated on every step. Text parts can now be marked transient. Automatic message breakpoints stop before the first transient part, and before a system update that it follows, since Anthropic sends such an update in another form once a reply follows it. The reminders are appended at the tail as transient text, and the generate and compaction prompts are transient. The text transcript that compaction falls back to when the history no longer fits is sent without breakpoints: no other request starts with it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
No conflicts. dev changed session/generate.ts (usage is now returned and recorded), session/compaction.ts (model resolve hook) and schema/messages.ts (Freeform) next to this branch's edits. Co-Authored-By: Claude <[email protected]>
The assertion compares a whole content block, so the local body type needs the `type` field for the file to type-check. Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
I don't see anything blocking. I ran the #62554 reproduction script on the base and on this branch. It compiles consecutive Anthropic request bodies for three steps after a compaction:
- Base: each step's tail breakpoint covers content the next step no longer sends (in step 2 it sits on the goal reminder), so that cache entry is never read.
- This branch: the breakpoint stays before the reminder, and the next request sends the same blocks up to it.
transientdoesn't appear in the body.
cache-policy.test.ts and the goal, plan, compaction and generate tests pass, and typecheck:tsc is clean in packages/ai and packages/core. This was not checked against the live API.
Public API: TextPart in @opencode/ai gets a new optional transient?: boolean. This is backwards compatible: existing callers and messages don't change, and it doesn't reach the server's OpenAPI spec.
One small trade-off is noted inline on the compaction transcript fallback.
Related: #61775
One conflict, in session-compaction.test.ts: dev's anomalyco#63590 added the stored metadata assertions next to this branch's `transient` summary prompt. Both are kept. Co-Authored-By: Claude Fable 5.2 <[email protected]> Claude-Session: https://claude.ai/code/session_01X7arpqRMkdsRWVTteqLJM9
Since anomalyco#63590, request messages carry the stored Session message's metadata for hooks to read. The goal and Plan reminders replaced the last user message with a new UserMessage, whose constructor drops that field, so a context hook that ran after them no longer saw the prompt's metadata. Spread the message instead. The request is built from it either way: metadata is stripped and the message is made again before it is sent. Co-Authored-By: Claude Fable 5.2 <[email protected]> Claude-Session: https://claude.ai/code/session_01X7arpqRMkdsRWVTteqLJM9
There was a problem hiding this comment.
The new commits look fine. The merge leaves this PR's diff unchanged. The reminders now copy the last user message instead of building a new UserMessage, which keeps the request metadata #63590 added. That works with how #63590 strips the metadata and rebuilds each message before sending. I checked the new head: the goal, plan, compaction, generate and session-runner tests pass in packages/core, cache-policy.test.ts passes, and typecheck:tsc is clean in packages/ai and packages/core.
Public API: the same as before. TextPart in @opencode/ai gets an optional transient?: boolean, which is backwards compatible.
I have no new concerns.
Issue for this PR
Closes #62554
Type of change
What does this PR do?
Some text goes out with one request only: the goal reminder after a compaction, the reconciled Plan mode reminder, the
session.generateprompt with the instruction update previewed before it, and the compaction summary prompt with its template nudge. The conversation-tail cache breakpoint landed on that text, so the request wrote a cache entry that no later request could read. With an active goal after a compaction this happened on every step, so each step wrote the conversation again instead of reading it. #62554 has numbers from a 22-hour goal session on 2.2.7.Changes:
transientflag for request-local text. Automatic message breakpoints now stop before the first transient part, so the tail breakpoint sits on the last content the next request repeats. That can be the leading parts of a message whose last part is a reminder. The flag is never sent to a provider, and manual cache hints are not touched.session.generatemarks its prompt and the previewed instruction update as transient. Compaction marks the summary prompt and the nudge.cache: "none". No other request starts with the transcript, so breakpoints there only paid for writes.One Anthropic detail: on models that take native system updates, an update followed by user content is sent after that content, and one followed by a reply stays in place. When request-local text follows a system update, the breakpoints therefore end before the update as well, so the next request still reads the entry.
This conflicts with #61690 in
markMessages(cache-policy.ts). I'll rebase whichever of the two is still open when the other lands.How did you verify your code works?
cache-policy.test.tscompile two consecutive Anthropic requests of a turn that carries a reminder and check that the first request's breakpoint is on content the second one still sends, and that a system update before request-local text stays out of the cached prefix. The goal, Plan, compaction andsession.generatetests check where the reminder or prompt is placed and that it is marked.dev's sources those tests fail (2 inpackages/ai, 10 inpackages/core). With this branch they pass.devat101776024:bun test(2104 pass, 0 fail) andbun typecheckinpackages/ai; oxlint and prettier on the changed files.packages/coresuite on Windows: 6244 pass, 107 fail. The 107 are shell, ripgrep, MCP, config reload and symlink tests that don't run in my setup, and the same 107 fail withdev's versions of the changed files.bun typecheckinpackages/corereports errors only inperf/*.bench.tsandsrc/mcp/client.ts, because my install is older thandev's lockfile. None are in the files changed here.Screenshots / recordings
Not a UI change.
Checklist
🤖 Generated with Claude Code
Added by the opencode bot (AI-generated).
Related: #61775
Public API: adds optional
transienttoTextPartin @opencode/ai (backwards compatible)