@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,476 @@
1
+ /**
2
+ * Type declarations for the framework-agnostic voice session core.
3
+ *
4
+ * Split out of `session/browser-session.ts` to keep that module focused on behaviour.
5
+ */
6
+ import type { Epoch } from "@alexkroman1/aai/internal";
7
+ import type { SessionIdentity } from "../client-identity.ts";
8
+ import type { AgentState, ChatMessage, SessionError, ToolCallInfo, WebSocketConstructor } from "../types.ts";
9
+ import type { AudioPath } from "./audio-state.ts";
10
+ /**
11
+ * A custom event emitted by the agent via `ctx.send(event, data)` — the
12
+ * payload the session records in `SessionSnapshot.customEvents` (`id` is a
13
+ * monotonic session-unique counter, `event` the name, `data` the payload).
14
+ *
15
+ * Deliberately NOT the DOM `CustomEvent`: it shares nothing with that
16
+ * interface, and the old name shadowed the global in `.tsx` files.
17
+ *
18
+ * @public
19
+ */
20
+ export type AgentCustomEvent = {
21
+ readonly id: number;
22
+ readonly event: string;
23
+ readonly data: unknown;
24
+ };
25
+ /**
26
+ * The agent's projected state as the client holds it: one entry per slot the
27
+ * agent's `syncState` names, keyed by that slot's name.
28
+ *
29
+ * @public
30
+ */
31
+ export type AgentStateFrame = Readonly<Record<string, unknown>>;
32
+ /**
33
+ * Immutable snapshot of the session state.
34
+ *
35
+ * Consumers (e.g. React hooks via `useSyncExternalStore`) read this to render.
36
+ * A new object reference is created on every state change.
37
+ *
38
+ * @remarks
39
+ * **Four fields describe liveness and they answer different questions.** They
40
+ * are routinely collapsed into one truthy check, which is how a chrome ends up
41
+ * showing a live indicator over a call that has ended:
42
+ *
43
+ * | Field | The question it answers |
44
+ * | --- | --- |
45
+ * | `started` | Has the caller pressed Start? `end()` puts it back to `false`; `disconnect()` does not. |
46
+ * | `running` | Is the socket MEANT to be up? `toggle()` is what flips it. |
47
+ * | `recording` | Is the microphone actually live right now? |
48
+ * | `state` | What is the agent doing — see {@link AgentState}. |
49
+ *
50
+ * @public
51
+ */
52
+ export type SessionSnapshot = {
53
+ /** What the agent is doing. See {@link AgentState} for the seven members. */
54
+ readonly state: AgentState;
55
+ /**
56
+ * True while the microphone is live and streaming to the server.
57
+ *
58
+ * This is the mic, not the session: a session can be `running` with the mic
59
+ * still opening, and a failure to acquire it leaves this `false` with the
60
+ * socket up.
61
+ */
62
+ readonly recording: boolean;
63
+ /**
64
+ * Whether the caller has MUTED the microphone — see
65
+ * {@link BrowserSession.setMicMuted}. Independent of `recording`: a muted
66
+ * mic stays open and keeps streaming (as silence), so `recording` stays
67
+ * `true`. UI state, so it survives reconnects, `disconnect()` and `end()`.
68
+ */
69
+ readonly micMuted: boolean;
70
+ /**
71
+ * The WebSocket URL a program can connect to directly — the long-living
72
+ * platform endpoint, e.g. `wss://host/my-agent/websocket`. Derived from
73
+ * `platformUrl` at construction — available before connecting — and never
74
+ * replaced by the brokered sandbox tunnel URL the session may actually be
75
+ * connected to: that URL is ephemeral (it dies when the sandbox is
76
+ * replaced), while the platform endpoint is stable and upgrades
77
+ * programmatic clients to the current sandbox endpoint itself.
78
+ */
79
+ readonly apiUrl: string;
80
+ /**
81
+ * Monotonically increasing counter bumped whenever rendered conversation
82
+ * content changes (`messages`, `toolCalls`, or either live transcript).
83
+ * Cheap dependency for scroll-to-bottom effects — unlike summed lengths it
84
+ * never collides when the capped arrays slide.
85
+ */
86
+ readonly contentVersion: number;
87
+ /**
88
+ * The conversation so far, oldest first — user and assistant turns only.
89
+ * Tool activity is NOT in here; it is in `toolCalls`. Capped, so the oldest
90
+ * entries slide off a long call.
91
+ */
92
+ readonly messages: ChatMessage[];
93
+ /**
94
+ * Every tool call the agent has made this session, in order, each carrying
95
+ * its own pending/settled state. Capped like `messages`. `useToolResult` and
96
+ * `useToolCallStart` are the narrow readers; this is the whole log.
97
+ */
98
+ readonly toolCalls: ToolCallInfo[];
99
+ /**
100
+ * Custom events the agent pushed with `ctx.send(event, data)`, in order.
101
+ * A LOG rather than a value — `useEvent(name, cb)` is the reader that
102
+ * delivers each one exactly once; reading this array directly means owning
103
+ * the cursor yourself.
104
+ */
105
+ readonly customEvents: AgentCustomEvent[];
106
+ /**
107
+ * Latest state the agent projected via `syncState` — keyed by slot name,
108
+ * `{ [slot]: view }` — or `null` before the first push. A value, not a log —
109
+ * a component that mounts mid-session reads current state rather than
110
+ * replaying events it missed. A slot whose view did not change keeps its
111
+ * previous value object, so a selector over one slot is stable across pushes.
112
+ */
113
+ readonly agentState: AgentStateFrame | null;
114
+ /**
115
+ * The caller's in-progress turn, as STT reports it.
116
+ *
117
+ * **`null` and `""` are different turns, and collapsing them is the mistake
118
+ * this field invites.** `null` is silence; `""` is speech DETECTED with no
119
+ * words back yet — where a live session sits for a few hundred milliseconds
120
+ * at the start of every turn. Read as one falsy check, the live-transcript
121
+ * row appears a beat late, on the first word rather than on the first sound,
122
+ * which is the moment it exists for.
123
+ *
124
+ * Prefer {@link useUserTranscript}, which returns the distinction as two
125
+ * named things (`speaking` to render on, `text` with a placeholder) rather
126
+ * than leaving each chrome to re-derive the ternary.
127
+ *
128
+ * Cleared when the turn is committed to `messages`.
129
+ */
130
+ readonly userTranscript: string | null;
131
+ /**
132
+ * The agent's reply as it streams, or `null` when it is not speaking.
133
+ * Cleared when the reply is committed to `messages`, so a chrome renders
134
+ * this row and the finished message, never both.
135
+ */
136
+ readonly agentTranscript: string | null;
137
+ /**
138
+ * The session's current failure, or `null`. Carries a `code`
139
+ * ({@link SessionErrorCode}), a message, and whether it was FATAL.
140
+ *
141
+ * A fatal error LATCHES: nothing clears it but the next completed handshake,
142
+ * because the frame announcing a session's death is also the frame that used
143
+ * to wipe the message explaining it. A non-fatal one is retired by later
144
+ * activity, which is what the recovery was written for.
145
+ */
146
+ readonly error: SessionError | null;
147
+ /**
148
+ * Whether the caller has pressed Start. `false` until the first `start()`,
149
+ * and back to `false` after `end()` — which is what makes a start-screen
150
+ * chrome show its Start control again. `disconnect()` leaves it `true`.
151
+ */
152
+ readonly started: boolean;
153
+ /**
154
+ * Whether the session is MEANT to be connected — the pause/resume state
155
+ * `toggle()` flips, not a report of the socket. A reconnecting session is
156
+ * still `running`.
157
+ */
158
+ readonly running: boolean;
159
+ };
160
+ /**
161
+ * The seal on a {@link BrowserSession}.
162
+ *
163
+ * TYPE-ONLY — there is no value at run time, so an object literal cannot carry
164
+ * the key and only `createBrowserSession` mints a session. That is what lets
165
+ * the handle grow a member without breaking anybody: push-to-talk added three
166
+ * REQUIRED methods and broke every hand-written double, which is the failure a
167
+ * handle a caller RECEIVES should not be able to cause.
168
+ *
169
+ * @public
170
+ */
171
+ export declare const browserSessionBrand: unique symbol;
172
+ /**
173
+ * Push-to-talk's three edges on a {@link BrowserSession} — `session.userTurn`.
174
+ *
175
+ * Only an agent declaring `turnTaking: { detection: "manual" }` honours them; any other
176
+ * agent logs once and ignores them, because its transcriber already ends each
177
+ * turn on a pause. `usePushToTalk` is the hook a button is built on, and the
178
+ * way a `client.tsx` reaches these: a sub-handle rather than three methods on
179
+ * the session, so a feature one agent in many declares is not three members
180
+ * every session carries in its autocomplete.
181
+ *
182
+ * @public
183
+ */
184
+ export type UserTurnControls = {
185
+ /**
186
+ * OPEN a turn — the button went down. Stops the agent if it is speaking
187
+ * (discarding its queued audio here at once, rather than a round trip later)
188
+ * and lets the microphone through to the transcriber.
189
+ */
190
+ start(): void;
191
+ /** CLOSE the turn and have the agent answer everything said since `start()` — the button came up. */
192
+ commit(): void;
193
+ /**
194
+ * Close the turn and THROW AWAY what was said in it — a cancelled press (the
195
+ * pointer left the button, Escape). The agent answers nothing.
196
+ */
197
+ clear(): void;
198
+ };
199
+ /**
200
+ * How a page answers a tool call it ran — see {@link BrowserSession.sendToolResult}.
201
+ *
202
+ * @public
203
+ */
204
+ export type ToolCallOutcome = {
205
+ result: unknown;
206
+ } | {
207
+ error: string;
208
+ };
209
+ /**
210
+ * Options for {@link BrowserSession.sendText}.
211
+ *
212
+ * @public
213
+ */
214
+ export type SendTextOptions = {
215
+ /**
216
+ * Open the session for this message if it is not up: `start()` before the
217
+ * first call, `toggle()` after a hang-up (so a resumable session RESUMES),
218
+ * then send once the server has configured it. Messages typed meanwhile are
219
+ * kept in order. They are DROPPED if the session stops before it is up — a
220
+ * hang-up, `end()`, a failed connection — so a message typed into a call
221
+ * that never came is not answered by a later one. Default `false`: sending
222
+ * while disconnected does nothing.
223
+ */
224
+ connect?: boolean | undefined;
225
+ };
226
+ /**
227
+ * A framework-agnostic voice session that manages WebSocket communication,
228
+ * audio capture/playback, and agent state transitions.
229
+ *
230
+ * Uses a subscribe/getSnapshot pattern (compatible with React's
231
+ * `useSyncExternalStore`). Implements `Disposable` for resource cleanup.
232
+ *
233
+ * @sealed Only `createBrowserSession` produces one — see
234
+ * {@link browserSessionBrand}. A test double for a component is a real
235
+ * session with no socket, not an object literal.
236
+ *
237
+ * @public
238
+ */
239
+ export type BrowserSession = {
240
+ /** The seal — see {@link browserSessionBrand}. */
241
+ readonly [browserSessionBrand]: true;
242
+ /** Return the current immutable state snapshot. */
243
+ getSnapshot(): SessionSnapshot;
244
+ /** Subscribe to state changes. Returns an unsubscribe function. */
245
+ subscribe(callback: () => void): () => void;
246
+ /**
247
+ * Open a WebSocket connection to the server and begin audio capture,
248
+ * without touching the `started`/`running` flags — the low-level half of
249
+ * `start()`. Most UIs call `start()` (first activation) or `toggle()`
250
+ * (mute-style connect/disconnect) instead.
251
+ * @param options - Optional. `signal` is an AbortSignal that, when aborted, disconnects the session.
252
+ */
253
+ connect(options?: {
254
+ signal?: AbortSignal;
255
+ }): void;
256
+ /** Cancel the current agent turn and discard in-flight TTS audio. */
257
+ cancel(): void;
258
+ /** Push-to-talk's three edges — see {@link UserTurnControls}. */
259
+ readonly userTurn: UserTurnControls;
260
+ /**
261
+ * Who this session is to its agent — the base URL it dials, the client id it
262
+ * sends, this tab's inbox holder id, and the server's session id. What
263
+ * `useInbox()`, `useClientId()` and `useSessionId()` read; see
264
+ * {@link SessionIdentity}.
265
+ */
266
+ readonly identity: SessionIdentity;
267
+ /**
268
+ * Send a TYPED user turn: the agent answers `text` exactly as if the caller
269
+ * had said it — aloud, with tools, under any `turnTaking.detection`.
270
+ *
271
+ * Interrupts the agent if it is speaking or thinking (its queued audio is
272
+ * discarded here at once, as `cancel()` does). The message is NOT echoed into
273
+ * `messages` locally: the server reports it as the same
274
+ * `userTranscript.committed` a spoken turn produces, and that is what adds
275
+ * the row — so it is also what a resumed session replays.
276
+ *
277
+ * `text` is trimmed; an empty message sends nothing, and so does a call
278
+ * while disconnected — unless `options.connect` is set, which opens the
279
+ * session (see {@link SendTextOptions}) and sends once it is up. Text longer than `MAX_TRANSCRIPT_CHARS` (100,000) is refused by
280
+ * the server. A speech-to-speech agent cannot take a typed turn: the server
281
+ * logs a warning once and the message is ignored.
282
+ *
283
+ * @example
284
+ * ```ts
285
+ * declare const session: import("@alexkroman1/aai-ui").Session;
286
+ * session.sendText("What's the weather tomorrow?");
287
+ * ```
288
+ */
289
+ sendText(text: string, options?: SendTextOptions): void;
290
+ /**
291
+ * Answer a pending tool call the agent asked THIS PAGE to run — a
292
+ * `clientTool` on the server. `result` is JSON-serialized and becomes the
293
+ * value the model reads; `error` fails the call with that message. A no-op
294
+ * while disconnected, and ignored by the server for a call nothing waits on.
295
+ *
296
+ * Most pages use `useClientTool(name, handler)`, which calls this for them.
297
+ */
298
+ sendToolResult(toolCallId: string, outcome: ToolCallOutcome): void;
299
+ /**
300
+ * Mute or unmute the microphone WITHOUT dropping the session — the gate a
301
+ * hold-to-talk button over an agent with automatic turn detection is built
302
+ * on (mute by default, unmute while held).
303
+ *
304
+ * While muted the session keeps streaming frames of the same length and
305
+ * cadence, zero-filled, so the server's transcriber hears silence: its
306
+ * automatic endpointing closes the turn on release, and the stream's clock
307
+ * stays true. Purely local — no command is sent and a speaking agent is not
308
+ * interrupted (call `cancel()` for that).
309
+ *
310
+ * UI state rather than connection state: it survives reconnects, resumes,
311
+ * `disconnect()` → `connect()` and `end()`, and may be set before the first
312
+ * `connect()` so a session opens already muted. Read it back as
313
+ * `micMuted` on the snapshot.
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * declare const session: import("@alexkroman1/aai-ui").Session;
318
+ * session.setMicMuted(true); // typed-only until the talk button is held
319
+ * ```
320
+ */
321
+ setMicMuted(muted: boolean): void;
322
+ /**
323
+ * Clear messages, transcripts, and error state while keeping the current
324
+ * connection (unlike `reset()`, which also reconnects).
325
+ */
326
+ resetState(): void;
327
+ /**
328
+ * Reset the session: clear state as `resetState()` does, then drop and
329
+ * reopen the connection for a fresh conversation.
330
+ */
331
+ reset(): void;
332
+ /** Close the WebSocket and release all audio resources. */
333
+ disconnect(): void;
334
+ /**
335
+ * Start the session for the first time: sets `started` and `running`, then
336
+ * connects. Use this for the initial "start conversation" action;
337
+ * afterwards `toggle()` is the pause/resume control.
338
+ */
339
+ start(): void;
340
+ /** Toggle between connected and disconnected states (after `start()`). */
341
+ toggle(): void;
342
+ /**
343
+ * End the call: close the connection, clear the conversation, and return
344
+ * to the not-started state (`started` flips back to false, so a
345
+ * start-screen UI shows its Start control again). Unlike `reset()` —
346
+ * which keeps the call live and only clears the conversation — the next
347
+ * `start()` mints a brand-new session: a new session id, fresh
348
+ * per-session tool state, greeting included.
349
+ */
350
+ end(): void;
351
+ /**
352
+ * End the current call and immediately begin a new one — `end()` then
353
+ * `start()`, which is what "New Conversation" means for an agent that keeps
354
+ * SESSION-SCOPED STATE.
355
+ *
356
+ * `reset()` is the one whose name suggests this and it is not the same
357
+ * thing: it clears the transcript and reconnects, but the reconnect carries
358
+ * the same `?sessionId=`, so every `sessionSlot` on the server survives —
359
+ * the game world, the incident board, the cart. A caller who asked to start
360
+ * over gets a blank transcript in front of the old state. This drops the
361
+ * session id, so the next connect mints a fresh one and the greeting plays
362
+ * again.
363
+ *
364
+ * Three templates had each written `session.end(); session.start();` with
365
+ * the same paragraph explaining why `reset()` was wrong; the six on the
366
+ * stock shell could not, because {@link Controls} called `reset()` for them.
367
+ *
368
+ * @example
369
+ * ```ts
370
+ * declare const session: import("@alexkroman1/aai-ui").Session;
371
+ * session.restart();
372
+ * ```
373
+ */
374
+ restart(): void;
375
+ /**
376
+ * Continue an EARLIER session — one of this client's past conversations, say,
377
+ * picked from a list — without reloading the page: hang up the current call
378
+ * if there is one, clear the transcript on screen, and connect presenting
379
+ * `sessionId` as `?sessionId=`, so the server resumes THAT session.
380
+ *
381
+ * The server restores it the way a reload does: the session's own turns come
382
+ * back in `history.restored` (a session bound to a `client` keeps its events
383
+ * after it ends), together with the client's other prior sessions as seed —
384
+ * never counting this one twice. The greeting is skipped, as on any resume.
385
+ * The id is stored like a `config` frame's, so a reload continues it too.
386
+ *
387
+ * Throws a `RangeError` for an id the server would not honor (1-128 letters,
388
+ * digits, `-` or `_`) BEFORE touching the current call. An id that names no
389
+ * session the server has starts a fresh conversation under it, greeting
390
+ * skipped — the same answer a stale bookmark gets.
391
+ *
392
+ * @example
393
+ * ```ts
394
+ * declare const session: import("@alexkroman1/aai-ui").Session;
395
+ * declare const picked: { sessionId: string };
396
+ * session.resume(picked.sessionId);
397
+ * ```
398
+ */
399
+ resume(sessionId: string): void;
400
+ /** Alias for `disconnect` for use with `using`. */
401
+ [Symbol.dispose](): void;
402
+ };
403
+ /**
404
+ * Shared mutable connection state.
405
+ *
406
+ * **It used to carry the audio path too**, and the four fields that went are
407
+ * worth naming because the shape recurs: a `voiceIO` slot, an
408
+ * `audioSetupInFlight` latch, a `generation` epoch whose only readers were the
409
+ * bring-up's four staleness checks, and the two pre-init buffers. Each was a
410
+ * question about a position the connection did not have, readable and writable
411
+ * from anywhere. They are the audio path's own statechart now — see
412
+ * `session/audio-state.ts`.
413
+ *
414
+ * What is left is what the CONNECTION really owns: the socket, the server's
415
+ * idle retirement, and the turn boundary.
416
+ */
417
+ export type ConnState = {
418
+ ws: InstanceType<WebSocketConstructor> | null;
419
+ /**
420
+ * The server retired this session for idleness (`idle_timeout`), so the
421
+ * close that follows is EXPECTED and must not be retried.
422
+ *
423
+ * Without this the automatic reconnect would immediately re-open the
424
+ * session the server just reclaimed — a tab left open would cycle forever
425
+ * and the guest would never see zero sessions, which is the whole point of
426
+ * the timeout. Reconnecting is the user's call from here (the controls
427
+ * reconnect on demand).
428
+ */
429
+ retiredByServer: boolean;
430
+ /**
431
+ * Turn epoch, bumped at every turn boundary — a committed user turn, a
432
+ * barge-in, a reset, AND every audio-path teardown (`cleanupAudio`).
433
+ *
434
+ * Async playback completions (`settleWhenAudioDrained`) capture it and
435
+ * discard themselves when it has moved. The teardown bumps are why it lives
436
+ * here rather than as a closure local in the message handlers: a reply's
437
+ * drain resolves whenever the AudioContext closes, so a session torn down
438
+ * mid-speech (hang up, fatal error, reconnect) would otherwise have
439
+ * `state: "listening"` written over its "disconnected"/"error" a moment
440
+ * later — a dead session reporting a live mic.
441
+ */
442
+ turn: Epoch;
443
+ };
444
+ /**
445
+ * The two liveness fields at rest.
446
+ *
447
+ * `running` and `recording` ride with almost every state transition and were
448
+ * spread as a pair of literals at seven sites across three modules — the same
449
+ * shape `session/state.ts` folded `state` and `error` out of, one field
450
+ * short. Naming it relates them: a transition that ends the call says so once,
451
+ * and a reader looking for "what stops the mic" finds one symbol rather than a
452
+ * grep.
453
+ *
454
+ * It is deliberately NOT the whole snapshot patch — a transition still supplies
455
+ * its own `agentState.apply(...)` projection beside this.
456
+ */
457
+ export declare const STOPPED: {
458
+ readonly running: false;
459
+ readonly recording: false;
460
+ };
461
+ /**
462
+ * A turn boundary: end the current turn and settle whatever it was playing.
463
+ *
464
+ * The two calls are one fact and were written out at four sites — `cancel()`
465
+ * and `reset()` here, `reply.cancelled` and `session.reset` on the server side
466
+ * — where the pair is load-bearing in both halves. The bump stops a stale drain
467
+ * continuation from stamping `"listening"` over a state the session has since
468
+ * moved to; the flush settles the interrupted turn's `done()` so it cannot
469
+ * strand.
470
+ *
471
+ * Two further sites bump WITHOUT flushing (`cleanupAudio`, a committed user
472
+ * transcript) and stay spelled out, which is the point of naming this one: a
473
+ * bump on its own now reads as a deliberate choice rather than a forgotten
474
+ * flush.
475
+ */
476
+ export declare function bargeIn(conn: ConnState, audio: AudioPath): void;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * What the client reports about itself on every attempt: `?location=`,
3
+ * `?phone=` and `?client=`, each already resolved and trimmed (empty = not
4
+ * reported).
5
+ */
6
+ export type ClientReport = {
7
+ location?: string | undefined;
8
+ phone?: string | undefined;
9
+ client?: string | undefined;
10
+ };
11
+ /** Build the session WebSocket URL from the platform URL and resume state. */
12
+ export declare function buildWsUrl(platformUrl: string, sessionId?: string, report?: ClientReport): URL;
13
+ /**
14
+ * Turn a broker-provided session URL (`sessionUrl` from `GET client-config`
15
+ * — the agent's live sandbox endpoint) into this attempt's connect URL.
16
+ */
17
+ export declare function buildBrokeredWsUrl(sessionUrl: string, sessionId?: string, report?: ClientReport): URL;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Push-to-talk's three edges on the browser session — `session.userTurn`'s
3
+ * `start`, `commit` and `clear` — for an agent that declares
4
+ * `turnTaking: { detection: "manual" }`; and `session.sendText`, a turn the caller TYPED.
5
+ *
6
+ * Split out of `session/browser-session.ts` at the source-length cap. Each is a frame to
7
+ * the server; what the server does with it is `aai-runtime`'s
8
+ * `aai-runtime/src/transports/pipeline/speech/manual-turn.ts`. The two things done HERE rather than waiting a
9
+ * round trip for are the reason these are more than `sendJson` calls: a press
10
+ * stops the agent's queued audio at once, and a discarded turn's caption is
11
+ * cleared because no transcript for it will ever arrive.
12
+ *
13
+ * @module
14
+ */
15
+ import type { SessionCommand } from "@alexkroman1/aai/protocol";
16
+ import type { SessionStateMachine } from "./state.ts";
17
+ import type { SendTextOptions, SessionSnapshot, ToolCallOutcome, UserTurnControls } from "./types.ts";
18
+ /** What the three edges need from the session around them. @internal */
19
+ export type UserTurnDeps = {
20
+ snapshot: () => SessionSnapshot;
21
+ /** A socket is open and can carry a frame. */
22
+ connected: () => boolean;
23
+ /** The local turn boundary — see `bargeIn` in `session/types.ts`. */
24
+ bargeIn: () => void;
25
+ agentState: SessionStateMachine;
26
+ updateState: (partial: Partial<SessionSnapshot>) => void;
27
+ sendJson: (msg: SessionCommand) => void;
28
+ /**
29
+ * Typed turns waiting for a session — `sendText(text, { connect: true })`
30
+ * while none is up. OWNED by the session core, which empties it whenever the
31
+ * session stops being meant to run (`running: false`): a hang-up, `end()`, a
32
+ * terminal close. A message typed into a call that then failed must not be
33
+ * answered by the next one.
34
+ */
35
+ queued: string[];
36
+ /** Bring the session up if it is not meant to be running — `start()` or `toggle()`. */
37
+ open: () => void;
38
+ };
39
+ /**
40
+ * Everything a caller's turn can be started by: push-to-talk's three edges
41
+ * and a TYPED turn — `session.userTurn` and `session.sendText`. One builder
42
+ * over one set of deps, because both are the same kind of thing (a user turn
43
+ * the client, not the transcriber, delimits) and both interrupt the same way.
44
+ *
45
+ * @internal
46
+ */
47
+ export declare function createUserInput(deps: UserTurnDeps): {
48
+ userTurn: UserTurnControls;
49
+ sendText: (text: string, options?: SendTextOptions) => void;
50
+ /** A session came up (a `config` frame): send what was typed while it was not. */
51
+ flushQueued: () => void;
52
+ sendToolResult: (toolCallId: string, outcome: ToolCallOutcome) => void;
53
+ };
54
+ /** Build the three push-to-talk edges. @internal */
55
+ export declare function createUserTurnActions(deps: UserTurnDeps): UserTurnControls;