@alexkroman1/aai-ui 0.12.2 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +58 -0
- package/dist/components/button.js +85 -0
- package/dist/components/chat-view.d.ts +35 -0
- package/dist/components/chat-view.js +3 -0
- package/dist/components/console-shell.d.ts +85 -0
- package/dist/components/controls.d.ts +33 -0
- package/dist/components/controls.js +49 -0
- 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 +48 -0
- package/dist/components/message-list.js +3 -0
- 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 +42 -0
- package/dist/components/sidebar-layout.js +56 -0
- package/dist/components/start-screen.d.ts +37 -0
- package/dist/components/start-screen.js +71 -0
- package/dist/components/tool-call-block.d.ts +28 -0
- package/dist/components/tool-call-block.js +3 -0
- 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 +129 -32
- package/dist/index.js +5503 -18
- 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 +58 -31
- package/styles.css +152 -30
- package/dist/_components/app.d.ts +0 -23
- package/dist/_components/app.js +0 -41
- package/dist/_components/button.d.ts +0 -50
- package/dist/_components/button.js +0 -46
- package/dist/_components/chat-view.d.ts +0 -29
- package/dist/_components/chat-view.js +0 -61
- package/dist/_components/controls.d.ts +0 -18
- package/dist/_components/controls.js +0 -37
- 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/message-list.d.ts +0 -21
- package/dist/_components/message-list.js +0 -76
- package/dist/_components/sidebar-layout.d.ts +0 -21
- package/dist/_components/sidebar-layout.js +0 -36
- package/dist/_components/start-screen.d.ts +0 -26
- package/dist/_components/start-screen.js +0 -51
- 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-call-block.d.ts +0 -27
- package/dist/_components/tool-call-block.js +0 -118
- 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/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/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
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `useTapToTalk`'s decisions as a statechart, with no React and no session:
|
|
3
|
+
* what a tap does, when a call hangs itself up, and when a connection attempt
|
|
4
|
+
* has failed. The hook feeds it what the session DID (`SESSION`) and what the
|
|
5
|
+
* caller pressed (`TAP`, `TEXT`, `HANG_UP`), and it calls back through
|
|
6
|
+
* {@link TapToTalkEffects} — the pattern `session/audio-state.ts` uses, so
|
|
7
|
+
* `_tap-to-talk-state.test.ts` specs every timer without a browser.
|
|
8
|
+
*
|
|
9
|
+
* Two regions, because they move independently:
|
|
10
|
+
*
|
|
11
|
+
* - **`live`** — whether the caller has the mic open for a realtime
|
|
12
|
+
* conversation. Only a tap enters it; a tap, a hang-up or the session going
|
|
13
|
+
* down leaves it. The mic is muted on the way out and unmuted on the way in
|
|
14
|
+
* (entry actions, so no path can forget).
|
|
15
|
+
* - **`session`** — the call as the session reports it: `idle`, `connecting`,
|
|
16
|
+
* or `active` split by what the agent is doing, because each of those has
|
|
17
|
+
* its own hang-up clock (`quiet`: the follow-up window; `thinking`: a longer
|
|
18
|
+
* one, so a slow tool is not cut off; `speaking`: none). Any session
|
|
19
|
+
* activity RE-ENTERS the active child, which restarts its clock — the
|
|
20
|
+
* firmware's `agent_last_activity_ms()`.
|
|
21
|
+
*
|
|
22
|
+
* A clock only hangs up when `live` is `off`: a live conversation ends when
|
|
23
|
+
* the caller says so, as the device's does.
|
|
24
|
+
*/
|
|
25
|
+
import type { AgentState } from "./types.ts";
|
|
26
|
+
/** What the session looks like to a tap: the three phases the hook publishes. */
|
|
27
|
+
export type TapToTalkPhase = "idle" | "connecting" | "active";
|
|
28
|
+
/** The three clocks, read per use so a re-render with new options takes effect. */
|
|
29
|
+
export type TapToTalkTiming = {
|
|
30
|
+
/** Quiet, not live, not thinking or speaking: hang up after this long. */
|
|
31
|
+
idleHangupMs: number;
|
|
32
|
+
/** Thinking, not live: hang up after this long. */
|
|
33
|
+
thinkingHangupMs: number;
|
|
34
|
+
/** Connecting: give up (and report `failed`) after this long. */
|
|
35
|
+
connectTimeoutMs: number;
|
|
36
|
+
};
|
|
37
|
+
/** What the machine decides and cannot do itself. */
|
|
38
|
+
export type TapToTalkEffects = {
|
|
39
|
+
/** Bring the session up if it is not meant to be running. Idempotent. */
|
|
40
|
+
connect(): void;
|
|
41
|
+
/** Hang up, resumably — `session.disconnect()`. */
|
|
42
|
+
hangUp(): void;
|
|
43
|
+
/** Stop the agent's current reply — `session.cancel()`. */
|
|
44
|
+
cancel(): void;
|
|
45
|
+
/** Mute (`true`) or open the mic. */
|
|
46
|
+
setMuted(muted: boolean): void;
|
|
47
|
+
};
|
|
48
|
+
/** Everything that moves the machine. */
|
|
49
|
+
export type TapToTalkEvent =
|
|
50
|
+
/** The talk button or key. */
|
|
51
|
+
{
|
|
52
|
+
type: "TAP";
|
|
53
|
+
}
|
|
54
|
+
/** Hang up now, whatever the state. */
|
|
55
|
+
| {
|
|
56
|
+
type: "HANG_UP";
|
|
57
|
+
}
|
|
58
|
+
/** A typed turn: it clears a previous failure like a tap does. */
|
|
59
|
+
| {
|
|
60
|
+
type: "TEXT";
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The session moved or did something — sent on every activity (a content
|
|
64
|
+
* change too), not only a phase change; every one restarts the active clock.
|
|
65
|
+
*/
|
|
66
|
+
| {
|
|
67
|
+
type: "SESSION";
|
|
68
|
+
phase: TapToTalkPhase;
|
|
69
|
+
agent: AgentState;
|
|
70
|
+
}
|
|
71
|
+
/** The session reported an error. */
|
|
72
|
+
| {
|
|
73
|
+
type: "ERROR";
|
|
74
|
+
};
|
|
75
|
+
/** What the hook renders from. A new object only when a field changes. */
|
|
76
|
+
export type TapToTalkView = {
|
|
77
|
+
live: boolean;
|
|
78
|
+
failed: boolean;
|
|
79
|
+
};
|
|
80
|
+
/** One running machine: send events, read and subscribe to its view, stop it. */
|
|
81
|
+
export type TapToTalkStore = {
|
|
82
|
+
send(event: TapToTalkEvent): void;
|
|
83
|
+
getView(): TapToTalkView;
|
|
84
|
+
subscribe(listener: () => void): () => void;
|
|
85
|
+
stop(): void;
|
|
86
|
+
};
|
|
87
|
+
/** Start a machine over `effects`. */
|
|
88
|
+
export declare function createTapToTalk(effects: TapToTalkEffects, timing: () => TapToTalkTiming): TapToTalkStore;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { safeJsonParse } from "@alexkroman1/aai";
|
|
2
|
+
//#region src/_utils.ts
|
|
3
|
+
/** Parse a JSON string, returning the input unchanged when it isn't valid JSON. */
|
|
4
|
+
function tryParseJSON(str) {
|
|
5
|
+
if (!str) return str;
|
|
6
|
+
return safeJsonParse(str) ?? str;
|
|
7
|
+
}
|
|
8
|
+
/** Truncate a string to `max` characters, appending an ellipsis when cut. */
|
|
9
|
+
function truncate(s, max = 80) {
|
|
10
|
+
return s.length > max ? `${s.slice(0, max)}...` : s;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The page this UI is served from — the agent's base URL when none is
|
|
14
|
+
* configured explicitly. One definition so `mountClient()`'s default and the
|
|
15
|
+
* shareable-URL chip can never disagree about which agent the page is.
|
|
16
|
+
*/
|
|
17
|
+
function pageBaseUrl() {
|
|
18
|
+
if (typeof location === "undefined") return "";
|
|
19
|
+
return location.origin + location.pathname;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Set the document title, when there is one to set and a document to set it on.
|
|
23
|
+
*
|
|
24
|
+
* Both mounts do this and neither may clobber a title the page's own HTML
|
|
25
|
+
* declared — `mountClient()`'s custom-component tier because there is no shell header
|
|
26
|
+
* to show the name in, `mountPage()` because there is no shell at all. One copy, for
|
|
27
|
+
* the reason `resolveContainer` and `mountRoot` are shared: the rule is the
|
|
28
|
+
* same, so the two mounts must not be able to disagree about it.
|
|
29
|
+
*/
|
|
30
|
+
function setPageTitle(name) {
|
|
31
|
+
if (name && typeof document !== "undefined") document.title = name;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* True when a key event came from somewhere typing belongs — where Space is a
|
|
35
|
+
* character, not a talk key. Shared by the two talk-button hooks
|
|
36
|
+
* (`use-push-to-talk.ts`, `use-tap-to-talk.ts`) so they cannot disagree.
|
|
37
|
+
*/
|
|
38
|
+
function isTypingTarget(target) {
|
|
39
|
+
if (typeof HTMLElement === "undefined" || !(target instanceof HTMLElement)) return false;
|
|
40
|
+
return target.isContentEditable || [
|
|
41
|
+
"INPUT",
|
|
42
|
+
"TEXTAREA",
|
|
43
|
+
"SELECT"
|
|
44
|
+
].includes(target.tagName);
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { tryParseJSON as a, truncate as i, pageBaseUrl as n, setPageTitle as r, isTypingTarget as t };
|
package/dist/_utils.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Parse a JSON string, returning the input unchanged when it isn't valid JSON. */
|
|
2
|
+
export declare function tryParseJSON(str: string | undefined): unknown;
|
|
3
|
+
/** Truncate a string to `max` characters, appending an ellipsis when cut. */
|
|
4
|
+
export declare function truncate(s: string, max?: number): string;
|
|
5
|
+
/**
|
|
6
|
+
* The page this UI is served from — the agent's base URL when none is
|
|
7
|
+
* configured explicitly. One definition so `mountClient()`'s default and the
|
|
8
|
+
* shareable-URL chip can never disagree about which agent the page is.
|
|
9
|
+
*/
|
|
10
|
+
export declare function pageBaseUrl(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Set the document title, when there is one to set and a document to set it on.
|
|
13
|
+
*
|
|
14
|
+
* Both mounts do this and neither may clobber a title the page's own HTML
|
|
15
|
+
* declared — `mountClient()`'s custom-component tier because there is no shell header
|
|
16
|
+
* to show the name in, `mountPage()` because there is no shell at all. One copy, for
|
|
17
|
+
* the reason `resolveContainer` and `mountRoot` are shared: the rule is the
|
|
18
|
+
* same, so the two mounts must not be able to disagree about it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function setPageTitle(name: string | undefined): void;
|
|
21
|
+
/**
|
|
22
|
+
* True when a key event came from somewhere typing belongs — where Space is a
|
|
23
|
+
* character, not a talk key. Shared by the two talk-button hooks
|
|
24
|
+
* (`use-push-to-talk.ts`, `use-tap-to-talk.ts`) so they cannot disagree.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isTypingTarget(target: EventTarget | null): boolean;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guarded access to the browser's key-value stores.
|
|
3
|
+
*
|
|
4
|
+
* Three modules in this package remember something across a load — the session
|
|
5
|
+
* id (`session/resume-store.ts`), the upload ids a form has minted
|
|
6
|
+
* (`upload/recall.ts`) and a page's run correlation key (`use-run-key.ts`) —
|
|
7
|
+
* and each had written out the same two rules by hand, eight `try`/`catch`
|
|
8
|
+
* blocks and two URL-derived key builders between them. The tell was that each
|
|
9
|
+
* module's doc cited the others as precedent, which is a convention held by
|
|
10
|
+
* authors reading each other's comments rather than by code.
|
|
11
|
+
*
|
|
12
|
+
* Both rules are here once:
|
|
13
|
+
*
|
|
14
|
+
* - **Every access is guarded.** Storage THROWS outright in some contexts
|
|
15
|
+
* (Safari private mode, an iframe blocked by policy) and is ABSENT in others
|
|
16
|
+
* (any server-side render) — and reaching for the PROPERTY is itself what
|
|
17
|
+
* throws, before a method is called, which is why the guard has to wrap the
|
|
18
|
+
* lookup and not just the call. A caller that cannot remember must degrade to
|
|
19
|
+
* the behaviour it would have had anyway, never fail to render.
|
|
20
|
+
* - **A slot is namespaced by the page's own URL**, so two agents served from
|
|
21
|
+
* one origin — every deployed agent, at `/:slug/` — cannot inherit each
|
|
22
|
+
* other's state.
|
|
23
|
+
*/
|
|
24
|
+
/** Which of the two stores; they differ only in how long an entry outlives the tab. */
|
|
25
|
+
export type StorageKind = "session" | "local";
|
|
26
|
+
/** The stored value, or undefined — for a missing entry and an absent store alike. */
|
|
27
|
+
export declare function storageGet(kind: StorageKind, key: string): string | undefined;
|
|
28
|
+
/** Remember a value. A store that refuses is a no-op, never a throw. */
|
|
29
|
+
export declare function storageSet(kind: StorageKind, key: string, value: string): void;
|
|
30
|
+
/** Forget a value. Nothing stored and no store are the same outcome. */
|
|
31
|
+
export declare function storageRemove(kind: StorageKind, key: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* A storage key namespaced by a URL.
|
|
34
|
+
*
|
|
35
|
+
* `target` is resolved against the document, so a relative path ("./", the
|
|
36
|
+
* default-client case) and the absolute form of the same agent agree on one
|
|
37
|
+
* key.
|
|
38
|
+
*
|
|
39
|
+
* @param prefix - The owning module's namespace, e.g. `"aai:session:"`.
|
|
40
|
+
* @param target - What to resolve — an agent's `platformUrl`, or `"./"` for the
|
|
41
|
+
* page's own directory.
|
|
42
|
+
*/
|
|
43
|
+
export declare function urlSlot(prefix: string, target: string): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client preamble every workflow hook needs, once.
|
|
3
|
+
*
|
|
4
|
+
* Five hooks (`useWorkflowRun`, `useWorkflowProgress`, `useWorkflowRuns`,
|
|
5
|
+
* `useWorkflows`, `useWorkflowSubmit`) opened with the same two refs and the
|
|
6
|
+
* same two paragraphs explaining them, and both halves are load-bearing rather
|
|
7
|
+
* than stylistic — which is exactly why they should not be re-derived per hook:
|
|
8
|
+
*
|
|
9
|
+
* - **The caller's client lives in a REF, never in an effect's dependency
|
|
10
|
+
* array.** The natural call site is
|
|
11
|
+
* `useWorkflowRun(id, { api: createWorkflowApi() })`, which passes a NEW
|
|
12
|
+
* object every render; as a dependency that tears the effect down and
|
|
13
|
+
* restarts it on each one, and because a restart clears state and re-renders,
|
|
14
|
+
* it schedules the next. The result is an unbounded request loop against the
|
|
15
|
+
* agent — on the platform, against the BROKER — with `error` wiped before
|
|
16
|
+
* anything can read it, presenting as "the page polls forever" rather than as
|
|
17
|
+
* a mistake at the call site.
|
|
18
|
+
* - **The no-client default is built lazily and ONCE.** As a render-time
|
|
19
|
+
* default (`api ?? createWorkflowApi()`) it is a fresh object per render,
|
|
20
|
+
* which is the same hazard one layer down; built inside an effect it is a
|
|
21
|
+
* fresh object per watch.
|
|
22
|
+
*
|
|
23
|
+
* The returned getter is stable for the life of the component and reads the ref
|
|
24
|
+
* on every call, so a caller that SWAPS clients mid-watch — a token arriving
|
|
25
|
+
* after login — is picked up by the next request without the watch restarting.
|
|
26
|
+
*/
|
|
27
|
+
import { type WorkflowApi } from "./workflow-client.ts";
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the client a workflow hook should use, now.
|
|
30
|
+
*
|
|
31
|
+
* @param api - The caller's client, or undefined for one aimed at the page's
|
|
32
|
+
* own agent.
|
|
33
|
+
* @returns A stable getter. Call it per request, never once per watch.
|
|
34
|
+
*
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export declare function useWorkflowApiRef(api: WorkflowApi | undefined): () => WorkflowApi;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which of a submitted form's values are FILES.
|
|
3
|
+
*
|
|
4
|
+
* Its own module because both submit hooks need the identical answer and then do
|
|
5
|
+
* two different things with it — `useWorkflowSubmit` stores each file and passes
|
|
6
|
+
* its id, `useWorkflowStream` mints the id first so the run can start on it.
|
|
7
|
+
* A second copy of this predicate would be a form field that one hook treats as a
|
|
8
|
+
* file and the other does not, which is invisible until the run reads the wrong
|
|
9
|
+
* kind of string.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The files a submitted field carries, if that is what it carries.
|
|
13
|
+
*
|
|
14
|
+
* An array counts only when it is files ALL the way through — a mixed array is
|
|
15
|
+
* some other field's value that happens to contain one, and turning half of it
|
|
16
|
+
* into ids would corrupt it silently.
|
|
17
|
+
*/
|
|
18
|
+
export declare function filesOf(value: unknown): File[];
|
|
19
|
+
/**
|
|
20
|
+
* The input properties still carrying a `File` — i.e. the ones that CANNOT survive
|
|
21
|
+
* being sent.
|
|
22
|
+
*
|
|
23
|
+
* A run input is JSON, and `JSON.stringify(new File(…))` is `{}` — no `toJSON`, no
|
|
24
|
+
* own enumerable properties. So a File left in a payload does not fail to send: it
|
|
25
|
+
* arrives as an empty object, and the workflow rejects it against whatever its own
|
|
26
|
+
* schema says the property should be. Measured in production as
|
|
27
|
+
* `Invalid input for workflow "transcribe": recording: Invalid input` — a message
|
|
28
|
+
* about a type, on a form where the user had picked a perfectly good file.
|
|
29
|
+
*
|
|
30
|
+
* Exported beside {@link filesOf} because it is the same question asked at the
|
|
31
|
+
* other end: that one decides which fields to UPLOAD, this one checks that none
|
|
32
|
+
* were missed. Both hooks are the callers.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fileFields(input: unknown): string[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthetic workflow DEF types for this package's specs.
|
|
3
|
+
*
|
|
4
|
+
* The workflow hooks take a def rather than an output type, and the def is
|
|
5
|
+
* REQUIRED — there is no untyped fallback, because an escape hatch nobody needs
|
|
6
|
+
* is one somebody uses. That leaves the specs, whose subject is upload plumbing
|
|
7
|
+
* and polling rather than typing, needing a def to name.
|
|
8
|
+
*
|
|
9
|
+
* Built structurally rather than with a schema library: `zod` is not a
|
|
10
|
+
* dependency of this package, and `StandardSchemaV1` is published on
|
|
11
|
+
* `@alexkroman1/aai/host-internal`, which a browser package may not import. The
|
|
12
|
+
* shape below is the part of that contract `InferSchemaOutput` reads — the
|
|
13
|
+
* `types.output` slot — and nothing else, which is all a type-level def needs.
|
|
14
|
+
*
|
|
15
|
+
* A `.ts` module rather than a `_test-utils` export because it is types only.
|
|
16
|
+
*/
|
|
17
|
+
import type { WorkflowDef } from "@alexkroman1/aai";
|
|
18
|
+
/** A Standard-Schema-shaped type whose parsed output is `O`. Never constructed. */
|
|
19
|
+
type SchemaOf<O extends Record<string, unknown>> = {
|
|
20
|
+
readonly "~standard": {
|
|
21
|
+
readonly version: 1;
|
|
22
|
+
readonly vendor: string;
|
|
23
|
+
readonly validate: (value: unknown) => {
|
|
24
|
+
readonly value: O;
|
|
25
|
+
};
|
|
26
|
+
readonly types?: {
|
|
27
|
+
readonly input: unknown;
|
|
28
|
+
readonly output: O;
|
|
29
|
+
} | undefined;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/** A workflow taking `I` and answering `O`. */
|
|
33
|
+
export type TestWorkflow<I extends Record<string, unknown> = Record<string, unknown>, O = unknown> = WorkflowDef<SchemaOf<I>, O>;
|
|
34
|
+
/** The shape most specs here need: one `recording` upload id, an unknown result. */
|
|
35
|
+
export type UploadWorkflow = TestWorkflow<{
|
|
36
|
+
recording: unknown;
|
|
37
|
+
}>;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useTheme } from "./context.js";
|
|
2
|
+
import { memo } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/aai-logo.tsx
|
|
5
|
+
/** @jsxImportSource react */
|
|
6
|
+
/**
|
|
7
|
+
* The AssemblyAI wordmark (design-system "website refresh" asset).
|
|
8
|
+
*
|
|
9
|
+
* The mark keeps its brand blues; the letterforms inherit the theme's text
|
|
10
|
+
* color so the logo works on the cream default and custom themes alike.
|
|
11
|
+
*
|
|
12
|
+
* @param size - Rendered height in px. Defaults to 20.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
const AaiLogo = memo(function AaiLogo({ size = 20 }) {
|
|
16
|
+
const theme = useTheme();
|
|
17
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
18
|
+
role: "img",
|
|
19
|
+
"aria-label": "AssemblyAI",
|
|
20
|
+
height: size,
|
|
21
|
+
viewBox: "0 0 141 24",
|
|
22
|
+
fill: "none",
|
|
23
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
24
|
+
style: {
|
|
25
|
+
display: "block",
|
|
26
|
+
color: theme.text
|
|
27
|
+
},
|
|
28
|
+
children: [
|
|
29
|
+
/* @__PURE__ */ jsx("path", {
|
|
30
|
+
d: "M37.698 16.7132L38.9234 13.4518H44.334L45.5782 16.7132H47.897L42.9766 3.51665H40.3939L35.4546 16.7132H37.698ZM41.6193 5.85433L43.7307 11.6042H39.5267L41.6193 5.85433Z",
|
|
31
|
+
fill: "currentColor"
|
|
32
|
+
}),
|
|
33
|
+
/* @__PURE__ */ jsx("path", {
|
|
34
|
+
d: "M48.9176 13.5272C48.9741 15.6198 50.7462 16.8263 53.329 16.8263C55.6667 16.8263 57.4199 15.6575 57.4199 13.81C57.4199 11.6608 55.6289 11.2083 53.4232 10.9444C52.0282 10.7936 51.1044 10.6805 51.1044 9.77558C51.1044 9.00264 51.8962 8.51249 53.1028 8.51249C54.3093 8.51249 55.1388 9.13461 55.2519 10.0207H57.2502C57.1183 8.04118 55.4404 6.94775 53.065 6.94775C50.7462 6.9289 49.1061 8.11659 49.1061 9.94525C49.1061 11.9436 50.8405 12.4149 53.0462 12.6788C54.5355 12.8673 55.4216 12.9428 55.4216 13.9796C55.4216 14.7526 54.5921 15.2427 53.329 15.2427C51.8585 15.2427 50.9913 14.5263 50.9159 13.5272H48.9176Z",
|
|
35
|
+
fill: "currentColor"
|
|
36
|
+
}),
|
|
37
|
+
/* @__PURE__ */ jsx("path", {
|
|
38
|
+
d: "M58.9645 13.5272C59.021 15.6198 60.7931 16.8263 63.3759 16.8263C65.7135 16.8263 67.4668 15.6575 67.4668 13.81C67.4668 11.6608 65.6758 11.2083 63.4701 10.9444C62.0751 10.7936 61.1513 10.6805 61.1513 9.77558C61.1513 9.00264 61.9431 8.51249 63.1497 8.51249C64.3562 8.51249 65.1857 9.13461 65.2988 10.0207H67.2971C67.1652 8.04118 65.4873 6.94775 63.1119 6.94775C60.7931 6.9289 59.153 8.11659 59.153 9.94525C59.153 11.9436 60.8874 12.4149 63.0931 12.6788C64.5824 12.8673 65.4685 12.9428 65.4685 13.9796C65.4685 14.7526 64.639 15.2427 63.3759 15.2427C61.9054 15.2427 61.0382 14.5263 60.9628 13.5272H58.9645Z",
|
|
39
|
+
fill: "currentColor"
|
|
40
|
+
}),
|
|
41
|
+
/* @__PURE__ */ jsx("path", {
|
|
42
|
+
d: "M74.1913 16.8263C76.5855 16.8263 78.2068 15.3747 78.5462 13.4706H76.5101C76.2273 14.5452 75.3224 15.1673 74.0782 15.1673C72.4757 15.1673 71.4389 14.0927 71.3823 12.4526V12.3206H78.6593C78.697 12.0567 78.7158 11.7928 78.7158 11.5477C78.6593 8.71986 76.7929 6.94775 74.0028 6.94775C71.1561 6.94775 69.252 8.92723 69.252 11.9059C69.252 14.8657 71.1561 16.8263 74.1913 16.8263ZM71.4577 10.8313C71.6085 9.4551 72.7208 8.5879 74.0216 8.5879C75.4355 8.5879 76.4347 9.39854 76.6044 10.8313H71.4577Z",
|
|
43
|
+
fill: "currentColor"
|
|
44
|
+
}),
|
|
45
|
+
/* @__PURE__ */ jsx("path", {
|
|
46
|
+
d: "M92.0314 6.94775C90.4478 6.94775 89.3544 7.64529 88.7322 8.70101C88.1478 7.45676 87.0167 6.94775 85.7536 6.94775C84.302 6.96661 83.4725 7.60758 82.9258 8.32396L82.6995 7.06087H80.9274V16.7132H82.9635V11.5477C82.9635 9.83214 83.8307 8.70101 85.2257 8.70101C86.5642 8.70101 87.2618 9.58706 87.2618 11.2838V16.7132H89.3167V11.4911C89.3167 9.75673 90.2027 8.70101 91.5978 8.70101C92.9174 8.70101 93.615 9.58706 93.615 11.2838V16.7132H95.651V11.1518C95.651 8.09774 94.0297 6.94775 92.0314 6.94775Z",
|
|
47
|
+
fill: "currentColor"
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ jsx("path", {
|
|
50
|
+
d: "M103.228 6.94775C101.738 6.94775 100.739 7.62643 100.098 8.49363V3.51665H98.0623V16.7132H99.8344L100.079 15.3181C100.683 16.1853 101.72 16.8263 103.228 16.8263C105.867 16.8263 107.79 14.8468 107.79 11.887C107.79 8.77642 105.867 6.94775 103.228 6.94775ZM102.888 15.1108C101.192 15.1108 100.079 13.7722 100.079 11.8682C100.079 10.0018 101.192 8.68216 102.888 8.68216C104.585 8.68216 105.716 10.0018 105.716 11.887C105.716 13.7911 104.585 15.1108 102.888 15.1108Z",
|
|
51
|
+
fill: "currentColor"
|
|
52
|
+
}),
|
|
53
|
+
/* @__PURE__ */ jsx("path", {
|
|
54
|
+
d: "M109.987 16.7132H112.023V3.51665H109.987V16.7132Z",
|
|
55
|
+
fill: "currentColor"
|
|
56
|
+
}),
|
|
57
|
+
/* @__PURE__ */ jsx("path", {
|
|
58
|
+
d: "M117.375 16.7697L116.998 17.7124C116.696 18.5041 116.507 18.6927 115.716 18.6927H114.283V20.4836H116.47C117.884 20.4836 118.298 19.7861 118.902 18.2214L123.275 7.06087H121.107L118.487 14.3944L115.791 7.06087H113.623L117.375 16.7697Z",
|
|
59
|
+
fill: "currentColor"
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ jsx("path", {
|
|
62
|
+
d: "M125.769 16.7132L126.994 13.4518H132.405L133.649 16.7132H135.968L131.047 3.51665H128.465L123.525 16.7132H125.769ZM129.69 5.85433L131.801 11.6042H127.597L129.69 5.85433Z",
|
|
63
|
+
fill: "currentColor"
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ jsx("path", {
|
|
66
|
+
d: "M137.887 16.7132H140.055V3.51665H137.887V16.7132Z",
|
|
67
|
+
fill: "currentColor"
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ jsx("path", {
|
|
70
|
+
fillRule: "evenodd",
|
|
71
|
+
clipRule: "evenodd",
|
|
72
|
+
d: "M12.2496 0C10.4867 0 8.90488 1.08157 8.26713 2.72302L0 24H6.28017L12.7874 7.25245H12.7902C12.9534 6.84425 13.353 6.55584 13.8199 6.55584C14.2869 6.55584 14.6864 6.84425 14.8497 7.25245H15.7167V3.85532H14.1073L15.6053 0H12.2496Z",
|
|
73
|
+
fill: "#2545D3"
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ jsx("path", {
|
|
76
|
+
fillRule: "evenodd",
|
|
77
|
+
clipRule: "evenodd",
|
|
78
|
+
d: "M8.2677 2.72302C8.87959 1.1483 10.3603 0.0888597 12.0361 0.00532694L12.034 0H12.2501H14.6661H15.4972C17.2601 0 18.8419 1.08157 19.4797 2.72302L27.7468 24H21.3592L13.3424 3.36747C12.8835 2.35631 11.864 1.65296 10.6801 1.65296C9.49331 1.65296 8.47176 2.35976 8.0144 3.37493L8.2677 2.72302Z",
|
|
79
|
+
fill: "#566DE8"
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//#endregion
|
|
85
|
+
export { AaiLogo as t };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One word for where the CALL has got to, for each {@link AgentState} there is.
|
|
3
|
+
*
|
|
4
|
+
* The sibling of `WORKFLOW_STATUS_LABELS` next door, for the same reason and
|
|
5
|
+
* with the same shape. Three custom chromes carried three renderings of this
|
|
6
|
+
* one seven-member union, all written as a chain of ternaries over the raw
|
|
7
|
+
* member: one mapped `speaking` to "Narrating" and fell through to "Idle" for
|
|
8
|
+
* everything it had not listed, one shouted (`thinking` → "PROCESSING"), and
|
|
9
|
+
* the third rendered the enum member itself — so a caller of that agent read a
|
|
10
|
+
* lowercase `disconnected` in the header of a page nobody had decided to say
|
|
11
|
+
* that on.
|
|
12
|
+
*
|
|
13
|
+
* The exhaustiveness argument is the one that makes this worth exporting rather
|
|
14
|
+
* than documenting. A `Record` over {@link AgentState} means a state ADDED to
|
|
15
|
+
* the union is a compile error HERE, in one place every page inherits, instead
|
|
16
|
+
* of falling through each page's own `: "Idle"` tail into whichever word that
|
|
17
|
+
* page happened to end on — which is a silent wrong label, not a missing one. A
|
|
18
|
+
* page overriding one member keeps that: spreading a complete record cannot
|
|
19
|
+
* drop a key.
|
|
20
|
+
*
|
|
21
|
+
* `SessionStateDot` (`components/session-state-dot.tsx`) is the dot beside it,
|
|
22
|
+
* and this paragraph used to argue against one: the dot's palette is what each
|
|
23
|
+
* chrome exists to look like — a CRT's glow, a dispatch board's alert colours —
|
|
24
|
+
* and a component would take the one part that is genuinely shared (the words)
|
|
25
|
+
* hostage to the part that is not. It takes the palette as a PROP, so it does
|
|
26
|
+
* not: what it shares is the exhaustive colour lookup, this record as the label
|
|
27
|
+
* fallback, and the pulse rule, and the three chromes that had each written
|
|
28
|
+
* those fourteen lines around their own `satisfies Record<AgentState, string>`
|
|
29
|
+
* keep the record and lose the lines.
|
|
30
|
+
*/
|
|
31
|
+
import type { AgentState } from "./types.ts";
|
|
32
|
+
/**
|
|
33
|
+
* The default label per {@link AgentState}.
|
|
34
|
+
*
|
|
35
|
+
* Override the ones your page has a better word for and keep the rest:
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* import type { AgentState } from "@alexkroman1/aai-ui";
|
|
39
|
+
* import { AGENT_STATE_LABELS } from "@alexkroman1/aai-ui";
|
|
40
|
+
*
|
|
41
|
+
* // A dispatch board that shouts, and renames one state.
|
|
42
|
+
* const STATE_LABEL = { ...AGENT_STATE_LABELS, thinking: "Processing" };
|
|
43
|
+
* const shout = (s: AgentState) => STATE_LABEL[s].toUpperCase();
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* **Sentence case, deliberately.** A template that wants caps applies its own
|
|
47
|
+
* `.toUpperCase()`, and a template that wants Title Case is already there;
|
|
48
|
+
* shipping the shouted form instead would leave the two chromes that do not
|
|
49
|
+
* shout with a string they have to un-shout, which no case transform does
|
|
50
|
+
* correctly.
|
|
51
|
+
*
|
|
52
|
+
* Two wordings are decisions rather than transliterations of the member name:
|
|
53
|
+
*
|
|
54
|
+
* - `disconnected` is **"Idle"**. It is the state a session is in BEFORE it has
|
|
55
|
+
* ever started as well as after it ends, so it is the first word most callers
|
|
56
|
+
* see; "Disconnected" reads as a fault on a page where nothing has gone
|
|
57
|
+
* wrong yet. Both chromes that mapped this state by hand chose "Idle" too.
|
|
58
|
+
* - `connecting` and `thinking` carry an ellipsis, `listening` and `speaking`
|
|
59
|
+
* do not. The first two are waits with nothing for the caller to do; the
|
|
60
|
+
* other two describe someone actually talking. Same distinction
|
|
61
|
+
* `WORKFLOW_STATUS_LABELS` draws with its one "Working…".
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export declare const AGENT_STATE_LABELS: Readonly<Record<AgentState, string>>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading what the agent projects — `agent({ syncState })` — in the browser.
|
|
3
|
+
*
|
|
4
|
+
* The frame is KEYED by slot name (`{ [slot]: view }`), so every reader here
|
|
5
|
+
* selects ONE slot by the name the agent keyed it under. That is what lets a
|
|
6
|
+
* component re-render only when ITS slot changed: the session core keeps an
|
|
7
|
+
* unchanged slot's value referentially stable across pushes, and
|
|
8
|
+
* {@link selectAgentState} is a stable selector per key, so
|
|
9
|
+
* `useSessionSelector`'s `Object.is` comparison does the rest.
|
|
10
|
+
*
|
|
11
|
+
* Split out of `hooks.ts` at the source-length cap; re-exported from there.
|
|
12
|
+
*/
|
|
13
|
+
import type { DefaultToolResult, StateProjection } from "@alexkroman1/aai";
|
|
14
|
+
import type { AgentStateFrame, SessionSnapshot } from "./session/index.ts";
|
|
15
|
+
/**
|
|
16
|
+
* A `useSessionSelector` selector for ONE slot of the agent's projected state:
|
|
17
|
+
* its value, or `undefined` before the agent has pushed it.
|
|
18
|
+
*
|
|
19
|
+
* The same function for the same name on every call, which is load-bearing:
|
|
20
|
+
* `useSessionSelector` caches its selection on the selector's identity, and an
|
|
21
|
+
* inline arrow would re-run it on every snapshot.
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { selectAgentState, useSessionSelector } from "@alexkroman1/aai-ui";
|
|
25
|
+
*
|
|
26
|
+
* function CartBadge() {
|
|
27
|
+
* // Re-renders when the `cart` slot changes, and on nothing else.
|
|
28
|
+
* const cart = useSessionSelector(selectAgentState<{ count: number }>("cart"));
|
|
29
|
+
* return <span>{cart?.count ?? 0}</span>;
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export declare function selectAgentState<V = DefaultToolResult>(slot: string): (snapshot: SessionSnapshot) => V | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The agent's whole projected frame — `{ [slot]: view }` for every slot its
|
|
38
|
+
* `syncState` names — or `null` before the first push. Prefer naming the slot
|
|
39
|
+
* (the overloads below): a component reading the whole frame re-renders when
|
|
40
|
+
* any slot changes.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export declare function useAgentState(): AgentStateFrame | null;
|
|
45
|
+
/**
|
|
46
|
+
* One slot's projected state, typed and defaulted by the SAME projection the
|
|
47
|
+
* agent pushes — pass `slot.projected` and there is no type argument to
|
|
48
|
+
* restate, no slot name to repeat and no empty frame to derive.
|
|
49
|
+
*
|
|
50
|
+
* ```tsx
|
|
51
|
+
* import { sessionSlot } from "@alexkroman1/aai";
|
|
52
|
+
* import { useAgentState } from "@alexkroman1/aai-ui";
|
|
53
|
+
*
|
|
54
|
+
* // In a real project the slot is declared beside the agent and imported here;
|
|
55
|
+
* // the agent declares `syncState: cartSlot.projected`.
|
|
56
|
+
* const cartSlot = sessionSlot("cart", () => ({ items: [] as string[] }), {
|
|
57
|
+
* view: (cart) => ({ count: cart.items.length }),
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* function CartBadge() {
|
|
61
|
+
* const cart = useAgentState(cartSlot.projected); // reads state.cart
|
|
62
|
+
* return <span>{cart.count}</span>;
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* The projection carries its slot key, so this selects `state[projection.key]`
|
|
67
|
+
* — the key the agent's `syncState` frame is keyed by. Before the first
|
|
68
|
+
* push it answers `projection()`, the slot's DEFAULT through the same view,
|
|
69
|
+
* memoized on the projection's identity; `slot.projected` is built once with
|
|
70
|
+
* the slot, so that identity is stable for the life of the component.
|
|
71
|
+
*
|
|
72
|
+
* **The one case that cannot use this overload is a slot whose declaring
|
|
73
|
+
* module is expensive to IMPORT** (a seeded factory pulls its seed into the
|
|
74
|
+
* browser bundle): name the slot instead, with a fallback.
|
|
75
|
+
*
|
|
76
|
+
* @public
|
|
77
|
+
*/
|
|
78
|
+
export declare function useAgentState<V>(projection: StateProjection<V>): V;
|
|
79
|
+
/**
|
|
80
|
+
* One slot's projected state by NAME, or `null` before the agent pushed it.
|
|
81
|
+
* Typed by the caller, as `useToolResult` is: the shape is the author's own
|
|
82
|
+
* projection, which this file cannot see.
|
|
83
|
+
*
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
export declare function useAgentState<V = DefaultToolResult>(slot: string): V | null;
|
|
87
|
+
/**
|
|
88
|
+
* One slot's projected state by NAME, falling back to `fallback` before the
|
|
89
|
+
* first push — for a slot whose module the browser should not import. Build the
|
|
90
|
+
* fallback by running the SAME view over an empty state, and hoist it to module
|
|
91
|
+
* scope so it is a stable reference.
|
|
92
|
+
*
|
|
93
|
+
* ```tsx
|
|
94
|
+
* import { useAgentState } from "@alexkroman1/aai-ui";
|
|
95
|
+
*
|
|
96
|
+
* type StoreView = { orders: string[] };
|
|
97
|
+
* // Hoisted, so it is one reference for the life of the component.
|
|
98
|
+
* const EMPTY: StoreView = { orders: [] };
|
|
99
|
+
*
|
|
100
|
+
* function Orders() {
|
|
101
|
+
* const view = useAgentState("retail", EMPTY);
|
|
102
|
+
* return <p>{view.orders.length} orders</p>;
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
export declare function useAgentState<V>(slot: string, fallback: V): V;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Throw unless the browser honored a requested context sample rate. The
|
|
3
|
+
* requested rates are never advisory: captured audio is tagged with the
|
|
4
|
+
* requested rate on the wire, so a context running at some other rate ships
|
|
5
|
+
* audio that only sounds like speech to the wrong decoder. Every capture
|
|
6
|
+
* path must call this after context creation.
|
|
7
|
+
*/
|
|
8
|
+
export declare function assertGranted(granted: number, requested: number, side: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* The error a dead worklet processor reports.
|
|
11
|
+
*
|
|
12
|
+
* A processor exception permanently kills the node — no further messages or
|
|
13
|
+
* audio will ever arrive — so both sides log it and hand it on. One spelling of
|
|
14
|
+
* that, because the pair differed only in the word "capture"/"playback" and in
|
|
15
|
+
* what the playback side has to settle afterwards.
|
|
16
|
+
*/
|
|
17
|
+
export declare function workletCrash(side: "capture" | "playback"): Error;
|
|
18
|
+
/**
|
|
19
|
+
* Release a microphone that was (or later gets) granted while another init
|
|
20
|
+
* step failed; if `getUserMedia` itself rejected, this is a no-op. Without
|
|
21
|
+
* it, a mic granted after a failed init keeps the browser's recording
|
|
22
|
+
* indicator lit with no way to turn it off.
|
|
23
|
+
*/
|
|
24
|
+
export declare function releaseStreamOnFailure(streamPromise: Promise<MediaStream>): void;
|
|
25
|
+
/** Handle to one capture worklet node (`worklets/capture-processor.ts`). */
|
|
26
|
+
export type CaptureNode = {
|
|
27
|
+
node: AudioWorkletNode;
|
|
28
|
+
/** Begin accumulating — the worklet gates capture on its start/stop protocol. */
|
|
29
|
+
start(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Stop accumulating and wait (bounded by {@link CAPTURE_STOP_ACK_TIMEOUT_MS})
|
|
32
|
+
* for the 'stopped' ack that follows the worklet's final flush, so the tail
|
|
33
|
+
* of speech reaches `onChunk` before the node is torn down.
|
|
34
|
+
*/
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Wire one capture worklet node: node construction, the chunk/silent/stopped
|
|
39
|
+
* port protocol, and the stop→ack handshake. No `processorOptions`: the
|
|
40
|
+
* worklet reads the context rate from its global scope (callers assert the
|
|
41
|
+
* granted rate first) and owns its own batching default — re-spelling
|
|
42
|
+
* defaults caller-side is drift.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createCaptureNode(ctx: AudioContext, onChunk: (pcm16: ArrayBuffer) => void, onSilent?: () => void): CaptureNode;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser audio layer's import surface for the rest of the package: the
|
|
3
|
+
* {@link VoiceIO} a live call plays and captures through, and the pre-connect
|
|
4
|
+
* capture that buffers the mic before the server names its rates.
|
|
5
|
+
*
|
|
6
|
+
* `capture.ts` (the grant checks and the capture node both halves share) is
|
|
7
|
+
* private to this directory — guard-invariants rule 37 fails an import from
|
|
8
|
+
* outside `audio/` that names any module but this one.
|
|
9
|
+
*
|
|
10
|
+
* The session core reaches this module only through a DYNAMIC `import()`
|
|
11
|
+
* (`session/audio-setup.ts`, `session/preconnect.ts`), so it is a lazily
|
|
12
|
+
* fetched chunk; a static VALUE import of it from session code would put it
|
|
13
|
+
* back on the main bundle. Type imports are free.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
export { openPreConnectCapture, type PreConnectCapture } from "./preconnect.ts";
|
|
18
|
+
export { createVoiceIO, type VoiceIO, type VoiceIOOptions } from "./voice-io.ts";
|