Skip to content

fix(agent): answer sibling tool calls when the exit validator rejects finish - #70

Merged
wolfy-j merged 1 commit into
masterfrom
fix/exit-validation-sibling-tool-results
Aug 10, 2026
Merged

fix(agent): answer sibling tool calls when the exit validator rejects finish#70
wolfy-j merged 1 commit into
masterfrom
fix/exit-validation-sibling-tool-results

Conversation

@wolfy-j

@wolfy-j wolfy-j commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Symptom

When an assistant turn contains the finish exit call plus other tool calls (e.g. parallel KB searches), and arena_config.exit_func_id rejects the finish (missing declared outputs), the workflow permanently stalls on the next iteration with:

messages.N: `tool_use` ids were found without `tool_result` blocks immediately after: toolu-...

Observed in production: a digest whose exit validator enforces complete outputs failed every scheduled run for four days with exactly this error.

Root cause

node/agent/node.lua, process_tool_results: on validator rejection the code records the rejection observation, sets skip_call = true, and returns early via if task_complete or skip_call then return ... end — skipping the loop below that records tool_result observations for the sibling tool calls in the same turn. Those siblings already executed (their output sits in tool_results); they only lack recorded observations. The next prompt rebuild therefore carries orphaned tool_use blocks and the LLM provider rejects the whole request.

Fix

Drop skip_call; gate the early return on task_complete alone, so a rejected finish falls through into the existing sibling-observation loop. The loop already no-ops for the exit call itself (it is never in tool_resultssplit_exit_tool_calls keeps it out of execute_tools), so nothing is double-recorded, and the genuine-completion path is unchanged.

Tests

process_tool_results exposed via the existing _test table; new process_tool_results_test.lua with a stub always-rejecting exit validator:

  1. rejected finish + two sibling calls in one turn → exactly 3 observations recorded (rejection + both siblings), task_complete == false;
  2. unconditional finish (no exit_func_id) → early return, sibling results untouched.

Full suite: 952 passed.

process_tool_results returned as soon as a rejected finish set
skip_call, before the loop that records tool_result observations for
any other tool calls made in the same assistant turn. Those siblings
had already run (their output sat in tool_results), so the next
prompt rebuild carried tool_use ids the API never saw answered,
and Anthropic's messages API rejected the whole request.

Only a genuine completion (task_complete) should skip the loop; a
rejected finish must fall through so siblings still get recorded.
@wolfy-j
wolfy-j force-pushed the fix/exit-validation-sibling-tool-results branch from a88a707 to 5723b80 Compare August 10, 2026 21:34
@wolfy-j
wolfy-j merged commit 66ede44 into master Aug 10, 2026
8 checks passed
@wolfy-j
wolfy-j deleted the fix/exit-validation-sibling-tool-results branch August 10, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant