fix(claude-sdk-oauth): ignore volatile top hooks in continuity hashes - #1085
fix(claude-sdk-oauth): ignore volatile top hooks in continuity hashes#1085codeg-dev wants to merge 3 commits into
Conversation
Top-of-turn injections (memory notice, goal continuation, rule/task blocks) convert to user-role bodies. Hashing them makes a rewrite or prepend look like sent_stream_diverged and flatten to a cold seed. Exclude them from isTransmittedMessage the same way content-less user messages are excluded (PR code-yeongyu#791). Genuine user rewrites stay fail-closed.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9aab0085ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| */ | ||
| export function isTransmittedMessage(message: { role: string }): message is SentMessage { | ||
| if (message.role !== "user" && message.role !== "toolResult") return false; | ||
| if (isVolatileHookMessage(message)) return false; |
There was a problem hiding this comment.
Preserve hook messages in incremental payloads
On any non-flatten resident turn containing one of these hooks—especially an automatic goal-continuation turn—this filter removes the hook from sentMessages(), and session-stream.ts later builds the actual delta payload from that same filtered array via buildDeltaPromptBlocks(messages.slice(from)). The SDK therefore never receives the continuation or updated memory/team/task context (and a hook-only turn can submit an empty user payload), even though the turn may be recorded as synchronized; exclude these messages only from continuity hashing, not from the transport message list.
Useful? React with 👍 / 👎.
…wire Review P1: isTransmittedMessage also feeds buildDeltaPromptBlocks(messages.slice(from)). Dropping hooks there would omit a goal-continuation-only turn. Neutralize hook content inside sentMessageHashes instead so rewrite does not flatten, while from still indexes the full transmitted list.
|
P1 accepted. Structural prepend still reports Pushed on this branch ( |
…tile hook types Co-authored-by: Code_G <288527233+codeg-dev@users.noreply.github.com> Signed-off-by: Code_G <288527233+codeg-dev@users.noreply.github.com>
Summary
Follow-on to #791. Top-of-turn hook injections (omo-memory notice, goal-continuation, mindy-team context blocks, senpi-task usage) convert to user-role bodies. Hashing those bodies makes a rewrite or prepend look like
sent_stream_diverged, sodecideFromBindingflattens to a cold seed and burns the Anthropic prompt cache even when the real conversation prefix is intact.isTransmittedMessageexcludes those hooks. Detection uses customType / provenance when present, and content signatures after convertToLlm strips customType.sent_stream_diverged(fail-closed).This is complementary to #1075 (rolling cache checkpoints after serialize). #1075 cannot help if continuity flattens the session first.
Evidence
bun x vitest --run packages/coding-agent/test/suite/regressions/claude-sdk-oauth-volatile-hook-continuity.test.ts packages/coding-agent/test/suite/regressions/790-claude-sdk-oauth-empty-user-continuity.test.ts(9 passed).Test plan
Summary by cubic
Prevents false session divergence in
claude-sdk-oauthby excluding volatile top-of-turn hook content from continuity hashes. Previously we hashed their converted user bodies, triggeringsent_stream_divergedand a flatten; now we hash them by kind while still transmitting them, so only real user edits cause divergence.customType/provenance and content signatures afterconvertToLlm.isTransmittedMessageunchanged; neutralizes hook content insidesentMessageHashesso delta indexing stays correct. Genuine user rewrites and structural prepends still diverge. Regression tests added.Written for commit 3fd8bde. Summary will update on new commits.