Skip to content

Fix deferred realtime completion delivery - #14245

Merged
kodjima33 merged 1 commit into
BasedHardware:mainfrom
aryanorastar:codex/12732-realtime-voice-delivery
Sep 17, 2026
Merged

kodjima33 merged 1 commit into
BasedHardware:mainfrom
aryanorastar:codex/12732-realtime-voice-delivery

Conversation

@aryanorastar

@aryanorastar aryanorastar commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #12732.

Realtime-owned agent runs can now wake the existing deferred voice-delivery path as soon as their authoritative kernel completion lands. The completed answer is injected as silent background context and remains governed by the existing next-natural-turn behavior; this change does not interrupt speech or create a second response owner.

Root cause

The realtime tool path completed runs directly through the external-surface protocol. Unlike Swift-owned background runs, it never produced an AgentRuntimeStatusStore lifecycle projection, so AgentCompletionVoiceDelivery.observe() had no terminal transition to react to.

The shared chat session made the gap easy to miss: realtime resolves through a realtime_voice alias, but the canonical persisted session can remain floating_chat. The kernel had the answer and journal entry, while delivery only retried on an unrelated later voice connect/input-window event.

Changes

  • Return the canonical persisted surfaceKind in successful external-run begin receipts and carry it in ExternalSurfaceRunBinding.
  • Project accepted and kernel-confirmed terminal receipts onto a run-scoped status surface after the owner fence is revalidated.
  • Wake voice completion delivery for run-scoped floating_chat, realtime_voice, and legacy realtime projections.
  • Keep ordinary floating/realtime chat terminal transitions excluded, preventing a normal chat answer from polling the background completion backlog.
  • Skip terminal projection during previous-owner cleanup, so an owner transition cannot publish a stale delivery wakeup.
  • Move the external-run wire builders into the dedicated authority file, reducing AgentRuntimeProcess.swift below its previous size.
  • Register FC-terminal-work-without-consumer-wakeup with behavioral guard artifacts and add a user-facing changelog entry.

Correctness and safety

  • The kernel journal remains the only completion-content authority. The Swift projection is only a wakeup signal.
  • The existing per-surface delivery checkpoint advances only after context injection succeeds; retryable delivery still leaves it untouched.
  • Context injection remains silent. The realtime model can mention the result at the next natural turn boundary, preserving barge-in semantics.
  • Surface identity comes from the persisted kernel session, not from the caller's realtime alias.
  • Failed and cancelled external runs project their confirmed terminal status without fabricating success.

Proof

  • npm run build
  • Focused agent contracts: 53 passed across external-surface-authority, protocol-v2, and runtime-stdio-contract.
  • Focused Swift suites with the pinned Xcode 26.6 toolchain: 55 passed, including delivery, status-store, external-authority, and authorized-tool execution coverage.
  • desktop/macos/scripts/agent-logic-harness.sh --cross-surface-smoke with Xcode 26.6: Swift and agent cross-surface contracts passed.
  • python3 desktop/macos/scripts/check_desktop_test_quality.py: passed.
  • Exact regression coverage proves a realtime alias reuses the persisted floating-chat session, returns surfaceKind: floating_chat, publishes the confirmed terminal transition, injects once, and acknowledges once.
  • Negative coverage proves an ordinary floating-chat terminal does not trigger delivery.

No iOS, Android, or hardware path is changed. The defect is at the deterministic macOS kernel-to-Swift lifecycle boundary, so no pendant validation is required.

Product invariants affected

  • INV-AGENT-*
  • INV-CHAT-1
  • INV-VOICE-1

Failure-Class: new

This PR adds .github/failure-classes/FC-terminal-work-without-consumer-wakeup.json and its reusable guard tests.

Line-Count-Exception: desktop/macos/Desktop/Sources/FloatingControlBar/RealtimeHubController.swift | 1591 -> 1592 | Updates the existing DEBUG owner-boundary fixture for the new required binding field; extracting a one-line fixture initializer would reduce reviewability.

Review in cubic

Return the persisted session surface from external-run admission, project confirmed begin and terminal receipts onto a run-scoped status surface, and wake deferred voice delivery without treating ordinary chat terminals as background completions.

The kernel journal and delivery checkpoint remain authoritative. Owner-transition cleanup cannot publish a stale wakeup, failed injection leaves the checkpoint unadvanced, and ordinary floating-chat answers stay excluded.

Tests: 53 focused agent contract tests; 55 focused Swift tests; pinned-Xcode cross-surface harness; desktop test-quality check.

Failure-Class: new
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Verified against #12732 — nice catch and a careful fix for a real defect: deferred "let me verify…" answers completed silently in the journal and were only delivered if an unrelated voice connect or input-window event happened to drain the backlog.

What I checked:

Root cause confirmed. External realtime runs resolve through the shared chat session and never created an AgentRuntimeStatusStore projection, so AgentCompletionVoiceDelivery.observe() had no terminal transition to react to, and triggerSurfaceKinds excluded the chat surfaces entirely — matching the field trace in the issue.

Fix shape holds up:

  • kernel-core.ts returns the persisted session.surfaceKind on both admission paths (duplicate join and fresh run), and kernel-types.ts documents it as projection-only metadata. Swift treats it strictly as projection data — ownerId equality and the RuntimeOwnerIdentity fence remain the authorization check, so the new field adds no authority. A missing/empty surfaceKind is rejected as malformed on the Swift side.
  • AgentRuntimeProcess.beginExternalSurfaceRun / completeExternalSurfaceRun project accepted and terminal receipts onto the run-scoped .externalRun(...) surface behind a revalidated isAuthorizationCurrent fence on the MainActor. The terminal projection is skipped when authorizationSnapshot is nil (previous-owner transition cleanup), so an owner transition cannot publish a stale delivery wakeup.
  • recordConfirmedTerminalRun is wakeup-only: isTerminal guard, payload carries ids/timestamps, no completion content — the kernel journal and per-surface checkpoint stay authoritative, preserving the exactly-once delivery contract.
  • The run-scoped key (floating_chat|run|<runId>) cannot collide with the visible chat projection (floating_chat|chat|<chatId>), so lifecycle wakeups don't clobber the user-facing request projection.
  • canTriggerDelivery gates on externalRefKind == "run" plus the three chat surface kinds, so an ordinary floating-chat answer still cannot wake the background-completion dispatcher — covered by the new negative test.
  • The wire-builder move into ExternalSurfaceRunAuthority.swift is a verbatim relocation; the RealtimeHubController and test call-site updates just carry the new binding field.

Test coverage is layered well: the TS authority test pins the realtime→floating-chat session aliasing (the subtle part of the bug), the store tests pin accepted→terminal lifecycle plus non-terminal rejection, and the delivery tests cover both the new trigger and the ordinary-chat exclusion. The FC-terminal-work-without-consumer-wakeup entry follows the existing failure-class convention and points at real guard artifacts; changelog entry appreciated.

One minor, non-blocking observation: the terminal projection stores ExternalSurfaceRunAnswer.normalized(finalText) as statusText, which slightly blurs the "projection never carries completion content" invariant in recordConfirmedTerminalRun's doc comment. It's the same owner's confirmed text, so there's no new exposure — just worth confirming no surface ever renders run-scoped chat projections' statusText.

Human review needed before merge: this change sits inside the external-surface owner-authorization fence, so a maintainer should sign off on the projection/concurrency semantics (owner-transition skip plus MainActor fencing), and the queued Desktop Swift Release Compile should land green first.

Automated maintainer-assist feedback on behalf of the Omi maintainers.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@Git-on-my-level Git-on-my-level added macOS positive-signal Automation verified a genuine fix/quality contribution needs-maintainer-review Needs a human maintainer to sign off before merge labels Sep 16, 2026

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Desktop bug fix (owner-override): fixes #12732, root cause identified, CI green, no abuse signals, confirmed not already fixed on main. Merging.

@kodjima33
kodjima33 merged commit ec566e1 into BasedHardware:main Sep 17, 2026
39 of 40 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macOS needs-maintainer-review Needs a human maintainer to sign off before merge positive-signal Automation verified a genuine fix/quality contribution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AgentCompletionVoiceDelivery never fires for realtime-spawned (floating_chat) runs

3 participants