@alexkroman1/aai-ui 5.13.2 → 6.1.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 (57) 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-DadZOvJO.js → chat-view-CK61bWWx.js} +4 -3
  7. package/dist/components/_form-values.d.ts +19 -0
  8. package/dist/components/auto-scroll.d.ts +63 -0
  9. package/dist/components/chat-view.js +1 -1
  10. package/dist/components/controls.js +1 -1
  11. package/dist/components/form-types.d.ts +67 -0
  12. package/dist/components/form.d.ts +138 -0
  13. package/dist/components/message-list.js +1 -1
  14. package/dist/components/start-screen.js +1 -1
  15. package/dist/components/tool-call-block.js +1 -1
  16. package/dist/components/workflow-fields.d.ts +57 -0
  17. package/dist/components/workflow-progress.d.ts +55 -0
  18. package/dist/default-client/assets/audio-fO7SVU64.js +1 -0
  19. package/dist/default-client/assets/{capture-processor-CWRLCPS3.js → capture-processor-Dmc-KEpb.js} +4 -4
  20. package/dist/default-client/assets/client-audio-constants-Ck0IJO4c.js +1 -0
  21. package/dist/default-client/assets/index-4u908fff.js +293 -0
  22. package/dist/default-client/assets/index-CDugAuLK.css +2 -0
  23. package/dist/default-client/assets/{playback-processor-SKKE9qu2.js → playback-processor-DUsmALNH.js} +10 -3
  24. package/dist/default-client/index.html +3 -2
  25. package/dist/define-client.d.ts +40 -1
  26. package/dist/define-client.js +61 -19
  27. package/dist/hooks.d.ts +30 -0
  28. package/dist/hooks.js +4 -26
  29. package/dist/index.d.ts +11 -0
  30. package/dist/index.js +1597 -7
  31. package/dist/{message-list-YdLocGoT.js → message-list-BwA3rdPi.js} +105 -27
  32. package/dist/page.d.ts +88 -0
  33. package/dist/{session-core-BA8H3qtF.js → session-core-ClKdVgRU.js} +245 -112
  34. package/dist/session-core-dial.d.ts +38 -0
  35. package/dist/session-core-handshake.d.ts +16 -1
  36. package/dist/session-core-messages.d.ts +2 -2
  37. package/dist/session-core-reconnect.d.ts +2 -7
  38. package/dist/session-core.js +1 -1
  39. package/dist/session-resume-store.d.ts +43 -0
  40. package/dist/types.d.ts +1 -1
  41. package/dist/types.js +1 -1
  42. package/dist/use-user-transcript.d.ts +70 -0
  43. package/dist/use-workflow-form.d.ts +136 -0
  44. package/dist/use-workflow-progress.d.ts +100 -0
  45. package/dist/use-workflow-run.d.ts +56 -0
  46. package/dist/use-workflow-runs.d.ts +71 -0
  47. package/dist/workflow-client.d.ts +97 -0
  48. package/dist/workflow-events.d.ts +39 -0
  49. package/dist/worklets/playback-processor.d.ts +1 -1
  50. package/dist/worklets/playback-processor.js +8 -1
  51. package/package.json +9 -8
  52. package/dist/default-client/assets/audio-BqyrSHNq.js +0 -1
  53. package/dist/default-client/assets/index-Ctjrde3-.css +0 -2
  54. package/dist/default-client/assets/index-DfVI-qZ8.js +0 -293
  55. package/dist/{aai-logo-B8lDmsut.js → aai-logo-9xRBGVFl.js} +1 -1
  56. package/dist/{controls-DzQEKq9c.js → controls-Cy_YVfsa.js} +1 -1
  57. package/dist/{tool-call-block-CAscLGFy.js → tool-call-block-CrLN7xlI.js} +1 -1
@@ -1,12 +1,82 @@
1
1
  import { useSessionSelector, useTheme } from "./context.js";
2
2
  import { i as primaryTint, r as inkTint } from "./_colors-CcAi2FOU.js";
3
- import { t as ToolCallBlock } from "./tool-call-block-CAscLGFy.js";
3
+ import { t as ToolCallBlock } from "./tool-call-block-CrLN7xlI.js";
4
4
  import clsx from "clsx";
5
- import { memo, useMemo } from "react";
6
- import { jsx, jsxs } from "react/jsx-runtime";
7
5
  import { StickToBottom } from "use-stick-to-bottom";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { memo, useMemo } from "react";
8
8
  import ReactMarkdown from "react-markdown";
9
9
  import remarkGfm from "remark-gfm";
10
+ //#region components/auto-scroll.tsx
11
+ /** @jsxImportSource react */
12
+ /**
13
+ * A scroll container that stays pinned to the bottom as its content grows,
14
+ * releases when the reader scrolls up, and re-engages once they return to the
15
+ * bottom.
16
+ *
17
+ * For clients that render their own chat chrome instead of using
18
+ * {@link MessageList} — a terminal, a dispatch board, a themed transcript.
19
+ * `MessageList` already behaves this way; this is the same mechanism with no
20
+ * opinion about what goes inside it.
21
+ *
22
+ * @remarks
23
+ * The pattern this replaces is a `useEffect` that calls
24
+ * `ref.current?.scrollIntoView()` on every message change. That version has
25
+ * three faults, and they compound: it fights the reader, since scrolling up to
26
+ * re-read is undone by the next transcript delta; it misses growth that is not
27
+ * a new message, because a streamed reply, an expanding tool block or a
28
+ * markdown reflow changes height without changing the dependency array; and it
29
+ * needs a synthetic dependency (`messages.length + transcript.length`) to fire
30
+ * at all, which is where the dead `if (version < 0) return;` line comes from.
31
+ * A `ResizeObserver` on the content — what this uses — has none of those.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * import { AutoScroll, useSession } from "@alexkroman1/aai-ui";
36
+ *
37
+ * function Transcript() {
38
+ * const session = useSession();
39
+ * return (
40
+ * <AutoScroll className="flex-1 min-h-0" contentClassName="flex flex-col gap-2 p-4">
41
+ * {session.messages.map((m) => (
42
+ * <div key={m.id}>{m.content}</div>
43
+ * ))}
44
+ * </AutoScroll>
45
+ * );
46
+ * }
47
+ * ```
48
+ *
49
+ * @param children - The scrollable content.
50
+ * @param className - Classes for the outer container. It must be given a
51
+ * bounded height (`flex-1 min-h-0`, `h-full`, a fixed height) — an unbounded
52
+ * one grows with its content and never scrolls, so nothing pins.
53
+ * @param contentClassName - Classes for the inner content element, where
54
+ * padding and the children's own layout belong.
55
+ * @param scrollClassName - Classes for the scrolling element itself. Defaults
56
+ * to hiding the scrollbar; pass `"overflow-y-auto"` to show a native one.
57
+ * @param style - Inline styles for the outer container.
58
+ * @param initial - Scroll behavior on mount. Defaults to `"instant"` (start at
59
+ * the latest content without animating a scroll the reader did not ask for).
60
+ * @param resize - Scroll behavior when pinned content grows. Defaults to
61
+ * `"smooth"`.
62
+ *
63
+ * @public
64
+ */
65
+ function AutoScroll({ children, className, contentClassName, scrollClassName = "overflow-y-auto [scrollbar-width:none]", style, initial = "instant", resize = "smooth" }) {
66
+ return /* @__PURE__ */ jsx(StickToBottom, {
67
+ role: "log",
68
+ className: clsx("flex-1 min-h-0", className),
69
+ style,
70
+ initial,
71
+ resize,
72
+ children: /* @__PURE__ */ jsx(StickToBottom.Content, {
73
+ scrollClassName,
74
+ className: contentClassName,
75
+ children
76
+ })
77
+ });
78
+ }
79
+ //#endregion
10
80
  //#region components/markdown.tsx
11
81
  /** @jsxImportSource react */
12
82
  const BARE_ORDERED_MARKER = /^(\s*)(\d{1,9})([.)])\s*$/;
@@ -191,11 +261,25 @@ const DOT_STYLES = [
191
261
  animation: "aai-bounce 1.4s infinite ease-in-out both",
192
262
  animationDelay: `${delay}s`
193
263
  }));
194
- /** Animated three-dot "thinking" indicator. @internal */
264
+ /**
265
+ * Animated three-dot "thinking" indicator.
266
+ *
267
+ * `role="status"` with a label, for the same reason `ConsoleShell` announces
268
+ * its error banner: three animated dots are the only signal that the agent is
269
+ * working on a reply, and to a screen reader they are three empty `<div>`s.
270
+ * It is also the indicator's semantic handle — a spec asserting its presence by
271
+ * counting `.rounded-full` elements breaks when the three dots become a spinner
272
+ * (correct behaviour, red test) and again when any sibling row gains a round
273
+ * badge (wrong behaviour, green test).
274
+ *
275
+ * @internal
276
+ */
195
277
  function ThinkingDots() {
196
278
  const theme = useTheme();
197
279
  const muted = inkTint(theme.text, theme.surface, 75);
198
280
  return /* @__PURE__ */ jsx("div", {
281
+ role: "status",
282
+ "aria-label": "Thinking",
199
283
  className: "flex items-center gap-2 text-sm font-medium min-h-5",
200
284
  style: { color: muted },
201
285
  children: DOT_STYLES.map((style, i) => /* @__PURE__ */ jsx("div", {
@@ -332,30 +416,24 @@ const MessageList = memo(function MessageList({ className }) {
332
416
  toolCalls,
333
417
  theme
334
418
  ]);
335
- return /* @__PURE__ */ jsx(StickToBottom, {
336
- role: "log",
337
- className: clsx("flex-1 min-h-0", className),
419
+ return /* @__PURE__ */ jsxs(AutoScroll, {
420
+ className,
338
421
  style: { background: theme.surface },
339
- initial: "instant",
340
- resize: "smooth",
341
- children: /* @__PURE__ */ jsxs(StickToBottom.Content, {
342
- scrollClassName: "overflow-y-auto [scrollbar-width:none]",
343
- className: "flex flex-col gap-4 p-7",
344
- children: [
345
- items,
346
- streamingMessage && /* @__PURE__ */ jsx(MessageBubble, {
347
- message: streamingMessage,
348
- theme
349
- }),
350
- userTranscript !== null && /* @__PURE__ */ jsx(UserBubble, {
351
- theme,
352
- color: inkTint(theme.text, theme.surface, 65),
353
- children: userTranscript ? userTranscript : /* @__PURE__ */ jsx(ThinkingDots, {})
354
- }),
355
- showThinking && /* @__PURE__ */ jsx(ThinkingDots, {})
356
- ]
357
- })
422
+ contentClassName: "flex flex-col gap-4 p-7",
423
+ children: [
424
+ items,
425
+ streamingMessage && /* @__PURE__ */ jsx(MessageBubble, {
426
+ message: streamingMessage,
427
+ theme
428
+ }),
429
+ userTranscript !== null && /* @__PURE__ */ jsx(UserBubble, {
430
+ theme,
431
+ color: inkTint(theme.text, theme.surface, 65),
432
+ children: userTranscript ? userTranscript : /* @__PURE__ */ jsx(ThinkingDots, {})
433
+ }),
434
+ showThinking && /* @__PURE__ */ jsx(ThinkingDots, {})
435
+ ]
358
436
  });
359
437
  });
360
438
  //#endregion
361
- export { Markdown as n, MessageList as t };
439
+ export { Markdown as n, AutoScroll as r, MessageList as t };
package/dist/page.d.ts ADDED
@@ -0,0 +1,88 @@
1
+ /** @jsxImportSource react */
2
+ /**
3
+ * `page()` — mount a WORKFLOW APP's UI: React, theme, no session.
4
+ *
5
+ * The twin of `client()` for an agent whose front door is a form rather than a
6
+ * microphone (`workflowApp()`). It is a separate entry rather than
7
+ * an option on `client()` because of what `client()` unavoidably does: it
8
+ * constructs a `SessionCore`, which owns a WebSocket URL provider, an audio
9
+ * graph, and a microphone request. A flag would have to make all of that
10
+ * conditional, and every session hook would then have to answer "what does this
11
+ * mean with no session?" — so the honest split is two mounts. A page that wants
12
+ * voice uses `client()`; a page that wants neither audio nor a socket uses this.
13
+ *
14
+ * Authoring is otherwise identical — the file is still `client.tsx`, still
15
+ * React, still Tailwind, still the same theme tokens — so a workflow app reads
16
+ * like every other agent. What it reaches for instead of `useSession()` is
17
+ * `createWorkflowApi()` / `useWorkflowRun()`.
18
+ */
19
+ import { type ComponentType } from "react";
20
+ import type { ClientTheme } from "./types.ts";
21
+ /**
22
+ * Configuration for {@link page}.
23
+ *
24
+ * @public
25
+ */
26
+ export type PageConfig = {
27
+ /**
28
+ * The root component. Required — a workflow app has no default shell to fall
29
+ * back to, because there is no session for one to render.
30
+ */
31
+ component: ComponentType;
32
+ /** CSS selector or DOM element to render into. Defaults to `"#app"`. */
33
+ target?: string | HTMLElement;
34
+ /**
35
+ * Page title. Set only when given, so a title the HTML shell declared is never
36
+ * clobbered — the same rule `client()`'s custom-component tier follows.
37
+ */
38
+ name?: string;
39
+ /** Theme color overrides, read by the same tokens the voice components use. */
40
+ theme?: ClientTheme;
41
+ };
42
+ /**
43
+ * Handle returned by {@link page}. `Disposable`, so `using` works.
44
+ *
45
+ * @public
46
+ */
47
+ export type PageHandle = {
48
+ /** Unmount the React tree. */
49
+ dispose(): void;
50
+ /** Alias for `dispose` for use with `using`. */
51
+ [Symbol.dispose](): void;
52
+ };
53
+ /**
54
+ * Mount a page for an agent whose work happens in workflows.
55
+ *
56
+ * There is deliberately no session, no microphone, and no socket: the component
57
+ * talks to the agent over the workflow HTTP API
58
+ * (`createWorkflowApi`/`useWorkflowRun`), which is durable and outlives the tab.
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * import { createWorkflowApi, page, useWorkflowRun } from "@alexkroman1/aai-ui";
63
+ * import { useState } from "react";
64
+ *
65
+ * // Hoisted: a client built in render is a new object every render.
66
+ * const api = createWorkflowApi();
67
+ *
68
+ * function App() {
69
+ * const [runId, setRunId] = useState<string>();
70
+ * const { run } = useWorkflowRun(runId, { api });
71
+ * return (
72
+ * <button
73
+ * type="button"
74
+ * onClick={() => void api.start("digest", { topic: "ai" }).then(setRunId)}
75
+ * >
76
+ * {run ? run.status : "Start"}
77
+ * </button>
78
+ * );
79
+ * }
80
+ *
81
+ * page({ name: "Digest", component: App });
82
+ * ```
83
+ *
84
+ * @throws If the target element is not found in the DOM.
85
+ *
86
+ * @public
87
+ */
88
+ export declare function page(config: PageConfig): PageHandle;