@alexkroman1/aai-ui 5.2.0 → 5.4.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 (42) hide show
  1. package/README.md +59 -0
  2. package/dist/{chat-view-C6N2oXjo.js → chat-view-CqRGHImR.js} +12 -6
  3. package/dist/client-config.d.ts +13 -2
  4. package/dist/components/button.d.ts +17 -11
  5. package/dist/components/button.js +9 -6
  6. package/dist/components/chat-view.d.ts +10 -4
  7. package/dist/components/chat-view.js +1 -1
  8. package/dist/components/controls.d.ts +6 -2
  9. package/dist/components/controls.js +1 -1
  10. package/dist/components/message-list.d.ts +6 -2
  11. package/dist/components/message-list.js +1 -1
  12. package/dist/components/sidebar-layout.d.ts +13 -3
  13. package/dist/components/sidebar-layout.js +13 -3
  14. package/dist/components/start-screen.d.ts +2 -0
  15. package/dist/components/start-screen.js +2 -0
  16. package/dist/components/tool-call-block.d.ts +1 -6
  17. package/dist/components/tool-call-block.js +1 -1
  18. package/dist/components/tool-config-context.d.ts +3 -3
  19. package/dist/components/url-chips.d.ts +3 -3
  20. package/dist/context.d.ts +59 -2
  21. package/dist/context.js +45 -0
  22. package/dist/{controls-Cqg7T4FN.js → controls-CoBO6sId.js} +9 -5
  23. package/dist/default-client/assets/{audio-C1U_foBG.js → audio-DXQj0wCf.js} +1 -1
  24. package/dist/default-client/assets/{capture-processor-dyyJArQs.js → capture-processor-DZg_Q6hY.js} +1 -1
  25. package/dist/default-client/assets/{index-CGZajs1V.js → index-DyY8OeVc.js} +25 -25
  26. package/dist/default-client/assets/{playback-processor-BO2TdYrv.js → playback-processor-DZlwpHHt.js} +1 -1
  27. package/dist/default-client/index.html +1 -1
  28. package/dist/define-client.d.ts +44 -9
  29. package/dist/define-client.js +22 -4
  30. package/dist/hooks.d.ts +51 -19
  31. package/dist/hooks.js +37 -7
  32. package/dist/index.d.ts +5 -5
  33. package/dist/index.js +6 -6
  34. package/dist/{message-list-CD9GxrlH.js → message-list-CdtrNi4w.js} +7 -3
  35. package/dist/{session-core-Bvga6tUS.js → session-core-DX2SIpdQ.js} +30 -4
  36. package/dist/session-core-types.d.ts +34 -9
  37. package/dist/session-core.d.ts +15 -0
  38. package/dist/session-core.js +1 -1
  39. package/dist/{tool-call-block-O9vLqoyU.js → tool-call-block-C--Bj04_.js} +4 -9
  40. package/dist/types.d.ts +23 -7
  41. package/dist/types.js +3 -0
  42. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import{i as e}from"./index-CGZajs1V.js";import{t}from"./_module-url-BX0RuRU2.js";var n=t(`
1
+ import{i as e}from"./index-DyY8OeVc.js";import{t}from"./_module-url-BX0RuRU2.js";var n=t(`
2
2
  class PlaybackProcessor extends AudioWorkletProcessor {
3
3
  constructor(options) {
4
4
  super();
@@ -6,7 +6,7 @@
6
6
  <title>aai</title>
7
7
  <link rel="icon" href="./favicon.ico" />
8
8
  <style>html, body { background: #FBF8F2; margin: 0; }</style>
9
- <script type="module" crossorigin src="./assets/index-CGZajs1V.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-DyY8OeVc.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-CRfdZPH1.css">
11
11
  </head>
12
12
  <body>
@@ -4,7 +4,8 @@ import { type ToolDisplayConfig } from "./components/tool-config-context.ts";
4
4
  import type { SessionCore } from "./session-core-types.ts";
5
5
  import type { ClientTheme, VoiceSessionOptions } from "./types.ts";
6
6
  /**
7
- * Base options shared by both client tiers.
7
+ * Options shared by both {@link client} tiers (config-only and custom
8
+ * component).
8
9
  *
9
10
  * The session-forwarded fields are picked from {@link VoiceSessionOptions}
10
11
  * (one source of truth for types and docs) rather than re-declared — a
@@ -12,7 +13,7 @@ import type { ClientTheme, VoiceSessionOptions } from "./types.ts";
12
13
  *
13
14
  * @public
14
15
  */
15
- type BaseOptions = Pick<VoiceSessionOptions, "onSessionId" | "resumeSessionId" | "WebSocket"> & {
16
+ export type BaseOptions = Pick<VoiceSessionOptions, "onSessionId" | "resumeSessionId" | "WebSocket"> & {
16
17
  /** CSS selector or DOM element to render into. Defaults to `"#app"`. */
17
18
  target?: string | HTMLElement;
18
19
  /** Base URL of the AAI platform server. Derived from `location.href` by default. */
@@ -21,11 +22,12 @@ type BaseOptions = Pick<VoiceSessionOptions, "onSessionId" | "resumeSessionId" |
21
22
  theme?: ClientTheme;
22
23
  };
23
24
  /**
24
- * Tier 1: Config-only options. Renders the default shell (StartScreen + ChatView).
25
+ * Tier 1: config-only options — no `component`. Renders the default shell
26
+ * (StartScreen + ChatView).
25
27
  *
26
28
  * @public
27
29
  */
28
- type ConfigTier = BaseOptions & {
30
+ export type ConfigTier = BaseOptions & {
29
31
  component?: never;
30
32
  /** Agent name shown in the header and start screen. */
31
33
  name?: string;
@@ -37,11 +39,12 @@ type ConfigTier = BaseOptions & {
37
39
  tools?: ToolDisplayConfig;
38
40
  };
39
41
  /**
40
- * Tier 2: Custom component. Renders the provided component inside the providers.
42
+ * Tier 2: custom component renders the provided `component` inside the
43
+ * providers instead of the default shell.
41
44
  *
42
45
  * @public
43
46
  */
44
- type ComponentTier = BaseOptions & {
47
+ export type ComponentTier = BaseOptions & {
45
48
  /** Full custom component to render instead of the default shell. */
46
49
  component: ComponentType;
47
50
  /**
@@ -58,7 +61,22 @@ type ComponentTier = BaseOptions & {
58
61
  name?: string;
59
62
  sidebar?: never;
60
63
  sidebarWidth?: never;
61
- tools?: never;
64
+ /**
65
+ * Tool display config: icon and label overrides keyed by tool name.
66
+ *
67
+ * Allowed here for the same reason as `name` above, and it was found the
68
+ * same way: four starters across an eval run wrote
69
+ * `client({ component, tools })` and lost a build round each time to
70
+ * *"Type '{ … }' is not assignable to type 'undefined'"*.
71
+ *
72
+ * Unlike `sidebar`/`sidebarWidth`, this is not a property of the default
73
+ * shell. `client()` below wraps BOTH tiers in `ToolConfigContext.Provider`
74
+ * from `config.tools ?? {}`, and the consumer is `ToolCallBlock` — which a
75
+ * custom component renders as soon as it uses `MessageList` or `ChatView`,
76
+ * the usual way to build one. So the value was always honoured at runtime;
77
+ * only the type refused it.
78
+ */
79
+ tools?: ToolDisplayConfig;
62
80
  };
63
81
  /**
64
82
  * Configuration passed to {@link client}.
@@ -88,10 +106,21 @@ export type ClientHandle = {
88
106
  * default shell (StartScreen + ChatView, optional sidebar).
89
107
  *
90
108
  * **Tier 2 (custom component):** Pass `component` to render a fully custom
91
- * root component inside the providers.
109
+ * root component inside the providers. In this tier a provided `name` also
110
+ * sets `document.title` (there is no shell header to show it in).
111
+ *
112
+ * Mounts into `target` — a CSS selector or DOM element, defaulting to
113
+ * `"#app"` — and throws `Element not found: <target>` when the selector
114
+ * matches nothing.
92
115
  *
93
116
  * @example Tier 1
94
117
  * ```tsx
118
+ * import { client } from "@alexkroman1/aai-ui";
119
+ *
120
+ * function OrderPanel() {
121
+ * return <div>Cart</div>;
122
+ * }
123
+ *
95
124
  * client({
96
125
  * name: "Pizza Ordering",
97
126
  * theme: { bg: "#1a1a1a", primary: "#e55" },
@@ -102,6 +131,13 @@ export type ClientHandle = {
102
131
  *
103
132
  * @example Tier 2
104
133
  * ```tsx
134
+ * import { client, useSession } from "@alexkroman1/aai-ui";
135
+ *
136
+ * function MyCustomApp() {
137
+ * const session = useSession();
138
+ * return <div>{session.state}</div>;
139
+ * }
140
+ *
105
141
  * client({ component: MyCustomApp });
106
142
  * ```
107
143
  *
@@ -111,4 +147,3 @@ export type ClientHandle = {
111
147
  * @public
112
148
  */
113
149
  export declare function client(config: ClientConfig): ClientHandle;
114
- export {};
@@ -1,8 +1,8 @@
1
- import { r as fetchClientConfig, t as createSessionCore } from "./session-core-Bvga6tUS.js";
1
+ import { r as fetchClientConfig, t as createSessionCore } from "./session-core-DX2SIpdQ.js";
2
2
  import { SessionProvider, ThemeProvider } from "./context.js";
3
- import { t as ChatView } from "./chat-view-C6N2oXjo.js";
3
+ import { t as ChatView } from "./chat-view-CqRGHImR.js";
4
4
  import { t as pageBaseUrl } from "./_utils-CsqbIVGI.js";
5
- import { n as ToolConfigContext } from "./tool-call-block-O9vLqoyU.js";
5
+ import { n as ToolConfigContext } from "./tool-call-block-C--Bj04_.js";
6
6
  import { SidebarLayout } from "./components/sidebar-layout.js";
7
7
  import { StartScreen } from "./components/start-screen.js";
8
8
  import { createElement, useEffect, useState } from "react";
@@ -63,10 +63,21 @@ function DefaultRoot({ platformUrl, name, Sidebar, sidebarWidth }) {
63
63
  * default shell (StartScreen + ChatView, optional sidebar).
64
64
  *
65
65
  * **Tier 2 (custom component):** Pass `component` to render a fully custom
66
- * root component inside the providers.
66
+ * root component inside the providers. In this tier a provided `name` also
67
+ * sets `document.title` (there is no shell header to show it in).
68
+ *
69
+ * Mounts into `target` — a CSS selector or DOM element, defaulting to
70
+ * `"#app"` — and throws `Element not found: <target>` when the selector
71
+ * matches nothing.
67
72
  *
68
73
  * @example Tier 1
69
74
  * ```tsx
75
+ * import { client } from "@alexkroman1/aai-ui";
76
+ *
77
+ * function OrderPanel() {
78
+ * return <div>Cart</div>;
79
+ * }
80
+ *
70
81
  * client({
71
82
  * name: "Pizza Ordering",
72
83
  * theme: { bg: "#1a1a1a", primary: "#e55" },
@@ -77,6 +88,13 @@ function DefaultRoot({ platformUrl, name, Sidebar, sidebarWidth }) {
77
88
  *
78
89
  * @example Tier 2
79
90
  * ```tsx
91
+ * import { client, useSession } from "@alexkroman1/aai-ui";
92
+ *
93
+ * function MyCustomApp() {
94
+ * const session = useSession();
95
+ * return <div>{session.state}</div>;
96
+ * }
97
+ *
80
98
  * client({ component: MyCustomApp });
81
99
  * ```
82
100
  *
package/dist/hooks.d.ts CHANGED
@@ -3,18 +3,14 @@ import type { ToolCallInfo } from "./types.ts";
3
3
  /**
4
4
  * Fire a callback when a tool call settles, with the tool's JSON result.
5
5
  *
6
- * @typeParam R - The result shape. Defaults to {@link DefaultToolResult} —
7
- * `any`, for the same reason `ctx.state` is: the value is the author's own
8
- * tool output round-tripped through JSON, so `unknown` (which this was) made
9
- * the ordinary spelling
10
- *
11
- * ```tsx
12
- * useToolResult("get_quote", (r) => setPrice(r.price))
13
- * ```
14
- *
15
- * a compile error on a client that runs correctly, and `aai build` refuses
16
- * to publish it. Pass the shape — `useToolResult<Quote>(…)` — to get real
17
- * checking, which also documents what the tool returns.
6
+ * For new code prefer explicit events — `ctx.send(event, data)` in the tool
7
+ * paired with {@link useEvent} here over listening to tool results.
8
+ *
9
+ * @typeParam R - The result shape. Defaults to {@link DefaultToolResult}
10
+ * (`any`) so the ordinary untyped spelling compiles; pass the shape —
11
+ * `useToolResult<Quote>(…)` — for real checking.
12
+ *
13
+ * @public
18
14
  */
19
15
  export declare function useToolResult<R = DefaultToolResult>(toolName: string, callback: (result: R, toolCall: ToolCallInfo) => void): void;
20
16
  export declare function useToolResult<R = DefaultToolResult>(callback: (name: string, result: R, toolCall: ToolCallInfo) => void): void;
@@ -22,23 +18,59 @@ export declare function useToolResult<R = DefaultToolResult>(callback: (name: st
22
18
  * The agent's projected session state, or `null` before the first push.
23
19
  *
24
20
  * The counterpart to `syncState` on the agent: whatever that projection
25
- * returns is what arrives here. It replaces the pattern this exists to
26
- * remove — returning a state snapshot from every tool, declaring a type for
27
- * what those tools happen to return, and mirroring it into `useState` through
28
- * `useToolResult`, which was three things to keep in step and which 58% of
29
- * measured generated agents built by hand.
21
+ * returns is what arrives here no per-tool result mirroring needed.
30
22
  *
31
23
  * ```tsx
32
- * const cart = useAgentState<{ cart: Item[] }>();
33
- * return <Cart items={cart?.cart ?? []} />;
24
+ * import { useAgentState } from "@alexkroman1/aai-ui";
25
+ *
26
+ * type Item = { sku: string; qty: number };
27
+ *
28
+ * function Cart() {
29
+ * const state = useAgentState<{ cart: Item[] }>();
30
+ * return <ul>{state?.cart.map((item) => <li key={item.sku}>{item.qty}</li>)}</ul>;
31
+ * }
34
32
  * ```
35
33
  *
36
34
  * Typed by the caller for the same reason `useToolResult` is: the shape is
37
35
  * the author's own projection, which the framework cannot see. It is
38
36
  * nullable on purpose — nothing has been pushed before the first tool call,
39
37
  * and a UI has to render that moment.
38
+ *
39
+ * @public
40
40
  */
41
41
  export declare function useAgentState<S = DefaultToolResult>(): S | null;
42
+ /**
43
+ * Subscribe to custom events emitted by agent tools via
44
+ * `ctx.send(event, data)`; the callback receives each event's `data`.
45
+ *
46
+ * This is the preferred way to drive UI from tools — an explicit event beats
47
+ * inferring state from tool results with {@link useToolResult}.
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * import { useEvent } from "@alexkroman1/aai-ui";
52
+ * import { useState } from "react";
53
+ *
54
+ * type Item = { sku: string; qty: number };
55
+ *
56
+ * function Cart() {
57
+ * const [cart, setCart] = useState<Item[]>([]);
58
+ * // Tool: ctx.send("item_added", { sku, qty })
59
+ * useEvent<Item>("item_added", (data) => {
60
+ * setCart((cart) => [...cart, data]);
61
+ * });
62
+ * return <div>{cart.length} items</div>;
63
+ * }
64
+ * ```
65
+ *
66
+ * @public
67
+ */
42
68
  export declare function useEvent<T = unknown>(event: string, callback: (data: T) => void): void;
69
+ /**
70
+ * Fire a callback when a tool call starts (before its result arrives).
71
+ * Optionally filter by tool name.
72
+ *
73
+ * @public
74
+ */
43
75
  export declare function useToolCallStart(toolName: string, callback: (toolCall: ToolCallInfo) => void): void;
44
76
  export declare function useToolCallStart(callback: (toolCall: ToolCallInfo) => void): void;
package/dist/hooks.js CHANGED
@@ -81,25 +81,55 @@ function useToolResult(...args) {
81
81
  * The agent's projected session state, or `null` before the first push.
82
82
  *
83
83
  * The counterpart to `syncState` on the agent: whatever that projection
84
- * returns is what arrives here. It replaces the pattern this exists to
85
- * remove — returning a state snapshot from every tool, declaring a type for
86
- * what those tools happen to return, and mirroring it into `useState` through
87
- * `useToolResult`, which was three things to keep in step and which 58% of
88
- * measured generated agents built by hand.
84
+ * returns is what arrives here no per-tool result mirroring needed.
89
85
  *
90
86
  * ```tsx
91
- * const cart = useAgentState<{ cart: Item[] }>();
92
- * return <Cart items={cart?.cart ?? []} />;
87
+ * import { useAgentState } from "@alexkroman1/aai-ui";
88
+ *
89
+ * type Item = { sku: string; qty: number };
90
+ *
91
+ * function Cart() {
92
+ * const state = useAgentState<{ cart: Item[] }>();
93
+ * return <ul>{state?.cart.map((item) => <li key={item.sku}>{item.qty}</li>)}</ul>;
94
+ * }
93
95
  * ```
94
96
  *
95
97
  * Typed by the caller for the same reason `useToolResult` is: the shape is
96
98
  * the author's own projection, which the framework cannot see. It is
97
99
  * nullable on purpose — nothing has been pushed before the first tool call,
98
100
  * and a UI has to render that moment.
101
+ *
102
+ * @public
99
103
  */
100
104
  function useAgentState() {
101
105
  return useSessionSelector((snapshot) => snapshot.agentState);
102
106
  }
107
+ /**
108
+ * Subscribe to custom events emitted by agent tools via
109
+ * `ctx.send(event, data)`; the callback receives each event's `data`.
110
+ *
111
+ * This is the preferred way to drive UI from tools — an explicit event beats
112
+ * inferring state from tool results with {@link useToolResult}.
113
+ *
114
+ * @example
115
+ * ```tsx
116
+ * import { useEvent } from "@alexkroman1/aai-ui";
117
+ * import { useState } from "react";
118
+ *
119
+ * type Item = { sku: string; qty: number };
120
+ *
121
+ * function Cart() {
122
+ * const [cart, setCart] = useState<Item[]>([]);
123
+ * // Tool: ctx.send("item_added", { sku, qty })
124
+ * useEvent<Item>("item_added", (data) => {
125
+ * setCart((cart) => [...cart, data]);
126
+ * });
127
+ * return <div>{cart.length} items</div>;
128
+ * }
129
+ * ```
130
+ *
131
+ * @public
132
+ */
103
133
  function useEvent(event, callback) {
104
134
  const customEvents = useSessionSelector((s) => s.customEvents);
105
135
  const watermarkRef = useRef(0);
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { buildAgentUrl, type ClientConfigResponse, fetchClientConfig, } from "./client-config.ts";
2
- export { Button } from "./components/button.tsx";
1
+ export { buildAgentUrl, type ClientConfigResponse, fetchClientConfig, loadClientConfig, } from "./client-config.ts";
2
+ export { Button, type ButtonSize, type ButtonVariant } from "./components/button.tsx";
3
3
  export { ChatView } from "./components/chat-view.tsx";
4
4
  export { Controls } from "./components/controls.tsx";
5
5
  export { Markdown } from "./components/markdown.tsx";
@@ -11,10 +11,10 @@ export { ToolConfigContext } from "./components/tool-config-context.ts";
11
11
  export { ApiUrlChip, SessionUrlChips, UiUrlChip } from "./components/url-chips.tsx";
12
12
  export type { Session } from "./context.ts";
13
13
  export { SessionProvider, ThemeProvider, useSession, useSessionSelector, useTheme, } from "./context.ts";
14
- export type { ClientConfig, ClientHandle, } from "./define-client.tsx";
14
+ export type { BaseOptions, ClientConfig, ClientHandle, ComponentTier, ConfigTier, } from "./define-client.tsx";
15
15
  export { client } from "./define-client.tsx";
16
16
  export { useAgentState, useEvent, useToolCallStart, useToolResult } from "./hooks.ts";
17
17
  export { createSessionCore } from "./session-core.ts";
18
- export type { CustomEvent, SessionCore, SessionCoreOptions, SessionSnapshot, } from "./session-core-types.ts";
19
- export type { AgentState, ChatMessage, ClientTheme, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, } from "./types.ts";
18
+ export type { AgentCustomEvent, SessionCore, SessionCoreOptions, SessionSnapshot, } from "./session-core-types.ts";
19
+ export type { AgentState, ChatMessage, ClientTheme, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor, } from "./types.ts";
20
20
  export { VOICE_CAPTURE_CONSTRAINTS } from "./types.ts";
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-Bvga6tUS.js";
1
+ import { i as loadClientConfig, n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-DX2SIpdQ.js";
2
2
  import { SessionProvider, ThemeProvider, useSession, useSessionSelector, useTheme } from "./context.js";
3
3
  import { Button } from "./components/button.js";
4
- import { t as ChatView } from "./chat-view-C6N2oXjo.js";
5
- import { i as UiUrlChip, n as ApiUrlChip, r as SessionUrlChips, t as Controls } from "./controls-Cqg7T4FN.js";
6
- import { n as Markdown, t as MessageList } from "./message-list-CD9GxrlH.js";
7
- import { n as ToolConfigContext } from "./tool-call-block-O9vLqoyU.js";
4
+ import { t as ChatView } from "./chat-view-CqRGHImR.js";
5
+ import { i as UiUrlChip, n as ApiUrlChip, r as SessionUrlChips, t as Controls } from "./controls-CoBO6sId.js";
6
+ import { n as Markdown, t as MessageList } from "./message-list-CdtrNi4w.js";
7
+ import { n as ToolConfigContext } from "./tool-call-block-C--Bj04_.js";
8
8
  import { SidebarLayout } from "./components/sidebar-layout.js";
9
9
  import { StartScreen } from "./components/start-screen.js";
10
10
  import { VOICE_CAPTURE_CONSTRAINTS } from "./types.js";
11
11
  import { client } from "./define-client.js";
12
12
  import { useAgentState, useEvent, useToolCallStart, useToolResult } from "./hooks.js";
13
- export { ApiUrlChip, Button, ChatView, Controls, Markdown, MessageList, SessionProvider, SessionUrlChips, SidebarLayout, StartScreen, ThemeProvider, ToolConfigContext, UiUrlChip, VOICE_CAPTURE_CONSTRAINTS, buildAgentUrl, client, createSessionCore, fetchClientConfig, useAgentState, useEvent, useSession, useSessionSelector, useTheme, useToolCallStart, useToolResult };
13
+ export { ApiUrlChip, Button, ChatView, Controls, Markdown, MessageList, SessionProvider, SessionUrlChips, SidebarLayout, StartScreen, ThemeProvider, ToolConfigContext, UiUrlChip, VOICE_CAPTURE_CONSTRAINTS, buildAgentUrl, client, createSessionCore, fetchClientConfig, loadClientConfig, useAgentState, useEvent, useSession, useSessionSelector, useTheme, useToolCallStart, useToolResult };
@@ -1,6 +1,6 @@
1
1
  import { useSessionSelector, useTheme } from "./context.js";
2
2
  import { i as TEXT_MUTED, n as SURFACE_TINT, o as primaryTint, r as TEXT_FAINT } from "./_colors-Bfh3-BVE.js";
3
- import { t as ToolCallBlock } from "./tool-call-block-O9vLqoyU.js";
3
+ import { t as ToolCallBlock } from "./tool-call-block-C--Bj04_.js";
4
4
  import clsx from "clsx";
5
5
  import { memo, useCallback, useEffect, useMemo, useRef } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -312,11 +312,15 @@ function interleave(messages, toolCalls, renderMessage, renderToolCall) {
312
312
  * Messages and tool calls are interleaved in the correct order. The list
313
313
  * auto-scrolls to the latest content.
314
314
  *
315
- * Must be rendered inside a {@link SessionProvider}.
315
+ * Must be rendered inside a `SessionProvider`.
316
316
  *
317
317
  * @example
318
318
  * ```tsx
319
- * <MessageList className="flex-1" />
319
+ * import { MessageList } from "@alexkroman1/aai-ui";
320
+ *
321
+ * function Conversation() {
322
+ * return <MessageList className="flex-1" />;
323
+ * }
320
324
  * ```
321
325
  *
322
326
  * @param className - Additional CSS class names applied to the scroll container.
@@ -1,6 +1,7 @@
1
1
  import { MIC_SEND_MAX_BUFFERED_BYTES } from "./types.js";
2
2
  import { CLIENT_CONFIG_PATH, ClientConfigResponseSchema, ServerMessageSchema, lenientParse } from "@alexkroman1/aai/protocol";
3
- import { DEFAULT_MAX_HISTORY, WS_OPEN, createEpoch, errorMessage, safeJsonParse, toArgsRecord } from "@alexkroman1/aai";
3
+ import { DEFAULT_MAX_HISTORY, WS_OPEN, errorMessage, safeJsonParse, toArgsRecord } from "@alexkroman1/aai";
4
+ import { createEpoch } from "@alexkroman1/aai/internal";
4
5
  import ReconnectingWebSocket from "partysocket/ws";
5
6
  //#region client-config.ts
6
7
  /**
@@ -17,7 +18,11 @@ import ReconnectingWebSocket from "partysocket/ws";
17
18
  * keeps "the lookup failed" (`null`) distinct from "the server answered and
18
19
  * named no sessionUrl" (`{}`). See its doc comment.
19
20
  */
20
- /** Resolve a relative endpoint path against the agent's base URL. */
21
+ /**
22
+ * Resolve a relative endpoint path against the agent's base URL.
23
+ *
24
+ * @internal
25
+ */
21
26
  function buildAgentUrl(platformUrl, endpointPath) {
22
27
  return new URL(endpointPath, platformUrl.endsWith("/") ? platformUrl : `${platformUrl}/`);
23
28
  }
@@ -35,6 +40,8 @@ const AGENT_DEFAULT = {};
35
40
  * platform's `/:slug/websocket` — a WebSocket redirect browsers don't
36
41
  * follow, so every retry failed with no re-brokering even after the agent
37
42
  * recovered.
43
+ *
44
+ * @internal
38
45
  */
39
46
  async function loadClientConfig(platformUrl, fetchFn) {
40
47
  const doFetch = fetchFn ?? ((input, init) => globalThis.fetch(input, init));
@@ -47,7 +54,11 @@ async function loadClientConfig(platformUrl, fetchFn) {
47
54
  return null;
48
55
  }
49
56
  }
50
- /** Fetch the agent's client config; any failure yields the agent default. */
57
+ /**
58
+ * Fetch the agent's client config; any failure yields the agent default.
59
+ *
60
+ * @internal
61
+ */
51
62
  async function fetchClientConfig(platformUrl, fetchFn) {
52
63
  return await loadClientConfig(platformUrl, fetchFn) ?? AGENT_DEFAULT;
53
64
  }
@@ -517,6 +528,21 @@ function applyResumeParams(wsUrl, resume, sessionId) {
517
528
  * Uses a subscribe/getSnapshot pattern for state management, compatible with
518
529
  * React's `useSyncExternalStore` and other external store integrations.
519
530
  *
531
+ * Most clients never call this: `client()` creates a core and installs it in
532
+ * React context for the hooks. Reach for it directly when building a
533
+ * non-React UI (or wiring the session into another framework's store).
534
+ *
535
+ * @example
536
+ * ```ts
537
+ * import { createSessionCore, type SessionSnapshot } from "@alexkroman1/aai-ui";
538
+ *
539
+ * declare function render(snapshot: SessionSnapshot): void;
540
+ *
541
+ * const session = createSessionCore({ platformUrl: "https://host/my-agent/" });
542
+ * session.subscribe(() => render(session.getSnapshot()));
543
+ * session.start();
544
+ * ```
545
+ *
520
546
  * @param options - Session configuration including the platform server URL.
521
547
  * @returns A {@link SessionCore} handle for controlling the session.
522
548
  *
@@ -797,4 +823,4 @@ function createSessionCore(options) {
797
823
  };
798
824
  }
799
825
  //#endregion
800
- export { buildAgentUrl as n, fetchClientConfig as r, createSessionCore as t };
826
+ export { loadClientConfig as i, buildAgentUrl as n, fetchClientConfig as r, createSessionCore as t };
@@ -3,15 +3,20 @@
3
3
  *
4
4
  * Split out of `session-core.ts` to keep that module focused on behaviour.
5
5
  */
6
- import type { Epoch } from "@alexkroman1/aai";
6
+ import type { Epoch } from "@alexkroman1/aai/internal";
7
7
  import type { VoiceIO } from "./audio.ts";
8
8
  import type { AgentState, ChatMessage, SessionError, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor } from "./types.ts";
9
9
  /**
10
- * A custom event emitted by the agent via `ctx.send`.
10
+ * A custom event emitted by the agent via `ctx.send(event, data)` — the
11
+ * payload the session records in `SessionSnapshot.customEvents` (`id` is a
12
+ * monotonic session-unique counter, `event` the name, `data` the payload).
13
+ *
14
+ * Deliberately NOT the DOM `CustomEvent`: it shares nothing with that
15
+ * interface, and the old name shadowed the global in `.tsx` files.
11
16
  *
12
17
  * @public
13
18
  */
14
- export type CustomEvent = {
19
+ export type AgentCustomEvent = {
15
20
  readonly id: number;
16
21
  readonly event: string;
17
22
  readonly data: unknown;
@@ -47,7 +52,7 @@ export type SessionSnapshot = {
47
52
  readonly contentVersion: number;
48
53
  readonly messages: ChatMessage[];
49
54
  readonly toolCalls: ToolCallInfo[];
50
- readonly customEvents: CustomEvent[];
55
+ readonly customEvents: AgentCustomEvent[];
51
56
  /**
52
57
  * Latest state the agent projected via `syncState`, or `null` before the
53
58
  * first push. A value, not a log — a component that mounts mid-session
@@ -75,7 +80,10 @@ export type SessionCore = {
75
80
  /** Subscribe to state changes. Returns an unsubscribe function. */
76
81
  subscribe(callback: () => void): () => void;
77
82
  /**
78
- * Open a WebSocket connection to the server and begin audio capture.
83
+ * Open a WebSocket connection to the server and begin audio capture,
84
+ * without touching the `started`/`running` flags — the low-level half of
85
+ * `start()`. Most UIs call `start()` (first activation) or `toggle()`
86
+ * (mute-style connect/disconnect) instead.
79
87
  * @param options - Optional. `signal` is an AbortSignal that, when aborted, disconnects the session.
80
88
  */
81
89
  connect(options?: {
@@ -83,19 +91,36 @@ export type SessionCore = {
83
91
  }): void;
84
92
  /** Cancel the current agent turn and discard in-flight TTS audio. */
85
93
  cancel(): void;
86
- /** Clear messages, transcript, and error state without disconnecting. */
94
+ /**
95
+ * Clear messages, transcripts, and error state while keeping the current
96
+ * connection (unlike `reset()`, which also reconnects).
97
+ */
87
98
  resetState(): void;
88
- /** Reset the session: clear state and reconnect. */
99
+ /**
100
+ * Reset the session: clear state as `resetState()` does, then drop and
101
+ * reopen the connection for a fresh conversation.
102
+ */
89
103
  reset(): void;
90
104
  /** Close the WebSocket and release all audio resources. */
91
105
  disconnect(): void;
92
- /** Start the session for the first time (sets `started` and `running`). */
106
+ /**
107
+ * Start the session for the first time: sets `started` and `running`, then
108
+ * connects. Use this for the initial "start conversation" action;
109
+ * afterwards `toggle()` is the pause/resume control.
110
+ */
93
111
  start(): void;
94
- /** Toggle between connected and disconnected states. */
112
+ /** Toggle between connected and disconnected states (after `start()`). */
95
113
  toggle(): void;
96
114
  /** Alias for `disconnect` for use with `using`. */
97
115
  [Symbol.dispose](): void;
98
116
  };
117
+ /**
118
+ * Options accepted by `createSessionCore` — an alias of
119
+ * {@link VoiceSessionOptions}, which documents every field. Two names, one
120
+ * type: `client()` and `createSessionCore` share the same session options.
121
+ *
122
+ * @public
123
+ */
99
124
  export type SessionCoreOptions = VoiceSessionOptions;
100
125
  /**
101
126
  * Shared mutable connection state for audio initialization.
@@ -6,6 +6,21 @@ import type { SessionCore, SessionCoreOptions } from "./session-core-types.ts";
6
6
  * Uses a subscribe/getSnapshot pattern for state management, compatible with
7
7
  * React's `useSyncExternalStore` and other external store integrations.
8
8
  *
9
+ * Most clients never call this: `client()` creates a core and installs it in
10
+ * React context for the hooks. Reach for it directly when building a
11
+ * non-React UI (or wiring the session into another framework's store).
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { createSessionCore, type SessionSnapshot } from "@alexkroman1/aai-ui";
16
+ *
17
+ * declare function render(snapshot: SessionSnapshot): void;
18
+ *
19
+ * const session = createSessionCore({ platformUrl: "https://host/my-agent/" });
20
+ * session.subscribe(() => render(session.getSnapshot()));
21
+ * session.start();
22
+ * ```
23
+ *
9
24
  * @param options - Session configuration including the platform server URL.
10
25
  * @returns A {@link SessionCore} handle for controlling the session.
11
26
  *
@@ -1,2 +1,2 @@
1
- import { t as createSessionCore } from "./session-core-Bvga6tUS.js";
1
+ import { t as createSessionCore } from "./session-core-DX2SIpdQ.js";
2
2
  export { createSessionCore };
@@ -7,10 +7,10 @@ import { createContext, memo, useContext, useMemo, useState } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  //#region components/tool-config-context.ts
9
9
  /**
10
- * Context for tool display configuration.
11
- * Provided by `client` or manually via `ToolConfigContext.Provider`.
10
+ * Context for tool display configuration. Installed by `client()` from
11
+ * `ClientConfig.tools`; the built-in components read it via `useToolConfig`.
12
12
  *
13
- * @public
13
+ * @internal
14
14
  */
15
15
  const ToolConfigContext = createContext({});
16
16
  /**
@@ -44,15 +44,10 @@ function formatResult(result) {
44
44
  * snapshots and rows are keyed on the stable `callId`, so a list update only
45
45
  * re-renders the rows whose tool call actually changed.
46
46
  *
47
- * @example
48
- * ```tsx
49
- * <ToolCallBlock toolCall={toolCall} />
50
- * ```
51
- *
52
47
  * @param toolCall - The tool call to render (see {@link ToolCallInfo}).
53
48
  * @param className - Additional CSS class names.
54
49
  *
55
- * @public
50
+ * @internal Not exported from the package — rendered by `MessageList`.
56
51
  */
57
52
  const ToolCallBlock = memo(function ToolCallBlock({ toolCall, className }) {
58
53
  const [isOpen, setIsOpen] = useState(false);