Skip to content

fix(agents): preserve thinking blocks in latest assistant message during compaction#25381

Closed
Nipurn123 wants to merge 9 commits intoopenclaw:mainfrom
Nipurn123:fix/thinking-blocks-compaction-25347
Closed

fix(agents): preserve thinking blocks in latest assistant message during compaction#25381
Nipurn123 wants to merge 9 commits intoopenclaw:mainfrom
Nipurn123:fix/thinking-blocks-compaction-25347

Conversation

@Nipurn123
Copy link
Copy Markdown

@Nipurn123 Nipurn123 commented Feb 24, 2026

Summary

Root Cause

The Anthropic API requires that thinking/redacted_thinking blocks in the latest assistant message remain exactly as received. The dropThinkingBlocks() function was stripping ALL thinking blocks from ALL assistant messages, causing this error during longer conversations:

LLM request rejected: messages.51.content.1: thinking or redacted_thinking blocks in the latest assistant message cannot be modified.

Changes

  • src/agents/pi-embedded-runner/thinking.ts - Added logic to find and skip the latest assistant message when dropping thinking blocks
  • src/agents/pi-embedded-runner/thinking.test.ts - Added 4 new tests for latest assistant preservation
  • src/agents/pi-embedded-runner.sanitize-session-history.test.ts - Updated 3 tests + added 1 new test for the behavior

Testing

  • All 31 related tests pass
  • pnpm check passes (lint/format)

Greptile Summary

This PR bundles three independent changes: (1) a fix for Anthropic API 400 errors by preserving thinking blocks in the latest assistant message during context compaction, (2) a refactor of extra-params.ts from inline provider if/else to a registry-based pattern, and (3) a new Telegram sendDice action with full threading/gating support plus orphan transcript cleanup on gateway startup.

  • Thinking block fix (thinking.ts): dropThinkingBlocks() now scans backward to find the latest assistant message and preserves it intact, only stripping thinking blocks from older assistant messages. This directly fixes the API rejection error. Well-tested with 4 new unit tests and updated integration tests.
  • Provider handler registry (extra-params.ts): Refactored provider-specific stream wrapper logic into a Map<string, ProviderHandler[]> registry with a * wildcard for universal handlers. Functionally equivalent to the old code — Map insertion order preserves the original application sequence.
  • Telegram dice action: Adds sendDice support across the full stack — types, send function, action handler, plugin adapter, and action spec. Includes emoji validation, threading, and gating. Minor formatting bug in the error message (missing space between emojis).
  • Orphan transcript cleanup (server-startup.ts): New cleanupOrphanTranscripts() archives .jsonl transcript files not referenced in the session store, with a safety threshold of 10 files before cleanup activates.

Confidence Score: 4/5

  • This PR is safe to merge with one minor formatting fix recommended in the dice emoji error message.
  • The core thinking block fix is well-implemented and thoroughly tested. The provider handler registry refactor is functionally equivalent to the original code. The Telegram dice feature follows established patterns. The only issue found is a missing space in an error message string. The orphan cleanup has appropriate safety guards (threshold, best-effort error handling).
  • src/agents/tools/telegram-actions.ts has a minor formatting bug in the dice emoji error message (missing space between ⚽ and 🎳).

Last reviewed commit: 70f78dd

Nipurn123 and others added 8 commits February 24, 2026 16:37
- Add sendDiceTelegram function to telegram/send.ts
- Support all dice emojis: 🎲 🎯 🏀 ⚽ 🎳 🎰
- Return dice value in result so agent knows outcome
- Wire into message tool via handleTelegramAction
- Default enabled via sendDice action gate

Closes openclaw#25263
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Replace hardcoded provider checks with a provider handler registry pattern:

- Add ProviderHandler type with createWrapper and enabledWhen hooks
- Create providerHandlers registry with entries for:
  - anthropic: beta headers
  - openrouter: app headers + reasoning effort + system cache
  - amazon-bedrock: non-Anthropic cache disable
  - zai/z-ai: tool_stream injection
  - *: OpenAI Responses store wrapper (applies to all)
- Simplify applyExtraParamsToAgent with registry iteration

Benefits:
- Easier to add new providers
- Clearer separation of concerns
- Each provider's logic is self-contained

Closes openclaw#25311
…ing compaction

Anthropic's API requires that thinking/redacted_thinking blocks in the
latest assistant message remain exactly as received. The dropThinkingBlocks()
function was stripping ALL thinking blocks from ALL assistant messages,
causing API 400 errors during context compaction in longer conversations.

Now the function preserves thinking blocks in the latest assistant message
while still stripping them from older messages (needed for GitHub Copilot
compatibility).

Fixes openclaw#25347
@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram gateway Gateway runtime agents Agent runtime and tooling size: L labels Feb 24, 2026
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

12 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

const to = readStringParam(params, "to", { required: true });
const emoji = readStringParam(params, "emoji");
if (emoji && !["🎲", "🎯", "🏀", "⚽", "🎳", "🎰"].includes(emoji)) {
throw new Error(`Invalid dice emoji: ${emoji}. Must be one of: 🎲 🎯 🏀 ⚽🎳 🎰`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space in error message

The error message is missing a space between and 🎳. The validation array on line 382 correctly lists all 6 emoji as separate items, but the user-facing error message concatenates two of them.

Suggested change
throw new Error(`Invalid dice emoji: ${emoji}. Must be one of: 🎲 🎯 🏀 ⚽🎳 🎰`);
throw new Error(`Invalid dice emoji: ${emoji}. Must be one of: 🎲 🎯 🏀 ⚽ 🎳 🎰`);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/telegram-actions.ts
Line: 383

Comment:
**Missing space in error message**

The error message is missing a space between `` and `🎳`. The validation array on line 382 correctly lists all 6 emoji as separate items, but the user-facing error message concatenates two of them.

```suggestion
      throw new Error(`Invalid dice emoji: ${emoji}. Must be one of: 🎲 🎯 🏀 ⚽ 🎳 🎰`);
```

How can I resolve this? If you propose a fix, please make it concise.

…ompaction-25347

# Conflicts:
#	src/agents/pi-embedded-runner/extra-params.ts
@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Mar 3, 2026
Copy link
Copy Markdown
Contributor

@xiaoyaner0201 xiaoyaner0201 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Duplicate PR Group: Anthropic Thinking Block Compaction

This PR is one of 7 open PRs addressing the same issue: Anthropic thinking/redacted_thinking blocks from older assistant messages cause API errors during context compaction.

Related PRs

PR Author Date Approach Preserves latest redacted_thinking Compaction path Tests Clean diff
#24261 @Vaibhavee89 02-23 Guard functions + logging N/A (no actual strip) Detect only Medium
#25381 @Nipurn123 02-24 Modify dropThinkingBlocks skip latest Good ❌ (bundles sendDice)
#27142 @slatem 02-26 Extend dropThinkingBlocks to Anthropic ❌ (strips all) Limited
#39919 @taw0002 03-08 New strip function in sanitizeSessionHistory Good
#39940 @liangruochong44-ui 03-08 Policy flag for Anthropic ❌ (strips all) Medium ❌ (bundles cron/SQLite/UI)
#43783 @coletoncodes 03-12 New stripThinkingFromNonLatestAssistant + compact path Best
#44650 @rikisann 03-13 Runtime monkey-patch of node_modules None ⚠️ Fragile approach

Analysis

After reading all 7 diffs:

#43783 is the strongest candidate. It:

  1. Creates a standalone stripThinkingFromNonLatestAssistant() without changing dropThinkingBlocks semantics (preserves Copilot behavior)
  2. Integrates via existing policy.preserveSignatures flag (proper transcript policy mechanism)
  3. Only PR that also fixes the compaction path (compact.ts) — others only fix sanitizeSessionHistory
  4. Handles both thinking and redacted_thinking block types
  5. Clean diff with comprehensive tests (toolResult interleaving, empty blocks, reference equality)

#39919 is a close second (same core function, clean diff, good tests) but misses the compaction path.

Notable discovery from #44650: sanitizeSurrogates may corrupt thinking block signatures — worth investigating separately even though the monkey-patch approach is not viable.

Not recommended: #27142 and #39940 strip thinking from ALL messages including latest (breaks multi-turn quality). #25381 and #39940 bundle unrelated changes.

Similarities identified via embedding-based clustering (cosine > 0.82). Maintainers: #43783 appears ready for review.

@openclaw-barnacle openclaw-barnacle bot removed the stale Marked as stale due to inactivity label Mar 23, 2026
@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Mar 30, 2026
@obviyus
Copy link
Copy Markdown
Contributor

obviyus commented Apr 1, 2026

Closing as duplicate; this was superseded by #58916.

@obviyus obviyus closed this Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: telegram Channel integration: telegram gateway Gateway runtime size: L stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: thinking/redacted_thinking blocks get modified during context compaction → API 400 error

3 participants