@alexkroman1/aai-ui 8.2.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/_workflow-test-defs.d.ts +38 -0
- package/dist/components/upload-progress.d.ts +4 -3
- package/dist/components/workflow-fields.d.ts +4 -3
- package/dist/default-client/assets/index-CA2w_SUi.js +299 -0
- package/dist/default-client/index.html +1 -1
- package/dist/define-client.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +29 -15
- package/dist/{session-core-CMEpwRP1.js → session-core-0hClhPz-.js} +47 -5
- package/dist/session-core-close.d.ts +26 -0
- package/dist/session-core.js +1 -1
- package/dist/use-download-url.d.ts +3 -2
- package/dist/use-workflow-form.d.ts +38 -10
- package/dist/use-workflow-stream.d.ts +4 -2
- package/dist/workflow-client.d.ts +1 -1
- package/dist/workflow-def-types.d.ts +31 -0
- package/package.json +2 -2
- package/dist/default-client/assets/index-Bp1iPrLa.js +0 -299
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>aai</title>
|
|
7
7
|
<link rel="icon" href="./favicon.ico" />
|
|
8
8
|
<style>html, body { background: #FBF8F2; margin: 0; }</style>
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-CA2w_SUi.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="./assets/client-audio-constants-Ck0IJO4c.js">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="./assets/index-S5fkKi6B.css">
|
|
12
12
|
</head>
|
package/dist/define-client.js
CHANGED
|
@@ -5,7 +5,7 @@ import { n as setPageTitle, t as pageBaseUrl } from "./_utils-B6498_bm.js";
|
|
|
5
5
|
import { t as ToolConfigContext } from "./tool-config-context-DzAofqi_.js";
|
|
6
6
|
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
7
7
|
import { StartScreen } from "./components/start-screen.js";
|
|
8
|
-
import { t as createSessionCore } from "./session-core-
|
|
8
|
+
import { t as createSessionCore } from "./session-core-0hClhPz-.js";
|
|
9
9
|
import { jsx } from "react/jsx-runtime";
|
|
10
10
|
import { createElement, useEffect, useState } from "react";
|
|
11
11
|
import { flushSync } from "react-dom";
|
package/dist/index.d.ts
CHANGED
|
@@ -31,5 +31,6 @@ export { type UseWorkflowProgressResult, useWorkflowProgress, } from "./use-work
|
|
|
31
31
|
export { type UseWorkflowRunResult, useWorkflowRun } from "./use-workflow-run.ts";
|
|
32
32
|
export { type UseWorkflowRunsOptions, type UseWorkflowRunsResult, useWorkflowRuns, } from "./use-workflow-runs.ts";
|
|
33
33
|
export { type UseWorkflowStreamOptions, useWorkflowStream, type WorkflowStreamSubmission, } from "./use-workflow-stream.ts";
|
|
34
|
-
export { createWorkflowApi, isTerminal, type WorkflowApi, type WorkflowApiOptions, type WorkflowOutputOf, type WorkflowRun, type WorkflowRunStatus, type WorkflowSummary, } from "./workflow-client.ts";
|
|
34
|
+
export { createWorkflowApi, isTerminal, type WorkflowApi, type WorkflowApiOptions, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRun, type WorkflowRunStatus, type WorkflowSummary, } from "./workflow-client.ts";
|
|
35
|
+
export type { SubmitInputOf } from "./workflow-def-types.ts";
|
|
35
36
|
export { WORKFLOW_STATUS_LABELS } from "./workflow-status-labels.ts";
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { n as ToolCallRow } from "./tool-call-block-B7KlhaWl.js";
|
|
|
11
11
|
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
12
12
|
import { StartScreen } from "./components/start-screen.js";
|
|
13
13
|
import { a as useWorkflowRun, c as isTerminal, n as useWorkflowProgress, o as useWorkflowApiRef, s as createWorkflowApi } from "./use-workflow-progress-C4KgVldr.js";
|
|
14
|
-
import { t as createSessionCore } from "./session-core-
|
|
14
|
+
import { t as createSessionCore } from "./session-core-0hClhPz-.js";
|
|
15
15
|
import { client, mountRoot, resolveContainer } from "./define-client.js";
|
|
16
16
|
import { useAgentState, useEvent, useToolCallStart, useToolResult } from "./hooks.js";
|
|
17
17
|
import clsx from "clsx";
|
|
@@ -690,13 +690,14 @@ const TRACK_TINT_PCT = 12;
|
|
|
690
690
|
* parent's state) has nothing to pause.
|
|
691
691
|
*
|
|
692
692
|
* @example
|
|
693
|
-
* ```tsx
|
|
693
|
+
* ```tsx no-check
|
|
694
694
|
* import { Form, SubmitButton, UploadProgressBar, useWorkflowSubmit, WorkflowFields } from "@alexkroman1/aai-ui";
|
|
695
|
+
* import type { transcribe } from "./agent.ts";
|
|
695
696
|
*
|
|
696
697
|
* function TranscribeForm() {
|
|
697
|
-
* const {
|
|
698
|
+
* const { submitForm, upload, pending, error } = useWorkflowSubmit<typeof transcribe>("transcribe");
|
|
698
699
|
* return (
|
|
699
|
-
* <Form onSubmit={
|
|
700
|
+
* <Form onSubmit={submitForm} error={error}>
|
|
700
701
|
* <WorkflowFields workflow="transcribe" />
|
|
701
702
|
* <UploadProgressBar upload={upload} />
|
|
702
703
|
* <SubmitButton pending={pending}>Transcribe</SubmitButton>
|
|
@@ -1373,21 +1374,30 @@ function useWorkflows(opts = {}) {
|
|
|
1373
1374
|
/**
|
|
1374
1375
|
* Start a workflow from a form, and follow the run it creates.
|
|
1375
1376
|
*
|
|
1376
|
-
* @typeParam
|
|
1377
|
-
*
|
|
1378
|
-
* `
|
|
1377
|
+
* @typeParam D - The workflow DEFINITION, which types both halves of the
|
|
1378
|
+
* submission: `submit(input)` takes what the workflow's schema parses to, and
|
|
1379
|
+
* `run.status === "completed"` narrows to a typed `run.output`.
|
|
1380
|
+
*
|
|
1381
|
+
* It used to be the OUTPUT type alone, and the asymmetry was the bug: a page
|
|
1382
|
+
* already wrote `WorkflowOutputOf<typeof digest>` to get the output, while
|
|
1383
|
+
* `submit` took `unknown`, so `submit({ ur1: 42 })` compiled and arrived as a
|
|
1384
|
+
* 400 in the browser. Naming the def instead types the input from the same
|
|
1385
|
+
* declaration — and `import type` is ERASED, so it costs the bundle nothing.
|
|
1386
|
+
* Passing an output type where a def belongs is now a compile error rather
|
|
1387
|
+
* than a silent loss of typing, which is the point.
|
|
1379
1388
|
*
|
|
1380
1389
|
* @example
|
|
1381
|
-
* ```tsx
|
|
1390
|
+
* ```tsx no-check
|
|
1382
1391
|
* import { Form, SubmitButton, TextField, useWorkflowSubmit } from "@alexkroman1/aai-ui";
|
|
1392
|
+
* import type { digest } from "./agent.ts";
|
|
1383
1393
|
*
|
|
1384
1394
|
* function DigestForm() {
|
|
1385
|
-
* const { submit, run, pending, error } = useWorkflowSubmit("digest");
|
|
1395
|
+
* const { submit, run, pending, error } = useWorkflowSubmit<typeof digest>("digest");
|
|
1386
1396
|
* return (
|
|
1387
1397
|
* <Form onSubmit={(values) => submit(values)} error={error}>
|
|
1388
1398
|
* <TextField name="url" label="Link" type="url" required />
|
|
1389
1399
|
* <SubmitButton pending={pending}>Digest</SubmitButton>
|
|
1390
|
-
* {run?.status === "completed" && <p>
|
|
1400
|
+
* {run?.status === "completed" && <p>{run.output.title}</p>}
|
|
1391
1401
|
* </Form>
|
|
1392
1402
|
* );
|
|
1393
1403
|
* }
|
|
@@ -1449,6 +1459,7 @@ function useWorkflowSubmit(workflow, opts = {}) {
|
|
|
1449
1459
|
const { pauseUpload, resumeUpload } = useUploadPause(useCallback(() => session.current?.gate, []), setUpload);
|
|
1450
1460
|
return {
|
|
1451
1461
|
submit,
|
|
1462
|
+
submitForm: submit,
|
|
1452
1463
|
reset,
|
|
1453
1464
|
wake,
|
|
1454
1465
|
cancel,
|
|
@@ -1498,14 +1509,15 @@ function useWorkflowSubmit(workflow, opts = {}) {
|
|
|
1498
1509
|
* beside it are not reordered when the schema lands.
|
|
1499
1510
|
*
|
|
1500
1511
|
* @example
|
|
1501
|
-
* ```tsx
|
|
1512
|
+
* ```tsx no-check
|
|
1502
1513
|
* import { Form, SubmitButton, WorkflowFields, useWorkflowSubmit }
|
|
1503
1514
|
* from "@alexkroman1/aai-ui";
|
|
1515
|
+
* import type { transcribe } from "./agent.ts";
|
|
1504
1516
|
*
|
|
1505
1517
|
* function StartRun() {
|
|
1506
|
-
* const {
|
|
1518
|
+
* const { submitForm, pending, error } = useWorkflowSubmit<typeof transcribe>("transcribe");
|
|
1507
1519
|
* return (
|
|
1508
|
-
* <Form onSubmit={
|
|
1520
|
+
* <Form onSubmit={submitForm} error={error}>
|
|
1509
1521
|
* <WorkflowFields workflow="transcribe" />
|
|
1510
1522
|
* <SubmitButton pending={pending}>Transcribe</SubmitButton>
|
|
1511
1523
|
* </Form>
|
|
@@ -1750,11 +1762,12 @@ const PENDING = { pending: true };
|
|
|
1750
1762
|
* @returns See {@link UseDownloadUrlResult}.
|
|
1751
1763
|
*
|
|
1752
1764
|
* @example
|
|
1753
|
-
* ```tsx
|
|
1765
|
+
* ```tsx no-check
|
|
1754
1766
|
* import { useDownloadUrl, useWorkflowSubmit } from "@alexkroman1/aai-ui";
|
|
1767
|
+
* import type { spokenSummary } from "./agent.ts";
|
|
1755
1768
|
*
|
|
1756
1769
|
* function Playback() {
|
|
1757
|
-
* const { run } = useWorkflowSubmit<
|
|
1770
|
+
* const { run } = useWorkflowSubmit<typeof spokenSummary>("spokenSummary");
|
|
1758
1771
|
* const output = run?.status === "completed" ? run.output : undefined;
|
|
1759
1772
|
* const audio = useDownloadUrl(output?.audio);
|
|
1760
1773
|
* if (audio.pending) return <p>Fetching audio…</p>;
|
|
@@ -2073,6 +2086,7 @@ function useWorkflowStream(workflow, opts = {}) {
|
|
|
2073
2086
|
const { pauseUpload, resumeUpload } = useUploadPause(useCallback(() => gateRef.current, []), setUpload);
|
|
2074
2087
|
return {
|
|
2075
2088
|
submit,
|
|
2089
|
+
submitForm: submit,
|
|
2076
2090
|
reset,
|
|
2077
2091
|
wake,
|
|
2078
2092
|
cancel,
|
|
@@ -119,6 +119,47 @@ async function initAudioCapture(conn, msg, deps) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
//#endregion
|
|
122
|
+
//#region session-core-close.ts
|
|
123
|
+
/**
|
|
124
|
+
* What a socket's CLOSE means to the caller.
|
|
125
|
+
*
|
|
126
|
+
* One decision, in its own module because `session-core.ts` is at its length cap
|
|
127
|
+
* and because the decision is worth reading on its own: which endings are
|
|
128
|
+
* ordinary, and which carry something the user has to be told.
|
|
129
|
+
*
|
|
130
|
+
* @module
|
|
131
|
+
*/
|
|
132
|
+
/**
|
|
133
|
+
* The one close code whose reason is never worth showing.
|
|
134
|
+
*
|
|
135
|
+
* `1000` is a deliberate, successful close — the caller hanging up, or the
|
|
136
|
+
* server retiring a session it finished with. A browser reports a socket that
|
|
137
|
+
* closed with no status as `1005`, which carries no reason either, so testing
|
|
138
|
+
* for text is enough to exclude it.
|
|
139
|
+
*/
|
|
140
|
+
const NORMAL_CLOSE = 1e3;
|
|
141
|
+
/**
|
|
142
|
+
* What to REPORT for a socket that closed for good, or null for an ordinary end.
|
|
143
|
+
*
|
|
144
|
+
* A sentence the peer wrote beats one this file invented. A guest that cannot
|
|
145
|
+
* build its runtime closes 1011 with the remedy already in it — "Anthropic LLM:
|
|
146
|
+
* missing API key. Set ANTHROPIC_API_KEY in the agent env." — and this handler
|
|
147
|
+
* used to discard `event.reason` entirely, so the one thing a misconfigured
|
|
148
|
+
* deployment needed to be told surfaced as "WebSocket connection error", or as a
|
|
149
|
+
* plain disconnect with nothing at all. Measured against a deployed agent with no
|
|
150
|
+
* provider key.
|
|
151
|
+
*
|
|
152
|
+
* A NORMAL close carries no reason worth showing (1000 is the caller hanging up
|
|
153
|
+
* or the server retiring a finished session; a browser reports a status-less
|
|
154
|
+
* close as 1005, which has no reason either), so the two ordinary endings are
|
|
155
|
+
* untouched.
|
|
156
|
+
*/
|
|
157
|
+
function closeFailure(event, socketErrored) {
|
|
158
|
+
const refusal = event.reason.trim();
|
|
159
|
+
if (refusal !== "" && event.code !== NORMAL_CLOSE) return refusal;
|
|
160
|
+
return socketErrored ? "WebSocket connection error" : null;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
122
163
|
//#region session-core-reconnect.ts
|
|
123
164
|
/**
|
|
124
165
|
* Automatic reconnection for the browser session socket, built on
|
|
@@ -1172,11 +1213,11 @@ function createSessionCore(options) {
|
|
|
1172
1213
|
socket.addEventListener("error", () => {
|
|
1173
1214
|
socketErrored = true;
|
|
1174
1215
|
}, { signal: sig });
|
|
1175
|
-
socket.addEventListener("close", () => {
|
|
1216
|
+
socket.addEventListener("close", (event) => {
|
|
1176
1217
|
if (sig.aborted) return;
|
|
1177
1218
|
handshake.disarm();
|
|
1178
1219
|
cleanupAudio();
|
|
1179
|
-
if (!conn.retiredByServer && reconnectPending(socket)) {
|
|
1220
|
+
if (!(conn.retiredByServer || agentState.fatal()) && reconnectPending(socket)) {
|
|
1180
1221
|
conn.generation.bump();
|
|
1181
1222
|
socketErrored = false;
|
|
1182
1223
|
updateState({
|
|
@@ -1188,14 +1229,15 @@ function createSessionCore(options) {
|
|
|
1188
1229
|
controller.abort();
|
|
1189
1230
|
socket.close();
|
|
1190
1231
|
conn.ws = null;
|
|
1232
|
+
const failure = closeFailure(event, socketErrored);
|
|
1191
1233
|
updateState({
|
|
1192
|
-
...
|
|
1234
|
+
...failure === null ? agentState.apply({ type: "CLOSED" }) : agentState.apply({
|
|
1193
1235
|
type: "FAILED",
|
|
1194
1236
|
error: {
|
|
1195
1237
|
code: "connection",
|
|
1196
|
-
message:
|
|
1238
|
+
message: failure
|
|
1197
1239
|
}
|
|
1198
|
-
})
|
|
1240
|
+
}),
|
|
1199
1241
|
running: false,
|
|
1200
1242
|
recording: false
|
|
1201
1243
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a socket's CLOSE means to the caller.
|
|
3
|
+
*
|
|
4
|
+
* One decision, in its own module because `session-core.ts` is at its length cap
|
|
5
|
+
* and because the decision is worth reading on its own: which endings are
|
|
6
|
+
* ordinary, and which carry something the user has to be told.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* What to REPORT for a socket that closed for good, or null for an ordinary end.
|
|
12
|
+
*
|
|
13
|
+
* A sentence the peer wrote beats one this file invented. A guest that cannot
|
|
14
|
+
* build its runtime closes 1011 with the remedy already in it — "Anthropic LLM:
|
|
15
|
+
* missing API key. Set ANTHROPIC_API_KEY in the agent env." — and this handler
|
|
16
|
+
* used to discard `event.reason` entirely, so the one thing a misconfigured
|
|
17
|
+
* deployment needed to be told surfaced as "WebSocket connection error", or as a
|
|
18
|
+
* plain disconnect with nothing at all. Measured against a deployed agent with no
|
|
19
|
+
* provider key.
|
|
20
|
+
*
|
|
21
|
+
* A NORMAL close carries no reason worth showing (1000 is the caller hanging up
|
|
22
|
+
* or the server retiring a finished session; a browser reports a status-less
|
|
23
|
+
* close as 1005, which has no reason either), so the two ordinary endings are
|
|
24
|
+
* untouched.
|
|
25
|
+
*/
|
|
26
|
+
export declare function closeFailure(event: CloseEvent, socketErrored: boolean): string | null;
|
package/dist/session-core.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createSessionCore } from "./session-core-
|
|
1
|
+
import { t as createSessionCore } from "./session-core-0hClhPz-.js";
|
|
2
2
|
export { createSessionCore };
|
|
@@ -61,11 +61,12 @@ export type UseDownloadUrlResult = {
|
|
|
61
61
|
* @returns See {@link UseDownloadUrlResult}.
|
|
62
62
|
*
|
|
63
63
|
* @example
|
|
64
|
-
* ```tsx
|
|
64
|
+
* ```tsx no-check
|
|
65
65
|
* import { useDownloadUrl, useWorkflowSubmit } from "@alexkroman1/aai-ui";
|
|
66
|
+
* import type { spokenSummary } from "./agent.ts";
|
|
66
67
|
*
|
|
67
68
|
* function Playback() {
|
|
68
|
-
* const { run } = useWorkflowSubmit<
|
|
69
|
+
* const { run } = useWorkflowSubmit<typeof spokenSummary>("spokenSummary");
|
|
69
70
|
* const output = run?.status === "completed" ? run.output : undefined;
|
|
70
71
|
* const audio = useDownloadUrl(output?.audio);
|
|
71
72
|
* if (audio.pending) return <p>Fetching audio…</p>;
|
|
@@ -32,8 +32,10 @@
|
|
|
32
32
|
* `wait` here when the page really does want one request, and the run is
|
|
33
33
|
* followed from the same id either way.
|
|
34
34
|
*/
|
|
35
|
-
import type { UploadParallel, UploadProgress, WorkflowSummary } from "@alexkroman1/aai/workflow-api";
|
|
35
|
+
import type { AnyWorkflowDef, UploadParallel, UploadProgress, WorkflowOutputOf, WorkflowSummary } from "@alexkroman1/aai/workflow-api";
|
|
36
|
+
import type { FormValues } from "./components/form-types.ts";
|
|
36
37
|
import type { WorkflowApi, WorkflowRun } from "./workflow-client.ts";
|
|
38
|
+
import type { SubmitInputOf } from "./workflow-def-types.ts";
|
|
37
39
|
/** Options for {@link useWorkflows}. */
|
|
38
40
|
export type UseWorkflowsOptions = {
|
|
39
41
|
/** The client to read the listing with. Defaults to one for the page's own agent. */
|
|
@@ -138,13 +140,30 @@ export type UploadStatus = UploadProgress & {
|
|
|
138
140
|
* in, so a page can render `<WorkflowProgress>` beside the upload bar instead
|
|
139
141
|
* of after it. Here the run does not exist until the last byte lands.
|
|
140
142
|
*/
|
|
141
|
-
export type WorkflowSubmission<R = unknown> = {
|
|
143
|
+
export type WorkflowSubmission<R = unknown, I = unknown> = {
|
|
142
144
|
/**
|
|
143
145
|
* Start a run with this input. Resolves once the run EXISTS — progress
|
|
144
146
|
* arrives through `run` — so a `<Form>`'s handler can await it to know the
|
|
145
147
|
* submission was accepted.
|
|
146
148
|
*/
|
|
147
|
-
submit: (input:
|
|
149
|
+
submit: (input: I) => Promise<void>;
|
|
150
|
+
/**
|
|
151
|
+
* Start a run from a `<Form>`'s values, which are UNVALIDATED.
|
|
152
|
+
*
|
|
153
|
+
* The same function as {@link WorkflowSubmission.submit}, with the type the
|
|
154
|
+
* form path can honestly offer. `FormValues` is `Record<string, unknown>`
|
|
155
|
+
* scraped off the DOM at submit time — a `<TextField name="limit">`
|
|
156
|
+
* contributes a string whatever the schema says — so the shape is not known
|
|
157
|
+
* here and the SERVER is what checks it against the workflow's schema.
|
|
158
|
+
*
|
|
159
|
+
* Two doors rather than one loose one: `submit` takes the workflow's own
|
|
160
|
+
* input type, so a hand-built object is checked at compile time and
|
|
161
|
+
* `submit({ ur1: 42 })` is an error; widening it to accept `FormValues` would
|
|
162
|
+
* have made every object satisfy it and given the typing back. Reaching for
|
|
163
|
+
* this one is the author saying "these came from a form", which is a fact
|
|
164
|
+
* about the values and not a cast.
|
|
165
|
+
*/
|
|
166
|
+
submitForm: (values: FormValues) => Promise<void>;
|
|
148
167
|
/** Clear the run and any error, putting the form back to its initial state. */
|
|
149
168
|
reset: () => void;
|
|
150
169
|
/**
|
|
@@ -236,21 +255,30 @@ export type UseWorkflowSubmitOptions = {
|
|
|
236
255
|
/**
|
|
237
256
|
* Start a workflow from a form, and follow the run it creates.
|
|
238
257
|
*
|
|
239
|
-
* @typeParam
|
|
240
|
-
*
|
|
241
|
-
* `
|
|
258
|
+
* @typeParam D - The workflow DEFINITION, which types both halves of the
|
|
259
|
+
* submission: `submit(input)` takes what the workflow's schema parses to, and
|
|
260
|
+
* `run.status === "completed"` narrows to a typed `run.output`.
|
|
261
|
+
*
|
|
262
|
+
* It used to be the OUTPUT type alone, and the asymmetry was the bug: a page
|
|
263
|
+
* already wrote `WorkflowOutputOf<typeof digest>` to get the output, while
|
|
264
|
+
* `submit` took `unknown`, so `submit({ ur1: 42 })` compiled and arrived as a
|
|
265
|
+
* 400 in the browser. Naming the def instead types the input from the same
|
|
266
|
+
* declaration — and `import type` is ERASED, so it costs the bundle nothing.
|
|
267
|
+
* Passing an output type where a def belongs is now a compile error rather
|
|
268
|
+
* than a silent loss of typing, which is the point.
|
|
242
269
|
*
|
|
243
270
|
* @example
|
|
244
|
-
* ```tsx
|
|
271
|
+
* ```tsx no-check
|
|
245
272
|
* import { Form, SubmitButton, TextField, useWorkflowSubmit } from "@alexkroman1/aai-ui";
|
|
273
|
+
* import type { digest } from "./agent.ts";
|
|
246
274
|
*
|
|
247
275
|
* function DigestForm() {
|
|
248
|
-
* const { submit, run, pending, error } = useWorkflowSubmit("digest");
|
|
276
|
+
* const { submit, run, pending, error } = useWorkflowSubmit<typeof digest>("digest");
|
|
249
277
|
* return (
|
|
250
278
|
* <Form onSubmit={(values) => submit(values)} error={error}>
|
|
251
279
|
* <TextField name="url" label="Link" type="url" required />
|
|
252
280
|
* <SubmitButton pending={pending}>Digest</SubmitButton>
|
|
253
|
-
* {run?.status === "completed" && <p>
|
|
281
|
+
* {run?.status === "completed" && <p>{run.output.title}</p>}
|
|
254
282
|
* </Form>
|
|
255
283
|
* );
|
|
256
284
|
* }
|
|
@@ -258,4 +286,4 @@ export type UseWorkflowSubmitOptions = {
|
|
|
258
286
|
*
|
|
259
287
|
* @public
|
|
260
288
|
*/
|
|
261
|
-
export declare function useWorkflowSubmit<
|
|
289
|
+
export declare function useWorkflowSubmit<D extends AnyWorkflowDef>(workflow: string, opts?: UseWorkflowSubmitOptions): WorkflowSubmission<WorkflowOutputOf<D>, SubmitInputOf<D>>;
|
|
@@ -76,7 +76,9 @@
|
|
|
76
76
|
* `stream.ts`'s idle bound (five minutes of no new bytes) is what decides that a
|
|
77
77
|
* pause has become an abandonment.
|
|
78
78
|
*/
|
|
79
|
+
import type { AnyWorkflowDef, WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
|
|
79
80
|
import type { UseWorkflowSubmitOptions, WorkflowSubmission } from "./use-workflow-form.ts";
|
|
81
|
+
import type { SubmitInputOf } from "./workflow-def-types.ts";
|
|
80
82
|
/**
|
|
81
83
|
* Options for {@link useWorkflowStream}.
|
|
82
84
|
*
|
|
@@ -111,7 +113,7 @@ export type UseWorkflowStreamOptions = Omit<UseWorkflowSubmitOptions, "wait">;
|
|
|
111
113
|
* are in. That is what lets a page render `<WorkflowProgress>` beside the
|
|
112
114
|
* upload bar rather than after it.
|
|
113
115
|
*/
|
|
114
|
-
export type WorkflowStreamSubmission<R = unknown> = WorkflowSubmission<R>;
|
|
116
|
+
export type WorkflowStreamSubmission<R = unknown, I = unknown> = WorkflowSubmission<R, I>;
|
|
115
117
|
/**
|
|
116
118
|
* Start a workflow run and stream a file into it while it works.
|
|
117
119
|
*
|
|
@@ -137,4 +139,4 @@ export type WorkflowStreamSubmission<R = unknown> = WorkflowSubmission<R>;
|
|
|
137
139
|
*
|
|
138
140
|
* @public
|
|
139
141
|
*/
|
|
140
|
-
export declare function useWorkflowStream<
|
|
142
|
+
export declare function useWorkflowStream<D extends AnyWorkflowDef>(workflow: string, opts?: UseWorkflowStreamOptions): WorkflowStreamSubmission<WorkflowOutputOf<D>, SubmitInputOf<D>>;
|
|
@@ -57,7 +57,7 @@ export type WorkflowRun<R = unknown> = WorkflowRunSnapshot<R>;
|
|
|
57
57
|
* and a structural restatement would be a second thing to keep in step with the
|
|
58
58
|
* routes for no gain.
|
|
59
59
|
*/
|
|
60
|
-
export type { WorkflowApi, WorkflowOutputOf, WorkflowRunStatus, WorkflowSummary, } from "@alexkroman1/aai/workflow-api";
|
|
60
|
+
export type { WorkflowApi, WorkflowInputOf, WorkflowOutputOf, WorkflowRunStatus, WorkflowSummary, } from "@alexkroman1/aai/workflow-api";
|
|
61
61
|
/**
|
|
62
62
|
* A run status nothing will change again.
|
|
63
63
|
*
|
|
@@ -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>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexkroman1/aai-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"use-stick-to-bottom": "^1.1.6",
|
|
34
34
|
"use-sync-external-store": "^1.6.0",
|
|
35
35
|
"xstate": "^5.32.5",
|
|
36
|
-
"@alexkroman1/aai": "
|
|
36
|
+
"@alexkroman1/aai": "9.0.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": "^19.0.0",
|