@runtypelabs/persona 4.27.0 → 4.28.1

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.
Files changed (72) hide show
  1. package/README.md +25 -0
  2. package/dist/{approval-ui-QAKWNFNM.js → approval-ui-OBBI62ES.js} +1 -1
  3. package/dist/approval-ui.cjs +2 -2
  4. package/dist/approval-ui.d.cts +20 -5
  5. package/dist/approval-ui.d.ts +20 -5
  6. package/dist/approval-ui.js +2 -2
  7. package/dist/artifacts-ui.d.cts +20 -5
  8. package/dist/artifacts-ui.d.ts +20 -5
  9. package/dist/{chunk-NQLDCJAP.js → chunk-D4TDKCT5.js} +2 -2
  10. package/dist/chunk-FNXK3VTC.js +1 -0
  11. package/dist/{client-history-HTRKHBAF.js → client-history-QGAFMCBE.js} +1 -1
  12. package/dist/client-history.js +1 -1
  13. package/dist/{client-stream-N22JHTLE.js → client-stream-WXD2FL23.js} +1 -1
  14. package/dist/client-stream.js +3 -3
  15. package/dist/codegen.cjs +4 -4
  16. package/dist/codegen.js +5 -5
  17. package/dist/context-mentions.d.cts +20 -5
  18. package/dist/context-mentions.d.ts +20 -5
  19. package/dist/event-stream-view.d.cts +20 -5
  20. package/dist/event-stream-view.d.ts +20 -5
  21. package/dist/forms-ui.d.cts +26 -5
  22. package/dist/forms-ui.d.ts +26 -5
  23. package/dist/index.cjs +41 -41
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +59 -30
  26. package/dist/index.d.ts +59 -30
  27. package/dist/index.global.js +1 -1
  28. package/dist/index.global.js.map +1 -1
  29. package/dist/index.js +41 -41
  30. package/dist/index.js.map +1 -1
  31. package/dist/session-reconnect.d.cts +20 -5
  32. package/dist/session-reconnect.d.ts +20 -5
  33. package/dist/smart-dom-reader.d.cts +20 -5
  34. package/dist/smart-dom-reader.d.ts +20 -5
  35. package/dist/theme-editor-preview.cjs +63 -63
  36. package/dist/theme-editor-preview.d.cts +20 -5
  37. package/dist/theme-editor-preview.d.ts +20 -5
  38. package/dist/theme-editor-preview.js +6 -6
  39. package/dist/theme-editor.d.cts +21 -6
  40. package/dist/theme-editor.d.ts +21 -6
  41. package/dist/voice-runtime-TWFJ4UUS.js +17 -0
  42. package/dist/voice-runtime.cjs +8 -8
  43. package/dist/voice-runtime.d.cts +31 -5
  44. package/dist/voice-runtime.d.ts +31 -5
  45. package/dist/voice-runtime.js +8 -8
  46. package/dist/webmcp-runtime-5Q3IHAHP.js +6 -0
  47. package/dist/webmcp-runtime.cjs +2 -2
  48. package/dist/webmcp-runtime.d.cts +22 -26
  49. package/dist/webmcp-runtime.d.ts +22 -26
  50. package/dist/webmcp-runtime.js +2 -2
  51. package/package.json +5 -2
  52. package/src/client.interrupt.test.ts +18 -0
  53. package/src/client.ts +7 -0
  54. package/src/generated/runtype-openapi-contract.ts +3 -0
  55. package/src/session.ts +11 -3
  56. package/src/session.voice.test.ts +140 -0
  57. package/src/theme-editor/webmcp/types.ts +1 -1
  58. package/src/types.ts +26 -5
  59. package/src/voice/runtype-voice-provider.ts +93 -11
  60. package/src/voice/voice-clause-buffer.test.ts +143 -0
  61. package/src/voice/voice-clause-buffer.ts +187 -0
  62. package/src/voice/voice-delegation.ts +85 -3
  63. package/src/voice/voice.test.ts +257 -2
  64. package/src/webmcp-bridge.test.ts +87 -21
  65. package/src/webmcp-bridge.ts +21 -26
  66. package/src/webmcp-polyfill.integration.test.ts +339 -0
  67. package/src/webmcp-polyfill.ts +7 -4
  68. package/src/webmcp-runtime-bundle.test.ts +1 -1
  69. package/src/webmcp-runtime-entry.ts +34 -19
  70. package/dist/chunk-3255TNY7.js +0 -1
  71. package/dist/voice-runtime-RHRX4F3T.js +0 -17
  72. package/dist/webmcp-runtime-V6ZWW3PI.js +0 -6
@@ -3281,9 +3281,8 @@ type WebMcpConfirmInfo = {
3281
3281
  };
3282
3282
  /**
3283
3283
  * Why the confirm was requested. Currently always `'gate'`: the default
3284
- * confirm-by-default gate that fires before every `webmcp:*` call. (The
3285
- * `@mcp-b/webmcp-polyfill` owns the spec's `requestUserInteraction` callback
3286
- * internally, so Persona no longer surfaces a nested in-tool confirm.)
3284
+ * confirm-by-default gate that fires before every `webmcp:*` call. Tool
3285
+ * callbacks on v6 receive an AbortSignal, not a nested confirmation API.
3287
3286
  */
3288
3287
  reason: 'gate';
3289
3288
  };
@@ -7294,6 +7293,13 @@ type VoiceDelegationRequest = {
7294
7293
  role: string;
7295
7294
  content: unknown;
7296
7295
  }>;
7296
+ /**
7297
+ * Set when the server streams delegated answers (`delegation_stream`): called
7298
+ * with each speakable piece of the turn's answer, in order, while it renders.
7299
+ * The pieces, concatenated, are a prefix of the result's `text`; the result
7300
+ * says how much of it with `streamedChars`.
7301
+ */
7302
+ stream?: (text: string) => void;
7297
7303
  };
7298
7304
  /**
7299
7305
  * How a delegated turn ended, or that it waits on an approval (contract
@@ -7324,6 +7330,12 @@ type VoiceDelegationResult = {
7324
7330
  * @default true
7325
7331
  */
7326
7332
  inChat?: boolean;
7333
+ /**
7334
+ * How many leading characters of `text` already went out through
7335
+ * `request.stream` (the rest, such as an approval script, is unstreamed).
7336
+ * Omitted or 0: nothing was streamed.
7337
+ */
7338
+ streamedChars?: number;
7327
7339
  /**
7328
7340
  * Set when the turn parked on approvals (`text` then asks for the decision).
7329
7341
  * Resolves with the terminal result once the visitor decides (or the
@@ -9541,8 +9553,11 @@ type AgentWidgetConfig = {
9541
9553
  /**
9542
9554
  * WebMCP: consume page-registered tools (`document.modelContext.registerTool`).
9543
9555
  * When `enabled`, the widget installs `@mcp-b/webmcp-polyfill`, snapshots the
9544
- * registry on every dispatch, ships it as `clientTools[]`, and executes
9545
- * returned `webmcp:*` tool calls with confirm-by-default gating.
9556
+ * current document's registry on every dispatch, ships it as `clientTools[]`,
9557
+ * and executes returned `webmcp:*` calls with confirm-by-default gating.
9558
+ * Supports host-installed v5 JSON-string and v6 object-input contracts.
9559
+ * The automatic fallback stays on v5 to preserve existing browser support
9560
+ * and callback-result behavior.
9546
9561
  *
9547
9562
  * Server-side policy on the chat surface is the source of truth: these
9548
9563
  * fields layer on top.
@@ -10635,11 +10650,16 @@ declare class KeyedVoiceTranscript {
10635
10650
  /**
10636
10651
  * What a delegated turn streamed: its assistant messages, whether it failed,
10637
10652
  * and whether the server dropped its result (then browser TTS may read it).
10653
+ * `onUpdate` runs after each of its assistant messages is stored (the answer
10654
+ * grew), so a streaming bridge can read the new text.
10638
10655
  */
10639
10656
  type VoiceDelegationCapture = {
10640
10657
  ids: string[];
10641
10658
  failed: boolean;
10642
10659
  dropped?: boolean;
10660
+ onUpdate?: () => void;
10661
+ /** Stops a streaming answer (its pending idle flush included); set while it streams. */
10662
+ stopStream?: () => void;
10643
10663
  };
10644
10664
  /** The session internals the delegation bridge drives. */
10645
10665
  interface VoiceDelegationHost {
@@ -10683,6 +10703,12 @@ type DispatchOptions = {
10683
10703
  * `submitMode: "interrupt"` so the server cancels the prior run.
10684
10704
  */
10685
10705
  interrupt?: boolean;
10706
+ /**
10707
+ * Client-token only: a voice model reads the reply aloud (a delegated voice
10708
+ * turn). Sends `voice: { spoken: true }` so the server asks for a speakable
10709
+ * answer.
10710
+ */
10711
+ voiceSpoken?: boolean;
10686
10712
  };
10687
10713
  type SSEHandler = (event: AgentWidgetEvent) => void;
10688
10714
  type SSEEventCallback = (eventType: string, payload: unknown) => void;
@@ -1,17 +1,17 @@
1
- var P=class{#e=null;#r=0;#d=[];#i=[];#a=[];#c=!1;#f=!1;#m=0;#n=!1;#p=!1;#l;#t=[];#y=0;#M=!1;#o;#u;#g;#h=null;constructor(e=24e3,t={}){this.#u=e;let s=Math.max(0,t.prebufferMs??0);this.#g=Math.round(e*s/1e3),this.#l=this.#g>0}#b(){if(!this.#e){let t=typeof window<"u"?window:void 0;if(!t)throw new Error("AudioPlaybackManager requires a browser environment");let s=t.AudioContext||t.webkitAudioContext;this.#e=new s({sampleRate:this.#u})}let e=this.#e;return e.state==="suspended"&&!this.#p&&e.resume(),e}enqueue(e){if(e.length===0)return;let t=e;if(this.#h){let n=new Uint8Array(this.#h.length+e.length);n.set(this.#h),n.set(e,this.#h.length),t=n,this.#h=null}if(t.length%2!==0&&(this.#h=new Uint8Array([t[t.length-1]]),t=t.subarray(0,t.length-1)),t.length===0)return;let s=this.#S(t);s.length!==0&&(this.#l?(this.#t.push(s),this.#y+=s.length,clearTimeout(this.#o),this.#y>=this.#g?this.#v():this.#M&&(this.#o=setTimeout(()=>this.#v(),this.#g/this.#u*1e3))):this.#w(s))}markStreamEnd(){this.#t.length>0&&this.#v(),this.#f=!0,this.#k()}flush(){for(let e of this.#d){e.onended=null;try{e.stop(),e.disconnect()}catch{}}this.#d=[],this.#m=0,this.#r=0,this.#c=!1,this.#f=!1,this.#i=[],this.#a=[],this.#h=null,this.#t=[],this.#y=0,this.#l=this.#g>0,this.#n=!1,clearTimeout(this.#o)}setContinuousMode(e){this.#M=e}isPlaying(){return this.#c}onFinished(e){this.#i.push(e)}onStarted(e){this.#a.push(e)}pause(){this.#p=!0,this.#e&&this.#e.state==="running"&&this.#e.suspend()}resume(){this.#p=!1,this.#e&&this.#e.state==="suspended"&&this.#e.resume()}async destroy(){this.flush(),this.#e&&(await this.#e.close(),this.#e=null)}#v(){this.#l=!1;let e=this.#t;this.#t=[],this.#y=0;for(let t of e)this.#w(t)}#w(e){if(e.length===0)return;let t=this.#b(),s=t.createBuffer(1,e.length,this.#u);s.getChannelData(0).set(e);let n=t.createBufferSource();n.buffer=s,n.connect(t.destination);let r=t.currentTime;if(this.#r===0?this.#r=r:this.#r<r&&(this.#r=r,this.#g>0&&(this.#l=!0)),n.start(this.#r),this.#r+=s.duration,this.#d.push(n),this.#m++,this.#c=!0,!this.#n){this.#n=!0;let c=this.#a.slice();this.#a=[];for(let d of c)d()}n.onended=()=>{let c=this.#d.indexOf(n);c!==-1&&(this.#d.splice(c,1),this.#m--,this.#k())}}#k(){if(this.#f&&this.#m<=0&&this.#t.length===0){this.#c=!1,this.#f=!1;let e=this.#i.slice();this.#i=[];for(let t of e)t()}}#S(e){let t=Math.floor(e.length/2),s=new Float32Array(t),n=new DataView(e.buffer,e.byteOffset,e.byteLength);for(let r=0;r<t;r++){let c=n.getInt16(r*2,!0);s[r]=c/32768}return s}};var Y="4.27.0";var Z=Y;var W=16e3,fe=24e3,me=4096,ye=W*2*8,be=4,ve=1380533830,we=3e4,Se=1e3,ke=5e3,Ae=3e4,Ce=3e4,Me=6e5,Te="full-duplex-v1",Ee=300,xe=2e3,_e=2e3,Ie="runtype-browser-v1",Pe=54e4,Ve="You're talking to an AI assistant. Voice is processed by OpenAI.",je=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."]]),Q=["provider_error","server_restart"],V="Voice connection lost.",Re=8e3,Le=4e3,Oe=12,ee=2e3;function Ne(i,e){let t="Conversation so far:",s=e.slice(0,Le).trim(),n=Re-(s?s.length+2:0)-t.length,r=[];for(let d of i.slice(-Oe).reverse()){let a=d.content.replace(/\s+/g," ").trim();if(!a)continue;a.length>ee&&(a=`${a.slice(0,ee-1)}\u2026`);let o=`${d.role==="user"?"User":"Assistant"}: ${a}`;if(o.length+1>n)break;n-=o.length+1,r.unshift(o)}let c=r.length>0?[`${t}
1
+ var L=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 ae="4.28.1";var ce=ae;var Y=16e3,_e=24e3,Ee=4096,xe=Y*2*8,Ie=4,Pe=1380533830,Ve=3e4,Re=1e3,je=5e3,Le=3e4,Ne=3e4,Oe=6e5,Ue="full-duplex-v1",De=300,Be=2e3,qe=2e3,$e="runtype-browser-v1",We=54e4,He="You're talking to an AI assistant. Voice is processed by OpenAI.",Fe=new Map([["idle_timeout","Voice call ended after a quiet period."],["max_duration","This voice call reached its time limit."],["provider_ended","The voice session ended."],["quota","Voice is unavailable right now."],["auth_expired","Voice session expired. Tap the mic to reconnect."]]),le=["provider_error","server_restart"],N="Voice connection lost.",ze=8e3,Xe=4e3,Ge=12,de=2e3;function Ke(n,e){let t="Conversation so far:",s=e.slice(0,Xe).trim(),i=ze-(s?s.length+2:0)-t.length,r=[];for(let d of n.slice(-Ge).reverse()){let a=d.content.replace(/\s+/g," ").trim();if(!a)continue;a.length>de&&(a=`${a.slice(0,de-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
- `)}`]:[];return s&&c.push(s),c.join(`
3
+ `)}`]:[];return s&&l.push(s),l.join(`
4
4
 
5
- `)}function De(i){return i.byteLength>=44&&new DataView(i).getUint32(0,!1)===ve?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 qe(i){return te(i).replace(/^ws/i,"http")}function Ue(i){return typeof i!="number"||!Number.isFinite(i)?Ae:Math.min(Me,Math.max(Ce,Math.round(i)))}var _=class{constructor(e){this.config=e;this.type="runtype";this.#e=null;this.#r=null;this.#d=[];this.#i=null;this.#a=null;this.#c=null;this.#f=[];this.#m=0;this.#n=null;this.#p=!1;this.#l=!1;this.#t=0;this.#y=!1;this.#M=Number.NEGATIVE_INFINITY;this.#o=null;this.#u=!1;this.#g=!1;this.#h=0;this.#b=0;this.#w=!1;this.bridge=null;this.#k=!1;this.#S=new Set;this.#T=new Map;this.#_=new Set;this.#I=null;this.#A=null;this.#N=!1;this.#D=!1;this.#q=!1;this.#P=null;this.#U=null;this.#B=Promise.resolve();this.#V=new Set;this.#E=!1;this.#j=new Set;this.#R=new Set;this.#Y=[];this.#W=[];this.#$=[];this.#F=[];this.#H=[]}#e;#r;#d;#i;#a;#c;#f;#m;#n;#p;#l;#t;#y;#M;#o;#u;#g;#h;#b;#v;#w;#k;#S;#T;#_;#O;#I;#A;#J;#N;#D;#q;#P;#U;#B;#V;#E;#j;#R;#Y;#W;#$;#F;#H;async connect(){}setSessionBridge(e){this.bridge=e}prewarm(){if(this.#p||this.#o)return;let e=this.config?.agentId,t=this.config?.clientToken,s=this.config?.host;if(!e||!t||!s)return;let n=Date.now();if(!(n-this.#M<we)){this.#M=n;try{this.config?.prewarmMode==="attach"?this.#oe(s,e,t):this.#re(s,e,t)}catch{}}}#re(e,t,s){if(typeof fetch!="function")return;let n=`${qe(e)}/v1/client/agents/${encodeURIComponent(t)}/voice/prewarm`;fetch(n,{method:"POST",headers:{Authorization:`Bearer ${s}`},keepalive:!0}).catch(()=>{})}#oe(e,t,s){let n=new URLSearchParams,r=this.config?.attachIdleMs,c=Ue(r);r!==void 0&&n.set("attachIdleMs",String(c));let d=new WebSocket(this.#Q(e,t,n),["runtype.bearer","runtype.attach",s]);d.binaryType="arraybuffer";let a=()=>{},o=new Promise(u=>{a=u}),l={ws:d,state:"connecting",ready:o,settle:a,openedAt:0,idleTimer:void 0};this.#o=l,d.onopen=()=>{this.#o===l&&(l.state=d.protocol==="runtype.attach"?"attached":"live",l.openedAt=Date.now(),this.#Z(l,c),l.state==="attached"&&d.send('{"type":"ping"}'),l.settle())},d.onmessage=u=>{if(this.#o!==l||typeof u.data!="string")return;let p;try{p=JSON.parse(u.data)}catch{return}p.type==="attached"&&typeof p.idleMs=="number"&&this.#Z(l,p.idleMs-(Date.now()-l.openedAt))},d.onerror=()=>{},d.onclose=()=>{this.#o===l&&this.#L()}}#Z(e,t){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>{this.#o===e&&this.#L()},Math.max(0,t))}#L(){let e=this.#o;if(!e)return;this.#o=null,clearTimeout(e.idleTimer);let{ws:t}=e;if(t.onopen=null,t.onmessage=null,t.onerror=null,t.onclose=null,e.settle(),t.readyState===WebSocket.CONNECTING||t.readyState===WebSocket.OPEN)try{t.close(1e3,"prewarm released")}catch{}}async#ae(){let e=this.#o;if(!e)return null;if(e.state==="connecting"){let t;await Promise.race([e.ready,new Promise(s=>{t=setTimeout(s,ke)})]),clearTimeout(t)}return this.#o!==e?null:e.state==="connecting"||e.ws.readyState!==WebSocket.OPEN?(this.#L(),null):(this.#o=null,clearTimeout(e.idleTimer),{ws:e.ws,live:e.state==="live"})}#Q(e,t,s){let n=["partial_transcript","context"];this.bridge&&this.config?.clientDelegation!==!1&&n.push("client_delegation","delegation_update","delegation_read_back"),s&&n.unshift("attach");let r=new URLSearchParams({voiceProtocol:Ie,clientVersion:`persona/${Z}`,voiceCapabilities:Te,clientCapabilities:n.join(",")});return s?.forEach((c,d)=>r.set(d,c)),`${te(e)}/ws/agents/${encodeURIComponent(t)}/voice?${r}`}async startListening(){if(this.#p)return;let e=this.#D;e||(this.#N=!1,this.#A=null),this.#D=!1;let t=this.config?.agentId,s=this.config?.clientToken,n=this.config?.host;if(!t)throw new Error("Runtype voice requires an agentId");if(!s)throw new Error("Runtype voice requires a clientToken");if(!n)throw new Error("Runtype voice requires a host (or widget apiUrl)");let r=++this.#t;this.#y=!1,this.#p=!0;try{let c=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:W,channelCount:1,echoCancellation:!0}});if(r!==this.#t){c.getTracks().forEach(p=>p.stop());return}this.#i=c;let d=window.AudioContext||window.webkitAudioContext,a=new d({sampleRate:W});if(this.#r=a,a.state==="suspended"){if(await Promise.race([a.resume().catch(()=>{}),new Promise(p=>setTimeout(p,e?500:Se))]),r!==this.#t)return;if(a.state!=="running")throw e?new Error(this.#A=`${V} Tap the mic to reconnect.`):new Error("Audio blocked until a tap")}let o=this.config?.createPlaybackEngine?await this.config.createPlaybackEngine():new P(fe);if(r!==this.#t){o.destroy(),c.getTracks().forEach(p=>p.stop()),a.close().catch(()=>{});return}this.#n=o,this.#G(),this.#le(a,c,r);let l=await this.#ae();if(r!==this.#t){l?.ws.close(1e3,"client ended call");return}if(l){let{ws:p}=l;this.#e=p,this.#ee(p,r),l.live||p.send('{"type":"start"}'),this.#z(p),this.#s("listening");return}let u=new WebSocket(this.#Q(n,t),["runtype.bearer",s]);u.binaryType="arraybuffer",this.#e=u,u.onopen=()=>{r===this.#t&&(this.#z(u),this.#s("listening"))},this.#ee(u,r)}catch(c){throw this.#C(),this.#x(c),this.#s("error"),c}}#ee(e,t){e.onmessage=s=>this.#de(s,t),e.onerror=()=>{t!==this.#t||this.#I||(this.#x(new Error("Voice connection failed")),this.#s("error"),this.#C())},e.onclose=s=>{if(this.#y){this.#y=!1;return}if(t!==this.#t)return;let n=this.#I??(s.code===4408?{reason:"idle_timeout"}:null);if(!n){if(s.code!==1e3){let r=s.code?` (code ${s.code})`:"";this.#x(new Error(`Voice connection closed${r}`)),this.#s("error")}else this.#s("idle");this.#C();return}this.#ce(n.reason,n.message)}}#ce(e,t){let s=Q.includes(e)&&!this.#N;if(this.#C(),s){this.#N=!0,this.#p=!0,this.#A=e==="provider_error"?`${V} Reconnecting\u2026`:"Reconnecting\u2026",this.#J=setTimeout(()=>{this.#p=!1,this.#D=!0,this.startListening().catch(()=>{})},1e3+Math.random()*1e3),this.#s("idle");return}if(Q.includes(e))return this.#A=V,this.#x(new Error(V)),this.#s("error");if(e==="error")return this.#s("error");this.#A=e==="quota"&&t||je.get(e)||null,this.#s("idle")}takeNotice(){let e=this.#A;return this.#A=null,e}getDisclosure(){let e=this.config?.disclosureText;return this.#p&&this.#u&&e!==!1?e||Ve:null}async stopListening(){this.#C(),this.#s("idle")}async disconnect(){this.#C(),this.#s("disconnected"),this.#Y=[],this.#W=[],this.#$=[],this.#F=[],this.#H=[]}stopPlayback(){this.#ne();let e=this.#e;e&&e.readyState===WebSocket.OPEN&&(this.#u&&(this.#h=Date.now()+xe,e.send('{"type":"cancel"}')),this.#s("listening"))}getInterruptionMode(){return"barge-in"}isBargeInActive(){return this.#p}onLevel(e){this.#d.push(e)}async deactivateBargeIn(){this.#C(),this.#s("idle")}#le(e,t,s){let n=e.createMediaStreamSource(t);this.#a=n;let r=e.createScriptProcessor(me,1,1);this.#c=r,r.onaudioprocess=c=>{if(s!==this.#t)return;let d=this.#e,a=d?.readyState===WebSocket.OPEN;if(d&&!a&&d.readyState!==WebSocket.CONNECTING)return;let o=c.inputBuffer.getChannelData(0),l=new Int16Array(o.length),u=0;for(let p=0;p<o.length;p++){let m=Math.max(-1,Math.min(1,o[p]));u+=m*m,l[p]=m<0?m*32768:m*32767}if(d&&a)this.#z(d),d.send(l.buffer);else for(this.#f.push(l.buffer),this.#m+=l.byteLength;this.#m>ye;)this.#m-=this.#f.shift().byteLength;if(this.#d.length>0){let p=Math.sqrt(u/o.length),m=Math.max(0,Math.min(1,p*be));for(let h of this.#d)h(m)}},n.connect(r),r.connect(e.destination)}#z(e){for(let t of this.#f)e.send(t);this.#f=[],this.#m=0}#de(e,t){if(t!==this.#t)return;if(e.data instanceof ArrayBuffer){this.#ge(e.data,t);return}let s;try{s=JSON.parse(e.data)}catch{return}switch(s.type){case"session_config":s.speechMode&&(this.#u=s.speechMode==="speech_to_speech",this.#n?.setContinuousMode?.(this.#u)),Array.isArray(s.capabilities)&&(this.#S=new Set(s.capabilities)),typeof s.callId=="string"&&(this.#O=s.callId),this.#k=this.#u&&this.#S.has("client_delegation")&&!!this.bridge,this.#u&&!this.#l&&this.#s("listening"),this.#S.has("context")&&!this.#q&&(this.#q=!0,this.#P=this.#ue());break;case"transcript_update":{let n=s.role==="assistant"?"assistant":"user",r=s.utteranceId??s.turnId;if(!r||n==="assistant"&&this.#X())break;let c=String(r);if(n==="user")s.final===!0&&this.#te(t),this.#E=!1;else{if(this.#S.has("delegation_read_back")){let d=s.delegationId;typeof d=="string"&&this.#V.has(d)&&!this.#j.has(c)&&this.#R.add(c)}else this.#E&&!this.#j.has(c)&&(this.#R.add(c),this.#E=!1);if(this.#j.add(c),this.#R.has(c))break}this.#K(n,s.text??"",s.final===!0,{turnId:c,...typeof s.startMs=="number"&&{startMs:s.startMs},...typeof s.endMs=="number"&&{endMs:s.endMs},...this.#k&&{caption:!0}});break}case"delegation_started":case"delegation_completed":{let n=String(s.delegationId??s.turnId);if(s.type==="delegation_started"){this.#te(t);let r=s.input;this.#k&&r&&this.#he(n,{delegationId:n,userText:String(r.text??""),userUtteranceIds:Array.isArray(r.userUtteranceIds)?r.userUtteranceIds.filter(c=>typeof c=="string"):[],messages:Array.isArray(r.messages)?r.messages:[]},t)}else s.speak!==!1&&this.#V.has(n)&&(this.#E=!0);this.#g=s.type==="delegation_started",!this.#l&&!this.#X()&&this.#s(this.#g?"processing":"listening");break}case"delegation_cancelled":this.#se(String(s.delegationId),s.reason!=="session_ending"&&s.reason!=="provider_cancelled");break;case"warning":console.warn(`[Persona voice] ${s.code}: ${s.message??""}`,this.#O??""),s.delegationId&&(s.code==="UNKNOWN_DELEGATION"||s.code==="LATE_RESULT_LIMIT")&&this.#se(String(s.delegationId));break;case"audio_clear":this.#ne(),this.#h=0,this.#s("listening");break;case"transcript_interim":this.#s("listening"),this.#K("user",s.text??"",!1);break;case"transcript_final":{let n=s.role==="assistant"?"assistant":"user";this.#s(n==="user"?"processing":"speaking"),this.#K(n,s.text??"",!0);break}case"audio_end":this.#n?this.#n.markStreamEnd():(this.#l=!1,this.#s("listening"));break;case"metrics":this.#me({llmMs:s.llm_ms,ttsMs:s.tts_ms,firstAudioMs:s.first_audio_ms,totalMs:s.total_ms});break;case"error":this.#x(new Error(s.error||"Voice error")),this.#s("error");break;case"session_end":this.#I={reason:String(s.reason),...typeof s.message=="string"&&{message:s.message}};break}}async#ue(){let e=this.bridge?.getHistory()??[],t="";try{let s=this.config?.callContext;t=String((typeof s=="function"?await s():s)??"")}catch{}return Ne(e,t)}#te(e){let t=this.#P;if(!t)return;this.#P=null;let s=!1,n=t.then(r=>{let c=this.#e;s||!r||e!==this.#t||c?.readyState!==WebSocket.OPEN||c.send(JSON.stringify({type:"context",text:r}))});this.#U={done:n,drop:()=>s=!0}}async#pe(){let e=this.#U;if(!e)return;let t,s=await Promise.race([e.done.then(()=>!1),new Promise(n=>{t=setTimeout(()=>n(!0),_e)})]);clearTimeout(t),s&&e.drop()}#se(e,t=!1){this.#_.add(e),this.bridge?.dropDelegation?.(e,t),this.#T.get(e)?.abort()}#he(e,t,s){let n=this.bridge,r=(c,d,a)=>{let o=this.#e;return s!==this.#t||o?.readyState!==WebSocket.OPEN||this.#_.has(e)?!1:(o.send(JSON.stringify({type:c,delegationId:e,status:d,text:a})),!0)};this.#B=this.#B.then(async()=>{if(s!==this.#t||this.#_.has(e))return;let c=await n.runDelegatedTurn(t).catch(()=>({status:"failed",text:""}));await this.#pe();let d=!!c.followUp,a=d&&this.#S.has("delegation_update");if(!r(a?"delegation_update":"delegation_result",d&&!a?"completed":c.status,c.text)||(c.status!=="failed"&&c.inChat!==!1&&this.#V.add(e),!c.followUp))return;let l=new AbortController;this.#T.set(e,l),c.followUp({signal:l.signal,approvalTimeoutMs:this.config?.approvalTimeoutMs&&Math.min(this.config.approvalTimeoutMs,Pe),readBack:a,onUpdate:u=>r("delegation_update","pending_approval",u)}).then(u=>{this.#T.delete(e),a&&u&&!l.signal.aborted&&r("delegation_result",u.status,u.text)})})}#ge(e,t){if(t!==this.#t||!this.#n||this.#X())return;let s=De(e);s.length!==0&&(this.#l||(this.#l=!0,this.#s("speaking")),this.#G(),this.#n.enqueue(s),this.#u&&this.#fe(s.length))}#X(){return Date.now()<this.#h}#G(){if(this.#w||!this.#n)return;this.#w=!0;let e=this.#t;this.#n.onFinished(()=>{e===this.#t&&(this.#w=!1,this.#ie())})}#fe(e){let t=Date.now();this.#b=Math.max(t,this.#b)+e/48,clearTimeout(this.#v),this.#v=setTimeout(()=>this.#ie(),this.#b-t+Ee)}#ie(){this.#l=!1,this.#b=0,this.#e&&this.#e.readyState===WebSocket.OPEN&&this.#s(this.#g?"processing":"listening")}#ne(){this.#n?.flush(),this.#w=!1,this.#G(),this.#l=!1,this.#b=0,clearTimeout(this.#v)}#C(){this.#t+=1,this.#p=!1,this.#l=!1,this.#L(),this.#u=!1,this.#g=!1,this.#k=!1,this.#S=new Set;for(let e of this.#T.values())e.abort();if(this.#T.clear(),this.#_.clear(),this.#O=void 0,this.#I=null,clearTimeout(this.#J),this.#q=!1,this.#P=null,this.#U=null,this.#B=Promise.resolve(),this.#V.clear(),this.#E=!1,this.#j.clear(),this.#R.clear(),this.#w=!1,this.#h=0,this.#b=0,clearTimeout(this.#v),this.#f=[],this.#m=0,this.#c&&(this.#c.onaudioprocess=null,this.#c.disconnect(),this.#c=null),this.#a&&(this.#a.disconnect(),this.#a=null),this.#i&&(this.#i.getTracks().forEach(e=>e.stop()),this.#i=null),this.#r&&(this.#r.close().catch(()=>{}),this.#r=null),this.#n&&(this.#n.destroy(),this.#n=null),this.#e){this.#y=!0;try{this.#e.close(1e3,"client ended call")}catch{}this.#e=null}}onResult(e){this.#Y.push(e)}onError(e){this.#W.push(e)}onStatusChange(e){this.#$.push(e)}onTranscript(e){this.#F.push(e)}onMetrics(e){this.#H.push(e)}#s(e){this.#$.forEach(t=>t(e))}#x(e){this.#W.forEach(t=>t(e))}#K(e,t,s,n){this.#F.forEach(r=>r(e,t,s,n))}#me(e){this.#H.forEach(t=>t(e))}};var T=class{constructor(e={}){this.config=e;this.type="browser";this.#e=null;this.#r=[];this.#d=[];this.#i=[];this.#a=!1;this.#c=typeof window<"u"?window:void 0}#e;#r;#d;#i;#a;#c;async connect(){this.#i.forEach(e=>e("connected"))}async startListening(){try{if(this.#a)throw new Error("Already listening");if(!this.#c)throw new Error("Window object not available");let e=this.#c.SpeechRecognition||this.#c.webkitSpeechRecognition;if(!e)throw new Error("Browser speech recognition not supported");this.#e=new e,this.#e.lang=this.config?.language||"en-US",this.#e.continuous=this.config?.continuous||!1,this.#e.interimResults=!0,this.#e.onresult=t=>{let s=Array.from(t.results).map(r=>r[0]).map(r=>r.transcript).join(""),n=t.results[t.results.length-1].isFinal;this.#r.forEach(r=>r({text:s,confidence:n?.8:.5,provider:"browser"})),n&&!this.config?.continuous&&this.stopListening()},this.#e.onerror=t=>{this.#d.forEach(s=>s(new Error(t.error))),this.#i.forEach(s=>s("error"))},this.#e.onstart=()=>{this.#a=!0,this.#i.forEach(t=>t("listening"))},this.#e.onend=()=>{this.#a=!1,this.#i.forEach(t=>t("idle"))},this.#e.start()}catch(e){throw this.#d.forEach(t=>t(e)),this.#i.forEach(t=>t("error")),e}}async stopListening(){this.#e&&(this.#e.stop(),this.#e=null),this.#a=!1,this.#i.forEach(e=>e("idle"))}onResult(e){this.#r.push(e)}onError(e){this.#d.push(e)}onStatusChange(e){this.#i.push(e)}async disconnect(){await this.stopListening(),this.#i.forEach(e=>e("disconnected"))}static isSupported(){return"SpeechRecognition"in window||"webkitSpeechRecognition"in window}};function j(i){switch(i.type){case"runtype":if(!i.runtype)throw new Error("Runtype voice provider requires configuration");return new _(i.runtype);case"browser":if(!T.isSupported())throw new Error("Browser speech recognition not supported");return new T(i.browser||{});case"custom":{let e=i.custom;if(!e)throw new Error("Custom voice provider requires a `custom` provider instance or factory");let t=typeof e=="function"?e():e;if(!t||typeof t.startListening!="function")throw new Error("Custom voice provider `custom` must be a VoiceProvider (or a factory returning one)");return t}default:throw new Error(`Unknown voice provider type: ${i.type}`)}}function se(i){if(i?.type==="custom"&&i.custom)return j({type:"custom",custom:i.custom});if(i?.type==="runtype"&&i.runtype)return j({type:"runtype",runtype:i.runtype});if(T.isSupported())return j({type:"browser",browser:i?.browser||{language:"en-US"}});throw new Error("No supported voice providers available")}function Be(i){try{return se(i),!0}catch{return!1}}var ie=i=>i.toLowerCase().replace(/[^\p{L}\p{N}]+/gu,""),$=class{constructor(e){this.host=e;this.turns=new Map;this.latestId=null;this.cancelled=new Set}apply(e,t,s,n,r,c){let d=this.host;t=t.trim();let a=this.turns.get(n);if(a||(a={},this.turns.set(n,a),this.latestId=n),e==="user"){a.userFinal=s;let o=a.userId?d.find(a.userId):void 0;if(o){let l=a.userStartMs===void 0&&r!==void 0;l&&(a.userStartMs=r),d.upsert({...o,content:t,voiceProcessing:!s,...l&&this.placeBefore(this.startedAfter(r))})}else{a.userStartMs=r;let l=a.assistantId?d.find(a.assistantId):void 0;a.userId=d.inject({role:"user",content:t,streaming:!1,voiceProcessing:!s,voiceCaption:c,...this.placeBefore(this.startedAfter(r)??l)}).id}}else if(!this.cancelled.has(n)){a.assistantFinal=s;let o=a.assistantId?d.find(a.assistantId):void 0;if(o){let l=a.assistantStartMs===void 0&&r!==void 0;l&&(a.assistantStartMs=r),d.upsert({...o,content:t,streaming:!s,voiceProcessing:!s,...l&&this.placeBefore(this.startedAfter(r))})}else t&&(a.assistantStartMs=r,a.assistantId=d.inject({role:"assistant",content:t,streaming:!s,voiceProcessing:!s,voiceCaption:c,...this.placeBefore(this.startedAfter(r))}).id);s&&a.assistantId&&d.markSpoken(a.assistantId)}this.sync()}claimUserTurn(e,t=[]){let s=t[t.length-1];for(let r of t)r!==s&&(this.turns.has(r)||this.turns.set(r,{}),this.turns.get(r).claimed=!0);let n;if(s){if(n=this.turns.get(s),n||(n={},this.turns.set(s,n)),n.claimed)return null;(!n.userId||!this.host.find(n.userId))&&(n.userFinal=!0,n.userId=this.host.inject({role:"user",content:e.trim()}).id)}else{let r=ie(e),c=[...this.turns.values()].reverse().flatMap(d=>{let a=d.userId&&!d.claimed?this.host.find(d.userId):void 0;return a?[{turn:d,text:ie(a.content)}]:[]}).filter(({text:d})=>d&&r);n=(c.find(({text:d})=>d===r)??c.find(({text:d})=>d.startsWith(r)||r.startsWith(d)))?.turn}return n?(n.claimed=!0,n.userId):null}cancel(){let e=this.inFlight();if(e.length===0){let t=this.awaiting();if(!t)return;e=[t]}for(let t of e)this.cancelled.add(t);this.closeReplies(e),this.sync()}fail(e){let t=this.awaiting(),s=this.inFlight();if(!t&&s.length===0)return;for(let c of s)this.turns.get(c).assistantFinal=!0;this.closeReplies(s);let n=this.host.inject({role:"assistant",content:e,streaming:!1,voiceProcessing:!1}),r=t?this.turns.get(t):void 0;r&&(r.assistantId=n.id,r.assistantFinal=!0),this.sync()}settle(){if(this.turns.size===0)return;let e=this.pending(),t=new Set;for(let s of this.turns.values())s.userId&&t.add(s.userId),s.assistantId&&(t.add(s.assistantId),this.host.markSpoken(s.assistantId));this.turns.clear(),this.latestId=null,this.host.settle(t),e&&this.host.setStreaming(!1)}startedAfter(e){if(e===void 0)return;let t;for(let s of this.turns.values())for(let[n,r]of[[s.userId,s.userStartMs],[s.assistantId,s.assistantStartMs]])n&&r!==void 0&&r>e&&(!t||r<t.start)&&(t={start:r,id:n});return t&&this.host.find(t.id)}placeBefore(e){if(!e)return;let t=e.sequence??0,s=t-1;for(let n of this.turns.values())for(let r of[n.userId,n.assistantId]){let c=r?this.host.find(r):void 0,d=c?.sequence;c?.createdAt===e.createdAt&&d!==void 0&&d>s&&d<t&&(s=d)}return{createdAt:e.createdAt,sequence:(s+t)/2}}closeReplies(e){let t=new Set;for(let s of e){let n=this.turns.get(s)?.assistantId;n&&(t.add(n),this.host.markSpoken(n))}t.size>0&&this.host.settle(t)}inFlight(){let e=[];for(let[t,s]of this.turns)s.assistantId&&!s.assistantFinal&&!this.cancelled.has(t)&&e.push(t);return e}awaiting(){let e=this.latestId;if(!e)return null;let t=this.turns.get(e);return t?.userFinal&&!t.assistantId&&!t.claimed&&!this.cancelled.has(e)?e:null}pending(){return this.awaiting()!==null||this.inFlight().length>0}sync(){this.host.setStreaming(this.pending())}};var We="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)",$e=new RegExp(`^(?:${ne})(?: (?:${ne}))?(?: thanks| thank you)?$`),Fe=i=>$e.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)),F=(i,e)=>i.length>e?`${i.slice(0,e-1).trimEnd()}\u2026`:i,x=i=>i.replace(/^webmcp:/,"").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/[_\-.]+/g," ").trim().toLowerCase();function H(i,e=0){if(i==null||i==="")return"";if(typeof i!="object")return String(i);if(e>2)return"";if(Array.isArray(i))return i.map(r=>H(r,e+1)).filter(Boolean).join(", ");let t=i,s=t.quantity??t.qty??t.count,n=t.name??t.item??t.product??t.title;return s!=null&&n!=null&&typeof n!="object"?`${s} ${n}`:Object.entries(t).filter(([r])=>!r.startsWith("_")).map(([r,c])=>{let d=H(c,e+1);return d&&(e?`${x(r)} ${d}`:`${x(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=[x(n.toolName)];n.description&&r.push(`(${F(n.description.trim(),160)})`);let c=H(n.parameters);return c&&r.push(`with ${c}`),n.reason&&r.push(`because: ${F(n.reason.trim(),160)}`),F(`- ${r.join(" ")}`,Math.floor(t/i.length)-1)});return`${e}
5
+ `)}function Ye(n){return n.byteLength>=44&&new DataView(n).getUint32(0,!1)===Pe?new Uint8Array(n,44):new Uint8Array(n)}function ue(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 Je(n){return ue(n).replace(/^ws/i,"http")}function Ze(n){return typeof n!="number"||!Number.isFinite(n)?Le:Math.min(Oe,Math.max(Ne,Math.round(n)))}var V=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.#_<Ve)){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=`${Je(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=Ze(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,je)})]),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:$e,clientVersion:`persona/${ce}`,voiceCapabilities:Ue,clientCapabilities:i.join(",")});return s?.forEach((l,d)=>r.set(d,l)),`${ue(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:Y,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:Y});if(this.#i=a,a.state==="suspended"){if(await Promise.race([a.resume().catch(()=>{}),new Promise(p=>setTimeout(p,e?500:Re))]),r!==this.#t)return;if(a.state!=="running")throw e?new Error(this.#C=`${N} Tap the mic to reconnect.`):new Error("Audio blocked until a tap")}let o=this.config?.createPlaybackEngine?await this.config.createPlaybackEngine():new L(_e);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=le.includes(e)&&!this.#U;if(this.#M(),s){this.#U=!0,this.#p=!0,this.#C=e==="provider_error"?`${N} 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(le.includes(e))return this.#C=N,this.#R(new Error(N)),this.#s("error");if(e==="error")return this.#s("error");this.#C=e==="quota"&&t||Fe.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||He: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()+Be,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(Ee,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>xe;)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*Ie));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 Ke(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),qe)})]);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,We),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=Ye(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+De)}#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 O(n){switch(n.type){case"runtype":if(!n.runtype)throw new Error("Runtype voice provider requires configuration");return new V(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 pe(n){if(n?.type==="custom"&&n.custom)return O({type:"custom",custom:n.custom});if(n?.type==="runtype"&&n.runtype)return O({type:"runtype",runtype:n.runtype});if(_.isSupported())return O({type:"browser",browser:n?.browser||{language:"en-US"}});throw new Error("No supported voice providers available")}function Qe(n){try{return pe(n),!0}catch{return!1}}var he=n=>n.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,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=he(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:he(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 et=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"]),tt=/([.!?]+|[,;:])(["'”’)\]*_]*)(\s+)|\n\s*/g;function st(n){let e=/(\S+)$/.exec(n)?.[1];if(!e)return!1;let t=e.replace(/^[("'“‘[*_]+/,"").toLowerCase();if(et.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*ge(n,e){let t=new RegExp(tt.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==="."&&st(n.slice(0,s.index))))continue;let r=s.index+s[0].length;r<n.length&&(yield r)}}function fe(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 Z(n){let e=0;for(let i of ge(n.slice(0,220),!0))e=i;if(e)return e;let t=fe(n,220);if(t)return t;let s=n.charCodeAt(219);return s>=55296&&s<=56319?219:220}var U=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?Z(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?Z(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=ge(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=fe(e,220);if(r)return r}}return e.length>220?Z(e):0}};var it=200,nt=(n,e)=>{let t=0;for(;t<n.length&&t<e.length&&n[t]===e[t];)t+=1;return t},rt=50,ot="I need your answer in the chat before I can continue.",at=1e3,ct=5*6e4,me="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)",lt=new RegExp(`^(?:${me})(?: (?:${me}))?(?: thanks| thank you)?$`),dt=n=>lt.test(n.toLowerCase().replace(/[^a-z' ]+/g," ").replace(/\s+/g," ").trim()),ye="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.",be=()=>new Promise(n=>setTimeout(n,rt)),Q=(n,e)=>n.length>e?`${n.slice(0,e-1).trimEnd()}\u2026`:n,E=n=>n.replace(/^webmcp:/,"").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/[_\-.]+/g," ").trim().toLowerCase();function ee(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=>ee(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=ee(l,e+1);return d&&(e?`${E(r)} ${d}`:`${E(r)}: ${d}`)}).filter(Boolean).join(e?", ":"; ")}function ve(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=at-e.length-ye.length-2,s=n.map(i=>{let r=[E(i.toolName)];i.description&&r.push(`(${Q(i.description.trim(),160)})`);let l=ee(i.parameters);return l&&r.push(`with ${l}`),i.reason&&r.push(`because: ${Q(i.reason.trim(),160)}`),Q(`- ${r.join(" ")}`,Math.floor(t/n.length)-1)});return`${e}
6
6
  ${s.join(`
7
7
  `)}
8
8
 
9
- ${re}`}var R=i=>i.variant==="approval"&&i.approval?.status==="pending";function He(i){let e=null,t=null,s=()=>i.track(e??t),n=[],r=new Map,c=new Map,d=(h,f)=>{r.set(h,[...r.get(h)??[],f]),r.size>32&&r.delete(r.keys().next().value)},a=h=>i.messages().find(f=>f.id===h),o=h=>h.approvals.filter(f=>a(f)?.approval?.status==="pending"),l=h=>x(a(h)?.approval?.toolName??""),u=(h,f,w)=>{h.outcome={status:f,text:w};for(let y of o(h))i.decide(y)},p=h=>h.flatMap(f=>i.messages().find(w=>w.id===f)??[]).filter(f=>!f.variant&&f.content.trim()).map(f=>f.content.trim()).join(`
9
+ ${ye}`}var D=n=>n.variant==="approval"&&n.approval?.status==="pending";function ut(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=>E(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
- `),m=async h=>{do await oe();while(i.busy()&&!(h&&(i.parked()||h.failed)))};return{getHistory:()=>{let h=i.messages().filter(y=>(y.role==="user"||y.role==="assistant")&&!y.variant&&!y.voiceProcessing&&!y.streaming&&y.content),f=!1,w=[];for(let y=h.length-1;y>=0;y-=1){let k=h[y];if(k.role==="user")f=!1;else if(!k.voiceCaption)f=!0;else if(f)continue;w.unshift({role:k.role,content:k.content})}return w},dropDelegation(h,f){c.set(h,!!f),c.size>32&&c.delete(c.keys().next().value);let w=f&&n.find(y=>y.delegationId===h);w&&!w.outcome&&u(w,"timeout","");for(let y of r.get(h)??[])y.dropped=!0,y.ids.length&&i.unspoken(y.ids)},async runDelegatedTurn({delegationId:h,userText:f,userUtteranceIds:w}){let y=n.filter(g=>o(g).length),k=y.flatMap(o);if(k.length===1&&Fe(f)){let g=l(k[0]);return u(y[0],"denied",""),{status:"denied",text:`Okay, I cancelled the ${g} request. Nothing was done.`,inChat:!1}}let z=i.parked()&&i.messages().every(g=>!R(g)||k.includes(g.id));i.busy()&&!z&&await m();let ce=new Set(i.messages().map(g=>g.id)),L=()=>i.messages().filter(g=>!ce.has(g.id)&&g.variant==="approval"),A={ids:[],failed:!1};d(h,A),e=A,s();try{await i.send(f,i.claim(f,w)??void 0),await m(A)}catch{A.failed=!0}finally{e=null,s()}let le=A.ids.flatMap(g=>i.messages().find(v=>v.id===g)??[]),E=p(A.ids),I=A.failed?[]:L().filter(R),de=new Set(I.map(g=>x(g.approval.toolName)));for(let g of y){if(g.outcome)continue;for(let S of o(g).filter(O=>de.has(l(O))))g.replaced.add(S),i.decide(S);let v=l(g.approvals[0]);g.approvals.every(S=>g.replaced.has(S))?g.outcome={status:"cancelled",text:`The earlier ${v} request was replaced by the new one; it was not done.`}:z&&g.approvals.every(S=>a(S)?.approval?.status==="denied")&&(g.outcome={status:"cancelled",text:`The earlier ${v} request was replaced by the new one; it was not done.`})}if(I.length){let g=new Set(I.map(S=>S.id)),v={delegationId:h,approvals:[...g],at:Date.now(),replaced:new Set};return n.push(v),c.get(h)&&u(v,"timeout",""),E=`${E}
11
+ `),m=async g=>{do await be();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),B=C.flatMap(o);if(B.length===1&&dt(f)){let h=c(B[0]);return u(C[0],"denied",""),{status:"denied",text:`Okay, I cancelled the ${h} request. Nothing was done.`,inChat:!1}}let te=n.parked()&&n.messages().every(h=>!D(h)||B.includes(h.id));n.busy()&&!te&&await m();let we=new Set(n.messages().map(h=>h.id)),q=()=>n.messages().filter(h=>!we.has(h.id)&&h.variant==="approval"),S={ids:[],failed:!1},x=v?new U:null,R="",se="",I=!1,$=h=>{for(let y of h)se+=y,v(y)},P;x&&(S.onUpdate=()=>{if(I)return;let h=p(S.ids);if(!h.startsWith(R)){I=!0,clearTimeout(P);return}if(h.length===R.length)return;let y=h.slice(R.length);R=h,$(x.push(y)),clearTimeout(P),P=setTimeout(()=>{I||$(x.idle())},it)},S.stopStream=()=>{clearTimeout(P),I=!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()}x&&(S.onUpdate?.(),clearTimeout(P),I||$(x.flush()),S.onUpdate=void 0,S.stopStream=void 0);let W=h=>{let y=nt(se,h);return y>0?{streamedChars:y}:{}},Se=S.ids.flatMap(h=>n.messages().find(y=>y.id===h)??[]),k=p(S.ids),j=S.failed?[]:q().filter(D),Ae=new Set(j.map(h=>E(h.approval.toolName)));for(let h of C){if(h.outcome)continue;for(let A of o(h).filter(H=>Ae.has(c(H))))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.`}:te&&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(j.length){let h=new Set(j.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
- ${ae(I.map(S=>S.approval))}`.trim(),{status:"pending_approval",text:E,followUp:async({signal:S,approvalTimeoutMs:O=3e5,readBack:X=!0,onUpdate:ue})=>{let C={ids:[],failed:!1};r.delete(h),d(h,C);let G=()=>L().filter(b=>g.has(b.id)||C.ids.includes(b.id)),pe=()=>L().filter(b=>R(b)&&!g.has(b.id)&&!n.some(M=>M.approvals.includes(b.id))&&(C.ids.includes(b.id)||b.approval?.toolType==="webmcp"&&t===C)),K=()=>{t=C,s()};X&&K();try{for(;!S.aborted&&!v.outcome&&(e||i.busy()||G().some(R));){X&&t!==C&&!o(v).length&&K();let b=pe();if(b.length){for(let M of b)g.add(M.id),v.approvals.push(M.id);v.at=Date.now(),ue?.(ae(b.map(M=>M.approval)))}if(Date.now()-v.at>=O&&o(v).length&&(!i.busy()||i.parked())){u(v,"timeout",`That ${l(v.approvals[0])} request expired, so nothing was done.`);break}await oe()}}finally{t===C&&(t=null,s()),n.splice(n.indexOf(v),1)}if(S.aborted)return null;if(v.outcome)return v.outcome;if(C.failed)return{status:"failed",text:`The ${l(v.approvals[0])} request didn't complete.`};let J=G(),N=b=>J.filter(b).map(M=>x(M.approval.toolName)).join(", "),D=J.some(b=>b.approval?.status==="approved"),q=N(b=>b.approval?.status==="denied"&&!v.replaced.has(b.id)),U=N(b=>v.replaced.has(b.id)),B=N(b=>b.approval?.status==="timeout"),he=[D?p(C.ids):"",q&&`The user declined the ${q} request in the chat, so ${D?"that part was not done":"nothing was done"}.`,U&&`The earlier ${U} request was replaced by the new one; it was not done.`,B&&`The ${B} request timed out, so it was not done.`].filter(Boolean).join(`
13
+ ${ve(j.map(A=>A.approval))}`.trim(),{status:"pending_approval",text:k,...W(k),followUp:async({signal:A,approvalTimeoutMs:H=ct,readBack:ie=!0,onUpdate:ke})=>{let M={ids:[],failed:!1};r.delete(g),d(g,M);let ne=()=>q().filter(w=>h.has(w.id)||M.ids.includes(w.id)),Ce=()=>q().filter(w=>D(w)&&!h.has(w.id)&&!i.some(T=>T.approvals.includes(w.id))&&(M.ids.includes(w.id)||w.approval?.toolType==="webmcp"&&t===M)),re=()=>{t=M,s()};ie&&re();try{for(;!A.aborted&&!y.outcome&&(e||n.busy()||ne().some(D));){ie&&t!==M&&!o(y).length&&re();let w=Ce();if(w.length){for(let T of w)h.add(T.id),y.approvals.push(T.id);y.at=Date.now(),ke?.(ve(w.map(T=>T.approval)))}if(Date.now()-y.at>=H&&o(y).length&&(!n.busy()||n.parked())){u(y,"timeout",`That ${c(y.approvals[0])} request expired, so nothing was done.`);break}await be()}}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 oe=ne(),F=w=>oe.filter(w).map(T=>E(T.approval.toolName)).join(", "),z=oe.some(w=>w.approval?.status==="approved"),X=F(w=>w.approval?.status==="denied"&&!y.replaced.has(w.id)),G=F(w=>y.replaced.has(w.id)),K=F(w=>w.approval?.status==="timeout"),Me=[z?p(M.ids):"",X&&`The user declined the ${X} request in the chat, so ${z?"that part was not done":"nothing was done"}.`,G&&`The earlier ${G} request was replaced by the new one; it was not done.`,K&&`The ${K} request timed out, so it was not done.`].filter(Boolean).join(`
14
14
 
15
- `);return{status:D?"completed":q?"denied":U?"cancelled":B?"timeout":"completed",text:he}}}}return!A.failed&&i.parked()||le.some(g=>g.agentMetadata?.awaitingLocalTool&&!g.agentMetadata.askUserQuestionAnswered&&!g.toolCall?.name?.startsWith("webmcp:"))?{status:A.failed?"failed":"completed",text:`${E}
15
+ `);return{status:z?"completed":X?"denied":G?"cancelled":K?"timeout":"completed",text:Me}}}}return!S.failed&&n.parked()||Se.some(h=>h.agentMetadata?.awaitingLocalTool&&!h.agentMetadata.askUserQuestionAnswered&&!h.toolCall?.name?.startsWith("webmcp:"))?(k=`${k}
16
16
 
17
- ${We}`.trim()}:{status:!A.failed&&E?"completed":"failed",text:E}}}}var ze=(i,e,t,s)=>{let n=i.session;try{i.keyed=t?new t({find:o=>n.messages.find(l=>l.id===o),inject:o=>n.injectMessage(o),upsert:o=>n.upsertMessage(o),settle:o=>{n.messages=n.messages.map(l=>o.has(l.id)?{...l,streaming:!1,voiceProcessing:!1}:l),n.callbacks.onMessagesChanged([...n.messages])},setStreaming:o=>{(o||!i.busy())&&i.setStreaming(o)},markSpoken:o=>{n.ttsSpokenMessageIds.add(o)}}):null,s&&e.setSessionBridge&&e.setSessionBridge(s({messages:()=>n.messages,busy:()=>i.busy(),parked:()=>n.webMcpApprovalResolvers.size>0,claim:(o,l)=>i.keyed?.claimUserTurn(o,l)??null,send:(o,l)=>n.sendMessage(o,{viaVoice:!0,voiceTurn:{userMessageId:l}}),track:o=>{i.setDelegation(o)},unspoken:o=>{for(let l of o)n.ttsSpokenMessageIds.delete(l);n.streaming||n.speakLatestAssistantMessage(o)},decide:o=>{if(n.webMcpApprovalResolvers.has(o))return n.resolveWebMcpApproval(o,"denied");let l=n.messages.find(u=>u.id===o)?.approval;l?.status==="pending"&&n.resolveApproval(l,"denied")}}));let r=i.generation(),c=()=>i.provider()===e&&r===i.generation(),a=(n.config.voiceRecognition??{}).processingErrorText??"Voice processing failed. Please try again.";e.onResult(o=>{c()&&o.provider!=="runtype"&&o.text&&o.text.trim()&&n.sendMessage(o.text,{viaVoice:!0})}),e.onTranscript&&e.onTranscript((o,l,u,p)=>{if(c()){if(p?.turnId){i.keyed?.apply(o,l,u,p.turnId,p.startMs,p.caption);return}if(o==="user"){if(i.pendingUser)n.upsertMessage({id:i.pendingUser,role:"user",content:l,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!u});else{let m=n.injectMessage({role:"user",content:l,streaming:!1,voiceProcessing:!u});i.pendingUser=m.id}if(u){i.turns().start(p?.turnId),i.pendingUser=null;let m=n.injectMessage({role:"assistant",content:"",streaming:!0,voiceProcessing:!0});i.pendingAssistant=m.id,i.setStreaming(!0)}}else{if(!i.turns().accepts(p?.turnId))return;if(i.pendingAssistant)n.upsertMessage({id:i.pendingAssistant,role:"assistant",content:l,createdAt:new Date().toISOString(),streaming:!u,voiceProcessing:!u});else{let m=n.injectMessage({role:"assistant",content:l,streaming:!u,voiceProcessing:!u});i.pendingAssistant=m.id}u&&(i.pendingAssistant&&n.ttsSpokenMessageIds.add(i.pendingAssistant),i.setStreaming(!1),i.pendingAssistant=null)}}}),e.onLevel&&e.onLevel(o=>{c()&&i.setLevel(Number.isFinite(o)?Math.max(0,Math.min(1,o)):0)}),e.onMetrics&&e.onMetrics(o=>{c()&&n.config.voiceRecognition?.onMetrics?.(o)}),e.onError(o=>{c()&&(console.error("Voice error:",o),i.pendingAssistant&&(n.upsertMessage({id:i.pendingAssistant,role:"assistant",content:a,createdAt:new Date().toISOString(),streaming:!1,voiceProcessing:!1}),i.setStreaming(!1),i.pendingUser=null,i.pendingAssistant=null),i.keyed?.fail(a))}),e.onStatusChange(o=>{c()&&(i.setStatus(o),(o==="listening"||o==="idle"||o==="disconnected")&&i.settlePending(o!=="listening"),(o==="idle"||o==="disconnected")&&i.keyed?.settle(),n.callbacks.onVoiceStatusChanged?.(o))}),e.connect()}catch(r){console.error("Failed to setup voice:",r)}};var Xe=i=>{let e=a=>{if(i.original)return;let o=i.config().voiceRecognition??{};i.original={backgroundColor:a.style.backgroundColor,color:a.style.color,borderColor:a.style.borderColor,iconName:o.iconName??"mic",iconSize:parseFloat(o.iconSize??"")||i.iconFallbackPx}},t=(a,o,l)=>{let u=a.querySelector("svg");u&&u.remove();let p=i.original?.iconSize??(parseFloat(i.config().voiceRecognition?.iconSize??"")||i.iconFallbackPx),m=i.renderIcon(o,p,l,1.5);m&&a.appendChild(m)},s=a=>{a.classList.remove("persona-voice-recording","persona-voice-processing","persona-voice-speaking")};return{recording:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},l=o.recordingBackgroundColor,u=o.recordingIconColor,p=o.recordingBorderColor;if(s(a),a.classList.add("persona-voice-recording"),i.setMicState("recording"),a.style.backgroundColor=l??"var(--persona-voice-recording-bg, #ef4444)",a.style.color=u??"var(--persona-voice-recording-indicator, #ffffff)",u){let m=a.querySelector("svg");m&&m.setAttribute("stroke",u)}p&&(a.style.borderColor=p),a.setAttribute("aria-label","Stop voice recognition")},processing:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},l=i.session().getVoiceInterruptionMode(),u=i.original,p=o.processingIconName??"loader",m=o.processingIconColor??u?.color??"",h=o.processingBackgroundColor??u?.backgroundColor??"",f=o.processingBorderColor??u?.borderColor??"";s(a),a.classList.add("persona-voice-processing"),i.setMicState("processing"),a.style.backgroundColor=h,a.style.borderColor=f;let w=m||"currentColor";a.style.color=w,t(a,p,w),a.setAttribute("aria-label","Processing voice input"),l==="none"&&(a.style.cursor="default")},speaking:()=>{let a=i.mic();if(!a)return;e(a);let o=i.config().voiceRecognition??{},l=i.session().getVoiceInterruptionMode(),u=i.original,p=l==="cancel"?"square":l==="barge-in"?"mic":"volume-2",m=o.speakingIconName??p,h=o.speakingIconColor??(l==="barge-in"?o.recordingIconColor??u?.color??"":u?.color??""),f=o.speakingBackgroundColor??(l==="barge-in"?o.recordingBackgroundColor??"var(--persona-voice-recording-bg, #ef4444)":u?.backgroundColor??""),w=o.speakingBorderColor??(l==="barge-in"?o.recordingBorderColor??"":u?.borderColor??"");s(a),a.classList.add("persona-voice-speaking"),i.setMicState("speaking"),a.style.backgroundColor=f,a.style.borderColor=w;let y=h||"currentColor";a.style.color=y,t(a,m,y);let k=l==="cancel"?"Stop playback and re-record":l==="barge-in"?"Speak to interrupt":"Agent is speaking";a.setAttribute("aria-label",k),l==="none"&&(a.style.cursor="default"),l==="barge-in"&&a.classList.add("persona-voice-recording")},reset:()=>{let a=i.mic();if(!a)return;s(a),i.setMicState("idle");let o=i.original;o&&(a.style.backgroundColor=o.backgroundColor??"",a.style.color=o.color??"",a.style.borderColor=o.borderColor??"",t(a,o.iconName,o.color||"currentColor"),i.original=null),a.style.cursor="",a.setAttribute("aria-label","Start voice recognition")}}};export{T as BrowserVoiceProvider,$ as KeyedVoiceTranscript,_ as RuntypeVoiceProvider,se as createBestAvailableVoiceProvider,Xe as createMicStateStyles,j as createVoiceProvider,He as createVoiceSessionBridge,Be as isVoiceSupported,ze as wireSessionVoice};
17
+ ${ot}`.trim(),{status:S.failed?"failed":"completed",text:k,...W(k)}):{status:!S.failed&&k?"completed":"failed",text:k,...W(k)}}}}var pt=(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 ht=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")}}};export{_ as BrowserVoiceProvider,J as KeyedVoiceTranscript,V as RuntypeVoiceProvider,pe as createBestAvailableVoiceProvider,ht as createMicStateStyles,O as createVoiceProvider,ut as createVoiceSessionBridge,Qe as isVoiceSupported,pt as wireSessionVoice};
@@ -0,0 +1,6 @@
1
+ var C="webmcp:",w=t=>t.startsWith(C)?t.slice(C.length):t,u={warn(t,...e){typeof console<"u"&&typeof console.warn=="function"&&console.warn(`[Persona/WebMCP] ${t}`,...e)}},b=class{constructor(e,n){this.config=e;this.#e=n,this.#o=e.onConfirm??null,this.#r=3e4}#o;#r;#t=!1;#i=null;#l=!1;#e;setConfirmHandler(e){this.#o=e}isOperational(){return this.config.enabled!==!0||!this.#t?!1:this.#n()!==null}async snapshotForDispatch(){if(await this.#s(),this.config.enabled!==!0)return[];let e=this.#n();if(!e)return[];let n;try{n=(await e.getTools()).filter(h)}catch(i){return u.warn("getTools() threw: shipping an empty WebMCP snapshot.",i),[]}this.#e.recordToolDisplayTitles(n);let o=typeof location<"u"?location.origin:"";return n.filter(i=>this.#c(i.name)).map(i=>{let l=P(i.annotations);return{name:i.name,description:i.description,parametersSchema:W(i.inputSchema),origin:"webmcp",...o?{pageOrigin:o}:{},...l?{annotations:l}:{},...l?.untrustedContentHint===!0?{untrustedContentHint:!0}:{}}})}async executeToolCall(e,n,o){if(await this.#s(),this.config.enabled!==!0)return s("WebMCP is not enabled on this widget.");let i=this.#n();if(!i){let r=typeof document<"u"&&!!document.modelContext;return s(r?"WebMCP is not operational: document.modelContext is present but does not expose the strict getTools()/executeTool() surface (likely a different or older WebMCP polyfill).":"WebMCP bridge is not operational on this page (document.modelContext not available).")}let l=w(e),c;try{c=(await i.getTools()).filter(h)}catch(r){let p=r instanceof Error?r.message:String(r);return s(`Failed to read WebMCP registry: ${p}`)}this.#e.recordToolDisplayTitles(c);let f=c.find(r=>r.name===l);if(!f)return s(`WebMCP tool not registered on this page: ${l}`);if(!this.#c(l))return s(`WebMCP tool not allowed by client allowlist: ${l}`);if(o?.aborted)return s("Aborted by cancel()");let m=this.#e.getToolDisplayTitle(l),M={toolName:l,args:n,description:f.description,...m?{title:m}:{},reason:"gate"};if(!await this.#u(M))return s("User declined the tool call.");if(o?.aborted)return s("Aborted by cancel()");let a=new AbortController,y=!1,T=setTimeout(()=>{y=!0,a.abort()},this.#r),g=()=>a.abort();o&&(o.aborted?a.abort():o.addEventListener("abort",g,{once:!0}));try{let r=await i.executeTool(f,O(n),{signal:a.signal});return A(r)}catch(r){if(y)return s(`WebMCP tool '${l}' timed out after ${this.#r}ms`);if(o?.aborted)return s("Aborted by cancel()");let p=r instanceof Error?r.message:String(r);return s(p)}finally{clearTimeout(T),o&&o.removeEventListener("abort",g)}}#s(){return this.config.enabled!==!0?Promise.resolve():(this.#i||(this.#i=this.#a()),this.#i)}async#a(){try{if(this.#n()){this.#t=!0;return}let e=await this.#e.loadPolyfill();"initializeWebMCPPolyfill"in e?e.initializeWebMCPPolyfill():e.installWebMCP(),this.#t=!0}catch(e){u.warn("Failed to load @mcp-b/webmcp-polyfill: WebMCP consumption disabled.",e),this.#t=!1}}#n(){if(typeof document>"u")return null;let e=document.modelContext;if(!e||typeof e!="object")return null;let n=e;return typeof n.getTools!="function"||typeof n.executeTool!="function"?(this.#l||(this.#l=!0,u.warn("document.modelContext is present but does not expose getTools()/executeTool(): WebMCP consumption is disabled. Another (incompatible or older) WebMCP polyfill likely installed document.modelContext before Persona. Remove it, or use a polyfill implementing the strict standard surface (e.g. @mcp-b/webmcp-polyfill).")),null):e}async#u(e){let n=this.#o??k;try{return await n(e)}catch(o){return u.warn(`Confirm handler threw for WebMCP tool '${e.toolName}'; declining.`,o),!1}}#c(e){let n=this.config.allowlist;return!n||n.length===0?!0:n.some(o=>x(e,o))}},x=(t,e)=>{if(e==="*")return!0;let n=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return new RegExp("^"+n.replace(/\*/g,".*")+"$").test(t)},d={type:"object",properties:{}},P=t=>{if(!t||typeof t!="object")return;let e={...typeof t.readOnlyHint=="boolean"?{readOnlyHint:t.readOnlyHint}:{},...typeof t.untrustedContentHint=="boolean"?{untrustedContentHint:t.untrustedContentHint}:{}};return Object.keys(e).length>0?e:void 0},W=t=>{if(t===void 0||t==="")return{...d};if(typeof t=="object")return t!==null&&!Array.isArray(t)?t:{...d};try{let e=JSON.parse(t);return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{...d}}catch{return{...d}}},A=t=>{if(t==null)return{content:[{type:"text",text:""}]};let e;try{e=JSON.parse(t)}catch{return{content:[{type:"text",text:t}]}}return e!==null&&typeof e=="object"&&Array.isArray(e.content)?e:{content:[{type:"text",text:typeof e=="string"?e:D(e)}]}},O=t=>{let e;try{e=JSON.stringify(t)??"{}"}catch{e="{}"}let n=JSON.parse(e);if(n===null||typeof n!="object")throw new TypeError("WebMCP tool arguments must be an object or array.");return Object.defineProperty(n,Symbol.toPrimitive,{value:()=>e}),n},s=t=>({isError:!0,content:[{type:"text",text:t}]}),k=async t=>{if(typeof window>"u"||typeof window.confirm!="function")return!1;let e=S(t.args),n=`Allow the AI to call ${t.toolName}`+(e?`
2
+
3
+ Arguments:
4
+ ${e}`:"")+(t.description?`
5
+
6
+ ${t.description}`:"");return window.confirm(n)},S=t=>{if(t==null)return"";try{let e=JSON.stringify(t,null,2);return e.length>500?e.slice(0,500)+"\u2026":e}catch{return String(t)}},h=t=>(t.window===void 0||typeof window<"u"&&t.window===window)&&(t.origin===void 0||typeof location<"u"&&t.origin===location.origin),D=t=>{if(t===void 0)return"";try{return JSON.stringify(t)}catch{return String(t)}};export{b as WebMcpBridge};
@@ -1,6 +1,6 @@
1
- "use strict";var m=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var w=(t,e)=>{for(var n in e)m(t,n,{get:e[n],enumerable:!0})},A=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of W(e))!P.call(t,r)&&r!==n&&m(t,r,{get:()=>e[r],enumerable:!(o=x(e,r))||o.enumerable});return t};var O=t=>A(m({},"__esModule",{value:!0}),t);var L={};w(L,{WebMcpBridge:()=>f});module.exports=O(L);var C="webmcp:",k=t=>t.startsWith(C)?t.slice(C.length):t,u={warn(t,...e){typeof console<"u"&&typeof console.warn=="function"&&console.warn(`[Persona/WebMCP] ${t}`,...e)}},f=class{constructor(e,n){this.config=e;this.#e=n,this.#o=e.onConfirm??null,this.#r=3e4}#o;#r;#t=!1;#i=null;#l=!1;#e;setConfirmHandler(e){this.#o=e}isOperational(){return this.config.enabled!==!0||!this.#t?!1:this.#n()!==null}async snapshotForDispatch(){if(await this.#s(),this.config.enabled!==!0)return[];let e=this.#n();if(!e)return[];let n;try{n=await e.getTools()}catch(r){return u.warn("getTools() threw: shipping an empty WebMCP snapshot.",r),[]}this.#e.recordToolDisplayTitles(n);let o=typeof location<"u"?location.origin:"";return n.filter(r=>this.#c(r.name)).map(r=>{let l=S(r.annotations);return{name:r.name,description:r.description,parametersSchema:H(r.inputSchema),origin:"webmcp",...o?{pageOrigin:o}:{},...l?{annotations:l}:{},...l?.untrustedContentHint===!0?{untrustedContentHint:!0}:{}}})}async executeToolCall(e,n,o){if(await this.#s(),this.config.enabled!==!0)return s("WebMCP is not enabled on this widget.");let r=this.#n();if(!r){let i=typeof document<"u"&&!!document.modelContext;return s(i?"WebMCP is not operational: document.modelContext is present but does not expose the strict getTools()/executeTool() surface (likely a different or older WebMCP polyfill).":"WebMCP bridge is not operational on this page (document.modelContext not available).")}let l=k(e),c;try{c=await r.getTools()}catch(i){let b=i instanceof Error?i.message:String(i);return s(`Failed to read WebMCP registry: ${b}`)}this.#e.recordToolDisplayTitles(c);let p=c.find(i=>i.name===l);if(!p)return s(`WebMCP tool not registered on this page: ${l}`);if(!this.#c(l))return s(`WebMCP tool not allowed by client allowlist: ${l}`);if(o?.aborted)return s("Aborted by cancel()");let y=this.#e.getToolDisplayTitle(l),M={toolName:l,args:n,description:p.description,...y?{title:y}:{},reason:"gate"};if(!await this.#u(M))return s("User declined the tool call.");if(o?.aborted)return s("Aborted by cancel()");let a=new AbortController,g=!1,T=setTimeout(()=>{g=!0,a.abort()},this.#r),h=()=>a.abort();o&&(o.aborted?a.abort():o.addEventListener("abort",h,{once:!0}));try{let i=await r.executeTool(p,$(n),{signal:a.signal});return I(i)}catch(i){if(g)return s(`WebMCP tool '${l}' timed out after ${this.#r}ms`);if(o?.aborted)return s("Aborted by cancel()");let b=i instanceof Error?i.message:String(i);return s(b)}finally{clearTimeout(T),o&&o.removeEventListener("abort",h)}}#s(){return this.config.enabled!==!0?Promise.resolve():(this.#i||(this.#i=this.#a()),this.#i)}async#a(){try{if(this.#n()){this.#t=!0;return}(await this.#e.loadPolyfill()).initializeWebMCPPolyfill(),this.#t=!0}catch(e){u.warn("Failed to load @mcp-b/webmcp-polyfill: WebMCP consumption disabled.",e),this.#t=!1}}#n(){if(typeof document>"u")return null;let e=document.modelContext;if(!e||typeof e!="object")return null;let n=e;return typeof n.getTools!="function"||typeof n.executeTool!="function"?(this.#l||(this.#l=!0,u.warn("document.modelContext is present but does not expose getTools()/executeTool(): WebMCP consumption is disabled. Another (incompatible or older) WebMCP polyfill likely installed document.modelContext before Persona. Remove it, or use a polyfill implementing the strict standard surface (e.g. @mcp-b/webmcp-polyfill).")),null):e}async#u(e){let n=this.#o??E;try{return await n(e)}catch(o){return u.warn(`Confirm handler threw for WebMCP tool '${e.toolName}'; declining.`,o),!1}}#c(e){let n=this.config.allowlist;return!n||n.length===0?!0:n.some(o=>D(e,o))}},D=(t,e)=>{if(e==="*")return!0;let n=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return new RegExp("^"+n.replace(/\*/g,".*")+"$").test(t)},d={type:"object",properties:{}},S=t=>{if(!t||typeof t!="object")return;let e={...typeof t.readOnlyHint=="boolean"?{readOnlyHint:t.readOnlyHint}:{},...typeof t.untrustedContentHint=="boolean"?{untrustedContentHint:t.untrustedContentHint}:{}};return Object.keys(e).length>0?e:void 0},H=t=>{if(t===void 0||t==="")return{...d};if(typeof t=="object")return t!==null&&!Array.isArray(t)?t:{...d};try{let e=JSON.parse(t);return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{...d}}catch{return{...d}}},I=t=>{if(t==null)return{content:[{type:"text",text:""}]};let e;try{e=JSON.parse(t)}catch{return{content:[{type:"text",text:t}]}}return e!==null&&typeof e=="object"&&Array.isArray(e.content)?e:{content:[{type:"text",text:typeof e=="string"?e:j(e)}]}},s=t=>({isError:!0,content:[{type:"text",text:t}]}),E=async t=>{if(typeof window>"u"||typeof window.confirm!="function")return!1;let e=v(t.args),n=`Allow the AI to call ${t.toolName}`+(e?`
1
+ "use strict";var m=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var A=(t,e)=>{for(var n in e)m(t,n,{get:e[n],enumerable:!0})},O=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of P(e))!W.call(t,r)&&r!==n&&m(t,r,{get:()=>e[r],enumerable:!(o=x(e,r))||o.enumerable});return t};var k=t=>O(m({},"__esModule",{value:!0}),t);var N={};A(N,{WebMcpBridge:()=>f});module.exports=k(N);var h="webmcp:",S=t=>t.startsWith(h)?t.slice(h.length):t,u={warn(t,...e){typeof console<"u"&&typeof console.warn=="function"&&console.warn(`[Persona/WebMCP] ${t}`,...e)}},f=class{constructor(e,n){this.config=e;this.#e=n,this.#o=e.onConfirm??null,this.#r=3e4}#o;#r;#t=!1;#i=null;#l=!1;#e;setConfirmHandler(e){this.#o=e}isOperational(){return this.config.enabled!==!0||!this.#t?!1:this.#n()!==null}async snapshotForDispatch(){if(await this.#s(),this.config.enabled!==!0)return[];let e=this.#n();if(!e)return[];let n;try{n=(await e.getTools()).filter(M)}catch(r){return u.warn("getTools() threw: shipping an empty WebMCP snapshot.",r),[]}this.#e.recordToolDisplayTitles(n);let o=typeof location<"u"?location.origin:"";return n.filter(r=>this.#c(r.name)).map(r=>{let l=I(r.annotations);return{name:r.name,description:r.description,parametersSchema:j(r.inputSchema),origin:"webmcp",...o?{pageOrigin:o}:{},...l?{annotations:l}:{},...l?.untrustedContentHint===!0?{untrustedContentHint:!0}:{}}})}async executeToolCall(e,n,o){if(await this.#s(),this.config.enabled!==!0)return s("WebMCP is not enabled on this widget.");let r=this.#n();if(!r){let i=typeof document<"u"&&!!document.modelContext;return s(i?"WebMCP is not operational: document.modelContext is present but does not expose the strict getTools()/executeTool() surface (likely a different or older WebMCP polyfill).":"WebMCP bridge is not operational on this page (document.modelContext not available).")}let l=S(e),c;try{c=(await r.getTools()).filter(M)}catch(i){let b=i instanceof Error?i.message:String(i);return s(`Failed to read WebMCP registry: ${b}`)}this.#e.recordToolDisplayTitles(c);let p=c.find(i=>i.name===l);if(!p)return s(`WebMCP tool not registered on this page: ${l}`);if(!this.#c(l))return s(`WebMCP tool not allowed by client allowlist: ${l}`);if(o?.aborted)return s("Aborted by cancel()");let y=this.#e.getToolDisplayTitle(l),T={toolName:l,args:n,description:p.description,...y?{title:y}:{},reason:"gate"};if(!await this.#u(T))return s("User declined the tool call.");if(o?.aborted)return s("Aborted by cancel()");let a=new AbortController,g=!1,w=setTimeout(()=>{g=!0,a.abort()},this.#r),C=()=>a.abort();o&&(o.aborted?a.abort():o.addEventListener("abort",C,{once:!0}));try{let i=await r.executeTool(p,v(n),{signal:a.signal});return H(i)}catch(i){if(g)return s(`WebMCP tool '${l}' timed out after ${this.#r}ms`);if(o?.aborted)return s("Aborted by cancel()");let b=i instanceof Error?i.message:String(i);return s(b)}finally{clearTimeout(w),o&&o.removeEventListener("abort",C)}}#s(){return this.config.enabled!==!0?Promise.resolve():(this.#i||(this.#i=this.#a()),this.#i)}async#a(){try{if(this.#n()){this.#t=!0;return}let e=await this.#e.loadPolyfill();"initializeWebMCPPolyfill"in e?e.initializeWebMCPPolyfill():e.installWebMCP(),this.#t=!0}catch(e){u.warn("Failed to load @mcp-b/webmcp-polyfill: WebMCP consumption disabled.",e),this.#t=!1}}#n(){if(typeof document>"u")return null;let e=document.modelContext;if(!e||typeof e!="object")return null;let n=e;return typeof n.getTools!="function"||typeof n.executeTool!="function"?(this.#l||(this.#l=!0,u.warn("document.modelContext is present but does not expose getTools()/executeTool(): WebMCP consumption is disabled. Another (incompatible or older) WebMCP polyfill likely installed document.modelContext before Persona. Remove it, or use a polyfill implementing the strict standard surface (e.g. @mcp-b/webmcp-polyfill).")),null):e}async#u(e){let n=this.#o??E;try{return await n(e)}catch(o){return u.warn(`Confirm handler threw for WebMCP tool '${e.toolName}'; declining.`,o),!1}}#c(e){let n=this.config.allowlist;return!n||n.length===0?!0:n.some(o=>D(e,o))}},D=(t,e)=>{if(e==="*")return!0;let n=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return new RegExp("^"+n.replace(/\*/g,".*")+"$").test(t)},d={type:"object",properties:{}},I=t=>{if(!t||typeof t!="object")return;let e={...typeof t.readOnlyHint=="boolean"?{readOnlyHint:t.readOnlyHint}:{},...typeof t.untrustedContentHint=="boolean"?{untrustedContentHint:t.untrustedContentHint}:{}};return Object.keys(e).length>0?e:void 0},j=t=>{if(t===void 0||t==="")return{...d};if(typeof t=="object")return t!==null&&!Array.isArray(t)?t:{...d};try{let e=JSON.parse(t);return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{...d}}catch{return{...d}}},H=t=>{if(t==null)return{content:[{type:"text",text:""}]};let e;try{e=JSON.parse(t)}catch{return{content:[{type:"text",text:t}]}}return e!==null&&typeof e=="object"&&Array.isArray(e.content)?e:{content:[{type:"text",text:typeof e=="string"?e:L(e)}]}},v=t=>{let e;try{e=JSON.stringify(t)??"{}"}catch{e="{}"}let n=JSON.parse(e);if(n===null||typeof n!="object")throw new TypeError("WebMCP tool arguments must be an object or array.");return Object.defineProperty(n,Symbol.toPrimitive,{value:()=>e}),n},s=t=>({isError:!0,content:[{type:"text",text:t}]}),E=async t=>{if(typeof window>"u"||typeof window.confirm!="function")return!1;let e=$(t.args),n=`Allow the AI to call ${t.toolName}`+(e?`
2
2
 
3
3
  Arguments:
4
4
  ${e}`:"")+(t.description?`
5
5
 
6
- ${t.description}`:"");return window.confirm(n)},v=t=>{if(t==null)return"";try{let e=JSON.stringify(t,null,2);return e.length>500?e.slice(0,500)+"\u2026":e}catch{return String(t)}},$=t=>{if(t===void 0)return"{}";try{let e=JSON.stringify(t);return e===void 0?"{}":e}catch{return"{}"}},j=t=>{if(t===void 0)return"";try{return JSON.stringify(t)}catch{return String(t)}};0&&(module.exports={WebMcpBridge});
6
+ ${t.description}`:"");return window.confirm(n)},$=t=>{if(t==null)return"";try{let e=JSON.stringify(t,null,2);return e.length>500?e.slice(0,500)+"\u2026":e}catch{return String(t)}},M=t=>(t.window===void 0||typeof window<"u"&&t.window===window)&&(t.origin===void 0||typeof location<"u"&&t.origin===location.origin),L=t=>{if(t===void 0)return"";try{return JSON.stringify(t)}catch{return String(t)}};0&&(module.exports={WebMcpBridge});
@@ -60,9 +60,8 @@ type WebMcpConfirmInfo = {
60
60
  };
61
61
  /**
62
62
  * Why the confirm was requested. Currently always `'gate'`: the default
63
- * confirm-by-default gate that fires before every `webmcp:*` call. (The
64
- * `@mcp-b/webmcp-polyfill` owns the spec's `requestUserInteraction` callback
65
- * internally, so Persona no longer surfaces a nested in-tool confirm.)
63
+ * confirm-by-default gate that fires before every `webmcp:*` call. Tool
64
+ * callbacks on v6 receive an AbortSignal, not a nested confirmation API.
66
65
  */
67
66
  reason: 'gate';
68
67
  };
@@ -153,26 +152,19 @@ type AgentWidgetWebMcpConfig = {
153
152
  * enforcement live on the Runtype API; this bridge mirrors those checks
154
153
  * client-side as a usability convenience, not a security boundary.
155
154
  *
156
- * About `@mcp-b/webmcp-polyfill`: it polyfills the *strict standard surface*
157
- * only (`registerTool` / `getTools` / `executeTool` on `document.modelContext`),
158
- * with no MCP-B-only extensions. The spec standardizes the *producer* side;
159
- * Persona is an in-page *consumer*, so it reads the registry via the
160
- * producer-facing preview API:
161
- * - `getTools()`: async; returns `{ name, description, inputSchema }` where
162
- * `inputSchema` is a JSON *string*. Annotations are not exposed here.
163
- * - `executeTool(toolInfo, inputArgsJson, { signal })`: async; validates args
164
- * against the tool's schema, runs `execute()`, and returns the raw result as
165
- * a JSON *string* (or `null` for `undefined`). Honors `signal` for abort.
155
+ * Supports v5's JSON-string input and v6's object input with a single call:
156
+ * the runtime passes a JSON object that also string-coerces to JSON text.
157
+ * Never infer the execution contract from metadata or retry a failed call.
158
+ * Only tools owned by this document are exposed: the wire addresses tools by
159
+ * name, not by frame. Callbacks must validate their own input.
166
160
  *
167
- * The polyfill auto-installs `document.modelContext` at module-evaluation time,
168
- * so it is imported *dynamically* and only when `config.webmcp.enabled === true`
169
- *: a static import would install the global for every widget consumer,
170
- * including those that never opted into WebMCP.
161
+ * The automatic fallback stays on v5 to preserve its browser requirements and
162
+ * result semantics. Host pages may install v5 or v6 themselves; Persona does
163
+ * not replace an existing context. v5's initializeWebMCPPolyfill() and v6's
164
+ * installWebMCP() are both accepted by custom loaders.
171
165
  *
172
- * Confirm model: every `webmcp:*` call goes through one confirm gate before
173
- * `execute()` runs, regardless of `annotations.readOnlyHint`. (The polyfill owns
174
- * the spec's `client.requestUserInteraction` callback internally; Persona cannot
175
- * inject a nested confirm there, so the single outer gate is the whole story.)
166
+ * Every call passes one confirm gate before execution, regardless of
167
+ * annotations.readOnlyHint. v6 callbacks also receive an invocation signal.
176
168
  */
177
169
 
178
170
  /**
@@ -193,18 +185,20 @@ interface ModelContextToolInfo {
193
185
  * object. `@mcp-b/webmcp-polyfill` made the switch in v5, and Chrome ships it
194
186
  * from 154.0.8013 (cross-document tools first) -- but Chrome 149-153, most of
195
187
  * the Origin Trial population, and 154's same-document tools still emit the
196
- * string. Both are live in the field, so we accept both.
188
+ * string. Both input execution contracts are supported independently of
189
+ * schema representation.
197
190
  *
198
191
  * Absent when the tool registered no schema: v5 omits the member, where v4
199
192
  * always emitted a `{"type":"object"}` string.
200
193
  */
201
194
  inputSchema?: object | string;
195
+ /** Owning frame and origin, when supplied by the registry. Never sent on the wire. */
196
+ window?: Window;
197
+ origin?: string;
202
198
  /**
203
199
  * Display title declared on the tool (`ToolDescriptor.title` in the WebMCP
204
200
  * spec). The polyfill returns `""` when the tool didn't declare one. Note:
205
- * `annotations` (incl. the legacy `annotations.title`) are NOT exposed on
206
- * this strict consumer surface: top-level `title` is the only display-name
207
- * channel available to us.
201
+ * top-level `title` is the display-name channel, not `annotations.title`.
208
202
  */
209
203
  title?: string;
210
204
  /**
@@ -221,6 +215,8 @@ interface ModelContextToolInfo {
221
215
  /** The slice of `@mcp-b/webmcp-polyfill` the bridge consumes on install. */
222
216
  type WebMcpPolyfillModule = {
223
217
  initializeWebMCPPolyfill: () => void;
218
+ } | {
219
+ installWebMCP: () => void;
224
220
  };
225
221
 
226
222
  /**
@@ -287,7 +283,7 @@ declare class WebMcpBridge {
287
283
  * - tool not in registry (e.g. unmounted between snapshot and call)
288
284
  * - tool excluded by the client allowlist
289
285
  * - user declined the confirm gate
290
- * - `execute()` threw or failed schema validation
286
+ * - `execute()` threw or returned a non-serializable result
291
287
  * - `execute()` exceeded the 30s timeout
292
288
  * - `signal` fired (session-level `cancel()`)
293
289
  *
@@ -60,9 +60,8 @@ type WebMcpConfirmInfo = {
60
60
  };
61
61
  /**
62
62
  * Why the confirm was requested. Currently always `'gate'`: the default
63
- * confirm-by-default gate that fires before every `webmcp:*` call. (The
64
- * `@mcp-b/webmcp-polyfill` owns the spec's `requestUserInteraction` callback
65
- * internally, so Persona no longer surfaces a nested in-tool confirm.)
63
+ * confirm-by-default gate that fires before every `webmcp:*` call. Tool
64
+ * callbacks on v6 receive an AbortSignal, not a nested confirmation API.
66
65
  */
67
66
  reason: 'gate';
68
67
  };
@@ -153,26 +152,19 @@ type AgentWidgetWebMcpConfig = {
153
152
  * enforcement live on the Runtype API; this bridge mirrors those checks
154
153
  * client-side as a usability convenience, not a security boundary.
155
154
  *
156
- * About `@mcp-b/webmcp-polyfill`: it polyfills the *strict standard surface*
157
- * only (`registerTool` / `getTools` / `executeTool` on `document.modelContext`),
158
- * with no MCP-B-only extensions. The spec standardizes the *producer* side;
159
- * Persona is an in-page *consumer*, so it reads the registry via the
160
- * producer-facing preview API:
161
- * - `getTools()`: async; returns `{ name, description, inputSchema }` where
162
- * `inputSchema` is a JSON *string*. Annotations are not exposed here.
163
- * - `executeTool(toolInfo, inputArgsJson, { signal })`: async; validates args
164
- * against the tool's schema, runs `execute()`, and returns the raw result as
165
- * a JSON *string* (or `null` for `undefined`). Honors `signal` for abort.
155
+ * Supports v5's JSON-string input and v6's object input with a single call:
156
+ * the runtime passes a JSON object that also string-coerces to JSON text.
157
+ * Never infer the execution contract from metadata or retry a failed call.
158
+ * Only tools owned by this document are exposed: the wire addresses tools by
159
+ * name, not by frame. Callbacks must validate their own input.
166
160
  *
167
- * The polyfill auto-installs `document.modelContext` at module-evaluation time,
168
- * so it is imported *dynamically* and only when `config.webmcp.enabled === true`
169
- *: a static import would install the global for every widget consumer,
170
- * including those that never opted into WebMCP.
161
+ * The automatic fallback stays on v5 to preserve its browser requirements and
162
+ * result semantics. Host pages may install v5 or v6 themselves; Persona does
163
+ * not replace an existing context. v5's initializeWebMCPPolyfill() and v6's
164
+ * installWebMCP() are both accepted by custom loaders.
171
165
  *
172
- * Confirm model: every `webmcp:*` call goes through one confirm gate before
173
- * `execute()` runs, regardless of `annotations.readOnlyHint`. (The polyfill owns
174
- * the spec's `client.requestUserInteraction` callback internally; Persona cannot
175
- * inject a nested confirm there, so the single outer gate is the whole story.)
166
+ * Every call passes one confirm gate before execution, regardless of
167
+ * annotations.readOnlyHint. v6 callbacks also receive an invocation signal.
176
168
  */
177
169
 
178
170
  /**
@@ -193,18 +185,20 @@ interface ModelContextToolInfo {
193
185
  * object. `@mcp-b/webmcp-polyfill` made the switch in v5, and Chrome ships it
194
186
  * from 154.0.8013 (cross-document tools first) -- but Chrome 149-153, most of
195
187
  * the Origin Trial population, and 154's same-document tools still emit the
196
- * string. Both are live in the field, so we accept both.
188
+ * string. Both input execution contracts are supported independently of
189
+ * schema representation.
197
190
  *
198
191
  * Absent when the tool registered no schema: v5 omits the member, where v4
199
192
  * always emitted a `{"type":"object"}` string.
200
193
  */
201
194
  inputSchema?: object | string;
195
+ /** Owning frame and origin, when supplied by the registry. Never sent on the wire. */
196
+ window?: Window;
197
+ origin?: string;
202
198
  /**
203
199
  * Display title declared on the tool (`ToolDescriptor.title` in the WebMCP
204
200
  * spec). The polyfill returns `""` when the tool didn't declare one. Note:
205
- * `annotations` (incl. the legacy `annotations.title`) are NOT exposed on
206
- * this strict consumer surface: top-level `title` is the only display-name
207
- * channel available to us.
201
+ * top-level `title` is the display-name channel, not `annotations.title`.
208
202
  */
209
203
  title?: string;
210
204
  /**
@@ -221,6 +215,8 @@ interface ModelContextToolInfo {
221
215
  /** The slice of `@mcp-b/webmcp-polyfill` the bridge consumes on install. */
222
216
  type WebMcpPolyfillModule = {
223
217
  initializeWebMCPPolyfill: () => void;
218
+ } | {
219
+ installWebMCP: () => void;
224
220
  };
225
221
 
226
222
  /**
@@ -287,7 +283,7 @@ declare class WebMcpBridge {
287
283
  * - tool not in registry (e.g. unmounted between snapshot and call)
288
284
  * - tool excluded by the client allowlist
289
285
  * - user declined the confirm gate
290
- * - `execute()` threw or failed schema validation
286
+ * - `execute()` threw or returned a non-serializable result
291
287
  * - `execute()` exceeded the 30s timeout
292
288
  * - `signal` fired (session-level `cancel()`)
293
289
  *