@alexkroman1/aai-ui 0.17.0 → 0.18.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 +6 -7
- package/dist/_submission-timing.d.ts +40 -0
- package/dist/_submission.d.ts +56 -0
- package/dist/_theme.d.ts +17 -0
- package/dist/_theme.test-d.d.ts +14 -0
- package/dist/{_utils-Mi-SCFA1.js → _utils-BlZBJPdj.js} +4 -5
- package/dist/_utils.d.ts +4 -5
- package/dist/agent-state.d.ts +4 -2
- package/dist/append-dictation.d.ts +23 -0
- package/dist/audio/dictation.d.ts +36 -0
- package/dist/audio/index.d.ts +4 -2
- package/dist/audio/index.js +44 -1
- package/dist/{chat-view-W6KcdjJY.js → chat-view-BwKpF0MN.js} +27 -17
- package/dist/{client-config-CzvWmw4X.js → client-config-DcMCWmkO.js} +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/chat-view.js +1 -2
- package/dist/components/controls.js +2 -2
- package/dist/components/form-fields.d.ts +24 -5
- package/dist/components/form-types.d.ts +32 -0
- package/dist/components/form.d.ts +1 -1
- package/dist/components/message-list.js +1 -2
- package/dist/components/session-state-dot.d.ts +30 -18
- package/dist/components/sidebar-layout.js +1 -1
- package/dist/components/start-screen.js +2 -2
- package/dist/components/tool-call-block.js +1 -2
- package/dist/components/tool-config-context.d.ts +21 -4
- package/dist/components/workflow-fields.d.ts +36 -12
- package/dist/components/workflow-pending-note.d.ts +30 -12
- package/dist/context-BF0KsI9X.js +473 -0
- package/dist/context.js +1 -381
- package/dist/default-client/assets/audio-CtBvSS3L.js +1 -0
- package/dist/default-client/assets/{capture-processor-Cx1AdMHL.js → capture-processor-BZXisGjZ.js} +1 -1
- package/dist/default-client/assets/index-BkjCv4MX.css +2 -0
- package/dist/default-client/assets/index-DUQoaxdq.js +127 -0
- package/dist/default-client/assets/{playback-processor-CCwTknSu.js → playback-processor-BHk-iXEU.js} +1 -1
- package/dist/default-client/index.html +2 -2
- package/dist/default-client.d.ts +1 -3
- package/dist/define-client.d.ts +30 -28
- package/dist/define-client.js +84 -43
- package/dist/dictation-transcriber.d.ts +49 -0
- package/dist/{eyebrow-UfmSz9yy.js → eyebrow-Bp4y1rZ9.js} +1 -1
- package/dist/{hooks-DN4gHYsj.js → hooks-1CoQY_Fc.js} +2 -2
- package/dist/hooks.js +1 -2
- package/dist/index.d.ts +11 -8
- package/dist/index.js +849 -263
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +6 -6
- package/dist/{message-list-BsaBkBgo.js → message-list-BBHLK05X.js} +3 -3
- package/dist/route-fetch.d.ts +7 -1
- package/dist/session/index.js +1 -1
- package/dist/{session-3lgPYNNO.js → session-Rud8mmU-.js} +2 -2
- package/dist/{tool-call-block-uXtMOUWN.js → tool-call-block-C8s6AhjS.js} +4 -4
- package/dist/tool-config-context-Bd-7xrfP.js +28 -0
- package/dist/types.d.ts +47 -2
- package/dist/{url-chips-oyy_Eiqh.js → url-chips-C_SHU6fq.js} +2 -2
- package/dist/use-dictation.d.ts +145 -0
- package/dist/use-route.d.ts +49 -7
- package/dist/use-run-key.d.ts +6 -1
- package/dist/{use-user-transcript-uyHhzy4d.js → use-user-transcript-lOu_uMnf.js} +1 -1
- package/dist/use-workflow-form.d.ts +74 -172
- package/dist/{use-workflow-run-DdhWmbx-.js → use-workflow-run-BTEemod0.js} +2 -2
- package/dist/use-workflow-runs.d.ts +8 -2
- package/dist/use-workflow-stream.d.ts +9 -5
- package/dist/workflow-def-types.d.ts +18 -2
- package/dist/workflow-field-kind.d.ts +59 -7
- package/dist/workflow-submission.d.ts +265 -0
- package/package.json +2 -2
- package/dist/default-client/assets/audio-Ct7JpSNT.js +0 -1
- package/dist/default-client/assets/index-BlUYCTB5.js +0 -126
- package/dist/default-client/assets/index-_-x5JLLa.css +0 -2
- package/dist/tool-config-context-Es4YUzV2.js +0 -19
package/dist/internal.d.ts
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* @module internal
|
|
35
35
|
*/
|
|
36
36
|
export { buildAgentUrl, loadClientConfig } from "./client-config.ts";
|
|
37
|
-
export { ToolConfigContext } from "./components/tool-config-context.ts";
|
|
37
|
+
export { ToolConfigContext, type ToolDisplayConfig } from "./components/tool-config-context.ts";
|
|
38
38
|
export { ApiUrlChip, SessionUrlChips, UiUrlChip } from "./components/url-chips.tsx";
|
|
39
39
|
export { SessionProvider, ThemeProvider } from "./context.ts";
|
|
40
40
|
export { VOICE_CAPTURE_CONSTRAINTS } from "./types.ts";
|
package/dist/internal.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-
|
|
2
|
-
import {
|
|
3
|
-
import { n as SessionUrlChips, r as UiUrlChip, t as ApiUrlChip } from "./url-chips-
|
|
4
|
-
import { t as TRANSCRIBING_PLACEHOLDER } from "./use-user-transcript-
|
|
5
|
-
import {
|
|
6
|
-
import { i as DEFAULT_PROGRESS_POLL_MS, n as MAX_MISSING_READS, t as DEFAULT_WORKFLOW_POLL_MS } from "./use-workflow-run-
|
|
1
|
+
import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-DcMCWmkO.js";
|
|
2
|
+
import { n as ThemeProvider, t as SessionProvider } from "./context-BF0KsI9X.js";
|
|
3
|
+
import { n as SessionUrlChips, r as UiUrlChip, t as ApiUrlChip } from "./url-chips-C_SHU6fq.js";
|
|
4
|
+
import { t as TRANSCRIBING_PLACEHOLDER } from "./use-user-transcript-lOu_uMnf.js";
|
|
5
|
+
import { n as ToolConfigContext } from "./tool-config-context-Bd-7xrfP.js";
|
|
6
|
+
import { i as DEFAULT_PROGRESS_POLL_MS, n as MAX_MISSING_READS, t as DEFAULT_WORKFLOW_POLL_MS } from "./use-workflow-run-BTEemod0.js";
|
|
7
7
|
import { VOICE_CAPTURE_CONSTRAINTS } from "./types.js";
|
|
8
8
|
export { ApiUrlChip, DEFAULT_PROGRESS_POLL_MS, DEFAULT_WORKFLOW_POLL_MS, MAX_MISSING_READS, SessionProvider, SessionUrlChips, TRANSCRIBING_PLACEHOLDER, ThemeProvider, ToolConfigContext, UiUrlChip, VOICE_CAPTURE_CONSTRAINTS, buildAgentUrl, loadClientConfig };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useSessionSelector, useTheme } from "./context.js";
|
|
1
|
+
import { c as useSessionSelector, u as useTheme } from "./context-BF0KsI9X.js";
|
|
2
2
|
import { a as inkTint, o as primaryTint } from "./_colors-CpZO-88A.js";
|
|
3
|
-
import { n as useUserTranscript } from "./use-user-transcript-
|
|
4
|
-
import { n as ToolCallRow, t as ToolCallBlock } from "./tool-call-block-
|
|
3
|
+
import { n as useUserTranscript } from "./use-user-transcript-lOu_uMnf.js";
|
|
4
|
+
import { n as ToolCallRow, t as ToolCallBlock } from "./tool-call-block-C8s6AhjS.js";
|
|
5
5
|
import { memo, useCallback, useMemo } from "react";
|
|
6
6
|
import clsx from "clsx";
|
|
7
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
package/dist/route-fetch.d.ts
CHANGED
|
@@ -41,6 +41,12 @@ export type RouteFetchOptions = {
|
|
|
41
41
|
client?: string | undefined;
|
|
42
42
|
/** The agent's base URL. Default: the page's own directory. */
|
|
43
43
|
baseUrl?: string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Extra request headers — an `authorization` for a route behind
|
|
46
|
+
* `apiKeyRoute`, say. Names are case-insensitive, so a `content-type` (or
|
|
47
|
+
* `Content-Type`) here beats the JSON one a body would set.
|
|
48
|
+
*/
|
|
49
|
+
headers?: Readonly<Record<string, string>> | undefined;
|
|
44
50
|
/** Abort the request. */
|
|
45
51
|
signal?: AbortSignal | undefined;
|
|
46
52
|
};
|
|
@@ -72,7 +78,7 @@ export type RouteFetchOptions = {
|
|
|
72
78
|
* @param method - The route's method.
|
|
73
79
|
* @param path - The route's path as declared, starting with `/`; `?query` allowed.
|
|
74
80
|
* @param body - Sent as JSON when given.
|
|
75
|
-
* @param options - `client`, `baseUrl` and `signal`; see {@link RouteFetchOptions}.
|
|
81
|
+
* @param options - `client`, `baseUrl`, `headers` and `signal`; see {@link RouteFetchOptions}.
|
|
76
82
|
* @returns The parsed JSON body.
|
|
77
83
|
*
|
|
78
84
|
* @public
|
package/dist/session/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ticketCarriage, i as resolveSessionTokenSync, n as CLEARED_SESSION_STATE, o as loadAudioModules, r as resolveSessionToken, t as createBrowserSession } from "../session-
|
|
1
|
+
import { a as ticketCarriage, i as resolveSessionTokenSync, n as CLEARED_SESSION_STATE, o as loadAudioModules, r as resolveSessionToken, t as createBrowserSession } from "../session-Rud8mmU-.js";
|
|
2
2
|
export { CLEARED_SESSION_STATE, createBrowserSession, loadAudioModules, resolveSessionToken, resolveSessionTokenSync, ticketCarriage };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as pageBaseUrl } from "./_utils-
|
|
2
|
-
import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-
|
|
1
|
+
import { n as pageBaseUrl } from "./_utils-BlZBJPdj.js";
|
|
2
|
+
import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-DcMCWmkO.js";
|
|
3
3
|
import { MIC_SEND_MAX_BUFFERED_BYTES } from "./types.js";
|
|
4
4
|
import { errorMessage, safeJsonParse } from "@alexkroman1/aai";
|
|
5
5
|
import { SESSION_AUTH_PROTOCOL_PREFIX, SESSION_PROTOCOL, SessionEventSchema, lenientParse } from "@alexkroman1/aai/protocol";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as tryParseJSON, i as truncate } from "./_utils-
|
|
2
|
-
import { useTheme } from "./context.js";
|
|
1
|
+
import { a as tryParseJSON, i as truncate } from "./_utils-BlZBJPdj.js";
|
|
2
|
+
import { u as useTheme } from "./context-BF0KsI9X.js";
|
|
3
3
|
import { a as inkTint } from "./_colors-CpZO-88A.js";
|
|
4
|
-
import { t as Eyebrow } from "./eyebrow-
|
|
5
|
-
import {
|
|
4
|
+
import { t as Eyebrow } from "./eyebrow-Bp4y1rZ9.js";
|
|
5
|
+
import { r as useToolConfig } from "./tool-config-context-Bd-7xrfP.js";
|
|
6
6
|
import { memo, useMemo, useState } from "react";
|
|
7
7
|
import clsx from "clsx";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
//#region src/components/tool-config-context.ts
|
|
3
|
+
/**
|
|
4
|
+
* The value the context holds before the lookup lands (and forever, when the
|
|
5
|
+
* lookup fails): one frozen object, so the provider's value is stable across
|
|
6
|
+
* renders rather than a fresh `{}` per commit.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
const EMPTY_TOOL_DISPLAY = Object.freeze({});
|
|
11
|
+
/**
|
|
12
|
+
* Context for tool display configuration. Installed by `mountClient()` from
|
|
13
|
+
* the agent's `GET /client-config` `tools`; the built-in components read it
|
|
14
|
+
* via `useToolConfig`.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
const ToolConfigContext = createContext(EMPTY_TOOL_DISPLAY);
|
|
19
|
+
/**
|
|
20
|
+
* Read tool display configuration from the nearest `ToolConfigContext.Provider`.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
function useToolConfig() {
|
|
25
|
+
return useContext(ToolConfigContext);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { ToolConfigContext as n, useToolConfig as r, EMPTY_TOOL_DISPLAY as t };
|
package/dist/types.d.ts
CHANGED
|
@@ -340,12 +340,13 @@ export type WebSocketConstructor = {
|
|
|
340
340
|
readonly OPEN: number;
|
|
341
341
|
};
|
|
342
342
|
/**
|
|
343
|
-
*
|
|
343
|
+
* The five theme tokens, each optional — the long form of {@link ClientTheme},
|
|
344
|
+
* for a page that names its own ground and surfaces.
|
|
344
345
|
*
|
|
345
346
|
* @input
|
|
346
347
|
* @public
|
|
347
348
|
*/
|
|
348
|
-
export type
|
|
349
|
+
export type ClientThemeTokens = {
|
|
349
350
|
/** Background color, also painted on `html`/`body`. Default: `#FAFAFA`. */
|
|
350
351
|
bg?: string;
|
|
351
352
|
/** Primary accent color. Default: `#18181B`. */
|
|
@@ -357,6 +358,50 @@ export type ClientTheme = {
|
|
|
357
358
|
/** Border color. Default: `#E4E4E7`. */
|
|
358
359
|
border?: string;
|
|
359
360
|
};
|
|
361
|
+
/**
|
|
362
|
+
* The short form of {@link ClientTheme}: one accent and a light or dark
|
|
363
|
+
* ground, from which `bg`, `surface`, `text` and `border` are DERIVED.
|
|
364
|
+
*
|
|
365
|
+
* Most pages that themed at all set `primary` and nothing else — and the few
|
|
366
|
+
* that wanted a dark page had to look up four neutrals that go together.
|
|
367
|
+
* `{ primary: "#e55", mode: "dark" }` is that lookup done once
|
|
368
|
+
* (`resolveClientTheme`, `_theme.ts`); `mode` defaults to `"light"`, which is
|
|
369
|
+
* the default palette, so `{ primary }` means the same thing in both forms.
|
|
370
|
+
*
|
|
371
|
+
* @input
|
|
372
|
+
* @public
|
|
373
|
+
*/
|
|
374
|
+
export type ClientThemePreset = {
|
|
375
|
+
/** Primary accent color. */
|
|
376
|
+
primary: string;
|
|
377
|
+
/** The ground the neutrals are derived for. Default: `"light"`. */
|
|
378
|
+
mode?: "dark" | "light";
|
|
379
|
+
};
|
|
380
|
+
/**
|
|
381
|
+
* Theme color overrides for the AAI UI components: the five tokens
|
|
382
|
+
* ({@link ClientThemeTokens}), or an accent plus a light/dark mode
|
|
383
|
+
* ({@link ClientThemePreset}). Either resolves to a {@link ResolvedClientTheme}.
|
|
384
|
+
*
|
|
385
|
+
* The two forms are EXCLUSIVE: a theme naming `mode` may name no token but
|
|
386
|
+
* `primary`, and a theme naming a token may not name `mode`. Without the
|
|
387
|
+
* guards a mixed `{ primary, mode: "dark", bg }` compiled (an object literal is
|
|
388
|
+
* checked against the union as a whole, so a key from either member passed)
|
|
389
|
+
* and `bg` was silently dropped — the preset's derived neutrals won. The guard
|
|
390
|
+
* is `?: undefined` rather than `?: never` so an options bag that spells a hole
|
|
391
|
+
* as `undefined` still fits. `{ primary }` alone is both forms and resolves
|
|
392
|
+
* alike.
|
|
393
|
+
*
|
|
394
|
+
* @input
|
|
395
|
+
* @public
|
|
396
|
+
*/
|
|
397
|
+
export type ClientTheme = (ClientThemeTokens & {
|
|
398
|
+
mode?: undefined;
|
|
399
|
+
}) | (ClientThemePreset & {
|
|
400
|
+
bg?: undefined;
|
|
401
|
+
text?: undefined;
|
|
402
|
+
surface?: undefined;
|
|
403
|
+
border?: undefined;
|
|
404
|
+
});
|
|
360
405
|
/**
|
|
361
406
|
* The theme a component reads back from `useTheme()`: every
|
|
362
407
|
* {@link ClientTheme} field, filled with its default where the client set
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as pageBaseUrl } from "./_utils-
|
|
2
|
-
import { useSessionSelector, useTheme } from "./context.js";
|
|
1
|
+
import { n as pageBaseUrl } from "./_utils-BlZBJPdj.js";
|
|
2
|
+
import { c as useSessionSelector, u as useTheme } from "./context-BF0KsI9X.js";
|
|
3
3
|
import { a as inkTint, i as focusRingStyle, n as FOCUS_RING } from "./_colors-CpZO-88A.js";
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
5
|
import clsx from "clsx";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `useDictation` — speak into a text box: record a clip, have it transcribed,
|
|
3
|
+
* hand the words to the page.
|
|
4
|
+
*
|
|
5
|
+
* Not a session. There is no agent on the other end and no socket: the clip
|
|
6
|
+
* goes to AssemblyAI's dictation API in ONE request, through a `transcribe`
|
|
7
|
+
* callback the page supplies — on the far side of which is a server holding
|
|
8
|
+
* the key, calling `transcribeDictation` from `@alexkroman1/aai/experimental`.
|
|
9
|
+
* The key never reaches the browser, which is why this hook takes a callback
|
|
10
|
+
* rather than a credential.
|
|
11
|
+
*
|
|
12
|
+
* The two ends that are not this hook are published too: `dictationTranscriber`
|
|
13
|
+
* is the `transcribe` for a server answering `handleDictationRequest`'s
|
|
14
|
+
* `{ text } | { error }`, and `appendDictation` adds the words to a draft.
|
|
15
|
+
*
|
|
16
|
+
* What it owns, because each is a way a hand-written mic button goes wrong:
|
|
17
|
+
*
|
|
18
|
+
* - **The recording indicator goes out.** Every way out — stop, cancel, the
|
|
19
|
+
* length cap, an unmount mid-recording — releases the microphone.
|
|
20
|
+
* - **A late answer lands nowhere.** A transcription that settles after a
|
|
21
|
+
* cancel, a newer recording or an unmount is dropped, never typed into the
|
|
22
|
+
* box the user has moved on from.
|
|
23
|
+
* - **The button cannot be pressed into a bad state.** `buttonProps` keeps a
|
|
24
|
+
* recording stoppable while `disabled`, and takes no press mid-transition.
|
|
25
|
+
* - **The clip fits the endpoint.** Recording stops by itself at `maxSeconds`
|
|
26
|
+
* and is transcribed, rather than growing into a clip the service refuses
|
|
27
|
+
* whole.
|
|
28
|
+
*/
|
|
29
|
+
import type { DictationRecorder } from "./audio/index.ts";
|
|
30
|
+
/**
|
|
31
|
+
* Options for {@link useDictation}.
|
|
32
|
+
*
|
|
33
|
+
* @input
|
|
34
|
+
*/
|
|
35
|
+
export type UseDictationOptions = {
|
|
36
|
+
/**
|
|
37
|
+
* Turn one clip — a mono 16-bit WAV — into text. Called once per recording,
|
|
38
|
+
* with a signal that aborts when the result would no longer be used. Usually
|
|
39
|
+
* a `POST` to the page's own server, which forwards the clip to the
|
|
40
|
+
* dictation API under its key. A rejection is shown as `error`.
|
|
41
|
+
*/
|
|
42
|
+
transcribe: (audio: Blob, options: {
|
|
43
|
+
signal: AbortSignal;
|
|
44
|
+
}) => Promise<string>;
|
|
45
|
+
/**
|
|
46
|
+
* The words, once a recording is transcribed. Not called for an empty
|
|
47
|
+
* transcript (the user said nothing) or for a recording that was cancelled.
|
|
48
|
+
*/
|
|
49
|
+
onText: (text: string) => void;
|
|
50
|
+
/**
|
|
51
|
+
* The longest recording, in seconds: it stops and is transcribed by itself
|
|
52
|
+
* then. Defaults to the dictation API's own ceiling, 120.
|
|
53
|
+
*/
|
|
54
|
+
maxSeconds?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Refuse to START a recording — the text box is not accepting input right
|
|
57
|
+
* now. A recording already running can still be stopped and transcribed, so
|
|
58
|
+
* the words said before the box went dead are not lost. Default `false`.
|
|
59
|
+
*/
|
|
60
|
+
disabled?: boolean;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* What {@link useDictation} returns.
|
|
64
|
+
*
|
|
65
|
+
* @sealed
|
|
66
|
+
* @public
|
|
67
|
+
*/
|
|
68
|
+
export type UseDictationResult = {
|
|
69
|
+
/**
|
|
70
|
+
* Where the hook is: `"idle"`, `"starting"` (asking for the microphone),
|
|
71
|
+
* `"recording"` or `"transcribing"`.
|
|
72
|
+
*/
|
|
73
|
+
phase: "idle" | "starting" | "recording" | "transcribing" | (string & {});
|
|
74
|
+
/** Why the last recording produced no text, or `null`. Cleared by `start`. */
|
|
75
|
+
error: string | null;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this browser can record at all — a microphone API, an
|
|
78
|
+
* `AudioContext` and audio worklets. A button should not render without it.
|
|
79
|
+
*/
|
|
80
|
+
supported: boolean;
|
|
81
|
+
/** Ask for the microphone and start recording. Ignored unless idle, and while `disabled`. */
|
|
82
|
+
start: () => void;
|
|
83
|
+
/** Stop recording and transcribe what was said. Ignored unless recording. */
|
|
84
|
+
stop: () => void;
|
|
85
|
+
/** Throw the recording (or the transcription in flight) away. */
|
|
86
|
+
cancel: () => void;
|
|
87
|
+
/** `start` when idle, `stop` when recording — one button. */
|
|
88
|
+
toggle: () => void;
|
|
89
|
+
/**
|
|
90
|
+
* Spread onto a `<button>`: `toggle`, and the two rules a hand-written one
|
|
91
|
+
* gets wrong — a recording can ALWAYS be stopped (even with `disabled` set),
|
|
92
|
+
* and nothing can be pressed while the microphone opens or the clip is
|
|
93
|
+
* transcribing. Label and style it however you like.
|
|
94
|
+
*/
|
|
95
|
+
buttonProps: {
|
|
96
|
+
onClick: () => void;
|
|
97
|
+
disabled: boolean;
|
|
98
|
+
"aria-pressed": boolean;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
/** How a recorder is opened; the real one loads the audio chunk on first use. */
|
|
102
|
+
export type OpenDictationRecorder = (opts: {
|
|
103
|
+
sampleRate: number;
|
|
104
|
+
maxSeconds: number;
|
|
105
|
+
}) => Promise<DictationRecorder>;
|
|
106
|
+
/**
|
|
107
|
+
* Record what the user says and hand it back as text — a microphone button
|
|
108
|
+
* for a text box.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```tsx
|
|
112
|
+
* import { appendDictation, dictationTranscriber, useDictation } from "@alexkroman1/aai-ui";
|
|
113
|
+
* import { useState } from "react";
|
|
114
|
+
*
|
|
115
|
+
* // `POST /dictation` on your own server is `handleDictationRequest`
|
|
116
|
+
* // (`@alexkroman1/aai/experimental`), which holds the API key.
|
|
117
|
+
* const transcribe = dictationTranscriber("/dictation");
|
|
118
|
+
*
|
|
119
|
+
* export function SpokenNote() {
|
|
120
|
+
* const [draft, setDraft] = useState("");
|
|
121
|
+
* const dictation = useDictation({
|
|
122
|
+
* transcribe,
|
|
123
|
+
* onText: (text) => setDraft((d) => appendDictation(d, text)),
|
|
124
|
+
* });
|
|
125
|
+
* return (
|
|
126
|
+
* <div>
|
|
127
|
+
* <textarea value={draft} onChange={(e) => setDraft(e.target.value)} />
|
|
128
|
+
* {dictation.supported && (
|
|
129
|
+
* <button type="button" {...dictation.buttonProps}>
|
|
130
|
+
* {dictation.phase === "recording" ? "Stop" : "Speak"}
|
|
131
|
+
* </button>
|
|
132
|
+
* )}
|
|
133
|
+
* </div>
|
|
134
|
+
* );
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @public
|
|
139
|
+
*/
|
|
140
|
+
export declare function useDictation(options: UseDictationOptions): UseDictationResult;
|
|
141
|
+
/**
|
|
142
|
+
* {@link useDictation} over an injected recorder — the seam the specs drive.
|
|
143
|
+
* Not on the barrel.
|
|
144
|
+
*/
|
|
145
|
+
export declare function useDictationWith(options: UseDictationOptions, open: OpenDictationRecorder): UseDictationResult;
|
package/dist/use-route.d.ts
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
* dropped — `useWorkflowRuns`' rule), a read landing after unmount, and a
|
|
8
8
|
* failure rendered as an empty answer. `data` is KEPT through a failed re-read,
|
|
9
9
|
* so a poll that hiccups does not blank the panel; `error` says it is stale.
|
|
10
|
+
* It is NOT kept across a change of `path`: the answer is remembered with the
|
|
11
|
+
* path it came from, so a page switching from one record to the next never
|
|
12
|
+
* shows the previous one under the new id while the first read is in flight.
|
|
13
|
+
*
|
|
14
|
+
* The poll is `repeatUntil`'s loop (`_repeat-until.ts`), re-armed from the
|
|
15
|
+
* SETTLED read rather than on an interval — a slow route would otherwise
|
|
16
|
+
* stack overlapping reads — and stopped by `until`, by a change of what is
|
|
17
|
+
* read, and by unmount, with the in-flight request aborted on the same signal.
|
|
10
18
|
*
|
|
11
19
|
* @module
|
|
12
20
|
*/
|
|
@@ -16,15 +24,31 @@
|
|
|
16
24
|
* @input
|
|
17
25
|
* @public
|
|
18
26
|
*/
|
|
19
|
-
export type UseRouteOptions = {
|
|
20
|
-
/**
|
|
27
|
+
export type UseRouteOptions<T = unknown> = {
|
|
28
|
+
/**
|
|
29
|
+
* Read again every this many ms, while mounted. `0` or unset: never. A
|
|
30
|
+
* negative or `NaN` value throws rather than polling as fast as the route
|
|
31
|
+
* answers.
|
|
32
|
+
*/
|
|
21
33
|
pollMs?: number | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Stop polling once an answer satisfies this — a call that is over, a job
|
|
36
|
+
* that has settled. Judged on every read, the first included; `reload()`
|
|
37
|
+
* still works afterwards. Read per request, so an inline function is fine.
|
|
38
|
+
*/
|
|
39
|
+
until?: ((value: T) => boolean) | undefined;
|
|
22
40
|
/**
|
|
23
41
|
* The `?client=` to send. Default: the session's client
|
|
24
42
|
* (`session.identity.clientId()`, read per request) inside `mountClient()`,
|
|
25
43
|
* none on a page with no session.
|
|
26
44
|
*/
|
|
27
45
|
client?: string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Extra request headers, as `routeFetch`'s — an `authorization` for a route
|
|
48
|
+
* behind `apiKeyRoute`. Read per request, so an inline object does not
|
|
49
|
+
* re-trigger the read.
|
|
50
|
+
*/
|
|
51
|
+
headers?: Readonly<Record<string, string>> | undefined;
|
|
28
52
|
};
|
|
29
53
|
/**
|
|
30
54
|
* What {@link useRoute} returns.
|
|
@@ -33,9 +57,12 @@ export type UseRouteOptions = {
|
|
|
33
57
|
* @public
|
|
34
58
|
*/
|
|
35
59
|
export type UseRouteResult<T> = {
|
|
36
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* The last answer for THIS `path`, kept through a failed re-read.
|
|
62
|
+
* `undefined` until the first, and again whenever `path` changes.
|
|
63
|
+
*/
|
|
37
64
|
data: T | undefined;
|
|
38
|
-
/** Why the LAST read failed — the route's `{ error }` when it said — or `undefined`. */
|
|
65
|
+
/** Why the LAST read of this `path` failed — the route's `{ error }` when it said — or `undefined`. */
|
|
39
66
|
error: string | undefined;
|
|
40
67
|
/** Whether a read is in flight. */
|
|
41
68
|
loading: boolean;
|
|
@@ -44,7 +71,7 @@ export type UseRouteResult<T> = {
|
|
|
44
71
|
};
|
|
45
72
|
/**
|
|
46
73
|
* `GET` one of the agent's own routes, on mount, on `reload()` and every
|
|
47
|
-
* `pollMs` — see this module's doc.
|
|
74
|
+
* `pollMs` until `until` says so — see this module's doc.
|
|
48
75
|
*
|
|
49
76
|
* @example A list that re-reads after each delete
|
|
50
77
|
* ```tsx
|
|
@@ -74,11 +101,26 @@ export type UseRouteResult<T> = {
|
|
|
74
101
|
* }
|
|
75
102
|
* ```
|
|
76
103
|
*
|
|
104
|
+
* @example A call followed until it is over
|
|
105
|
+
* ```tsx
|
|
106
|
+
* import { useRoute } from "@alexkroman1/aai-ui";
|
|
107
|
+
*
|
|
108
|
+
* type Call = { status: string; transcript: { role: string; text: string }[] };
|
|
109
|
+
*
|
|
110
|
+
* function LiveCall({ id }: { id: string }) {
|
|
111
|
+
* const { data } = useRoute<Call>(`/calls/${id}`, {
|
|
112
|
+
* pollMs: 2000,
|
|
113
|
+
* until: (call) => call.status === "completed",
|
|
114
|
+
* });
|
|
115
|
+
* return <ol>{data?.transcript.map((line, i) => <li key={String(i)}>{line.text}</li>)}</ol>;
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
77
119
|
* @typeParam T - The shape the route answers. Not checked.
|
|
78
120
|
* @param path - The route's path as declared, without `/api`. `null` reads nothing.
|
|
79
|
-
* @param options - `pollMs` and `
|
|
121
|
+
* @param options - `pollMs`, `until`, `client` and `headers`; see {@link UseRouteOptions}.
|
|
80
122
|
* @returns The answer, the last error, and `reload`; see {@link UseRouteResult}.
|
|
81
123
|
*
|
|
82
124
|
* @public
|
|
83
125
|
*/
|
|
84
|
-
export declare function useRoute<T = unknown>(path: string | null, options?: UseRouteOptions): UseRouteResult<T>;
|
|
126
|
+
export declare function useRoute<T = unknown>(path: string | null, options?: UseRouteOptions<T>): UseRouteResult<T>;
|
package/dist/use-run-key.d.ts
CHANGED
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
* the behaviour it would have had anyway — one run per load — rather than
|
|
88
88
|
* failing to render.
|
|
89
89
|
*/
|
|
90
|
+
import { type StorageKind } from "./_web-storage.ts";
|
|
90
91
|
/**
|
|
91
92
|
* The key `useWorkflowSubmit` uses when the page named none.
|
|
92
93
|
*
|
|
@@ -107,10 +108,14 @@
|
|
|
107
108
|
*
|
|
108
109
|
* @param explicit - The caller's own key, or undefined for a page with none.
|
|
109
110
|
* @returns The key to record runs under and look them up by.
|
|
111
|
+
* @throws When the caller's key is empty or whitespace — see
|
|
112
|
+
* {@link assertUsableRunKey}.
|
|
110
113
|
*
|
|
111
114
|
* @internal
|
|
112
115
|
*/
|
|
113
|
-
export declare function useDefaultRunKey(explicit: string |
|
|
116
|
+
export declare function useDefaultRunKey(explicit: string | {
|
|
117
|
+
readonly storage?: StorageKind | undefined;
|
|
118
|
+
} | undefined): string;
|
|
114
119
|
/**
|
|
115
120
|
* A lookup key for `useWorkflowSubmit({ key })`, stable across reloads.
|
|
116
121
|
*
|