@devicai/ui 0.61.1 → 0.62.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.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/api/client.js +3 -2
  3. package/dist/cjs/api/client.js.map +1 -1
  4. package/dist/cjs/components/ChatDrawer/ChatDrawer.js +10 -2
  5. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
  6. package/dist/cjs/components/ChatDrawer/ChatInput.js +8 -2
  7. package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -1
  8. package/dist/cjs/components/ChatDrawer/LiveVoicePanel.js +20 -72
  9. package/dist/cjs/components/ChatDrawer/LiveVoicePanel.js.map +1 -1
  10. package/dist/cjs/hooks/useDevicLiveVoice.js +1 -0
  11. package/dist/cjs/hooks/useDevicLiveVoice.js.map +1 -1
  12. package/dist/cjs/index.js +4 -0
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/styles.css +1 -1
  15. package/dist/cjs/utils/voiceInvitation.js +33 -0
  16. package/dist/cjs/utils/voiceInvitation.js.map +1 -0
  17. package/dist/cjs/voice/LiveVoiceController.js +98 -2
  18. package/dist/cjs/voice/LiveVoiceController.js.map +1 -1
  19. package/dist/esm/api/client.d.ts +2 -1
  20. package/dist/esm/api/client.js +3 -2
  21. package/dist/esm/api/client.js.map +1 -1
  22. package/dist/esm/api/liveVoice.types.d.ts +5 -0
  23. package/dist/esm/components/ChatDrawer/ChatDrawer.js +10 -2
  24. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
  25. package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +31 -1
  26. package/dist/esm/components/ChatDrawer/ChatInput.js +8 -2
  27. package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -1
  28. package/dist/esm/components/ChatDrawer/LiveVoicePanel.d.ts +11 -9
  29. package/dist/esm/components/ChatDrawer/LiveVoicePanel.js +20 -72
  30. package/dist/esm/components/ChatDrawer/LiveVoicePanel.js.map +1 -1
  31. package/dist/esm/hooks/useDevicLiveVoice.d.ts +2 -0
  32. package/dist/esm/hooks/useDevicLiveVoice.js +1 -0
  33. package/dist/esm/hooks/useDevicLiveVoice.js.map +1 -1
  34. package/dist/esm/index.d.ts +2 -0
  35. package/dist/esm/index.js +1 -0
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/styles.css +1 -1
  38. package/dist/esm/utils/voiceInvitation.d.ts +3 -0
  39. package/dist/esm/utils/voiceInvitation.js +29 -0
  40. package/dist/esm/utils/voiceInvitation.js.map +1 -0
  41. package/dist/esm/voice/LiveVoiceController.d.ts +10 -0
  42. package/dist/esm/voice/LiveVoiceController.js +98 -2
  43. package/dist/esm/voice/LiveVoiceController.js.map +1 -1
  44. package/package.json +1 -1
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Whether the person closed the voice invitation for an assistant. Kept in
5
+ * localStorage, per assistant, so it stays closed across conversations and
6
+ * page loads; storage that is missing, full or blocked counts as "not hidden".
7
+ */
8
+ const key = (assistantId) => `devic-ui:voice-invitation-hidden:${assistantId}`;
9
+ function isVoiceInvitationHidden(assistantId) {
10
+ try {
11
+ return typeof localStorage !== 'undefined' && localStorage.getItem(key(assistantId)) === '1';
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ function hideVoiceInvitation(assistantId) {
18
+ try {
19
+ localStorage.setItem(key(assistantId), '1');
20
+ }
21
+ catch { /* Private mode or quota: the card comes back next load. */ }
22
+ }
23
+ function showVoiceInvitation(assistantId) {
24
+ try {
25
+ localStorage.removeItem(key(assistantId));
26
+ }
27
+ catch { /* Nothing to undo. */ }
28
+ }
29
+
30
+ exports.hideVoiceInvitation = hideVoiceInvitation;
31
+ exports.isVoiceInvitationHidden = isVoiceInvitationHidden;
32
+ exports.showVoiceInvitation = showVoiceInvitation;
33
+ //# sourceMappingURL=voiceInvitation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voiceInvitation.js","sources":["../../../../src/utils/voiceInvitation.ts"],"sourcesContent":["/**\n * Whether the person closed the voice invitation for an assistant. Kept in\n * localStorage, per assistant, so it stays closed across conversations and\n * page loads; storage that is missing, full or blocked counts as \"not hidden\".\n */\nconst key = (assistantId: string) => `devic-ui:voice-invitation-hidden:${assistantId}`;\n\nexport function isVoiceInvitationHidden(assistantId: string): boolean {\n try { return typeof localStorage !== 'undefined' && localStorage.getItem(key(assistantId)) === '1'; }\n catch { return false; }\n}\n\nexport function hideVoiceInvitation(assistantId: string): void {\n try { localStorage.setItem(key(assistantId), '1'); } catch { /* Private mode or quota: the card comes back next load. */ }\n}\n\nexport function showVoiceInvitation(assistantId: string): void {\n try { localStorage.removeItem(key(assistantId)); } catch { /* Nothing to undo. */ }\n}\n"],"names":[],"mappings":";;AAAA;;;;AAIG;AACH,MAAM,GAAG,GAAG,CAAC,WAAmB,KAAK,CAAA,iCAAA,EAAoC,WAAW,CAAA,CAAE;AAEhF,SAAU,uBAAuB,CAAC,WAAmB,EAAA;AACzD,IAAA,IAAI;AAAE,QAAA,OAAO,OAAO,YAAY,KAAK,WAAW,IAAI,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,GAAG;IAAE;AACpG,IAAA,MAAM;AAAE,QAAA,OAAO,KAAK;IAAE;AACxB;AAEM,SAAU,mBAAmB,CAAC,WAAmB,EAAA;AACrD,IAAA,IAAI;QAAE,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC;IAAE;AAAE,IAAA,MAAM,8DAA8D;AAC3H;AAEM,SAAU,mBAAmB,CAAC,WAAmB,EAAA;AACrD,IAAA,IAAI;QAAE,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAAE;AAAE,IAAA,MAAM,yBAAyB;AACpF;;;;;;"}
@@ -14,6 +14,8 @@ class LiveVoiceController {
14
14
  this.attempts = 0;
15
15
  this.disposeTransport = () => { };
16
16
  this.disposed = false;
17
+ /** Last moment anyone spoke, or the person confirmed presence. */
18
+ this.lastActivity = 0;
17
19
  }
18
20
  update(patch) {
19
21
  this.snapshot = { ...this.snapshot, ...patch };
@@ -33,6 +35,15 @@ class LiveVoiceController {
33
35
  this.update({ playbackBlocked: true });
34
36
  }
35
37
  }
38
+ /** The person is still there: restart the idle clock here and on the server. */
39
+ stillHere() {
40
+ this.lastActivity = Date.now();
41
+ if (this.snapshot.idleEndsAt)
42
+ this.update({ idleEndsAt: undefined });
43
+ const id = this.snapshot.sessionId;
44
+ if (id && this.snapshot.state === 'connected')
45
+ void this.client.getLiveSessionStatus(this.assistantId, id, true).catch(() => { });
46
+ }
36
47
  async start(chatUid, recovering = false) {
37
48
  if (this.disposed || this.closing || (!recovering && !['idle', 'error'].includes(this.snapshot.state)))
38
49
  return;
@@ -41,7 +52,8 @@ class LiveVoiceController {
41
52
  if (!recovering)
42
53
  this.attempts = 0;
43
54
  this.update({ state: 'connecting', error: undefined, chatUid, sessionId: undefined,
44
- seconds: 0, ...(recovering ? {} : { transcript: [], muted: false }) });
55
+ seconds: 0, idleEndsAt: undefined, endReason: undefined, ...(recovering ? {} : { transcript: [], muted: false }) });
56
+ this.lastActivity = Date.now();
45
57
  let media;
46
58
  let peer;
47
59
  let channel;
@@ -54,10 +66,23 @@ class LiveVoiceController {
54
66
  let sessionId;
55
67
  let connectionLostAt = 0;
56
68
  let healthFailures = 0;
69
+ let micCheck;
70
+ let micContext;
71
+ let micAnalyser;
72
+ let micQuiet = 0;
57
73
  const cleanup = () => {
58
74
  clearInterval(health);
59
75
  clearTimeout(deadline);
60
76
  clearTimeout(connectDeadline);
77
+ clearInterval(micCheck);
78
+ if (micContext) {
79
+ try {
80
+ void micContext.close().catch(() => { });
81
+ }
82
+ catch { /* Already closed. */ }
83
+ micContext = undefined;
84
+ micAnalyser = undefined;
85
+ }
61
86
  media?.getTracks().forEach(track => track.stop());
62
87
  if (channel) {
63
88
  channel.onclose = null;
@@ -82,8 +107,64 @@ class LiveVoiceController {
82
107
  return;
83
108
  clearTimeout(connectDeadline);
84
109
  media?.getAudioTracks().forEach(track => { track.enabled = !this.snapshot.muted; });
110
+ if (this.snapshot.state !== 'connected') {
111
+ this.lastActivity = Date.now();
112
+ watchMicrophone();
113
+ }
85
114
  this.update({ state: 'connected' });
86
115
  };
116
+ // A microphone that delivers nothing — ended track, system mute, or a
117
+ // stream of exact digital silence — would otherwise keep a paid call open
118
+ // with nobody able to speak. Analyse only; never route audio.
119
+ const watchMicrophone = () => {
120
+ if (micCheck)
121
+ return;
122
+ const track = media?.getAudioTracks()[0];
123
+ if (!track)
124
+ return;
125
+ const samples = new Uint8Array(256);
126
+ try {
127
+ if (typeof AudioContext !== 'undefined') {
128
+ micContext = new AudioContext();
129
+ micAnalyser = micContext.createAnalyser();
130
+ micAnalyser.fftSize = 256;
131
+ micContext.createMediaStreamSource(media).connect(micAnalyser);
132
+ void micContext.resume().catch(() => { });
133
+ }
134
+ }
135
+ catch {
136
+ micAnalyser = undefined;
137
+ }
138
+ micCheck = setInterval(() => {
139
+ if (!current() || this.snapshot.state !== 'connected')
140
+ return;
141
+ const fail = () => {
142
+ this.update({ error: new Error('No microphone signal. Check your microphone and start again.') });
143
+ void this.stop();
144
+ };
145
+ if (track.readyState === 'ended') {
146
+ fail();
147
+ return;
148
+ }
149
+ if (this.snapshot.muted) {
150
+ micQuiet = 0;
151
+ return;
152
+ }
153
+ let silent = track.muted === true;
154
+ if (micAnalyser && !silent) {
155
+ try {
156
+ micAnalyser.getByteTimeDomainData(samples);
157
+ silent = samples.every(sample => sample === 128);
158
+ }
159
+ catch {
160
+ silent = false;
161
+ }
162
+ }
163
+ micQuiet = silent ? micQuiet + 1 : 0;
164
+ if (micQuiet >= 15)
165
+ fail();
166
+ }, 1000);
167
+ };
87
168
  const recover = async () => {
88
169
  if (!current())
89
170
  return;
@@ -157,6 +238,9 @@ class LiveVoiceController {
157
238
  }
158
239
  if (['session.input_transcript.delta', 'session.output_transcript.delta'].includes(event.type) && typeof event.delta === 'string') {
159
240
  lastTranscript = Date.now();
241
+ this.lastActivity = lastTranscript;
242
+ if (this.snapshot.idleEndsAt)
243
+ this.update({ idleEndsAt: undefined });
160
244
  const role = event.type === 'session.input_transcript.delta' ? 'user' : 'assistant';
161
245
  const turns = this.snapshot.transcript.slice(-3).map(turn => ({ ...turn }));
162
246
  if (turns[turns.length - 1]?.role === role)
@@ -169,6 +253,8 @@ class LiveVoiceController {
169
253
  void this.client.getLiveSessionStatus(this.assistantId, sessionId).then(state => {
170
254
  if (!current())
171
255
  return;
256
+ if (state.endReason)
257
+ this.update({ endReason: state.endReason });
172
258
  if (state.restartRequested)
173
259
  void recover();
174
260
  else
@@ -213,7 +299,7 @@ class LiveVoiceController {
213
299
  void this.client.closeLiveSession(this.assistantId, sessionId).catch(() => { });
214
300
  return;
215
301
  }
216
- this.update({ sessionId, chatUid: result.chatUid });
302
+ this.update({ sessionId, chatUid: result.chatUid, idleTimeoutSeconds: result.idleTimeoutSeconds || 0 });
217
303
  this.created(result.chatUid);
218
304
  deadline = setTimeout(() => { void this.stop(); }, Math.max(1, Math.min(6000, result.maxDurationSeconds || 6000)) * 1000);
219
305
  await peer.setRemoteDescription({ type: 'answer', sdp: result.sdp });
@@ -228,6 +314,16 @@ class LiveVoiceController {
228
314
  return;
229
315
  healthFailures = 0;
230
316
  this.update({ seconds: state.seconds });
317
+ // The server ends a silent call at idleTimeoutSeconds; warn for the
318
+ // last 30 s (or half the window when it is short) so the person can
319
+ // say "I'm here" instead of losing the call.
320
+ const idle = this.snapshot.idleTimeoutSeconds || 0;
321
+ if (idle > 0 && this.snapshot.state === 'connected') {
322
+ const endsAt = this.lastActivity + idle * 1000;
323
+ const warn = Date.now() >= endsAt - Math.min(30000, idle * 500);
324
+ if (warn ? this.snapshot.idleEndsAt !== endsAt : !!this.snapshot.idleEndsAt)
325
+ this.update({ idleEndsAt: warn ? endsAt : undefined });
326
+ }
231
327
  if (state.interrupted || state.restartRequested || (connectionLostAt && Date.now() - connectionLostAt > 5000)) {
232
328
  void recover();
233
329
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"LiveVoiceController.js","sources":["../../../../src/voice/LiveVoiceController.ts"],"sourcesContent":["import type { DevicApiClient } from '../api/client';\nimport type { LiveVoiceContext, LiveVoiceTurn } from '../api/liveVoice.types';\n\nexport type LiveVoiceState = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'closing' | 'error';\nexport interface LiveVoiceSnapshot {\n state: LiveVoiceState;\n chatUid?: string;\n sessionId?: string;\n muted: boolean;\n seconds: number;\n transcript: LiveVoiceTurn[];\n input?: MediaStream;\n output?: MediaStream;\n error?: Error;\n playbackBlocked?: boolean;\n}\nexport const initialVoiceSnapshot = (): LiveVoiceSnapshot => ({ state: 'idle', muted: false, seconds: 0, transcript: [] });\n\n/** No browser globals at import/constructor time; loaded only by start(). */\nexport class LiveVoiceController {\n private snapshot = initialVoiceSnapshot();\n private generation = 0;\n private attempts = 0;\n private disposeTransport: () => void = () => {};\n private audio?: HTMLAudioElement;\n private closing?: Promise<void>;\n private disposed = false;\n constructor(private client: DevicApiClient, private assistantId: string,\n private context: LiveVoiceContext, private changed: (value: LiveVoiceSnapshot) => void,\n private created: (chatUid: string) => void) {}\n\n private update(patch: Partial<LiveVoiceSnapshot>) {\n this.snapshot = { ...this.snapshot, ...patch };\n if (!this.disposed) this.changed(this.snapshot);\n }\n mute(muted: boolean) {\n this.snapshot.input?.getAudioTracks().forEach(track => { track.enabled = !muted && this.snapshot.state === 'connected'; });\n this.update({ muted });\n }\n async play() {\n try { await this.audio?.play(); this.update({ playbackBlocked: false }); }\n catch { this.update({ playbackBlocked: true }); }\n }\n async start(chatUid?: string, recovering = false): Promise<void> {\n if (this.disposed || this.closing || (!recovering && !['idle', 'error'].includes(this.snapshot.state))) return;\n const generation = ++this.generation;\n const current = () => generation === this.generation && !this.disposed;\n if (!recovering) this.attempts = 0;\n this.update({ state: 'connecting', error: undefined, chatUid, sessionId: undefined,\n seconds: 0, ...(recovering ? {} : { transcript: [], muted: false }) });\n let media: MediaStream | undefined;\n let peer: RTCPeerConnection | undefined;\n let channel: RTCDataChannel | undefined;\n let audio: HTMLAudioElement | undefined;\n let health: ReturnType<typeof setInterval> | undefined;\n let deadline: ReturnType<typeof setTimeout> | undefined;\n let connectDeadline: ReturnType<typeof setTimeout> | undefined;\n let backendReady = false;\n let lastTranscript = 0;\n let sessionId: string | undefined;\n let connectionLostAt = 0;\n let healthFailures = 0;\n const cleanup = () => {\n clearInterval(health); clearTimeout(deadline); clearTimeout(connectDeadline);\n media?.getTracks().forEach(track => track.stop());\n if (channel) { channel.onclose = null; channel.onmessage = null; channel.close(); }\n if (peer) { peer.onconnectionstatechange = null; peer.ontrack = null; peer.close(); }\n if (audio) { audio.pause(); audio.srcObject = null; }\n this.audio = undefined;\n this.update({ input: undefined, output: undefined });\n };\n this.disposeTransport = cleanup;\n const ready = () => {\n if (!current() || !backendReady || peer?.connectionState !== 'connected') return;\n clearTimeout(connectDeadline);\n media?.getAudioTracks().forEach(track => { track.enabled = !this.snapshot.muted; });\n this.update({ state: 'connected' });\n };\n const recover = async () => {\n if (!current()) return;\n ++this.generation;\n const ticket = this.generation;\n cleanup();\n this.update({ state: 'reconnecting' });\n try {\n if (!sessionId || ++this.attempts > 3) throw new Error('Voice connection interrupted. Please start again.');\n await this.client.closeLiveSession(this.assistantId, sessionId);\n // Never open another paid transport before the old one is confirmed closed.\n for (let i = 0; i < 35 && ticket === this.generation && !this.disposed; i++) {\n const state = await this.client.getLiveSessionStatus(this.assistantId, sessionId);\n if (state.status === 'closed') {\n if (ticket === this.generation && !this.disposed) await this.start(this.snapshot.chatUid, true);\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 2000));\n }\n if (ticket === this.generation) throw new Error('Could not confirm the previous voice session closed.');\n } catch (error) {\n if (ticket === this.generation) this.update({ state: 'error', error: error as Error });\n }\n };\n try {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices?.getUserMedia || typeof RTCPeerConnection === 'undefined')\n throw new Error('Voice requires microphone access on HTTPS or localhost.');\n media = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true }, video: false });\n if (!current()) { media.getTracks().forEach(track => track.stop()); return; }\n media.getAudioTracks().forEach(track => { track.enabled = false; });\n this.update({ input: media });\n peer = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });\n audio = new Audio(); this.audio = audio; audio.autoplay = true;\n peer.ontrack = event => {\n if (!current()) return;\n const output = new MediaStream([event.track]);\n audio!.srcObject = output;\n this.update({ output }); void this.play();\n };\n peer.onconnectionstatechange = () => {\n ready();\n if (peer?.connectionState === 'disconnected') connectionLostAt ||= Date.now();\n else connectionLostAt = 0;\n if (peer?.connectionState === 'failed') void recover();\n };\n media.getTracks().forEach(track => peer!.addTrack(track, media!));\n channel = peer.createDataChannel('oai-events');\n channel.onmessage = message => {\n if (!current()) return;\n try {\n const event = JSON.parse(message.data);\n if (event.type === 'session.started') { backendReady = true; ready(); }\n if (['session.input_transcript.delta', 'session.output_transcript.delta'].includes(event.type) && typeof event.delta === 'string') {\n lastTranscript = Date.now();\n const role = event.type === 'session.input_transcript.delta' ? 'user' : 'assistant';\n const turns = this.snapshot.transcript.slice(-3).map(turn => ({ ...turn }));\n if (turns[turns.length - 1]?.role === role) turns[turns.length - 1].text = (turns[turns.length - 1].text + event.delta).slice(-2000);\n else turns.push({ role, text: event.delta.slice(-2000) });\n this.update({ transcript: turns });\n }\n if (event.type === 'session.closed' && sessionId) {\n void this.client.getLiveSessionStatus(this.assistantId, sessionId).then(state => {\n if (!current()) return;\n if (state.restartRequested) void recover(); else void this.stop();\n }).catch(() => { if (current()) void this.stop(); });\n }\n if (event.type === 'error') { this.update({ error: new Error('Voice session failed.') }); void this.stop(); }\n } catch { /* Only lifecycle and spoken transcript events are accepted. */ }\n };\n channel.onclose = () => { if (current()) void recover(); };\n connectDeadline = setTimeout(() => {\n if (current()) { this.update({ error: new Error('Voice connection timed out.') }); void this.stop(); }\n }, 30000);\n await peer.setLocalDescription(await peer.createOffer());\n await new Promise<void>((resolve, reject) => {\n if (peer!.iceGatheringState === 'complete') return resolve();\n const done = () => {\n if (peer!.iceGatheringState !== 'complete') return;\n clearTimeout(timer); peer!.removeEventListener('icegatheringstatechange', done); resolve();\n };\n const timer = setTimeout(() => { peer!.removeEventListener('icegatheringstatechange', done); reject(new Error('Could not prepare the audio connection.')); }, 10000);\n peer!.addEventListener('icegatheringstatechange', done);\n });\n if (!current()) return;\n const result = await this.client.createLiveSession(this.assistantId, { ...this.context, chatUid, sdp: peer.localDescription!.sdp });\n sessionId = result.sessionId;\n if (!current()) { void this.client.closeLiveSession(this.assistantId, sessionId).catch(() => {}); return; }\n this.update({ sessionId, chatUid: result.chatUid }); this.created(result.chatUid);\n deadline = setTimeout(() => { void this.stop(); }, Math.max(1, Math.min(6000, result.maxDurationSeconds || 6000)) * 1000);\n await peer.setRemoteDescription({ type: 'answer', sdp: result.sdp });\n let busy = false;\n health = setInterval(async () => {\n if (!current() || busy) return;\n busy = true;\n try {\n const state = await this.client.getLiveSessionStatus(this.assistantId, sessionId!);\n if (!current()) return;\n healthFailures = 0;\n this.update({ seconds: state.seconds });\n if (state.interrupted || state.restartRequested || (connectionLostAt && Date.now() - connectionLostAt > 5000)) { void recover(); return; }\n if (state.status === 'closed') { void this.stop(); return; }\n backendReady = state.connected; ready();\n if (Date.now() - lastTranscript > 1500 && state.transcript?.length)\n this.update({ transcript: state.transcript.slice(-4).filter(t => t.role === 'user' || t.role === 'assistant').map(t => ({ role: t.role, text: t.text.slice(-2000) })) });\n } catch {\n if (current() && ++healthFailures >= 5) { this.update({ error: new Error('Voice status unavailable. Session stopped.')} ); void this.stop(); }\n } finally { busy = false; }\n }, 1000);\n } catch (error) {\n if (!current()) return;\n this.update({ error: error instanceof Error ? error : new Error(String(error)) });\n await this.stop();\n }\n }\n stop(): Promise<void> {\n if (this.closing) return this.closing;\n ++this.generation;\n this.disposeTransport();\n const id = this.snapshot.sessionId;\n this.update({ state: id ? 'closing' : (this.snapshot.error ? 'error' : 'idle') });\n this.closing = (async () => {\n if (id) {\n try { await this.client.closeLiveSession(this.assistantId, id); }\n catch (error) { this.update({ error: error as Error }); }\n }\n this.update({ state: this.snapshot.error ? 'error' : 'idle', sessionId: undefined });\n })().finally(() => { this.closing = undefined; });\n return this.closing;\n }\n dispose() { this.disposed = true; void this.stop(); }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LiveVoiceController.js","sources":["../../../../src/voice/LiveVoiceController.ts"],"sourcesContent":["import type { DevicApiClient } from '../api/client';\nimport type { LiveVoiceContext, LiveVoiceTurn } from '../api/liveVoice.types';\n\nexport type LiveVoiceState = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'closing' | 'error';\nexport interface LiveVoiceSnapshot {\n state: LiveVoiceState;\n chatUid?: string;\n sessionId?: string;\n muted: boolean;\n seconds: number;\n transcript: LiveVoiceTurn[];\n input?: MediaStream;\n output?: MediaStream;\n error?: Error;\n playbackBlocked?: boolean;\n /** Seconds of silence after which the server ends the call; 0 = never. */\n idleTimeoutSeconds?: number;\n /** Set while the call is about to end for silence: when it will, so a UI can count down. */\n idleEndsAt?: number;\n /** Why the server ended the last call, e.g. `idle`. */\n endReason?: string;\n}\nexport const initialVoiceSnapshot = (): LiveVoiceSnapshot => ({ state: 'idle', muted: false, seconds: 0, transcript: [] });\n\n/** No browser globals at import/constructor time; loaded only by start(). */\nexport class LiveVoiceController {\n private snapshot = initialVoiceSnapshot();\n private generation = 0;\n private attempts = 0;\n private disposeTransport: () => void = () => {};\n private audio?: HTMLAudioElement;\n private closing?: Promise<void>;\n private disposed = false;\n /** Last moment anyone spoke, or the person confirmed presence. */\n private lastActivity = 0;\n constructor(private client: DevicApiClient, private assistantId: string,\n private context: LiveVoiceContext, private changed: (value: LiveVoiceSnapshot) => void,\n private created: (chatUid: string) => void) {}\n\n private update(patch: Partial<LiveVoiceSnapshot>) {\n this.snapshot = { ...this.snapshot, ...patch };\n if (!this.disposed) this.changed(this.snapshot);\n }\n mute(muted: boolean) {\n this.snapshot.input?.getAudioTracks().forEach(track => { track.enabled = !muted && this.snapshot.state === 'connected'; });\n this.update({ muted });\n }\n async play() {\n try { await this.audio?.play(); this.update({ playbackBlocked: false }); }\n catch { this.update({ playbackBlocked: true }); }\n }\n /** The person is still there: restart the idle clock here and on the server. */\n stillHere() {\n this.lastActivity = Date.now();\n if (this.snapshot.idleEndsAt) this.update({ idleEndsAt: undefined });\n const id = this.snapshot.sessionId;\n if (id && this.snapshot.state === 'connected') void this.client.getLiveSessionStatus(this.assistantId, id, true).catch(() => {});\n }\n async start(chatUid?: string, recovering = false): Promise<void> {\n if (this.disposed || this.closing || (!recovering && !['idle', 'error'].includes(this.snapshot.state))) return;\n const generation = ++this.generation;\n const current = () => generation === this.generation && !this.disposed;\n if (!recovering) this.attempts = 0;\n this.update({ state: 'connecting', error: undefined, chatUid, sessionId: undefined,\n seconds: 0, idleEndsAt: undefined, endReason: undefined, ...(recovering ? {} : { transcript: [], muted: false }) });\n this.lastActivity = Date.now();\n let media: MediaStream | undefined;\n let peer: RTCPeerConnection | undefined;\n let channel: RTCDataChannel | undefined;\n let audio: HTMLAudioElement | undefined;\n let health: ReturnType<typeof setInterval> | undefined;\n let deadline: ReturnType<typeof setTimeout> | undefined;\n let connectDeadline: ReturnType<typeof setTimeout> | undefined;\n let backendReady = false;\n let lastTranscript = 0;\n let sessionId: string | undefined;\n let connectionLostAt = 0;\n let healthFailures = 0;\n let micCheck: ReturnType<typeof setInterval> | undefined;\n let micContext: AudioContext | undefined;\n let micAnalyser: AnalyserNode | undefined;\n let micQuiet = 0;\n const cleanup = () => {\n clearInterval(health); clearTimeout(deadline); clearTimeout(connectDeadline); clearInterval(micCheck);\n if (micContext) { try { void micContext.close().catch(() => {}); } catch { /* Already closed. */ } micContext = undefined; micAnalyser = undefined; }\n media?.getTracks().forEach(track => track.stop());\n if (channel) { channel.onclose = null; channel.onmessage = null; channel.close(); }\n if (peer) { peer.onconnectionstatechange = null; peer.ontrack = null; peer.close(); }\n if (audio) { audio.pause(); audio.srcObject = null; }\n this.audio = undefined;\n this.update({ input: undefined, output: undefined });\n };\n this.disposeTransport = cleanup;\n const ready = () => {\n if (!current() || !backendReady || peer?.connectionState !== 'connected') return;\n clearTimeout(connectDeadline);\n media?.getAudioTracks().forEach(track => { track.enabled = !this.snapshot.muted; });\n if (this.snapshot.state !== 'connected') { this.lastActivity = Date.now(); watchMicrophone(); }\n this.update({ state: 'connected' });\n };\n // A microphone that delivers nothing — ended track, system mute, or a\n // stream of exact digital silence — would otherwise keep a paid call open\n // with nobody able to speak. Analyse only; never route audio.\n const watchMicrophone = () => {\n if (micCheck) return;\n const track = media?.getAudioTracks()[0];\n if (!track) return;\n const samples = new Uint8Array(256);\n try {\n if (typeof AudioContext !== 'undefined') {\n micContext = new AudioContext(); micAnalyser = micContext.createAnalyser(); micAnalyser.fftSize = 256;\n micContext.createMediaStreamSource(media!).connect(micAnalyser); void micContext.resume().catch(() => {});\n }\n } catch { micAnalyser = undefined; }\n micCheck = setInterval(() => {\n if (!current() || this.snapshot.state !== 'connected') return;\n const fail = () => {\n this.update({ error: new Error('No microphone signal. Check your microphone and start again.') });\n void this.stop();\n };\n if (track.readyState === 'ended') { fail(); return; }\n if (this.snapshot.muted) { micQuiet = 0; return; }\n let silent = track.muted === true;\n if (micAnalyser && !silent) {\n try {\n micAnalyser.getByteTimeDomainData(samples);\n silent = samples.every(sample => sample === 128);\n } catch { silent = false; }\n }\n micQuiet = silent ? micQuiet + 1 : 0;\n if (micQuiet >= 15) fail();\n }, 1000);\n };\n const recover = async () => {\n if (!current()) return;\n ++this.generation;\n const ticket = this.generation;\n cleanup();\n this.update({ state: 'reconnecting' });\n try {\n if (!sessionId || ++this.attempts > 3) throw new Error('Voice connection interrupted. Please start again.');\n await this.client.closeLiveSession(this.assistantId, sessionId);\n // Never open another paid transport before the old one is confirmed closed.\n for (let i = 0; i < 35 && ticket === this.generation && !this.disposed; i++) {\n const state = await this.client.getLiveSessionStatus(this.assistantId, sessionId);\n if (state.status === 'closed') {\n if (ticket === this.generation && !this.disposed) await this.start(this.snapshot.chatUid, true);\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 2000));\n }\n if (ticket === this.generation) throw new Error('Could not confirm the previous voice session closed.');\n } catch (error) {\n if (ticket === this.generation) this.update({ state: 'error', error: error as Error });\n }\n };\n try {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices?.getUserMedia || typeof RTCPeerConnection === 'undefined')\n throw new Error('Voice requires microphone access on HTTPS or localhost.');\n media = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true }, video: false });\n if (!current()) { media.getTracks().forEach(track => track.stop()); return; }\n media.getAudioTracks().forEach(track => { track.enabled = false; });\n this.update({ input: media });\n peer = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });\n audio = new Audio(); this.audio = audio; audio.autoplay = true;\n peer.ontrack = event => {\n if (!current()) return;\n const output = new MediaStream([event.track]);\n audio!.srcObject = output;\n this.update({ output }); void this.play();\n };\n peer.onconnectionstatechange = () => {\n ready();\n if (peer?.connectionState === 'disconnected') connectionLostAt ||= Date.now();\n else connectionLostAt = 0;\n if (peer?.connectionState === 'failed') void recover();\n };\n media.getTracks().forEach(track => peer!.addTrack(track, media!));\n channel = peer.createDataChannel('oai-events');\n channel.onmessage = message => {\n if (!current()) return;\n try {\n const event = JSON.parse(message.data);\n if (event.type === 'session.started') { backendReady = true; ready(); }\n if (['session.input_transcript.delta', 'session.output_transcript.delta'].includes(event.type) && typeof event.delta === 'string') {\n lastTranscript = Date.now(); this.lastActivity = lastTranscript;\n if (this.snapshot.idleEndsAt) this.update({ idleEndsAt: undefined });\n const role = event.type === 'session.input_transcript.delta' ? 'user' : 'assistant';\n const turns = this.snapshot.transcript.slice(-3).map(turn => ({ ...turn }));\n if (turns[turns.length - 1]?.role === role) turns[turns.length - 1].text = (turns[turns.length - 1].text + event.delta).slice(-2000);\n else turns.push({ role, text: event.delta.slice(-2000) });\n this.update({ transcript: turns });\n }\n if (event.type === 'session.closed' && sessionId) {\n void this.client.getLiveSessionStatus(this.assistantId, sessionId).then(state => {\n if (!current()) return;\n if (state.endReason) this.update({ endReason: state.endReason });\n if (state.restartRequested) void recover(); else void this.stop();\n }).catch(() => { if (current()) void this.stop(); });\n }\n if (event.type === 'error') { this.update({ error: new Error('Voice session failed.') }); void this.stop(); }\n } catch { /* Only lifecycle and spoken transcript events are accepted. */ }\n };\n channel.onclose = () => { if (current()) void recover(); };\n connectDeadline = setTimeout(() => {\n if (current()) { this.update({ error: new Error('Voice connection timed out.') }); void this.stop(); }\n }, 30000);\n await peer.setLocalDescription(await peer.createOffer());\n await new Promise<void>((resolve, reject) => {\n if (peer!.iceGatheringState === 'complete') return resolve();\n const done = () => {\n if (peer!.iceGatheringState !== 'complete') return;\n clearTimeout(timer); peer!.removeEventListener('icegatheringstatechange', done); resolve();\n };\n const timer = setTimeout(() => { peer!.removeEventListener('icegatheringstatechange', done); reject(new Error('Could not prepare the audio connection.')); }, 10000);\n peer!.addEventListener('icegatheringstatechange', done);\n });\n if (!current()) return;\n const result = await this.client.createLiveSession(this.assistantId, { ...this.context, chatUid, sdp: peer.localDescription!.sdp });\n sessionId = result.sessionId;\n if (!current()) { void this.client.closeLiveSession(this.assistantId, sessionId).catch(() => {}); return; }\n this.update({ sessionId, chatUid: result.chatUid, idleTimeoutSeconds: result.idleTimeoutSeconds || 0 }); this.created(result.chatUid);\n deadline = setTimeout(() => { void this.stop(); }, Math.max(1, Math.min(6000, result.maxDurationSeconds || 6000)) * 1000);\n await peer.setRemoteDescription({ type: 'answer', sdp: result.sdp });\n let busy = false;\n health = setInterval(async () => {\n if (!current() || busy) return;\n busy = true;\n try {\n const state = await this.client.getLiveSessionStatus(this.assistantId, sessionId!);\n if (!current()) return;\n healthFailures = 0;\n this.update({ seconds: state.seconds });\n // The server ends a silent call at idleTimeoutSeconds; warn for the\n // last 30 s (or half the window when it is short) so the person can\n // say \"I'm here\" instead of losing the call.\n const idle = this.snapshot.idleTimeoutSeconds || 0;\n if (idle > 0 && this.snapshot.state === 'connected') {\n const endsAt = this.lastActivity + idle * 1000;\n const warn = Date.now() >= endsAt - Math.min(30000, idle * 500);\n if (warn ? this.snapshot.idleEndsAt !== endsAt : !!this.snapshot.idleEndsAt) this.update({ idleEndsAt: warn ? endsAt : undefined });\n }\n if (state.interrupted || state.restartRequested || (connectionLostAt && Date.now() - connectionLostAt > 5000)) { void recover(); return; }\n if (state.status === 'closed') { void this.stop(); return; }\n backendReady = state.connected; ready();\n if (Date.now() - lastTranscript > 1500 && state.transcript?.length)\n this.update({ transcript: state.transcript.slice(-4).filter(t => t.role === 'user' || t.role === 'assistant').map(t => ({ role: t.role, text: t.text.slice(-2000) })) });\n } catch {\n if (current() && ++healthFailures >= 5) { this.update({ error: new Error('Voice status unavailable. Session stopped.')} ); void this.stop(); }\n } finally { busy = false; }\n }, 1000);\n } catch (error) {\n if (!current()) return;\n this.update({ error: error instanceof Error ? error : new Error(String(error)) });\n await this.stop();\n }\n }\n stop(): Promise<void> {\n if (this.closing) return this.closing;\n ++this.generation;\n this.disposeTransport();\n const id = this.snapshot.sessionId;\n this.update({ state: id ? 'closing' : (this.snapshot.error ? 'error' : 'idle') });\n this.closing = (async () => {\n if (id) {\n try { await this.client.closeLiveSession(this.assistantId, id); }\n catch (error) { this.update({ error: error as Error }); }\n }\n this.update({ state: this.snapshot.error ? 'error' : 'idle', sessionId: undefined });\n })().finally(() => { this.closing = undefined; });\n return this.closing;\n }\n dispose() { this.disposed = true; void this.stop(); }\n}\n"],"names":[],"mappings":"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"}
@@ -85,7 +85,8 @@ export declare class DevicApiClient {
85
85
  private request;
86
86
  private liveRequest;
87
87
  createLiveSession(assistantId: string, body: CreateLiveSessionRequest): Promise<LiveVoiceSession>;
88
- getLiveSessionStatus(assistantId: string, sessionId: string): Promise<LiveVoiceSessionStatus>;
88
+ /** `touch`: the person confirmed they are still on the call; the server restarts its idle clock. */
89
+ getLiveSessionStatus(assistantId: string, sessionId: string, touch?: boolean): Promise<LiveVoiceSessionStatus>;
89
90
  closeLiveSession(assistantId: string, sessionId: string): Promise<{
90
91
  closing: boolean;
91
92
  chatUid: string;
@@ -184,8 +184,9 @@ class DevicApiClient {
184
184
  method: 'POST', body: JSON.stringify(body),
185
185
  });
186
186
  }
187
- getLiveSessionStatus(assistantId, sessionId) {
188
- return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}`);
187
+ /** `touch`: the person confirmed they are still on the call; the server restarts its idle clock. */
188
+ getLiveSessionStatus(assistantId, sessionId, touch = false) {
189
+ return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}${touch ? '?touch=1' : ''}`);
189
190
  }
190
191
  closeLiveSession(assistantId, sessionId) {
191
192
  return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}`, { method: 'DELETE', keepalive: true });