@absolutejs/voice 0.0.22-beta.463 → 0.0.22-beta.464
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 +265 -0
- package/dist/client/htmxBootstrap.js +330 -7
- package/dist/client/index.js +265 -0
- package/dist/generated/htmxBootstrapBundle.d.ts +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +591 -50
- package/dist/mediaPipelineRoutes.d.ts +55 -1
- package/dist/mediaPipelineSurfaces.d.ts +48 -0
- package/dist/react/index.js +265 -0
- package/dist/svelte/index.js +265 -0
- package/dist/testing/index.js +265 -0
- package/dist/vue/index.js +265 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5186,7 +5186,7 @@ var createVoiceSession = (options) => {
|
|
|
5186
5186
|
};
|
|
5187
5187
|
|
|
5188
5188
|
// src/generated/htmxBootstrapBundle.ts
|
|
5189
|
-
var HTMX_BOOTSTRAP_BUNDLE = 'var Ue=(e)=>{if(typeof e!=="string")return e;return document.querySelector(e)},Ne=(e,n,t,o)=>{let r=n??e.getAttribute("hx-get")??"";if(!r)return"";let i=new URL(r,window.location.origin);if(o)i.searchParams.set(t,o);else i.searchParams.delete(t);return`${i.pathname}${i.search}${i.hash}`},de=(e,n)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let t=Ue(n.element);if(!t)return()=>{};let o=n.eventName??"voice-refresh",r=n.sessionQueryParam??"sessionId",i=()=>{let l=window,g=Ne(t,n.route,r,e.sessionId);if(g)t.setAttribute("hx-get",g);l.htmx?.process?.(t),l.htmx?.trigger?.(t,o)},c=e.subscribe(i);return i(),()=>{c()}};var He=(e)=>Math.max(-1,Math.min(1,e)),Ge=(e)=>{let n=new Int16Array(e.length);for(let t=0;t<e.length;t+=1){let o=He(e[t]??0);n[t]=o<0?o*32768:o*32767}return new Uint8Array(n.buffer)},Be=(e)=>{let n=e instanceof Uint8Array?e:new Uint8Array(e);if(n.byteLength<2)return 0;let t=new Int16Array(n.buffer,n.byteOffset,Math.floor(n.byteLength/2));if(t.length===0)return 0;let o=0;for(let r of t){let i=r/32768;o+=i*i}return Math.min(1,Math.max(0,Math.sqrt(o/t.length)*5.5))},We=(e,n,t)=>{if(n===t)return e;let o=n/t,r=Math.round(e.length/o),i=new Float32Array(r),c=0,l=0;while(c<i.length){let g=Math.round((c+1)*o),y=0,d=0;for(let h=l;h<g&&h<e.length;h+=1)y+=e[h]??0,d+=1;i[c]=d>0?y/d:0,c+=1,l=g}return i},ge=(e)=>{let n=null,t=null,o=null,r=null;return{start:async()=>{if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let l=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!l)throw Error("Browser microphone capture requires AudioContext support.");r=await navigator.mediaDevices.getUserMedia({audio:{channelCount:e.channelCount??1}}),n=new l,t=n.createMediaStreamSource(r),o=n.createScriptProcessor(4096,1,1),o.onaudioprocess=(g)=>{let y=g.inputBuffer.getChannelData(0),d=We(y,n?.sampleRate??48000,e.sampleRateHz??16000),h=Ge(d);e.onLevel?.(Be(h)),e.onAudio(h)},t.connect(o),o.connect(n.destination)},stop:()=>{o?.disconnect(),t?.disconnect(),r?.getTracks().forEach((l)=>l.stop()),n?.close(),e.onLevel?.(0),n=null,r=null,o=null,t=null}}};var ee=(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 n=e;for(let t of["message","reason","description"]){let o=n[t];if(typeof o==="string"&&o.trim())return o}if("error"in n)return ee(n.error);if("cause"in n)return ee(n.cause);try{return JSON.stringify(e)}catch{}}return"Unexpected error"},Ae=(e)=>{switch(e.type){case"audio":return{chunk:Uint8Array.from(atob(e.chunkBase64),(n)=>n.charCodeAt(0)),format:e.format,receivedAt:e.receivedAt,turnId:e.turnId,type:"audio"};case"assistant":return{text:e.text,type:"assistant"};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:ee(e.message),type:"error"};case"final":return{transcript:e.transcript,type:"final"};case"partial":return{transcript:e.transcript,type:"partial"};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{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 H=(e,n,t,o)=>{e.push({code:t,message:o,severity:n})};var $e=(e)=>e.length===0?void 0:e.reduce((n,t)=>n+t,0)/e.length,K=(e)=>e.length===0?void 0:Math.max(...e);var b=(e,n)=>{let t=e[n];return typeof t==="number"&&Number.isFinite(t)?t:void 0},Z=(e,n)=>{let t=e[n];return typeof t==="boolean"?t:void 0},D=(e,n)=>{let t=e[n];return typeof t==="string"?t:void 0},ne=(e)=>String(e.id??D(e,"ssrc")??b(e,"ssrc")??D(e,"trackIdentifier")??D(e,"mid")??"unknown"),he=(e)=>e===void 0?void 0:e*1000;var ke=(e)=>{let n={};for(let[t,o]of Object.entries(e))if(o===null||typeof o==="boolean"||typeof o==="number"||typeof o==="string")n[t]=o;return n};var ye=(e={})=>{let n=e.stats??[],t=[],o=n.filter((s)=>s.type==="inbound-rtp"&&D(s,"kind")!=="video"),r=n.filter((s)=>s.type==="outbound-rtp"&&D(s,"kind")!=="video"),i=n.filter((s)=>s.type==="candidate-pair"),c=n.filter((s)=>(s.type==="track"||s.type==="media-source")&&D(s,"kind")==="audio"),l=i.filter((s)=>Z(s,"selected")===!0||Z(s,"nominated")===!0||D(s,"state")==="succeeded").length,g=c.filter((s)=>D(s,"readyState")!=="ended"&&D(s,"trackState")!=="ended"&&Z(s,"ended")!==!0).length,y=c.filter((s)=>D(s,"readyState")==="ended"||D(s,"trackState")==="ended"||Z(s,"ended")===!0).length,d=o.reduce((s,S)=>s+(b(S,"packetsReceived")??0),0),h=r.reduce((s,S)=>s+(b(S,"packetsSent")??0),0),a=[...o,...r].reduce((s,S)=>s+Math.max(0,b(S,"packetsLost")??0),0),M=d+a,C=M===0?0:a/M,I=o.reduce((s,S)=>s+(b(S,"bytesReceived")??0),0),w=r.reduce((s,S)=>s+(b(S,"bytesSent")??0),0),R=K(i.map((s)=>he(b(s,"currentRoundTripTime")??b(s,"roundTripTime"))).filter((s)=>s!==void 0)),u=K([...o,...r].map((s)=>he(b(s,"jitter"))).filter((s)=>s!==void 0)),O=K(o.map((s)=>{let S=b(s,"jitterBufferDelay"),L=b(s,"jitterBufferEmittedCount");return S!==void 0&&L!==void 0&&L>0?S/L*1000:void 0}).filter((s)=>s!==void 0)),U=c.map((s)=>b(s,"audioLevel")).filter((s)=>s!==void 0);if(e.requireConnectedCandidatePair&&i.length>0&&l===0)H(t,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(e.requireLiveAudioTrack&&g===0)H(t,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(e.maxPacketLossRatio!==void 0&&C>e.maxPacketLossRatio)H(t,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(C)} above ${String(e.maxPacketLossRatio)}.`);if(e.maxRoundTripTimeMs!==void 0&&R!==void 0&&R>e.maxRoundTripTimeMs)H(t,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(R)}ms above ${String(e.maxRoundTripTimeMs)}ms.`);if(e.maxJitterMs!==void 0&&u!==void 0&&u>e.maxJitterMs)H(t,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(u)}ms above ${String(e.maxJitterMs)}ms.`);return{activeCandidatePairs:l,audioLevelAverage:$e(U),bytesReceived:I,bytesSent:w,checkedAt:Date.now(),endedAudioTracks:y,inboundPackets:d,issues:t,jitterBufferDelayMs:O,jitterMs:u,liveAudioTracks:g,outboundPackets:h,packetLossRatio:C,packetsLost:a,roundTripTimeMs:R,status:t.some((s)=>s.severity==="error")?"fail":t.length>0?"warn":"pass",totalStats:n.length}},Ce=async(e)=>{return[...(await e.peerConnection.getStats(e.selector??null)).values()].map(ke)};var fe=(e={})=>{let n=e.stats??[],t=e.previousStats??[],o=[],r=new Map(t.map((a)=>[ne(a),a])),c=n.filter((a)=>(a.type==="inbound-rtp"||a.type==="outbound-rtp")&&D(a,"kind")!=="video"&&D(a,"mediaType")!=="video").map((a)=>{let M=a.type==="outbound-rtp"?"outbound":"inbound",C=M==="outbound"?"packetsSent":"packetsReceived",I=M==="outbound"?"bytesSent":"bytesReceived",w=r.get(ne(a)),R=b(a,C),u=w?b(w,C):void 0,O=b(a,I),U=w?b(w,I):void 0,s=a.timestamp!==void 0&&w?.timestamp!==void 0?a.timestamp-w.timestamp:void 0;return{bytesDelta:O!==void 0&&U!==void 0?O-U:void 0,currentPackets:R,direction:M,id:ne(a),packetDelta:R!==void 0&&u!==void 0?R-u:void 0,previousPackets:u,timeDeltaMs:s}}),l=c.filter((a)=>a.direction==="inbound"),g=c.filter((a)=>a.direction==="outbound"),y=K(c.map((a)=>a.timeDeltaMs).filter((a)=>a!==void 0)),d=l.filter((a)=>e.maxInboundPacketStallMs!==void 0&&a.timeDeltaMs!==void 0&&a.timeDeltaMs>=e.maxInboundPacketStallMs&&a.packetDelta!==void 0&&a.packetDelta<=0).length,h=g.filter((a)=>e.maxOutboundPacketStallMs!==void 0&&a.timeDeltaMs!==void 0&&a.timeDeltaMs>=e.maxOutboundPacketStallMs&&a.packetDelta!==void 0&&a.packetDelta<=0).length;if(e.requireInboundAudio&&l.length===0)H(o,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(e.requireOutboundAudio&&g.length===0)H(o,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(e.maxGapMs!==void 0&&y!==void 0&&y>e.maxGapMs)H(o,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(y)}ms above ${String(e.maxGapMs)}ms.`);if(d>0)H(o,"error","media.webrtc_inbound_stalled",`${String(d)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)H(o,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:l.length,issues:o,maxObservedGapMs:y,outboundAudioStreams:g.length,stalledInboundStreams:d,stalledOutboundStreams:h,status:o.some((a)=>a.severity==="error")?"fail":o.length>0?"warn":"pass",streams:c,totalStats:n.length}};var qe="/api/voice/browser-media",Xe=5000,ze=async(e)=>e.peerConnection??await e.getPeerConnection?.()??null,Ye=async(e,n)=>{let t=n.fetch??globalThis.fetch;if(!t)return;await t(n.path??qe,{body:JSON.stringify(e),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},Te=(e)=>{let n=null,t=[],o=async()=>{let c=await ze(e);if(!c)return;let l=await Ce({peerConnection:c}),g=ye({...e,stats:l}),y=e.continuity===!1?void 0:fe({...e.continuity,previousStats:t,stats:l}),d={at:Date.now(),continuity:y,report:g,scenarioId:e.getScenarioId?.()??null,sessionId:e.getSessionId?.()??null};return t=l,e.onReport?.(d),await Ye(d,e),d},r=()=>{o().catch((c)=>{e.onError?.(c)})},i=()=>{if(n)clearInterval(n),n=null};return{close:i,reportOnce:o,start:()=>{if(n)return;r(),n=setInterval(r,e.intervalMs??Xe)},stop:i}};var B=()=>{},Je=()=>B,Qe={callControl:B,close:B,endTurn:B,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",send:B,sendAudio:B,simulateDisconnect:B,start:()=>{},subscribe:Je},Ze=()=>crypto.randomUUID(),Ke=(e,n,t)=>{let{hostname:o,port:r,protocol:i}=window.location,c=i==="https:"?"wss:":"ws:",l=r?`:${r}`:"",g=new URL(`${c}//${o}${l}${e}`);if(g.searchParams.set("sessionId",n),t)g.searchParams.set("scenarioId",t);return g.toString()},me=(e)=>{if(!e||typeof e!=="object"||!("type"in e))return!1;switch(e.type){case"audio":case"assistant":case"call_lifecycle":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},je=(e)=>{if(typeof e.data!=="string")return null;try{let n=JSON.parse(e.data);return me(n)?n:null}catch{return null}},Se=(e,n={})=>{if(typeof window>"u")return Qe;let t=new Set,o=n.reconnect!==!1,r=n.maxReconnectAttempts??10,i=n.pingInterval??30000,c={isConnected:!1,pendingMessages:[],scenarioId:n.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:n.sessionId??Ze(),ws:null},l=(s)=>{t.forEach((S)=>S(s))},g=()=>{if(c.pingInterval)clearInterval(c.pingInterval),c.pingInterval=null;if(c.reconnectTimeout)clearTimeout(c.reconnectTimeout),c.reconnectTimeout=null},y=()=>{if(c.ws?.readyState!==1)return;while(c.pendingMessages.length>0){let s=c.pendingMessages.shift();if(s!==void 0)c.ws.send(s)}},d=()=>{let s=Date.now()+500;c.reconnectAttempts+=1,l({reconnect:{attempts:c.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:r,nextAttemptAt:s,status:"reconnecting"},type:"connection"}),c.reconnectTimeout=setTimeout(()=>{if(c.reconnectAttempts>r){l({reconnect:{attempts:c.reconnectAttempts,maxAttempts:r,status:"exhausted"},type:"connection"});return}h()},500)},h=()=>{let s=new WebSocket(Ke(e,c.sessionId,c.scenarioId));s.binaryType="arraybuffer",s.onopen=()=>{let S=c.reconnectAttempts>0;if(c.isConnected=!0,y(),S)l({reconnect:{attempts:c.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:r,status:"resumed"},type:"connection"}),c.reconnectAttempts=0;t.forEach((L)=>L({scenarioId:c.scenarioId??void 0,sessionId:c.sessionId,status:"active",type:"session"})),c.pingInterval=setInterval(()=>{if(s.readyState===1)s.send(JSON.stringify({type:"ping"}))},i)},s.onmessage=(S)=>{let L=je(S);if(!L)return;if(L.type==="session")c.sessionId=L.sessionId,c.scenarioId=L.scenarioId??c.scenarioId;t.forEach((X)=>X(L))},s.onclose=(S)=>{if(c.isConnected=!1,g(),o&&S.code!==1000&&c.reconnectAttempts<r)d();else if(o&&S.code!==1000)l({reconnect:{attempts:c.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:r,status:"exhausted"},type:"connection"})},c.ws=s},a=(s)=>{if(c.ws?.readyState===1){c.ws.send(s);return}c.pendingMessages.push(s)},M=(s)=>{a(JSON.stringify(s))},C=(s={})=>{if(s.sessionId)c.sessionId=s.sessionId;if(s.scenarioId)c.scenarioId=s.scenarioId;M({type:"start",sessionId:c.sessionId,scenarioId:c.scenarioId??void 0})},I=(s)=>{a(s)},w=()=>{M({type:"end_turn"})},R=(s)=>{M({...s,type:"call_control"})},u=()=>{if(g(),c.ws)c.ws.close(1000),c.ws=null;c.isConnected=!1,t.clear()},O=()=>{if(c.ws?.readyState===1)c.ws.close(4000,"absolutejs-voice-reconnect-proof")},U=(s)=>{return t.add(s),()=>{t.delete(s)}};return h(),{callControl:R,close:u,endTurn:w,getReadyState:()=>c.ws?.readyState??3,getScenarioId:()=>c.scenarioId??"",getSessionId:()=>c.sessionId,send:M,sendAudio:I,simulateDisconnect:O,start:C,subscribe:U}};var ve=()=>({attempts:0,maxAttempts:0,status:"idle"}),Fe=()=>({assistantAudio:[],assistantTexts:[],call:null,error:null,isConnected:!1,sessionMetadata:null,scenarioId:null,partial:"",reconnect:ve(),sessionId:null,status:"idle",turns:[]}),Me=()=>{let e=Fe(),n=new Set,t=()=>{n.forEach((r)=>r())};return{dispatch:(r)=>{switch(r.type){case"audio":e={...e,assistantAudio:[...e.assistantAudio,{chunk:r.chunk,format:r.format,receivedAt:r.receivedAt,turnId:r.turnId}]};break;case"assistant":e={...e,assistantTexts:[...e.assistantTexts,r.text]};break;case"complete":e={...e,sessionId:r.sessionId,status:"completed"};break;case"call_lifecycle":e={...e,call:{...e.call,disposition:r.event.type==="end"?r.event.disposition:e.call?.disposition,endedAt:r.event.type==="end"?r.event.at:e.call?.endedAt,events:[...e.call?.events??[],r.event],lastEventAt:r.event.at,startedAt:e.call?.startedAt??r.event.at},sessionId:r.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:r.reconnect};break;case"disconnected":e={...e,isConnected:!1};break;case"error":e={...e,error:r.message};break;case"final":e={...e,partial:r.transcript.text,turns:e.turns.map((i)=>i)};break;case"partial":e={...e,partial:r.transcript.text};break;case"replay":e={...e,assistantTexts:[...r.assistantTexts],call:r.call??null,error:null,isConnected:r.status==="active",partial:r.partial,reconnect:e.reconnect.status==="reconnecting"?{...e.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:e.reconnect,scenarioId:r.scenarioId??e.scenarioId,sessionId:r.sessionId,sessionMetadata:r.sessionMetadata??e.sessionMetadata,status:r.status,turns:[...r.turns]};break;case"session":e={...e,error:null,scenarioId:r.scenarioId??e.scenarioId,isConnected:r.status==="active",sessionId:r.sessionId,sessionMetadata:r.sessionMetadata??e.sessionMetadata,status:r.status};break;case"turn":e={...e,partial:"",turns:[...e.turns,r.turn]};break}t()},getServerSnapshot:()=>e,getSnapshot:()=>e,subscribe:(r)=>{return n.add(r),()=>{n.delete(r)}}}};var Ie=(e,n={})=>{let t=Se(e,n),o=Me(),r=n.browserMedia&&typeof window<"u"?Te({...n.browserMedia,getScenarioId:()=>n.browserMedia?n.browserMedia.getScenarioId?.()??t.getScenarioId():t.getScenarioId(),getSessionId:()=>n.browserMedia?n.browserMedia.getSessionId?.()??t.getSessionId():t.getSessionId()}):null,i=new Set,c=(d)=>Promise.resolve().then(()=>{if(!d?.sessionId&&!d?.scenarioId)return;t.start(d),r?.start()}),l=()=>{i.forEach((d)=>d())},g=()=>{if(!n.reconnectReportPath||typeof fetch>"u")return;let d=o.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:d.reconnect,scenarioId:d.scenarioId,sessionId:t.getSessionId(),turnIds:d.turns.map((a)=>a.id)});fetch(n.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},y=t.subscribe((d)=>{let h=Ae(d);if(h){if(o.dispatch(h),d.type==="connection")g();l()}});return{callControl(d){t.callControl(d)},close(){y(),r?.close(),t.close(),o.dispatch({type:"disconnected"}),l()},endTurn(){t.endTurn()},get error(){return o.getSnapshot().error},getServerSnapshot(){return o.getServerSnapshot()},getSnapshot(){return o.getSnapshot()},get isConnected(){return o.getSnapshot().isConnected},get scenarioId(){return o.getSnapshot().scenarioId},get sessionMetadata(){return o.getSnapshot().sessionMetadata},start:c,get partial(){return o.getSnapshot().partial},get reconnect(){return o.getSnapshot().reconnect},get sessionId(){return t.getSessionId()},get status(){return o.getSnapshot().status},get turns(){return o.getSnapshot().turns},get assistantTexts(){return o.getSnapshot().assistantTexts},get assistantAudio(){return o.getSnapshot().assistantAudio},get call(){return o.getSnapshot().call},sendAudio(d){t.sendAudio(d)},simulateDisconnect(){t.simulateDisconnect()},subscribe(d){return i.add(d),()=>{i.delete(d)}}}};var Ve=(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 pe={balanced:{qualityProfile:"general",silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},en={general:{},"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var we=(e)=>{let n=e?.profile??"fast",t=e?.qualityProfile??"general",o=pe[n],r=en[t];return{profile:n,qualityProfile:t,silenceMs:e?.silenceMs??r.silenceMs??o.silenceMs,speechThreshold:e?.speechThreshold??r.speechThreshold??o.speechThreshold,transcriptStabilityMs:e?.transcriptStabilityMs??r.transcriptStabilityMs??o.transcriptStabilityMs}};var nn={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:{qualityProfile:"short-command",profile:"balanced"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{qualityProfile:"general",profile:"fast"}},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:{qualityProfile:"accent-heavy",profile:"long-form"}},"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:{qualityProfile:"accent-heavy",profile:"long-form"}},"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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form"}}},Le=(e="default")=>{let n=nn[e];return{audioConditioning:Ve(n.audioConditioning),capture:{channelCount:n.capture?.channelCount??1,sampleRateHz:n.capture?.sampleRateHz??16000},connection:{...n.connection},name:e,sttLifecycle:n.sttLifecycle??"continuous",turnDetection:we(n.turnDetection)}};var on=(e)=>({assistantAudio:[...e.assistantAudio],assistantTexts:[...e.assistantTexts],call:e.call,error:e.error,isConnected:e.isConnected,isRecording:!1,partial:e.partial,reconnect:e.reconnect,recordingError:null,sessionId:e.sessionId,sessionMetadata:e.sessionMetadata,scenarioId:e.scenarioId,status:e.status,turns:[...e.turns]}),m=(e,n={})=>{let t=Le(n.preset),o=Ie(e,{...t.connection,...n.connection}),r=null,i=on(o),c=new Set,l=()=>{for(let C of c)C()},g=()=>{if(i={...i,assistantAudio:[...o.assistantAudio],assistantTexts:[...o.assistantTexts],call:o.call,error:o.error,isConnected:o.isConnected,partial:o.partial,reconnect:o.reconnect,sessionId:o.sessionId,sessionMetadata:o.sessionMetadata,scenarioId:o.scenarioId,status:o.status,turns:[...o.turns]},n.autoStopOnComplete!==!1&&i.status==="completed"&&i.isRecording)r?.stop(),r=null,i={...i,isRecording:!1};l()},y=o.subscribe(g);g();let d=()=>{if(r)return r;return r=ge({channelCount:n.capture?.channelCount??t.capture.channelCount,onLevel:n.capture?.onLevel,onAudio:(C)=>{if(n.capture?.onAudio){n.capture.onAudio(C,o.sendAudio);return}o.sendAudio(C)},sampleRateHz:n.capture?.sampleRateHz??t.capture.sampleRateHz}),r},h=()=>{r?.stop(),r=null,i={...i,isRecording:!1},l()},a=async()=>{if(i.isRecording)return;try{i={...i,recordingError:null},l(),await d().start(),i={...i,isRecording:!0},l()}catch(C){throw r=null,i={...i,isRecording:!1,recordingError:C instanceof Error?C.message:String(C)},l(),C}};return{bindHTMX(C){return de(o,C)},callControl:(C)=>o.callControl(C),close:()=>{y(),h(),o.close()},endTurn:()=>o.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 recordingError(){return i.recordingError},get reconnect(){return i.reconnect},sendAudio:(C)=>o.sendAudio(C),simulateDisconnect:()=>o.simulateDisconnect(),get sessionId(){return i.sessionId},get sessionMetadata(){return i.sessionMetadata},get scenarioId(){return i.scenarioId},startRecording:a,get status(){return i.status},stopRecording:h,subscribe:(C)=>{return c.add(C),()=>{c.delete(C)}},toggleRecording:async()=>{if(i.isRecording){h();return}await a()},get turns(){return i.turns},get assistantTexts(){return i.assistantTexts},get assistantAudio(){return i.assistantAudio},get call(){return i.call}}};var tn=()=>({activeSourceCount:0,error:null,isActive:!1,isPlaying:!1,lastInterruptLatencyMs:void 0,lastPlaybackStopLatencyMs:void 0,processedChunkCount:0,queuedChunkCount:0}),cn=()=>{if(typeof window>"u")return typeof AudioContext>"u"?void 0:AudioContext;return window.AudioContext??window.webkitAudioContext},rn=(e,n)=>{let t=n.format;if(t.container!=="raw"||t.encoding!=="pcm_s16le")throw Error(`Unsupported assistant audio format: ${t.container}/${t.encoding}`);let o=n.chunk,r=Math.max(1,t.channels),i=Math.floor(o.byteLength/2),c=Math.max(1,Math.floor(i/r)),l=e.createBuffer(r,c,t.sampleRateHz),g=new DataView(o.buffer,o.byteOffset,o.byteLength);for(let y=0;y<r;y+=1){let d=l.getChannelData(y);for(let h=0;h<c;h+=1){let M=(h*r+y)*2;if(M+1>=o.byteLength){d[h]=0;continue}d[h]=g.getInt16(M,!0)/32768}}return l},j=(e,n={})=>{let t=new Set,o=new Set,r=(n.lookaheadMs??15)/1000,i=tn(),c=null,l=null,g=0,y=Promise.resolve(),d=null,h=null,a=null,M=null,C=()=>{for(let A of t)A()},I=(A)=>{i={...i,...A},C()},w=()=>{if(i.error!==null)I({error:null})},R=()=>{if(M!==null)clearTimeout(M),M=null},u=(A)=>{R(),d=null,I({activeSourceCount:o.size,isPlaying:!1,lastInterruptLatencyMs:A,lastPlaybackStopLatencyMs:i.lastPlaybackStopLatencyMs??A}),a?.(),a=null,h=null},O=(A)=>{if(!A)return 0;return Math.max(0,((A.baseLatency??0)+(A.outputLatency??0))*1000)},U=(A)=>{if(!l)return;let f=1;if(l.gain.setValueAtTime){l.gain.setValueAtTime(f,A?.currentTime??0);return}l.gain.value=f},s=(A)=>{if(!l)return;let f=0;if(l.gain.setValueAtTime){l.gain.setValueAtTime(f,A?.currentTime??0);return}l.gain.value=f},S=()=>{if(d===null||o.size>0)return;u(Date.now()-d)},L=async()=>{if(c)return c;if(n.createAudioContext)c=n.createAudioContext();else{let A=cn();if(!A)throw Error("Assistant audio playback requires AudioContext support.");c=new A}if(c.createGain)l=c.createGain(),l.connect?.(c.destination);return g=c.currentTime,c},X=async(A)=>{let f=await L(),E=rn(f,A),V=f.createBufferSource();V.buffer=E,V.connect(l??f.destination),V.onended=()=>{o.delete(V),V.disconnect?.(),I({activeSourceCount:o.size,isPlaying:o.size>0&&i.isActive}),S()};let Y=Math.max(f.currentTime+r,g);g=Y+E.duration,o.add(V),I({activeSourceCount:o.size,isPlaying:!0}),V.start(Y)},_=(A)=>{for(let f of[...o])f.stop?.();if(g=c?c.currentTime:0,A?.forceClear){for(let f of o)f.disconnect?.();o.clear(),S()}},W=async()=>{if(!i.isActive)return;let A=e.assistantAudio.slice(i.processedChunkCount);if(A.length===0)return;try{w();for(let f of A)await X(f);I({processedChunkCount:e.assistantAudio.length,queuedChunkCount:i.queuedChunkCount+A.length})}catch(f){I({error:f instanceof Error?f.message:String(f)})}},P=()=>{return y=y.then(()=>W(),()=>W()),y},$=e.subscribe(()=>{if(n.autoStart&&!i.isActive&&e.assistantAudio.length>0){N.start();return}if(i.isActive)P()}),N={close:async()=>{if($(),_({forceClear:!0}),R(),a?.(),a=null,h=null,d=null,c&&c.state!=="closed")await c.close();c=null,l?.disconnect?.(),l=null,g=0,I({activeSourceCount:0,isActive:!1,isPlaying:!1})},get activeSourceCount(){return i.activeSourceCount},get error(){return i.error},getSnapshot:()=>i,get isActive(){return i.isActive},get isPlaying(){return i.isPlaying},interrupt:async()=>{let A=Date.now(),f=await L();d=A,s(f);let E=Date.now()-A+O(f);if(I({isActive:!1,isPlaying:o.size>0,lastPlaybackStopLatencyMs:E}),o.size===0){u(E);return}if(!h)h=new Promise((V)=>{a=V});R(),M=setTimeout(()=>{for(let V of o)V.disconnect?.();o.clear(),u(Date.now()-A)},250),_(),await h},get lastInterruptLatencyMs(){return i.lastInterruptLatencyMs},get lastPlaybackStopLatencyMs(){return i.lastPlaybackStopLatencyMs},pause:async()=>{if(!c){I({activeSourceCount:0,isActive:!1,isPlaying:!1});return}await c.suspend(),I({activeSourceCount:o.size,isActive:!1,isPlaying:!1})},get processedChunkCount(){return i.processedChunkCount},get queuedChunkCount(){return i.queuedChunkCount},start:async()=>{try{w();let A=await L();if(U(A),A.state==="suspended")await A.resume();I({activeSourceCount:o.size,isActive:!0,isPlaying:A.state==="running"}),await P()}catch(A){throw I({error:A instanceof Error?A.message:String(A),isActive:!1,isPlaying:!1}),A}},subscribe:(A)=>{return t.add(A),()=>{t.delete(A)}}};return N};var sn=()=>`barge-in:${Date.now()}:${crypto.randomUUID?.()??Math.random().toString(36).slice(2)}`,ln=(e,n)=>{let t=e.filter((c)=>c.status==="stopped"),o=t.map((c)=>c.latencyMs).filter((c)=>typeof c==="number"),r=t.filter((c)=>typeof c.latencyMs==="number"&&c.latencyMs>n).length,i=t.length-r;return{averageLatencyMs:o.length>0?Math.round(o.reduce((c,l)=>c+l,0)/o.length):void 0,events:[...e],failed:r,lastEvent:e.at(-1),passed:i,status:e.length===0?"empty":r>0?"fail":t.length===0?"warn":"pass",thresholdMs:n,total:t.length}},ue=(e={})=>{let n=new Set,t=e.thresholdMs??250,o=e.fetch??globalThis.fetch,r=[],i=()=>{for(let g of n)g()},c=(g)=>{if(!e.path||typeof o!=="function")return;o(e.path,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},method:"POST"}).catch(()=>{})},l=(g,y)=>{let d={at:Date.now(),id:sn(),latencyMs:y.latencyMs,playbackStopLatencyMs:y.playbackStopLatencyMs,reason:y.reason,sessionId:y.sessionId,status:g,thresholdMs:t};return r.push(d),c(d),i(),d};return{getSnapshot:()=>ln(r,t),recordRequested:(g)=>l("requested",g),recordSkipped:(g)=>l("skipped",g),recordStopped:(g)=>l("stopped",g),subscribe:(g)=>{return n.add(g),()=>{n.delete(g)}}}};var an=0.08,dn=(e,n={})=>(n.enabled??!0)&&e>=(n.interruptThreshold??an),oe=(e,n,t={})=>{let o=e.partial,r=(c)=>{if(!n.isPlaying||t.enabled===!1){t.monitor?.recordSkipped({reason:c,sessionId:e.sessionId});return}t.monitor?.recordRequested({reason:c,sessionId:e.sessionId}),n.interrupt().then(()=>{t.monitor?.recordStopped({latencyMs:n.lastInterruptLatencyMs,playbackStopLatencyMs:n.lastPlaybackStopLatencyMs,reason:c,sessionId:e.sessionId})})},i=e.subscribe(()=>{if(t.interruptOnPartial===!1){o=e.partial;return}if(!o&&e.partial)r("partial-transcript");o=e.partial});return{close:()=>{i()},handleLevel:(c)=>{if(dn(c,t))r("input-level")},sendAudio:(c)=>{r("manual-audio"),e.sendAudio(c)}}};var se=48,gn=320,An=88,hn="Guided test",yn="General recording",Cn="Pick a scenario to begin the demo.",fn="I can walk you through a short guided voice test.",Tn="I can capture one freeform recording and confirm that it landed.",Sn="Choose a scenario to begin. Guided test asks follow-up prompts. General recording just captures what you say.",Mn="Click Start general recording to capture one freeform answer.",_e="Speak freely. When you pause, the recording will be captured.",re="Recording saved. Start again if you want another capture.",Ee="Guided test complete. Review the saved summary below.",Pe="All prompts are covered. You can stop the microphone or keep speaking for extra detail.",In="Ready. Start guided test or general recording to begin.",Vn="Live. Answer the prompt, then click Stop microphone when finished.",Re=["Start with a quick introduction about who you are.","Now describe what you are trying to do or test.","Finish with any detail that feels blocked, risky, or unclear."],De=(e,n,t)=>Math.min(t,Math.max(n,e)),q=(e)=>e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll(\'"\',""").replaceAll("\'","'"),te=(e,n)=>{let t=e[n];if(typeof t==="string"&&t.trim())return t;return null},ie=(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 n=e,t=te(n,"message")??te(n,"reason")??te(n,"description");if(t)return t;if("error"in n)return ie(n.error);if("cause"in n)return ie(n.cause);try{return JSON.stringify(e)}catch{}}return"Unexpected error"},wn=(e)=>{let n=[e.status];if(e.attempts>0||e.maxAttempts>0)n.push(`${e.attempts}/${e.maxAttempts} attempts`);if(e.nextAttemptAt){let t=Math.max(0,e.nextAttemptAt-Date.now());n.push(`retry in ${Math.ceil(t/100)/10}s`)}return n.join(" \xB7 ")},v=(e=se)=>Array.from({length:e},()=>0),be=(e,n,t=se)=>{let o=e.slice(-(t-1));o.push(De(n,0,1));while(o.length<t)o.unshift(0);return o},Ln=(e,n=gn,t=An)=>{let o=e.length>1?e:v(se),r=n/(o.length-1),i=t/2,c=t*0.34;if(Math.max(...o,0)<=0.015)return`M 0 ${i} L ${n} ${i}`;let g=o.map((d,h)=>{let a=h*0.76,M=Math.sin(a)*0.78+Math.sin(a*0.41)*0.22,C=d*c,I=r*h,w=De(i+M*C,8,t-8);return{x:I,y:w}});if(g.length===0)return`M 0 ${i} L ${n} ${i}`;let y=`M ${g[0]?.x??0} ${g[0]?.y??i}`;for(let d=1;d<g.length;d+=1){let h=g[d-1],a=g[d];if(!h||!a)continue;let M=(h.x+a.x)/2;y+=` Q ${M} ${h.y} ${a.x} ${a.y}`}return y},un=(e)=>{if(!e)return Re;try{let n=JSON.parse(e);if(Array.isArray(n)){let t=n.filter((o)=>typeof o==="string").map((o)=>o.trim()).filter(Boolean);if(t.length>0)return t}}catch{}return Re},ce=(e)=>{if(!e)return;let n=Number(e);return Number.isFinite(n)?n:void 0},Rn=(e,n,t)=>{if(!n)return null;let o=document.querySelector(n);return o instanceof t?o:null},x=(e,n,t,o)=>{let r=n?document.querySelector(n):null;if(r instanceof t)return r;let i=e.querySelector(`#${o}`);if(i instanceof t)return i;throw Error(`Voice HTMX bootstrap could not find the required element "${o}".`)},bn=(e)=>{if(!e.mode)return Cn;if(!e.hasStarted)return e.mode==="guided"?fn:Tn;if(e.status==="completed")return e.mode==="guided"?Ee:re;if(e.mode==="general")return _e;return e.guidedPrompts[e.turnCount]??Pe},_n=(e)=>{if(!e.mode)return Sn;if(e.status==="completed")return e.mode==="guided"?Ee:re;if(!e.hasStarted)return e.mode==="guided"?`Click Start guided test to begin. First prompt: ${e.guidedPrompts[0]??"Answer the first prompt."}`:Mn;if(e.mode==="general")return e.turnCount===0?_e:re;return e.guidedPrompts[e.turnCount]??Pe},En=(e)=>{let n=e.dataset.voiceGuidedPath,t=e.dataset.voiceGeneralPath;if(!n||!t)throw Error("Voice HTMX bootstrap requires data-voice-guided-path and data-voice-general-path.");let o=un(e.dataset.voiceGuidedPrompts),r=e.dataset.voiceGuidedLabel??hn,i=e.dataset.voiceGeneralLabel??yn,c=e.dataset.voiceReconnectReportPath,l=e.dataset.voiceBargeInPath,g=l?ue({path:l,thresholdMs:ce(e.dataset.voiceBargeInThresholdMs)}):null,y=ce(e.dataset.voiceBargeInRecentWindowMs)??4000,d=ce(e.dataset.voiceBargeInSpeechThreshold)??0.04,h=x(document,e.dataset.voiceSync,HTMLElement,"voice-htmx-sync"),a=x(e,e.dataset.voiceConnection,HTMLElement,"metric-connection"),M=x(e,e.dataset.voiceError,HTMLElement,"status-error"),C=x(e,e.dataset.voiceMicrophone,HTMLElement,"status-mic"),I=x(e,e.dataset.voicePrompt,HTMLElement,"status-prompt"),w=Rn(e,e.dataset.voiceReconnect,HTMLElement),R=x(e,e.dataset.voiceChat,HTMLElement,"chat-list"),u=x(e,e.dataset.voiceStartGuided,HTMLButtonElement,"start-guided"),O=x(e,e.dataset.voiceStartGeneral,HTMLButtonElement,"start-general"),U=x(e,e.dataset.voiceStop,HTMLButtonElement,"stop-mic"),s=x(e,e.dataset.voiceMonitor,HTMLElement,"voice-monitor"),S=x(e,e.dataset.voiceMonitorCopy,HTMLElement,"voice-monitor-copy"),L=x(e,e.dataset.voiceWaveGlow,SVGPathElement,"voice-wave-glow"),X=x(e,e.dataset.voiceWavePath,SVGPathElement,"voice-wave-path"),_=null,W={general:!1,guided:!1},P=!1,$=null,N=v(),A=null,f=null,E=m(n,{capture:{onAudio:(T,G)=>{if(A){A.sendAudio(T);return}G(T)},onLevel:(T)=>{A?.handleLevel(T),N=be(N,T),F()}},connection:{reconnectReportPath:c},preset:"guided-intake"}),V=m(t,{capture:{onAudio:(T,G)=>{if(f){f.sendAudio(T);return}G(T)},onLevel:(T)=>{f?.handleLevel(T),N=be(N,T),F()}},connection:{reconnectReportPath:c},preset:"dictation"}),Y=E.bindHTMX({element:h}),xe=V.bindHTMX({element:h}),J=j(E),Q=j(V);A=oe(E,J,{interruptThreshold:d,monitor:g??void 0}),f=oe(V,Q,{interruptThreshold:d,monitor:g??void 0});let z=()=>_==="general"?V:E,Dn=()=>_==="general"?Q:J,F=()=>{let T=Ln(N);L.setAttribute("d",T),X.setAttribute("d",T),S.innerHTML=`<span class="voice-live-dot"></span>${P?"Microphone live":"Microphone idle"}`,S.classList.toggle("is-live",P),s.classList.toggle("is-live",P)},k=()=>{let T=z(),G=(_?W[_]:!1)||T.turns.length>0,ae=T.status;if(a.textContent=T.isConnected?"Connected":"Waiting",M.textContent=$||T.error||"None",w)w.textContent=wn(T.reconnect);C.textContent=P?Vn:In,I.textContent=_n({guidedPrompts:o,hasStarted:G,mode:_,status:ae,turnCount:T.turns.length}),u.hidden=P,O.hidden=P,U.hidden=!P,R.innerHTML=`<article class="voice-chat-message assistant">\n <div class="voice-chat-role">${q(_==="general"?i:_==="guided"?r:"Voice demo")}</div>\n <p class="voice-turn-text">${q(bn({generalLabel:i,guidedLabel:r,guidedPrompts:o,hasStarted:G,mode:_,status:ae,turnCount:T.turns.length}))}</p>\n</article>${T.turns.map((p)=>`<div class="voice-chat-stack">\n <article class="voice-chat-message user">\n <div class="voice-chat-role">You</div>\n <p class="voice-turn-text">${q(p.text)}</p>\n </article>\n ${p.assistantText?`<article class="voice-chat-message assistant">\n <div class="voice-chat-role">${q(_==="general"?i:_==="guided"?r:"Guide")}</div>\n <p class="voice-turn-text">${q(p.assistantText)}</p>\n </article>`:""}\n</div>`).join("")}${T.partial?`<article class="voice-chat-message user pending">\n <div class="voice-chat-role">Speaking</div>\n <p class="voice-turn-text">${q(T.partial)}</p>\n</article>`:""}`,F()},Oe=()=>{z().stopRecording(),P=!1,$=null,N=v(),k()},le=async(T)=>{_=T,W={...W,[T]:!0};try{await z().startRecording(),$=null,P=!0,k()}catch(G){z().stopRecording(),P=!1,N=v(),$=ie(G),k()}};E.subscribe(()=>{if(E.assistantAudio.length>0)J.start().catch(()=>{});k()}),V.subscribe(()=>{if(V.assistantAudio.length>0)Q.start().catch(()=>{});k()}),u.addEventListener("click",()=>{le("guided")}),O.addEventListener("click",()=>{le("general")}),U.addEventListener("click",()=>{Oe()}),e.addEventListener("absolute-voice-simulate-disconnect",()=>{z().simulateDisconnect()}),window.addEventListener("beforeunload",()=>{E.stopRecording(),V.stopRecording(),A?.close(),f?.close(),J.close(),Q.close(),Y(),xe(),E.close(),V.close()}),k()},Pn=()=>{if(typeof window>"u"||typeof document>"u")return;let e=Array.from(document.querySelectorAll("[data-voice-htmx]"));for(let n of e)if(n instanceof HTMLElement)En(n)};Pn();export{Pn as initVoiceHTMX};\n';
|
|
5189
|
+
var HTMX_BOOTSTRAP_BUNDLE = 'var We=(e)=>{if(typeof e!=="string")return e;return document.querySelector(e)},$e=(e,n,c,o)=>{let s=n??e.getAttribute("hx-get")??"";if(!s)return"";let t=new URL(s,window.location.origin);if(o)t.searchParams.set(c,o);else t.searchParams.delete(c);return`${t.pathname}${t.search}${t.hash}`},fe=(e,n)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let c=We(n.element);if(!c)return()=>{};let o=n.eventName??"voice-refresh",s=n.sessionQueryParam??"sessionId",t=()=>{let r=window,d=$e(c,n.route,s,e.sessionId);if(d)c.setAttribute("hx-get",d);r.htmx?.process?.(c),r.htmx?.trigger?.(c,o)},i=e.subscribe(t);return t(),()=>{i()}};var ke=(e)=>Math.max(-1,Math.min(1,e)),qe=(e)=>{let n=new Int16Array(e.length);for(let c=0;c<e.length;c+=1){let o=ke(e[c]??0);n[c]=o<0?o*32768:o*32767}return new Uint8Array(n.buffer)},Xe=(e)=>{let n=e instanceof Uint8Array?e:new Uint8Array(e);if(n.byteLength<2)return 0;let c=new Int16Array(n.buffer,n.byteOffset,Math.floor(n.byteLength/2));if(c.length===0)return 0;let o=0;for(let s of c){let t=s/32768;o+=t*t}return Math.min(1,Math.max(0,Math.sqrt(o/c.length)*5.5))},ze=(e,n,c)=>{if(n===c)return e;let o=n/c,s=Math.round(e.length/o),t=new Float32Array(s),i=0,r=0;while(i<t.length){let d=Math.round((i+1)*o),f=0,a=0;for(let A=r;A<d&&A<e.length;A+=1)f+=e[A]??0,a+=1;t[i]=a>0?f/a:0,i+=1,r=d}return t},Ae=(e)=>{let n=null,c=null,o=null,s=null;return{start:async()=>{if(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.");s=await navigator.mediaDevices.getUserMedia({audio:{channelCount:e.channelCount??1}}),n=new r,c=n.createMediaStreamSource(s),o=n.createScriptProcessor(4096,1,1),o.onaudioprocess=(d)=>{let f=d.inputBuffer.getChannelData(0),a=ze(f,n?.sampleRate??48000,e.sampleRateHz??16000),A=qe(a);e.onLevel?.(Xe(A)),e.onAudio(A)},c.connect(o),o.connect(n.destination)},stop:()=>{o?.disconnect(),c?.disconnect(),s?.getTracks().forEach((r)=>r.stop()),n?.close(),e.onLevel?.(0),n=null,s=null,o=null,c=null}}};var ne=(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 n=e;for(let c of["message","reason","description"]){let o=n[c];if(typeof o==="string"&&o.trim())return o}if("error"in n)return ne(n.error);if("cause"in n)return ne(n.cause);try{return JSON.stringify(e)}catch{}}return"Unexpected error"},he=(e)=>{switch(e.type){case"audio":return{chunk:Uint8Array.from(atob(e.chunkBase64),(n)=>n.charCodeAt(0)),format:e.format,receivedAt:e.receivedAt,turnId:e.turnId,type:"audio"};case"assistant":return{text:e.text,type:"assistant"};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:ne(e.message),type:"error"};case"final":return{transcript:e.transcript,type:"final"};case"partial":return{transcript:e.transcript,type:"partial"};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{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{mkdir:pn,writeFile:ec}=(()=>({}));function H(e){if(typeof e!=="string")throw TypeError("Path must be a string. Received "+JSON.stringify(e))}function Ce(e,n){var c="",o=0,s=-1,t=0,i;for(var r=0;r<=e.length;++r){if(r<e.length)i=e.charCodeAt(r);else if(i===47)break;else i=47;if(i===47){if(s===r-1||t===1);else if(s!==r-1&&t===2){if(c.length<2||o!==2||c.charCodeAt(c.length-1)!==46||c.charCodeAt(c.length-2)!==46){if(c.length>2){var d=c.lastIndexOf("/");if(d!==c.length-1){if(d===-1)c="",o=0;else c=c.slice(0,d),o=c.length-1-c.lastIndexOf("/");s=r,t=0;continue}}else if(c.length===2||c.length===1){c="",o=0,s=r,t=0;continue}}if(n){if(c.length>0)c+="/..";else c="..";o=2}}else{if(c.length>0)c+="/"+e.slice(s+1,r);else c=e.slice(s+1,r);o=r-s-1}s=r,t=0}else if(i===46&&t!==-1)++t;else t=-1}return c}function Ye(e,n){var c=n.dir||n.root,o=n.base||(n.name||"")+(n.ext||"");if(!c)return o;if(c===n.root)return c+o;return c+e+o}function ce(){var e="",n=!1,c;for(var o=arguments.length-1;o>=-1&&!n;o--){var s;if(o>=0)s=arguments[o];else{if(c===void 0)c=process.cwd();s=c}if(H(s),s.length===0)continue;e=s+"/"+e,n=s.charCodeAt(0)===47}if(e=Ce(e,!n),n)if(e.length>0)return"/"+e;else return"/";else if(e.length>0)return e;else return"."}function ye(e){if(H(e),e.length===0)return".";var n=e.charCodeAt(0)===47,c=e.charCodeAt(e.length-1)===47;if(e=Ce(e,!n),e.length===0&&!n)e=".";if(e.length>0&&c)e+="/";if(n)return"/"+e;return e}function Je(e){return H(e),e.length>0&&e.charCodeAt(0)===47}function Te(){if(arguments.length===0)return".";var e;for(var n=0;n<arguments.length;++n){var c=arguments[n];if(H(c),c.length>0)if(e===void 0)e=c;else e+="/"+c}if(e===void 0)return".";return ye(e)}function Qe(e,n){if(H(e),H(n),e===n)return"";if(e=ce(e),n=ce(n),e===n)return"";var c=1;for(;c<e.length;++c)if(e.charCodeAt(c)!==47)break;var o=e.length,s=o-c,t=1;for(;t<n.length;++t)if(n.charCodeAt(t)!==47)break;var i=n.length,r=i-t,d=s<r?s:r,f=-1,a=0;for(;a<=d;++a){if(a===d){if(r>d){if(n.charCodeAt(t+a)===47)return n.slice(t+a+1);else if(a===0)return n.slice(t+a)}else if(s>d){if(e.charCodeAt(c+a)===47)f=a;else if(a===0)f=0}break}var A=e.charCodeAt(c+a),g=n.charCodeAt(t+a);if(A!==g)break;else if(A===47)f=a}var y="";for(a=c+f+1;a<=o;++a)if(a===o||e.charCodeAt(a)===47)if(y.length===0)y+="..";else y+="/..";if(y.length>0)return y+n.slice(t+f);else{if(t+=f,n.charCodeAt(t)===47)++t;return n.slice(t)}}function Ze(e){return e}function Ke(e){if(H(e),e.length===0)return".";var n=e.charCodeAt(0),c=n===47,o=-1,s=!0;for(var t=e.length-1;t>=1;--t)if(n=e.charCodeAt(t),n===47){if(!s){o=t;break}}else s=!1;if(o===-1)return c?"/":".";if(c&&o===1)return"//";return e.slice(0,o)}function me(e,n){if(n!==void 0&&typeof n!=="string")throw TypeError(\'"ext" argument must be a string\');H(e);var c=0,o=-1,s=!0,t;if(n!==void 0&&n.length>0&&n.length<=e.length){if(n.length===e.length&&n===e)return"";var i=n.length-1,r=-1;for(t=e.length-1;t>=0;--t){var d=e.charCodeAt(t);if(d===47){if(!s){c=t+1;break}}else{if(r===-1)s=!1,r=t+1;if(i>=0)if(d===n.charCodeAt(i)){if(--i===-1)o=t}else i=-1,o=r}}if(c===o)o=r;else if(o===-1)o=e.length;return e.slice(c,o)}else{for(t=e.length-1;t>=0;--t)if(e.charCodeAt(t)===47){if(!s){c=t+1;break}}else if(o===-1)s=!1,o=t+1;if(o===-1)return"";return e.slice(c,o)}}function je(e){H(e);var n=-1,c=0,o=-1,s=!0,t=0;for(var i=e.length-1;i>=0;--i){var r=e.charCodeAt(i);if(r===47){if(!s){c=i+1;break}continue}if(o===-1)s=!1,o=i+1;if(r===46){if(n===-1)n=i;else if(t!==1)t=1}else if(n!==-1)t=-1}if(n===-1||o===-1||t===0||t===1&&n===o-1&&n===c+1)return"";return e.slice(n,o)}function Fe(e){if(e===null||typeof e!=="object")throw TypeError(\'The "pathObject" argument must be of type Object. Received type \'+typeof e);return Ye("/",e)}function ve(e){H(e);var n={root:"",dir:"",base:"",ext:"",name:""};if(e.length===0)return n;var c=e.charCodeAt(0),o=c===47,s;if(o)n.root="/",s=1;else s=0;var t=-1,i=0,r=-1,d=!0,f=e.length-1,a=0;for(;f>=s;--f){if(c=e.charCodeAt(f),c===47){if(!d){i=f+1;break}continue}if(r===-1)d=!1,r=f+1;if(c===46){if(t===-1)t=f;else if(a!==1)a=1}else if(t!==-1)a=-1}if(t===-1||r===-1||a===0||a===1&&t===r-1&&t===i+1){if(r!==-1)if(i===0&&o)n.base=n.name=e.slice(1,r);else n.base=n.name=e.slice(i,r)}else{if(i===0&&o)n.name=e.slice(1,t),n.base=e.slice(1,r);else n.name=e.slice(i,t),n.base=e.slice(i,r);n.ext=e.slice(t,r)}if(i>0)n.dir=e.slice(0,i-1);else if(o)n.dir="/";return n}var pe="/",en=":",jn=((e)=>(e.posix=e,e))({resolve:ce,normalize:ye,isAbsolute:Je,join:Te,relative:Qe,_makeLong:Ze,dirname:Ke,basename:me,extname:je,format:Fe,parse:ve,sep:pe,delimiter:en,win32:null,posix:null});var G=(e,n,c,o)=>{e.push({code:c,message:o,severity:n})};var nn=(e)=>e.length===0?void 0:e.reduce((n,c)=>n+c,0)/e.length,m=(e)=>e.length===0?void 0:Math.max(...e);var u=(e,n)=>{let c=e[n];return typeof c==="number"&&Number.isFinite(c)?c:void 0},K=(e,n)=>{let c=e[n];return typeof c==="boolean"?c:void 0},D=(e,n)=>{let c=e[n];return typeof c==="string"?c:void 0},oe=(e)=>String(e.id??D(e,"ssrc")??u(e,"ssrc")??D(e,"trackIdentifier")??D(e,"mid")??"unknown"),Se=(e)=>e===void 0?void 0:e*1000;var cn=(e)=>{let n={};for(let[c,o]of Object.entries(e))if(o===null||typeof o==="boolean"||typeof o==="number"||typeof o==="string")n[c]=o;return n};var Me=(e={})=>{let n=e.stats??[],c=[],o=n.filter((l)=>l.type==="inbound-rtp"&&D(l,"kind")!=="video"),s=n.filter((l)=>l.type==="outbound-rtp"&&D(l,"kind")!=="video"),t=n.filter((l)=>l.type==="candidate-pair"),i=n.filter((l)=>(l.type==="track"||l.type==="media-source")&&D(l,"kind")==="audio"),r=t.filter((l)=>K(l,"selected")===!0||K(l,"nominated")===!0||D(l,"state")==="succeeded").length,d=i.filter((l)=>D(l,"readyState")!=="ended"&&D(l,"trackState")!=="ended"&&K(l,"ended")!==!0).length,f=i.filter((l)=>D(l,"readyState")==="ended"||D(l,"trackState")==="ended"||K(l,"ended")===!0).length,a=o.reduce((l,M)=>l+(u(M,"packetsReceived")??0),0),A=s.reduce((l,M)=>l+(u(M,"packetsSent")??0),0),g=[...o,...s].reduce((l,M)=>l+Math.max(0,u(M,"packetsLost")??0),0),y=a+g,C=y===0?0:g/y,I=o.reduce((l,M)=>l+(u(M,"bytesReceived")??0),0),L=s.reduce((l,M)=>l+(u(M,"bytesSent")??0),0),R=m(t.map((l)=>Se(u(l,"currentRoundTripTime")??u(l,"roundTripTime"))).filter((l)=>l!==void 0)),w=m([...o,...s].map((l)=>Se(u(l,"jitter"))).filter((l)=>l!==void 0)),x=m(o.map((l)=>{let M=u(l,"jitterBufferDelay"),b=u(l,"jitterBufferEmittedCount");return M!==void 0&&b!==void 0&&b>0?M/b*1000:void 0}).filter((l)=>l!==void 0)),U=i.map((l)=>u(l,"audioLevel")).filter((l)=>l!==void 0);if(e.requireConnectedCandidatePair&&t.length>0&&r===0)G(c,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(e.requireLiveAudioTrack&&d===0)G(c,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(e.maxPacketLossRatio!==void 0&&C>e.maxPacketLossRatio)G(c,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(C)} above ${String(e.maxPacketLossRatio)}.`);if(e.maxRoundTripTimeMs!==void 0&&R!==void 0&&R>e.maxRoundTripTimeMs)G(c,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(R)}ms above ${String(e.maxRoundTripTimeMs)}ms.`);if(e.maxJitterMs!==void 0&&w!==void 0&&w>e.maxJitterMs)G(c,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(w)}ms above ${String(e.maxJitterMs)}ms.`);return{activeCandidatePairs:r,audioLevelAverage:nn(U),bytesReceived:I,bytesSent:L,checkedAt:Date.now(),endedAudioTracks:f,inboundPackets:a,issues:c,jitterBufferDelayMs:x,jitterMs:w,liveAudioTracks:d,outboundPackets:A,packetLossRatio:C,packetsLost:g,roundTripTimeMs:R,status:c.some((l)=>l.severity==="error")?"fail":c.length>0?"warn":"pass",totalStats:n.length}},Ie=async(e)=>{return[...(await e.peerConnection.getStats(e.selector??null)).values()].map(cn)};var Ve=(e={})=>{let n=e.stats??[],c=e.previousStats??[],o=[],s=new Map(c.map((g)=>[oe(g),g])),i=n.filter((g)=>(g.type==="inbound-rtp"||g.type==="outbound-rtp")&&D(g,"kind")!=="video"&&D(g,"mediaType")!=="video").map((g)=>{let y=g.type==="outbound-rtp"?"outbound":"inbound",C=y==="outbound"?"packetsSent":"packetsReceived",I=y==="outbound"?"bytesSent":"bytesReceived",L=s.get(oe(g)),R=u(g,C),w=L?u(L,C):void 0,x=u(g,I),U=L?u(L,I):void 0,l=g.timestamp!==void 0&&L?.timestamp!==void 0?g.timestamp-L.timestamp:void 0;return{bytesDelta:x!==void 0&&U!==void 0?x-U:void 0,currentPackets:R,direction:y,id:oe(g),packetDelta:R!==void 0&&w!==void 0?R-w:void 0,previousPackets:w,timeDeltaMs:l}}),r=i.filter((g)=>g.direction==="inbound"),d=i.filter((g)=>g.direction==="outbound"),f=m(i.map((g)=>g.timeDeltaMs).filter((g)=>g!==void 0)),a=r.filter((g)=>e.maxInboundPacketStallMs!==void 0&&g.timeDeltaMs!==void 0&&g.timeDeltaMs>=e.maxInboundPacketStallMs&&g.packetDelta!==void 0&&g.packetDelta<=0).length,A=d.filter((g)=>e.maxOutboundPacketStallMs!==void 0&&g.timeDeltaMs!==void 0&&g.timeDeltaMs>=e.maxOutboundPacketStallMs&&g.packetDelta!==void 0&&g.packetDelta<=0).length;if(e.requireInboundAudio&&r.length===0)G(o,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(e.requireOutboundAudio&&d.length===0)G(o,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(e.maxGapMs!==void 0&&f!==void 0&&f>e.maxGapMs)G(o,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(f)}ms above ${String(e.maxGapMs)}ms.`);if(a>0)G(o,"error","media.webrtc_inbound_stalled",`${String(a)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(A>0)G(o,"error","media.webrtc_outbound_stalled",`${String(A)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:r.length,issues:o,maxObservedGapMs:f,outboundAudioStreams:d.length,stalledInboundStreams:a,stalledOutboundStreams:A,status:o.some((g)=>g.severity==="error")?"fail":o.length>0?"warn":"pass",streams:i,totalStats:n.length}};var on="/api/voice/browser-media",tn=5000,sn=async(e)=>e.peerConnection??await e.getPeerConnection?.()??null,rn=async(e,n)=>{let c=n.fetch??globalThis.fetch;if(!c)return;await c(n.path??on,{body:JSON.stringify(e),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},Le=(e)=>{let n=null,c=[],o=async()=>{let i=await sn(e);if(!i)return;let r=await Ie({peerConnection:i}),d=Me({...e,stats:r}),f=e.continuity===!1?void 0:Ve({...e.continuity,previousStats:c,stats:r}),a={at:Date.now(),continuity:f,report:d,scenarioId:e.getScenarioId?.()??null,sessionId:e.getSessionId?.()??null};return c=r,e.onReport?.(a),await rn(a,e),a},s=()=>{o().catch((i)=>{e.onError?.(i)})},t=()=>{if(n)clearInterval(n),n=null};return{close:t,reportOnce:o,start:()=>{if(n)return;s(),n=setInterval(s,e.intervalMs??tn)},stop:t}};var W=()=>{},ln=()=>W,an={callControl:W,close:W,endTurn:W,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",send:W,sendAudio:W,simulateDisconnect:W,start:()=>{},subscribe:ln},dn=()=>crypto.randomUUID(),gn=(e,n,c)=>{let{hostname:o,port:s,protocol:t}=window.location,i=t==="https:"?"wss:":"ws:",r=s?`:${s}`:"",d=new URL(`${i}//${o}${r}${e}`);if(d.searchParams.set("sessionId",n),c)d.searchParams.set("scenarioId",c);return d.toString()},fn=(e)=>{if(!e||typeof e!=="object"||!("type"in e))return!1;switch(e.type){case"audio":case"assistant":case"call_lifecycle":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},An=(e)=>{if(typeof e.data!=="string")return null;try{let n=JSON.parse(e.data);return fn(n)?n:null}catch{return null}},be=(e,n={})=>{if(typeof window>"u")return an;let c=new Set,o=n.reconnect!==!1,s=n.maxReconnectAttempts??10,t=n.pingInterval??30000,i={isConnected:!1,pendingMessages:[],scenarioId:n.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:n.sessionId??dn(),ws:null},r=(l)=>{c.forEach((M)=>M(l))},d=()=>{if(i.pingInterval)clearInterval(i.pingInterval),i.pingInterval=null;if(i.reconnectTimeout)clearTimeout(i.reconnectTimeout),i.reconnectTimeout=null},f=()=>{if(i.ws?.readyState!==1)return;while(i.pendingMessages.length>0){let l=i.pendingMessages.shift();if(l!==void 0)i.ws.send(l)}},a=()=>{let l=Date.now()+500;i.reconnectAttempts+=1,r({reconnect:{attempts:i.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:s,nextAttemptAt:l,status:"reconnecting"},type:"connection"}),i.reconnectTimeout=setTimeout(()=>{if(i.reconnectAttempts>s){r({reconnect:{attempts:i.reconnectAttempts,maxAttempts:s,status:"exhausted"},type:"connection"});return}A()},500)},A=()=>{let l=new WebSocket(gn(e,i.sessionId,i.scenarioId));l.binaryType="arraybuffer",l.onopen=()=>{let M=i.reconnectAttempts>0;if(i.isConnected=!0,f(),M)r({reconnect:{attempts:i.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:s,status:"resumed"},type:"connection"}),i.reconnectAttempts=0;c.forEach((b)=>b({scenarioId:i.scenarioId??void 0,sessionId:i.sessionId,status:"active",type:"session"})),i.pingInterval=setInterval(()=>{if(l.readyState===1)l.send(JSON.stringify({type:"ping"}))},t)},l.onmessage=(M)=>{let b=An(M);if(!b)return;if(b.type==="session")i.sessionId=b.sessionId,i.scenarioId=b.scenarioId??i.scenarioId;c.forEach((z)=>z(b))},l.onclose=(M)=>{if(i.isConnected=!1,d(),o&&M.code!==1000&&i.reconnectAttempts<s)a();else if(o&&M.code!==1000)r({reconnect:{attempts:i.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:s,status:"exhausted"},type:"connection"})},i.ws=l},g=(l)=>{if(i.ws?.readyState===1){i.ws.send(l);return}i.pendingMessages.push(l)},y=(l)=>{g(JSON.stringify(l))},C=(l={})=>{if(l.sessionId)i.sessionId=l.sessionId;if(l.scenarioId)i.scenarioId=l.scenarioId;y({type:"start",sessionId:i.sessionId,scenarioId:i.scenarioId??void 0})},I=(l)=>{g(l)},L=()=>{y({type:"end_turn"})},R=(l)=>{y({...l,type:"call_control"})},w=()=>{if(d(),i.ws)i.ws.close(1000),i.ws=null;i.isConnected=!1,c.clear()},x=()=>{if(i.ws?.readyState===1)i.ws.close(4000,"absolutejs-voice-reconnect-proof")},U=(l)=>{return c.add(l),()=>{c.delete(l)}};return A(),{callControl:R,close:w,endTurn:L,getReadyState:()=>i.ws?.readyState??3,getScenarioId:()=>i.scenarioId??"",getSessionId:()=>i.sessionId,send:y,sendAudio:I,simulateDisconnect:x,start:C,subscribe:U}};var hn=()=>({attempts:0,maxAttempts:0,status:"idle"}),Cn=()=>({assistantAudio:[],assistantTexts:[],call:null,error:null,isConnected:!1,sessionMetadata:null,scenarioId:null,partial:"",reconnect:hn(),sessionId:null,status:"idle",turns:[]}),we=()=>{let e=Cn(),n=new Set,c=()=>{n.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,assistantTexts:[...e.assistantTexts,s.text]};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};break;case"final":e={...e,partial:s.transcript.text,turns:e.turns.map((t)=>t)};break;case"partial":e={...e,partial:s.transcript.text};break;case"replay":e={...e,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,scenarioId:s.scenarioId??e.scenarioId,isConnected:s.status==="active",sessionId:s.sessionId,sessionMetadata:s.sessionMetadata??e.sessionMetadata,status:s.status};break;case"turn":e={...e,partial:"",turns:[...e.turns,s.turn]};break}c()},getServerSnapshot:()=>e,getSnapshot:()=>e,subscribe:(s)=>{return n.add(s),()=>{n.delete(s)}}}};var Re=(e,n={})=>{let c=be(e,n),o=we(),s=n.browserMedia&&typeof window<"u"?Le({...n.browserMedia,getScenarioId:()=>n.browserMedia?n.browserMedia.getScenarioId?.()??c.getScenarioId():c.getScenarioId(),getSessionId:()=>n.browserMedia?n.browserMedia.getSessionId?.()??c.getSessionId():c.getSessionId()}):null,t=new Set,i=(a)=>Promise.resolve().then(()=>{if(!a?.sessionId&&!a?.scenarioId)return;c.start(a),s?.start()}),r=()=>{t.forEach((a)=>a())},d=()=>{if(!n.reconnectReportPath||typeof fetch>"u")return;let a=o.getSnapshot(),A=JSON.stringify({at:Date.now(),reconnect:a.reconnect,scenarioId:a.scenarioId,sessionId:c.getSessionId(),turnIds:a.turns.map((g)=>g.id)});fetch(n.reconnectReportPath,{body:A,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},f=c.subscribe((a)=>{let A=he(a);if(A){if(o.dispatch(A),a.type==="connection")d();r()}});return{callControl(a){c.callControl(a)},close(){f(),s?.close(),c.close(),o.dispatch({type:"disconnected"}),r()},endTurn(){c.endTurn()},get error(){return o.getSnapshot().error},getServerSnapshot(){return o.getServerSnapshot()},getSnapshot(){return o.getSnapshot()},get isConnected(){return o.getSnapshot().isConnected},get scenarioId(){return o.getSnapshot().scenarioId},get sessionMetadata(){return o.getSnapshot().sessionMetadata},start:i,get partial(){return o.getSnapshot().partial},get reconnect(){return o.getSnapshot().reconnect},get sessionId(){return c.getSessionId()},get status(){return o.getSnapshot().status},get turns(){return o.getSnapshot().turns},get assistantTexts(){return o.getSnapshot().assistantTexts},get assistantAudio(){return o.getSnapshot().assistantAudio},get call(){return o.getSnapshot().call},sendAudio(a){c.sendAudio(a)},simulateDisconnect(){c.simulateDisconnect()},subscribe(a){return t.add(a),()=>{t.delete(a)}}}};var ue=(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 yn={balanced:{qualityProfile:"general",silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},Tn={general:{},"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var _e=(e)=>{let n=e?.profile??"fast",c=e?.qualityProfile??"general",o=yn[n],s=Tn[c];return{profile:n,qualityProfile:c,silenceMs:e?.silenceMs??s.silenceMs??o.silenceMs,speechThreshold:e?.speechThreshold??s.speechThreshold??o.speechThreshold,transcriptStabilityMs:e?.transcriptStabilityMs??s.transcriptStabilityMs??o.transcriptStabilityMs}};var Sn={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:{qualityProfile:"short-command",profile:"balanced"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{qualityProfile:"general",profile:"fast"}},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:{qualityProfile:"accent-heavy",profile:"long-form"}},"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:{qualityProfile:"accent-heavy",profile:"long-form"}},"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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form"}}},Ee=(e="default")=>{let n=Sn[e];return{audioConditioning:ue(n.audioConditioning),capture:{channelCount:n.capture?.channelCount??1,sampleRateHz:n.capture?.sampleRateHz??16000},connection:{...n.connection},name:e,sttLifecycle:n.sttLifecycle??"continuous",turnDetection:_e(n.turnDetection)}};var Mn=(e)=>({assistantAudio:[...e.assistantAudio],assistantTexts:[...e.assistantTexts],call:e.call,error:e.error,isConnected:e.isConnected,isRecording:!1,partial:e.partial,reconnect:e.reconnect,recordingError:null,sessionId:e.sessionId,sessionMetadata:e.sessionMetadata,scenarioId:e.scenarioId,status:e.status,turns:[...e.turns]}),j=(e,n={})=>{let c=Ee(n.preset),o=Re(e,{...c.connection,...n.connection}),s=null,t=Mn(o),i=new Set,r=()=>{for(let C of i)C()},d=()=>{if(t={...t,assistantAudio:[...o.assistantAudio],assistantTexts:[...o.assistantTexts],call:o.call,error:o.error,isConnected:o.isConnected,partial:o.partial,reconnect:o.reconnect,sessionId:o.sessionId,sessionMetadata:o.sessionMetadata,scenarioId:o.scenarioId,status:o.status,turns:[...o.turns]},n.autoStopOnComplete!==!1&&t.status==="completed"&&t.isRecording)s?.stop(),s=null,t={...t,isRecording:!1};r()},f=o.subscribe(d);d();let a=()=>{if(s)return s;return s=Ae({channelCount:n.capture?.channelCount??c.capture.channelCount,onLevel:n.capture?.onLevel,onAudio:(C)=>{if(n.capture?.onAudio){n.capture.onAudio(C,o.sendAudio);return}o.sendAudio(C)},sampleRateHz:n.capture?.sampleRateHz??c.capture.sampleRateHz}),s},A=()=>{s?.stop(),s=null,t={...t,isRecording:!1},r()},g=async()=>{if(t.isRecording)return;try{t={...t,recordingError:null},r(),await a().start(),t={...t,isRecording:!0},r()}catch(C){throw s=null,t={...t,isRecording:!1,recordingError:C instanceof Error?C.message:String(C)},r(),C}};return{bindHTMX(C){return fe(o,C)},callControl:(C)=>o.callControl(C),close:()=>{f(),A(),o.close()},endTurn:()=>o.endTurn(),get error(){return t.error},getServerSnapshot:()=>t,getSnapshot:()=>t,get isConnected(){return t.isConnected},get isRecording(){return t.isRecording},get partial(){return t.partial},get recordingError(){return t.recordingError},get reconnect(){return t.reconnect},sendAudio:(C)=>o.sendAudio(C),simulateDisconnect:()=>o.simulateDisconnect(),get sessionId(){return t.sessionId},get sessionMetadata(){return t.sessionMetadata},get scenarioId(){return t.scenarioId},startRecording:g,get status(){return t.status},stopRecording:A,subscribe:(C)=>{return i.add(C),()=>{i.delete(C)}},toggleRecording:async()=>{if(t.isRecording){A();return}await g()},get turns(){return t.turns},get assistantTexts(){return t.assistantTexts},get assistantAudio(){return t.assistantAudio},get call(){return t.call}}};var In=()=>({activeSourceCount:0,error:null,isActive:!1,isPlaying:!1,lastInterruptLatencyMs:void 0,lastPlaybackStopLatencyMs:void 0,processedChunkCount:0,queuedChunkCount:0}),Vn=()=>{if(typeof window>"u")return typeof AudioContext>"u"?void 0:AudioContext;return window.AudioContext??window.webkitAudioContext},Ln=(e,n)=>{let c=n.format;if(c.container!=="raw"||c.encoding!=="pcm_s16le")throw Error(`Unsupported assistant audio format: ${c.container}/${c.encoding}`);let o=n.chunk,s=Math.max(1,c.channels),t=Math.floor(o.byteLength/2),i=Math.max(1,Math.floor(t/s)),r=e.createBuffer(s,i,c.sampleRateHz),d=new DataView(o.buffer,o.byteOffset,o.byteLength);for(let f=0;f<s;f+=1){let a=r.getChannelData(f);for(let A=0;A<i;A+=1){let y=(A*s+f)*2;if(y+1>=o.byteLength){a[A]=0;continue}a[A]=d.getInt16(y,!0)/32768}}return r},F=(e,n={})=>{let c=new Set,o=new Set,s=(n.lookaheadMs??15)/1000,t=In(),i=null,r=null,d=0,f=Promise.resolve(),a=null,A=null,g=null,y=null,C=()=>{for(let h of c)h()},I=(h)=>{t={...t,...h},C()},L=()=>{if(t.error!==null)I({error:null})},R=()=>{if(y!==null)clearTimeout(y),y=null},w=(h)=>{R(),a=null,I({activeSourceCount:o.size,isPlaying:!1,lastInterruptLatencyMs:h,lastPlaybackStopLatencyMs:t.lastPlaybackStopLatencyMs??h}),g?.(),g=null,A=null},x=(h)=>{if(!h)return 0;return Math.max(0,((h.baseLatency??0)+(h.outputLatency??0))*1000)},U=(h)=>{if(!r)return;let T=1;if(r.gain.setValueAtTime){r.gain.setValueAtTime(T,h?.currentTime??0);return}r.gain.value=T},l=(h)=>{if(!r)return;let T=0;if(r.gain.setValueAtTime){r.gain.setValueAtTime(T,h?.currentTime??0);return}r.gain.value=T},M=()=>{if(a===null||o.size>0)return;w(Date.now()-a)},b=async()=>{if(i)return i;if(n.createAudioContext)i=n.createAudioContext();else{let h=Vn();if(!h)throw Error("Assistant audio playback requires AudioContext support.");i=new h}if(i.createGain)r=i.createGain(),r.connect?.(i.destination);return d=i.currentTime,i},z=async(h)=>{let T=await b(),E=Ln(T,h),V=T.createBufferSource();V.buffer=E,V.connect(r??T.destination),V.onended=()=>{o.delete(V),V.disconnect?.(),I({activeSourceCount:o.size,isPlaying:o.size>0&&t.isActive}),M()};let J=Math.max(T.currentTime+s,d);d=J+E.duration,o.add(V),I({activeSourceCount:o.size,isPlaying:!0}),V.start(J)},_=(h)=>{for(let T of[...o])T.stop?.();if(d=i?i.currentTime:0,h?.forceClear){for(let T of o)T.disconnect?.();o.clear(),M()}},$=async()=>{if(!t.isActive)return;let h=e.assistantAudio.slice(t.processedChunkCount);if(h.length===0)return;try{L();for(let T of h)await z(T);I({processedChunkCount:e.assistantAudio.length,queuedChunkCount:t.queuedChunkCount+h.length})}catch(T){I({error:T instanceof Error?T.message:String(T)})}},P=()=>{return f=f.then(()=>$(),()=>$()),f},k=e.subscribe(()=>{if(n.autoStart&&!t.isActive&&e.assistantAudio.length>0){N.start();return}if(t.isActive)P()}),N={close:async()=>{if(k(),_({forceClear:!0}),R(),g?.(),g=null,A=null,a=null,i&&i.state!=="closed")await i.close();i=null,r?.disconnect?.(),r=null,d=0,I({activeSourceCount:0,isActive:!1,isPlaying:!1})},get activeSourceCount(){return t.activeSourceCount},get error(){return t.error},getSnapshot:()=>t,get isActive(){return t.isActive},get isPlaying(){return t.isPlaying},interrupt:async()=>{let h=Date.now(),T=await b();a=h,l(T);let E=Date.now()-h+x(T);if(I({isActive:!1,isPlaying:o.size>0,lastPlaybackStopLatencyMs:E}),o.size===0){w(E);return}if(!A)A=new Promise((V)=>{g=V});R(),y=setTimeout(()=>{for(let V of o)V.disconnect?.();o.clear(),w(Date.now()-h)},250),_(),await A},get lastInterruptLatencyMs(){return t.lastInterruptLatencyMs},get lastPlaybackStopLatencyMs(){return t.lastPlaybackStopLatencyMs},pause:async()=>{if(!i){I({activeSourceCount:0,isActive:!1,isPlaying:!1});return}await i.suspend(),I({activeSourceCount:o.size,isActive:!1,isPlaying:!1})},get processedChunkCount(){return t.processedChunkCount},get queuedChunkCount(){return t.queuedChunkCount},start:async()=>{try{L();let h=await b();if(U(h),h.state==="suspended")await h.resume();I({activeSourceCount:o.size,isActive:!0,isPlaying:h.state==="running"}),await P()}catch(h){throw I({error:h instanceof Error?h.message:String(h),isActive:!1,isPlaying:!1}),h}},subscribe:(h)=>{return c.add(h),()=>{c.delete(h)}}};return N};var bn=()=>`barge-in:${Date.now()}:${crypto.randomUUID?.()??Math.random().toString(36).slice(2)}`,wn=(e,n)=>{let c=e.filter((i)=>i.status==="stopped"),o=c.map((i)=>i.latencyMs).filter((i)=>typeof i==="number"),s=c.filter((i)=>typeof i.latencyMs==="number"&&i.latencyMs>n).length,t=c.length-s;return{averageLatencyMs:o.length>0?Math.round(o.reduce((i,r)=>i+r,0)/o.length):void 0,events:[...e],failed:s,lastEvent:e.at(-1),passed:t,status:e.length===0?"empty":s>0?"fail":c.length===0?"warn":"pass",thresholdMs:n,total:c.length}},Pe=(e={})=>{let n=new Set,c=e.thresholdMs??250,o=e.fetch??globalThis.fetch,s=[],t=()=>{for(let d of n)d()},i=(d)=>{if(!e.path||typeof o!=="function")return;o(e.path,{body:JSON.stringify(d),headers:{"Content-Type":"application/json"},method:"POST"}).catch(()=>{})},r=(d,f)=>{let a={at:Date.now(),id:bn(),latencyMs:f.latencyMs,playbackStopLatencyMs:f.playbackStopLatencyMs,reason:f.reason,sessionId:f.sessionId,status:d,thresholdMs:c};return s.push(a),i(a),t(),a};return{getSnapshot:()=>wn(s,c),recordRequested:(d)=>r("requested",d),recordSkipped:(d)=>r("skipped",d),recordStopped:(d)=>r("stopped",d),subscribe:(d)=>{return n.add(d),()=>{n.delete(d)}}}};var Rn=0.08,un=(e,n={})=>(n.enabled??!0)&&e>=(n.interruptThreshold??Rn),te=(e,n,c={})=>{let o=e.partial,s=(i)=>{if(!n.isPlaying||c.enabled===!1){c.monitor?.recordSkipped({reason:i,sessionId:e.sessionId});return}c.monitor?.recordRequested({reason:i,sessionId:e.sessionId}),n.interrupt().then(()=>{c.monitor?.recordStopped({latencyMs:n.lastInterruptLatencyMs,playbackStopLatencyMs:n.lastPlaybackStopLatencyMs,reason:i,sessionId:e.sessionId})})},t=e.subscribe(()=>{if(c.interruptOnPartial===!1){o=e.partial;return}if(!o&&e.partial)s("partial-transcript");o=e.partial});return{close:()=>{t()},handleLevel:(i)=>{if(un(i,c))s("input-level")},sendAudio:(i)=>{s("manual-audio"),e.sendAudio(i)}}};var ae=48,_n=320,En=88,Pn="Guided test",Dn="General recording",On="Pick a scenario to begin the demo.",xn="I can walk you through a short guided voice test.",Un="I can capture one freeform recording and confirm that it landed.",Nn="Choose a scenario to begin. Guided test asks follow-up prompts. General recording just captures what you say.",Hn="Click Start general recording to capture one freeform answer.",xe="Speak freely. When you pause, the recording will be captured.",re="Recording saved. Start again if you want another capture.",Ue="Guided test complete. Review the saved summary below.",Ne="All prompts are covered. You can stop the microphone or keep speaking for extra detail.",Gn="Ready. Start guided test or general recording to begin.",Bn="Live. Answer the prompt, then click Stop microphone when finished.",De=["Start with a quick introduction about who you are.","Now describe what you are trying to do or test.","Finish with any detail that feels blocked, risky, or unclear."],He=(e,n,c)=>Math.min(c,Math.max(n,e)),X=(e)=>e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll(\'"\',""").replaceAll("\'","'"),ie=(e,n)=>{let c=e[n];if(typeof c==="string"&&c.trim())return c;return null},le=(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 n=e,c=ie(n,"message")??ie(n,"reason")??ie(n,"description");if(c)return c;if("error"in n)return le(n.error);if("cause"in n)return le(n.cause);try{return JSON.stringify(e)}catch{}}return"Unexpected error"},Wn=(e)=>{let n=[e.status];if(e.attempts>0||e.maxAttempts>0)n.push(`${e.attempts}/${e.maxAttempts} attempts`);if(e.nextAttemptAt){let c=Math.max(0,e.nextAttemptAt-Date.now());n.push(`retry in ${Math.ceil(c/100)/10}s`)}return n.join(" \xB7 ")},v=(e=ae)=>Array.from({length:e},()=>0),Oe=(e,n,c=ae)=>{let o=e.slice(-(c-1));o.push(He(n,0,1));while(o.length<c)o.unshift(0);return o},$n=(e,n=_n,c=En)=>{let o=e.length>1?e:v(ae),s=n/(o.length-1),t=c/2,i=c*0.34;if(Math.max(...o,0)<=0.015)return`M 0 ${t} L ${n} ${t}`;let d=o.map((a,A)=>{let g=A*0.76,y=Math.sin(g)*0.78+Math.sin(g*0.41)*0.22,C=a*i,I=s*A,L=He(t+y*C,8,c-8);return{x:I,y:L}});if(d.length===0)return`M 0 ${t} L ${n} ${t}`;let f=`M ${d[0]?.x??0} ${d[0]?.y??t}`;for(let a=1;a<d.length;a+=1){let A=d[a-1],g=d[a];if(!A||!g)continue;let y=(A.x+g.x)/2;f+=` Q ${y} ${A.y} ${g.x} ${g.y}`}return f},kn=(e)=>{if(!e)return De;try{let n=JSON.parse(e);if(Array.isArray(n)){let c=n.filter((o)=>typeof o==="string").map((o)=>o.trim()).filter(Boolean);if(c.length>0)return c}}catch{}return De},se=(e)=>{if(!e)return;let n=Number(e);return Number.isFinite(n)?n:void 0},qn=(e,n,c)=>{if(!n)return null;let o=document.querySelector(n);return o instanceof c?o:null},O=(e,n,c,o)=>{let s=n?document.querySelector(n):null;if(s instanceof c)return s;let t=e.querySelector(`#${o}`);if(t instanceof c)return t;throw Error(`Voice HTMX bootstrap could not find the required element "${o}".`)},Xn=(e)=>{if(!e.mode)return On;if(!e.hasStarted)return e.mode==="guided"?xn:Un;if(e.status==="completed")return e.mode==="guided"?Ue:re;if(e.mode==="general")return xe;return e.guidedPrompts[e.turnCount]??Ne},zn=(e)=>{if(!e.mode)return Nn;if(e.status==="completed")return e.mode==="guided"?Ue:re;if(!e.hasStarted)return e.mode==="guided"?`Click Start guided test to begin. First prompt: ${e.guidedPrompts[0]??"Answer the first prompt."}`:Hn;if(e.mode==="general")return e.turnCount===0?xe:re;return e.guidedPrompts[e.turnCount]??Ne},Yn=(e)=>{let n=e.dataset.voiceGuidedPath,c=e.dataset.voiceGeneralPath;if(!n||!c)throw Error("Voice HTMX bootstrap requires data-voice-guided-path and data-voice-general-path.");let o=kn(e.dataset.voiceGuidedPrompts),s=e.dataset.voiceGuidedLabel??Pn,t=e.dataset.voiceGeneralLabel??Dn,i=e.dataset.voiceReconnectReportPath,r=e.dataset.voiceBargeInPath,d=r?Pe({path:r,thresholdMs:se(e.dataset.voiceBargeInThresholdMs)}):null,f=se(e.dataset.voiceBargeInRecentWindowMs)??4000,a=se(e.dataset.voiceBargeInSpeechThreshold)??0.04,A=O(document,e.dataset.voiceSync,HTMLElement,"voice-htmx-sync"),g=O(e,e.dataset.voiceConnection,HTMLElement,"metric-connection"),y=O(e,e.dataset.voiceError,HTMLElement,"status-error"),C=O(e,e.dataset.voiceMicrophone,HTMLElement,"status-mic"),I=O(e,e.dataset.voicePrompt,HTMLElement,"status-prompt"),L=qn(e,e.dataset.voiceReconnect,HTMLElement),R=O(e,e.dataset.voiceChat,HTMLElement,"chat-list"),w=O(e,e.dataset.voiceStartGuided,HTMLButtonElement,"start-guided"),x=O(e,e.dataset.voiceStartGeneral,HTMLButtonElement,"start-general"),U=O(e,e.dataset.voiceStop,HTMLButtonElement,"stop-mic"),l=O(e,e.dataset.voiceMonitor,HTMLElement,"voice-monitor"),M=O(e,e.dataset.voiceMonitorCopy,HTMLElement,"voice-monitor-copy"),b=O(e,e.dataset.voiceWaveGlow,SVGPathElement,"voice-wave-glow"),z=O(e,e.dataset.voiceWavePath,SVGPathElement,"voice-wave-path"),_=null,$={general:!1,guided:!1},P=!1,k=null,N=v(),h=null,T=null,E=j(n,{capture:{onAudio:(S,B)=>{if(h){h.sendAudio(S);return}B(S)},onLevel:(S)=>{h?.handleLevel(S),N=Oe(N,S),p()}},connection:{reconnectReportPath:i},preset:"guided-intake"}),V=j(c,{capture:{onAudio:(S,B)=>{if(T){T.sendAudio(S);return}B(S)},onLevel:(S)=>{T?.handleLevel(S),N=Oe(N,S),p()}},connection:{reconnectReportPath:i},preset:"dictation"}),J=E.bindHTMX({element:A}),Ge=V.bindHTMX({element:A}),Q=F(E),Z=F(V);h=te(E,Q,{interruptThreshold:a,monitor:d??void 0}),T=te(V,Z,{interruptThreshold:a,monitor:d??void 0});let Y=()=>_==="general"?V:E,Qn=()=>_==="general"?Z:Q,p=()=>{let S=$n(N);b.setAttribute("d",S),z.setAttribute("d",S),M.innerHTML=`<span class="voice-live-dot"></span>${P?"Microphone live":"Microphone idle"}`,M.classList.toggle("is-live",P),l.classList.toggle("is-live",P)},q=()=>{let S=Y(),B=(_?$[_]:!1)||S.turns.length>0,ge=S.status;if(g.textContent=S.isConnected?"Connected":"Waiting",y.textContent=k||S.error||"None",L)L.textContent=Wn(S.reconnect);C.textContent=P?Bn:Gn,I.textContent=zn({guidedPrompts:o,hasStarted:B,mode:_,status:ge,turnCount:S.turns.length}),w.hidden=P,x.hidden=P,U.hidden=!P,R.innerHTML=`<article class="voice-chat-message assistant">\n <div class="voice-chat-role">${X(_==="general"?t:_==="guided"?s:"Voice demo")}</div>\n <p class="voice-turn-text">${X(Xn({generalLabel:t,guidedLabel:s,guidedPrompts:o,hasStarted:B,mode:_,status:ge,turnCount:S.turns.length}))}</p>\n</article>${S.turns.map((ee)=>`<div class="voice-chat-stack">\n <article class="voice-chat-message user">\n <div class="voice-chat-role">You</div>\n <p class="voice-turn-text">${X(ee.text)}</p>\n </article>\n ${ee.assistantText?`<article class="voice-chat-message assistant">\n <div class="voice-chat-role">${X(_==="general"?t:_==="guided"?s:"Guide")}</div>\n <p class="voice-turn-text">${X(ee.assistantText)}</p>\n </article>`:""}\n</div>`).join("")}${S.partial?`<article class="voice-chat-message user pending">\n <div class="voice-chat-role">Speaking</div>\n <p class="voice-turn-text">${X(S.partial)}</p>\n</article>`:""}`,p()},Be=()=>{Y().stopRecording(),P=!1,k=null,N=v(),q()},de=async(S)=>{_=S,$={...$,[S]:!0};try{await Y().startRecording(),k=null,P=!0,q()}catch(B){Y().stopRecording(),P=!1,N=v(),k=le(B),q()}};E.subscribe(()=>{if(E.assistantAudio.length>0)Q.start().catch(()=>{});q()}),V.subscribe(()=>{if(V.assistantAudio.length>0)Z.start().catch(()=>{});q()}),w.addEventListener("click",()=>{de("guided")}),x.addEventListener("click",()=>{de("general")}),U.addEventListener("click",()=>{Be()}),e.addEventListener("absolute-voice-simulate-disconnect",()=>{Y().simulateDisconnect()}),window.addEventListener("beforeunload",()=>{E.stopRecording(),V.stopRecording(),h?.close(),T?.close(),Q.close(),Z.close(),J(),Ge(),E.close(),V.close()}),q()},Jn=()=>{if(typeof window>"u"||typeof document>"u")return;let e=Array.from(document.querySelectorAll("[data-voice-htmx]"));for(let n of e)if(n instanceof HTMLElement)Yn(n)};Jn();export{Jn as initVoiceHTMX};\n';
|
|
5190
5190
|
|
|
5191
5191
|
// src/profileSwitchRecommendation.ts
|
|
5192
5192
|
import { Elysia } from "elysia";
|
|
@@ -12557,6 +12557,8 @@ var createVoiceDiagnosticsRoutes = (options) => {
|
|
|
12557
12557
|
import { Elysia as Elysia13 } from "elysia";
|
|
12558
12558
|
|
|
12559
12559
|
// node_modules/@absolutejs/media/dist/index.js
|
|
12560
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
12561
|
+
import { join } from "path";
|
|
12560
12562
|
var formatLabel2 = (format) => `${format.container}/${format.encoding}/${String(format.sampleRateHz)}hz/${String(format.channels)}ch`;
|
|
12561
12563
|
var formatMatches2 = (actual, expected) => actual.container === expected.container && actual.encoding === expected.encoding && actual.sampleRateHz === expected.sampleRateHz && actual.channels === expected.channels;
|
|
12562
12564
|
var pushIssue = (issues, severity, code, message) => {
|
|
@@ -13217,6 +13219,269 @@ var buildMediaPipelineCalibrationReport = (input = {}) => {
|
|
|
13217
13219
|
turnCommitFrames: turnCommitFrames.length
|
|
13218
13220
|
};
|
|
13219
13221
|
};
|
|
13222
|
+
var DEFAULT_METADATA_DENY = [
|
|
13223
|
+
"audioPayload",
|
|
13224
|
+
"auth",
|
|
13225
|
+
"authorization",
|
|
13226
|
+
"cookie",
|
|
13227
|
+
"email",
|
|
13228
|
+
"phone",
|
|
13229
|
+
"phoneNumber",
|
|
13230
|
+
"rawPayload",
|
|
13231
|
+
"secret",
|
|
13232
|
+
"token",
|
|
13233
|
+
"transcript",
|
|
13234
|
+
"utterance"
|
|
13235
|
+
];
|
|
13236
|
+
var DEFAULT_TRUNCATE = 8;
|
|
13237
|
+
var issueCodes = (issues) => Array.from(new Set(issues.map((issue) => issue.code)));
|
|
13238
|
+
var lastEventKind = (events) => events[events.length - 1]?.kind;
|
|
13239
|
+
var formatOptionalMs = (value) => value === undefined ? "n/a" : `${String(Math.round(value))}ms`;
|
|
13240
|
+
var formatRatio = (value) => `${(value * 100).toFixed(1)}%`;
|
|
13241
|
+
var escapeMarkdownCell = (value) => value.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
13242
|
+
var renderIssuesTable = (issues) => {
|
|
13243
|
+
if (issues.length === 0) {
|
|
13244
|
+
return `- No issues.
|
|
13245
|
+
`;
|
|
13246
|
+
}
|
|
13247
|
+
const rows = issues.map((issue) => `| ${issue.severity} | ${escapeMarkdownCell(issue.code)} | ${escapeMarkdownCell(issue.message)} |`).join(`
|
|
13248
|
+
`);
|
|
13249
|
+
return `| Severity | Code | Message |
|
|
13250
|
+
| --- | --- | --- |
|
|
13251
|
+
${rows}
|
|
13252
|
+
`;
|
|
13253
|
+
};
|
|
13254
|
+
var summarizeMediaQualityReport = (report) => ({
|
|
13255
|
+
backpressureEvents: report.backpressureEvents,
|
|
13256
|
+
description: `${report.totalFrames} frame(s), ${report.gapCount} gap(s), speech ${formatRatio(report.speechRatio)}, status ${report.status}.`,
|
|
13257
|
+
driftMs: report.timestampDriftMs,
|
|
13258
|
+
frameCount: report.totalFrames,
|
|
13259
|
+
gapCount: report.gapCount,
|
|
13260
|
+
issueCodes: issueCodes(report.issues),
|
|
13261
|
+
issueCount: report.issues.length,
|
|
13262
|
+
jitterMs: report.jitterMs,
|
|
13263
|
+
silenceRatio: report.silenceRatio,
|
|
13264
|
+
speechRatio: report.speechRatio,
|
|
13265
|
+
status: report.status
|
|
13266
|
+
});
|
|
13267
|
+
var summarizeMediaTransportReport = (report) => ({
|
|
13268
|
+
backpressureEvents: report.backpressureEvents,
|
|
13269
|
+
description: `${report.name}: ${report.state}, in ${report.inputFrames}, out ${report.outputFrames}, backpressure ${report.backpressureEvents}.`,
|
|
13270
|
+
errors: report.events.filter((event) => event.kind === "error").length,
|
|
13271
|
+
inputFrames: report.inputFrames,
|
|
13272
|
+
lastEventKind: lastEventKind(report.events),
|
|
13273
|
+
name: report.name,
|
|
13274
|
+
outputFrames: report.outputFrames,
|
|
13275
|
+
state: report.state,
|
|
13276
|
+
status: report.status
|
|
13277
|
+
});
|
|
13278
|
+
var summarizeMediaProcessorGraphReport = (report) => {
|
|
13279
|
+
const errorIssueCodes = Array.from(new Set(report.errors.map((event) => event.kind)));
|
|
13280
|
+
return {
|
|
13281
|
+
backpressureEvents: report.backpressure.events.length,
|
|
13282
|
+
description: `${report.name}: ${report.state}, ${report.nodes.length} node(s), in ${report.inputFrames}, out ${report.emittedFrames}, dropped ${report.droppedFrames}.`,
|
|
13283
|
+
droppedFrames: report.droppedFrames,
|
|
13284
|
+
edgeCount: report.edges.length,
|
|
13285
|
+
edgeEventCount: report.edgeEvents.length,
|
|
13286
|
+
emittedFrames: report.emittedFrames,
|
|
13287
|
+
errorCount: report.errors.length,
|
|
13288
|
+
inputFrames: report.inputFrames,
|
|
13289
|
+
issueCodes: errorIssueCodes,
|
|
13290
|
+
lifecycleEventCount: report.lifecycleEvents.length,
|
|
13291
|
+
name: report.name,
|
|
13292
|
+
nodeCount: report.nodes.length,
|
|
13293
|
+
state: report.state,
|
|
13294
|
+
status: report.status,
|
|
13295
|
+
timingMaxMs: report.timing.maxNodeMs
|
|
13296
|
+
};
|
|
13297
|
+
};
|
|
13298
|
+
var renderMediaQualityMarkdown = (report, options = {}) => {
|
|
13299
|
+
const title = options.title ?? "Media Quality Report";
|
|
13300
|
+
const lines = [
|
|
13301
|
+
`# ${title}`,
|
|
13302
|
+
"",
|
|
13303
|
+
`Status: **${report.status}**`,
|
|
13304
|
+
"",
|
|
13305
|
+
"| Metric | Value |",
|
|
13306
|
+
"| --- | ---: |",
|
|
13307
|
+
`| Total frames | ${report.totalFrames} |`,
|
|
13308
|
+
`| Input audio | ${report.inputAudioFrames} |`,
|
|
13309
|
+
`| Assistant audio | ${report.assistantAudioFrames} |`,
|
|
13310
|
+
`| Gaps | ${report.gapCount} |`,
|
|
13311
|
+
`| Jitter | ${formatOptionalMs(report.jitterMs)} |`,
|
|
13312
|
+
`| Timestamp drift | ${formatOptionalMs(report.timestampDriftMs)} |`,
|
|
13313
|
+
`| Speech ratio | ${formatRatio(report.speechRatio)} |`,
|
|
13314
|
+
`| Silence ratio | ${formatRatio(report.silenceRatio)} |`,
|
|
13315
|
+
`| Backpressure events | ${report.backpressureEvents} |`,
|
|
13316
|
+
"",
|
|
13317
|
+
"## Issues",
|
|
13318
|
+
"",
|
|
13319
|
+
renderIssuesTable(report.issues).trimEnd()
|
|
13320
|
+
];
|
|
13321
|
+
return `${lines.join(`
|
|
13322
|
+
`)}
|
|
13323
|
+
`;
|
|
13324
|
+
};
|
|
13325
|
+
var renderMediaTransportMarkdown = (report, options = {}) => {
|
|
13326
|
+
const title = options.title ?? `Media Transport: ${report.name}`;
|
|
13327
|
+
const limit = options.redact?.truncateArraysAt ?? DEFAULT_TRUNCATE;
|
|
13328
|
+
const events = report.events.slice(-limit);
|
|
13329
|
+
const eventRows = events.length === 0 ? "- No transport events recorded." : ["| At | Kind | State | Buffered | Error |", "| --- | --- | --- | ---: | --- |"].concat(events.map((event) => `| ${event.at} | ${event.kind} | ${event.state} | ${event.bufferedFrames ?? ""} | ${escapeMarkdownCell(event.error ?? "")} |`)).join(`
|
|
13330
|
+
`);
|
|
13331
|
+
const lines = [
|
|
13332
|
+
`# ${title}`,
|
|
13333
|
+
"",
|
|
13334
|
+
`Status: **${report.status}** \xB7 State: **${report.state}**`,
|
|
13335
|
+
"",
|
|
13336
|
+
"| Metric | Value |",
|
|
13337
|
+
"| --- | ---: |",
|
|
13338
|
+
`| Input frames | ${report.inputFrames} |`,
|
|
13339
|
+
`| Output frames | ${report.outputFrames} |`,
|
|
13340
|
+
`| Backpressure events | ${report.backpressureEvents} |`,
|
|
13341
|
+
`| Connected | ${report.connected ? "yes" : "no"} |`,
|
|
13342
|
+
`| Closed | ${report.closed ? "yes" : "no"} |`,
|
|
13343
|
+
`| Failed | ${report.failed ? "yes" : "no"} |`,
|
|
13344
|
+
"",
|
|
13345
|
+
`## Last ${events.length} event(s)`,
|
|
13346
|
+
"",
|
|
13347
|
+
eventRows
|
|
13348
|
+
];
|
|
13349
|
+
return `${lines.join(`
|
|
13350
|
+
`)}
|
|
13351
|
+
`;
|
|
13352
|
+
};
|
|
13353
|
+
var renderMediaProcessorGraphMarkdown = (report, options = {}) => {
|
|
13354
|
+
const title = options.title ?? `Media Processor Graph: ${report.name}`;
|
|
13355
|
+
const limit = options.redact?.truncateArraysAt ?? DEFAULT_TRUNCATE;
|
|
13356
|
+
const nodeRows = report.nodes.map((node) => `| ${escapeMarkdownCell(node.name)} | ${node.kind} | ${node.status} | ${node.inputFrames} | ${node.emittedFrames} | ${node.droppedFrames} | ${node.errors.length} |`).join(`
|
|
13357
|
+
`);
|
|
13358
|
+
const edgeRows = report.edges.slice(0, limit).map((edge) => `| ${escapeMarkdownCell(edge.from)} | ${escapeMarkdownCell(edge.to)} | ${edge.status} | ${edge.emittedFrames} |`).join(`
|
|
13359
|
+
`);
|
|
13360
|
+
const issues = report.errors.map((event) => ({
|
|
13361
|
+
code: event.kind,
|
|
13362
|
+
message: event.error ?? `Processor graph ${event.kind} (state ${event.state}).`,
|
|
13363
|
+
severity: "error"
|
|
13364
|
+
}));
|
|
13365
|
+
const lines = [
|
|
13366
|
+
`# ${title}`,
|
|
13367
|
+
"",
|
|
13368
|
+
`Status: **${report.status}** \xB7 State: **${report.state}**`,
|
|
13369
|
+
"",
|
|
13370
|
+
"| Metric | Value |",
|
|
13371
|
+
"| --- | ---: |",
|
|
13372
|
+
`| Nodes | ${report.nodes.length} |`,
|
|
13373
|
+
`| Input frames | ${report.inputFrames} |`,
|
|
13374
|
+
`| Emitted frames | ${report.emittedFrames} |`,
|
|
13375
|
+
`| Dropped frames | ${report.droppedFrames} |`,
|
|
13376
|
+
`| Lifecycle events | ${report.lifecycleEvents.length} |`,
|
|
13377
|
+
`| Edge events | ${report.edgeEvents.length} |`,
|
|
13378
|
+
`| Backpressure events | ${report.backpressure.events.length} |`,
|
|
13379
|
+
`| Timing max | ${formatOptionalMs(report.timing.maxNodeMs)} |`,
|
|
13380
|
+
`| Timing average | ${formatOptionalMs(report.timing.averageNodeMs)} |`,
|
|
13381
|
+
"",
|
|
13382
|
+
"## Nodes",
|
|
13383
|
+
"",
|
|
13384
|
+
nodeRows ? `| Node | Kind | Status | In | Out | Dropped | Errors |
|
|
13385
|
+
| --- | --- | --- | ---: | ---: | ---: | ---: |
|
|
13386
|
+
${nodeRows}` : "- No nodes.",
|
|
13387
|
+
"",
|
|
13388
|
+
`## Edges (showing up to ${limit})`,
|
|
13389
|
+
"",
|
|
13390
|
+
edgeRows ? `| From | To | Status | Frames |
|
|
13391
|
+
| --- | --- | --- | ---: |
|
|
13392
|
+
${edgeRows}` : "- No edges.",
|
|
13393
|
+
"",
|
|
13394
|
+
"## Errors",
|
|
13395
|
+
"",
|
|
13396
|
+
renderIssuesTable(issues).trimEnd()
|
|
13397
|
+
];
|
|
13398
|
+
return `${lines.join(`
|
|
13399
|
+
`)}
|
|
13400
|
+
`;
|
|
13401
|
+
};
|
|
13402
|
+
var truncateArrays = (value, limit, seen) => {
|
|
13403
|
+
if (Array.isArray(value)) {
|
|
13404
|
+
const head = value.slice(0, limit).map((entry) => truncateArrays(entry, limit, seen));
|
|
13405
|
+
if (value.length > limit) {
|
|
13406
|
+
return [...head, { truncated: value.length - limit }];
|
|
13407
|
+
}
|
|
13408
|
+
return head;
|
|
13409
|
+
}
|
|
13410
|
+
if (value && typeof value === "object") {
|
|
13411
|
+
if (seen.has(value))
|
|
13412
|
+
return value;
|
|
13413
|
+
seen.add(value);
|
|
13414
|
+
const next = {};
|
|
13415
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
13416
|
+
next[key] = truncateArrays(entry, limit, seen);
|
|
13417
|
+
}
|
|
13418
|
+
return next;
|
|
13419
|
+
}
|
|
13420
|
+
return value;
|
|
13421
|
+
};
|
|
13422
|
+
var applyRedaction = (value, options, seen) => {
|
|
13423
|
+
const mode = options.mode ?? "omit";
|
|
13424
|
+
const maskValue = options.maskValue ?? "[redacted]";
|
|
13425
|
+
const allow = new Set(options.metadataAllow ?? []);
|
|
13426
|
+
const deny = new Set(options.metadataDeny ?? DEFAULT_METADATA_DENY);
|
|
13427
|
+
const walk = (input) => {
|
|
13428
|
+
if (Array.isArray(input)) {
|
|
13429
|
+
return input.map((entry) => walk(entry));
|
|
13430
|
+
}
|
|
13431
|
+
if (input && typeof input === "object") {
|
|
13432
|
+
if (seen.has(input))
|
|
13433
|
+
return input;
|
|
13434
|
+
seen.add(input);
|
|
13435
|
+
const next = {};
|
|
13436
|
+
for (const [key, entry] of Object.entries(input)) {
|
|
13437
|
+
if (allow.has(key)) {
|
|
13438
|
+
next[key] = entry;
|
|
13439
|
+
continue;
|
|
13440
|
+
}
|
|
13441
|
+
if (deny.has(key)) {
|
|
13442
|
+
if (mode === "mask")
|
|
13443
|
+
next[key] = maskValue;
|
|
13444
|
+
continue;
|
|
13445
|
+
}
|
|
13446
|
+
next[key] = walk(entry);
|
|
13447
|
+
}
|
|
13448
|
+
return next;
|
|
13449
|
+
}
|
|
13450
|
+
return input;
|
|
13451
|
+
};
|
|
13452
|
+
return walk(value);
|
|
13453
|
+
};
|
|
13454
|
+
var redactMediaReport = (report, options = {}) => {
|
|
13455
|
+
const limit = options.truncateArraysAt ?? DEFAULT_TRUNCATE;
|
|
13456
|
+
const truncated = truncateArrays(report, limit, new WeakSet);
|
|
13457
|
+
return applyRedaction(truncated, options, new WeakSet);
|
|
13458
|
+
};
|
|
13459
|
+
var buildArtifactPair = (report, summary, markdown, options) => {
|
|
13460
|
+
const jsonValue = options.redact ? redactMediaReport(report, options.redact) : report;
|
|
13461
|
+
return {
|
|
13462
|
+
json: JSON.stringify(jsonValue, null, 2),
|
|
13463
|
+
jsonValue,
|
|
13464
|
+
markdown,
|
|
13465
|
+
summary
|
|
13466
|
+
};
|
|
13467
|
+
};
|
|
13468
|
+
var buildMediaQualityArtifact = (report, options = {}) => buildArtifactPair(report, summarizeMediaQualityReport(report), renderMediaQualityMarkdown(report, options), options);
|
|
13469
|
+
var buildMediaTransportArtifact = (report, options = {}) => buildArtifactPair(report, summarizeMediaTransportReport(report), renderMediaTransportMarkdown(report, options), options);
|
|
13470
|
+
var buildMediaProcessorGraphArtifact = (report, options = {}) => buildArtifactPair(report, summarizeMediaProcessorGraphReport(report), renderMediaProcessorGraphMarkdown(report, options), options);
|
|
13471
|
+
var writeMediaArtifact = async (input) => {
|
|
13472
|
+
await mkdir(input.dir, { recursive: true });
|
|
13473
|
+
const jsonPath = join(input.dir, `${input.slug}.json`);
|
|
13474
|
+
const markdownPath = join(input.dir, `${input.slug}.md`);
|
|
13475
|
+
await Promise.all([
|
|
13476
|
+
writeFile(jsonPath, input.json, "utf8"),
|
|
13477
|
+
writeFile(markdownPath, input.markdown, "utf8")
|
|
13478
|
+
]);
|
|
13479
|
+
return {
|
|
13480
|
+
jsonPath,
|
|
13481
|
+
markdownPath,
|
|
13482
|
+
summary: input.summary
|
|
13483
|
+
};
|
|
13484
|
+
};
|
|
13220
13485
|
|
|
13221
13486
|
// src/mediaPipelineRoutes.ts
|
|
13222
13487
|
var escapeHtml16 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
@@ -13460,6 +13725,70 @@ var createVoiceMediaPipelineRoutes = (options = {}) => {
|
|
|
13460
13725
|
}
|
|
13461
13726
|
return app;
|
|
13462
13727
|
};
|
|
13728
|
+
var PROOF_SUMMARY_ISSUE_LIMIT = 8;
|
|
13729
|
+
var collectIssueCodes = (issues) => Array.from(new Set(issues.map((issue) => issue.code)));
|
|
13730
|
+
var summarizeVoiceMediaPipelineReport = (report, options = {}) => {
|
|
13731
|
+
const calibration = report.calibration;
|
|
13732
|
+
const quality = summarizeMediaQualityReport(report.quality);
|
|
13733
|
+
const processorGraph = report.processorGraph ? summarizeMediaProcessorGraphReport(report.processorGraph) : undefined;
|
|
13734
|
+
const transport = report.transport ? summarizeMediaTransportReport(report.transport) : undefined;
|
|
13735
|
+
const interruptionIssueCodes = collectIssueCodes(report.interruption.issues);
|
|
13736
|
+
const issueCodes2 = Array.from(new Set([
|
|
13737
|
+
...collectIssueCodes(calibration.issues),
|
|
13738
|
+
...quality.issueCodes,
|
|
13739
|
+
...interruptionIssueCodes,
|
|
13740
|
+
...processorGraph?.issueCodes ?? []
|
|
13741
|
+
]));
|
|
13742
|
+
const issues = [
|
|
13743
|
+
...calibration.issues,
|
|
13744
|
+
...report.quality.issues,
|
|
13745
|
+
...report.interruption.issues
|
|
13746
|
+
].slice(0, PROOF_SUMMARY_ISSUE_LIMIT);
|
|
13747
|
+
return {
|
|
13748
|
+
artifacts: options.artifacts,
|
|
13749
|
+
calibration: {
|
|
13750
|
+
assistantAudioFrames: calibration.assistantAudioFrames,
|
|
13751
|
+
backpressureFrames: calibration.backpressureFrames,
|
|
13752
|
+
firstAudioLatencyMs: calibration.firstAudioLatencyMs,
|
|
13753
|
+
inputAudioFrames: calibration.inputAudioFrames,
|
|
13754
|
+
interruptionFrames: calibration.interruptionFrames,
|
|
13755
|
+
issueCodes: collectIssueCodes(calibration.issues),
|
|
13756
|
+
jitterMs: calibration.jitterMs,
|
|
13757
|
+
resamplingRequired: calibration.resamplingRequired,
|
|
13758
|
+
status: calibration.status,
|
|
13759
|
+
surface: calibration.surface,
|
|
13760
|
+
traceLinkedFrames: calibration.traceLinkedFrames,
|
|
13761
|
+
turnCommitFrames: calibration.turnCommitFrames
|
|
13762
|
+
},
|
|
13763
|
+
checkedAt: report.checkedAt,
|
|
13764
|
+
frames: report.frames,
|
|
13765
|
+
interruption: {
|
|
13766
|
+
interruptionFrames: report.interruption.interruptionFrames,
|
|
13767
|
+
issueCodes: interruptionIssueCodes,
|
|
13768
|
+
latenciesMs: report.interruption.latenciesMs,
|
|
13769
|
+
status: report.interruption.status
|
|
13770
|
+
},
|
|
13771
|
+
issueCodes: issueCodes2,
|
|
13772
|
+
issues,
|
|
13773
|
+
ok: report.ok,
|
|
13774
|
+
processorGraph,
|
|
13775
|
+
quality,
|
|
13776
|
+
resampling: report.resampling ? {
|
|
13777
|
+
ratio: report.resampling.ratio,
|
|
13778
|
+
required: report.resampling.required,
|
|
13779
|
+
status: report.resampling.status
|
|
13780
|
+
} : undefined,
|
|
13781
|
+
sessionIds: report.sessionIds,
|
|
13782
|
+
status: report.status,
|
|
13783
|
+
surface: report.surface,
|
|
13784
|
+
transport,
|
|
13785
|
+
vad: {
|
|
13786
|
+
inputAudioFrames: report.vad.inputAudioFrames,
|
|
13787
|
+
segmentCount: report.vad.segments.length,
|
|
13788
|
+
status: report.vad.status
|
|
13789
|
+
}
|
|
13790
|
+
};
|
|
13791
|
+
};
|
|
13463
13792
|
// src/telephonyMediaRoutes.ts
|
|
13464
13793
|
import { Elysia as Elysia14 } from "elysia";
|
|
13465
13794
|
var demoPayload = Buffer.from(new Uint8Array([1, 2, 3, 4])).toString("base64");
|
|
@@ -13964,6 +14293,213 @@ var createVoiceBrowserCallProfileRoutes = (options = {}) => {
|
|
|
13964
14293
|
}
|
|
13965
14294
|
return routes;
|
|
13966
14295
|
};
|
|
14296
|
+
// src/mediaPipelineSurfaces.ts
|
|
14297
|
+
var calibrationIssues = (report) => report.calibration.issues.map((issue) => ({
|
|
14298
|
+
code: issue.code,
|
|
14299
|
+
message: issue.message,
|
|
14300
|
+
severity: issue.severity,
|
|
14301
|
+
source: "calibration",
|
|
14302
|
+
surface: report.surface
|
|
14303
|
+
}));
|
|
14304
|
+
var qualityIssues = (report) => report.quality.issues.map((issue) => ({
|
|
14305
|
+
code: issue.code,
|
|
14306
|
+
message: issue.message,
|
|
14307
|
+
severity: issue.severity,
|
|
14308
|
+
source: "quality",
|
|
14309
|
+
surface: report.surface
|
|
14310
|
+
}));
|
|
14311
|
+
var interruptionIssues = (report) => report.interruption.issues.map((issue) => ({
|
|
14312
|
+
code: issue.code,
|
|
14313
|
+
message: issue.message,
|
|
14314
|
+
severity: issue.severity,
|
|
14315
|
+
source: "interruption",
|
|
14316
|
+
surface: report.surface
|
|
14317
|
+
}));
|
|
14318
|
+
var transportIssues = (report) => {
|
|
14319
|
+
if (!report.transport)
|
|
14320
|
+
return [];
|
|
14321
|
+
const entries = [];
|
|
14322
|
+
if (report.transport.failed) {
|
|
14323
|
+
entries.push({
|
|
14324
|
+
code: "media.transport_failed",
|
|
14325
|
+
message: `Media transport ${report.transport.name} entered the failed state.`,
|
|
14326
|
+
severity: "error",
|
|
14327
|
+
source: "transport",
|
|
14328
|
+
surface: report.surface
|
|
14329
|
+
});
|
|
14330
|
+
}
|
|
14331
|
+
if (report.transport.backpressureEvents > 0) {
|
|
14332
|
+
entries.push({
|
|
14333
|
+
code: "media.transport_backpressure",
|
|
14334
|
+
message: `Media transport ${report.transport.name} reported ${String(report.transport.backpressureEvents)} backpressure event(s).`,
|
|
14335
|
+
severity: "warning",
|
|
14336
|
+
source: "transport",
|
|
14337
|
+
surface: report.surface
|
|
14338
|
+
});
|
|
14339
|
+
}
|
|
14340
|
+
const errorEvents = report.transport.events.filter((event) => event.kind === "error");
|
|
14341
|
+
for (const event of errorEvents) {
|
|
14342
|
+
entries.push({
|
|
14343
|
+
code: "media.transport_error",
|
|
14344
|
+
message: event.error ?? "Media transport error event.",
|
|
14345
|
+
severity: "error",
|
|
14346
|
+
source: "transport",
|
|
14347
|
+
surface: report.surface
|
|
14348
|
+
});
|
|
14349
|
+
}
|
|
14350
|
+
return entries;
|
|
14351
|
+
};
|
|
14352
|
+
var processorGraphIssues = (report) => {
|
|
14353
|
+
if (!report.processorGraph)
|
|
14354
|
+
return [];
|
|
14355
|
+
return report.processorGraph.errors.map((event) => ({
|
|
14356
|
+
code: `media.graph_${event.kind}`,
|
|
14357
|
+
message: event.error ?? `Processor graph reported ${event.kind} (state ${event.state}).`,
|
|
14358
|
+
severity: "error",
|
|
14359
|
+
source: "processor-graph",
|
|
14360
|
+
surface: report.surface
|
|
14361
|
+
}));
|
|
14362
|
+
};
|
|
14363
|
+
var extractVoiceMediaPipelineIssueEntries = (report) => [
|
|
14364
|
+
...calibrationIssues(report),
|
|
14365
|
+
...qualityIssues(report),
|
|
14366
|
+
...interruptionIssues(report),
|
|
14367
|
+
...transportIssues(report),
|
|
14368
|
+
...processorGraphIssues(report)
|
|
14369
|
+
];
|
|
14370
|
+
var toReadinessStatus = (status) => status === "fail" ? "fail" : status === "warn" ? "warn" : "pass";
|
|
14371
|
+
var readinessStatusFromIssues = (issues) => {
|
|
14372
|
+
if (issues.some((issue) => issue.severity === "error"))
|
|
14373
|
+
return "fail";
|
|
14374
|
+
if (issues.length > 0)
|
|
14375
|
+
return "warn";
|
|
14376
|
+
return "pass";
|
|
14377
|
+
};
|
|
14378
|
+
var buildVoiceMediaPipelineReadinessChecks = (report, options = {}) => {
|
|
14379
|
+
const baseHref = options.baseHref ?? "/voice/media-pipeline";
|
|
14380
|
+
const label = options.label ?? "Media pipeline";
|
|
14381
|
+
const checks = [
|
|
14382
|
+
{
|
|
14383
|
+
detail: `Status ${report.status}, surface ${report.surface}, ${String(report.frames)} frame(s).`,
|
|
14384
|
+
href: baseHref,
|
|
14385
|
+
label: `${label}: overall`,
|
|
14386
|
+
status: toReadinessStatus(report.status)
|
|
14387
|
+
},
|
|
14388
|
+
{
|
|
14389
|
+
detail: `${String(report.quality.issues.length)} quality issue(s); gaps ${String(report.quality.gapCount)}, jitter ${String(report.quality.jitterMs ?? "n/a")}ms, speech ratio ${(report.quality.speechRatio * 100).toFixed(1)}%.`,
|
|
14390
|
+
href: baseHref,
|
|
14391
|
+
label: `${label}: media quality`,
|
|
14392
|
+
status: toReadinessStatus(report.quality.status),
|
|
14393
|
+
value: report.quality.gapCount
|
|
14394
|
+
}
|
|
14395
|
+
];
|
|
14396
|
+
if (report.transport) {
|
|
14397
|
+
checks.push({
|
|
14398
|
+
detail: `${report.transport.state}, in ${String(report.transport.inputFrames)}, out ${String(report.transport.outputFrames)}, backpressure ${String(report.transport.backpressureEvents)}.`,
|
|
14399
|
+
href: baseHref,
|
|
14400
|
+
label: `${label}: transport`,
|
|
14401
|
+
status: toReadinessStatus(report.transport.status),
|
|
14402
|
+
value: report.transport.state
|
|
14403
|
+
});
|
|
14404
|
+
}
|
|
14405
|
+
if (report.processorGraph) {
|
|
14406
|
+
checks.push({
|
|
14407
|
+
detail: `${report.processorGraph.state}, nodes ${String(report.processorGraph.nodes.length)}, errors ${String(report.processorGraph.errors.length)}, dropped ${String(report.processorGraph.droppedFrames)}.`,
|
|
14408
|
+
href: baseHref,
|
|
14409
|
+
label: `${label}: processor graph`,
|
|
14410
|
+
status: toReadinessStatus(report.processorGraph.status),
|
|
14411
|
+
value: report.processorGraph.state
|
|
14412
|
+
});
|
|
14413
|
+
}
|
|
14414
|
+
checks.push({
|
|
14415
|
+
detail: `${String(report.interruption.interruptionFrames)} interruption frame(s); ${String(report.interruption.issues.length)} issue(s).`,
|
|
14416
|
+
href: baseHref,
|
|
14417
|
+
label: `${label}: interruption`,
|
|
14418
|
+
status: readinessStatusFromIssues(report.interruption.issues),
|
|
14419
|
+
value: report.interruption.interruptionFrames
|
|
14420
|
+
});
|
|
14421
|
+
return checks;
|
|
14422
|
+
};
|
|
14423
|
+
var severityToIncident = (severity) => severity === "error" ? "critical" : "warn";
|
|
14424
|
+
var sourceSuffix = {
|
|
14425
|
+
calibration: "calibration",
|
|
14426
|
+
interruption: "interruption",
|
|
14427
|
+
"processor-graph": "graph",
|
|
14428
|
+
quality: "quality",
|
|
14429
|
+
transport: "transport"
|
|
14430
|
+
};
|
|
14431
|
+
var buildVoiceMediaPipelineIncidentEvents = (report, options = {}) => {
|
|
14432
|
+
const baseHref = options.baseHref ?? "/voice/media-pipeline";
|
|
14433
|
+
const category = options.category ?? "monitor";
|
|
14434
|
+
const source = options.source ?? "media-pipeline";
|
|
14435
|
+
const now = options.now ?? (() => Date.now());
|
|
14436
|
+
const at = now();
|
|
14437
|
+
const entries = extractVoiceMediaPipelineIssueEntries(report);
|
|
14438
|
+
return entries.map((entry, index) => ({
|
|
14439
|
+
at,
|
|
14440
|
+
category,
|
|
14441
|
+
detail: entry.message,
|
|
14442
|
+
href: baseHref,
|
|
14443
|
+
id: `media-pipeline:${sourceSuffix[entry.source]}:${entry.code}:${String(index)}`,
|
|
14444
|
+
label: `Media ${sourceSuffix[entry.source]} ${entry.severity}: ${entry.code}`,
|
|
14445
|
+
severity: severityToIncident(entry.severity),
|
|
14446
|
+
source,
|
|
14447
|
+
value: entry.code
|
|
14448
|
+
}));
|
|
14449
|
+
};
|
|
14450
|
+
var buildHref = (base, jsonPath, fallbackSlug) => {
|
|
14451
|
+
if (!base)
|
|
14452
|
+
return;
|
|
14453
|
+
const filename = jsonPath.split("/").pop() ?? `${fallbackSlug}.json`;
|
|
14454
|
+
return `${base.replace(/\/$/, "")}/${filename}`;
|
|
14455
|
+
};
|
|
14456
|
+
var recordFromWrite = (kind, write, hrefBase, slug) => ({
|
|
14457
|
+
href: buildHref(hrefBase, write.jsonPath, slug),
|
|
14458
|
+
jsonPath: write.jsonPath,
|
|
14459
|
+
kind,
|
|
14460
|
+
markdownPath: write.markdownPath,
|
|
14461
|
+
summary: write.summary
|
|
14462
|
+
});
|
|
14463
|
+
var writeVoiceMediaPipelineArtifacts = async (options) => {
|
|
14464
|
+
const slugPrefix = options.slugPrefix ?? "media";
|
|
14465
|
+
const qualitySlug = `${slugPrefix}-quality`;
|
|
14466
|
+
const transportSlug = `${slugPrefix}-transport`;
|
|
14467
|
+
const graphSlug = `${slugPrefix}-processor-graph`;
|
|
14468
|
+
const artifacts = [];
|
|
14469
|
+
const hrefs = {};
|
|
14470
|
+
const qualityArtifact = buildMediaQualityArtifact(options.report.quality);
|
|
14471
|
+
const qualityWrite = await writeMediaArtifact({
|
|
14472
|
+
dir: options.dir,
|
|
14473
|
+
slug: qualitySlug,
|
|
14474
|
+
...qualityArtifact
|
|
14475
|
+
});
|
|
14476
|
+
const qualityRecord = recordFromWrite("quality", qualityWrite, options.hrefBase, qualitySlug);
|
|
14477
|
+
artifacts.push(qualityRecord);
|
|
14478
|
+
hrefs.quality = qualityRecord.href;
|
|
14479
|
+
if (options.report.transport) {
|
|
14480
|
+
const transportArtifact = buildMediaTransportArtifact(options.report.transport);
|
|
14481
|
+
const transportWrite = await writeMediaArtifact({
|
|
14482
|
+
dir: options.dir,
|
|
14483
|
+
slug: transportSlug,
|
|
14484
|
+
...transportArtifact
|
|
14485
|
+
});
|
|
14486
|
+
const transportRecord = recordFromWrite("transport", transportWrite, options.hrefBase, transportSlug);
|
|
14487
|
+
artifacts.push(transportRecord);
|
|
14488
|
+
hrefs.transport = transportRecord.href;
|
|
14489
|
+
}
|
|
14490
|
+
if (options.report.processorGraph) {
|
|
14491
|
+
const graphArtifact = buildMediaProcessorGraphArtifact(options.report.processorGraph);
|
|
14492
|
+
const graphWrite = await writeMediaArtifact({
|
|
14493
|
+
dir: options.dir,
|
|
14494
|
+
slug: graphSlug,
|
|
14495
|
+
...graphArtifact
|
|
14496
|
+
});
|
|
14497
|
+
const graphRecord = recordFromWrite("processor-graph", graphWrite, options.hrefBase, graphSlug);
|
|
14498
|
+
artifacts.push(graphRecord);
|
|
14499
|
+
hrefs.processorGraph = graphRecord.href;
|
|
14500
|
+
}
|
|
14501
|
+
return { artifacts, hrefs };
|
|
14502
|
+
};
|
|
13967
14503
|
// src/demoReadyRoutes.ts
|
|
13968
14504
|
import { Elysia as Elysia17 } from "elysia";
|
|
13969
14505
|
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
@@ -21813,8 +22349,8 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
21813
22349
|
};
|
|
21814
22350
|
// src/deliveryRuntime.ts
|
|
21815
22351
|
import { Elysia as Elysia32 } from "elysia";
|
|
21816
|
-
import { mkdir } from "fs/promises";
|
|
21817
|
-
import { dirname, join } from "path";
|
|
22352
|
+
import { mkdir as mkdir2 } from "fs/promises";
|
|
22353
|
+
import { dirname, join as join2 } from "path";
|
|
21818
22354
|
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21819
22355
|
var renderSummaryCard = (label, summary) => {
|
|
21820
22356
|
if (!summary) {
|
|
@@ -21839,8 +22375,8 @@ var createDeliveryRuntimeFileSink = (input) => ({
|
|
|
21839
22375
|
deliver: async ({ events }) => {
|
|
21840
22376
|
const firstEvent = events[0];
|
|
21841
22377
|
const fileName = `${Date.now()}-${encodeURIComponent(firstEvent?.id ?? crypto.randomUUID())}.json`;
|
|
21842
|
-
const path =
|
|
21843
|
-
await
|
|
22378
|
+
const path = join2(input.directory, input.kind, fileName);
|
|
22379
|
+
await mkdir2(dirname(path), { recursive: true });
|
|
21844
22380
|
await Bun.write(path, JSON.stringify({
|
|
21845
22381
|
eventCount: events.length,
|
|
21846
22382
|
events,
|
|
@@ -28345,8 +28881,8 @@ var createVoiceIncidentTimelineRoutes = (options) => {
|
|
|
28345
28881
|
import { Elysia as Elysia45 } from "elysia";
|
|
28346
28882
|
import { Database as Database4 } from "bun:sqlite";
|
|
28347
28883
|
import { createHash } from "crypto";
|
|
28348
|
-
import { mkdir as
|
|
28349
|
-
import { join as
|
|
28884
|
+
import { mkdir as mkdir3, readFile, stat, unlink } from "fs/promises";
|
|
28885
|
+
import { join as join3 } from "path";
|
|
28350
28886
|
var voiceObservabilityExportSchemaVersion = "1.0.0";
|
|
28351
28887
|
var voiceObservabilityExportSchemaId = "com.absolutejs.voice.observability-export";
|
|
28352
28888
|
var createVoiceObservabilityExportSchema = () => ({
|
|
@@ -28921,15 +29457,15 @@ var loadVoiceObservabilityExportReplaySource = async (source) => {
|
|
|
28921
29457
|
return source;
|
|
28922
29458
|
}
|
|
28923
29459
|
if (source.kind === "file") {
|
|
28924
|
-
const root =
|
|
28925
|
-
const receiptPath = source.receiptDirectory ?
|
|
29460
|
+
const root = join3(source.directory, source.runId);
|
|
29461
|
+
const receiptPath = source.receiptDirectory ? join3(source.receiptDirectory, `${encodeURIComponent(deliveryReceiptId(source.runId))}.json`) : undefined;
|
|
28926
29462
|
const deliveryReceipt = receiptPath ? await Bun.file(receiptPath).text().then(JSON.parse).catch(() => {
|
|
28927
29463
|
return;
|
|
28928
29464
|
}) : undefined;
|
|
28929
29465
|
return {
|
|
28930
|
-
artifactIndex: JSON.parse(await Bun.file(
|
|
29466
|
+
artifactIndex: JSON.parse(await Bun.file(join3(root, "artifact-index.json")).text()),
|
|
28931
29467
|
deliveryReceipt,
|
|
28932
|
-
manifest: JSON.parse(await Bun.file(
|
|
29468
|
+
manifest: JSON.parse(await Bun.file(join3(root, "manifest.json")).text())
|
|
28933
29469
|
};
|
|
28934
29470
|
}
|
|
28935
29471
|
if (source.kind === "s3") {
|
|
@@ -29139,7 +29675,7 @@ var createVoiceMemoryObservabilityExportDeliveryReceiptStore = () => {
|
|
|
29139
29675
|
};
|
|
29140
29676
|
};
|
|
29141
29677
|
var createVoiceFileObservabilityExportDeliveryReceiptStore = (options) => {
|
|
29142
|
-
const receiptPath = (id) =>
|
|
29678
|
+
const receiptPath = (id) => join3(options.directory, `${encodeURIComponent(id)}.json`);
|
|
29143
29679
|
return {
|
|
29144
29680
|
get: async (id) => {
|
|
29145
29681
|
const file = Bun.file(receiptPath(id));
|
|
@@ -29149,10 +29685,10 @@ var createVoiceFileObservabilityExportDeliveryReceiptStore = (options) => {
|
|
|
29149
29685
|
return JSON.parse(await file.text());
|
|
29150
29686
|
},
|
|
29151
29687
|
list: async () => {
|
|
29152
|
-
await
|
|
29688
|
+
await mkdir3(options.directory, { recursive: true });
|
|
29153
29689
|
const receipts = [];
|
|
29154
29690
|
for (const entry of await Array.fromAsync(new Bun.Glob("*.json").scan(options.directory))) {
|
|
29155
|
-
const file = Bun.file(
|
|
29691
|
+
const file = Bun.file(join3(options.directory, entry));
|
|
29156
29692
|
receipts.push(JSON.parse(await file.text()));
|
|
29157
29693
|
}
|
|
29158
29694
|
return receipts.sort((left, right) => right.checkedAt - left.checkedAt);
|
|
@@ -29163,7 +29699,7 @@ var createVoiceFileObservabilityExportDeliveryReceiptStore = (options) => {
|
|
|
29163
29699
|
});
|
|
29164
29700
|
},
|
|
29165
29701
|
set: async (id, receipt) => {
|
|
29166
|
-
await
|
|
29702
|
+
await mkdir3(options.directory, { recursive: true });
|
|
29167
29703
|
await Bun.write(receiptPath(id), `${JSON.stringify(receipt, null, 2)}
|
|
29168
29704
|
`);
|
|
29169
29705
|
}
|
|
@@ -29669,16 +30205,16 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29669
30205
|
const label = destination.label ?? (destination.kind === "file" ? "File observability export" : destination.kind === "s3" ? "S3 observability export" : destination.kind === "sqlite" ? "SQLite observability export" : destination.kind === "postgres" ? "Postgres observability export" : "Webhook observability export");
|
|
29670
30206
|
try {
|
|
29671
30207
|
if (destination.kind === "file") {
|
|
29672
|
-
const target =
|
|
29673
|
-
await
|
|
29674
|
-
await Bun.write(
|
|
29675
|
-
await Bun.write(
|
|
30208
|
+
const target = join3(destination.directory, runId);
|
|
30209
|
+
await mkdir3(join3(target, "artifacts"), { recursive: true });
|
|
30210
|
+
await Bun.write(join3(target, "manifest.json"), manifest);
|
|
30211
|
+
await Bun.write(join3(target, "artifact-index.json"), index);
|
|
29676
30212
|
if (destination.includeArtifacts !== false) {
|
|
29677
30213
|
for (const artifact of options.report.artifacts) {
|
|
29678
30214
|
if (!artifact.path) {
|
|
29679
30215
|
continue;
|
|
29680
30216
|
}
|
|
29681
|
-
await Bun.write(
|
|
30217
|
+
await Bun.write(join3(target, "artifacts", safeArtifactFileName(artifact)), await readFile(stripArtifactPathAnchor(artifact.path)));
|
|
29682
30218
|
}
|
|
29683
30219
|
}
|
|
29684
30220
|
return {
|
|
@@ -32910,7 +33446,7 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
32910
33446
|
};
|
|
32911
33447
|
// src/evalRoutes.ts
|
|
32912
33448
|
import { Elysia as Elysia49 } from "elysia";
|
|
32913
|
-
import { mkdir as
|
|
33449
|
+
import { mkdir as mkdir4 } from "fs/promises";
|
|
32914
33450
|
import { dirname as dirname2 } from "path";
|
|
32915
33451
|
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32916
33452
|
var rate4 = (count, total) => count / Math.max(1, total);
|
|
@@ -33222,7 +33758,7 @@ var createVoiceFileEvalBaselineStore = (filePath) => ({
|
|
|
33222
33758
|
return text.trim() ? JSON.parse(text) : undefined;
|
|
33223
33759
|
},
|
|
33224
33760
|
set: async (report) => {
|
|
33225
|
-
await
|
|
33761
|
+
await mkdir4(dirname2(filePath), { recursive: true });
|
|
33226
33762
|
await Bun.write(filePath, JSON.stringify(report, null, 2));
|
|
33227
33763
|
}
|
|
33228
33764
|
});
|
|
@@ -36053,21 +36589,21 @@ var createVoicePhoneAgent = (options) => {
|
|
|
36053
36589
|
};
|
|
36054
36590
|
// src/fileStore.ts
|
|
36055
36591
|
import {
|
|
36056
|
-
mkdir as
|
|
36592
|
+
mkdir as mkdir5,
|
|
36057
36593
|
readFile as readFile2,
|
|
36058
36594
|
readdir,
|
|
36059
36595
|
rename,
|
|
36060
36596
|
rm,
|
|
36061
36597
|
stat as stat2,
|
|
36062
|
-
writeFile
|
|
36598
|
+
writeFile as writeFile2
|
|
36063
36599
|
} from "fs/promises";
|
|
36064
|
-
import { join as
|
|
36600
|
+
import { join as join4 } from "path";
|
|
36065
36601
|
var listJsonFiles = async (directory) => {
|
|
36066
36602
|
try {
|
|
36067
36603
|
const entries = await readdir(directory, {
|
|
36068
36604
|
withFileTypes: true
|
|
36069
36605
|
});
|
|
36070
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) =>
|
|
36606
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => join4(directory, entry.name));
|
|
36071
36607
|
} catch (error) {
|
|
36072
36608
|
if (error.code === "ENOENT") {
|
|
36073
36609
|
return [];
|
|
@@ -36085,7 +36621,7 @@ var listRecentJsonFiles = async (directory, limit) => {
|
|
|
36085
36621
|
}
|
|
36086
36622
|
return (await rebuildRecentJsonFileIndex(directory)).slice(0, limit).map((entry) => entry.path);
|
|
36087
36623
|
};
|
|
36088
|
-
var recentJsonFileIndexPath = (directory) =>
|
|
36624
|
+
var recentJsonFileIndexPath = (directory) => join4(directory, ".recent-index");
|
|
36089
36625
|
var sortRecentJsonFileIndexEntries = (entries) => entries.sort((left, right) => right.updatedAt - left.updatedAt);
|
|
36090
36626
|
var readRecentJsonFileIndex = async (directory) => {
|
|
36091
36627
|
try {
|
|
@@ -36099,12 +36635,12 @@ var readRecentJsonFileIndex = async (directory) => {
|
|
|
36099
36635
|
}
|
|
36100
36636
|
};
|
|
36101
36637
|
var writeRecentJsonFileIndex = async (directory, files) => {
|
|
36102
|
-
await
|
|
36638
|
+
await mkdir5(directory, {
|
|
36103
36639
|
recursive: true
|
|
36104
36640
|
});
|
|
36105
36641
|
const path = recentJsonFileIndexPath(directory);
|
|
36106
36642
|
const tempPath = `${path}.${crypto.randomUUID()}.tmp`;
|
|
36107
|
-
await
|
|
36643
|
+
await writeFile2(tempPath, JSON.stringify({
|
|
36108
36644
|
files: sortRecentJsonFileIndexEntries(files).slice(0, 5000),
|
|
36109
36645
|
version: 1
|
|
36110
36646
|
}));
|
|
@@ -36180,15 +36716,15 @@ var omitReadWindow = (filter) => {
|
|
|
36180
36716
|
return next;
|
|
36181
36717
|
};
|
|
36182
36718
|
var encodeStoreId = (id) => `${encodeURIComponent(id)}.json`;
|
|
36183
|
-
var resolveFilePath = (directory, id) =>
|
|
36719
|
+
var resolveFilePath = (directory, id) => join4(directory, encodeStoreId(id));
|
|
36184
36720
|
var createMemoryStoreId = (input) => `${input.assistantId}:${input.namespace}:${input.key}`;
|
|
36185
36721
|
var readJsonFile = async (path) => JSON.parse(await readFile2(path, "utf8"));
|
|
36186
36722
|
var writeJsonFile = async (path, value, options) => {
|
|
36187
|
-
await
|
|
36723
|
+
await mkdir5(options.directory, {
|
|
36188
36724
|
recursive: true
|
|
36189
36725
|
});
|
|
36190
36726
|
const tempPath = `${path}.${crypto.randomUUID()}.tmp`;
|
|
36191
|
-
await
|
|
36727
|
+
await writeFile2(tempPath, JSON.stringify(value, null, options.pretty === false ? undefined : 2));
|
|
36192
36728
|
await rename(tempPath, path);
|
|
36193
36729
|
};
|
|
36194
36730
|
var createVoiceFileSessionStore = (options) => {
|
|
@@ -36562,51 +37098,51 @@ var createVoiceFileIncidentBundleStore = (options) => {
|
|
|
36562
37098
|
var createVoiceFileRuntimeStorage = (options) => ({
|
|
36563
37099
|
audit: createVoiceFileAuditEventStore({
|
|
36564
37100
|
...options,
|
|
36565
|
-
directory:
|
|
37101
|
+
directory: join4(options.directory, "audit")
|
|
36566
37102
|
}),
|
|
36567
37103
|
auditDeliveries: createVoiceFileAuditSinkDeliveryStore({
|
|
36568
37104
|
...options,
|
|
36569
|
-
directory:
|
|
37105
|
+
directory: join4(options.directory, "audit-deliveries")
|
|
36570
37106
|
}),
|
|
36571
37107
|
campaigns: createVoiceFileCampaignStore({
|
|
36572
37108
|
...options,
|
|
36573
|
-
directory:
|
|
37109
|
+
directory: join4(options.directory, "campaigns")
|
|
36574
37110
|
}),
|
|
36575
37111
|
events: createVoiceFileIntegrationEventStore({
|
|
36576
37112
|
...options,
|
|
36577
|
-
directory:
|
|
37113
|
+
directory: join4(options.directory, "events")
|
|
36578
37114
|
}),
|
|
36579
37115
|
externalObjects: createVoiceFileExternalObjectMapStore({
|
|
36580
37116
|
...options,
|
|
36581
|
-
directory:
|
|
37117
|
+
directory: join4(options.directory, "external-objects")
|
|
36582
37118
|
}),
|
|
36583
37119
|
incidentBundles: createVoiceFileIncidentBundleStore({
|
|
36584
37120
|
...options,
|
|
36585
|
-
directory:
|
|
37121
|
+
directory: join4(options.directory, "incident-bundles")
|
|
36586
37122
|
}),
|
|
36587
37123
|
memories: createVoiceFileAssistantMemoryStore({
|
|
36588
37124
|
...options,
|
|
36589
|
-
directory:
|
|
37125
|
+
directory: join4(options.directory, "memories")
|
|
36590
37126
|
}),
|
|
36591
37127
|
reviews: createVoiceFileReviewStore({
|
|
36592
37128
|
...options,
|
|
36593
|
-
directory:
|
|
37129
|
+
directory: join4(options.directory, "reviews")
|
|
36594
37130
|
}),
|
|
36595
37131
|
session: createVoiceFileSessionStore({
|
|
36596
37132
|
...options,
|
|
36597
|
-
directory:
|
|
37133
|
+
directory: join4(options.directory, "sessions")
|
|
36598
37134
|
}),
|
|
36599
37135
|
tasks: createVoiceFileTaskStore({
|
|
36600
37136
|
...options,
|
|
36601
|
-
directory:
|
|
37137
|
+
directory: join4(options.directory, "tasks")
|
|
36602
37138
|
}),
|
|
36603
37139
|
traceDeliveries: createVoiceFileTraceSinkDeliveryStore({
|
|
36604
37140
|
...options,
|
|
36605
|
-
directory:
|
|
37141
|
+
directory: join4(options.directory, "trace-deliveries")
|
|
36606
37142
|
}),
|
|
36607
37143
|
traces: createVoiceFileTraceEventStore({
|
|
36608
37144
|
...options,
|
|
36609
|
-
directory:
|
|
37145
|
+
directory: join4(options.directory, "traces")
|
|
36610
37146
|
})
|
|
36611
37147
|
});
|
|
36612
37148
|
var createStoredVoiceCallReviewArtifact = (id, artifact) => withVoiceCallReviewId(id, artifact);
|
|
@@ -42445,8 +42981,8 @@ var shapeTelephonyAssistantText = (text, options = {}) => {
|
|
|
42445
42981
|
};
|
|
42446
42982
|
// src/proofPack.ts
|
|
42447
42983
|
import { Elysia as Elysia69 } from "elysia";
|
|
42448
|
-
import { mkdir as
|
|
42449
|
-
import { dirname as dirname3, join as
|
|
42984
|
+
import { mkdir as mkdir6 } from "fs/promises";
|
|
42985
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
42450
42986
|
var toGeneratedAt = (value) => value === undefined ? new Date().toISOString() : typeof value === "number" ? new Date(value).toISOString() : value;
|
|
42451
42987
|
var getProofPackMetadata = (proofPack) => {
|
|
42452
42988
|
const built = buildVoiceProofPack(proofPack);
|
|
@@ -42975,10 +43511,10 @@ var writeVoiceProofPack = async (input, options = { outputDir: ".voice-runtime/p
|
|
|
42975
43511
|
...input,
|
|
42976
43512
|
outputDir: options.outputDir
|
|
42977
43513
|
});
|
|
42978
|
-
const jsonPath =
|
|
42979
|
-
const markdownPath =
|
|
42980
|
-
await
|
|
42981
|
-
await
|
|
43514
|
+
const jsonPath = join5(options.outputDir, options.jsonFileName ?? "latest.json");
|
|
43515
|
+
const markdownPath = join5(options.outputDir, options.markdownFileName ?? "latest.md");
|
|
43516
|
+
await mkdir6(dirname3(jsonPath), { recursive: true });
|
|
43517
|
+
await mkdir6(dirname3(markdownPath), { recursive: true });
|
|
42982
43518
|
await Promise.all([
|
|
42983
43519
|
Bun.write(jsonPath, JSON.stringify(proofPack, null, 2)),
|
|
42984
43520
|
Bun.write(markdownPath, renderVoiceProofPackMarkdown(proofPack))
|
|
@@ -43051,6 +43587,7 @@ var createVoiceProofPackRoutes = (options) => {
|
|
|
43051
43587
|
};
|
|
43052
43588
|
export {
|
|
43053
43589
|
writeVoiceProofPack,
|
|
43590
|
+
writeVoiceMediaPipelineArtifacts,
|
|
43054
43591
|
withVoiceOpsTaskId,
|
|
43055
43592
|
withVoiceIntegrationEventId,
|
|
43056
43593
|
voiceTelephonyOutcomeToRouteResult,
|
|
@@ -43088,6 +43625,7 @@ export {
|
|
|
43088
43625
|
summarizeVoiceOpsTaskQueue,
|
|
43089
43626
|
summarizeVoiceOpsTaskAnalytics,
|
|
43090
43627
|
summarizeVoiceOpsStatus,
|
|
43628
|
+
summarizeVoiceMediaPipelineReport,
|
|
43091
43629
|
summarizeVoiceLiveLatency,
|
|
43092
43630
|
summarizeVoiceIntegrationEvents,
|
|
43093
43631
|
summarizeVoiceHandoffHealth,
|
|
@@ -43294,6 +43832,7 @@ export {
|
|
|
43294
43832
|
filterVoiceAuditEvents,
|
|
43295
43833
|
fetchVoiceProofTarget,
|
|
43296
43834
|
failVoiceOpsTask,
|
|
43835
|
+
extractVoiceMediaPipelineIssueEntries,
|
|
43297
43836
|
exportVoiceTrace,
|
|
43298
43837
|
exportVoiceAuditTrail,
|
|
43299
43838
|
evaluateVoiceTrace,
|
|
@@ -43736,6 +44275,8 @@ export {
|
|
|
43736
44275
|
buildVoiceObservabilityArtifactIndex,
|
|
43737
44276
|
buildVoiceMonitorRunReport,
|
|
43738
44277
|
buildVoiceMediaPipelineReport,
|
|
44278
|
+
buildVoiceMediaPipelineReadinessChecks,
|
|
44279
|
+
buildVoiceMediaPipelineIncidentEvents,
|
|
43739
44280
|
buildVoiceLiveOpsControlState,
|
|
43740
44281
|
buildVoiceLatencySLOGate,
|
|
43741
44282
|
buildVoiceIncidentTimelineReport,
|