@absolutejs/voice 0.0.22-beta.660 → 0.0.22-beta.661
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 +0 -6
- package/dist/client/htmxBootstrap.js +0 -6
- package/dist/client/index.js +0 -6
- package/dist/core/types.d.ts +4 -0
- package/dist/embed/index.js +0 -6
- package/dist/embed/voice-widget.js +1 -1
- package/dist/index.js +14 -2
- package/dist/react/index.js +0 -6
- package/dist/svelte/index.js +0 -6
- package/dist/testing/index.js +4 -6
- package/dist/vue/index.js +0 -6
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -885,12 +885,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
885
885
|
state.reconnectResetTimeout = null;
|
|
886
886
|
}, reconnectResetAfterMs);
|
|
887
887
|
}
|
|
888
|
-
listeners.forEach((listener) => listener({
|
|
889
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
890
|
-
sessionId: state.sessionId,
|
|
891
|
-
status: "active",
|
|
892
|
-
type: "session"
|
|
893
|
-
}));
|
|
894
888
|
state.pingInterval = setInterval(() => {
|
|
895
889
|
if (ws.readyState === WS_OPEN) {
|
|
896
890
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -802,12 +802,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
802
802
|
state.reconnectResetTimeout = null;
|
|
803
803
|
}, reconnectResetAfterMs);
|
|
804
804
|
}
|
|
805
|
-
listeners.forEach((listener) => listener({
|
|
806
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
807
|
-
sessionId: state.sessionId,
|
|
808
|
-
status: "active",
|
|
809
|
-
type: "session"
|
|
810
|
-
}));
|
|
811
805
|
state.pingInterval = setInterval(() => {
|
|
812
806
|
if (ws.readyState === WS_OPEN) {
|
|
813
807
|
ws.send(JSON.stringify({ type: "ping" }));
|
package/dist/client/index.js
CHANGED
|
@@ -366,12 +366,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
366
366
|
state.reconnectResetTimeout = null;
|
|
367
367
|
}, reconnectResetAfterMs);
|
|
368
368
|
}
|
|
369
|
-
listeners.forEach((listener) => listener({
|
|
370
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
371
|
-
sessionId: state.sessionId,
|
|
372
|
-
status: "active",
|
|
373
|
-
type: "session"
|
|
374
|
-
}));
|
|
375
369
|
state.pingInterval = setInterval(() => {
|
|
376
370
|
if (ws.readyState === WS_OPEN) {
|
|
377
371
|
ws.send(JSON.stringify({ type: "ping" }));
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1281,6 +1281,8 @@ export type VoiceClientPingMessage = {
|
|
|
1281
1281
|
export type VoiceClientMessage = VoiceClientStartMessage | VoiceClientEndTurnMessage | VoiceClientCloseMessage | VoiceClientCallControlMessage | VoiceClientPingMessage;
|
|
1282
1282
|
export type VoiceServerSessionMessage = {
|
|
1283
1283
|
type: "session";
|
|
1284
|
+
paused?: boolean;
|
|
1285
|
+
pauseExpiresAt?: number;
|
|
1284
1286
|
sessionId: string;
|
|
1285
1287
|
status: VoiceSessionStatus;
|
|
1286
1288
|
scenarioId?: string;
|
|
@@ -1697,6 +1699,8 @@ export type VoiceHTMXBindingOptions = {
|
|
|
1697
1699
|
};
|
|
1698
1700
|
export type VoiceStoreAction<TResult = unknown> = {
|
|
1699
1701
|
type: "session";
|
|
1702
|
+
paused?: boolean;
|
|
1703
|
+
pauseExpiresAt?: number;
|
|
1700
1704
|
sessionId: string;
|
|
1701
1705
|
sessionMetadata?: Record<string, unknown>;
|
|
1702
1706
|
scenarioId?: string;
|
package/dist/embed/index.js
CHANGED
|
@@ -799,12 +799,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
799
799
|
state.reconnectResetTimeout = null;
|
|
800
800
|
}, reconnectResetAfterMs);
|
|
801
801
|
}
|
|
802
|
-
listeners.forEach((listener) => listener({
|
|
803
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
804
|
-
sessionId: state.sessionId,
|
|
805
|
-
status: "active",
|
|
806
|
-
type: "session"
|
|
807
|
-
}));
|
|
808
802
|
state.pingInterval = setInterval(() => {
|
|
809
803
|
if (ws.readyState === WS_OPEN) {
|
|
810
804
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(()=>{var{defineProperty:k,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=k({},"__esModule",{value:!0}),V&&typeof V==="object"||typeof V==="function"){for(var A of w0(V))if(!S0.call(g,A))k(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)k(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)},N0=(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))},z0=(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=++_,U=(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=z0(c,J?.sampleRate??48000,V.sampleRateHz??16000),$=q0(q);V.onLevel?.(N0($)),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===U)D=null});return D=U,U},stop:()=>{_+=1,X({audioContext:g,mediaStream:R,processorNode:A,sourceNode:C}),V.onLevel?.(0),g=null,R=null,A=null,C=null}}};var F=(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 F(g.error);if("cause"in g)return F(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:F(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 N=(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,x=(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},j=(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(($)=>j($,"selected")===!0||j($,"nominated")===!0||E($,"state")==="succeeded").length,H=D.filter(($)=>E($,"readyState")!=="ended"&&E($,"trackState")!=="ended"&&j($,"ended")!==!0).length,O=D.filter(($)=>E($,"readyState")==="ended"||E($,"trackState")==="ended"||j($,"ended")===!0).length,L=A.reduce(($,S)=>$+(K(S,"packetsReceived")??0),0),W=R.reduce(($,S)=>$+(K(S,"packetsSent")??0),0),U=[...A,...R].reduce(($,S)=>$+Math.max(0,K(S,"packetsLost")??0),0),T=L+U,J=T===0?0:U/T,h=A.reduce(($,S)=>$+(K(S,"bytesReceived")??0),0),Z=R.reduce(($,S)=>$+(K(S,"bytesSent")??0),0),Q=x(_.map(($)=>o(K($,"currentRoundTripTime")??K($,"roundTripTime"))).filter(($)=>$!==void 0)),G=x([...A,...R].map(($)=>o(K($,"jitter"))).filter(($)=>$!==void 0)),c=x(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)N(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(V.requireLiveAudioTrack&&H===0)N(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(V.maxPacketLossRatio!==void 0&&J>V.maxPacketLossRatio)N(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)N(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)N(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:U,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((U)=>[f(U),U])),D=g.filter((U)=>(U.type==="inbound-rtp"||U.type==="outbound-rtp")&&E(U,"kind")!=="video"&&E(U,"mediaType")!=="video").map((U)=>{let T=U.type==="outbound-rtp"?"outbound":"inbound",J=T==="outbound"?"packetsSent":"packetsReceived",h=T==="outbound"?"bytesSent":"bytesReceived",Z=R.get(f(U)),Q=K(U,J),G=Z?K(Z,J):void 0,c=K(U,h),q=Z?K(Z,h):void 0,$=U.timestamp!==void 0&&Z?.timestamp!==void 0?U.timestamp-Z.timestamp:void 0;return{bytesDelta:c!==void 0&&q!==void 0?c-q:void 0,currentPackets:Q,direction:T,id:f(U),packetDelta:Q!==void 0&&G!==void 0?Q-G:void 0,previousPackets:G,timeDeltaMs:$}}),X=D.filter((U)=>U.direction==="inbound"),H=D.filter((U)=>U.direction==="outbound"),O=x(D.map((U)=>U.timeDeltaMs).filter((U)=>U!==void 0)),L=X.filter((U)=>V.maxInboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxInboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length,W=H.filter((U)=>V.maxOutboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxOutboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length;if(V.requireInboundAudio&&X.length===0)N(A,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(V.requireOutboundAudio&&H.length===0)N(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)N(A,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(O)}ms above ${String(V.maxGapMs)}ms.`);if(L>0)N(A,"error","media.webrtc_inbound_stalled",`${String(L)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(W>0)N(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((U)=>U.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,U=(I)=>k0(I,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=(I)=>{C.forEach((w)=>w(I))},h=(I)=>{C.forEach((w)=>w({message:I,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 I=T.pendingMessages.shift();if(I!==void 0)T.ws.send(I)}},G=(I)=>{for(let w of A.values())clearTimeout(w.timeout),w.reject(Error(I));A.clear()},c=()=>{if(L)return;let I=O;T.reconnectAttempts+=1;let w=U(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!==I)return;if(T.reconnectAttempts>_){h("Voice connection could not be restored.");return}try{if(g.prepareReconnect){let Y=new AbortController;W=Y;let B=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((M,O0)=>{Y.signal.addEventListener("abort",()=>O0(Error("Voice reconnect preparation timed out.")),{once:!0})})])}finally{if(clearTimeout(B),W===Y)W=null}}}catch(Y){if(L||O!==I)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!==I)return;q()},w)},q=()=>{if(L)return;let I=new WebSocket(v0(V,T.sessionId,T.scenarioId,g.query??{}));I.binaryType="arraybuffer",I.onopen=()=>{if(T.ws!==I){I.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===I&&I.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(I.readyState===1)I.send(JSON.stringify({type:"ping"}))},X)},I.onmessage=(w)=>{if(T.ws!==I)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))},I.onclose=(w)=>{if(T.ws!==I)return;T.ws=null,T.isConnected=!1,Z(),G("Voice connection interrupted");let y=R&&w.code!==1000&&w.code!==4401&&w.code!==4403&&w.code!==4500&&T.reconnectAttempts<_,Y=w.code===4401||w.code===4403,B=w.code===4500;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(B)C.forEach((M)=>M({message:"Voice provider initialization failed.",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 if(!B)h("Voice connection could not be restored.")}},T.ws=I},$=(I)=>{if(L)return;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)},S=(I)=>{$(JSON.stringify(I))},b=(I={})=>{if(I.sessionId&&I.sessionId!==T.sessionId)throw Error("Voice session switching requires a new connection instance.");if(I.sessionId)T.sessionId=I.sessionId;if(I.scenarioId)T.scenarioId=I.scenarioId;S({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,type:"start"})},I0=(I)=>{$(I)},U0=()=>{S({type:"end_turn"})},L0=(I)=>{if(T.ws?.readyState!==1)return Promise.reject(Error(`${I.action} is unavailable while disconnected`));let w=crypto.randomUUID(),{promise:y,reject:Y,resolve:B}=Promise.withResolvers(),M=setTimeout(()=>{A.delete(w),Y(Error(`${I.action} acknowledgement timed out`))},5000);return A.set(w,{reject:Y,resolve:B,timeout:M}),T.ws.send(JSON.stringify({...I,requestId:w,type:"call_control"})),y},W0=(I="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:I,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 I=T.ws;T.ws=null,I.close(1000)}T.isConnected=!1,C.clear()},X0=()=>{if(T.ws?.readyState===1)T.ws.close(4000,"absolutejs-voice-reconnect-proof")},G0=(I)=>{return C.add(I),()=>{C.delete(I)}};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(),U=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:U,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=C.subscribe((W)=>{let U=i(W);if(U){if(A.dispatch(U),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()},U=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,U(),J(),A.close(G)},disconnect:()=>{D=!0,U(),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 z=(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;">${z(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;">${z(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;">${z(V.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${V.agentState}" class="${z(V.classes.container)}" style="${C}">
|
|
1
|
+
(()=>{var{defineProperty:k,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=k({},"__esModule",{value:!0}),V&&typeof V==="object"||typeof V==="function"){for(var A of w0(V))if(!S0.call(g,A))k(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)k(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)},N0=(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))},z0=(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=++_,U=(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,y=null,Z=null,Q=null;try{if(y=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(y),Z=J.createScriptProcessor(4096,1,1),Z.onaudioprocess=(G)=>{let c=G.inputBuffer.getChannelData(0),q=z0(c,J?.sampleRate??48000,V.sampleRateHz??16000),$=q0(q);V.onLevel?.(N0($)),V.onAudio($)},Q.connect(Z),Z.connect(J.destination),L!==_)throw Error("Microphone capture stopped during startup.");g=J,R=y,A=Z,C=Q}catch(G){throw X({audioContext:J,mediaStream:y,processorNode:Z,sourceNode:Q}),G}})().finally(()=>{if(D===U)D=null});return D=U,U},stop:()=>{_+=1,X({audioContext:g,mediaStream:R,processorNode:A,sourceNode:C}),V.onLevel?.(0),g=null,R=null,A=null,C=null}}};var F=(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 F(g.error);if("cause"in g)return F(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:F(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 N=(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,x=(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},j=(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(($)=>j($,"selected")===!0||j($,"nominated")===!0||E($,"state")==="succeeded").length,H=D.filter(($)=>E($,"readyState")!=="ended"&&E($,"trackState")!=="ended"&&j($,"ended")!==!0).length,O=D.filter(($)=>E($,"readyState")==="ended"||E($,"trackState")==="ended"||j($,"ended")===!0).length,L=A.reduce(($,S)=>$+(K(S,"packetsReceived")??0),0),W=R.reduce(($,S)=>$+(K(S,"packetsSent")??0),0),U=[...A,...R].reduce(($,S)=>$+Math.max(0,K(S,"packetsLost")??0),0),T=L+U,J=T===0?0:U/T,y=A.reduce(($,S)=>$+(K(S,"bytesReceived")??0),0),Z=R.reduce(($,S)=>$+(K(S,"bytesSent")??0),0),Q=x(_.map(($)=>o(K($,"currentRoundTripTime")??K($,"roundTripTime"))).filter(($)=>$!==void 0)),G=x([...A,...R].map(($)=>o(K($,"jitter"))).filter(($)=>$!==void 0)),c=x(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)N(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(V.requireLiveAudioTrack&&H===0)N(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(V.maxPacketLossRatio!==void 0&&J>V.maxPacketLossRatio)N(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)N(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)N(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(G)}ms above ${String(V.maxJitterMs)}ms.`);return{activeCandidatePairs:X,audioLevelAverage:P0(q),bytesReceived:y,bytesSent:Z,checkedAt:Date.now(),endedAudioTracks:O,inboundPackets:L,issues:C,jitterBufferDelayMs:c,jitterMs:G,liveAudioTracks:H,outboundPackets:W,packetLossRatio:J,packetsLost:U,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((U)=>[f(U),U])),D=g.filter((U)=>(U.type==="inbound-rtp"||U.type==="outbound-rtp")&&E(U,"kind")!=="video"&&E(U,"mediaType")!=="video").map((U)=>{let T=U.type==="outbound-rtp"?"outbound":"inbound",J=T==="outbound"?"packetsSent":"packetsReceived",y=T==="outbound"?"bytesSent":"bytesReceived",Z=R.get(f(U)),Q=K(U,J),G=Z?K(Z,J):void 0,c=K(U,y),q=Z?K(Z,y):void 0,$=U.timestamp!==void 0&&Z?.timestamp!==void 0?U.timestamp-Z.timestamp:void 0;return{bytesDelta:c!==void 0&&q!==void 0?c-q:void 0,currentPackets:Q,direction:T,id:f(U),packetDelta:Q!==void 0&&G!==void 0?Q-G:void 0,previousPackets:G,timeDeltaMs:$}}),X=D.filter((U)=>U.direction==="inbound"),H=D.filter((U)=>U.direction==="outbound"),O=x(D.map((U)=>U.timeDeltaMs).filter((U)=>U!==void 0)),L=X.filter((U)=>V.maxInboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxInboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length,W=H.filter((U)=>V.maxOutboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxOutboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length;if(V.requireInboundAudio&&X.length===0)N(A,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(V.requireOutboundAudio&&H.length===0)N(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)N(A,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(O)}ms above ${String(V.maxGapMs)}ms.`);if(L>0)N(A,"error","media.webrtc_inbound_stalled",`${String(L)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(W>0)N(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((U)=>U.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,U=(I)=>k0(I,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=(I)=>{C.forEach((w)=>w(I))},y=(I)=>{C.forEach((w)=>w({message:I,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 I=T.pendingMessages.shift();if(I!==void 0)T.ws.send(I)}},G=(I)=>{for(let w of A.values())clearTimeout(w.timeout),w.reject(Error(I));A.clear()},c=()=>{if(L)return;let I=O;T.reconnectAttempts+=1;let w=U(T.reconnectAttempts),h=Date.now()+w;J({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,nextAttemptAt:h,status:"reconnecting"},type:"connection"}),T.reconnectTimeout=setTimeout(async()=>{if(L||O!==I)return;if(T.reconnectAttempts>_){y("Voice connection could not be restored.");return}try{if(g.prepareReconnect){let Y=new AbortController;W=Y;let B=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((M,O0)=>{Y.signal.addEventListener("abort",()=>O0(Error("Voice reconnect preparation timed out.")),{once:!0})})])}finally{if(clearTimeout(B),W===Y)W=null}}}catch(Y){if(L||O!==I)return;if(Y instanceof s){y(Y.message);return}if(T.reconnectAttempts<_)c();else y("Voice authorization could not be renewed for reconnect.");return}if(L||O!==I)return;q()},w)},q=()=>{if(L)return;let I=new WebSocket(v0(V,T.sessionId,T.scenarioId,g.query??{}));I.binaryType="arraybuffer",I.onopen=()=>{if(T.ws!==I){I.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===I&&I.readyState===1)T.reconnectAttempts=0;T.reconnectResetTimeout=null},H);T.pingInterval=setInterval(()=>{if(I.readyState===1)I.send(JSON.stringify({type:"ping"}))},X)},I.onmessage=(w)=>{if(T.ws!==I)return;let h=o0(w);if(!h)return;if(h.type==="session")T.sessionId=h.sessionId,T.scenarioId=h.scenarioId??T.scenarioId;if(h.type==="call_control_ack"){let Y=A.get(h.requestId);if(Y)if(clearTimeout(Y.timeout),A.delete(h.requestId),h.ok)Y.resolve();else Y.reject(Error(h.message??`${h.action} was not applied`))}C.forEach((Y)=>Y(h))},I.onclose=(w)=>{if(T.ws!==I)return;T.ws=null,T.isConnected=!1,Z(),G("Voice connection interrupted");let h=R&&w.code!==1000&&w.code!==4401&&w.code!==4403&&w.code!==4500&&T.reconnectAttempts<_,Y=w.code===4401||w.code===4403,B=w.code===4500;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(B)C.forEach((M)=>M({message:"Voice provider initialization failed.",recoverable:!1,type:"error"}));if(h)c();else if(R&&w.code!==1000){if(Y)J({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,status:"exhausted"},type:"connection"});else if(!B)y("Voice connection could not be restored.")}},T.ws=I},$=(I)=>{if(L)return;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)},S=(I)=>{$(JSON.stringify(I))},b=(I={})=>{if(I.sessionId&&I.sessionId!==T.sessionId)throw Error("Voice session switching requires a new connection instance.");if(I.sessionId)T.sessionId=I.sessionId;if(I.scenarioId)T.scenarioId=I.scenarioId;S({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,type:"start"})},I0=(I)=>{$(I)},U0=()=>{S({type:"end_turn"})},L0=(I)=>{if(T.ws?.readyState!==1)return Promise.reject(Error(`${I.action} is unavailable while disconnected`));let w=crypto.randomUUID(),{promise:h,reject:Y,resolve:B}=Promise.withResolvers(),M=setTimeout(()=>{A.delete(w),Y(Error(`${I.action} acknowledgement timed out`))},5000);return A.set(w,{reject:Y,resolve:B,timeout:M}),T.ws.send(JSON.stringify({...I,requestId:w,type:"call_control"})),h},W0=(I="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:I,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 I=T.ws;T.ws=null,I.close(1000)}T.isConnected=!1,C.clear()},X0=()=>{if(T.ws?.readyState===1)T.ws.close(4000,"absolutejs-voice-reconnect-proof")},G0=(I)=>{return C.add(I),()=>{C.delete(I)}};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(),U=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:U,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=C.subscribe((W)=>{let U=i(W);if(U){if(A.dispatch(U),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()},U=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()},y=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,U(),J(),A.close(G)},disconnect:()=>{D=!0,U(),J(),A.disconnect()},startRecording:y,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 y()},get turns(){return H.turns}}};var z=(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;">${z(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;">${z(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;">${z(V.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${V.agentState}" class="${z(V.classes.container)}" style="${C}">
|
|
2
2
|
<div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
|
|
3
3
|
<span aria-hidden="true" class="${z(V.classes.dot)}" style="${A}"></span>
|
|
4
4
|
<strong style="font-size:15px;">${z(V.title)}</strong>
|
package/dist/index.js
CHANGED
|
@@ -6880,6 +6880,8 @@ var createVoiceSession = (options) => {
|
|
|
6880
6880
|
if (session.status === "completed" || session.status === "failed") {
|
|
6881
6881
|
await options.store.set(options.id, session);
|
|
6882
6882
|
await send({
|
|
6883
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
6884
|
+
paused: Boolean(session.pause),
|
|
6883
6885
|
sessionId: options.id,
|
|
6884
6886
|
status: session.status,
|
|
6885
6887
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
|
@@ -6915,6 +6917,8 @@ var createVoiceSession = (options) => {
|
|
|
6915
6917
|
await sendCallLifecycle(session);
|
|
6916
6918
|
}
|
|
6917
6919
|
await send({
|
|
6920
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
6921
|
+
paused: callerPaused,
|
|
6918
6922
|
sessionId: options.id,
|
|
6919
6923
|
status: session.status,
|
|
6920
6924
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
|
@@ -40429,8 +40433,15 @@ var voice = (config) => {
|
|
|
40429
40433
|
};
|
|
40430
40434
|
const createAndConnectSession = async (ws, sessionId, scenarioId) => {
|
|
40431
40435
|
const identity = socketIdentity(ws);
|
|
40432
|
-
|
|
40433
|
-
|
|
40436
|
+
let session;
|
|
40437
|
+
try {
|
|
40438
|
+
session = await createManagedSession(ws, sessionId, scenarioId);
|
|
40439
|
+
} catch (error) {
|
|
40440
|
+
runtime.logger.warn?.(`[voice] session initialization failed for "${sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
40441
|
+
closedSockets.add(identity);
|
|
40442
|
+
ws.close(4500, "voice session initialization failed");
|
|
40443
|
+
throw error;
|
|
40444
|
+
}
|
|
40434
40445
|
if (closedSockets.has(identity) || !socketIsOpen(ws) || runtime.activeSockets.get(sessionId) !== identity) {
|
|
40435
40446
|
ws.close(1000, "superseded");
|
|
40436
40447
|
throw new Error("Voice socket was superseded during session creation");
|
|
@@ -40446,6 +40457,7 @@ var voice = (config) => {
|
|
|
40446
40457
|
ws.close(4500, "voice session initialization failed");
|
|
40447
40458
|
throw error;
|
|
40448
40459
|
}
|
|
40460
|
+
const typedSession = session;
|
|
40449
40461
|
if (closedSockets.has(identity) || !socketIsOpen(ws) || runtime.activeSockets.get(sessionId) !== identity) {
|
|
40450
40462
|
await session.disconnect({
|
|
40451
40463
|
code: 1000,
|
package/dist/react/index.js
CHANGED
|
@@ -11698,12 +11698,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
11698
11698
|
state.reconnectResetTimeout = null;
|
|
11699
11699
|
}, reconnectResetAfterMs);
|
|
11700
11700
|
}
|
|
11701
|
-
listeners.forEach((listener) => listener({
|
|
11702
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
11703
|
-
sessionId: state.sessionId,
|
|
11704
|
-
status: "active",
|
|
11705
|
-
type: "session"
|
|
11706
|
-
}));
|
|
11707
11701
|
state.pingInterval = setInterval(() => {
|
|
11708
11702
|
if (ws.readyState === WS_OPEN) {
|
|
11709
11703
|
ws.send(JSON.stringify({ type: "ping" }));
|
package/dist/svelte/index.js
CHANGED
|
@@ -1067,12 +1067,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
1067
1067
|
state.reconnectResetTimeout = null;
|
|
1068
1068
|
}, reconnectResetAfterMs);
|
|
1069
1069
|
}
|
|
1070
|
-
listeners.forEach((listener) => listener({
|
|
1071
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
1072
|
-
sessionId: state.sessionId,
|
|
1073
|
-
status: "active",
|
|
1074
|
-
type: "session"
|
|
1075
|
-
}));
|
|
1076
1070
|
state.pingInterval = setInterval(() => {
|
|
1077
1071
|
if (ws.readyState === WS_OPEN) {
|
|
1078
1072
|
ws.send(JSON.stringify({ type: "ping" }));
|
package/dist/testing/index.js
CHANGED
|
@@ -3288,12 +3288,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
3288
3288
|
state.reconnectResetTimeout = null;
|
|
3289
3289
|
}, reconnectResetAfterMs);
|
|
3290
3290
|
}
|
|
3291
|
-
listeners.forEach((listener) => listener({
|
|
3292
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
3293
|
-
sessionId: state.sessionId,
|
|
3294
|
-
status: "active",
|
|
3295
|
-
type: "session"
|
|
3296
|
-
}));
|
|
3297
3291
|
state.pingInterval = setInterval(() => {
|
|
3298
3292
|
if (ws.readyState === WS_OPEN) {
|
|
3299
3293
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -9817,6 +9811,8 @@ var createVoiceSession = (options) => {
|
|
|
9817
9811
|
if (session.status === "completed" || session.status === "failed") {
|
|
9818
9812
|
await options.store.set(options.id, session);
|
|
9819
9813
|
await send({
|
|
9814
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
9815
|
+
paused: Boolean(session.pause),
|
|
9820
9816
|
sessionId: options.id,
|
|
9821
9817
|
status: session.status,
|
|
9822
9818
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
|
@@ -9852,6 +9848,8 @@ var createVoiceSession = (options) => {
|
|
|
9852
9848
|
await sendCallLifecycle(session);
|
|
9853
9849
|
}
|
|
9854
9850
|
await send({
|
|
9851
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
9852
|
+
paused: callerPaused,
|
|
9855
9853
|
sessionId: options.id,
|
|
9856
9854
|
status: session.status,
|
|
9857
9855
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
package/dist/vue/index.js
CHANGED
|
@@ -11094,12 +11094,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
11094
11094
|
state.reconnectResetTimeout = null;
|
|
11095
11095
|
}, reconnectResetAfterMs);
|
|
11096
11096
|
}
|
|
11097
|
-
listeners.forEach((listener) => listener({
|
|
11098
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
11099
|
-
sessionId: state.sessionId,
|
|
11100
|
-
status: "active",
|
|
11101
|
-
type: "session"
|
|
11102
|
-
}));
|
|
11103
11097
|
state.pingInterval = setInterval(() => {
|
|
11104
11098
|
if (ws.readyState === WS_OPEN) {
|
|
11105
11099
|
ws.send(JSON.stringify({ type: "ping" }));
|