Skip to content

Comments

fix(gateway): repair orphaned tool_use blocks on session load#8243

Closed
unisone wants to merge 1 commit intoopenclaw:mainfrom
unisone:fix/session-load-repair-tool-use
Closed

fix(gateway): repair orphaned tool_use blocks on session load#8243
unisone wants to merge 1 commit intoopenclaw:mainfrom
unisone:fix/session-load-repair-tool-use

Conversation

@unisone
Copy link
Contributor

@unisone unisone commented Feb 3, 2026

Summary

When browser operations timeout, sessions can be saved with orphaned tool_use blocks (no matching tool_result). On reload, this causes API errors:

unexpected tool_use_id in tool_result blocks

Root Cause

repairToolUseResultPairing() already exists in session-transcript-repair.ts and handles this case during context sanitization, but wasn't called when loading sessions from disk in readSessionMessages().

Fix

Call repairToolUseResultPairing() on messages when loading from disk, before returning them.

Testing

  • Existing tests pass (26/26 in session-utils.fs.test.ts, 6/6 in session-transcript-repair.test.ts)
  • The repair function is battle-tested (already used in context sanitization path)

Fixes #7930

Greptile Overview

Greptile Summary

This PR fixes session reload failures by running repairToolUseResultPairing() on messages loaded from disk in readSessionMessages(), ensuring any orphaned/misordered tool_use/tool_result pairs are repaired before the transcript is used downstream.

The approach aligns the “load from disk” path with the existing context-sanitization path that already performs this repair, addressing provider-side strict validation errors like unexpected tool_use_id in tool_result blocks.

Confidence Score: 4/5

  • Largely safe, but currently blocked by an import resolution issue that would fail typechecking/builds.
  • The behavioral change is localized and leverages an existing, tested repair function; the main risk is the newly introduced ../agents/types.js type import, which does not appear to exist in the repo and would break module resolution.
  • src/gateway/session-utils.fs.ts (import of AgentMessage)

@openclaw-barnacle openclaw-barnacle bot added the gateway Gateway runtime label Feb 3, 2026
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, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +40 to +42
// See: https://github.com/openclaw/openclaw/issues/7930
const repaired = repairToolUseResultPairing(messages as AgentMessage[]);
return repaired.messages;
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2] Type-only import path looks incorrect and will break builds

session-utils.fs.ts imports AgentMessage from ../agents/types.js, but there doesn’t appear to be a corresponding src/agents/types.* file in the repo. Even though it’s a type-only import, TS still needs to resolve the module; this will fail typechecking/bundling.

If the intent is to use the same AgentMessage used by repairToolUseResultPairing, consider importing it from @mariozechner/pi-agent-core instead (or from whatever existing local module already re-exports it).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/session-utils.fs.ts
Line: 40:42

Comment:
[P2] Type-only import path looks incorrect and will break builds

`session-utils.fs.ts` imports `AgentMessage` from `../agents/types.js`, but there doesn’t appear to be a corresponding `src/agents/types.*` file in the repo. Even though it’s a type-only import, TS still needs to resolve the module; this will fail typechecking/bundling.

If the intent is to use the same `AgentMessage` used by `repairToolUseResultPairing`, consider importing it from `@mariozechner/pi-agent-core` instead (or from whatever existing local module already re-exports it).

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

Copy link

@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: 2c32d21ad2

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +41 to +42
const repaired = repairToolUseResultPairing(messages as AgentMessage[]);
return repaired.messages;

Choose a reason for hiding this comment

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

P2 Badge Avoid mutating chat.history with repair-only transcript logic

Applying repairToolUseResultPairing() on every readSessionMessages() call means chat.history now returns a modified transcript, not what was actually stored. That repair function drops toolResult messages that appear after a later assistant turn (it only matches results in the span before the next assistant), and inserts synthetic error toolResults instead. In sessions where a long-running tool result is written after another assistant message, the real tool output will be silently removed from history and replaced with an error, which is a behavior change for UI and tools that consume chat.history (e.g., sessions_history with includeTools=true). Consider keeping chat.history as a faithful read and applying repair only in provider-context sanitization.

Useful? React with 👍 / 👎.

@unisone unisone force-pushed the fix/session-load-repair-tool-use branch from 2c32d21 to e5103bb Compare February 3, 2026 20:23
@unisone
Copy link
Contributor Author

unisone commented Feb 3, 2026

Re: Codex P2 (history mutation concern)

Valid point. The trade-off:

  • Without repair on load: Sessions with orphaned tool_use blocks cause API errors (unexpected tool_use_id) on next use — session is broken until manually fixed.
  • With repair on load: History may differ from raw storage, but sessions are usable.

repairToolUseResultPairing() is already applied during context sanitization before API calls, so provider-facing transcripts are already repaired. This ensures consistency between what's in memory and what providers see.

If UI fidelity to raw storage matters, I can add a separate readSessionMessagesRaw() for debugging/inspection while keeping readSessionMessages() API-safe. Happy to adjust if preferred.

@unisone
Copy link
Contributor Author

unisone commented Feb 3, 2026

Re: Greptile P2 (import path)

Fixed in latest commit — now imports AgentMessage from @mariozechner/pi-agent-core (same source as session-transcript-repair.ts).

@unisone unisone force-pushed the fix/session-load-repair-tool-use branch 2 times, most recently from 4e57958 to 9d81cf3 Compare February 9, 2026 21:02
hongw pushed a commit to hongw/openclaw that referenced this pull request Feb 10, 2026
Cherry-picked from upstream PR openclaw#8243

When browser operations timeout, sessions can be saved with orphaned
tool_use blocks (no matching tool_result). On reload, this causes API
errors: 'unexpected tool_use_id in tool_result blocks'.

The repairToolUseResultPairing() function already exists and handles
this case during context sanitization, but wasn't called when loading
sessions from disk.

Fixes openclaw#7930
When browser operations timeout, sessions can be saved with orphaned
tool_use blocks (no matching tool_result). On reload, this causes API
errors: 'unexpected tool_use_id in tool_result blocks'.

The repairToolUseResultPairing() function already exists and handles
this case during context sanitization, but wasn't called when loading
sessions from disk.

Fixes #7930
@unisone unisone force-pushed the fix/session-load-repair-tool-use branch from 9d81cf3 to cfc6bb3 Compare February 11, 2026 16:53
@unisone
Copy link
Contributor Author

unisone commented Feb 11, 2026

All bot feedback addressed and CI is green across all platforms. Ready for review.

hongw pushed a commit to hongw/openclaw that referenced this pull request Feb 15, 2026
Cherry-picked from upstream OpenClaw:
- PR openclaw#9416: drop errored/aborted assistant tool pairs in transcript repair
- PR openclaw#12487: strip orphaned tool_result when tool_use is sanitized on retry
- PR openclaw#8243: repair orphaned tool_use blocks on session load

Fixes session-killing errors caused by orphaned tool_use/tool_result blocks.
When these orphaned blocks reach the API, they cause permanent HTTP 400 errors
that break every subsequent message in the session.
@unisone
Copy link
Contributor Author

unisone commented Feb 18, 2026

Friendly ping — this is ready for review. Let me know if any changes needed.

@unisone unisone closed this Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Browser timeout leaves orphaned tool_use blocks causing API errors on session reload

1 participant