Skip to content

fix(agent-core): ignore truncated tool calls#97140

Merged
steipete merged 2 commits into
mainfrom
fix/truncated-tool-call-terminals-97092
Jun 27, 2026
Merged

fix(agent-core): ignore truncated tool calls#97140
steipete merged 2 commits into
mainfrom
fix/truncated-tool-call-terminals-97092

Conversation

@steipete

@steipete steipete commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Closes #97091. A model response that reaches a length, error, or aborted terminal while still emitting tool calls can contain incomplete calls. Those calls must not execute, persist, or replay as valid tool use.

This supersedes #97092. The contributor fork cannot accept maintainer pushes, so this branch preserves @galiniliev's work and coauthor credit while carrying the review fixes.

Why This Change Was Made

  • Make toolUse the final agent-loop authorization gate for tool dispatch.
  • Remove tool-call blocks from non-executable terminal messages before events, persistence, return, and next-turn replay.
  • Preserve explicit length and error terminals across Google, Ollama, shared OpenAI-compatible, and DeepSeek DSML normalization instead of reclassifying them from parsed calls.
  • Require an observed provider terminal before recovered DSML calls become executable, so EOF cannot authorize a complete-looking partial call.
  • Emit provider failures through the shared error terminal path rather than a successful done event.
  • Keep completed tool-use behavior unchanged.

User Impact

Truncated or failed generations no longer execute partial tool calls, including unintended child-session spawns. Complete tool calls still execute normally.

Evidence

  • node scripts/run-vitest.mjs packages/agent-core/src/agent-loop.test.ts src/plugin-sdk/provider-stream-shared.test.ts src/llm/providers/google-shared.test.ts src/agents/openai-transport-stream.test.ts extensions/google/transport-stream.test.ts extensions/ollama/src/stream.test.ts — 451 tests passed across four shards.
  • oxfmt --check and oxlint --deny-warnings passed for all 12 changed files.
  • git diff --check origin/main...HEAD passed.
  • Fresh autoreview after all accepted fixes: no findings; patch correct at 0.96 confidence.

@clawsweeper

clawsweeper Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 26, 2026, 10:13 PM ET / 02:13 UTC.

Summary
The branch gates agent-core tool dispatch on final toolUse turns, strips non-executable terminal tool calls from committed/replayed messages, and updates Google, Ollama, OpenAI-compatible, and provider-wrapper normalization tests.

PR surface: Source +26, Tests +382. Total +408 across 12 files.

Reproducibility: yes. Source inspection gives a high-confidence reproduction path: return a final assistant message with stopReason: "length" and a toolCall block, and current main routes it into executeToolCalls.

Review metrics: 1 noteworthy metric.

  • Tool execution contract: 1 core dispatch gate tightened; 5 provider/wrapper terminal paths covered. This is the boundary that decides whether provider-returned tool-call blocks can run side-effectful tools.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #97091
Summary: This PR is the current candidate fix for the canonical truncated assistant tool-call execution bug and supersedes the earlier contributor branch.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🌊 off-meta tidepool
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Confirm maintainer acceptance of the toolUse-only execution contract after required checks finish.

Risk before merge

  • [P1] Merging intentionally changes compatibility for provider/plugin adapters: tool-call blocks with length, error, EOF, or other non-toolUse terminals will no longer execute, so adapters must emit toolUse for complete executable calls.
  • [P1] The original Telegram/GitHub Copilot incident was not rerun on the patched branch; the available proof is source-level, targeted runtime-seam tests, and loopback provider tests.

Maintainer options:

  1. Accept the toolUse terminal contract (recommended)
    Maintainers can accept that only assistant turns ending in toolUse may execute tools, with provider/plugin adapters responsible for preserving toolUse on complete executable tool-call turns.
  2. Ask for adapter-contract proof first
    If compatibility is uncertain, require targeted evidence for supported adapters showing complete tool-call turns still normalize to toolUse while length/error/EOF paths do not.
  3. Keep the original branch superseded
    If this replacement lands, close fix(agent-core): ignore truncated assistant tool calls #97092 as superseded so the older fork branch does not remain a competing landing path.

Next step before merge

  • [P1] Manual maintainer review is needed because the PR has a protected maintainer label and intentionally changes the provider/plugin tool execution contract.

Security
Cleared: No concrete security or supply-chain regression was found; the diff narrows side-effectful tool execution and does not add dependencies, scripts, workflow permissions, or secret handling.

Review details

Best possible solution:

Land this PR after maintainers accept the toolUse-only execution contract and required checks finish; then close the linked issue and superseded contributor PR.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection gives a high-confidence reproduction path: return a final assistant message with stopReason: "length" and a toolCall block, and current main routes it into executeToolCalls.

Is this the best way to solve the issue?

Yes. Agent-core is the correct final authorization boundary for tool execution and replay, and the PR also updates sibling provider normalization so the fix is not one-provider-only.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 552ec2b49d4a.

Label changes

Label changes:

  • add P1: The PR fixes a real agent-core workflow bug where a truncated assistant turn can launch unintended side-effectful subagent work.
  • add merge-risk: 🚨 compatibility: The diff changes behavior for provider/plugin adapters that return tool-call blocks with non-toolUse terminal reasons.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🌊 off-meta tidepool and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: The contributor proof gate is not applied because this is a protected maintainer-labeled replacement PR; the PR body provides targeted test evidence rather than live-provider proof.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P1: The PR fixes a real agent-core workflow bug where a truncated assistant turn can launch unintended side-effectful subagent work.
  • merge-risk: 🚨 compatibility: The diff changes behavior for provider/plugin adapters that return tool-call blocks with non-toolUse terminal reasons.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🌊 off-meta tidepool and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: The contributor proof gate is not applied because this is a protected maintainer-labeled replacement PR; the PR body provides targeted test evidence rather than live-provider proof.
Evidence reviewed

PR surface:

Source +26, Tests +382. Total +408 across 12 files.

View PR surface stats
Area Files Added Removed Net
Source 6 44 18 +26
Tests 6 396 14 +382
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 12 440 32 +408

What I checked:

  • Current main failure path: Current main exits early only for error or aborted, then executes any toolCall blocks present in the final assistant message, so a length terminal with tool calls can dispatch tools. (packages/agent-core/src/agent-loop.ts:339, 552ec2b49d4a)
  • PR core guard: PR head adds removeNonExecutableToolCalls, gates dispatch on message.stopReason === "toolUse", and scrubs final messages before message_end and replay. (packages/agent-core/src/agent-loop.ts:83, e080b60311d3)
  • Regression coverage: The new agent-core test verifies a length assistant message containing sessions_spawn does not execute, does not emit tool_execution_start, and is scrubbed from returned messages, message_end, and next-turn replay context. (packages/agent-core/src/agent-loop.test.ts:168, e080b60311d3)
  • Sibling normalization coverage: PR head preserves non-executable terminals across DeepSeek DSML recovery, Google MAX_TOKENS, Ollama length, and shared plain-text tool-call wrappers instead of relying only on the core gate. (src/agents/openai-transport-stream.ts:3244, e080b60311d3)
  • Linked issue and superseded branch: Live GitHub data shows this PR closes the canonical issue and explicitly supersedes the earlier contributor PR, which remains open and unmerged.
  • Latest release still has old behavior: The latest release tag v2026.6.10 still executes collected tool calls without requiring toolUse, so the fix is not shipped yet and the PR remains necessary. (packages/agent-core/src/agent-loop.ts:306, aa69b12d0086)

Likely related people:

  • steipete: PR history shows steipete authored the agent-core extraction and later terminal-classifier work in the same loop/terminal area, so they are a strong routing candidate beyond this PR authorship. (role: area introducer and recent agent-runtime contributor; confidence: high; commits: bb46b79d3c14, 0314819f918a; files: packages/agent-core/src/agent-loop.ts, packages/agent-core/src/agent-loop.test.ts)
  • vincentkoc: Recent merged work in the same agent-loop terminal lifecycle area includes several commits by vincentkoc, and they merged the aborted-tool-run fix PR. (role: recent adjacent owner/reviewer; confidence: high; commits: 7fe287b0d30d; files: packages/agent-core/src/agent-loop.ts, packages/agent-core/src/agent-loop.test.ts)
  • szsip239: szsip239 authored the recent aborted-tool-run fix touching the same agent-core loop files, which is adjacent to this terminal-state execution change. (role: recent adjacent bug-fix contributor; confidence: medium; commits: 7fe287b0d30d; files: packages/agent-core/src/agent-loop.ts, packages/agent-core/src/agent-loop.test.ts)
  • fuller-stack-dev: History shows coauthor metadata on terminal-classifier work and recent tool-search/deferred execution changes in the same agent-core test and dispatch area. (role: adjacent tool-execution contributor; confidence: medium; commits: 0314819f918a, 965fa05df38b; files: packages/agent-core/src/agent-loop.ts, packages/agent-core/src/agent-loop.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 27, 2026
@steipete

Copy link
Copy Markdown
Contributor Author

Land-ready proof for e080b60311d3f0edaa350bc9f67a14be90ee8840:

  • Local focused regression: node scripts/run-vitest.mjs packages/agent-core/src/agent-loop.test.ts src/plugin-sdk/provider-stream-shared.test.ts src/llm/providers/google-shared.test.ts src/agents/openai-transport-stream.test.ts extensions/google/transport-stream.test.ts extensions/ollama/src/stream.test.ts — 451 tests passed across four shards.
  • Local static proof: oxfmt --check, oxlint --deny-warnings, and git diff --check passed for all 12 changed files.
  • Blacksmith Testbox focused proof: provider blacksmith-testbox, lease tbx_01kw3d3p5rc0qffryfpaqqdktm, 451 tests passed.
  • Blacksmith Testbox full changed gate: provider blacksmith-testbox, lease tbx_01kw3d6f8fhm4wmr4pcjzb82mv; core/core-test/extension/extension-test typechecks, lint, import-cycle, architecture, and storage guards passed.
  • Hosted CI: run https://github.com/openclaw/openclaw/actions/runs/28275302226 passed on rerun attempt 2. The only first-attempt failure was an unrelated timeout in src/gateway/server-startup-session-migration.test.ts; exact-job rerun passed.
  • OpenGrep: run https://github.com/openclaw/openclaw/actions/runs/28275302204 passed on attempt 2 after cancelling an anomalous hung first attempt.
  • Fresh autoreview thread 019f06cd-56d3-7091-879e-a5b8f0e5278e: no findings; patch correct at 0.96 confidence.

Behavioral proof covers completed tool-use dispatch, length/error/abort suppression, provider stop-reason preservation, EOF without a finish reason, error versus done terminal events, message_end, persistence, returned messages, and next-turn replay.

Known proof gaps: none.

@steipete
steipete merged commit 5625960 into main Jun 27, 2026
200 of 212 checks passed
@steipete
steipete deleted the fix/truncated-tool-call-terminals-97092 branch June 27, 2026 02:31
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
* fix(agent-core): ignore truncated tool calls

Co-authored-by: Galin Iliev <[email protected]>

* fix(agent-core): require explicit tool-call terminals

---------

Co-authored-by: Galin Iliev <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
* fix(agent-core): ignore truncated tool calls

Co-authored-by: Galin Iliev <[email protected]>

* fix(agent-core): require explicit tool-call terminals

---------

Co-authored-by: Galin Iliev <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
* fix(agent-core): ignore truncated tool calls

Co-authored-by: Galin Iliev <[email protected]>

* fix(agent-core): require explicit tool-call terminals

---------

Co-authored-by: Galin Iliev <[email protected]>
wheakerd pushed a commit to wheakerd/clawdbot that referenced this pull request Jul 15, 2026
* fix(agent-core): ignore truncated tool calls

Co-authored-by: Galin Iliev <[email protected]>

* fix(agent-core): require explicit tool-call terminals

---------

Co-authored-by: Galin Iliev <[email protected]>
(cherry picked from commit 5625960)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling extensions: google extensions: ollama maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: truncated assistant tool-call turn executes unintended sessions_spawn

1 participant