Skip to content

fix: handle thinking/redacted_thinking block immutability on context pruning#49714

Open
imaddde867 wants to merge 2 commits intoopenclaw:mainfrom
imaddde867:fix/thinking-block-pruning-error
Open

fix: handle thinking/redacted_thinking block immutability on context pruning#49714
imaddde867 wants to merge 2 commits intoopenclaw:mainfrom
imaddde867:fix/thinking-block-pruning-error

Conversation

@imaddde867
Copy link
Copy Markdown

Summary

  • Problem: When a long session with Anthropic extended thinking triggers context pruning, the API rejects with "thinking or redacted_thinking blocks cannot be modified" and the raw error string leaks to end-user chat channels (e.g. Telegram groups).
  • Why it matters: Users see confusing internal API error text instead of a helpful message, and the session becomes stuck with no auto-recovery.
  • What changed: (1) dropThinkingBlocks now also strips redacted_thinking blocks, (2) pruner char estimate excludes thinking blocks (they're stripped before the API, so counting them caused over-pruning), (3) new error classifier catches the specific Anthropic rejection and returns a friendly message, (4) auto-recovery resets the session (matching the existing role-ordering recovery pattern).
  • What did NOT change: No changes to pruning strategy, no changes to how thinking blocks are handled for non-Anthropic providers, no changes to the context event hook flow.

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • Gateway / orchestration

Linked Issue/PR

User-visible / Behavior Changes

  • Users no longer see raw API error strings about thinking block immutability in chat
  • Sessions with the error auto-reset with a friendly message: "Session history conflict (thinking block mismatch). I've reset the conversation - please try again."
  • Context pruning no longer over-prunes tool results when large thinking blocks are present

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS / any
  • Runtime: Node 22+
  • Model/provider: Anthropic Claude with extended thinking enabled
  • Integration/channel: Any (reported on Telegram)
  • Relevant config: contextPruning.mode: "cache-ttl" with extended thinking sessions

Steps

  1. Have a long multi-turn conversation (60+ messages) with extended thinking enabled
  2. Context pruning triggers (cache-ttl mode)
  3. A prior assistant message contains thinking/redacted_thinking blocks
  4. Pruning modifies context → Anthropic rejects

Expected

  • Error handled internally with session reset and friendly user message

Actual (before fix)

  • Raw API error string sent to chat channel

Evidence

  • Failing test/log before + passing after

All 3 test suites pass (37 tests total):

pnpm test -- src/agents/pi-embedded-runner/thinking.test.ts           # 5 passed
pnpm test -- src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts  # 24 passed
pnpm test -- src/agents/pi-extensions/context-pruning/pruner.test.ts  # 8 passed

Human Verification (required)

  • Verified scenarios: All three test suites pass with new tests covering redacted_thinking stripping, error classification (JSON-wrapped and plain), and pruner char estimate exclusion
  • Edge cases checked: Malformed thinking blocks (already tested in existing suite), empty content after stripping, short vs JSON-wrapped error strings
  • What I did not verify: Live end-to-end test with a real Anthropic extended thinking session (requires long conversation + cache-ttl expiry timing)

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert this commit
  • Files/config to restore: None
  • Known bad symptoms: If the regex is too broad, it could misclassify other errors as thinking-block errors (mitigated by specific pattern)

Risks and Mitigations

  • Risk: Regex thinking.*blocks?.*cannot.*modified could match unrelated errors
    • Mitigation: Pattern is specific to the Anthropic API error message format; placed before generic invalidRequest handler so it only intercepts the exact case

AI-assisted: Yes (lightly tested via unit tests; I understand what the code does)
Testing degree: Fully tested with 4 new unit tests across 3 test files

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 18, 2026

Greptile Summary

This PR fixes three related issues that surfaced when Anthropic extended-thinking sessions hit context pruning: (1) redacted_thinking blocks were not being stripped alongside thinking blocks, causing the API to reject with an immutability error; (2) the pruner was counting thinking-block chars in its context estimate, leading to over-pruning of tool results; and (3) the resulting raw API error string was leaking directly to end-user chat channels with no recovery path.

Key changes:

  • dropThinkingBlocks now drops both thinking and redacted_thinking block types — the test for the new case is included and correct.
  • estimateMessageChars in the pruner no longer counts thinking/redacted_thinking chars, since those blocks are stripped before the API call. The new test with a 10k thinking block validates the fix against a contextWindowTokensOverride: 100 budget.
  • isThinkingBlockImmutabilityError uses /thinking.*blocks?.*cannot.*modified/i. The regex is specific enough for the known Anthropic error message, and it is correctly placed before the generic invalid_request_error catch-all in formatAssistantErrorText.
  • Auto-recovery in agent-runner-execution.ts reuses resetSessionAfterRoleOrderingConflict — this works but the function name no longer reflects all callers (see inline comment).
  • The two-level fallback (early return on successful reset; ternary fallback in the generic handler) ensures the friendly message surfaces in all code paths.

Confidence Score: 4/5

  • Safe to merge — targeted bug fix with good test coverage and no behaviour changes for non-Anthropic providers.
  • All four changes are narrowly scoped to the thinking-block immutability problem. The regex is specific enough to avoid false positives, error ordering in formatAssistantErrorText is correct, the pruner fix is straightforward, and every new code path has a corresponding test. The only non-critical issue is the semantic mismatch of reusing resetSessionAfterRoleOrderingConflict for a different error class.
  • src/auto-reply/reply/agent-runner-execution.ts — verify resetSessionAfterRoleOrderingConflict has no role-ordering-specific guards that could prevent it from firing for thinking-block errors.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 737-739

Comment:
**Thinking-block check placed after missing-tool-call check**

The new `isThinkingBlockImmutabilityError` guard is positioned _after_ `isMissingToolCallInputError` but _before_ the generic `"type":"invalid_request_error"` regex. That ordering is intentional and correct — the Anthropic thinking-block rejection is itself an `invalid_request_error`, so the specific check must precede the catch-all.

One minor note: if a future error message somehow starts with a tool-call-input pattern _and_ contains the thinking-block phrase (highly unlikely), the tool-call handler would win. The current order appears fine given real-world messages, but it's worth documenting the dependency in a brief comment so the ordering is not accidentally swapped later.

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

---

This is a comment left during a code review.
Path: src/auto-reply/reply/agent-runner-execution.ts
Line: 565-575

Comment:
**`resetSessionAfterRoleOrderingConflict` reused for a semantically different error**

The function name implies it handles role-ordering conflicts specifically, but here it is called for a thinking-block immutability error. If `resetSessionAfterRoleOrderingConflict` ever gains role-ordering-specific logic (e.g., a guard that checks whether the error actually looks like a role conflict before resetting), it could inadvertently skip the reset for thinking-block errors.

Consider either:
- renaming the function to something more generic like `resetSessionAfterHistoryConflict`, or
- introducing a thin wrapper / a dedicated `resetSessionAfterThinkingConflict` that delegates to the same underlying reset.

As-is this works, but the semantic mismatch is a latent maintenance hazard.

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

Last reviewed commit: "fix: handle thinking..."

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cddf119cba

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: S labels Mar 18, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1d08eb03c0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

minupla pushed a commit to minupla/openclaw that referenced this pull request Mar 18, 2026
…ility on context pruning

Fixes leaked 'thinking or redacted_thinking blocks cannot be modified'
error message reaching chat channels during context pruning.
Also drops redacted_thinking from context estimator to prevent over-pruning.

Source: openclaw#49714
@imaddde867 imaddde867 force-pushed the fix/thinking-block-pruning-error branch from 42cf7c8 to 0867445 Compare March 18, 2026 12:37
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0867445e76

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

…pruning

Context pruning with Anthropic extended thinking triggers API rejection
("thinking or redacted_thinking blocks cannot be modified") and the raw
error leaks to end-user chat channels.

- Strip redacted_thinking blocks in dropThinkingBlocks (same immutability
  constraint as thinking blocks)
- Exclude thinking block chars from pruner context estimate (they are
  stripped before reaching the API, so counting them causes over-pruning)
- Classify the thinking-block immutability error with a friendly message
  and auto-recover via session reset
- Add tests for all three changes

Closes openclaw#49573
@imaddde867 imaddde867 force-pushed the fix/thinking-block-pruning-error branch from 0867445 to 037cb79 Compare March 18, 2026 13:00
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 037cb79808

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Address review feedback: document why isThinkingBlockImmutabilityError
must precede the generic invalid_request_error regex.
@imaddde867 imaddde867 force-pushed the fix/thinking-block-pruning-error branch from dcdc022 to c79d589 Compare March 18, 2026 13:26
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dcdc022335

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

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

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: thinking/redacted_thinking blocks exposed to chat on context pruning

1 participant