Skip to content

fix: drop assistant messages with stopReason 'error' to avoid orphaning tool results (#3860)#3880

Closed
SalimBinYousuf1 wants to merge 1 commit intoopenclaw:mainfrom
SalimBinYousuf1:fix-issue-3860-orphaned-tool-result
Closed

fix: drop assistant messages with stopReason 'error' to avoid orphaning tool results (#3860)#3880
SalimBinYousuf1 wants to merge 1 commit intoopenclaw:mainfrom
SalimBinYousuf1:fix-issue-3860-orphaned-tool-result

Conversation

@SalimBinYousuf1
Copy link

@SalimBinYousuf1 SalimBinYousuf1 commented Jan 29, 2026

This PR fixes issue #3860 where assistant messages with stopReason 'error' (e.g., from content filtering) would have synthetic tool results added by the transcript repair logic. These tool results would then become orphaned if the provider filtered out the errored assistant message on subsequent requests, leading to 400 errors.

The fix ensures that assistant messages with an error stop reason are dropped during transcript repair, preventing the addition of synthetic tool results for them.

Greptile Overview

Greptile Summary

This PR updates repairToolUseResultPairing to drop assistant messages whose stopReason is "error", preventing transcript-repair from inserting synthetic tool results that could later become orphaned if a provider filters the errored assistant turn (the #3860 scenario). The change fits into the existing transcript sanitizer’s responsibilities: keeping tool calls/results strictly adjacent and removing free-floating toolResult entries so strict providers don’t reject requests.

Main follow-ups: avoid the new as any access for stopReason and add a regression test covering an errored assistant toolCall turn to ensure the fix stays in place.

Confidence Score: 4/5

  • This PR is likely safe to merge and addresses a real provider-compatibility failure mode.
  • The change is small and localized to transcript repair logic. Main concerns are maintainability (new as any) and missing regression coverage for the new behavior, rather than functional correctness of the fix itself.
  • src/agents/session-transcript-repair.ts (type-safety + add targeted test coverage)

Context used:

  • Context from dashboard - CLAUDE.md (source)
  • Context from dashboard - AGENTS.md (source)

Copy link
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.

1 file reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +120 to +126
// If the assistant message has an error stop reason, it might be filtered out
// by the provider on subsequent requests (e.g. Anthropic content filtering).
// We drop it to avoid orphaning any tool results that would be added below.
if ((assistant as any).stopReason === "error") {
changed = true;
continue;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2] Avoid as any for stopReason access

(assistant as any).stopReason bypasses type checking and is inconsistent with the rest of this file’s defensive-typing approach. Consider using a narrow structural cast (e.g. const stopReason = (assistant as { stopReason?: unknown }).stopReason; if (stopReason === "error") ...) so the check stays type-safe without introducing any.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/session-transcript-repair.ts
Line: 120:126

Comment:
[P2] Avoid `as any` for `stopReason` access

`(assistant as any).stopReason` bypasses type checking and is inconsistent with the rest of this file’s defensive-typing approach. Consider using a narrow structural cast (e.g. `const stopReason = (assistant as { stopReason?: unknown }).stopReason; if (stopReason === "error") ...`) so the check stays type-safe without introducing `any`.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

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

Comment on lines +120 to +126
// If the assistant message has an error stop reason, it might be filtered out
// by the provider on subsequent requests (e.g. Anthropic content filtering).
// We drop it to avoid orphaning any tool results that would be added below.
if ((assistant as any).stopReason === "error") {
changed = true;
continue;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2] Add a regression test for dropping stopReason === "error" assistant turns

This PR changes pairing behavior by skipping assistant messages with stopReason: "error", but src/agents/session-transcript-repair.test.ts doesn’t cover this case. A test with an errored assistant toolCall + subsequent toolResult would help ensure we keep dropping the assistant and don’t insert synthetic results for it (the #3860 regression).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/session-transcript-repair.ts
Line: 120:126

Comment:
[P2] Add a regression test for dropping `stopReason === "error"` assistant turns

This PR changes pairing behavior by skipping assistant messages with `stopReason: "error"`, but `src/agents/session-transcript-repair.test.ts` doesn’t cover this case. A test with an errored assistant toolCall + subsequent toolResult would help ensure we keep dropping the assistant and don’t insert synthetic results for it (the #3860 regression).

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

@steipete
Copy link
Contributor

Stale triage: superseded by merged #4598 (Feb 6, 2026). Main already includes stopReason error/aborted skip in session transcript repair.

@steipete steipete closed this Feb 24, 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants