Skip to content

[Bug]: eval summary clamping triggers assistant_rewritten with claude-sdk-oauth #1472

Description

@yjacket

What happened?

With the built-in eval tool and claude-sdk-oauth, eval.prepareArguments clamps a summary longer than 80 characters by mutating the assistant tool-call arguments.

AssistantCommitBoundary hashes the provider-final assistant before that mutation and the committed assistant after it. The two summaries differ, so the turn is classified assistant_rewritten and continuity is invalidated. The next turn then forks or cold-flattens the session.

Live confirmation on an interactive root session (senpi 2026.9.6, claude-opus-5): I sent an 81-character summary, the session stored 80 characters ending in ..., a claude-sdk-oauth-binding entry recorded {"invalidated":true,"reason":"assistant_rewritten"}, and the following turn reported {"kind":"flatten","reason":"assistant_rewritten","deltaMessages":193,"payloadBytes":1209471} with 562,740 cache-write tokens in that single request.

In one earlier long session, 11/11 assistant_rewritten events matched the same pattern: original summaries were 81-103 characters and every committed summary was exactly 80.

This is distinct from #691, which normalized volatile thinking.startedAt / thinking.endedAt. Here the differing field is content[*].arguments.summary.

Steps to reproduce

Deterministic and offline, against the installed modules:

  1. Import AssistantCommitBoundary from .../claude-sdk-oauth/session-commit-boundary.js and clampEvalSummary from .../senpi-codemode/src/tool/eval-request.ts.

  2. Build a resident assistant message whose content is one eval tool call with this 81-character summary:

    01234567890123456789012345678901234567890123456789012345678901234567890123456789X

  3. Call captureProviderFinal(key, message).

  4. Apply the clamp: message.content[0].arguments.summary = clampEvalSummary(message.content[0].arguments.summary).

  5. Call commit(key, message, modelId).

Observed: rewritten. With a summary of 80 characters or fewer the same sequence returns clean.

Live variant: in an interactive claude-sdk-oauth session, have the model call eval once with the same 81-character summary, send one more message, then read the session JSONL.

Relevant paths:

  • packages/senpi-codemode/src/tool/eval-request.ts (clampEvalSummary)
  • packages/senpi-codemode/src/tool/eval-tool.ts (prepareArguments)
  • packages/coding-agent/src/core/extensions/builtin/claude-sdk-oauth/session-commit-boundary.ts (assistantContentHash)

Expected behavior

Argument normalization should not invalidate Claude SDK session continuity. Either canonicalize the summary before captureProviderFinal, or apply the same normalization inside assistantContentHash. The reproduction above should return clean, and the next turn should stay incremental when nothing semantic changed.

Version

  • senpi: 2026.9.6
  • omo-ai: 5.0.0-0.beta.45
  • Provider: claude-sdk-oauth
  • Models observed: claude-opus-5, claude-fable-5-1
  • OS: Windows 11 x64

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions