| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
…es (anomalyco#16748) Add failing test demonstrating that normalizeMessages() removes empty text parts between reasoning blocks in assistant messages, invalidating Anthropic thinking block signatures. The test constructs [reasoning(sig1), text(''), reasoning(sig2), text('...'), tool-call] and asserts all 5 parts are preserved. Currently fails with Expected length: 5, Received length: 4.
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
Sorry, something went wrong.
|
The following comment was made by an LLM, it may be inaccurate: Based on my search results, I found related PRs addressing thinking block and empty content filtering issues, but these appear to be related fixes rather than duplicates of the current test reproduction PR (#16750): Related PRs:
The current PR #16750 is a test reproduction case that demonstrates the issue described in #16748, whereas the related PRs are attempted fixes or related provider handling. No exact duplicate reproduction test was found. |
Sorry, something went wrong.
…rmalizeMessages Assistant messages must be replayed verbatim because Anthropic thinking block signatures encode positional context. Removing an empty text part between two reasoning blocks changes the block arrangement and invalidates the cryptographic signatures, causing the API to reject with 'thinking blocks cannot be modified'. The empty-text filter is still applied to user and tool messages where Anthropic rejects empty content. Update existing tests to reflect that assistant content is now preserved, and add tests for non-assistant filtering.
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
Sorry, something went wrong.
The previous fix preserved all assistant messages verbatim in normalizeMessages to protect thinking block signatures. This was too broad — assistant messages without reasoning blocks (e.g. compaction summaries) also had empty text parts preserved, causing Anthropic to reject with 'text content blocks must be non-empty'. Now only assistant messages with reasoning blocks are preserved verbatim. Assistant messages without reasoning have empty text blocks filtered normally. Also clean up empty text parts at the source: in the processor text-end handler, remove parts that end up empty (no text, no metadata) instead of persisting them. Parts with metadata (thinking signatures) are still preserved.
…elete race The text-start handler persists an empty part to the DB, then text-end would conditionally delete it. If the process crashes between the two, a dangling empty part remains. The transform.ts and message-v2.ts replay-time defenses already handle empty text parts correctly, making the processor-level cleanup redundant.
History of the Modified CodeTimeline
How the bug emergedThe empty-content filter from Jan 5 (c285304a) was written before Opus 4.6 adaptive thinking existed (Feb 13). At the time, reasoning parts with empty text were genuinely useless — there were no cryptographic signatures to preserve. The filter treated all roles identically. Once Opus 4.6 arrived, it began producing patterns like: reasoning(sig1) → text("") → reasoning(sig2) → text("answer")
The empty text("") is structurally significant — the signatures encode positional context. There are two independent stripping points:
PRs in flight
SummaryThe code being modified was never designed for the Opus 4.6 world. The empty-content filter (c285304a, Jan 5) predates adaptive thinking by 5+ weeks and assumed empty parts are always safe to strip. The differentModel metadata guard (021e42c0b, Jan 20) was solving a real cross-provider problem but created a gap where same-model empty text parts lose their metadata lifeline. Both pieces of code were correct when written — the bug is an emergent interaction with Opus 4.6's signature-sensitive thinking blocks. |
Sorry, something went wrong.
Aborted assistant messages with [step-start, reasoning, text('')] were
included in the conversation replay because the empty text part passed
the 'has real content' check. The empty text survived normalizeMessages
(reasoning blocks present) and received cache_control via applyCaching,
causing Anthropic to reject with 'cache_control cannot be set for empty
text blocks'.
Two fixes:
- Exclude empty text from the aborted-message content check so messages
with only reasoning + empty text are skipped entirely
- Strip trailing empty text from assistant messages with reasoning in
normalizeMessages (interstitial empty text between reasoning blocks is
preserved for signature integrity)
Reproduces: ses_3272b8b1dffe8ACUMp7xjxhFEw
…ejection Defense-in-depth: when applyCaching selects the last content part to decorate with cache_control, it now walks backwards past empty text parts (text === ""). This prevents Anthropic from rejecting requests with 'cache_control cannot be set for empty text blocks', regardless of how the empty text ended up in the message array. If every content part is empty text, cache_control falls through to message-level options instead.
|
谢谢你的修复,这个问题困扰了我很久。 |
Sorry, something went wrong.
# Conflicts: # packages/app/src/context/layout.tsx # packages/app/src/pages/layout/sidebar-items.tsx
# Conflicts: # packages/opencode/src/provider/transform.ts # packages/opencode/test/session/message-v2.test.ts
# Conflicts: # packages/opencode/src/plugin/codex.ts
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Issue for this PR
Closes #16748
Related: #13286, #16246, #15074, #10970, #14716, #6176, #9364, #8010
Type of change
What does this PR do?
Fixes Anthropic API rejections (thinking blocks in the latest assistant message cannot be modified) caused by empty text parts being stripped from assistant messages, shifting thinking block positions and invalidating cryptographic signatures.
Root cause
Two independent filters remove empty text parts from assistant messages:
When Anthropic models use adaptive thinking (Opus 4.6, Sonnet 4.6), the model commonly emits a whitespace-only text part between reasoning blocks. After processor.ts:321 calls trimEnd(), this becomes "". Removing it changes the block arrangement (e.g., [thinking, text, thinking, text, tool_use] → [thinking, thinking, text, tool_use]), invalidating the positionally-sensitive thinking block signatures.
Changes
Relationship to other open PRs
AI SDK v5→v6 migration (#13527, #15997, #12342, #13228): The AI SDK's empty-text filter in convertToLanguageModelPrompt is identical in v5 and v6 — this bug exists on both versions and the v6 migration does not address it. Those PRs only change transform.ts/message-v2.ts for type compatibility (async toModelMessages, as typeof msg.content casts, toModelOutput wrapper change) and Opus 4.6 variant definitions.
Thinking block / signature PRs:
None of these PRs is a superset of this one. The transform.ts fix here is not covered by any other open PR.
How did you verify your code works?
Checklist