@flowingspring/dsh-voco 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cordis.patch.yml +6 -3
- package/lib/client.js +631 -40
- package/lib/client.js.map +1 -1
- package/lib/plugins/voice-assistant.js +5135 -32
- package/package.json +4 -1
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["css","css","useState","css","css","createSnapshotStore"],"sources":["../../../packages/ui-voice/src/client/VoiceControl.tsx","../../../packages/ui-voice/src/client/VoiceNodeViews.tsx","../../../packages/ui-voice/src/client/VoiceOverlay.tsx","../../../packages/ui-voice/src/client/VoiceSessionMarkers.tsx","../../../packages/ui-voice/src/client/voice-controller.ts","../../../packages/ui-voice/src/client/voice-history.ts","../../../packages/ui-voice/src/client/voice-text-submit.ts","../../../packages/ui-voice/src/client/voice-definitions.ts","../../../packages/ui-voice/src/client/locales.ts","../../../packages/ui-voice/src/client/index.ts"],"sourcesContent":["import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type { VoiceClientSnapshot } from './voice-controller.ts'\r\nimport css from './VoiceControl.module.css'\r\n\r\n/** Business callbacks and the root-owned transport snapshot. */\r\nexport interface VoiceControlInjected {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n /** Start a fresh Voice conversation located from the current Session. */\n readonly startVoice: (sourceSessionId: SessionId) => Promise<void>\n readonly retryVoice: () => Promise<void>\n readonly interruptResponse: () => void\n readonly setVoiceMuted: (muted: boolean) => void\n}\n\r\nexport type VoiceControlProps =\r\n PropsRuntime<'conversation.input.right'> & InjectFace<VoiceControlInjected> & PropsLocale<'voice'>\r\n\r\n/** Start a fresh Voice Session from this Session's location or control the active connection. */\r\nexport function VoiceControl({\n sessionId, useVoice, startVoice, retryVoice, setVoiceMuted, t,\n interruptResponse,\n}: VoiceControlProps) {\n const state = useVoice(snapshot => snapshot.state)\n const activeSessionId = useVoice(snapshot => snapshot.sessionId)\n const inputMuted = useVoice(snapshot => snapshot.inputMuted)\n\r\n const toggle = async (): Promise<void> => {\r\n if (state === 'error' && activeSessionId !== undefined) {\r\n try { await retryVoice() } catch { /* controller owns the visible error state */ }\r\n return\r\n }\r\n if (state !== 'off' && state !== 'error') {\n setVoiceMuted(!inputMuted)\n return\n }\r\n try {\r\n await startVoice(sessionId)\r\n } catch { /* controller owns the visible error state */ }\r\n }\r\n\r\n const label = state === 'off'\n ? t('control.start')\n : state === 'error'\n ? t('control.retry')\n : inputMuted\n ? t('control.unmute')\n : t('control.mute')\n const active = state !== 'off' && state !== 'error'\n const interrupt = (): void => {\n try { interruptResponse() } catch { /* controller owns the visible connection state */ }\n }\n return (\n <span className={css.controls}>\n {state === 'speaking' && (\n <button\n type=\"button\"\n className={`${css.button} ${css.interruptButton}`}\n aria-label={t('control.interrupt')}\n title={t('control.interrupt')}\n data-state={state}\n onClick={interrupt}\n >\n <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" aria-hidden>\n <circle cx=\"8\" cy=\"8\" r=\"6.25\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" />\n <rect x=\"5.25\" y=\"5.25\" width=\"5.5\" height=\"5.5\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n )}\n <button\n type=\"button\"\n className={`${css.button} ${active ? css.active : ''}`}\n aria-label={label}\n aria-pressed={active ? inputMuted : undefined}\n title={label}\n data-state={state}\n data-muted={inputMuted}\n onClick={() => { void toggle() }}\n >\n <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" aria-hidden>\n <rect x=\"5\" y=\"2\" width=\"6\" height=\"8\" rx=\"3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" />\n <path d=\"M3.5 7.5a4.5 4.5 0 0 0 9 0M8 12v2M5.5 14h5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" strokeLinecap=\"round\" />\n {inputMuted && (\n <path d=\"M2.5 2.5l11 11\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" />\n )}\n </svg>\n </button>\n </span>\n )\n}\n","import { useState } from 'react'\r\nimport type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type { VoiceClientSnapshot } from './voice-controller.ts'\r\nimport type { VoiceDelegationChatData } from './voice-definitions.ts'\r\nimport type { VoiceKey } from './locales.ts'\r\nimport css from './VoiceNodeViews.module.css'\r\n\r\n/** Live transcript source injected into the Voice utterance renderer. */\r\nexport interface VoiceUtteranceInjected {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n}\r\n\r\n/** Navigation action injected into the task-card renderer. */\r\nexport interface VoiceDelegationInjected {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n readonly openSession: (id: SessionId) => void\r\n readonly cancelTask: (id: string) => void\r\n}\r\n\r\nexport type VoiceUtteranceViewProps =\r\n PropsRuntime<'conversation.chat.node', 'voice-utterance'>\r\n & InjectFace<VoiceUtteranceInjected>\r\n & PropsLocale<'voice'>\r\nexport type VoiceDelegationViewProps =\r\n PropsRuntime<'conversation.chat.node', 'voice-delegation'>\r\n & InjectFace<VoiceDelegationInjected>\r\n & PropsLocale<'voice'>\r\n\r\n/** Render a durable Voice utterance while replacing its unsettled text with live WebSocket deltas. */\r\nexport function VoiceUtteranceView({ node, sessionId, useVoice, t }: VoiceUtteranceViewProps) {\r\n const liveText = useVoice(snapshot => snapshot.sessionId === sessionId\r\n ? snapshot.textById[String(node.data.utteranceId)]?.text\r\n : undefined)\r\n const text = node.data.text ?? liveText ?? (node.data.role === 'user'\r\n ? t('utterance.user.pending')\r\n : t('utterance.assistant.pending'))\r\n return (\r\n <article\r\n className={css.utterance}\r\n data-voice-utterance\r\n data-role={node.data.role}\r\n data-state={node.data.state}\r\n >\r\n <div className={css.bubble}>{text}</div>\r\n <div className={css.meta}>\r\n <span className={css.voiceBadge}>\r\n <span className={css.miniWave} aria-hidden><i /><i /><i /></span>\r\n {t('badge.voice')}\r\n </span>\r\n {node.data.state === 'interrupted' && <span>{t('utterance.interrupted')}</span>}\r\n </div>\r\n </article>\r\n )\r\n}\r\n\r\nconst STATUS_KEYS: Record<VoiceDelegationChatData['status'], VoiceKey> = {\r\n accepted: 'task.status.accepted',\r\n queued: 'task.status.queued',\r\n running: 'task.status.running',\r\n 'waiting-user': 'task.status.waiting-user',\r\n completed: 'task.status.completed',\r\n failed: 'task.status.failed',\r\n cancelled: 'task.status.cancelled',\r\n interrupted: 'task.status.interrupted',\r\n}\r\n\r\n/** Render the task link from a Voice Session to its bound background Agent Session. */\r\nexport function VoiceDelegationView({ node, sessionId, useSessions, useVoice, openSession, cancelTask, t }: VoiceDelegationViewProps) {\r\n const [expanded, setExpanded] = useState(false)\r\n const navigable = useSessions(sessions => sessions.ids.includes(node.data.taskSessionId))\r\n const connected = useVoice(voice => voice.sessionId === sessionId && voice.state !== 'off' && voice.state !== 'error')\r\n const cancellable = connected && !isTerminalTaskStatus(node.data.status)\r\n return (\r\n <article\r\n className={css.taskCard}\r\n data-voice-delegation\r\n data-status={node.data.status}\r\n data-expanded={expanded}\r\n >\r\n <button\r\n type=\"button\"\r\n className={css.taskSummary}\r\n aria-expanded={expanded}\r\n aria-label={expanded ? t('task.collapse') : t('task.expand')}\r\n onClick={() => { setExpanded(value => !value) }}\r\n >\r\n <span className={css.taskDot} aria-hidden />\r\n <span className={css.taskTitle}>{t('task.title')}</span>\r\n <span className={css.taskStatus}>{t(STATUS_KEYS[node.data.status])}</span>\r\n <span className={css.taskChevron} aria-hidden />\r\n </button>\r\n {expanded && (\r\n <div className={css.taskDetails}>\r\n <p className={css.taskInput}>{node.data.input}</p>\r\n {node.data.update !== undefined && <p className={css.taskUpdate}>{node.data.update}</p>}\r\n <div className={css.taskActions}>\r\n {cancellable && (\r\n <button type=\"button\" className={`${css.taskLink} ${css.taskCancel}`} onClick={() => { cancelTask(String(node.data.taskId)) }}>\r\n {t('task.cancel')}\r\n </button>\r\n )}\r\n <button\r\n type=\"button\"\r\n className={css.taskLink}\r\n disabled={!navigable}\r\n onClick={() => { openSession(node.data.taskSessionId) }}\r\n >\r\n {t('task.open')}\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n </article>\r\n )\r\n}\r\n\r\nfunction isTerminalTaskStatus(status: VoiceDelegationChatData['status']): boolean {\r\n return status === 'completed' || status === 'failed' || status === 'cancelled' || status === 'interrupted'\r\n}\r\n","import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { VoiceClientSnapshot, VoiceClientState } from './voice-controller.ts'\r\nimport type { VoiceKey } from './locales.ts'\r\nimport css from './VoiceOverlay.module.css'\r\n\r\n/** Root-level voice connection actions. */\r\nexport interface VoiceOverlayInjected {\n hooks: {\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\n }\n readonly stopVoice: () => Promise<void>\n}\n\r\nexport type VoiceOverlayProps =\r\n PropsRuntime<'shell.overlay'> & InjectFace<VoiceOverlayInjected> & PropsLocale<'voice'>\r\n\r\nconst STATE_KEYS: Record<Exclude<VoiceClientState, 'off'>, VoiceKey> = {\r\n connecting: 'overlay.connecting',\r\n listening: 'overlay.listening',\r\n speaking: 'overlay.speaking',\r\n error: 'overlay.error',\r\n}\r\n\r\n/** Keep the active Voice Session controllable while another Session is selected. */\r\nexport function VoiceOverlay({ useVoice, stopVoice, t }: VoiceOverlayProps) {\n const voice = useVoice(snapshot => snapshot)\n if (voice.state === 'off') return null\n const statusKey = voice.inputMuted && voice.state !== 'error' ? 'overlay.muted' : STATE_KEYS[voice.state]\n return (\n <aside className={css.root} data-voice-overlay data-state={voice.state} data-muted={voice.inputMuted} aria-live=\"polite\">\n <span className={css.wave} aria-hidden>\r\n <i /><i /><i /><i />\r\n </span>\r\n <span className={css.status}>{t(statusKey)}</span>\n <button type=\"button\" className={css.stop} onClick={() => { void stopVoice() }}>\n {t('overlay.stop')}\r\n </button>\r\n </aside>\r\n )\r\n}\r\n","import { useEffect } from 'react'\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { VoiceHistorySnapshot } from './voice-history.ts'\nimport css from './VoiceSessionMarkers.module.css'\n\n/** Root overlay that annotates the host-owned session rows with Voice markers. */\nexport interface VoiceSessionMarkersInjected {\n hooks: {\n voiceHistory: { getSnapshot(): VoiceHistorySnapshot; subscribe(listener: () => void): () => void }\n }\n}\n\nexport type VoiceSessionMarkersProps =\n PropsRuntime<'shell.overlay'> & InjectFace<VoiceSessionMarkersInjected>\n\n/**\n * The workspace package currently owns the session-row renderer and does not\n * expose a row-level slot. This small, read-only decorator keeps the marker in\n * sync with that renderer while leaving row interactions and layout intact.\n */\nexport function VoiceSessionMarkers({ useSessions, useVoiceHistory }: VoiceSessionMarkersProps) {\n const sessions = useSessions(state => state.byId)\n const history = useVoiceHistory(state => state.entries)\n\n useEffect(() => {\n const voiceTitles = new Set<SessionId>(history.map(entry => entry.sessionId))\n const sessionIds = new Set(Object.keys(sessions))\n\n let frame = 0\n const decorate = (): void => {\n frame = 0\n const rows = document.querySelectorAll<HTMLElement>('[role=\"treeitem\"].sessionRow, [role=\"treeitem\"][class*=\"sessionRow\"]')\n for (const row of rows) {\n const slot = row.querySelector<HTMLElement>('[class*=\"slot\"]')\n const marker = row.querySelector<HTMLElement>('[data-voice-session-marker]')\n const sessionId = findSessionKey(row, sessionIds)\n const isVoice = sessionId !== undefined && voiceTitles.has(sessionId as SessionId)\n if (!isVoice) {\n marker?.remove()\n continue\n }\n if (marker !== null) continue\n const target = slot ?? createMarkerSlot(row)\n target.append(createMarker())\n }\n }\n const schedule = (): void => {\n if (frame !== 0) return\n frame = requestAnimationFrame(decorate)\n }\n decorate()\n const observer = new MutationObserver(schedule)\n observer.observe(document.body, { childList: true, subtree: true, characterData: true })\n return () => {\n observer.disconnect()\n if (frame !== 0) cancelAnimationFrame(frame)\n document.querySelectorAll('[data-voice-session-marker]').forEach(node => { node.remove() })\n document.querySelectorAll('[data-voice-session-marker-slot]').forEach(node => { node.remove() })\n }\n }, [history, sessions])\n\n return null\n}\n\n/** React keeps the keyed SessionNodeItem identity on the row's owner fiber. */\nfunction findSessionKey(row: HTMLElement, sessionIds: Set<string>): string | undefined {\n const fiberKey = Object.keys(row).find(key => key.startsWith('__reactFiber$'))\n if (fiberKey === undefined) return undefined\n let fiber = (row as unknown as Record<string, unknown>)[fiberKey] as { key: string | null; return?: unknown } | undefined\n while (fiber !== undefined) {\n if (fiber.key !== null && sessionIds.has(fiber.key)) return fiber.key\n fiber = fiber.return as typeof fiber | undefined\n }\n return undefined\n}\n\nfunction createMarkerSlot(row: HTMLElement): HTMLSpanElement {\n const slot = document.createElement('span')\n slot.dataset.voiceSessionMarkerSlot = ''\n slot.className = css.slot ?? 'voice-session-marker-slot'\n const title = row.querySelector<HTMLElement>('[class*=\"title\"]')\n row.insertBefore(slot, title ?? row.firstChild ?? null)\n return slot\n}\n\nfunction createMarker(): HTMLSpanElement {\n const marker = document.createElement('span')\n marker.dataset.voiceSessionMarker = ''\n marker.className = css.marker ?? 'voice-session-marker'\n marker.setAttribute('aria-hidden', 'true')\n marker.innerHTML = '<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M3 8h1.5M6 5v6M9 3.5v9M12 5.5v5M14 7h-1\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\" stroke-linecap=\"round\"/></svg>'\n return marker\n}\n","import type { ObservableSnapshot, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\n\r\n/** Browser-visible lifecycle of the one active voice transport. */\r\nexport type VoiceClientState = 'off' | 'connecting' | 'listening' | 'speaking' | 'error'\r\n\r\n/** Live text retained until the matching durable utterance settles. */\r\nexport interface VoiceLiveText {\r\n readonly text: string\r\n}\r\n\r\n/** Root-owned voice transport projection shared by every UI seat. */\r\nexport interface VoiceClientSnapshot {\n readonly state: VoiceClientState\n readonly inputMuted: boolean\n readonly sessionId?: SessionId\n readonly textById: Readonly<Record<string, VoiceLiveText>>\n}\n\ninterface VoiceTransport {\n close(): Promise<void>\n cancelTask(taskId: string): void\n interruptResponse(): void\n setInputMuted(muted: boolean): void\n submitText(text: string): void\n}\n\r\ninterface VoiceTransportHandlers {\n readonly onBinary: (audio: ArrayBuffer) => void\r\n readonly onEvent: (event: unknown) => void\r\n readonly onPlaybackEnded: () => void\r\n readonly onUnexpectedClose: () => void\r\n}\n\nexport interface VoiceControllerOptions {\n /** Called once after the first non-empty durable voice turn is completed. */\n readonly onConversationStarted?: (sessionId: SessionId) => void\n}\n\r\ninterface VoiceReadyEvent {\r\n readonly type: 'ready'\r\n readonly voiceSessionId: string\r\n readonly audio: {\r\n readonly inputSampleRate: number\r\n readonly outputSampleRate: number\r\n readonly format: 'pcm_s16le' | 'audio_mpeg'\r\n }\r\n readonly interactionMode: 'speech-shell' | 'frontend-agent'\r\n}\r\n\r\nconst INITIAL_SNAPSHOT: VoiceClientSnapshot = { state: 'off', inputMuted: false, textById: {} }\n\r\n/** Own the single browser microphone, provider WebSocket, playback queue, and live transcript feed. */\r\nexport class VoiceController implements ObservableSnapshot<VoiceClientSnapshot> {\n private snapshot = INITIAL_SNAPSHOT\r\n private readonly listeners = new Set<() => void>()\r\n private transport: VoiceTransport | undefined\r\n private openingTransport: VoiceTransport | undefined\r\n private openingAbort: AbortController | undefined\r\n private generation = 0\r\n private frame: number | undefined\r\n private readonly pendingText: string[] = []\n private readonly onConversationStarted: ((sessionId: SessionId) => void) | undefined\n private conversationStarted = false\n\n constructor(options: VoiceControllerOptions = {}) {\n this.onConversationStarted = options.onConversationStarted\n }\n\r\n /** Return the identity-stable snapshot until a voice fact changes. */\r\n getSnapshot = (): VoiceClientSnapshot => this.snapshot\r\n\r\n /** Subscribe to state and frame-coalesced transcript changes. */\r\n subscribe = (listener: () => void): (() => void) => {\r\n this.listeners.add(listener)\r\n return () => { this.listeners.delete(listener) }\r\n }\r\n\r\n /**\n * Open one voice transport and make it the root-owned active session.\n * @param sessionId - durable voice session to connect.\n */\n async start(sessionId: SessionId): Promise<void> {\n await this.open(sessionId, false)\n }\n\n private async open(sessionId: SessionId, inputMuted: boolean): Promise<void> {\n const generation = ++this.generation\n this.pendingText.splice(0)\n this.conversationStarted = false\n // Construct and unlock both contexts before the first await so browser\r\n // autoplay policy still treats the microphone button as the user gesture.\r\n const contexts = createAudioContexts()\r\n await this.closeTransport()\r\n if (generation !== this.generation) {\r\n await closeAudioContexts(contexts)\r\n return\r\n }\r\n const openingAbort = new AbortController()\r\n this.openingAbort = openingAbort\r\n this.publish({ state: 'connecting', inputMuted, sessionId, textById: {} })\n try {\r\n const transport = await openVoiceTransport(String(sessionId), {\r\n onBinary: () => { this.setState('speaking') },\r\n onEvent: (event) => { this.handleEvent(event) },\r\n onPlaybackEnded: () => { this.setState('listening') },\r\n onUnexpectedClose: () => { this.handleUnexpectedClose() },\r\n }, openingAbort.signal, (opening) => {\n if (generation === this.generation) {\n this.openingTransport = opening\n opening.setInputMuted(this.snapshot.inputMuted)\n }\n else void opening.close()\n }, contexts)\r\n if (generation !== this.generation) {\r\n await transport.close()\r\n return\r\n }\r\n this.openingTransport = undefined\r\n this.transport = transport\r\n for (const text of this.pendingText.splice(0)) transport.submitText(text)\r\n this.setState('listening')\r\n } catch (cause) {\r\n if (generation !== this.generation) return\r\n this.setState('error')\r\n throw cause\r\n } finally {\r\n if (this.openingAbort === openingAbort) this.openingAbort = undefined\r\n if (generation === this.generation) this.openingTransport = undefined\r\n }\r\n }\r\n\r\n /** Retry the failed active Voice Session, when one was created successfully. */\r\n async retry(): Promise<void> {\n const sessionId = this.snapshot.sessionId\n if (sessionId === undefined) throw new Error('voice retry requires an active session')\n await this.open(sessionId, this.snapshot.inputMuted)\n }\n\n /** Mute or resume microphone input without closing text submission or playback. */\n setInputMuted(muted: boolean): void {\n if (this.snapshot.state === 'off' || this.snapshot.state === 'error' || this.snapshot.sessionId === undefined) {\n throw new Error('voice input mute requires an active connection')\n }\n if (this.snapshot.inputMuted === muted) return\n this.openingTransport?.setInputMuted(muted)\n this.transport?.setInputMuted(muted)\n this.publish({ ...this.snapshot, inputMuted: muted })\n }\n\r\n /** Cancel the exact active background task through the attached Voice transport. */\r\n cancelTask(taskId: string): void {\n if (taskId === '') throw new Error('voice task id is required')\r\n if (this.transport === undefined) throw new Error('voice task cancellation requires an active connection')\r\n this.transport.cancelTask(taskId)\n }\n\n /** Stop the active assistant response without ending the Voice Session. */\n interruptResponse(): void {\n if (this.snapshot.state === 'off' || this.snapshot.state === 'error' || this.snapshot.sessionId === undefined) {\n throw new Error('voice response interruption requires an active connection')\n }\n const transport = this.transport ?? this.openingTransport\n if (transport === undefined) throw new Error('voice response interruption requires an active connection')\n transport.interruptResponse()\n this.setState('listening')\n }\n\r\n /** Submit composer text as a voice turn, queueing it while the transport connects. */\r\n submitText(text: string): void {\r\n const value = text.trim()\r\n if (value === '') throw new Error('voice text submission requires non-empty text')\r\n if (this.snapshot.state === 'off' || this.snapshot.state === 'error' || this.snapshot.sessionId === undefined) {\r\n throw new Error('voice text submission requires an active connection')\r\n }\r\n if (this.transport === undefined) this.pendingText.push(value)\r\n else this.transport.submitText(value)\r\n }\r\n\r\n /** Stop capture/playback and await owned browser-resource teardown. */\r\n async stop(): Promise<void> {\r\n ++this.generation\r\n this.openingAbort?.abort()\r\n this.openingAbort = undefined\r\n this.publish(INITIAL_SNAPSHOT)\r\n this.pendingText.splice(0)\r\n await this.closeTransport()\r\n }\r\n\r\n private async closeTransport(): Promise<void> {\r\n const transports = new Set<VoiceTransport>()\r\n if (this.transport !== undefined) transports.add(this.transport)\r\n if (this.openingTransport !== undefined) transports.add(this.openingTransport)\r\n this.transport = undefined\r\n this.openingTransport = undefined\r\n if (this.frame !== undefined) {\r\n cancelAnimationFrame(this.frame)\r\n this.frame = undefined\r\n }\r\n const settled = await Promise.allSettled([...transports].map(transport => transport.close()))\r\n const failures: unknown[] = []\r\n for (const result of settled) {\r\n if (result.status === 'rejected') failures.push(result.reason as unknown)\r\n }\r\n if (failures.length > 0) throw new AggregateError(failures, 'voice transport cleanup failed')\r\n }\r\n\r\n private handleUnexpectedClose(): void {\r\n this.openingAbort?.abort()\r\n this.setState('error')\r\n void this.closeTransport().catch((cause: unknown) => {\r\n console.error('voice transport cleanup failed:', cause)\r\n })\r\n }\r\n\r\n private setState(state: VoiceClientState): void {\r\n if (this.snapshot.state === state) return\r\n this.publish({ ...this.snapshot, state })\r\n }\r\n\r\n private setText(id: string, text: string, cadence: 'immediate' | 'animation-frame'): void {\r\n if (id === '') return\r\n const current = this.snapshot.textById[id]\r\n if (current?.text === text) return\r\n this.snapshot = {\r\n ...this.snapshot,\r\n textById: { ...this.snapshot.textById, [id]: { text } },\r\n }\r\n if (cadence === 'immediate') this.notify()\r\n else this.notifyOnFrame()\r\n }\r\n\r\n private appendText(id: string, delta: string): void {\r\n if (id === '' || delta === '') return\r\n this.setText(id, `${this.snapshot.textById[id]?.text ?? ''}${delta}`, 'animation-frame')\r\n }\r\n\r\n private handleEvent(input: unknown): void {\r\n const event = recordOf(input)\r\n if (event === undefined) return\r\n const type = stringOf(event.type)\r\n if (type === 'transcription.started') {\r\n this.setText(stringOf(event.utteranceId), '', 'immediate')\r\n this.setState('listening')\r\n return\r\n }\r\n if (type === 'transcription.updated') {\r\n this.setText(stringOf(event.utteranceId), stringOf(event.text), 'animation-frame')\r\n return\r\n }\r\n if (type === 'transcription.completed') {\n const text = stringOf(event.text)\n this.setText(stringOf(event.utteranceId), text, 'immediate')\n if (text.trim() !== '') this.markConversationStarted()\n return\n }\r\n if (type === 'output_text.started') {\r\n this.setText(stringOf(event.utteranceId), '', 'immediate')\r\n return\r\n }\r\n if (type === 'output_text.delta') {\r\n this.appendText(stringOf(event.utteranceId), stringOf(event.text))\r\n return\r\n }\r\n if (type === 'output_text.done') {\n const text = stringOf(event.text)\n if (text !== '') this.setText(stringOf(event.utteranceId), text, 'immediate')\n if (text.trim() !== '') this.markConversationStarted()\n return\n }\r\n if (type === 'output_audio.started') {\r\n this.setState('speaking')\r\n return\r\n }\r\n if (type === 'response.interrupted') {\r\n this.setState('listening')\r\n return\r\n }\r\n if (type === 'error') this.handleUnexpectedClose()\r\n }\n\n private markConversationStarted(): void {\n if (this.conversationStarted) return\n const sessionId = this.snapshot.sessionId\n if (sessionId === undefined) return\n this.conversationStarted = true\n this.onConversationStarted?.(sessionId)\n }\n\r\n private publish(snapshot: VoiceClientSnapshot): void {\r\n if (this.frame !== undefined) {\r\n cancelAnimationFrame(this.frame)\r\n this.frame = undefined\r\n }\r\n this.snapshot = snapshot\r\n this.notify()\r\n }\r\n\r\n private notifyOnFrame(): void {\r\n this.frame ??= requestAnimationFrame(() => {\r\n this.frame = undefined\r\n this.notify()\r\n })\r\n }\r\n\r\n private notify(): void {\r\n for (const listener of this.listeners) {\r\n try { listener() } catch (cause) { console.error('voice snapshot listener failed:', cause) }\r\n }\r\n }\r\n}\r\n\r\nfunction recordOf(value: unknown): Record<string, unknown> | undefined {\r\n return value !== null && typeof value === 'object' ? value as Record<string, unknown> : undefined\r\n}\r\n\r\nfunction stringOf(value: unknown): string {\r\n return typeof value === 'string' ? value : ''\r\n}\r\n\r\nasync function openVoiceTransport(\r\n sessionId: string,\r\n handlers: VoiceTransportHandlers,\r\n signal: AbortSignal,\r\n onOpening: (transport: VoiceTransport) => void,\r\n contexts: AudioContexts,\r\n): Promise<VoiceTransport> {\r\n const { input: inputContext, output: outputContext } = contexts\r\n const socket = new WebSocket(voiceUrl(sessionId))\r\n const workletUrl = URL.createObjectURL(new Blob([CAPTURE_WORKLET], { type: 'text/javascript' }))\r\n let stream: MediaStream | undefined\r\n let source: MediaStreamAudioSourceNode | undefined\r\n let processor: AudioWorkletNode | undefined\r\n let silent: GainNode | undefined\r\n let stopped = false\r\n let socketClosed = false\r\n let ready = false\r\n let outputDone = false\r\n let encodedPending = 0\r\n let playbackGeneration = 0\r\n let encodedQueue: Promise<void> = Promise.resolve()\r\n let inputSampleRate = 16_000\r\n let outputSampleRate = 24_000\r\n let audioFormat: VoiceReadyEvent['audio']['format'] = 'pcm_s16le'\r\n let playAt = outputContext.currentTime\n let inputMuted = false\n const chunks: number[] = []\n const playing = new Set<AudioBufferSourceNode>()\r\n\r\n const transport: VoiceTransport = {\n cancelTask: (taskId) => {\n if (socket.readyState !== WebSocket.OPEN) throw new Error('voice transport is not open')\n socket.send(JSON.stringify({ type: 'task.cancel', taskId }))\n },\n interruptResponse: () => {\n if (socket.readyState !== WebSocket.OPEN) throw new Error('voice transport is not open')\n socket.send(JSON.stringify({ type: 'response.interrupt' }))\n stopPlayback()\n },\n setInputMuted: (muted) => {\n if (inputMuted === muted) return\n inputMuted = muted\n chunks.splice(0)\n for (const track of stream?.getTracks() ?? []) track.enabled = !muted\n if (muted && !stopped && socket.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify({ type: 'audio.commit' }))\n }\n },\n submitText: (text) => {\r\n if (socket.readyState !== WebSocket.OPEN) throw new Error('voice transport is not open')\r\n socket.send(JSON.stringify({ type: 'text.submit', text }))\r\n },\r\n close: async () => {\r\n /* v8 ignore next -- controller ownership closes a transport once; the guard protects browser close races. */\r\n if (stopped) return\r\n stopped = true\r\n if (!socketClosed && socket.readyState === WebSocket.OPEN) {\r\n try { socket.send(JSON.stringify({ type: 'session.close' })) } catch {\r\n /* A socket closing concurrently cannot carry the final control; the server expires its reconnect grace. */\r\n }\r\n }\r\n socket.removeEventListener('message', onMessage)\r\n socket.removeEventListener('close', onClose)\r\n stopPlayback()\r\n source?.disconnect()\r\n processor?.disconnect()\r\n silent?.disconnect()\r\n processor?.port.close()\r\n for (const track of stream?.getTracks() ?? []) track.stop()\r\n socket.close()\r\n await Promise.allSettled([inputContext.close(), outputContext.close()])\r\n },\r\n }\r\n\r\n const stopPlayback = (): void => {\r\n playbackGeneration += 1\r\n encodedPending = 0\r\n encodedQueue = Promise.resolve()\r\n for (const node of playing) {\r\n try { node.stop() } catch { /* a completed source is already stopped */ }\r\n }\r\n playing.clear()\r\n playAt = outputContext.currentTime\r\n outputDone = false\r\n }\r\n const notifyPlaybackEnded = (): void => {\r\n if (outputDone && encodedPending === 0 && playing.size === 0 && socket.readyState === WebSocket.OPEN) {\r\n socket.send(JSON.stringify({ type: 'playback.ended' }))\r\n outputDone = false\r\n handlers.onPlaybackEnded()\r\n }\r\n }\r\n const onMessage = (message: MessageEvent): void => {\r\n if (!ready) return\r\n if (message.data instanceof ArrayBuffer) {\r\n if (audioFormat === 'audio_mpeg') {\r\n const generation = playbackGeneration\r\n encodedPending += 1\r\n encodedQueue = encodedQueue.catch(() => {}).then(() => scheduleEncoded(\r\n outputContext,\r\n message.data,\r\n playing,\r\n notifyPlaybackEnded,\r\n (value) => { playAt = value },\r\n () => playAt,\r\n () => generation === playbackGeneration && !stopped,\r\n )).catch(error => {\r\n if (generation === playbackGeneration && !stopped) {\r\n handlers.onEvent({ type: 'error', message: `audio decode failed: ${String(error)}` })\r\n }\r\n }).finally(() => {\r\n if (generation === playbackGeneration) {\r\n encodedPending -= 1\r\n notifyPlaybackEnded()\r\n }\r\n })\r\n } else {\r\n schedulePcm(outputContext, message.data, outputSampleRate, playing, notifyPlaybackEnded, (value) => { playAt = value }, playAt)\r\n }\r\n handlers.onBinary(message.data)\r\n return\r\n }\r\n let event: unknown\r\n try { event = JSON.parse(String(message.data)) } catch { return }\r\n const record = recordOf(event)\r\n if (record?.type === 'response.interrupted') stopPlayback()\n if (record?.type === 'output_audio.done') {\r\n outputDone = true\r\n notifyPlaybackEnded()\r\n }\r\n handlers.onEvent(event)\r\n }\r\n const onClose = (): void => {\r\n socketClosed = true\r\n handlers.onUnexpectedClose()\r\n }\r\n\r\n socket.binaryType = 'arraybuffer'\r\n onOpening(transport)\r\n try {\r\n await socketOpened(socket, signal)\r\n socket.addEventListener('message', onMessage)\r\n socket.addEventListener('close', onClose)\r\n const readyEvent = await socketReady(socket, signal)\r\n inputSampleRate = readyEvent.audio.inputSampleRate\r\n outputSampleRate = readyEvent.audio.outputSampleRate\r\n audioFormat = readyEvent.audio.format\r\n ready = true\r\n const captured = await microphone(signal)\r\n if (openingStopped(signal, stopped)) {\r\n for (const track of captured.getTracks()) track.stop()\r\n throw new Error('voice connection opening aborted')\r\n }\r\n stream = captured\n for (const track of stream.getTracks()) track.enabled = !inputMuted\n await abortable(inputContext.audioWorklet.addModule(workletUrl), signal)\r\n if (openingStopped(signal, stopped)) throw new Error('voice connection opening aborted')\r\n source = inputContext.createMediaStreamSource(stream)\r\n processor = new AudioWorkletNode(inputContext, 'dsh-pcm-capture')\r\n silent = inputContext.createGain()\r\n silent.gain.value = 0\r\n processor.port.onmessage = (event: MessageEvent<Float32Array>) => {\n if (inputMuted || socket.readyState !== WebSocket.OPEN) return\n chunks.push(...resample(event.data, inputContext.sampleRate, inputSampleRate))\r\n const frameSize = Math.max(1, Math.round(inputSampleRate / 5))\r\n while (chunks.length >= frameSize) {\r\n const part = chunks.splice(0, frameSize)\r\n const pcm = new Int16Array(part.length)\r\n for (const [index, sample] of part.entries()) {\r\n pcm[index] = Math.round(Math.max(-1, Math.min(1, sample)) * 32767)\r\n }\r\n socket.send(pcm.buffer)\r\n }\r\n }\r\n source.connect(processor)\r\n processor.connect(silent)\r\n silent.connect(inputContext.destination)\r\n } catch (cause) {\r\n await transport.close()\r\n throw cause\r\n } finally {\r\n URL.revokeObjectURL(workletUrl)\r\n }\r\n\r\n return transport\r\n}\r\n\r\ninterface AudioContexts {\r\n readonly input: AudioContext\r\n readonly output: AudioContext\r\n}\r\n\r\nfunction createAudioContexts(): AudioContexts {\r\n const contexts = { input: new AudioContext(), output: new AudioContext() }\r\n // Calling resume synchronously is required on browsers that start contexts\r\n // suspended when they are created outside a trusted user gesture.\r\n void contexts.input.resume().catch(() => {})\r\n void contexts.output.resume().catch(() => {})\r\n return contexts\r\n}\r\n\r\nasync function closeAudioContexts(contexts: AudioContexts): Promise<void> {\r\n await Promise.allSettled([contexts.input.close(), contexts.output.close()])\r\n}\r\n\r\nfunction microphone(signal: AbortSignal): Promise<MediaStream> {\r\n if (signal.aborted) return Promise.reject(new Error('voice connection opening aborted'))\r\n return new Promise((resolve, reject) => {\r\n let cancelled = false\r\n const cleanup = (): void => { signal.removeEventListener('abort', aborted) }\r\n const aborted = (): void => {\r\n cancelled = true\r\n cleanup()\r\n reject(new Error('voice connection opening aborted'))\r\n }\r\n signal.addEventListener('abort', aborted, { once: true })\r\n let request: Promise<MediaStream>\r\n try {\r\n request = navigator.mediaDevices.getUserMedia({\r\n audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true },\r\n })\r\n } catch (cause) {\r\n cleanup()\r\n reject(errorOf(cause))\r\n return\r\n }\r\n void request.then((value) => {\r\n cleanup()\r\n if (cancelled || signal.aborted) {\r\n for (const track of value.getTracks()) track.stop()\r\n return\r\n }\r\n resolve(value)\r\n }, (cause: unknown) => {\r\n cleanup()\r\n if (!cancelled) reject(errorOf(cause))\r\n })\r\n })\r\n}\r\n\r\nfunction abortable<T>(operation: Promise<T>, signal: AbortSignal): Promise<T> {\r\n if (signal.aborted) return Promise.reject(new Error('voice connection opening aborted'))\r\n return new Promise((resolve, reject) => {\r\n let cancelled = false\r\n const cleanup = (): void => { signal.removeEventListener('abort', aborted) }\r\n const aborted = (): void => {\r\n cleanup()\r\n cancelled = true\r\n reject(new Error('voice connection opening aborted'))\r\n }\r\n signal.addEventListener('abort', aborted, { once: true })\r\n void operation.then((value) => {\r\n cleanup()\r\n if (!cancelled) resolve(value)\r\n }, (cause: unknown) => {\r\n cleanup()\r\n if (!cancelled) reject(errorOf(cause))\r\n })\r\n })\r\n}\r\n\r\nfunction socketOpened(socket: WebSocket, signal: AbortSignal): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const cleanup = (): void => {\r\n socket.removeEventListener('open', opened)\r\n socket.removeEventListener('error', failed)\r\n signal.removeEventListener('abort', aborted)\r\n }\r\n const opened = (): void => { cleanup(); resolve() }\r\n const failed = (): void => { cleanup(); reject(new Error('voice websocket failed')) }\r\n const aborted = (): void => { cleanup(); reject(new Error('voice connection opening aborted')) }\r\n if (signal.aborted) { aborted(); return }\r\n socket.addEventListener('open', opened, { once: true })\r\n socket.addEventListener('error', failed, { once: true })\r\n signal.addEventListener('abort', aborted, { once: true })\r\n })\r\n}\r\n\r\nfunction socketReady(socket: WebSocket, signal: AbortSignal): Promise<VoiceReadyEvent> {\r\n return new Promise((resolve, reject) => {\r\n const cleanup = (): void => {\r\n socket.removeEventListener('message', received)\r\n socket.removeEventListener('error', failed)\r\n socket.removeEventListener('close', closed)\r\n signal.removeEventListener('abort', aborted)\r\n }\r\n const settle = (operation: () => void): void => { cleanup(); operation() }\r\n const received = (message: MessageEvent): void => {\r\n try {\r\n const value: unknown = message.data instanceof ArrayBuffer\r\n ? undefined\r\n : JSON.parse(String(message.data)) as unknown\r\n settle(() => { resolve(parseReady(value)) })\r\n } catch (cause) {\r\n settle(() => { reject(errorOf(cause)) })\r\n }\r\n }\r\n const failed = (): void => { settle(() => { reject(new Error('voice websocket failed before ready')) }) }\r\n const closed = (): void => { settle(() => { reject(new Error('voice websocket closed before ready')) }) }\r\n const aborted = (): void => { settle(() => { reject(new Error('voice connection opening aborted')) }) }\r\n if (signal.aborted) { aborted(); return }\r\n if (socket.readyState !== WebSocket.OPEN) { closed(); return }\r\n socket.addEventListener('message', received)\r\n socket.addEventListener('error', failed, { once: true })\r\n socket.addEventListener('close', closed, { once: true })\r\n signal.addEventListener('abort', aborted, { once: true })\r\n })\r\n}\r\n\r\nfunction openingStopped(signal: AbortSignal, stopped: boolean): boolean {\r\n return signal.aborted || stopped\r\n}\r\n\r\nfunction errorOf(cause: unknown): Error {\r\n return cause instanceof Error ? cause : new Error(String(cause))\r\n}\r\n\r\nfunction parseReady(value: unknown): VoiceReadyEvent {\r\n const event = recordOf(value)\r\n if (event?.type === 'error') {\r\n const message = stringOf(event.message)\r\n throw new Error(message === '' ? 'voice setup failed before ready' : message)\r\n }\r\n if (event?.type !== 'ready') throw new Error('voice websocket expected a ready event')\r\n const voiceSessionId = stringOf(event.voiceSessionId)\r\n if (voiceSessionId === '') throw new Error('voice websocket ready event has no voiceSessionId')\r\n const audio = recordOf(event.audio)\r\n if (audio?.inputSampleRate !== 16_000\r\n || (audio.outputSampleRate !== 24_000 && audio.outputSampleRate !== 48_000)\r\n || (audio.format !== 'pcm_s16le' && audio.format !== 'audio_mpeg')) {\r\n throw new Error('voice websocket ready event has unsupported audio settings')\r\n }\r\n if (event.interactionMode !== 'speech-shell' && event.interactionMode !== 'frontend-agent') {\r\n throw new Error('voice websocket ready event has an invalid interactionMode')\r\n }\r\n return { type: 'ready', voiceSessionId, audio: {\r\n inputSampleRate: audio.inputSampleRate,\r\n outputSampleRate: audio.outputSampleRate,\r\n format: audio.format,\r\n }, interactionMode: event.interactionMode }\r\n}\r\n\r\n/**\r\n * Resolve the dedicated WebSocket URL for one durable Voice Session.\r\n * @param sessionId - durable voice session id.\r\n * @param location - browser location used for host and protocol defaults.\r\n * @returns the /voice WebSocket URL carrying the session id.\r\n */\r\nexport function voiceUrl(sessionId: string, location: Pick<Location, 'href' | 'protocol'> = window.location): URL {\r\n const url = new URL('/voice', location.href)\r\n url.protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'\r\n url.searchParams.set('sessionId', sessionId)\r\n return url\r\n}\r\n\r\nconst CAPTURE_WORKLET = `\r\nclass DshPcmCaptureProcessor extends AudioWorkletProcessor {\r\n process(inputs) {\r\n const channel = inputs[0] && inputs[0][0]\r\n if (channel) this.port.postMessage(channel.slice())\r\n return true\r\n }\r\n}\r\nregisterProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)\r\n`\r\n\r\n/**\r\n * Resample browser float PCM into the provider input rate.\r\n * @param input - float samples at `fromRate`.\r\n * @param fromRate - source sample rate in Hz.\r\n * @param toRate - target sample rate in Hz.\r\n * @returns linearly interpolated samples at `toRate`.\r\n */\r\nexport function resample(input: Float32Array, fromRate: number, toRate: number): number[] {\r\n if (fromRate === toRate) return [...input]\r\n const ratio = fromRate / toRate\r\n const result = new Array<number>(Math.floor(input.length / ratio))\r\n for (let index = 0; index < result.length; index += 1) {\r\n const position = index * ratio\r\n const left = Math.floor(position)\r\n const fraction = position - left\r\n const leftSample = input[left] as number\r\n const rightSample = input[Math.min(left + 1, input.length - 1)] as number\r\n result[index] = leftSample * (1 - fraction) + rightSample * fraction\r\n }\r\n return result\r\n}\r\n\r\nfunction schedulePcm(\r\n context: AudioContext,\r\n bytes: ArrayBuffer,\r\n sampleRate: number,\r\n playing: Set<AudioBufferSourceNode>,\r\n ended: () => void,\r\n setPlayAt: (value: number) => void,\r\n currentPlayAt: number,\r\n): void {\r\n const pcm = new Int16Array(bytes)\r\n const buffer = context.createBuffer(1, pcm.length, sampleRate)\r\n const channel = buffer.getChannelData(0)\r\n for (const [index, sample] of pcm.entries()) channel[index] = sample / 32768\r\n const node = context.createBufferSource()\r\n node.buffer = buffer\r\n node.connect(context.destination)\r\n const start = Math.max(currentPlayAt, context.currentTime)\r\n setPlayAt(start + buffer.duration)\r\n playing.add(node)\r\n node.onended = () => { playing.delete(node); ended() }\r\n node.start(start)\r\n}\r\n\r\nasync function scheduleEncoded(\r\n context: AudioContext,\r\n bytes: ArrayBuffer,\r\n playing: Set<AudioBufferSourceNode>,\r\n ended: () => void,\r\n setPlayAt: (value: number) => void,\r\n getPlayAt: () => number,\r\n shouldSchedule: () => boolean,\r\n): Promise<void> {\r\n const buffer = await context.decodeAudioData(bytes.slice(0))\r\n if (!shouldSchedule()) return\r\n const node = context.createBufferSource()\r\n node.buffer = buffer\r\n node.connect(context.destination)\r\n const start = Math.max(getPlayAt(), context.currentTime)\r\n setPlayAt(start + buffer.duration)\r\n playing.add(node)\r\n node.onended = () => { playing.delete(node); ended() }\r\n node.start(start)\r\n}\r\n","import {\r\n createSnapshotStore, type SessionId, type SnapshotStore,\r\n} from '@deepseek-ai/dsh-client-runtime/client'\r\n\r\nconst STORAGE_KEY = 'dsh.voice.history.v1'\r\n\r\n/** One locally indexed durable Voice Session. */\r\nexport interface VoiceHistoryEntry {\r\n readonly sessionId: SessionId\r\n readonly lastActiveAt: number\r\n}\r\n\r\n/** Browser-persistent Voice Session index. */\r\nexport interface VoiceHistorySnapshot {\r\n readonly entries: readonly VoiceHistoryEntry[]\r\n}\r\n\r\ninterface StoredVoiceHistory {\r\n readonly version: 1\r\n readonly entries: readonly VoiceHistoryEntry[]\r\n}\r\n\r\nfunction parseEntry(input: unknown): VoiceHistoryEntry | undefined {\r\n if (typeof input !== 'object' || input === null) return undefined\r\n const value = input as Record<string, unknown>\r\n if (typeof value.sessionId !== 'string' || value.sessionId === '') return undefined\r\n if (typeof value.lastActiveAt !== 'number' || !Number.isFinite(value.lastActiveAt) || value.lastActiveAt < 0) {\r\n return undefined\r\n }\r\n return { sessionId: value.sessionId as SessionId, lastActiveAt: value.lastActiveAt }\r\n}\r\n\r\nfunction readHistory(storage: Storage | undefined): VoiceHistorySnapshot {\r\n if (storage === undefined) return { entries: [] }\r\n try {\r\n const raw = storage.getItem(STORAGE_KEY)\r\n if (raw === null) return { entries: [] }\r\n const parsed = JSON.parse(raw) as unknown\r\n if (typeof parsed !== 'object' || parsed === null) return { entries: [] }\r\n const value = parsed as Record<string, unknown>\r\n if (value.version !== 1 || !Array.isArray(value.entries)) return { entries: [] }\r\n const entries: VoiceHistoryEntry[] = []\r\n const seen = new Set<SessionId>()\r\n for (const candidate of value.entries) {\r\n const entry = parseEntry(candidate)\r\n if (entry === undefined || seen.has(entry.sessionId)) continue\r\n seen.add(entry.sessionId)\r\n entries.push(entry)\r\n }\r\n entries.sort((left, right) => right.lastActiveAt - left.lastActiveAt)\r\n return { entries }\r\n } catch (error: unknown) {\r\n console.error('voice history rehydration failed:', error)\r\n return { entries: [] }\r\n }\r\n}\r\n\r\n/** Own the local history index without adding Voice metadata to Host session projections. */\r\nexport class VoiceHistoryStore {\r\n readonly snapshot: SnapshotStore<VoiceHistorySnapshot>\r\n private readonly storage: Storage | undefined\r\n private readonly unsubscribe: () => void\r\n\r\n constructor(storage: Storage | undefined = typeof localStorage === 'undefined' ? undefined : localStorage) {\r\n this.storage = storage\r\n this.snapshot = createSnapshotStore(readHistory(storage))\r\n this.unsubscribe = this.snapshot.subscribe(() => { this.persist() })\r\n }\r\n\r\n /** Move one successfully opened Voice Session to the front of the index. */\r\n record(sessionId: SessionId, lastActiveAt = Date.now()): void {\r\n this.snapshot.set({\r\n entries: [\r\n { sessionId, lastActiveAt },\r\n ...this.snapshot.getSnapshot().entries.filter(entry => entry.sessionId !== sessionId),\r\n ],\r\n })\r\n }\r\n\r\n /** Stop persistence notifications. */\r\n dispose(): void {\r\n this.unsubscribe()\r\n }\r\n\r\n private persist(): void {\r\n if (this.storage === undefined) return\r\n const value: StoredVoiceHistory = { version: 1, entries: this.snapshot.getSnapshot().entries }\r\n try {\r\n this.storage.setItem(STORAGE_KEY, JSON.stringify(value))\r\n } catch (error: unknown) {\r\n console.error('voice history persistence failed:', error)\r\n }\r\n }\r\n}\r\n","import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type { VoiceClientSnapshot } from './voice-controller.ts'\r\n\r\ninterface VoiceTextInputState {\r\n readonly draft: string\r\n readonly imageIds: readonly unknown[]\r\n}\r\n\r\nexport interface VoiceTextInput {\r\n readonly state: { getSnapshot(): VoiceTextInputState }\r\n setDraft(text: string): void\r\n submit(mode?: unknown): void\r\n notify(level: 'info' | 'error', text: string): void\r\n}\r\n\r\ninterface VoiceTextController {\r\n getSnapshot(): VoiceClientSnapshot\r\n submitText(text: string): void\r\n}\r\n\r\ninterface PatchedInput {\r\n readonly input: VoiceTextInput\r\n readonly originalOwnDescriptor: PropertyDescriptor | undefined\r\n readonly patchedSubmit: (mode?: unknown) => void\r\n}\r\n\r\n/** Routes the native composer through Voice while preserving its ordinary offline submission. */\r\nexport class VoiceTextSubmitBridge {\r\n private readonly patched = new Map<SessionId, PatchedInput>()\r\n\r\n constructor(\r\n private readonly voice: VoiceTextController,\r\n private readonly resolveInput: (sessionId: SessionId) => VoiceTextInput,\r\n ) {}\r\n\r\n install(sessionId: SessionId): void {\r\n if (this.patched.has(sessionId)) return\r\n const input = this.resolveInput(sessionId)\r\n const originalOwnDescriptor = Object.getOwnPropertyDescriptor(input, 'submit')\r\n const originalSubmit = input.submit.bind(input)\r\n const patchedSubmit = (mode?: unknown): void => {\r\n const voice = this.voice.getSnapshot()\r\n const state = input.state.getSnapshot()\r\n const active = voice.sessionId === sessionId\r\n && voice.state !== 'off'\r\n && voice.state !== 'error'\r\n if (!active || state.draft.trim() === '' || state.imageIds.length > 0) {\r\n originalSubmit(mode)\r\n return\r\n }\r\n try {\r\n this.voice.submitText(state.draft)\r\n input.setDraft('')\r\n } catch (cause: unknown) {\r\n input.notify('error', cause instanceof Error ? cause.message : String(cause))\r\n }\r\n }\r\n input.submit = patchedSubmit\r\n this.patched.set(sessionId, { input, originalOwnDescriptor, patchedSubmit })\r\n }\r\n\r\n dispose(): void {\r\n for (const { input, originalOwnDescriptor, patchedSubmit } of this.patched.values()) {\r\n if (input.submit !== patchedSubmit) continue\r\n if (originalOwnDescriptor === undefined) delete (input as Partial<VoiceTextInput>).submit\r\n else Object.defineProperty(input, 'submit', originalOwnDescriptor)\r\n }\r\n this.patched.clear()\r\n }\r\n}\r\n","import type {\r\n ChatConversationViewNode, ConversationNodeDefinition, SessionId,\r\n} from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type {\r\n TaskObservation, VoiceTaskId, VoiceUtteranceId,\r\n} from '@flowingspring/dsh-voice'\n\r\n/** Renderer-ready durable Voice utterance. */\r\nexport interface VoiceUtteranceChatData {\r\n readonly utteranceId: VoiceUtteranceId\r\n readonly role: 'user' | 'assistant'\r\n readonly text?: string\r\n readonly state: 'streaming' | 'completed' | 'interrupted'\r\n}\r\n\r\n/** Renderer-ready delegated task link and its latest observation. */\r\nexport interface VoiceDelegationChatData {\r\n readonly taskId: VoiceTaskId\r\n readonly taskSessionId: SessionId\r\n readonly input: string\r\n readonly status: TaskObservation['status']\r\n readonly update?: string\r\n}\r\n\r\ndeclare module '@deepseek-ai/dsh-client-ui-conversation/client' {\r\n interface ChatNodeDataMap {\r\n /** One user ASR or assistant TTS transcript produced in Voice Mode. */\r\n 'voice-utterance': VoiceUtteranceChatData\r\n /** One independent DSH task delegated by the Voice frontend Agent. */\r\n 'voice-delegation': VoiceDelegationChatData\r\n }\r\n}\r\n\r\ntype VoiceUtteranceState = VoiceUtteranceChatData\r\ntype VoiceDelegationState = VoiceDelegationChatData\r\n\r\n/** Fold one streamed utterance into a stable Chat node. */\r\nexport const voiceUtteranceDefinition: ConversationNodeDefinition<VoiceUtteranceState> = {\r\n kind: 'voice-utterance',\r\n target: 'chat',\r\n match: (event) => {\r\n if (event.type === 'voice/utterance-start') {\r\n return { id: String(event.data.utteranceId), role: 'start' }\r\n }\r\n if (event.type === 'voice/utterance-end') {\r\n return { id: String(event.data.utteranceId), role: 'update' }\r\n }\r\n return null\r\n },\r\n start: (_context, match) => {\r\n if (match.event.type !== 'voice/utterance-start') {\r\n throw new Error('voice utterance start requires voice/utterance-start')\r\n }\r\n return {\r\n utteranceId: match.event.data.utteranceId,\r\n role: match.event.data.role,\r\n state: 'streaming',\r\n }\r\n },\r\n update: (context, match) => {\r\n if (match.event.type !== 'voice/utterance-end') return context.state\r\n return {\r\n ...context.state,\r\n text: match.event.data.text,\r\n state: match.event.data.state,\r\n }\r\n },\r\n buildViewNode: (context): ChatConversationViewNode | null => {\r\n if (context.start === undefined || context.state === undefined) return null\r\n const emptyInterrupted = context.state.state === 'interrupted'\r\n && (context.state.text?.trim() ?? '') === ''\r\n return {\r\n key: context.key,\r\n kind: 'voice-utterance',\r\n id: context.id,\r\n target: 'chat',\r\n anchorSeq: context.start.event.seq,\r\n location: context.start.location,\r\n // A live start may already be materialized before an empty noise segment\r\n // settles. Conversation nodes cannot be withdrawn after publication, so\r\n // keep its stable identity and hide it instead.\r\n visibility: emptyInterrupted ? 'hidden' : 'visible',\r\n data: context.state as VoiceUtteranceState,\r\n }\r\n },\r\n}\r\n\r\n/** Fold a delegated task and all observations into one navigation card. */\r\nexport const voiceDelegationDefinition: ConversationNodeDefinition<VoiceDelegationState> = {\r\n kind: 'voice-delegation',\r\n target: 'chat',\r\n match: (event) => {\r\n if (event.type === 'voice/task-delegated') {\r\n return { id: String(event.data.taskId), role: 'start' }\r\n }\r\n if (event.type === 'voice/task-observation') {\r\n return { id: String(event.data.taskId), role: 'update' }\r\n }\r\n return null\r\n },\r\n start: (_context, match) => {\r\n if (match.event.type !== 'voice/task-delegated') {\r\n throw new Error('voice delegation start requires voice/task-delegated')\r\n }\r\n return {\r\n taskId: match.event.data.taskId,\r\n taskSessionId: match.event.data.taskSessionId,\r\n input: match.event.data.input,\r\n status: 'accepted',\r\n }\r\n },\r\n update: (context, match) => {\r\n if (match.event.type !== 'voice/task-observation') return context.state\r\n const observation = match.event.data\r\n const update = observation.voiceMessage?.text\r\n ?? observation.announcement\r\n ?? observation.reason\r\n ?? context.state.update\r\n return {\r\n ...context.state,\r\n status: observation.status,\r\n ...(update === undefined ? {} : { update }),\r\n }\r\n },\r\n buildViewNode: (context): ChatConversationViewNode | null => {\r\n if (context.start === undefined) return null\r\n return {\r\n key: context.key,\r\n kind: 'voice-delegation',\r\n id: context.id,\r\n target: 'chat',\r\n anchorSeq: context.start.event.seq,\r\n location: context.start.location,\r\n visibility: 'visible',\r\n data: context.state as VoiceDelegationState,\r\n }\r\n },\r\n}\r\n","/** `voice` namespace dictionaries. */\r\n\r\n/** Dictionary namespace owned by this plugin. */\r\nexport const NS = 'voice'\r\n\r\n/** Simplified Chinese dictionary (the key-set source of truth). */\r\nexport const zh = {\r\n 'badge.voice': 'VOICE',\r\n 'control.start': '开始语音对话',\n 'control.retry': '语音连接失败,点击重试',\n 'control.interrupt': '打断播放',\n 'control.mute': '静音麦克风',\n 'control.unmute': '解除静音',\n 'overlay.connecting': '正在连接语音',\n 'overlay.listening': '正在聆听',\n 'overlay.speaking': '正在回复',\n 'overlay.error': '语音连接失败',\n 'overlay.muted': '已静音',\n 'overlay.stop': '结束',\n 'utterance.user.pending': '正在聆听…',\r\n 'utterance.assistant.pending': '正在生成语音回复…',\r\n 'utterance.interrupted': '已打断',\r\n 'task.title': '后台处理',\r\n 'task.status.accepted': '已接受',\r\n 'task.status.queued': '排队中',\r\n 'task.status.running': '执行中',\r\n 'task.status.waiting-user': '等待确认',\r\n 'task.status.completed': '已完成',\r\n 'task.status.failed': '失败',\r\n 'task.status.cancelled': '已取消',\r\n 'task.status.interrupted': '服务中断',\r\n 'task.expand': '展开后台处理详情',\r\n 'task.collapse': '收起后台处理详情',\r\n 'task.cancel': '取消任务',\r\n 'task.open': '查看后台详情',\r\n} satisfies Record<string, string>\r\n\r\n/** Union of this namespace's dictionary keys. */\r\nexport type VoiceKey = keyof typeof zh\r\n\r\n/** English dictionary, checked complete against the zh key set. */\r\nexport const en = {\r\n 'badge.voice': 'VOICE',\r\n 'control.start': 'Start voice conversation',\n 'control.retry': 'Voice connection failed, press to retry',\n 'control.interrupt': 'Stop playback',\n 'control.mute': 'Mute microphone',\n 'control.unmute': 'Unmute microphone',\n 'overlay.connecting': 'Connecting voice',\n 'overlay.listening': 'Listening',\n 'overlay.speaking': 'Playing response',\n 'overlay.error': 'Voice connection failed',\n 'overlay.muted': 'Muted',\n 'overlay.stop': 'End',\n 'utterance.user.pending': 'Listening…',\r\n 'utterance.assistant.pending': 'Generating voice response…',\r\n 'utterance.interrupted': 'Interrupted',\r\n 'task.title': 'Background task',\r\n 'task.status.accepted': 'Accepted',\r\n 'task.status.queued': 'Queued',\r\n 'task.status.running': 'Running',\r\n 'task.status.waiting-user': 'Waiting for you',\r\n 'task.status.completed': 'Completed',\r\n 'task.status.failed': 'Failed',\r\n 'task.status.cancelled': 'Cancelled',\r\n 'task.status.interrupted': 'Interrupted',\r\n 'task.expand': 'Show background task details',\r\n 'task.collapse': 'Hide background task details',\r\n 'task.cancel': 'Cancel task',\r\n 'task.open': 'View background details',\r\n} satisfies Record<VoiceKey, string>\r\n","/** Browser voice UI assembly. @module @flowingspring/dsh-client-ui-voice/client */\nimport type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport { VoiceControl, type VoiceControlInjected } from './VoiceControl.tsx'\nimport {\n VoiceDelegationView, type VoiceDelegationInjected,\r\n VoiceUtteranceView, type VoiceUtteranceInjected,\r\n} from './VoiceNodeViews.tsx'\r\nimport { VoiceOverlay, type VoiceOverlayInjected } from './VoiceOverlay.tsx'\nimport { VoiceSessionMarkers, type VoiceSessionMarkersInjected } from './VoiceSessionMarkers.tsx'\nimport { VoiceController } from './voice-controller.ts'\r\nimport { VoiceHistoryStore } from './voice-history.ts'\r\nimport { VoiceTextSubmitBridge, type VoiceTextInput } from './voice-text-submit.ts'\r\nimport { voiceDelegationDefinition, voiceUtteranceDefinition } from './voice-definitions.ts'\r\nimport { en, NS, type VoiceKey, zh } from './locales.ts'\r\n\r\nexport type { VoiceKey } from './locales.ts'\r\n\r\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\r\n interface LocaleNamespaceMap {\r\n /** Browser Voice conversation copy. */\r\n voice: VoiceKey\r\n }\r\n}\r\n\r\nexport const inject = ['conversation', 'conversationEvents', 'slots', 'sessions', 'locale']\n\n/** Refresh the Host-backed Session list when the runtime exposes its baseline pull. */\nfunction refreshSessions(ctx: ClientContext): void {\n // `refresh()` exists on the concrete SessionRuntime used by dsh Web, but is\n // intentionally omitted from the narrow feature-facing ISessions contract.\n // Keep this compatibility bridge optional for older runtimes and fixtures.\n const service = ctx.sessions as unknown as { refresh?: () => Promise<void> }\n if (typeof service.refresh !== 'function') return\n void service.refresh.call(ctx.sessions).catch((cause: unknown) => {\n console.warn('voice session list refresh failed:', cause)\n })\n}\n\n/** Mount root transport controls and durable Voice conversation renderers. @param ctx - browser context. */\nexport function apply(ctx: ClientContext): void {\n const controller = new VoiceController({\n onConversationStarted: () => {\n // Voice events are appended by the Host, while the browser's session\n // list keeps its own blank-bit cache. Refresh once after the first\n // completed turn so Workspace new-session creation does not reuse the\n // now-engaged Voice Session.\n refreshSessions(ctx)\n },\n })\n const history = new VoiceHistoryStore()\r\n const textSubmit = new VoiceTextSubmitBridge(controller, (sessionId) => {\r\n const scope = ctx.sessions.scope(sessionId)\r\n if (scope === undefined) throw new Error(`voice input session \"${sessionId}\" is unavailable`)\r\n return ctx.conversation.input.for(scope) as VoiceTextInput\r\n })\r\n const stopVoice = (): Promise<void> => controller.stop()\r\n const startVoice = async (sourceSessionId: SessionId): Promise<void> => {\r\n ctx.sessions.open(sourceSessionId)\r\n textSubmit.install(sourceSessionId)\r\n await controller.start(sourceSessionId)\r\n history.record(sourceSessionId)\r\n }\r\n const voiceControlInjected = (): VoiceControlInjected => ({\r\n hooks: { voice: controller },\r\n startVoice,\r\n retryVoice: async () => {\n await controller.retry()\n const sessionId = controller.getSnapshot().sessionId\n if (sessionId !== undefined) history.record(sessionId)\n },\n interruptResponse: () => { controller.interruptResponse() },\n setVoiceMuted: (muted) => { controller.setInputMuted(muted) },\n })\n const voiceOverlayInjected = (): VoiceOverlayInjected => ({ hooks: { voice: controller }, stopVoice })\n const voiceSessionMarkersInjected = (): VoiceSessionMarkersInjected => ({\n hooks: { voiceHistory: history.snapshot },\n })\n const utteranceInjected = (): VoiceUtteranceInjected => ({ hooks: { voice: controller } })\r\n const delegationInjected = (): VoiceDelegationInjected => ({\r\n hooks: { voice: controller },\r\n openSession: (id) => { ctx.sessions.open(id) },\r\n cancelTask: (id) => { controller.cancelTask(id) },\r\n })\r\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-voice: dictionaries')\r\n ctx.effect(() => async () => { await controller.stop() }, 'ui-voice: transport teardown')\r\n ctx.effect(() => () => { textSubmit.dispose() }, 'ui-voice: text submit bridge teardown')\r\n ctx.effect(() => () => { history.dispose() }, 'ui-voice: history persistence teardown')\r\n ctx.conversationEvents.register(voiceUtteranceDefinition)\r\n ctx.conversationEvents.register(voiceDelegationDefinition)\r\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\r\n name: 'conversation.input.right',\r\n id: 'voice',\r\n order: 20,\r\n locale: NS,\r\n inject: voiceControlInjected,\r\n }, VoiceControl))\r\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\r\n id: 'voice-active',\r\n order: 20,\r\n locale: NS,\r\n inject: voiceOverlayInjected,\r\n }, VoiceOverlay))\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\n id: 'voice-session-markers',\n order: 10,\n locale: NS,\n inject: voiceSessionMarkersInjected,\n }, VoiceSessionMarkers))\n ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({\r\n name: 'conversation.chat.node',\r\n key: 'voice-utterance',\r\n locale: NS,\r\n inject: utteranceInjected,\r\n }, VoiceUtteranceView))\r\n ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({\r\n name: 'conversation.chat.node',\r\n key: 'voice-delegation',\r\n locale: NS,\r\n inject: delegationInjected,\r\n }, VoiceDelegationView))\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["css","css","useState","css","useRef","css","createRoot","useState","IconEditOutline16","IconBranchOutline16","IconTrashOutline16","Menu","IconEllipsisOutline16","Modal","Button","createSnapshotStore"],"sources":["../../../packages/ui-voice/src/client/VoiceControl.tsx","../../../packages/ui-voice/src/client/session-archive.ts","../../../packages/ui-voice/src/client/VoiceNodeViews.tsx","../../../packages/ui-voice/src/client/VoiceOverlay.tsx","../../../packages/ui-voice/src/client/VoiceSessionMarkers.tsx","../../../packages/ui-voice/src/client/voice-controller.ts","../../../packages/ui-voice/src/client/voice-history.ts","../../../packages/ui-voice/src/client/voice-text-submit.ts","../../../packages/ui-voice/src/client/voice-definitions.ts","../../../packages/ui-voice/src/client/locales.ts","../../../packages/ui-voice/src/client/index.ts"],"sourcesContent":["import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type { VoiceClientSnapshot } from './voice-controller.ts'\r\nimport css from './VoiceControl.module.css'\r\n\r\n/** Business callbacks and the root-owned transport snapshot. */\r\nexport interface VoiceControlInjected {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n /** Start a fresh Voice conversation located from the current Session. */\n readonly startVoice: (sourceSessionId: SessionId) => Promise<void>\n readonly retryVoice: () => Promise<void>\n readonly interruptResponse: () => void\n readonly setVoiceMuted: (muted: boolean) => void\n}\n\r\nexport type VoiceControlProps =\r\n PropsRuntime<'conversation.input.right'> & InjectFace<VoiceControlInjected> & PropsLocale<'voice'>\r\n\r\n/** Start a fresh Voice Session from this Session's location or control the active connection. */\r\nexport function VoiceControl({\n sessionId, useVoice, startVoice, retryVoice, setVoiceMuted, t,\n interruptResponse,\n}: VoiceControlProps) {\n const state = useVoice(snapshot => snapshot.state)\n const activeSessionId = useVoice(snapshot => snapshot.sessionId)\n const inputMuted = useVoice(snapshot => snapshot.inputMuted)\n\r\n const toggle = async (): Promise<void> => {\r\n if (state === 'error' && activeSessionId !== undefined) {\r\n try { await retryVoice() } catch { /* controller owns the visible error state */ }\r\n return\r\n }\r\n if (state !== 'off' && state !== 'error') {\n setVoiceMuted(!inputMuted)\n return\n }\r\n try {\r\n await startVoice(sessionId)\r\n } catch { /* controller owns the visible error state */ }\r\n }\r\n\r\n const label = state === 'off'\n ? t('control.start')\n : state === 'error'\n ? t('control.retry')\n : inputMuted\n ? t('control.unmute')\n : t('control.mute')\n const active = state !== 'off' && state !== 'error'\n const interrupt = (): void => {\n try { interruptResponse() } catch { /* controller owns the visible connection state */ }\n }\n return (\n <span className={css.controls}>\n {state === 'speaking' && (\n <button\n type=\"button\"\n className={`${css.button} ${css.interruptButton}`}\n aria-label={t('control.interrupt')}\n title={t('control.interrupt')}\n data-state={state}\n onClick={interrupt}\n >\n <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" aria-hidden>\n <circle cx=\"8\" cy=\"8\" r=\"6.25\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" />\n <rect x=\"5.25\" y=\"5.25\" width=\"5.5\" height=\"5.5\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </button>\n )}\n <button\n type=\"button\"\n className={`${css.button} ${active ? css.active : ''}`}\n aria-label={label}\n aria-pressed={active ? inputMuted : undefined}\n title={label}\n data-state={state}\n data-muted={inputMuted}\n onClick={() => { void toggle() }}\n >\n <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" aria-hidden>\n <rect x=\"5\" y=\"2\" width=\"6\" height=\"8\" rx=\"3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" />\n <path d=\"M3.5 7.5a4.5 4.5 0 0 0 9 0M8 12v2M5.5 14h5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" strokeLinecap=\"round\" />\n {inputMuted && (\n <path d=\"M2.5 2.5l11 11\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" />\n )}\n </svg>\n </button>\n </span>\n )\n}\n","import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\n\n/** Minimal session shape needed to walk the Host-owned parent chain. */\nexport interface SessionArchiveSummary {\n readonly parentId?: SessionId\n}\n\n/**\n * Returns whether a session is archived itself or inherits archive state from\n * any known ancestor. The optional fallback resolves a parent when the\n * summary is not present yet (for example while a subagent route is loading).\n * Cycles terminate the walk without throwing in render paths.\n */\nexport function isSessionEffectivelyArchived(\n sessionId: SessionId,\n archivedSessionIds: ReadonlySet<SessionId> | readonly SessionId[],\n summaries: Readonly<Record<SessionId, unknown>>,\n fallbackParent?: (id: SessionId) => SessionId | undefined,\n): boolean {\n const archived = archivedSessionIds instanceof Set\n ? archivedSessionIds\n : new Set(archivedSessionIds)\n const visited = new Set<SessionId>()\n let current: SessionId | undefined = sessionId\n while (current !== undefined && !visited.has(current)) {\n if (archived.has(current)) return true\n visited.add(current)\n const summary: unknown = summaries[current]\n const parentId: SessionId | undefined = summary !== null && typeof summary === 'object' && 'parentId' in summary\n ? (summary as SessionArchiveSummary).parentId\n : undefined\n current = parentId ?? fallbackParent?.(current)\n }\n return false\n}\n","import { useEffect, useState } from 'react'\nimport type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type { VoiceClientSnapshot } from './voice-controller.ts'\r\nimport type { VoiceDelegationChatData } from './voice-definitions.ts'\r\nimport type { VoiceKey } from './locales.ts'\nimport { isSessionEffectivelyArchived } from './session-archive.ts'\nimport css from './VoiceNodeViews.module.css'\n\r\n/** Live transcript source injected into the Voice utterance renderer. */\r\nexport interface VoiceUtteranceInjected {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n}\r\n\r\n/** Navigation action injected into the task-card renderer. */\r\nexport interface VoiceDelegationInjected {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n readonly openSession: (id: SessionId) => void\n readonly cancelTask: (id: string) => void\n readonly recordTaskActivity?: (id: SessionId, at: number, parentSessionId?: SessionId) => void\n}\r\n\r\nexport type VoiceUtteranceViewProps =\r\n PropsRuntime<'conversation.chat.node', 'voice-utterance'>\r\n & InjectFace<VoiceUtteranceInjected>\r\n & PropsLocale<'voice'>\r\nexport type VoiceDelegationViewProps =\r\n PropsRuntime<'conversation.chat.node', 'voice-delegation'>\r\n & InjectFace<VoiceDelegationInjected>\r\n & PropsLocale<'voice'>\r\n\r\n/** Render a durable Voice utterance while replacing its unsettled text with live WebSocket deltas. */\r\nexport function VoiceUtteranceView({ node, sessionId, useVoice, t }: VoiceUtteranceViewProps) {\r\n const liveText = useVoice(snapshot => snapshot.sessionId === sessionId\r\n ? snapshot.textById[String(node.data.utteranceId)]?.text\r\n : undefined)\r\n const text = node.data.text ?? liveText ?? (node.data.role === 'user'\r\n ? t('utterance.user.pending')\r\n : t('utterance.assistant.pending'))\r\n return (\r\n <article\r\n className={css.utterance}\r\n data-voice-utterance\r\n data-role={node.data.role}\r\n data-state={node.data.state}\r\n >\r\n <div className={css.bubble}>{text}</div>\r\n <div className={css.meta}>\r\n <span className={css.voiceBadge}>\r\n <span className={css.miniWave} aria-hidden><i /><i /><i /></span>\r\n {t('badge.voice')}\r\n </span>\r\n {node.data.state === 'interrupted' && <span>{t('utterance.interrupted')}</span>}\r\n </div>\r\n </article>\r\n )\r\n}\r\n\r\nconst STATUS_KEYS: Record<VoiceDelegationChatData['status'], VoiceKey> = {\r\n accepted: 'task.status.accepted',\r\n queued: 'task.status.queued',\r\n running: 'task.status.running',\r\n 'waiting-user': 'task.status.waiting-user',\r\n completed: 'task.status.completed',\r\n failed: 'task.status.failed',\r\n cancelled: 'task.status.cancelled',\r\n interrupted: 'task.status.interrupted',\r\n}\r\n\r\n/** Render the task link from a Voice Session to its bound background Agent Session. */\r\nexport function VoiceDelegationView({ node, sessionId, useSessions, useWorkspaces, useVoice, openSession, cancelTask, recordTaskActivity, t }: VoiceDelegationViewProps) {\n const [expanded, setExpanded] = useState(false)\n useEffect(() => {\n const at = node.data.lastActivityAt\n if (recordTaskActivity !== undefined && at !== undefined) {\n recordTaskActivity(node.data.taskSessionId, at, sessionId)\n }\n }, [node.data.lastActivityAt, node.data.taskSessionId, recordTaskActivity, sessionId])\n const archivedSessionIds = useWorkspaces(state => state.archivedSessionIds)\n const navigable = useSessions(sessions => !isSessionEffectivelyArchived(\n node.data.taskSessionId,\n archivedSessionIds,\n sessions.byId,\n id => id === node.data.taskSessionId ? sessionId : undefined,\n ) && (sessions.ids.includes(node.data.taskSessionId)\n || Object.values(sessions.subagentsByParent).some(catalog => catalog.entries.some(entry => (\n entry.kind === 'child' && entry.id === node.data.taskSessionId\n )))))\n const connected = useVoice(voice => voice.sessionId === sessionId && voice.state !== 'off' && voice.state !== 'error')\r\n const cancellable = connected && !isTerminalTaskStatus(node.data.status)\r\n return (\r\n <article\r\n className={css.taskCard}\r\n data-voice-delegation\r\n data-status={node.data.status}\r\n data-expanded={expanded}\r\n >\r\n <button\r\n type=\"button\"\r\n className={css.taskSummary}\r\n aria-expanded={expanded}\r\n aria-label={expanded ? t('task.collapse') : t('task.expand')}\r\n onClick={() => { setExpanded(value => !value) }}\r\n >\r\n <span className={css.taskDot} aria-hidden />\r\n <span className={css.taskTitle}>{t('task.title')}</span>\r\n <span className={css.taskStatus}>{t(STATUS_KEYS[node.data.status])}</span>\r\n <span className={css.taskChevron} aria-hidden />\r\n </button>\r\n {expanded && (\r\n <div className={css.taskDetails}>\r\n <p className={css.taskInput}>{node.data.input}</p>\r\n {node.data.update !== undefined && <p className={css.taskUpdate}>{node.data.update}</p>}\r\n <div className={css.taskActions}>\r\n {cancellable && (\r\n <button type=\"button\" className={`${css.taskLink} ${css.taskCancel}`} onClick={() => { cancelTask(String(node.data.taskId)) }}>\r\n {t('task.cancel')}\r\n </button>\r\n )}\r\n <button\r\n type=\"button\"\r\n className={css.taskLink}\r\n disabled={!navigable}\r\n onClick={() => { openSession(node.data.taskSessionId) }}\r\n >\r\n {t('task.open')}\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n </article>\r\n )\r\n}\r\n\r\nfunction isTerminalTaskStatus(status: VoiceDelegationChatData['status']): boolean {\r\n return status === 'completed' || status === 'failed' || status === 'cancelled' || status === 'interrupted'\r\n}\r\n","import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { VoiceClientSnapshot, VoiceClientState } from './voice-controller.ts'\r\nimport type { VoiceKey } from './locales.ts'\r\nimport css from './VoiceOverlay.module.css'\r\n\r\n/** Root-level voice connection actions. */\r\nexport interface VoiceOverlayInjected {\n hooks: {\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\n }\n readonly stopVoice: () => Promise<void>\n}\n\r\nexport type VoiceOverlayProps =\r\n PropsRuntime<'shell.overlay'> & InjectFace<VoiceOverlayInjected> & PropsLocale<'voice'>\r\n\r\nconst STATE_KEYS: Record<Exclude<VoiceClientState, 'off'>, VoiceKey> = {\r\n connecting: 'overlay.connecting',\r\n listening: 'overlay.listening',\r\n speaking: 'overlay.speaking',\r\n error: 'overlay.error',\r\n}\r\n\r\n/** Keep the active Voice Session controllable while another Session is selected. */\r\nexport function VoiceOverlay({ useVoice, stopVoice, t }: VoiceOverlayProps) {\n const voice = useVoice(snapshot => snapshot)\n if (voice.state === 'off') return null\n const statusKey = voice.inputMuted && voice.state !== 'error' ? 'overlay.muted' : STATE_KEYS[voice.state]\n return (\n <aside className={css.root} data-voice-overlay data-state={voice.state} data-muted={voice.inputMuted} aria-live=\"polite\">\n <span className={css.wave} aria-hidden>\r\n <i /><i /><i /><i />\r\n </span>\r\n <span className={css.status}>{t(statusKey)}</span>\n <button type=\"button\" className={css.stop} onClick={() => { void stopVoice() }}>\n {t('overlay.stop')}\r\n </button>\r\n </aside>\r\n )\r\n}\r\n","import { useEffect, useRef, useState } from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport {\n Button, IconBranchOutline16, IconEditOutline16, IconEllipsisOutline16,\n IconTrashOutline16, Menu, Modal,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { VoiceHistorySnapshot } from './voice-history.ts'\nimport { isSessionEffectivelyArchived } from './session-archive.ts'\nimport css from './VoiceSessionMarkers.module.css'\n\n/** Root overlay that annotates the host-owned session rows with Voice markers. */\nexport interface VoiceSessionMarkersInjected {\n hooks: {\n voiceHistory: { getSnapshot(): VoiceHistorySnapshot; subscribe(listener: () => void): () => void }\n }\n openSession: (id: SessionId) => void\n childActions?: {\n rename?: (id: SessionId, title: string) => Promise<void>\n fork?: (id: SessionId) => Promise<void>\n /** Optional archive-manager capability; absent when that plugin is not installed. */\n delete?: (id: SessionId, title: string) => Promise<void>\n }\n refreshSubagents: (parentSessionId: SessionId) => void\n setSubagentCatalogOpen: (parentSessionId: SessionId, open: boolean) => void\n}\n\nexport type VoiceSessionMarkersProps =\n PropsRuntime<'shell.overlay'> & InjectFace<VoiceSessionMarkersInjected>\n\n/**\n * The workspace package currently owns the session-row renderer and filters\n * subagent children from its top-level list. This decorator adds the voice\n * marker and a small parent-owned child tree. Child actions are forwarded to\n * the same runtime/registry operations used by the Host row menu.\n */\nexport function VoiceSessionMarkers({ useSessions, useWorkspaces, useVoiceHistory, openSession, childActions, refreshSubagents, setSubagentCatalogOpen }: VoiceSessionMarkersProps) {\n const sessions = useSessions(state => state)\n const archivedSessionIds = useWorkspaces(state => state.archivedSessionIds)\n const history = useVoiceHistory(state => state)\n const expandedParents = useRef(new Set<SessionId>())\n const requestedParents = useRef(new Set<SessionId>())\n\n useEffect(() => {\n const voiceTitles = new Set<SessionId>(history.entries.map(entry => entry.sessionId))\n // A session list can outlive the local parent index (for example after a\n // profile reload). Delegation cards persist the child -> Voice parent\n // association, which is enough to recover the parent's disclosure row.\n for (const entry of history.taskActivity ?? []) {\n if (entry.parentSessionId !== undefined) voiceTitles.add(entry.parentSessionId)\n }\n const taskActivity = new Map((history.taskActivity ?? []).map(entry => [entry.sessionId, entry.lastActiveAt]))\n const sessionIds = new Set(Object.keys(sessions.byId))\n for (const parentId of voiceTitles) {\n if (!requestedParents.current.has(parentId)) {\n requestedParents.current.add(parentId)\n refreshSubagents(parentId)\n }\n }\n\n let frame = 0\n const decorate = (): void => {\n frame = 0\n const rows = document.querySelectorAll<HTMLElement>('[role=\"treeitem\"].sessionRow, [role=\"treeitem\"][class*=\"sessionRow\"]')\n for (const row of rows) {\n const slot = row.querySelector<HTMLElement>('[class*=\"slot\"]')\n const marker = row.querySelector<HTMLElement>('[data-voice-session-marker]')\n const sessionId = findSessionKey(row, sessionIds)\n const isVoice = sessionId !== undefined && voiceTitles.has(sessionId as SessionId)\n if (!isVoice) {\n marker?.remove()\n row.querySelector('[data-voice-subagent-toggle]')?.remove()\n removeSubagentList(row, sessionId as SessionId | undefined)\n continue\n }\n const target = slot ?? createMarkerSlot(row)\n if (marker === null) target.append(createMarker())\n const parentId = sessionId as SessionId\n const catalog = sessions.subagentsByParent[parentId]\n // The host's catalog can remain pending while its header already\n // knows that children exist. Keep the disclosure affordance mounted\n // for every Voice parent so a pending/error catalog is still\n // reachable and retryable.\n const hasChildren = true\n if (!hasChildren) {\n row.querySelector('[data-voice-subagent-toggle]')?.remove()\n removeSubagentList(row, parentId)\n continue\n }\n const expanded = expandedParents.current.has(parentId)\n const toggle = row.querySelector<HTMLButtonElement>('[data-voice-subagent-toggle]') ?? createSubagentToggle(parentId, expanded, () => {\n const next = !expandedParents.current.has(parentId)\n if (next) expandedParents.current.add(parentId)\n else expandedParents.current.delete(parentId)\n setSubagentCatalogOpen(parentId, next)\n if (next) refreshSubagents(parentId)\n decorate()\n })\n updateSubagentToggle(toggle, parentId, expanded, () => {\n const next = !expandedParents.current.has(parentId)\n if (next) expandedParents.current.add(parentId)\n else expandedParents.current.delete(parentId)\n setSubagentCatalogOpen(parentId, next)\n if (next) refreshSubagents(parentId)\n decorate()\n })\n const title = row.querySelector<HTMLElement>('[class*=\"title\"]')\n if (toggle.parentElement !== row) row.insertBefore(toggle, title ?? null)\n renderSubagentChildren(row, parentId, catalog?.entries ?? [], expanded, sessions.current, sessions.byId, new Set(archivedSessionIds), taskActivity, openSession, childActions)\n }\n }\n const schedule = (): void => {\n if (frame !== 0) return\n frame = requestAnimationFrame(decorate)\n }\n decorate()\n const clock = window.setInterval(schedule, 60_000)\n const observer = new MutationObserver(schedule)\n const suppressChildHover = (event: Event): void => {\n const target = event.target\n if (!(target instanceof Element)) return\n const child = target.closest<HTMLElement>('[data-voice-subagent-child]')\n if (child === null) return\n event.stopPropagation()\n suppressHostHover(child)\n }\n // The Host HoverCard listens high in the tree. Capture-phase suppression\n // is needed because stopping a child bubble event is already too late for\n // a delegated host listener.\n document.addEventListener('pointerover', suppressChildHover, true)\n document.addEventListener('mouseover', suppressChildHover, true)\n document.addEventListener('pointerenter', suppressChildHover, true)\n document.addEventListener('mouseenter', suppressChildHover, true)\n observer.observe(document.body, { childList: true, subtree: true, characterData: true })\n return () => {\n observer.disconnect()\n document.removeEventListener('pointerover', suppressChildHover, true)\n document.removeEventListener('mouseover', suppressChildHover, true)\n document.removeEventListener('pointerenter', suppressChildHover, true)\n document.removeEventListener('mouseenter', suppressChildHover, true)\n window.clearInterval(clock)\n if (frame !== 0) cancelAnimationFrame(frame)\n document.querySelectorAll('[data-voice-session-marker]').forEach(node => { node.remove() })\n document.querySelectorAll('[data-voice-session-marker-slot]').forEach(node => { node.remove() })\n document.querySelectorAll<HTMLElement>('[data-voice-subagent-list]').forEach(node => {\n unmountChildMenus(node)\n node.remove()\n })\n document.querySelectorAll('[data-voice-subagent-toggle]').forEach(node => { node.remove() })\n }\n }, [history, sessions, archivedSessionIds, openSession, childActions, refreshSubagents, setSubagentCatalogOpen])\n\n return null\n}\n\nfunction createSubagentToggle(parentId: SessionId, expanded: boolean, onClick: () => void): HTMLButtonElement {\n const button = document.createElement('button')\n button.type = 'button'\n button.dataset.voiceSubagentToggle = ''\n button.className = css.toggle ?? 'voice-subagent-toggle'\n updateSubagentToggle(button, parentId, expanded, onClick)\n button.onclick = event => {\n event.stopPropagation()\n onClick()\n }\n button.dataset.parentSessionId = parentId\n return button\n}\n\nfunction updateSubagentToggle(button: HTMLButtonElement, parentId: SessionId, expanded: boolean, onClick: () => void): void {\n button.dataset.parentSessionId = parentId\n const label = expanded ? '收起语音子会话' : '展开语音子会话'\n if (button.getAttribute('aria-label') !== label) button.setAttribute('aria-label', label)\n const expandedValue = String(expanded)\n if (button.getAttribute('aria-expanded') !== expandedValue) button.setAttribute('aria-expanded', expandedValue)\n if (button.title !== label) button.title = label\n const icon = expanded ? '⌄' : '›'\n if (button.textContent !== icon) button.innerHTML = `<span aria-hidden=\"true\">${icon}</span>`\n button.onclick = event => {\n event.stopPropagation()\n onClick()\n }\n}\n\nfunction renderSubagentChildren(\n row: HTMLElement,\n parentId: SessionId,\n entries: readonly { readonly kind: string; readonly id: SessionId; readonly label?: string; readonly activity?: string; readonly updatedAt?: number }[],\n expanded: boolean,\n current: SessionId | undefined,\n summaries: Readonly<Record<SessionId, { readonly updatedAt?: number; readonly parentId?: SessionId }>>,\n archivedSessionIds: ReadonlySet<SessionId>,\n taskActivity: ReadonlyMap<SessionId, number>,\n openSession: (id: SessionId) => void,\n childActions?: VoiceSessionMarkersInjected['childActions'],\n): void {\n let list = findSubagentList(row, parentId)\n if (!expanded) {\n if (list !== undefined && list !== null) unmountChildMenus(list)\n list?.remove()\n return\n }\n if (list === null || list === undefined) {\n list = document.createElement('div')\n list.dataset.voiceSubagentList = String(parentId)\n list.className = css.children ?? 'voice-subagent-children'\n row.parentElement?.insertBefore(list, row.nextSibling)\n }\n // Keep broken/stale catalog rows visible as diagnostics instead of making\n // an expanded parent look empty. Only healthy child entries are navigable.\n const children = entries.filter(entry => entry.kind !== 'parent' && !isSessionEffectivelyArchived(\n entry.id,\n archivedSessionIds,\n summaries,\n id => id === entry.id ? parentId : undefined,\n ))\n const signature = children.map(entry => `${entry.id}:${entry.label ?? ''}:${entry.activity ?? ''}:${childUpdatedAt(entry.id, entry, summaries, taskActivity) ?? ''}`).join('|')\n if (list.dataset.signature === signature && list.dataset.current === String(current ?? '')) return\n list.dataset.signature = signature\n list.dataset.current = String(current ?? '')\n unmountChildMenus(list)\n list.replaceChildren(...children.map(entry => {\n const child = document.createElement('div')\n child.className = css.child ?? 'voice-subagent-child'\n child.dataset.voiceSubagentChild = ''\n child.dataset.sessionId = String(entry.id)\n ;(child as HTMLElement & { disabled?: boolean }).disabled = entry.kind !== 'child'\n if (entry.kind !== 'child') child.dataset.state = 'unavailable'\n child.setAttribute('role', 'treeitem')\n child.tabIndex = entry.kind === 'child' ? 0 : -1\n child.setAttribute('aria-current', entry.id === current ? 'page' : 'false')\n const unavailableLabel = entry.kind === 'diagnostic'\n ? '会话记录损坏'\n : '子会话暂时不可用'\n const displayLabel = entry.label ?? (entry.kind === 'child' ? String(entry.id) : unavailableLabel)\n child.addEventListener('mouseenter', event => suppressHostHover(child, event), true)\n child.addEventListener('mouseover', event => suppressHostHover(child, event), true)\n child.addEventListener('pointerenter', event => suppressHostHover(child, event), true)\n child.addEventListener('click', event => {\n if (event.target !== child || entry.kind !== 'child') return\n openSession(entry.id)\n })\n const dot = document.createElement('span')\n dot.className = css.childDot ?? 'voice-subagent-child-dot'\n dot.dataset.activity = entry.activity ?? 'inactive'\n const label = document.createElement('span')\n label.className = css.childLabel ?? 'voice-subagent-child-label'\n label.textContent = displayLabel\n const open = document.createElement('button')\n open.type = 'button'\n open.className = css.childMain ?? 'voice-subagent-child-main'\n open.disabled = entry.kind !== 'child'\n open.append(dot, label)\n child.append(open)\n const updatedAt = childUpdatedAt(entry.id, entry, summaries, taskActivity)\n if (updatedAt !== undefined) {\n const time = document.createElement('span')\n time.className = css.childTime ?? 'voice-subagent-child-time'\n time.dataset.voiceSubagentChildTime = ''\n time.dataset.updatedAt = String(updatedAt)\n time.textContent = relativeTimeLabel(updatedAt, Date.now())\n open.append(time)\n }\n open.addEventListener('click', event => {\n event.stopPropagation()\n if (entry.kind !== 'child') return\n openSession(entry.id)\n })\n if (entry.kind === 'child') mountChildMenu(child, entry.id, displayLabel, childActions)\n return child\n }))\n}\n\nfunction suppressHostHover(child: HTMLElement, event?: Event): void {\n event?.stopPropagation()\n child.dataset.voiceChildHover = 'true'\n const list = child.closest<HTMLElement>('[data-voice-subagent-list]')\n const parentRow = list?.previousElementSibling\n if (!(parentRow instanceof HTMLElement)) return\n // HoverCard is controlled by the parent SessionNodeItem. A synthetic leave\n // clears that state when the pointer moves into our sibling child row.\n const outside = document.body\n if (typeof PointerEvent === 'function') {\n parentRow.dispatchEvent(new PointerEvent('pointerleave', { bubbles: false, relatedTarget: outside }))\n parentRow.dispatchEvent(new PointerEvent('pointerout', { bubbles: true, relatedTarget: outside }))\n }\n parentRow.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false, relatedTarget: outside }))\n parentRow.dispatchEvent(new MouseEvent('mouseout', { bubbles: true, relatedTarget: outside }))\n}\n\nconst childMenuRoots = new WeakMap<HTMLElement, Root>()\n\nfunction mountChildMenu(\n child: HTMLElement,\n id: SessionId,\n title: string,\n actions: VoiceSessionMarkersInjected['childActions'],\n): void {\n const wrapper = document.createElement('span')\n wrapper.className = css.childActions ?? 'voice-subagent-child-actions'\n wrapper.dataset.voiceChildMenuRoot = ''\n child.append(wrapper)\n const root = createRoot(wrapper)\n childMenuRoots.set(wrapper, root)\n root.render(<OfficialChildMenu id={id} title={title} actions={actions} onOpenChange={open => {\n child.dataset.menuOpen = String(open)\n }} />)\n}\n\nfunction unmountChildMenus(list: HTMLElement): void {\n list.querySelectorAll<HTMLElement>('[data-voice-child-menu-root]').forEach(root => {\n childMenuRoots.get(root)?.unmount()\n childMenuRoots.delete(root)\n })\n}\n\nfunction OfficialChildMenu({ id, title, actions, onOpenChange }: {\n id: SessionId\n title: string\n actions: VoiceSessionMarkersInjected['childActions']\n onOpenChange: (open: boolean) => void\n}) {\n const [open, setOpen] = useState(false)\n const [deleteOpen, setDeleteOpen] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const [deleteError, setDeleteError] = useState<string | null>(null)\n const [actionError, setActionError] = useState<string | null>(null)\n const items = [\n { id: 'rename', label: '重命名', icon: <IconEditOutline16 /> },\n { id: 'fork', label: '分叉会话', icon: <IconBranchOutline16 /> },\n ...actions?.delete === undefined ? [] : [{\n id: 'delete', label: '删除会话', icon: <IconTrashOutline16 />, danger: true,\n }],\n ]\n const setMenuOpen = (next: boolean): void => {\n setOpen(next)\n onOpenChange(next)\n }\n const closeDelete = (): void => {\n if (deleting) return\n setDeleteOpen(false)\n setDeleteError(null)\n }\n const confirmDelete = (): void => {\n if (deleting || actions?.delete === undefined) return\n setDeleting(true)\n setDeleteError(null)\n void actions.delete(id, title).then(() => {\n setDeleting(false)\n setDeleteOpen(false)\n }, cause => {\n setDeleting(false)\n setDeleteError(cause instanceof Error ? cause.message : String(cause))\n })\n }\n return <>\n <Menu\n open={open}\n onClose={() => { setMenuOpen(false) }}\n items={items}\n onSelect={selected => {\n setMenuOpen(false)\n setActionError(null)\n if (selected === 'delete') {\n setDeleteError(null)\n setDeleteOpen(true)\n return\n }\n const run = selected === 'rename'\n ? (() => {\n if (actions?.rename === undefined) return undefined\n const next = window.prompt('重命名会话', title)\n return next === null ? undefined : actions.rename(id, next)\n })()\n : actions?.fork?.(id)\n void run?.catch(error => {\n console.warn('voice child action failed:', error)\n setActionError(error instanceof Error ? error.message : String(error))\n })\n }}\n portal\n closeOnPointerLeave\n anchor={<button\n type=\"button\"\n className={css.childMenuButton ?? 'voice-subagent-child-menu-button'}\n aria-label={`会话“${title}”的操作`}\n onClick={event => { event.stopPropagation(); setMenuOpen(!open) }}\n ><IconEllipsisOutline16 /></button>}\n />\n <Modal\n open={deleteOpen}\n onClose={closeDelete}\n closeLabel=\"关闭\"\n title=\"删除会话\"\n description={`将永久删除会话“${title}”及其子代理(含正在运行的)和全部记录(对话内容、统计、缓存),此操作不可恢复。`}\n footer={<>\n <Button variant=\"outline\" disabled={deleting} onClick={closeDelete}>取消</Button>\n <Button\n variant=\"outline\"\n className={css.deleteAction ?? 'voice-subagent-delete-action'}\n disabled={deleting}\n onClick={confirmDelete}\n >删除会话</Button>\n </>}\n >\n {deleting && <div className={css.deleteStatus} role=\"status\">正在删除会话…</div>}\n {deleteError !== null && <div className={css.deleteError} role=\"alert\">删除会话失败:{deleteError}</div>}\n </Modal>\n <Modal\n open={actionError !== null}\n onClose={() => { setActionError(null) }}\n closeLabel=\"关闭\"\n title=\"会话操作失败\"\n description={actionError ?? ''}\n footer={<Button variant=\"outline\" onClick={() => { setActionError(null) }}>关闭</Button>}\n />\n </>\n}\n\nfunction childUpdatedAt(\n id: SessionId,\n entry: { readonly updatedAt?: number },\n summaries: Readonly<Record<SessionId, { readonly updatedAt?: number }>>,\n taskActivity: ReadonlyMap<SessionId, number>,\n): number | undefined {\n if (typeof entry.updatedAt === 'number' && entry.updatedAt > 0) return entry.updatedAt\n const summaryTime = summaries[id]?.updatedAt\n if (typeof summaryTime === 'number' && summaryTime > 0) return summaryTime\n const taskTime = taskActivity.get(id)\n return typeof taskTime === 'number' && taskTime > 0 ? taskTime : undefined\n}\n\n/** Match the Host workspace's compact relative-time buckets for child rows. */\nexport function relativeTimeLabel(updatedAt: number, now: number, language = typeof navigator !== 'undefined' ? navigator.language : 'en-US'): string {\n const diff = Math.max(0, now - updatedAt)\n const minute = 60_000\n const hour = 3_600_000\n const day = 86_400_000\n const chinese = language.toLowerCase().startsWith('zh')\n if (diff < minute) return chinese ? '刚刚' : 'now'\n if (diff < hour) {\n const n = Math.floor(diff / minute)\n return chinese ? `${n}分钟` : `${n}min`\n }\n if (diff < day) {\n const n = Math.floor(diff / hour)\n return chinese ? `${n}小时` : `${n}h`\n }\n if (diff < 30 * day) {\n const n = Math.floor(diff / day)\n return chinese ? `${n}天` : `${n}d`\n }\n if (diff < 365 * day) {\n const n = Math.floor(diff / (30 * day))\n return chinese ? `${n}个月` : `${n}mo`\n }\n const n = Math.floor(diff / (365 * day))\n return chinese ? `${n}年` : `${n}y`\n}\n\nfunction findSubagentList(row: HTMLElement, parentId: SessionId): HTMLElement | undefined {\n return [...(row.parentElement?.querySelectorAll<HTMLElement>('[data-voice-subagent-list]') ?? [])]\n .find(candidate => candidate.dataset.voiceSubagentList === String(parentId))\n}\n\nfunction removeSubagentList(row: HTMLElement, parentId: SessionId | undefined): void {\n if (parentId === undefined) return\n const list = findSubagentList(row, parentId)\n if (list === undefined) return\n unmountChildMenus(list)\n list.remove()\n}\n\n/** React keeps the keyed SessionNodeItem identity on the row's owner fiber. */\nfunction findSessionKey(row: HTMLElement, sessionIds: Set<string>): string | undefined {\n const fiberKey = Object.keys(row).find(key => key.startsWith('__reactFiber$'))\n if (fiberKey === undefined) return undefined\n let fiber = (row as unknown as Record<string, unknown>)[fiberKey] as { key: string | null; return?: unknown } | undefined\n while (fiber !== undefined) {\n if (fiber.key !== null && sessionIds.has(fiber.key)) return fiber.key\n fiber = fiber.return as typeof fiber | undefined\n }\n return undefined\n}\n\nfunction createMarkerSlot(row: HTMLElement): HTMLSpanElement {\n const slot = document.createElement('span')\n slot.dataset.voiceSessionMarkerSlot = ''\n slot.className = css.slot ?? 'voice-session-marker-slot'\n const title = row.querySelector<HTMLElement>('[class*=\"title\"]')\n row.insertBefore(slot, title ?? row.firstChild ?? null)\n return slot\n}\n\nfunction createMarker(): HTMLSpanElement {\n const marker = document.createElement('span')\n marker.dataset.voiceSessionMarker = ''\n marker.className = css.marker ?? 'voice-session-marker'\n marker.setAttribute('aria-hidden', 'true')\n marker.innerHTML = '<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M3 8h1.5M6 5v6M9 3.5v9M12 5.5v5M14 7h-1\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\" stroke-linecap=\"round\"/></svg>'\n return marker\n}\n","import type { ObservableSnapshot, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\n\r\n/** Browser-visible lifecycle of the one active voice transport. */\r\nexport type VoiceClientState = 'off' | 'connecting' | 'listening' | 'speaking' | 'error'\r\n\r\n/** Live text retained until the matching durable utterance settles. */\r\nexport interface VoiceLiveText {\r\n readonly text: string\r\n}\r\n\r\n/** Root-owned voice transport projection shared by every UI seat. */\r\nexport interface VoiceClientSnapshot {\n readonly state: VoiceClientState\n readonly inputMuted: boolean\n readonly sessionId?: SessionId\n readonly textById: Readonly<Record<string, VoiceLiveText>>\n}\n\ninterface VoiceTransport {\n close(): Promise<void>\n cancelTask(taskId: string): void\n interruptResponse(): void\n setInputMuted(muted: boolean): void\n submitText(text: string): void\n}\n\r\ninterface VoiceTransportHandlers {\n readonly onBinary: (audio: ArrayBuffer) => void\r\n readonly onEvent: (event: unknown) => void\r\n readonly onPlaybackEnded: () => void\r\n readonly onUnexpectedClose: () => void\r\n}\n\nexport interface VoiceControllerOptions {\n /** Called once after the first non-empty durable voice turn is completed. */\n readonly onConversationStarted?: (sessionId: SessionId) => void\n}\n\r\ninterface VoiceReadyEvent {\r\n readonly type: 'ready'\r\n readonly voiceSessionId: string\r\n readonly audio: {\r\n readonly inputSampleRate: number\r\n readonly outputSampleRate: number\r\n readonly format: 'pcm_s16le' | 'audio_mpeg'\r\n }\r\n readonly interactionMode: 'speech-shell' | 'frontend-agent'\r\n}\r\n\r\nconst INITIAL_SNAPSHOT: VoiceClientSnapshot = { state: 'off', inputMuted: false, textById: {} }\n\r\n/** Own the single browser microphone, provider WebSocket, playback queue, and live transcript feed. */\r\nexport class VoiceController implements ObservableSnapshot<VoiceClientSnapshot> {\n private snapshot = INITIAL_SNAPSHOT\r\n private readonly listeners = new Set<() => void>()\r\n private transport: VoiceTransport | undefined\r\n private openingTransport: VoiceTransport | undefined\r\n private openingAbort: AbortController | undefined\r\n private generation = 0\r\n private frame: number | undefined\r\n private readonly pendingText: string[] = []\n private readonly onConversationStarted: ((sessionId: SessionId) => void) | undefined\n private conversationStarted = false\n\n constructor(options: VoiceControllerOptions = {}) {\n this.onConversationStarted = options.onConversationStarted\n }\n\r\n /** Return the identity-stable snapshot until a voice fact changes. */\r\n getSnapshot = (): VoiceClientSnapshot => this.snapshot\r\n\r\n /** Subscribe to state and frame-coalesced transcript changes. */\r\n subscribe = (listener: () => void): (() => void) => {\r\n this.listeners.add(listener)\r\n return () => { this.listeners.delete(listener) }\r\n }\r\n\r\n /**\n * Open one voice transport and make it the root-owned active session.\n * @param sessionId - durable voice session to connect.\n */\n async start(sessionId: SessionId): Promise<void> {\n await this.open(sessionId, false)\n }\n\n private async open(sessionId: SessionId, inputMuted: boolean): Promise<void> {\n const generation = ++this.generation\n this.pendingText.splice(0)\n this.conversationStarted = false\n // Construct and unlock both contexts before the first await so browser\r\n // autoplay policy still treats the microphone button as the user gesture.\r\n const contexts = createAudioContexts()\r\n await this.closeTransport()\r\n if (generation !== this.generation) {\r\n await closeAudioContexts(contexts)\r\n return\r\n }\r\n const openingAbort = new AbortController()\r\n this.openingAbort = openingAbort\r\n this.publish({ state: 'connecting', inputMuted, sessionId, textById: {} })\n try {\r\n const transport = await openVoiceTransport(String(sessionId), {\r\n onBinary: () => { this.setState('speaking') },\r\n onEvent: (event) => { this.handleEvent(event) },\r\n onPlaybackEnded: () => { this.setState('listening') },\r\n onUnexpectedClose: () => { this.handleUnexpectedClose() },\r\n }, openingAbort.signal, (opening) => {\n if (generation === this.generation) {\n this.openingTransport = opening\n opening.setInputMuted(this.snapshot.inputMuted)\n }\n else void opening.close()\n }, contexts)\r\n if (generation !== this.generation) {\r\n await transport.close()\r\n return\r\n }\r\n this.openingTransport = undefined\r\n this.transport = transport\r\n for (const text of this.pendingText.splice(0)) transport.submitText(text)\r\n this.setState('listening')\r\n } catch (cause) {\r\n if (generation !== this.generation) return\r\n this.setState('error')\r\n throw cause\r\n } finally {\r\n if (this.openingAbort === openingAbort) this.openingAbort = undefined\r\n if (generation === this.generation) this.openingTransport = undefined\r\n }\r\n }\r\n\r\n /** Retry the failed active Voice Session, when one was created successfully. */\r\n async retry(): Promise<void> {\n const sessionId = this.snapshot.sessionId\n if (sessionId === undefined) throw new Error('voice retry requires an active session')\n await this.open(sessionId, this.snapshot.inputMuted)\n }\n\n /** Mute or resume microphone input without closing text submission or playback. */\n setInputMuted(muted: boolean): void {\n if (this.snapshot.state === 'off' || this.snapshot.state === 'error' || this.snapshot.sessionId === undefined) {\n throw new Error('voice input mute requires an active connection')\n }\n if (this.snapshot.inputMuted === muted) return\n this.openingTransport?.setInputMuted(muted)\n this.transport?.setInputMuted(muted)\n this.publish({ ...this.snapshot, inputMuted: muted })\n }\n\r\n /** Cancel the exact active background task through the attached Voice transport. */\r\n cancelTask(taskId: string): void {\n if (taskId === '') throw new Error('voice task id is required')\r\n if (this.transport === undefined) throw new Error('voice task cancellation requires an active connection')\r\n this.transport.cancelTask(taskId)\n }\n\n /** Stop the active assistant response without ending the Voice Session. */\n interruptResponse(): void {\n if (this.snapshot.state === 'off' || this.snapshot.state === 'error' || this.snapshot.sessionId === undefined) {\n throw new Error('voice response interruption requires an active connection')\n }\n const transport = this.transport ?? this.openingTransport\n if (transport === undefined) throw new Error('voice response interruption requires an active connection')\n transport.interruptResponse()\n this.setState('listening')\n }\n\r\n /** Submit composer text as a voice turn, queueing it while the transport connects. */\r\n submitText(text: string): void {\r\n const value = text.trim()\r\n if (value === '') throw new Error('voice text submission requires non-empty text')\r\n if (this.snapshot.state === 'off' || this.snapshot.state === 'error' || this.snapshot.sessionId === undefined) {\r\n throw new Error('voice text submission requires an active connection')\r\n }\r\n if (this.transport === undefined) this.pendingText.push(value)\r\n else this.transport.submitText(value)\r\n }\r\n\r\n /** Stop capture/playback and await owned browser-resource teardown. */\r\n async stop(): Promise<void> {\r\n ++this.generation\r\n this.openingAbort?.abort()\r\n this.openingAbort = undefined\r\n this.publish(INITIAL_SNAPSHOT)\r\n this.pendingText.splice(0)\r\n await this.closeTransport()\r\n }\r\n\r\n private async closeTransport(): Promise<void> {\r\n const transports = new Set<VoiceTransport>()\r\n if (this.transport !== undefined) transports.add(this.transport)\r\n if (this.openingTransport !== undefined) transports.add(this.openingTransport)\r\n this.transport = undefined\r\n this.openingTransport = undefined\r\n if (this.frame !== undefined) {\r\n cancelAnimationFrame(this.frame)\r\n this.frame = undefined\r\n }\r\n const settled = await Promise.allSettled([...transports].map(transport => transport.close()))\r\n const failures: unknown[] = []\r\n for (const result of settled) {\r\n if (result.status === 'rejected') failures.push(result.reason as unknown)\r\n }\r\n if (failures.length > 0) throw new AggregateError(failures, 'voice transport cleanup failed')\r\n }\r\n\r\n private handleUnexpectedClose(): void {\r\n this.openingAbort?.abort()\r\n this.setState('error')\r\n void this.closeTransport().catch((cause: unknown) => {\r\n console.error('voice transport cleanup failed:', cause)\r\n })\r\n }\r\n\r\n private setState(state: VoiceClientState): void {\r\n if (this.snapshot.state === state) return\r\n this.publish({ ...this.snapshot, state })\r\n }\r\n\r\n private setText(id: string, text: string, cadence: 'immediate' | 'animation-frame'): void {\r\n if (id === '') return\r\n const current = this.snapshot.textById[id]\r\n if (current?.text === text) return\r\n this.snapshot = {\r\n ...this.snapshot,\r\n textById: { ...this.snapshot.textById, [id]: { text } },\r\n }\r\n if (cadence === 'immediate') this.notify()\r\n else this.notifyOnFrame()\r\n }\r\n\r\n private appendText(id: string, delta: string): void {\r\n if (id === '' || delta === '') return\r\n this.setText(id, `${this.snapshot.textById[id]?.text ?? ''}${delta}`, 'animation-frame')\r\n }\r\n\r\n private handleEvent(input: unknown): void {\r\n const event = recordOf(input)\r\n if (event === undefined) return\r\n const type = stringOf(event.type)\r\n if (type === 'transcription.started') {\r\n this.setText(stringOf(event.utteranceId), '', 'immediate')\r\n this.setState('listening')\r\n return\r\n }\r\n if (type === 'transcription.updated') {\r\n this.setText(stringOf(event.utteranceId), stringOf(event.text), 'animation-frame')\r\n return\r\n }\r\n if (type === 'transcription.completed') {\n const text = stringOf(event.text)\n this.setText(stringOf(event.utteranceId), text, 'immediate')\n if (text.trim() !== '') this.markConversationStarted()\n return\n }\r\n if (type === 'output_text.started') {\r\n this.setText(stringOf(event.utteranceId), '', 'immediate')\r\n return\r\n }\r\n if (type === 'output_text.delta') {\r\n this.appendText(stringOf(event.utteranceId), stringOf(event.text))\r\n return\r\n }\r\n if (type === 'output_text.done') {\n const text = stringOf(event.text)\n if (text !== '') this.setText(stringOf(event.utteranceId), text, 'immediate')\n if (text.trim() !== '') this.markConversationStarted()\n return\n }\r\n if (type === 'output_audio.started') {\r\n this.setState('speaking')\r\n return\r\n }\r\n if (type === 'response.interrupted') {\r\n this.setState('listening')\r\n return\r\n }\r\n if (type === 'error') this.handleUnexpectedClose()\r\n }\n\n private markConversationStarted(): void {\n if (this.conversationStarted) return\n const sessionId = this.snapshot.sessionId\n if (sessionId === undefined) return\n this.conversationStarted = true\n this.onConversationStarted?.(sessionId)\n }\n\r\n private publish(snapshot: VoiceClientSnapshot): void {\r\n if (this.frame !== undefined) {\r\n cancelAnimationFrame(this.frame)\r\n this.frame = undefined\r\n }\r\n this.snapshot = snapshot\r\n this.notify()\r\n }\r\n\r\n private notifyOnFrame(): void {\r\n this.frame ??= requestAnimationFrame(() => {\r\n this.frame = undefined\r\n this.notify()\r\n })\r\n }\r\n\r\n private notify(): void {\r\n for (const listener of this.listeners) {\r\n try { listener() } catch (cause) { console.error('voice snapshot listener failed:', cause) }\r\n }\r\n }\r\n}\r\n\r\nfunction recordOf(value: unknown): Record<string, unknown> | undefined {\r\n return value !== null && typeof value === 'object' ? value as Record<string, unknown> : undefined\r\n}\r\n\r\nfunction stringOf(value: unknown): string {\r\n return typeof value === 'string' ? value : ''\r\n}\r\n\r\nasync function openVoiceTransport(\r\n sessionId: string,\r\n handlers: VoiceTransportHandlers,\r\n signal: AbortSignal,\r\n onOpening: (transport: VoiceTransport) => void,\r\n contexts: AudioContexts,\r\n): Promise<VoiceTransport> {\r\n const { input: inputContext, output: outputContext } = contexts\r\n const socket = new WebSocket(voiceUrl(sessionId))\r\n const workletUrl = URL.createObjectURL(new Blob([CAPTURE_WORKLET], { type: 'text/javascript' }))\r\n let stream: MediaStream | undefined\r\n let source: MediaStreamAudioSourceNode | undefined\r\n let processor: AudioWorkletNode | undefined\r\n let silent: GainNode | undefined\r\n let stopped = false\r\n let socketClosed = false\r\n let ready = false\r\n let outputDone = false\r\n let encodedPending = 0\r\n let playbackGeneration = 0\r\n let encodedQueue: Promise<void> = Promise.resolve()\r\n let inputSampleRate = 16_000\r\n let outputSampleRate = 24_000\r\n let audioFormat: VoiceReadyEvent['audio']['format'] = 'pcm_s16le'\r\n let playAt = outputContext.currentTime\n let inputMuted = false\n const chunks: number[] = []\n const playing = new Set<AudioBufferSourceNode>()\r\n\r\n const transport: VoiceTransport = {\n cancelTask: (taskId) => {\n if (socket.readyState !== WebSocket.OPEN) throw new Error('voice transport is not open')\n socket.send(JSON.stringify({ type: 'task.cancel', taskId }))\n },\n interruptResponse: () => {\n if (socket.readyState !== WebSocket.OPEN) throw new Error('voice transport is not open')\n socket.send(JSON.stringify({ type: 'response.interrupt' }))\n stopPlayback()\n },\n setInputMuted: (muted) => {\n if (inputMuted === muted) return\n inputMuted = muted\n chunks.splice(0)\n for (const track of stream?.getTracks() ?? []) track.enabled = !muted\n if (muted && !stopped && socket.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify({ type: 'audio.commit' }))\n }\n },\n submitText: (text) => {\r\n if (socket.readyState !== WebSocket.OPEN) throw new Error('voice transport is not open')\r\n socket.send(JSON.stringify({ type: 'text.submit', text }))\r\n },\r\n close: async () => {\r\n /* v8 ignore next -- controller ownership closes a transport once; the guard protects browser close races. */\r\n if (stopped) return\r\n stopped = true\r\n if (!socketClosed && socket.readyState === WebSocket.OPEN) {\r\n try { socket.send(JSON.stringify({ type: 'session.close' })) } catch {\r\n /* A socket closing concurrently cannot carry the final control; the server expires its reconnect grace. */\r\n }\r\n }\r\n socket.removeEventListener('message', onMessage)\r\n socket.removeEventListener('close', onClose)\r\n stopPlayback()\r\n source?.disconnect()\r\n processor?.disconnect()\r\n silent?.disconnect()\r\n processor?.port.close()\r\n for (const track of stream?.getTracks() ?? []) track.stop()\r\n socket.close()\r\n await Promise.allSettled([inputContext.close(), outputContext.close()])\r\n },\r\n }\r\n\r\n const stopPlayback = (): void => {\r\n playbackGeneration += 1\r\n encodedPending = 0\r\n encodedQueue = Promise.resolve()\r\n for (const node of playing) {\r\n try { node.stop() } catch { /* a completed source is already stopped */ }\r\n }\r\n playing.clear()\r\n playAt = outputContext.currentTime\r\n outputDone = false\r\n }\r\n const notifyPlaybackEnded = (): void => {\r\n if (outputDone && encodedPending === 0 && playing.size === 0 && socket.readyState === WebSocket.OPEN) {\r\n socket.send(JSON.stringify({ type: 'playback.ended' }))\r\n outputDone = false\r\n handlers.onPlaybackEnded()\r\n }\r\n }\r\n const onMessage = (message: MessageEvent): void => {\r\n if (!ready) return\r\n if (message.data instanceof ArrayBuffer) {\r\n if (audioFormat === 'audio_mpeg') {\r\n const generation = playbackGeneration\r\n encodedPending += 1\r\n encodedQueue = encodedQueue.catch(() => {}).then(() => scheduleEncoded(\r\n outputContext,\r\n message.data,\r\n playing,\r\n notifyPlaybackEnded,\r\n (value) => { playAt = value },\r\n () => playAt,\r\n () => generation === playbackGeneration && !stopped,\r\n )).catch(error => {\r\n if (generation === playbackGeneration && !stopped) {\r\n handlers.onEvent({ type: 'error', message: `audio decode failed: ${String(error)}` })\r\n }\r\n }).finally(() => {\r\n if (generation === playbackGeneration) {\r\n encodedPending -= 1\r\n notifyPlaybackEnded()\r\n }\r\n })\r\n } else {\r\n schedulePcm(outputContext, message.data, outputSampleRate, playing, notifyPlaybackEnded, (value) => { playAt = value }, playAt)\r\n }\r\n handlers.onBinary(message.data)\r\n return\r\n }\r\n let event: unknown\r\n try { event = JSON.parse(String(message.data)) } catch { return }\r\n const record = recordOf(event)\r\n if (record?.type === 'response.interrupted') stopPlayback()\n if (record?.type === 'output_audio.done') {\r\n outputDone = true\r\n notifyPlaybackEnded()\r\n }\r\n handlers.onEvent(event)\r\n }\r\n const onClose = (): void => {\r\n socketClosed = true\r\n handlers.onUnexpectedClose()\r\n }\r\n\r\n socket.binaryType = 'arraybuffer'\r\n onOpening(transport)\r\n try {\r\n await socketOpened(socket, signal)\r\n socket.addEventListener('message', onMessage)\r\n socket.addEventListener('close', onClose)\r\n const readyEvent = await socketReady(socket, signal)\r\n inputSampleRate = readyEvent.audio.inputSampleRate\r\n outputSampleRate = readyEvent.audio.outputSampleRate\r\n audioFormat = readyEvent.audio.format\r\n ready = true\r\n const captured = await microphone(signal)\r\n if (openingStopped(signal, stopped)) {\r\n for (const track of captured.getTracks()) track.stop()\r\n throw new Error('voice connection opening aborted')\r\n }\r\n stream = captured\n for (const track of stream.getTracks()) track.enabled = !inputMuted\n await abortable(inputContext.audioWorklet.addModule(workletUrl), signal)\r\n if (openingStopped(signal, stopped)) throw new Error('voice connection opening aborted')\r\n source = inputContext.createMediaStreamSource(stream)\r\n processor = new AudioWorkletNode(inputContext, 'dsh-pcm-capture')\r\n silent = inputContext.createGain()\r\n silent.gain.value = 0\r\n processor.port.onmessage = (event: MessageEvent<Float32Array>) => {\n if (inputMuted || socket.readyState !== WebSocket.OPEN) return\n chunks.push(...resample(event.data, inputContext.sampleRate, inputSampleRate))\r\n const frameSize = Math.max(1, Math.round(inputSampleRate / 5))\r\n while (chunks.length >= frameSize) {\r\n const part = chunks.splice(0, frameSize)\r\n const pcm = new Int16Array(part.length)\r\n for (const [index, sample] of part.entries()) {\r\n pcm[index] = Math.round(Math.max(-1, Math.min(1, sample)) * 32767)\r\n }\r\n socket.send(pcm.buffer)\r\n }\r\n }\r\n source.connect(processor)\r\n processor.connect(silent)\r\n silent.connect(inputContext.destination)\r\n } catch (cause) {\r\n await transport.close()\r\n throw cause\r\n } finally {\r\n URL.revokeObjectURL(workletUrl)\r\n }\r\n\r\n return transport\r\n}\r\n\r\ninterface AudioContexts {\r\n readonly input: AudioContext\r\n readonly output: AudioContext\r\n}\r\n\r\nfunction createAudioContexts(): AudioContexts {\r\n const contexts = { input: new AudioContext(), output: new AudioContext() }\r\n // Calling resume synchronously is required on browsers that start contexts\r\n // suspended when they are created outside a trusted user gesture.\r\n void contexts.input.resume().catch(() => {})\r\n void contexts.output.resume().catch(() => {})\r\n return contexts\r\n}\r\n\r\nasync function closeAudioContexts(contexts: AudioContexts): Promise<void> {\r\n await Promise.allSettled([contexts.input.close(), contexts.output.close()])\r\n}\r\n\r\nfunction microphone(signal: AbortSignal): Promise<MediaStream> {\r\n if (signal.aborted) return Promise.reject(new Error('voice connection opening aborted'))\r\n return new Promise((resolve, reject) => {\r\n let cancelled = false\r\n const cleanup = (): void => { signal.removeEventListener('abort', aborted) }\r\n const aborted = (): void => {\r\n cancelled = true\r\n cleanup()\r\n reject(new Error('voice connection opening aborted'))\r\n }\r\n signal.addEventListener('abort', aborted, { once: true })\r\n let request: Promise<MediaStream>\r\n try {\r\n request = navigator.mediaDevices.getUserMedia({\r\n audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true },\r\n })\r\n } catch (cause) {\r\n cleanup()\r\n reject(errorOf(cause))\r\n return\r\n }\r\n void request.then((value) => {\r\n cleanup()\r\n if (cancelled || signal.aborted) {\r\n for (const track of value.getTracks()) track.stop()\r\n return\r\n }\r\n resolve(value)\r\n }, (cause: unknown) => {\r\n cleanup()\r\n if (!cancelled) reject(errorOf(cause))\r\n })\r\n })\r\n}\r\n\r\nfunction abortable<T>(operation: Promise<T>, signal: AbortSignal): Promise<T> {\r\n if (signal.aborted) return Promise.reject(new Error('voice connection opening aborted'))\r\n return new Promise((resolve, reject) => {\r\n let cancelled = false\r\n const cleanup = (): void => { signal.removeEventListener('abort', aborted) }\r\n const aborted = (): void => {\r\n cleanup()\r\n cancelled = true\r\n reject(new Error('voice connection opening aborted'))\r\n }\r\n signal.addEventListener('abort', aborted, { once: true })\r\n void operation.then((value) => {\r\n cleanup()\r\n if (!cancelled) resolve(value)\r\n }, (cause: unknown) => {\r\n cleanup()\r\n if (!cancelled) reject(errorOf(cause))\r\n })\r\n })\r\n}\r\n\r\nfunction socketOpened(socket: WebSocket, signal: AbortSignal): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const cleanup = (): void => {\r\n socket.removeEventListener('open', opened)\r\n socket.removeEventListener('error', failed)\r\n signal.removeEventListener('abort', aborted)\r\n }\r\n const opened = (): void => { cleanup(); resolve() }\r\n const failed = (): void => { cleanup(); reject(new Error('voice websocket failed')) }\r\n const aborted = (): void => { cleanup(); reject(new Error('voice connection opening aborted')) }\r\n if (signal.aborted) { aborted(); return }\r\n socket.addEventListener('open', opened, { once: true })\r\n socket.addEventListener('error', failed, { once: true })\r\n signal.addEventListener('abort', aborted, { once: true })\r\n })\r\n}\r\n\r\nfunction socketReady(socket: WebSocket, signal: AbortSignal): Promise<VoiceReadyEvent> {\r\n return new Promise((resolve, reject) => {\r\n const cleanup = (): void => {\r\n socket.removeEventListener('message', received)\r\n socket.removeEventListener('error', failed)\r\n socket.removeEventListener('close', closed)\r\n signal.removeEventListener('abort', aborted)\r\n }\r\n const settle = (operation: () => void): void => { cleanup(); operation() }\r\n const received = (message: MessageEvent): void => {\r\n try {\r\n const value: unknown = message.data instanceof ArrayBuffer\r\n ? undefined\r\n : JSON.parse(String(message.data)) as unknown\r\n settle(() => { resolve(parseReady(value)) })\r\n } catch (cause) {\r\n settle(() => { reject(errorOf(cause)) })\r\n }\r\n }\r\n const failed = (): void => { settle(() => { reject(new Error('voice websocket failed before ready')) }) }\r\n const closed = (): void => { settle(() => { reject(new Error('voice websocket closed before ready')) }) }\r\n const aborted = (): void => { settle(() => { reject(new Error('voice connection opening aborted')) }) }\r\n if (signal.aborted) { aborted(); return }\r\n if (socket.readyState !== WebSocket.OPEN) { closed(); return }\r\n socket.addEventListener('message', received)\r\n socket.addEventListener('error', failed, { once: true })\r\n socket.addEventListener('close', closed, { once: true })\r\n signal.addEventListener('abort', aborted, { once: true })\r\n })\r\n}\r\n\r\nfunction openingStopped(signal: AbortSignal, stopped: boolean): boolean {\r\n return signal.aborted || stopped\r\n}\r\n\r\nfunction errorOf(cause: unknown): Error {\r\n return cause instanceof Error ? cause : new Error(String(cause))\r\n}\r\n\r\nfunction parseReady(value: unknown): VoiceReadyEvent {\r\n const event = recordOf(value)\r\n if (event?.type === 'error') {\r\n const message = stringOf(event.message)\r\n throw new Error(message === '' ? 'voice setup failed before ready' : message)\r\n }\r\n if (event?.type !== 'ready') throw new Error('voice websocket expected a ready event')\r\n const voiceSessionId = stringOf(event.voiceSessionId)\r\n if (voiceSessionId === '') throw new Error('voice websocket ready event has no voiceSessionId')\r\n const audio = recordOf(event.audio)\r\n if (audio?.inputSampleRate !== 16_000\r\n || (audio.outputSampleRate !== 24_000 && audio.outputSampleRate !== 48_000)\r\n || (audio.format !== 'pcm_s16le' && audio.format !== 'audio_mpeg')) {\r\n throw new Error('voice websocket ready event has unsupported audio settings')\r\n }\r\n if (event.interactionMode !== 'speech-shell' && event.interactionMode !== 'frontend-agent') {\r\n throw new Error('voice websocket ready event has an invalid interactionMode')\r\n }\r\n return { type: 'ready', voiceSessionId, audio: {\r\n inputSampleRate: audio.inputSampleRate,\r\n outputSampleRate: audio.outputSampleRate,\r\n format: audio.format,\r\n }, interactionMode: event.interactionMode }\r\n}\r\n\r\n/**\r\n * Resolve the dedicated WebSocket URL for one durable Voice Session.\r\n * @param sessionId - durable voice session id.\r\n * @param location - browser location used for host and protocol defaults.\r\n * @returns the /voice WebSocket URL carrying the session id.\r\n */\r\nexport function voiceUrl(sessionId: string, location: Pick<Location, 'href' | 'protocol'> = window.location): URL {\r\n const url = new URL('/voice', location.href)\r\n url.protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'\r\n url.searchParams.set('sessionId', sessionId)\r\n return url\r\n}\r\n\r\nconst CAPTURE_WORKLET = `\r\nclass DshPcmCaptureProcessor extends AudioWorkletProcessor {\r\n process(inputs) {\r\n const channel = inputs[0] && inputs[0][0]\r\n if (channel) this.port.postMessage(channel.slice())\r\n return true\r\n }\r\n}\r\nregisterProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)\r\n`\r\n\r\n/**\r\n * Resample browser float PCM into the provider input rate.\r\n * @param input - float samples at `fromRate`.\r\n * @param fromRate - source sample rate in Hz.\r\n * @param toRate - target sample rate in Hz.\r\n * @returns linearly interpolated samples at `toRate`.\r\n */\r\nexport function resample(input: Float32Array, fromRate: number, toRate: number): number[] {\r\n if (fromRate === toRate) return [...input]\r\n const ratio = fromRate / toRate\r\n const result = new Array<number>(Math.floor(input.length / ratio))\r\n for (let index = 0; index < result.length; index += 1) {\r\n const position = index * ratio\r\n const left = Math.floor(position)\r\n const fraction = position - left\r\n const leftSample = input[left] as number\r\n const rightSample = input[Math.min(left + 1, input.length - 1)] as number\r\n result[index] = leftSample * (1 - fraction) + rightSample * fraction\r\n }\r\n return result\r\n}\r\n\r\nfunction schedulePcm(\r\n context: AudioContext,\r\n bytes: ArrayBuffer,\r\n sampleRate: number,\r\n playing: Set<AudioBufferSourceNode>,\r\n ended: () => void,\r\n setPlayAt: (value: number) => void,\r\n currentPlayAt: number,\r\n): void {\r\n const pcm = new Int16Array(bytes)\r\n const buffer = context.createBuffer(1, pcm.length, sampleRate)\r\n const channel = buffer.getChannelData(0)\r\n for (const [index, sample] of pcm.entries()) channel[index] = sample / 32768\r\n const node = context.createBufferSource()\r\n node.buffer = buffer\r\n node.connect(context.destination)\r\n const start = Math.max(currentPlayAt, context.currentTime)\r\n setPlayAt(start + buffer.duration)\r\n playing.add(node)\r\n node.onended = () => { playing.delete(node); ended() }\r\n node.start(start)\r\n}\r\n\r\nasync function scheduleEncoded(\r\n context: AudioContext,\r\n bytes: ArrayBuffer,\r\n playing: Set<AudioBufferSourceNode>,\r\n ended: () => void,\r\n setPlayAt: (value: number) => void,\r\n getPlayAt: () => number,\r\n shouldSchedule: () => boolean,\r\n): Promise<void> {\r\n const buffer = await context.decodeAudioData(bytes.slice(0))\r\n if (!shouldSchedule()) return\r\n const node = context.createBufferSource()\r\n node.buffer = buffer\r\n node.connect(context.destination)\r\n const start = Math.max(getPlayAt(), context.currentTime)\r\n setPlayAt(start + buffer.duration)\r\n playing.add(node)\r\n node.onended = () => { playing.delete(node); ended() }\r\n node.start(start)\r\n}\r\n","import {\r\n createSnapshotStore, type SessionId, type SnapshotStore,\r\n} from '@deepseek-ai/dsh-client-runtime/client'\r\n\r\nconst STORAGE_KEY = 'dsh.voice.history.v1'\r\n\r\n/** One locally indexed durable Voice Session. */\r\nexport interface VoiceHistoryEntry {\n readonly sessionId: SessionId\r\n readonly lastActiveAt: number\r\n}\n\n/** Latest durable activity observed for one delegated child session. */\nexport interface VoiceTaskActivityEntry {\n readonly sessionId: SessionId\n readonly lastActiveAt: number\n /** Voice parent that owns this delegated child, when observed by the UI. */\n readonly parentSessionId?: SessionId\n}\n\r\n/** Browser-persistent Voice Session index. */\r\nexport interface VoiceHistorySnapshot {\n readonly entries: readonly VoiceHistoryEntry[]\n readonly taskActivity?: readonly VoiceTaskActivityEntry[]\n}\n\r\ninterface StoredVoiceHistory {\n readonly version: 1\n readonly entries: readonly VoiceHistoryEntry[]\n readonly taskActivity?: readonly VoiceTaskActivityEntry[]\n}\n\r\nfunction parseEntry(input: unknown): VoiceHistoryEntry | undefined {\r\n if (typeof input !== 'object' || input === null) return undefined\r\n const value = input as Record<string, unknown>\r\n if (typeof value.sessionId !== 'string' || value.sessionId === '') return undefined\r\n if (typeof value.lastActiveAt !== 'number' || !Number.isFinite(value.lastActiveAt) || value.lastActiveAt < 0) {\r\n return undefined\r\n }\r\n return { sessionId: value.sessionId as SessionId, lastActiveAt: value.lastActiveAt }\r\n}\r\n\r\nfunction readHistory(storage: Storage | undefined): VoiceHistorySnapshot {\n if (storage === undefined) return { entries: [], taskActivity: [] }\n try {\r\n const raw = storage.getItem(STORAGE_KEY)\r\n if (raw === null) return { entries: [], taskActivity: [] }\n const parsed = JSON.parse(raw) as unknown\r\n if (typeof parsed !== 'object' || parsed === null) return { entries: [], taskActivity: [] }\n const value = parsed as Record<string, unknown>\r\n if (value.version !== 1 || !Array.isArray(value.entries)) return { entries: [], taskActivity: [] }\n const entries: VoiceHistoryEntry[] = []\r\n const seen = new Set<SessionId>()\r\n for (const candidate of value.entries) {\r\n const entry = parseEntry(candidate)\r\n if (entry === undefined || seen.has(entry.sessionId)) continue\r\n seen.add(entry.sessionId)\r\n entries.push(entry)\r\n }\r\n entries.sort((left, right) => right.lastActiveAt - left.lastActiveAt)\r\n const taskActivity: VoiceTaskActivityEntry[] = []\n const taskSeen = new Set<SessionId>()\n if (Array.isArray(value.taskActivity)) {\n for (const candidate of value.taskActivity) {\n if (typeof candidate !== 'object' || candidate === null) continue\n const item = candidate as Record<string, unknown>\n if (typeof item.sessionId !== 'string' || item.sessionId === ''\n || typeof item.lastActiveAt !== 'number' || !Number.isFinite(item.lastActiveAt)\n || item.lastActiveAt < 0) continue\n const sessionId = item.sessionId as SessionId\n if (taskSeen.has(sessionId)) continue\n taskSeen.add(sessionId)\n const parentSessionId = typeof item.parentSessionId === 'string' && item.parentSessionId !== ''\n ? item.parentSessionId as SessionId\n : undefined\n taskActivity.push({\n sessionId,\n lastActiveAt: item.lastActiveAt,\n ...(parentSessionId === undefined ? {} : { parentSessionId }),\n })\n }\n taskActivity.sort((left, right) => right.lastActiveAt - left.lastActiveAt)\n }\n return { entries, taskActivity }\n } catch (error: unknown) {\r\n console.error('voice history rehydration failed:', error)\r\n return { entries: [], taskActivity: [] }\n }\r\n}\r\n\r\n/** Own the local history index without adding Voice metadata to Host session projections. */\r\nexport class VoiceHistoryStore {\r\n readonly snapshot: SnapshotStore<VoiceHistorySnapshot>\r\n private readonly storage: Storage | undefined\r\n private readonly unsubscribe: () => void\r\n\r\n constructor(storage: Storage | undefined = typeof localStorage === 'undefined' ? undefined : localStorage) {\r\n this.storage = storage\r\n this.snapshot = createSnapshotStore(readHistory(storage))\r\n this.unsubscribe = this.snapshot.subscribe(() => { this.persist() })\r\n }\r\n\r\n /** Move one successfully opened Voice Session to the front of the index. */\r\n record(sessionId: SessionId, lastActiveAt = Date.now()): void {\n this.snapshot.set({\r\n entries: [\r\n { sessionId, lastActiveAt },\r\n ...this.snapshot.getSnapshot().entries.filter(entry => entry.sessionId !== sessionId),\r\n ],\r\n })\n }\n\n /** Retain the latest timestamp seen in a delegated task's durable events. */\n recordTaskActivity(sessionId: SessionId, lastActiveAt: number, parentSessionId?: SessionId): void {\n if (!Number.isFinite(lastActiveAt) || lastActiveAt < 0) return\n const entries = this.snapshot.getSnapshot().taskActivity ?? []\n const previousEntry = entries.find(entry => entry.sessionId === sessionId)\n const previous = previousEntry?.lastActiveAt ?? 0\n const nextTime = Math.max(previous, lastActiveAt)\n const owner = parentSessionId ?? previousEntry?.parentSessionId\n if (nextTime === previous && owner === previousEntry?.parentSessionId) return\n const next = [\n {\n sessionId,\n lastActiveAt: nextTime,\n ...(owner === undefined ? {} : { parentSessionId: owner }),\n },\n ...entries.filter(entry => entry.sessionId !== sessionId),\n ]\n this.snapshot.set({ ...this.snapshot.getSnapshot(), taskActivity: next })\n }\n\r\n /** Stop persistence notifications. */\r\n dispose(): void {\r\n this.unsubscribe()\r\n }\r\n\r\n private persist(): void {\r\n if (this.storage === undefined) return\r\n const snapshot = this.snapshot.getSnapshot()\n const value: StoredVoiceHistory = {\n version: 1,\n entries: snapshot.entries,\n ...(snapshot.taskActivity === undefined ? {} : { taskActivity: snapshot.taskActivity }),\n }\n try {\r\n this.storage.setItem(STORAGE_KEY, JSON.stringify(value))\r\n } catch (error: unknown) {\r\n console.error('voice history persistence failed:', error)\r\n }\r\n }\r\n}\r\n","import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type { VoiceClientSnapshot } from './voice-controller.ts'\r\n\r\ninterface VoiceTextInputState {\r\n readonly draft: string\r\n readonly imageIds: readonly unknown[]\r\n}\r\n\r\nexport interface VoiceTextInput {\r\n readonly state: { getSnapshot(): VoiceTextInputState }\r\n setDraft(text: string): void\r\n submit(mode?: unknown): void\r\n notify(level: 'info' | 'error', text: string): void\r\n}\r\n\r\ninterface VoiceTextController {\r\n getSnapshot(): VoiceClientSnapshot\r\n submitText(text: string): void\r\n}\r\n\r\ninterface PatchedInput {\r\n readonly input: VoiceTextInput\r\n readonly originalOwnDescriptor: PropertyDescriptor | undefined\r\n readonly patchedSubmit: (mode?: unknown) => void\r\n}\r\n\r\n/** Routes the native composer through Voice while preserving its ordinary offline submission. */\r\nexport class VoiceTextSubmitBridge {\r\n private readonly patched = new Map<SessionId, PatchedInput>()\r\n\r\n constructor(\r\n private readonly voice: VoiceTextController,\r\n private readonly resolveInput: (sessionId: SessionId) => VoiceTextInput,\r\n ) {}\r\n\r\n install(sessionId: SessionId): void {\r\n if (this.patched.has(sessionId)) return\r\n const input = this.resolveInput(sessionId)\r\n const originalOwnDescriptor = Object.getOwnPropertyDescriptor(input, 'submit')\r\n const originalSubmit = input.submit.bind(input)\r\n const patchedSubmit = (mode?: unknown): void => {\r\n const voice = this.voice.getSnapshot()\r\n const state = input.state.getSnapshot()\r\n const active = voice.sessionId === sessionId\r\n && voice.state !== 'off'\r\n && voice.state !== 'error'\r\n if (!active || state.draft.trim() === '' || state.imageIds.length > 0) {\r\n originalSubmit(mode)\r\n return\r\n }\r\n try {\r\n this.voice.submitText(state.draft)\r\n input.setDraft('')\r\n } catch (cause: unknown) {\r\n input.notify('error', cause instanceof Error ? cause.message : String(cause))\r\n }\r\n }\r\n input.submit = patchedSubmit\r\n this.patched.set(sessionId, { input, originalOwnDescriptor, patchedSubmit })\r\n }\r\n\r\n dispose(): void {\r\n for (const { input, originalOwnDescriptor, patchedSubmit } of this.patched.values()) {\r\n if (input.submit !== patchedSubmit) continue\r\n if (originalOwnDescriptor === undefined) delete (input as Partial<VoiceTextInput>).submit\r\n else Object.defineProperty(input, 'submit', originalOwnDescriptor)\r\n }\r\n this.patched.clear()\r\n }\r\n}\r\n","import type {\r\n ChatConversationViewNode, ConversationNodeDefinition, SessionId,\r\n} from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type {\r\n TaskObservation, VoiceTaskId, VoiceUtteranceId,\r\n} from '@flowingspring/dsh-voice'\n\r\n/** Renderer-ready durable Voice utterance. */\r\nexport interface VoiceUtteranceChatData {\r\n readonly utteranceId: VoiceUtteranceId\r\n readonly role: 'user' | 'assistant'\r\n readonly text?: string\r\n readonly state: 'streaming' | 'completed' | 'interrupted'\r\n}\r\n\r\n/** Renderer-ready delegated task link and its latest observation. */\r\nexport interface VoiceDelegationChatData {\n readonly taskId: VoiceTaskId\r\n readonly taskSessionId: SessionId\r\n readonly input: string\r\n readonly status: TaskObservation['status']\r\n readonly update?: string\n /** Latest source event time for this delegated task (epoch ms). */\n readonly lastActivityAt?: number\n}\r\n\r\ndeclare module '@deepseek-ai/dsh-client-ui-conversation/client' {\r\n interface ChatNodeDataMap {\r\n /** One user ASR or assistant TTS transcript produced in Voice Mode. */\r\n 'voice-utterance': VoiceUtteranceChatData\r\n /** One independent DSH task delegated by the Voice frontend Agent. */\r\n 'voice-delegation': VoiceDelegationChatData\r\n }\r\n}\r\n\r\ntype VoiceUtteranceState = VoiceUtteranceChatData\r\ntype VoiceDelegationState = VoiceDelegationChatData\r\n\r\n/** Fold one streamed utterance into a stable Chat node. */\r\nexport const voiceUtteranceDefinition: ConversationNodeDefinition<VoiceUtteranceState> = {\r\n kind: 'voice-utterance',\r\n target: 'chat',\r\n match: (event) => {\r\n if (event.type === 'voice/utterance-start') {\r\n return { id: String(event.data.utteranceId), role: 'start' }\r\n }\r\n if (event.type === 'voice/utterance-end') {\r\n return { id: String(event.data.utteranceId), role: 'update' }\r\n }\r\n return null\r\n },\r\n start: (_context, match) => {\r\n if (match.event.type !== 'voice/utterance-start') {\r\n throw new Error('voice utterance start requires voice/utterance-start')\r\n }\r\n return {\n utteranceId: match.event.data.utteranceId,\r\n role: match.event.data.role,\r\n state: 'streaming',\r\n }\r\n },\r\n update: (context, match) => {\r\n if (match.event.type !== 'voice/utterance-end') return context.state\r\n return {\r\n ...context.state,\r\n text: match.event.data.text,\r\n state: match.event.data.state,\r\n }\r\n },\r\n buildViewNode: (context): ChatConversationViewNode | null => {\r\n if (context.start === undefined || context.state === undefined) return null\r\n const emptyInterrupted = context.state.state === 'interrupted'\r\n && (context.state.text?.trim() ?? '') === ''\r\n return {\r\n key: context.key,\r\n kind: 'voice-utterance',\r\n id: context.id,\r\n target: 'chat',\r\n anchorSeq: context.start.event.seq,\r\n location: context.start.location,\r\n // A live start may already be materialized before an empty noise segment\r\n // settles. Conversation nodes cannot be withdrawn after publication, so\r\n // keep its stable identity and hide it instead.\r\n visibility: emptyInterrupted ? 'hidden' : 'visible',\r\n data: context.state as VoiceUtteranceState,\r\n }\r\n },\r\n}\r\n\r\n/** Fold a delegated task and all observations into one navigation card. */\r\nexport const voiceDelegationDefinition: ConversationNodeDefinition<VoiceDelegationState> = {\r\n kind: 'voice-delegation',\r\n target: 'chat',\r\n match: (event) => {\r\n if (event.type === 'voice/task-delegated') {\r\n return { id: String(event.data.taskId), role: 'start' }\r\n }\r\n if (event.type === 'voice/task-observation') {\r\n return { id: String(event.data.taskId), role: 'update' }\r\n }\r\n return null\r\n },\r\n start: (_context, match) => {\r\n if (match.event.type !== 'voice/task-delegated') {\r\n throw new Error('voice delegation start requires voice/task-delegated')\r\n }\r\n return {\r\n taskId: match.event.data.taskId,\r\n taskSessionId: match.event.data.taskSessionId,\r\n input: match.event.data.input,\r\n status: 'accepted',\n lastActivityAt: match.event.time,\n }\r\n },\r\n update: (context, match) => {\r\n if (match.event.type !== 'voice/task-observation') return context.state\r\n const observation = match.event.data\r\n const update = observation.voiceMessage?.text\r\n ?? observation.announcement\r\n ?? observation.reason\r\n ?? context.state.update\r\n return {\n ...context.state,\n status: observation.status,\n lastActivityAt: Math.max(context.state.lastActivityAt ?? 0, match.event.time),\n ...(update === undefined ? {} : { update }),\r\n }\r\n },\r\n buildViewNode: (context): ChatConversationViewNode | null => {\r\n if (context.start === undefined) return null\r\n return {\r\n key: context.key,\r\n kind: 'voice-delegation',\r\n id: context.id,\r\n target: 'chat',\r\n anchorSeq: context.start.event.seq,\r\n location: context.start.location,\r\n visibility: 'visible',\r\n data: context.state as VoiceDelegationState,\r\n }\r\n },\r\n}\r\n","/** `voice` namespace dictionaries. */\r\n\r\n/** Dictionary namespace owned by this plugin. */\r\nexport const NS = 'voice'\r\n\r\n/** Simplified Chinese dictionary (the key-set source of truth). */\r\nexport const zh = {\r\n 'badge.voice': 'VOICE',\r\n 'control.start': '开始语音对话',\n 'control.retry': '语音连接失败,点击重试',\n 'control.interrupt': '打断播放',\n 'control.mute': '静音麦克风',\n 'control.unmute': '解除静音',\n 'overlay.connecting': '正在连接语音',\n 'overlay.listening': '正在聆听',\n 'overlay.speaking': '正在回复',\n 'overlay.error': '语音连接失败',\n 'overlay.muted': '已静音',\n 'overlay.stop': '结束',\n 'utterance.user.pending': '正在聆听…',\r\n 'utterance.assistant.pending': '正在生成语音回复…',\r\n 'utterance.interrupted': '已打断',\r\n 'task.title': '后台处理',\r\n 'task.status.accepted': '已接受',\r\n 'task.status.queued': '排队中',\r\n 'task.status.running': '执行中',\r\n 'task.status.waiting-user': '等待确认',\r\n 'task.status.completed': '已完成',\r\n 'task.status.failed': '失败',\r\n 'task.status.cancelled': '已取消',\r\n 'task.status.interrupted': '服务中断',\r\n 'task.expand': '展开后台处理详情',\r\n 'task.collapse': '收起后台处理详情',\r\n 'task.cancel': '取消任务',\r\n 'task.open': '查看后台详情',\r\n} satisfies Record<string, string>\r\n\r\n/** Union of this namespace's dictionary keys. */\r\nexport type VoiceKey = keyof typeof zh\r\n\r\n/** English dictionary, checked complete against the zh key set. */\r\nexport const en = {\r\n 'badge.voice': 'VOICE',\r\n 'control.start': 'Start voice conversation',\n 'control.retry': 'Voice connection failed, press to retry',\n 'control.interrupt': 'Stop playback',\n 'control.mute': 'Mute microphone',\n 'control.unmute': 'Unmute microphone',\n 'overlay.connecting': 'Connecting voice',\n 'overlay.listening': 'Listening',\n 'overlay.speaking': 'Playing response',\n 'overlay.error': 'Voice connection failed',\n 'overlay.muted': 'Muted',\n 'overlay.stop': 'End',\n 'utterance.user.pending': 'Listening…',\r\n 'utterance.assistant.pending': 'Generating voice response…',\r\n 'utterance.interrupted': 'Interrupted',\r\n 'task.title': 'Background task',\r\n 'task.status.accepted': 'Accepted',\r\n 'task.status.queued': 'Queued',\r\n 'task.status.running': 'Running',\r\n 'task.status.waiting-user': 'Waiting for you',\r\n 'task.status.completed': 'Completed',\r\n 'task.status.failed': 'Failed',\r\n 'task.status.cancelled': 'Cancelled',\r\n 'task.status.interrupted': 'Interrupted',\r\n 'task.expand': 'Show background task details',\r\n 'task.collapse': 'Hide background task details',\r\n 'task.cancel': 'Cancel task',\r\n 'task.open': 'View background details',\r\n} satisfies Record<VoiceKey, string>\r\n","/** Browser voice UI assembly. @module @flowingspring/dsh-client-ui-voice/client */\nimport type { ClientContext, SessionFace, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport { VoiceControl, type VoiceControlInjected } from './VoiceControl.tsx'\nimport {\n VoiceDelegationView, type VoiceDelegationInjected,\r\n VoiceUtteranceView, type VoiceUtteranceInjected,\r\n} from './VoiceNodeViews.tsx'\r\nimport { VoiceOverlay, type VoiceOverlayInjected } from './VoiceOverlay.tsx'\nimport { VoiceSessionMarkers, type VoiceSessionMarkersInjected } from './VoiceSessionMarkers.tsx'\nimport { VoiceController } from './voice-controller.ts'\r\nimport { VoiceHistoryStore } from './voice-history.ts'\r\nimport { VoiceTextSubmitBridge, type VoiceTextInput } from './voice-text-submit.ts'\nimport { voiceDelegationDefinition, voiceUtteranceDefinition } from './voice-definitions.ts'\nimport { en, NS, type VoiceKey, zh } from './locales.ts'\nimport { isSessionEffectivelyArchived } from './session-archive.ts'\n\r\nexport type { VoiceKey } from './locales.ts'\r\n\r\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\r\n interface LocaleNamespaceMap {\r\n /** Browser Voice conversation copy. */\r\n voice: VoiceKey\r\n }\r\n}\r\n\r\nexport const inject = ['conversation', 'conversationEvents', 'slots', 'sessions', 'workspaces', 'locale', 'remote']\n\ntype SessionAddress = {\n readonly parentSessionId: SessionId\n readonly childSessionId: SessionId\n readonly mode: 'one-shot' | 'continuable'\n}\n\n/**\n * The Harness model-selection UI intentionally hides addressed children. Voice\n * tasks are ordinary durable Agent Sessions, so let that official UI use the\n * same model directory as the parent while retaining navigationAddress for\n * child routing and breadcrumbs.\n */\nfunction enableChildModelSelection(ctx: ClientContext): void {\n const sessions = ctx.sessions as typeof ctx.sessions & {\n subagentAddress: (sessionId: SessionId) => SessionAddress | undefined\n navigationAddress?: (sessionId: SessionId) => SessionAddress | undefined\n }\n const original = sessions.subagentAddress\n if (typeof original !== 'function') return\n ctx.effect(() => {\n sessions.subagentAddress = () => undefined\n return () => { sessions.subagentAddress = original }\n }, 'ui-voice: child model selection compatibility')\n}\n\n/** Public archive-manager RPC surface. Kept structural so the voice package\n * remains optional and does not take a hard dependency on the community plugin. */\ninterface ArchiveManagerWorkspaceRegistry {\n deleteSession?: (sessionId: SessionId) => Promise<{\n readonly ok: boolean\n readonly error?: { readonly message?: string }\n }>\n}\n\nfunction archiveManagerRegistry(ctx: ClientContext): ArchiveManagerWorkspaceRegistry | undefined {\n try {\n const registry = ctx.get('remote.workspaceRegistry') as unknown\n if (registry === null || typeof registry !== 'object') return undefined\n return registry as ArchiveManagerWorkspaceRegistry\n } catch {\n return undefined\n }\n}\n\n/** Call archive-manager's complete deletion path when its remote is installed. */\nasync function deleteWithArchiveManager(ctx: ClientContext, sessionId: SessionId): Promise<void> {\n const deleteSession = archiveManagerRegistry(ctx)?.deleteSession\n if (typeof deleteSession !== 'function') throw new Error('archive-manager 删除服务不可用')\n const result = await deleteSession(sessionId)\n if (!result.ok) throw new Error(result.error?.message ?? 'archive-manager 删除会话失败')\n}\n\n/** Refresh the Host-backed Session list when the runtime exposes its baseline pull. */\nfunction refreshSessions(ctx: ClientContext): void {\n // `refresh()` exists on the concrete SessionRuntime used by dsh Web, but is\n // intentionally omitted from the narrow feature-facing ISessions contract.\n // Keep this compatibility bridge optional for older runtimes and fixtures.\n const service = ctx.sessions as unknown as { refresh?: () => Promise<void> }\n if (typeof service.refresh !== 'function') return\n void service.refresh.call(ctx.sessions).catch((cause: unknown) => {\n console.warn('voice session list refresh failed:', cause)\n })\n}\n\n/** Mount root transport controls and durable Voice conversation renderers. @param ctx - browser context. */\nexport function apply(ctx: ClientContext): void {\n const controller = new VoiceController({\n onConversationStarted: () => {\n // Voice events are appended by the Host, while the browser's session\n // list keeps its own blank-bit cache. Refresh once after the first\n // completed turn so Workspace new-session creation does not reuse the\n // now-engaged Voice Session.\n refreshSessions(ctx)\n },\n })\n const history = new VoiceHistoryStore()\r\n const textSubmit = new VoiceTextSubmitBridge(controller, (sessionId) => {\r\n const scope = ctx.sessions.scope(sessionId)\r\n if (scope === undefined) throw new Error(`voice input session \"${sessionId}\" is unavailable`)\r\n return ctx.conversation.input.for(scope) as VoiceTextInput\r\n })\r\n const stopVoice = (): Promise<void> => controller.stop()\r\n const startVoice = async (sourceSessionId: SessionId): Promise<void> => {\r\n ctx.sessions.open(sourceSessionId)\r\n textSubmit.install(sourceSessionId)\r\n await controller.start(sourceSessionId)\r\n history.record(sourceSessionId)\r\n }\r\n const voiceControlInjected = (): VoiceControlInjected => ({\r\n hooks: { voice: controller },\r\n startVoice,\r\n retryVoice: async () => {\n await controller.retry()\n const sessionId = controller.getSnapshot().sessionId\n if (sessionId !== undefined) history.record(sessionId)\n },\n interruptResponse: () => { controller.interruptResponse() },\n setVoiceMuted: (muted) => { controller.setInputMuted(muted) },\n })\n const voiceOverlayInjected = (): VoiceOverlayInjected => ({ hooks: { voice: controller }, stopVoice })\n const voiceSessionMarkersInjected = (): VoiceSessionMarkersInjected => ({\n hooks: { voiceHistory: history.snapshot },\n childActions: {\n rename: async (id, title) => {\n const session = ensureChildSession(ctx, id)\n if (session === undefined) throw new Error(`unknown session \"${id}\"`)\n const result = await session.rename(title)\n if (!result.ok) throw new Error(result.error.message)\n },\n fork: async (id) => {\n ensureChildSession(ctx, id)\n const childId = await ctx.sessions.fork({ sessionId: id, increaseTitle: true })\n ctx.sessions.open(childId)\n },\n ...(archiveManagerRegistry(ctx)?.deleteSession === undefined ? {} : {\n delete: async (id: SessionId) => {\n const parentId = (ctx.sessions as typeof ctx.sessions & {\n navigationAddress?: (sessionId: SessionId) => { readonly parentSessionId: SessionId } | undefined\n }).navigationAddress?.(id)?.parentSessionId\n await deleteWithArchiveManager(ctx, id)\n refreshSessions(ctx)\n if (parentId !== undefined) {\n const refreshSubagents = (ctx.sessions as typeof ctx.sessions & {\n refreshSubagents?: (sessionId: SessionId) => Promise<void>\n }).refreshSubagents\n await refreshSubagents?.call(ctx.sessions, parentId)\n }\n },\n }),\n },\n openSession: (id) => {\n if (isEffectivelyArchivedInContext(ctx, id)) return\n const sessions = ctx.sessions as typeof ctx.sessions & {\n subagentAddress?: (sessionId: SessionId) => { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' } | undefined\n navigationAddress?: (sessionId: SessionId) => { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' } | undefined\n openSubagent?: (address: { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' }) => void\n }\n const address = sessions.navigationAddress?.(id) ?? sessions.subagentAddress?.(id)\n if (address !== undefined && sessions.openSubagent !== undefined) {\n sessions.openSubagent(address)\n return\n }\n ctx.sessions.open(id)\n },\n refreshSubagents: (parentSessionId) => {\n const refresh = (ctx.sessions as typeof ctx.sessions & {\n refreshSubagents?: (id: SessionId) => Promise<void>\n }).refreshSubagents\n if (refresh === undefined) return\n void refresh.call(ctx.sessions, parentSessionId).catch((error: unknown) => {\n console.warn('voice subagent catalog refresh failed:', error)\n })\n },\n setSubagentCatalogOpen: (parentSessionId, open) => {\n const setOpen = (ctx.sessions as typeof ctx.sessions & {\n setSubagentCatalogOpen?: (id: SessionId, open: boolean) => void\n }).setSubagentCatalogOpen\n setOpen?.call(ctx.sessions, parentSessionId, open)\n },\n })\n const utteranceInjected = (): VoiceUtteranceInjected => ({ hooks: { voice: controller } })\r\n const delegationInjected = (): VoiceDelegationInjected => ({\n hooks: { voice: controller },\n recordTaskActivity: (id, at, parentSessionId) => { history.recordTaskActivity(id, at, parentSessionId) },\n openSession: (id) => {\n if (isEffectivelyArchivedInContext(ctx, id)) return\n const sessions = ctx.sessions as typeof ctx.sessions & {\n subagentAddress?: (sessionId: SessionId) => { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' } | undefined\n navigationAddress?: (sessionId: SessionId) => { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' } | undefined\n openSubagent?: (address: { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' }) => void\n }\n const address = sessions.navigationAddress?.(id) ?? sessions.subagentAddress?.(id)\n if (address !== undefined && sessions.openSubagent !== undefined) {\n sessions.openSubagent(address)\n return\n }\n ctx.sessions.open(id)\n },\n cancelTask: (id) => { controller.cancelTask(id) },\n })\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-voice: dictionaries')\r\n ctx.effect(() => async () => { await controller.stop() }, 'ui-voice: transport teardown')\r\n ctx.effect(() => () => { textSubmit.dispose() }, 'ui-voice: text submit bridge teardown')\n ctx.effect(() => () => { history.dispose() }, 'ui-voice: history persistence teardown')\n enableChildModelSelection(ctx)\n ctx.conversationEvents.register(voiceUtteranceDefinition)\r\n ctx.conversationEvents.register(voiceDelegationDefinition)\r\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\r\n name: 'conversation.input.right',\r\n id: 'voice',\r\n order: 20,\r\n locale: NS,\r\n inject: voiceControlInjected,\r\n }, VoiceControl))\r\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\r\n id: 'voice-active',\r\n order: 20,\r\n locale: NS,\r\n inject: voiceOverlayInjected,\r\n }, VoiceOverlay))\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\n id: 'voice-session-markers',\n order: 10,\n locale: NS,\n inject: voiceSessionMarkersInjected,\n }, VoiceSessionMarkers))\n ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({\r\n name: 'conversation.chat.node',\r\n key: 'voice-utterance',\r\n locale: NS,\r\n inject: utteranceInjected,\r\n }, VoiceUtteranceView))\r\n ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({\r\n name: 'conversation.chat.node',\r\n key: 'voice-delegation',\r\n locale: NS,\r\n inject: delegationInjected,\r\n }, VoiceDelegationView))\r\n}\n\n/** Archive-manager archives one requested ID; Voice treats that state as\n * inherited by every descendant without mutating the third-party archive set. */\nfunction isEffectivelyArchivedInContext(ctx: ClientContext, sessionId: SessionId): boolean {\n const workspaces = (ctx as ClientContext & {\n workspaces?: { list: { getSnapshot(): { readonly archivedSessionIds: readonly SessionId[] } } }\n }).workspaces\n if (workspaces === undefined) return false\n const snapshot = ctx.sessions.list.getSnapshot()\n const sessions = ctx.sessions as typeof ctx.sessions & {\n navigationAddress?: (id: SessionId) => { readonly parentSessionId: SessionId } | undefined\n }\n return isSessionEffectivelyArchived(\n sessionId,\n workspaces.list.getSnapshot().archivedSessionIds,\n snapshot.byId,\n id => sessions.navigationAddress?.(id)?.parentSessionId,\n )\n}\n\nfunction ensureChildSession(ctx: ClientContext, id: SessionId): SessionFace | undefined {\n const sessions = ctx.sessions as typeof ctx.sessions & {\n navigationAddress?: (sessionId: SessionId) => { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' } | undefined\n openSubagent?: (address: { readonly parentSessionId: SessionId; readonly childSessionId: SessionId; readonly mode: 'one-shot' | 'continuable' }) => void\n }\n const address = sessions.navigationAddress?.(id)\n if (address !== undefined) sessions.openSubagent?.(address)\n return ctx.sessions.binding(id)?.session\n}\n"],"mappings":"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"}
|