@absolutejs/voice 0.0.22-beta.655 → 0.0.22-beta.657

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.
@@ -100,48 +100,89 @@ var createMicrophoneCapture = (options) => {
100
100
  let sourceNode = null;
101
101
  let processorNode = null;
102
102
  let mediaStream = null;
103
- const start = async () => {
104
- if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
105
- throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
106
- }
107
- const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
108
- if (!AudioContextCtor) {
109
- throw new Error("Browser microphone capture requires AudioContext support.");
110
- }
111
- try {
112
- mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
113
- audio: {
114
- autoGainControl: true,
115
- channelCount: options.channelCount ?? 1,
116
- echoCancellation: true,
117
- noiseSuppression: true
103
+ let lifecycleGeneration = 0;
104
+ let startPromise = null;
105
+ const release = (resources) => {
106
+ resources.processorNode?.disconnect();
107
+ resources.sourceNode?.disconnect();
108
+ resources.mediaStream?.getTracks().forEach((track) => track.stop());
109
+ resources.audioContext?.close();
110
+ };
111
+ const start = () => {
112
+ if (mediaStream)
113
+ return Promise.resolve();
114
+ if (startPromise)
115
+ return startPromise;
116
+ const generation = ++lifecycleGeneration;
117
+ const operation = async () => {
118
+ if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
119
+ throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
120
+ }
121
+ const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
122
+ if (!AudioContextCtor) {
123
+ throw new Error("Browser microphone capture requires AudioContext support.");
124
+ }
125
+ let pendingAudioContext = null;
126
+ let pendingMediaStream = null;
127
+ let pendingProcessorNode = null;
128
+ let pendingSourceNode = null;
129
+ try {
130
+ pendingMediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
131
+ audio: {
132
+ autoGainControl: true,
133
+ channelCount: options.channelCount ?? 1,
134
+ echoCancellation: true,
135
+ noiseSuppression: true
136
+ }
137
+ });
138
+ if (generation !== lifecycleGeneration) {
139
+ throw new Error("Microphone capture stopped during startup.");
118
140
  }
119
- });
120
- audioContext = new AudioContextCtor;
121
- if (audioContext.state === "suspended") {
122
- await audioContext.resume();
141
+ pendingAudioContext = new AudioContextCtor;
142
+ if (pendingAudioContext.state === "suspended") {
143
+ await pendingAudioContext.resume();
144
+ }
145
+ if (generation !== lifecycleGeneration) {
146
+ throw new Error("Microphone capture stopped during startup.");
147
+ }
148
+ pendingSourceNode = pendingAudioContext.createMediaStreamSource(pendingMediaStream);
149
+ pendingProcessorNode = pendingAudioContext.createScriptProcessor(4096, 1, 1);
150
+ pendingProcessorNode.onaudioprocess = (event) => {
151
+ const channel = event.inputBuffer.getChannelData(0);
152
+ const downsampled = downsampleBuffer(channel, pendingAudioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
153
+ const pcm = floatTo16BitPCM(downsampled);
154
+ options.onLevel?.(getPcmLevel(pcm));
155
+ options.onAudio(pcm);
156
+ };
157
+ pendingSourceNode.connect(pendingProcessorNode);
158
+ pendingProcessorNode.connect(pendingAudioContext.destination);
159
+ if (generation !== lifecycleGeneration) {
160
+ throw new Error("Microphone capture stopped during startup.");
161
+ }
162
+ audioContext = pendingAudioContext;
163
+ mediaStream = pendingMediaStream;
164
+ processorNode = pendingProcessorNode;
165
+ sourceNode = pendingSourceNode;
166
+ } catch (error) {
167
+ release({
168
+ audioContext: pendingAudioContext,
169
+ mediaStream: pendingMediaStream,
170
+ processorNode: pendingProcessorNode,
171
+ sourceNode: pendingSourceNode
172
+ });
173
+ throw error;
123
174
  }
124
- sourceNode = audioContext.createMediaStreamSource(mediaStream);
125
- processorNode = audioContext.createScriptProcessor(4096, 1, 1);
126
- processorNode.onaudioprocess = (event) => {
127
- const channel = event.inputBuffer.getChannelData(0);
128
- const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
129
- const pcm = floatTo16BitPCM(downsampled);
130
- options.onLevel?.(getPcmLevel(pcm));
131
- options.onAudio(pcm);
132
- };
133
- sourceNode.connect(processorNode);
134
- processorNode.connect(audioContext.destination);
135
- } catch (error) {
136
- stop();
137
- throw error;
138
- }
175
+ };
176
+ const pending = operation().finally(() => {
177
+ if (startPromise === pending)
178
+ startPromise = null;
179
+ });
180
+ startPromise = pending;
181
+ return pending;
139
182
  };
140
183
  const stop = () => {
141
- processorNode?.disconnect();
142
- sourceNode?.disconnect();
143
- mediaStream?.getTracks().forEach((track) => track.stop());
144
- audioContext?.close();
184
+ lifecycleGeneration += 1;
185
+ release({ audioContext, mediaStream, processorNode, sourceNode });
145
186
  options.onLevel?.(0);
146
187
  audioContext = null;
147
188
  mediaStream = null;
@@ -502,11 +543,19 @@ var DEFAULT_MAX_RECONNECT_ATTEMPTS = 15;
502
543
  var DEFAULT_PING_INTERVAL = 30000;
503
544
  var DEFAULT_RECONNECT_RESET_AFTER_MS = 30000;
504
545
  var DEFAULT_CALL_CONTROL_ACK_TIMEOUT_MS = 5000;
546
+ var DEFAULT_PREPARE_RECONNECT_TIMEOUT_MS = 1e4;
505
547
  var MAX_PENDING_CONTROL_MESSAGES = 100;
506
548
  var RECONNECT_BASE_DELAY_MS = 500;
507
549
  var DEFAULT_RECONNECT_MAX_DELAY_MS = 8000;
508
550
  var computeVoiceReconnectDelayMs = (attempt, baseMs, maxDelayMs) => Math.min(maxDelayMs, baseMs * 2 ** (Math.max(1, attempt) - 1));
509
551
  var DEFAULT_SCENARIO_QUERY_PARAM = "scenarioId";
552
+
553
+ class VoiceReconnectRejectedError extends Error {
554
+ constructor(message = "Voice authorization could not be renewed.") {
555
+ super(message);
556
+ this.name = "VoiceReconnectRejectedError";
557
+ }
558
+ }
510
559
  var noop = () => {};
511
560
  var noopAsync = () => Promise.resolve();
512
561
  var noopUnsubscribe = () => noop;
@@ -586,6 +635,9 @@ var createVoiceConnection = (path, options = {}) => {
586
635
  const reconnectMaxDelayMs = options.reconnectMaxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS;
587
636
  const pingInterval = options.pingInterval ?? DEFAULT_PING_INTERVAL;
588
637
  const reconnectResetAfterMs = options.reconnectResetAfterMs ?? DEFAULT_RECONNECT_RESET_AFTER_MS;
638
+ let lifecycleGeneration = 0;
639
+ let disposed = false;
640
+ let reconnectPreparationAbort = null;
589
641
  const computeReconnectDelayMs = (attempt) => computeVoiceReconnectDelayMs(attempt, RECONNECT_BASE_DELAY_MS, reconnectMaxDelayMs);
590
642
  const state = {
591
643
  isConnected: false,
@@ -649,6 +701,9 @@ var createVoiceConnection = (path, options = {}) => {
649
701
  pendingCallControls.clear();
650
702
  };
651
703
  const scheduleReconnect = () => {
704
+ if (disposed)
705
+ return;
706
+ const scheduledGeneration = lifecycleGeneration;
652
707
  state.reconnectAttempts += 1;
653
708
  const delayMs = computeReconnectDelayMs(state.reconnectAttempts);
654
709
  const nextAttemptAt = Date.now() + delayMs;
@@ -663,18 +718,44 @@ var createVoiceConnection = (path, options = {}) => {
663
718
  type: "connection"
664
719
  });
665
720
  state.reconnectTimeout = setTimeout(async () => {
721
+ if (disposed || lifecycleGeneration !== scheduledGeneration)
722
+ return;
666
723
  if (state.reconnectAttempts > maxReconnectAttempts) {
667
724
  emitTerminalFailure("Voice connection could not be restored.");
668
725
  return;
669
726
  }
670
727
  try {
671
- await options.prepareReconnect?.({
672
- attempt: state.reconnectAttempts,
673
- path,
674
- scenarioId: state.scenarioId,
675
- sessionId: state.sessionId
676
- });
677
- } catch {
728
+ if (options.prepareReconnect) {
729
+ const preparationAbort = new AbortController;
730
+ reconnectPreparationAbort = preparationAbort;
731
+ const timeout = setTimeout(() => preparationAbort.abort("Voice reconnect preparation timed out"), options.prepareReconnectTimeoutMs ?? DEFAULT_PREPARE_RECONNECT_TIMEOUT_MS);
732
+ try {
733
+ await Promise.race([
734
+ options.prepareReconnect({
735
+ attempt: state.reconnectAttempts,
736
+ path,
737
+ scenarioId: state.scenarioId,
738
+ sessionId: state.sessionId,
739
+ signal: preparationAbort.signal
740
+ }),
741
+ new Promise((_, reject) => {
742
+ preparationAbort.signal.addEventListener("abort", () => reject(new Error("Voice reconnect preparation timed out.")), { once: true });
743
+ })
744
+ ]);
745
+ } finally {
746
+ clearTimeout(timeout);
747
+ if (reconnectPreparationAbort === preparationAbort) {
748
+ reconnectPreparationAbort = null;
749
+ }
750
+ }
751
+ }
752
+ } catch (error) {
753
+ if (disposed || lifecycleGeneration !== scheduledGeneration)
754
+ return;
755
+ if (error instanceof VoiceReconnectRejectedError) {
756
+ emitTerminalFailure(error.message);
757
+ return;
758
+ }
678
759
  if (state.reconnectAttempts < maxReconnectAttempts) {
679
760
  scheduleReconnect();
680
761
  } else {
@@ -682,10 +763,14 @@ var createVoiceConnection = (path, options = {}) => {
682
763
  }
683
764
  return;
684
765
  }
766
+ if (disposed || lifecycleGeneration !== scheduledGeneration)
767
+ return;
685
768
  connect();
686
769
  }, delayMs);
687
770
  };
688
771
  const connect = () => {
772
+ if (disposed)
773
+ return;
689
774
  const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId, options.query ?? {}));
690
775
  ws.binaryType = "arraybuffer";
691
776
  ws.onopen = () => {
@@ -756,6 +841,7 @@ var createVoiceConnection = (path, options = {}) => {
756
841
  state.ws = null;
757
842
  state.isConnected = false;
758
843
  clearTimers();
844
+ rejectPendingCallControls("Voice connection interrupted");
759
845
  const reconnectable = shouldReconnect && event.code !== WS_NORMAL_CLOSURE && event.code !== WS_UNAUTHORIZED && event.code !== WS_FORBIDDEN && state.reconnectAttempts < maxReconnectAttempts;
760
846
  const authorizationFailure = event.code === WS_UNAUTHORIZED || event.code === WS_FORBIDDEN;
761
847
  if (authorizationFailure) {
@@ -786,6 +872,8 @@ var createVoiceConnection = (path, options = {}) => {
786
872
  state.ws = ws;
787
873
  };
788
874
  const sendSerialized = (value) => {
875
+ if (disposed)
876
+ return;
789
877
  if (state.ws?.readyState === WS_OPEN) {
790
878
  state.ws.send(value);
791
879
  return;
@@ -821,6 +909,9 @@ var createVoiceConnection = (path, options = {}) => {
821
909
  send({ type: "end_turn" });
822
910
  };
823
911
  const callControl = (message) => {
912
+ if (state.ws?.readyState !== WS_OPEN) {
913
+ return Promise.reject(new Error(`${message.action} is unavailable while disconnected`));
914
+ }
824
915
  const requestId = crypto.randomUUID();
825
916
  const { promise, reject, resolve } = Promise.withResolvers();
826
917
  const timeout = setTimeout(() => {
@@ -828,16 +919,21 @@ var createVoiceConnection = (path, options = {}) => {
828
919
  reject(new Error(`${message.action} acknowledgement timed out`));
829
920
  }, DEFAULT_CALL_CONTROL_ACK_TIMEOUT_MS);
830
921
  pendingCallControls.set(requestId, { reject, resolve, timeout });
831
- send({
922
+ state.ws.send(JSON.stringify({
832
923
  ...message,
833
924
  requestId,
834
925
  type: "call_control"
835
- });
926
+ }));
836
927
  return promise;
837
928
  };
838
929
  const close = (reason = "client-close") => {
930
+ disposed = true;
931
+ reconnectPreparationAbort?.abort();
932
+ reconnectPreparationAbort = null;
933
+ lifecycleGeneration += 1;
839
934
  clearTimers();
840
935
  rejectPendingCallControls("Voice connection closed");
936
+ state.pendingMessages.length = 0;
841
937
  if (state.ws) {
842
938
  const ws = state.ws;
843
939
  state.ws = null;
@@ -850,8 +946,13 @@ var createVoiceConnection = (path, options = {}) => {
850
946
  listeners.clear();
851
947
  };
852
948
  const disconnect = () => {
949
+ disposed = true;
950
+ reconnectPreparationAbort?.abort();
951
+ reconnectPreparationAbort = null;
952
+ lifecycleGeneration += 1;
853
953
  clearTimers();
854
954
  rejectPendingCallControls("Voice connection disconnected");
955
+ state.pendingMessages.length = 0;
855
956
  if (state.ws) {
856
957
  const ws = state.ws;
857
958
  state.ws = null;
@@ -1099,7 +1200,10 @@ var createVoiceStream = (path, options = {}) => {
1099
1200
  getSessionId: () => options.browserMedia ? options.browserMedia.getSessionId?.() ?? connection.getSessionId() : connection.getSessionId()
1100
1201
  }) : null;
1101
1202
  const subscribers = new Set;
1203
+ let disposed = false;
1102
1204
  const start = (input) => Promise.resolve().then(() => {
1205
+ if (disposed)
1206
+ return;
1103
1207
  if (!input?.sessionId && !input?.scenarioId) {
1104
1208
  return;
1105
1209
  }
@@ -1158,6 +1262,7 @@ var createVoiceStream = (path, options = {}) => {
1158
1262
  return connection.callControl(message);
1159
1263
  },
1160
1264
  close(reason) {
1265
+ disposed = true;
1161
1266
  unsubscribeConnection();
1162
1267
  browserMediaReporter?.close();
1163
1268
  connection.close(reason);
@@ -1165,6 +1270,7 @@ var createVoiceStream = (path, options = {}) => {
1165
1270
  notify();
1166
1271
  },
1167
1272
  disconnect() {
1273
+ disposed = true;
1168
1274
  unsubscribeConnection();
1169
1275
  browserMediaReporter?.close();
1170
1276
  connection.disconnect();
@@ -1531,6 +1637,9 @@ var createVoiceController = (path, options = {}) => {
1531
1637
  ...options.connection
1532
1638
  });
1533
1639
  let capture = null;
1640
+ let captureGeneration = 0;
1641
+ let disposed = false;
1642
+ let startRecordingPromise = null;
1534
1643
  let state = createInitialState2(stream);
1535
1644
  const subscribers = new Set;
1536
1645
  const notify = () => {
@@ -1587,6 +1696,7 @@ var createVoiceController = (path, options = {}) => {
1587
1696
  return capture;
1588
1697
  };
1589
1698
  const stopRecording = () => {
1699
+ captureGeneration += 1;
1590
1700
  capture?.stop();
1591
1701
  capture = null;
1592
1702
  state = {
@@ -1596,39 +1706,63 @@ var createVoiceController = (path, options = {}) => {
1596
1706
  notify();
1597
1707
  };
1598
1708
  const startRecording = async () => {
1709
+ if (disposed) {
1710
+ throw new Error("Voice controller is closed.");
1711
+ }
1599
1712
  if (state.isRecording) {
1600
1713
  return;
1601
1714
  }
1602
- try {
1603
- state = {
1604
- ...state,
1605
- recordingError: null
1606
- };
1607
- notify();
1608
- await ensureCapture().start();
1609
- state = {
1610
- ...state,
1611
- isRecording: true
1612
- };
1613
- notify();
1614
- } catch (error) {
1615
- capture?.stop();
1616
- capture = null;
1617
- state = {
1618
- ...state,
1619
- isRecording: false,
1620
- recordingError: error instanceof Error ? error.message : String(error)
1621
- };
1622
- notify();
1623
- throw error;
1624
- }
1715
+ if (startRecordingPromise)
1716
+ return startRecordingPromise;
1717
+ const generation = ++captureGeneration;
1718
+ const activeCapture = ensureCapture();
1719
+ const operation = (async () => {
1720
+ try {
1721
+ state = {
1722
+ ...state,
1723
+ recordingError: null
1724
+ };
1725
+ notify();
1726
+ await activeCapture.start();
1727
+ if (disposed || generation !== captureGeneration || capture !== activeCapture) {
1728
+ activeCapture.stop();
1729
+ return;
1730
+ }
1731
+ state = {
1732
+ ...state,
1733
+ isRecording: true
1734
+ };
1735
+ notify();
1736
+ } catch (error) {
1737
+ activeCapture.stop();
1738
+ if (generation !== captureGeneration || capture !== activeCapture) {
1739
+ throw error;
1740
+ }
1741
+ capture = null;
1742
+ state = {
1743
+ ...state,
1744
+ isRecording: false,
1745
+ recordingError: error instanceof Error ? error.message : String(error)
1746
+ };
1747
+ notify();
1748
+ throw error;
1749
+ }
1750
+ })();
1751
+ const pending = operation.finally(() => {
1752
+ if (startRecordingPromise === pending)
1753
+ startRecordingPromise = null;
1754
+ });
1755
+ startRecordingPromise = pending;
1756
+ return startRecordingPromise;
1625
1757
  };
1626
1758
  const close = (reason) => {
1759
+ disposed = true;
1627
1760
  unsubscribeStream();
1628
1761
  stopRecording();
1629
1762
  stream.close(reason);
1630
1763
  };
1631
1764
  const disconnect = () => {
1765
+ disposed = true;
1632
1766
  unsubscribeStream();
1633
1767
  stopRecording();
1634
1768
  stream.disconnect();
@@ -1,10 +1,10 @@
1
- (()=>{var{defineProperty:x,getOwnPropertyNames:L0,getOwnPropertyDescriptor:G0}=Object,W0=Object.prototype.hasOwnProperty;function D0(g){return this[g]}var S0=(g)=>{var A=(f??=new WeakMap).get(g),C;if(A)return A;if(A=x({},"__esModule",{value:!0}),g&&typeof g==="object"||typeof g==="function"){for(var V of L0(g))if(!W0.call(A,V))x(A,V,{get:D0.bind(g,V),enumerable:!(C=G0(g,V))||C.enumerable})}return f.set(g,A),A},f;var y0=(g)=>g;function X0(g,A){this[g]=y0.bind(null,A)}var O0=(g,A)=>{for(var C in A)x(g,C,{get:A[C],enumerable:!0,configurable:!0,set:X0.bind(A,C)})};var e0={};O0(e0,{mount:()=>c0,default:()=>gg,VOICE_EMBED_VERSION:()=>_0});var J0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},Y0=(g,A,C,V)=>{let T=A??g.getAttribute("hx-get")??"";if(!T)return"";let c=new URL(T,window.location.origin);if(V)c.searchParams.set(C,V);else c.searchParams.delete(C);return`${c.pathname}${c.search}${c.hash}`},d=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=J0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",T=A.sessionQueryParam??"sessionId",c=()=>{let I=window,G=Y0(C,A.route,T,g.sessionId);if(G)C.setAttribute("hx-get",G);I.htmx?.process?.(C),I.htmx?.trigger?.(C,V)},U=g.subscribe(c);return c(),()=>{U()}};var Z0=(g)=>Math.max(-1,Math.min(1,g)),h0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=Z0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},w0=(g)=>{let A=g instanceof Uint8Array?g:new Uint8Array(g);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let V=0;for(let T of C){let c=T/32768;V+=c*c}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},Q0=(g,A,C)=>{if(A===C)return g;let V=A/C,T=Math.round(g.length/V),c=new Float32Array(T),U=0,I=0;while(U<c.length){let G=Math.round((U+1)*V),W=0,_=0;for(let L=I;L<G&&L<g.length;L+=1)W+=g[L]??0,_+=1;c[U]=_>0?W/_:0,U+=1,I=G}return c},l=(g)=>{let A=null,C=null,V=null,T=null,c=async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let I=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!I)throw Error("Browser microphone capture requires AudioContext support.");try{if(T=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new I,A.state==="suspended")await A.resume();C=A.createMediaStreamSource(T),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=(G)=>{let W=G.inputBuffer.getChannelData(0),_=Q0(W,A?.sampleRate??48000,g.sampleRateHz??16000),L=h0(_);g.onLevel?.(w0(L)),g.onAudio(L)},C.connect(V),V.connect(A.destination)}catch(G){throw U(),G}},U=()=>{V?.disconnect(),C?.disconnect(),T?.getTracks().forEach((I)=>I.stop()),A?.close(),g.onLevel?.(0),A=null,T=null,V=null,C=null};return{start:c,stop:U}};var k=(g)=>{if(typeof g==="string"&&g.trim())return g;if(g instanceof Error&&g.message.trim())return g.message;if(g&&typeof g==="object"){let A=g;for(let C of["message","reason","description"]){let V=A[C];if(typeof V==="string"&&V.trim())return V}if("error"in A)return k(A.error);if("cause"in A)return k(A.cause);try{return JSON.stringify(g)}catch{}}return"Unexpected error"},v=(g)=>{switch(g.type){case"audio":return{chunk:Uint8Array.from(atob(g.chunkBase64),(A)=>A.charCodeAt(0)),format:g.format,receivedAt:g.receivedAt,turnId:g.turnId,type:"audio"};case"assistant":return{text:g.text,turnId:g.turnId,type:"assistant"};case"assistant_delta":return{delta:g.delta,turnId:g.turnId,type:"assistant_delta"};case"complete":return{sessionId:g.sessionId,type:"complete"};case"connection":return{reconnect:g.reconnect,type:"connection"};case"call_lifecycle":return{event:g.event,sessionId:g.sessionId,type:"call_lifecycle"};case"error":return{message:k(g.message),recoverable:g.recoverable,type:"error"};case"call_control_ack":return null;case"final":return{transcript:g.transcript,type:"final"};case"partial":return{transcript:g.transcript,type:"partial"};case"replay":return{assistantTexts:g.assistantTexts,call:g.call,partial:g.partial,scenarioId:g.scenarioId,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,status:g.status,turns:g.turns,type:"replay"};case"session":return{sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,type:"session"};case"turn":return{turn:g.turn,type:"turn"};default:return null}};var _g=Math.PI*2;var P=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var P0=(g)=>g.length===0?void 0:g.reduce((A,C)=>A+C,0)/g.length,M=(g)=>g.length===0?void 0:Math.max(...g);var X=(g,A)=>{let C=g[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},B=(g,A)=>{let C=g[A];return typeof C==="boolean"?C:void 0},J=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},F=(g)=>String(g.id??J(g,"ssrc")??X(g,"ssrc")??J(g,"trackIdentifier")??J(g,"mid")??"unknown"),i=(g)=>g===void 0?void 0:g*1000;var K0=(g)=>{let A={};for(let[C,V]of Object.entries(g))if(V===null||typeof V==="boolean"||typeof V==="number"||typeof V==="string")A[C]=V;return A};var n=(g={})=>{let A=g.stats??[],C=[],V=A.filter((R)=>R.type==="inbound-rtp"&&J(R,"kind")!=="video"),T=A.filter((R)=>R.type==="outbound-rtp"&&J(R,"kind")!=="video"),c=A.filter((R)=>R.type==="candidate-pair"),U=A.filter((R)=>(R.type==="track"||R.type==="media-source")&&J(R,"kind")==="audio"),I=c.filter((R)=>B(R,"selected")===!0||B(R,"nominated")===!0||J(R,"state")==="succeeded").length,G=U.filter((R)=>J(R,"readyState")!=="ended"&&J(R,"trackState")!=="ended"&&B(R,"ended")!==!0).length,W=U.filter((R)=>J(R,"readyState")==="ended"||J(R,"trackState")==="ended"||B(R,"ended")===!0).length,_=V.reduce((R,O)=>R+(X(O,"packetsReceived")??0),0),L=T.reduce((R,O)=>R+(X(O,"packetsSent")??0),0),H=[...V,...T].reduce((R,O)=>R+Math.max(0,X(O,"packetsLost")??0),0),Z=_+H,E=Z===0?0:H/Z,D=V.reduce((R,O)=>R+(X(O,"bytesReceived")??0),0),h=T.reduce((R,O)=>R+(X(O,"bytesSent")??0),0),w=M(c.map((R)=>i(X(R,"currentRoundTripTime")??X(R,"roundTripTime"))).filter((R)=>R!==void 0)),Q=M([...V,...T].map((R)=>i(X(R,"jitter"))).filter((R)=>R!==void 0)),N=M(V.map((R)=>{let O=X(R,"jitterBufferDelay"),b=X(R,"jitterBufferEmittedCount");return O!==void 0&&b!==void 0&&b>0?O/b*1000:void 0}).filter((R)=>R!==void 0)),z=U.map((R)=>X(R,"audioLevel")).filter((R)=>R!==void 0);if(g.requireConnectedCandidatePair&&c.length>0&&I===0)P(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&G===0)P(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&E>g.maxPacketLossRatio)P(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(E)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&w!==void 0&&w>g.maxRoundTripTimeMs)P(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(w)}ms above ${String(g.maxRoundTripTimeMs)}ms.`);if(g.maxJitterMs!==void 0&&Q!==void 0&&Q>g.maxJitterMs)P(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(Q)}ms above ${String(g.maxJitterMs)}ms.`);return{activeCandidatePairs:I,audioLevelAverage:P0(z),bytesReceived:D,bytesSent:h,checkedAt:Date.now(),endedAudioTracks:W,inboundPackets:_,issues:C,jitterBufferDelayMs:N,jitterMs:Q,liveAudioTracks:G,outboundPackets:L,packetLossRatio:E,packetsLost:H,roundTripTimeMs:w,status:C.some((R)=>R.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},o=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(K0)};var m=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],T=new Map(C.map((H)=>[F(H),H])),U=A.filter((H)=>(H.type==="inbound-rtp"||H.type==="outbound-rtp")&&J(H,"kind")!=="video"&&J(H,"mediaType")!=="video").map((H)=>{let Z=H.type==="outbound-rtp"?"outbound":"inbound",E=Z==="outbound"?"packetsSent":"packetsReceived",D=Z==="outbound"?"bytesSent":"bytesReceived",h=T.get(F(H)),w=X(H,E),Q=h?X(h,E):void 0,N=X(H,D),z=h?X(h,D):void 0,R=H.timestamp!==void 0&&h?.timestamp!==void 0?H.timestamp-h.timestamp:void 0;return{bytesDelta:N!==void 0&&z!==void 0?N-z:void 0,currentPackets:w,direction:Z,id:F(H),packetDelta:w!==void 0&&Q!==void 0?w-Q:void 0,previousPackets:Q,timeDeltaMs:R}}),I=U.filter((H)=>H.direction==="inbound"),G=U.filter((H)=>H.direction==="outbound"),W=M(U.map((H)=>H.timeDeltaMs).filter((H)=>H!==void 0)),_=I.filter((H)=>g.maxInboundPacketStallMs!==void 0&&H.timeDeltaMs!==void 0&&H.timeDeltaMs>=g.maxInboundPacketStallMs&&H.packetDelta!==void 0&&H.packetDelta<=0).length,L=G.filter((H)=>g.maxOutboundPacketStallMs!==void 0&&H.timeDeltaMs!==void 0&&H.timeDeltaMs>=g.maxOutboundPacketStallMs&&H.packetDelta!==void 0&&H.packetDelta<=0).length;if(g.requireInboundAudio&&I.length===0)P(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&G.length===0)P(V,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(g.maxGapMs!==void 0&&W!==void 0&&W>g.maxGapMs)P(V,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(W)}ms above ${String(g.maxGapMs)}ms.`);if(_>0)P(V,"error","media.webrtc_inbound_stalled",`${String(_)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(L>0)P(V,"error","media.webrtc_outbound_stalled",`${String(L)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:I.length,issues:V,maxObservedGapMs:W,outboundAudioStreams:G.length,stalledInboundStreams:_,stalledOutboundStreams:L,status:V.some((H)=>H.severity==="error")?"fail":V.length>0?"warn":"pass",streams:U,totalStats:A.length}};var E0="/api/voice/browser-media",N0=5000,q0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,z0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??E0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(g)=>{let A=null,C=[],V=async()=>{let U=await q0(g);if(!U)return;let I=await o({peerConnection:U}),G=n({...g,stats:I}),W=g.continuity===!1?void 0:m({...g.continuity,previousStats:C,stats:I}),_={at:Date.now(),continuity:W,report:G,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=I,g.onReport?.(_),await z0(_,g),_},T=()=>{V().catch((U)=>{g.onError?.(U)})},c=()=>{if(A)clearInterval(A),A=null};return{close:c,reportOnce:V,stop:c,start:()=>{if(A)return;T(),A=setInterval(T,g.intervalMs??N0)}}};var b0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));var q=()=>{},B0=()=>Promise.resolve(),M0=()=>q,j0={callControl:B0,close:q,disconnect:q,endTurn:q,send:q,sendAudio:q,simulateDisconnect:q,subscribe:M0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},x0=()=>crypto.randomUUID(),k0=(g,A,C,V)=>{let{hostname:T,port:c,protocol:U}=window.location,I=U==="https:"?"wss:":"ws:",G=c?`:${c}`:"",W=new URL(`${I}//${T}${G}${g}`);if(W.searchParams.set("sessionId",A),C)W.searchParams.set("scenarioId",C);for(let[_,L]of Object.entries(V))if(_!=="sessionId"&&_!=="scenarioId"&&L)W.searchParams.set(_,L);return W.toString()},F0=(g)=>{if(!g||typeof g!=="object"||!("type"in g))return!1;switch(g.type){case"audio":case"assistant":case"call_lifecycle":case"call_control_ack":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},f0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return F0(A)?A:null}catch{return null}},u=(g,A={})=>{if(typeof window>"u")return j0;let C=new Set,V=new Map,T=A.reconnect!==!1,c=A.maxReconnectAttempts??15,U=A.reconnectMaxDelayMs??8000,I=A.pingInterval??30000,G=A.reconnectResetAfterMs??30000,W=($)=>b0($,500,U),_={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:A.sessionId??x0(),ws:null},L=($)=>{C.forEach((S)=>S($))},H=($)=>{C.forEach((S)=>S({message:$,recoverable:!1,type:"error"})),L({reconnect:{attempts:_.reconnectAttempts,maxAttempts:c,status:"exhausted"},type:"connection"})},Z=()=>{if(_.pingInterval)clearInterval(_.pingInterval),_.pingInterval=null;if(_.reconnectTimeout)clearTimeout(_.reconnectTimeout),_.reconnectTimeout=null;if(_.reconnectResetTimeout)clearTimeout(_.reconnectResetTimeout),_.reconnectResetTimeout=null},E=()=>{if(_.ws?.readyState!==1)return;while(_.pendingMessages.length>0){let $=_.pendingMessages.shift();if($!==void 0)_.ws.send($)}},D=($)=>{for(let S of V.values())clearTimeout(S.timeout),S.reject(Error($));V.clear()},h=()=>{_.reconnectAttempts+=1;let $=W(_.reconnectAttempts),S=Date.now()+$;L({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,nextAttemptAt:S,status:"reconnecting"},type:"connection"}),_.reconnectTimeout=setTimeout(async()=>{if(_.reconnectAttempts>c){H("Voice connection could not be restored.");return}try{await A.prepareReconnect?.({attempt:_.reconnectAttempts,path:g,scenarioId:_.scenarioId,sessionId:_.sessionId})}catch{if(_.reconnectAttempts<c)h();else H("Voice authorization could not be renewed for reconnect.");return}w()},$)},w=()=>{let $=new WebSocket(k0(g,_.sessionId,_.scenarioId,A.query??{}));$.binaryType="arraybuffer",$.onopen=()=>{if(_.ws!==$){$.close(1000);return}let S=_.reconnectAttempts>0;if(_.isConnected=!0,E(),S)L({reconnect:{attempts:_.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:c,status:"resumed"},type:"connection"}),_.reconnectResetTimeout=setTimeout(()=>{if(_.ws===$&&$.readyState===1)_.reconnectAttempts=0;_.reconnectResetTimeout=null},G);C.forEach((y)=>y({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,status:"active",type:"session"})),_.pingInterval=setInterval(()=>{if($.readyState===1)$.send(JSON.stringify({type:"ping"}))},I)},$.onmessage=(S)=>{if(_.ws!==$)return;let y=f0(S);if(!y)return;if(y.type==="session")_.sessionId=y.sessionId,_.scenarioId=y.scenarioId??_.scenarioId;if(y.type==="call_control_ack"){let Y=V.get(y.requestId);if(Y)if(clearTimeout(Y.timeout),V.delete(y.requestId),y.ok)Y.resolve();else Y.reject(Error(y.message??`${y.action} was not applied`))}C.forEach((Y)=>Y(y))},$.onclose=(S)=>{if(_.ws!==$)return;_.ws=null,_.isConnected=!1,Z();let y=T&&S.code!==1000&&S.code!==4401&&S.code!==4403&&_.reconnectAttempts<c,Y=S.code===4401||S.code===4403;if(Y)C.forEach((j)=>j({message:S.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(y)h();else if(T&&S.code!==1000)if(Y)L({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,status:"exhausted"},type:"connection"});else H("Voice connection could not be restored.")},_.ws=$},Q=($)=>{if(_.ws?.readyState===1){_.ws.send($);return}if(typeof $!=="string")return;if(_.pendingMessages.length>=100)_.pendingMessages.shift();_.pendingMessages.push($)},N=($)=>{Q(JSON.stringify($))},z=($={})=>{if($.sessionId)_.sessionId=$.sessionId;if($.scenarioId)_.scenarioId=$.scenarioId;N({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,type:"start"})},R=($)=>{Q($)},O=()=>{N({type:"end_turn"})},b=($)=>{let S=crypto.randomUUID(),{promise:y,reject:Y,resolve:j}=Promise.withResolvers(),U0=setTimeout(()=>{V.delete(S),Y(Error(`${$.action} acknowledgement timed out`))},5000);return V.set(S,{reject:Y,resolve:j,timeout:U0}),N({...$,requestId:S,type:"call_control"}),y},R0=($="client-close")=>{if(Z(),D("Voice connection closed"),_.ws){let S=_.ws;if(_.ws=null,S.readyState===1)S.send(JSON.stringify({reason:$,type:"close"}));S.close(1000)}_.isConnected=!1,C.clear()},$0=()=>{if(Z(),D("Voice connection disconnected"),_.ws){let $=_.ws;_.ws=null,$.close(1000)}_.isConnected=!1,C.clear()},H0=()=>{if(_.ws?.readyState===1)_.ws.close(4000,"absolutejs-voice-reconnect-proof")},I0=($)=>{return C.add($),()=>{C.delete($)}};return w(),{callControl:b,close:R0,disconnect:$0,endTurn:O,send:N,sendAudio:R,simulateDisconnect:H0,start:z,subscribe:I0,getReadyState:()=>_.ws?.readyState??3,getScenarioId:()=>_.scenarioId??"",getSessionId:()=>_.sessionId}};var d0=()=>({attempts:0,maxAttempts:0,status:"idle"}),l0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return g;if(!g)return C;if(g===C||g.endsWith(C))return g;if(C.includes(g))return C;return`${g} ${C}`},v0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},i0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:d0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),s=()=>{let g=i0(),A="",C=new Set,V=()=>{C.forEach((c)=>c())};return{dispatch:(c)=>{switch(c.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:c.chunk,format:c.format,receivedAt:c.receivedAt,turnId:c.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,c.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${c.delta}`};break;case"complete":g={...g,sessionId:c.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:c.event.type==="end"?c.event.disposition:g.call?.disposition,endedAt:c.event.type==="end"?c.event.at:g.call?.endedAt,events:[...g.call?.events??[],c.event],lastEventAt:c.event.at,startedAt:g.call?.startedAt??c.event.at},sessionId:c.sessionId};break;case"connected":g={...g,isConnected:!0,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect};break;case"connection":g={...g,reconnect:c.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:c.message,...c.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":A=l0(A,c.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:v0(A,c.transcript.text)};break;case"replay":A=c.partial,g={...g,assistantStreamingText:"",assistantTexts:[...c.assistantTexts],call:c.call??null,error:null,isConnected:c.status==="active",partial:c.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:c.scenarioId??g.scenarioId,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata??g.sessionMetadata,status:c.status,turns:[...c.turns]};break;case"session":g={...g,error:null,scenarioId:c.scenarioId??g.scenarioId,isConnected:c.status==="active",sessionId:c.sessionId,sessionMetadata:c.sessionMetadata??g.sessionMetadata,status:c.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,c.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(c)=>{return C.add(c),()=>{C.delete(c)}}}};var a=(g,A={})=>{let C=u(g,A),V=s(),T=A.browserMedia&&typeof window<"u"?r({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,c=new Set,U=(_)=>Promise.resolve().then(()=>{if(!_?.sessionId&&!_?.scenarioId)return;C.start(_),T?.start()}),I=()=>{c.forEach((_)=>_())},G=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let _=V.getSnapshot(),L=JSON.stringify({at:Date.now(),reconnect:_.reconnect,scenarioId:_.scenarioId,sessionId:C.getSessionId(),turnIds:_.turns.map((H)=>H.id)});fetch(A.reconnectReportPath,{body:L,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},W=C.subscribe((_)=>{let L=v(_);if(L){if(V.dispatch(L),_.type==="connection")G();I()}});return{start:U,get assistantAudio(){return V.getSnapshot().assistantAudio},get assistantTexts(){return V.getSnapshot().assistantTexts},get assistantStreamingText(){return V.getSnapshot().assistantStreamingText},get call(){return V.getSnapshot().call},callControl(_){return C.callControl(_)},close(_){W(),T?.close(),C.close(_),V.dispatch({type:"disconnected"}),I()},disconnect(){W(),T?.close(),C.disconnect(),V.dispatch({type:"disconnected"}),I()},endTurn(){C.endTurn()},get error(){return V.getSnapshot().error},getServerSnapshot(){return V.getServerSnapshot()},getSnapshot(){return V.getSnapshot()},get isConnected(){return V.getSnapshot().isConnected},get partial(){return V.getSnapshot().partial},get reconnect(){return V.getSnapshot().reconnect},get scenarioId(){return V.getSnapshot().scenarioId},sendAudio(_){C.sendAudio(_)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(_){return c.add(_),()=>{c.delete(_)}},get turns(){return V.getSnapshot().turns}}};var p=(g)=>{if(!g||g.enabled===!1)return;return{enabled:!0,maxGain:g.maxGain??3,noiseGateAttenuation:g.noiseGateAttenuation??0.15,noiseGateThreshold:g.noiseGateThreshold??0.006,targetLevel:g.targetLevel??0.08}};var n0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},o0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var t=(g)=>{let A=g?.profile??"fast",C=g?.qualityProfile??"general",V=n0[A],T=o0[C],c=g?.silenceMs??T.silenceMs??V.silenceMs;return{profile:A,qualityProfile:C,minSilenceMs:Math.min(c,g?.minSilenceMs??T.minSilenceMs??V.minSilenceMs),silenceMs:c,speechThreshold:g?.speechThreshold??T.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??T.transcriptStabilityMs??V.transcriptStabilityMs}};var m0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},e=(g="default")=>{let A=m0[g];return{audioConditioning:p(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:t(A.turnDetection)}};var r0=(g)=>({assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,isRecording:!1,partial:g.partial,reconnect:g.reconnect,recordingError:null,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]}),g0=(g,A={})=>{let C=e(A.preset),V=a(g,{...C.connection,...A.connection}),T=null,c=r0(V),U=new Set,I=()=>{for(let D of U)D()},G=()=>{if(c={...c,assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,partial:V.partial,reconnect:V.reconnect,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]},A.autoStopOnComplete!==!1&&c.status==="completed"&&c.isRecording)T?.stop(),T=null,c={...c,isRecording:!1};I()},W=V.subscribe(G);G();let _=()=>{if(T)return T;return T=l({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(D)=>{if(A.capture?.onAudio){A.capture.onAudio(D,V.sendAudio);return}V.sendAudio(D)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),T},L=()=>{T?.stop(),T=null,c={...c,isRecording:!1},I()},H=async()=>{if(c.isRecording)return;try{c={...c,recordingError:null},I(),await _().start(),c={...c,isRecording:!0},I()}catch(D){throw T?.stop(),T=null,c={...c,isRecording:!1,recordingError:D instanceof Error?D.message:String(D)},I(),D}};return{close:(D)=>{W(),L(),V.close(D)},disconnect:()=>{W(),L(),V.disconnect()},startRecording:H,stopRecording:L,get assistantAudio(){return c.assistantAudio},get assistantTexts(){return c.assistantTexts},get assistantStreamingText(){return c.assistantStreamingText},bindHTMX(D){return d(V,D)},get call(){return c.call},callControl:(D)=>V.callControl(D),endTurn:()=>V.endTurn(),get error(){return c.error},getServerSnapshot:()=>c,getSnapshot:()=>c,get isConnected(){return c.isConnected},get isRecording(){return c.isRecording},get partial(){return c.partial},get reconnect(){return c.reconnect},get recordingError(){return c.recordingError},get scenarioId(){return c.scenarioId},sendAudio:(D)=>V.sendAudio(D),get sessionId(){return c.sessionId},get sessionMetadata(){return c.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return c.status},subscribe:(D)=>{return U.add(D),()=>{U.delete(D)}},toggleRecording:async()=>{if(c.isRecording){L();return}await H()},get turns(){return c.turns}}};var K=(g)=>String(g).replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;");var A0=(g)=>{if(!g.isConnected)return"idle";if(g.isPlaying)return"speaking";if(g.isRecording&&g.hasActivePartial)return"listening";if(g.isRecording)return"listening";if(g.lastTranscriptAt&&!g.lastAssistantAt)return"thinking";if(g.lastTranscriptAt&&g.lastAssistantAt&&g.lastTranscriptAt>g.lastAssistantAt)return"thinking";return"idle"};var u0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},s0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},a0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},V0=(g)=>{let A={...u0,...g.theme},C={...s0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,T=g.state.turns.at(-1)?.committedAt,c=A0({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:T}),U=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,I=g.state.error?"Error":U?C.connecting:g.state.status==="completed"?C.callEnded:a0(c,C);return{agentState:c,classes:{container:`absolute-voice-widget absolute-voice-widget--${c}`,dot:`absolute-voice-widget__dot${g.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:g.state.isConnected,canMute:g.state.isRecording,canStart:!g.state.isRecording&&g.state.status!=="completed"},errorMessage:g.state.error??void 0,labels:C,partial:g.state.partial||void 0,statusLabel:I,theme:A,title:g.title??"Voice"}},p0=(g)=>typeof g==="number"?`${g}px`:g,C0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${p0(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,V=`background:${g.errorMessage?A.errorAccent:g.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,T=[];if(g.controls.canStart)T.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.startCall)}</button>`);if(g.controls.canMute)T.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.mute)}</button>`);if(g.controls.canEnd)T.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${K(g.classes.container)}" style="${C}">
1
+ (()=>{var{defineProperty:x,getOwnPropertyNames:w0,getOwnPropertyDescriptor:J0}=Object,S0=Object.prototype.hasOwnProperty;function Y0(V){return this[V]}var Z0=(V)=>{var g=(l??=new WeakMap).get(V),C;if(g)return g;if(g=x({},"__esModule",{value:!0}),V&&typeof V==="object"||typeof V==="function"){for(var A of w0(V))if(!S0.call(g,A))x(g,A,{get:Y0.bind(V,A),enumerable:!(C=J0(V,A))||C.enumerable})}return l.set(V,g),g},l;var y0=(V)=>V;function h0(V,g){this[V]=y0.bind(null,g)}var Q0=(V,g)=>{for(var C in g)x(V,C,{get:g[C],enumerable:!0,configurable:!0,set:h0.bind(g,C)})};var _V={};Q0(_V,{mount:()=>$0,default:()=>TV,VOICE_EMBED_VERSION:()=>R0});var K0=(V)=>{if(typeof V!=="string")return V;return document.querySelector(V)},c0=(V,g,C,A)=>{let R=g??V.getAttribute("hx-get")??"";if(!R)return"";let _=new URL(R,window.location.origin);if(A)_.searchParams.set(C,A);else _.searchParams.delete(C);return`${_.pathname}${_.search}${_.hash}`},d=(V,g)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=K0(g.element);if(!C)return()=>{};let A=g.eventName??"voice-refresh",R=g.sessionQueryParam??"sessionId",_=()=>{let X=window,H=c0(C,g.route,R,V.sessionId);if(H)C.setAttribute("hx-get",H);X.htmx?.process?.(C),X.htmx?.trigger?.(C,A)},D=V.subscribe(_);return _(),()=>{D()}};var E0=(V)=>Math.max(-1,Math.min(1,V)),q0=(V)=>{let g=new Int16Array(V.length);for(let C=0;C<V.length;C+=1){let A=E0(V[C]??0);g[C]=A<0?A*32768:A*32767}return new Uint8Array(g.buffer)},z0=(V)=>{let g=V instanceof Uint8Array?V:new Uint8Array(V);if(g.byteLength<2)return 0;let C=new Int16Array(g.buffer,g.byteOffset,Math.floor(g.byteLength/2));if(C.length===0)return 0;let A=0;for(let R of C){let _=R/32768;A+=_*_}return Math.min(1,Math.max(0,Math.sqrt(A/C.length)*5.5))},N0=(V,g,C)=>{if(g===C)return V;let A=g/C,R=Math.round(V.length/A),_=new Float32Array(R),D=0,X=0;while(D<_.length){let H=Math.round((D+1)*A),O=0,L=0;for(let W=X;W<H&&W<V.length;W+=1)O+=V[W]??0,L+=1;_[D]=L>0?O/L:0,D+=1,X=H}return _},v=(V)=>{let g=null,C=null,A=null,R=null,_=0,D=null,X=(L)=>{L.processorNode?.disconnect(),L.sourceNode?.disconnect(),L.mediaStream?.getTracks().forEach((W)=>W.stop()),L.audioContext?.close()};return{start:()=>{if(R)return Promise.resolve();if(D)return D;let L=++_,I=(async()=>{if(!V.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let T=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!T)throw Error("Browser microphone capture requires AudioContext support.");let J=null,h=null,Z=null,Q=null;try{if(h=V.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:V.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),L!==_)throw Error("Microphone capture stopped during startup.");if(J=new T,J.state==="suspended")await J.resume();if(L!==_)throw Error("Microphone capture stopped during startup.");if(Q=J.createMediaStreamSource(h),Z=J.createScriptProcessor(4096,1,1),Z.onaudioprocess=(G)=>{let c=G.inputBuffer.getChannelData(0),q=N0(c,J?.sampleRate??48000,V.sampleRateHz??16000),$=q0(q);V.onLevel?.(z0($)),V.onAudio($)},Q.connect(Z),Z.connect(J.destination),L!==_)throw Error("Microphone capture stopped during startup.");g=J,R=h,A=Z,C=Q}catch(G){throw X({audioContext:J,mediaStream:h,processorNode:Z,sourceNode:Q}),G}})().finally(()=>{if(D===I)D=null});return D=I,I},stop:()=>{_+=1,X({audioContext:g,mediaStream:R,processorNode:A,sourceNode:C}),V.onLevel?.(0),g=null,R=null,A=null,C=null}}};var k=(V)=>{if(typeof V==="string"&&V.trim())return V;if(V instanceof Error&&V.message.trim())return V.message;if(V&&typeof V==="object"){let g=V;for(let C of["message","reason","description"]){let A=g[C];if(typeof A==="string"&&A.trim())return A}if("error"in g)return k(g.error);if("cause"in g)return k(g.cause);try{return JSON.stringify(V)}catch{}}return"Unexpected error"},i=(V)=>{switch(V.type){case"audio":return{chunk:Uint8Array.from(atob(V.chunkBase64),(g)=>g.charCodeAt(0)),format:V.format,receivedAt:V.receivedAt,turnId:V.turnId,type:"audio"};case"assistant":return{text:V.text,turnId:V.turnId,type:"assistant"};case"assistant_delta":return{delta:V.delta,turnId:V.turnId,type:"assistant_delta"};case"complete":return{sessionId:V.sessionId,type:"complete"};case"connection":return{reconnect:V.reconnect,type:"connection"};case"call_lifecycle":return{event:V.event,sessionId:V.sessionId,type:"call_lifecycle"};case"error":return{message:k(V.message),recoverable:V.recoverable,type:"error"};case"call_control_ack":return null;case"final":return{transcript:V.transcript,type:"final"};case"partial":return{transcript:V.transcript,type:"partial"};case"replay":return{assistantTexts:V.assistantTexts,call:V.call,partial:V.partial,scenarioId:V.scenarioId,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,status:V.status,turns:V.turns,type:"replay"};case"session":return{sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,type:"session"};case"turn":return{turn:V.turn,type:"turn"};default:return null}};var UV=Math.PI*2;var z=(V,g,C,A)=>{V.push({code:C,message:A,severity:g})};var P0=(V)=>V.length===0?void 0:V.reduce((g,C)=>g+C,0)/V.length,j=(V)=>V.length===0?void 0:Math.max(...V);var K=(V,g)=>{let C=V[g];return typeof C==="number"&&Number.isFinite(C)?C:void 0},b=(V,g)=>{let C=V[g];return typeof C==="boolean"?C:void 0},E=(V,g)=>{let C=V[g];return typeof C==="string"?C:void 0},F=(V)=>String(V.id??E(V,"ssrc")??K(V,"ssrc")??E(V,"trackIdentifier")??E(V,"mid")??"unknown"),o=(V)=>V===void 0?void 0:V*1000;var B0=(V)=>{let g={};for(let[C,A]of Object.entries(V))if(A===null||typeof A==="boolean"||typeof A==="number"||typeof A==="string")g[C]=A;return g};var n=(V={})=>{let g=V.stats??[],C=[],A=g.filter(($)=>$.type==="inbound-rtp"&&E($,"kind")!=="video"),R=g.filter(($)=>$.type==="outbound-rtp"&&E($,"kind")!=="video"),_=g.filter(($)=>$.type==="candidate-pair"),D=g.filter(($)=>($.type==="track"||$.type==="media-source")&&E($,"kind")==="audio"),X=_.filter(($)=>b($,"selected")===!0||b($,"nominated")===!0||E($,"state")==="succeeded").length,H=D.filter(($)=>E($,"readyState")!=="ended"&&E($,"trackState")!=="ended"&&b($,"ended")!==!0).length,O=D.filter(($)=>E($,"readyState")==="ended"||E($,"trackState")==="ended"||b($,"ended")===!0).length,L=A.reduce(($,S)=>$+(K(S,"packetsReceived")??0),0),W=R.reduce(($,S)=>$+(K(S,"packetsSent")??0),0),I=[...A,...R].reduce(($,S)=>$+Math.max(0,K(S,"packetsLost")??0),0),T=L+I,J=T===0?0:I/T,h=A.reduce(($,S)=>$+(K(S,"bytesReceived")??0),0),Z=R.reduce(($,S)=>$+(K(S,"bytesSent")??0),0),Q=j(_.map(($)=>o(K($,"currentRoundTripTime")??K($,"roundTripTime"))).filter(($)=>$!==void 0)),G=j([...A,...R].map(($)=>o(K($,"jitter"))).filter(($)=>$!==void 0)),c=j(A.map(($)=>{let S=K($,"jitterBufferDelay"),B=K($,"jitterBufferEmittedCount");return S!==void 0&&B!==void 0&&B>0?S/B*1000:void 0}).filter(($)=>$!==void 0)),q=D.map(($)=>K($,"audioLevel")).filter(($)=>$!==void 0);if(V.requireConnectedCandidatePair&&_.length>0&&X===0)z(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(V.requireLiveAudioTrack&&H===0)z(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(V.maxPacketLossRatio!==void 0&&J>V.maxPacketLossRatio)z(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(J)} above ${String(V.maxPacketLossRatio)}.`);if(V.maxRoundTripTimeMs!==void 0&&Q!==void 0&&Q>V.maxRoundTripTimeMs)z(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(Q)}ms above ${String(V.maxRoundTripTimeMs)}ms.`);if(V.maxJitterMs!==void 0&&G!==void 0&&G>V.maxJitterMs)z(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(G)}ms above ${String(V.maxJitterMs)}ms.`);return{activeCandidatePairs:X,audioLevelAverage:P0(q),bytesReceived:h,bytesSent:Z,checkedAt:Date.now(),endedAudioTracks:O,inboundPackets:L,issues:C,jitterBufferDelayMs:c,jitterMs:G,liveAudioTracks:H,outboundPackets:W,packetLossRatio:J,packetsLost:I,roundTripTimeMs:Q,status:C.some(($)=>$.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:g.length}},m=async(V)=>{return[...(await V.peerConnection.getStats(V.selector??null)).values()].map(B0)};var u=(V={})=>{let g=V.stats??[],C=V.previousStats??[],A=[],R=new Map(C.map((I)=>[F(I),I])),D=g.filter((I)=>(I.type==="inbound-rtp"||I.type==="outbound-rtp")&&E(I,"kind")!=="video"&&E(I,"mediaType")!=="video").map((I)=>{let T=I.type==="outbound-rtp"?"outbound":"inbound",J=T==="outbound"?"packetsSent":"packetsReceived",h=T==="outbound"?"bytesSent":"bytesReceived",Z=R.get(F(I)),Q=K(I,J),G=Z?K(Z,J):void 0,c=K(I,h),q=Z?K(Z,h):void 0,$=I.timestamp!==void 0&&Z?.timestamp!==void 0?I.timestamp-Z.timestamp:void 0;return{bytesDelta:c!==void 0&&q!==void 0?c-q:void 0,currentPackets:Q,direction:T,id:F(I),packetDelta:Q!==void 0&&G!==void 0?Q-G:void 0,previousPackets:G,timeDeltaMs:$}}),X=D.filter((I)=>I.direction==="inbound"),H=D.filter((I)=>I.direction==="outbound"),O=j(D.map((I)=>I.timeDeltaMs).filter((I)=>I!==void 0)),L=X.filter((I)=>V.maxInboundPacketStallMs!==void 0&&I.timeDeltaMs!==void 0&&I.timeDeltaMs>=V.maxInboundPacketStallMs&&I.packetDelta!==void 0&&I.packetDelta<=0).length,W=H.filter((I)=>V.maxOutboundPacketStallMs!==void 0&&I.timeDeltaMs!==void 0&&I.timeDeltaMs>=V.maxOutboundPacketStallMs&&I.packetDelta!==void 0&&I.packetDelta<=0).length;if(V.requireInboundAudio&&X.length===0)z(A,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(V.requireOutboundAudio&&H.length===0)z(A,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(V.maxGapMs!==void 0&&O!==void 0&&O>V.maxGapMs)z(A,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(O)}ms above ${String(V.maxGapMs)}ms.`);if(L>0)z(A,"error","media.webrtc_inbound_stalled",`${String(L)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(W>0)z(A,"error","media.webrtc_outbound_stalled",`${String(W)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:X.length,issues:A,maxObservedGapMs:O,outboundAudioStreams:H.length,stalledInboundStreams:L,stalledOutboundStreams:W,status:A.some((I)=>I.severity==="error")?"fail":A.length>0?"warn":"pass",streams:D,totalStats:g.length}};var M0="/api/voice/browser-media",b0=5000,j0=async(V)=>V.peerConnection??await V.getPeerConnection?.()??null,x0=async(V,g)=>{let C=g.fetch??globalThis.fetch;if(!C)return;await C(g.path??M0,{body:JSON.stringify(V),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(V)=>{let g=null,C=[],A=async()=>{let D=await j0(V);if(!D)return;let X=await m({peerConnection:D}),H=n({...V,stats:X}),O=V.continuity===!1?void 0:u({...V.continuity,previousStats:C,stats:X}),L={at:Date.now(),continuity:O,report:H,scenarioId:V.getScenarioId?.()??null,sessionId:V.getSessionId?.()??null};return C=X,V.onReport?.(L),await x0(L,V),L},R=()=>{A().catch((D)=>{V.onError?.(D)})},_=()=>{if(g)clearInterval(g),g=null};return{close:_,reportOnce:A,stop:_,start:()=>{if(g)return;R(),g=setInterval(R,V.intervalMs??b0)}}};var k0=(V,g,C)=>Math.min(C,g*2**(Math.max(1,V)-1));class s extends Error{constructor(V="Voice authorization could not be renewed."){super(V);this.name="VoiceReconnectRejectedError"}}var P=()=>{},F0=()=>Promise.resolve(),f0=()=>P,l0={callControl:F0,close:P,disconnect:P,endTurn:P,send:P,sendAudio:P,simulateDisconnect:P,subscribe:f0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},d0=()=>crypto.randomUUID(),v0=(V,g,C,A)=>{let{hostname:R,port:_,protocol:D}=window.location,X=D==="https:"?"wss:":"ws:",H=_?`:${_}`:"",O=new URL(`${X}//${R}${H}${V}`);if(O.searchParams.set("sessionId",g),C)O.searchParams.set("scenarioId",C);for(let[L,W]of Object.entries(A))if(L!=="sessionId"&&L!=="scenarioId"&&W)O.searchParams.set(L,W);return O.toString()},i0=(V)=>{if(!V||typeof V!=="object"||!("type"in V))return!1;switch(V.type){case"audio":case"assistant":case"call_lifecycle":case"call_control_ack":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},o0=(V)=>{if(typeof V.data!=="string")return null;try{let g=JSON.parse(V.data);return i0(g)?g:null}catch{return null}},a=(V,g={})=>{if(typeof window>"u")return l0;let C=new Set,A=new Map,R=g.reconnect!==!1,_=g.maxReconnectAttempts??15,D=g.reconnectMaxDelayMs??8000,X=g.pingInterval??30000,H=g.reconnectResetAfterMs??30000,O=0,L=!1,W=null,I=(U)=>k0(U,500,D),T={isConnected:!1,pendingMessages:[],scenarioId:g.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:g.sessionId??d0(),ws:null},J=(U)=>{C.forEach((w)=>w(U))},h=(U)=>{C.forEach((w)=>w({message:U,recoverable:!1,type:"error"})),J({reconnect:{attempts:T.reconnectAttempts,maxAttempts:_,status:"exhausted"},type:"connection"})},Z=()=>{if(T.pingInterval)clearInterval(T.pingInterval),T.pingInterval=null;if(T.reconnectTimeout)clearTimeout(T.reconnectTimeout),T.reconnectTimeout=null;if(T.reconnectResetTimeout)clearTimeout(T.reconnectResetTimeout),T.reconnectResetTimeout=null},Q=()=>{if(T.ws?.readyState!==1)return;while(T.pendingMessages.length>0){let U=T.pendingMessages.shift();if(U!==void 0)T.ws.send(U)}},G=(U)=>{for(let w of A.values())clearTimeout(w.timeout),w.reject(Error(U));A.clear()},c=()=>{if(L)return;let U=O;T.reconnectAttempts+=1;let w=I(T.reconnectAttempts),y=Date.now()+w;J({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,nextAttemptAt:y,status:"reconnecting"},type:"connection"}),T.reconnectTimeout=setTimeout(async()=>{if(L||O!==U)return;if(T.reconnectAttempts>_){h("Voice connection could not be restored.");return}try{if(g.prepareReconnect){let Y=new AbortController;W=Y;let M=setTimeout(()=>Y.abort("Voice reconnect preparation timed out"),g.prepareReconnectTimeoutMs??1e4);try{await Promise.race([g.prepareReconnect({attempt:T.reconnectAttempts,path:V,scenarioId:T.scenarioId,sessionId:T.sessionId,signal:Y.signal}),new Promise((f,O0)=>{Y.signal.addEventListener("abort",()=>O0(Error("Voice reconnect preparation timed out.")),{once:!0})})])}finally{if(clearTimeout(M),W===Y)W=null}}}catch(Y){if(L||O!==U)return;if(Y instanceof s){h(Y.message);return}if(T.reconnectAttempts<_)c();else h("Voice authorization could not be renewed for reconnect.");return}if(L||O!==U)return;q()},w)},q=()=>{if(L)return;let U=new WebSocket(v0(V,T.sessionId,T.scenarioId,g.query??{}));U.binaryType="arraybuffer",U.onopen=()=>{if(T.ws!==U){U.close(1000);return}let w=T.reconnectAttempts>0;if(T.isConnected=!0,Q(),w)J({reconnect:{attempts:T.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:_,status:"resumed"},type:"connection"}),T.reconnectResetTimeout=setTimeout(()=>{if(T.ws===U&&U.readyState===1)T.reconnectAttempts=0;T.reconnectResetTimeout=null},H);C.forEach((y)=>y({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,status:"active",type:"session"})),T.pingInterval=setInterval(()=>{if(U.readyState===1)U.send(JSON.stringify({type:"ping"}))},X)},U.onmessage=(w)=>{if(T.ws!==U)return;let y=o0(w);if(!y)return;if(y.type==="session")T.sessionId=y.sessionId,T.scenarioId=y.scenarioId??T.scenarioId;if(y.type==="call_control_ack"){let Y=A.get(y.requestId);if(Y)if(clearTimeout(Y.timeout),A.delete(y.requestId),y.ok)Y.resolve();else Y.reject(Error(y.message??`${y.action} was not applied`))}C.forEach((Y)=>Y(y))},U.onclose=(w)=>{if(T.ws!==U)return;T.ws=null,T.isConnected=!1,Z(),G("Voice connection interrupted");let y=R&&w.code!==1000&&w.code!==4401&&w.code!==4403&&T.reconnectAttempts<_,Y=w.code===4401||w.code===4403;if(Y)C.forEach((M)=>M({message:w.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(y)c();else if(R&&w.code!==1000)if(Y)J({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,status:"exhausted"},type:"connection"});else h("Voice connection could not be restored.")},T.ws=U},$=(U)=>{if(L)return;if(T.ws?.readyState===1){T.ws.send(U);return}if(typeof U!=="string")return;if(T.pendingMessages.length>=100)T.pendingMessages.shift();T.pendingMessages.push(U)},S=(U)=>{$(JSON.stringify(U))},B=(U={})=>{if(U.sessionId)T.sessionId=U.sessionId;if(U.scenarioId)T.scenarioId=U.scenarioId;S({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,type:"start"})},I0=(U)=>{$(U)},U0=()=>{S({type:"end_turn"})},L0=(U)=>{if(T.ws?.readyState!==1)return Promise.reject(Error(`${U.action} is unavailable while disconnected`));let w=crypto.randomUUID(),{promise:y,reject:Y,resolve:M}=Promise.withResolvers(),f=setTimeout(()=>{A.delete(w),Y(Error(`${U.action} acknowledgement timed out`))},5000);return A.set(w,{reject:Y,resolve:M,timeout:f}),T.ws.send(JSON.stringify({...U,requestId:w,type:"call_control"})),y},W0=(U="client-close")=>{if(L=!0,W?.abort(),W=null,O+=1,Z(),G("Voice connection closed"),T.pendingMessages.length=0,T.ws){let w=T.ws;if(T.ws=null,w.readyState===1)w.send(JSON.stringify({reason:U,type:"close"}));w.close(1000)}T.isConnected=!1,C.clear()},D0=()=>{if(L=!0,W?.abort(),W=null,O+=1,Z(),G("Voice connection disconnected"),T.pendingMessages.length=0,T.ws){let U=T.ws;T.ws=null,U.close(1000)}T.isConnected=!1,C.clear()},X0=()=>{if(T.ws?.readyState===1)T.ws.close(4000,"absolutejs-voice-reconnect-proof")},G0=(U)=>{return C.add(U),()=>{C.delete(U)}};return q(),{callControl:L0,close:W0,disconnect:D0,endTurn:U0,send:S,sendAudio:I0,simulateDisconnect:X0,start:B,subscribe:G0,getReadyState:()=>T.ws?.readyState??3,getScenarioId:()=>T.scenarioId??"",getSessionId:()=>T.sessionId}};var n0=()=>({attempts:0,maxAttempts:0,status:"idle"}),m0=(V,g)=>{let C=g.trim().replace(/\s+/g," ");if(!C)return V;if(!V)return C;if(V===C||V.endsWith(C))return V;if(C.includes(V))return C;return`${V} ${C}`},u0=(V,g)=>{let C=g.trim().replace(/\s+/g," ");if(!V)return C;if(!C||V.endsWith(C))return V;return`${V} ${C}`},r0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:n0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),p=()=>{let V=r0(),g="",C=new Set,A=()=>{C.forEach((_)=>_())};return{dispatch:(_)=>{switch(_.type){case"audio":V={...V,assistantAudio:[...V.assistantAudio,{chunk:_.chunk,format:_.format,receivedAt:_.receivedAt,turnId:_.turnId}]};break;case"assistant":V={...V,assistantStreamingText:"",assistantTexts:[...V.assistantTexts,_.text]};break;case"assistant_delta":V={...V,assistantStreamingText:`${V.assistantStreamingText}${_.delta}`};break;case"complete":V={...V,sessionId:_.sessionId,status:"completed"};break;case"call_lifecycle":V={...V,call:{...V.call,disposition:_.event.type==="end"?_.event.disposition:V.call?.disposition,endedAt:_.event.type==="end"?_.event.at:V.call?.endedAt,events:[...V.call?.events??[],_.event],lastEventAt:_.event.at,startedAt:V.call?.startedAt??_.event.at},sessionId:_.sessionId};break;case"connected":V={...V,isConnected:!0,reconnect:V.reconnect.status==="reconnecting"?{...V.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:V.reconnect};break;case"connection":V={...V,reconnect:_.reconnect};break;case"disconnected":V={...V,isConnected:!1};break;case"error":V={...V,error:_.message,..._.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":g=m0(g,_.transcript.text),V={...V,partial:g};break;case"partial":V={...V,partial:u0(g,_.transcript.text)};break;case"replay":g=_.partial,V={...V,assistantStreamingText:"",assistantTexts:[..._.assistantTexts],call:_.call??null,error:null,isConnected:_.status==="active",partial:_.partial,reconnect:V.reconnect.status==="reconnecting"?{...V.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:V.reconnect,scenarioId:_.scenarioId??V.scenarioId,sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??V.sessionMetadata,status:_.status,turns:[..._.turns]};break;case"session":V={...V,error:null,scenarioId:_.scenarioId??V.scenarioId,isConnected:_.status==="active",sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??V.sessionMetadata,status:_.status};break;case"turn":g="",V={...V,partial:"",turns:[...V.turns,_.turn]};break}A()},getServerSnapshot:()=>V,getSnapshot:()=>V,subscribe:(_)=>{return C.add(_),()=>{C.delete(_)}}}};var t=(V,g={})=>{let C=a(V,g),A=p(),R=g.browserMedia&&typeof window<"u"?r({...g.browserMedia,getScenarioId:()=>g.browserMedia?g.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>g.browserMedia?g.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,_=new Set,D=!1,X=(W)=>Promise.resolve().then(()=>{if(D)return;if(!W?.sessionId&&!W?.scenarioId)return;C.start(W),R?.start()}),H=()=>{_.forEach((W)=>W())},O=()=>{if(!g.reconnectReportPath||typeof fetch>"u")return;let W=A.getSnapshot(),I=JSON.stringify({at:Date.now(),reconnect:W.reconnect,scenarioId:W.scenarioId,sessionId:C.getSessionId(),turnIds:W.turns.map((T)=>T.id)});fetch(g.reconnectReportPath,{body:I,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=C.subscribe((W)=>{let I=i(W);if(I){if(A.dispatch(I),W.type==="connection")O();H()}});return{start:X,get assistantAudio(){return A.getSnapshot().assistantAudio},get assistantTexts(){return A.getSnapshot().assistantTexts},get assistantStreamingText(){return A.getSnapshot().assistantStreamingText},get call(){return A.getSnapshot().call},callControl(W){return C.callControl(W)},close(W){D=!0,L(),R?.close(),C.close(W),A.dispatch({type:"disconnected"}),H()},disconnect(){D=!0,L(),R?.close(),C.disconnect(),A.dispatch({type:"disconnected"}),H()},endTurn(){C.endTurn()},get error(){return A.getSnapshot().error},getServerSnapshot(){return A.getServerSnapshot()},getSnapshot(){return A.getSnapshot()},get isConnected(){return A.getSnapshot().isConnected},get partial(){return A.getSnapshot().partial},get reconnect(){return A.getSnapshot().reconnect},get scenarioId(){return A.getSnapshot().scenarioId},sendAudio(W){C.sendAudio(W)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return A.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return A.getSnapshot().status},subscribe(W){return _.add(W),()=>{_.delete(W)}},get turns(){return A.getSnapshot().turns}}};var e=(V)=>{if(!V||V.enabled===!1)return;return{enabled:!0,maxGain:V.maxGain??3,noiseGateAttenuation:V.noiseGateAttenuation??0.15,noiseGateThreshold:V.noiseGateThreshold??0.006,targetLevel:V.targetLevel??0.08}};var s0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},a0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var V0=(V)=>{let g=V?.profile??"fast",C=V?.qualityProfile??"general",A=s0[g],R=a0[C],_=V?.silenceMs??R.silenceMs??A.silenceMs;return{profile:g,qualityProfile:C,minSilenceMs:Math.min(_,V?.minSilenceMs??R.minSilenceMs??A.minSilenceMs),silenceMs:_,speechThreshold:V?.speechThreshold??R.speechThreshold??A.speechThreshold,transcriptStabilityMs:V?.transcriptStabilityMs??R.transcriptStabilityMs??A.transcriptStabilityMs}};var p0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},g0=(V="default")=>{let g=p0[V];return{audioConditioning:e(g.audioConditioning),capture:{channelCount:g.capture?.channelCount??1,sampleRateHz:g.capture?.sampleRateHz??16000},connection:{...g.connection},name:V,sttLifecycle:g.sttLifecycle??"continuous",turnDetection:V0(g.turnDetection)}};var t0=(V)=>({assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,isRecording:!1,partial:V.partial,reconnect:V.reconnect,recordingError:null,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]}),A0=(V,g={})=>{let C=g0(g.preset),A=t(V,{...C.connection,...g.connection}),R=null,_=0,D=!1,X=null,H=t0(A),O=new Set,L=()=>{for(let G of O)G()},W=()=>{if(H={...H,assistantAudio:[...A.assistantAudio],assistantStreamingText:A.assistantStreamingText,assistantTexts:[...A.assistantTexts],call:A.call,error:A.error,isConnected:A.isConnected,partial:A.partial,reconnect:A.reconnect,sessionId:A.sessionId,sessionMetadata:A.sessionMetadata,scenarioId:A.scenarioId,status:A.status,turns:[...A.turns]},g.autoStopOnComplete!==!1&&H.status==="completed"&&H.isRecording)R?.stop(),R=null,H={...H,isRecording:!1};L()},I=A.subscribe(W);W();let T=()=>{if(R)return R;return R=v({channelCount:g.capture?.channelCount??C.capture.channelCount,onLevel:g.capture?.onLevel,onAudio:(G)=>{if(g.capture?.onAudio){g.capture.onAudio(G,A.sendAudio);return}A.sendAudio(G)},sampleRateHz:g.capture?.sampleRateHz??C.capture.sampleRateHz,...g.capture?.stream?{stream:g.capture.stream}:{}}),R},J=()=>{_+=1,R?.stop(),R=null,H={...H,isRecording:!1},L()},h=async()=>{if(D)throw Error("Voice controller is closed.");if(H.isRecording)return;if(X)return X;let G=++_,c=T(),$=(async()=>{try{if(H={...H,recordingError:null},L(),await c.start(),D||G!==_||R!==c){c.stop();return}H={...H,isRecording:!0},L()}catch(S){if(c.stop(),G!==_||R!==c)throw S;throw R=null,H={...H,isRecording:!1,recordingError:S instanceof Error?S.message:String(S)},L(),S}})().finally(()=>{if(X===$)X=null});return X=$,X};return{close:(G)=>{D=!0,I(),J(),A.close(G)},disconnect:()=>{D=!0,I(),J(),A.disconnect()},startRecording:h,stopRecording:J,get assistantAudio(){return H.assistantAudio},get assistantTexts(){return H.assistantTexts},get assistantStreamingText(){return H.assistantStreamingText},bindHTMX(G){return d(A,G)},get call(){return H.call},callControl:(G)=>A.callControl(G),endTurn:()=>A.endTurn(),get error(){return H.error},getServerSnapshot:()=>H,getSnapshot:()=>H,get isConnected(){return H.isConnected},get isRecording(){return H.isRecording},get partial(){return H.partial},get reconnect(){return H.reconnect},get recordingError(){return H.recordingError},get scenarioId(){return H.scenarioId},sendAudio:(G)=>A.sendAudio(G),get sessionId(){return H.sessionId},get sessionMetadata(){return H.sessionMetadata},simulateDisconnect:()=>A.simulateDisconnect(),get status(){return H.status},subscribe:(G)=>{return O.add(G),()=>{O.delete(G)}},toggleRecording:async()=>{if(H.isRecording){J();return}await h()},get turns(){return H.turns}}};var N=(V)=>String(V).replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;");var C0=(V)=>{if(!V.isConnected)return"idle";if(V.isPlaying)return"speaking";if(V.isRecording&&V.hasActivePartial)return"listening";if(V.isRecording)return"listening";if(V.lastTranscriptAt&&!V.lastAssistantAt)return"thinking";if(V.lastTranscriptAt&&V.lastAssistantAt&&V.lastTranscriptAt>V.lastAssistantAt)return"thinking";return"idle"};var e0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},VV={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},gV=(V,g)=>{switch(V){case"listening":return g.listening;case"speaking":return g.speaking;case"thinking":return g.thinking;case"idle":return g.idle}},_0=(V)=>{let g={...e0,...V.theme},C={...VV,...V.labels},A=V.state.assistantAudio.at(-1)?.receivedAt,R=V.state.turns.at(-1)?.committedAt,_=C0({hasActivePartial:V.state.partial.length>0,isConnected:V.state.isConnected,isPlaying:!1,isRecording:V.state.isRecording,lastAssistantAt:A,lastTranscriptAt:R}),D=!V.state.isConnected&&V.state.status!=="idle"&&!V.state.error,X=V.state.error?"Error":D?C.connecting:V.state.status==="completed"?C.callEnded:gV(_,C);return{agentState:_,classes:{container:`absolute-voice-widget absolute-voice-widget--${_}`,dot:`absolute-voice-widget__dot${V.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:V.state.isConnected,canMute:V.state.isRecording,canStart:!V.state.isRecording&&V.state.status!=="completed"},errorMessage:V.state.error??void 0,labels:C,partial:V.state.partial||void 0,statusLabel:X,theme:g,title:V.title??"Voice"}},AV=(V)=>typeof V==="number"?`${V}px`:V,T0=(V)=>{let g=V.theme,C=`background:${g.background};border-radius:${AV(g.radius)};color:${g.foreground};font-family:${g.fontFamily};min-width:240px;padding:20px 22px;`,A=`background:${V.errorMessage?g.errorAccent:V.agentState==="idle"?"rgba(148,163,184,0.6)":g.accent};border-radius:50%;height:10px;width:10px;`,R=[];if(V.controls.canStart)R.push(`<button type="button" data-action="start" style="background:${g.accent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${N(V.labels.startCall)}</button>`);if(V.controls.canMute)R.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${N(V.labels.mute)}</button>`);if(V.controls.canEnd)R.push(`<button type="button" data-action="end" style="background:${g.errorAccent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${N(V.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${V.agentState}" class="${N(V.classes.container)}" style="${C}">
2
2
  <div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
3
- <span aria-hidden="true" class="${K(g.classes.dot)}" style="${V}"></span>
4
- <strong style="font-size:15px;">${K(g.title)}</strong>
5
- <span style="font-size:13px;margin-left:auto;opacity:0.7;">${K(g.statusLabel)}</span>
3
+ <span aria-hidden="true" class="${N(V.classes.dot)}" style="${A}"></span>
4
+ <strong style="font-size:15px;">${N(V.title)}</strong>
5
+ <span style="font-size:13px;margin-left:auto;opacity:0.7;">${N(V.statusLabel)}</span>
6
6
  </div>
7
- ${g.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${K(g.partial)}”</p>`:""}
8
- <div style="display:flex;gap:10px;">${T.join("")}</div>
9
- ${g.errorMessage?`<p style="color:${A.errorAccent};font-size:12px;margin-top:12px;">${K(g.errorMessage)}</p>`:""}
10
- </div>`};var t0=(g)=>{if(typeof g!=="string")return g;let A=document.querySelector(g);if(!A)throw Error(`AbsoluteVoice.mount: no element matches "${g}"`);return A},c0=(g,A={})=>{let C=t0(g),V=g0(A.path??"/voice",A.controllerOptions),T=null,c=null,U=()=>{let G=V0({...A.labels!==void 0?{labels:A.labels}:{},state:{assistantAudio:V.assistantAudio,error:V.error,isConnected:V.isConnected,isRecording:V.isRecording,partial:V.partial,status:V.status,turns:V.turns},...A.theme!==void 0?{theme:A.theme}:{},...A.title!==void 0?{title:A.title}:{}});C.innerHTML=C0(G);for(let W of C.querySelectorAll("button[data-action]")){let{action:_}=W.dataset;W.addEventListener("click",()=>{if(_==="start")V.startRecording();else if(_==="mute")V.stopRecording();else if(_==="end")V.close()})}if(V.error&&V.error!==T)T=V.error,A.onError?.(V.error);if(V.status!==c)c=V.status,A.onStatusChange?.(V.status)},I=V.subscribe(U);if(U(),A.autoStart)V.startRecording();return{controller:V,async end(){await V.close()},mute(){V.stopRecording()},async start(){await V.startRecording()},unmount(){I(),V.close(),C.innerHTML=""}}},_0="0.0.22-beta.516",T0={mount:c0,version:_0};if(typeof globalThis<"u")globalThis.AbsoluteVoice=T0;var gg=T0;})();
7
+ ${V.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${N(V.partial)}”</p>`:""}
8
+ <div style="display:flex;gap:10px;">${R.join("")}</div>
9
+ ${V.errorMessage?`<p style="color:${g.errorAccent};font-size:12px;margin-top:12px;">${N(V.errorMessage)}</p>`:""}
10
+ </div>`};var CV=(V)=>{if(typeof V!=="string")return V;let g=document.querySelector(V);if(!g)throw Error(`AbsoluteVoice.mount: no element matches "${V}"`);return g},$0=(V,g={})=>{let C=CV(V),A=A0(g.path??"/voice",g.controllerOptions),R=null,_=null,D=()=>{let H=_0({...g.labels!==void 0?{labels:g.labels}:{},state:{assistantAudio:A.assistantAudio,error:A.error,isConnected:A.isConnected,isRecording:A.isRecording,partial:A.partial,status:A.status,turns:A.turns},...g.theme!==void 0?{theme:g.theme}:{},...g.title!==void 0?{title:g.title}:{}});C.innerHTML=T0(H);for(let O of C.querySelectorAll("button[data-action]")){let{action:L}=O.dataset;O.addEventListener("click",()=>{if(L==="start")A.startRecording();else if(L==="mute")A.stopRecording();else if(L==="end")A.close()})}if(A.error&&A.error!==R)R=A.error,g.onError?.(A.error);if(A.status!==_)_=A.status,g.onStatusChange?.(A.status)},X=A.subscribe(D);if(D(),g.autoStart)A.startRecording();return{controller:A,async end(){await A.close()},mute(){A.stopRecording()},async start(){await A.startRecording()},unmount(){X(),A.close(),C.innerHTML=""}}},R0="0.0.22-beta.516",H0={mount:$0,version:R0};if(typeof globalThis<"u")globalThis.AbsoluteVoice=H0;var TV=H0;})();