@absolutejs/voice 0.0.22-beta.674 → 0.0.22-beta.676
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/CHANGELOG.md +13 -0
- package/changelog.json +19 -0
- package/dist/angular/index.js +29 -29
- package/dist/client/htmxBootstrap.js +1 -1
- package/dist/client/index.js +181 -181
- package/dist/drizzle/index.js +40 -40
- package/dist/embed/index.js +3 -3
- package/dist/embed/voice-widget.js +8 -8
- package/dist/index.js +998 -959
- package/dist/react/index.js +863 -863
- package/dist/svelte/index.js +35 -35
- package/dist/testing/index.js +98 -72
- package/dist/vue/index.js +47 -47
- package/package.json +8 -4
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(()=>{var{defineProperty:k,getOwnPropertyNames:S0,getOwnPropertyDescriptor:O0}=Object,w0=Object.prototype.hasOwnProperty;function h0(V){return this[V]}var J0=(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 S0(V))if(!w0.call(g,A))k(g,A,{get:h0.bind(V,A),enumerable:!(C=O0(V,A))||C.enumerable})}return l.set(V,g),g},l;var Y0=(V)=>V;function Z0(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:Z0.bind(g,C)})};var _V={};Q0(_V,{mount:()=>T0,default:()=>RV,VOICE_EMBED_VERSION:()=>$0});var E0=(V)=>{if(typeof V!=="string")return V;return document.querySelector(V)},c0=(V,g,C,A)=>{let H=g??V.getAttribute("hx-get")??"";if(!H)return"";let _=new URL(H,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=E0(g.element);if(!C)return()=>{};let A=g.eventName??"voice-refresh",H=g.sessionQueryParam??"sessionId",_=()=>{let D=window,$=c0(C,g.route,H,V.sessionId);if($)C.setAttribute("hx-get",$);D.htmx?.process?.(C),D.htmx?.trigger?.(C,A)},y=V.subscribe(_);return _(),()=>{y()}};var K0=(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=K0(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 H of C){let _=H/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,H=Math.round(V.length/A),_=new Float32Array(H),y=0,D=0;while(y<_.length){let $=Math.round((y+1)*A),G=0,L=0;for(let W=D;W<$&&W<V.length;W+=1)G+=V[W]??0,L+=1;_[y]=L>0?G/L:0,y+=1,D=$}return _},v=(V)=>{let g=null,C=null,A=null,H=null,_=0,y=null,D=(L)=>{L.processorNode?.disconnect(),L.sourceNode?.disconnect(),L.mediaStream?.getTracks().forEach((W)=>W.stop()),L.audioContext?.close()};return{start:()=>{if(H)return Promise.resolve();if(y)return y;let L=++_,U=(async()=>{if(!V.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let R=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!R)throw Error("Browser microphone capture requires AudioContext support.");let O=null,Y=null,J=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(O=new R,O.state==="suspended")await O.resume();if(L!==_)throw Error("Microphone capture stopped during startup.");if(Q=O.createMediaStreamSource(Y),J=O.createScriptProcessor(4096,1,1),J.onaudioprocess=(X)=>{let c=X.inputBuffer.getChannelData(0),q=z0(c,O?.sampleRate??48000,V.sampleRateHz??16000),T=q0(q);V.onLevel?.(N0(T)),V.onAudio(T)},Q.connect(J),J.connect(O.destination),L!==_)throw Error("Microphone capture stopped during startup.");g=O,H=Y,A=J,C=Q}catch(X){throw D({audioContext:O,mediaStream:Y,processorNode:J,sourceNode:Q}),X}})().finally(()=>{if(y===U)y=null});return y=U,U},stop:()=>{_+=1,D({audioContext:g,mediaStream:H,processorNode:A,sourceNode:C}),V.onLevel?.(0),g=null,H=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"playback_rate":return{rate:V.rate,type:"playback_rate"};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{paused:V.paused,pauseExpiresAt:V.pauseExpiresAt,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 b0=(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 E=(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},K=(V,g)=>{let C=V[g];return typeof C==="string"?C:void 0},f=(V)=>String(V.id??K(V,"ssrc")??E(V,"ssrc")??K(V,"trackIdentifier")??K(V,"mid")??"unknown"),o=(V)=>V===void 0?void 0:V*1000;var P0=(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((T)=>T.type==="inbound-rtp"&&K(T,"kind")!=="video"),H=g.filter((T)=>T.type==="outbound-rtp"&&K(T,"kind")!=="video"),_=g.filter((T)=>T.type==="candidate-pair"),y=g.filter((T)=>(T.type==="track"||T.type==="media-source")&&K(T,"kind")==="audio"),D=_.filter((T)=>j(T,"selected")===!0||j(T,"nominated")===!0||K(T,"state")==="succeeded").length,$=y.filter((T)=>K(T,"readyState")!=="ended"&&K(T,"trackState")!=="ended"&&j(T,"ended")!==!0).length,G=y.filter((T)=>K(T,"readyState")==="ended"||K(T,"trackState")==="ended"||j(T,"ended")===!0).length,L=A.reduce((T,w)=>T+(E(w,"packetsReceived")??0),0),W=H.reduce((T,w)=>T+(E(w,"packetsSent")??0),0),U=[...A,...H].reduce((T,w)=>T+Math.max(0,E(w,"packetsLost")??0),0),R=L+U,O=R===0?0:U/R,Y=A.reduce((T,w)=>T+(E(w,"bytesReceived")??0),0),J=H.reduce((T,w)=>T+(E(w,"bytesSent")??0),0),Q=x(_.map((T)=>o(E(T,"currentRoundTripTime")??E(T,"roundTripTime"))).filter((T)=>T!==void 0)),X=x([...A,...H].map((T)=>o(E(T,"jitter"))).filter((T)=>T!==void 0)),c=x(A.map((T)=>{let w=E(T,"jitterBufferDelay"),M=E(T,"jitterBufferEmittedCount");return w!==void 0&&M!==void 0&&M>0?w/M*1000:void 0}).filter((T)=>T!==void 0)),q=y.map((T)=>E(T,"audioLevel")).filter((T)=>T!==void 0);if(V.requireConnectedCandidatePair&&_.length>0&&D===0)N(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(V.requireLiveAudioTrack&&$===0)N(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(V.maxPacketLossRatio!==void 0&&O>V.maxPacketLossRatio)N(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(O)} 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&&X!==void 0&&X>V.maxJitterMs)N(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(X)}ms above ${String(V.maxJitterMs)}ms.`);return{activeCandidatePairs:D,audioLevelAverage:b0(q),bytesReceived:Y,bytesSent:J,checkedAt:Date.now(),endedAudioTracks:G,inboundPackets:L,issues:C,jitterBufferDelayMs:c,jitterMs:X,liveAudioTracks:$,outboundPackets:W,packetLossRatio:O,packetsLost:U,roundTripTimeMs:Q,status:C.some((T)=>T.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:g.length}},m=async(V)=>{return[...(await V.peerConnection.getStats(V.selector??null)).values()].map(P0)};var u=(V={})=>{let g=V.stats??[],C=V.previousStats??[],A=[],H=new Map(C.map((U)=>[f(U),U])),y=g.filter((U)=>(U.type==="inbound-rtp"||U.type==="outbound-rtp")&&K(U,"kind")!=="video"&&K(U,"mediaType")!=="video").map((U)=>{let R=U.type==="outbound-rtp"?"outbound":"inbound",O=R==="outbound"?"packetsSent":"packetsReceived",Y=R==="outbound"?"bytesSent":"bytesReceived",J=H.get(f(U)),Q=E(U,O),X=J?E(J,O):void 0,c=E(U,Y),q=J?E(J,Y):void 0,T=U.timestamp!==void 0&&J?.timestamp!==void 0?U.timestamp-J.timestamp:void 0;return{bytesDelta:c!==void 0&&q!==void 0?c-q:void 0,currentPackets:Q,direction:R,id:f(U),packetDelta:Q!==void 0&&X!==void 0?Q-X:void 0,previousPackets:X,timeDeltaMs:T}}),D=y.filter((U)=>U.direction==="inbound"),$=y.filter((U)=>U.direction==="outbound"),G=x(y.map((U)=>U.timeDeltaMs).filter((U)=>U!==void 0)),L=D.filter((U)=>V.maxInboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxInboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length,W=$.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&&D.length===0)N(A,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(V.requireOutboundAudio&&$.length===0)N(A,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(V.maxGapMs!==void 0&&G!==void 0&&G>V.maxGapMs)N(A,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(G)}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:D.length,issues:A,maxObservedGapMs:G,outboundAudioStreams:$.length,stalledInboundStreams:L,stalledOutboundStreams:W,status:A.some((U)=>U.severity==="error")?"fail":A.length>0?"warn":"pass",streams:y,totalStats:g.length}};var B0="/api/voice/browser-media",M0=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??B0,{body:JSON.stringify(V),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(V)=>{let g=null,C=[],A=async()=>{let y=await j0(V);if(!y)return;let D=await m({peerConnection:y}),$=n({...V,stats:D}),G=V.continuity===!1?void 0:u({...V.continuity,previousStats:C,stats:D}),L={at:Date.now(),continuity:G,report:$,scenarioId:V.getScenarioId?.()??null,sessionId:V.getSessionId?.()??null};return C=D,V.onReport?.(L),await x0(L,V),L},H=()=>{A().catch((y)=>{V.onError?.(y)})},_=()=>{if(g)clearInterval(g),g=null};return{close:_,reportOnce:A,stop:_,start:()=>{if(g)return;H(),g=setInterval(H,V.intervalMs??M0)}}};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 b=()=>{},F0=()=>Promise.resolve(),f0=()=>b,l0={callControl:F0,close:b,disconnect:b,endTurn:b,send:b,sendAudio:b,simulateDisconnect:b,subscribe:f0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},d0=()=>crypto.randomUUID(),v0=(V,g,C,A)=>{let{hostname:H,port:_,protocol:y}=window.location,D=y==="https:"?"wss:":"ws:",$=_?`:${_}`:"",G=new URL(`${D}//${H}${$}${V}`);if(G.searchParams.set("sessionId",g),C)G.searchParams.set("scenarioId",C);for(let[L,W]of Object.entries(A))if(L!=="sessionId"&&L!=="scenarioId"&&W)G.searchParams.set(L,W);return G.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"playback_rate":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,H=g.reconnect!==!1,_=g.maxReconnectAttempts??15,y=g.reconnectMaxDelayMs??8000,D=g.pingInterval??30000,$=g.reconnectResetAfterMs??30000,G=0,L=!1,W=null,U=(I)=>k0(I,500,y),R={isConnected:!1,pendingMessages:[],scenarioId:g.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:g.sessionId??d0(),ws:null},O=(I)=>{C.forEach((S)=>S(I))},Y=(I)=>{C.forEach((S)=>S({message:I,recoverable:!1,type:"error"})),O({reconnect:{attempts:R.reconnectAttempts,maxAttempts:_,status:"exhausted"},type:"connection"})},J=()=>{if(R.pingInterval)clearInterval(R.pingInterval),R.pingInterval=null;if(R.reconnectTimeout)clearTimeout(R.reconnectTimeout),R.reconnectTimeout=null;if(R.reconnectResetTimeout)clearTimeout(R.reconnectResetTimeout),R.reconnectResetTimeout=null},Q=()=>{if(R.ws?.readyState!==1)return;while(R.pendingMessages.length>0){let I=R.pendingMessages.shift();if(I!==void 0)R.ws.send(I)}},X=(I)=>{for(let S of A.values())clearTimeout(S.timeout),S.reject(Error(I));A.clear()},c=()=>{if(L)return;let I=G;R.reconnectAttempts+=1;let S=U(R.reconnectAttempts),Z=Date.now()+S;O({reconnect:{attempts:R.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,nextAttemptAt:Z,status:"reconnecting"},type:"connection"}),R.reconnectTimeout=setTimeout(async()=>{if(L||G!==I)return;if(R.reconnectAttempts>_){Y("Voice connection could not be restored.");return}try{if(g.prepareReconnect){let h=new AbortController;W=h;let P=setTimeout(()=>h.abort("Voice reconnect preparation timed out"),g.prepareReconnectTimeoutMs??1e4);try{await Promise.race([g.prepareReconnect({attempt:R.reconnectAttempts,path:V,scenarioId:R.scenarioId,sessionId:R.sessionId,signal:h.signal}),new Promise((B,G0)=>{h.signal.addEventListener("abort",()=>G0(Error("Voice reconnect preparation timed out.")),{once:!0})})])}finally{if(clearTimeout(P),W===h)W=null}}}catch(h){if(L||G!==I)return;if(h instanceof s){Y(h.message);return}if(R.reconnectAttempts<_)c();else Y("Voice authorization could not be renewed for reconnect.");return}if(L||G!==I)return;q()},S)},q=()=>{if(L)return;let I=new WebSocket(v0(V,R.sessionId,R.scenarioId,g.query??{}));I.binaryType="arraybuffer",I.onopen=()=>{if(R.ws!==I){I.close(1000);return}let S=R.reconnectAttempts>0;if(R.isConnected=!0,Q(),S)O({reconnect:{attempts:R.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:_,status:"resumed"},type:"connection"}),R.reconnectResetTimeout=setTimeout(()=>{if(R.ws===I&&I.readyState===1)R.reconnectAttempts=0;R.reconnectResetTimeout=null},$);R.pingInterval=setInterval(()=>{if(I.readyState===1)I.send(JSON.stringify({type:"ping"}))},D)},I.onmessage=(S)=>{if(R.ws!==I)return;let Z=o0(S);if(!Z)return;if(Z.type==="session")R.sessionId=Z.sessionId,R.scenarioId=Z.scenarioId??R.scenarioId;if(Z.type==="call_control_ack"){let h=A.get(Z.requestId);if(h)if(clearTimeout(h.timeout),A.delete(Z.requestId),Z.ok)h.resolve();else h.reject(Error(Z.message??`${Z.action} was not applied`))}C.forEach((h)=>h(Z))},I.onclose=(S)=>{if(R.ws!==I)return;R.ws=null,R.isConnected=!1,J(),X("Voice connection interrupted");let Z=H&&S.code!==1000&&S.code!==4401&&S.code!==4403&&S.code!==4500&&R.reconnectAttempts<_,h=S.code===4401||S.code===4403,P=S.code===4500;if(h)C.forEach((B)=>B({message:S.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(P)C.forEach((B)=>B({message:"Voice provider initialization failed.",recoverable:!1,type:"error"}));if(Z)c();else if(H&&S.code!==1000){if(h)O({reconnect:{attempts:R.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,status:"exhausted"},type:"connection"});else if(!P)Y("Voice connection could not be restored.")}},R.ws=I},T=(I)=>{if(L)return;if(R.ws?.readyState===1){R.ws.send(I);return}if(typeof I!=="string")return;if(R.pendingMessages.length>=100)R.pendingMessages.shift();R.pendingMessages.push(I)},w=(I)=>{T(JSON.stringify(I))},M=(I={})=>{if(I.sessionId&&I.sessionId!==R.sessionId)throw Error("Voice session switching requires a new connection instance.");if(I.sessionId)R.sessionId=I.sessionId;if(I.scenarioId)R.scenarioId=I.scenarioId;w({scenarioId:R.scenarioId??void 0,sessionId:R.sessionId,type:"start"})},I0=(I)=>{T(I)},U0=()=>{w({type:"end_turn"})},L0=(I)=>{if(R.ws?.readyState!==1)return Promise.reject(Error(`${I.action} is unavailable while disconnected`));let S=crypto.randomUUID(),{promise:Z,reject:h,resolve:P}=Promise.withResolvers(),B=setTimeout(()=>{A.delete(S),h(Error(`${I.action} acknowledgement timed out`))},5000);return A.set(S,{reject:h,resolve:P,timeout:B}),R.ws.send(JSON.stringify({...I,requestId:S,type:"call_control"})),Z},W0=(I="client-close")=>{if(L=!0,W?.abort(),W=null,G+=1,J(),X("Voice connection closed"),R.pendingMessages.length=0,R.ws){let S=R.ws;if(R.ws=null,S.readyState===1)S.send(JSON.stringify({reason:I,type:"close"}));S.close(1000)}R.isConnected=!1,C.clear()},y0=()=>{if(L=!0,W?.abort(),W=null,G+=1,J(),X("Voice connection disconnected"),R.pendingMessages.length=0,R.ws){let I=R.ws;R.ws=null,I.close(1000)}R.isConnected=!1,C.clear()},D0=()=>{if(R.ws?.readyState===1)R.ws.close(4000,"absolutejs-voice-reconnect-proof")},X0=(I)=>{return C.add(I),()=>{C.delete(I)}};return q(),{callControl:L0,close:W0,disconnect:y0,endTurn:U0,send:w,sendAudio:I0,simulateDisconnect:D0,start:M,subscribe:X0,getReadyState:()=>R.ws?.readyState??3,getScenarioId:()=>R.scenarioId??"",getSessionId:()=>R.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,paused:!1,partial:"",playbackRate:null,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"playback_rate":V={...V,playbackRate:Math.max(0.5,Math.min(2,_.rate))};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,paused:_.paused??!1,pauseExpiresAt:_.pauseExpiresAt,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(),H=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,y=!1,D=(W)=>Promise.resolve().then(()=>{if(y)return;if(!W?.sessionId&&!W?.scenarioId)return;C.start(W),H?.start()}),$=()=>{_.forEach((W)=>W())},G=()=>{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((R)=>R.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")G();$()}});return{start:D,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){y=!0,L(),H?.close(),C.close(W),A.dispatch({type:"disconnected"}),$()},disconnect(){y=!0,L(),H?.close(),C.disconnect(),A.dispatch({type:"disconnected"}),$()},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 playbackRate(){return A.getSnapshot().playbackRate},get paused(){return A.getSnapshot().paused},get pauseExpiresAt(){return A.getSnapshot().pauseExpiresAt},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],H=a0[C],_=V?.silenceMs??H.silenceMs??A.silenceMs;return{profile:g,qualityProfile:C,minSilenceMs:Math.min(_,V?.minSilenceMs??H.minSilenceMs??A.minSilenceMs),silenceMs:_,speechThreshold:V?.speechThreshold??H.speechThreshold??A.speechThreshold,transcriptStabilityMs:V?.transcriptStabilityMs??H.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,paused:V.paused,pauseExpiresAt:V.pauseExpiresAt,partial:V.partial,playbackRate:V.playbackRate,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}),H=null,_=0,y=!1,D=null,$=t0(A),G=new Set,L=()=>{for(let X of G)X()},W=()=>{if($={...$,assistantAudio:[...A.assistantAudio],assistantStreamingText:A.assistantStreamingText,assistantTexts:[...A.assistantTexts],call:A.call,error:A.error,isConnected:A.isConnected,paused:A.paused,pauseExpiresAt:A.pauseExpiresAt,partial:A.partial,playbackRate:A.playbackRate,reconnect:A.reconnect,sessionId:A.sessionId,sessionMetadata:A.sessionMetadata,scenarioId:A.scenarioId,status:A.status,turns:[...A.turns]},g.autoStopOnComplete!==!1&&$.status==="completed"&&$.isRecording)H?.stop(),H=null,$={...$,isRecording:!1};L()},U=A.subscribe(W);W();let R=()=>{if(H)return H;return H=v({channelCount:g.capture?.channelCount??C.capture.channelCount,onLevel:g.capture?.onLevel,onAudio:(X)=>{if(g.capture?.onAudio){g.capture.onAudio(X,A.sendAudio);return}A.sendAudio(X)},sampleRateHz:g.capture?.sampleRateHz??C.capture.sampleRateHz,...g.capture?.stream?{stream:g.capture.stream}:{}}),H},O=()=>{_+=1,H?.stop(),H=null,$={...$,isRecording:!1},L()},Y=async()=>{if(y)throw Error("Voice controller is closed.");if($.isRecording)return;if(D)return D;let X=++_,c=R(),T=(async()=>{try{if($={...$,recordingError:null},L(),await c.start(),y||X!==_||H!==c){c.stop();return}$={...$,isRecording:!0},L()}catch(w){if(c.stop(),X!==_||H!==c)throw w;throw H=null,$={...$,isRecording:!1,recordingError:w instanceof Error?w.message:String(w)},L(),w}})().finally(()=>{if(D===T)D=null});return D=T,D};return{close:(X)=>{y=!0,U(),O(),A.close(X)},disconnect:()=>{y=!0,U(),O(),A.disconnect()},startRecording:Y,stopRecording:O,get assistantAudio(){return $.assistantAudio},get assistantTexts(){return $.assistantTexts},get assistantStreamingText(){return $.assistantStreamingText},bindHTMX(X){return d(A,X)},get call(){return $.call},callControl:(X)=>A.callControl(X),endTurn:()=>A.endTurn(),get error(){return $.error},getServerSnapshot:()=>$,getSnapshot:()=>$,get isConnected(){return $.isConnected},get isRecording(){return $.isRecording},get partial(){return $.partial},get playbackRate(){return $.playbackRate},get paused(){return $.paused},get pauseExpiresAt(){return $.pauseExpiresAt},get reconnect(){return $.reconnect},get recordingError(){return $.recordingError},get scenarioId(){return $.scenarioId},sendAudio:(X)=>A.sendAudio(X),get sessionId(){return $.sessionId},get sessionMetadata(){return $.sessionMetadata},simulateDisconnect:()=>A.simulateDisconnect(),get status(){return $.status},subscribe:(X)=>{return G.add(X),()=>{G.delete(X)}},toggleRecording:async()=>{if($.isRecording){O();return}await Y()},get turns(){return $.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,H=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:H}),y=!V.state.isConnected&&V.state.status!=="idle"&&!V.state.error,D=V.state.error?"Error":y?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:D,theme:g,title:V.title??"Voice"}},AV=(V)=>typeof V==="number"?`${V}px`:V,R0=(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;`,H=[];if(V.controls.canStart)H.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)H.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)H.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:O,getOwnPropertyNames:be,getOwnPropertyDescriptor:ve}=Object,Ae=Object.prototype.hasOwnProperty;function Se(e){return this[e]}var Me=(e)=>{var t=(B??=new WeakMap).get(e),r;if(t)return t;if(t=O({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function"){for(var n of be(e))if(!Ae.call(t,n))O(t,n,{get:Se.bind(e,n),enumerable:!(r=ve(e,n))||r.enumerable})}return B.set(e,t),t},B;var we=(e)=>e;function Ie(e,t){this[e]=we.bind(null,t)}var Te=(e,t)=>{for(var r in t)O(e,r,{get:t[r],enumerable:!0,configurable:!0,set:Ie.bind(t,r)})};var ot={};Te(ot,{VOICE_EMBED_VERSION:()=>ce,default:()=>at,mount:()=>ie});var Re=(e)=>{if(typeof e!=="string")return e;return document.querySelector(e)},Ee=(e,t,r,n)=>{let c=t??e.getAttribute("hx-get")??"";if(!c)return"";let s=new URL(c,window.location.origin);if(n)s.searchParams.set(r,n);else s.searchParams.delete(r);return`${s.pathname}${s.search}${s.hash}`},W=(e,t)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let r=Re(t.element);if(!r)return()=>{};let n=t.eventName??"voice-refresh",c=t.sessionQueryParam??"sessionId",s=()=>{let f=window,i=Ee(r,t.route,c,e.sessionId);if(i)r.setAttribute("hx-get",i);f.htmx?.process?.(r),f.htmx?.trigger?.(r,n)},p=e.subscribe(s);return s(),()=>{p()}};var xe=(e)=>Math.max(-1,Math.min(1,e)),_e=(e)=>{let t=new Int16Array(e.length);for(let r=0;r<e.length;r+=1){let n=xe(e[r]??0);t[r]=n<0?n*32768:n*32767}return new Uint8Array(t.buffer)},Fe=(e)=>{let t=e instanceof Uint8Array?e:new Uint8Array(e);if(t.byteLength<2)return 0;let r=new Int16Array(t.buffer,t.byteOffset,Math.floor(t.byteLength/2));if(r.length===0)return 0;let n=0;for(let c of r){let s=c/32768;n+=s*s}return Math.min(1,Math.max(0,Math.sqrt(n/r.length)*5.5))},ke=(e,t,r)=>{if(t===r)return e;let n=t/r,c=Math.round(e.length/n),s=new Float32Array(c),p=0,f=0;while(p<s.length){let i=Math.round((p+1)*n),h=0,u=0;for(let m=f;m<i&&m<e.length;m+=1)h+=e[m]??0,u+=1;s[p]=u>0?h/u:0,p+=1,f=i}return s},q=(e)=>{let t=null,r=null,n=null,c=null,s=0,p=null,f=(u)=>{u.processorNode?.disconnect(),u.sourceNode?.disconnect(),u.mediaStream?.getTracks().forEach((m)=>m.stop()),u.audioContext?.close()};return{start:()=>{if(c)return Promise.resolve();if(p)return p;let u=++s,l=(async()=>{if(!e.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let o=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!o)throw Error("Browser microphone capture requires AudioContext support.");let b=null,M=null,S=null,I=null;try{if(M=e.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:e.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),u!==s)throw Error("Microphone capture stopped during startup.");if(b=new o,b.state==="suspended")await b.resume();if(u!==s)throw Error("Microphone capture stopped during startup.");if(I=b.createMediaStreamSource(M),S=b.createScriptProcessor(4096,1,1),S.onaudioprocess=(g)=>{let R=g.inputBuffer.getChannelData(0),x=ke(R,b?.sampleRate??48000,e.sampleRateHz??16000),a=_e(x);e.onLevel?.(Fe(a)),e.onAudio(a)},I.connect(S),S.connect(b.destination),u!==s)throw Error("Microphone capture stopped during startup.");t=b,c=M,n=S,r=I}catch(g){throw f({audioContext:b,mediaStream:M,processorNode:S,sourceNode:I}),g}})().finally(()=>{if(p===l)p=null});return p=l,l},stop:()=>{s+=1,f({audioContext:t,mediaStream:c,processorNode:n,sourceNode:r}),e.onLevel?.(0),t=null,c=null,n=null,r=null}}};var D=(e)=>{if(typeof e==="string"&&e.trim())return e;if(e instanceof Error&&e.message.trim())return e.message;if(e&&typeof e==="object"){let t=e;for(let r of["message","reason","description"]){let n=t[r];if(typeof n==="string"&&n.trim())return n}if("error"in t)return D(t.error);if("cause"in t)return D(t.cause);try{return JSON.stringify(e)}catch{}}return"Unexpected error"},H=(e)=>{switch(e.type){case"audio":return{chunk:Uint8Array.from(atob(e.chunkBase64),(t)=>t.charCodeAt(0)),format:e.format,receivedAt:e.receivedAt,turnId:e.turnId,type:"audio"};case"assistant":return{text:e.text,turnId:e.turnId,type:"assistant"};case"assistant_delta":return{delta:e.delta,turnId:e.turnId,type:"assistant_delta"};case"complete":return{sessionId:e.sessionId,type:"complete"};case"connection":return{reconnect:e.reconnect,type:"connection"};case"call_lifecycle":return{event:e.event,sessionId:e.sessionId,type:"call_lifecycle"};case"error":return{message:D(e.message),recoverable:e.recoverable,type:"error"};case"call_control_ack":return null;case"final":return{transcript:e.transcript,type:"final"};case"partial":return{transcript:e.transcript,type:"partial"};case"playback_rate":return{rate:e.rate,type:"playback_rate"};case"replay":return{assistantTexts:e.assistantTexts,call:e.call,partial:e.partial,scenarioId:e.scenarioId,sessionId:e.sessionId,sessionMetadata:e.sessionMetadata,status:e.status,turns:e.turns,type:"replay"};case"session":return{paused:e.paused,pauseExpiresAt:e.pauseExpiresAt,sessionId:e.sessionId,sessionMetadata:e.sessionMetadata,scenarioId:e.scenarioId,status:e.status,type:"session"};case"turn":return{turn:e.turn,type:"turn"};default:return null}};var ut=Math.PI*2;var _=(e,t,r,n)=>{e.push({code:r,message:n,severity:t})};var Ce=(e)=>e.length===0?void 0:e.reduce((t,r)=>t+r,0)/e.length,P=(e)=>e.length===0?void 0:Math.max(...e);var T=(e,t)=>{let r=e[t];return typeof r==="number"&&Number.isFinite(r)?r:void 0},N=(e,t)=>{let r=e[t];return typeof r==="boolean"?r:void 0},E=(e,t)=>{let r=e[t];return typeof r==="string"?r:void 0},U=(e)=>String(e.id??E(e,"ssrc")??T(e,"ssrc")??E(e,"trackIdentifier")??E(e,"mid")??"unknown"),G=(e)=>e===void 0?void 0:e*1000;var Ve=(e)=>{let t={};for(let[r,n]of Object.entries(e))if(n===null||typeof n==="boolean"||typeof n==="number"||typeof n==="string")t[r]=n;return t};var z=(e={})=>{let t=e.stats??[],r=[],n=t.filter((a)=>a.type==="inbound-rtp"&&E(a,"kind")!=="video"),c=t.filter((a)=>a.type==="outbound-rtp"&&E(a,"kind")!=="video"),s=t.filter((a)=>a.type==="candidate-pair"),p=t.filter((a)=>(a.type==="track"||a.type==="media-source")&&E(a,"kind")==="audio"),f=s.filter((a)=>N(a,"selected")===!0||N(a,"nominated")===!0||E(a,"state")==="succeeded").length,i=p.filter((a)=>E(a,"readyState")!=="ended"&&E(a,"trackState")!=="ended"&&N(a,"ended")!==!0).length,h=p.filter((a)=>E(a,"readyState")==="ended"||E(a,"trackState")==="ended"||N(a,"ended")===!0).length,u=n.reduce((a,v)=>a+(T(v,"packetsReceived")??0),0),m=c.reduce((a,v)=>a+(T(v,"packetsSent")??0),0),l=[...n,...c].reduce((a,v)=>a+Math.max(0,T(v,"packetsLost")??0),0),o=u+l,b=o===0?0:l/o,M=n.reduce((a,v)=>a+(T(v,"bytesReceived")??0),0),S=c.reduce((a,v)=>a+(T(v,"bytesSent")??0),0),I=P(s.map((a)=>G(T(a,"currentRoundTripTime")??T(a,"roundTripTime"))).filter((a)=>a!==void 0)),g=P([...n,...c].map((a)=>G(T(a,"jitter"))).filter((a)=>a!==void 0)),R=P(n.map((a)=>{let v=T(a,"jitterBufferDelay"),L=T(a,"jitterBufferEmittedCount");return v!==void 0&&L!==void 0&&L>0?v/L*1000:void 0}).filter((a)=>a!==void 0)),x=p.map((a)=>T(a,"audioLevel")).filter((a)=>a!==void 0);if(e.requireConnectedCandidatePair&&s.length>0&&f===0)_(r,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(e.requireLiveAudioTrack&&i===0)_(r,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(e.maxPacketLossRatio!==void 0&&b>e.maxPacketLossRatio)_(r,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(b)} above ${String(e.maxPacketLossRatio)}.`);if(e.maxRoundTripTimeMs!==void 0&&I!==void 0&&I>e.maxRoundTripTimeMs)_(r,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(I)}ms above ${String(e.maxRoundTripTimeMs)}ms.`);if(e.maxJitterMs!==void 0&&g!==void 0&&g>e.maxJitterMs)_(r,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(g)}ms above ${String(e.maxJitterMs)}ms.`);return{activeCandidatePairs:f,audioLevelAverage:Ce(x),bytesReceived:M,bytesSent:S,checkedAt:Date.now(),endedAudioTracks:h,inboundPackets:u,issues:r,jitterBufferDelayMs:R,jitterMs:g,liveAudioTracks:i,outboundPackets:m,packetLossRatio:b,packetsLost:l,roundTripTimeMs:I,status:r.some((a)=>a.severity==="error")?"fail":r.length>0?"warn":"pass",totalStats:t.length}},j=async(e)=>[...(await e.peerConnection.getStats(e.selector??null)).values()].map(Ve);var Q=(e={})=>{let t=e.stats??[],r=e.previousStats??[],n=[],c=new Map(r.map((l)=>[U(l),l])),p=t.filter((l)=>(l.type==="inbound-rtp"||l.type==="outbound-rtp")&&E(l,"kind")!=="video"&&E(l,"mediaType")!=="video").map((l)=>{let o=l.type==="outbound-rtp"?"outbound":"inbound",b=o==="outbound"?"packetsSent":"packetsReceived",M=o==="outbound"?"bytesSent":"bytesReceived",S=c.get(U(l)),I=T(l,b),g=S?T(S,b):void 0,R=T(l,M),x=S?T(S,M):void 0,a=l.timestamp!==void 0&&S?.timestamp!==void 0?l.timestamp-S.timestamp:void 0;return{bytesDelta:R!==void 0&&x!==void 0?R-x:void 0,currentPackets:I,direction:o,id:U(l),packetDelta:I!==void 0&&g!==void 0?I-g:void 0,previousPackets:g,timeDeltaMs:a}}),f=p.filter((l)=>l.direction==="inbound"),i=p.filter((l)=>l.direction==="outbound"),h=P(p.map((l)=>l.timeDeltaMs).filter((l)=>l!==void 0)),u=f.filter((l)=>e.maxInboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=e.maxInboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length,m=i.filter((l)=>e.maxOutboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=e.maxOutboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length;if(e.requireInboundAudio&&f.length===0)_(n,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(e.requireOutboundAudio&&i.length===0)_(n,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(e.maxGapMs!==void 0&&h!==void 0&&h>e.maxGapMs)_(n,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(h)}ms above ${String(e.maxGapMs)}ms.`);if(u>0)_(n,"error","media.webrtc_inbound_stalled",`${String(u)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(m>0)_(n,"error","media.webrtc_outbound_stalled",`${String(m)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:f.length,issues:n,maxObservedGapMs:h,outboundAudioStreams:i.length,stalledInboundStreams:u,stalledOutboundStreams:m,status:n.some((l)=>l.severity==="error")?"fail":n.length>0?"warn":"pass",streams:p,totalStats:t.length}};var Le="/api/voice/browser-media",Ne=5000,Pe=async(e)=>e.peerConnection??await e.getPeerConnection?.()??null,Oe=async(e,t)=>{let r=t.fetch??globalThis.fetch;if(!r)return;await r(t.path??Le,{body:JSON.stringify(e),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},Y=(e)=>{let t=null,r=[],n=async()=>{let p=await Pe(e);if(!p)return;let f=await j({peerConnection:p}),i=z({...e,stats:f}),h=e.continuity===!1?void 0:Q({...e.continuity,previousStats:r,stats:f}),u={at:Date.now(),continuity:h,report:i,scenarioId:e.getScenarioId?.()??null,sessionId:e.getSessionId?.()??null};return r=f,e.onReport?.(u),await Oe(u,e),u},c=()=>{n().catch((p)=>{e.onError?.(p)})},s=()=>{if(t)clearInterval(t),t=null};return{close:s,reportOnce:n,stop:s,start:()=>{if(t)return;c(),t=setInterval(c,e.intervalMs??Ne)}}};var $e=(e,t,r)=>Math.min(r,t*2**(Math.max(1,e)-1));class J extends Error{constructor(e="Voice authorization could not be renewed."){super(e);this.name="VoiceReconnectRejectedError"}}var k=()=>{},De=()=>Promise.resolve(),Ue=()=>k,Be={callControl:De,close:k,disconnect:k,endTurn:k,send:k,sendAudio:k,simulateDisconnect:k,subscribe:Ue,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},We=()=>crypto.randomUUID(),qe=(e,t,r,n)=>{let{hostname:c,port:s,protocol:p}=window.location,f=p==="https:"?"wss:":"ws:",i=s?`:${s}`:"",h=new URL(`${f}//${c}${i}${e}`);if(h.searchParams.set("sessionId",t),r)h.searchParams.set("scenarioId",r);for(let[u,m]of Object.entries(n))if(u!=="sessionId"&&u!=="scenarioId"&&m)h.searchParams.set(u,m);return h.toString()},He=(e)=>{if(!e||typeof e!=="object"||!("type"in e))return!1;switch(e.type){case"audio":case"assistant":case"call_lifecycle":case"call_control_ack":case"complete":case"connection":case"error":case"final":case"partial":case"playback_rate":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},Ge=(e)=>{if(typeof e.data!=="string")return null;try{let t=JSON.parse(e.data);return He(t)?t:null}catch{return null}},X=(e,t={})=>{if(typeof window>"u")return Be;let r=new Set,n=new Map,c=t.reconnect!==!1,s=t.maxReconnectAttempts??15,p=t.reconnectMaxDelayMs??8000,f=t.pingInterval??30000,i=t.reconnectResetAfterMs??30000,h=0,u=!1,m=null,l=(d)=>$e(d,500,p),o={isConnected:!1,pendingMessages:[],scenarioId:t.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:t.sessionId??We(),ws:null},b=(d)=>{r.forEach((y)=>y(d))},M=(d)=>{r.forEach((y)=>y({message:d,recoverable:!1,type:"error"})),b({reconnect:{attempts:o.reconnectAttempts,maxAttempts:s,status:"exhausted"},type:"connection"})},S=()=>{if(o.pingInterval)clearInterval(o.pingInterval),o.pingInterval=null;if(o.reconnectTimeout)clearTimeout(o.reconnectTimeout),o.reconnectTimeout=null;if(o.reconnectResetTimeout)clearTimeout(o.reconnectResetTimeout),o.reconnectResetTimeout=null},I=()=>{if(o.ws?.readyState!==1)return;while(o.pendingMessages.length>0){let d=o.pendingMessages.shift();if(d!==void 0)o.ws.send(d)}},g=(d)=>{for(let y of n.values())clearTimeout(y.timeout),y.reject(Error(d));n.clear()},R=()=>{if(u)return;let d=h;o.reconnectAttempts+=1;let y=l(o.reconnectAttempts),w=Date.now()+y;b({reconnect:{attempts:o.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:s,nextAttemptAt:w,status:"reconnecting"},type:"connection"}),o.reconnectTimeout=setTimeout(async()=>{if(u||h!==d)return;if(o.reconnectAttempts>s){M("Voice connection could not be restored.");return}try{if(t.prepareReconnect){let A=new AbortController;m=A;let C=setTimeout(()=>A.abort("Voice reconnect preparation timed out"),t.prepareReconnectTimeoutMs??1e4);try{await Promise.race([t.prepareReconnect({attempt:o.reconnectAttempts,path:e,scenarioId:o.scenarioId,sessionId:o.sessionId,signal:A.signal}),new Promise((V,ye)=>{A.signal.addEventListener("abort",()=>ye(Error("Voice reconnect preparation timed out.")),{once:!0})})])}finally{if(clearTimeout(C),m===A)m=null}}}catch(A){if(u||h!==d)return;if(A instanceof J){M(A.message);return}if(o.reconnectAttempts<s)R();else M("Voice authorization could not be renewed for reconnect.");return}if(u||h!==d)return;x()},y)},x=()=>{if(u)return;let d=new WebSocket(qe(e,o.sessionId,o.scenarioId,t.query??{}));d.binaryType="arraybuffer",d.onopen=()=>{if(o.ws!==d){d.close(1000);return}let y=o.reconnectAttempts>0;if(o.isConnected=!0,I(),y)b({reconnect:{attempts:o.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:s,status:"resumed"},type:"connection"}),o.reconnectResetTimeout=setTimeout(()=>{if(o.ws===d&&d.readyState===1)o.reconnectAttempts=0;o.reconnectResetTimeout=null},i);o.pingInterval=setInterval(()=>{if(d.readyState===1)d.send(JSON.stringify({type:"ping"}))},f)},d.onmessage=(y)=>{if(o.ws!==d)return;let w=Ge(y);if(!w)return;if(w.type==="session")o.sessionId=w.sessionId,o.scenarioId=w.scenarioId??o.scenarioId;if(w.type==="call_control_ack"){let A=n.get(w.requestId);if(A)if(clearTimeout(A.timeout),n.delete(w.requestId),w.ok)A.resolve();else A.reject(Error(w.message??`${w.action} was not applied`))}r.forEach((A)=>A(w))},d.onclose=(y)=>{if(o.ws!==d)return;o.ws=null,o.isConnected=!1,S(),g("Voice connection interrupted");let w=c&&y.code!==1000&&y.code!==4401&&y.code!==4403&&y.code!==4500&&o.reconnectAttempts<s,A=y.code===4401||y.code===4403,C=y.code===4500;if(A)r.forEach((V)=>V({message:y.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(C)r.forEach((V)=>V({message:"Voice provider initialization failed.",recoverable:!1,type:"error"}));if(w)R();else if(c&&y.code!==1000){if(A)b({reconnect:{attempts:o.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:s,status:"exhausted"},type:"connection"});else if(!C)M("Voice connection could not be restored.")}},o.ws=d},a=(d)=>{if(u)return;if(o.ws?.readyState===1){o.ws.send(d);return}if(typeof d!=="string")return;if(o.pendingMessages.length>=100)o.pendingMessages.shift();o.pendingMessages.push(d)},v=(d)=>{a(JSON.stringify(d))},L=(d={})=>{if(d.sessionId&&d.sessionId!==o.sessionId)throw Error("Voice session switching requires a new connection instance.");if(d.sessionId)o.sessionId=d.sessionId;if(d.scenarioId)o.scenarioId=d.scenarioId;v({scenarioId:o.scenarioId??void 0,sessionId:o.sessionId,type:"start"})},le=(d)=>{a(d)},ue=()=>{v({type:"end_turn"})},me=(d)=>{if(o.ws?.readyState!==1)return Promise.reject(Error(`${d.action} is unavailable while disconnected`));let y=crypto.randomUUID(),{promise:w,reject:A,resolve:C}=Promise.withResolvers(),V=setTimeout(()=>{n.delete(y),A(Error(`${d.action} acknowledgement timed out`))},5000);return n.set(y,{reject:A,resolve:C,timeout:V}),o.ws.send(JSON.stringify({...d,requestId:y,type:"call_control"})),w},pe=(d="client-close")=>{if(u=!0,m?.abort(),m=null,h+=1,S(),g("Voice connection closed"),o.pendingMessages.length=0,o.ws){let y=o.ws;if(o.ws=null,y.readyState===1)y.send(JSON.stringify({reason:d,type:"close"}));y.close(1000)}o.isConnected=!1,r.clear()},fe=()=>{if(u=!0,m?.abort(),m=null,h+=1,S(),g("Voice connection disconnected"),o.pendingMessages.length=0,o.ws){let d=o.ws;o.ws=null,d.close(1000)}o.isConnected=!1,r.clear()},ge=()=>{if(o.ws?.readyState===1)o.ws.close(4000,"absolutejs-voice-reconnect-proof")},he=(d)=>(r.add(d),()=>{r.delete(d)});return x(),{callControl:me,close:pe,disconnect:fe,endTurn:ue,send:v,sendAudio:le,simulateDisconnect:ge,start:L,subscribe:he,getReadyState:()=>o.ws?.readyState??3,getScenarioId:()=>o.scenarioId??"",getSessionId:()=>o.sessionId}};var ze=()=>({attempts:0,maxAttempts:0,status:"idle"}),je=(e,t)=>{let r=t.trim().replace(/\s+/g," ");if(!r)return e;if(!e)return r;if(e===r||e.endsWith(r))return e;if(r.includes(e))return r;return`${e} ${r}`},Qe=(e,t)=>{let r=t.trim().replace(/\s+/g," ");if(!e)return r;if(!r||e.endsWith(r))return e;return`${e} ${r}`},Ye=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,paused:!1,partial:"",playbackRate:null,reconnect:ze(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),K=()=>{let e=Ye(),t="",r=new Set,n=()=>{r.forEach((s)=>s())};return{dispatch:(s)=>{switch(s.type){case"audio":e={...e,assistantAudio:[...e.assistantAudio,{chunk:s.chunk,format:s.format,receivedAt:s.receivedAt,turnId:s.turnId}]};break;case"assistant":e={...e,assistantStreamingText:"",assistantTexts:[...e.assistantTexts,s.text]};break;case"assistant_delta":e={...e,assistantStreamingText:`${e.assistantStreamingText}${s.delta}`};break;case"complete":e={...e,sessionId:s.sessionId,status:"completed"};break;case"call_lifecycle":e={...e,call:{...e.call,disposition:s.event.type==="end"?s.event.disposition:e.call?.disposition,endedAt:s.event.type==="end"?s.event.at:e.call?.endedAt,events:[...e.call?.events??[],s.event],lastEventAt:s.event.at,startedAt:e.call?.startedAt??s.event.at},sessionId:s.sessionId};break;case"connected":e={...e,isConnected:!0,reconnect:e.reconnect.status==="reconnecting"?{...e.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:e.reconnect};break;case"connection":e={...e,reconnect:s.reconnect};break;case"disconnected":e={...e,isConnected:!1};break;case"error":e={...e,error:s.message,...s.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":t=je(t,s.transcript.text),e={...e,partial:t};break;case"partial":e={...e,partial:Qe(t,s.transcript.text)};break;case"playback_rate":e={...e,playbackRate:Math.max(0.5,Math.min(2,s.rate))};break;case"replay":t=s.partial,e={...e,assistantStreamingText:"",assistantTexts:[...s.assistantTexts],call:s.call??null,error:null,isConnected:s.status==="active",partial:s.partial,reconnect:e.reconnect.status==="reconnecting"?{...e.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:e.reconnect,scenarioId:s.scenarioId??e.scenarioId,sessionId:s.sessionId,sessionMetadata:s.sessionMetadata??e.sessionMetadata,status:s.status,turns:[...s.turns]};break;case"session":e={...e,error:null,paused:s.paused??!1,pauseExpiresAt:s.pauseExpiresAt,scenarioId:s.scenarioId??e.scenarioId,isConnected:s.status==="active",sessionId:s.sessionId,sessionMetadata:s.sessionMetadata??e.sessionMetadata,status:s.status};break;case"turn":t="",e={...e,partial:"",turns:[...e.turns,s.turn]};break}n()},getServerSnapshot:()=>e,getSnapshot:()=>e,subscribe:(s)=>(r.add(s),()=>{r.delete(s)})}};var Z=(e,t={})=>{let r=X(e,t),n=K(),c=t.browserMedia&&typeof window<"u"?Y({...t.browserMedia,getScenarioId:()=>t.browserMedia?t.browserMedia.getScenarioId?.()??r.getScenarioId():r.getScenarioId(),getSessionId:()=>t.browserMedia?t.browserMedia.getSessionId?.()??r.getSessionId():r.getSessionId()}):null,s=new Set,p=!1,f=(m)=>Promise.resolve().then(()=>{if(p)return;if(!m?.sessionId&&!m?.scenarioId)return;r.start(m),c?.start()}),i=()=>{s.forEach((m)=>m())},h=()=>{if(!t.reconnectReportPath||typeof fetch>"u")return;let m=n.getSnapshot(),l=JSON.stringify({at:Date.now(),reconnect:m.reconnect,scenarioId:m.scenarioId,sessionId:r.getSessionId(),turnIds:m.turns.map((o)=>o.id)});fetch(t.reconnectReportPath,{body:l,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},u=r.subscribe((m)=>{let l=H(m);if(l){if(n.dispatch(l),m.type==="connection")h();i()}});return{start:f,get assistantAudio(){return n.getSnapshot().assistantAudio},get assistantTexts(){return n.getSnapshot().assistantTexts},get assistantStreamingText(){return n.getSnapshot().assistantStreamingText},get call(){return n.getSnapshot().call},callControl(m){return r.callControl(m)},close(m){p=!0,u(),c?.close(),r.close(m),n.dispatch({type:"disconnected"}),i()},disconnect(){p=!0,u(),c?.close(),r.disconnect(),n.dispatch({type:"disconnected"}),i()},endTurn(){r.endTurn()},get error(){return n.getSnapshot().error},getServerSnapshot(){return n.getServerSnapshot()},getSnapshot(){return n.getSnapshot()},get isConnected(){return n.getSnapshot().isConnected},get partial(){return n.getSnapshot().partial},get playbackRate(){return n.getSnapshot().playbackRate},get paused(){return n.getSnapshot().paused},get pauseExpiresAt(){return n.getSnapshot().pauseExpiresAt},get reconnect(){return n.getSnapshot().reconnect},get scenarioId(){return n.getSnapshot().scenarioId},sendAudio(m){r.sendAudio(m)},get sessionId(){return r.getSessionId()},get sessionMetadata(){return n.getSnapshot().sessionMetadata},simulateDisconnect(){r.simulateDisconnect()},get status(){return n.getSnapshot().status},subscribe(m){return s.add(m),()=>{s.delete(m)}},get turns(){return n.getSnapshot().turns}}};var ee=(e)=>{if(!e||e.enabled===!1)return;return{enabled:!0,maxGain:e.maxGain??3,noiseGateAttenuation:e.noiseGateAttenuation??0.15,noiseGateThreshold:e.noiseGateThreshold??0.006,targetLevel:e.targetLevel??0.08}};var Je={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}},Xe={"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 te=(e)=>{let t=e?.profile??"fast",r=e?.qualityProfile??"general",n=Je[t],c=Xe[r],s=e?.silenceMs??c.silenceMs??n.silenceMs;return{profile:t,qualityProfile:r,minSilenceMs:Math.min(s,e?.minSilenceMs??c.minSilenceMs??n.minSilenceMs),silenceMs:s,speechThreshold:e?.speechThreshold??c.speechThreshold??n.speechThreshold,transcriptStabilityMs:e?.transcriptStabilityMs??c.transcriptStabilityMs??n.transcriptStabilityMs}};var Ke={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"}}},ne=(e="default")=>{let t=Ke[e];return{audioConditioning:ee(t.audioConditioning),capture:{channelCount:t.capture?.channelCount??1,sampleRateHz:t.capture?.sampleRateHz??16000},connection:{...t.connection},name:e,sttLifecycle:t.sttLifecycle??"continuous",turnDetection:te(t.turnDetection)}};var Ze=(e)=>({assistantAudio:[...e.assistantAudio],assistantStreamingText:e.assistantStreamingText,assistantTexts:[...e.assistantTexts],call:e.call,error:e.error,isConnected:e.isConnected,isRecording:!1,paused:e.paused,pauseExpiresAt:e.pauseExpiresAt,partial:e.partial,playbackRate:e.playbackRate,reconnect:e.reconnect,recordingError:null,sessionId:e.sessionId,sessionMetadata:e.sessionMetadata,scenarioId:e.scenarioId,status:e.status,turns:[...e.turns]}),re=(e,t={})=>{let r=ne(t.preset),n=Z(e,{...r.connection,...t.connection}),c=null,s=0,p=!1,f=null,i=Ze(n),h=new Set,u=()=>{for(let g of h)g()},m=()=>{if(i={...i,assistantAudio:[...n.assistantAudio],assistantStreamingText:n.assistantStreamingText,assistantTexts:[...n.assistantTexts],call:n.call,error:n.error,isConnected:n.isConnected,paused:n.paused,pauseExpiresAt:n.pauseExpiresAt,partial:n.partial,playbackRate:n.playbackRate,reconnect:n.reconnect,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,turns:[...n.turns]},t.autoStopOnComplete!==!1&&i.status==="completed"&&i.isRecording)c?.stop(),c=null,i={...i,isRecording:!1};u()},l=n.subscribe(m);m();let o=()=>{if(c)return c;return c=q({channelCount:t.capture?.channelCount??r.capture.channelCount,onLevel:t.capture?.onLevel,onAudio:(g)=>{if(t.capture?.onAudio){t.capture.onAudio(g,n.sendAudio);return}n.sendAudio(g)},sampleRateHz:t.capture?.sampleRateHz??r.capture.sampleRateHz,...t.capture?.stream?{stream:t.capture.stream}:{}}),c},b=()=>{s+=1,c?.stop(),c=null,i={...i,isRecording:!1},u()},M=async()=>{if(p)throw Error("Voice controller is closed.");if(i.isRecording)return;if(f)return f;let g=++s,R=o(),a=(async()=>{try{if(i={...i,recordingError:null},u(),await R.start(),p||g!==s||c!==R){R.stop();return}i={...i,isRecording:!0},u()}catch(v){if(R.stop(),g!==s||c!==R)throw v;throw c=null,i={...i,isRecording:!1,recordingError:v instanceof Error?v.message:String(v)},u(),v}})().finally(()=>{if(f===a)f=null});return f=a,f};return{close:(g)=>{p=!0,l(),b(),n.close(g)},disconnect:()=>{p=!0,l(),b(),n.disconnect()},startRecording:M,stopRecording:b,get assistantAudio(){return i.assistantAudio},get assistantTexts(){return i.assistantTexts},get assistantStreamingText(){return i.assistantStreamingText},bindHTMX(g){return W(n,g)},get call(){return i.call},callControl:(g)=>n.callControl(g),endTurn:()=>n.endTurn(),get error(){return i.error},getServerSnapshot:()=>i,getSnapshot:()=>i,get isConnected(){return i.isConnected},get isRecording(){return i.isRecording},get partial(){return i.partial},get playbackRate(){return i.playbackRate},get paused(){return i.paused},get pauseExpiresAt(){return i.pauseExpiresAt},get reconnect(){return i.reconnect},get recordingError(){return i.recordingError},get scenarioId(){return i.scenarioId},sendAudio:(g)=>n.sendAudio(g),get sessionId(){return i.sessionId},get sessionMetadata(){return i.sessionMetadata},simulateDisconnect:()=>n.simulateDisconnect(),get status(){return i.status},subscribe:(g)=>(h.add(g),()=>{h.delete(g)}),toggleRecording:async()=>{if(i.isRecording){b();return}await M()},get turns(){return i.turns}}};var F=(e)=>String(e).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var se=(e)=>{if(!e.isConnected)return"idle";if(e.isPlaying)return"speaking";if(e.isRecording&&e.hasActivePartial)return"listening";if(e.isRecording)return"listening";if(e.lastTranscriptAt&&!e.lastAssistantAt)return"thinking";if(e.lastTranscriptAt&&e.lastAssistantAt&&e.lastTranscriptAt>e.lastAssistantAt)return"thinking";return"idle"};var et={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},tt={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},nt=(e,t)=>{switch(e){case"listening":return t.listening;case"speaking":return t.speaking;case"thinking":return t.thinking;case"idle":return t.idle}},oe=(e)=>{let t={...et,...e.theme},r={...tt,...e.labels},n=e.state.assistantAudio.at(-1)?.receivedAt,c=e.state.turns.at(-1)?.committedAt,s=se({hasActivePartial:e.state.partial.length>0,isConnected:e.state.isConnected,isPlaying:!1,isRecording:e.state.isRecording,lastAssistantAt:n,lastTranscriptAt:c}),p=!e.state.isConnected&&e.state.status!=="idle"&&!e.state.error,f=e.state.error?"Error":p?r.connecting:e.state.status==="completed"?r.callEnded:nt(s,r);return{agentState:s,classes:{container:`absolute-voice-widget absolute-voice-widget--${s}`,dot:`absolute-voice-widget__dot${e.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:e.state.isConnected,canMute:e.state.isRecording,canStart:!e.state.isRecording&&e.state.status!=="completed"},errorMessage:e.state.error??void 0,labels:r,partial:e.state.partial||void 0,statusLabel:f,theme:t,title:e.title??"Voice"}},rt=(e)=>typeof e==="number"?`${e}px`:e,ae=(e)=>{let t=e.theme,r=`background:${t.background};border-radius:${rt(t.radius)};color:${t.foreground};font-family:${t.fontFamily};min-width:240px;padding:20px 22px;`,n=`background:${e.errorMessage?t.errorAccent:e.agentState==="idle"?"rgba(148,163,184,0.6)":t.accent};border-radius:50%;height:10px;width:10px;`,c=[];if(e.controls.canStart)c.push(`<button type="button" data-action="start" style="background:${t.accent};border:none;border-radius:12px;color:${t.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${F(e.labels.startCall)}</button>`);if(e.controls.canMute)c.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${t.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${F(e.labels.mute)}</button>`);if(e.controls.canEnd)c.push(`<button type="button" data-action="end" style="background:${t.errorAccent};border:none;border-radius:12px;color:${t.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${F(e.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${e.agentState}" class="${F(e.classes.container)}" style="${r}">
|
|
2
2
|
<div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
|
|
3
|
-
<span aria-hidden="true" class="${
|
|
4
|
-
<strong style="font-size:15px;">${
|
|
5
|
-
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${
|
|
3
|
+
<span aria-hidden="true" class="${F(e.classes.dot)}" style="${n}"></span>
|
|
4
|
+
<strong style="font-size:15px;">${F(e.title)}</strong>
|
|
5
|
+
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${F(e.statusLabel)}</span>
|
|
6
6
|
</div>
|
|
7
|
-
${
|
|
8
|
-
<div style="display:flex;gap:10px;">${
|
|
9
|
-
${
|
|
10
|
-
</div>`};var
|
|
7
|
+
${e.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${F(e.partial)}”</p>`:""}
|
|
8
|
+
<div style="display:flex;gap:10px;">${c.join("")}</div>
|
|
9
|
+
${e.errorMessage?`<p style="color:${t.errorAccent};font-size:12px;margin-top:12px;">${F(e.errorMessage)}</p>`:""}
|
|
10
|
+
</div>`};var st=(e)=>{if(typeof e!=="string")return e;let t=document.querySelector(e);if(!t)throw Error(`AbsoluteVoice.mount: no element matches "${e}"`);return t},ie=(e,t={})=>{let r=st(e),n=re(t.path??"/voice",t.controllerOptions),c=null,s=null,p=()=>{let i=oe({...t.labels!==void 0?{labels:t.labels}:{},state:{assistantAudio:n.assistantAudio,error:n.error,isConnected:n.isConnected,isRecording:n.isRecording,partial:n.partial,status:n.status,turns:n.turns},...t.theme!==void 0?{theme:t.theme}:{},...t.title!==void 0?{title:t.title}:{}});r.innerHTML=ae(i);for(let h of r.querySelectorAll("button[data-action]")){let{action:u}=h.dataset;h.addEventListener("click",()=>{if(u==="start")n.startRecording();else if(u==="mute")n.stopRecording();else if(u==="end")n.close()})}if(n.error&&n.error!==c)c=n.error,t.onError?.(n.error);if(n.status!==s)s=n.status,t.onStatusChange?.(n.status)},f=n.subscribe(p);if(p(),t.autoStart)n.startRecording();return{controller:n,async end(){await n.close()},mute(){n.stopRecording()},async start(){await n.startRecording()},unmount(){f(),n.close(),r.innerHTML=""}}},ce="0.0.22-beta.516",de={mount:ie,version:ce};if(typeof globalThis<"u")globalThis.AbsoluteVoice=de;var at=de;})();
|