Skip to content

fix(voice): deliver tool results to realtime session on interruption - #6600

Open
longcw wants to merge 1 commit into
mainfrom
longc/gemini-tool-output-on-interrupt
Open

fix(voice): deliver tool results to realtime session on interruption#6600
longcw wants to merge 1 commit into
mainfrom
longc/gemini-tool-output-on-interrupt

Conversation

@longcw

@longcw longcw commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Gemini Live blocks a turn until every tool call it emitted is answered, and offers no way to cancel one. If playout is interrupted from our side while a tool result is still owed, dropping that result leaves the server waiting forever: it stops responding and subsequent generate_reply() calls produce no generation. Reported in #6569.

When it happens

Only when the interrupt is client-initiated — a programmatic session.interrupt(), a handoff or close, false-interruption resume, or local turn detection firing alone. A voice barge-in makes Gemini send interrupted, which releases its wait on its own.

Fix

The realtime path now mirrors what #6349 did for the pipeline path: commit the outputs of tools that finished despite the interruption, handoffs excluded so they stay retryable. On top of that it syncs those outputs to the realtime session, which the pipeline has no need to do.

Delivering a result makes Gemini reply, which is unwanted right after an interruption, so it goes out with SILENT scheduling. Gemini ignores scheduling on BLOCKING declarations (the default), so with blocking tools the reply is unavoidable — unblocking the turn is the better trade.

A realtime model keeps a tool call open server-side. Gemini Live blocks the turn
until every call it emitted is answered and offers no way to cancel one, so
discarding a result the handler already returned strands the session: it stops
responding and subsequent generate_reply() calls produce no generation.

Mirror the pipeline path on the realtime path — commit the outputs of tools that
finished despite the interruption, handoffs excluded so they stay retryable — and
additionally sync them to the realtime session.

Gemini answers a delivered result with speech, which is unwanted right after an
interruption, so the response is sent with SILENT scheduling where the API
honours it (NON_BLOCKING declarations on the Gemini API).

Also stop setting tool_response_scheduling on Vertex AI, which does not support
the field, and warn when it is configured there instead of dropping it silently.
@longcw
longcw requested a review from a team as a code owner July 29, 2026 09:19

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

if append_ctx.items:
scheduling = self._opts.tool_response_scheduling
if (
not self._opts.vertexai # scheduling is not supported by vertex

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Redundant now that create_function_response skips scheduling for vertexai — this check can go.

self._session._tool_items_added(interrupted_fnc_outputs)

# unlike the pipeline, a realtime model holds the call open server-side
chat_ctx = self._rt_session.chat_ctx.copy()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

chat_ctx already returns self._chat_ctx.copy(), so this copies twice.

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.

2 participants