@absolutejs/voice 0.0.22-beta.656 → 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.
- package/dist/angular/index.js +167 -67
- package/dist/client/htmxBootstrap.js +167 -67
- package/dist/client/index.js +167 -67
- package/dist/core/types.d.ts +4 -0
- package/dist/embed/index.js +167 -67
- package/dist/embed/voice-widget.js +8 -8
- package/dist/react/index.js +167 -67
- package/dist/svelte/index.js +167 -67
- package/dist/testing/index.js +168 -68
- package/dist/vue/index.js +167 -67
- package/package.json +1 -1
package/dist/embed/index.js
CHANGED
|
@@ -100,48 +100,89 @@ var createMicrophoneCapture = (options) => {
|
|
|
100
100
|
let sourceNode = null;
|
|
101
101
|
let processorNode = null;
|
|
102
102
|
let mediaStream = null;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
142
|
-
sourceNode
|
|
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,6 +543,7 @@ 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;
|
|
@@ -595,6 +637,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
595
637
|
const reconnectResetAfterMs = options.reconnectResetAfterMs ?? DEFAULT_RECONNECT_RESET_AFTER_MS;
|
|
596
638
|
let lifecycleGeneration = 0;
|
|
597
639
|
let disposed = false;
|
|
640
|
+
let reconnectPreparationAbort = null;
|
|
598
641
|
const computeReconnectDelayMs = (attempt) => computeVoiceReconnectDelayMs(attempt, RECONNECT_BASE_DELAY_MS, reconnectMaxDelayMs);
|
|
599
642
|
const state = {
|
|
600
643
|
isConnected: false,
|
|
@@ -682,12 +725,30 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
682
725
|
return;
|
|
683
726
|
}
|
|
684
727
|
try {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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
|
+
}
|
|
691
752
|
} catch (error) {
|
|
692
753
|
if (disposed || lifecycleGeneration !== scheduledGeneration)
|
|
693
754
|
return;
|
|
@@ -811,6 +872,8 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
811
872
|
state.ws = ws;
|
|
812
873
|
};
|
|
813
874
|
const sendSerialized = (value) => {
|
|
875
|
+
if (disposed)
|
|
876
|
+
return;
|
|
814
877
|
if (state.ws?.readyState === WS_OPEN) {
|
|
815
878
|
state.ws.send(value);
|
|
816
879
|
return;
|
|
@@ -865,6 +928,8 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
865
928
|
};
|
|
866
929
|
const close = (reason = "client-close") => {
|
|
867
930
|
disposed = true;
|
|
931
|
+
reconnectPreparationAbort?.abort();
|
|
932
|
+
reconnectPreparationAbort = null;
|
|
868
933
|
lifecycleGeneration += 1;
|
|
869
934
|
clearTimers();
|
|
870
935
|
rejectPendingCallControls("Voice connection closed");
|
|
@@ -882,6 +947,8 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
882
947
|
};
|
|
883
948
|
const disconnect = () => {
|
|
884
949
|
disposed = true;
|
|
950
|
+
reconnectPreparationAbort?.abort();
|
|
951
|
+
reconnectPreparationAbort = null;
|
|
885
952
|
lifecycleGeneration += 1;
|
|
886
953
|
clearTimers();
|
|
887
954
|
rejectPendingCallControls("Voice connection disconnected");
|
|
@@ -1133,7 +1200,10 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1133
1200
|
getSessionId: () => options.browserMedia ? options.browserMedia.getSessionId?.() ?? connection.getSessionId() : connection.getSessionId()
|
|
1134
1201
|
}) : null;
|
|
1135
1202
|
const subscribers = new Set;
|
|
1203
|
+
let disposed = false;
|
|
1136
1204
|
const start = (input) => Promise.resolve().then(() => {
|
|
1205
|
+
if (disposed)
|
|
1206
|
+
return;
|
|
1137
1207
|
if (!input?.sessionId && !input?.scenarioId) {
|
|
1138
1208
|
return;
|
|
1139
1209
|
}
|
|
@@ -1192,6 +1262,7 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1192
1262
|
return connection.callControl(message);
|
|
1193
1263
|
},
|
|
1194
1264
|
close(reason) {
|
|
1265
|
+
disposed = true;
|
|
1195
1266
|
unsubscribeConnection();
|
|
1196
1267
|
browserMediaReporter?.close();
|
|
1197
1268
|
connection.close(reason);
|
|
@@ -1199,6 +1270,7 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1199
1270
|
notify();
|
|
1200
1271
|
},
|
|
1201
1272
|
disconnect() {
|
|
1273
|
+
disposed = true;
|
|
1202
1274
|
unsubscribeConnection();
|
|
1203
1275
|
browserMediaReporter?.close();
|
|
1204
1276
|
connection.disconnect();
|
|
@@ -1565,6 +1637,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1565
1637
|
...options.connection
|
|
1566
1638
|
});
|
|
1567
1639
|
let capture = null;
|
|
1640
|
+
let captureGeneration = 0;
|
|
1641
|
+
let disposed = false;
|
|
1642
|
+
let startRecordingPromise = null;
|
|
1568
1643
|
let state = createInitialState2(stream);
|
|
1569
1644
|
const subscribers = new Set;
|
|
1570
1645
|
const notify = () => {
|
|
@@ -1621,6 +1696,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1621
1696
|
return capture;
|
|
1622
1697
|
};
|
|
1623
1698
|
const stopRecording = () => {
|
|
1699
|
+
captureGeneration += 1;
|
|
1624
1700
|
capture?.stop();
|
|
1625
1701
|
capture = null;
|
|
1626
1702
|
state = {
|
|
@@ -1630,39 +1706,63 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1630
1706
|
notify();
|
|
1631
1707
|
};
|
|
1632
1708
|
const startRecording = async () => {
|
|
1709
|
+
if (disposed) {
|
|
1710
|
+
throw new Error("Voice controller is closed.");
|
|
1711
|
+
}
|
|
1633
1712
|
if (state.isRecording) {
|
|
1634
1713
|
return;
|
|
1635
1714
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
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;
|
|
1659
1757
|
};
|
|
1660
1758
|
const close = (reason) => {
|
|
1759
|
+
disposed = true;
|
|
1661
1760
|
unsubscribeStream();
|
|
1662
1761
|
stopRecording();
|
|
1663
1762
|
stream.close(reason);
|
|
1664
1763
|
};
|
|
1665
1764
|
const disconnect = () => {
|
|
1765
|
+
disposed = true;
|
|
1666
1766
|
unsubscribeStream();
|
|
1667
1767
|
stopRecording();
|
|
1668
1768
|
stream.disconnect();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(()=>{var{defineProperty:x,getOwnPropertyNames:G0,getOwnPropertyDescriptor:S0}=Object,X0=Object.prototype.hasOwnProperty;function O0(g){return this[g]}var y0=(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 G0(g))if(!X0.call(A,V))x(A,V,{get:O0.bind(g,V),enumerable:!(C=S0(g,V))||C.enumerable})}return f.set(g,A),A},f;var J0=(g)=>g;function Y0(g,A){this[g]=J0.bind(null,A)}var Z0=(g,A)=>{for(var C in A)x(g,C,{get:A[C],enumerable:!0,configurable:!0,set:Y0.bind(A,C)})};var Vg={};Z0(Vg,{mount:()=>T0,default:()=>Cg,VOICE_EMBED_VERSION:()=>$0});var w0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},h0=(g,A,C,V)=>{let $=A??g.getAttribute("hx-get")??"";if(!$)return"";let _=new URL($,window.location.origin);if(V)_.searchParams.set(C,V);else _.searchParams.delete(C);return`${_.pathname}${_.search}${_.hash}`},d=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=w0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",$=A.sessionQueryParam??"sessionId",_=()=>{let U=window,c=h0(C,A.route,$,g.sessionId);if(c)C.setAttribute("hx-get",c);U.htmx?.process?.(C),U.htmx?.trigger?.(C,V)},L=g.subscribe(_);return _(),()=>{L()}};var Q0=(g)=>Math.max(-1,Math.min(1,g)),K0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=Q0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},P0=(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 $ of C){let _=$/32768;V+=_*_}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},N0=(g,A,C)=>{if(A===C)return g;let V=A/C,$=Math.round(g.length/V),_=new Float32Array($),L=0,U=0;while(L<_.length){let c=Math.round((L+1)*V),W=0,R=0;for(let S=U;S<c&&S<g.length;S+=1)W+=g[S]??0,R+=1;_[L]=R>0?W/R:0,L+=1,U=c}return _},l=(g)=>{let A=null,C=null,V=null,$=null,_=async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let U=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!U)throw Error("Browser microphone capture requires AudioContext support.");try{if($=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new U,A.state==="suspended")await A.resume();C=A.createMediaStreamSource($),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=(c)=>{let W=c.inputBuffer.getChannelData(0),R=N0(W,A?.sampleRate??48000,g.sampleRateHz??16000),S=K0(R);g.onLevel?.(P0(S)),g.onAudio(S)},C.connect(V),V.connect(A.destination)}catch(c){throw L(),c}},L=()=>{V?.disconnect(),C?.disconnect(),$?.getTracks().forEach((U)=>U.stop()),A?.close(),g.onLevel?.(0),A=null,$=null,V=null,C=null};return{start:_,stop:L}};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 Rg=Math.PI*2;var P=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var E0=(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 O=(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},Y=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},F=(g)=>String(g.id??Y(g,"ssrc")??O(g,"ssrc")??Y(g,"trackIdentifier")??Y(g,"mid")??"unknown"),i=(g)=>g===void 0?void 0:g*1000;var q0=(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((H)=>H.type==="inbound-rtp"&&Y(H,"kind")!=="video"),$=A.filter((H)=>H.type==="outbound-rtp"&&Y(H,"kind")!=="video"),_=A.filter((H)=>H.type==="candidate-pair"),L=A.filter((H)=>(H.type==="track"||H.type==="media-source")&&Y(H,"kind")==="audio"),U=_.filter((H)=>B(H,"selected")===!0||B(H,"nominated")===!0||Y(H,"state")==="succeeded").length,c=L.filter((H)=>Y(H,"readyState")!=="ended"&&Y(H,"trackState")!=="ended"&&B(H,"ended")!==!0).length,W=L.filter((H)=>Y(H,"readyState")==="ended"||Y(H,"trackState")==="ended"||B(H,"ended")===!0).length,R=V.reduce((H,J)=>H+(O(J,"packetsReceived")??0),0),S=$.reduce((H,J)=>H+(O(J,"packetsSent")??0),0),T=[...V,...$].reduce((H,J)=>H+Math.max(0,O(J,"packetsLost")??0),0),Z=R+T,w=Z===0?0:T/Z,D=V.reduce((H,J)=>H+(O(J,"bytesReceived")??0),0),K=$.reduce((H,J)=>H+(O(J,"bytesSent")??0),0),h=M(_.map((H)=>i(O(H,"currentRoundTripTime")??O(H,"roundTripTime"))).filter((H)=>H!==void 0)),Q=M([...V,...$].map((H)=>i(O(H,"jitter"))).filter((H)=>H!==void 0)),E=M(V.map((H)=>{let J=O(H,"jitterBufferDelay"),b=O(H,"jitterBufferEmittedCount");return J!==void 0&&b!==void 0&&b>0?J/b*1000:void 0}).filter((H)=>H!==void 0)),q=L.map((H)=>O(H,"audioLevel")).filter((H)=>H!==void 0);if(g.requireConnectedCandidatePair&&_.length>0&&U===0)P(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&c===0)P(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&w>g.maxPacketLossRatio)P(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(w)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&h!==void 0&&h>g.maxRoundTripTimeMs)P(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(h)}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:U,audioLevelAverage:E0(q),bytesReceived:D,bytesSent:K,checkedAt:Date.now(),endedAudioTracks:W,inboundPackets:R,issues:C,jitterBufferDelayMs:E,jitterMs:Q,liveAudioTracks:c,outboundPackets:S,packetLossRatio:w,packetsLost:T,roundTripTimeMs:h,status:C.some((H)=>H.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},o=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(q0)};var m=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],$=new Map(C.map((T)=>[F(T),T])),L=A.filter((T)=>(T.type==="inbound-rtp"||T.type==="outbound-rtp")&&Y(T,"kind")!=="video"&&Y(T,"mediaType")!=="video").map((T)=>{let Z=T.type==="outbound-rtp"?"outbound":"inbound",w=Z==="outbound"?"packetsSent":"packetsReceived",D=Z==="outbound"?"bytesSent":"bytesReceived",K=$.get(F(T)),h=O(T,w),Q=K?O(K,w):void 0,E=O(T,D),q=K?O(K,D):void 0,H=T.timestamp!==void 0&&K?.timestamp!==void 0?T.timestamp-K.timestamp:void 0;return{bytesDelta:E!==void 0&&q!==void 0?E-q:void 0,currentPackets:h,direction:Z,id:F(T),packetDelta:h!==void 0&&Q!==void 0?h-Q:void 0,previousPackets:Q,timeDeltaMs:H}}),U=L.filter((T)=>T.direction==="inbound"),c=L.filter((T)=>T.direction==="outbound"),W=M(L.map((T)=>T.timeDeltaMs).filter((T)=>T!==void 0)),R=U.filter((T)=>g.maxInboundPacketStallMs!==void 0&&T.timeDeltaMs!==void 0&&T.timeDeltaMs>=g.maxInboundPacketStallMs&&T.packetDelta!==void 0&&T.packetDelta<=0).length,S=c.filter((T)=>g.maxOutboundPacketStallMs!==void 0&&T.timeDeltaMs!==void 0&&T.timeDeltaMs>=g.maxOutboundPacketStallMs&&T.packetDelta!==void 0&&T.packetDelta<=0).length;if(g.requireInboundAudio&&U.length===0)P(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&c.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(R>0)P(V,"error","media.webrtc_inbound_stalled",`${String(R)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(S>0)P(V,"error","media.webrtc_outbound_stalled",`${String(S)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:U.length,issues:V,maxObservedGapMs:W,outboundAudioStreams:c.length,stalledInboundStreams:R,stalledOutboundStreams:S,status:V.some((T)=>T.severity==="error")?"fail":V.length>0?"warn":"pass",streams:L,totalStats:A.length}};var z0="/api/voice/browser-media",b0=5000,B0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,M0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??z0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(g)=>{let A=null,C=[],V=async()=>{let L=await B0(g);if(!L)return;let U=await o({peerConnection:L}),c=n({...g,stats:U}),W=g.continuity===!1?void 0:m({...g.continuity,previousStats:C,stats:U}),R={at:Date.now(),continuity:W,report:c,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=U,g.onReport?.(R),await M0(R,g),R},$=()=>{V().catch((L)=>{g.onError?.(L)})},_=()=>{if(A)clearInterval(A),A=null};return{close:_,reportOnce:V,stop:_,start:()=>{if(A)return;$(),A=setInterval($,g.intervalMs??b0)}}};var j0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));class u extends Error{constructor(g="Voice authorization could not be renewed."){super(g);this.name="VoiceReconnectRejectedError"}}var z=()=>{},x0=()=>Promise.resolve(),k0=()=>z,F0={callControl:x0,close:z,disconnect:z,endTurn:z,send:z,sendAudio:z,simulateDisconnect:z,subscribe:k0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},f0=()=>crypto.randomUUID(),d0=(g,A,C,V)=>{let{hostname:$,port:_,protocol:L}=window.location,U=L==="https:"?"wss:":"ws:",c=_?`:${_}`:"",W=new URL(`${U}//${$}${c}${g}`);if(W.searchParams.set("sessionId",A),C)W.searchParams.set("scenarioId",C);for(let[R,S]of Object.entries(V))if(R!=="sessionId"&&R!=="scenarioId"&&S)W.searchParams.set(R,S);return W.toString()},l0=(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}},v0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return l0(A)?A:null}catch{return null}},s=(g,A={})=>{if(typeof window>"u")return F0;let C=new Set,V=new Map,$=A.reconnect!==!1,_=A.maxReconnectAttempts??15,L=A.reconnectMaxDelayMs??8000,U=A.pingInterval??30000,c=A.reconnectResetAfterMs??30000,W=0,R=!1,S=(I)=>j0(I,500,L),T={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:A.sessionId??f0(),ws:null},Z=(I)=>{C.forEach((G)=>G(I))},w=(I)=>{C.forEach((G)=>G({message:I,recoverable:!1,type:"error"})),Z({reconnect:{attempts:T.reconnectAttempts,maxAttempts:_,status:"exhausted"},type:"connection"})},D=()=>{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},K=()=>{if(T.ws?.readyState!==1)return;while(T.pendingMessages.length>0){let I=T.pendingMessages.shift();if(I!==void 0)T.ws.send(I)}},h=(I)=>{for(let G of V.values())clearTimeout(G.timeout),G.reject(Error(I));V.clear()},Q=()=>{if(R)return;let I=W;T.reconnectAttempts+=1;let G=S(T.reconnectAttempts),X=Date.now()+G;Z({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,nextAttemptAt:X,status:"reconnecting"},type:"connection"}),T.reconnectTimeout=setTimeout(async()=>{if(R||W!==I)return;if(T.reconnectAttempts>_){w("Voice connection could not be restored.");return}try{await A.prepareReconnect?.({attempt:T.reconnectAttempts,path:g,scenarioId:T.scenarioId,sessionId:T.sessionId})}catch(y){if(R||W!==I)return;if(y instanceof u){w(y.message);return}if(T.reconnectAttempts<_)Q();else w("Voice authorization could not be renewed for reconnect.");return}if(R||W!==I)return;E()},G)},E=()=>{if(R)return;let I=new WebSocket(d0(g,T.sessionId,T.scenarioId,A.query??{}));I.binaryType="arraybuffer",I.onopen=()=>{if(T.ws!==I){I.close(1000);return}let G=T.reconnectAttempts>0;if(T.isConnected=!0,K(),G)Z({reconnect:{attempts:T.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:_,status:"resumed"},type:"connection"}),T.reconnectResetTimeout=setTimeout(()=>{if(T.ws===I&&I.readyState===1)T.reconnectAttempts=0;T.reconnectResetTimeout=null},c);C.forEach((X)=>X({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,status:"active",type:"session"})),T.pingInterval=setInterval(()=>{if(I.readyState===1)I.send(JSON.stringify({type:"ping"}))},U)},I.onmessage=(G)=>{if(T.ws!==I)return;let X=v0(G);if(!X)return;if(X.type==="session")T.sessionId=X.sessionId,T.scenarioId=X.scenarioId??T.scenarioId;if(X.type==="call_control_ack"){let y=V.get(X.requestId);if(y)if(clearTimeout(y.timeout),V.delete(X.requestId),X.ok)y.resolve();else y.reject(Error(X.message??`${X.action} was not applied`))}C.forEach((y)=>y(X))},I.onclose=(G)=>{if(T.ws!==I)return;T.ws=null,T.isConnected=!1,D(),h("Voice connection interrupted");let X=$&&G.code!==1000&&G.code!==4401&&G.code!==4403&&T.reconnectAttempts<_,y=G.code===4401||G.code===4403;if(y)C.forEach((j)=>j({message:G.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(X)Q();else if($&&G.code!==1000)if(y)Z({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,status:"exhausted"},type:"connection"});else w("Voice connection could not be restored.")},T.ws=I},q=(I)=>{if(T.ws?.readyState===1){T.ws.send(I);return}if(typeof I!=="string")return;if(T.pendingMessages.length>=100)T.pendingMessages.shift();T.pendingMessages.push(I)},H=(I)=>{q(JSON.stringify(I))},J=(I={})=>{if(I.sessionId)T.sessionId=I.sessionId;if(I.scenarioId)T.scenarioId=I.scenarioId;H({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,type:"start"})},b=(I)=>{q(I)},R0=()=>{H({type:"end_turn"})},I0=(I)=>{if(T.ws?.readyState!==1)return Promise.reject(Error(`${I.action} is unavailable while disconnected`));let G=crypto.randomUUID(),{promise:X,reject:y,resolve:j}=Promise.withResolvers(),D0=setTimeout(()=>{V.delete(G),y(Error(`${I.action} acknowledgement timed out`))},5000);return V.set(G,{reject:y,resolve:j,timeout:D0}),T.ws.send(JSON.stringify({...I,requestId:G,type:"call_control"})),X},U0=(I="client-close")=>{if(R=!0,W+=1,D(),h("Voice connection closed"),T.pendingMessages.length=0,T.ws){let G=T.ws;if(T.ws=null,G.readyState===1)G.send(JSON.stringify({reason:I,type:"close"}));G.close(1000)}T.isConnected=!1,C.clear()},L0=()=>{if(R=!0,W+=1,D(),h("Voice connection disconnected"),T.pendingMessages.length=0,T.ws){let I=T.ws;T.ws=null,I.close(1000)}T.isConnected=!1,C.clear()},W0=()=>{if(T.ws?.readyState===1)T.ws.close(4000,"absolutejs-voice-reconnect-proof")},c0=(I)=>{return C.add(I),()=>{C.delete(I)}};return E(),{callControl:I0,close:U0,disconnect:L0,endTurn:R0,send:H,sendAudio:b,simulateDisconnect:W0,start:J,subscribe:c0,getReadyState:()=>T.ws?.readyState??3,getScenarioId:()=>T.scenarioId??"",getSessionId:()=>T.sessionId}};var i0=()=>({attempts:0,maxAttempts:0,status:"idle"}),n0=(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}`},o0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},m0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:i0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),a=()=>{let g=m0(),A="",C=new Set,V=()=>{C.forEach((_)=>_())};return{dispatch:(_)=>{switch(_.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:_.chunk,format:_.format,receivedAt:_.receivedAt,turnId:_.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,_.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${_.delta}`};break;case"complete":g={...g,sessionId:_.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:_.event.type==="end"?_.event.disposition:g.call?.disposition,endedAt:_.event.type==="end"?_.event.at:g.call?.endedAt,events:[...g.call?.events??[],_.event],lastEventAt:_.event.at,startedAt:g.call?.startedAt??_.event.at},sessionId:_.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:_.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:_.message,..._.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":A=n0(A,_.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:o0(A,_.transcript.text)};break;case"replay":A=_.partial,g={...g,assistantStreamingText:"",assistantTexts:[..._.assistantTexts],call:_.call??null,error:null,isConnected:_.status==="active",partial:_.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:_.scenarioId??g.scenarioId,sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??g.sessionMetadata,status:_.status,turns:[..._.turns]};break;case"session":g={...g,error:null,scenarioId:_.scenarioId??g.scenarioId,isConnected:_.status==="active",sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??g.sessionMetadata,status:_.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,_.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(_)=>{return C.add(_),()=>{C.delete(_)}}}};var p=(g,A={})=>{let C=s(g,A),V=a(),$=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,_=new Set,L=(R)=>Promise.resolve().then(()=>{if(!R?.sessionId&&!R?.scenarioId)return;C.start(R),$?.start()}),U=()=>{_.forEach((R)=>R())},c=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let R=V.getSnapshot(),S=JSON.stringify({at:Date.now(),reconnect:R.reconnect,scenarioId:R.scenarioId,sessionId:C.getSessionId(),turnIds:R.turns.map((T)=>T.id)});fetch(A.reconnectReportPath,{body:S,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},W=C.subscribe((R)=>{let S=v(R);if(S){if(V.dispatch(S),R.type==="connection")c();U()}});return{start:L,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(R){return C.callControl(R)},close(R){W(),$?.close(),C.close(R),V.dispatch({type:"disconnected"}),U()},disconnect(){W(),$?.close(),C.disconnect(),V.dispatch({type:"disconnected"}),U()},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(R){C.sendAudio(R)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(R){return _.add(R),()=>{_.delete(R)}},get turns(){return V.getSnapshot().turns}}};var t=(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 r0={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}},u0={"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 e=(g)=>{let A=g?.profile??"fast",C=g?.qualityProfile??"general",V=r0[A],$=u0[C],_=g?.silenceMs??$.silenceMs??V.silenceMs;return{profile:A,qualityProfile:C,minSilenceMs:Math.min(_,g?.minSilenceMs??$.minSilenceMs??V.minSilenceMs),silenceMs:_,speechThreshold:g?.speechThreshold??$.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??$.transcriptStabilityMs??V.transcriptStabilityMs}};var s0={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=(g="default")=>{let A=s0[g];return{audioConditioning:t(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:e(A.turnDetection)}};var a0=(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]}),A0=(g,A={})=>{let C=g0(A.preset),V=p(g,{...C.connection,...A.connection}),$=null,_=a0(V),L=new Set,U=()=>{for(let D of L)D()},c=()=>{if(_={..._,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&&_.status==="completed"&&_.isRecording)$?.stop(),$=null,_={..._,isRecording:!1};U()},W=V.subscribe(c);c();let R=()=>{if($)return $;return $=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}:{}}),$},S=()=>{$?.stop(),$=null,_={..._,isRecording:!1},U()},T=async()=>{if(_.isRecording)return;try{_={..._,recordingError:null},U(),await R().start(),_={..._,isRecording:!0},U()}catch(D){throw $?.stop(),$=null,_={..._,isRecording:!1,recordingError:D instanceof Error?D.message:String(D)},U(),D}};return{close:(D)=>{W(),S(),V.close(D)},disconnect:()=>{W(),S(),V.disconnect()},startRecording:T,stopRecording:S,get assistantAudio(){return _.assistantAudio},get assistantTexts(){return _.assistantTexts},get assistantStreamingText(){return _.assistantStreamingText},bindHTMX(D){return d(V,D)},get call(){return _.call},callControl:(D)=>V.callControl(D),endTurn:()=>V.endTurn(),get error(){return _.error},getServerSnapshot:()=>_,getSnapshot:()=>_,get isConnected(){return _.isConnected},get isRecording(){return _.isRecording},get partial(){return _.partial},get reconnect(){return _.reconnect},get recordingError(){return _.recordingError},get scenarioId(){return _.scenarioId},sendAudio:(D)=>V.sendAudio(D),get sessionId(){return _.sessionId},get sessionMetadata(){return _.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return _.status},subscribe:(D)=>{return L.add(D),()=>{L.delete(D)}},toggleRecording:async()=>{if(_.isRecording){S();return}await T()},get turns(){return _.turns}}};var N=(g)=>String(g).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var V0=(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 p0={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},t0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},e0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},C0=(g)=>{let A={...p0,...g.theme},C={...t0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,$=g.state.turns.at(-1)?.committedAt,_=V0({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:$}),L=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,U=g.state.error?"Error":L?C.connecting:g.state.status==="completed"?C.callEnded:e0(_,C);return{agentState:_,classes:{container:`absolute-voice-widget absolute-voice-widget--${_}`,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:U,theme:A,title:g.title??"Voice"}},gg=(g)=>typeof g==="number"?`${g}px`:g,_0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${gg(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;`,$=[];if(g.controls.canStart)$.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;">${N(g.labels.startCall)}</button>`);if(g.controls.canMute)$.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;">${N(g.labels.mute)}</button>`);if(g.controls.canEnd)$.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;">${N(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${N(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("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");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="${N(
|
|
4
|
-
<strong style="font-size:15px;">${N(
|
|
5
|
-
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${N(
|
|
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
|
-
${
|
|
8
|
-
<div style="display:flex;gap:10px;">${
|
|
9
|
-
${
|
|
10
|
-
</div>`};var
|
|
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;})();
|