@alexkroman1/aai-ui 13.2.0 → 14.0.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 +159 -69
- package/dist/{_colors-j8XMToi9.js → _colors-CpZO-88A.js} +25 -2
- package/dist/{_module-url-C_4gRVL0.js → _module-url-C13kAJ87.js} +1 -1
- package/dist/_recover-run.d.ts +13 -7
- package/dist/_submission-state.d.ts +92 -0
- package/dist/_upload-files.d.ts +2 -2
- package/dist/_upload-report.d.ts +26 -0
- package/dist/{_utils-B6498_bm.js → _utils-DnQDM9Uy.js} +4 -4
- package/dist/_utils.d.ts +3 -3
- package/dist/_web-storage.d.ts +43 -0
- package/dist/_workflow-files.d.ts +1 -1
- package/dist/{aai-logo-CXZGPSIY.js → aai-logo-CFlomZlS.js} +1 -1
- package/dist/agent-state-labels.d.ts +60 -0
- package/dist/audio.js +21 -15
- package/dist/{chat-view-DDTtrh7N.js → chat-view-C_3T7Ln8.js} +100 -33
- package/dist/{client-config-BT_kWID5.js → client-config-DJQHnYjm.js} +5 -5
- package/dist/client-config.d.ts +4 -4
- package/dist/client-dir.d.ts +1 -1
- package/dist/client-dir.js +2 -2
- package/dist/components/_colors.d.ts +23 -0
- package/dist/components/_form-readiness.d.ts +1 -1
- package/dist/components/bullet-list.d.ts +74 -0
- package/dist/components/button.js +4 -4
- package/dist/components/chat-view.js +1 -1
- package/dist/components/console-shell.d.ts +16 -20
- package/dist/components/controls.js +4 -4
- package/dist/components/facts.d.ts +81 -0
- package/dist/components/form-fields.d.ts +6 -6
- package/dist/components/form-types.d.ts +1 -1
- package/dist/components/form.d.ts +1 -1
- package/dist/components/message-list.js +1 -1
- package/dist/components/session-error-banner.d.ts +69 -0
- package/dist/components/sidebar-layout.js +1 -1
- package/dist/components/start-screen.js +4 -4
- package/dist/components/tool-call-block.js +1 -1
- package/dist/components/tool-config-context.d.ts +1 -1
- package/dist/components/workflow-progress.d.ts +11 -4
- package/dist/context.d.ts +142 -19
- package/dist/context.js +156 -18
- package/dist/default-client/assets/{audio-BuDICbPf.js → audio-9zQsNc1w.js} +1 -1
- package/dist/default-client/assets/index-BTv30Z4F.css +2 -0
- package/dist/default-client/assets/index-RAZ-29Sz.js +284 -0
- package/dist/default-client/index.html +2 -2
- package/dist/default-client.d.ts +1 -1
- package/dist/define-client.d.ts +19 -19
- package/dist/define-client.js +20 -20
- package/dist/{eyebrow-C6ZFuiz6.js → eyebrow-UfmSz9yy.js} +1 -1
- package/dist/hooks.d.ts +44 -8
- package/dist/hooks.js +20 -14
- package/dist/index.d.ts +13 -8
- package/dist/index.js +1447 -1160
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +5 -5
- package/dist/{message-list-BJYyuIcR.js → message-list-CdOnSh5m.js} +23 -16
- package/dist/page.d.ts +11 -11
- package/dist/session-core-audio-setup.d.ts +1 -1
- package/dist/session-core-dial.d.ts +0 -2
- package/dist/{session-core-DxBYsfHA.js → session-core-gwePM95B.js} +135 -62
- package/dist/session-core-messages.d.ts +2 -2
- package/dist/session-core-types.d.ts +58 -1
- package/dist/session-core.d.ts +6 -6
- package/dist/session-core.js +2 -2
- package/dist/session-resume-store.d.ts +3 -3
- package/dist/{tool-call-block-tcPQAkcP.js → tool-call-block-C2t_5fpp.js} +30 -12
- package/dist/{tool-config-context-DzAofqi_.js → tool-config-context-Es4YUzV2.js} +2 -2
- package/dist/types.d.ts +19 -4
- package/dist/types.js +3 -3
- package/dist/{url-chips-YqhCjWfQ.js → url-chips-BxhzZgk2.js} +5 -5
- package/dist/use-conversation.d.ts +1 -1
- package/dist/use-run-key.d.ts +44 -10
- package/dist/{use-user-transcript-C14qWFu2.js → use-user-transcript-uyHhzy4d.js} +4 -3
- package/dist/use-workflow-form.d.ts +64 -91
- package/dist/{use-workflow-progress-Cu0SxMyg.js → use-workflow-run-CP2ekKPV.js} +254 -257
- package/dist/use-workflow-stream.d.ts +5 -2
- package/dist/use-workflows.d.ts +77 -0
- package/dist/workflow-client.d.ts +1 -1
- package/dist/worklets/capture-processor.js +2 -2
- package/dist/worklets/playback-processor.js +2 -2
- package/package.json +6 -6
- package/styles.css +78 -0
- package/dist/default-client/assets/index-B1_ROnTJ.js +0 -284
- package/dist/default-client/assets/index-S5fkKi6B.css +0 -2
- package/dist/tsdown.config.d.ts +0 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useSessionCore, useSessionSelector } from "../context.js";
|
|
2
2
|
import { Button } from "./button.js";
|
|
3
|
-
import { n as SessionUrlChips } from "../url-chips-
|
|
3
|
+
import { n as SessionUrlChips } from "../url-chips-BxhzZgk2.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { memo } from "react";
|
|
7
|
-
//#region components/controls.tsx
|
|
7
|
+
//#region src/components/controls.tsx
|
|
8
8
|
/** @jsxImportSource react */
|
|
9
9
|
/**
|
|
10
10
|
* Session control buttons: **Stop / Resume** and **New Conversation**.
|
|
@@ -27,7 +27,7 @@ import { memo } from "react";
|
|
|
27
27
|
*/
|
|
28
28
|
const Controls = memo(function Controls({ className }) {
|
|
29
29
|
const running = useSessionSelector((s) => s.running);
|
|
30
|
-
const { toggle,
|
|
30
|
+
const { toggle, restart } = useSessionCore();
|
|
31
31
|
return /* @__PURE__ */ jsxs("div", {
|
|
32
32
|
className: clsx("flex flex-wrap items-center gap-3 shrink-0", className),
|
|
33
33
|
children: [
|
|
@@ -38,7 +38,7 @@ const Controls = memo(function Controls({ className }) {
|
|
|
38
38
|
}),
|
|
39
39
|
/* @__PURE__ */ jsx(Button, {
|
|
40
40
|
variant: "ghost",
|
|
41
|
-
onClick:
|
|
41
|
+
onClick: restart,
|
|
42
42
|
children: "New Conversation"
|
|
43
43
|
}),
|
|
44
44
|
/* @__PURE__ */ jsx(SessionUrlChips, { className: "basis-full sm:basis-auto sm:ml-auto sm:max-w-[60%]" })
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props for {@link Facts}.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export type FactsProps = {
|
|
8
|
+
/**
|
|
9
|
+
* The facts, in reading order. Anything `false`, `null`, `undefined` or the
|
|
10
|
+
* empty string is DROPPED, so a page writes `cond && \`${n} skipped\`` inline
|
|
11
|
+
* instead of splicing a separator into a conditional string.
|
|
12
|
+
*
|
|
13
|
+
* `0` is NOT dropped — it is a fact ("0 words"), and treating it as absent is
|
|
14
|
+
* the bug a plain truthiness filter would ship.
|
|
15
|
+
*
|
|
16
|
+
* They are TEXT rather than `ReactNode`: every one of the nine lines this
|
|
17
|
+
* replaced was a string, and taking strings is what lets this JOIN them (see
|
|
18
|
+
* the component doc) instead of interleaving keyed separator elements.
|
|
19
|
+
*/
|
|
20
|
+
items: readonly (string | number | false | null | undefined)[];
|
|
21
|
+
/**
|
|
22
|
+
* Which of the two muted typographies the pages use. `"sm"` is
|
|
23
|
+
* `text-sm opacity-70`, `"xs"` is `text-xs opacity-60` — the size and the
|
|
24
|
+
* muting move together, because that is the pair every site had.
|
|
25
|
+
*/
|
|
26
|
+
size?: "sm" | "xs" | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The element to render. `"p"` by default; `"span"` for a line that sits
|
|
29
|
+
* inside phrasing content, where a `<p>` is invalid nesting the browser will
|
|
30
|
+
* reparent out from under React.
|
|
31
|
+
*/
|
|
32
|
+
as?: "p" | "span" | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* ADDED to the base classes rather than replacing them — `tabular-nums`,
|
|
35
|
+
* `uppercase tracking-[1.2px]`. There is no `tailwind-merge` in this package,
|
|
36
|
+
* so a class that CONFLICTS with a base one is not reliably the winner.
|
|
37
|
+
*/
|
|
38
|
+
className?: string | undefined;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* A muted line of run facts, joined by `·` — "6 segments · 12:04 of audio ·
|
|
42
|
+
* 1,840 words".
|
|
43
|
+
*
|
|
44
|
+
* Nine pages had written this by hand under four different typographies for
|
|
45
|
+
* one role, two of them (`call-audit` and `spoken-summary`) byte-identical down
|
|
46
|
+
* to the payload. Three things it takes off the caller:
|
|
47
|
+
*
|
|
48
|
+
* - **The separator cannot be forgotten, and neither can the space around it.**
|
|
49
|
+
* Four of the nine carried a literal `{" "}` at the end of a line, because
|
|
50
|
+
* Prettier's wrap ate the space that made `· ` read as a separator rather
|
|
51
|
+
* than as punctuation glued to the next word. A line that is correct only
|
|
52
|
+
* because somebody remembered an invisible JSX expression is exactly the
|
|
53
|
+
* thing a component should own.
|
|
54
|
+
* - **A fact worth omitting is omitted, and by the caller's own condition.**
|
|
55
|
+
* The hand-written shape for a conditional fact was to splice the separator
|
|
56
|
+
* into the string — `{x ? \` · budget exhausted\` : ""}` — which puts the
|
|
57
|
+
* punctuation in two places and gets the leading separator wrong the moment
|
|
58
|
+
* the fact before it also disappears. Passing the condition and letting this
|
|
59
|
+
* drop it keeps the separator in one place.
|
|
60
|
+
* - **A line with nothing left to say renders NOTHING.** With every fact
|
|
61
|
+
* conditional, the alternative is a muted empty row, or a bare `·`.
|
|
62
|
+
*
|
|
63
|
+
* The facts are JOINED into one string rather than interleaved as elements, and
|
|
64
|
+
* that is why the prop is text: joined, there is no per-fact `key` to invent —
|
|
65
|
+
* the same reasoning `WorkflowProgress` gives for its log lines. A line that
|
|
66
|
+
* genuinely needs an element in it (a link) wants its own markup.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* import { Facts } from "@alexkroman1/aai-ui";
|
|
71
|
+
*
|
|
72
|
+
* function RunFacts({ words, cut }: { words: number; cut: number }) {
|
|
73
|
+
* return <Facts size="xs" items={[`${words} words`, cut > 0 && `${cut} blind cuts`]} />;
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @param props - Facts-line props.
|
|
78
|
+
*
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
export declare function Facts({ items, size, as, className }: FactsProps): ReactNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { InputHTMLAttributes, ReactNode, SelectHTMLAttributes, TextareaHTMLAttributes } from "react";
|
|
2
|
-
import type { FieldShell,
|
|
2
|
+
import type { FieldShell, FileReadMode } from "./form-types.ts";
|
|
3
3
|
/**
|
|
4
4
|
* Label + control + hint, in the layout every field here uses.
|
|
5
5
|
*
|
|
@@ -47,7 +47,7 @@ export declare function Field({ label, hint, htmlFor, className, children, }: {
|
|
|
47
47
|
*
|
|
48
48
|
* @public
|
|
49
49
|
*/
|
|
50
|
-
export declare function TextField(
|
|
50
|
+
export declare function TextField(props: FieldShell & Omit<InputHTMLAttributes<HTMLInputElement>, "name" | "className">): import("react").JSX.Element;
|
|
51
51
|
/**
|
|
52
52
|
* A number input. Contributes a NUMBER to {@link FormValues}, or nothing when
|
|
53
53
|
* left empty.
|
|
@@ -60,7 +60,7 @@ export declare function TextField({ name, label, hint, className, ...rest }: Fie
|
|
|
60
60
|
*
|
|
61
61
|
* @public
|
|
62
62
|
*/
|
|
63
|
-
export declare function NumberField(
|
|
63
|
+
export declare function NumberField(props: FieldShell & Omit<InputHTMLAttributes<HTMLInputElement>, "name" | "className" | "type">): import("react").JSX.Element;
|
|
64
64
|
/**
|
|
65
65
|
* A multi-line text input.
|
|
66
66
|
*
|
|
@@ -116,14 +116,14 @@ export declare function CheckboxField({ name, label, hint, className, ...rest }:
|
|
|
116
116
|
* travel in it. With `upload` the field contributes the `File` itself,
|
|
117
117
|
* `useWorkflowSubmit` stores it through `POST /workflows/uploads` before
|
|
118
118
|
* starting the run, and the input carries the upload id — which a step reads
|
|
119
|
-
* windows of with `
|
|
119
|
+
* windows of with `stepReadUpload`. Declaring the property in the workflow's
|
|
120
120
|
* `uploads` list makes `<WorkflowFields>` render exactly this, so a declared
|
|
121
121
|
* form needs no file markup at all.
|
|
122
122
|
*
|
|
123
123
|
* **Without it the field describes the file and does not read it.** `read`
|
|
124
124
|
* exists for the cases where the bytes really are small and really are the
|
|
125
125
|
* input — a CSV of ids, a config — and the size is the author's to check. See
|
|
126
|
-
* {@link
|
|
126
|
+
* {@link FileReadMode} for the four values; `upload` is shorthand for
|
|
127
127
|
* `read="upload"`.
|
|
128
128
|
*
|
|
129
129
|
* Otherwise accepts every `<input>` attribute except `name`, `className` and
|
|
@@ -136,7 +136,7 @@ export declare function CheckboxField({ name, label, hint, className, ...rest }:
|
|
|
136
136
|
* @public
|
|
137
137
|
*/
|
|
138
138
|
export declare function FileField({ name, label, hint, className, read, upload, ...rest }: FieldShell & {
|
|
139
|
-
read?:
|
|
139
|
+
read?: FileReadMode;
|
|
140
140
|
/** Shorthand for `read="upload"` — see above. */
|
|
141
141
|
upload?: boolean;
|
|
142
142
|
} & Omit<InputHTMLAttributes<HTMLInputElement>, "name" | "className" | "type">): import("react").JSX.Element;
|
|
@@ -2,7 +2,7 @@ import type { ButtonHTMLAttributes, FormHTMLAttributes, ReactNode } from "react"
|
|
|
2
2
|
import { type ButtonSize, type ButtonVariant } from "./button.tsx";
|
|
3
3
|
import type { FormValues } from "./form-types.ts";
|
|
4
4
|
export { CheckboxField, Field, FileField, NumberField, SelectField, TextAreaField, TextField, } from "./form-fields.tsx";
|
|
5
|
-
export type { FieldShell,
|
|
5
|
+
export type { FieldShell, FileReadMode, FileValue, FormValues } from "./form-types.ts";
|
|
6
6
|
/** Props of {@link Form}. */
|
|
7
7
|
export type FormProps = {
|
|
8
8
|
/**
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props of {@link SessionErrorBanner}.
|
|
4
|
+
*
|
|
5
|
+
* Every field is optional, so `<SessionErrorBanner />` is the whole call. It is
|
|
6
|
+
* a NAMED type all the same, for the reason `ControlsProps` and
|
|
7
|
+
* `ConsoleShellProps` are: an inline object literal in the signature leaves a
|
|
8
|
+
* `createElement(SessionErrorBanner, { className })` caller unable to infer the
|
|
9
|
+
* props at all, and gives the reference page nothing to link to.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export type SessionErrorBannerProps = {
|
|
14
|
+
/** Additional CSS class names for the banner, appended to its own. */
|
|
15
|
+
className?: string | undefined;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The announced banner for a failed session: the error's message and code, or
|
|
19
|
+
* nothing at all when the session is fine.
|
|
20
|
+
*
|
|
21
|
+
* **This used to be four lines inside `ConsoleShell`, and that is why it is its
|
|
22
|
+
* own component.** The banner was the reason `ConsoleShell` was published —
|
|
23
|
+
* `role="alert"` is the one part of that component a reviewer cannot see is
|
|
24
|
+
* missing, since per the `fatalError` latch in `session-core.ts` the banner is
|
|
25
|
+
* the ONLY remaining signal a session died (the state eyebrow beside it goes
|
|
26
|
+
* back to reading like a live session), and a screen reader is never told an
|
|
27
|
+
* unannounced one appeared. But `ConsoleShell` is a whole FRAME: a centred
|
|
28
|
+
* `max-w-190` column with its own header and footer. Every full-bleed chrome —
|
|
29
|
+
* a two-pane board, a CRT — therefore could not adopt it, rebuilt the banner
|
|
30
|
+
* instead, and the three that did had ALREADY drifted: one rendered
|
|
31
|
+
* `ERROR: {message}` and dropped the code entirely, one `ERROR: {message}
|
|
32
|
+
* ({code})`, one `{message} ({code})`. Splitting the banner out is what lets a
|
|
33
|
+
* chrome take the announced-error decision without taking the layout, and
|
|
34
|
+
* `ConsoleShell` composes this rather than keeping a second copy, so the two
|
|
35
|
+
* cannot drift again.
|
|
36
|
+
*
|
|
37
|
+
* **It reads the session itself.** There is no `error` prop: a banner that
|
|
38
|
+
* takes its text from the caller is a banner a caller can forget to wire, which
|
|
39
|
+
* is exactly the failure above with an extra step. It subscribes narrowly via
|
|
40
|
+
* {@link useSessionError}, so a page that renders it does not re-render with
|
|
41
|
+
* the transcript.
|
|
42
|
+
*
|
|
43
|
+
* **The code is shown, always.** `SessionError.code` is the eight-member wire
|
|
44
|
+
* union — it is what a user pastes into a bug report and the only part of the
|
|
45
|
+
* error that is stable across wordings — and the chrome that dropped it left
|
|
46
|
+
* its readers with a sentence and no way to say which failure it was.
|
|
47
|
+
*
|
|
48
|
+
* Must be rendered inside the providers `client()` installs.
|
|
49
|
+
*
|
|
50
|
+
* @example A full-bleed chrome that wants the banner and not the frame
|
|
51
|
+
* ```tsx
|
|
52
|
+
* import { SessionErrorBanner } from "@alexkroman1/aai-ui";
|
|
53
|
+
*
|
|
54
|
+
* function Board() {
|
|
55
|
+
* return (
|
|
56
|
+
* <div className="grid grid-cols-[1fr_320px] h-screen">
|
|
57
|
+
* <main>…</main>
|
|
58
|
+
* <aside>…</aside>
|
|
59
|
+
* <SessionErrorBanner className="col-span-2" />
|
|
60
|
+
* </div>
|
|
61
|
+
* );
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @param props - See {@link SessionErrorBannerProps}.
|
|
66
|
+
*
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
export declare function SessionErrorBanner({ className }: SessionErrorBannerProps): ReactNode;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useTheme } from "../context.js";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
//#region components/sidebar-layout.tsx
|
|
4
|
+
//#region src/components/sidebar-layout.tsx
|
|
5
5
|
/** @jsxImportSource react */
|
|
6
6
|
/**
|
|
7
7
|
* A two-column layout with a fixed-width sidebar and a flexible main area.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useSessionCore, useSessionSelector, useTheme } from "../context.js";
|
|
2
|
-
import {
|
|
2
|
+
import { a as inkTint } from "../_colors-CpZO-88A.js";
|
|
3
3
|
import { Button } from "./button.js";
|
|
4
|
-
import { t as AaiLogo } from "../aai-logo-
|
|
5
|
-
import { t as Eyebrow } from "../eyebrow-
|
|
4
|
+
import { t as AaiLogo } from "../aai-logo-CFlomZlS.js";
|
|
5
|
+
import { t as Eyebrow } from "../eyebrow-UfmSz9yy.js";
|
|
6
6
|
import clsx from "clsx";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
//#region components/start-screen.tsx
|
|
8
|
+
//#region src/components/start-screen.tsx
|
|
9
9
|
/** @jsxImportSource react */
|
|
10
10
|
/**
|
|
11
11
|
* A centered start screen: a white card on the cream page with the logo, an
|
|
@@ -8,7 +8,7 @@ export type ToolDisplayConfig = Record<string, {
|
|
|
8
8
|
label?: string;
|
|
9
9
|
}>;
|
|
10
10
|
/**
|
|
11
|
-
* Context for tool display configuration. Installed by `
|
|
11
|
+
* Context for tool display configuration. Installed by `mountClient()` from
|
|
12
12
|
* `ClientConfig.tools`; the built-in components read it via `useToolConfig`.
|
|
13
13
|
*
|
|
14
14
|
* @internal
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
2
|
import type { WorkflowApi } from "../workflow-client.ts";
|
|
3
3
|
/**
|
|
4
4
|
* What a run has said so far, rendered.
|
|
5
5
|
*
|
|
6
6
|
* The complement of a status line, and the reason both exist: a run is
|
|
7
7
|
* `running` for its whole life, so a one-round job and a ten-round one look
|
|
8
|
-
* identical while they happen. These lines come from the run itself (`
|
|
8
|
+
* identical while they happen. These lines come from the run itself (`stepReport()`
|
|
9
9
|
* in a `"use step"` body), which is the only channel a workflow has before it
|
|
10
10
|
* produces an output.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* Four rules are baked in, and they are why this is a component rather than
|
|
13
13
|
* three lines each page writes for itself — the two templates that had written
|
|
14
|
-
* it had written
|
|
14
|
+
* it had written three of them, comments included:
|
|
15
15
|
*
|
|
16
16
|
* - **It renders nothing until there is something to render.** `supported` is
|
|
17
17
|
* what keeps this from being an empty box forever on an agent deployed before
|
|
@@ -25,6 +25,13 @@ import type { WorkflowApi } from "../workflow-client.ts";
|
|
|
25
25
|
* or opening a finished run tomorrow — shows how it got there rather than an
|
|
26
26
|
* empty box. That is `useWorkflowProgress`'s doing; this is what makes it
|
|
27
27
|
* visible.
|
|
28
|
+
* - **They are ANNOUNCED**, for the reason the first paragraph gives: this is
|
|
29
|
+
* the only channel a run has before it produces an output, and a `<pre>` that
|
|
30
|
+
* grows is a silent one. A screen-reader user pressing "Digest" got nothing
|
|
31
|
+
* between the click and a terminal state minutes later — no "fetching", no
|
|
32
|
+
* "summarising", no evidence the button did anything. See `role="log"` below.
|
|
33
|
+
* The six pages that render this pass only `className`, so no template could
|
|
34
|
+
* have fixed it locally; that is what makes it this component's job.
|
|
28
35
|
*
|
|
29
36
|
* @example
|
|
30
37
|
* ```tsx
|
package/dist/context.d.ts
CHANGED
|
@@ -1,34 +1,45 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import type {
|
|
3
|
-
import type { ClientTheme } from "./types.ts";
|
|
2
|
+
import type { BrowserSession, SessionSnapshot } from "./session-core-types.ts";
|
|
3
|
+
import type { AgentState, ClientTheme, SessionError } from "./types.ts";
|
|
4
4
|
/**
|
|
5
|
-
* Provides the {@link
|
|
5
|
+
* Provides the {@link BrowserSession} the session hooks read. `mountClient()`
|
|
6
6
|
* installs it automatically; a custom tree only needs it when bypassing
|
|
7
|
-
* `
|
|
7
|
+
* `mountClient()` and mounting React itself.
|
|
8
8
|
*
|
|
9
9
|
* @internal
|
|
10
10
|
*/
|
|
11
|
-
export declare function SessionProvider({ value, children }: {
|
|
12
|
-
value:
|
|
11
|
+
export declare function SessionProvider({ value, children, }: {
|
|
12
|
+
value: BrowserSession;
|
|
13
13
|
children?: ReactNode;
|
|
14
|
-
}): import("react").FunctionComponentElement<import("react").ProviderProps<
|
|
14
|
+
}): import("react").FunctionComponentElement<import("react").ProviderProps<BrowserSession | null>>;
|
|
15
|
+
/**
|
|
16
|
+
* The session's control methods, and nothing else — what a `client.tsx` may
|
|
17
|
+
* legitimately CALL on a session, as against what it may read.
|
|
18
|
+
*
|
|
19
|
+
* Declared once and merged into {@link Session} rather than written out at both
|
|
20
|
+
* places: the two lists have to be the same list, and a member added to one and
|
|
21
|
+
* not the other is a hook that cannot do what `useSession()` can.
|
|
22
|
+
*
|
|
23
|
+
* Method signatures come from {@link BrowserSession} — one source of truth.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export type SessionActions = Pick<BrowserSession, "start" | "cancel" | "resetState" | "reset" | "restart" | "disconnect" | "toggle" | "end">;
|
|
15
28
|
/**
|
|
16
29
|
* What {@link useSession} returns: the live {@link SessionSnapshot} fields
|
|
17
30
|
* (`state`, `messages`, `toolCalls`, `agentState`, live transcripts, `error`,
|
|
18
31
|
* `apiUrl`, `started`/`running`/`recording`, …) merged with the session's
|
|
19
|
-
* control methods (`start`, `toggle`, `reset`, `
|
|
20
|
-
* `cancel`, `end`).
|
|
32
|
+
* control methods (`start`, `toggle`, `reset`, `restart`, `resetState`,
|
|
33
|
+
* `disconnect`, `cancel`, `end`).
|
|
21
34
|
*
|
|
22
35
|
* Note there is no text-send method — sessions are voice-only; the only
|
|
23
36
|
* client→server inputs are audio and the control methods above.
|
|
24
37
|
*
|
|
25
|
-
* Method signatures come from {@link SessionCore} — one source of truth.
|
|
26
|
-
*
|
|
27
38
|
* @public
|
|
28
39
|
*/
|
|
29
|
-
export type Session = SessionSnapshot &
|
|
40
|
+
export type Session = SessionSnapshot & SessionActions;
|
|
30
41
|
/**
|
|
31
|
-
* Return the raw {@link
|
|
42
|
+
* Return the raw {@link BrowserSession} from context without subscribing to
|
|
32
43
|
* snapshot changes. Useful for accessing stable methods (`start`, `toggle`,
|
|
33
44
|
* `reset`, …) from components that select narrow state via
|
|
34
45
|
* {@link useSessionSelector}.
|
|
@@ -36,15 +47,73 @@ export type Session = SessionSnapshot & Pick<SessionCore, "start" | "cancel" | "
|
|
|
36
47
|
* Not part of the package's public export surface — internal to aai-ui
|
|
37
48
|
* components.
|
|
38
49
|
*/
|
|
39
|
-
export declare function useSessionCore():
|
|
50
|
+
export declare function useSessionCore(): BrowserSession;
|
|
51
|
+
/**
|
|
52
|
+
* The session's control methods — `start`, `cancel`, `resetState`, `reset`,
|
|
53
|
+
* `restart`, `disconnect`, `toggle`, `end` — with **no snapshot
|
|
54
|
+
* subscription**.
|
|
55
|
+
*
|
|
56
|
+
* This is the narrow half of {@link useSession}, and it is the half a custom
|
|
57
|
+
* chrome could not reach. `<Controls>` and `<StartScreen>` in this package pair
|
|
58
|
+
* a one-field `useSessionSelector` with this package's own `useSessionCore`
|
|
59
|
+
* (`context.ts`, unpublished); a `client.tsx`
|
|
60
|
+
* could not, because that hook is not published — so a footer needing `start`
|
|
61
|
+
* and `toggle` held a WHOLE-SNAPSHOT `useSession()`, and `session-core.ts`
|
|
62
|
+
* rebuilds the snapshot object on every change. Measured consequence: four
|
|
63
|
+
* components across three templates re-rendered on every STT partial and every
|
|
64
|
+
* streaming delta, in files whose every other component is narrowly subscribed
|
|
65
|
+
* on purpose. One of them (`infocom-adventure`'s `TitleScreen`) reads nothing
|
|
66
|
+
* from the snapshot at all and subscribes to all of it for `session.start`.
|
|
67
|
+
*
|
|
68
|
+
* **Why publishing this does not reopen what `/internal` closed.**
|
|
69
|
+
* `useSessionCore` hands back the STORE — `subscribe`, `getSnapshot`,
|
|
70
|
+
* `connect`, `Symbol.dispose` — which is the framework's own plumbing, the same
|
|
71
|
+
* category as the providers and `buildAgentUrl` that live on
|
|
72
|
+
* `@alexkroman1/aai-ui/internal`. A client that holds it can subscribe out of
|
|
73
|
+
* band of React, dial a socket the mount did not, and dispose the session under
|
|
74
|
+
* the tree that is rendering it. What comes back from here is the SAME eight
|
|
75
|
+
* methods `useSession()` already publishes on its result, built into a fresh
|
|
76
|
+
* object rather than passed through, so the store is not reachable from it.
|
|
77
|
+
* There is no new capability here — only the existing one without the
|
|
78
|
+
* subscription tax.
|
|
79
|
+
*
|
|
80
|
+
* Identity-stable per core, so it is safe in a dependency array and in a
|
|
81
|
+
* `memo()` child's props: the methods are closures created once by
|
|
82
|
+
* `createBrowserSession`, and the object wrapping them is memoized on the core.
|
|
83
|
+
*
|
|
84
|
+
* Throws outside the provider `mountClient()` installs, like every session hook.
|
|
85
|
+
*
|
|
86
|
+
* @example A footer that acts on the session without re-rendering with it
|
|
87
|
+
* ```tsx
|
|
88
|
+
* import { useSessionActions, useSessionSelector } from "@alexkroman1/aai-ui";
|
|
89
|
+
*
|
|
90
|
+
* function Footer() {
|
|
91
|
+
* // Two narrow subscriptions and no snapshot read: this row re-renders when
|
|
92
|
+
* // `running` flips, and not on every transcript delta.
|
|
93
|
+
* const running = useSessionSelector((s) => s.running);
|
|
94
|
+
* const { toggle, end } = useSessionActions();
|
|
95
|
+
* return (
|
|
96
|
+
* <>
|
|
97
|
+
* <button onClick={toggle}>{running ? "Pause" : "Resume"}</button>
|
|
98
|
+
* <button onClick={end}>Hang up</button>
|
|
99
|
+
* </>
|
|
100
|
+
* );
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @returns The eight control methods — see {@link SessionActions}.
|
|
105
|
+
*
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
export declare function useSessionActions(): SessionActions;
|
|
40
109
|
/**
|
|
41
110
|
* Return the live {@link Session}: the current snapshot fields plus the
|
|
42
111
|
* control methods (`start`, `toggle`, `reset`, `resetState`, `disconnect`,
|
|
43
112
|
* `cancel`, `end`).
|
|
44
113
|
*
|
|
45
|
-
* Throws if used outside the provider `
|
|
114
|
+
* Throws if used outside the provider `mountClient()` installs (the error names
|
|
46
115
|
* `<SessionProvider>` — you only mount that yourself when bypassing
|
|
47
|
-
* `
|
|
116
|
+
* `mountClient()`). Re-renders the component on *every* snapshot change; for a
|
|
48
117
|
* component that reads one field, prefer {@link useSessionSelector} for a
|
|
49
118
|
* targeted subscription.
|
|
50
119
|
*
|
|
@@ -94,9 +163,63 @@ export declare function useSession(): Session;
|
|
|
94
163
|
*/
|
|
95
164
|
export declare function useSessionSelector<T>(selector: (snapshot: SessionSnapshot) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
96
165
|
/**
|
|
97
|
-
*
|
|
166
|
+
* The agent's live {@link AgentState} — `disconnected`, `connecting`, `ready`,
|
|
167
|
+
* `listening`, `thinking`, `speaking`, `error` — on its own narrow
|
|
168
|
+
* subscription.
|
|
169
|
+
*
|
|
170
|
+
* `useSessionSelector((s) => s.state)` spelled once. It is one of exactly two
|
|
171
|
+
* snapshot fields that more than one custom chrome ever selects (the other is
|
|
172
|
+
* {@link useSessionError}), and it had been written inline at eight sites —
|
|
173
|
+
* including inside this package and, worse, in `ConsoleShell`'s own `@example`,
|
|
174
|
+
* which taught the inline form to everyone who read it.
|
|
175
|
+
*
|
|
176
|
+
* **Named `useSessionStatus`, not `useSessionState`.** `useAgentState` is the
|
|
177
|
+
* SLOT hook — the agent's own synced application state, whatever a
|
|
178
|
+
* `sessionSlot()` projects — and `AgentState` here is the phase of the CALL.
|
|
179
|
+
* Two different concepts one letter apart, so the shorter-sounding name is the
|
|
180
|
+
* one deliberately not taken.
|
|
181
|
+
*
|
|
182
|
+
* Pair it with {@link AGENT_STATE_LABELS} for a rendered word; the raw member
|
|
183
|
+
* is a wire value, not a label.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```tsx
|
|
187
|
+
* import { AGENT_STATE_LABELS, useSessionStatus } from "@alexkroman1/aai-ui";
|
|
188
|
+
*
|
|
189
|
+
* function StatusDot() {
|
|
190
|
+
* const status = useSessionStatus();
|
|
191
|
+
* return <span data-state={status}>{AGENT_STATE_LABELS[status]}</span>;
|
|
192
|
+
* }
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* @returns The current agent state.
|
|
196
|
+
*
|
|
197
|
+
* @public
|
|
198
|
+
*/
|
|
199
|
+
export declare function useSessionStatus(): AgentState;
|
|
200
|
+
/**
|
|
201
|
+
* The session's current {@link SessionError}, or `null` when there is none, on
|
|
202
|
+
* its own narrow subscription.
|
|
203
|
+
*
|
|
204
|
+
* The other half of {@link useSessionStatus} — the second of the two fields a
|
|
205
|
+
* custom chrome reads over and over, and the one whose absence is invisible:
|
|
206
|
+
* per the `fatalError` latch in `session-core.ts` the error is the ONLY
|
|
207
|
+
* remaining signal that a session died, since the state beside it goes back to
|
|
208
|
+
* reading like a live one.
|
|
209
|
+
*
|
|
210
|
+
* A chrome rendering it owes `role="alert"` — which is what
|
|
211
|
+
* {@link SessionErrorBanner} is for, and why reaching for that beats reaching
|
|
212
|
+
* for this.
|
|
213
|
+
*
|
|
214
|
+
* @returns The current error, or `null`.
|
|
215
|
+
*
|
|
216
|
+
* @public
|
|
217
|
+
*/
|
|
218
|
+
export declare function useSessionError(): SessionError | null;
|
|
219
|
+
/**
|
|
220
|
+
* Provides the theme the components read via `useTheme`. `mountClient()` installs
|
|
98
221
|
* it automatically (from `ClientConfig.theme`); a custom tree only needs it
|
|
99
|
-
* when bypassing `
|
|
222
|
+
* when bypassing `mountClient()` and mounting React itself.
|
|
100
223
|
*
|
|
101
224
|
* @internal
|
|
102
225
|
*/
|
|
@@ -110,7 +233,7 @@ export declare function ThemeProvider({ value, children, }: {
|
|
|
110
233
|
* provider is present, so components can call it unconditionally.
|
|
111
234
|
*
|
|
112
235
|
* This is how a custom component stays on the agent's palette: a
|
|
113
|
-
* `
|
|
236
|
+
* `mountClient({ theme })` override reaches it here, where a hardcoded colour or a
|
|
114
237
|
* Tailwind class cannot see it.
|
|
115
238
|
*
|
|
116
239
|
* @example
|