diff --git a/apps/desktop/src/app/desktop-controller.tsx b/apps/desktop/src/app/desktop-controller.tsx index 72cd6d10a4a..fb4589bdadb 100644 --- a/apps/desktop/src/app/desktop-controller.tsx +++ b/apps/desktop/src/app/desktop-controller.tsx @@ -746,7 +746,10 @@ export function DesktopController() { const handleGatewayEventWithWake = useCallback( (event: Parameters[0]) => { if (event.type === 'wake.detected') { - startFreshSessionDraft() + const payload = event.payload as { start_new_session?: boolean } | undefined + if (payload?.start_new_session !== false) { + startFreshSessionDraft() + } requestVoiceConversationStart() return } diff --git a/tui_gateway/server.py b/tui_gateway/server.py index 5f637863ab8..399c2d7068d 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -17630,19 +17630,22 @@ def _wake_on_detect() -> None: with _wake_lock: sid = _wake_event_sid transport = _wake_transport + phrase, new_session = "", True try: - from tools.wake_word import wake_phrase - phrase = wake_phrase() + from tools.wake_word import load_wake_word_config, wake_phrase + cfg = load_wake_word_config() + phrase = wake_phrase(cfg) + new_session = bool(cfg.get("start_new_session", True)) except Exception: - phrase = "" + pass logger.info("wake.detected: emitting to sid=%r (transport=%s)", sid, type(transport).__name__ if transport else None) # Bind the arming request's transport so write_json reaches the right peer # (WS for desktop/dashboard) instead of falling back to stdio on this - # background thread. + # background thread. Carry start_new_session so every surface honors it. token = bind_transport(transport) if transport is not None else None try: - _emit("wake.detected", sid, {"phrase": phrase}) + _emit("wake.detected", sid, {"phrase": phrase, "start_new_session": new_session}) finally: if token is not None: reset_transport(token) diff --git a/ui-tui/src/app/createGatewayEventHandler.ts b/ui-tui/src/app/createGatewayEventHandler.ts index d52e6b03ee9..9d4132e93a9 100644 --- a/ui-tui/src/app/createGatewayEventHandler.ts +++ b/ui-tui/src/app/createGatewayEventHandler.ts @@ -941,10 +941,12 @@ export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev: } case 'wake.detected': { - // "Hey Hermes": open a fresh session, then arm voice capture so the - // user can speak their request hands-free. Mirrors the CLI flow. + // "Hey Hermes": optionally open a fresh session (start_new_session), + // then arm voice capture so the user can speak hands-free. Mirrors CLI. void (async () => { - await newSession() + if (ev.payload?.start_new_session !== false) { + await newSession() + } const sid = getUiState().sid if (!sid) { return diff --git a/ui-tui/src/gatewayTypes.ts b/ui-tui/src/gatewayTypes.ts index 30a6efd241b..db7503828b6 100644 --- a/ui-tui/src/gatewayTypes.ts +++ b/ui-tui/src/gatewayTypes.ts @@ -589,7 +589,7 @@ export type GatewayEvent = } | { payload?: { state?: 'idle' | 'listening' | 'transcribing' }; session_id?: string; type: 'voice.status' } | { payload?: { no_speech_limit?: boolean; text?: string }; session_id?: string; type: 'voice.transcript' } - | { payload?: { phrase?: string }; session_id?: string; type: 'wake.detected' } + | { payload?: { phrase?: string; start_new_session?: boolean }; session_id?: string; type: 'wake.detected' } | { payload?: { reason?: string }; session_id?: string; type: 'dashboard.new_session_requested' } | { payload: { line: string }; session_id?: string; type: 'gateway.stderr' } | {