@runtypelabs/persona 4.26.1 → 4.28.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 +18 -0
- package/dist/approval-ui.d.ts +18 -0
- package/dist/artifacts-ui.d.cts +18 -0
- package/dist/artifacts-ui.d.ts +18 -0
- package/dist/chunk-AALCT54S.js +1 -0
- package/dist/{client-history-GOZWBDA5.js → client-history-LV3KHEFA.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 +18 -0
- package/dist/context-mentions.d.ts +18 -0
- package/dist/event-stream-view.d.cts +18 -0
- package/dist/event-stream-view.d.ts +18 -0
- package/dist/forms-ui.d.cts +26 -0
- package/dist/forms-ui.d.ts +26 -0
- package/dist/index.cjs +57 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -0
- package/dist/index.d.ts +34 -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 +18 -0
- package/dist/session-reconnect.d.ts +18 -0
- package/dist/smart-dom-reader.d.cts +18 -0
- package/dist/smart-dom-reader.d.ts +18 -0
- package/dist/theme-editor-preview.cjs +66 -66
- package/dist/theme-editor-preview.d.cts +18 -0
- package/dist/theme-editor-preview.d.ts +18 -0
- package/dist/theme-editor-preview.js +31 -31
- package/dist/theme-editor.d.cts +18 -0
- package/dist/theme-editor.d.ts +18 -0
- package/dist/voice-runtime-LVUMPUDS.js +17 -0
- package/dist/voice-runtime.cjs +7 -7
- package/dist/voice-runtime.d.cts +33 -0
- package/dist/voice-runtime.d.ts +33 -0
- package/dist/voice-runtime.js +7 -7
- package/package.json +1 -1
- package/src/client-stream.ts +10 -3
- package/src/client.interrupt.test.ts +18 -0
- package/src/client.test.ts +20 -0
- package/src/client.ts +7 -0
- package/src/session.ts +16 -3
- package/src/session.voice.test.ts +199 -3
- package/src/types.ts +24 -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 +205 -21
- package/src/voice/voice-clause-buffer.test.ts +143 -0
- package/src/voice/voice-clause-buffer.ts +187 -0
- package/src/voice/voice-delegation.ts +111 -13
- package/src/voice/voice.test.ts +433 -2
- package/dist/chunk-GKPCIQPB.js +0 -1
- package/dist/client-stream-42FOI3EC.js +0 -4
- package/dist/voice-runtime-XLU6YK2N.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 = {
|
|
@@ -7125,6 +7130,13 @@ type VoiceDelegationRequest = {
|
|
|
7125
7130
|
role: string;
|
|
7126
7131
|
content: unknown;
|
|
7127
7132
|
}>;
|
|
7133
|
+
/**
|
|
7134
|
+
* Set when the server streams delegated answers (`delegation_stream`): called
|
|
7135
|
+
* with each speakable piece of the turn's answer, in order, while it renders.
|
|
7136
|
+
* The pieces, concatenated, are a prefix of the result's `text`; the result
|
|
7137
|
+
* says how much of it with `streamedChars`.
|
|
7138
|
+
*/
|
|
7139
|
+
stream?: (text: string) => void;
|
|
7128
7140
|
};
|
|
7129
7141
|
/**
|
|
7130
7142
|
* How a delegated turn ended, or that it waits on an approval (contract
|
|
@@ -7155,6 +7167,12 @@ type VoiceDelegationResult = {
|
|
|
7155
7167
|
* @default true
|
|
7156
7168
|
*/
|
|
7157
7169
|
inChat?: boolean;
|
|
7170
|
+
/**
|
|
7171
|
+
* How many leading characters of `text` already went out through
|
|
7172
|
+
* `request.stream` (the rest, such as an approval script, is unstreamed).
|
|
7173
|
+
* Omitted or 0: nothing was streamed.
|
|
7174
|
+
*/
|
|
7175
|
+
streamedChars?: number;
|
|
7158
7176
|
/**
|
|
7159
7177
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7160
7178
|
* 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 = {
|
|
@@ -7125,6 +7130,13 @@ type VoiceDelegationRequest = {
|
|
|
7125
7130
|
role: string;
|
|
7126
7131
|
content: unknown;
|
|
7127
7132
|
}>;
|
|
7133
|
+
/**
|
|
7134
|
+
* Set when the server streams delegated answers (`delegation_stream`): called
|
|
7135
|
+
* with each speakable piece of the turn's answer, in order, while it renders.
|
|
7136
|
+
* The pieces, concatenated, are a prefix of the result's `text`; the result
|
|
7137
|
+
* says how much of it with `streamedChars`.
|
|
7138
|
+
*/
|
|
7139
|
+
stream?: (text: string) => void;
|
|
7128
7140
|
};
|
|
7129
7141
|
/**
|
|
7130
7142
|
* How a delegated turn ended, or that it waits on an approval (contract
|
|
@@ -7155,6 +7167,12 @@ type VoiceDelegationResult = {
|
|
|
7155
7167
|
* @default true
|
|
7156
7168
|
*/
|
|
7157
7169
|
inChat?: boolean;
|
|
7170
|
+
/**
|
|
7171
|
+
* How many leading characters of `text` already went out through
|
|
7172
|
+
* `request.stream` (the rest, such as an approval script, is unstreamed).
|
|
7173
|
+
* Omitted or 0: nothing was streamed.
|
|
7174
|
+
*/
|
|
7175
|
+
streamedChars?: number;
|
|
7158
7176
|
/**
|
|
7159
7177
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7160
7178
|
* Resolves with the terminal result once the visitor decides (or the
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import{a as ae}from"./chunk-6V3MNEKB.js";import{a as oe}from"./chunk-AALCT54S.js";var K=16e3,Me=24e3,Te=4096,_e=K*2*8,Ee=4,Ie=1380533830,Ve=3e4,Pe=1e3,Re=5e3,Le=3e4,Ne=3e4,Oe=6e5,De="full-duplex-v1",Ue=300,xe=2e3,$e=2e3,Be="runtype-browser-v1",We=54e4,He="You're talking to an AI assistant. Voice is processed by OpenAI.",qe=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."]]),ce=["provider_error","server_restart"],O="Voice connection lost.",je=8e3,Fe=4e3,Xe=12,le=2e3;function ze(i,e){let t="Conversation so far:",s=e.slice(0,Fe).trim(),n=je-(s?s.length+2:0)-t.length,r=[];for(let l of i.slice(-Xe).reverse()){let a=l.content.replace(/\s+/g," ").trim();if(!a)continue;a.length>le&&(a=`${a.slice(0,le-1)}\u2026`);let o=`${l.role==="user"?"User":"Assistant"}: ${a}`;if(o.length+1>n)break;n-=o.length+1,r.unshift(o)}let d=r.length>0?[`${t}
|
|
2
|
+
${r.join(`
|
|
3
|
+
`)}`]:[];return s&&d.push(s),d.join(`
|
|
4
|
+
|
|
5
|
+
`)}function Ge(i){return i.byteLength>=44&&new DataView(i).getUint32(0,!1)===Ie?new Uint8Array(i,44):new Uint8Array(i)}function de(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 Ke(i){return de(i).replace(/^ws/i,"http")}function Ye(i){return typeof i!="number"||!Number.isFinite(i)?Le:Math.min(Oe,Math.max(Ne,Math.round(i)))}var R=class{constructor(e){this.config=e;this.type="runtype";this.#e=null;this.#n=null;this.#a=[];this.#i=null;this.#c=null;this.#l=null;this.#y=[];this.#b=0;this.#r=null;this.#h=!1;this.#g=!1;this.#s=0;this.#E=!1;this.#J=Number.NEGATIVE_INFINITY;this.#o=null;this.#f=!1;this.#I=!1;this.#V=0;this.#v=0;this.#w=!1;this.bridge=null;this.#R=!1;this.#d=new Set;this.#A=new Map;this.#C=new Set;this.#L=null;this.#p=null;this.#U=!1;this.#x=!1;this.#$=!1;this.#N=null;this.#B=null;this.#W=Promise.resolve();this.#S=new Set;this.#k=new Set;this.#H=null;this.#u=!1;this.#M=new Set;this.#T=new Set;this.#Q=[];this.#q=[];this.#j=[];this.#F=[];this.#X=[]}#e;#n;#a;#i;#c;#l;#y;#b;#r;#h;#g;#s;#E;#J;#o;#f;#I;#V;#v;#P;#w;#R;#d;#A;#C;#D;#L;#p;#Z;#U;#x;#$;#N;#B;#W;#S;#k;#H;#u;#M;#T;#Q;#q;#j;#F;#X;async connect(){}setSessionBridge(e){this.bridge=e}prewarm(){if(this.#h||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.#J<Ve)){this.#J=n;try{this.config?.prewarmMode==="attach"?this.#de(s,e,t):this.#le(s,e,t)}catch{}}}#le(e,t,s){if(typeof fetch!="function")return;let n=`${Ke(e)}/v1/client/agents/${encodeURIComponent(t)}/voice/prewarm`;fetch(n,{method:"POST",headers:{Authorization:`Bearer ${s}`},keepalive:!0}).catch(()=>{})}#de(e,t,s){let n=new URLSearchParams,r=this.config?.attachIdleMs,d=Ye(r);r!==void 0&&n.set("attachIdleMs",String(d));let l=new WebSocket(this.#te(e,t,n),["runtype.bearer","runtype.attach",s]);l.binaryType="arraybuffer";let a=()=>{},o=new Promise(u=>{a=u}),c={ws:l,state:"connecting",ready:o,settle:a,openedAt:0,idleTimer:void 0};this.#o=c,l.onopen=()=>{this.#o===c&&(c.state=l.protocol==="runtype.attach"?"attached":"live",c.openedAt=Date.now(),this.#ee(c,d),c.state==="attached"&&l.send('{"type":"ping"}'),c.settle())},l.onmessage=u=>{if(this.#o!==c||typeof u.data!="string")return;let h;try{h=JSON.parse(u.data)}catch{return}h.type==="attached"&&typeof h.idleMs=="number"&&this.#ee(c,h.idleMs-(Date.now()-c.openedAt))},l.onerror=()=>{},l.onclose=()=>{this.#o===c&&this.#O()}}#ee(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#ue(){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,Re)})]),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"})}#te(e,t,s){let n=["partial_transcript","context"];this.bridge&&this.config?.clientDelegation!==!1&&n.push("client_delegation","delegation_update","delegation_read_back","delegation_stream"),s&&n.unshift("attach");let r=new URLSearchParams({voiceProtocol:Be,clientVersion:`persona/${oe}`,voiceCapabilities:De,clientCapabilities:n.join(",")});return s?.forEach((d,l)=>r.set(l,d)),`${de(e)}/ws/agents/${encodeURIComponent(t)}/voice?${r}`}async startListening(){if(this.#h)return;let e=this.#x;e||(this.#U=!1,this.#p=null),this.#x=!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.#E=!1,this.#h=!0;try{let d=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:K,channelCount:1,echoCancellation:!0}});if(r!==this.#s){d.getTracks().forEach(h=>h.stop());return}this.#i=d;let l=window.AudioContext||window.webkitAudioContext,a=new l({sampleRate:K});if(this.#n=a,a.state==="suspended"){if(await Promise.race([a.resume().catch(()=>{}),new Promise(h=>setTimeout(h,e?500:Pe))]),r!==this.#s)return;if(a.state!=="running")throw e?new Error(this.#p=`${O} Tap the mic to reconnect.`):new Error("Audio blocked until a tap")}let o=this.config?.createPlaybackEngine?await this.config.createPlaybackEngine():new ae(Me);if(r!==this.#s){o.destroy(),d.getTracks().forEach(h=>h.stop()),a.close().catch(()=>{});return}this.#r=o,this.#K(),this.#ge(a,d,r);let c=await this.#ue();if(r!==this.#s){c?.ws.close(1e3,"client ended call");return}if(c){let{ws:h}=c;this.#e=h,this.#se(h,r),c.live||h.send('{"type":"start"}'),this.#z(h),this.#t("listening");return}let u=new WebSocket(this.#te(n,t),["runtype.bearer",s]);u.binaryType="arraybuffer",this.#e=u,u.onopen=()=>{r===this.#s&&(this.#z(u),this.#t("listening"))},this.#se(u,r)}catch(d){throw this.#m(),this.#_(d),this.#t("error"),d}}#se(e,t){e.onmessage=s=>this.#fe(s,t),e.onerror=()=>{t!==this.#s||this.#L||(this.#_(new Error("Voice connection failed")),this.#t("error"),this.#m())},e.onclose=s=>{if(this.#E){this.#E=!1;return}if(t!==this.#s)return;let n=this.#L??(s.code===4408?{reason:"idle_timeout"}:null);if(!n){if(s.code!==1e3){let r=s.code?` (code ${s.code})`:"";this.#_(new Error(`Voice connection closed${r}`)),this.#t("error")}else this.#t("idle");this.#m();return}this.#he(n.reason,n.message)}}#he(e,t){let s=ce.includes(e)&&!this.#U;if(this.#m(),s){this.#U=!0,this.#h=!0,this.#p=e==="provider_error"?`${O} Reconnecting\u2026`:"Reconnecting\u2026",this.#Z=setTimeout(()=>{this.#h=!1,this.#x=!0,this.startListening().catch(()=>{})},1e3+Math.random()*1e3),this.#t("idle");return}if(ce.includes(e))return this.#p=O,this.#_(new Error(O)),this.#t("error");if(e==="error")return this.#t("error");this.#p=e==="quota"&&t||qe.get(e)||null,this.#t("idle")}takeNotice(){let e=this.#p;return this.#p=null,e}getDisclosure(){let e=this.config?.disclosureText;return this.#h&&this.#f&&e!==!1?e||He:null}async stopListening(){this.#m(),this.#t("idle")}async disconnect(){this.#m(),this.#t("disconnected"),this.#Q=[],this.#q=[],this.#j=[],this.#F=[],this.#X=[]}stopPlayback(){this.#ce();let e=this.#e;e&&e.readyState===WebSocket.OPEN&&(this.#f&&(this.#V=Date.now()+xe,e.send('{"type":"cancel"}')),this.#t("listening"))}getInterruptionMode(){return"barge-in"}isBargeInActive(){return this.#h}onLevel(e){this.#a.push(e)}async deactivateBargeIn(){this.#m(),this.#t("idle")}#ge(e,t,s){let n=e.createMediaStreamSource(t);this.#c=n;let r=e.createScriptProcessor(Te,1,1);this.#l=r,r.onaudioprocess=d=>{if(s!==this.#s)return;let l=this.#e,a=l?.readyState===WebSocket.OPEN;if(l&&!a&&l.readyState!==WebSocket.CONNECTING)return;let o=d.inputBuffer.getChannelData(0),c=new Int16Array(o.length),u=0;for(let h=0;h<o.length;h++){let m=Math.max(-1,Math.min(1,o[h]));u+=m*m,c[h]=m<0?m*32768:m*32767}if(l&&a)this.#z(l),l.send(c.buffer);else for(this.#y.push(c.buffer),this.#b+=c.byteLength;this.#b>_e;)this.#b-=this.#y.shift().byteLength;if(this.#a.length>0){let h=Math.sqrt(u/o.length),m=Math.max(0,Math.min(1,h*Ee));for(let f of this.#a)f(m)}},n.connect(r),r.connect(e.destination)}#z(e){for(let t of this.#y)e.send(t);this.#y=[],this.#b=0}#fe(e,t){if(t!==this.#s)return;if(e.data instanceof ArrayBuffer){this.#ve(e.data,t);return}let s;try{s=JSON.parse(e.data)}catch{return}switch(s.type){case"session_config":s.speechMode&&(this.#f=s.speechMode==="speech_to_speech",this.#r?.setContinuousMode?.(this.#f)),Array.isArray(s.capabilities)&&(this.#d=new Set(s.capabilities)),typeof s.callId=="string"&&(this.#D=s.callId),this.#R=this.#f&&this.#d.has("client_delegation")&&!!this.bridge,this.#f&&!this.#g&&this.#t("listening"),this.#d.has("context")&&!this.#$&&(this.#$=!0,this.#N=this.#pe());break;case"transcript_update":{let n=s.role==="assistant"?"assistant":"user",r=s.utteranceId??s.turnId;if(!r||n==="assistant"&&this.#G())break;let d=String(r);if(n==="user")s.final===!0&&this.#ie(t),this.#u=!1;else{if(this.#d.has("delegation_read_back")){let l=s.delegationId;typeof l=="string"&&this.#S.has(l)&&!this.#M.has(d)?(this.#T.add(d),this.#u=!1):this.#u&&!this.#M.has(d)&&(this.#T.add(d),this.#u=!1)}else this.#u&&!this.#M.has(d)&&(this.#T.add(d),this.#u=!1);if(this.#M.add(d),this.#T.has(d))break}this.#Y(n,s.text??"",s.final===!0,{turnId:d,...typeof s.startMs=="number"&&{startMs:s.startMs},...typeof s.endMs=="number"&&{endMs:s.endMs},...this.#R&&{caption:!0}});break}case"delegation_started":case"delegation_completed":{let n=String(s.delegationId??s.turnId);if(s.type==="delegation_started"){this.#ie(t);let r=s.input;this.#R&&r&&this.#me(n,{delegationId:n,userText:String(r.text??""),userUtteranceIds:Array.isArray(r.userUtteranceIds)?r.userUtteranceIds.filter(d=>typeof d=="string"):[],messages:Array.isArray(r.messages)?r.messages:[]},t)}else s.speak!==!1&&this.#S.has(n)&&!this.#k.delete(n)&&!this.#d.has("delegation_read_back")&&this.#re(n);this.#I=s.type==="delegation_started",!this.#g&&!this.#G()&&this.#t(this.#I?"processing":"listening");break}case"delegation_progress":{let n=String(s.delegationId);this.#S.has(n)&&!this.#k.has(n)&&!this.#C.has(n)&&(this.#k.add(n),this.#re(n));break}case"delegation_cancelled":this.#oe(String(s.delegationId),s.reason!=="session_ending"&&s.reason!=="provider_cancelled");break;case"warning":console.warn(`[Persona voice] ${s.code}: ${s.message??""}`,this.#D??""),s.delegationId&&(s.code==="UNKNOWN_DELEGATION"||s.code==="LATE_RESULT_LIMIT")&&this.#oe(String(s.delegationId));break;case"audio_clear":this.#ce(),this.#V=0,this.#t("listening");break;case"transcript_interim":this.#t("listening"),this.#Y("user",s.text??"",!1);break;case"transcript_final":{let n=s.role==="assistant"?"assistant":"user";this.#t(n==="user"?"processing":"speaking"),this.#Y(n,s.text??"",!0);break}case"audio_end":this.#r?this.#r.markStreamEnd():(this.#g=!1,this.#t("listening"));break;case"metrics":this.#ye({llmMs:s.llm_ms,ttsMs:s.tts_ms,firstAudioMs:s.first_audio_ms,totalMs:s.total_ms});break;case"error":this.#_(new Error(s.error||"Voice error")),this.#t("error");break;case"session_end":this.#L={reason:String(s.reason),...typeof s.message=="string"&&{message:s.message}};break}}async#pe(){let e=this.bridge?.getHistory()??[],t="";try{let s=this.config?.callContext;t=String((typeof s=="function"?await s():s)??"")}catch{}return ze(e,t)}#ie(e){let t=this.#N;if(!t)return;this.#N=null;let s=!1,n=t.then(r=>{let d=this.#e;s||!r||e!==this.#s||d?.readyState!==WebSocket.OPEN||d.send(JSON.stringify({type:"context",text:r}))});this.#B={done:n,drop:()=>s=!0}}async#ne(){let e=this.#B;if(!e)return;let t,s=await Promise.race([e.done.then(()=>!1),new Promise(n=>{t=setTimeout(()=>n(!0),$e)})]);clearTimeout(t),s&&e.drop()}#re(e){this.#u=!0,this.#H=e}#oe(e,t=!1){this.#C.add(e),this.#H===e&&(this.#u=!1),this.#k.delete(e),this.bridge?.dropDelegation?.(e,t),this.#A.get(e)?.abort()}#me(e,t,s){let n=this.bridge,r=({type:l,...a})=>{let o=this.#e;return s!==this.#s||o?.readyState!==WebSocket.OPEN||this.#C.has(e)?!1:(o.send(JSON.stringify({type:l,delegationId:e,...a})),!0)},d=(l,a,o,c=0)=>r({type:l,status:a,text:o,...c>0&&{streamedChars:c}});this.#W=this.#W.then(async()=>{if(s!==this.#s||this.#C.has(e))return;let l=null,a=this.#d.has("delegation_stream")&&this.#d.has("delegation_read_back"),o=S=>{l=(l??this.#ne()).then(()=>{r({type:"delegation_delta",text:S})&&this.#S.add(e)})},c=await n.runDelegatedTurn(a?{...t,stream:o}:t).catch(()=>({status:"failed",text:""}));await this.#ne(),await l;let u=a?c.streamedChars??0:0,h=!!c.followUp,m=h&&this.#d.has("delegation_update");if(!d(m?"delegation_update":"delegation_result",h&&!m?"completed":c.status,c.text,u)||(c.status!=="failed"&&c.inChat!==!1&&this.#S.add(e),!c.followUp))return;let p=new AbortController;this.#A.set(e,p),c.followUp({signal:p.signal,approvalTimeoutMs:this.config?.approvalTimeoutMs&&Math.min(this.config.approvalTimeoutMs,We),readBack:m,onUpdate:S=>d("delegation_update","pending_approval",S)}).then(S=>{this.#A.delete(e),m&&S&&!p.signal.aborted&&d("delegation_result",S.status,S.text)})})}#ve(e,t){if(t!==this.#s||!this.#r||this.#G())return;let s=Ge(e);s.length!==0&&(this.#g||(this.#g=!0,this.#t("speaking")),this.#K(),this.#r.enqueue(s),this.#f&&this.#Se(s.length))}#G(){return Date.now()<this.#V}#K(){if(this.#w||!this.#r)return;this.#w=!0;let e=this.#s;this.#r.onFinished(()=>{e===this.#s&&(this.#w=!1,this.#ae())})}#Se(e){let t=Date.now();this.#v=Math.max(t,this.#v)+e/48,clearTimeout(this.#P),this.#P=setTimeout(()=>this.#ae(),this.#v-t+Ue)}#ae(){this.#g=!1,this.#v=0,this.#e&&this.#e.readyState===WebSocket.OPEN&&this.#t(this.#I?"processing":"listening")}#ce(){this.#r?.flush(),this.#w=!1,this.#K(),this.#g=!1,this.#v=0,clearTimeout(this.#P)}#m(){this.#s+=1,this.#h=!1,this.#g=!1,this.#O(),this.#f=!1,this.#I=!1,this.#R=!1,this.#d=new Set;for(let e of this.#A.values())e.abort();if(this.#A.clear(),this.#C.clear(),this.#D=void 0,this.#L=null,clearTimeout(this.#Z),this.#$=!1,this.#N=null,this.#B=null,this.#W=Promise.resolve(),this.#S.clear(),this.#k.clear(),this.#H=null,this.#u=!1,this.#M.clear(),this.#T.clear(),this.#w=!1,this.#V=0,this.#v=0,clearTimeout(this.#P),this.#y=[],this.#b=0,this.#l&&(this.#l.onaudioprocess=null,this.#l.disconnect(),this.#l=null),this.#c&&(this.#c.disconnect(),this.#c=null),this.#i&&(this.#i.getTracks().forEach(e=>e.stop()),this.#i=null),this.#n&&(this.#n.close().catch(()=>{}),this.#n=null),this.#r&&(this.#r.destroy(),this.#r=null),this.#e){this.#E=!0;try{this.#e.close(1e3,"client ended call")}catch{}this.#e=null}}onResult(e){this.#Q.push(e)}onError(e){this.#q.push(e)}onStatusChange(e){this.#j.push(e)}onTranscript(e){this.#F.push(e)}onMetrics(e){this.#X.push(e)}#t(e){this.#j.forEach(t=>t(e))}#_(e){this.#q.forEach(t=>t(e))}#Y(e,t,s,n){this.#F.forEach(r=>r(e,t,s,n))}#ye(e){this.#X.forEach(t=>t(e))}};var _=class{constructor(e={}){this.config=e;this.type="browser";this.#e=null;this.#n=[];this.#a=[];this.#i=[];this.#c=!1;this.#l=typeof window<"u"?window:void 0}#e;#n;#a;#i;#c;#l;async connect(){this.#i.forEach(e=>e("connected"))}async startListening(){try{if(this.#c)throw new Error("Already listening");if(!this.#l)throw new Error("Window object not available");let e=this.#l.SpeechRecognition||this.#l.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.#n.forEach(r=>r({text:s,confidence:n?.8:.5,provider:"browser"})),n&&!this.config?.continuous&&this.stopListening()},this.#e.onerror=t=>{this.#a.forEach(s=>s(new Error(t.error))),this.#i.forEach(s=>s("error"))},this.#e.onstart=()=>{this.#c=!0,this.#i.forEach(t=>t("listening"))},this.#e.onend=()=>{this.#c=!1,this.#i.forEach(t=>t("idle"))},this.#e.start()}catch(e){throw this.#a.forEach(t=>t(e)),this.#i.forEach(t=>t("error")),e}}async stopListening(){this.#e&&(this.#e.stop(),this.#e=null),this.#c=!1,this.#i.forEach(e=>e("idle"))}onResult(e){this.#n.push(e)}onError(e){this.#a.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 D(i){switch(i.type){case"runtype":if(!i.runtype)throw new Error("Runtype voice provider requires configuration");return new R(i.runtype);case"browser":if(!_.isSupported())throw new Error("Browser speech recognition not supported");return new _(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 ue(i){if(i?.type==="custom"&&i.custom)return D({type:"custom",custom:i.custom});if(i?.type==="runtype"&&i.runtype)return D({type:"runtype",runtype:i.runtype});if(_.isSupported())return D({type:"browser",browser:i?.browser||{language:"en-US"}});throw new Error("No supported voice providers available")}function Je(i){try{return ue(i),!0}catch{return!1}}var he=i=>i.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,""),Y=class{constructor(e){this.host=e;this.turns=new Map;this.latestId=null;this.cancelled=new Set}apply(e,t,s,n,r,d){let l=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?l.find(a.userId):void 0;if(o){let c=a.userStartMs===void 0&&r!==void 0;c&&(a.userStartMs=r),l.upsert({...o,content:t,voiceProcessing:!s,...c&&this.placeBefore(this.startedAfter(r))})}else{a.userStartMs=r;let c=a.assistantId?l.find(a.assistantId):void 0;a.userId=l.inject({role:"user",content:t,streaming:!1,voiceProcessing:!s,voiceCaption:d,...this.placeBefore(this.startedAfter(r)??c)}).id}}else if(!this.cancelled.has(n)){a.assistantFinal=s;let o=a.assistantId?l.find(a.assistantId):void 0;if(o){let c=a.assistantStartMs===void 0&&r!==void 0;c&&(a.assistantStartMs=r),l.upsert({...o,content:t,streaming:!s,voiceProcessing:!s,...c&&this.placeBefore(this.startedAfter(r))})}else t&&(a.assistantStartMs=r,a.assistantId=l.inject({role:"assistant",content:t,streaming:!s,voiceProcessing:!s,voiceCaption:d,...this.placeBefore(this.startedAfter(r))}).id);s&&a.assistantId&&l.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=he(e),d=[...this.turns.values()].reverse().flatMap(l=>{let a=l.userId&&!l.claimed?this.host.find(l.userId):void 0;return a?[{turn:l,text:he(a.content)}]:[]}).filter(({text:l})=>l&&r);n=(d.find(({text:l})=>l===r)??d.find(({text:l})=>l.startsWith(r)||r.startsWith(l)))?.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 d of s)this.turns.get(d).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 d=r?this.host.find(r):void 0,l=d?.sequence;d?.createdAt===e.createdAt&&l!==void 0&&l>s&&l<t&&(s=l)}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=new Set(["mr","mrs","ms","dr","prof","sr","jr","st","mt","vs","etc","approx","inc","ltd","co","corp","no","nos","fig","ft","dept","est","min","max","e.g","i.e","a.m","p.m","u.s","u.k"]),Qe=/([.!?]+|[,;:])(["'”’)\]*_]*)(\s+)|\n\s*/g;function et(i){let e=/(\S+)$/.exec(i)?.[1];if(!e)return!1;let t=e.replace(/^[("'“‘[*_]+/,"").toLowerCase();if(Ze.has(t)||/^[a-z](?:\.[a-z])*$/.test(t))return!0;if(/^\d+$/.test(e)){let s=i.length-e.length;return s===0||/\n\s*$/.test(i.slice(0,s))}return!1}function*ge(i,e){let t=new RegExp(Qe.source,"g");for(let s=t.exec(i);s;s=t.exec(i)){let n=s[1];if(!i.slice(0,s.index+(n?.length??0)).trim()||n!==void 0&&(/^[,;:]$/.test(n)&&!e||n==="."&&et(i.slice(0,s.index))))continue;let r=s.index+s[0].length;r<i.length&&(yield r)}}function fe(i,e){let t=i.slice(0,e),s=0;for(let n of t.matchAll(/\s+/g))t.slice(0,n.index).trim()&&(s=n.index+n[0].length);return s}function J(i){let e=0;for(let n of ge(i.slice(0,220),!0))e=n;if(e)return e;let t=fe(i,220);if(t)return t;let s=i.charCodeAt(219);return s>=55296&&s<=56319?219:220}var U=class{#e="";#n=!0;push(e){return this.#e+=e,this.#a()}flush(){let e=this.#a(),t=this.#e;if(this.#e="",t.trim()){for(let s=0;s<t.length;){let n=t.slice(s),r=n.length>220?J(n):n.length;e.push(n.slice(0,r)),s+=r}this.#n=!1}return e}idle(){let e=this.#e;if(!e.trim()||!/(?:[.!?…]["'”’)\]*_]*|\n)\s*$/.test(e))return[];this.#e="",this.#n=!1;let t=[];for(let s=0;s<e.length;){let n=e.slice(s),r=n.length>220?J(n):n.length;t.push(n.slice(0,r)),s+=r}return t}#a(){let e=[];for(let t=this.#i();t>0;t=this.#i())e.push(this.#e.slice(0,t)),this.#e=this.#e.slice(t),this.#n=!1;return e}#i(){let e=this.#e;if(!e.trim())return 0;let t=ge(e,this.#n).next().value??0;if(t&&t<=220)return t;let s=/[.!?]["'”’)\]*_]*$/.test(e);if(this.#n&&!s){let n=e.match(/\S+\s+/g)?.length??0;if(e.trim().length>=30||n>=6){let r=fe(e,220);if(r)return r}}return e.length>220?J(e):0}};var tt=200,st=(i,e)=>{let t=0;for(;t<i.length&&t<e.length&&i[t]===e[t];)t+=1;return t},it=50,nt="I need your answer in the chat before I can continue.",rt=1e3,ot=5*6e4,pe="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)",at=new RegExp(`^(?:${pe})(?: (?:${pe}))?(?: thanks| thank you)?$`),ct=i=>at.test(i.toLowerCase().replace(/[^a-z' ]+/g," ").replace(/\s+/g," ").trim()),me="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.",ve=()=>new Promise(i=>setTimeout(i,it)),Z=(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 Q(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=>Q(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,d])=>{let l=Q(d,e+1);return l&&(e?`${E(r)} ${l}`:`${E(r)}: ${l}`)}).filter(Boolean).join(e?", ":"; ")}function Se(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=rt-e.length-me.length-2,s=i.map(n=>{let r=[E(n.toolName)];n.description&&r.push(`(${Z(n.description.trim(),160)})`);let d=Q(n.parameters);return d&&r.push(`with ${d}`),n.reason&&r.push(`because: ${Z(n.reason.trim(),160)}`),Z(`- ${r.join(" ")}`,Math.floor(t/i.length)-1)});return`${e}
|
|
6
|
+
${s.join(`
|
|
7
|
+
`)}
|
|
8
|
+
|
|
9
|
+
${me}`}var x=i=>i.variant==="approval"&&i.approval?.status==="pending";function lt(i){let e=null,t=null,s=()=>i.track(e??t),n=[],r=new Map,d=new Map,l=(f,p)=>{r.set(f,[...r.get(f)??[],p]),r.size>32&&r.delete(r.keys().next().value)},a=f=>i.messages().find(p=>p.id===f),o=f=>f.approvals.filter(p=>a(p)?.approval?.status==="pending"),c=f=>E(a(f)?.approval?.toolName??""),u=(f,p,S)=>{f.outcome={status:p,text:S};for(let y of o(f))i.decide(y)},h=f=>f.flatMap(p=>i.messages().find(S=>S.id===p)??[]).filter(p=>!p.variant&&p.content.trim()).map(p=>p.content.trim()).join(`
|
|
10
|
+
|
|
11
|
+
`),m=async f=>{do await ve();while(i.busy()&&!(f&&(i.parked()||f.failed)))};return{getHistory:()=>{let f=i.messages().filter(y=>(y.role==="user"||y.role==="assistant")&&!y.variant&&!y.voiceProcessing&&!y.streaming&&y.content),p=!1,S=[];for(let y=f.length-1;y>=0;y-=1){let k=f[y];if(k.role==="user")p=!1;else if(!k.voiceCaption)p=!0;else if(p)continue;S.unshift({role:k.role,content:k.content})}return S},dropDelegation(f,p){d.set(f,!!p),d.size>32&&d.delete(d.keys().next().value);let S=p&&n.find(y=>y.delegationId===f);S&&!S.outcome&&u(S,"timeout","");for(let y of r.get(f)??[])y.stopStream?.(),y.dropped=!0,y.ids.length&&i.unspoken(y.ids)},async runDelegatedTurn({delegationId:f,userText:p,userUtteranceIds:S,stream:y}){let k=n.filter(g=>o(g).length),$=k.flatMap(o);if($.length===1&&ct(p)){let g=c($[0]);return u(k[0],"denied",""),{status:"denied",text:`Okay, I cancelled the ${g} request. Nothing was done.`,inChat:!1}}let ee=i.parked()&&i.messages().every(g=>!x(g)||$.includes(g.id));i.busy()&&!ee&&await m();let ye=new Set(i.messages().map(g=>g.id)),B=()=>i.messages().filter(g=>!ye.has(g.id)&&g.variant==="approval"),w={ids:[],failed:!1},I=y?new U:null,L="",te="",V=!1,W=g=>{for(let v of g)te+=v,y(v)},P;I&&(w.onUpdate=()=>{if(V)return;let g=h(w.ids);if(!g.startsWith(L)){V=!0,clearTimeout(P);return}if(g.length===L.length)return;let v=g.slice(L.length);L=g,W(I.push(v)),clearTimeout(P),P=setTimeout(()=>{V||W(I.idle())},tt)},w.stopStream=()=>{clearTimeout(P),V=!0,w.onUpdate=void 0}),l(f,w),e=w,s();try{await i.send(p,i.claim(p,S)??void 0),await m(w)}catch{w.failed=!0}finally{e=null,s()}I&&(w.onUpdate?.(),clearTimeout(P),V||W(I.flush()),w.onUpdate=void 0,w.stopStream=void 0);let H=g=>{let v=st(te,g);return v>0?{streamedChars:v}:{}},be=w.ids.flatMap(g=>i.messages().find(v=>v.id===g)??[]),C=h(w.ids),N=w.failed?[]:B().filter(x),we=new Set(N.map(g=>E(g.approval.toolName)));for(let g of k){if(g.outcome)continue;for(let A of o(g).filter(q=>we.has(c(q))))g.replaced.add(A),i.decide(A);let v=c(g.approvals[0]);g.approvals.every(A=>g.replaced.has(A))?g.outcome={status:"cancelled",text:`The earlier ${v} request was replaced by the new one; it was not done.`}:ee&&g.approvals.every(A=>a(A)?.approval?.status==="denied")&&(g.outcome={status:"cancelled",text:`The earlier ${v} request was replaced by the new one; it was not done.`})}if(N.length){let g=new Set(N.map(A=>A.id)),v={delegationId:f,approvals:[...g],at:Date.now(),replaced:new Set};return n.push(v),d.get(f)&&u(v,"timeout",""),C=`${C}
|
|
12
|
+
|
|
13
|
+
${Se(N.map(A=>A.approval))}`.trim(),{status:"pending_approval",text:C,...H(C),followUp:async({signal:A,approvalTimeoutMs:q=ot,readBack:se=!0,onUpdate:Ae})=>{let M={ids:[],failed:!1};r.delete(f),l(f,M);let ie=()=>B().filter(b=>g.has(b.id)||M.ids.includes(b.id)),Ce=()=>B().filter(b=>x(b)&&!g.has(b.id)&&!n.some(T=>T.approvals.includes(b.id))&&(M.ids.includes(b.id)||b.approval?.toolType==="webmcp"&&t===M)),ne=()=>{t=M,s()};se&&ne();try{for(;!A.aborted&&!v.outcome&&(e||i.busy()||ie().some(x));){se&&t!==M&&!o(v).length&&ne();let b=Ce();if(b.length){for(let T of b)g.add(T.id),v.approvals.push(T.id);v.at=Date.now(),Ae?.(Se(b.map(T=>T.approval)))}if(Date.now()-v.at>=q&&o(v).length&&(!i.busy()||i.parked())){u(v,"timeout",`That ${c(v.approvals[0])} request expired, so nothing was done.`);break}await ve()}}finally{t===M&&(t=null,s()),n.splice(n.indexOf(v),1)}if(A.aborted)return null;if(v.outcome)return v.outcome;if(M.failed)return{status:"failed",text:`The ${c(v.approvals[0])} request didn't complete.`};let re=ie(),j=b=>re.filter(b).map(T=>E(T.approval.toolName)).join(", "),F=re.some(b=>b.approval?.status==="approved"),X=j(b=>b.approval?.status==="denied"&&!v.replaced.has(b.id)),z=j(b=>v.replaced.has(b.id)),G=j(b=>b.approval?.status==="timeout"),ke=[F?h(M.ids):"",X&&`The user declined the ${X} request in the chat, so ${F?"that part was not done":"nothing was done"}.`,z&&`The earlier ${z} request was replaced by the new one; it was not done.`,G&&`The ${G} request timed out, so it was not done.`].filter(Boolean).join(`
|
|
14
|
+
|
|
15
|
+
`);return{status:F?"completed":X?"denied":z?"cancelled":G?"timeout":"completed",text:ke}}}}return!w.failed&&i.parked()||be.some(g=>g.agentMetadata?.awaitingLocalTool&&!g.agentMetadata.askUserQuestionAnswered&&!g.toolCall?.name?.startsWith("webmcp:"))?(C=`${C}
|
|
16
|
+
|
|
17
|
+
${nt}`.trim(),{status:w.failed?"failed":"completed",text:C,...H(C)}):{status:!w.failed&&C?"completed":"failed",text:C,...H(C)}}}}var dt=(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(),d=()=>i.provider()===e&&r===i.generation(),a=(n.config.voiceRecognition??{}).processingErrorText??"Voice processing failed. Please try again.";e.onResult(o=>{d()&&o.provider!=="runtype"&&o.text&&o.text.trim()&&n.sendMessage(o.text,{viaVoice:!0})}),e.onTranscript&&e.onTranscript((o,c,u,h)=>{if(d()){if(h?.turnId){i.keyed?.apply(o,c,u,h.turnId,h.startMs,h.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(h?.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(h?.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=>{d()&&i.setLevel(Number.isFinite(o)?Math.max(0,Math.min(1,o)):0)}),e.onMetrics&&e.onMetrics(o=>{d()&&n.config.voiceRecognition?.onMetrics?.(o)}),e.onError(o=>{d()&&(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=>{d()&&(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 ut=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 h=i.original?.iconSize??(parseFloat(i.config().voiceRecognition?.iconSize??"")||i.iconFallbackPx),m=i.renderIcon(o,h,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,h=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)}h&&(a.style.borderColor=h),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,h=o.processingIconName??"loader",m=o.processingIconColor??u?.color??"",f=o.processingBackgroundColor??u?.backgroundColor??"",p=o.processingBorderColor??u?.borderColor??"";s(a),a.classList.add("persona-voice-processing"),i.setMicState("processing"),a.style.backgroundColor=f,a.style.borderColor=p;let S=m||"currentColor";a.style.color=S,t(a,h,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,h=c==="cancel"?"square":c==="barge-in"?"mic":"volume-2",m=o.speakingIconName??h,f=o.speakingIconColor??(c==="barge-in"?o.recordingIconColor??u?.color??"":u?.color??""),p=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=p,a.style.borderColor=S;let y=f||"currentColor";a.style.color=y,t(a,m,y);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{_ as BrowserVoiceProvider,Y as KeyedVoiceTranscript,R as RuntypeVoiceProvider,ue as createBestAvailableVoiceProvider,ut as createMicStateStyles,D as createVoiceProvider,lt as createVoiceSessionBridge,Je as isVoiceSupported,dt as wireSessionVoice};
|
package/dist/voice-runtime.cjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var J=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var Ve=Object.getOwnPropertyNames;var Re=Object.prototype.hasOwnProperty;var je=(n,e)=>{for(var t in e)J(n,t,{get:e[t],enumerable:!0})},Le=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ve(e))!Re.call(n,i)&&i!==t&&J(n,i,{get:()=>e[i],enumerable:!(s=Pe(e,i))||s.enumerable});return n};var Ne=n=>Le(J({},"__esModule",{value:!0}),n);var St={};je(St,{BrowserVoiceProvider:()=>_,KeyedVoiceTranscript:()=>U,RuntypeVoiceProvider:()=>E,createBestAvailableVoiceProvider:()=>Q,createMicStateStyles:()=>Ce,createVoiceProvider:()=>R,createVoiceSessionBridge:()=>Ae,isVoiceSupported:()=>ge,wireSessionVoice:()=>ke});module.exports=Ne(St);var N=class{#e=null;#i=0;#r=[];#n=[];#c=[];#l=!1;#m=!1;#y=0;#o=!1;#p=!1;#d;#t=[];#b=0;#_=!1;#a;#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.#d=this.#g>0}#w(){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 i=new Uint8Array(this.#h.length+e.length);i.set(this.#h),i.set(e,this.#h.length),t=i,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.#f(t);s.length!==0&&(this.#d?(this.#t.push(s),this.#b+=s.length,clearTimeout(this.#a),this.#b>=this.#g?this.#S():this.#_&&(this.#a=setTimeout(()=>this.#S(),this.#g/this.#u*1e3))):this.#A(s))}markStreamEnd(){this.#t.length>0&&this.#S(),this.#m=!0,this.#k()}flush(){for(let e of this.#r){e.onended=null;try{e.stop(),e.disconnect()}catch{}}this.#r=[],this.#y=0,this.#i=0,this.#l=!1,this.#m=!1,this.#n=[],this.#c=[],this.#h=null,this.#t=[],this.#b=0,this.#d=this.#g>0,this.#o=!1,clearTimeout(this.#a)}setContinuousMode(e){this.#_=e}isPlaying(){return this.#l}onFinished(e){this.#n.push(e)}onStarted(e){this.#c.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)}#S(){this.#d=!1;let e=this.#t;this.#t=[],this.#b=0;for(let t of e)this.#A(t)}#A(e){if(e.length===0)return;let t=this.#w(),s=t.createBuffer(1,e.length,this.#u);s.getChannelData(0).set(e);let i=t.createBufferSource();i.buffer=s,i.connect(t.destination);let r=t.currentTime;if(this.#i===0?this.#i=r:this.#i<r&&(this.#i=r,this.#g>0&&(this.#d=!0)),i.start(this.#i),this.#i+=s.duration,this.#r.push(i),this.#y++,this.#l=!0,!this.#o){this.#o=!0;let l=this.#c.slice();this.#c=[];for(let d of l)d()}i.onended=()=>{let l=this.#r.indexOf(i);l!==-1&&(this.#r.splice(l,1),this.#y--,this.#k())}}#k(){if(this.#m&&this.#y<=0&&this.#t.length===0){this.#l=!1,this.#m=!1;let e=this.#n.slice();this.#n=[];for(let t of e)t()}}#f(e){let t=Math.floor(e.length/2),s=new Float32Array(t),i=new DataView(e.buffer,e.byteOffset,e.byteLength);for(let r=0;r<t;r++){let l=i.getInt16(r*2,!0);s[r]=l/32768}return s}};var le="4.28.0";var de=le;var Z=16e3,Ue=24e3,De=4096,Be=Z*2*8,qe=4,$e=1380533830,We=3e4,He=1e3,Fe=5e3,ze=3e4,Xe=3e4,Ge=6e5,Ke="full-duplex-v1",Ye=300,Je=2e3,Ze=2e3,Qe="runtype-browser-v1",et=54e4,tt="You're talking to an AI assistant. Voice is processed by OpenAI.",st=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."]]),ue=["provider_error","server_restart"],O="Voice connection lost.",it=8e3,nt=4e3,rt=12,pe=2e3;function ot(n,e){let t="Conversation so far:",s=e.slice(0,nt).trim(),i=it-(s?s.length+2:0)-t.length,r=[];for(let d of n.slice(-rt).reverse()){let a=d.content.replace(/\s+/g," ").trim();if(!a)continue;a.length>pe&&(a=`${a.slice(0,pe-1)}\u2026`);let o=`${d.role==="user"?"User":"Assistant"}: ${a}`;if(o.length+1>i)break;i-=o.length+1,r.unshift(o)}let l=r.length>0?[`${t}
|
|
2
2
|
${r.join(`
|
|
3
3
|
`)}`]:[];return s&&l.push(s),l.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.#k=!1;this.#S=new Set;this.#M=new Map;this.#x=new Set;this.#L=!1;this.#E=null;this.#O=null;this.#D=Promise.resolve();this.#P=new Set;this.#T=!1;this.#I=new Set;this.#V=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;#k;#S;#M;#x;#R;#L;#E;#O;#D;#P;#T;#I;#V;#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.#_()}}#X(e,t){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>{this.#o===e&&this.#_()},Math.max(0,t))}#_(){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.#_(),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","delegation_read_back"),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.#j(r),this.#s("error"),r}}#K(e,t){e.onmessage=s=>this.#ne(s,t),e.onerror=()=>{t===this.#t&&(this.#j(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.#j(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.#S=new Set(s.capabilities)),typeof s.callId=="string"&&(this.#R=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.#L&&(this.#L=!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.#S.has("delegation_read_back")){let d=s.delegationId;typeof d=="string"&&this.#P.has(d)&&!this.#I.has(l)&&this.#V.add(l)}else this.#T&&!this.#I.has(l)&&(this.#V.add(l),this.#T=!1);if(this.#I.add(l),this.#V.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.#k&&{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.#k&&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.#P.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.#R??""),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.#j(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.#O={done:n,drop:()=>s=!0}}async#oe(){let e=this.#O;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.#D=this.#D.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.#S.has("delegation_update");if(!r(a?"delegation_update":"delegation_result",d&&!a?"completed":l.status,l.text)||(l.status!=="failed"&&l.inChat!==!1&&this.#P.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.#_(),this.#u=!1,this.#h=!1,this.#k=!1,this.#S=new Set;for(let e of this.#M.values())e.abort();if(this.#M.clear(),this.#x.clear(),this.#R=void 0,this.#L=!1,this.#E=null,this.#O=null,this.#D=Promise.resolve(),this.#P.clear(),this.#T=!1,this.#I.clear(),this.#V.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))}#j(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 at(n){return n.byteLength>=44&&new DataView(n).getUint32(0,!1)===$e?new Uint8Array(n,44):new Uint8Array(n)}function he(n){let e=n.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 ct(n){return he(n).replace(/^ws/i,"http")}function lt(n){return typeof n!="number"||!Number.isFinite(n)?ze:Math.min(Ge,Math.max(Xe,Math.round(n)))}var E=class{constructor(e){this.config=e;this.type="runtype";this.#e=null;this.#i=null;this.#r=[];this.#n=null;this.#c=null;this.#l=null;this.#m=[];this.#y=0;this.#o=null;this.#p=!1;this.#d=!1;this.#t=0;this.#b=!1;this.#_=Number.NEGATIVE_INFINITY;this.#a=null;this.#u=!1;this.#g=!1;this.#h=0;this.#w=0;this.#A=!1;this.bridge=null;this.#k=!1;this.#f=new Set;this.#E=new Map;this.#x=new Set;this.#j=null;this.#C=null;this.#U=!1;this.#D=!1;this.#B=!1;this.#L=null;this.#q=null;this.#$=Promise.resolve();this.#T=new Set;this.#I=new Set;this.#W=null;this.#v=!1;this.#P=new Set;this.#V=new Set;this.#Q=[];this.#H=[];this.#F=[];this.#z=[];this.#X=[]}#e;#i;#r;#n;#c;#l;#m;#y;#o;#p;#d;#t;#b;#_;#a;#u;#g;#h;#w;#S;#A;#k;#f;#E;#x;#O;#j;#C;#Z;#U;#D;#B;#L;#q;#$;#T;#I;#W;#v;#P;#V;#Q;#H;#F;#z;#X;async connect(){}setSessionBridge(e){this.bridge=e}prewarm(){if(this.#p||this.#a)return;let e=this.config?.agentId,t=this.config?.clientToken,s=this.config?.host;if(!e||!t||!s)return;let i=Date.now();if(!(i-this.#_<We)){this.#_=i;try{this.config?.prewarmMode==="attach"?this.#de(s,e,t):this.#le(s,e,t)}catch{}}}#le(e,t,s){if(typeof fetch!="function")return;let i=`${ct(e)}/v1/client/agents/${encodeURIComponent(t)}/voice/prewarm`;fetch(i,{method:"POST",headers:{Authorization:`Bearer ${s}`},keepalive:!0}).catch(()=>{})}#de(e,t,s){let i=new URLSearchParams,r=this.config?.attachIdleMs,l=lt(r);r!==void 0&&i.set("attachIdleMs",String(l));let d=new WebSocket(this.#te(e,t,i),["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.#a=c,d.onopen=()=>{this.#a===c&&(c.state=d.protocol==="runtype.attach"?"attached":"live",c.openedAt=Date.now(),this.#ee(c,l),c.state==="attached"&&d.send('{"type":"ping"}'),c.settle())},d.onmessage=u=>{if(this.#a!==c||typeof u.data!="string")return;let p;try{p=JSON.parse(u.data)}catch{return}p.type==="attached"&&typeof p.idleMs=="number"&&this.#ee(c,p.idleMs-(Date.now()-c.openedAt))},d.onerror=()=>{},d.onclose=()=>{this.#a===c&&this.#N()}}#ee(e,t){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>{this.#a===e&&this.#N()},Math.max(0,t))}#N(){let e=this.#a;if(!e)return;this.#a=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#ue(){let e=this.#a;if(!e)return null;if(e.state==="connecting"){let t;await Promise.race([e.ready,new Promise(s=>{t=setTimeout(s,Fe)})]),clearTimeout(t)}return this.#a!==e?null:e.state==="connecting"||e.ws.readyState!==WebSocket.OPEN?(this.#N(),null):(this.#a=null,clearTimeout(e.idleTimer),{ws:e.ws,live:e.state==="live"})}#te(e,t,s){let i=["partial_transcript","context"];this.bridge&&this.config?.clientDelegation!==!1&&i.push("client_delegation","delegation_update","delegation_read_back","delegation_stream"),s&&i.unshift("attach");let r=new URLSearchParams({voiceProtocol:Qe,clientVersion:`persona/${de}`,voiceCapabilities:Ke,clientCapabilities:i.join(",")});return s?.forEach((l,d)=>r.set(d,l)),`${he(e)}/ws/agents/${encodeURIComponent(t)}/voice?${r}`}async startListening(){if(this.#p)return;let e=this.#D;e||(this.#U=!1,this.#C=null),this.#D=!1;let t=this.config?.agentId,s=this.config?.clientToken,i=this.config?.host;if(!t)throw new Error("Runtype voice requires an agentId");if(!s)throw new Error("Runtype voice requires a clientToken");if(!i)throw new Error("Runtype voice requires a host (or widget apiUrl)");let r=++this.#t;this.#b=!1,this.#p=!0;try{let l=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:Z,channelCount:1,echoCancellation:!0}});if(r!==this.#t){l.getTracks().forEach(p=>p.stop());return}this.#n=l;let d=window.AudioContext||window.webkitAudioContext,a=new d({sampleRate:Z});if(this.#i=a,a.state==="suspended"){if(await Promise.race([a.resume().catch(()=>{}),new Promise(p=>setTimeout(p,e?500:He))]),r!==this.#t)return;if(a.state!=="running")throw e?new Error(this.#C=`${O} Tap the mic to reconnect.`):new Error("Audio blocked until a tap")}let o=this.config?.createPlaybackEngine?await this.config.createPlaybackEngine():new N(Ue);if(r!==this.#t){o.destroy(),l.getTracks().forEach(p=>p.stop()),a.close().catch(()=>{});return}this.#o=o,this.#Y(),this.#he(a,l,r);let c=await this.#ue();if(r!==this.#t){c?.ws.close(1e3,"client ended call");return}if(c){let{ws:p}=c;this.#e=p,this.#se(p,r),c.live||p.send('{"type":"start"}'),this.#G(p),this.#s("listening");return}let u=new WebSocket(this.#te(i,t),["runtype.bearer",s]);u.binaryType="arraybuffer",this.#e=u,u.onopen=()=>{r===this.#t&&(this.#G(u),this.#s("listening"))},this.#se(u,r)}catch(l){throw this.#M(),this.#R(l),this.#s("error"),l}}#se(e,t){e.onmessage=s=>this.#ge(s,t),e.onerror=()=>{t!==this.#t||this.#j||(this.#R(new Error("Voice connection failed")),this.#s("error"),this.#M())},e.onclose=s=>{if(this.#b){this.#b=!1;return}if(t!==this.#t)return;let i=this.#j??(s.code===4408?{reason:"idle_timeout"}:null);if(!i){if(s.code!==1e3){let r=s.code?` (code ${s.code})`:"";this.#R(new Error(`Voice connection closed${r}`)),this.#s("error")}else this.#s("idle");this.#M();return}this.#pe(i.reason,i.message)}}#pe(e,t){let s=ue.includes(e)&&!this.#U;if(this.#M(),s){this.#U=!0,this.#p=!0,this.#C=e==="provider_error"?`${O} Reconnecting\u2026`:"Reconnecting\u2026",this.#Z=setTimeout(()=>{this.#p=!1,this.#D=!0,this.startListening().catch(()=>{})},1e3+Math.random()*1e3),this.#s("idle");return}if(ue.includes(e))return this.#C=O,this.#R(new Error(O)),this.#s("error");if(e==="error")return this.#s("error");this.#C=e==="quota"&&t||st.get(e)||null,this.#s("idle")}takeNotice(){let e=this.#C;return this.#C=null,e}getDisclosure(){let e=this.config?.disclosureText;return this.#p&&this.#u&&e!==!1?e||tt:null}async stopListening(){this.#M(),this.#s("idle")}async disconnect(){this.#M(),this.#s("disconnected"),this.#Q=[],this.#H=[],this.#F=[],this.#z=[],this.#X=[]}stopPlayback(){this.#ce();let e=this.#e;e&&e.readyState===WebSocket.OPEN&&(this.#u&&(this.#h=Date.now()+Je,e.send('{"type":"cancel"}')),this.#s("listening"))}getInterruptionMode(){return"barge-in"}isBargeInActive(){return this.#p}onLevel(e){this.#r.push(e)}async deactivateBargeIn(){this.#M(),this.#s("idle")}#he(e,t,s){let i=e.createMediaStreamSource(t);this.#c=i;let r=e.createScriptProcessor(De,1,1);this.#l=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 p=0;p<o.length;p++){let m=Math.max(-1,Math.min(1,o[p]));u+=m*m,c[p]=m<0?m*32768:m*32767}if(d&&a)this.#G(d),d.send(c.buffer);else for(this.#m.push(c.buffer),this.#y+=c.byteLength;this.#y>Be;)this.#y-=this.#m.shift().byteLength;if(this.#r.length>0){let p=Math.sqrt(u/o.length),m=Math.max(0,Math.min(1,p*qe));for(let g of this.#r)g(m)}},i.connect(r),r.connect(e.destination)}#G(e){for(let t of this.#m)e.send(t);this.#m=[],this.#y=0}#ge(e,t){if(t!==this.#t)return;if(e.data instanceof ArrayBuffer){this.#ye(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.#o?.setContinuousMode?.(this.#u)),Array.isArray(s.capabilities)&&(this.#f=new Set(s.capabilities)),typeof s.callId=="string"&&(this.#O=s.callId),this.#k=this.#u&&this.#f.has("client_delegation")&&!!this.bridge,this.#u&&!this.#d&&this.#s("listening"),this.#f.has("context")&&!this.#B&&(this.#B=!0,this.#L=this.#fe());break;case"transcript_update":{let i=s.role==="assistant"?"assistant":"user",r=s.utteranceId??s.turnId;if(!r||i==="assistant"&&this.#K())break;let l=String(r);if(i==="user")s.final===!0&&this.#ie(t),this.#v=!1;else{if(this.#f.has("delegation_read_back")){let d=s.delegationId;typeof d=="string"&&this.#T.has(d)&&!this.#P.has(l)?(this.#V.add(l),this.#v=!1):this.#v&&!this.#P.has(l)&&(this.#V.add(l),this.#v=!1)}else this.#v&&!this.#P.has(l)&&(this.#V.add(l),this.#v=!1);if(this.#P.add(l),this.#V.has(l))break}this.#J(i,s.text??"",s.final===!0,{turnId:l,...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 i=String(s.delegationId??s.turnId);if(s.type==="delegation_started"){this.#ie(t);let r=s.input;this.#k&&r&&this.#me(i,{delegationId:i,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.#T.has(i)&&!this.#I.delete(i)&&!this.#f.has("delegation_read_back")&&this.#re(i);this.#g=s.type==="delegation_started",!this.#d&&!this.#K()&&this.#s(this.#g?"processing":"listening");break}case"delegation_progress":{let i=String(s.delegationId);this.#T.has(i)&&!this.#I.has(i)&&!this.#x.has(i)&&(this.#I.add(i),this.#re(i));break}case"delegation_cancelled":this.#oe(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.#oe(String(s.delegationId));break;case"audio_clear":this.#ce(),this.#h=0,this.#s("listening");break;case"transcript_interim":this.#s("listening"),this.#J("user",s.text??"",!1);break;case"transcript_final":{let i=s.role==="assistant"?"assistant":"user";this.#s(i==="user"?"processing":"speaking"),this.#J(i,s.text??"",!0);break}case"audio_end":this.#o?this.#o.markStreamEnd():(this.#d=!1,this.#s("listening"));break;case"metrics":this.#ve({llmMs:s.llm_ms,ttsMs:s.tts_ms,firstAudioMs:s.first_audio_ms,totalMs:s.total_ms});break;case"error":this.#R(new Error(s.error||"Voice error")),this.#s("error");break;case"session_end":this.#j={reason:String(s.reason),...typeof s.message=="string"&&{message:s.message}};break}}async#fe(){let e=this.bridge?.getHistory()??[],t="";try{let s=this.config?.callContext;t=String((typeof s=="function"?await s():s)??"")}catch{}return ot(e,t)}#ie(e){let t=this.#L;if(!t)return;this.#L=null;let s=!1,i=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.#q={done:i,drop:()=>s=!0}}async#ne(){let e=this.#q;if(!e)return;let t,s=await Promise.race([e.done.then(()=>!1),new Promise(i=>{t=setTimeout(()=>i(!0),Ze)})]);clearTimeout(t),s&&e.drop()}#re(e){this.#v=!0,this.#W=e}#oe(e,t=!1){this.#x.add(e),this.#W===e&&(this.#v=!1),this.#I.delete(e),this.bridge?.dropDelegation?.(e,t),this.#E.get(e)?.abort()}#me(e,t,s){let i=this.bridge,r=({type:d,...a})=>{let o=this.#e;return s!==this.#t||o?.readyState!==WebSocket.OPEN||this.#x.has(e)?!1:(o.send(JSON.stringify({type:d,delegationId:e,...a})),!0)},l=(d,a,o,c=0)=>r({type:d,status:a,text:o,...c>0&&{streamedChars:c}});this.#$=this.#$.then(async()=>{if(s!==this.#t||this.#x.has(e))return;let d=null,a=this.#f.has("delegation_stream")&&this.#f.has("delegation_read_back"),o=b=>{d=(d??this.#ne()).then(()=>{r({type:"delegation_delta",text:b})&&this.#T.add(e)})},c=await i.runDelegatedTurn(a?{...t,stream:o}:t).catch(()=>({status:"failed",text:""}));await this.#ne(),await d;let u=a?c.streamedChars??0:0,p=!!c.followUp,m=p&&this.#f.has("delegation_update");if(!l(m?"delegation_update":"delegation_result",p&&!m?"completed":c.status,c.text,u)||(c.status!=="failed"&&c.inChat!==!1&&this.#T.add(e),!c.followUp))return;let f=new AbortController;this.#E.set(e,f),c.followUp({signal:f.signal,approvalTimeoutMs:this.config?.approvalTimeoutMs&&Math.min(this.config.approvalTimeoutMs,et),readBack:m,onUpdate:b=>l("delegation_update","pending_approval",b)}).then(b=>{this.#E.delete(e),m&&b&&!f.signal.aborted&&l("delegation_result",b.status,b.text)})})}#ye(e,t){if(t!==this.#t||!this.#o||this.#K())return;let s=at(e);s.length!==0&&(this.#d||(this.#d=!0,this.#s("speaking")),this.#Y(),this.#o.enqueue(s),this.#u&&this.#be(s.length))}#K(){return Date.now()<this.#h}#Y(){if(this.#A||!this.#o)return;this.#A=!0;let e=this.#t;this.#o.onFinished(()=>{e===this.#t&&(this.#A=!1,this.#ae())})}#be(e){let t=Date.now();this.#w=Math.max(t,this.#w)+e/48,clearTimeout(this.#S),this.#S=setTimeout(()=>this.#ae(),this.#w-t+Ye)}#ae(){this.#d=!1,this.#w=0,this.#e&&this.#e.readyState===WebSocket.OPEN&&this.#s(this.#g?"processing":"listening")}#ce(){this.#o?.flush(),this.#A=!1,this.#Y(),this.#d=!1,this.#w=0,clearTimeout(this.#S)}#M(){this.#t+=1,this.#p=!1,this.#d=!1,this.#N(),this.#u=!1,this.#g=!1,this.#k=!1,this.#f=new Set;for(let e of this.#E.values())e.abort();if(this.#E.clear(),this.#x.clear(),this.#O=void 0,this.#j=null,clearTimeout(this.#Z),this.#B=!1,this.#L=null,this.#q=null,this.#$=Promise.resolve(),this.#T.clear(),this.#I.clear(),this.#W=null,this.#v=!1,this.#P.clear(),this.#V.clear(),this.#A=!1,this.#h=0,this.#w=0,clearTimeout(this.#S),this.#m=[],this.#y=0,this.#l&&(this.#l.onaudioprocess=null,this.#l.disconnect(),this.#l=null),this.#c&&(this.#c.disconnect(),this.#c=null),this.#n&&(this.#n.getTracks().forEach(e=>e.stop()),this.#n=null),this.#i&&(this.#i.close().catch(()=>{}),this.#i=null),this.#o&&(this.#o.destroy(),this.#o=null),this.#e){this.#b=!0;try{this.#e.close(1e3,"client ended call")}catch{}this.#e=null}}onResult(e){this.#Q.push(e)}onError(e){this.#H.push(e)}onStatusChange(e){this.#F.push(e)}onTranscript(e){this.#z.push(e)}onMetrics(e){this.#X.push(e)}#s(e){this.#F.forEach(t=>t(e))}#R(e){this.#H.forEach(t=>t(e))}#J(e,t,s,i){this.#z.forEach(r=>r(e,t,s,i))}#ve(e){this.#X.forEach(t=>t(e))}};var _=class{constructor(e={}){this.config=e;this.type="browser";this.#e=null;this.#i=[];this.#r=[];this.#n=[];this.#c=!1;this.#l=typeof window<"u"?window:void 0}#e;#i;#r;#n;#c;#l;async connect(){this.#n.forEach(e=>e("connected"))}async startListening(){try{if(this.#c)throw new Error("Already listening");if(!this.#l)throw new Error("Window object not available");let e=this.#l.SpeechRecognition||this.#l.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(""),i=t.results[t.results.length-1].isFinal;this.#i.forEach(r=>r({text:s,confidence:i?.8:.5,provider:"browser"})),i&&!this.config?.continuous&&this.stopListening()},this.#e.onerror=t=>{this.#r.forEach(s=>s(new Error(t.error))),this.#n.forEach(s=>s("error"))},this.#e.onstart=()=>{this.#c=!0,this.#n.forEach(t=>t("listening"))},this.#e.onend=()=>{this.#c=!1,this.#n.forEach(t=>t("idle"))},this.#e.start()}catch(e){throw this.#r.forEach(t=>t(e)),this.#n.forEach(t=>t("error")),e}}async stopListening(){this.#e&&(this.#e.stop(),this.#e=null),this.#c=!1,this.#n.forEach(e=>e("idle"))}onResult(e){this.#i.push(e)}onError(e){this.#r.push(e)}onStatusChange(e){this.#n.push(e)}async disconnect(){await this.stopListening(),this.#n.forEach(e=>e("disconnected"))}static isSupported(){return"SpeechRecognition"in window||"webkitSpeechRecognition"in window}};function R(n){switch(n.type){case"runtype":if(!n.runtype)throw new Error("Runtype voice provider requires configuration");return new E(n.runtype);case"browser":if(!_.isSupported())throw new Error("Browser speech recognition not supported");return new _(n.browser||{});case"custom":{let e=n.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: ${n.type}`)}}function Q(n){if(n?.type==="custom"&&n.custom)return R({type:"custom",custom:n.custom});if(n?.type==="runtype"&&n.runtype)return R({type:"runtype",runtype:n.runtype});if(_.isSupported())return R({type:"browser",browser:n?.browser||{language:"en-US"}});throw new Error("No supported voice providers available")}function ge(n){try{return Q(n),!0}catch{return!1}}var fe=n=>n.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,""),U=class{constructor(e){this.host=e;this.turns=new Map;this.latestId=null;this.cancelled=new Set}apply(e,t,s,i,r,l){let d=this.host;t=t.trim();let a=this.turns.get(i);if(a||(a={},this.turns.set(i,a),this.latestId=i),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(i)){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 i;if(s){if(i=this.turns.get(s),i||(i={},this.turns.set(s,i)),i.claimed)return null;(!i.userId||!this.host.find(i.userId))&&(i.userFinal=!0,i.userId=this.host.inject({role:"user",content:e.trim()}).id)}else{let r=fe(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:fe(a.content)}]:[]}).filter(({text:d})=>d&&r);i=(l.find(({text:d})=>d===r)??l.find(({text:d})=>d.startsWith(r)||r.startsWith(d)))?.turn}return i?(i.claimed=!0,i.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 i=this.host.inject({role:"assistant",content:e,streaming:!1,voiceProcessing:!1}),r=t?this.turns.get(t):void 0;r&&(r.assistantId=i.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[i,r]of[[s.userId,s.userStartMs],[s.assistantId,s.assistantStartMs]])i&&r!==void 0&&r>e&&(!t||r<t.start)&&(t={start:r,id:i});return t&&this.host.find(t.id)}placeBefore(e){if(!e)return;let t=e.sequence??0,s=t-1;for(let i of this.turns.values())for(let r of[i.userId,i.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 i=this.turns.get(s)?.assistantId;i&&(t.add(i),this.host.markSpoken(i))}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 dt=new Set(["mr","mrs","ms","dr","prof","sr","jr","st","mt","vs","etc","approx","inc","ltd","co","corp","no","nos","fig","ft","dept","est","min","max","e.g","i.e","a.m","p.m","u.s","u.k"]),ut=/([.!?]+|[,;:])(["'”’)\]*_]*)(\s+)|\n\s*/g;function pt(n){let e=/(\S+)$/.exec(n)?.[1];if(!e)return!1;let t=e.replace(/^[("'“‘[*_]+/,"").toLowerCase();if(dt.has(t)||/^[a-z](?:\.[a-z])*$/.test(t))return!0;if(/^\d+$/.test(e)){let s=n.length-e.length;return s===0||/\n\s*$/.test(n.slice(0,s))}return!1}function*me(n,e){let t=new RegExp(ut.source,"g");for(let s=t.exec(n);s;s=t.exec(n)){let i=s[1];if(!n.slice(0,s.index+(i?.length??0)).trim()||i!==void 0&&(/^[,;:]$/.test(i)&&!e||i==="."&&pt(n.slice(0,s.index))))continue;let r=s.index+s[0].length;r<n.length&&(yield r)}}function ye(n,e){let t=n.slice(0,e),s=0;for(let i of t.matchAll(/\s+/g))t.slice(0,i.index).trim()&&(s=i.index+i[0].length);return s}function ee(n){let e=0;for(let i of me(n.slice(0,220),!0))e=i;if(e)return e;let t=ye(n,220);if(t)return t;let s=n.charCodeAt(219);return s>=55296&&s<=56319?219:220}var D=class{#e="";#i=!0;push(e){return this.#e+=e,this.#r()}flush(){let e=this.#r(),t=this.#e;if(this.#e="",t.trim()){for(let s=0;s<t.length;){let i=t.slice(s),r=i.length>220?ee(i):i.length;e.push(i.slice(0,r)),s+=r}this.#i=!1}return e}idle(){let e=this.#e;if(!e.trim()||!/(?:[.!?…]["'”’)\]*_]*|\n)\s*$/.test(e))return[];this.#e="",this.#i=!1;let t=[];for(let s=0;s<e.length;){let i=e.slice(s),r=i.length>220?ee(i):i.length;t.push(i.slice(0,r)),s+=r}return t}#r(){let e=[];for(let t=this.#n();t>0;t=this.#n())e.push(this.#e.slice(0,t)),this.#e=this.#e.slice(t),this.#i=!1;return e}#n(){let e=this.#e;if(!e.trim())return 0;let t=me(e,this.#i).next().value??0;if(t&&t<=220)return t;let s=/[.!?]["'”’)\]*_]*$/.test(e);if(this.#i&&!s){let i=e.match(/\S+\s+/g)?.length??0;if(e.trim().length>=30||i>=6){let r=ye(e,220);if(r)return r}}return e.length>220?ee(e):0}};var ht=200,gt=(n,e)=>{let t=0;for(;t<n.length&&t<e.length&&n[t]===e[t];)t+=1;return t},ft=50,mt="I need your answer in the chat before I can continue.",yt=1e3,bt=5*6e4,be="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)",vt=new RegExp(`^(?:${be})(?: (?:${be}))?(?: thanks| thank you)?$`),wt=n=>vt.test(n.toLowerCase().replace(/[^a-z' ]+/g," ").replace(/\s+/g," ").trim()),ve="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.",we=()=>new Promise(n=>setTimeout(n,ft)),te=(n,e)=>n.length>e?`${n.slice(0,e-1).trimEnd()}\u2026`:n,x=n=>n.replace(/^webmcp:/,"").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/[_\-.]+/g," ").trim().toLowerCase();function se(n,e=0){if(n==null||n==="")return"";if(typeof n!="object")return String(n);if(e>2)return"";if(Array.isArray(n))return n.map(r=>se(r,e+1)).filter(Boolean).join(", ");let t=n,s=t.quantity??t.qty??t.count,i=t.name??t.item??t.product??t.title;return s!=null&&i!=null&&typeof i!="object"?`${s} ${i}`:Object.entries(t).filter(([r])=>!r.startsWith("_")).map(([r,l])=>{let d=se(l,e+1);return d&&(e?`${x(r)} ${d}`:`${x(r)}: ${d}`)}).filter(Boolean).join(e?", ":"; ")}function Se(n){let e=n.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=yt-e.length-ve.length-2,s=n.map(i=>{let r=[x(i.toolName)];i.description&&r.push(`(${te(i.description.trim(),160)})`);let l=se(i.parameters);return l&&r.push(`with ${l}`),i.reason&&r.push(`because: ${te(i.reason.trim(),160)}`),te(`- ${r.join(" ")}`,Math.floor(t/n.length)-1)});return`${e}
|
|
6
6
|
${s.join(`
|
|
7
7
|
`)}
|
|
8
8
|
|
|
9
|
-
${
|
|
9
|
+
${ve}`}var B=n=>n.variant==="approval"&&n.approval?.status==="pending";function Ae(n){let e=null,t=null,s=()=>n.track(e??t),i=[],r=new Map,l=new Map,d=(g,f)=>{r.set(g,[...r.get(g)??[],f]),r.size>32&&r.delete(r.keys().next().value)},a=g=>n.messages().find(f=>f.id===g),o=g=>g.approvals.filter(f=>a(f)?.approval?.status==="pending"),c=g=>x(a(g)?.approval?.toolName??""),u=(g,f,b)=>{g.outcome={status:f,text:b};for(let v of o(g))n.decide(v)},p=g=>g.flatMap(f=>n.messages().find(b=>b.id===f)??[]).filter(f=>!f.variant&&f.content.trim()).map(f=>f.content.trim()).join(`
|
|
10
10
|
|
|
11
|
-
`),
|
|
11
|
+
`),m=async g=>{do await we();while(n.busy()&&!(g&&(n.parked()||g.failed)))};return{getHistory:()=>{let g=n.messages().filter(v=>(v.role==="user"||v.role==="assistant")&&!v.variant&&!v.voiceProcessing&&!v.streaming&&v.content),f=!1,b=[];for(let v=g.length-1;v>=0;v-=1){let C=g[v];if(C.role==="user")f=!1;else if(!C.voiceCaption)f=!0;else if(f)continue;b.unshift({role:C.role,content:C.content})}return b},dropDelegation(g,f){l.set(g,!!f),l.size>32&&l.delete(l.keys().next().value);let b=f&&i.find(v=>v.delegationId===g);b&&!b.outcome&&u(b,"timeout","");for(let v of r.get(g)??[])v.stopStream?.(),v.dropped=!0,v.ids.length&&n.unspoken(v.ids)},async runDelegatedTurn({delegationId:g,userText:f,userUtteranceIds:b,stream:v}){let C=i.filter(h=>o(h).length),q=C.flatMap(o);if(q.length===1&&wt(f)){let h=c(q[0]);return u(C[0],"denied",""),{status:"denied",text:`Okay, I cancelled the ${h} request. Nothing was done.`,inChat:!1}}let ie=n.parked()&&n.messages().every(h=>!B(h)||q.includes(h.id));n.busy()&&!ie&&await m();let Me=new Set(n.messages().map(h=>h.id)),$=()=>n.messages().filter(h=>!Me.has(h.id)&&h.variant==="approval"),S={ids:[],failed:!1},I=v?new D:null,j="",ne="",P=!1,W=h=>{for(let y of h)ne+=y,v(y)},V;I&&(S.onUpdate=()=>{if(P)return;let h=p(S.ids);if(!h.startsWith(j)){P=!0,clearTimeout(V);return}if(h.length===j.length)return;let y=h.slice(j.length);j=h,W(I.push(y)),clearTimeout(V),V=setTimeout(()=>{P||W(I.idle())},ht)},S.stopStream=()=>{clearTimeout(V),P=!0,S.onUpdate=void 0}),d(g,S),e=S,s();try{await n.send(f,n.claim(f,b)??void 0),await m(S)}catch{S.failed=!0}finally{e=null,s()}I&&(S.onUpdate?.(),clearTimeout(V),P||W(I.flush()),S.onUpdate=void 0,S.stopStream=void 0);let H=h=>{let y=gt(ne,h);return y>0?{streamedChars:y}:{}},Te=S.ids.flatMap(h=>n.messages().find(y=>y.id===h)??[]),k=p(S.ids),L=S.failed?[]:$().filter(B),_e=new Set(L.map(h=>x(h.approval.toolName)));for(let h of C){if(h.outcome)continue;for(let A of o(h).filter(F=>_e.has(c(F))))h.replaced.add(A),n.decide(A);let y=c(h.approvals[0]);h.approvals.every(A=>h.replaced.has(A))?h.outcome={status:"cancelled",text:`The earlier ${y} request was replaced by the new one; it was not done.`}:ie&&h.approvals.every(A=>a(A)?.approval?.status==="denied")&&(h.outcome={status:"cancelled",text:`The earlier ${y} request was replaced by the new one; it was not done.`})}if(L.length){let h=new Set(L.map(A=>A.id)),y={delegationId:g,approvals:[...h],at:Date.now(),replaced:new Set};return i.push(y),l.get(g)&&u(y,"timeout",""),k=`${k}
|
|
12
12
|
|
|
13
|
-
${
|
|
13
|
+
${Se(L.map(A=>A.approval))}`.trim(),{status:"pending_approval",text:k,...H(k),followUp:async({signal:A,approvalTimeoutMs:F=bt,readBack:re=!0,onUpdate:Ee})=>{let M={ids:[],failed:!1};r.delete(g),d(g,M);let oe=()=>$().filter(w=>h.has(w.id)||M.ids.includes(w.id)),xe=()=>$().filter(w=>B(w)&&!h.has(w.id)&&!i.some(T=>T.approvals.includes(w.id))&&(M.ids.includes(w.id)||w.approval?.toolType==="webmcp"&&t===M)),ae=()=>{t=M,s()};re&&ae();try{for(;!A.aborted&&!y.outcome&&(e||n.busy()||oe().some(B));){re&&t!==M&&!o(y).length&&ae();let w=xe();if(w.length){for(let T of w)h.add(T.id),y.approvals.push(T.id);y.at=Date.now(),Ee?.(Se(w.map(T=>T.approval)))}if(Date.now()-y.at>=F&&o(y).length&&(!n.busy()||n.parked())){u(y,"timeout",`That ${c(y.approvals[0])} request expired, so nothing was done.`);break}await we()}}finally{t===M&&(t=null,s()),i.splice(i.indexOf(y),1)}if(A.aborted)return null;if(y.outcome)return y.outcome;if(M.failed)return{status:"failed",text:`The ${c(y.approvals[0])} request didn't complete.`};let ce=oe(),z=w=>ce.filter(w).map(T=>x(T.approval.toolName)).join(", "),X=ce.some(w=>w.approval?.status==="approved"),G=z(w=>w.approval?.status==="denied"&&!y.replaced.has(w.id)),K=z(w=>y.replaced.has(w.id)),Y=z(w=>w.approval?.status==="timeout"),Ie=[X?p(M.ids):"",G&&`The user declined the ${G} request in the chat, so ${X?"that part was not done":"nothing was done"}.`,K&&`The earlier ${K} request was replaced by the new one; it was not done.`,Y&&`The ${Y} request timed out, so it was not done.`].filter(Boolean).join(`
|
|
14
14
|
|
|
15
|
-
`);return{status:
|
|
15
|
+
`);return{status:X?"completed":G?"denied":K?"cancelled":Y?"timeout":"completed",text:Ie}}}}return!S.failed&&n.parked()||Te.some(h=>h.agentMetadata?.awaitingLocalTool&&!h.agentMetadata.askUserQuestionAnswered&&!h.toolCall?.name?.startsWith("webmcp:"))?(k=`${k}
|
|
16
16
|
|
|
17
|
-
${
|
|
17
|
+
${mt}`.trim(),{status:S.failed?"failed":"completed",text:k,...H(k)}):{status:!S.failed&&k?"completed":"failed",text:k,...H(k)}}}}var ke=(n,e,t,s)=>{let i=n.session;try{n.keyed=t?new t({find:o=>i.messages.find(c=>c.id===o),inject:o=>i.injectMessage(o),upsert:o=>i.upsertMessage(o),settle:o=>{i.messages=i.messages.map(c=>o.has(c.id)?{...c,streaming:!1,voiceProcessing:!1}:c),i.callbacks.onMessagesChanged([...i.messages])},setStreaming:o=>{(o||!n.busy())&&n.setStreaming(o)},markSpoken:o=>{i.ttsSpokenMessageIds.add(o)}}):null,s&&e.setSessionBridge&&e.setSessionBridge(s({messages:()=>i.messages,busy:()=>n.busy(),parked:()=>i.webMcpApprovalResolvers.size>0,claim:(o,c)=>n.keyed?.claimUserTurn(o,c)??null,send:(o,c)=>i.sendMessage(o,{viaVoice:!0,voiceTurn:{userMessageId:c}}),track:o=>{n.setDelegation(o)},unspoken:o=>{for(let c of o)i.ttsSpokenMessageIds.delete(c);i.streaming||i.speakLatestAssistantMessage(o)},decide:o=>{if(i.webMcpApprovalResolvers.has(o))return i.resolveWebMcpApproval(o,"denied");let c=i.messages.find(u=>u.id===o)?.approval;c?.status==="pending"&&i.resolveApproval(c,"denied")}}));let r=n.generation(),l=()=>n.provider()===e&&r===n.generation(),a=(i.config.voiceRecognition??{}).processingErrorText??"Voice processing failed. Please try again.";e.onResult(o=>{l()&&o.provider!=="runtype"&&o.text&&o.text.trim()&&i.sendMessage(o.text,{viaVoice:!0})}),e.onTranscript&&e.onTranscript((o,c,u,p)=>{if(l()){if(p?.turnId){n.keyed?.apply(o,c,u,p.turnId,p.startMs,p.caption);return}if(o==="user"){if(n.pendingUser)i.upsertMessage({id:n.pendingUser,role:"user",content:c,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!u});else{let m=i.injectMessage({role:"user",content:c,streaming:!1,voiceProcessing:!u});n.pendingUser=m.id}if(u){n.turns().start(p?.turnId),n.pendingUser=null;let m=i.injectMessage({role:"assistant",content:"",streaming:!0,voiceProcessing:!0});n.pendingAssistant=m.id,n.setStreaming(!0)}}else{if(!n.turns().accepts(p?.turnId))return;if(n.pendingAssistant)i.upsertMessage({id:n.pendingAssistant,role:"assistant",content:c,createdAt:new Date().toISOString(),streaming:!u,voiceProcessing:!u});else{let m=i.injectMessage({role:"assistant",content:c,streaming:!u,voiceProcessing:!u});n.pendingAssistant=m.id}u&&(n.pendingAssistant&&i.ttsSpokenMessageIds.add(n.pendingAssistant),n.setStreaming(!1),n.pendingAssistant=null)}}}),e.onLevel&&e.onLevel(o=>{l()&&n.setLevel(Number.isFinite(o)?Math.max(0,Math.min(1,o)):0)}),e.onMetrics&&e.onMetrics(o=>{l()&&i.config.voiceRecognition?.onMetrics?.(o)}),e.onError(o=>{l()&&(console.error("Voice error:",o),n.pendingAssistant&&(i.upsertMessage({id:n.pendingAssistant,role:"assistant",content:a,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!1}),n.setStreaming(!1),n.pendingUser=null,n.pendingAssistant=null),n.keyed?.fail(a))}),e.onStatusChange(o=>{l()&&(n.setStatus(o),(o==="listening"||o==="idle"||o==="disconnected")&&n.settlePending(o!=="listening"),(o==="idle"||o==="disconnected")&&n.keyed?.settle(),i.callbacks.onVoiceStatusChanged?.(o))}),e.connect()}catch(r){console.error("Failed to setup voice:",r)}};var Ce=n=>{let e=a=>{if(n.original)return;let o=n.config().voiceRecognition??{};n.original={backgroundColor:a.style.backgroundColor,color:a.style.color,borderColor:a.style.borderColor,iconName:o.iconName??"mic",iconSize:parseFloat(o.iconSize??"")||n.iconFallbackPx}},t=(a,o,c)=>{let u=a.querySelector("svg");u&&u.remove();let p=n.original?.iconSize??(parseFloat(n.config().voiceRecognition?.iconSize??"")||n.iconFallbackPx),m=n.renderIcon(o,p,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=n.mic();if(!a)return;e(a);let o=n.config().voiceRecognition??{},c=o.recordingBackgroundColor,u=o.recordingIconColor,p=o.recordingBorderColor;if(s(a),a.classList.add("persona-voice-recording"),n.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)}p&&(a.style.borderColor=p),a.setAttribute("aria-label","Stop voice recognition")},processing:()=>{let a=n.mic();if(!a)return;e(a);let o=n.config().voiceRecognition??{},c=n.session().getVoiceInterruptionMode(),u=n.original,p=o.processingIconName??"loader",m=o.processingIconColor??u?.color??"",g=o.processingBackgroundColor??u?.backgroundColor??"",f=o.processingBorderColor??u?.borderColor??"";s(a),a.classList.add("persona-voice-processing"),n.setMicState("processing"),a.style.backgroundColor=g,a.style.borderColor=f;let b=m||"currentColor";a.style.color=b,t(a,p,b),a.setAttribute("aria-label","Processing voice input"),c==="none"&&(a.style.cursor="default")},speaking:()=>{let a=n.mic();if(!a)return;e(a);let o=n.config().voiceRecognition??{},c=n.session().getVoiceInterruptionMode(),u=n.original,p=c==="cancel"?"square":c==="barge-in"?"mic":"volume-2",m=o.speakingIconName??p,g=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??""),b=o.speakingBorderColor??(c==="barge-in"?o.recordingBorderColor??"":u?.borderColor??"");s(a),a.classList.add("persona-voice-speaking"),n.setMicState("speaking"),a.style.backgroundColor=f,a.style.borderColor=b;let v=g||"currentColor";a.style.color=v,t(a,m,v);let C=c==="cancel"?"Stop playback and re-record":c==="barge-in"?"Speak to interrupt":"Agent is speaking";a.setAttribute("aria-label",C),c==="none"&&(a.style.cursor="default"),c==="barge-in"&&a.classList.add("persona-voice-recording")},reset:()=>{let a=n.mic();if(!a)return;s(a),n.setMicState("idle");let o=n.original;o&&(a.style.backgroundColor=o.backgroundColor??"",a.style.color=o.color??"",a.style.borderColor=o.borderColor??"",t(a,o.iconName,o.color||"currentColor"),n.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 = {
|
|
@@ -7289,6 +7294,13 @@ type VoiceDelegationRequest = {
|
|
|
7289
7294
|
role: string;
|
|
7290
7295
|
content: unknown;
|
|
7291
7296
|
}>;
|
|
7297
|
+
/**
|
|
7298
|
+
* Set when the server streams delegated answers (`delegation_stream`): called
|
|
7299
|
+
* with each speakable piece of the turn's answer, in order, while it renders.
|
|
7300
|
+
* The pieces, concatenated, are a prefix of the result's `text`; the result
|
|
7301
|
+
* says how much of it with `streamedChars`.
|
|
7302
|
+
*/
|
|
7303
|
+
stream?: (text: string) => void;
|
|
7292
7304
|
};
|
|
7293
7305
|
/**
|
|
7294
7306
|
* How a delegated turn ended, or that it waits on an approval (contract
|
|
@@ -7319,6 +7331,12 @@ type VoiceDelegationResult = {
|
|
|
7319
7331
|
* @default true
|
|
7320
7332
|
*/
|
|
7321
7333
|
inChat?: boolean;
|
|
7334
|
+
/**
|
|
7335
|
+
* How many leading characters of `text` already went out through
|
|
7336
|
+
* `request.stream` (the rest, such as an approval script, is unstreamed).
|
|
7337
|
+
* Omitted or 0: nothing was streamed.
|
|
7338
|
+
*/
|
|
7339
|
+
streamedChars?: number;
|
|
7322
7340
|
/**
|
|
7323
7341
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7324
7342
|
* Resolves with the terminal result once the visitor decides (or the
|
|
@@ -10506,6 +10524,8 @@ declare class RuntypeVoiceProvider implements VoiceProvider {
|
|
|
10506
10524
|
prewarm(): void;
|
|
10507
10525
|
/** Start the call: acquire mic, open the WS, stream PCM until hang-up. */
|
|
10508
10526
|
startListening(): Promise<void>;
|
|
10527
|
+
/** Status-line text for the call (why it ended, or that it is reconnecting), once. */
|
|
10528
|
+
takeNotice(): string | null;
|
|
10509
10529
|
/** The AI-disclosure notice for a live speech-to-speech call (`disclosureText`; `false` hides it). */
|
|
10510
10530
|
getDisclosure(): string | null;
|
|
10511
10531
|
/** End the call (hang up). */
|
|
@@ -10628,11 +10648,16 @@ declare class KeyedVoiceTranscript {
|
|
|
10628
10648
|
/**
|
|
10629
10649
|
* What a delegated turn streamed: its assistant messages, whether it failed,
|
|
10630
10650
|
* and whether the server dropped its result (then browser TTS may read it).
|
|
10651
|
+
* `onUpdate` runs after each of its assistant messages is stored (the answer
|
|
10652
|
+
* grew), so a streaming bridge can read the new text.
|
|
10631
10653
|
*/
|
|
10632
10654
|
type VoiceDelegationCapture = {
|
|
10633
10655
|
ids: string[];
|
|
10634
10656
|
failed: boolean;
|
|
10635
10657
|
dropped?: boolean;
|
|
10658
|
+
onUpdate?: () => void;
|
|
10659
|
+
/** Stops a streaming answer (its pending idle flush included); set while it streams. */
|
|
10660
|
+
stopStream?: () => void;
|
|
10636
10661
|
};
|
|
10637
10662
|
/** The session internals the delegation bridge drives. */
|
|
10638
10663
|
interface VoiceDelegationHost {
|
|
@@ -10676,6 +10701,12 @@ type DispatchOptions = {
|
|
|
10676
10701
|
* `submitMode: "interrupt"` so the server cancels the prior run.
|
|
10677
10702
|
*/
|
|
10678
10703
|
interrupt?: boolean;
|
|
10704
|
+
/**
|
|
10705
|
+
* Client-token only: a voice model reads the reply aloud (a delegated voice
|
|
10706
|
+
* turn). Sends `voice: { spoken: true }` so the server asks for a speakable
|
|
10707
|
+
* answer.
|
|
10708
|
+
*/
|
|
10709
|
+
voiceSpoken?: boolean;
|
|
10679
10710
|
};
|
|
10680
10711
|
type SSEHandler = (event: AgentWidgetEvent) => void;
|
|
10681
10712
|
type SSEEventCallback = (eventType: string, payload: unknown) => void;
|
|
@@ -11077,6 +11108,8 @@ declare class AgentWidgetSession {
|
|
|
11077
11108
|
* Get current voice status
|
|
11078
11109
|
*/
|
|
11079
11110
|
getVoiceStatus(): VoiceStatus;
|
|
11111
|
+
/** The voice call's pending status-line notice (why it ended, or reconnecting), once. */
|
|
11112
|
+
getVoiceNotice(): string | null;
|
|
11080
11113
|
/** The live call's AI-disclosure notice, if it shows one. */
|
|
11081
11114
|
getVoiceDisclosure(): string | null;
|
|
11082
11115
|
/**
|
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 = {
|
|
@@ -7289,6 +7294,13 @@ type VoiceDelegationRequest = {
|
|
|
7289
7294
|
role: string;
|
|
7290
7295
|
content: unknown;
|
|
7291
7296
|
}>;
|
|
7297
|
+
/**
|
|
7298
|
+
* Set when the server streams delegated answers (`delegation_stream`): called
|
|
7299
|
+
* with each speakable piece of the turn's answer, in order, while it renders.
|
|
7300
|
+
* The pieces, concatenated, are a prefix of the result's `text`; the result
|
|
7301
|
+
* says how much of it with `streamedChars`.
|
|
7302
|
+
*/
|
|
7303
|
+
stream?: (text: string) => void;
|
|
7292
7304
|
};
|
|
7293
7305
|
/**
|
|
7294
7306
|
* How a delegated turn ended, or that it waits on an approval (contract
|
|
@@ -7319,6 +7331,12 @@ type VoiceDelegationResult = {
|
|
|
7319
7331
|
* @default true
|
|
7320
7332
|
*/
|
|
7321
7333
|
inChat?: boolean;
|
|
7334
|
+
/**
|
|
7335
|
+
* How many leading characters of `text` already went out through
|
|
7336
|
+
* `request.stream` (the rest, such as an approval script, is unstreamed).
|
|
7337
|
+
* Omitted or 0: nothing was streamed.
|
|
7338
|
+
*/
|
|
7339
|
+
streamedChars?: number;
|
|
7322
7340
|
/**
|
|
7323
7341
|
* Set when the turn parked on approvals (`text` then asks for the decision).
|
|
7324
7342
|
* Resolves with the terminal result once the visitor decides (or the
|
|
@@ -10506,6 +10524,8 @@ declare class RuntypeVoiceProvider implements VoiceProvider {
|
|
|
10506
10524
|
prewarm(): void;
|
|
10507
10525
|
/** Start the call: acquire mic, open the WS, stream PCM until hang-up. */
|
|
10508
10526
|
startListening(): Promise<void>;
|
|
10527
|
+
/** Status-line text for the call (why it ended, or that it is reconnecting), once. */
|
|
10528
|
+
takeNotice(): string | null;
|
|
10509
10529
|
/** The AI-disclosure notice for a live speech-to-speech call (`disclosureText`; `false` hides it). */
|
|
10510
10530
|
getDisclosure(): string | null;
|
|
10511
10531
|
/** End the call (hang up). */
|
|
@@ -10628,11 +10648,16 @@ declare class KeyedVoiceTranscript {
|
|
|
10628
10648
|
/**
|
|
10629
10649
|
* What a delegated turn streamed: its assistant messages, whether it failed,
|
|
10630
10650
|
* and whether the server dropped its result (then browser TTS may read it).
|
|
10651
|
+
* `onUpdate` runs after each of its assistant messages is stored (the answer
|
|
10652
|
+
* grew), so a streaming bridge can read the new text.
|
|
10631
10653
|
*/
|
|
10632
10654
|
type VoiceDelegationCapture = {
|
|
10633
10655
|
ids: string[];
|
|
10634
10656
|
failed: boolean;
|
|
10635
10657
|
dropped?: boolean;
|
|
10658
|
+
onUpdate?: () => void;
|
|
10659
|
+
/** Stops a streaming answer (its pending idle flush included); set while it streams. */
|
|
10660
|
+
stopStream?: () => void;
|
|
10636
10661
|
};
|
|
10637
10662
|
/** The session internals the delegation bridge drives. */
|
|
10638
10663
|
interface VoiceDelegationHost {
|
|
@@ -10676,6 +10701,12 @@ type DispatchOptions = {
|
|
|
10676
10701
|
* `submitMode: "interrupt"` so the server cancels the prior run.
|
|
10677
10702
|
*/
|
|
10678
10703
|
interrupt?: boolean;
|
|
10704
|
+
/**
|
|
10705
|
+
* Client-token only: a voice model reads the reply aloud (a delegated voice
|
|
10706
|
+
* turn). Sends `voice: { spoken: true }` so the server asks for a speakable
|
|
10707
|
+
* answer.
|
|
10708
|
+
*/
|
|
10709
|
+
voiceSpoken?: boolean;
|
|
10679
10710
|
};
|
|
10680
10711
|
type SSEHandler = (event: AgentWidgetEvent) => void;
|
|
10681
10712
|
type SSEEventCallback = (eventType: string, payload: unknown) => void;
|
|
@@ -11077,6 +11108,8 @@ declare class AgentWidgetSession {
|
|
|
11077
11108
|
* Get current voice status
|
|
11078
11109
|
*/
|
|
11079
11110
|
getVoiceStatus(): VoiceStatus;
|
|
11111
|
+
/** The voice call's pending status-line notice (why it ended, or reconnecting), once. */
|
|
11112
|
+
getVoiceNotice(): string | null;
|
|
11080
11113
|
/** The live call's AI-disclosure notice, if it shows one. */
|
|
11081
11114
|
getVoiceDisclosure(): string | null;
|
|
11082
11115
|
/**
|