Skip to content

fix: fall back for streamed text tool calls - #158

Merged
vedaant00 merged 4 commits into
vedaant00:mainfrom
Siteshcodes:fix/140-stream-tool-call-fallback
Sep 3, 2026
Merged

vedaant00 merged 4 commits into
vedaant00:mainfrom
Siteshcodes:fix/140-stream-tool-call-fallback

Conversation

@Siteshcodes

@Siteshcodes Siteshcodes commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

What & why

Detect tool calls emitted as plain text during streaming and fall back to the non-streaming path so the tool call is executed correctly.

How I verified it

Added tests for plain-text <tool_call> and bare JSON fallback, malformed payloads, normal structured streaming tool calls, and usage accounting. tests/test_loop.py and tests/test_usage.py pass locally.

Checklist

  • Small and focused (one change)
  • Added/updated tests; pytest passes locally
  • If it touches reversibility/ or a mutating tool: actions are snapshotted and undo still restores exactly (tests added)
  • If it changes the UI: screenshot / short recording included below

Related to #140

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The fallback is triggered only after streaming has already yielded text events, which can leak raw <tool_call> payloads to callers and also affects retry behavior by marking output as produced.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Fixes streaming-mode tool execution for providers that emit tool-call payloads as plain text by detecting those payloads and falling back to the non-streaming turn path so tool calls aren’t silently dropped (Issue #140).

Changes:

  • Added _looks_like_tool_call heuristic and _StreamUnsupported raise in _stream_turn to trigger non-streaming fallback when a plain-text tool call is detected.
  • Added test coverage for <tool_call>…</tool_call> detection, bare-JSON detection, malformed payload handling, structured streaming tool calls (no fallback), and usage accounting around the failed streaming attempt.
File summaries
File Description
src/opendot/agent/loop.py Adds plain-text tool-call detection in streaming and raises _StreamUnsupported to activate the existing non-streaming fallback path.
tests/test_loop.py Adds tests validating detection/fallback behavior and ensuring usage isn’t double-counted when the streaming attempt is abandoned.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/opendot/agent/loop.py
Address review: _stream_turn yielded each content delta as a text event while
streaming and only raised _StreamUnsupported at the end, so a plain-text
<tool_call> payload was briefly surfaced to the caller, and produced_output was
set True (which could suppress a retry if the non-stream fallback then hit a
transient error).

Now hold text back while the assembled content could still be a tool call
(starts with <tool_call>, a code fence, or a bare {), flushing the buffer as one
text event only once it is clearly prose. When it is a tool call we raise before
any flush, so nothing is yielded and produced_output stays False. Ordinary prose
still streams live after the first non-matching delta.

Test: a chunked plain-text tool call yields no text event before the raise
(regression-proven against the eager-yield behavior).
@vedaant00

Copy link
Copy Markdown
Owner

Pushed a follow-up for Copilot's finding: _stream_turn now buffers suspected tool-call text so no raw <tool_call> payload leaks before the fallback, and produced_output stays False so a fallback error can still retry. Added a regression test. Good to merge @Siteshcodes.

@vedaant00
vedaant00 merged commit 885fc8c into vedaant00:main Sep 3, 2026
4 checks passed
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.

3 participants