@alexkroman1/aai-ui 0.12.3 → 0.14.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 (203) hide show
  1. package/README.md +253 -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 +34 -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 +29 -21
  40. package/dist/components/button.js +62 -23
  41. package/dist/components/chat-view.d.ts +24 -18
  42. package/dist/components/chat-view.js +2 -60
  43. package/dist/components/console-shell.d.ts +85 -0
  44. package/dist/components/controls.d.ts +21 -6
  45. package/dist/components/controls.js +31 -19
  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 +34 -7
  54. package/dist/components/message-list.js +2 -75
  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 +31 -10
  59. package/dist/components/sidebar-layout.js +32 -12
  60. package/dist/components/start-screen.d.ts +17 -6
  61. package/dist/components/start-screen.js +34 -14
  62. package/dist/components/tool-call-block.d.ts +15 -14
  63. package/dist/components/tool-call-block.js +2 -117
  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-mpgipo2Q.js +1 -0
  78. package/dist/default-client/assets/capture-processor-D0q7Qrdd.js +90 -0
  79. package/dist/default-client/assets/index-8ihb1Urm.css +2 -0
  80. package/dist/default-client/assets/index-DPfmSFmc.js +126 -0
  81. package/dist/default-client/assets/playback-processor-CjDbc9iH.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-entry.d.ts +6 -0
  85. package/dist/default-client.d.ts +19 -0
  86. package/dist/define-client.d.ts +169 -26
  87. package/dist/define-client.js +209 -55
  88. package/dist/eyebrow-UfmSz9yy.js +27 -0
  89. package/dist/hooks-DN4gHYsj.js +182 -0
  90. package/dist/hooks.d.ts +172 -0
  91. package/dist/hooks.js +3 -0
  92. package/dist/hooks.test-d.d.ts +14 -0
  93. package/dist/inbox-protocol.d.ts +128 -0
  94. package/dist/inbox.d.ts +132 -0
  95. package/dist/index.d.ts +126 -29
  96. package/dist/index.js +5500 -15
  97. package/dist/internal.d.ts +43 -0
  98. package/dist/internal.js +8 -0
  99. package/dist/linked-client.d.ts +70 -0
  100. package/dist/message-list-DHZcLhRA.js +682 -0
  101. package/dist/notice-player.d.ts +70 -0
  102. package/dist/page.d.ts +114 -0
  103. package/dist/phone.d.ts +50 -0
  104. package/dist/route-fetch.d.ts +79 -0
  105. package/dist/session/audio-effects.d.ts +37 -0
  106. package/dist/session/audio-setup.d.ts +57 -0
  107. package/dist/session/audio-state.d.ts +157 -0
  108. package/dist/session/browser-session.d.ts +39 -0
  109. package/dist/session/close.d.ts +26 -0
  110. package/dist/session/dial.d.ts +65 -0
  111. package/dist/session/handshake.d.ts +60 -0
  112. package/dist/session/index.d.ts +17 -0
  113. package/dist/session/index.js +2 -0
  114. package/dist/session/messages.d.ts +63 -0
  115. package/dist/session/mic.d.ts +64 -0
  116. package/dist/session/preconnect.d.ts +48 -0
  117. package/dist/session/reconnect.d.ts +25 -0
  118. package/dist/session/resume-store.d.ts +57 -0
  119. package/dist/session/state.d.ts +146 -0
  120. package/dist/session/ticket.d.ts +44 -0
  121. package/dist/session/types.d.ts +476 -0
  122. package/dist/session/url.d.ts +17 -0
  123. package/dist/session/user-turn.d.ts +55 -0
  124. package/dist/session-D9jM5-TF.js +2140 -0
  125. package/dist/stored-value.d.ts +103 -0
  126. package/dist/tool-call-block-uXtMOUWN.js +204 -0
  127. package/dist/tool-config-context-Es4YUzV2.js +19 -0
  128. package/dist/types.d.ts +272 -34
  129. package/dist/types.js +35 -4
  130. package/dist/upload/files.d.ts +83 -0
  131. package/dist/upload/index.d.ts +15 -0
  132. package/dist/upload/pause.d.ts +31 -0
  133. package/dist/upload/recall.d.ts +67 -0
  134. package/dist/upload/report.d.ts +26 -0
  135. package/dist/upload/session.d.ts +99 -0
  136. package/dist/url-chips-oyy_Eiqh.js +239 -0
  137. package/dist/use-client-runs.d.ts +87 -0
  138. package/dist/use-conversation-log.d.ts +86 -0
  139. package/dist/use-conversation.d.ts +131 -0
  140. package/dist/use-copy.d.ts +74 -0
  141. package/dist/use-download-url.d.ts +84 -0
  142. package/dist/use-flash.d.ts +61 -0
  143. package/dist/use-inbox.d.ts +101 -0
  144. package/dist/use-push-to-talk.d.ts +105 -0
  145. package/dist/use-route-mutation.d.ts +113 -0
  146. package/dist/use-route.d.ts +82 -0
  147. package/dist/use-run-key.d.ts +133 -0
  148. package/dist/use-session-controls.d.ts +69 -0
  149. package/dist/use-session-id.d.ts +57 -0
  150. package/dist/use-tap-to-talk.d.ts +138 -0
  151. package/dist/use-user-transcript-uyHhzy4d.js +73 -0
  152. package/dist/use-user-transcript.d.ts +75 -0
  153. package/dist/use-workflow-form.d.ts +285 -0
  154. package/dist/use-workflow-progress.d.ts +137 -0
  155. package/dist/use-workflow-run-DdhWmbx-.js +697 -0
  156. package/dist/use-workflow-run.d.ts +100 -0
  157. package/dist/use-workflow-runs.d.ts +71 -0
  158. package/dist/use-workflow-stream.d.ts +154 -0
  159. package/dist/use-workflows.d.ts +77 -0
  160. package/dist/workflow-client.d.ts +136 -0
  161. package/dist/workflow-def-types.d.ts +31 -0
  162. package/dist/workflow-events.d.ts +39 -0
  163. package/dist/workflow-field-kind.d.ts +95 -0
  164. package/dist/workflow-status-labels.d.ts +35 -0
  165. package/dist/worklets/_module-url.d.ts +10 -0
  166. package/dist/worklets/_playback-bench-harness.d.ts +181 -0
  167. package/dist/worklets/_playback-bench-host.d.ts +63 -0
  168. package/dist/worklets/_playback-bench-page.d.ts +65 -0
  169. package/dist/worklets/_tts-trace-harness.d.ts +142 -0
  170. package/dist/worklets/_worklet-test-utils.d.ts +27 -0
  171. package/dist/worklets/capture-processor.d.ts +4 -2
  172. package/dist/worklets/capture-processor.js +73 -33
  173. package/dist/worklets/playback-processor.d.ts +4 -2
  174. package/dist/worklets/playback-processor.js +258 -42
  175. package/package.json +59 -32
  176. package/styles.css +152 -30
  177. package/dist/_jsdom-setup.d.ts +0 -0
  178. package/dist/audio.d.ts +0 -45
  179. package/dist/audio.js +0 -121
  180. package/dist/client-context.d.ts +0 -33
  181. package/dist/client-context.js +0 -15
  182. package/dist/client-handler.d.ts +0 -43
  183. package/dist/components/app.d.ts +0 -23
  184. package/dist/components/app.js +0 -41
  185. package/dist/components/error-banner.d.ts +0 -21
  186. package/dist/components/error-banner.js +0 -27
  187. package/dist/components/message-bubble.d.ts +0 -23
  188. package/dist/components/message-bubble.js +0 -35
  189. package/dist/components/state-indicator.d.ts +0 -29
  190. package/dist/components/state-indicator.js +0 -37
  191. package/dist/components/thinking-indicator.d.ts +0 -16
  192. package/dist/components/thinking-indicator.js +0 -34
  193. package/dist/components/tool-icons.d.ts +0 -17
  194. package/dist/components/tool-icons.js +0 -128
  195. package/dist/components/transcript.d.ts +0 -25
  196. package/dist/components/transcript.js +0 -35
  197. package/dist/session-CWB7vmqz.js +0 -429
  198. package/dist/session.d.ts +0 -69
  199. package/dist/session.js +0 -2
  200. package/dist/signals.d.ts +0 -120
  201. package/dist/signals.js +0 -161
  202. package/dist/tsdown.config.d.ts +0 -2
  203. package/dist/types.test-d.d.ts +0 -7
package/styles.css CHANGED
@@ -1,30 +1,38 @@
1
1
  @import "tailwindcss";
2
+
2
3
  @source "./";
3
4
  @source "../dist/ui/";
4
5
 
6
+ /*
7
+ * AssemblyAI design system ("website refresh") tokens.
8
+ * - font-aai: Monument Grotesk when the host page loads it, warm system
9
+ * grotesque otherwise (the package ships no font binaries).
10
+ * - font-aai-serif: editorial serif for headings (Source Serif 4 stand-in,
11
+ * graceful Georgia-class fallbacks).
12
+ * - font-aai-mono: JetBrains Mono stand-in for code/tool rows.
13
+ * - radius-aai: the refresh's squared-off 4px control radius.
14
+ * - color-aai-*: the five `ClientTheme` fields, so a Tailwind class can see
15
+ * them. `ThemeProvider` writes `--aai-bg` … `--aai-primary` onto `:root`
16
+ * from `client({ theme })`; these map them into Tailwind's `--color-*`
17
+ * namespace, which is what makes `bg-aai-surface`, `text-aai-text`,
18
+ * `border-aai-border` and `text-aai-primary` real utilities. The fallbacks
19
+ * ARE the default theme, so the classes work on a page that mounts no
20
+ * provider at all (a static page, a Storybook frame) instead of collapsing
21
+ * to transparent — and they must be kept in step with `DEFAULT_THEME` in
22
+ * `context.ts`, which `theme-css-vars.test.ts` asserts.
23
+ */
5
24
  @theme {
6
- --color-aai-bg: #101010;
7
- --color-aai-surface: #151515;
8
- --color-aai-surface-faint: rgba(255, 255, 255, 0.031);
9
- --color-aai-surface-hover: rgba(255, 255, 255, 0.059);
10
- --color-aai-border: #282828;
11
- --color-aai-primary: #fab283;
12
- --color-aai-text: rgba(255, 255, 255, 0.936);
13
- --color-aai-text-secondary: rgba(255, 255, 255, 0.618);
14
- --color-aai-text-muted: rgba(255, 255, 255, 0.284);
15
- --color-aai-text-dim: rgba(255, 255, 255, 0.422);
16
- --color-aai-error: #e06c75;
17
- --color-aai-ring: #56b6c2;
18
- --color-aai-state-disconnected: rgba(255, 255, 255, 0.422);
19
- --color-aai-state-connecting: rgba(255, 255, 255, 0.422);
20
- --color-aai-state-ready: #7fd88f;
21
- --color-aai-state-listening: #56b6c2;
22
- --color-aai-state-thinking: #f5a742;
23
- --color-aai-state-speaking: #e06c75;
24
- --color-aai-state-error: #e06c75;
25
- --radius-aai: 6px;
26
- --font-aai: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
27
- --font-aai-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
25
+ --color-aai-bg: var(--aai-bg, #fbf8f2);
26
+ --color-aai-surface: var(--aai-surface, #ffffff);
27
+ --color-aai-text: var(--aai-text, #1b1a18);
28
+ --color-aai-border: var(--aai-border, #dcd7cc);
29
+ --color-aai-primary: var(--aai-primary, #3f2bc1);
30
+ --font-aai:
31
+ "Monument Grotesk", "ABC Monument Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif;
32
+ --font-aai-serif:
33
+ "Source Serif 4", "Source Serif Pro", Charter, "Iowan Old Style", Georgia, serif;
34
+ --font-aai-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
35
+ --radius-aai: 4px;
28
36
  }
29
37
 
30
38
  @layer base {
@@ -32,7 +40,18 @@
32
40
  body {
33
41
  margin: 0;
34
42
  padding: 0;
35
- background: var(--color-aai-bg);
43
+ }
44
+ }
45
+
46
+ @keyframes aai-pulse {
47
+ 0%,
48
+ 100% {
49
+ opacity: 1;
50
+ transform: scale(1);
51
+ }
52
+ 50% {
53
+ opacity: 0.45;
54
+ transform: scale(0.82);
36
55
  }
37
56
  }
38
57
 
@@ -59,15 +78,118 @@
59
78
  }
60
79
 
61
80
  .tool-shimmer {
62
- background: linear-gradient(
63
- 90deg,
64
- var(--color-aai-text) 25%,
65
- var(--color-aai-text-dim) 50%,
66
- var(--color-aai-text) 75%
67
- );
81
+ background: linear-gradient(90deg, currentColor 25%, transparent 50%, currentColor 75%);
68
82
  background-size: 200% 100%;
69
83
  -webkit-background-clip: text;
70
84
  background-clip: text;
71
85
  -webkit-text-fill-color: transparent;
72
- animation: aai-shimmer 2s ease-in-out infinite;
86
+ animation: aai-shimmer 2s infinite;
87
+ }
88
+
89
+ /*
90
+ * Reduced motion is honoured HERE, once, for everything this stylesheet reaches.
91
+ *
92
+ * Roughly nineteen INFINITE animations ship in an aai app and, until this block,
93
+ * not one of them asked: `prefers-reduced-motion` appeared zero times in the
94
+ * repository. `aai-pulse` on the console shell's live dot, `aai-bounce` on the
95
+ * thinking dots, `aai-shimmer` on every streaming tool row, Tailwind's
96
+ * `animate-pulse` on an indeterminate upload bar — all of them running for as
97
+ * long as the page is open. For a reader with a vestibular disorder that is not
98
+ * decoration, it is the reason they close the tab.
99
+ *
100
+ * **The universal selector is the leverage point, and it is the only thing that
101
+ * reaches the TEMPLATES.** Every template's `client.tsx` opens with
102
+ * `import "@alexkroman1/aai-ui/styles.css"`, and several then declare keyframes
103
+ * of their own in an inline `<style>` block: `dc-pulse`/`dc-slide-in`
104
+ * (emergency-dispatch-agent), `rt-pulse`/`rt-slide-in` (retail), `crisisPulse`
105
+ * (tabletop-rpg-agent), and `ic-flicker`/`ic-scanline`/`ic-pulse` (text-adventure-agent,
106
+ * which flickers the whole viewport's opacity and sweeps a scanline across the
107
+ * page — the worst thing in the repo for a motion-sensitive reader). Nothing in
108
+ * this package knows those names, and no per-component fix could: it would have
109
+ * to be written again in every template, by every author who copies one, and
110
+ * the author who forgets leaves no trace in a diff. A universal selector does
111
+ * not need to know the name of the animation it is stopping. That is also what
112
+ * makes this the right FILE rather than merely a convenient one — the published
113
+ * sheet is the single artifact every client already imports, so a template opts
114
+ * in by existing, and one written next year opts in before it is written.
115
+ *
116
+ * Four properties, because motion arrives four ways:
117
+ *
118
+ * - `animation-duration` and `animation-iteration-count` — the keyframe half.
119
+ * The count carries its own weight: cut the duration alone and an `infinite`
120
+ * animation is still infinite, merely very fast, which is worse than what it
121
+ * replaced.
122
+ * - `transition-duration` — the property-change half, which no search for
123
+ * `@keyframes` would ever turn up.
124
+ * - `scroll-behavior` — the CSS half of scrolling: a host page or template
125
+ * declaring `scroll-behavior: smooth`, and any `scrollIntoView()` /
126
+ * `scrollTo()` that left the behaviour to CSS. Note what it does NOT reach.
127
+ * `AutoScroll`'s `resize: "smooth"` default is a requestAnimationFrame SPRING
128
+ * inside `use-stick-to-bottom` (which reads no media query of its own, and
129
+ * sets `scroll-behavior: auto` inline while it writes `scrollTop` anyway), so
130
+ * silencing that one is a change in `components/auto-scroll.tsx` and is still
131
+ * owed. Recording the gap beats letting the next reader assume it is covered.
132
+ *
133
+ * `0.01ms` rather than `0s` on both durations is deliberate: a zero-duration
134
+ * animation or transition fires no `animationend`/`transitionend`, so anything
135
+ * awaiting one — ours or a consumer's — waits forever. Effectively instant, and
136
+ * still an event.
137
+ *
138
+ * `!important`, and no `@layer`, is what lets this outrank the three ways motion
139
+ * is actually declared here: a Tailwind utility (`animate-pulse`), a template's
140
+ * own `<style>` block, and the inline `style={{ animation: … }}` that
141
+ * `ConsoleShell` and `MessageList` write — an author `!important` beats a normal
142
+ * inline declaration, which is the only reason those last two are covered. A
143
+ * reader who asked their OS for less motion outranks all three.
144
+ *
145
+ * Biome's `noImportantStyles` warns on all four declarations and the warnings
146
+ * STAY. The rule's argument — that `!important` reverses the cascade — is the
147
+ * property being used on purpose here, this block existing precisely to outrank
148
+ * a declaration written closer to the element. It is not suppressed either: a
149
+ * lint suppression is a counted escape hatch (`pnpm check:hatches`), so
150
+ * silencing a warning that is really a design note would spend four of them, and
151
+ * `biome check .` exits 0 on warnings, so nothing is gated on it.
152
+ *
153
+ * `src/styles-motion.test.ts` asserts this block against the stylesheet SOURCE,
154
+ * a spec having no way to render CSS.
155
+ */
156
+ @media (prefers-reduced-motion: reduce) {
157
+ *,
158
+ *::before,
159
+ *::after {
160
+ animation-duration: 0.01ms !important;
161
+ animation-iteration-count: 1 !important;
162
+ transition-duration: 0.01ms !important;
163
+ scroll-behavior: auto !important;
164
+ }
165
+ }
166
+
167
+ /*
168
+ * `.aai-scroll` — the thin, quiet scrollbar every custom chrome had drawn.
169
+ *
170
+ * Four template clients each carried the same three `::-webkit-scrollbar`
171
+ * rules under their own class name, differing only in the thumb colour — which
172
+ * is this package's business to make a variable and not to choose. The thumb
173
+ * defaults to the theme's border token and the track to transparent; a chrome
174
+ * with its own scrollbar palette sets `--aai-scrollbar-thumb` and
175
+ * `--aai-scrollbar-track` on the element or an ancestor (in its own `<style>`
176
+ * block, or as an inline custom property) and keeps the six lines out of its
177
+ * file. `scrollbar-width`/`scrollbar-color` are the standard half and cover
178
+ * Firefox; the `::-webkit-` pseudo-elements are the half Chromium and WebKit
179
+ * still read.
180
+ */
181
+ .aai-scroll {
182
+ scrollbar-width: thin;
183
+ scrollbar-color: var(--aai-scrollbar-thumb, var(--aai-border, #dcd7cc))
184
+ var(--aai-scrollbar-track, transparent);
185
+ }
186
+ .aai-scroll::-webkit-scrollbar {
187
+ width: 6px;
188
+ }
189
+ .aai-scroll::-webkit-scrollbar-track {
190
+ background: var(--aai-scrollbar-track, transparent);
191
+ }
192
+ .aai-scroll::-webkit-scrollbar-thumb {
193
+ background: var(--aai-scrollbar-thumb, var(--aai-border, #dcd7cc));
194
+ border-radius: 3px;
73
195
  }
File without changes
package/dist/audio.d.ts DELETED
@@ -1,45 +0,0 @@
1
- /** Configuration for creating a {@link VoiceIO} instance. */
2
- export type VoiceIOOptions = {
3
- /** Sample rate in Hz expected by the STT engine (e.g. 16000). */
4
- sttSampleRate: number;
5
- /** Sample rate in Hz used by the TTS engine (e.g. 22050). */
6
- ttsSampleRate: number;
7
- /** Source URL or data URI for the capture AudioWorklet processor. */
8
- captureWorkletSrc: string;
9
- /** Source URL or data URI for the playback AudioWorklet processor. */
10
- playbackWorkletSrc: string;
11
- /** Callback invoked with buffered PCM16 microphone data to send to the server. */
12
- onMicData: (pcm16: ArrayBuffer) => void;
13
- /** Callback invoked with the current playback position in samples. */
14
- onPlaybackProgress?: (samplesPlayed: number) => void;
15
- };
16
- /**
17
- * Audio I/O interface for voice capture and playback.
18
- *
19
- * Manages microphone capture via an AudioWorklet, resampling to the STT
20
- * sample rate, and TTS audio playback through a second AudioWorklet. Implements
21
- * {@link AsyncDisposable} for resource cleanup.
22
- */
23
- export type VoiceIO = AsyncDisposable & {
24
- /** Enqueue a PCM16 audio buffer for playback through the TTS pipeline. */
25
- enqueue(pcm16Buffer: ArrayBuffer): void;
26
- /** Signal that all TTS audio for the current turn has been enqueued.
27
- * Resolves when the worklet has finished playing all buffered audio. */
28
- done(): Promise<void>;
29
- /** Immediately stop playback and discard any buffered TTS audio. */
30
- flush(): void;
31
- /** Release all audio resources (microphone, AudioContext, worklets). */
32
- close(): Promise<void>;
33
- };
34
- /**
35
- * Create a {@link VoiceIO} instance that captures microphone audio and
36
- * plays back TTS audio using the Web Audio API.
37
- *
38
- * The AudioContext runs at the TTS sample rate for playback fidelity.
39
- * Captured audio is resampled to the STT rate when the rates differ.
40
- *
41
- * @param opts - Voice I/O configuration options.
42
- * @returns A promise that resolves to a {@link VoiceIO} handle.
43
- * @throws If microphone access is denied or AudioWorklet registration fails.
44
- */
45
- export declare function createVoiceIO(opts: VoiceIOOptions): Promise<VoiceIO>;
package/dist/audio.js DELETED
@@ -1,121 +0,0 @@
1
- import { MIC_BUFFER_SECONDS } from "./types.js";
2
- //#region audio.ts
3
- /**
4
- * Create a {@link VoiceIO} instance that captures microphone audio and
5
- * plays back TTS audio using the Web Audio API.
6
- *
7
- * The AudioContext runs at the TTS sample rate for playback fidelity.
8
- * Captured audio is resampled to the STT rate when the rates differ.
9
- *
10
- * @param opts - Voice I/O configuration options.
11
- * @returns A promise that resolves to a {@link VoiceIO} handle.
12
- * @throws If microphone access is denied or AudioWorklet registration fails.
13
- */
14
- async function createVoiceIO(opts) {
15
- const { sttSampleRate, ttsSampleRate, captureWorkletSrc, playbackWorkletSrc, onMicData } = opts;
16
- const contextRate = ttsSampleRate;
17
- const ctx = new AudioContext({
18
- sampleRate: contextRate,
19
- latencyHint: "playback"
20
- });
21
- await ctx.resume();
22
- const stream = await navigator.mediaDevices.getUserMedia({ audio: {
23
- sampleRate: contextRate,
24
- echoCancellation: true,
25
- noiseSuppression: true,
26
- autoGainControl: true
27
- } });
28
- try {
29
- await Promise.all([ctx.audioWorklet.addModule(captureWorkletSrc), ctx.audioWorklet.addModule(playbackWorkletSrc)]);
30
- } catch (err) {
31
- for (const t of stream.getTracks()) t.stop();
32
- await ctx.close().catch((err) => {
33
- console.warn("AudioContext close failed:", err);
34
- });
35
- throw err;
36
- }
37
- const mic = ctx.createMediaStreamSource(stream);
38
- const capNode = new AudioWorkletNode(ctx, "capture-processor", {
39
- channelCount: 1,
40
- channelCountMode: "explicit",
41
- processorOptions: {
42
- contextRate,
43
- sttSampleRate
44
- }
45
- });
46
- mic.connect(capNode);
47
- const chunkSizeBytes = Math.floor(sttSampleRate * MIC_BUFFER_SECONDS) * 2;
48
- const capBufA = new Uint8Array(chunkSizeBytes * 2);
49
- const capBufB = new Uint8Array(chunkSizeBytes * 2);
50
- let capBuf = capBufA;
51
- let capOffset = 0;
52
- capNode.port.postMessage({ event: "start" });
53
- capNode.port.onmessage = (e) => {
54
- if (e.data.event !== "chunk") return;
55
- const chunk = new Uint8Array(e.data.buffer);
56
- capBuf.set(chunk, capOffset);
57
- capOffset += chunk.byteLength;
58
- if (capOffset >= chunkSizeBytes) {
59
- const sendBuf = capBuf;
60
- const filled = capOffset;
61
- capBuf = capBuf === capBufA ? capBufB : capBufA;
62
- capOffset = 0;
63
- onMicData(sendBuf.buffer.slice(0, filled));
64
- }
65
- };
66
- let playNode = null;
67
- let onPlaybackStop = null;
68
- const lifecycle = new AbortController();
69
- const { onPlaybackProgress } = opts;
70
- function ensurePlayNode() {
71
- if (playNode) return playNode;
72
- const node = new AudioWorkletNode(ctx, "playback-processor", { processorOptions: { sampleRate: contextRate } });
73
- node.connect(ctx.destination);
74
- node.port.onmessage = (e) => {
75
- if (e.data.event === "stop") {
76
- node.disconnect();
77
- if (playNode === node) playNode = null;
78
- onPlaybackStop?.();
79
- onPlaybackStop = null;
80
- } else if (e.data.event === "progress") onPlaybackProgress?.(e.data.readPos);
81
- };
82
- playNode = node;
83
- return node;
84
- }
85
- const io = {
86
- enqueue(pcm16Buffer) {
87
- if (lifecycle.signal.aborted) return;
88
- if (pcm16Buffer.byteLength === 0) return;
89
- ensurePlayNode().port.postMessage({
90
- event: "write",
91
- buffer: new Uint8Array(pcm16Buffer)
92
- }, [pcm16Buffer]);
93
- },
94
- done() {
95
- if (!playNode) return Promise.resolve();
96
- return new Promise((resolve) => {
97
- onPlaybackStop = resolve;
98
- playNode?.port.postMessage({ event: "done" });
99
- });
100
- },
101
- flush() {
102
- if (playNode) playNode.port.postMessage({ event: "interrupt" });
103
- },
104
- async close() {
105
- if (lifecycle.signal.aborted) return;
106
- lifecycle.abort();
107
- capNode.port.postMessage({ event: "stop" });
108
- mic.disconnect();
109
- capNode.disconnect();
110
- if (playNode) playNode.disconnect();
111
- for (const t of stream.getTracks()) t.stop();
112
- await ctx.close().catch(() => {});
113
- },
114
- async [Symbol.asyncDispose]() {
115
- await io.close();
116
- }
117
- };
118
- return io;
119
- }
120
- //#endregion
121
- export { createVoiceIO };
@@ -1,33 +0,0 @@
1
- /**
2
- * Theme overrides for the default UI. Applied as CSS custom properties.
3
- *
4
- * @public
5
- */
6
- export type ClientTheme = {
7
- /** Background color. Default: `#101010`. */
8
- bg?: string;
9
- /** Primary accent color. Default: `#fab283`. */
10
- primary?: string;
11
- /** Main text color. */
12
- text?: string;
13
- /** Surface/card color. */
14
- surface?: string;
15
- /** Border color. */
16
- border?: string;
17
- };
18
- /**
19
- * Resolved client-level configuration available to default UI components.
20
- *
21
- * @public
22
- */
23
- export type ClientConfig = {
24
- title?: string | undefined;
25
- theme?: ClientTheme | undefined;
26
- };
27
- export declare const ClientConfigProvider: import("preact").Provider<ClientConfig>;
28
- /**
29
- * Read client config (title, theme) from the nearest provider.
30
- *
31
- * @public
32
- */
33
- export declare function useClientConfig(): ClientConfig;
@@ -1,15 +0,0 @@
1
- import { createContext } from "preact";
2
- import { useContext } from "preact/hooks";
3
- //#region client-context.ts
4
- const Ctx = createContext({});
5
- const ClientConfigProvider = Ctx.Provider;
6
- /**
7
- * Read client config (title, theme) from the nearest provider.
8
- *
9
- * @public
10
- */
11
- function useClientConfig() {
12
- return useContext(Ctx);
13
- }
14
- //#endregion
15
- export { ClientConfigProvider, useClientConfig };
@@ -1,43 +0,0 @@
1
- import type { ReadyConfig } from "@alexkroman1/aai/protocol";
2
- import type { VoiceIO } from "./audio.ts";
3
- import type { AgentState, ChatMessage, Reactive, SessionError, ToolCallInfo } from "./types.ts";
4
- type BatchFn = (fn: () => void) => void;
5
- /**
6
- * Handles server→client messages and updates reactive Preact signals
7
- * accordingly (state transitions, transcripts, messages, audio playback).
8
- *
9
- * @internal Exported for testing only.
10
- */
11
- export declare class ClientHandler {
12
- #private;
13
- constructor(opts: {
14
- state: Reactive<AgentState>;
15
- messages: Reactive<ChatMessage[]>;
16
- toolCalls: Reactive<ToolCallInfo[]>;
17
- userUtterance: Reactive<string | null>;
18
- agentUtterance: Reactive<string | null>;
19
- error: Reactive<SessionError | null>;
20
- voiceIO: () => VoiceIO | null;
21
- batch: BatchFn;
22
- });
23
- /** Single entry point for all server→client session events. */
24
- event(e: import("@alexkroman1/aai/protocol").ClientEvent): void;
25
- /** Enqueue a PCM16 audio chunk for playback. Transitions state to `"speaking"` on the first chunk. */
26
- playAudioChunk(chunk: Uint8Array): void;
27
- /**
28
- * Signal that the server has finished sending audio for this turn.
29
- * Waits for the audio queue to drain, then transitions state to `"listening"`.
30
- * Uses the `#generation` counter to discard stale completions from interrupted turns.
31
- */
32
- playAudioDone(): void;
33
- /**
34
- * Dispatch an incoming WebSocket message (text or binary).
35
- *
36
- * Returns the parsed config if the message is a `config` message,
37
- * otherwise `null`.
38
- */
39
- handleMessage(data: string | ArrayBuffer): (ReadyConfig & {
40
- sessionId?: string;
41
- }) | null;
42
- }
43
- export {};
@@ -1,23 +0,0 @@
1
- import type * as preact from "preact";
2
- /**
3
- * The default top-level UI component for an AAI voice agent.
4
- * Renders a {@link StartScreen} (with the AAI logo or a custom title from
5
- * {@link useClientConfig}) followed by a {@link ChatView} once the session starts.
6
- *
7
- * This is the component rendered by {@link defineClient} when no custom component is
8
- * provided.
9
- *
10
- * @example
11
- * ```tsx
12
- * import { App, defineClient } from "@aai/ui";
13
- *
14
- * defineClient(App, { target: "#app", title: "My Agent" });
15
- * ```
16
- *
17
- * @param className - Additional CSS class names applied to the root element.
18
- *
19
- * @public
20
- */
21
- export declare function App({ className }: {
22
- className?: string;
23
- }): preact.JSX.Element;
@@ -1,41 +0,0 @@
1
- import { useClientConfig } from "../client-context.js";
2
- import { ChatView } from "./chat-view.js";
3
- import { StartScreen } from "./start-screen.js";
4
- import { jsx } from "preact/jsx-runtime";
5
- //#region components/app.tsx
6
- function AnsiLogo() {
7
- return /* @__PURE__ */ jsx("pre", {
8
- class: "font-aai-mono text-lg leading-[1.1] font-bold text-aai-primary m-0",
9
- children: "▄▀█ ▄▀█ █\n█▀█ █▀█ █"
10
- });
11
- }
12
- /**
13
- * The default top-level UI component for an AAI voice agent.
14
- * Renders a {@link StartScreen} (with the AAI logo or a custom title from
15
- * {@link useClientConfig}) followed by a {@link ChatView} once the session starts.
16
- *
17
- * This is the component rendered by {@link defineClient} when no custom component is
18
- * provided.
19
- *
20
- * @example
21
- * ```tsx
22
- * import { App, defineClient } from "@aai/ui";
23
- *
24
- * defineClient(App, { target: "#app", title: "My Agent" });
25
- * ```
26
- *
27
- * @param className - Additional CSS class names applied to the root element.
28
- *
29
- * @public
30
- */
31
- function App({ className }) {
32
- const { title } = useClientConfig();
33
- return /* @__PURE__ */ jsx(StartScreen, {
34
- icon: title ? void 0 : /* @__PURE__ */ jsx(AnsiLogo, {}),
35
- title,
36
- className,
37
- children: /* @__PURE__ */ jsx(ChatView, {})
38
- });
39
- }
40
- //#endregion
41
- export { App };
@@ -1,21 +0,0 @@
1
- import type * as preact from "preact";
2
- import type { Reactive, SessionError } from "../types.ts";
3
- /**
4
- * Displays a session error as a styled inline banner.
5
- * Returns `null` when there is no active error.
6
- *
7
- * @example
8
- * ```tsx
9
- * const { session } = useSession();
10
- * <ErrorBanner error={session.error} />
11
- * ```
12
- *
13
- * @param error - A reactive {@link SessionError} (or `null`).
14
- * @param className - Additional CSS class names.
15
- *
16
- * @public
17
- */
18
- export declare function ErrorBanner({ error, className, }: {
19
- error: Reactive<SessionError | null>;
20
- className?: string;
21
- }): preact.JSX.Element | null;
@@ -1,27 +0,0 @@
1
- import clsx from "clsx";
2
- import { jsx } from "preact/jsx-runtime";
3
- //#region components/error-banner.tsx
4
- /**
5
- * Displays a session error as a styled inline banner.
6
- * Returns `null` when there is no active error.
7
- *
8
- * @example
9
- * ```tsx
10
- * const { session } = useSession();
11
- * <ErrorBanner error={session.error} />
12
- * ```
13
- *
14
- * @param error - A reactive {@link SessionError} (or `null`).
15
- * @param className - Additional CSS class names.
16
- *
17
- * @public
18
- */
19
- function ErrorBanner({ error, className }) {
20
- if (!error.value) return null;
21
- return /* @__PURE__ */ jsx("div", {
22
- class: clsx("mx-4 mt-3 px-3 py-2 rounded-aai border border-aai-error/40 bg-aai-error/8 text-[13px] leading-[130%] text-aai-error", className),
23
- children: error.value.message
24
- });
25
- }
26
- //#endregion
27
- export { ErrorBanner };
@@ -1,23 +0,0 @@
1
- import type * as preact from "preact";
2
- import type { ChatMessage } from "../types.ts";
3
- /**
4
- * Renders a single chat message as a styled bubble.
5
- *
6
- * - **User** messages appear right-aligned with a faint surface background.
7
- * - **Assistant** messages appear left-aligned as plain text.
8
- *
9
- * @example
10
- * ```tsx
11
- * <MessageBubble message={{ role: "user", content: "Hello!" }} />
12
- * <MessageBubble message={{ role: "assistant", content: "Hi there!" }} />
13
- * ```
14
- *
15
- * @param message - The chat message to display (see {@link ChatMessage}).
16
- * @param className - Additional CSS class names applied to the root element.
17
- *
18
- * @public
19
- */
20
- export declare function MessageBubble({ message, className, }: {
21
- message: ChatMessage;
22
- className?: string;
23
- }): preact.JSX.Element;
@@ -1,35 +0,0 @@
1
- import clsx from "clsx";
2
- import { jsx } from "preact/jsx-runtime";
3
- //#region components/message-bubble.tsx
4
- /**
5
- * Renders a single chat message as a styled bubble.
6
- *
7
- * - **User** messages appear right-aligned with a faint surface background.
8
- * - **Assistant** messages appear left-aligned as plain text.
9
- *
10
- * @example
11
- * ```tsx
12
- * <MessageBubble message={{ role: "user", content: "Hello!" }} />
13
- * <MessageBubble message={{ role: "assistant", content: "Hi there!" }} />
14
- * ```
15
- *
16
- * @param message - The chat message to display (see {@link ChatMessage}).
17
- * @param className - Additional CSS class names applied to the root element.
18
- *
19
- * @public
20
- */
21
- function MessageBubble({ message, className }) {
22
- if (message.role === "user") return /* @__PURE__ */ jsx("div", {
23
- class: clsx("flex flex-col w-full items-end", className),
24
- children: /* @__PURE__ */ jsx("div", {
25
- class: "max-w-[min(82%,64ch)] bg-aai-surface-faint border border-aai-border px-3 py-2 rounded-aai whitespace-pre-wrap wrap-break-word text-sm font-normal leading-[150%] text-aai-text",
26
- children: message.content
27
- })
28
- });
29
- return /* @__PURE__ */ jsx("div", {
30
- class: clsx("whitespace-pre-wrap wrap-break-word text-sm font-normal leading-[150%] text-aai-text", className),
31
- children: message.content
32
- });
33
- }
34
- //#endregion
35
- export { MessageBubble };
@@ -1,29 +0,0 @@
1
- import type * as preact from "preact";
2
- import type { AgentState, Reactive } from "../types.ts";
3
- /**
4
- * Colored dot + label showing the current {@link AgentState}.
5
- *
6
- * State-to-color mapping:
7
- * - `disconnected` — gray
8
- * - `connecting` — yellow
9
- * - `ready` — green
10
- * - `listening` — blue
11
- * - `thinking` — purple
12
- * - `speaking` — red
13
- * - `error` — red
14
- *
15
- * @example
16
- * ```tsx
17
- * const { session } = useSession();
18
- * <StateIndicator state={session.state} />
19
- * ```
20
- *
21
- * @param state - A reactive {@link AgentState} value.
22
- * @param className - Additional CSS class names.
23
- *
24
- * @public
25
- */
26
- export declare function StateIndicator({ state, className, }: {
27
- state: Reactive<AgentState>;
28
- className?: string;
29
- }): preact.JSX.Element;