@alexkroman1/aai-ui 5.14.0 → 6.2.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 (53) hide show
  1. package/README.md +2 -1
  2. package/dist/_repeat-until.d.ts +30 -0
  3. package/dist/_sse.d.ts +56 -0
  4. package/dist/_workflow-api-ref.d.ts +37 -0
  5. package/dist/audio.js +26 -26
  6. package/dist/{chat-view-CgFytvGy.js → chat-view-CK61bWWx.js} +2 -1
  7. package/dist/components/_form-values.d.ts +19 -0
  8. package/dist/components/chat-view.js +1 -1
  9. package/dist/components/form-types.d.ts +67 -0
  10. package/dist/components/form.d.ts +138 -0
  11. package/dist/components/message-list.js +1 -1
  12. package/dist/components/workflow-fields.d.ts +57 -0
  13. package/dist/components/workflow-progress.d.ts +55 -0
  14. package/dist/default-client/assets/audio-fO7SVU64.js +1 -0
  15. package/dist/default-client/assets/{capture-processor-B_5Ive8e.js → capture-processor-Dmc-KEpb.js} +4 -4
  16. package/dist/default-client/assets/client-audio-constants-Ck0IJO4c.js +1 -0
  17. package/dist/default-client/assets/index-CDugAuLK.css +2 -0
  18. package/dist/default-client/assets/index-DCI51Xz_.js +293 -0
  19. package/dist/default-client/assets/{playback-processor-6L8SIQ_l.js → playback-processor-DwQ9tE7X.js} +16 -13
  20. package/dist/default-client/index.html +3 -2
  21. package/dist/define-client.d.ts +40 -1
  22. package/dist/define-client.js +59 -17
  23. package/dist/index.d.ts +10 -0
  24. package/dist/index.js +1595 -5
  25. package/dist/{message-list-CcjgWRVZ.js → message-list-BwA3rdPi.js} +15 -1
  26. package/dist/page.d.ts +88 -0
  27. package/dist/{session-core-BA8H3qtF.js → session-core-ClKdVgRU.js} +245 -112
  28. package/dist/session-core-dial.d.ts +38 -0
  29. package/dist/session-core-handshake.d.ts +16 -1
  30. package/dist/session-core-messages.d.ts +2 -2
  31. package/dist/session-core-reconnect.d.ts +2 -7
  32. package/dist/session-core.js +1 -1
  33. package/dist/session-resume-store.d.ts +43 -0
  34. package/dist/types.d.ts +1 -1
  35. package/dist/types.js +2 -2
  36. package/dist/use-user-transcript.d.ts +70 -0
  37. package/dist/use-workflow-form.d.ts +136 -0
  38. package/dist/use-workflow-progress.d.ts +100 -0
  39. package/dist/use-workflow-run.d.ts +56 -0
  40. package/dist/use-workflow-runs.d.ts +71 -0
  41. package/dist/workflow-client.d.ts +97 -0
  42. package/dist/workflow-events.d.ts +39 -0
  43. package/dist/worklets/_playback-bench-harness.d.ts +181 -0
  44. package/dist/worklets/_playback-bench-host.d.ts +63 -0
  45. package/dist/worklets/_playback-bench-page.d.ts +65 -0
  46. package/dist/worklets/_tts-trace-harness.d.ts +142 -0
  47. package/dist/worklets/_worklet-test-utils.d.ts +27 -0
  48. package/dist/worklets/playback-processor.d.ts +1 -1
  49. package/dist/worklets/playback-processor.js +15 -12
  50. package/package.json +9 -8
  51. package/dist/default-client/assets/audio-CsQVQn3f.js +0 -1
  52. package/dist/default-client/assets/index-D35_z2WM.js +0 -293
  53. package/dist/default-client/assets/index-DCjB3qtb.css +0 -2
@@ -1,4 +1,4 @@
1
- import{i as e}from"./index-D35_z2WM.js";import{t}from"./_module-url-BX0RuRU2.js";var n=t(`
1
+ import{a as e}from"./client-audio-constants-Ck0IJO4c.js";import{t}from"./_module-url-BX0RuRU2.js";var n=`
2
2
  class PlaybackProcessor extends AudioWorkletProcessor {
3
3
  constructor(options) {
4
4
  super();
@@ -7,12 +7,17 @@ class PlaybackProcessor extends AudioWorkletProcessor {
7
7
  // so the worklet-global sampleRate is authoritative; the option exists
8
8
  // for the node-less test harness.
9
9
  const rate = opts.sampleRate ?? sampleRate;
10
- // Fill target for the start of a turn. If 'done' arrives first (short
11
- // utterance), start immediately instead of waiting for audio that is
12
- // never coming.
13
- this.jitterSamples = Math.floor((rate * (opts.jitterMs ?? 400)) / 1000);
14
- // Fill target after an underrun — see PLAYBACK_REFILL_MS.
15
- this.refillSamples = Math.floor((rate * (opts.refillMs ?? 200)) / 1000);
10
+ // Kept, because every derived quantity below reads it and \`bufferedMs\` in
11
+ // process() is the one that used to read the worklet global instead. Those
12
+ // agree in production (the option is unset, so \`rate\` IS \`sampleRate\`) and
13
+ // diverge only in the node-less harness — which is the one place a spec
14
+ // could ever assert on the reported backlog, so the divergence made the
15
+ // number untestable rather than wrong.
16
+ this.rate = rate;
17
+ // The one fill target — for the start of a turn and for recovery after an
18
+ // underrun alike. If 'done' arrives first (short utterance), start
19
+ // immediately instead of waiting for audio that is never coming.
20
+ this.fillSamples = Math.floor((rate * (opts.fillMs ?? 200)) / 1000);
16
21
  // Concealment source: a ring of the most recently played samples, looped
17
22
  // under a decaying gain to cover a gap. Sized to the fade window, with a
18
23
  // per-sample decay that reaches the floor exactly at its end.
@@ -69,7 +74,6 @@ class PlaybackProcessor extends AudioWorkletProcessor {
69
74
  // pre-roll (nothing to extrapolate from, and not a defect) from a
70
75
  // mid-turn underrun.
71
76
  this.hasPlayed = false;
72
- this.fillTarget = this.jitterSamples;
73
77
  // Carry-over byte for split samples across chunks
74
78
  this.carry = null;
75
79
  this.writePos = 0;
@@ -254,14 +258,14 @@ class PlaybackProcessor extends AudioWorkletProcessor {
254
258
  if (this.sinceReportSamples >= this.reportIntervalSamples) {
255
259
  this.sinceReportSamples = 0;
256
260
  if (avail > 0) {
257
- this.port.postMessage({ event: 'progress', bufferedMs: (avail / sampleRate) * 1000 });
261
+ this.port.postMessage({ event: 'progress', bufferedMs: (avail / this.rate) * 1000 });
258
262
  }
259
263
  }
260
264
 
261
265
  // Filling: wait for the target. 'done' short-circuits it — what is
262
266
  // buffered is all there will be, so there is nothing left to wait for.
263
267
  if (!this.playing) {
264
- if (avail >= this.fillTarget || this.isDone) {
268
+ if (avail >= this.fillSamples || this.isDone) {
265
269
  this.playing = true;
266
270
  } else {
267
271
  this.coverGap(out, 0);
@@ -270,13 +274,12 @@ class PlaybackProcessor extends AudioWorkletProcessor {
270
274
  }
271
275
 
272
276
  // Underrun: this quantum cannot be filled and more audio is still coming.
273
- // Go back to filling (at the refill target) and cover the gap, leaving
277
+ // Go back to filling and cover the gap, leaving
274
278
  // readPos untouched — the fragment stays buffered and plays intact once
275
279
  // the buffer recovers, instead of being dribbled out a few samples at a
276
280
  // time for the rest of the turn.
277
281
  if (avail < out.length && !this.isDone) {
278
282
  this.playing = false;
279
- this.fillTarget = this.refillSamples;
280
283
  this.coverGap(out, 0);
281
284
  return true;
282
285
  }
@@ -308,4 +311,4 @@ class PlaybackProcessor extends AudioWorkletProcessor {
308
311
  }
309
312
 
310
313
  registerProcessor('playback-processor', PlaybackProcessor);
311
- `);export{n as default};
314
+ `,r=t(n);export{r as default};
@@ -6,8 +6,9 @@
6
6
  <title>aai</title>
7
7
  <link rel="icon" href="./favicon.ico" />
8
8
  <style>html, body { background: #FBF8F2; margin: 0; }</style>
9
- <script type="module" crossorigin src="./assets/index-D35_z2WM.js"></script>
10
- <link rel="stylesheet" crossorigin href="./assets/index-DCjB3qtb.css">
9
+ <script type="module" crossorigin src="./assets/index-DCI51Xz_.js"></script>
10
+ <link rel="modulepreload" crossorigin href="./assets/client-audio-constants-Ck0IJO4c.js">
11
+ <link rel="stylesheet" crossorigin href="./assets/index-CDugAuLK.css">
11
12
  </head>
12
13
  <body>
13
14
  <main id="app"></main>
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource react */
2
- import { type ComponentType } from "react";
2
+ import { type ComponentType, type ReactNode } from "react";
3
3
  import { type ToolDisplayConfig } from "./components/tool-config-context.ts";
4
4
  import type { SessionCore } from "./session-core-types.ts";
5
5
  import type { ClientTheme, VoiceSessionOptions } from "./types.ts";
@@ -99,6 +99,45 @@ export type ClientHandle = {
99
99
  /** Alias for `dispose` for use with `using`. */
100
100
  [Symbol.dispose](): void;
101
101
  };
102
+ /**
103
+ * The element a mount renders into.
104
+ *
105
+ * Exported so `page()` resolves its target the same way `client()` does — the
106
+ * default selector and the "element not found" sentence are part of what an
107
+ * author has learned, and a second copy is how the two mounts come to disagree
108
+ * about which one they were given.
109
+ *
110
+ * @internal
111
+ */
112
+ export declare function resolveContainer(target?: string | HTMLElement): HTMLElement;
113
+ /**
114
+ * What a mount hands back: unmount, and `using` support.
115
+ *
116
+ * @internal
117
+ */
118
+ export type MountedRoot = {
119
+ /** Unmount the React tree (and, for `client()`, dispose the session). */
120
+ dispose(): void;
121
+ /** Alias for `dispose` for use with `using`. */
122
+ [Symbol.dispose](): void;
123
+ };
124
+ /**
125
+ * Render `node` into `container` and hand back its teardown.
126
+ *
127
+ * Shared by {@link client} and `page()` because the plumbing is identical and
128
+ * the two decisions in it are not obvious enough to be re-derived: the root is
129
+ * created here rather than by the caller so nothing else can hold one, and the
130
+ * render is `flushSync` so the mount is observable to the caller's NEXT
131
+ * STATEMENT (and to a test) rather than scheduled — `client()` returns a handle
132
+ * whose session is expected to be live, and `page()` returns one a caller may
133
+ * dispose immediately.
134
+ *
135
+ * `onDispose` runs after the unmount, which is the order `client()` needs: the
136
+ * tree comes down before the session under it goes away.
137
+ *
138
+ * @internal
139
+ */
140
+ export declare function mountRoot(container: HTMLElement, node: ReactNode, onDispose?: () => void): MountedRoot;
102
141
  /**
103
142
  * Define and mount a client UI for a voice agent.
104
143
  *
@@ -1,6 +1,6 @@
1
- import { r as fetchClientConfig, t as createSessionCore } from "./session-core-BA8H3qtF.js";
1
+ import { r as fetchClientConfig, t as createSessionCore } from "./session-core-ClKdVgRU.js";
2
2
  import { SessionProvider, ThemeProvider } from "./context.js";
3
- import { t as ChatView } from "./chat-view-CgFytvGy.js";
3
+ import { t as ChatView } from "./chat-view-CK61bWWx.js";
4
4
  import { t as pageBaseUrl } from "./_utils-CsqbIVGI.js";
5
5
  import { n as ToolConfigContext } from "./tool-call-block-CrLN7xlI.js";
6
6
  import { SidebarLayout } from "./components/sidebar-layout.js";
@@ -11,6 +11,16 @@ import { flushSync } from "react-dom";
11
11
  import { createRoot } from "react-dom/client";
12
12
  //#region define-client.tsx
13
13
  /** @jsxImportSource react */
14
+ /**
15
+ * The element a mount renders into.
16
+ *
17
+ * Exported so `page()` resolves its target the same way `client()` does — the
18
+ * default selector and the "element not found" sentence are part of what an
19
+ * author has learned, and a second copy is how the two mounts come to disagree
20
+ * about which one they were given.
21
+ *
22
+ * @internal
23
+ */
14
24
  function resolveContainer(target = "#app") {
15
25
  if (typeof target !== "string") return target;
16
26
  const el = document.querySelector(target);
@@ -18,6 +28,37 @@ function resolveContainer(target = "#app") {
18
28
  return el;
19
29
  }
20
30
  /**
31
+ * Render `node` into `container` and hand back its teardown.
32
+ *
33
+ * Shared by {@link client} and `page()` because the plumbing is identical and
34
+ * the two decisions in it are not obvious enough to be re-derived: the root is
35
+ * created here rather than by the caller so nothing else can hold one, and the
36
+ * render is `flushSync` so the mount is observable to the caller's NEXT
37
+ * STATEMENT (and to a test) rather than scheduled — `client()` returns a handle
38
+ * whose session is expected to be live, and `page()` returns one a caller may
39
+ * dispose immediately.
40
+ *
41
+ * `onDispose` runs after the unmount, which is the order `client()` needs: the
42
+ * tree comes down before the session under it goes away.
43
+ *
44
+ * @internal
45
+ */
46
+ function mountRoot(container, node, onDispose) {
47
+ const root = createRoot(container);
48
+ flushSync(() => {
49
+ root.render(node);
50
+ });
51
+ return {
52
+ dispose() {
53
+ root.unmount();
54
+ onDispose?.();
55
+ },
56
+ [Symbol.dispose]() {
57
+ this.dispose();
58
+ }
59
+ };
60
+ }
61
+ /**
21
62
  * Default shell rendered in config tier.
22
63
  * Wraps StartScreen → (SidebarLayout →) ChatView.
23
64
  */
@@ -38,10 +79,22 @@ function DefaultShell({ name, Sidebar, sidebarWidth }) {
38
79
  * immediately — optimistically — while the lookup is in flight; servers
39
80
  * without the endpoint (every lookup failure resolves to the empty default)
40
81
  * work exactly as before.
82
+ *
83
+ * **The lookup is SKIPPED when the caller already named the agent.** The
84
+ * response's only consumer here is the fallback below, so with an explicit
85
+ * `client({ name })` the request was issued and its answer thrown away — and on
86
+ * the platform this endpoint is the BROKER, so the discarded request is one that
87
+ * can boot a sandbox. The session's own per-attempt lookup
88
+ * (`session-core.ts`'s URL provider) is a different question and deliberately
89
+ * left alone: it re-brokers on every connection attempt, which is what makes a
90
+ * reconnect land on a REPLACEMENT sandbox, so it may not be served from
91
+ * anything this render already has.
41
92
  */
42
93
  function DefaultRoot({ platformUrl, name, Sidebar, sidebarWidth }) {
43
94
  const [resolved, setResolved] = useState(null);
95
+ const needsLookup = name === void 0;
44
96
  useEffect(() => {
97
+ if (!needsLookup) return;
45
98
  let cancelled = false;
46
99
  fetchClientConfig(platformUrl).then((cfg) => {
47
100
  if (!cancelled) setResolved(cfg);
@@ -49,7 +102,7 @@ function DefaultRoot({ platformUrl, name, Sidebar, sidebarWidth }) {
49
102
  return () => {
50
103
  cancelled = true;
51
104
  };
52
- }, [platformUrl]);
105
+ }, [platformUrl, needsLookup]);
53
106
  return /* @__PURE__ */ jsx(DefaultShell, {
54
107
  name: name ?? resolved?.name,
55
108
  Sidebar,
@@ -120,21 +173,10 @@ function client(config) {
120
173
  sidebarWidth: config.sidebarWidth
121
174
  });
122
175
  const toolConfig = config.tools ?? {};
123
- const root = createRoot(container);
124
- flushSync(() => {
125
- root.render(createElement(ToolConfigContext.Provider, { value: toolConfig }, createElement(ThemeProvider, { value: config.theme }, createElement(SessionProvider, { value: session }, rootNode))));
126
- });
127
- const handle = {
176
+ return {
128
177
  session,
129
- dispose() {
130
- root.unmount();
131
- session[Symbol.dispose]();
132
- },
133
- [Symbol.dispose]() {
134
- handle.dispose();
135
- }
178
+ ...mountRoot(container, createElement(ToolConfigContext.Provider, { value: toolConfig }, createElement(ThemeProvider, { value: config.theme }, createElement(SessionProvider, { value: session }, rootNode))), () => session[Symbol.dispose]())
136
179
  };
137
- return handle;
138
180
  }
139
181
  //#endregion
140
- export { client };
182
+ export { client, mountRoot, resolveContainer };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export { AutoScroll } from "./components/auto-scroll.tsx";
3
3
  export { Button, type ButtonSize, type ButtonVariant } from "./components/button.tsx";
4
4
  export { ChatView } from "./components/chat-view.tsx";
5
5
  export { Controls } from "./components/controls.tsx";
6
+ export { CheckboxField, Field, type FieldShell, FileField, type FileRead, type FileValue, Form, type FormProps, type FormValues, NumberField, SelectField, SubmitButton, TextAreaField, TextField, } from "./components/form.tsx";
6
7
  export { Markdown, type MarkdownVariant } from "./components/markdown.tsx";
7
8
  export { MessageList } from "./components/message-list.tsx";
8
9
  export { SidebarLayout } from "./components/sidebar-layout.tsx";
@@ -11,12 +12,21 @@ export { ToolCallRow, type ToolCallRowProps, type ToolCallRowVariant, } from "./
11
12
  export type { ToolDisplayConfig } from "./components/tool-config-context.ts";
12
13
  export { ToolConfigContext } from "./components/tool-config-context.ts";
13
14
  export { ApiUrlChip, SessionUrlChips, UiUrlChip } from "./components/url-chips.tsx";
15
+ export { WorkflowFields } from "./components/workflow-fields.tsx";
16
+ export { WorkflowProgress } from "./components/workflow-progress.tsx";
14
17
  export type { Session } from "./context.ts";
15
18
  export { SessionProvider, ThemeProvider, useSession, useSessionSelector, useTheme, } from "./context.ts";
16
19
  export type { BaseOptions, ClientConfig, ClientHandle, ComponentTier, ConfigTier, } from "./define-client.tsx";
17
20
  export { client } from "./define-client.tsx";
18
21
  export { useAgentState, useEvent, useToolCallStart, useToolResult } from "./hooks.ts";
22
+ export { type PageConfig, type PageHandle, page } from "./page.tsx";
19
23
  export { createSessionCore } from "./session-core.ts";
20
24
  export type { AgentCustomEvent, SessionCore, SessionCoreOptions, SessionSnapshot, } from "./session-core-types.ts";
21
25
  export type { AgentState, ChatMessage, ClientTheme, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor, } from "./types.ts";
22
26
  export { VOICE_CAPTURE_CONSTRAINTS } from "./types.ts";
27
+ export { TRANSCRIBING_PLACEHOLDER, type UseUserTranscriptResult, useUserTranscript, } from "./use-user-transcript.ts";
28
+ export { type UseWorkflowSubmitOptions, type UseWorkflowsOptions, type UseWorkflowsResult, useWorkflowSubmit, useWorkflows, type WorkflowSubmission, } from "./use-workflow-form.ts";
29
+ export { DEFAULT_PROGRESS_POLL_MS, type UseWorkflowProgressResult, useWorkflowProgress, } from "./use-workflow-progress.ts";
30
+ export { DEFAULT_WORKFLOW_POLL_MS, MAX_MISSING_READS, type UseWorkflowRunResult, useWorkflowRun, } from "./use-workflow-run.ts";
31
+ export { type UseWorkflowRunsOptions, type UseWorkflowRunsResult, useWorkflowRuns, } from "./use-workflow-runs.ts";
32
+ export { createWorkflowApi, isTerminal, type WorkflowApi, type WorkflowApiOptions, type WorkflowOutputOf, type WorkflowRun, type WorkflowSummary, } from "./workflow-client.ts";