@runtypelabs/persona 4.26.0 → 4.27.0
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/approval-ui.d.cts +11 -0
- package/dist/approval-ui.d.ts +11 -0
- package/dist/artifacts-ui.d.cts +11 -0
- package/dist/artifacts-ui.d.ts +11 -0
- package/dist/chunk-3255TNY7.js +1 -0
- package/dist/{client-history-YPEG45Q4.js → client-history-HTRKHBAF.js} +1 -1
- package/dist/client-history.js +1 -1
- package/dist/client-stream-N22JHTLE.js +4 -0
- package/dist/client-stream.js +3 -3
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions.d.cts +11 -0
- package/dist/context-mentions.d.ts +11 -0
- package/dist/event-stream-view.d.cts +11 -0
- package/dist/event-stream-view.d.ts +11 -0
- package/dist/forms-ui.d.cts +13 -0
- package/dist/forms-ui.d.ts +13 -0
- package/dist/index.cjs +57 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +58 -58
- package/dist/index.js.map +1 -1
- package/dist/session-reconnect.d.cts +11 -0
- package/dist/session-reconnect.d.ts +11 -0
- package/dist/smart-dom-reader.d.cts +11 -0
- package/dist/smart-dom-reader.d.ts +11 -0
- package/dist/theme-editor-preview.cjs +59 -59
- package/dist/theme-editor-preview.d.cts +11 -0
- package/dist/theme-editor-preview.d.ts +11 -0
- package/dist/theme-editor-preview.js +31 -31
- package/dist/theme-editor.d.cts +11 -0
- package/dist/theme-editor.d.ts +11 -0
- package/dist/voice-runtime-RHRX4F3T.js +17 -0
- package/dist/voice-runtime.cjs +8 -8
- package/dist/voice-runtime.d.cts +15 -0
- package/dist/voice-runtime.d.ts +15 -0
- package/dist/voice-runtime.js +8 -8
- package/package.json +1 -1
- package/src/approval-paused-tool-settle.test.ts +108 -4
- package/src/client-stream.ts +10 -3
- package/src/client.test.ts +20 -0
- package/src/session.ts +56 -10
- package/src/session.voice.test.ts +60 -3
- package/src/types.ts +11 -0
- package/src/ui.composer-defer-one.test.ts +17 -0
- package/src/ui.ts +49 -12
- package/src/voice/__fixtures__/voice-wire/server/session_end-provider-error.json +6 -0
- package/src/voice/__fixtures__/voice-wire/server/session_end-unknown-reason.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/session_end.json +5 -0
- package/src/voice/runtype-voice-provider.ts +131 -19
- package/src/voice/voice-delegation.ts +27 -11
- package/src/voice/voice.test.ts +257 -2
- package/dist/chunk-QPPJUSZH.js +0 -1
- package/dist/client-stream-42FOI3EC.js +0 -4
- package/dist/voice-runtime-UOQOFAFY.js +0 -17
package/dist/theme-editor.d.cts
CHANGED
|
@@ -7094,6 +7094,11 @@ interface VoiceProvider {
|
|
|
7094
7094
|
setSessionBridge?(bridge: VoiceSessionBridge): void;
|
|
7095
7095
|
/** The AI-disclosure notice for the live call, if one should show (speech-to-speech). */
|
|
7096
7096
|
getDisclosure?(): string | null;
|
|
7097
|
+
/**
|
|
7098
|
+
* Status-line text for the call, returned once: why the server ended it
|
|
7099
|
+
* (`session_end`) or that it is reconnecting. `null` when there is none.
|
|
7100
|
+
*/
|
|
7101
|
+
takeNotice?(): string | null;
|
|
7097
7102
|
}
|
|
7098
7103
|
/** Metadata on a {@link VoiceProvider.onTranscript} update. */
|
|
7099
7104
|
type VoiceTranscriptMetadata = {
|
|
@@ -7149,6 +7154,12 @@ type VoiceDelegationResult = {
|
|
|
7149
7154
|
status: VoiceDelegationStatus;
|
|
7150
7155
|
/** The assistant text (Markdown allowed). */
|
|
7151
7156
|
text: string;
|
|
7157
|
+
/**
|
|
7158
|
+
* `false` when no chat message carries this answer (it is only spoken), so
|
|
7159
|
+
* the voice model's read-back of it stays visible as a caption.
|
|
7160
|
+
* @default true
|
|
7161
|
+
*/
|
|
7162
|
+
inChat?: boolean;
|
|
7152
7163
|
/**
|
|
7153
7164
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7154
7165
|
* Resolves with the terminal result once the visitor decides (or the
|
package/dist/theme-editor.d.ts
CHANGED
|
@@ -7094,6 +7094,11 @@ interface VoiceProvider {
|
|
|
7094
7094
|
setSessionBridge?(bridge: VoiceSessionBridge): void;
|
|
7095
7095
|
/** The AI-disclosure notice for the live call, if one should show (speech-to-speech). */
|
|
7096
7096
|
getDisclosure?(): string | null;
|
|
7097
|
+
/**
|
|
7098
|
+
* Status-line text for the call, returned once: why the server ended it
|
|
7099
|
+
* (`session_end`) or that it is reconnecting. `null` when there is none.
|
|
7100
|
+
*/
|
|
7101
|
+
takeNotice?(): string | null;
|
|
7097
7102
|
}
|
|
7098
7103
|
/** Metadata on a {@link VoiceProvider.onTranscript} update. */
|
|
7099
7104
|
type VoiceTranscriptMetadata = {
|
|
@@ -7149,6 +7154,12 @@ type VoiceDelegationResult = {
|
|
|
7149
7154
|
status: VoiceDelegationStatus;
|
|
7150
7155
|
/** The assistant text (Markdown allowed). */
|
|
7151
7156
|
text: string;
|
|
7157
|
+
/**
|
|
7158
|
+
* `false` when no chat message carries this answer (it is only spoken), so
|
|
7159
|
+
* the voice model's read-back of it stays visible as a caption.
|
|
7160
|
+
* @default true
|
|
7161
|
+
*/
|
|
7162
|
+
inChat?: boolean;
|
|
7152
7163
|
/**
|
|
7153
7164
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7154
7165
|
* Resolves with the terminal result once the visitor decides (or the
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import{a as J}from"./chunk-6V3MNEKB.js";import{a as Y}from"./chunk-3255TNY7.js";var $=16e3,he=24e3,pe=4096,fe=$*2*8,me=4,ve=1380533830,ye=3e4,be=1e3,Se=5e3,we=3e4,ke=3e4,Ae=6e5,Ce="full-duplex-v1",Me=300,Te=2e3,Ee=2e3,_e="runtype-browser-v1",Ie=54e4,Pe="You're talking to an AI assistant. Voice is processed by OpenAI.",Ve=new Map([["idle_timeout","Voice call ended after a quiet period."],["max_duration","This voice call reached its time limit."],["provider_ended","The voice session ended."],["quota","Voice is unavailable right now."],["auth_expired","Voice session expired. Tap the mic to reconnect."]]),Z=["provider_error","server_restart"],V="Voice connection lost.",Re=8e3,Le=4e3,Oe=12,Q=2e3;function Ne(i,e){let t="Conversation so far:",s=e.slice(0,Le).trim(),n=Re-(s?s.length+2:0)-t.length,r=[];for(let d of i.slice(-Oe).reverse()){let a=d.content.replace(/\s+/g," ").trim();if(!a)continue;a.length>Q&&(a=`${a.slice(0,Q-1)}\u2026`);let o=`${d.role==="user"?"User":"Assistant"}: ${a}`;if(o.length+1>n)break;n-=o.length+1,r.unshift(o)}let l=r.length>0?[`${t}
|
|
2
|
+
${r.join(`
|
|
3
|
+
`)}`]:[];return s&&l.push(s),l.join(`
|
|
4
|
+
|
|
5
|
+
`)}function De(i){return i.byteLength>=44&&new DataView(i).getUint32(0,!1)===ve?new Uint8Array(i,44):new Uint8Array(i)}function ee(i){let e=i.replace(/\/+$/,"");return/^wss?:\/\//i.test(e)?e:/^https?:\/\//i.test(e)?e.replace(/^http/i,"ws"):`${typeof window<"u"&&window.location?.protocol==="https:"?"wss:":"ws:"}//${e}`}function Ue(i){return ee(i).replace(/^ws/i,"http")}function xe(i){return typeof i!="number"||!Number.isFinite(i)?we:Math.min(Ae,Math.max(ke,Math.round(i)))}var I=class{constructor(e){this.config=e;this.type="runtype";this.#e=null;this.#u=null;this.#g=[];this.#i=null;this.#r=null;this.#a=null;this.#v=[];this.#y=0;this.#n=null;this.#c=!1;this.#l=!1;this.#s=0;this.#A=!1;this.#K=Number.NEGATIVE_INFINITY;this.#o=null;this.#d=!1;this.#C=!1;this.#M=0;this.#f=0;this.#b=!1;this.bridge=null;this.#E=!1;this.#m=new Set;this.#S=new Map;this.#_=new Set;this.#I=null;this.#h=null;this.#D=!1;this.#U=!1;this.#x=!1;this.#P=null;this.#B=null;this.#W=Promise.resolve();this.#V=new Set;this.#w=!1;this.#R=new Set;this.#L=new Set;this.#J=[];this.#$=[];this.#q=[];this.#j=[];this.#H=[]}#e;#u;#g;#i;#r;#a;#v;#y;#n;#c;#l;#s;#A;#K;#o;#d;#C;#M;#f;#T;#b;#E;#m;#S;#_;#N;#I;#h;#Y;#D;#U;#x;#P;#B;#W;#V;#w;#R;#L;#J;#$;#q;#j;#H;async connect(){}setSessionBridge(e){this.bridge=e}prewarm(){if(this.#c||this.#o)return;let e=this.config?.agentId,t=this.config?.clientToken,s=this.config?.host;if(!e||!t||!s)return;let n=Date.now();if(!(n-this.#K<ye)){this.#K=n;try{this.config?.prewarmMode==="attach"?this.#re(s,e,t):this.#oe(s,e,t)}catch{}}}#oe(e,t,s){if(typeof fetch!="function")return;let n=`${Ue(e)}/v1/client/agents/${encodeURIComponent(t)}/voice/prewarm`;fetch(n,{method:"POST",headers:{Authorization:`Bearer ${s}`},keepalive:!0}).catch(()=>{})}#re(e,t,s){let n=new URLSearchParams,r=this.config?.attachIdleMs,l=xe(r);r!==void 0&&n.set("attachIdleMs",String(l));let d=new WebSocket(this.#Q(e,t,n),["runtype.bearer","runtype.attach",s]);d.binaryType="arraybuffer";let a=()=>{},o=new Promise(u=>{a=u}),c={ws:d,state:"connecting",ready:o,settle:a,openedAt:0,idleTimer:void 0};this.#o=c,d.onopen=()=>{this.#o===c&&(c.state=d.protocol==="runtype.attach"?"attached":"live",c.openedAt=Date.now(),this.#Z(c,l),c.state==="attached"&&d.send('{"type":"ping"}'),c.settle())},d.onmessage=u=>{if(this.#o!==c||typeof u.data!="string")return;let g;try{g=JSON.parse(u.data)}catch{return}g.type==="attached"&&typeof g.idleMs=="number"&&this.#Z(c,g.idleMs-(Date.now()-c.openedAt))},d.onerror=()=>{},d.onclose=()=>{this.#o===c&&this.#O()}}#Z(e,t){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>{this.#o===e&&this.#O()},Math.max(0,t))}#O(){let e=this.#o;if(!e)return;this.#o=null,clearTimeout(e.idleTimer);let{ws:t}=e;if(t.onopen=null,t.onmessage=null,t.onerror=null,t.onclose=null,e.settle(),t.readyState===WebSocket.CONNECTING||t.readyState===WebSocket.OPEN)try{t.close(1e3,"prewarm released")}catch{}}async#ae(){let e=this.#o;if(!e)return null;if(e.state==="connecting"){let t;await Promise.race([e.ready,new Promise(s=>{t=setTimeout(s,Se)})]),clearTimeout(t)}return this.#o!==e?null:e.state==="connecting"||e.ws.readyState!==WebSocket.OPEN?(this.#O(),null):(this.#o=null,clearTimeout(e.idleTimer),{ws:e.ws,live:e.state==="live"})}#Q(e,t,s){let n=["partial_transcript","context"];this.bridge&&this.config?.clientDelegation!==!1&&n.push("client_delegation","delegation_update","delegation_read_back"),s&&n.unshift("attach");let r=new URLSearchParams({voiceProtocol:_e,clientVersion:`persona/${Y}`,voiceCapabilities:Ce,clientCapabilities:n.join(",")});return s?.forEach((l,d)=>r.set(d,l)),`${ee(e)}/ws/agents/${encodeURIComponent(t)}/voice?${r}`}async startListening(){if(this.#c)return;let e=this.#U;e||(this.#D=!1,this.#h=null),this.#U=!1;let t=this.config?.agentId,s=this.config?.clientToken,n=this.config?.host;if(!t)throw new Error("Runtype voice requires an agentId");if(!s)throw new Error("Runtype voice requires a clientToken");if(!n)throw new Error("Runtype voice requires a host (or widget apiUrl)");let r=++this.#s;this.#A=!1,this.#c=!0;try{let l=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:$,channelCount:1,echoCancellation:!0}});if(r!==this.#s){l.getTracks().forEach(g=>g.stop());return}this.#i=l;let d=window.AudioContext||window.webkitAudioContext,a=new d({sampleRate:$});if(this.#u=a,a.state==="suspended"){if(await Promise.race([a.resume().catch(()=>{}),new Promise(g=>setTimeout(g,e?500:be))]),r!==this.#s)return;if(a.state!=="running")throw e?new Error(this.#h=`${V} Tap the mic to reconnect.`):new Error("Audio blocked until a tap")}let o=this.config?.createPlaybackEngine?await this.config.createPlaybackEngine():new J(he);if(r!==this.#s){o.destroy(),l.getTracks().forEach(g=>g.stop()),a.close().catch(()=>{});return}this.#n=o,this.#X(),this.#le(a,l,r);let c=await this.#ae();if(r!==this.#s){c?.ws.close(1e3,"client ended call");return}if(c){let{ws:g}=c;this.#e=g,this.#ee(g,r),c.live||g.send('{"type":"start"}'),this.#F(g),this.#t("listening");return}let u=new WebSocket(this.#Q(n,t),["runtype.bearer",s]);u.binaryType="arraybuffer",this.#e=u,u.onopen=()=>{r===this.#s&&(this.#F(u),this.#t("listening"))},this.#ee(u,r)}catch(l){throw this.#p(),this.#k(l),this.#t("error"),l}}#ee(e,t){e.onmessage=s=>this.#de(s,t),e.onerror=()=>{t!==this.#s||this.#I||(this.#k(new Error("Voice connection failed")),this.#t("error"),this.#p())},e.onclose=s=>{if(this.#A){this.#A=!1;return}if(t!==this.#s)return;let n=this.#I??(s.code===4408?{reason:"idle_timeout"}:null);if(!n){if(s.code!==1e3){let r=s.code?` (code ${s.code})`:"";this.#k(new Error(`Voice connection closed${r}`)),this.#t("error")}else this.#t("idle");this.#p();return}this.#ce(n.reason,n.message)}}#ce(e,t){let s=Z.includes(e)&&!this.#D;if(this.#p(),s){this.#D=!0,this.#c=!0,this.#h=e==="provider_error"?`${V} Reconnecting\u2026`:"Reconnecting\u2026",this.#Y=setTimeout(()=>{this.#c=!1,this.#U=!0,this.startListening().catch(()=>{})},1e3+Math.random()*1e3),this.#t("idle");return}if(Z.includes(e))return this.#h=V,this.#k(new Error(V)),this.#t("error");if(e==="error")return this.#t("error");this.#h=e==="quota"&&t||Ve.get(e)||null,this.#t("idle")}takeNotice(){let e=this.#h;return this.#h=null,e}getDisclosure(){let e=this.config?.disclosureText;return this.#c&&this.#d&&e!==!1?e||Pe:null}async stopListening(){this.#p(),this.#t("idle")}async disconnect(){this.#p(),this.#t("disconnected"),this.#J=[],this.#$=[],this.#q=[],this.#j=[],this.#H=[]}stopPlayback(){this.#ne();let e=this.#e;e&&e.readyState===WebSocket.OPEN&&(this.#d&&(this.#M=Date.now()+Te,e.send('{"type":"cancel"}')),this.#t("listening"))}getInterruptionMode(){return"barge-in"}isBargeInActive(){return this.#c}onLevel(e){this.#g.push(e)}async deactivateBargeIn(){this.#p(),this.#t("idle")}#le(e,t,s){let n=e.createMediaStreamSource(t);this.#r=n;let r=e.createScriptProcessor(pe,1,1);this.#a=r,r.onaudioprocess=l=>{if(s!==this.#s)return;let d=this.#e,a=d?.readyState===WebSocket.OPEN;if(d&&!a&&d.readyState!==WebSocket.CONNECTING)return;let o=l.inputBuffer.getChannelData(0),c=new Int16Array(o.length),u=0;for(let g=0;g<o.length;g++){let m=Math.max(-1,Math.min(1,o[g]));u+=m*m,c[g]=m<0?m*32768:m*32767}if(d&&a)this.#F(d),d.send(c.buffer);else for(this.#v.push(c.buffer),this.#y+=c.byteLength;this.#y>fe;)this.#y-=this.#v.shift().byteLength;if(this.#g.length>0){let g=Math.sqrt(u/o.length),m=Math.max(0,Math.min(1,g*me));for(let h of this.#g)h(m)}},n.connect(r),r.connect(e.destination)}#F(e){for(let t of this.#v)e.send(t);this.#v=[],this.#y=0}#de(e,t){if(t!==this.#s)return;if(e.data instanceof ArrayBuffer){this.#pe(e.data,t);return}let s;try{s=JSON.parse(e.data)}catch{return}switch(s.type){case"session_config":s.speechMode&&(this.#d=s.speechMode==="speech_to_speech",this.#n?.setContinuousMode?.(this.#d)),Array.isArray(s.capabilities)&&(this.#m=new Set(s.capabilities)),typeof s.callId=="string"&&(this.#N=s.callId),this.#E=this.#d&&this.#m.has("client_delegation")&&!!this.bridge,this.#d&&!this.#l&&this.#t("listening"),this.#m.has("context")&&!this.#x&&(this.#x=!0,this.#P=this.#ue());break;case"transcript_update":{let n=s.role==="assistant"?"assistant":"user",r=s.utteranceId??s.turnId;if(!r||n==="assistant"&&this.#z())break;let l=String(r);if(n==="user")s.final===!0&&this.#te(t),this.#w=!1;else{if(this.#m.has("delegation_read_back")){let d=s.delegationId;typeof d=="string"&&this.#V.has(d)&&!this.#R.has(l)&&this.#L.add(l)}else this.#w&&!this.#R.has(l)&&(this.#L.add(l),this.#w=!1);if(this.#R.add(l),this.#L.has(l))break}this.#G(n,s.text??"",s.final===!0,{turnId:l,...typeof s.startMs=="number"&&{startMs:s.startMs},...typeof s.endMs=="number"&&{endMs:s.endMs},...this.#E&&{caption:!0}});break}case"delegation_started":case"delegation_completed":{let n=String(s.delegationId??s.turnId);if(s.type==="delegation_started"){this.#te(t);let r=s.input;this.#E&&r&&this.#he(n,{delegationId:n,userText:String(r.text??""),userUtteranceIds:Array.isArray(r.userUtteranceIds)?r.userUtteranceIds.filter(l=>typeof l=="string"):[],messages:Array.isArray(r.messages)?r.messages:[]},t)}else s.speak!==!1&&this.#V.has(n)&&(this.#w=!0);this.#C=s.type==="delegation_started",!this.#l&&!this.#z()&&this.#t(this.#C?"processing":"listening");break}case"delegation_cancelled":this.#se(String(s.delegationId),s.reason!=="session_ending"&&s.reason!=="provider_cancelled");break;case"warning":console.warn(`[Persona voice] ${s.code}: ${s.message??""}`,this.#N??""),s.delegationId&&(s.code==="UNKNOWN_DELEGATION"||s.code==="LATE_RESULT_LIMIT")&&this.#se(String(s.delegationId));break;case"audio_clear":this.#ne(),this.#M=0,this.#t("listening");break;case"transcript_interim":this.#t("listening"),this.#G("user",s.text??"",!1);break;case"transcript_final":{let n=s.role==="assistant"?"assistant":"user";this.#t(n==="user"?"processing":"speaking"),this.#G(n,s.text??"",!0);break}case"audio_end":this.#n?this.#n.markStreamEnd():(this.#l=!1,this.#t("listening"));break;case"metrics":this.#me({llmMs:s.llm_ms,ttsMs:s.tts_ms,firstAudioMs:s.first_audio_ms,totalMs:s.total_ms});break;case"error":this.#k(new Error(s.error||"Voice error")),this.#t("error");break;case"session_end":this.#I={reason:String(s.reason),...typeof s.message=="string"&&{message:s.message}};break}}async#ue(){let e=this.bridge?.getHistory()??[],t="";try{let s=this.config?.callContext;t=String((typeof s=="function"?await s():s)??"")}catch{}return Ne(e,t)}#te(e){let t=this.#P;if(!t)return;this.#P=null;let s=!1,n=t.then(r=>{let l=this.#e;s||!r||e!==this.#s||l?.readyState!==WebSocket.OPEN||l.send(JSON.stringify({type:"context",text:r}))});this.#B={done:n,drop:()=>s=!0}}async#ge(){let e=this.#B;if(!e)return;let t,s=await Promise.race([e.done.then(()=>!1),new Promise(n=>{t=setTimeout(()=>n(!0),Ee)})]);clearTimeout(t),s&&e.drop()}#se(e,t=!1){this.#_.add(e),this.bridge?.dropDelegation?.(e,t),this.#S.get(e)?.abort()}#he(e,t,s){let n=this.bridge,r=(l,d,a)=>{let o=this.#e;return s!==this.#s||o?.readyState!==WebSocket.OPEN||this.#_.has(e)?!1:(o.send(JSON.stringify({type:l,delegationId:e,status:d,text:a})),!0)};this.#W=this.#W.then(async()=>{if(s!==this.#s||this.#_.has(e))return;let l=await n.runDelegatedTurn(t).catch(()=>({status:"failed",text:""}));await this.#ge();let d=!!l.followUp,a=d&&this.#m.has("delegation_update");if(!r(a?"delegation_update":"delegation_result",d&&!a?"completed":l.status,l.text)||(l.status!=="failed"&&l.inChat!==!1&&this.#V.add(e),!l.followUp))return;let c=new AbortController;this.#S.set(e,c),l.followUp({signal:c.signal,approvalTimeoutMs:this.config?.approvalTimeoutMs&&Math.min(this.config.approvalTimeoutMs,Ie),readBack:a,onUpdate:u=>r("delegation_update","pending_approval",u)}).then(u=>{this.#S.delete(e),a&&u&&!c.signal.aborted&&r("delegation_result",u.status,u.text)})})}#pe(e,t){if(t!==this.#s||!this.#n||this.#z())return;let s=De(e);s.length!==0&&(this.#l||(this.#l=!0,this.#t("speaking")),this.#X(),this.#n.enqueue(s),this.#d&&this.#fe(s.length))}#z(){return Date.now()<this.#M}#X(){if(this.#b||!this.#n)return;this.#b=!0;let e=this.#s;this.#n.onFinished(()=>{e===this.#s&&(this.#b=!1,this.#ie())})}#fe(e){let t=Date.now();this.#f=Math.max(t,this.#f)+e/48,clearTimeout(this.#T),this.#T=setTimeout(()=>this.#ie(),this.#f-t+Me)}#ie(){this.#l=!1,this.#f=0,this.#e&&this.#e.readyState===WebSocket.OPEN&&this.#t(this.#C?"processing":"listening")}#ne(){this.#n?.flush(),this.#b=!1,this.#X(),this.#l=!1,this.#f=0,clearTimeout(this.#T)}#p(){this.#s+=1,this.#c=!1,this.#l=!1,this.#O(),this.#d=!1,this.#C=!1,this.#E=!1,this.#m=new Set;for(let e of this.#S.values())e.abort();if(this.#S.clear(),this.#_.clear(),this.#N=void 0,this.#I=null,clearTimeout(this.#Y),this.#x=!1,this.#P=null,this.#B=null,this.#W=Promise.resolve(),this.#V.clear(),this.#w=!1,this.#R.clear(),this.#L.clear(),this.#b=!1,this.#M=0,this.#f=0,clearTimeout(this.#T),this.#v=[],this.#y=0,this.#a&&(this.#a.onaudioprocess=null,this.#a.disconnect(),this.#a=null),this.#r&&(this.#r.disconnect(),this.#r=null),this.#i&&(this.#i.getTracks().forEach(e=>e.stop()),this.#i=null),this.#u&&(this.#u.close().catch(()=>{}),this.#u=null),this.#n&&(this.#n.destroy(),this.#n=null),this.#e){this.#A=!0;try{this.#e.close(1e3,"client ended call")}catch{}this.#e=null}}onResult(e){this.#J.push(e)}onError(e){this.#$.push(e)}onStatusChange(e){this.#q.push(e)}onTranscript(e){this.#j.push(e)}onMetrics(e){this.#H.push(e)}#t(e){this.#q.forEach(t=>t(e))}#k(e){this.#$.forEach(t=>t(e))}#G(e,t,s,n){this.#j.forEach(r=>r(e,t,s,n))}#me(e){this.#H.forEach(t=>t(e))}};var T=class{constructor(e={}){this.config=e;this.type="browser";this.#e=null;this.#u=[];this.#g=[];this.#i=[];this.#r=!1;this.#a=typeof window<"u"?window:void 0}#e;#u;#g;#i;#r;#a;async connect(){this.#i.forEach(e=>e("connected"))}async startListening(){try{if(this.#r)throw new Error("Already listening");if(!this.#a)throw new Error("Window object not available");let e=this.#a.SpeechRecognition||this.#a.webkitSpeechRecognition;if(!e)throw new Error("Browser speech recognition not supported");this.#e=new e,this.#e.lang=this.config?.language||"en-US",this.#e.continuous=this.config?.continuous||!1,this.#e.interimResults=!0,this.#e.onresult=t=>{let s=Array.from(t.results).map(r=>r[0]).map(r=>r.transcript).join(""),n=t.results[t.results.length-1].isFinal;this.#u.forEach(r=>r({text:s,confidence:n?.8:.5,provider:"browser"})),n&&!this.config?.continuous&&this.stopListening()},this.#e.onerror=t=>{this.#g.forEach(s=>s(new Error(t.error))),this.#i.forEach(s=>s("error"))},this.#e.onstart=()=>{this.#r=!0,this.#i.forEach(t=>t("listening"))},this.#e.onend=()=>{this.#r=!1,this.#i.forEach(t=>t("idle"))},this.#e.start()}catch(e){throw this.#g.forEach(t=>t(e)),this.#i.forEach(t=>t("error")),e}}async stopListening(){this.#e&&(this.#e.stop(),this.#e=null),this.#r=!1,this.#i.forEach(e=>e("idle"))}onResult(e){this.#u.push(e)}onError(e){this.#g.push(e)}onStatusChange(e){this.#i.push(e)}async disconnect(){await this.stopListening(),this.#i.forEach(e=>e("disconnected"))}static isSupported(){return"SpeechRecognition"in window||"webkitSpeechRecognition"in window}};function R(i){switch(i.type){case"runtype":if(!i.runtype)throw new Error("Runtype voice provider requires configuration");return new I(i.runtype);case"browser":if(!T.isSupported())throw new Error("Browser speech recognition not supported");return new T(i.browser||{});case"custom":{let e=i.custom;if(!e)throw new Error("Custom voice provider requires a `custom` provider instance or factory");let t=typeof e=="function"?e():e;if(!t||typeof t.startListening!="function")throw new Error("Custom voice provider `custom` must be a VoiceProvider (or a factory returning one)");return t}default:throw new Error(`Unknown voice provider type: ${i.type}`)}}function te(i){if(i?.type==="custom"&&i.custom)return R({type:"custom",custom:i.custom});if(i?.type==="runtype"&&i.runtype)return R({type:"runtype",runtype:i.runtype});if(T.isSupported())return R({type:"browser",browser:i?.browser||{language:"en-US"}});throw new Error("No supported voice providers available")}function Be(i){try{return te(i),!0}catch{return!1}}var se=i=>i.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,""),q=class{constructor(e){this.host=e;this.turns=new Map;this.latestId=null;this.cancelled=new Set}apply(e,t,s,n,r,l){let d=this.host;t=t.trim();let a=this.turns.get(n);if(a||(a={},this.turns.set(n,a),this.latestId=n),e==="user"){a.userFinal=s;let o=a.userId?d.find(a.userId):void 0;if(o){let c=a.userStartMs===void 0&&r!==void 0;c&&(a.userStartMs=r),d.upsert({...o,content:t,voiceProcessing:!s,...c&&this.placeBefore(this.startedAfter(r))})}else{a.userStartMs=r;let c=a.assistantId?d.find(a.assistantId):void 0;a.userId=d.inject({role:"user",content:t,streaming:!1,voiceProcessing:!s,voiceCaption:l,...this.placeBefore(this.startedAfter(r)??c)}).id}}else if(!this.cancelled.has(n)){a.assistantFinal=s;let o=a.assistantId?d.find(a.assistantId):void 0;if(o){let c=a.assistantStartMs===void 0&&r!==void 0;c&&(a.assistantStartMs=r),d.upsert({...o,content:t,streaming:!s,voiceProcessing:!s,...c&&this.placeBefore(this.startedAfter(r))})}else t&&(a.assistantStartMs=r,a.assistantId=d.inject({role:"assistant",content:t,streaming:!s,voiceProcessing:!s,voiceCaption:l,...this.placeBefore(this.startedAfter(r))}).id);s&&a.assistantId&&d.markSpoken(a.assistantId)}this.sync()}claimUserTurn(e,t=[]){let s=t[t.length-1];for(let r of t)r!==s&&(this.turns.has(r)||this.turns.set(r,{}),this.turns.get(r).claimed=!0);let n;if(s){if(n=this.turns.get(s),n||(n={},this.turns.set(s,n)),n.claimed)return null;(!n.userId||!this.host.find(n.userId))&&(n.userFinal=!0,n.userId=this.host.inject({role:"user",content:e.trim()}).id)}else{let r=se(e),l=[...this.turns.values()].reverse().flatMap(d=>{let a=d.userId&&!d.claimed?this.host.find(d.userId):void 0;return a?[{turn:d,text:se(a.content)}]:[]}).filter(({text:d})=>d&&r);n=(l.find(({text:d})=>d===r)??l.find(({text:d})=>d.startsWith(r)||r.startsWith(d)))?.turn}return n?(n.claimed=!0,n.userId):null}cancel(){let e=this.inFlight();if(e.length===0){let t=this.awaiting();if(!t)return;e=[t]}for(let t of e)this.cancelled.add(t);this.closeReplies(e),this.sync()}fail(e){let t=this.awaiting(),s=this.inFlight();if(!t&&s.length===0)return;for(let l of s)this.turns.get(l).assistantFinal=!0;this.closeReplies(s);let n=this.host.inject({role:"assistant",content:e,streaming:!1,voiceProcessing:!1}),r=t?this.turns.get(t):void 0;r&&(r.assistantId=n.id,r.assistantFinal=!0),this.sync()}settle(){if(this.turns.size===0)return;let e=this.pending(),t=new Set;for(let s of this.turns.values())s.userId&&t.add(s.userId),s.assistantId&&(t.add(s.assistantId),this.host.markSpoken(s.assistantId));this.turns.clear(),this.latestId=null,this.host.settle(t),e&&this.host.setStreaming(!1)}startedAfter(e){if(e===void 0)return;let t;for(let s of this.turns.values())for(let[n,r]of[[s.userId,s.userStartMs],[s.assistantId,s.assistantStartMs]])n&&r!==void 0&&r>e&&(!t||r<t.start)&&(t={start:r,id:n});return t&&this.host.find(t.id)}placeBefore(e){if(!e)return;let t=e.sequence??0,s=t-1;for(let n of this.turns.values())for(let r of[n.userId,n.assistantId]){let l=r?this.host.find(r):void 0,d=l?.sequence;l?.createdAt===e.createdAt&&d!==void 0&&d>s&&d<t&&(s=d)}return{createdAt:e.createdAt,sequence:(s+t)/2}}closeReplies(e){let t=new Set;for(let s of e){let n=this.turns.get(s)?.assistantId;n&&(t.add(n),this.host.markSpoken(n))}t.size>0&&this.host.settle(t)}inFlight(){let e=[];for(let[t,s]of this.turns)s.assistantId&&!s.assistantFinal&&!this.cancelled.has(t)&&e.push(t);return e}awaiting(){let e=this.latestId;if(!e)return null;let t=this.turns.get(e);return t?.userFinal&&!t.assistantId&&!t.claimed&&!this.cancelled.has(e)?e:null}pending(){return this.awaiting()!==null||this.inFlight().length>0}sync(){this.host.setStreaming(this.pending())}};var We="I need your answer in the chat before I can continue.";var ie="no|nope|never ?mind|decline(?: it| that)?|cancel(?: it| that| this)?(?: (?:the|my|that|this) (?:[a-z]+ )?(?:order|request))?|don'?t (?:do|place) (?:it|that|the (?:[a-z]+ )?order)",$e=new RegExp(`^(?:${ie})(?: (?:${ie}))?(?: thanks| thank you)?$`),qe=i=>$e.test(i.toLowerCase().replace(/[^a-z' ]+/g," ").replace(/\s+/g," ").trim()),ne="Briefly tell the user what you're about to do and ask them to approve or decline it in the chat. Don't claim it's done.",oe=()=>new Promise(i=>setTimeout(i,50)),j=(i,e)=>i.length>e?`${i.slice(0,e-1).trimEnd()}\u2026`:i,_=i=>i.replace(/^webmcp:/,"").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/[_\-.]+/g," ").trim().toLowerCase();function H(i,e=0){if(i==null||i==="")return"";if(typeof i!="object")return String(i);if(e>2)return"";if(Array.isArray(i))return i.map(r=>H(r,e+1)).filter(Boolean).join(", ");let t=i,s=t.quantity??t.qty??t.count,n=t.name??t.item??t.product??t.title;return s!=null&&n!=null&&typeof n!="object"?`${s} ${n}`:Object.entries(t).filter(([r])=>!r.startsWith("_")).map(([r,l])=>{let d=H(l,e+1);return d&&(e?`${_(r)} ${d}`:`${_(r)}: ${d}`)}).filter(Boolean).join(e?", ":"; ")}function re(i){let e=i.length>1?"These actions need the user's approval in the chat before they happen:":"This action needs the user's approval in the chat before it happens:",t=1e3-e.length-ne.length-2,s=i.map(n=>{let r=[_(n.toolName)];n.description&&r.push(`(${j(n.description.trim(),160)})`);let l=H(n.parameters);return l&&r.push(`with ${l}`),n.reason&&r.push(`because: ${j(n.reason.trim(),160)}`),j(`- ${r.join(" ")}`,Math.floor(t/i.length)-1)});return`${e}
|
|
6
|
+
${s.join(`
|
|
7
|
+
`)}
|
|
8
|
+
|
|
9
|
+
${ne}`}var L=i=>i.variant==="approval"&&i.approval?.status==="pending";function je(i){let e=null,t=null,s=()=>i.track(e??t),n=[],r=new Map,l=new Map,d=(h,f)=>{r.set(h,[...r.get(h)??[],f]),r.size>32&&r.delete(r.keys().next().value)},a=h=>i.messages().find(f=>f.id===h),o=h=>h.approvals.filter(f=>a(f)?.approval?.status==="pending"),c=h=>_(a(h)?.approval?.toolName??""),u=(h,f,S)=>{h.outcome={status:f,text:S};for(let v of o(h))i.decide(v)},g=h=>h.flatMap(f=>i.messages().find(S=>S.id===f)??[]).filter(f=>!f.variant&&f.content.trim()).map(f=>f.content.trim()).join(`
|
|
10
|
+
|
|
11
|
+
`),m=async h=>{do await oe();while(i.busy()&&!(h&&(i.parked()||h.failed)))};return{getHistory:()=>{let h=i.messages().filter(v=>(v.role==="user"||v.role==="assistant")&&!v.variant&&!v.voiceProcessing&&!v.streaming&&v.content),f=!1,S=[];for(let v=h.length-1;v>=0;v-=1){let k=h[v];if(k.role==="user")f=!1;else if(!k.voiceCaption)f=!0;else if(f)continue;S.unshift({role:k.role,content:k.content})}return S},dropDelegation(h,f){l.set(h,!!f),l.size>32&&l.delete(l.keys().next().value);let S=f&&n.find(v=>v.delegationId===h);S&&!S.outcome&&u(S,"timeout","");for(let v of r.get(h)??[])v.dropped=!0,v.ids.length&&i.unspoken(v.ids)},async runDelegatedTurn({delegationId:h,userText:f,userUtteranceIds:S}){let v=n.filter(p=>o(p).length),k=v.flatMap(o);if(k.length===1&&qe(f)){let p=c(k[0]);return u(v[0],"denied",""),{status:"denied",text:`Okay, I cancelled the ${p} request. Nothing was done.`,inChat:!1}}let F=i.parked()&&i.messages().every(p=>!L(p)||k.includes(p.id));i.busy()&&!F&&await m();let ae=new Set(i.messages().map(p=>p.id)),O=()=>i.messages().filter(p=>!ae.has(p.id)&&p.variant==="approval"),A={ids:[],failed:!1};d(h,A),e=A,s();try{await i.send(f,i.claim(f,S)??void 0),await m(A)}catch{A.failed=!0}finally{e=null,s()}let ce=A.ids.flatMap(p=>i.messages().find(b=>b.id===p)??[]),E=g(A.ids),P=A.failed?[]:O().filter(L),le=new Set(P.map(p=>_(p.approval.toolName)));for(let p of v){if(p.outcome)continue;for(let w of o(p).filter(N=>le.has(c(N))))p.replaced.add(w),i.decide(w);let b=c(p.approvals[0]);p.approvals.every(w=>p.replaced.has(w))?p.outcome={status:"cancelled",text:`The earlier ${b} request was replaced by the new one; it was not done.`}:F&&p.approvals.every(w=>a(w)?.approval?.status==="denied")&&(p.outcome={status:"cancelled",text:`The earlier ${b} request was replaced by the new one; it was not done.`})}if(P.length){let p=new Set(P.map(w=>w.id)),b={delegationId:h,approvals:[...p],at:Date.now(),replaced:new Set};return n.push(b),l.get(h)&&u(b,"timeout",""),E=`${E}
|
|
12
|
+
|
|
13
|
+
${re(P.map(w=>w.approval))}`.trim(),{status:"pending_approval",text:E,followUp:async({signal:w,approvalTimeoutMs:N=3e5,readBack:z=!0,onUpdate:de})=>{let C={ids:[],failed:!1};r.delete(h),d(h,C);let X=()=>O().filter(y=>p.has(y.id)||C.ids.includes(y.id)),ue=()=>O().filter(y=>L(y)&&!p.has(y.id)&&!n.some(M=>M.approvals.includes(y.id))&&(C.ids.includes(y.id)||y.approval?.toolType==="webmcp"&&t===C)),G=()=>{t=C,s()};z&&G();try{for(;!w.aborted&&!b.outcome&&(e||i.busy()||X().some(L));){z&&t!==C&&!o(b).length&&G();let y=ue();if(y.length){for(let M of y)p.add(M.id),b.approvals.push(M.id);b.at=Date.now(),de?.(re(y.map(M=>M.approval)))}if(Date.now()-b.at>=N&&o(b).length&&(!i.busy()||i.parked())){u(b,"timeout",`That ${c(b.approvals[0])} request expired, so nothing was done.`);break}await oe()}}finally{t===C&&(t=null,s()),n.splice(n.indexOf(b),1)}if(w.aborted)return null;if(b.outcome)return b.outcome;if(C.failed)return{status:"failed",text:`The ${c(b.approvals[0])} request didn't complete.`};let K=X(),D=y=>K.filter(y).map(M=>_(M.approval.toolName)).join(", "),U=K.some(y=>y.approval?.status==="approved"),x=D(y=>y.approval?.status==="denied"&&!b.replaced.has(y.id)),B=D(y=>b.replaced.has(y.id)),W=D(y=>y.approval?.status==="timeout"),ge=[U?g(C.ids):"",x&&`The user declined the ${x} request in the chat, so ${U?"that part was not done":"nothing was done"}.`,B&&`The earlier ${B} request was replaced by the new one; it was not done.`,W&&`The ${W} request timed out, so it was not done.`].filter(Boolean).join(`
|
|
14
|
+
|
|
15
|
+
`);return{status:U?"completed":x?"denied":B?"cancelled":W?"timeout":"completed",text:ge}}}}return!A.failed&&i.parked()||ce.some(p=>p.agentMetadata?.awaitingLocalTool&&!p.agentMetadata.askUserQuestionAnswered&&!p.toolCall?.name?.startsWith("webmcp:"))?{status:A.failed?"failed":"completed",text:`${E}
|
|
16
|
+
|
|
17
|
+
${We}`.trim()}:{status:!A.failed&&E?"completed":"failed",text:E}}}}var He=(i,e,t,s)=>{let n=i.session;try{i.keyed=t?new t({find:o=>n.messages.find(c=>c.id===o),inject:o=>n.injectMessage(o),upsert:o=>n.upsertMessage(o),settle:o=>{n.messages=n.messages.map(c=>o.has(c.id)?{...c,streaming:!1,voiceProcessing:!1}:c),n.callbacks.onMessagesChanged([...n.messages])},setStreaming:o=>{(o||!i.busy())&&i.setStreaming(o)},markSpoken:o=>{n.ttsSpokenMessageIds.add(o)}}):null,s&&e.setSessionBridge&&e.setSessionBridge(s({messages:()=>n.messages,busy:()=>i.busy(),parked:()=>n.webMcpApprovalResolvers.size>0,claim:(o,c)=>i.keyed?.claimUserTurn(o,c)??null,send:(o,c)=>n.sendMessage(o,{viaVoice:!0,voiceTurn:{userMessageId:c}}),track:o=>{i.setDelegation(o)},unspoken:o=>{for(let c of o)n.ttsSpokenMessageIds.delete(c);n.streaming||n.speakLatestAssistantMessage(o)},decide:o=>{if(n.webMcpApprovalResolvers.has(o))return n.resolveWebMcpApproval(o,"denied");let c=n.messages.find(u=>u.id===o)?.approval;c?.status==="pending"&&n.resolveApproval(c,"denied")}}));let r=i.generation(),l=()=>i.provider()===e&&r===i.generation(),a=(n.config.voiceRecognition??{}).processingErrorText??"Voice processing failed. Please try again.";e.onResult(o=>{l()&&o.provider!=="runtype"&&o.text&&o.text.trim()&&n.sendMessage(o.text,{viaVoice:!0})}),e.onTranscript&&e.onTranscript((o,c,u,g)=>{if(l()){if(g?.turnId){i.keyed?.apply(o,c,u,g.turnId,g.startMs,g.caption);return}if(o==="user"){if(i.pendingUser)n.upsertMessage({id:i.pendingUser,role:"user",content:c,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!u});else{let m=n.injectMessage({role:"user",content:c,streaming:!1,voiceProcessing:!u});i.pendingUser=m.id}if(u){i.turns().start(g?.turnId),i.pendingUser=null;let m=n.injectMessage({role:"assistant",content:"",streaming:!0,voiceProcessing:!0});i.pendingAssistant=m.id,i.setStreaming(!0)}}else{if(!i.turns().accepts(g?.turnId))return;if(i.pendingAssistant)n.upsertMessage({id:i.pendingAssistant,role:"assistant",content:c,createdAt:new Date().toISOString(),streaming:!u,voiceProcessing:!u});else{let m=n.injectMessage({role:"assistant",content:c,streaming:!u,voiceProcessing:!u});i.pendingAssistant=m.id}u&&(i.pendingAssistant&&n.ttsSpokenMessageIds.add(i.pendingAssistant),i.setStreaming(!1),i.pendingAssistant=null)}}}),e.onLevel&&e.onLevel(o=>{l()&&i.setLevel(Number.isFinite(o)?Math.max(0,Math.min(1,o)):0)}),e.onMetrics&&e.onMetrics(o=>{l()&&n.config.voiceRecognition?.onMetrics?.(o)}),e.onError(o=>{l()&&(console.error("Voice error:",o),i.pendingAssistant&&(n.upsertMessage({id:i.pendingAssistant,role:"assistant",content:a,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!1}),i.setStreaming(!1),i.pendingUser=null,i.pendingAssistant=null),i.keyed?.fail(a))}),e.onStatusChange(o=>{l()&&(i.setStatus(o),(o==="listening"||o==="idle"||o==="disconnected")&&i.settlePending(o!=="listening"),(o==="idle"||o==="disconnected")&&i.keyed?.settle(),n.callbacks.onVoiceStatusChanged?.(o))}),e.connect()}catch(r){console.error("Failed to setup voice:",r)}};var Fe=i=>{let e=a=>{if(i.original)return;let o=i.config().voiceRecognition??{};i.original={backgroundColor:a.style.backgroundColor,color:a.style.color,borderColor:a.style.borderColor,iconName:o.iconName??"mic",iconSize:parseFloat(o.iconSize??"")||i.iconFallbackPx}},t=(a,o,c)=>{let u=a.querySelector("svg");u&&u.remove();let g=i.original?.iconSize??(parseFloat(i.config().voiceRecognition?.iconSize??"")||i.iconFallbackPx),m=i.renderIcon(o,g,c,1.5);m&&a.appendChild(m)},s=a=>{a.classList.remove("persona-voice-recording","persona-voice-processing","persona-voice-speaking")};return{recording:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},c=o.recordingBackgroundColor,u=o.recordingIconColor,g=o.recordingBorderColor;if(s(a),a.classList.add("persona-voice-recording"),i.setMicState("recording"),a.style.backgroundColor=c??"var(--persona-voice-recording-bg, #ef4444)",a.style.color=u??"var(--persona-voice-recording-indicator, #ffffff)",u){let m=a.querySelector("svg");m&&m.setAttribute("stroke",u)}g&&(a.style.borderColor=g),a.setAttribute("aria-label","Stop voice recognition")},processing:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},c=i.session().getVoiceInterruptionMode(),u=i.original,g=o.processingIconName??"loader",m=o.processingIconColor??u?.color??"",h=o.processingBackgroundColor??u?.backgroundColor??"",f=o.processingBorderColor??u?.borderColor??"";s(a),a.classList.add("persona-voice-processing"),i.setMicState("processing"),a.style.backgroundColor=h,a.style.borderColor=f;let S=m||"currentColor";a.style.color=S,t(a,g,S),a.setAttribute("aria-label","Processing voice input"),c==="none"&&(a.style.cursor="default")},speaking:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},c=i.session().getVoiceInterruptionMode(),u=i.original,g=c==="cancel"?"square":c==="barge-in"?"mic":"volume-2",m=o.speakingIconName??g,h=o.speakingIconColor??(c==="barge-in"?o.recordingIconColor??u?.color??"":u?.color??""),f=o.speakingBackgroundColor??(c==="barge-in"?o.recordingBackgroundColor??"var(--persona-voice-recording-bg, #ef4444)":u?.backgroundColor??""),S=o.speakingBorderColor??(c==="barge-in"?o.recordingBorderColor??"":u?.borderColor??"");s(a),a.classList.add("persona-voice-speaking"),i.setMicState("speaking"),a.style.backgroundColor=f,a.style.borderColor=S;let v=h||"currentColor";a.style.color=v,t(a,m,v);let k=c==="cancel"?"Stop playback and re-record":c==="barge-in"?"Speak to interrupt":"Agent is speaking";a.setAttribute("aria-label",k),c==="none"&&(a.style.cursor="default"),c==="barge-in"&&a.classList.add("persona-voice-recording")},reset:()=>{let a=i.mic();if(!a)return;s(a),i.setMicState("idle");let o=i.original;o&&(a.style.backgroundColor=o.backgroundColor??"",a.style.color=o.color??"",a.style.borderColor=o.borderColor??"",t(a,o.iconName,o.color||"currentColor"),i.original=null),a.style.cursor="",a.setAttribute("aria-label","Start voice recognition")}}};export{T as BrowserVoiceProvider,q as KeyedVoiceTranscript,I as RuntypeVoiceProvider,te as createBestAvailableVoiceProvider,Fe as createMicStateStyles,R as createVoiceProvider,je as createVoiceSessionBridge,Be as isVoiceSupported,He as wireSessionVoice};
|
package/dist/voice-runtime.cjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var $=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var Se=Object.prototype.hasOwnProperty;var ke=(i,e)=>{for(var t in e)$(i,t,{get:e[t],enumerable:!0})},Ae=(i,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of we(e))!Se.call(i,n)&&n!==t&&$(i,n,{get:()=>e[n],enumerable:!(s=ve(e,n))||s.enumerable});return i};var Ce=i=>Ae($({},"__esModule",{value:!0}),i);var tt={};ke(tt,{BrowserVoiceProvider:()=>T,KeyedVoiceTranscript:()=>R,RuntypeVoiceProvider:()=>x,createBestAvailableVoiceProvider:()=>H,createMicStateStyles:()=>pe,createVoiceProvider:()=>I,createVoiceSessionBridge:()=>de,isVoiceSupported:()=>ne,wireSessionVoice:()=>ue});module.exports=Ce(tt);var V=class{#e=null;#r=0;#d=[];#i=[];#a=[];#c=!1;#f=!1;#m=0;#n=!1;#p=!1;#l;#t=[];#y=0;#M=!1;#o;#u;#g;#h=null;constructor(e=24e3,t={}){this.#u=e;let s=Math.max(0,t.prebufferMs??0);this.#g=Math.round(e*s/1e3),this.#l=this.#g>0}#b(){if(!this.#e){let t=typeof window<"u"?window:void 0;if(!t)throw new Error("AudioPlaybackManager requires a browser environment");let s=t.AudioContext||t.webkitAudioContext;this.#e=new s({sampleRate:this.#u})}let e=this.#e;return e.state==="suspended"&&!this.#p&&e.resume(),e}enqueue(e){if(e.length===0)return;let t=e;if(this.#h){let n=new Uint8Array(this.#h.length+e.length);n.set(this.#h),n.set(e,this.#h.length),t=n,this.#h=null}if(t.length%2!==0&&(this.#h=new Uint8Array([t[t.length-1]]),t=t.subarray(0,t.length-1)),t.length===0)return;let s=this.#S(t);s.length!==0&&(this.#l?(this.#t.push(s),this.#y+=s.length,clearTimeout(this.#o),this.#y>=this.#g?this.#v():this.#M&&(this.#o=setTimeout(()=>this.#v(),this.#g/this.#u*1e3))):this.#w(s))}markStreamEnd(){this.#t.length>0&&this.#v(),this.#f=!0,this.#k()}flush(){for(let e of this.#d){e.onended=null;try{e.stop(),e.disconnect()}catch{}}this.#d=[],this.#m=0,this.#r=0,this.#c=!1,this.#f=!1,this.#i=[],this.#a=[],this.#h=null,this.#t=[],this.#y=0,this.#l=this.#g>0,this.#n=!1,clearTimeout(this.#o)}setContinuousMode(e){this.#M=e}isPlaying(){return this.#c}onFinished(e){this.#i.push(e)}onStarted(e){this.#a.push(e)}pause(){this.#p=!0,this.#e&&this.#e.state==="running"&&this.#e.suspend()}resume(){this.#p=!1,this.#e&&this.#e.state==="suspended"&&this.#e.resume()}async destroy(){this.flush(),this.#e&&(await this.#e.close(),this.#e=null)}#v(){this.#l=!1;let e=this.#t;this.#t=[],this.#y=0;for(let t of e)this.#w(t)}#w(e){if(e.length===0)return;let t=this.#b(),s=t.createBuffer(1,e.length,this.#u);s.getChannelData(0).set(e);let n=t.createBufferSource();n.buffer=s,n.connect(t.destination);let r=t.currentTime;if(this.#r===0?this.#r=r:this.#r<r&&(this.#r=r,this.#g>0&&(this.#l=!0)),n.start(this.#r),this.#r+=s.duration,this.#d.push(n),this.#m++,this.#c=!0,!this.#n){this.#n=!0;let c=this.#a.slice();this.#a=[];for(let d of c)d()}n.onended=()=>{let c=this.#d.indexOf(n);c!==-1&&(this.#d.splice(c,1),this.#m--,this.#k())}}#k(){if(this.#f&&this.#m<=0&&this.#t.length===0){this.#c=!1,this.#f=!1;let e=this.#i.slice();this.#i=[];for(let t of e)t()}}#S(e){let t=Math.floor(e.length/2),s=new Float32Array(t),n=new DataView(e.buffer,e.byteOffset,e.byteLength);for(let r=0;r<t;r++){let c=n.getInt16(r*2,!0);s[r]=c/32768}return s}};var Q="4.27.0";var ee=Q;var F=16e3,Te=24e3,Ee=4096,xe=F*2*8,_e=4,Ie=1380533830,Pe=3e4,Ve=1e3,je=5e3,Re=3e4,Le=3e4,Oe=6e5,Ne="full-duplex-v1",De=300,qe=2e3,Ue=2e3,Be="runtype-browser-v1",We=54e4,$e="You're talking to an AI assistant. Voice is processed by OpenAI.",Fe=new Map([["idle_timeout","Voice call ended after a quiet period."],["max_duration","This voice call reached its time limit."],["provider_ended","The voice session ended."],["quota","Voice is unavailable right now."],["auth_expired","Voice session expired. Tap the mic to reconnect."]]),te=["provider_error","server_restart"],j="Voice connection lost.",He=8e3,ze=4e3,Xe=12,se=2e3;function Ge(i,e){let t="Conversation so far:",s=e.slice(0,ze).trim(),n=He-(s?s.length+2:0)-t.length,r=[];for(let d of i.slice(-Xe).reverse()){let a=d.content.replace(/\s+/g," ").trim();if(!a)continue;a.length>se&&(a=`${a.slice(0,se-1)}\u2026`);let o=`${d.role==="user"?"User":"Assistant"}: ${a}`;if(o.length+1>n)break;n-=o.length+1,r.unshift(o)}let c=r.length>0?[`${t}
|
|
2
2
|
${r.join(`
|
|
3
|
-
`)}`]:[];return s&&
|
|
3
|
+
`)}`]:[];return s&&c.push(s),c.join(`
|
|
4
4
|
|
|
5
|
-
`)}function He(i){return i.byteLength>=44&&new DataView(i).getUint32(0,!1)===Ee?new Uint8Array(i,44):new Uint8Array(i)}function te(i){let e=i.replace(/\/+$/,"");return/^wss?:\/\//i.test(e)?e:/^https?:\/\//i.test(e)?e.replace(/^http/i,"ws"):`${typeof window<"u"&&window.location?.protocol==="https:"?"wss:":"ws:"}//${e}`}function ze(i){return te(i).replace(/^ws/i,"http")}function Xe(i){return typeof i!="number"||!Number.isFinite(i)?Ve:Math.min(je,Math.max(_e,Math.round(i)))}var x=class{constructor(e){this.config=e;this.type="runtype";this.#e=null;this.#r=null;this.#d=[];this.#i=null;this.#a=null;this.#c=null;this.#g=[];this.#f=0;this.#n=null;this.#m=!1;this.#l=!1;this.#t=0;this.#y=!1;this.#C=Number.NEGATIVE_INFINITY;this.#o=null;this.#u=!1;this.#h=!1;this.#p=0;this.#b=0;this.#w=!1;this.bridge=null;this.#S=!1;this.#k=new Set;this.#M=new Map;this.#x=new Set;this.#_=!1;this.#E=null;this.#j=null;this.#R=Promise.resolve();this.#L=new Set;this.#T=!1;this.#O=new Set;this.#D=new Set;this.#z=[];this.#N=[];this.#B=[];this.#q=[];this.#U=[]}#e;#r;#d;#i;#a;#c;#g;#f;#n;#m;#l;#t;#y;#C;#o;#u;#h;#p;#b;#v;#w;#S;#k;#M;#x;#V;#_;#E;#j;#R;#L;#T;#O;#D;#z;#N;#B;#q;#U;async connect(){}setSessionBridge(e){this.bridge=e}prewarm(){if(this.#m||this.#o)return;let e=this.config?.agentId,t=this.config?.clientToken,s=this.config?.host;if(!e||!t||!s)return;let n=Date.now();if(!(n-this.#C<Pe)){this.#C=n;try{this.config?.prewarmMode==="attach"?this.#te(s,e,t):this.#ee(s,e,t)}catch{}}}#ee(e,t,s){if(typeof fetch!="function")return;let n=`${ze(e)}/v1/client/agents/${encodeURIComponent(t)}/voice/prewarm`;fetch(n,{method:"POST",headers:{Authorization:`Bearer ${s}`},keepalive:!0}).catch(()=>{})}#te(e,t,s){let n=new URLSearchParams,r=this.config?.attachIdleMs,l=Xe(r);r!==void 0&&n.set("attachIdleMs",String(l));let d=new WebSocket(this.#G(e,t,n),["runtype.bearer","runtype.attach",s]);d.binaryType="arraybuffer";let a=()=>{},o=new Promise(u=>{a=u}),c={ws:d,state:"connecting",ready:o,settle:a,openedAt:0,idleTimer:void 0};this.#o=c,d.onopen=()=>{this.#o===c&&(c.state=d.protocol==="runtype.attach"?"attached":"live",c.openedAt=Date.now(),this.#X(c,l),c.state==="attached"&&d.send('{"type":"ping"}'),c.settle())},d.onmessage=u=>{if(this.#o!==c||typeof u.data!="string")return;let g;try{g=JSON.parse(u.data)}catch{return}g.type==="attached"&&typeof g.idleMs=="number"&&this.#X(c,g.idleMs-(Date.now()-c.openedAt))},d.onerror=()=>{},d.onclose=()=>{this.#o===c&&this.#P()}}#X(e,t){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>{this.#o===e&&this.#P()},Math.max(0,t))}#P(){let e=this.#o;if(!e)return;this.#o=null,clearTimeout(e.idleTimer);let{ws:t}=e;if(t.onopen=null,t.onmessage=null,t.onerror=null,t.onclose=null,e.settle(),t.readyState===WebSocket.CONNECTING||t.readyState===WebSocket.OPEN)try{t.close(1e3,"prewarm released")}catch{}}async#se(){let e=this.#o;if(!e)return null;if(e.state==="connecting"){let t;await Promise.race([e.ready,new Promise(s=>{t=setTimeout(s,Ie)})]),clearTimeout(t)}return this.#o!==e?null:e.state==="connecting"||e.ws.readyState!==WebSocket.OPEN?(this.#P(),null):(this.#o=null,clearTimeout(e.idleTimer),{ws:e.ws,live:e.state==="live"})}#G(e,t,s){let n=["partial_transcript","context"];this.bridge&&this.config?.clientDelegation!==!1&&n.push("client_delegation","delegation_update"),s&&n.unshift("attach");let r=new URLSearchParams({voiceProtocol:Ne,clientVersion:`persona/${Q}`,voiceCapabilities:Re,clientCapabilities:n.join(",")});return s?.forEach((l,d)=>r.set(d,l)),`${te(e)}/ws/agents/${encodeURIComponent(t)}/voice?${r}`}async startListening(){if(this.#m)return;let e=this.config?.agentId,t=this.config?.clientToken,s=this.config?.host;if(!e)throw new Error("Runtype voice requires an agentId");if(!t)throw new Error("Runtype voice requires a clientToken");if(!s)throw new Error("Runtype voice requires a host (or widget apiUrl)");let n=++this.#t;this.#y=!1,this.#m=!0;try{let r=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:$,channelCount:1,echoCancellation:!0}});if(n!==this.#t){r.getTracks().forEach(u=>u.stop());return}this.#i=r;let l=window.AudioContext||window.webkitAudioContext,d=new l({sampleRate:$});d.state==="suspended"&&await d.resume().catch(()=>{}),this.#r=d;let a=this.config?.createPlaybackEngine?await this.config.createPlaybackEngine():new _(Ce);if(n!==this.#t){a.destroy(),r.getTracks().forEach(u=>u.stop()),d.close().catch(()=>{});return}this.#n=a,this.#F(),this.#ie(d,r,n);let o=await this.#se();if(n!==this.#t){o?.ws.close(1e3,"client ended call");return}if(o){let{ws:u}=o;this.#e=u,this.#K(u,n),o.live||u.send('{"type":"start"}'),this.#W(u),this.#s("listening");return}let c=new WebSocket(this.#G(s,e),["runtype.bearer",t]);c.binaryType="arraybuffer",this.#e=c,c.onopen=()=>{n===this.#t&&(this.#W(c),this.#s("listening"))},this.#K(c,n)}catch(r){throw this.#A(),this.#I(r),this.#s("error"),r}}#K(e,t){e.onmessage=s=>this.#ne(s,t),e.onerror=()=>{t===this.#t&&(this.#I(new Error("Voice connection failed")),this.#s("error"),this.#A())},e.onclose=s=>{if(this.#y){this.#y=!1;return}if(t===this.#t){if(s.code!==1e3){let n=s.code?` (code ${s.code})`:"";this.#I(new Error(`Voice connection closed${n}`)),this.#s("error")}else this.#s("idle");this.#A()}}}getDisclosure(){let e=this.config?.disclosureText;return this.#m&&this.#u&&e!==!1?e||qe:null}async stopListening(){this.#A(),this.#s("idle")}async disconnect(){this.#A(),this.#s("disconnected"),this.#z=[],this.#N=[],this.#B=[],this.#q=[],this.#U=[]}stopPlayback(){this.#Q();let e=this.#e;e&&e.readyState===WebSocket.OPEN&&(this.#u&&(this.#p=Date.now()+Oe,e.send('{"type":"cancel"}')),this.#s("listening"))}getInterruptionMode(){return"barge-in"}isBargeInActive(){return this.#m}onLevel(e){this.#d.push(e)}async deactivateBargeIn(){this.#A(),this.#s("idle")}#ie(e,t,s){let n=e.createMediaStreamSource(t);this.#a=n;let r=e.createScriptProcessor(Me,1,1);this.#c=r,r.onaudioprocess=l=>{if(s!==this.#t)return;let d=this.#e,a=d?.readyState===WebSocket.OPEN;if(d&&!a&&d.readyState!==WebSocket.CONNECTING)return;let o=l.inputBuffer.getChannelData(0),c=new Int16Array(o.length),u=0;for(let g=0;g<o.length;g++){let f=Math.max(-1,Math.min(1,o[g]));u+=f*f,c[g]=f<0?f*32768:f*32767}if(d&&a)this.#W(d),d.send(c.buffer);else for(this.#g.push(c.buffer),this.#f+=c.byteLength;this.#f>Te;)this.#f-=this.#g.shift().byteLength;if(this.#d.length>0){let g=Math.sqrt(u/o.length),f=Math.max(0,Math.min(1,g*xe));for(let p of this.#d)p(f)}},n.connect(r),r.connect(e.destination)}#W(e){for(let t of this.#g)e.send(t);this.#g=[],this.#f=0}#ne(e,t){if(t!==this.#t)return;if(e.data instanceof ArrayBuffer){this.#ce(e.data,t);return}let s;try{s=JSON.parse(e.data)}catch{return}switch(s.type){case"session_config":s.speechMode&&(this.#u=s.speechMode==="speech_to_speech",this.#n?.setContinuousMode?.(this.#u)),Array.isArray(s.capabilities)&&(this.#k=new Set(s.capabilities)),typeof s.callId=="string"&&(this.#V=s.callId),this.#S=this.#u&&this.#k.has("client_delegation")&&!!this.bridge,this.#u&&!this.#l&&this.#s("listening"),this.#k.has("context")&&!this.#_&&(this.#_=!0,this.#E=this.#re());break;case"transcript_update":{let n=s.role==="assistant"?"assistant":"user",r=s.utteranceId??s.turnId;if(!r||n==="assistant"&&this.#$())break;let l=String(r);if(n==="user")s.final===!0&&this.#J(t),this.#T=!1;else if(this.#T&&!this.#O.has(l)&&(this.#D.add(l),this.#T=!1),this.#O.add(l),this.#D.has(l))break;this.#H(n,s.text??"",s.final===!0,{turnId:l,...typeof s.startMs=="number"&&{startMs:s.startMs},...typeof s.endMs=="number"&&{endMs:s.endMs},...this.#S&&{caption:!0}});break}case"delegation_started":case"delegation_completed":{let n=String(s.delegationId??s.turnId);if(s.type==="delegation_started"){this.#J(t);let r=s.input;this.#S&&r&&this.#ae(n,{delegationId:n,userText:String(r.text??""),userUtteranceIds:Array.isArray(r.userUtteranceIds)?r.userUtteranceIds.filter(l=>typeof l=="string"):[],messages:Array.isArray(r.messages)?r.messages:[]},t)}else s.speak!==!1&&this.#L.has(n)&&(this.#T=!0);this.#h=s.type==="delegation_started",!this.#l&&!this.#$()&&this.#s(this.#h?"processing":"listening");break}case"delegation_cancelled":this.#Y(String(s.delegationId),s.reason!=="session_ending"&&s.reason!=="provider_cancelled");break;case"warning":console.warn(`[Persona voice] ${s.code}: ${s.message??""}`,this.#V??""),s.delegationId&&(s.code==="UNKNOWN_DELEGATION"||s.code==="LATE_RESULT_LIMIT")&&this.#Y(String(s.delegationId));break;case"audio_clear":this.#Q(),this.#p=0,this.#s("listening");break;case"transcript_interim":this.#s("listening"),this.#H("user",s.text??"",!1);break;case"transcript_final":{let n=s.role==="assistant"?"assistant":"user";this.#s(n==="user"?"processing":"speaking"),this.#H(n,s.text??"",!0);break}case"audio_end":this.#n?this.#n.markStreamEnd():(this.#l=!1,this.#s("listening"));break;case"metrics":this.#de({llmMs:s.llm_ms,ttsMs:s.tts_ms,firstAudioMs:s.first_audio_ms,totalMs:s.total_ms});break;case"error":this.#I(new Error(s.error||"Voice error")),this.#s("error");break}}async#re(){let e=this.bridge?.getHistory()??[],t="";try{let s=this.config?.callContext;t=String((typeof s=="function"?await s():s)??"")}catch{}return Fe(e,t)}#J(e){let t=this.#E;if(!t)return;this.#E=null;let s=!1,n=t.then(r=>{let l=this.#e;s||!r||e!==this.#t||l?.readyState!==WebSocket.OPEN||l.send(JSON.stringify({type:"context",text:r}))});this.#j={done:n,drop:()=>s=!0}}async#oe(){let e=this.#j;if(!e)return;let t,s=await Promise.race([e.done.then(()=>!1),new Promise(n=>{t=setTimeout(()=>n(!0),De)})]);clearTimeout(t),s&&e.drop()}#Y(e,t=!1){this.#x.add(e),this.bridge?.dropDelegation?.(e,t),this.#M.get(e)?.abort()}#ae(e,t,s){let n=this.bridge,r=(l,d,a)=>{let o=this.#e;return s!==this.#t||o?.readyState!==WebSocket.OPEN||this.#x.has(e)?!1:(o.send(JSON.stringify({type:l,delegationId:e,status:d,text:a})),!0)};this.#R=this.#R.then(async()=>{if(s!==this.#t||this.#x.has(e))return;let l=await n.runDelegatedTurn(t).catch(()=>({status:"failed",text:""}));await this.#oe();let d=!!l.followUp,a=d&&this.#k.has("delegation_update");if(!r(a?"delegation_update":"delegation_result",d&&!a?"completed":l.status,l.text)||(l.status!=="failed"&&this.#L.add(e),!l.followUp))return;let c=new AbortController;this.#M.set(e,c),l.followUp({signal:c.signal,approvalTimeoutMs:this.config?.approvalTimeoutMs&&Math.min(this.config.approvalTimeoutMs,Be),readBack:a,onUpdate:u=>r("delegation_update","pending_approval",u)}).then(u=>{this.#M.delete(e),a&&u&&!c.signal.aborted&&r("delegation_result",u.status,u.text)})})}#ce(e,t){if(t!==this.#t||!this.#n||this.#$())return;let s=He(e);s.length!==0&&(this.#l||(this.#l=!0,this.#s("speaking")),this.#F(),this.#n.enqueue(s),this.#u&&this.#le(s.length))}#$(){return Date.now()<this.#p}#F(){if(this.#w||!this.#n)return;this.#w=!0;let e=this.#t;this.#n.onFinished(()=>{e===this.#t&&(this.#w=!1,this.#Z())})}#le(e){let t=Date.now();this.#b=Math.max(t,this.#b)+e/48,clearTimeout(this.#v),this.#v=setTimeout(()=>this.#Z(),this.#b-t+Le)}#Z(){this.#l=!1,this.#b=0,this.#e&&this.#e.readyState===WebSocket.OPEN&&this.#s(this.#h?"processing":"listening")}#Q(){this.#n?.flush(),this.#w=!1,this.#F(),this.#l=!1,this.#b=0,clearTimeout(this.#v)}#A(){this.#t+=1,this.#m=!1,this.#l=!1,this.#P(),this.#u=!1,this.#h=!1,this.#S=!1,this.#k=new Set;for(let e of this.#M.values())e.abort();if(this.#M.clear(),this.#x.clear(),this.#V=void 0,this.#_=!1,this.#E=null,this.#j=null,this.#R=Promise.resolve(),this.#L.clear(),this.#T=!1,this.#O.clear(),this.#D.clear(),this.#w=!1,this.#p=0,this.#b=0,clearTimeout(this.#v),this.#g=[],this.#f=0,this.#c&&(this.#c.onaudioprocess=null,this.#c.disconnect(),this.#c=null),this.#a&&(this.#a.disconnect(),this.#a=null),this.#i&&(this.#i.getTracks().forEach(e=>e.stop()),this.#i=null),this.#r&&(this.#r.close().catch(()=>{}),this.#r=null),this.#n&&(this.#n.destroy(),this.#n=null),this.#e){this.#y=!0;try{this.#e.close(1e3,"client ended call")}catch{}this.#e=null}}onResult(e){this.#z.push(e)}onError(e){this.#N.push(e)}onStatusChange(e){this.#B.push(e)}onTranscript(e){this.#q.push(e)}onMetrics(e){this.#U.push(e)}#s(e){this.#B.forEach(t=>t(e))}#I(e){this.#N.forEach(t=>t(e))}#H(e,t,s,n){this.#q.forEach(r=>r(e,t,s,n))}#de(e){this.#U.forEach(t=>t(e))}};var M=class{constructor(e={}){this.config=e;this.type="browser";this.#e=null;this.#r=[];this.#d=[];this.#i=[];this.#a=!1;this.#c=typeof window<"u"?window:void 0}#e;#r;#d;#i;#a;#c;async connect(){this.#i.forEach(e=>e("connected"))}async startListening(){try{if(this.#a)throw new Error("Already listening");if(!this.#c)throw new Error("Window object not available");let e=this.#c.SpeechRecognition||this.#c.webkitSpeechRecognition;if(!e)throw new Error("Browser speech recognition not supported");this.#e=new e,this.#e.lang=this.config?.language||"en-US",this.#e.continuous=this.config?.continuous||!1,this.#e.interimResults=!0,this.#e.onresult=t=>{let s=Array.from(t.results).map(r=>r[0]).map(r=>r.transcript).join(""),n=t.results[t.results.length-1].isFinal;this.#r.forEach(r=>r({text:s,confidence:n?.8:.5,provider:"browser"})),n&&!this.config?.continuous&&this.stopListening()},this.#e.onerror=t=>{this.#d.forEach(s=>s(new Error(t.error))),this.#i.forEach(s=>s("error"))},this.#e.onstart=()=>{this.#a=!0,this.#i.forEach(t=>t("listening"))},this.#e.onend=()=>{this.#a=!1,this.#i.forEach(t=>t("idle"))},this.#e.start()}catch(e){throw this.#d.forEach(t=>t(e)),this.#i.forEach(t=>t("error")),e}}async stopListening(){this.#e&&(this.#e.stop(),this.#e=null),this.#a=!1,this.#i.forEach(e=>e("idle"))}onResult(e){this.#r.push(e)}onError(e){this.#d.push(e)}onStatusChange(e){this.#i.push(e)}async disconnect(){await this.stopListening(),this.#i.forEach(e=>e("disconnected"))}static isSupported(){return"SpeechRecognition"in window||"webkitSpeechRecognition"in window}};function I(i){switch(i.type){case"runtype":if(!i.runtype)throw new Error("Runtype voice provider requires configuration");return new x(i.runtype);case"browser":if(!M.isSupported())throw new Error("Browser speech recognition not supported");return new M(i.browser||{});case"custom":{let e=i.custom;if(!e)throw new Error("Custom voice provider requires a `custom` provider instance or factory");let t=typeof e=="function"?e():e;if(!t||typeof t.startListening!="function")throw new Error("Custom voice provider `custom` must be a VoiceProvider (or a factory returning one)");return t}default:throw new Error(`Unknown voice provider type: ${i.type}`)}}function F(i){if(i?.type==="custom"&&i.custom)return I({type:"custom",custom:i.custom});if(i?.type==="runtype"&&i.runtype)return I({type:"runtype",runtype:i.runtype});if(M.isSupported())return I({type:"browser",browser:i?.browser||{language:"en-US"}});throw new Error("No supported voice providers available")}function se(i){try{return F(i),!0}catch{return!1}}var ie=i=>i.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,""),j=class{constructor(e){this.host=e;this.turns=new Map;this.latestId=null;this.cancelled=new Set}apply(e,t,s,n,r,l){let d=this.host;t=t.trim();let a=this.turns.get(n);if(a||(a={},this.turns.set(n,a),this.latestId=n),e==="user"){a.userFinal=s;let o=a.userId?d.find(a.userId):void 0;if(o){let c=a.userStartMs===void 0&&r!==void 0;c&&(a.userStartMs=r),d.upsert({...o,content:t,voiceProcessing:!s,...c&&this.placeBefore(this.startedAfter(r))})}else{a.userStartMs=r;let c=a.assistantId?d.find(a.assistantId):void 0;a.userId=d.inject({role:"user",content:t,streaming:!1,voiceProcessing:!s,voiceCaption:l,...this.placeBefore(this.startedAfter(r)??c)}).id}}else if(!this.cancelled.has(n)){a.assistantFinal=s;let o=a.assistantId?d.find(a.assistantId):void 0;if(o){let c=a.assistantStartMs===void 0&&r!==void 0;c&&(a.assistantStartMs=r),d.upsert({...o,content:t,streaming:!s,voiceProcessing:!s,...c&&this.placeBefore(this.startedAfter(r))})}else t&&(a.assistantStartMs=r,a.assistantId=d.inject({role:"assistant",content:t,streaming:!s,voiceProcessing:!s,voiceCaption:l,...this.placeBefore(this.startedAfter(r))}).id);s&&a.assistantId&&d.markSpoken(a.assistantId)}this.sync()}claimUserTurn(e,t=[]){let s=t[t.length-1];for(let r of t)r!==s&&(this.turns.has(r)||this.turns.set(r,{}),this.turns.get(r).claimed=!0);let n;if(s){if(n=this.turns.get(s),n||(n={},this.turns.set(s,n)),n.claimed)return null;(!n.userId||!this.host.find(n.userId))&&(n.userFinal=!0,n.userId=this.host.inject({role:"user",content:e.trim()}).id)}else{let r=ie(e),l=[...this.turns.values()].reverse().flatMap(d=>{let a=d.userId&&!d.claimed?this.host.find(d.userId):void 0;return a?[{turn:d,text:ie(a.content)}]:[]}).filter(({text:d})=>d&&r);n=(l.find(({text:d})=>d===r)??l.find(({text:d})=>d.startsWith(r)||r.startsWith(d)))?.turn}return n?(n.claimed=!0,n.userId):null}cancel(){let e=this.inFlight();if(e.length===0){let t=this.awaiting();if(!t)return;e=[t]}for(let t of e)this.cancelled.add(t);this.closeReplies(e),this.sync()}fail(e){let t=this.awaiting(),s=this.inFlight();if(!t&&s.length===0)return;for(let l of s)this.turns.get(l).assistantFinal=!0;this.closeReplies(s);let n=this.host.inject({role:"assistant",content:e,streaming:!1,voiceProcessing:!1}),r=t?this.turns.get(t):void 0;r&&(r.assistantId=n.id,r.assistantFinal=!0),this.sync()}settle(){if(this.turns.size===0)return;let e=this.pending(),t=new Set;for(let s of this.turns.values())s.userId&&t.add(s.userId),s.assistantId&&(t.add(s.assistantId),this.host.markSpoken(s.assistantId));this.turns.clear(),this.latestId=null,this.host.settle(t),e&&this.host.setStreaming(!1)}startedAfter(e){if(e===void 0)return;let t;for(let s of this.turns.values())for(let[n,r]of[[s.userId,s.userStartMs],[s.assistantId,s.assistantStartMs]])n&&r!==void 0&&r>e&&(!t||r<t.start)&&(t={start:r,id:n});return t&&this.host.find(t.id)}placeBefore(e){if(!e)return;let t=e.sequence??0,s=t-1;for(let n of this.turns.values())for(let r of[n.userId,n.assistantId]){let l=r?this.host.find(r):void 0,d=l?.sequence;l?.createdAt===e.createdAt&&d!==void 0&&d>s&&d<t&&(s=d)}return{createdAt:e.createdAt,sequence:(s+t)/2}}closeReplies(e){let t=new Set;for(let s of e){let n=this.turns.get(s)?.assistantId;n&&(t.add(n),this.host.markSpoken(n))}t.size>0&&this.host.settle(t)}inFlight(){let e=[];for(let[t,s]of this.turns)s.assistantId&&!s.assistantFinal&&!this.cancelled.has(t)&&e.push(t);return e}awaiting(){let e=this.latestId;if(!e)return null;let t=this.turns.get(e);return t?.userFinal&&!t.assistantId&&!t.claimed&&!this.cancelled.has(e)?e:null}pending(){return this.awaiting()!==null||this.inFlight().length>0}sync(){this.host.setStreaming(this.pending())}};var Ge="I need your answer in the chat before I can continue.";var ne="no|nope|never ?mind|decline(?: it| that)?|cancel(?: it| that| this)?(?: (?:the|my|that|this) (?:[a-z]+ )?(?:order|request))?|don'?t (?:do|place) (?:it|that|the (?:[a-z]+ )?order)",Ke=new RegExp(`^(?:${ne})(?: (?:${ne}))?(?: thanks| thank you)?$`),Je=i=>Ke.test(i.toLowerCase().replace(/[^a-z' ]+/g," ").replace(/\s+/g," ").trim()),re="Briefly tell the user what you're about to do and ask them to approve or decline it in the chat. Don't claim it's done.",oe=()=>new Promise(i=>setTimeout(i,50)),H=(i,e)=>i.length>e?`${i.slice(0,e-1).trimEnd()}\u2026`:i,E=i=>i.replace(/^webmcp:/,"").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/[_\-.]+/g," ").trim().toLowerCase();function z(i,e=0){if(i==null||i==="")return"";if(typeof i!="object")return String(i);if(e>2)return"";if(Array.isArray(i))return i.map(r=>z(r,e+1)).filter(Boolean).join(", ");let t=i,s=t.quantity??t.qty??t.count,n=t.name??t.item??t.product??t.title;return s!=null&&n!=null&&typeof n!="object"?`${s} ${n}`:Object.entries(t).filter(([r])=>!r.startsWith("_")).map(([r,l])=>{let d=z(l,e+1);return d&&(e?`${E(r)} ${d}`:`${E(r)}: ${d}`)}).filter(Boolean).join(e?", ":"; ")}function ae(i){let e=i.length>1?"These actions need the user's approval in the chat before they happen:":"This action needs the user's approval in the chat before it happens:",t=1e3-e.length-re.length-2,s=i.map(n=>{let r=[E(n.toolName)];n.description&&r.push(`(${H(n.description.trim(),160)})`);let l=z(n.parameters);return l&&r.push(`with ${l}`),n.reason&&r.push(`because: ${H(n.reason.trim(),160)}`),H(`- ${r.join(" ")}`,Math.floor(t/i.length)-1)});return`${e}
|
|
5
|
+
`)}function Ke(i){return i.byteLength>=44&&new DataView(i).getUint32(0,!1)===Ie?new Uint8Array(i,44):new Uint8Array(i)}function ie(i){let e=i.replace(/\/+$/,"");return/^wss?:\/\//i.test(e)?e:/^https?:\/\//i.test(e)?e.replace(/^http/i,"ws"):`${typeof window<"u"&&window.location?.protocol==="https:"?"wss:":"ws:"}//${e}`}function Je(i){return ie(i).replace(/^ws/i,"http")}function Ye(i){return typeof i!="number"||!Number.isFinite(i)?Re:Math.min(Oe,Math.max(Le,Math.round(i)))}var x=class{constructor(e){this.config=e;this.type="runtype";this.#e=null;this.#r=null;this.#d=[];this.#i=null;this.#a=null;this.#c=null;this.#f=[];this.#m=0;this.#n=null;this.#p=!1;this.#l=!1;this.#t=0;this.#y=!1;this.#M=Number.NEGATIVE_INFINITY;this.#o=null;this.#u=!1;this.#g=!1;this.#h=0;this.#b=0;this.#w=!1;this.bridge=null;this.#k=!1;this.#S=new Set;this.#T=new Map;this.#_=new Set;this.#I=null;this.#A=null;this.#N=!1;this.#D=!1;this.#q=!1;this.#P=null;this.#U=null;this.#B=Promise.resolve();this.#V=new Set;this.#E=!1;this.#j=new Set;this.#R=new Set;this.#Y=[];this.#W=[];this.#$=[];this.#F=[];this.#H=[]}#e;#r;#d;#i;#a;#c;#f;#m;#n;#p;#l;#t;#y;#M;#o;#u;#g;#h;#b;#v;#w;#k;#S;#T;#_;#O;#I;#A;#J;#N;#D;#q;#P;#U;#B;#V;#E;#j;#R;#Y;#W;#$;#F;#H;async connect(){}setSessionBridge(e){this.bridge=e}prewarm(){if(this.#p||this.#o)return;let e=this.config?.agentId,t=this.config?.clientToken,s=this.config?.host;if(!e||!t||!s)return;let n=Date.now();if(!(n-this.#M<Pe)){this.#M=n;try{this.config?.prewarmMode==="attach"?this.#oe(s,e,t):this.#re(s,e,t)}catch{}}}#re(e,t,s){if(typeof fetch!="function")return;let n=`${Je(e)}/v1/client/agents/${encodeURIComponent(t)}/voice/prewarm`;fetch(n,{method:"POST",headers:{Authorization:`Bearer ${s}`},keepalive:!0}).catch(()=>{})}#oe(e,t,s){let n=new URLSearchParams,r=this.config?.attachIdleMs,c=Ye(r);r!==void 0&&n.set("attachIdleMs",String(c));let d=new WebSocket(this.#Q(e,t,n),["runtype.bearer","runtype.attach",s]);d.binaryType="arraybuffer";let a=()=>{},o=new Promise(u=>{a=u}),l={ws:d,state:"connecting",ready:o,settle:a,openedAt:0,idleTimer:void 0};this.#o=l,d.onopen=()=>{this.#o===l&&(l.state=d.protocol==="runtype.attach"?"attached":"live",l.openedAt=Date.now(),this.#Z(l,c),l.state==="attached"&&d.send('{"type":"ping"}'),l.settle())},d.onmessage=u=>{if(this.#o!==l||typeof u.data!="string")return;let p;try{p=JSON.parse(u.data)}catch{return}p.type==="attached"&&typeof p.idleMs=="number"&&this.#Z(l,p.idleMs-(Date.now()-l.openedAt))},d.onerror=()=>{},d.onclose=()=>{this.#o===l&&this.#L()}}#Z(e,t){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>{this.#o===e&&this.#L()},Math.max(0,t))}#L(){let e=this.#o;if(!e)return;this.#o=null,clearTimeout(e.idleTimer);let{ws:t}=e;if(t.onopen=null,t.onmessage=null,t.onerror=null,t.onclose=null,e.settle(),t.readyState===WebSocket.CONNECTING||t.readyState===WebSocket.OPEN)try{t.close(1e3,"prewarm released")}catch{}}async#ae(){let e=this.#o;if(!e)return null;if(e.state==="connecting"){let t;await Promise.race([e.ready,new Promise(s=>{t=setTimeout(s,je)})]),clearTimeout(t)}return this.#o!==e?null:e.state==="connecting"||e.ws.readyState!==WebSocket.OPEN?(this.#L(),null):(this.#o=null,clearTimeout(e.idleTimer),{ws:e.ws,live:e.state==="live"})}#Q(e,t,s){let n=["partial_transcript","context"];this.bridge&&this.config?.clientDelegation!==!1&&n.push("client_delegation","delegation_update","delegation_read_back"),s&&n.unshift("attach");let r=new URLSearchParams({voiceProtocol:Be,clientVersion:`persona/${ee}`,voiceCapabilities:Ne,clientCapabilities:n.join(",")});return s?.forEach((c,d)=>r.set(d,c)),`${ie(e)}/ws/agents/${encodeURIComponent(t)}/voice?${r}`}async startListening(){if(this.#p)return;let e=this.#D;e||(this.#N=!1,this.#A=null),this.#D=!1;let t=this.config?.agentId,s=this.config?.clientToken,n=this.config?.host;if(!t)throw new Error("Runtype voice requires an agentId");if(!s)throw new Error("Runtype voice requires a clientToken");if(!n)throw new Error("Runtype voice requires a host (or widget apiUrl)");let r=++this.#t;this.#y=!1,this.#p=!0;try{let c=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:F,channelCount:1,echoCancellation:!0}});if(r!==this.#t){c.getTracks().forEach(p=>p.stop());return}this.#i=c;let d=window.AudioContext||window.webkitAudioContext,a=new d({sampleRate:F});if(this.#r=a,a.state==="suspended"){if(await Promise.race([a.resume().catch(()=>{}),new Promise(p=>setTimeout(p,e?500:Ve))]),r!==this.#t)return;if(a.state!=="running")throw e?new Error(this.#A=`${j} Tap the mic to reconnect.`):new Error("Audio blocked until a tap")}let o=this.config?.createPlaybackEngine?await this.config.createPlaybackEngine():new V(Te);if(r!==this.#t){o.destroy(),c.getTracks().forEach(p=>p.stop()),a.close().catch(()=>{});return}this.#n=o,this.#G(),this.#le(a,c,r);let l=await this.#ae();if(r!==this.#t){l?.ws.close(1e3,"client ended call");return}if(l){let{ws:p}=l;this.#e=p,this.#ee(p,r),l.live||p.send('{"type":"start"}'),this.#z(p),this.#s("listening");return}let u=new WebSocket(this.#Q(n,t),["runtype.bearer",s]);u.binaryType="arraybuffer",this.#e=u,u.onopen=()=>{r===this.#t&&(this.#z(u),this.#s("listening"))},this.#ee(u,r)}catch(c){throw this.#C(),this.#x(c),this.#s("error"),c}}#ee(e,t){e.onmessage=s=>this.#de(s,t),e.onerror=()=>{t!==this.#t||this.#I||(this.#x(new Error("Voice connection failed")),this.#s("error"),this.#C())},e.onclose=s=>{if(this.#y){this.#y=!1;return}if(t!==this.#t)return;let n=this.#I??(s.code===4408?{reason:"idle_timeout"}:null);if(!n){if(s.code!==1e3){let r=s.code?` (code ${s.code})`:"";this.#x(new Error(`Voice connection closed${r}`)),this.#s("error")}else this.#s("idle");this.#C();return}this.#ce(n.reason,n.message)}}#ce(e,t){let s=te.includes(e)&&!this.#N;if(this.#C(),s){this.#N=!0,this.#p=!0,this.#A=e==="provider_error"?`${j} Reconnecting\u2026`:"Reconnecting\u2026",this.#J=setTimeout(()=>{this.#p=!1,this.#D=!0,this.startListening().catch(()=>{})},1e3+Math.random()*1e3),this.#s("idle");return}if(te.includes(e))return this.#A=j,this.#x(new Error(j)),this.#s("error");if(e==="error")return this.#s("error");this.#A=e==="quota"&&t||Fe.get(e)||null,this.#s("idle")}takeNotice(){let e=this.#A;return this.#A=null,e}getDisclosure(){let e=this.config?.disclosureText;return this.#p&&this.#u&&e!==!1?e||$e:null}async stopListening(){this.#C(),this.#s("idle")}async disconnect(){this.#C(),this.#s("disconnected"),this.#Y=[],this.#W=[],this.#$=[],this.#F=[],this.#H=[]}stopPlayback(){this.#ne();let e=this.#e;e&&e.readyState===WebSocket.OPEN&&(this.#u&&(this.#h=Date.now()+qe,e.send('{"type":"cancel"}')),this.#s("listening"))}getInterruptionMode(){return"barge-in"}isBargeInActive(){return this.#p}onLevel(e){this.#d.push(e)}async deactivateBargeIn(){this.#C(),this.#s("idle")}#le(e,t,s){let n=e.createMediaStreamSource(t);this.#a=n;let r=e.createScriptProcessor(Ee,1,1);this.#c=r,r.onaudioprocess=c=>{if(s!==this.#t)return;let d=this.#e,a=d?.readyState===WebSocket.OPEN;if(d&&!a&&d.readyState!==WebSocket.CONNECTING)return;let o=c.inputBuffer.getChannelData(0),l=new Int16Array(o.length),u=0;for(let p=0;p<o.length;p++){let m=Math.max(-1,Math.min(1,o[p]));u+=m*m,l[p]=m<0?m*32768:m*32767}if(d&&a)this.#z(d),d.send(l.buffer);else for(this.#f.push(l.buffer),this.#m+=l.byteLength;this.#m>xe;)this.#m-=this.#f.shift().byteLength;if(this.#d.length>0){let p=Math.sqrt(u/o.length),m=Math.max(0,Math.min(1,p*_e));for(let h of this.#d)h(m)}},n.connect(r),r.connect(e.destination)}#z(e){for(let t of this.#f)e.send(t);this.#f=[],this.#m=0}#de(e,t){if(t!==this.#t)return;if(e.data instanceof ArrayBuffer){this.#ge(e.data,t);return}let s;try{s=JSON.parse(e.data)}catch{return}switch(s.type){case"session_config":s.speechMode&&(this.#u=s.speechMode==="speech_to_speech",this.#n?.setContinuousMode?.(this.#u)),Array.isArray(s.capabilities)&&(this.#S=new Set(s.capabilities)),typeof s.callId=="string"&&(this.#O=s.callId),this.#k=this.#u&&this.#S.has("client_delegation")&&!!this.bridge,this.#u&&!this.#l&&this.#s("listening"),this.#S.has("context")&&!this.#q&&(this.#q=!0,this.#P=this.#ue());break;case"transcript_update":{let n=s.role==="assistant"?"assistant":"user",r=s.utteranceId??s.turnId;if(!r||n==="assistant"&&this.#X())break;let c=String(r);if(n==="user")s.final===!0&&this.#te(t),this.#E=!1;else{if(this.#S.has("delegation_read_back")){let d=s.delegationId;typeof d=="string"&&this.#V.has(d)&&!this.#j.has(c)&&this.#R.add(c)}else this.#E&&!this.#j.has(c)&&(this.#R.add(c),this.#E=!1);if(this.#j.add(c),this.#R.has(c))break}this.#K(n,s.text??"",s.final===!0,{turnId:c,...typeof s.startMs=="number"&&{startMs:s.startMs},...typeof s.endMs=="number"&&{endMs:s.endMs},...this.#k&&{caption:!0}});break}case"delegation_started":case"delegation_completed":{let n=String(s.delegationId??s.turnId);if(s.type==="delegation_started"){this.#te(t);let r=s.input;this.#k&&r&&this.#he(n,{delegationId:n,userText:String(r.text??""),userUtteranceIds:Array.isArray(r.userUtteranceIds)?r.userUtteranceIds.filter(c=>typeof c=="string"):[],messages:Array.isArray(r.messages)?r.messages:[]},t)}else s.speak!==!1&&this.#V.has(n)&&(this.#E=!0);this.#g=s.type==="delegation_started",!this.#l&&!this.#X()&&this.#s(this.#g?"processing":"listening");break}case"delegation_cancelled":this.#se(String(s.delegationId),s.reason!=="session_ending"&&s.reason!=="provider_cancelled");break;case"warning":console.warn(`[Persona voice] ${s.code}: ${s.message??""}`,this.#O??""),s.delegationId&&(s.code==="UNKNOWN_DELEGATION"||s.code==="LATE_RESULT_LIMIT")&&this.#se(String(s.delegationId));break;case"audio_clear":this.#ne(),this.#h=0,this.#s("listening");break;case"transcript_interim":this.#s("listening"),this.#K("user",s.text??"",!1);break;case"transcript_final":{let n=s.role==="assistant"?"assistant":"user";this.#s(n==="user"?"processing":"speaking"),this.#K(n,s.text??"",!0);break}case"audio_end":this.#n?this.#n.markStreamEnd():(this.#l=!1,this.#s("listening"));break;case"metrics":this.#me({llmMs:s.llm_ms,ttsMs:s.tts_ms,firstAudioMs:s.first_audio_ms,totalMs:s.total_ms});break;case"error":this.#x(new Error(s.error||"Voice error")),this.#s("error");break;case"session_end":this.#I={reason:String(s.reason),...typeof s.message=="string"&&{message:s.message}};break}}async#ue(){let e=this.bridge?.getHistory()??[],t="";try{let s=this.config?.callContext;t=String((typeof s=="function"?await s():s)??"")}catch{}return Ge(e,t)}#te(e){let t=this.#P;if(!t)return;this.#P=null;let s=!1,n=t.then(r=>{let c=this.#e;s||!r||e!==this.#t||c?.readyState!==WebSocket.OPEN||c.send(JSON.stringify({type:"context",text:r}))});this.#U={done:n,drop:()=>s=!0}}async#pe(){let e=this.#U;if(!e)return;let t,s=await Promise.race([e.done.then(()=>!1),new Promise(n=>{t=setTimeout(()=>n(!0),Ue)})]);clearTimeout(t),s&&e.drop()}#se(e,t=!1){this.#_.add(e),this.bridge?.dropDelegation?.(e,t),this.#T.get(e)?.abort()}#he(e,t,s){let n=this.bridge,r=(c,d,a)=>{let o=this.#e;return s!==this.#t||o?.readyState!==WebSocket.OPEN||this.#_.has(e)?!1:(o.send(JSON.stringify({type:c,delegationId:e,status:d,text:a})),!0)};this.#B=this.#B.then(async()=>{if(s!==this.#t||this.#_.has(e))return;let c=await n.runDelegatedTurn(t).catch(()=>({status:"failed",text:""}));await this.#pe();let d=!!c.followUp,a=d&&this.#S.has("delegation_update");if(!r(a?"delegation_update":"delegation_result",d&&!a?"completed":c.status,c.text)||(c.status!=="failed"&&c.inChat!==!1&&this.#V.add(e),!c.followUp))return;let l=new AbortController;this.#T.set(e,l),c.followUp({signal:l.signal,approvalTimeoutMs:this.config?.approvalTimeoutMs&&Math.min(this.config.approvalTimeoutMs,We),readBack:a,onUpdate:u=>r("delegation_update","pending_approval",u)}).then(u=>{this.#T.delete(e),a&&u&&!l.signal.aborted&&r("delegation_result",u.status,u.text)})})}#ge(e,t){if(t!==this.#t||!this.#n||this.#X())return;let s=Ke(e);s.length!==0&&(this.#l||(this.#l=!0,this.#s("speaking")),this.#G(),this.#n.enqueue(s),this.#u&&this.#fe(s.length))}#X(){return Date.now()<this.#h}#G(){if(this.#w||!this.#n)return;this.#w=!0;let e=this.#t;this.#n.onFinished(()=>{e===this.#t&&(this.#w=!1,this.#ie())})}#fe(e){let t=Date.now();this.#b=Math.max(t,this.#b)+e/48,clearTimeout(this.#v),this.#v=setTimeout(()=>this.#ie(),this.#b-t+De)}#ie(){this.#l=!1,this.#b=0,this.#e&&this.#e.readyState===WebSocket.OPEN&&this.#s(this.#g?"processing":"listening")}#ne(){this.#n?.flush(),this.#w=!1,this.#G(),this.#l=!1,this.#b=0,clearTimeout(this.#v)}#C(){this.#t+=1,this.#p=!1,this.#l=!1,this.#L(),this.#u=!1,this.#g=!1,this.#k=!1,this.#S=new Set;for(let e of this.#T.values())e.abort();if(this.#T.clear(),this.#_.clear(),this.#O=void 0,this.#I=null,clearTimeout(this.#J),this.#q=!1,this.#P=null,this.#U=null,this.#B=Promise.resolve(),this.#V.clear(),this.#E=!1,this.#j.clear(),this.#R.clear(),this.#w=!1,this.#h=0,this.#b=0,clearTimeout(this.#v),this.#f=[],this.#m=0,this.#c&&(this.#c.onaudioprocess=null,this.#c.disconnect(),this.#c=null),this.#a&&(this.#a.disconnect(),this.#a=null),this.#i&&(this.#i.getTracks().forEach(e=>e.stop()),this.#i=null),this.#r&&(this.#r.close().catch(()=>{}),this.#r=null),this.#n&&(this.#n.destroy(),this.#n=null),this.#e){this.#y=!0;try{this.#e.close(1e3,"client ended call")}catch{}this.#e=null}}onResult(e){this.#Y.push(e)}onError(e){this.#W.push(e)}onStatusChange(e){this.#$.push(e)}onTranscript(e){this.#F.push(e)}onMetrics(e){this.#H.push(e)}#s(e){this.#$.forEach(t=>t(e))}#x(e){this.#W.forEach(t=>t(e))}#K(e,t,s,n){this.#F.forEach(r=>r(e,t,s,n))}#me(e){this.#H.forEach(t=>t(e))}};var T=class{constructor(e={}){this.config=e;this.type="browser";this.#e=null;this.#r=[];this.#d=[];this.#i=[];this.#a=!1;this.#c=typeof window<"u"?window:void 0}#e;#r;#d;#i;#a;#c;async connect(){this.#i.forEach(e=>e("connected"))}async startListening(){try{if(this.#a)throw new Error("Already listening");if(!this.#c)throw new Error("Window object not available");let e=this.#c.SpeechRecognition||this.#c.webkitSpeechRecognition;if(!e)throw new Error("Browser speech recognition not supported");this.#e=new e,this.#e.lang=this.config?.language||"en-US",this.#e.continuous=this.config?.continuous||!1,this.#e.interimResults=!0,this.#e.onresult=t=>{let s=Array.from(t.results).map(r=>r[0]).map(r=>r.transcript).join(""),n=t.results[t.results.length-1].isFinal;this.#r.forEach(r=>r({text:s,confidence:n?.8:.5,provider:"browser"})),n&&!this.config?.continuous&&this.stopListening()},this.#e.onerror=t=>{this.#d.forEach(s=>s(new Error(t.error))),this.#i.forEach(s=>s("error"))},this.#e.onstart=()=>{this.#a=!0,this.#i.forEach(t=>t("listening"))},this.#e.onend=()=>{this.#a=!1,this.#i.forEach(t=>t("idle"))},this.#e.start()}catch(e){throw this.#d.forEach(t=>t(e)),this.#i.forEach(t=>t("error")),e}}async stopListening(){this.#e&&(this.#e.stop(),this.#e=null),this.#a=!1,this.#i.forEach(e=>e("idle"))}onResult(e){this.#r.push(e)}onError(e){this.#d.push(e)}onStatusChange(e){this.#i.push(e)}async disconnect(){await this.stopListening(),this.#i.forEach(e=>e("disconnected"))}static isSupported(){return"SpeechRecognition"in window||"webkitSpeechRecognition"in window}};function I(i){switch(i.type){case"runtype":if(!i.runtype)throw new Error("Runtype voice provider requires configuration");return new x(i.runtype);case"browser":if(!T.isSupported())throw new Error("Browser speech recognition not supported");return new T(i.browser||{});case"custom":{let e=i.custom;if(!e)throw new Error("Custom voice provider requires a `custom` provider instance or factory");let t=typeof e=="function"?e():e;if(!t||typeof t.startListening!="function")throw new Error("Custom voice provider `custom` must be a VoiceProvider (or a factory returning one)");return t}default:throw new Error(`Unknown voice provider type: ${i.type}`)}}function H(i){if(i?.type==="custom"&&i.custom)return I({type:"custom",custom:i.custom});if(i?.type==="runtype"&&i.runtype)return I({type:"runtype",runtype:i.runtype});if(T.isSupported())return I({type:"browser",browser:i?.browser||{language:"en-US"}});throw new Error("No supported voice providers available")}function ne(i){try{return H(i),!0}catch{return!1}}var re=i=>i.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,""),R=class{constructor(e){this.host=e;this.turns=new Map;this.latestId=null;this.cancelled=new Set}apply(e,t,s,n,r,c){let d=this.host;t=t.trim();let a=this.turns.get(n);if(a||(a={},this.turns.set(n,a),this.latestId=n),e==="user"){a.userFinal=s;let o=a.userId?d.find(a.userId):void 0;if(o){let l=a.userStartMs===void 0&&r!==void 0;l&&(a.userStartMs=r),d.upsert({...o,content:t,voiceProcessing:!s,...l&&this.placeBefore(this.startedAfter(r))})}else{a.userStartMs=r;let l=a.assistantId?d.find(a.assistantId):void 0;a.userId=d.inject({role:"user",content:t,streaming:!1,voiceProcessing:!s,voiceCaption:c,...this.placeBefore(this.startedAfter(r)??l)}).id}}else if(!this.cancelled.has(n)){a.assistantFinal=s;let o=a.assistantId?d.find(a.assistantId):void 0;if(o){let l=a.assistantStartMs===void 0&&r!==void 0;l&&(a.assistantStartMs=r),d.upsert({...o,content:t,streaming:!s,voiceProcessing:!s,...l&&this.placeBefore(this.startedAfter(r))})}else t&&(a.assistantStartMs=r,a.assistantId=d.inject({role:"assistant",content:t,streaming:!s,voiceProcessing:!s,voiceCaption:c,...this.placeBefore(this.startedAfter(r))}).id);s&&a.assistantId&&d.markSpoken(a.assistantId)}this.sync()}claimUserTurn(e,t=[]){let s=t[t.length-1];for(let r of t)r!==s&&(this.turns.has(r)||this.turns.set(r,{}),this.turns.get(r).claimed=!0);let n;if(s){if(n=this.turns.get(s),n||(n={},this.turns.set(s,n)),n.claimed)return null;(!n.userId||!this.host.find(n.userId))&&(n.userFinal=!0,n.userId=this.host.inject({role:"user",content:e.trim()}).id)}else{let r=re(e),c=[...this.turns.values()].reverse().flatMap(d=>{let a=d.userId&&!d.claimed?this.host.find(d.userId):void 0;return a?[{turn:d,text:re(a.content)}]:[]}).filter(({text:d})=>d&&r);n=(c.find(({text:d})=>d===r)??c.find(({text:d})=>d.startsWith(r)||r.startsWith(d)))?.turn}return n?(n.claimed=!0,n.userId):null}cancel(){let e=this.inFlight();if(e.length===0){let t=this.awaiting();if(!t)return;e=[t]}for(let t of e)this.cancelled.add(t);this.closeReplies(e),this.sync()}fail(e){let t=this.awaiting(),s=this.inFlight();if(!t&&s.length===0)return;for(let c of s)this.turns.get(c).assistantFinal=!0;this.closeReplies(s);let n=this.host.inject({role:"assistant",content:e,streaming:!1,voiceProcessing:!1}),r=t?this.turns.get(t):void 0;r&&(r.assistantId=n.id,r.assistantFinal=!0),this.sync()}settle(){if(this.turns.size===0)return;let e=this.pending(),t=new Set;for(let s of this.turns.values())s.userId&&t.add(s.userId),s.assistantId&&(t.add(s.assistantId),this.host.markSpoken(s.assistantId));this.turns.clear(),this.latestId=null,this.host.settle(t),e&&this.host.setStreaming(!1)}startedAfter(e){if(e===void 0)return;let t;for(let s of this.turns.values())for(let[n,r]of[[s.userId,s.userStartMs],[s.assistantId,s.assistantStartMs]])n&&r!==void 0&&r>e&&(!t||r<t.start)&&(t={start:r,id:n});return t&&this.host.find(t.id)}placeBefore(e){if(!e)return;let t=e.sequence??0,s=t-1;for(let n of this.turns.values())for(let r of[n.userId,n.assistantId]){let c=r?this.host.find(r):void 0,d=c?.sequence;c?.createdAt===e.createdAt&&d!==void 0&&d>s&&d<t&&(s=d)}return{createdAt:e.createdAt,sequence:(s+t)/2}}closeReplies(e){let t=new Set;for(let s of e){let n=this.turns.get(s)?.assistantId;n&&(t.add(n),this.host.markSpoken(n))}t.size>0&&this.host.settle(t)}inFlight(){let e=[];for(let[t,s]of this.turns)s.assistantId&&!s.assistantFinal&&!this.cancelled.has(t)&&e.push(t);return e}awaiting(){let e=this.latestId;if(!e)return null;let t=this.turns.get(e);return t?.userFinal&&!t.assistantId&&!t.claimed&&!this.cancelled.has(e)?e:null}pending(){return this.awaiting()!==null||this.inFlight().length>0}sync(){this.host.setStreaming(this.pending())}};var Ze="I need your answer in the chat before I can continue.";var oe="no|nope|never ?mind|decline(?: it| that)?|cancel(?: it| that| this)?(?: (?:the|my|that|this) (?:[a-z]+ )?(?:order|request))?|don'?t (?:do|place) (?:it|that|the (?:[a-z]+ )?order)",Qe=new RegExp(`^(?:${oe})(?: (?:${oe}))?(?: thanks| thank you)?$`),et=i=>Qe.test(i.toLowerCase().replace(/[^a-z' ]+/g," ").replace(/\s+/g," ").trim()),ae="Briefly tell the user what you're about to do and ask them to approve or decline it in the chat. Don't claim it's done.",ce=()=>new Promise(i=>setTimeout(i,50)),z=(i,e)=>i.length>e?`${i.slice(0,e-1).trimEnd()}\u2026`:i,_=i=>i.replace(/^webmcp:/,"").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/[_\-.]+/g," ").trim().toLowerCase();function X(i,e=0){if(i==null||i==="")return"";if(typeof i!="object")return String(i);if(e>2)return"";if(Array.isArray(i))return i.map(r=>X(r,e+1)).filter(Boolean).join(", ");let t=i,s=t.quantity??t.qty??t.count,n=t.name??t.item??t.product??t.title;return s!=null&&n!=null&&typeof n!="object"?`${s} ${n}`:Object.entries(t).filter(([r])=>!r.startsWith("_")).map(([r,c])=>{let d=X(c,e+1);return d&&(e?`${_(r)} ${d}`:`${_(r)}: ${d}`)}).filter(Boolean).join(e?", ":"; ")}function le(i){let e=i.length>1?"These actions need the user's approval in the chat before they happen:":"This action needs the user's approval in the chat before it happens:",t=1e3-e.length-ae.length-2,s=i.map(n=>{let r=[_(n.toolName)];n.description&&r.push(`(${z(n.description.trim(),160)})`);let c=X(n.parameters);return c&&r.push(`with ${c}`),n.reason&&r.push(`because: ${z(n.reason.trim(),160)}`),z(`- ${r.join(" ")}`,Math.floor(t/i.length)-1)});return`${e}
|
|
6
6
|
${s.join(`
|
|
7
7
|
`)}
|
|
8
8
|
|
|
9
|
-
${
|
|
9
|
+
${ae}`}var L=i=>i.variant==="approval"&&i.approval?.status==="pending";function de(i){let e=null,t=null,s=()=>i.track(e??t),n=[],r=new Map,c=new Map,d=(h,f)=>{r.set(h,[...r.get(h)??[],f]),r.size>32&&r.delete(r.keys().next().value)},a=h=>i.messages().find(f=>f.id===h),o=h=>h.approvals.filter(f=>a(f)?.approval?.status==="pending"),l=h=>_(a(h)?.approval?.toolName??""),u=(h,f,w)=>{h.outcome={status:f,text:w};for(let y of o(h))i.decide(y)},p=h=>h.flatMap(f=>i.messages().find(w=>w.id===f)??[]).filter(f=>!f.variant&&f.content.trim()).map(f=>f.content.trim()).join(`
|
|
10
10
|
|
|
11
|
-
`),
|
|
11
|
+
`),m=async h=>{do await ce();while(i.busy()&&!(h&&(i.parked()||h.failed)))};return{getHistory:()=>{let h=i.messages().filter(y=>(y.role==="user"||y.role==="assistant")&&!y.variant&&!y.voiceProcessing&&!y.streaming&&y.content),f=!1,w=[];for(let y=h.length-1;y>=0;y-=1){let k=h[y];if(k.role==="user")f=!1;else if(!k.voiceCaption)f=!0;else if(f)continue;w.unshift({role:k.role,content:k.content})}return w},dropDelegation(h,f){c.set(h,!!f),c.size>32&&c.delete(c.keys().next().value);let w=f&&n.find(y=>y.delegationId===h);w&&!w.outcome&&u(w,"timeout","");for(let y of r.get(h)??[])y.dropped=!0,y.ids.length&&i.unspoken(y.ids)},async runDelegatedTurn({delegationId:h,userText:f,userUtteranceIds:w}){let y=n.filter(g=>o(g).length),k=y.flatMap(o);if(k.length===1&&et(f)){let g=l(k[0]);return u(y[0],"denied",""),{status:"denied",text:`Okay, I cancelled the ${g} request. Nothing was done.`,inChat:!1}}let G=i.parked()&&i.messages().every(g=>!L(g)||k.includes(g.id));i.busy()&&!G&&await m();let he=new Set(i.messages().map(g=>g.id)),O=()=>i.messages().filter(g=>!he.has(g.id)&&g.variant==="approval"),A={ids:[],failed:!1};d(h,A),e=A,s();try{await i.send(f,i.claim(f,w)??void 0),await m(A)}catch{A.failed=!0}finally{e=null,s()}let ge=A.ids.flatMap(g=>i.messages().find(v=>v.id===g)??[]),E=p(A.ids),P=A.failed?[]:O().filter(L),fe=new Set(P.map(g=>_(g.approval.toolName)));for(let g of y){if(g.outcome)continue;for(let S of o(g).filter(N=>fe.has(l(N))))g.replaced.add(S),i.decide(S);let v=l(g.approvals[0]);g.approvals.every(S=>g.replaced.has(S))?g.outcome={status:"cancelled",text:`The earlier ${v} request was replaced by the new one; it was not done.`}:G&&g.approvals.every(S=>a(S)?.approval?.status==="denied")&&(g.outcome={status:"cancelled",text:`The earlier ${v} request was replaced by the new one; it was not done.`})}if(P.length){let g=new Set(P.map(S=>S.id)),v={delegationId:h,approvals:[...g],at:Date.now(),replaced:new Set};return n.push(v),c.get(h)&&u(v,"timeout",""),E=`${E}
|
|
12
12
|
|
|
13
|
-
${
|
|
13
|
+
${le(P.map(S=>S.approval))}`.trim(),{status:"pending_approval",text:E,followUp:async({signal:S,approvalTimeoutMs:N=3e5,readBack:K=!0,onUpdate:me})=>{let C={ids:[],failed:!1};r.delete(h),d(h,C);let J=()=>O().filter(b=>g.has(b.id)||C.ids.includes(b.id)),ye=()=>O().filter(b=>L(b)&&!g.has(b.id)&&!n.some(M=>M.approvals.includes(b.id))&&(C.ids.includes(b.id)||b.approval?.toolType==="webmcp"&&t===C)),Y=()=>{t=C,s()};K&&Y();try{for(;!S.aborted&&!v.outcome&&(e||i.busy()||J().some(L));){K&&t!==C&&!o(v).length&&Y();let b=ye();if(b.length){for(let M of b)g.add(M.id),v.approvals.push(M.id);v.at=Date.now(),me?.(le(b.map(M=>M.approval)))}if(Date.now()-v.at>=N&&o(v).length&&(!i.busy()||i.parked())){u(v,"timeout",`That ${l(v.approvals[0])} request expired, so nothing was done.`);break}await ce()}}finally{t===C&&(t=null,s()),n.splice(n.indexOf(v),1)}if(S.aborted)return null;if(v.outcome)return v.outcome;if(C.failed)return{status:"failed",text:`The ${l(v.approvals[0])} request didn't complete.`};let Z=J(),D=b=>Z.filter(b).map(M=>_(M.approval.toolName)).join(", "),q=Z.some(b=>b.approval?.status==="approved"),U=D(b=>b.approval?.status==="denied"&&!v.replaced.has(b.id)),B=D(b=>v.replaced.has(b.id)),W=D(b=>b.approval?.status==="timeout"),be=[q?p(C.ids):"",U&&`The user declined the ${U} request in the chat, so ${q?"that part was not done":"nothing was done"}.`,B&&`The earlier ${B} request was replaced by the new one; it was not done.`,W&&`The ${W} request timed out, so it was not done.`].filter(Boolean).join(`
|
|
14
14
|
|
|
15
|
-
`);return{status:
|
|
15
|
+
`);return{status:q?"completed":U?"denied":B?"cancelled":W?"timeout":"completed",text:be}}}}return!A.failed&&i.parked()||ge.some(g=>g.agentMetadata?.awaitingLocalTool&&!g.agentMetadata.askUserQuestionAnswered&&!g.toolCall?.name?.startsWith("webmcp:"))?{status:A.failed?"failed":"completed",text:`${E}
|
|
16
16
|
|
|
17
|
-
${
|
|
17
|
+
${Ze}`.trim()}:{status:!A.failed&&E?"completed":"failed",text:E}}}}var ue=(i,e,t,s)=>{let n=i.session;try{i.keyed=t?new t({find:o=>n.messages.find(l=>l.id===o),inject:o=>n.injectMessage(o),upsert:o=>n.upsertMessage(o),settle:o=>{n.messages=n.messages.map(l=>o.has(l.id)?{...l,streaming:!1,voiceProcessing:!1}:l),n.callbacks.onMessagesChanged([...n.messages])},setStreaming:o=>{(o||!i.busy())&&i.setStreaming(o)},markSpoken:o=>{n.ttsSpokenMessageIds.add(o)}}):null,s&&e.setSessionBridge&&e.setSessionBridge(s({messages:()=>n.messages,busy:()=>i.busy(),parked:()=>n.webMcpApprovalResolvers.size>0,claim:(o,l)=>i.keyed?.claimUserTurn(o,l)??null,send:(o,l)=>n.sendMessage(o,{viaVoice:!0,voiceTurn:{userMessageId:l}}),track:o=>{i.setDelegation(o)},unspoken:o=>{for(let l of o)n.ttsSpokenMessageIds.delete(l);n.streaming||n.speakLatestAssistantMessage(o)},decide:o=>{if(n.webMcpApprovalResolvers.has(o))return n.resolveWebMcpApproval(o,"denied");let l=n.messages.find(u=>u.id===o)?.approval;l?.status==="pending"&&n.resolveApproval(l,"denied")}}));let r=i.generation(),c=()=>i.provider()===e&&r===i.generation(),a=(n.config.voiceRecognition??{}).processingErrorText??"Voice processing failed. Please try again.";e.onResult(o=>{c()&&o.provider!=="runtype"&&o.text&&o.text.trim()&&n.sendMessage(o.text,{viaVoice:!0})}),e.onTranscript&&e.onTranscript((o,l,u,p)=>{if(c()){if(p?.turnId){i.keyed?.apply(o,l,u,p.turnId,p.startMs,p.caption);return}if(o==="user"){if(i.pendingUser)n.upsertMessage({id:i.pendingUser,role:"user",content:l,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!u});else{let m=n.injectMessage({role:"user",content:l,streaming:!1,voiceProcessing:!u});i.pendingUser=m.id}if(u){i.turns().start(p?.turnId),i.pendingUser=null;let m=n.injectMessage({role:"assistant",content:"",streaming:!0,voiceProcessing:!0});i.pendingAssistant=m.id,i.setStreaming(!0)}}else{if(!i.turns().accepts(p?.turnId))return;if(i.pendingAssistant)n.upsertMessage({id:i.pendingAssistant,role:"assistant",content:l,createdAt:new Date().toISOString(),streaming:!u,voiceProcessing:!u});else{let m=n.injectMessage({role:"assistant",content:l,streaming:!u,voiceProcessing:!u});i.pendingAssistant=m.id}u&&(i.pendingAssistant&&n.ttsSpokenMessageIds.add(i.pendingAssistant),i.setStreaming(!1),i.pendingAssistant=null)}}}),e.onLevel&&e.onLevel(o=>{c()&&i.setLevel(Number.isFinite(o)?Math.max(0,Math.min(1,o)):0)}),e.onMetrics&&e.onMetrics(o=>{c()&&n.config.voiceRecognition?.onMetrics?.(o)}),e.onError(o=>{c()&&(console.error("Voice error:",o),i.pendingAssistant&&(n.upsertMessage({id:i.pendingAssistant,role:"assistant",content:a,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!1}),i.setStreaming(!1),i.pendingUser=null,i.pendingAssistant=null),i.keyed?.fail(a))}),e.onStatusChange(o=>{c()&&(i.setStatus(o),(o==="listening"||o==="idle"||o==="disconnected")&&i.settlePending(o!=="listening"),(o==="idle"||o==="disconnected")&&i.keyed?.settle(),n.callbacks.onVoiceStatusChanged?.(o))}),e.connect()}catch(r){console.error("Failed to setup voice:",r)}};var pe=i=>{let e=a=>{if(i.original)return;let o=i.config().voiceRecognition??{};i.original={backgroundColor:a.style.backgroundColor,color:a.style.color,borderColor:a.style.borderColor,iconName:o.iconName??"mic",iconSize:parseFloat(o.iconSize??"")||i.iconFallbackPx}},t=(a,o,l)=>{let u=a.querySelector("svg");u&&u.remove();let p=i.original?.iconSize??(parseFloat(i.config().voiceRecognition?.iconSize??"")||i.iconFallbackPx),m=i.renderIcon(o,p,l,1.5);m&&a.appendChild(m)},s=a=>{a.classList.remove("persona-voice-recording","persona-voice-processing","persona-voice-speaking")};return{recording:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},l=o.recordingBackgroundColor,u=o.recordingIconColor,p=o.recordingBorderColor;if(s(a),a.classList.add("persona-voice-recording"),i.setMicState("recording"),a.style.backgroundColor=l??"var(--persona-voice-recording-bg, #ef4444)",a.style.color=u??"var(--persona-voice-recording-indicator, #ffffff)",u){let m=a.querySelector("svg");m&&m.setAttribute("stroke",u)}p&&(a.style.borderColor=p),a.setAttribute("aria-label","Stop voice recognition")},processing:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},l=i.session().getVoiceInterruptionMode(),u=i.original,p=o.processingIconName??"loader",m=o.processingIconColor??u?.color??"",h=o.processingBackgroundColor??u?.backgroundColor??"",f=o.processingBorderColor??u?.borderColor??"";s(a),a.classList.add("persona-voice-processing"),i.setMicState("processing"),a.style.backgroundColor=h,a.style.borderColor=f;let w=m||"currentColor";a.style.color=w,t(a,p,w),a.setAttribute("aria-label","Processing voice input"),l==="none"&&(a.style.cursor="default")},speaking:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},l=i.session().getVoiceInterruptionMode(),u=i.original,p=l==="cancel"?"square":l==="barge-in"?"mic":"volume-2",m=o.speakingIconName??p,h=o.speakingIconColor??(l==="barge-in"?o.recordingIconColor??u?.color??"":u?.color??""),f=o.speakingBackgroundColor??(l==="barge-in"?o.recordingBackgroundColor??"var(--persona-voice-recording-bg, #ef4444)":u?.backgroundColor??""),w=o.speakingBorderColor??(l==="barge-in"?o.recordingBorderColor??"":u?.borderColor??"");s(a),a.classList.add("persona-voice-speaking"),i.setMicState("speaking"),a.style.backgroundColor=f,a.style.borderColor=w;let y=h||"currentColor";a.style.color=y,t(a,m,y);let k=l==="cancel"?"Stop playback and re-record":l==="barge-in"?"Speak to interrupt":"Agent is speaking";a.setAttribute("aria-label",k),l==="none"&&(a.style.cursor="default"),l==="barge-in"&&a.classList.add("persona-voice-recording")},reset:()=>{let a=i.mic();if(!a)return;s(a),i.setMicState("idle");let o=i.original;o&&(a.style.backgroundColor=o.backgroundColor??"",a.style.color=o.color??"",a.style.borderColor=o.borderColor??"",t(a,o.iconName,o.color||"currentColor"),i.original=null),a.style.cursor="",a.setAttribute("aria-label","Start voice recognition")}}};0&&(module.exports={BrowserVoiceProvider,KeyedVoiceTranscript,RuntypeVoiceProvider,createBestAvailableVoiceProvider,createMicStateStyles,createVoiceProvider,createVoiceSessionBridge,isVoiceSupported,wireSessionVoice});
|
package/dist/voice-runtime.d.cts
CHANGED
|
@@ -7258,6 +7258,11 @@ interface VoiceProvider {
|
|
|
7258
7258
|
setSessionBridge?(bridge: VoiceSessionBridge): void;
|
|
7259
7259
|
/** The AI-disclosure notice for the live call, if one should show (speech-to-speech). */
|
|
7260
7260
|
getDisclosure?(): string | null;
|
|
7261
|
+
/**
|
|
7262
|
+
* Status-line text for the call, returned once: why the server ended it
|
|
7263
|
+
* (`session_end`) or that it is reconnecting. `null` when there is none.
|
|
7264
|
+
*/
|
|
7265
|
+
takeNotice?(): string | null;
|
|
7261
7266
|
}
|
|
7262
7267
|
/** Metadata on a {@link VoiceProvider.onTranscript} update. */
|
|
7263
7268
|
type VoiceTranscriptMetadata = {
|
|
@@ -7313,6 +7318,12 @@ type VoiceDelegationResult = {
|
|
|
7313
7318
|
status: VoiceDelegationStatus;
|
|
7314
7319
|
/** The assistant text (Markdown allowed). */
|
|
7315
7320
|
text: string;
|
|
7321
|
+
/**
|
|
7322
|
+
* `false` when no chat message carries this answer (it is only spoken), so
|
|
7323
|
+
* the voice model's read-back of it stays visible as a caption.
|
|
7324
|
+
* @default true
|
|
7325
|
+
*/
|
|
7326
|
+
inChat?: boolean;
|
|
7316
7327
|
/**
|
|
7317
7328
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7318
7329
|
* Resolves with the terminal result once the visitor decides (or the
|
|
@@ -10500,6 +10511,8 @@ declare class RuntypeVoiceProvider implements VoiceProvider {
|
|
|
10500
10511
|
prewarm(): void;
|
|
10501
10512
|
/** Start the call: acquire mic, open the WS, stream PCM until hang-up. */
|
|
10502
10513
|
startListening(): Promise<void>;
|
|
10514
|
+
/** Status-line text for the call (why it ended, or that it is reconnecting), once. */
|
|
10515
|
+
takeNotice(): string | null;
|
|
10503
10516
|
/** The AI-disclosure notice for a live speech-to-speech call (`disclosureText`; `false` hides it). */
|
|
10504
10517
|
getDisclosure(): string | null;
|
|
10505
10518
|
/** End the call (hang up). */
|
|
@@ -11071,6 +11084,8 @@ declare class AgentWidgetSession {
|
|
|
11071
11084
|
* Get current voice status
|
|
11072
11085
|
*/
|
|
11073
11086
|
getVoiceStatus(): VoiceStatus;
|
|
11087
|
+
/** The voice call's pending status-line notice (why it ended, or reconnecting), once. */
|
|
11088
|
+
getVoiceNotice(): string | null;
|
|
11074
11089
|
/** The live call's AI-disclosure notice, if it shows one. */
|
|
11075
11090
|
getVoiceDisclosure(): string | null;
|
|
11076
11091
|
/**
|
package/dist/voice-runtime.d.ts
CHANGED
|
@@ -7258,6 +7258,11 @@ interface VoiceProvider {
|
|
|
7258
7258
|
setSessionBridge?(bridge: VoiceSessionBridge): void;
|
|
7259
7259
|
/** The AI-disclosure notice for the live call, if one should show (speech-to-speech). */
|
|
7260
7260
|
getDisclosure?(): string | null;
|
|
7261
|
+
/**
|
|
7262
|
+
* Status-line text for the call, returned once: why the server ended it
|
|
7263
|
+
* (`session_end`) or that it is reconnecting. `null` when there is none.
|
|
7264
|
+
*/
|
|
7265
|
+
takeNotice?(): string | null;
|
|
7261
7266
|
}
|
|
7262
7267
|
/** Metadata on a {@link VoiceProvider.onTranscript} update. */
|
|
7263
7268
|
type VoiceTranscriptMetadata = {
|
|
@@ -7313,6 +7318,12 @@ type VoiceDelegationResult = {
|
|
|
7313
7318
|
status: VoiceDelegationStatus;
|
|
7314
7319
|
/** The assistant text (Markdown allowed). */
|
|
7315
7320
|
text: string;
|
|
7321
|
+
/**
|
|
7322
|
+
* `false` when no chat message carries this answer (it is only spoken), so
|
|
7323
|
+
* the voice model's read-back of it stays visible as a caption.
|
|
7324
|
+
* @default true
|
|
7325
|
+
*/
|
|
7326
|
+
inChat?: boolean;
|
|
7316
7327
|
/**
|
|
7317
7328
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7318
7329
|
* Resolves with the terminal result once the visitor decides (or the
|
|
@@ -10500,6 +10511,8 @@ declare class RuntypeVoiceProvider implements VoiceProvider {
|
|
|
10500
10511
|
prewarm(): void;
|
|
10501
10512
|
/** Start the call: acquire mic, open the WS, stream PCM until hang-up. */
|
|
10502
10513
|
startListening(): Promise<void>;
|
|
10514
|
+
/** Status-line text for the call (why it ended, or that it is reconnecting), once. */
|
|
10515
|
+
takeNotice(): string | null;
|
|
10503
10516
|
/** The AI-disclosure notice for a live speech-to-speech call (`disclosureText`; `false` hides it). */
|
|
10504
10517
|
getDisclosure(): string | null;
|
|
10505
10518
|
/** End the call (hang up). */
|
|
@@ -11071,6 +11084,8 @@ declare class AgentWidgetSession {
|
|
|
11071
11084
|
* Get current voice status
|
|
11072
11085
|
*/
|
|
11073
11086
|
getVoiceStatus(): VoiceStatus;
|
|
11087
|
+
/** The voice call's pending status-line notice (why it ended, or reconnecting), once. */
|
|
11088
|
+
getVoiceNotice(): string | null;
|
|
11074
11089
|
/** The live call's AI-disclosure notice, if it shows one. */
|
|
11075
11090
|
getVoiceDisclosure(): string | null;
|
|
11076
11091
|
/**
|