@alexkroman1/aai-ui 0.12.3 → 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.
- package/README.md +257 -0
- package/dist/_colors-CpZO-88A.js +78 -0
- package/dist/_module-url-C13kAJ87.js +15 -0
- package/dist/_page-shell.d.ts +11 -0
- package/dist/_recover-run.d.ts +79 -0
- package/dist/_repeat-until.d.ts +30 -0
- package/dist/_run-controls.d.ts +33 -0
- package/dist/_submission-state.d.ts +92 -0
- package/dist/_tap-to-talk-state.d.ts +88 -0
- package/dist/_utils-Mi-SCFA1.js +47 -0
- package/dist/_utils.d.ts +26 -0
- package/dist/_web-storage.d.ts +43 -0
- package/dist/_workflow-api-ref.d.ts +37 -0
- package/dist/_workflow-files.d.ts +34 -0
- package/dist/_workflow-test-defs.d.ts +38 -0
- package/dist/aai-logo-D8pMVn9_.js +85 -0
- package/dist/agent-state-labels.d.ts +65 -0
- package/dist/agent-state.d.ts +108 -0
- package/dist/audio/capture.d.ts +44 -0
- package/dist/audio/index.d.ts +18 -0
- package/dist/audio/index.js +431 -0
- package/dist/audio/preconnect.d.ts +87 -0
- package/dist/audio/voice-io.d.ts +112 -0
- package/dist/build-default-client.d.ts +1 -0
- package/dist/chat-view-BCbI7gD4.js +396 -0
- package/dist/client-config-C7fQrioM.js +139 -0
- package/dist/client-config.d.ts +119 -0
- package/dist/client-dir.d.ts +44 -0
- package/dist/client-dir.js +58 -0
- package/dist/client-identity.d.ts +131 -0
- package/dist/client-tool.d.ts +51 -0
- package/dist/components/_colors.d.ts +73 -0
- package/dist/components/_form-readiness.d.ts +56 -0
- package/dist/components/_form-values.d.ts +19 -0
- package/dist/components/aai-logo.d.ts +12 -0
- package/dist/components/audio-result.d.ts +94 -0
- package/dist/components/auto-scroll.d.ts +74 -0
- package/dist/components/bullet-list.d.ts +74 -0
- package/dist/components/button.d.ts +29 -21
- package/dist/components/button.js +62 -23
- package/dist/components/chat-view.d.ts +24 -18
- package/dist/components/chat-view.js +2 -60
- package/dist/components/console-shell.d.ts +85 -0
- package/dist/components/controls.d.ts +21 -6
- package/dist/components/controls.js +31 -19
- package/dist/components/conversation-view.d.ts +130 -0
- package/dist/components/eyebrow.d.ts +12 -0
- package/dist/components/facts.d.ts +81 -0
- package/dist/components/form-fields.d.ts +142 -0
- package/dist/components/form-types.d.ts +73 -0
- package/dist/components/form.d.ts +96 -0
- package/dist/components/markdown.d.ts +57 -0
- package/dist/components/message-list.d.ts +34 -7
- package/dist/components/message-list.js +2 -75
- package/dist/components/session-controls.d.ts +125 -0
- package/dist/components/session-error-banner.d.ts +69 -0
- package/dist/components/session-state-dot.d.ts +111 -0
- package/dist/components/sidebar-layout.d.ts +31 -10
- package/dist/components/sidebar-layout.js +32 -12
- package/dist/components/start-screen.d.ts +17 -6
- package/dist/components/start-screen.js +34 -14
- package/dist/components/tool-call-block.d.ts +15 -14
- package/dist/components/tool-call-block.js +2 -117
- package/dist/components/tool-call-row.d.ts +75 -0
- package/dist/components/tool-config-context.d.ts +22 -0
- package/dist/components/upload-progress.d.ts +76 -0
- package/dist/components/url-chips.d.ts +29 -0
- package/dist/components/workflow-fields.d.ts +46 -0
- package/dist/components/workflow-pending-note.d.ts +81 -0
- package/dist/components/workflow-progress.d.ts +81 -0
- package/dist/components/workflow-run-error.d.ts +48 -0
- package/dist/components/workflow-run-panel.d.ts +79 -0
- package/dist/context.d.ts +288 -0
- package/dist/context.js +382 -0
- package/dist/conversation-log.d.ts +88 -0
- package/dist/default-client/assets/_module-url-BX0RuRU2.js +1 -0
- package/dist/default-client/assets/audio-cGFGID-2.js +1 -0
- package/dist/default-client/assets/capture-processor-BUABoo3_.js +90 -0
- package/dist/default-client/assets/index-8ihb1Urm.css +2 -0
- package/dist/default-client/assets/index-BQURVARl.js +126 -0
- package/dist/default-client/assets/playback-processor-ABOa11j0.js +314 -0
- package/dist/default-client/favicon.ico +0 -0
- package/dist/default-client/index.html +15 -0
- package/dist/default-client.d.ts +23 -0
- package/dist/define-client.d.ts +162 -26
- package/dist/define-client.js +201 -55
- package/dist/eyebrow-UfmSz9yy.js +27 -0
- package/dist/hooks-DN4gHYsj.js +182 -0
- package/dist/hooks.d.ts +172 -0
- package/dist/hooks.js +3 -0
- package/dist/hooks.test-d.d.ts +14 -0
- package/dist/inbox-protocol.d.ts +128 -0
- package/dist/inbox.d.ts +132 -0
- package/dist/index.d.ts +126 -29
- package/dist/index.js +5500 -15
- package/dist/internal.d.ts +43 -0
- package/dist/internal.js +8 -0
- package/dist/linked-client.d.ts +70 -0
- package/dist/message-list-DHZcLhRA.js +682 -0
- package/dist/notice-player.d.ts +70 -0
- package/dist/page.d.ts +114 -0
- package/dist/phone.d.ts +50 -0
- package/dist/route-fetch.d.ts +79 -0
- package/dist/session/audio-effects.d.ts +31 -0
- package/dist/session/audio-setup.d.ts +57 -0
- package/dist/session/audio-state.d.ts +157 -0
- package/dist/session/browser-session.d.ts +30 -0
- package/dist/session/close.d.ts +26 -0
- package/dist/session/dial.d.ts +65 -0
- package/dist/session/handshake.d.ts +60 -0
- package/dist/session/index.d.ts +17 -0
- package/dist/session/index.js +2 -0
- package/dist/session/messages.d.ts +63 -0
- package/dist/session/mic.d.ts +64 -0
- package/dist/session/preconnect.d.ts +48 -0
- package/dist/session/reconnect.d.ts +25 -0
- package/dist/session/resume-store.d.ts +57 -0
- package/dist/session/state.d.ts +146 -0
- package/dist/session/ticket.d.ts +44 -0
- package/dist/session/types.d.ts +476 -0
- package/dist/session/url.d.ts +17 -0
- package/dist/session/user-turn.d.ts +55 -0
- package/dist/session-CE0Ipsb3.js +2129 -0
- package/dist/stored-value.d.ts +103 -0
- package/dist/tool-call-block-uXtMOUWN.js +204 -0
- package/dist/tool-config-context-Es4YUzV2.js +19 -0
- package/dist/types.d.ts +272 -34
- package/dist/types.js +35 -4
- package/dist/upload/files.d.ts +83 -0
- package/dist/upload/index.d.ts +15 -0
- package/dist/upload/pause.d.ts +31 -0
- package/dist/upload/recall.d.ts +67 -0
- package/dist/upload/report.d.ts +26 -0
- package/dist/upload/session.d.ts +99 -0
- package/dist/url-chips-oyy_Eiqh.js +239 -0
- package/dist/use-client-runs.d.ts +87 -0
- package/dist/use-conversation-log.d.ts +86 -0
- package/dist/use-conversation.d.ts +131 -0
- package/dist/use-copy.d.ts +74 -0
- package/dist/use-download-url.d.ts +84 -0
- package/dist/use-flash.d.ts +61 -0
- package/dist/use-inbox.d.ts +101 -0
- package/dist/use-push-to-talk.d.ts +105 -0
- package/dist/use-route-mutation.d.ts +113 -0
- package/dist/use-route.d.ts +82 -0
- package/dist/use-run-key.d.ts +133 -0
- package/dist/use-session-controls.d.ts +69 -0
- package/dist/use-session-id.d.ts +57 -0
- package/dist/use-tap-to-talk.d.ts +138 -0
- package/dist/use-user-transcript-uyHhzy4d.js +73 -0
- package/dist/use-user-transcript.d.ts +75 -0
- package/dist/use-workflow-form.d.ts +285 -0
- package/dist/use-workflow-progress.d.ts +137 -0
- package/dist/use-workflow-run-DdhWmbx-.js +697 -0
- package/dist/use-workflow-run.d.ts +100 -0
- package/dist/use-workflow-runs.d.ts +71 -0
- package/dist/use-workflow-stream.d.ts +154 -0
- package/dist/use-workflows.d.ts +77 -0
- package/dist/workflow-client.d.ts +136 -0
- package/dist/workflow-def-types.d.ts +31 -0
- package/dist/workflow-events.d.ts +39 -0
- package/dist/workflow-field-kind.d.ts +95 -0
- package/dist/workflow-status-labels.d.ts +35 -0
- package/dist/worklets/_module-url.d.ts +10 -0
- package/dist/worklets/_playback-bench-harness.d.ts +181 -0
- package/dist/worklets/_playback-bench-host.d.ts +63 -0
- package/dist/worklets/_playback-bench-page.d.ts +65 -0
- package/dist/worklets/_tts-trace-harness.d.ts +142 -0
- package/dist/worklets/_worklet-test-utils.d.ts +27 -0
- package/dist/worklets/capture-processor.d.ts +4 -2
- package/dist/worklets/capture-processor.js +73 -33
- package/dist/worklets/playback-processor.d.ts +4 -2
- package/dist/worklets/playback-processor.js +258 -42
- package/package.json +57 -32
- package/styles.css +152 -30
- package/dist/audio.d.ts +0 -45
- package/dist/audio.js +0 -121
- package/dist/client-context.d.ts +0 -33
- package/dist/client-context.js +0 -15
- package/dist/client-handler.d.ts +0 -43
- package/dist/components/app.d.ts +0 -23
- package/dist/components/app.js +0 -41
- package/dist/components/error-banner.d.ts +0 -21
- package/dist/components/error-banner.js +0 -27
- package/dist/components/message-bubble.d.ts +0 -23
- package/dist/components/message-bubble.js +0 -35
- package/dist/components/state-indicator.d.ts +0 -29
- package/dist/components/state-indicator.js +0 -37
- package/dist/components/thinking-indicator.d.ts +0 -16
- package/dist/components/thinking-indicator.js +0 -34
- package/dist/components/tool-icons.d.ts +0 -17
- package/dist/components/tool-icons.js +0 -128
- package/dist/components/transcript.d.ts +0 -25
- package/dist/components/transcript.js +0 -35
- package/dist/session-CWB7vmqz.js +0 -429
- package/dist/session.d.ts +0 -69
- package/dist/session.js +0 -2
- package/dist/signals.d.ts +0 -120
- package/dist/signals.js +0 -161
- package/dist/tsdown.config.d.ts +0 -2
- package/dist/types.test-d.d.ts +0 -7
package/dist/define-client.js
CHANGED
|
@@ -1,74 +1,220 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
1
|
+
import { t as ChatView } from "./chat-view-BCbI7gD4.js";
|
|
2
|
+
import { n as pageBaseUrl, r as setPageTitle } from "./_utils-Mi-SCFA1.js";
|
|
3
|
+
import { n as fetchClientConfig } from "./client-config-C7fQrioM.js";
|
|
4
|
+
import { t as createBrowserSession } from "./session-CE0Ipsb3.js";
|
|
5
|
+
import { SessionProvider, ThemeProvider } from "./context.js";
|
|
6
|
+
import { t as ToolConfigContext } from "./tool-config-context-Es4YUzV2.js";
|
|
7
|
+
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
8
|
+
import { StartScreen } from "./components/start-screen.js";
|
|
9
|
+
import { createElement, useEffect, useState } from "react";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
import { flushSync } from "react-dom";
|
|
12
|
+
import { createRoot } from "react-dom/client";
|
|
13
|
+
//#region src/define-client.tsx
|
|
14
|
+
/** @jsxImportSource react */
|
|
15
|
+
/**
|
|
16
|
+
* The element a mount renders into.
|
|
17
|
+
*
|
|
18
|
+
* Exported so `mountPage()` resolves its target the same way `mountClient()` does — the
|
|
19
|
+
* default selector and the "element not found" sentence are part of what an
|
|
20
|
+
* author has learned, and a second copy is how the two mounts come to disagree
|
|
21
|
+
* about which one they were given.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
8
25
|
function resolveContainer(target = "#app") {
|
|
9
26
|
if (typeof target !== "string") return target;
|
|
10
27
|
const el = document.querySelector(target);
|
|
11
|
-
if (!el) throw new Error(`Element not found: ${target}
|
|
28
|
+
if (!el) throw new Error(`Element not found: ${target} — no element matches that selector when the mount runs. Add \`<div id="app"></div>\` (or the element your selector names) to the page before the script, or pass the element itself as the mount's \`target\` option.`);
|
|
12
29
|
return el;
|
|
13
30
|
}
|
|
14
31
|
/**
|
|
32
|
+
* Render `node` into `container` and hand back its teardown.
|
|
33
|
+
*
|
|
34
|
+
* Shared by {@link mountClient} and `mountPage()` because the plumbing is identical and
|
|
35
|
+
* the two decisions in it are not obvious enough to be re-derived: the root is
|
|
36
|
+
* created here rather than by the caller so nothing else can hold one, and the
|
|
37
|
+
* render is `flushSync` so the mount is observable to the caller's NEXT
|
|
38
|
+
* STATEMENT (and to a test) rather than scheduled — `mountClient()` returns a handle
|
|
39
|
+
* whose session is expected to be live, and `mountPage()` returns one a caller may
|
|
40
|
+
* dispose immediately.
|
|
41
|
+
*
|
|
42
|
+
* `onDispose` runs after the unmount, which is the order `mountClient()` needs: the
|
|
43
|
+
* tree comes down before the session under it goes away.
|
|
44
|
+
*
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
function mountRoot(container, node, onDispose) {
|
|
48
|
+
const root = createRoot(container);
|
|
49
|
+
flushSync(() => {
|
|
50
|
+
root.render(node);
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
dispose() {
|
|
54
|
+
root.unmount();
|
|
55
|
+
onDispose?.();
|
|
56
|
+
},
|
|
57
|
+
[Symbol.dispose]() {
|
|
58
|
+
this.dispose();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Default shell rendered in config tier.
|
|
64
|
+
* Wraps StartScreen → (SidebarLayout →) ChatView.
|
|
65
|
+
*/
|
|
66
|
+
function DefaultShell({ name, icon, subtitle, buttonText, Sidebar, ...layout }) {
|
|
67
|
+
const chat = /* @__PURE__ */ jsx(ChatView, {
|
|
68
|
+
title: name,
|
|
69
|
+
icon
|
|
70
|
+
});
|
|
71
|
+
return /* @__PURE__ */ jsx(StartScreen, {
|
|
72
|
+
title: name,
|
|
73
|
+
icon,
|
|
74
|
+
subtitle,
|
|
75
|
+
buttonText,
|
|
76
|
+
children: Sidebar ? /* @__PURE__ */ jsx(SidebarLayout, {
|
|
77
|
+
sidebar: /* @__PURE__ */ jsx(Sidebar, {}),
|
|
78
|
+
sidebarWidth: layout.sidebarWidth,
|
|
79
|
+
sidebarPosition: layout.sidebarPosition,
|
|
80
|
+
children: chat
|
|
81
|
+
}) : chat
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Config-tier root: fetches the server-declared display name via
|
|
86
|
+
* `GET client-config` and renders the chat shell. The shell renders
|
|
87
|
+
* immediately — optimistically — while the lookup is in flight; servers
|
|
88
|
+
* without the endpoint (every lookup failure resolves to the empty default)
|
|
89
|
+
* work exactly as before.
|
|
90
|
+
*
|
|
91
|
+
* **The lookup is SKIPPED when the caller already named the agent.** The
|
|
92
|
+
* response's only consumer here is the fallback below, so with an explicit
|
|
93
|
+
* `mountClient({ name })` the request was issued and its answer thrown away — and on
|
|
94
|
+
* the platform this endpoint is the BROKER, so the discarded request is one that
|
|
95
|
+
* can boot a sandbox. The session's own per-attempt lookup
|
|
96
|
+
* (`session/browser-session.ts`'s URL provider) is a different question and deliberately
|
|
97
|
+
* left alone: it re-brokers on every connection attempt, which is what makes a
|
|
98
|
+
* reconnect land on a REPLACEMENT sandbox, so it may not be served from
|
|
99
|
+
* anything this render already has.
|
|
100
|
+
*/
|
|
101
|
+
function DefaultRoot({ platformUrl, ...display }) {
|
|
102
|
+
const { name } = display;
|
|
103
|
+
const [resolved, setResolved] = useState(null);
|
|
104
|
+
const needsLookup = name === void 0;
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!needsLookup) return;
|
|
107
|
+
let cancelled = false;
|
|
108
|
+
fetchClientConfig(platformUrl).then((cfg) => {
|
|
109
|
+
if (!cancelled) setResolved(cfg);
|
|
110
|
+
});
|
|
111
|
+
return () => {
|
|
112
|
+
cancelled = true;
|
|
113
|
+
};
|
|
114
|
+
}, [platformUrl, needsLookup]);
|
|
115
|
+
return /* @__PURE__ */ jsx(DefaultShell, {
|
|
116
|
+
...display,
|
|
117
|
+
name: name ?? resolved?.name
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The tree under the providers: the caller's component, or the default shell.
|
|
122
|
+
*
|
|
123
|
+
* A custom component owns the whole page, so there is no header to hang a
|
|
124
|
+
* `sidebar` off — but the layout the default shell uses is right here, and
|
|
125
|
+
* `mountClient({ component, sidebar })` names one pane and one aside, which is
|
|
126
|
+
* exactly what it renders. Honouring the combination rather than ignoring it is
|
|
127
|
+
* the same call this file already made for `name` and `tools`.
|
|
128
|
+
*/
|
|
129
|
+
function rootFor(config, platformUrl) {
|
|
130
|
+
const Custom = config.component;
|
|
131
|
+
const Sidebar = config.sidebar;
|
|
132
|
+
if (!Custom) return /* @__PURE__ */ jsx(DefaultRoot, {
|
|
133
|
+
platformUrl,
|
|
134
|
+
name: config.name,
|
|
135
|
+
icon: config.icon,
|
|
136
|
+
subtitle: config.subtitle,
|
|
137
|
+
buttonText: config.buttonText,
|
|
138
|
+
Sidebar,
|
|
139
|
+
sidebarWidth: config.sidebarWidth,
|
|
140
|
+
sidebarPosition: config.sidebarPosition
|
|
141
|
+
});
|
|
142
|
+
if (!Sidebar) return /* @__PURE__ */ jsx(Custom, {});
|
|
143
|
+
return /* @__PURE__ */ jsx(SidebarLayout, {
|
|
144
|
+
sidebar: /* @__PURE__ */ jsx(Sidebar, {}),
|
|
145
|
+
sidebarWidth: config.sidebarWidth,
|
|
146
|
+
sidebarPosition: config.sidebarPosition,
|
|
147
|
+
children: /* @__PURE__ */ jsx(Custom, {})
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
15
151
|
* Define and mount a client UI for a voice agent.
|
|
16
152
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
153
|
+
* **Config only:** leave `component` out and the default shell renders
|
|
154
|
+
* (StartScreen + ChatView, optional sidebar).
|
|
155
|
+
*
|
|
156
|
+
* **A custom component:** pass `component` and it is rendered inside the same
|
|
157
|
+
* providers instead of the default shell — beside a `sidebar` if one is given,
|
|
158
|
+
* in the same {@link SidebarLayout}. A provided `name` then also sets
|
|
159
|
+
* `document.title`, there being no shell header to show it in.
|
|
160
|
+
*
|
|
161
|
+
* Mounts into `target` — a CSS selector or DOM element, defaulting to
|
|
162
|
+
* `"#app"` — and throws `Element not found: <target>` when the selector
|
|
163
|
+
* matches nothing.
|
|
164
|
+
*
|
|
165
|
+
* @example The default shell
|
|
166
|
+
* ```tsx
|
|
167
|
+
* import { mountClient } from "@alexkroman1/aai-ui";
|
|
168
|
+
*
|
|
169
|
+
* function OrderPanel() {
|
|
170
|
+
* return <div>Cart</div>;
|
|
171
|
+
* }
|
|
172
|
+
*
|
|
173
|
+
* mountClient({
|
|
174
|
+
* name: "Pizza Ordering",
|
|
175
|
+
* theme: { bg: "#1a1a1a", primary: "#e55" },
|
|
176
|
+
* sidebar: OrderPanel,
|
|
177
|
+
* tools: { add_pizza: { icon: "🍕", label: "Adding pizza" } },
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*
|
|
181
|
+
* @example A custom component
|
|
182
|
+
* ```tsx
|
|
183
|
+
* import { mountClient, useSession } from "@alexkroman1/aai-ui";
|
|
184
|
+
*
|
|
185
|
+
* function MyCustomApp() {
|
|
186
|
+
* const session = useSession();
|
|
187
|
+
* return <div>{session.state}</div>;
|
|
188
|
+
* }
|
|
189
|
+
*
|
|
190
|
+
* mountClient({ component: MyCustomApp });
|
|
191
|
+
* ```
|
|
20
192
|
*
|
|
21
|
-
* @param Component - The Preact component to render.
|
|
22
|
-
* @param options - Client options (target element, platform URL, theme).
|
|
23
193
|
* @returns A {@link ClientHandle} for cleanup.
|
|
24
194
|
* @throws If the target element is not found in the DOM.
|
|
25
195
|
*
|
|
26
196
|
* @public
|
|
27
197
|
*/
|
|
28
|
-
function
|
|
29
|
-
const container = resolveContainer(
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
198
|
+
function mountClient(config) {
|
|
199
|
+
const container = resolveContainer(config.target);
|
|
200
|
+
const platformUrl = config.platformUrl ?? pageBaseUrl();
|
|
201
|
+
const session = createBrowserSession({
|
|
202
|
+
platformUrl,
|
|
203
|
+
onSessionId: config.onSessionId,
|
|
204
|
+
resumeSessionId: config.resumeSessionId,
|
|
205
|
+
location: config.location,
|
|
206
|
+
phone: config.phone,
|
|
207
|
+
client: config.client,
|
|
208
|
+
token: config.token,
|
|
209
|
+
WebSocket: config.WebSocket
|
|
37
210
|
});
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
if (options?.theme) {
|
|
44
|
-
const t = options.theme;
|
|
45
|
-
const el = container;
|
|
46
|
-
if (t.bg) el.style.setProperty("--color-aai-bg", t.bg);
|
|
47
|
-
if (t.primary) el.style.setProperty("--color-aai-primary", t.primary);
|
|
48
|
-
if (t.text) el.style.setProperty("--color-aai-text", t.text);
|
|
49
|
-
if (t.surface) el.style.setProperty("--color-aai-surface", t.surface);
|
|
50
|
-
if (t.border) el.style.setProperty("--color-aai-border", t.border);
|
|
51
|
-
}
|
|
52
|
-
render(/* @__PURE__ */ jsx(ClientConfigProvider, {
|
|
53
|
-
value: clientConfig,
|
|
54
|
-
children: /* @__PURE__ */ jsx(SessionProvider, {
|
|
55
|
-
value: signals,
|
|
56
|
-
children: /* @__PURE__ */ jsx(Component, {})
|
|
57
|
-
})
|
|
58
|
-
}), container);
|
|
59
|
-
const handle = {
|
|
211
|
+
setPageTitle(config.name);
|
|
212
|
+
const rootNode = rootFor(config, platformUrl);
|
|
213
|
+
const toolConfig = config.tools ?? {};
|
|
214
|
+
return {
|
|
60
215
|
session,
|
|
61
|
-
|
|
62
|
-
dispose() {
|
|
63
|
-
render(null, container);
|
|
64
|
-
signals.dispose();
|
|
65
|
-
session.disconnect();
|
|
66
|
-
},
|
|
67
|
-
[Symbol.dispose]() {
|
|
68
|
-
handle.dispose();
|
|
69
|
-
}
|
|
216
|
+
...mountRoot(container, createElement(ToolConfigContext.Provider, { value: toolConfig }, createElement(ThemeProvider, { value: config.theme }, createElement(SessionProvider, { value: session }, rootNode))), () => session[Symbol.dispose]())
|
|
70
217
|
};
|
|
71
|
-
return handle;
|
|
72
218
|
}
|
|
73
219
|
//#endregion
|
|
74
|
-
export {
|
|
220
|
+
export { mountClient, mountRoot, resolveContainer };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useTheme } from "./context.js";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/eyebrow.tsx
|
|
5
|
+
/** @jsxImportSource react */
|
|
6
|
+
/**
|
|
7
|
+
* Eyebrow label — the design system's small outlined pill with ALL-CAPS,
|
|
8
|
+
* tracked text ("VOICE AGENT", "LISTENING", …). Used as a section label on
|
|
9
|
+
* the start screen and as the live status chip in the chat header.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
function Eyebrow({ children, className, style, ...rest }) {
|
|
14
|
+
const theme = useTheme();
|
|
15
|
+
return /* @__PURE__ */ jsx("span", {
|
|
16
|
+
className: clsx("inline-flex items-center gap-1.5 px-2 py-1 rounded-aai border leading-none", "font-aai text-[10px] font-medium tracking-[1.2px] uppercase", className),
|
|
17
|
+
style: {
|
|
18
|
+
borderColor: theme.border,
|
|
19
|
+
color: theme.text,
|
|
20
|
+
...style
|
|
21
|
+
},
|
|
22
|
+
...rest,
|
|
23
|
+
children
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { Eyebrow as t };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { a as tryParseJSON } from "./_utils-Mi-SCFA1.js";
|
|
2
|
+
import { useSessionSelector } from "./context.js";
|
|
3
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
4
|
+
//#region src/agent-state.ts
|
|
5
|
+
/** One stable selector per slot name — see {@link selectAgentState}. */
|
|
6
|
+
const selectors = /* @__PURE__ */ new Map();
|
|
7
|
+
/** The whole frame — module scope, so its identity is stable. */
|
|
8
|
+
const selectFrame = (snapshot) => snapshot.agentState;
|
|
9
|
+
/**
|
|
10
|
+
* A `useSessionSelector` selector for ONE slot of the agent's projected state:
|
|
11
|
+
* its value, or `undefined` before the agent has pushed it.
|
|
12
|
+
*
|
|
13
|
+
* The same function for the same name on every call, which is load-bearing:
|
|
14
|
+
* `useSessionSelector` caches its selection on the selector's identity, and an
|
|
15
|
+
* inline arrow would re-run it on every snapshot.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* import { selectAgentState, useSessionSelector } from "@alexkroman1/aai-ui";
|
|
19
|
+
*
|
|
20
|
+
* function CartBadge() {
|
|
21
|
+
* // Re-renders when the `cart` slot changes, and on nothing else.
|
|
22
|
+
* const cart = useSessionSelector(selectAgentState<{ count: number }>("cart"));
|
|
23
|
+
* return <span>{cart?.count ?? 0}</span>;
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
function selectAgentState(slot) {
|
|
30
|
+
let selector = selectors.get(slot);
|
|
31
|
+
if (selector === void 0) {
|
|
32
|
+
selector = (snapshot) => snapshot.agentState?.[slot];
|
|
33
|
+
selectors.set(slot, selector);
|
|
34
|
+
}
|
|
35
|
+
return selector;
|
|
36
|
+
}
|
|
37
|
+
function useAgentState(source, fallback) {
|
|
38
|
+
const projection = typeof source === "function" ? source : void 0;
|
|
39
|
+
const slot = projection?.key ?? (typeof source === "string" ? source : void 0);
|
|
40
|
+
const selected = useSessionSelector(slot === void 0 ? selectFrame : selectAgentState(slot));
|
|
41
|
+
const empty = useMemo(() => projection?.(), [projection]);
|
|
42
|
+
if (slot === void 0) return selected ?? null;
|
|
43
|
+
if (selected !== void 0) return selected;
|
|
44
|
+
if (projection !== void 0) return empty;
|
|
45
|
+
return fallback === void 0 ? null : fallback;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/hooks.ts
|
|
49
|
+
/** Index of the first item whose sequence number is above the watermark (tail scan from the end). */
|
|
50
|
+
function tailStart(items, seqOf, watermark) {
|
|
51
|
+
let start = items.length;
|
|
52
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
53
|
+
const item = items[i];
|
|
54
|
+
if (!item || seqOf(item) <= watermark) break;
|
|
55
|
+
start = i;
|
|
56
|
+
}
|
|
57
|
+
return start;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Process the unprocessed tail of `toolCalls`: fire `onNew` once per item that
|
|
61
|
+
* has settled (per `isSettled`), then advance the watermark past the leading
|
|
62
|
+
* run of settled items. Resets the cursor when the list is empty (session
|
|
63
|
+
* reset), matching the previous seen-set behavior.
|
|
64
|
+
*/
|
|
65
|
+
function processToolCallTail(toolCalls, cursor, isSettled, onNew) {
|
|
66
|
+
if (toolCalls.length === 0) {
|
|
67
|
+
cursor.seq = 0;
|
|
68
|
+
cursor.fired.clear();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const start = tailStart(toolCalls, (tc) => tc.seq, cursor.seq);
|
|
72
|
+
for (let i = start; i < toolCalls.length; i++) {
|
|
73
|
+
const tc = toolCalls[i];
|
|
74
|
+
if (!(tc && isSettled(tc)) || cursor.fired.has(tc.callId)) continue;
|
|
75
|
+
cursor.fired.add(tc.callId);
|
|
76
|
+
onNew(tc);
|
|
77
|
+
}
|
|
78
|
+
for (let i = start; i < toolCalls.length; i++) {
|
|
79
|
+
const tc = toolCalls[i];
|
|
80
|
+
if (!(tc && isSettled(tc))) break;
|
|
81
|
+
cursor.fired.delete(tc.callId);
|
|
82
|
+
cursor.seq = tc.seq;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The two `fire` implementations, at module scope so they are stable across
|
|
87
|
+
* renders — which is what lets `useToolCallEffect` name `fire` as a plain
|
|
88
|
+
* dependency instead of holding it in a ref.
|
|
89
|
+
*/
|
|
90
|
+
const fireResult = (callback, tc, filtered) => {
|
|
91
|
+
const parsed = tryParseJSON(tc.result);
|
|
92
|
+
if (filtered) callback(parsed, tc);
|
|
93
|
+
else callback(tc.name, parsed, tc);
|
|
94
|
+
};
|
|
95
|
+
const fireStart = (callback, tc) => {
|
|
96
|
+
callback(tc);
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Shared scaffold for the tool-call lifecycle hooks: parses the optional
|
|
100
|
+
* `(toolName, callback)` / `(callback)` overload args, dedups by call ID,
|
|
101
|
+
* and invokes `fire` once per tool call reaching `status`.
|
|
102
|
+
*/
|
|
103
|
+
function useToolCallEffect(status, args, fire) {
|
|
104
|
+
const first = args[0];
|
|
105
|
+
const filterName = typeof first === "string" ? first : null;
|
|
106
|
+
const callback = filterName === null ? first : args[1];
|
|
107
|
+
const toolCalls = useSessionSelector((s) => s.toolCalls);
|
|
108
|
+
const cursorRef = useRef({
|
|
109
|
+
seq: 0,
|
|
110
|
+
fired: /* @__PURE__ */ new Set()
|
|
111
|
+
});
|
|
112
|
+
const mountedRef = useRef(false);
|
|
113
|
+
const callbackRef = useRef(callback);
|
|
114
|
+
callbackRef.current = callback;
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
const firstRun = !mountedRef.current;
|
|
117
|
+
mountedRef.current = true;
|
|
118
|
+
processToolCallTail(toolCalls, cursorRef.current, (tc) => status === "pending" || tc.status === status, (tc) => {
|
|
119
|
+
if (tc.status !== status && firstRun) return;
|
|
120
|
+
if (filterName && tc.name !== filterName) return;
|
|
121
|
+
fire(callbackRef.current, tc, filterName !== null);
|
|
122
|
+
});
|
|
123
|
+
}, [
|
|
124
|
+
toolCalls,
|
|
125
|
+
filterName,
|
|
126
|
+
status,
|
|
127
|
+
fire
|
|
128
|
+
]);
|
|
129
|
+
}
|
|
130
|
+
function useToolResult(...args) {
|
|
131
|
+
useToolCallEffect("done", args, fireResult);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Subscribe to custom events emitted by agent tools via
|
|
135
|
+
* `ctx.send(event, data)`; the callback receives each event's `data`.
|
|
136
|
+
*
|
|
137
|
+
* This is the preferred way to drive UI from tools — an explicit event beats
|
|
138
|
+
* inferring state from tool results with {@link useToolResult}.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```tsx
|
|
142
|
+
* import { useEvent } from "@alexkroman1/aai-ui";
|
|
143
|
+
* import { useState } from "react";
|
|
144
|
+
*
|
|
145
|
+
* type Item = { sku: string; qty: number };
|
|
146
|
+
*
|
|
147
|
+
* function Cart() {
|
|
148
|
+
* const [cart, setCart] = useState<Item[]>([]);
|
|
149
|
+
* // Tool: ctx.send("item_added", { sku, qty })
|
|
150
|
+
* useEvent<Item>("item_added", (data) => {
|
|
151
|
+
* setCart((cart) => [...cart, data]);
|
|
152
|
+
* });
|
|
153
|
+
* return <div>{cart.length} items</div>;
|
|
154
|
+
* }
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @public
|
|
158
|
+
*/
|
|
159
|
+
function useEvent(event, callback) {
|
|
160
|
+
const customEvents = useSessionSelector((s) => s.customEvents);
|
|
161
|
+
const watermarkRef = useRef(0);
|
|
162
|
+
const callbackRef = useRef(callback);
|
|
163
|
+
callbackRef.current = callback;
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (customEvents.length === 0) {
|
|
166
|
+
watermarkRef.current = 0;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const start = tailStart(customEvents, (ce) => ce.id, watermarkRef.current);
|
|
170
|
+
for (let i = start; i < customEvents.length; i++) {
|
|
171
|
+
const ce = customEvents[i];
|
|
172
|
+
if (!ce) continue;
|
|
173
|
+
watermarkRef.current = ce.id;
|
|
174
|
+
if (ce.event === event) callbackRef.current(ce.data);
|
|
175
|
+
}
|
|
176
|
+
}, [customEvents, event]);
|
|
177
|
+
}
|
|
178
|
+
function useToolCallStart(...args) {
|
|
179
|
+
useToolCallEffect("pending", args, fireStart);
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
export { useAgentState as a, selectAgentState as i, useToolCallStart as n, useToolResult as r, useEvent as t };
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { ToolCallInfo } from "./types.ts";
|
|
2
|
+
export { selectAgentState, useAgentState } from "./agent-state.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Fire a callback when ONE named tool settles, with its parsed JSON result.
|
|
5
|
+
*
|
|
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
|
+
* A component that mounts late still receives the results of calls that
|
|
10
|
+
* already completed, because a result is a value the UI is driven from rather
|
|
11
|
+
* than a moment. Each call fires exactly once per hook instance.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { useState } from "react";
|
|
16
|
+
* import { useToolResult } from "@alexkroman1/aai-ui";
|
|
17
|
+
*
|
|
18
|
+
* type Quote = { symbol: string; price: number };
|
|
19
|
+
*
|
|
20
|
+
* function QuoteCard() {
|
|
21
|
+
* const [quote, setQuote] = useState<Quote>();
|
|
22
|
+
* useToolResult<Quote>("get_quote", (result) => setQuote(result));
|
|
23
|
+
* return quote ? <p>{quote.symbol}: {quote.price}</p> : null;
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @typeParam R - The result shape. Defaults to `unknown`, NOT to
|
|
28
|
+
* `DefaultToolResult` (`any`): the return type is inferred perfectly
|
|
29
|
+
* at `tool()` and this hook is the one place a client reads it, so an `any`
|
|
30
|
+
* default threw the whole inference away exactly where it was wanted —
|
|
31
|
+
* `useToolResult("get_order", (r) => r.a.b.c.d.e)` reported nothing. It is
|
|
32
|
+
* the tool's own shape that belongs here, and the spelling that costs a
|
|
33
|
+
* browser bundle nothing is a TYPE-ONLY import of the tool module:
|
|
34
|
+
* `import type getOrder from "./tools/get_order.ts"` is erased, so
|
|
35
|
+
* `useToolResult<InferToolOutput<typeof getOrder>>(…)` pulls no host code
|
|
36
|
+
* into the client graph. `useToolResult<Quote>(…)` against a hand-written
|
|
37
|
+
* shape is the other spelling. `DefaultToolResult` itself stays `any`
|
|
38
|
+
* — see `ToolCallInfo.args` for why a value the framework cannot see is
|
|
39
|
+
* typed that way at REST; the argument does not extend to a call site whose
|
|
40
|
+
* whole job is to name the shape.
|
|
41
|
+
* @param toolName - Only calls of this tool fire the callback.
|
|
42
|
+
* @param callback - Called with the parsed result and the call itself.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
export declare function useToolResult<R = unknown>(toolName: string, callback: (result: R, toolCall: ToolCallInfo) => void): void;
|
|
47
|
+
/**
|
|
48
|
+
* Fire a callback when ANY tool call settles — the tool's name is the
|
|
49
|
+
* callback's first argument.
|
|
50
|
+
*
|
|
51
|
+
* The unfiltered form, for a chrome rendering a log of everything the agent
|
|
52
|
+
* did rather than reacting to one tool.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* import { useState } from "react";
|
|
57
|
+
* import { useToolResult } from "@alexkroman1/aai-ui";
|
|
58
|
+
*
|
|
59
|
+
* function ToolLog() {
|
|
60
|
+
* const [lines, setLines] = useState<string[]>([]);
|
|
61
|
+
* useToolResult((name, result) => {
|
|
62
|
+
* setLines((prev) => [...prev, `${name}: ${JSON.stringify(result)}`]);
|
|
63
|
+
* });
|
|
64
|
+
* return <pre>{lines.join("\n")}</pre>;
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @typeParam R - The result shape. Defaults to `unknown`, for the reason the
|
|
69
|
+
* filtered overload's `@typeParam` gives. A log renderer is the one caller
|
|
70
|
+
* that legitimately wants no shape, and `unknown` is what it should say:
|
|
71
|
+
* `JSON.stringify(result)` takes it unchanged.
|
|
72
|
+
* @param callback - Called with the tool's name, the parsed result, and the
|
|
73
|
+
* call itself.
|
|
74
|
+
*
|
|
75
|
+
* @public
|
|
76
|
+
*/
|
|
77
|
+
export declare function useToolResult<R = unknown>(callback: (name: string, result: R, toolCall: ToolCallInfo) => void): void;
|
|
78
|
+
/**
|
|
79
|
+
* Subscribe to custom events emitted by agent tools via
|
|
80
|
+
* `ctx.send(event, data)`; the callback receives each event's `data`.
|
|
81
|
+
*
|
|
82
|
+
* This is the preferred way to drive UI from tools — an explicit event beats
|
|
83
|
+
* inferring state from tool results with {@link useToolResult}.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* import { useEvent } from "@alexkroman1/aai-ui";
|
|
88
|
+
* import { useState } from "react";
|
|
89
|
+
*
|
|
90
|
+
* type Item = { sku: string; qty: number };
|
|
91
|
+
*
|
|
92
|
+
* function Cart() {
|
|
93
|
+
* const [cart, setCart] = useState<Item[]>([]);
|
|
94
|
+
* // Tool: ctx.send("item_added", { sku, qty })
|
|
95
|
+
* useEvent<Item>("item_added", (data) => {
|
|
96
|
+
* setCart((cart) => [...cart, data]);
|
|
97
|
+
* });
|
|
98
|
+
* return <div>{cart.length} items</div>;
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export declare function useEvent<T = unknown>(event: string, callback: (data: T) => void): void;
|
|
105
|
+
/**
|
|
106
|
+
* Fire a callback when ONE named tool starts, before its result arrives.
|
|
107
|
+
*
|
|
108
|
+
* A start is a MOMENT rather than a value, so unlike {@link useToolResult}
|
|
109
|
+
* this never replays: a component that mounts mid-session learns nothing about
|
|
110
|
+
* calls that started before it.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```tsx
|
|
114
|
+
* import { useState } from "react";
|
|
115
|
+
* import { useToolCallStart } from "@alexkroman1/aai-ui";
|
|
116
|
+
*
|
|
117
|
+
* function Searching() {
|
|
118
|
+
* const [busy, setBusy] = useState(false);
|
|
119
|
+
* useToolCallStart("search_catalog", () => setBusy(true));
|
|
120
|
+
* return busy ? <p>Searching the catalog…</p> : null;
|
|
121
|
+
* }
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* @typeParam A - The tool's ARGUMENT shape. Defaults to
|
|
125
|
+
* `ToolCallInfo["args"]`, which is `Record<string, any>` — so an
|
|
126
|
+
* un-parameterized call behaves exactly as it always has, and
|
|
127
|
+
* `toolCall.args.totally_made_up_field` still compiles. That default is a
|
|
128
|
+
* property of {@link ToolCallInfo} rather than a choice made here (its doc
|
|
129
|
+
* carries the argument, and the escape hatch it recommends —
|
|
130
|
+
* `args as { url: string }` — is what this type parameter replaces); until
|
|
131
|
+
* that field is tightened there is nothing stricter for this hook to fall
|
|
132
|
+
* back to. What was missing was any way to opt IN: there was no type
|
|
133
|
+
* parameter at all, so a custom client could not check args even when it
|
|
134
|
+
* knew the shape. Name it — `useToolCallStart<{ query: string }>(…)` — or
|
|
135
|
+
* derive it from the tool with a TYPE-ONLY import, which is erased and so
|
|
136
|
+
* pulls no host code into the browser graph:
|
|
137
|
+
* `useToolCallStart<InferToolInput<typeof search>>("search", …)`.
|
|
138
|
+
* @param toolName - Only calls of this tool fire the callback.
|
|
139
|
+
* @param callback - Called with the pending call.
|
|
140
|
+
*
|
|
141
|
+
* @public
|
|
142
|
+
*/
|
|
143
|
+
export declare function useToolCallStart<A = ToolCallInfo["args"]>(toolName: string, callback: (toolCall: Omit<ToolCallInfo, "args"> & {
|
|
144
|
+
args: A;
|
|
145
|
+
}) => void): void;
|
|
146
|
+
/**
|
|
147
|
+
* Fire a callback when ANY tool call starts — read the tool's name off the
|
|
148
|
+
* call itself (`toolCall.name`).
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```tsx
|
|
152
|
+
* import { useState } from "react";
|
|
153
|
+
* import { useToolCallStart } from "@alexkroman1/aai-ui";
|
|
154
|
+
*
|
|
155
|
+
* function Activity() {
|
|
156
|
+
* const [now, setNow] = useState<string>();
|
|
157
|
+
* useToolCallStart((toolCall) => setNow(toolCall.name));
|
|
158
|
+
* return now ? <p>Running {now}…</p> : null;
|
|
159
|
+
* }
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @typeParam A - The tool's ARGUMENT shape; see the filtered overload. On the
|
|
163
|
+
* unfiltered form every tool's call arrives, so naming one shape here is
|
|
164
|
+
* only right for a page that switches on `toolCall.name` and narrows it
|
|
165
|
+
* itself — the default is the honest answer for a log renderer.
|
|
166
|
+
* @param callback - Called with the pending call.
|
|
167
|
+
*
|
|
168
|
+
* @public
|
|
169
|
+
*/
|
|
170
|
+
export declare function useToolCallStart<A = ToolCallInfo["args"]>(callback: (toolCall: Omit<ToolCallInfo, "args"> & {
|
|
171
|
+
args: A;
|
|
172
|
+
}) => void): void;
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-level contract for the four `aai-ui` hooks a custom client is written
|
|
3
|
+
* against. All four are generic, all four are typed BY THE CALLER, and every
|
|
4
|
+
* one of them was unpinned — the root guide claimed `aai-ui` (`.`) had
|
|
5
|
+
* type-level coverage and no `.test-d.ts` existed in this package at all.
|
|
6
|
+
*
|
|
7
|
+
* The reason these need a type test rather than a runtime one: nothing here
|
|
8
|
+
* has runtime behaviour to observe. `useAgentState` is one `useSessionSelector`
|
|
9
|
+
* call over a per-slot selector, and `useToolResult`'s two overloads erase to the same
|
|
10
|
+
* `(...args: unknown[])` implementation. What a consumer actually depends on
|
|
11
|
+
* is the SIGNATURE, and a signature is exactly what a runtime suite cannot
|
|
12
|
+
* assert.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|