it0/packages/services/voice-agent
hailin d097c64c81 feat(voice): add per-turn interrupt support to VoiceSessionManager
Implements a two-level abort controller design to support real-time
interruption when the user speaks while the agent is still responding:

  sessionAbortController (session-scoped)
    - Created once when startSession() is called
    - Fired only by terminateSession() (user hangs up)
    - Propagated into each turn via addEventListener

  turnAbort (per-turn, stored as handle.currentTurnAbort)
    - Created fresh at the start of each executeTurn() call
    - Stored on the VoiceSessionHandle so injectMessage() can abort it
    - When a new inject arrives while a turn is running, injectMessage()
      calls turnAbort.abort() BEFORE enqueuing the new message

Interruption flow:
  1. User speaks mid-response → LiveKit stops TTS playback (client-side)
  2. STT utterance → POST voice/inject → injectMessage() fires
  3. handle.currentTurnAbort.abort() called → sets aborted flag
  4. for-await loop checks turnAbort.signal.aborted on next SDK event → break
  5. catch block NOT reached (break ≠ exception) → no error event emitted
  6. finally block saves partial text with "[中断]" suffix to history
  7. New message dequeued → fresh executeTurn() starts immediately

Why no "Agent error" message plays to the user:
  - break exits the for-await loop silently, not via exception
  - The catch block's error-event emission is guarded by err?.name !== 'AbortError'
    AND requires an actual exception; a plain break never enters catch
  - Empty or partial responses are filtered by `if response:` in agent.py

Also update module-level JSDoc with full architecture explanation covering
the long-lived run loop design, two-level abort hierarchy, tenant context
injection pattern, and SDK session resume across turns.

Update agent.py module docstring to document voice session lifecycle and
interruption flow for future maintainers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 04:25:57 -08:00
..
src feat(voice): add per-turn interrupt support to VoiceSessionManager 2026-03-04 04:25:57 -08:00
Dockerfile fix: resolve websockets version conflict and use CPU-only torch 2026-02-28 09:02:31 -08:00
SPEECHMATICS_POSTMORTEM.md docs: add Speechmatics STT postmortem — all 4 modes failed, unusable 2026-03-03 05:03:30 -08:00
requirements.txt refactor: remove Speechmatics STT integration entirely, default to OpenAI 2026-03-03 04:58:38 -08:00