fix(voice): honor wake_word.start_new_session on every surface

start_new_session was respected only by the CLI; the TUI and desktop GUI
always opened a fresh session on wake, ignoring the config. The gateway
now carries the flag in the wake.detected payload and both clients honor
it (open a fresh session vs. continue the current one), matching the CLI.
This commit is contained in:
Brooklyn Nicholson 2026-06-27 11:43:18 -05:00 committed by Teknium
parent c01c3f4b28
commit 8e155bdcc8
No known key found for this signature in database
4 changed files with 18 additions and 10 deletions

View file

@ -746,7 +746,10 @@ export function DesktopController() {
const handleGatewayEventWithWake = useCallback(
(event: Parameters<typeof handleDesktopGatewayEvent>[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
}

View file

@ -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)

View file

@ -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

View file

@ -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' }
| {