@alexkroman1/aai-ui 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/agent-state-labels.d.ts +8 -3
  2. package/dist/{chat-view-DIwPoAEG.js → chat-view-W6KcdjJY.js} +40 -30
  3. package/dist/{client-config-C7fQrioM.js → client-config-CzvWmw4X.js} +7 -12
  4. package/dist/client-config.d.ts +29 -10
  5. package/dist/components/_form-readiness.d.ts +2 -1
  6. package/dist/components/audio-result.d.ts +2 -0
  7. package/dist/components/bullet-list.d.ts +1 -0
  8. package/dist/components/button.d.ts +2 -2
  9. package/dist/components/chat-view.js +1 -1
  10. package/dist/components/console-shell.d.ts +8 -5
  11. package/dist/components/controls.d.ts +1 -0
  12. package/dist/components/conversation-view.d.ts +1 -0
  13. package/dist/components/facts.d.ts +1 -0
  14. package/dist/components/form-fields.d.ts +8 -8
  15. package/dist/components/form-types.d.ts +16 -2
  16. package/dist/components/form.d.ts +9 -4
  17. package/dist/components/markdown.d.ts +1 -0
  18. package/dist/components/message-list.d.ts +1 -0
  19. package/dist/components/message-list.js +1 -1
  20. package/dist/components/session-controls.d.ts +7 -2
  21. package/dist/components/session-error-banner.d.ts +1 -0
  22. package/dist/components/session-state-dot.d.ts +20 -7
  23. package/dist/components/sidebar-layout.d.ts +2 -2
  24. package/dist/components/tool-call-block.d.ts +3 -3
  25. package/dist/components/tool-call-row.d.ts +1 -0
  26. package/dist/components/tool-config-context.d.ts +2 -1
  27. package/dist/components/url-chips.d.ts +4 -3
  28. package/dist/components/workflow-fields.d.ts +2 -1
  29. package/dist/components/workflow-pending-note.d.ts +1 -0
  30. package/dist/components/workflow-run-error.d.ts +1 -0
  31. package/dist/components/workflow-run-panel.d.ts +1 -0
  32. package/dist/context.d.ts +8 -7
  33. package/dist/context.js +2 -2
  34. package/dist/default-client/assets/{audio-DzwGxdv4.js → audio-Ct7JpSNT.js} +1 -1
  35. package/dist/default-client/assets/{capture-processor-CXCWxCO8.js → capture-processor-Cx1AdMHL.js} +1 -1
  36. package/dist/default-client/assets/index-BlUYCTB5.js +126 -0
  37. package/dist/default-client/assets/{playback-processor-DXHfyQD9.js → playback-processor-CCwTknSu.js} +1 -1
  38. package/dist/default-client/index.html +1 -1
  39. package/dist/define-client.d.ts +2 -0
  40. package/dist/define-client.js +4 -4
  41. package/dist/inbox-protocol.d.ts +14 -4
  42. package/dist/inbox.d.ts +1 -0
  43. package/dist/index.d.ts +3 -3
  44. package/dist/index.js +61 -19
  45. package/dist/internal.js +1 -1
  46. package/dist/linked-client.d.ts +2 -0
  47. package/dist/{message-list-DHZcLhRA.js → message-list-BsaBkBgo.js} +21 -10
  48. package/dist/page.d.ts +2 -0
  49. package/dist/phone.d.ts +1 -0
  50. package/dist/route-fetch.d.ts +1 -0
  51. package/dist/session/audio-setup.d.ts +1 -1
  52. package/dist/session/audio-state.d.ts +6 -6
  53. package/dist/session/index.js +1 -1
  54. package/dist/session/messages.d.ts +1 -9
  55. package/dist/session/preconnect.d.ts +1 -1
  56. package/dist/session/types.d.ts +4 -0
  57. package/dist/{session-CYdjRvbl.js → session-3lgPYNNO.js} +25 -14
  58. package/dist/stored-value.d.ts +2 -0
  59. package/dist/types.d.ts +48 -4
  60. package/dist/use-client-runs.d.ts +2 -0
  61. package/dist/use-conversation-log.d.ts +2 -0
  62. package/dist/use-conversation.d.ts +24 -9
  63. package/dist/use-copy.d.ts +1 -0
  64. package/dist/use-download-url.d.ts +6 -1
  65. package/dist/use-flash.d.ts +1 -0
  66. package/dist/use-inbox.d.ts +2 -0
  67. package/dist/use-push-to-talk.d.ts +6 -1
  68. package/dist/use-route-mutation.d.ts +3 -0
  69. package/dist/use-route.d.ts +2 -0
  70. package/dist/use-session-controls.d.ts +1 -0
  71. package/dist/use-tap-to-talk.d.ts +5 -2
  72. package/dist/use-user-transcript.d.ts +5 -1
  73. package/dist/use-workflow-form.d.ts +8 -1
  74. package/dist/use-workflow-progress.d.ts +5 -0
  75. package/dist/use-workflow-run.d.ts +5 -0
  76. package/dist/use-workflow-runs.d.ts +10 -2
  77. package/dist/use-workflow-stream.d.ts +25 -3
  78. package/dist/use-workflows.d.ts +10 -2
  79. package/dist/workflow-client.d.ts +5 -0
  80. package/dist/workflow-field-kind.d.ts +8 -4
  81. package/dist/worklets/capture-processor.d.ts +3 -3
  82. package/dist/worklets/capture-processor.js +2 -2
  83. package/dist/worklets/playback-processor.d.ts +3 -3
  84. package/dist/worklets/playback-processor.js +2 -2
  85. package/package.json +2 -2
  86. package/dist/default-client/assets/index-BOTLwsNO.js +0 -126
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource react */
2
- import { type ReactNode } from "react";
2
+ import { type FunctionComponent, type MemoExoticComponent } from "react";
3
3
  import type { ToolCallInfo } from "../types.ts";
4
4
  /**
5
5
  * Renders a tool invocation as the design system's console row (see
@@ -22,7 +22,7 @@ import type { ToolCallInfo } from "../types.ts";
22
22
  *
23
23
  * @internal Not exported from the package — rendered by `MessageList`.
24
24
  */
25
- export declare const ToolCallBlock: import("react").MemoExoticComponent<({ toolCall, className, }: {
25
+ export declare const ToolCallBlock: MemoExoticComponent<FunctionComponent<{
26
26
  toolCall: ToolCallInfo;
27
27
  className?: string;
28
- }) => ReactNode>;
28
+ }>>;
@@ -9,6 +9,7 @@ export type ToolCallRowVariant = "default" | "compact";
9
9
  /**
10
10
  * Props for {@link ToolCallRow}.
11
11
  *
12
+ * @input
12
13
  * @public
13
14
  */
14
15
  export interface ToolCallRowProps {
@@ -1,3 +1,4 @@
1
+ import { type Context } from "react";
1
2
  /**
2
3
  * Display configuration for a tool call in the UI.
3
4
  *
@@ -13,7 +14,7 @@ export type ToolDisplayConfig = Record<string, {
13
14
  *
14
15
  * @internal
15
16
  */
16
- export declare const ToolConfigContext: import("react").Context<ToolDisplayConfig>;
17
+ export declare const ToolConfigContext: Context<ToolDisplayConfig>;
17
18
  /**
18
19
  * Read tool display configuration from the nearest `ToolConfigContext.Provider`.
19
20
  *
@@ -1,3 +1,4 @@
1
+ import type { JSX } from "react";
1
2
  /**
2
3
  * The session's shareable UI URL — the page this UI is served from, what
3
4
  * you'd send someone to talk to the agent.
@@ -6,7 +7,7 @@
6
7
  */
7
8
  export declare function UiUrlChip({ className }: {
8
9
  className?: string | undefined;
9
- }): import("react").JSX.Element;
10
+ }): JSX.Element;
10
11
  /**
11
12
  * The session's programmatic WebSocket endpoint — the URL a script or backend
12
13
  * can connect to directly instead of using this UI.
@@ -15,7 +16,7 @@ export declare function UiUrlChip({ className }: {
15
16
  */
16
17
  export declare function ApiUrlChip({ className }: {
17
18
  className?: string | undefined;
18
- }): import("react").JSX.Element;
19
+ }): JSX.Element;
19
20
  /**
20
21
  * The UI and API URLs side by side. They answer the same question — "how do I
21
22
  * reach this agent?" — so they belong together and each needs its label to be
@@ -26,4 +27,4 @@ export declare function ApiUrlChip({ className }: {
26
27
  */
27
28
  export declare function SessionUrlChips({ className }: {
28
29
  className?: string | undefined;
29
- }): import("react").JSX.Element;
30
+ }): JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import type { WorkflowSummary } from "@alexkroman1/aai/workflow-api";
2
+ import type { JSX } from "react";
2
3
  /**
3
4
  * Render one field per scalar property of a workflow's input schema.
4
5
  *
@@ -43,4 +44,4 @@ export declare function WorkflowFields({ workflow, }: {
43
44
  * straight through before one is made.
44
45
  */
45
46
  workflow?: WorkflowSummary | string | undefined;
46
- }): import("react").JSX.Element | null;
47
+ }): JSX.Element | null;
@@ -3,6 +3,7 @@ import type { WorkflowRun } from "../workflow-client.ts";
3
3
  /**
4
4
  * Props for {@link WorkflowPendingNote}.
5
5
  *
6
+ * @input
6
7
  * @public
7
8
  */
8
9
  export type WorkflowPendingNoteProps = {
@@ -3,6 +3,7 @@ import type { WorkflowRun } from "../workflow-client.ts";
3
3
  /**
4
4
  * Props for {@link WorkflowRunError}.
5
5
  *
6
+ * @input
6
7
  * @public
7
8
  */
8
9
  export type WorkflowRunErrorProps = {
@@ -7,6 +7,7 @@ import { type WorkflowApi, type WorkflowRun } from "../workflow-client.ts";
7
7
  * @typeParam O - The run's output type; `run.output` narrows to it in the
8
8
  * completed slot.
9
9
  *
10
+ * @input
10
11
  * @public
11
12
  */
12
13
  export type WorkflowRunPanelProps<O> = {
package/dist/context.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { type ReactNode } from "react";
1
+ import { type ReactElement, type ReactNode } from "react";
2
2
  import type { BrowserSession, SendTextOptions, SessionSnapshot } from "./session/index.ts";
3
- import type { AgentState, ClientTheme, SessionError } from "./types.ts";
3
+ import type { AgentState, ClientTheme, ResolvedClientTheme, SessionError } from "./types.ts";
4
4
  /**
5
5
  * Provides the {@link BrowserSession} the session hooks read. `mountClient()`
6
6
  * installs it automatically; a custom tree only needs it when bypassing
@@ -11,7 +11,7 @@ import type { AgentState, ClientTheme, SessionError } from "./types.ts";
11
11
  export declare function SessionProvider({ value, children, }: {
12
12
  value: BrowserSession;
13
13
  children?: ReactNode;
14
- }): import("react").FunctionComponentElement<import("react").ProviderProps<BrowserSession | null>>;
14
+ }): ReactElement;
15
15
  /**
16
16
  * The session's control methods, and nothing else — what a `client.tsx` may
17
17
  * legitimately CALL on a session, as against what it may read.
@@ -27,6 +27,7 @@ export declare function SessionProvider({ value, children, }: {
27
27
  * actions every chrome is handed. `createBrowserSession` is what keeps each of
28
28
  * these assignable from the session's own methods.
29
29
  *
30
+ * @sealed
30
31
  * @public
31
32
  */
32
33
  export type SessionActions = {
@@ -219,7 +220,7 @@ export declare function useSessionSelector<T>(selector: (snapshot: SessionSnapsh
219
220
  *
220
221
  * function StatusDot() {
221
222
  * const status = useSessionStatus();
222
- * return <span data-state={status}>{AGENT_STATE_LABELS[status]}</span>;
223
+ * return <span data-state={status}>{AGENT_STATE_LABELS[status] ?? status}</span>;
223
224
  * }
224
225
  * ```
225
226
  *
@@ -257,7 +258,7 @@ export declare function useSessionError(): SessionError | null;
257
258
  export declare function ThemeProvider({ value, children, }: {
258
259
  value?: ClientTheme | undefined;
259
260
  children?: ReactNode;
260
- }): import("react").FunctionComponentElement<import("react").ProviderProps<Required<ClientTheme>>>;
261
+ }): ReactElement;
261
262
  /**
262
263
  * Read the resolved theme (every {@link ClientTheme} field filled with its
263
264
  * default) from the nearest theme context. Returns the default theme when no
@@ -281,8 +282,8 @@ export declare function ThemeProvider({ value, children, }: {
281
282
  * }
282
283
  * ```
283
284
  *
284
- * @returns Every {@link ClientTheme} field, filled in.
285
+ * @returns Every {@link ClientTheme} field, filled in — a {@link ResolvedClientTheme}.
285
286
  *
286
287
  * @public
287
288
  */
288
- export declare function useTheme(): Required<ClientTheme>;
289
+ export declare function useTheme(): ResolvedClientTheme;
package/dist/context.js CHANGED
@@ -219,7 +219,7 @@ const selectError = (s) => s.error;
219
219
  *
220
220
  * function StatusDot() {
221
221
  * const status = useSessionStatus();
222
- * return <span data-state={status}>{AGENT_STATE_LABELS[status]}</span>;
222
+ * return <span data-state={status}>{AGENT_STATE_LABELS[status] ?? status}</span>;
223
223
  * }
224
224
  * ```
225
225
  *
@@ -371,7 +371,7 @@ function useThemeStyles(theme) {
371
371
  * }
372
372
  * ```
373
373
  *
374
- * @returns Every {@link ClientTheme} field, filled in.
374
+ * @returns Every {@link ClientTheme} field, filled in — a {@link ResolvedClientTheme}.
375
375
  *
376
376
  * @public
377
377
  */
@@ -1 +1 @@
1
- import{a as e,i as t,t as n}from"./index-BOTLwsNO.js";var r={echoCancellation:!0,noiseSuppression:!1,autoGainControl:!1,voiceIsolation:!1};function i(e,t,n){if(e!==t)throw Error(`Browser refused the ${n} sample rate: asked for ${t} Hz, got ${e} Hz`)}function a(e){let t=Error(`Audio ${e} worklet crashed`);return console.error(`[aai-ui]`,t.message),t}function o(e){e.then(e=>{for(let t of e.getTracks())t.stop()}).catch(()=>{})}function s(e,t,n){let r=new AudioWorkletNode(e,`capture-processor`,{channelCount:1,channelCountMode:`explicit`}),i=null;return r.port.onmessage=e=>{let r=e.data;r.event===`chunk`&&r.buffer?t(r.buffer):r.event===`silent`?n?.():r.event===`stopped`&&(i?.(),i=null)},{node:r,start(){r.port.postMessage({event:`start`})},stop(){let{promise:e,resolve:t}=Promise.withResolvers(),n=setTimeout(t,250);return i=()=>{clearTimeout(n),t()},r.port.postMessage({event:`stop`}),e}}}async function c(e){let{sampleRate:t,captureWorkletSrc:n,maxSeconds:a}=e,c=new AudioContext({sampleRate:t,latencyHint:`interactive`}),l=navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...r}}),u;try{[u]=await Promise.all([l,c.resume(),c.audioWorklet.addModule(n)]),i(c.sampleRate,t,`capture`)}catch(e){throw o(l),await c.close().catch(()=>{}),e}let d=Math.round(t*a)*2,f=[],p=0,m=!1,h=null,g=c.createMediaStreamSource(u),_=s(c,e=>{if(h){h.onChunk(e);return}for(f.push(e),p+=e.byteLength;p>d&&f.length>1;)p-=f.shift()?.byteLength??0},()=>{h?h.onSilent?.():m=!0});g.connect(_.node),_.start();let v=()=>{let e=f;return f=[],p=0,e},y=!1,b=async()=>{y||(y=!0,g.disconnect(),_.node.disconnect(),await c.close().catch(e=>{console.warn(`AudioContext close failed:`,e)}))};return{sampleRate:t,stream:u,ctx:c,handOff(e){h=e;let t=v();return t.length>0&&e.onBuffered(t),m&&e.onSilent?.(),{mic:g,capture:_}},async detach(){return await _.stop(),await b(),{chunks:v(),sampleRate:t}},async close(){y||await _.stop();for(let e of u.getTracks())e.stop();await b()}}}function l(e){let t=new Int16Array(e.length);for(let n=0;n<e.length;n++){let r=Math.max(-1,Math.min(1,e[n]??0));t[n]=r<0?r*32768:r*32767}return t.buffer}async function u(e,t,r){let i=e.reduce((e,t)=>e+t.byteLength/2,0);if(i===0)return[];if(t===r)return e;try{let a=Math.round(i*r/t),o=new OfflineAudioContext(1,a,r),s=o.createBuffer(1,i,t),c=s.getChannelData(0),u=0;for(let t of e)for(let e of new Int16Array(t))c[u++]=e/32768;let d=o.createBufferSource();d.buffer=s,d.connect(o.destination),d.start();let f=(await o.startRendering()).getChannelData(0),p=Math.max(1,Math.round(r*n)),m=[];for(let e=0;e<f.length;e+=p)m.push(l(f.subarray(e,e+p)));return m}catch(e){return console.warn(`[aai-ui] pre-connect audio dropped: resample failed`,e),[]}}async function d(e,t,n){let r=e.createMediaStreamSource(t),i=s(e,n.onMicData,n.onMicSilent);if(r.connect(i.node),n.buffered){let{chunks:t,sampleRate:r}=n.buffered,i=await u(t,r,e.sampleRate);i.length>0&&n.onBuffered(i)}return i.start(),{mic:r,capture:i}}async function f(n){let{sttSampleRate:s,ttsSampleRate:c,captureWorkletSrc:l,playbackWorkletSrc:u,onMicData:f,onError:p,onPlaybackStats:m,onPlaybackProgress:h,onMicSilent:g,preConnect:_}=n,v=n.onPreConnectAudio??(e=>{for(let t of e)f(t)}),y=_?.sampleRate===s?_:null,b=_&&!y?await _.detach():null,x=new AudioContext({sampleRate:c,latencyHint:`playback`}),S=!y&&s===c,C=y?.ctx??(S?x:new AudioContext({sampleRate:s,latencyHint:`interactive`}));async function w(){let e=S?[x]:[x,C];await Promise.all(e.map(e=>e.close().catch(e=>{console.warn(`AudioContext close failed:`,e)})))}let T=_?Promise.resolve(_.stream):navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...r}}),E;try{[E]=await Promise.all([T,x.resume(),C.resume(),y?void 0:C.audioWorklet.addModule(l),x.audioWorklet.addModule(u)]),i(C.sampleRate,s,`capture`),i(x.sampleRate,c,`playback`)}catch(e){throw o(T),await w(),e}let{mic:D,capture:O}=y?y.handOff({onBuffered:v,onChunk:f,onSilent:g}):await d(C,E,{onMicData:f,onMicSilent:g,buffered:b,onBuffered:v});O.node.onprocessorerror=()=>p?.(a(`capture`));let k=null,A=0,j=null,M=new AbortController;function N(){let e=j;j=null,e?.settle()}function P(e){e.stats&&e.stats.concealedSamples>0&&m?.(e.stats),e.reason!==`interrupt`&&(j===null||e.turn===j.turn)&&N()}function F(){if(k)return k;let e=new AudioWorkletNode(x,`playback-processor`);return e.connect(x.destination),e.port.onmessage=e=>{e.data.event===`stop`?P(e.data):e.data.event===`progress`&&h?.(e.data.bufferedMs)},e.onprocessorerror=()=>{let e=a(`playback`);N(),p?.(e)},k=e,e}let I={enqueue(e){M.signal.aborted||e.byteLength!==0&&F().port.postMessage({event:`write`,buffer:new Uint8Array(e)},[e])},done(){if(!k)return Promise.resolve();let n=++A;if(k.port.postMessage({event:`done`,turn:n}),x.state!==`running`)return N(),Promise.resolve();let{promise:r,resolve:i}=Promise.withResolvers();N();let a=()=>{clearInterval(o),clearTimeout(s),j?.settle===a&&(j=null),i()},o=setInterval(()=>{x.state!==`running`&&a()},e),s=setTimeout(a,t);return j={turn:n,settle:a},r},flush(){k&&(N(),k.port.postMessage({event:`interrupt`}))},async close(){if(!M.signal.aborted){M.abort(),await O.stop(),D.disconnect(),O.node.disconnect(),k&&k.disconnect();for(let e of E.getTracks())e.stop();await w()}},async[Symbol.asyncDispose](){await I.close()}};return I}export{f as createVoiceIO,c as openPreConnectCapture};
1
+ import{a as e,i as t,t as n}from"./index-BlUYCTB5.js";var r={echoCancellation:!0,noiseSuppression:!1,autoGainControl:!1,voiceIsolation:!1};function i(e,t,n){if(e!==t)throw Error(`Browser refused the ${n} sample rate: asked for ${t} Hz, got ${e} Hz`)}function a(e){let t=Error(`Audio ${e} worklet crashed`);return console.error(`[aai-ui]`,t.message),t}function o(e){e.then(e=>{for(let t of e.getTracks())t.stop()}).catch(()=>{})}function s(e,t,n){let r=new AudioWorkletNode(e,`capture-processor`,{channelCount:1,channelCountMode:`explicit`}),i=null;return r.port.onmessage=e=>{let r=e.data;r.event===`chunk`&&r.buffer?t(r.buffer):r.event===`silent`?n?.():r.event===`stopped`&&(i?.(),i=null)},{node:r,start(){r.port.postMessage({event:`start`})},stop(){let{promise:e,resolve:t}=Promise.withResolvers(),n=setTimeout(t,250);return i=()=>{clearTimeout(n),t()},r.port.postMessage({event:`stop`}),e}}}async function c(e){let{sampleRate:t,captureWorkletSrc:n,maxSeconds:a}=e,c=new AudioContext({sampleRate:t,latencyHint:`interactive`}),l=navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...r}}),u;try{[u]=await Promise.all([l,c.resume(),c.audioWorklet.addModule(n)]),i(c.sampleRate,t,`capture`)}catch(e){throw o(l),await c.close().catch(()=>{}),e}let d=Math.round(t*a)*2,f=[],p=0,m=!1,h=null,g=c.createMediaStreamSource(u),_=s(c,e=>{if(h){h.onChunk(e);return}for(f.push(e),p+=e.byteLength;p>d&&f.length>1;)p-=f.shift()?.byteLength??0},()=>{h?h.onSilent?.():m=!0});g.connect(_.node),_.start();let v=()=>{let e=f;return f=[],p=0,e},y=!1,b=async()=>{y||(y=!0,g.disconnect(),_.node.disconnect(),await c.close().catch(e=>{console.warn(`AudioContext close failed:`,e)}))};return{sampleRate:t,stream:u,ctx:c,handOff(e){h=e;let t=v();return t.length>0&&e.onBuffered(t),m&&e.onSilent?.(),{mic:g,capture:_}},async detach(){return await _.stop(),await b(),{chunks:v(),sampleRate:t}},async close(){y||await _.stop();for(let e of u.getTracks())e.stop();await b()}}}function l(e){let t=new Int16Array(e.length);for(let n=0;n<e.length;n++){let r=Math.max(-1,Math.min(1,e[n]??0));t[n]=r<0?r*32768:r*32767}return t.buffer}async function u(e,t,r){let i=e.reduce((e,t)=>e+t.byteLength/2,0);if(i===0)return[];if(t===r)return e;try{let a=Math.round(i*r/t),o=new OfflineAudioContext(1,a,r),s=o.createBuffer(1,i,t),c=s.getChannelData(0),u=0;for(let t of e)for(let e of new Int16Array(t))c[u++]=e/32768;let d=o.createBufferSource();d.buffer=s,d.connect(o.destination),d.start();let f=(await o.startRendering()).getChannelData(0),p=Math.max(1,Math.round(r*n)),m=[];for(let e=0;e<f.length;e+=p)m.push(l(f.subarray(e,e+p)));return m}catch(e){return console.warn(`[aai-ui] pre-connect audio dropped: resample failed`,e),[]}}async function d(e,t,n){let r=e.createMediaStreamSource(t),i=s(e,n.onMicData,n.onMicSilent);if(r.connect(i.node),n.buffered){let{chunks:t,sampleRate:r}=n.buffered,i=await u(t,r,e.sampleRate);i.length>0&&n.onBuffered(i)}return i.start(),{mic:r,capture:i}}async function f(n){let{sttSampleRate:s,ttsSampleRate:c,captureWorkletSrc:l,playbackWorkletSrc:u,onMicData:f,onError:p,onPlaybackStats:m,onPlaybackProgress:h,onMicSilent:g,preConnect:_}=n,v=n.onPreConnectAudio??(e=>{for(let t of e)f(t)}),y=_?.sampleRate===s?_:null,b=_&&!y?await _.detach():null,x=new AudioContext({sampleRate:c,latencyHint:`playback`}),S=!y&&s===c,C=y?.ctx??(S?x:new AudioContext({sampleRate:s,latencyHint:`interactive`}));async function w(){let e=S?[x]:[x,C];await Promise.all(e.map(e=>e.close().catch(e=>{console.warn(`AudioContext close failed:`,e)})))}let T=_?Promise.resolve(_.stream):navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...r}}),E;try{[E]=await Promise.all([T,x.resume(),C.resume(),y?void 0:C.audioWorklet.addModule(l),x.audioWorklet.addModule(u)]),i(C.sampleRate,s,`capture`),i(x.sampleRate,c,`playback`)}catch(e){throw o(T),await w(),e}let{mic:D,capture:O}=y?y.handOff({onBuffered:v,onChunk:f,onSilent:g}):await d(C,E,{onMicData:f,onMicSilent:g,buffered:b,onBuffered:v});O.node.onprocessorerror=()=>p?.(a(`capture`));let k=null,A=0,j=null,M=new AbortController;function N(){let e=j;j=null,e?.settle()}function P(e){e.stats&&e.stats.concealedSamples>0&&m?.(e.stats),e.reason!==`interrupt`&&(j===null||e.turn===j.turn)&&N()}function F(){if(k)return k;let e=new AudioWorkletNode(x,`playback-processor`);return e.connect(x.destination),e.port.onmessage=e=>{e.data.event===`stop`?P(e.data):e.data.event===`progress`&&h?.(e.data.bufferedMs)},e.onprocessorerror=()=>{let e=a(`playback`);N(),p?.(e)},k=e,e}let I={enqueue(e){M.signal.aborted||e.byteLength!==0&&F().port.postMessage({event:`write`,buffer:new Uint8Array(e)},[e])},done(){if(!k)return Promise.resolve();let n=++A;if(k.port.postMessage({event:`done`,turn:n}),x.state!==`running`)return N(),Promise.resolve();let{promise:r,resolve:i}=Promise.withResolvers();N();let a=()=>{clearInterval(o),clearTimeout(s),j?.settle===a&&(j=null),i()},o=setInterval(()=>{x.state!==`running`&&a()},e),s=setTimeout(a,t);return j={turn:n,settle:a},r},flush(){k&&(N(),k.port.postMessage({event:`interrupt`}))},async close(){if(!M.signal.aborted){M.abort(),await O.stop(),D.disconnect(),O.node.disconnect(),k&&k.disconnect();for(let e of E.getTracks())e.stop();await w()}},async[Symbol.asyncDispose](){await I.close()}};return I}export{f as createVoiceIO,c as openPreConnectCapture};
@@ -1,4 +1,4 @@
1
- import{n as e,t}from"./index-BOTLwsNO.js";import{t as n}from"./_module-url-BX0RuRU2.js";var r=`
1
+ import{n as e,t}from"./index-BlUYCTB5.js";import{t as n}from"./_module-url-BX0RuRU2.js";var r=`
2
2
  class CaptureProcessor extends AudioWorkletProcessor {
3
3
  constructor(options) {
4
4
  super();