Skip to content

Voice backend: adopt Omni Chat route metadata for narration #329702

Description

Context

Omni Chat with multi-session routing landed in #326698. The frontend chooses a destination before dispatching each request: either an existing session or a newly created session. When Voice Mode is connected, VS Code already sends that decision to the voice backend, but the backend does not yet consume it.

The Omni behavior and routing flow are described in #326698 (comment).

Existing frontend contract

Each session in the Voice Mode session context can include:

omni_route?: 'existing_session' | 'new_session';

The field is set only on the selected active session and is accompanied by the existing session identity fields:

{
  "id": "<session URI>",
  "label": "Auth fix",
  "is_active": true,
  "omni_route": "existing_session",
  "agent_state": "thinking"
}

For a newly created destination, the value is new_session instead.

While Voice Mode is connected, this normally arrives through the existing merge-patch protocol:

{
  "type": "session_context",
  "mode": "delta",
  "upserts": [
    {
      "id": "<session URI>",
      "is_active": true,
      "omni_route": "existing_session"
    }
  ],
  "removes": []
}

The same field can be present in the full session_context carried by start_session or resume_session. When Omni releases or changes the target, the delta can clear the property with "omni_route": null, following the existing JSON Merge Patch semantics.

Frontend implementation:

  • src/vs/workbench/contrib/chat/common/voiceClient/voiceClientService.ts defines IVoiceSessionContext.sessions[].omni_route.
  • src/vs/workbench/contrib/chat/browser/voiceClient/voiceSessionController.ts places the marker on the active routed target.
  • src/vs/workbench/contrib/chat/browser/sessionRouter/chatSessionRoutingController.ts distinguishes existing_session from new_session after a successful single-target route.
  • Fan-out intentionally clears the single sticky target and does not provide an arbitrary route marker.

Backend work

  1. Extend the backend session-context model/parser to accept omni_route with the two values above, including merge-patch updates and null removal.
  2. Treat a live transition to existing_session as a one-shot routing event for the session identified by id. Use label when available to acknowledge the destination, for example: “Sending to Auth fix.”
  3. Treat a live transition to new_session as a one-shot routing event and acknowledge that a new session is being started, for example: “Starting a new session.”
  4. Emit the acknowledgement promptly and before the routed session's eventual confirmation/question/response narration.
  5. Deduplicate by session and route transition. Repeated context deltas, agent-state changes, reconnect hydration, or unchanged values must not repeat the acknowledgement.
  6. A null/missing marker clears backend route state and must not be narrated.
  7. Preserve all existing agent-state behavior: thinking, questions, approvals, completion summaries, interruption, and response narration should continue normally after the route acknowledgement.
  8. Do not announce a destination for fan-out because the frontend deliberately sends no single omni_route target in that case.

Exact spoken wording can follow backend localization and narration conventions; the important behavior is a concise, single acknowledgement that distinguishes an existing named destination from a new session.

Acceptance criteria

  • With Omni Voice Mode connected, routing to one existing session produces one destination acknowledgement using its label when available.
  • Routing to a new session produces one new-session acknowledgement.
  • The routed response is still narrated once after the acknowledgement.
  • Questions and approvals from the routed session remain narratable and answerable.
  • Repeated session_context updates do not repeat the route acknowledgement.
  • Clearing omni_route with null produces no speech.
  • Fan-out produces no misleading single-destination acknowledgement.
  • Reconnect/resume does not replay a stale route acknowledgement.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions