Summary
OpenCode V2 can leave a local tool call permanently pending when an OpenAI Responses-compatible stream announces a function call but reaches response.completed without a matching response.output_item.done event.
This was observed as an empty Patch card stuck for 13 minutes. Interrupting the session finally changed it to Tool execution interrupted.
Source report: https://slack.com/archives/C0BE69AHCQP/p1784134227920579
Deterministic reproduction
A focused provider-stream test reproduces the issue with this sequence:
{"type":"response.output_item.added","item":{"type":"function_call","id":"item_1","call_id":"call_1","name":"patch","arguments":""}}
{"type":"response.completed","response":{"usage":{"input_tokens":5,"output_tokens":1}}}
Run from packages/ai:
bun test test/provider/openai-responses.test.ts -t "finalizes an empty function call"
Current events are:
step-start
tool-input-start (patch)
step-finish (stop)
finish (stop)
The stream produces no tool-input-end, tool-call, or tool failure. This leaves the Patch card in a pending state until the session is interrupted.
Expected behavior
At terminal response handling, any pending function-call assembly should be finalized from its accumulated arguments. For empty arguments, the canonical parser should produce {}. The resulting Patch invocation can then fail normal schema validation immediately rather than remaining pending.
Expected terminal events include:
tool-input-end
tool-call (patch, input: {})
step-finish (tool-calls)
Likely cause
packages/ai/src/protocols/openai-responses.ts only finalizes pending ToolStream entries in onOutputItemDone. onResponseFinish closes the lifecycle without flushing state.tools, and hasFunctionCall remains false.
The V2 session publisher then has evidence for tool-input-start, but no actual call to settle or fail.
Notes
Blank patch text and a marker-only patch already fail synchronously in PatchTool; the hang occurs before PatchTool.execute is reached.
Related legacy reports include #30653 and #31843, but this issue has a minimal deterministic V2/OpenAI Responses protocol reproduction.
Summary
OpenCode V2 can leave a local tool call permanently pending when an OpenAI Responses-compatible stream announces a function call but reaches
response.completedwithout a matchingresponse.output_item.doneevent.This was observed as an empty Patch card stuck for 13 minutes. Interrupting the session finally changed it to
Tool execution interrupted.Source report: https://slack.com/archives/C0BE69AHCQP/p1784134227920579
Deterministic reproduction
A focused provider-stream test reproduces the issue with this sequence:
{"type":"response.output_item.added","item":{"type":"function_call","id":"item_1","call_id":"call_1","name":"patch","arguments":""}} {"type":"response.completed","response":{"usage":{"input_tokens":5,"output_tokens":1}}}Run from
packages/ai:Current events are:
The stream produces no
tool-input-end,tool-call, or tool failure. This leaves the Patch card in a pending state until the session is interrupted.Expected behavior
At terminal response handling, any pending function-call assembly should be finalized from its accumulated arguments. For empty arguments, the canonical parser should produce
{}. The resulting Patch invocation can then fail normal schema validation immediately rather than remaining pending.Expected terminal events include:
Likely cause
packages/ai/src/protocols/openai-responses.tsonly finalizes pendingToolStreamentries inonOutputItemDone.onResponseFinishcloses the lifecycle without flushingstate.tools, andhasFunctionCallremains false.The V2 session publisher then has evidence for
tool-input-start, but no actual call to settle or fail.Notes
Blank patch text and a marker-only patch already fail synchronously in
PatchTool; the hang occurs beforePatchTool.executeis reached.Related legacy reports include #30653 and #31843, but this issue has a minimal deterministic V2/OpenAI Responses protocol reproduction.