#12379·oh-my-pi

Grok /live: overlapping function-call batches abort session with hard error

Author: kvnlooCreated Sep 17, 2026Updated Sep 17, 2026

Summary

While using /live with the Grok (xAI) realtime backend, the session can terminate with:

Error: Grok issued new function calls before the previous function-call batch completed.

This is emitted by omp itself (not a raw xAI API message) when Grok sends a new delegation/tool-call batch before the prior batch’s function_call_output replies have all been submitted.

Reproduction

  1. Start /live with Grok available (/login xai or XAI_API_KEY, provider grok or auto when Codex is unavailable).
  2. Ask for something that triggers delegate_to_agent (coding / repo work).
  3. Let Grok delegate while the agent turn is still running (or slow), or interrupt / speak again before the delegation finishes.
  4. When Grok completes another realtime response that includes new function calls, live mode errors out and stops.

(Exact trigger timing varies; repro is intermittent but has been hit in normal use.)

Expected

  • Queue or coalesce overlapping Grok delegation batches, or
  • Block new Grok responses until pending function outputs are flushed, or
  • Degrade gracefully (warn + continue) instead of killing the live session.

Actual

GrokLiveTransport treats overlap as fatal and reports a terminal error via #reportFailure, which ends the live session.

Code path

Error sitepackages/coding-agent/src/live/grok-transport.ts:

typescript
#dispatchFunctionCalls(): void {
  if (this.#queuedFunctionCalls.length === 0) return;
  if (this.#pendingFunctionOutputIds.size > 0) {
    this.#reportFailure("Grok issued new function calls before the previous function-call batch completed.");
    return;
  }
  // ...
}

Flow today

  1. Grok emits response.function_call_arguments.done → calls queued.
  2. On response.done, #dispatchFunctionCalls() fires delegation.created events.
  3. Each call id stays in #pendingFunctionOutputIds until speakable delegation context is appended and #completeFunctionCall() sends function_call_output + response.create.
  4. If Grok starts a new response (new function calls) while step 3 is still in flight → hard error above.

Controller couplingpackages/coding-agent/src/live/controller.ts tracks a single #activeDelegationId and only completes the Grok function call after the delegated agent turn finishes and speakable chunks are sent. Slow or overlapping delegations widen the window for overlap.

Related

  • #7947 — original xAI voice /live request (implemented via GrokLiveTransport)
  • #11404 — /live provider picker / Codex exhaustion fallback (same surface area)

Suggested fix directions

  1. Queue: buffer #queuedFunctionCalls while #pendingFunctionOutputIds.size > 0, dispatch when the prior batch drains.
  2. Backpressure: suppress response.create / inbound audio handling until pending outputs complete (if xAI protocol allows).
  3. Controller: support multiple concurrent delegation ids (Grok can batch several calls per response).
  4. Tests: unit-test GrokLiveTransport.handleServerMessage for overlapping response.done + function-call sequences (no live WebSocket needed).

Environment

  • Feature: /live talk mode, Grok realtime (grok-voice-think-fast-2.0)
  • Reported: 2026-09-17 during normal live-mode use