@alexkroman1/aai-ui 0.12.3 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +257 -0
  2. package/dist/_colors-CpZO-88A.js +78 -0
  3. package/dist/_module-url-C13kAJ87.js +15 -0
  4. package/dist/_page-shell.d.ts +11 -0
  5. package/dist/_recover-run.d.ts +79 -0
  6. package/dist/_repeat-until.d.ts +30 -0
  7. package/dist/_run-controls.d.ts +33 -0
  8. package/dist/_submission-state.d.ts +92 -0
  9. package/dist/_tap-to-talk-state.d.ts +88 -0
  10. package/dist/_utils-Mi-SCFA1.js +47 -0
  11. package/dist/_utils.d.ts +26 -0
  12. package/dist/_web-storage.d.ts +43 -0
  13. package/dist/_workflow-api-ref.d.ts +37 -0
  14. package/dist/_workflow-files.d.ts +34 -0
  15. package/dist/_workflow-test-defs.d.ts +38 -0
  16. package/dist/aai-logo-D8pMVn9_.js +85 -0
  17. package/dist/agent-state-labels.d.ts +65 -0
  18. package/dist/agent-state.d.ts +108 -0
  19. package/dist/audio/capture.d.ts +44 -0
  20. package/dist/audio/index.d.ts +18 -0
  21. package/dist/audio/index.js +431 -0
  22. package/dist/audio/preconnect.d.ts +87 -0
  23. package/dist/audio/voice-io.d.ts +112 -0
  24. package/dist/build-default-client.d.ts +1 -0
  25. package/dist/chat-view-BCbI7gD4.js +396 -0
  26. package/dist/client-config-C7fQrioM.js +139 -0
  27. package/dist/client-config.d.ts +119 -0
  28. package/dist/client-dir.d.ts +44 -0
  29. package/dist/client-dir.js +58 -0
  30. package/dist/client-identity.d.ts +131 -0
  31. package/dist/client-tool.d.ts +51 -0
  32. package/dist/components/_colors.d.ts +73 -0
  33. package/dist/components/_form-readiness.d.ts +56 -0
  34. package/dist/components/_form-values.d.ts +19 -0
  35. package/dist/components/aai-logo.d.ts +12 -0
  36. package/dist/components/audio-result.d.ts +94 -0
  37. package/dist/components/auto-scroll.d.ts +74 -0
  38. package/dist/components/bullet-list.d.ts +74 -0
  39. package/dist/components/button.d.ts +29 -21
  40. package/dist/components/button.js +62 -23
  41. package/dist/components/chat-view.d.ts +24 -18
  42. package/dist/components/chat-view.js +2 -60
  43. package/dist/components/console-shell.d.ts +85 -0
  44. package/dist/components/controls.d.ts +21 -6
  45. package/dist/components/controls.js +31 -19
  46. package/dist/components/conversation-view.d.ts +130 -0
  47. package/dist/components/eyebrow.d.ts +12 -0
  48. package/dist/components/facts.d.ts +81 -0
  49. package/dist/components/form-fields.d.ts +142 -0
  50. package/dist/components/form-types.d.ts +73 -0
  51. package/dist/components/form.d.ts +96 -0
  52. package/dist/components/markdown.d.ts +57 -0
  53. package/dist/components/message-list.d.ts +34 -7
  54. package/dist/components/message-list.js +2 -75
  55. package/dist/components/session-controls.d.ts +125 -0
  56. package/dist/components/session-error-banner.d.ts +69 -0
  57. package/dist/components/session-state-dot.d.ts +111 -0
  58. package/dist/components/sidebar-layout.d.ts +31 -10
  59. package/dist/components/sidebar-layout.js +32 -12
  60. package/dist/components/start-screen.d.ts +17 -6
  61. package/dist/components/start-screen.js +34 -14
  62. package/dist/components/tool-call-block.d.ts +15 -14
  63. package/dist/components/tool-call-block.js +2 -117
  64. package/dist/components/tool-call-row.d.ts +75 -0
  65. package/dist/components/tool-config-context.d.ts +22 -0
  66. package/dist/components/upload-progress.d.ts +76 -0
  67. package/dist/components/url-chips.d.ts +29 -0
  68. package/dist/components/workflow-fields.d.ts +46 -0
  69. package/dist/components/workflow-pending-note.d.ts +81 -0
  70. package/dist/components/workflow-progress.d.ts +81 -0
  71. package/dist/components/workflow-run-error.d.ts +48 -0
  72. package/dist/components/workflow-run-panel.d.ts +79 -0
  73. package/dist/context.d.ts +288 -0
  74. package/dist/context.js +382 -0
  75. package/dist/conversation-log.d.ts +88 -0
  76. package/dist/default-client/assets/_module-url-BX0RuRU2.js +1 -0
  77. package/dist/default-client/assets/audio-cGFGID-2.js +1 -0
  78. package/dist/default-client/assets/capture-processor-BUABoo3_.js +90 -0
  79. package/dist/default-client/assets/index-8ihb1Urm.css +2 -0
  80. package/dist/default-client/assets/index-BQURVARl.js +126 -0
  81. package/dist/default-client/assets/playback-processor-ABOa11j0.js +314 -0
  82. package/dist/default-client/favicon.ico +0 -0
  83. package/dist/default-client/index.html +15 -0
  84. package/dist/default-client.d.ts +23 -0
  85. package/dist/define-client.d.ts +162 -26
  86. package/dist/define-client.js +201 -55
  87. package/dist/eyebrow-UfmSz9yy.js +27 -0
  88. package/dist/hooks-DN4gHYsj.js +182 -0
  89. package/dist/hooks.d.ts +172 -0
  90. package/dist/hooks.js +3 -0
  91. package/dist/hooks.test-d.d.ts +14 -0
  92. package/dist/inbox-protocol.d.ts +128 -0
  93. package/dist/inbox.d.ts +132 -0
  94. package/dist/index.d.ts +126 -29
  95. package/dist/index.js +5500 -15
  96. package/dist/internal.d.ts +43 -0
  97. package/dist/internal.js +8 -0
  98. package/dist/linked-client.d.ts +70 -0
  99. package/dist/message-list-DHZcLhRA.js +682 -0
  100. package/dist/notice-player.d.ts +70 -0
  101. package/dist/page.d.ts +114 -0
  102. package/dist/phone.d.ts +50 -0
  103. package/dist/route-fetch.d.ts +79 -0
  104. package/dist/session/audio-effects.d.ts +31 -0
  105. package/dist/session/audio-setup.d.ts +57 -0
  106. package/dist/session/audio-state.d.ts +157 -0
  107. package/dist/session/browser-session.d.ts +30 -0
  108. package/dist/session/close.d.ts +26 -0
  109. package/dist/session/dial.d.ts +65 -0
  110. package/dist/session/handshake.d.ts +60 -0
  111. package/dist/session/index.d.ts +17 -0
  112. package/dist/session/index.js +2 -0
  113. package/dist/session/messages.d.ts +63 -0
  114. package/dist/session/mic.d.ts +64 -0
  115. package/dist/session/preconnect.d.ts +48 -0
  116. package/dist/session/reconnect.d.ts +25 -0
  117. package/dist/session/resume-store.d.ts +57 -0
  118. package/dist/session/state.d.ts +146 -0
  119. package/dist/session/ticket.d.ts +44 -0
  120. package/dist/session/types.d.ts +476 -0
  121. package/dist/session/url.d.ts +17 -0
  122. package/dist/session/user-turn.d.ts +55 -0
  123. package/dist/session-CE0Ipsb3.js +2129 -0
  124. package/dist/stored-value.d.ts +103 -0
  125. package/dist/tool-call-block-uXtMOUWN.js +204 -0
  126. package/dist/tool-config-context-Es4YUzV2.js +19 -0
  127. package/dist/types.d.ts +272 -34
  128. package/dist/types.js +35 -4
  129. package/dist/upload/files.d.ts +83 -0
  130. package/dist/upload/index.d.ts +15 -0
  131. package/dist/upload/pause.d.ts +31 -0
  132. package/dist/upload/recall.d.ts +67 -0
  133. package/dist/upload/report.d.ts +26 -0
  134. package/dist/upload/session.d.ts +99 -0
  135. package/dist/url-chips-oyy_Eiqh.js +239 -0
  136. package/dist/use-client-runs.d.ts +87 -0
  137. package/dist/use-conversation-log.d.ts +86 -0
  138. package/dist/use-conversation.d.ts +131 -0
  139. package/dist/use-copy.d.ts +74 -0
  140. package/dist/use-download-url.d.ts +84 -0
  141. package/dist/use-flash.d.ts +61 -0
  142. package/dist/use-inbox.d.ts +101 -0
  143. package/dist/use-push-to-talk.d.ts +105 -0
  144. package/dist/use-route-mutation.d.ts +113 -0
  145. package/dist/use-route.d.ts +82 -0
  146. package/dist/use-run-key.d.ts +133 -0
  147. package/dist/use-session-controls.d.ts +69 -0
  148. package/dist/use-session-id.d.ts +57 -0
  149. package/dist/use-tap-to-talk.d.ts +138 -0
  150. package/dist/use-user-transcript-uyHhzy4d.js +73 -0
  151. package/dist/use-user-transcript.d.ts +75 -0
  152. package/dist/use-workflow-form.d.ts +285 -0
  153. package/dist/use-workflow-progress.d.ts +137 -0
  154. package/dist/use-workflow-run-DdhWmbx-.js +697 -0
  155. package/dist/use-workflow-run.d.ts +100 -0
  156. package/dist/use-workflow-runs.d.ts +71 -0
  157. package/dist/use-workflow-stream.d.ts +154 -0
  158. package/dist/use-workflows.d.ts +77 -0
  159. package/dist/workflow-client.d.ts +136 -0
  160. package/dist/workflow-def-types.d.ts +31 -0
  161. package/dist/workflow-events.d.ts +39 -0
  162. package/dist/workflow-field-kind.d.ts +95 -0
  163. package/dist/workflow-status-labels.d.ts +35 -0
  164. package/dist/worklets/_module-url.d.ts +10 -0
  165. package/dist/worklets/_playback-bench-harness.d.ts +181 -0
  166. package/dist/worklets/_playback-bench-host.d.ts +63 -0
  167. package/dist/worklets/_playback-bench-page.d.ts +65 -0
  168. package/dist/worklets/_tts-trace-harness.d.ts +142 -0
  169. package/dist/worklets/_worklet-test-utils.d.ts +27 -0
  170. package/dist/worklets/capture-processor.d.ts +4 -2
  171. package/dist/worklets/capture-processor.js +73 -33
  172. package/dist/worklets/playback-processor.d.ts +4 -2
  173. package/dist/worklets/playback-processor.js +258 -42
  174. package/package.json +57 -32
  175. package/styles.css +152 -30
  176. package/dist/audio.d.ts +0 -45
  177. package/dist/audio.js +0 -121
  178. package/dist/client-context.d.ts +0 -33
  179. package/dist/client-context.js +0 -15
  180. package/dist/client-handler.d.ts +0 -43
  181. package/dist/components/app.d.ts +0 -23
  182. package/dist/components/app.js +0 -41
  183. package/dist/components/error-banner.d.ts +0 -21
  184. package/dist/components/error-banner.js +0 -27
  185. package/dist/components/message-bubble.d.ts +0 -23
  186. package/dist/components/message-bubble.js +0 -35
  187. package/dist/components/state-indicator.d.ts +0 -29
  188. package/dist/components/state-indicator.js +0 -37
  189. package/dist/components/thinking-indicator.d.ts +0 -16
  190. package/dist/components/thinking-indicator.js +0 -34
  191. package/dist/components/tool-icons.d.ts +0 -17
  192. package/dist/components/tool-icons.js +0 -128
  193. package/dist/components/transcript.d.ts +0 -25
  194. package/dist/components/transcript.js +0 -35
  195. package/dist/session-CWB7vmqz.js +0 -429
  196. package/dist/session.d.ts +0 -69
  197. package/dist/session.js +0 -2
  198. package/dist/signals.d.ts +0 -120
  199. package/dist/signals.js +0 -161
  200. package/dist/tsdown.config.d.ts +0 -2
  201. package/dist/types.test-d.d.ts +0 -7
@@ -0,0 +1,100 @@
1
+ /**
2
+ * `useWorkflowRun` — watch one run until it settles.
3
+ *
4
+ * Split from `workflow-client.ts` on the seam that module's doc already draws:
5
+ * everything there is a REQUEST (one call, one answer, no React), and everything
6
+ * here is the loop that keeps asking. They are read for different reasons — the
7
+ * client is what a script or a `curl` equivalent needs, this is what a page needs
8
+ * — and only this half imports React.
9
+ *
10
+ * `workflow-events.ts` sits under it as the streaming fast path, and
11
+ * `use-workflow-form.ts` above it as the form-shaped caller.
12
+ */
13
+ import type { WorkflowApi, WorkflowRun } from "./workflow-client.ts";
14
+ /** How often {@link useWorkflowRun} re-reads a live run when it has to poll. */
15
+ export declare const DEFAULT_WORKFLOW_POLL_MS = 2000;
16
+ /**
17
+ * Consecutive "no such run" reads {@link useWorkflowRun} tolerates before giving
18
+ * up on the id.
19
+ *
20
+ * Small on purpose: a 404 is a stable answer, so the budget exists only to
21
+ * absorb a first read that races the run's creation — not to keep hoping.
22
+ * Unbounded, a stale id polls (and, on the platform, BROKERS) for as long as the
23
+ * tab is open.
24
+ */
25
+ export declare const MAX_MISSING_READS = 3;
26
+ export type UseWorkflowRunResult<R = unknown> = {
27
+ /** Latest snapshot, or undefined before the first read lands. */
28
+ run: WorkflowRun<R> | undefined;
29
+ /** The last read's failure, cleared by the next successful one. */
30
+ error: string | undefined;
31
+ /** True while a non-terminal run is still being watched. */
32
+ polling: boolean;
33
+ };
34
+ /**
35
+ * Watch one run until it reaches a terminal status.
36
+ *
37
+ * A watch rather than a subscription because a run is durable and the page is
38
+ * not: it can complete while the tab is closed, on a different sandbox, hours
39
+ * later. There is no session to reconnect — the id is the whole state.
40
+ *
41
+ * Which is also the limit of what this hook can do on its own. An id is state a
42
+ * RELOAD destroys, so a page holding nothing else comes back unable to name a
43
+ * run that is still going. The durable handle is `StartOptions.key`, read back
44
+ * with `find(workflow, key)`, and the hook that owns the id is where that
45
+ * belongs: `useWorkflowSubmit({ key, recover: true })` adopts the key's newest
46
+ * run as it mounts and passes the id here. See `_recover-run.ts` — the reason
47
+ * recovery is NOT in this hook is `reset()`, which leaves the owner holding no
48
+ * id on purpose, and a watcher that re-resolved one from a key would undo it.
49
+ *
50
+ * The stream (`GET /runs/:id/events`) is tried first and the poll is its
51
+ * fallback, so an agent deployed before that route existed still works. Watching
52
+ * STOPS on a terminal status, so a finished run costs nothing; passing
53
+ * `undefined` (nothing started yet) also costs nothing.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * import type { ToolInputSchema, WorkflowDef } from "@alexkroman1/aai";
58
+ * import type { WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
59
+ * import { useWorkflowRun } from "@alexkroman1/aai-ui";
60
+ *
61
+ * // A real page writes `import type { digest } from "./agent.ts"`. Stood in
62
+ * // for here so the example compiles on its own.
63
+ * declare const digest: WorkflowDef<ToolInputSchema, Promise<{ points: string[] }>>;
64
+ *
65
+ * type Digest = WorkflowOutputOf<typeof digest>;
66
+ *
67
+ * function RunPanel({ runId }: { runId: string | undefined }) {
68
+ * // The type argument is what makes `run.output` a `Digest` below.
69
+ * const { run, error, polling } = useWorkflowRun<Digest>(runId);
70
+ * if (error !== undefined) return <p role="alert">{error}</p>;
71
+ * if (run?.status === "completed") {
72
+ * return (
73
+ * <ul>
74
+ * {run.output.points.map((point) => (
75
+ * <li key={point}>{point}</li>
76
+ * ))}
77
+ * </ul>
78
+ * );
79
+ * }
80
+ * return <p>{polling ? "Working…" : "Nothing running."}</p>;
81
+ * }
82
+ * ```
83
+ *
84
+ * @typeParam R - The workflow's output type. Supplying it is what makes
85
+ * `run.status === "completed"` narrow to a typed `run.output` instead of
86
+ * `unknown`. Derive it with `WorkflowOutputOf<typeof myWorkflow>` — a
87
+ * type-only import of `agent.ts` is erased, so it costs the bundle nothing.
88
+ * @param runId - The run to watch. `undefined` costs nothing, so a page may
89
+ * pass its state straight through before a run exists.
90
+ * @param options - `api` when the page holds its own client; `intervalMs` to
91
+ * change the poll interval the stream falls back to.
92
+ * @returns The latest snapshot, the last read's error, and whether the watch
93
+ * is still going — see {@link UseWorkflowRunResult}.
94
+ *
95
+ * @public
96
+ */
97
+ export declare function useWorkflowRun<R = unknown>(runId: string | undefined, options?: {
98
+ api?: WorkflowApi;
99
+ intervalMs?: number;
100
+ }): UseWorkflowRunResult<R>;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * The RUNS a workflow has had — the list a page shows beside its form.
3
+ *
4
+ * `useWorkflowRun` watches one run you already hold an id for, which is the
5
+ * right shape for the run a page just started and the wrong one for everything
6
+ * before it. A workflow app that only offers that leaves its own history
7
+ * unreachable: a page reload drops the id, and the only way back to yesterday's
8
+ * transcript is to have written the id down — which is what
9
+ * `transcription-workflow` asked people to do, with a text box for pasting one.
10
+ *
11
+ * `GET /workflows/runs?workflow=…` has always been able to answer this. This is
12
+ * the hook over it, so a page renders history instead of asking for an id.
13
+ *
14
+ * ## It re-reads on demand, and does not poll on its own
15
+ *
16
+ * A list is not a live view: the run a page cares about right now is already
17
+ * being watched by `useWorkflowRun`, and a second polling loop over the whole
18
+ * history would broker N requests a minute on the platform to re-learn what the
19
+ * first one already knows. So this reads once and hands back `refresh` — which
20
+ * a page calls when its own run settles, which is exactly when the list is
21
+ * stale.
22
+ */
23
+ import type { WorkflowApi, WorkflowRun } from "./workflow-client.ts";
24
+ /** Options for {@link useWorkflowRuns}. */
25
+ export type UseWorkflowRunsOptions = {
26
+ /** The client to read with. Defaults to one for the page's own agent. */
27
+ api?: WorkflowApi;
28
+ /** Most runs to return, newest first. The agent clamps its own ceiling. */
29
+ limit?: number;
30
+ /**
31
+ * Narrow to one correlation key — the `key` a run was started with.
32
+ *
33
+ * Omitted, the list is every recent run of the workflow, which is what an
34
+ * operator's page wants. A page showing "your" runs passes the key it started
35
+ * them with; there is no per-user filtering behind this, so the key IS the
36
+ * scoping mechanism.
37
+ */
38
+ key?: string;
39
+ /** Skip the read entirely — for a page that does not know its workflow yet. */
40
+ skip?: boolean;
41
+ };
42
+ /** What {@link useWorkflowRuns} reports. */
43
+ export type UseWorkflowRunsResult<R = unknown> = {
44
+ /** The runs, newest first. Empty until the first read lands. */
45
+ runs: WorkflowRun<R>[];
46
+ /** True until the first read settles, and during an explicit refresh. */
47
+ loading: boolean;
48
+ /** The read's failure, alongside an empty list — which is why it exists. */
49
+ error: string | undefined;
50
+ /** Re-read now. Call it when a run this page started reaches a terminal status. */
51
+ refresh: () => void;
52
+ };
53
+ /**
54
+ * Read a workflow's recent runs.
55
+ *
56
+ * @typeParam R - The workflow's output type, so a completed run's `output` is
57
+ * typed rather than `unknown`. Derive it with `WorkflowOutputOf`.
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * import { useWorkflowRuns } from "@alexkroman1/aai-ui";
62
+ *
63
+ * function History() {
64
+ * const { runs } = useWorkflowRuns("transcribe", { limit: 10 });
65
+ * return <ul>{runs.map((run) => <li key={run.runId}>{run.status}</li>)}</ul>;
66
+ * }
67
+ * ```
68
+ *
69
+ * @public
70
+ */
71
+ export declare function useWorkflowRuns<R = unknown>(workflow: string | undefined, options?: UseWorkflowRunsOptions): UseWorkflowRunsResult<R>;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Starting a run BEFORE its file has finished uploading.
3
+ *
4
+ * `useWorkflowSubmit` (`use-workflow-form.ts`) stores every file and then starts the
5
+ * run, because a `POST /workflows/uploads` cannot answer with an id until the last
6
+ * byte is in — the store writes an ordinary upload's record last, so "incomplete"
7
+ * and "no such upload" are deliberately the same answer. For a long recording that
8
+ * order is most of the wall clock.
9
+ *
10
+ * This hook inverts it, and it takes ONE extra idea to do so: the id is the
11
+ * CLIENT's. It mints one, starts the run on it, and `PUT`s the whole file in a
12
+ * single streaming request; the upload record exists from the first byte with
13
+ * `complete: false` and its `size` grows, so the run reads whatever has arrived.
14
+ *
15
+ * ```text
16
+ * start run ─┬──────────────────────────────────────────────► (still running)
17
+ * │
18
+ * PUT /uploads/<id> ═══════════════════════════════════► wake
19
+ * (one request; the run polls `size` and `complete`)
20
+ * ```
21
+ *
22
+ * ## What it does NOT do, which is the point
23
+ *
24
+ * There is no cutting, no part numbering, no terminator and no per-part request. An
25
+ * earlier version of this hook took a `cut` callback and uploaded N parts into a
26
+ * "group" that a separate call had to seal; it worked, and every piece of it was
27
+ * something the caller had to get right. The whole of that is replaced by the store
28
+ * publishing `size` as bytes land — which `stepReadUpload` already clamped to — so the
29
+ * run does exactly what it does over a finished file and simply waits for windows to
30
+ * become present.
31
+ *
32
+ * It also means the FORMAT knowledge stays where it already was. Deciding where a
33
+ * recording may be divided is the run's business (`planSegments` in the
34
+ * transcription template), and nothing here needs to know it is audio at all.
35
+ *
36
+ * ## Three things it owns
37
+ *
38
+ * - **The id.** Minted here, put in the run input where the workflow's `uploads`
39
+ * list says, and never seen by the page. It is a capability — anyone holding it
40
+ * can read the bytes back — so it is a `crypto.randomUUID()` rather than anything
41
+ * derived from the file, and the store refuses a second `PUT` to it.
42
+ * - **The wake after the upload.** `POST /workflows/runs/:id/wake` ends a pending
43
+ * `sleep`, and a run waiting on an upload is asleep between polls — so without
44
+ * this it learns the file is complete up to a poll interval late, every time. On
45
+ * the transcription template's 5-second interval that is most of the tail it has
46
+ * left to pay. Best-effort, because a wake that finds nothing sleeping answers 0
47
+ * and a missed one costs latency rather than correctness.
48
+ * - **Reporting the bytes.** The same `UploadStatus` `useWorkflowSubmit` reports,
49
+ * so `<UploadProgressBar>` renders either without knowing which hook it came from.
50
+ *
51
+ * ## A failed upload is RESUMED, and only a spent budget cancels the run
52
+ *
53
+ * An upload that dies stays in the store, incomplete, and `complete` never becomes
54
+ * true — so a run left behind polls until its own abandonment bound and then fails,
55
+ * minutes after the page has already reported the error.
56
+ *
57
+ * That used to be the whole story, and it threw away a run and a file together for
58
+ * what is usually one dropped connection near the end. **The resume lives in the
59
+ * SDK now** (`aai/sdk/_upload-resume.ts`): a round that fails for a reason that
60
+ * looks like an outage is re-entered with `resume: true`, sending only the windows
61
+ * the store does not already have, on a budget sized to outlast a redeploy. The run
62
+ * is still waiting on the same id, so a resume that succeeds is invisible to it.
63
+ *
64
+ * This hook used to hand-roll one such retry and no longer does — one resume with
65
+ * no wait in front of it covers a dropped connection and cannot cover the case that
66
+ * actually strands people, which is the agent restarting underneath the upload.
67
+ * Cancelling the run is what happens when the whole budget is spent, and it is the
68
+ * honest end to a submission that did not happen.
69
+ *
70
+ * ## Pausing is the same mechanism, asked for
71
+ *
72
+ * `pauseUpload()` aborts the bytes in flight and holds the uploader;
73
+ * `resumeUpload()` sends what is missing. The store cannot tell that from an
74
+ * outage, because there is nothing to tell apart — see `upload/session.ts`. The
75
+ * RUN is untouched either way: it goes on polling the id it was started with, and
76
+ * `stream.ts`'s idle bound (five minutes of no new bytes) is what decides that a
77
+ * pause has become an abandonment.
78
+ */
79
+ import type { AnyWorkflowDef, WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
80
+ import type { UseWorkflowSubmitOptions, WorkflowSubmission } from "./use-workflow-form.ts";
81
+ import type { SubmitInputOf } from "./workflow-def-types.ts";
82
+ /**
83
+ * Options for {@link useWorkflowStream}.
84
+ *
85
+ * {@link UseWorkflowSubmitOptions} without `wait`, which is the synchronous
86
+ * mode: it holds the `POST` open until the run settles, and here the run is
87
+ * started before its bytes are, so there is nothing left to hold it for.
88
+ *
89
+ * Without `recover` either, and REFUSED rather than ignored: an option a hook
90
+ * accepts and does nothing with is the silent-no-op failure this repo keeps
91
+ * paying for. Adopting an earlier run by key would hand this hook a run whose
92
+ * input names an upload id it did not mint and is not filling — so the run
93
+ * would sit waiting for bytes nobody is sending until its own abandonment
94
+ * bound. That is the same reason `upload/recall.ts` deliberately does not
95
+ * recall for this hook, one layer up: here the id is part of a run's INPUT.
96
+ * `key` itself still works, and still makes the run findable — but it is NOT
97
+ * defaulted here the way `useWorkflowSubmit` defaults it, because the whole
98
+ * value of that default is the lookup this hook refuses, and minting a key
99
+ * nothing will ever read back is a slot left in storage for no one.
100
+ *
101
+ * `parallel` COMPOSES with what this hook is for rather than competing with it.
102
+ * The run still starts before the bytes, and the store still publishes how far
103
+ * the file is readable — that number is the CONTIGUOUS prefix, so a run reading
104
+ * ahead of the uplink sees the same growing file whether one connection or four
105
+ * are filling it. What changes is only how fast it grows.
106
+ */
107
+ export type UseWorkflowStreamOptions = Omit<UseWorkflowSubmitOptions, "wait" | "recover">;
108
+ /**
109
+ * What {@link useWorkflowStream} returns: a {@link WorkflowSubmission}, exactly.
110
+ *
111
+ * The same eight fields `useWorkflowSubmit` returns, of which this hook is a
112
+ * drop-in sibling — same `<Form>`, same `<UploadProgressBar>`, same
113
+ * `<WorkflowProgress>`. An ALIAS rather than a second declaration of the eight:
114
+ * the two have to agree field for field to be drop-in, and two copies of a type
115
+ * that have to agree are two copies that can stop agreeing.
116
+ *
117
+ * Exactly two of the fields mean something different here, and both differences
118
+ * follow from WHEN the run is created — it exists before its bytes do:
119
+ *
120
+ * - `submit()` resolves when the UPLOAD finishes, not when the run is accepted;
121
+ * the run's own progress arrives through `run`. It still resolves rather than
122
+ * rejecting on a failed upload — the failure is reported through `error`, the
123
+ * way a form expects.
124
+ * - `run` is set from the moment the run EXISTS, which here is before the bytes
125
+ * are in. That is what lets a page render `<WorkflowProgress>` beside the
126
+ * upload bar rather than after it.
127
+ */
128
+ export type WorkflowStreamSubmission<R = unknown, I = unknown> = WorkflowSubmission<R, I>;
129
+ /**
130
+ * Start a workflow run and stream a file into it while it works.
131
+ *
132
+ * The workflow declares which input property carries the upload
133
+ * (`workflow({ uploads: ["recording"] })`) — the same declaration
134
+ * `useWorkflowSubmit` reads, because what the property carries is an upload id
135
+ * either way. What differs is only WHEN the id becomes valid.
136
+ *
137
+ * @typeParam R - The workflow's output type, which is what makes
138
+ * `run.status === "completed"` narrow to a typed `run.output`. Derive it with
139
+ * `WorkflowOutputOf<typeof myWorkflow>`.
140
+ *
141
+ * @example
142
+ * ```tsx no-check
143
+ * const { submit, run, upload, pending, error } = useWorkflowStream("transcribe");
144
+ *
145
+ * <Form onSubmit={(values) => submit(values)} error={error}>
146
+ * <WorkflowFields workflow="transcribe" />
147
+ * <UploadProgressBar upload={upload} />
148
+ * <SubmitButton pending={pending}>Transcribe</SubmitButton>
149
+ * </Form>
150
+ * ```
151
+ *
152
+ * @public
153
+ */
154
+ export declare function useWorkflowStream<D extends AnyWorkflowDef>(workflow: string, options?: UseWorkflowStreamOptions): WorkflowStreamSubmission<WorkflowOutputOf<D>, SubmitInputOf<D>>;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The agent's declared workflows — what a form is rendered FROM.
3
+ *
4
+ * Split out of `use-workflow-form.ts` at the 500-line cap, along the seam that
5
+ * file's own doc already drew: it held "the two hooks a FORM needs", and only
6
+ * one of them is about a RUN. This is the other one, and it shares nothing with
7
+ * its former neighbours but the client ref every hook here uses — no state, no
8
+ * run id, no upload.
9
+ */
10
+ import type { WorkflowSummary } from "@alexkroman1/aai/workflow-api";
11
+ import type { WorkflowApi } from "./workflow-client.ts";
12
+ /** Options for {@link useWorkflows}. */
13
+ export type UseWorkflowsOptions = {
14
+ /** The client to read the listing with. Defaults to one for the page's own agent. */
15
+ api?: WorkflowApi;
16
+ /**
17
+ * Skip the lookup entirely, reporting an empty listing that is not loading.
18
+ *
19
+ * For a caller that may or may not need the listing and cannot decide with a
20
+ * conditional hook — `<WorkflowFields>` handed a summary rather than a name is
21
+ * the one in this package. It reports `loading: false`, because a skipped
22
+ * lookup is finished rather than pending.
23
+ */
24
+ skip?: boolean;
25
+ };
26
+ /** What {@link useWorkflows} reports. */
27
+ export type UseWorkflowsResult = {
28
+ /** The agent's declared workflows, each with the JSON Schema of its input. */
29
+ workflows: WorkflowSummary[];
30
+ /** True until the listing lands, so a form can hold its fields back. */
31
+ loading: boolean;
32
+ /** The lookup's failure. Set alongside an EMPTY list, which is why it exists. */
33
+ error: string | undefined;
34
+ };
35
+ /**
36
+ * Read the agent's declared workflows.
37
+ *
38
+ * What `<WorkflowFields>` renders a form FROM: each summary carries the JSON
39
+ * Schema of that workflow's input, converted server-side precisely so a browser
40
+ * can read it.
41
+ *
42
+ * The failure is reported rather than swallowed, because the alternative is an
43
+ * empty list — which renders as a form with no fields and reads as "this agent
44
+ * declares no workflows" about an agent that was merely unreachable.
45
+ *
46
+ * @example
47
+ * ```tsx
48
+ * import { useWorkflows } from "@alexkroman1/aai-ui";
49
+ *
50
+ * // A page rendering its own chrome from the listing — a picker, say. A form
51
+ * // for ONE workflow wants `<WorkflowFields workflow="name" />` instead,
52
+ * // which does this lookup itself.
53
+ * function WorkflowPicker({ onPick }: { onPick: (name: string) => void }) {
54
+ * const { workflows, loading, error } = useWorkflows();
55
+ * if (loading) return <p>Loading…</p>;
56
+ * if (error !== undefined) return <p role="alert">{error}</p>;
57
+ * return (
58
+ * <ul>
59
+ * {workflows.map((summary) => (
60
+ * <li key={summary.name}>
61
+ * <button type="button" onClick={() => onPick(summary.name)}>
62
+ * {summary.description ?? summary.name}
63
+ * </button>
64
+ * </li>
65
+ * ))}
66
+ * </ul>
67
+ * );
68
+ * }
69
+ * ```
70
+ *
71
+ * @param options - See {@link UseWorkflowsOptions}.
72
+ * @returns The listing, its loading flag and its failure — see
73
+ * {@link UseWorkflowsResult}.
74
+ *
75
+ * @public
76
+ */
77
+ export declare function useWorkflows(options?: UseWorkflowsOptions): UseWorkflowsResult;
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Browser client for the workflow HTTP API (`aai/host/workflow-api.ts`).
3
+ *
4
+ * This is the whole client half of a WORKFLOW APP: an agent whose front door is
5
+ * a form rather than a microphone (`workflowApp()`) starts runs
6
+ * here and watches them for the answer. It deliberately does NOT go through
7
+ * `BrowserSession` — there is no socket, no audio graph, and no session to resume.
8
+ *
9
+ * **The requests themselves are the SDK's now**
10
+ * (`createWorkflowApiClient`, `@alexkroman1/aai/workflow-api`), and what is left
11
+ * here is the one thing that is genuinely a BROWSER's: the default base URL.
12
+ * Every route, every query, the 404-is-an-answer rule and the `wait` clamp were
13
+ * written three times over — here, in the studio's Workflows card, and in
14
+ * `aai workflow` — and the parts the copies disagreed on were exactly the ones a
15
+ * reader cannot check by eye. The SDK module's doc carries that argument; this
16
+ * file must not grow a second implementation of any of it.
17
+ *
18
+ * The one thing worth knowing before using it: **a run outlives the page.**
19
+ * Starting one resolves as soon as the run is created, so `runId` is the only
20
+ * handle that matters and it stays valid across a reload, a different device, or
21
+ * `curl` — which is what makes `useWorkflowRun` a watch rather than a
22
+ * subscription to something the page owns.
23
+ *
24
+ * The loop that keeps asking lives in `use-workflow-run.ts`, and the streaming
25
+ * fast path under it in `workflow-events.ts`.
26
+ */
27
+ import type { WorkflowRunSnapshot } from "@alexkroman1/aai/workflow-api";
28
+ import { type AgentClient } from "@alexkroman1/aai/workflow-api";
29
+ /**
30
+ * A run's observable state.
31
+ *
32
+ * Aliased from the SDK rather than restated. `import type` is erased entirely,
33
+ * so a second definition of the fields and the five-member status union would
34
+ * buy nothing and cost the one thing that matters — nothing would assert the two
35
+ * agree, so a status added to the SDK would never reach the browser type.
36
+ *
37
+ * `WorkflowRun` keeps the shorter name because it is what a page's own code
38
+ * writes; nothing in a browser needs the word "snapshot" to know a read returns
39
+ * one.
40
+ *
41
+ * It is GENERIC on the run's output, and a page supplies it — see
42
+ * {@link useWorkflowRun}. It does NOT have to restate that type: a page can name
43
+ * its own workflow and derive the rest with `WorkflowOutputOf`, pulling no
44
+ * server graph into the bundle.
45
+ *
46
+ * @public
47
+ */
48
+ export type WorkflowRun<R = unknown> = WorkflowRunSnapshot<R>;
49
+ /**
50
+ * A workflow's own output type, and the shape `GET /workflows` lists — both
51
+ * re-exported so a page needs ONE import to type its runs and render its form.
52
+ */
53
+ /**
54
+ * The workflow half of what {@link createWorkflowApi} returns — every hook here
55
+ * takes it, because a run is all a hook needs.
56
+ *
57
+ * Re-exported from the SDK rather than declared here: it IS the SDK's client,
58
+ * and a structural restatement would be a second thing to keep in step with the
59
+ * routes for no gain.
60
+ */
61
+ export type { AgentClient, WorkflowApi, WorkflowInputOf, WorkflowOutputOf, WorkflowRunStatus, WorkflowSummary, } from "@alexkroman1/aai/workflow-api";
62
+ /**
63
+ * A run status nothing will change again.
64
+ *
65
+ * Re-exported from the SDK rather than defined here. A second implementation
66
+ * listing two of the three terminal statuses would leave a cancelled run polled
67
+ * forever by a page while the agent considered it finished — the kind of drift a
68
+ * status predicate beside the status union cannot have.
69
+ */
70
+ export { isTerminal } from "@alexkroman1/aai/workflow-api";
71
+ export type WorkflowApiOptions = {
72
+ /**
73
+ * Base URL of the agent. Defaults to the page's own origin + path, which is
74
+ * right for a page the agent itself serves — the only case that exists today,
75
+ * and the reason this wrapper exists at all: the SDK client requires a base
76
+ * URL, because `location` does not exist in that half of the SDK.
77
+ */
78
+ baseUrl?: string;
79
+ /**
80
+ * Bearer for an agent whose operator set `AAI_WORKFLOW_API_TOKEN`. A page
81
+ * served to the public has nothing to put here (and should not — it would be
82
+ * readable in the bundle); this exists for a programmatic caller written
83
+ * against the same client.
84
+ */
85
+ token?: string;
86
+ };
87
+ /**
88
+ * Create a client for the agent serving this page.
89
+ *
90
+ * **You usually do not need one.** Every hook and component here builds this
91
+ * exact client lazily and once when no `api` is passed
92
+ * (`_workflow-api-ref.ts`), so `useWorkflowSubmit("digest")` already talks to
93
+ * the right agent. Reach for this when the client has to be DIFFERENT from that
94
+ * default — another agent's `baseUrl`, or a `token` — or when a page wants
95
+ * `config()` and the run calls on one object.
96
+ *
97
+ * If you do build one, hoist it out of the component that uses it.
98
+ * `useWorkflowRun` holds the client in a ref precisely so a fresh object per
99
+ * render does not restart its watch, but a client built in render is still a new
100
+ * `fetch` closure every time and reads as though it were free.
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * import { createWorkflowApi, useWorkflowRun } from "@alexkroman1/aai-ui";
105
+ * import { useState } from "react";
106
+ *
107
+ * // A DIFFERENT agent than the one serving this page, so the client is
108
+ * // explicit — and module scope, not render scope, per above.
109
+ * const api = createWorkflowApi({ baseUrl: "https://agents.example/digest" });
110
+ *
111
+ * function StartDigest() {
112
+ * const [runId, setRunId] = useState<string>();
113
+ * const { run } = useWorkflowRun(runId, { api });
114
+ * return (
115
+ * <button
116
+ * type="button"
117
+ * onClick={() => void api.start("digest", { url: "…" }).then(setRunId)}
118
+ * >
119
+ * {run ? run.status : "Start"}
120
+ * </button>
121
+ * );
122
+ * }
123
+ * ```
124
+ *
125
+ * @param options - See {@link WorkflowApiOptions}. Both fields are optional; the
126
+ * default base URL is the page's own origin and path.
127
+ * @returns Every workflow call plus `config()` and `baseUrl` — see
128
+ * {@link AgentClient}. It was the narrow {@link WorkflowApi}, which left a page
129
+ * that also wanted the agent's own name building a SECOND client (or a bare
130
+ * `fetch` and a hand-written URL join) for one read; the SDK documents
131
+ * `createAgentClient` as a superset of the same routes, so delegating to it
132
+ * widens the return without a second implementation of anything.
133
+ *
134
+ * @public
135
+ */
136
+ export declare function createWorkflowApi(options?: WorkflowApiOptions): AgentClient;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The narrowing the workflow hooks apply to a DEF's input type.
3
+ *
4
+ * It used to fall back to `unknown` so an un-parameterized
5
+ * `useWorkflowSubmit("digest")` kept compiling. It does not any more — the def
6
+ * is required — because the fallback was the last way to get an untyped
7
+ * `submit` back, and an escape hatch nobody needs is one somebody uses.
8
+ *
9
+ * There used to be a `SubmitOutputOf<D>` beside it. It was `WorkflowOutputOf<D>`
10
+ * spelled a second way and nothing else, so the hooks name `WorkflowOutputOf`
11
+ * directly — the SDK type this package already re-exports, and the one a page
12
+ * reading the rendered signature can click through to.
13
+ */
14
+ import type { WorkflowInputOf } from "@alexkroman1/aai/workflow-api";
15
+ /**
16
+ * What `submit()` takes for `D` — `undefined` when `D` declares no schema.
17
+ *
18
+ * This is what {@link WorkflowInputOf} cannot say on its own: a def whose
19
+ * `input` schema is absent has no parsed input, and `never` as a parameter type
20
+ * accepts nothing at all — not even `undefined` — so a workflow that declares
21
+ * no schema would have an uncallable `submit`. It gets `undefined` instead, i.e.
22
+ * `submit(undefined)`. Explicit rather than `void`, which would let the argument
23
+ * be omitted and which Biome's `noConfusingVoidType` rejects outside a return or
24
+ * type-parameter position.
25
+ *
26
+ * The `[T] extends [never]` spelling is deliberate: a bare `T extends never`
27
+ * distributes over a naked type parameter and answers `never` for a union.
28
+ *
29
+ * @public
30
+ */
31
+ export type SubmitInputOf<D> = [WorkflowInputOf<D>] extends [never] ? undefined : WorkflowInputOf<D>;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Watching a run over server-sent events — the PUSH half of `useWorkflowRun`.
3
+ *
4
+ * Its own module because the seam is clean: everything in `workflow-client.ts`
5
+ * is request/response shaping plus the poll, and this is one long-lived stream
6
+ * and the SSE parser it needs.
7
+ *
8
+ * @internal
9
+ */
10
+ import type { WorkflowApi, WorkflowRun } from "./workflow-client.ts";
11
+ /**
12
+ * The slice of the client this needs: one method.
13
+ *
14
+ * Narrowed rather than taking the whole `WorkflowApi`, and the narrowing is the
15
+ * honest statement — nothing here reads a run, starts one, or cancels one, it
16
+ * opens ONE stream. It also makes a test double a plain object rather than a
17
+ * six-method stub cast into shape. A real client satisfies it structurally.
18
+ */
19
+ export type RunWatcher = Pick<WorkflowApi, "watch">;
20
+ /**
21
+ * Watch a run over SSE, falling back to the caller's poll on any failure.
22
+ *
23
+ * The poll stays the fallback rather than being replaced, and that is the whole
24
+ * shape of this: a stream is an optimisation over a mechanism that already
25
+ * works, so every way it can fail — an older agent with no `/events` route, a
26
+ * proxy that buffers, a network that drops it — has to degrade to the thing that
27
+ * does. What it buys is real, though: on the platform every polled read BROKERS,
28
+ * so N open tabs at `DEFAULT_WORKFLOW_POLL_MS` is N/2 brokered requests a
29
+ * second, each able to boot a sandbox. One stream per tab replaces all of it.
30
+ *
31
+ * `EventSource` is not used, for two reasons that both matter here: it cannot
32
+ * send an `Authorization` header (an agent with `AAI_WORKFLOW_API_TOKEN` set
33
+ * would be unreachable), and it reconnects on its own schedule, which would
34
+ * fight the caller's. A `fetch` stream gives both back.
35
+ *
36
+ * Returns a stop function. `onFallback` is called at most once, when this stream
37
+ * cannot be relied on and the poll should take over.
38
+ */
39
+ export declare function watchRunEvents<R>(getClient: () => RunWatcher, runId: string, onRun: (run: WorkflowRun<R>) => void, onSettled: () => void, onFallback: () => void): () => void;