@alexkroman1/aai-ui 0.16.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.
Files changed (123) hide show
  1. package/README.md +6 -7
  2. package/dist/_submission-timing.d.ts +40 -0
  3. package/dist/_submission.d.ts +56 -0
  4. package/dist/_theme.d.ts +17 -0
  5. package/dist/_theme.test-d.d.ts +14 -0
  6. package/dist/{_utils-Mi-SCFA1.js → _utils-BlZBJPdj.js} +4 -5
  7. package/dist/_utils.d.ts +4 -5
  8. package/dist/agent-state-labels.d.ts +8 -3
  9. package/dist/agent-state.d.ts +4 -2
  10. package/dist/append-dictation.d.ts +23 -0
  11. package/dist/audio/dictation.d.ts +36 -0
  12. package/dist/audio/index.d.ts +4 -2
  13. package/dist/audio/index.js +44 -1
  14. package/dist/{chat-view-DIwPoAEG.js → chat-view-BwKpF0MN.js} +65 -45
  15. package/dist/{client-config-C7fQrioM.js → client-config-DcMCWmkO.js} +8 -13
  16. package/dist/client-config.d.ts +29 -10
  17. package/dist/components/_form-readiness.d.ts +2 -1
  18. package/dist/components/audio-result.d.ts +2 -0
  19. package/dist/components/bullet-list.d.ts +1 -0
  20. package/dist/components/button.d.ts +2 -2
  21. package/dist/components/button.js +1 -1
  22. package/dist/components/chat-view.js +1 -2
  23. package/dist/components/console-shell.d.ts +8 -5
  24. package/dist/components/controls.d.ts +1 -0
  25. package/dist/components/controls.js +2 -2
  26. package/dist/components/conversation-view.d.ts +1 -0
  27. package/dist/components/facts.d.ts +1 -0
  28. package/dist/components/form-fields.d.ts +31 -12
  29. package/dist/components/form-types.d.ts +48 -2
  30. package/dist/components/form.d.ts +10 -5
  31. package/dist/components/markdown.d.ts +1 -0
  32. package/dist/components/message-list.d.ts +1 -0
  33. package/dist/components/message-list.js +1 -2
  34. package/dist/components/session-controls.d.ts +7 -2
  35. package/dist/components/session-error-banner.d.ts +1 -0
  36. package/dist/components/session-state-dot.d.ts +45 -20
  37. package/dist/components/sidebar-layout.d.ts +2 -2
  38. package/dist/components/sidebar-layout.js +1 -1
  39. package/dist/components/start-screen.js +2 -2
  40. package/dist/components/tool-call-block.d.ts +3 -3
  41. package/dist/components/tool-call-block.js +1 -2
  42. package/dist/components/tool-call-row.d.ts +1 -0
  43. package/dist/components/tool-config-context.d.ts +23 -5
  44. package/dist/components/url-chips.d.ts +4 -3
  45. package/dist/components/workflow-fields.d.ts +36 -11
  46. package/dist/components/workflow-pending-note.d.ts +31 -12
  47. package/dist/components/workflow-run-error.d.ts +1 -0
  48. package/dist/components/workflow-run-panel.d.ts +1 -0
  49. package/dist/context-BF0KsI9X.js +473 -0
  50. package/dist/context.d.ts +8 -7
  51. package/dist/context.js +1 -381
  52. package/dist/default-client/assets/audio-CtBvSS3L.js +1 -0
  53. package/dist/default-client/assets/{capture-processor-CXCWxCO8.js → capture-processor-BZXisGjZ.js} +1 -1
  54. package/dist/default-client/assets/index-BkjCv4MX.css +2 -0
  55. package/dist/default-client/assets/index-DUQoaxdq.js +127 -0
  56. package/dist/default-client/assets/{playback-processor-DXHfyQD9.js → playback-processor-BHk-iXEU.js} +1 -1
  57. package/dist/default-client/index.html +2 -2
  58. package/dist/default-client.d.ts +1 -3
  59. package/dist/define-client.d.ts +32 -28
  60. package/dist/define-client.js +85 -44
  61. package/dist/dictation-transcriber.d.ts +49 -0
  62. package/dist/{eyebrow-UfmSz9yy.js → eyebrow-Bp4y1rZ9.js} +1 -1
  63. package/dist/{hooks-DN4gHYsj.js → hooks-1CoQY_Fc.js} +2 -2
  64. package/dist/hooks.js +1 -2
  65. package/dist/inbox-protocol.d.ts +14 -4
  66. package/dist/inbox.d.ts +1 -0
  67. package/dist/index.d.ts +12 -9
  68. package/dist/index.js +905 -277
  69. package/dist/internal.d.ts +1 -1
  70. package/dist/internal.js +6 -6
  71. package/dist/linked-client.d.ts +2 -0
  72. package/dist/{message-list-DHZcLhRA.js → message-list-BBHLK05X.js} +24 -13
  73. package/dist/page.d.ts +2 -0
  74. package/dist/phone.d.ts +1 -0
  75. package/dist/route-fetch.d.ts +8 -1
  76. package/dist/session/audio-setup.d.ts +1 -1
  77. package/dist/session/audio-state.d.ts +6 -6
  78. package/dist/session/index.js +1 -1
  79. package/dist/session/messages.d.ts +1 -9
  80. package/dist/session/preconnect.d.ts +1 -1
  81. package/dist/session/types.d.ts +4 -0
  82. package/dist/{session-CYdjRvbl.js → session-Rud8mmU-.js} +26 -15
  83. package/dist/stored-value.d.ts +2 -0
  84. package/dist/{tool-call-block-uXtMOUWN.js → tool-call-block-C8s6AhjS.js} +4 -4
  85. package/dist/tool-config-context-Bd-7xrfP.js +28 -0
  86. package/dist/types.d.ts +95 -6
  87. package/dist/{url-chips-oyy_Eiqh.js → url-chips-C_SHU6fq.js} +2 -2
  88. package/dist/use-client-runs.d.ts +2 -0
  89. package/dist/use-conversation-log.d.ts +2 -0
  90. package/dist/use-conversation.d.ts +24 -9
  91. package/dist/use-copy.d.ts +1 -0
  92. package/dist/use-dictation.d.ts +145 -0
  93. package/dist/use-download-url.d.ts +6 -1
  94. package/dist/use-flash.d.ts +1 -0
  95. package/dist/use-inbox.d.ts +2 -0
  96. package/dist/use-push-to-talk.d.ts +6 -1
  97. package/dist/use-route-mutation.d.ts +3 -0
  98. package/dist/use-route.d.ts +51 -7
  99. package/dist/use-run-key.d.ts +6 -1
  100. package/dist/use-session-controls.d.ts +1 -0
  101. package/dist/use-tap-to-talk.d.ts +5 -2
  102. package/dist/{use-user-transcript-uyHhzy4d.js → use-user-transcript-lOu_uMnf.js} +1 -1
  103. package/dist/use-user-transcript.d.ts +5 -1
  104. package/dist/use-workflow-form.d.ts +76 -167
  105. package/dist/use-workflow-progress.d.ts +5 -0
  106. package/dist/{use-workflow-run-DdhWmbx-.js → use-workflow-run-BTEemod0.js} +2 -2
  107. package/dist/use-workflow-run.d.ts +5 -0
  108. package/dist/use-workflow-runs.d.ts +18 -4
  109. package/dist/use-workflow-stream.d.ts +33 -7
  110. package/dist/use-workflows.d.ts +10 -2
  111. package/dist/workflow-client.d.ts +5 -0
  112. package/dist/workflow-def-types.d.ts +18 -2
  113. package/dist/workflow-field-kind.d.ts +66 -10
  114. package/dist/workflow-submission.d.ts +265 -0
  115. package/dist/worklets/capture-processor.d.ts +3 -3
  116. package/dist/worklets/capture-processor.js +2 -2
  117. package/dist/worklets/playback-processor.d.ts +3 -3
  118. package/dist/worklets/playback-processor.js +2 -2
  119. package/package.json +2 -2
  120. package/dist/default-client/assets/audio-DzwGxdv4.js +0 -1
  121. package/dist/default-client/assets/index-BOTLwsNO.js +0 -126
  122. package/dist/default-client/assets/index-_-x5JLLa.css +0 -2
  123. package/dist/tool-config-context-Es4YUzV2.js +0 -19
@@ -33,6 +33,12 @@ import { type UseUserTranscriptResult } from "./use-user-transcript.ts";
33
33
  * is the thing this hook computes — handing back two lists would hand back the
34
34
  * problem. `kind` is what a `switch` in a custom renderer narrows on.
35
35
  *
36
+ * `"other"` is the row this version cannot describe — today, an item a newer
37
+ * page wrote into a stored conversation log (`type` is the `kind` it was
38
+ * stored under). It is a member from the start so that a row kind added
39
+ * later is a value an existing `switch` already has a branch for, not a
40
+ * compile error: render nothing for it, or a placeholder.
41
+ *
36
42
  * @public
37
43
  */
38
44
  export type ConversationItem = {
@@ -41,10 +47,14 @@ export type ConversationItem = {
41
47
  } | {
42
48
  kind: "tool";
43
49
  toolCall: ToolCallInfo;
50
+ } | {
51
+ kind: "other";
52
+ type: string;
44
53
  };
45
54
  /**
46
55
  * What {@link useConversation} returns.
47
56
  *
57
+ * @sealed
48
58
  * @public
49
59
  */
50
60
  export type UseConversationResult = {
@@ -107,15 +117,20 @@ export declare function interleave(messages: readonly ChatMessage[], toolCalls:
107
117
  * const { items, streaming, transcript, thinking } = useConversation();
108
118
  * return (
109
119
  * <div>
110
- * {items.map((item) =>
111
- * item.kind === "message" ? (
112
- * <p key={item.message.id} data-role={item.message.role}>
113
- * {item.message.content}
114
- * </p>
115
- * ) : (
116
- * <code key={item.toolCall.callId}>{item.toolCall.name}</code>
117
- * ),
118
- * )}
120
+ * {items.map((item) => {
121
+ * switch (item.kind) {
122
+ * case "message":
123
+ * return (
124
+ * <p key={item.message.id} data-role={item.message.role}>
125
+ * {item.message.content}
126
+ * </p>
127
+ * );
128
+ * case "tool":
129
+ * return <code key={item.toolCall.callId}>{item.toolCall.name}</code>;
130
+ * default:
131
+ * return null;
132
+ * }
133
+ * })}
119
134
  * {streaming !== null && <p data-role="assistant">{streaming}</p>}
120
135
  * {transcript.speaking && <p data-role="user">{transcript.text}</p>}
121
136
  * {thinking && <p>…</p>}
@@ -17,6 +17,7 @@
17
17
  * What {@link useCopy} hands back — the click handler and the two readings a
18
18
  * button needs off one shared flash.
19
19
  *
20
+ * @sealed
20
21
  * @public
21
22
  */
22
23
  export type UseCopyResult = {
@@ -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;
@@ -23,7 +23,11 @@
23
23
  * "downloading" as the same thing — so this reports it.
24
24
  */
25
25
  import type { WorkflowApi } from "./workflow-client.ts";
26
- /** Options for {@link useDownloadUrl}. */
26
+ /**
27
+ * Options for {@link useDownloadUrl}.
28
+ *
29
+ * @input
30
+ */
27
31
  export type UseDownloadUrlOptions = {
28
32
  /** The client to read the bytes with. Defaults to one for the page's own agent. */
29
33
  api?: WorkflowApi;
@@ -31,6 +35,7 @@ export type UseDownloadUrlOptions = {
31
35
  /**
32
36
  * What {@link useDownloadUrl} reports.
33
37
  *
38
+ * @sealed
34
39
  * @public
35
40
  */
36
41
  export type UseDownloadUrlResult = {
@@ -15,6 +15,7 @@
15
15
  * @typeParam T - What is being flashed. A `string` for a label; a record for a
16
16
  * flash that has to say WHICH thing it belongs to, as `useCopy` does.
17
17
  *
18
+ * @sealed
18
19
  * @public
19
20
  */
20
21
  export type UseFlashResult<T> = {
@@ -33,6 +33,7 @@ import type { InboxEvent, InboxNotice } from "./inbox-protocol.ts";
33
33
  /**
34
34
  * Options for {@link useInbox}.
35
35
  *
36
+ * @input
36
37
  * @public
37
38
  */
38
39
  export type UseInboxOptions = {
@@ -63,6 +64,7 @@ export type UseInboxOptions = {
63
64
  /**
64
65
  * What {@link useInbox} returns.
65
66
  *
67
+ * @sealed
66
68
  * @public
67
69
  */
68
70
  export type UseInboxResult = {
@@ -21,7 +21,11 @@
21
21
  * And one that is a nuisance rather than a stuck turn: the hold key is ignored
22
22
  * while focus is in a text field, where Space is a character.
23
23
  */
24
- /** Options for {@link usePushToTalk}. */
24
+ /**
25
+ * Options for {@link usePushToTalk}.
26
+ *
27
+ * @input
28
+ */
25
29
  export type UsePushToTalkOptions = {
26
30
  /**
27
31
  * The keyboard key that holds the turn open, as a `KeyboardEvent.code` —
@@ -34,6 +38,7 @@ export type UsePushToTalkOptions = {
34
38
  /**
35
39
  * What {@link usePushToTalk} returns.
36
40
  *
41
+ * @sealed
37
42
  * @public
38
43
  */
39
44
  export type UsePushToTalkResult = {
@@ -26,6 +26,7 @@ import { type RouteMethod } from "./route-fetch.ts";
26
26
  /**
27
27
  * Options for {@link useRouteMutation}.
28
28
  *
29
+ * @input
29
30
  * @public
30
31
  */
31
32
  export type UseRouteMutationOptions = {
@@ -45,6 +46,7 @@ export type UseRouteMutationOptions = {
45
46
  /**
46
47
  * Options for one {@link UseRouteMutationResult.run} call.
47
48
  *
49
+ * @input
48
50
  * @public
49
51
  */
50
52
  export type RouteMutationRunOptions = {
@@ -58,6 +60,7 @@ export type RouteMutationRunOptions = {
58
60
  /**
59
61
  * What {@link useRouteMutation} returns.
60
62
  *
63
+ * @sealed
61
64
  * @public
62
65
  */
63
66
  export type UseRouteMutationResult = {
@@ -7,33 +7,62 @@
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
  */
13
21
  /**
14
22
  * Options for {@link useRoute}.
15
23
  *
24
+ * @input
16
25
  * @public
17
26
  */
18
- export type UseRouteOptions = {
19
- /** Read again every this many ms, while mounted. Default: never. */
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
+ */
20
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;
21
40
  /**
22
41
  * The `?client=` to send. Default: the session's client
23
42
  * (`session.identity.clientId()`, read per request) inside `mountClient()`,
24
43
  * none on a page with no session.
25
44
  */
26
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;
27
52
  };
28
53
  /**
29
54
  * What {@link useRoute} returns.
30
55
  *
56
+ * @sealed
31
57
  * @public
32
58
  */
33
59
  export type UseRouteResult<T> = {
34
- /** The last answer, kept through a failed re-read. `undefined` until the first. */
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
+ */
35
64
  data: T | undefined;
36
- /** 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`. */
37
66
  error: string | undefined;
38
67
  /** Whether a read is in flight. */
39
68
  loading: boolean;
@@ -42,7 +71,7 @@ export type UseRouteResult<T> = {
42
71
  };
43
72
  /**
44
73
  * `GET` one of the agent's own routes, on mount, on `reload()` and every
45
- * `pollMs` — see this module's doc.
74
+ * `pollMs` until `until` says so — see this module's doc.
46
75
  *
47
76
  * @example A list that re-reads after each delete
48
77
  * ```tsx
@@ -72,11 +101,26 @@ export type UseRouteResult<T> = {
72
101
  * }
73
102
  * ```
74
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
+ *
75
119
  * @typeParam T - The shape the route answers. Not checked.
76
120
  * @param path - The route's path as declared, without `/api`. `null` reads nothing.
77
- * @param options - `pollMs` and `client`; see {@link UseRouteOptions}.
121
+ * @param options - `pollMs`, `until`, `client` and `headers`; see {@link UseRouteOptions}.
78
122
  * @returns The answer, the last error, and `reload`; see {@link UseRouteResult}.
79
123
  *
80
124
  * @public
81
125
  */
82
- 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>;
@@ -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 | undefined): 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
  *
@@ -14,6 +14,7 @@
14
14
  /**
15
15
  * What {@link useSessionControls} returns.
16
16
  *
17
+ * @sealed
17
18
  * @public
18
19
  */
19
20
  export type UseSessionControlsResult = {
@@ -31,6 +31,7 @@
31
31
  /**
32
32
  * Options for {@link useTapToTalk}.
33
33
  *
34
+ * @input
34
35
  * @public
35
36
  */
36
37
  export type UseTapToTalkOptions = {
@@ -56,14 +57,16 @@ export type UseTapToTalkOptions = {
56
57
  /**
57
58
  * What {@link useTapToTalk} returns.
58
59
  *
60
+ * @sealed
59
61
  * @public
60
62
  */
61
63
  export type UseTapToTalkResult = {
62
64
  /**
63
65
  * The call: `"idle"` (not meant to be running), `"connecting"`, or
64
- * `"active"` — up, whatever the agent is doing.
66
+ * `"active"` — up, whatever the agent is doing. Open (`| (string & {})`) so
67
+ * a phase added later is not a break.
65
68
  */
66
- phase: "idle" | "connecting" | "active";
69
+ phase: "idle" | "connecting" | "active" | (string & {});
67
70
  /** Whether the caller is live — mic open, in a realtime conversation. The button is ON. */
68
71
  live: boolean;
69
72
  /**
@@ -1,4 +1,4 @@
1
- import { useSessionSelector } from "./context.js";
1
+ import { c as useSessionSelector } from "./context-BF0KsI9X.js";
2
2
  import { useMemo } from "react";
3
3
  //#region src/use-user-transcript.ts
4
4
  /**
@@ -33,7 +33,11 @@
33
33
  * @internal
34
34
  */
35
35
  export declare const TRANSCRIBING_PLACEHOLDER = "\u2026";
36
- /** What {@link useUserTranscript} returns. */
36
+ /**
37
+ * What {@link useUserTranscript} returns.
38
+ *
39
+ * @sealed
40
+ */
37
41
  export interface UseUserTranscriptResult {
38
42
  /**
39
43
  * True while the caller holds the turn — from speech detection to the final