Skip to content

fix(core): continue after malformed tool input#37701

Merged
kitlangton merged 1 commit into
v2from
malformed-tool-continuation
Jul 19, 2026
Merged

fix(core): continue after malformed tool input#37701
kitlangton merged 1 commit into
v2from
malformed-tool-continuation

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

What

Treat malformed local tool arguments as an ordinary failed tool result instead of a one-use repair condition.

A malformed call remains strictly non-executable and is recorded with executed: false. Its provider-safe {} call and concise error result are included in the next model request, and the normal agent loop decides whether to continue. There is no malformed-input-specific retry scheduler, recovery flag, or process-local budget.

Before / After

Before: The first malformed local tool call produced a failed tool result but also marked the originating Step as provider.invalid-output. Core special-cased that failed Step to permit exactly one corrective model request. A later malformed call in the same drain terminated the execution even when a valid tool Step occurred between the two failures.

After: Each malformed local call produces Tool.Failed with executed: false, while the originating Step settles normally. Core continues exactly as it does for another failed local tool result. Repeated malformed calls may be corrected in subsequent Steps, subject to the current request capability and the agent's existing Step limit.

The resulting invariant is:

Every local tool proposal receives one terminal tool result. Malformed JSON never executes, and correction uses ordinary model continuation rather than provider retry.

How

  • packages/core/src/session/runner/publish-llm-event.ts keeps strict malformed-input settlement but removes the publisher-level malformed flag and assistant Step failure.
  • packages/core/src/session/runner/llm.ts treats tool-input-error as a continuation request only when the prepared request's existing resolveToolCall capability admits tools. This preserves request-specific tool availability and prevents continuation past agent.steps.
  • The runner no longer threads a malformed-recovery boolean through attemptStep, runStep, and drain.
  • packages/core/test/session-runner.test.ts verifies normal Step settlement, repeated correction, non-execution, provider-safe history, and Step-limit enforcement.

Scope

  • Malformed provider-executed calls remain terminal because Core cannot truthfully claim they were not executed.
  • Independent provider failures, infrastructure failures, interruptions, and user-declined actions remain terminal.
  • Strict JSON parsing and provider-facing {} history lowering are unchanged.
  • This is V2-only.

Testing

  • cd packages/core && bun run test -- test/session-runner.test.ts test/session-runner-message.test.ts test/session-runner-tool-events.test.ts test/aisdk.test.ts: 168 passed.
  • cd packages/core && bun typecheck: passed.
  • bun turbo typecheck --concurrency=3: 32 tasks passed across the 39-package scope.
  • git diff --check: passed.
  • Full Core suite: 1,347 passed, 6 skipped. Two unrelated user-environment isolation assertions failed because the configured execute tool and user-level cmux plugins were discovered.

Flow

sequenceDiagram
  participant Adapter
  participant Runner
  participant Store
  participant Model

  Adapter->>Runner: tool-input-error(call ID, tool name)
  Runner->>Store: Tool.Failed(executed=false)
  Runner->>Store: Step.Ended(tool-calls)
  Runner->>Runner: resolveToolCall(tool name)
  alt tools admitted for this Step
    Runner->>Model: next Step with safe call + error result
    Model-->>Runner: corrected call, another failure, or stop
  else tools unavailable or Step limit reached
    Runner-->>Runner: stop normal continuation
  end
Loading

@kitlangton
kitlangton merged commit a288cb5 into v2 Jul 19, 2026
10 checks passed
@kitlangton
kitlangton deleted the malformed-tool-continuation branch July 19, 2026 03:09
github-actions Bot pushed a commit to ReStranger/opencode that referenced this pull request Jul 19, 2026
* upstream/v2:
  mini: fix shell tool output display (anomalyco#37711)
  fix(core): detach disposed MCP registrations from root scope (anomalyco#37660)
  fix(core): preserve the first terminal failure (anomalyco#37705)
  fix(core): continue after malformed tool input (anomalyco#37701)
  fix(core): safely recover malformed tool input (anomalyco#37698)
  fix(simulation): render screenshot symbol glyphs (anomalyco#37691)
  fix(core): authorize relative external paths (anomalyco#37689)
  fix(tui): auto-approve permissions in auto mode
  feat(core): allow MCP Code Mode opt-out (anomalyco#37681)
  fix(codemode): stop leaking undefined into tool arguments (anomalyco#37652)
  fix(tui): style interrupted compaction neutrally (anomalyco#37655)
  fix(cli): harden managed service election (anomalyco#37645)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant