@flowingspring/dsh-voco 0.2.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["css","useState","css","css","useState","css","createSnapshotStore"],"sources":["../../../packages/ui-voice/src/client/VoiceControl.tsx","../../../packages/ui-voice/src/client/VoiceHistoryAction.tsx","../../../packages/ui-voice/src/client/VoiceNodeViews.tsx","../../../packages/ui-voice/src/client/VoiceOverlay.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. */\r\n readonly startVoice: (sourceSessionId: SessionId) => Promise<void>\r\n readonly retryVoice: () => Promise<void>\r\n readonly stopVoice: () => Promise<void>\r\n}\r\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({\r\n sessionId, useVoice, startVoice, retryVoice, stopVoice, t,\r\n}: VoiceControlProps) {\r\n const state = useVoice(snapshot => snapshot.state)\r\n const activeSessionId = useVoice(snapshot => snapshot.sessionId)\r\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') {\r\n await stopVoice()\r\n return\r\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'\r\n ? t('control.start')\r\n : state === 'error'\r\n ? t('control.retry')\r\n : t('control.stop')\r\n return (\r\n <button\r\n type=\"button\"\r\n className={`${css.button} ${state !== 'off' ? css.active : ''}`}\r\n aria-label={label}\r\n title={label}\r\n data-state={state}\r\n onClick={() => { void toggle() }}\r\n >\r\n <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" aria-hidden>\r\n <rect x=\"5\" y=\"2\" width=\"6\" height=\"8\" rx=\"3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" />\r\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\" />\r\n </svg>\r\n </button>\r\n )\r\n}\r\n","import { useEffect, 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 {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\r\nimport type { VoiceClientSnapshot } from './voice-controller.ts'\r\nimport type { VoiceHistorySnapshot } from './voice-history.ts'\r\nimport css from './VoiceHistoryAction.module.css'\r\n\r\n/** History state and navigation owned by the Voice UI plugin. */\r\nexport interface VoiceHistoryActionInjected {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n voiceHistory: { getSnapshot(): VoiceHistorySnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n readonly openSession: (id: SessionId) => void\r\n}\r\n\r\nexport type VoiceHistoryActionProps =\r\n PropsRuntime<'sidebar.footer.action'> & InjectFace<VoiceHistoryActionInjected> & PropsLocale<'voice'>\r\n\r\n/** Render the plugin-owned Voice history entry and its Session navigation panel. */\r\nexport function VoiceHistoryAction({\r\n wide, useSessions, useVoice, useVoiceHistory, openSession, t,\r\n}: VoiceHistoryActionProps) {\r\n const [open, setOpen] = useState(false)\r\n const sessions = useSessions(state => state)\r\n const entries = useVoiceHistory(state => state.entries)\r\n const activeSessionId = useVoice(state => state.sessionId)\r\n const available = entries.flatMap((entry) => {\r\n const session = sessions.byId[entry.sessionId]\r\n return session === undefined ? [] : [{ entry, session }]\r\n })\r\n\r\n useEffect(() => {\r\n if (!open) return\r\n const close = (event: KeyboardEvent): void => { if (event.key === 'Escape') setOpen(false) }\r\n document.addEventListener('keydown', close)\r\n return () => { document.removeEventListener('keydown', close) }\r\n }, [open])\r\n\r\n return (\r\n <>\r\n <button\r\n type=\"button\"\r\n className={css.trigger}\r\n aria-label={t('history.open')}\r\n aria-haspopup=\"dialog\"\r\n aria-expanded={open}\r\n onClick={() => { setOpen(value => !value) }}\r\n >\r\n <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" aria-hidden>\r\n <path d=\"M3 8a5 5 0 1 0 1.5-3.55M3 2.7v2.8h2.8M8 5.2V8l2 1.2\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.35\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n {wide && <span>{t('history.label')}</span>}\r\n </button>\r\n {open && (\r\n <section className={css.panel} role=\"dialog\" aria-label={t('history.title')}>\r\n <header className={css.header}>\r\n <strong>{t('history.title')}</strong>\r\n <button type=\"button\" className={css.close} aria-label={t('history.close')} onClick={() => { setOpen(false) }}>×</button>\r\n </header>\r\n <div className={css.list}>\r\n {available.length === 0 && <p className={css.empty}>{t('history.empty')}</p>}\r\n {available.map(({ entry, session }) => (\r\n <button\r\n key={entry.sessionId}\r\n type=\"button\"\r\n className={css.row}\r\n data-active={entry.sessionId === activeSessionId || undefined}\r\n onClick={() => {\r\n openSession(entry.sessionId)\r\n setOpen(false)\r\n }}\r\n >\r\n <span className={css.wave} aria-hidden><i /><i /><i /></span>\r\n <span className={css.rowText}>\r\n <span className={css.title}>{session.displayTitle}</span>\r\n <span className={css.meta}>{entry.sessionId === activeSessionId ? t('history.active') : t('history.saved')}</span>\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </section>\r\n )}\r\n </>\r\n )\r\n}\r\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 { 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, 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 {\r\n hooks: {\r\n voice: { getSnapshot(): VoiceClientSnapshot; subscribe(listener: () => void): () => void }\r\n }\r\n readonly openVoiceSession: (id: SessionId) => void\r\n readonly stopVoice: () => Promise<void>\r\n}\r\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, useSessions, openVoiceSession, stopVoice, t }: VoiceOverlayProps) {\r\n const voice = useVoice(snapshot => snapshot)\r\n const navigable = useSessions(sessions => voice.sessionId !== undefined && sessions.ids.includes(voice.sessionId))\r\n if (voice.state === 'off') return null\r\n return (\r\n <aside className={css.root} data-voice-overlay data-state={voice.state} aria-live=\"polite\">\r\n <span className={css.wave} aria-hidden>\r\n <i /><i /><i /><i />\r\n </span>\r\n <span className={css.status}>{t(STATE_KEYS[voice.state])}</span>\r\n {voice.sessionId !== undefined && (\r\n <button\r\n type=\"button\"\r\n className={css.link}\r\n disabled={!navigable}\r\n onClick={() => { openVoiceSession(voice.sessionId as SessionId) }}\r\n >\r\n {t('overlay.return')}\r\n </button>\r\n )}\r\n <button type=\"button\" className={css.stop} onClick={() => { void stopVoice() }}>\r\n {t('overlay.stop')}\r\n </button>\r\n </aside>\r\n )\r\n}\r\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 {\r\n readonly state: VoiceClientState\r\n readonly sessionId?: SessionId\r\n readonly textById: Readonly<Record<string, VoiceLiveText>>\r\n}\r\n\r\ninterface VoiceTransport {\r\n close(): Promise<void>\r\n cancelTask(taskId: string): void\r\n submitText(text: string): void\r\n}\r\n\r\ninterface VoiceTransportHandlers {\r\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}\r\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', textById: {} }\r\n\r\n/** Own the single browser microphone, provider WebSocket, playback queue, and live transcript feed. */\r\nexport class VoiceController implements ObservableSnapshot<VoiceClientSnapshot> {\r\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[] = []\r\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 /**\r\n * Open one voice transport and make it the root-owned active session.\r\n * @param sessionId - durable voice session to connect.\r\n */\r\n async start(sessionId: SessionId): Promise<void> {\r\n const generation = ++this.generation\r\n this.pendingText.splice(0)\r\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', sessionId, textById: {} })\r\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) => {\r\n if (generation === this.generation) this.openingTransport = opening\r\n else void opening.close()\r\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> {\r\n const sessionId = this.snapshot.sessionId\r\n if (sessionId === undefined) throw new Error('voice retry requires an active session')\r\n await this.start(sessionId)\r\n }\r\n\r\n /** Cancel the exact active background task through the attached Voice transport. */\r\n cancelTask(taskId: string): void {\r\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)\r\n }\r\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') {\r\n this.setText(stringOf(event.utteranceId), stringOf(event.text), 'immediate')\r\n return\r\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') {\r\n const text = stringOf(event.text)\r\n if (text !== '') this.setText(stringOf(event.utteranceId), text, 'immediate')\r\n return\r\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 }\r\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\r\n const chunks: number[] = []\r\n const playing = new Set<AudioBufferSourceNode>()\r\n\r\n const transport: VoiceTransport = {\r\n cancelTask: (taskId) => {\r\n if (socket.readyState !== WebSocket.OPEN) throw new Error('voice transport is not open')\r\n socket.send(JSON.stringify({ type: 'task.cancel', taskId }))\r\n },\r\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 === 'transcription.started' || record?.type === 'response.interrupted') stopPlayback()\r\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\r\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>) => {\r\n if (socket.readyState !== WebSocket.OPEN) return\r\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': '开始语音对话',\r\n 'control.retry': '语音连接失败,点击重试',\r\n 'control.stop': '结束语音对话',\r\n 'overlay.connecting': '正在连接语音',\r\n 'overlay.listening': '正在聆听',\r\n 'overlay.speaking': '正在播放回复',\r\n 'overlay.error': '语音连接失败',\r\n 'overlay.return': '返回语音对话',\r\n 'overlay.stop': '结束',\r\n 'history.open': '打开语音历史',\r\n 'history.label': '语音历史',\r\n 'history.title': '语音对话',\r\n 'history.close': '关闭语音历史',\r\n 'history.empty': '还没有语音对话',\r\n 'history.active': '通话中',\r\n 'history.saved': '已保存',\r\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',\r\n 'control.retry': 'Voice connection failed, press to retry',\r\n 'control.stop': 'End voice conversation',\r\n 'overlay.connecting': 'Connecting voice',\r\n 'overlay.listening': 'Listening',\r\n 'overlay.speaking': 'Playing response',\r\n 'overlay.error': 'Voice connection failed',\r\n 'overlay.return': 'Return to voice conversation',\r\n 'overlay.stop': 'End',\r\n 'history.open': 'Open voice history',\r\n 'history.label': 'Voice history',\r\n 'history.title': 'Voice conversations',\r\n 'history.close': 'Close voice history',\r\n 'history.empty': 'No voice conversations yet',\r\n 'history.active': 'Active',\r\n 'history.saved': 'Saved',\r\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'\r\nimport { VoiceControl, type VoiceControlInjected } from './VoiceControl.tsx'\r\nimport { VoiceHistoryAction, type VoiceHistoryActionInjected } from './VoiceHistoryAction.tsx'\r\nimport {\r\n VoiceDelegationView, type VoiceDelegationInjected,\r\n VoiceUtteranceView, type VoiceUtteranceInjected,\r\n} from './VoiceNodeViews.tsx'\r\nimport { VoiceOverlay, type VoiceOverlayInjected } from './VoiceOverlay.tsx'\r\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']\r\n\r\n/** Mount root transport controls and durable Voice conversation renderers. @param ctx - browser context. */\r\nexport function apply(ctx: ClientContext): void {\r\n const controller = new VoiceController()\r\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 () => {\r\n await controller.retry()\r\n const sessionId = controller.getSnapshot().sessionId\r\n if (sessionId !== undefined) history.record(sessionId)\r\n },\r\n stopVoice,\r\n })\r\n const voiceOverlayInjected = (): VoiceOverlayInjected => ({\r\n hooks: { voice: controller },\r\n openVoiceSession: (id) => { ctx.sessions.open(id) },\r\n stopVoice,\r\n })\r\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 const historyInjected = (): VoiceHistoryActionInjected => ({\r\n hooks: { voice: controller, voiceHistory: history.snapshot },\r\n openSession: (id) => {\r\n history.record(id)\r\n ctx.sessions.open(id)\r\n },\r\n })\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({\r\n name: 'shell.overlay',\r\n id: 'voice-active',\r\n order: 20,\r\n locale: NS,\r\n inject: voiceOverlayInjected,\r\n }, VoiceOverlay))\r\n ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({\r\n name: 'sidebar.footer.action',\r\n id: 'voice-history',\r\n order: 10,\r\n locale: NS,\r\n inject: historyInjected,\r\n }, VoiceHistoryAction))\r\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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"}
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ //#region lib/types/index.js
2
+ /** Voice profile patch package. @module @flowingspring/dsh-voco */
3
+ /** Runtime no-op; the package manifest exposes the patch layer. */
4
+ function apply() {}
5
+ //#endregion
6
+ export { apply };
@@ -0,0 +1,9 @@
1
+ //#region lib/types/invariant.js
2
+ const name = "voco-invariant";
3
+ const inject = ["invariants"];
4
+ /** No runtime invariant: this package is a static patch-list carrier. */
5
+ const install = () => {};
6
+ /** Register invariant ownership. @param ctx - runtime context. @returns disposer. */
7
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register("@flowingspring/dsh-voco", install));
8
+ //#endregion
9
+ export { apply, inject, name };
@@ -0,0 +1,101 @@
1
+ //#region ../llm-tool-call-compat/src/index.ts
2
+ /** Restore metadata omitted as empty strings by some OpenAI-compatible gateways. */
3
+ function normalizeToolCallSseEvent(event, states) {
4
+ if (!event.startsWith("data: ")) return event;
5
+ const payload = event.slice(6).trim();
6
+ if (payload === "[DONE]") return event;
7
+ let value;
8
+ try {
9
+ value = JSON.parse(payload);
10
+ } catch {
11
+ return event;
12
+ }
13
+ if (typeof value !== "object" || value === null) return event;
14
+ const choices = value.choices;
15
+ if (!Array.isArray(choices)) return event;
16
+ let changed = false;
17
+ for (const choice of choices) {
18
+ if (typeof choice !== "object" || choice === null) continue;
19
+ const delta = choice.delta;
20
+ if (typeof delta !== "object" || delta === null) continue;
21
+ const calls = delta.tool_calls;
22
+ if (!Array.isArray(calls)) continue;
23
+ for (const call of calls) {
24
+ if (typeof call !== "object" || call === null || typeof call.index !== "number") continue;
25
+ const index = call.index;
26
+ const state = states.get(index) ?? {};
27
+ const id = call.id;
28
+ if (typeof id === "string" && id.length > 0) state.id = id;
29
+ else if (state.id !== void 0 && id === "") {
30
+ call.id = state.id;
31
+ changed = true;
32
+ }
33
+ const type = call.type;
34
+ if (typeof type === "string" && type.length > 0) state.type = type;
35
+ else if (state.type !== void 0 && type === "") {
36
+ call.type = state.type;
37
+ changed = true;
38
+ }
39
+ const fn = call.function;
40
+ if (typeof fn === "object" && fn !== null) {
41
+ const name = fn.name;
42
+ if (typeof name === "string" && name.length > 0) state.name = name;
43
+ else if (state.name !== void 0 && name === "") {
44
+ fn.name = state.name;
45
+ changed = true;
46
+ }
47
+ }
48
+ states.set(index, state);
49
+ }
50
+ }
51
+ return changed ? `data: ${JSON.stringify(value)}` : event;
52
+ }
53
+ function wrapSseBody(body) {
54
+ const reader = body.getReader();
55
+ const decoder = new TextDecoder();
56
+ const encoder = new TextEncoder();
57
+ const states = /* @__PURE__ */ new Map();
58
+ let pending = "";
59
+ return new ReadableStream({
60
+ async pull(controller) {
61
+ const result = await reader.read();
62
+ if (result.done) {
63
+ pending += decoder.decode();
64
+ if (pending.length > 0) controller.enqueue(encoder.encode(normalizeToolCallSseEvent(pending, states)));
65
+ controller.close();
66
+ return;
67
+ }
68
+ pending += decoder.decode(result.value, { stream: true });
69
+ const events = pending.split(/\r?\n\r?\n/);
70
+ pending = events.pop() ?? "";
71
+ if (events.length > 0) controller.enqueue(encoder.encode(events.map((event) => normalizeToolCallSseEvent(event, states)).join("\n\n") + "\n\n"));
72
+ },
73
+ cancel(reason) {
74
+ return reader.cancel(reason);
75
+ }
76
+ });
77
+ }
78
+ const INSTALLED = Symbol.for("lgquan.dsh-voco.tool-call-compat");
79
+ /** Install the gateway compatibility layer once for this Harness process. */
80
+ function apply(_ctx) {
81
+ const global = globalThis;
82
+ if (global[INSTALLED]) return;
83
+ const original = global.fetch.bind(globalThis);
84
+ global.fetch = async (input, init) => {
85
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
86
+ const response = await original(input, init);
87
+ if (!url.endsWith("/chat/completions") || response.body === null) return response;
88
+ const headers = new Headers(response.headers);
89
+ headers.delete("content-length");
90
+ headers.delete("content-encoding");
91
+ return new Response(wrapSseBody(response.body), {
92
+ status: response.status,
93
+ statusText: response.statusText,
94
+ headers
95
+ });
96
+ };
97
+ global[INSTALLED] = true;
98
+ }
99
+ const name = "llm-tool-call-compat";
100
+ //#endregion
101
+ export { apply, name, normalizeToolCallSseEvent };