@alexkroman1/aai-ui 0.12.2 → 0.13.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 (215) hide show
  1. package/README.md +257 -0
  2. package/dist/_colors-CpZO-88A.js +78 -0
  3. package/dist/_module-url-C13kAJ87.js +15 -0
  4. package/dist/_page-shell.d.ts +11 -0
  5. package/dist/_recover-run.d.ts +79 -0
  6. package/dist/_repeat-until.d.ts +30 -0
  7. package/dist/_run-controls.d.ts +33 -0
  8. package/dist/_submission-state.d.ts +92 -0
  9. package/dist/_tap-to-talk-state.d.ts +88 -0
  10. package/dist/_utils-Mi-SCFA1.js +47 -0
  11. package/dist/_utils.d.ts +26 -0
  12. package/dist/_web-storage.d.ts +43 -0
  13. package/dist/_workflow-api-ref.d.ts +37 -0
  14. package/dist/_workflow-files.d.ts +34 -0
  15. package/dist/_workflow-test-defs.d.ts +38 -0
  16. package/dist/aai-logo-D8pMVn9_.js +85 -0
  17. package/dist/agent-state-labels.d.ts +65 -0
  18. package/dist/agent-state.d.ts +108 -0
  19. package/dist/audio/capture.d.ts +44 -0
  20. package/dist/audio/index.d.ts +18 -0
  21. package/dist/audio/index.js +431 -0
  22. package/dist/audio/preconnect.d.ts +87 -0
  23. package/dist/audio/voice-io.d.ts +112 -0
  24. package/dist/build-default-client.d.ts +1 -0
  25. package/dist/chat-view-BCbI7gD4.js +396 -0
  26. package/dist/client-config-C7fQrioM.js +139 -0
  27. package/dist/client-config.d.ts +119 -0
  28. package/dist/client-dir.d.ts +44 -0
  29. package/dist/client-dir.js +58 -0
  30. package/dist/client-identity.d.ts +131 -0
  31. package/dist/client-tool.d.ts +51 -0
  32. package/dist/components/_colors.d.ts +73 -0
  33. package/dist/components/_form-readiness.d.ts +56 -0
  34. package/dist/components/_form-values.d.ts +19 -0
  35. package/dist/components/aai-logo.d.ts +12 -0
  36. package/dist/components/audio-result.d.ts +94 -0
  37. package/dist/components/auto-scroll.d.ts +74 -0
  38. package/dist/components/bullet-list.d.ts +74 -0
  39. package/dist/components/button.d.ts +58 -0
  40. package/dist/components/button.js +85 -0
  41. package/dist/components/chat-view.d.ts +35 -0
  42. package/dist/components/chat-view.js +3 -0
  43. package/dist/components/console-shell.d.ts +85 -0
  44. package/dist/components/controls.d.ts +33 -0
  45. package/dist/components/controls.js +49 -0
  46. package/dist/components/conversation-view.d.ts +130 -0
  47. package/dist/components/eyebrow.d.ts +12 -0
  48. package/dist/components/facts.d.ts +81 -0
  49. package/dist/components/form-fields.d.ts +142 -0
  50. package/dist/components/form-types.d.ts +73 -0
  51. package/dist/components/form.d.ts +96 -0
  52. package/dist/components/markdown.d.ts +57 -0
  53. package/dist/components/message-list.d.ts +48 -0
  54. package/dist/components/message-list.js +3 -0
  55. package/dist/components/session-controls.d.ts +125 -0
  56. package/dist/components/session-error-banner.d.ts +69 -0
  57. package/dist/components/session-state-dot.d.ts +111 -0
  58. package/dist/components/sidebar-layout.d.ts +42 -0
  59. package/dist/components/sidebar-layout.js +56 -0
  60. package/dist/components/start-screen.d.ts +37 -0
  61. package/dist/components/start-screen.js +71 -0
  62. package/dist/components/tool-call-block.d.ts +28 -0
  63. package/dist/components/tool-call-block.js +3 -0
  64. package/dist/components/tool-call-row.d.ts +75 -0
  65. package/dist/components/tool-config-context.d.ts +22 -0
  66. package/dist/components/upload-progress.d.ts +76 -0
  67. package/dist/components/url-chips.d.ts +29 -0
  68. package/dist/components/workflow-fields.d.ts +46 -0
  69. package/dist/components/workflow-pending-note.d.ts +81 -0
  70. package/dist/components/workflow-progress.d.ts +81 -0
  71. package/dist/components/workflow-run-error.d.ts +48 -0
  72. package/dist/components/workflow-run-panel.d.ts +79 -0
  73. package/dist/context.d.ts +288 -0
  74. package/dist/context.js +382 -0
  75. package/dist/conversation-log.d.ts +88 -0
  76. package/dist/default-client/assets/_module-url-BX0RuRU2.js +1 -0
  77. package/dist/default-client/assets/audio-cGFGID-2.js +1 -0
  78. package/dist/default-client/assets/capture-processor-BUABoo3_.js +90 -0
  79. package/dist/default-client/assets/index-8ihb1Urm.css +2 -0
  80. package/dist/default-client/assets/index-BQURVARl.js +126 -0
  81. package/dist/default-client/assets/playback-processor-ABOa11j0.js +314 -0
  82. package/dist/default-client/favicon.ico +0 -0
  83. package/dist/default-client/index.html +15 -0
  84. package/dist/default-client.d.ts +23 -0
  85. package/dist/define-client.d.ts +162 -26
  86. package/dist/define-client.js +201 -55
  87. package/dist/eyebrow-UfmSz9yy.js +27 -0
  88. package/dist/hooks-DN4gHYsj.js +182 -0
  89. package/dist/hooks.d.ts +172 -0
  90. package/dist/hooks.js +3 -0
  91. package/dist/hooks.test-d.d.ts +14 -0
  92. package/dist/inbox-protocol.d.ts +128 -0
  93. package/dist/inbox.d.ts +132 -0
  94. package/dist/index.d.ts +129 -32
  95. package/dist/index.js +5503 -18
  96. package/dist/internal.d.ts +43 -0
  97. package/dist/internal.js +8 -0
  98. package/dist/linked-client.d.ts +70 -0
  99. package/dist/message-list-DHZcLhRA.js +682 -0
  100. package/dist/notice-player.d.ts +70 -0
  101. package/dist/page.d.ts +114 -0
  102. package/dist/phone.d.ts +50 -0
  103. package/dist/route-fetch.d.ts +79 -0
  104. package/dist/session/audio-effects.d.ts +31 -0
  105. package/dist/session/audio-setup.d.ts +57 -0
  106. package/dist/session/audio-state.d.ts +157 -0
  107. package/dist/session/browser-session.d.ts +30 -0
  108. package/dist/session/close.d.ts +26 -0
  109. package/dist/session/dial.d.ts +65 -0
  110. package/dist/session/handshake.d.ts +60 -0
  111. package/dist/session/index.d.ts +17 -0
  112. package/dist/session/index.js +2 -0
  113. package/dist/session/messages.d.ts +63 -0
  114. package/dist/session/mic.d.ts +64 -0
  115. package/dist/session/preconnect.d.ts +48 -0
  116. package/dist/session/reconnect.d.ts +25 -0
  117. package/dist/session/resume-store.d.ts +57 -0
  118. package/dist/session/state.d.ts +146 -0
  119. package/dist/session/ticket.d.ts +44 -0
  120. package/dist/session/types.d.ts +476 -0
  121. package/dist/session/url.d.ts +17 -0
  122. package/dist/session/user-turn.d.ts +55 -0
  123. package/dist/session-CE0Ipsb3.js +2129 -0
  124. package/dist/stored-value.d.ts +103 -0
  125. package/dist/tool-call-block-uXtMOUWN.js +204 -0
  126. package/dist/tool-config-context-Es4YUzV2.js +19 -0
  127. package/dist/types.d.ts +272 -34
  128. package/dist/types.js +35 -4
  129. package/dist/upload/files.d.ts +83 -0
  130. package/dist/upload/index.d.ts +15 -0
  131. package/dist/upload/pause.d.ts +31 -0
  132. package/dist/upload/recall.d.ts +67 -0
  133. package/dist/upload/report.d.ts +26 -0
  134. package/dist/upload/session.d.ts +99 -0
  135. package/dist/url-chips-oyy_Eiqh.js +239 -0
  136. package/dist/use-client-runs.d.ts +87 -0
  137. package/dist/use-conversation-log.d.ts +86 -0
  138. package/dist/use-conversation.d.ts +131 -0
  139. package/dist/use-copy.d.ts +74 -0
  140. package/dist/use-download-url.d.ts +84 -0
  141. package/dist/use-flash.d.ts +61 -0
  142. package/dist/use-inbox.d.ts +101 -0
  143. package/dist/use-push-to-talk.d.ts +105 -0
  144. package/dist/use-route-mutation.d.ts +113 -0
  145. package/dist/use-route.d.ts +82 -0
  146. package/dist/use-run-key.d.ts +133 -0
  147. package/dist/use-session-controls.d.ts +69 -0
  148. package/dist/use-session-id.d.ts +57 -0
  149. package/dist/use-tap-to-talk.d.ts +138 -0
  150. package/dist/use-user-transcript-uyHhzy4d.js +73 -0
  151. package/dist/use-user-transcript.d.ts +75 -0
  152. package/dist/use-workflow-form.d.ts +285 -0
  153. package/dist/use-workflow-progress.d.ts +137 -0
  154. package/dist/use-workflow-run-DdhWmbx-.js +697 -0
  155. package/dist/use-workflow-run.d.ts +100 -0
  156. package/dist/use-workflow-runs.d.ts +71 -0
  157. package/dist/use-workflow-stream.d.ts +154 -0
  158. package/dist/use-workflows.d.ts +77 -0
  159. package/dist/workflow-client.d.ts +136 -0
  160. package/dist/workflow-def-types.d.ts +31 -0
  161. package/dist/workflow-events.d.ts +39 -0
  162. package/dist/workflow-field-kind.d.ts +95 -0
  163. package/dist/workflow-status-labels.d.ts +35 -0
  164. package/dist/worklets/_module-url.d.ts +10 -0
  165. package/dist/worklets/_playback-bench-harness.d.ts +181 -0
  166. package/dist/worklets/_playback-bench-host.d.ts +63 -0
  167. package/dist/worklets/_playback-bench-page.d.ts +65 -0
  168. package/dist/worklets/_tts-trace-harness.d.ts +142 -0
  169. package/dist/worklets/_worklet-test-utils.d.ts +27 -0
  170. package/dist/worklets/capture-processor.d.ts +4 -2
  171. package/dist/worklets/capture-processor.js +73 -33
  172. package/dist/worklets/playback-processor.d.ts +4 -2
  173. package/dist/worklets/playback-processor.js +258 -42
  174. package/package.json +58 -31
  175. package/styles.css +152 -30
  176. package/dist/_components/app.d.ts +0 -23
  177. package/dist/_components/app.js +0 -41
  178. package/dist/_components/button.d.ts +0 -50
  179. package/dist/_components/button.js +0 -46
  180. package/dist/_components/chat-view.d.ts +0 -29
  181. package/dist/_components/chat-view.js +0 -61
  182. package/dist/_components/controls.d.ts +0 -18
  183. package/dist/_components/controls.js +0 -37
  184. package/dist/_components/error-banner.d.ts +0 -21
  185. package/dist/_components/error-banner.js +0 -27
  186. package/dist/_components/message-bubble.d.ts +0 -23
  187. package/dist/_components/message-bubble.js +0 -35
  188. package/dist/_components/message-list.d.ts +0 -21
  189. package/dist/_components/message-list.js +0 -76
  190. package/dist/_components/sidebar-layout.d.ts +0 -21
  191. package/dist/_components/sidebar-layout.js +0 -36
  192. package/dist/_components/start-screen.d.ts +0 -26
  193. package/dist/_components/start-screen.js +0 -51
  194. package/dist/_components/state-indicator.d.ts +0 -29
  195. package/dist/_components/state-indicator.js +0 -37
  196. package/dist/_components/thinking-indicator.d.ts +0 -16
  197. package/dist/_components/thinking-indicator.js +0 -34
  198. package/dist/_components/tool-call-block.d.ts +0 -27
  199. package/dist/_components/tool-call-block.js +0 -118
  200. package/dist/_components/tool-icons.d.ts +0 -17
  201. package/dist/_components/tool-icons.js +0 -128
  202. package/dist/_components/transcript.d.ts +0 -25
  203. package/dist/_components/transcript.js +0 -35
  204. package/dist/audio.d.ts +0 -45
  205. package/dist/audio.js +0 -121
  206. package/dist/client-context.d.ts +0 -33
  207. package/dist/client-context.js +0 -15
  208. package/dist/client-handler.d.ts +0 -43
  209. package/dist/session-CWB7vmqz.js +0 -429
  210. package/dist/session.d.ts +0 -69
  211. package/dist/session.js +0 -2
  212. package/dist/signals.d.ts +0 -120
  213. package/dist/signals.js +0 -161
  214. package/dist/tsdown.config.d.ts +0 -2
  215. package/dist/types.test-d.d.ts +0 -7
@@ -0,0 +1,74 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Props for {@link BulletList}.
4
+ *
5
+ * @public
6
+ */
7
+ export type BulletListProps = {
8
+ /**
9
+ * The bullets, in the order they should read.
10
+ *
11
+ * TEXT rather than `ReactNode`, deliberately: every list this replaced was a
12
+ * string array straight off a run's output, and taking strings is what lets
13
+ * this component key them (see the component doc). A page that needs a link
14
+ * inside a bullet wants its own `<ul>`, not a prop here.
15
+ */
16
+ items: readonly string[];
17
+ /**
18
+ * Rendered as a heading above the list, inside a wrapping `<section>`.
19
+ *
20
+ * Omitted (or `null`/`false`, so `title={cond && "Risks"}` means what it
21
+ * looks like) renders the bare `<ul>` with no wrapper — which is what four of
22
+ * the five lists this replaced were.
23
+ */
24
+ title?: ReactNode | undefined;
25
+ /**
26
+ * `"sm"` adds `text-sm`, which two of the five copies carried and three did
27
+ * not. `"base"` is the default and adds nothing.
28
+ */
29
+ size?: "sm" | "base" | undefined;
30
+ /**
31
+ * ADDED to the list's own classes rather than replacing them. There is no
32
+ * `tailwind-merge` in this package, so a class that CONFLICTS with a base one
33
+ * is not reliably the winner — use this for additions, not overrides.
34
+ */
35
+ className?: string | undefined;
36
+ };
37
+ /**
38
+ * A disc-bulleted list of short strings — a run's key points, findings, risks.
39
+ *
40
+ * Five pages had written this, byte-identical apart from a `text-sm` suffix on
41
+ * two of them, and all five had the same two defects. Both are the reason this
42
+ * is a component rather than four lines a page repeats:
43
+ *
44
+ * - **All five keyed by the string itself, and these lists are MODEL OUTPUT.**
45
+ * Two identical bullets are entirely plausible — a summariser that repeats
46
+ * itself is a bad summary, not a bad program — and a repeated string is then
47
+ * a duplicate `key`: React warns, and the two `<li>`s contend for one slot in
48
+ * the reconciliation. What is keyed here instead is the content PLUS how many
49
+ * times that content has already appeared in this list, which is unique by
50
+ * construction and unchanged by a re-render that did not change the text.
51
+ * (Position alone would also be sound — these lists are replaced wholesale by
52
+ * each new output and never reordered — but it is what `noArrayIndexKey`
53
+ * exists to talk you out of, and a unique key is one `Map` away, so there is
54
+ * no reason to spend a lint suppression on it.)
55
+ * - **Three of the five rendered an empty `<ul>` under a heading.** Two had
56
+ * hand-rolled `if (items.length === 0) return null` and three had not, so the
57
+ * same absent field was "nothing" on two pages and a stray heading with a
58
+ * void under it on three. Emptiness renders NOTHING here, `title` included:
59
+ * a heading over no bullets is a claim the run did not make.
60
+ *
61
+ * @example
62
+ * ```tsx
63
+ * import { BulletList } from "@alexkroman1/aai-ui";
64
+ *
65
+ * function Findings({ risks }: { risks: string[] }) {
66
+ * return <BulletList title="Risks" items={risks} size="sm" />;
67
+ * }
68
+ * ```
69
+ *
70
+ * @param props - Bullet-list props.
71
+ *
72
+ * @public
73
+ */
74
+ export declare function BulletList({ items, title, size, className }: BulletListProps): ReactNode;
@@ -0,0 +1,58 @@
1
+ import type { ButtonHTMLAttributes, ReactNode } from "react";
2
+ /**
3
+ * Visual style of a {@link Button} (design-system "website refresh":
4
+ * rectangular, ALL-CAPS, tracked labels).
5
+ *
6
+ * - `"default"` — Primary filled button (indigo background).
7
+ * - `"secondary"` — Outlined primary (transparent background, primary border).
8
+ * - `"ghost"` — Raised neutral (surface background with hairline border).
9
+ *
10
+ * @public
11
+ */
12
+ export type ButtonVariant = "default" | "secondary" | "ghost";
13
+ /**
14
+ * Size preset for a {@link Button}.
15
+ *
16
+ * - `"default"` — Compact control (height 36 px).
17
+ * - `"lg"` — Primary CTA (height 44 px, generous padding).
18
+ *
19
+ * @public
20
+ */
21
+ export type ButtonSize = "default" | "lg";
22
+ /**
23
+ * A styled button with variant and size presets.
24
+ *
25
+ * Accepts all standard `<button>` HTML attributes in addition to the props
26
+ * listed below.
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * import { Button } from "@alexkroman1/aai-ui";
31
+ *
32
+ * function Actions({ onStop }: { onStop: () => void }) {
33
+ * return (
34
+ * <>
35
+ * <Button variant="secondary" onClick={onStop}>Stop</Button>
36
+ * <Button size="lg" className="w-full">Start Conversation</Button>
37
+ * </>
38
+ * );
39
+ * }
40
+ * ```
41
+ *
42
+ * @param props - Button props: `variant` (visual style — see
43
+ * {@link ButtonVariant}, defaults to `"default"`), `size` (see
44
+ * {@link ButtonSize}, defaults to `"default"`), `className` (appended to the
45
+ * button's own classes), `children` (the label), and any `<button>` attribute.
46
+ *
47
+ * @public
48
+ */
49
+ export declare function Button({ variant, size, className, children, style, ...rest }: {
50
+ /** Visual style. Defaults to `"default"`. */
51
+ variant?: ButtonVariant;
52
+ /** Size preset. Defaults to `"default"`. */
53
+ size?: ButtonSize;
54
+ /** Additional CSS class names, appended to the button's own. */
55
+ className?: string;
56
+ /** Button label / content. */
57
+ children?: ReactNode;
58
+ } & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className">): import("react").JSX.Element;
@@ -0,0 +1,85 @@
1
+ import { useTheme } from "../context.js";
2
+ import { a as inkTint, i as focusRingStyle, n as FOCUS_RING, o as primaryTint } from "../_colors-CpZO-88A.js";
3
+ import clsx from "clsx";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/components/button.tsx
6
+ /** @jsxImportSource react */
7
+ /** One variant's rest and hover colors, derived from the theme. */
8
+ function variantColors(variant, theme) {
9
+ switch (variant) {
10
+ case "default": return {
11
+ bg: theme.primary,
12
+ fg: theme.surface,
13
+ border: "transparent",
14
+ hoverBg: inkTint(theme.text, theme.primary, 14),
15
+ hoverFg: theme.surface,
16
+ hoverBorder: "transparent"
17
+ };
18
+ case "secondary": return {
19
+ bg: "transparent",
20
+ fg: theme.primary,
21
+ border: theme.primary,
22
+ hoverBg: primaryTint(theme.primary, theme.surface, 8),
23
+ hoverFg: theme.primary,
24
+ hoverBorder: theme.primary
25
+ };
26
+ default: return {
27
+ bg: theme.surface,
28
+ fg: theme.text,
29
+ border: theme.border,
30
+ hoverBg: inkTint(theme.text, theme.surface, 5),
31
+ hoverFg: theme.text,
32
+ hoverBorder: theme.border
33
+ };
34
+ }
35
+ }
36
+ /**
37
+ * A styled button with variant and size presets.
38
+ *
39
+ * Accepts all standard `<button>` HTML attributes in addition to the props
40
+ * listed below.
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * import { Button } from "@alexkroman1/aai-ui";
45
+ *
46
+ * function Actions({ onStop }: { onStop: () => void }) {
47
+ * return (
48
+ * <>
49
+ * <Button variant="secondary" onClick={onStop}>Stop</Button>
50
+ * <Button size="lg" className="w-full">Start Conversation</Button>
51
+ * </>
52
+ * );
53
+ * }
54
+ * ```
55
+ *
56
+ * @param props - Button props: `variant` (visual style — see
57
+ * {@link ButtonVariant}, defaults to `"default"`), `size` (see
58
+ * {@link ButtonSize}, defaults to `"default"`), `className` (appended to the
59
+ * button's own classes), `children` (the label), and any `<button>` attribute.
60
+ *
61
+ * @public
62
+ */
63
+ function Button({ variant = "default", size = "default", className, children, style, ...rest }) {
64
+ const theme = useTheme();
65
+ const colors = variantColors(variant, theme);
66
+ const vars = {
67
+ "--aai-btn-bg": colors.bg,
68
+ "--aai-btn-fg": colors.fg,
69
+ "--aai-btn-bd": colors.border,
70
+ "--aai-btn-bg-hover": colors.hoverBg,
71
+ "--aai-btn-fg-hover": colors.hoverFg,
72
+ "--aai-btn-bd-hover": colors.hoverBorder,
73
+ ...focusRingStyle(theme.primary),
74
+ ...style
75
+ };
76
+ return /* @__PURE__ */ jsx("button", {
77
+ type: "button",
78
+ style: vars,
79
+ className: clsx("inline-flex items-center justify-center appearance-none m-0 w-fit whitespace-nowrap", size === "lg" ? "h-11 px-7 text-xs" : "h-9 px-5 text-[11px]", "rounded-aai font-aai font-medium tracking-[1.4px] uppercase leading-none", "cursor-pointer border transition-colors duration-150", "bg-(--aai-btn-bg) text-(--aai-btn-fg) border-(--aai-btn-bd)", "enabled:hover:bg-(--aai-btn-bg-hover) enabled:hover:text-(--aai-btn-fg-hover)", "enabled:hover:border-(--aai-btn-bd-hover)", FOCUS_RING, "disabled:cursor-not-allowed disabled:opacity-50", className),
80
+ ...rest,
81
+ children
82
+ });
83
+ }
84
+ //#endregion
85
+ export { Button };
@@ -0,0 +1,35 @@
1
+ /** @jsxImportSource react */
2
+ import type { ReactNode } from "react";
3
+ /**
4
+ * The main chat interface for a voice agent session — the design-system
5
+ * "voice agent console": a 760px column on the cream page with a header
6
+ * (logo + live-status eyebrow), the conversation on a raised white card,
7
+ * and the session controls beneath it.
8
+ *
9
+ * Must be rendered inside a `SessionProvider`.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * import { ChatView, StartScreen } from "@alexkroman1/aai-ui";
14
+ *
15
+ * function App() {
16
+ * return (
17
+ * <StartScreen icon="🍕" title="Pizza Palace">
18
+ * <ChatView />
19
+ * </StartScreen>
20
+ * );
21
+ * }
22
+ * ```
23
+ *
24
+ * @param props - Chat surface props.
25
+ *
26
+ * @public
27
+ */
28
+ export declare function ChatView({ icon, title, className, }: {
29
+ /** Element rendered in place of the logo in the header. */
30
+ icon?: ReactNode | undefined;
31
+ /** Title string for the header. Defaults to the agent's declared name. */
32
+ title?: string | undefined;
33
+ /** Additional CSS class names for the root element, appended to its own. */
34
+ className?: string | undefined;
35
+ }): ReactNode;
@@ -0,0 +1,3 @@
1
+ import { t as ChatView } from "../chat-view-BCbI7gD4.js";
2
+ import "../context.js";
3
+ export { ChatView };
@@ -0,0 +1,85 @@
1
+ import type { ReactNode } from "react";
2
+ import type { AgentState } from "../types.ts";
3
+ /**
4
+ * Props of {@link ConsoleShell}.
5
+ *
6
+ * @public
7
+ */
8
+ export type ConsoleShellProps = {
9
+ /** Element rendered in place of the logo in the header. */
10
+ icon?: ReactNode | undefined;
11
+ /** Title string for the header. */
12
+ title?: string | undefined;
13
+ /** Live status shown in the header eyebrow. */
14
+ state: AgentState;
15
+ /** Whether the status dot pulses. */
16
+ pulsing: boolean;
17
+ /** Card content — normally a {@link MessageList}. */
18
+ children: ReactNode;
19
+ /** Row rendered beneath the card (controls). */
20
+ footer: ReactNode;
21
+ /** Additional CSS class names for the root element, appended to its own. */
22
+ className?: string | undefined;
23
+ };
24
+ /**
25
+ * The design-system "console" chrome: a 760px column on the themed page with a
26
+ * header (icon + live-status eyebrow), an announced error banner, the main
27
+ * content on a raised card, and a footer row beneath it.
28
+ *
29
+ * {@link ChatView} is this shell with `<MessageList>` inside it and
30
+ * `<Controls>` under it, and until now that was the only way to get it — the
31
+ * shell itself was internal, so a client wanting its own conversation markup
32
+ * had to rebuild the chrome as well. Each one that did re-derived the error
33
+ * banner WITHOUT `role="alert"`.
34
+ *
35
+ * **The banner is {@link SessionErrorBanner} now, composed here rather than
36
+ * spelled out.** It was four lines of this file, and this file is a whole
37
+ * FRAME — a centred `max-w-190` column — so the full-bleed chromes that needed
38
+ * the announced banner could not take it without taking a layout that would
39
+ * replace the design they exist to demonstrate. Composing means there is one
40
+ * banner, and it means this component no longer takes an `error` prop: the
41
+ * banner reads the session itself, which is one fewer thing a caller can wire
42
+ * up wrong.
43
+ *
44
+ * Reach for it when the conversation is yours and the frame is not. Reach for
45
+ * `<ChatView>` when both are ours. Reach for `<SessionErrorBanner>` alone when
46
+ * neither is.
47
+ *
48
+ * Must be rendered inside the providers `mountClient()` installs.
49
+ *
50
+ * @example A custom conversation in the stock chrome
51
+ * ```tsx
52
+ * import {
53
+ * ConsoleShell,
54
+ * Controls,
55
+ * useConversation,
56
+ * useSessionStatus,
57
+ * } from "@alexkroman1/aai-ui";
58
+ *
59
+ * function Console() {
60
+ * const state = useSessionStatus();
61
+ * const { items } = useConversation();
62
+ * return (
63
+ * <ConsoleShell
64
+ * title="Dispatch"
65
+ * state={state}
66
+ * pulsing={state === "listening"}
67
+ * footer={<Controls />}
68
+ * >
69
+ * <ul>
70
+ * {items.map((item) => (
71
+ * <li key={item.kind === "message" ? item.message.id : item.toolCall.callId}>
72
+ * {item.kind === "message" ? item.message.content : item.toolCall.name}
73
+ * </li>
74
+ * ))}
75
+ * </ul>
76
+ * </ConsoleShell>
77
+ * );
78
+ * }
79
+ * ```
80
+ *
81
+ * @param props - See {@link ConsoleShellProps}.
82
+ *
83
+ * @public
84
+ */
85
+ export declare function ConsoleShell({ icon, title, state, pulsing, children, footer, className, }: ConsoleShellProps): ReactNode;
@@ -0,0 +1,33 @@
1
+ import { type FunctionComponent, type MemoExoticComponent } from "react";
2
+ /**
3
+ * Props of {@link Controls}.
4
+ *
5
+ * @public
6
+ */
7
+ export type ControlsProps = {
8
+ /**
9
+ * Additional CSS class names, appended to the container's own layout
10
+ * classes rather than replacing them.
11
+ */
12
+ className?: string;
13
+ };
14
+ /**
15
+ * Session control buttons: **Stop / Resume** and **New Conversation**.
16
+ *
17
+ * Reads session state from {@link useSession}. Must be rendered inside a
18
+ * `SessionProvider`.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * import { Controls } from "@alexkroman1/aai-ui";
23
+ *
24
+ * function Footer() {
25
+ * return <Controls className="justify-end" />;
26
+ * }
27
+ * ```
28
+ *
29
+ * @param props - Container props.
30
+ *
31
+ * @public
32
+ */
33
+ export declare const Controls: MemoExoticComponent<FunctionComponent<ControlsProps>>;
@@ -0,0 +1,49 @@
1
+ import { useSessionCore, useSessionSelector } from "../context.js";
2
+ import { Button } from "./button.js";
3
+ import { n as SessionUrlChips } from "../url-chips-oyy_Eiqh.js";
4
+ import { memo } from "react";
5
+ import clsx from "clsx";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/components/controls.tsx
8
+ /** @jsxImportSource react */
9
+ /**
10
+ * Session control buttons: **Stop / Resume** and **New Conversation**.
11
+ *
12
+ * Reads session state from {@link useSession}. Must be rendered inside a
13
+ * `SessionProvider`.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * import { Controls } from "@alexkroman1/aai-ui";
18
+ *
19
+ * function Footer() {
20
+ * return <Controls className="justify-end" />;
21
+ * }
22
+ * ```
23
+ *
24
+ * @param props - Container props.
25
+ *
26
+ * @public
27
+ */
28
+ const Controls = memo(function Controls({ className }) {
29
+ const running = useSessionSelector((s) => s.running);
30
+ const { toggle, restart } = useSessionCore();
31
+ return /* @__PURE__ */ jsxs("div", {
32
+ className: clsx("flex flex-wrap items-center gap-3 shrink-0", className),
33
+ children: [
34
+ /* @__PURE__ */ jsx(Button, {
35
+ variant: "secondary",
36
+ onClick: toggle,
37
+ children: running ? "Stop" : "Resume"
38
+ }),
39
+ /* @__PURE__ */ jsx(Button, {
40
+ variant: "ghost",
41
+ onClick: restart,
42
+ children: "New Conversation"
43
+ }),
44
+ /* @__PURE__ */ jsx(SessionUrlChips, { className: "basis-full sm:basis-auto sm:ml-auto sm:max-w-[60%]" })
45
+ ]
46
+ });
47
+ });
48
+ //#endregion
49
+ export { Controls };
@@ -0,0 +1,130 @@
1
+ /** @jsxImportSource react */
2
+ import type { CSSProperties, ReactNode } from "react";
3
+ import type { ConversationLogEntry } from "../conversation-log.ts";
4
+ import type { ChatMessage, ToolCallInfo } from "../types.ts";
5
+ import type { UseUserTranscriptResult } from "../use-user-transcript.ts";
6
+ /**
7
+ * Props of {@link ConversationView}.
8
+ *
9
+ * @public
10
+ */
11
+ export type ConversationViewProps = {
12
+ /** One finalized message, in this chrome's own markup. */
13
+ renderMessage: (message: ChatMessage) => ReactNode;
14
+ /**
15
+ * One tool invocation. Absent, a compact {@link ToolCallRow} naming the tool,
16
+ * shimmering while it is pending.
17
+ */
18
+ renderTool?: ((toolCall: ToolCallInfo) => ReactNode) | undefined;
19
+ /**
20
+ * The agent's reply as it arrives. Absent, `renderMessage` is called with a
21
+ * synthetic assistant message carrying the text so far (its `id` is `-1`,
22
+ * which no real message has) — every chrome so far rendered the two the same
23
+ * way, and this keeps them from drifting.
24
+ */
25
+ renderStreaming?: ((text: string) => ReactNode) | undefined;
26
+ /**
27
+ * The caller's in-progress turn. Rendered only while `transcript.speaking`,
28
+ * which is the `null`-vs-`""` distinction {@link useUserTranscript} makes
29
+ * (`""` is speech detected with no words yet — render on it, and read
30
+ * `transcript.text` for the placeholder). Absent, a muted italic line.
31
+ */
32
+ renderTranscript?: ((transcript: UseUserTranscriptResult) => ReactNode) | undefined;
33
+ /**
34
+ * Where the transcript row goes. `"inline"` (the default) is the last row
35
+ * inside the scroll region, as `MessageList` places it; `"below"` renders it
36
+ * after the scroll region as a sibling — the strip a two-pane board pins to
37
+ * the bottom of its conversation column, outside the scroll.
38
+ */
39
+ transcriptPosition?: "inline" | "below" | undefined;
40
+ /**
41
+ * A persisted transcript to render IN PLACE of the live session's items —
42
+ * `useConversationLog().entries`, whose newest session entry already is the
43
+ * live conversation. Session entries render through `renderMessage` /
44
+ * `renderTool`, each after `renderSessionHeader`; a `spoken` entry is
45
+ * `renderMessage` over an assistant message (id `-2`); a `note` is
46
+ * `renderNote`. The streaming reply, the transcript and the thinking row are
47
+ * rendered after it as usual.
48
+ */
49
+ log?: readonly ConversationLogEntry[] | undefined;
50
+ /** A log `note`. Absent, a small centred muted line. */
51
+ renderNote?: ((entry: Extract<ConversationLogEntry, {
52
+ kind: "note";
53
+ }>) => ReactNode) | undefined;
54
+ /**
55
+ * What goes above each log `session` entry — a timestamp, a "continue"
56
+ * button. Absent, nothing.
57
+ */
58
+ renderSessionHeader?: ((entry: Extract<ConversationLogEntry, {
59
+ kind: "session";
60
+ }>) => ReactNode) | undefined;
61
+ /** Rendered inside the scroll region while there is nothing to show at all. */
62
+ empty?: ReactNode | undefined;
63
+ /**
64
+ * The `aria-label` of the thinking row. Default `"Thinking"`. Say who: the
65
+ * dots are the only sign the agent is working, and to a screen reader they
66
+ * are punctuation.
67
+ */
68
+ thinkingLabel?: string | undefined;
69
+ /** What the thinking row shows. Default: three pulsing dots. */
70
+ thinkingIndicator?: ReactNode | undefined;
71
+ /** CSS class names for the thinking row itself (the `role="status"` element). */
72
+ thinkingClassName?: string | undefined;
73
+ /**
74
+ * Classes for the {@link AutoScroll} container. It must end up with a
75
+ * bounded height (`flex-1 min-h-0`, `h-full`) or nothing pins.
76
+ */
77
+ className?: string | undefined;
78
+ /** Classes for the scroll region's content element — padding, gap, direction. */
79
+ contentClassName?: string | undefined;
80
+ /** Classes for the scrolling element itself. See {@link AutoScroll}. */
81
+ scrollClassName?: string | undefined;
82
+ /** Inline styles for the scroll container. */
83
+ style?: CSSProperties | undefined;
84
+ };
85
+ /**
86
+ * The conversation's skeleton over {@link useConversation}, with every row a
87
+ * render slot: a pinned scroll region holding the empty state, the interleaved
88
+ * messages and tool calls, the streaming reply and the announced thinking row,
89
+ * plus the live transcript — inside the scroll or pinned beneath it.
90
+ *
91
+ * `useConversation()` already made the DATA one thing: the interleave, the
92
+ * streaming utterance, the `null`-vs-`""` transcript distinction and the
93
+ * thinking-suppression rule. What three custom chromes then each wrote around
94
+ * it was the same fifty lines of STRUCTURE: an `AutoScroll` with a bounded
95
+ * height, an empty-state guard on `items.length === 0 && streaming === null`,
96
+ * the map with its keys, the streaming row, the thinking row with its
97
+ * `role="status"` and `aria-label` (and the same comment about screen readers
98
+ * hearing punctuation), the transcript guarded on `speaking`. The bubbles are
99
+ * the part each template exists to show, so those are slots; the order and the
100
+ * accessibility contract are this component's.
101
+ *
102
+ * {@link MessageList} is this with the stock bubbles filled in.
103
+ *
104
+ * Must be rendered inside the providers `mountClient()` installs.
105
+ *
106
+ * @example A board's radio log: its own bubbles, the stock tool row, the transcript pinned below
107
+ * ```tsx
108
+ * import { ConversationView } from "@alexkroman1/aai-ui";
109
+ *
110
+ * function RadioLog() {
111
+ * return (
112
+ * <ConversationView
113
+ * contentClassName="p-4 flex flex-col gap-2"
114
+ * empty={<p className="text-center opacity-60">Standing by.</p>}
115
+ * renderMessage={({ role, content }) => (
116
+ * <div className={role === "assistant" ? "self-start" : "self-end"}>{content}</div>
117
+ * )}
118
+ * renderTranscript={({ text }) => <div className="px-4 py-2 italic">{text}</div>}
119
+ * transcriptPosition="below"
120
+ * thinkingLabel="Dispatch is thinking"
121
+ * />
122
+ * );
123
+ * }
124
+ * ```
125
+ *
126
+ * @param props - See {@link ConversationViewProps}.
127
+ *
128
+ * @public
129
+ */
130
+ export declare function ConversationView({ renderMessage, renderTool, renderStreaming, renderTranscript, transcriptPosition, log, renderNote, renderSessionHeader, empty, thinkingLabel, thinkingIndicator, thinkingClassName, className, contentClassName, scrollClassName, style, }: ConversationViewProps): ReactNode;
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Eyebrow label — the design system's small outlined pill with ALL-CAPS,
4
+ * tracked text ("VOICE AGENT", "LISTENING", …). Used as a section label on
5
+ * the start screen and as the live status chip in the chat header.
6
+ *
7
+ * @internal
8
+ */
9
+ export declare function Eyebrow({ children, className, style, ...rest }: {
10
+ children: ReactNode;
11
+ className?: string | undefined;
12
+ } & Omit<React.HTMLAttributes<HTMLSpanElement>, "className">): ReactNode;
@@ -0,0 +1,81 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Props for {@link Facts}.
4
+ *
5
+ * @public
6
+ */
7
+ export type FactsProps = {
8
+ /**
9
+ * The facts, in reading order. Anything `false`, `null`, `undefined` or the
10
+ * empty string is DROPPED, so a page writes `cond && \`${n} skipped\`` inline
11
+ * instead of splicing a separator into a conditional string.
12
+ *
13
+ * `0` is NOT dropped — it is a fact ("0 words"), and treating it as absent is
14
+ * the bug a plain truthiness filter would ship.
15
+ *
16
+ * They are TEXT rather than `ReactNode`: every one of the nine lines this
17
+ * replaced was a string, and taking strings is what lets this JOIN them (see
18
+ * the component doc) instead of interleaving keyed separator elements.
19
+ */
20
+ items: readonly (string | number | false | null | undefined)[];
21
+ /**
22
+ * Which of the two muted typographies the pages use. `"sm"` is
23
+ * `text-sm opacity-70`, `"xs"` is `text-xs opacity-60` — the size and the
24
+ * muting move together, because that is the pair every site had.
25
+ */
26
+ size?: "sm" | "xs" | undefined;
27
+ /**
28
+ * The element to render. `"p"` by default; `"span"` for a line that sits
29
+ * inside phrasing content, where a `<p>` is invalid nesting the browser will
30
+ * reparent out from under React.
31
+ */
32
+ as?: "p" | "span" | undefined;
33
+ /**
34
+ * ADDED to the base classes rather than replacing them — `tabular-nums`,
35
+ * `uppercase tracking-[1.2px]`. There is no `tailwind-merge` in this package,
36
+ * so a class that CONFLICTS with a base one is not reliably the winner.
37
+ */
38
+ className?: string | undefined;
39
+ };
40
+ /**
41
+ * A muted line of run facts, joined by `·` — "6 segments · 12:04 of audio ·
42
+ * 1,840 words".
43
+ *
44
+ * Nine pages had written this by hand under four different typographies for
45
+ * one role, two of them (`call-audit-workflow` and `spoken-summary-workflow`) byte-identical down
46
+ * to the payload. Three things it takes off the caller:
47
+ *
48
+ * - **The separator cannot be forgotten, and neither can the space around it.**
49
+ * Four of the nine carried a literal `{" "}` at the end of a line, because
50
+ * Prettier's wrap ate the space that made `· ` read as a separator rather
51
+ * than as punctuation glued to the next word. A line that is correct only
52
+ * because somebody remembered an invisible JSX expression is exactly the
53
+ * thing a component should own.
54
+ * - **A fact worth omitting is omitted, and by the caller's own condition.**
55
+ * The hand-written shape for a conditional fact was to splice the separator
56
+ * into the string — `{x ? \` · budget exhausted\` : ""}` — which puts the
57
+ * punctuation in two places and gets the leading separator wrong the moment
58
+ * the fact before it also disappears. Passing the condition and letting this
59
+ * drop it keeps the separator in one place.
60
+ * - **A line with nothing left to say renders NOTHING.** With every fact
61
+ * conditional, the alternative is a muted empty row, or a bare `·`.
62
+ *
63
+ * The facts are JOINED into one string rather than interleaved as elements, and
64
+ * that is why the prop is text: joined, there is no per-fact `key` to invent —
65
+ * the same reasoning `WorkflowProgress` gives for its log lines. A line that
66
+ * genuinely needs an element in it (a link) wants its own markup.
67
+ *
68
+ * @example
69
+ * ```tsx
70
+ * import { Facts } from "@alexkroman1/aai-ui";
71
+ *
72
+ * function RunFacts({ words, cut }: { words: number; cut: number }) {
73
+ * return <Facts size="xs" items={[`${words} words`, cut > 0 && `${cut} blind cuts`]} />;
74
+ * }
75
+ * ```
76
+ *
77
+ * @param props - Facts-line props.
78
+ *
79
+ * @public
80
+ */
81
+ export declare function Facts({ items, size, as, className }: FactsProps): ReactNode;