Skip to content

fix(agent): close tool-result tails on invalid-tool and truncated-tool early returns - #69810

Closed
fangliquanflq wants to merge 1 commit into
NousResearch:mainfrom
fangliquanflq:fix/close-tool-tail-on-invalid-tool-exhaustion
Closed

fix(agent): close tool-result tails on invalid-tool and truncated-tool early returns#69810
fangliquanflq wants to merge 1 commit into
NousResearch:mainfrom
fangliquanflq:fix/close-tool-tail-on-invalid-tool-exhaustion

Conversation

@fangliquanflq

@fangliquanflq fangliquanflq commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Closes durable tool-result tails when the conversation loop stops early for invalid tool names or truncated tool-call arguments, so the next user turn is not tool -> user for strict providers (same failure class as #48879).

Bug Cause

Invalid-tool 3-strike exhaustion, truncated JSON args (finish_reason=tool_calls), and length/stream truncated-tool exhaustion after retries all persist + return without reaching finalize_turn. Prior retries or successful tool batches leave role=tool as the transcript tail. close_interrupted_tool_sequence already fixes this for interrupt aborts, but these sibling early returns never called it.

Reproduction Steps

  1. Run a turn that executes at least one successful tool call (or that injects invalid-tool error tool results on retries).
  2. Force three consecutive all-invalid tool-name batches, or a truncated tool-arg response after a tool batch.
  3. Inspect the returned/persisted messages[-1].role, then send another user message.

Expected: transcript ends on assistant with the partial/error text; next turn is assistant -> user.
Before fix: transcript ends on tool; next turn is tool -> user (Gemini/Claude reject or hallucinate).

Fix

Call close_interrupted_tool_sequence(messages, _final_response) immediately before _persist_session on the three early-return paths in agent/conversation_loop.py. Added behavior-contract tests for invalid-tool exhaustion and both truncated-tool paths.

Related Issue

No issue

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Changes Made

  • agent/conversation_loop.py -- close tool tails on invalid-tool exhaustion, truncated-JSON refusal, and length/stream truncated-tool exhaustion
  • tests/agent/test_empty_tool_name_loop_dampening.py -- assert assistant tail after invalid-tool 3-strike partial
  • tests/run_agent/test_run_agent.py -- assert assistant tail after truncated-tool early returns following a successful tool batch

How to Test

  1. Manual: reproduce the steps above with a mock/weak model that emits unknown tool names or truncated tool JSON after a tool batch; confirm messages[-1].role == "assistant".
  2. Automated: scripts/run_tests.sh tests/agent/test_empty_tool_name_loop_dampening.py tests/run_agent/test_run_agent.py -q -k "closes_tool_tail or truncated_tool_args_detected or length_with_tool_calls_returns_partial"

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature
  • I've run scripts/run_tests.sh on relevant tests and they pass
  • I've added tests for my changes
  • I've tested on my platform: Windows 11 (WSL)

Documentation & Housekeeping

  • I've updated relevant documentation -- N/A
  • I've updated cli-config.yaml.example if I added/changed config keys -- N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows -- N/A
  • I've considered cross-platform impact -- N/A (message-role invariant, platform-agnostic)
  • I've updated tool descriptions/schemas if I changed tool behavior -- N/A

…l early returns

Invalid-tool exhaustion and truncated-tool early returns skipped finalize_turn, leaving role=tool transcripts that become tool→user on the next turn for strict providers. Call close_interrupted_tool_sequence before persist on those paths (same as interrupt aborts).
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P1 High — major feature broken, no workaround sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jul 23, 2026
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Merged via #70061. Your commits cherry-picked with authorship preserved. Thanks for the fix — correctly identified the sibling gap after #48879/#52592 and the three early-return paths that needed close_interrupted_tool_sequence before persist.

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

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P1 High — major feature broken, no workaround sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants