@alexkroman1/aai-ui 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) 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.d.ts +4 -2
  9. package/dist/append-dictation.d.ts +23 -0
  10. package/dist/audio/dictation.d.ts +36 -0
  11. package/dist/audio/index.d.ts +4 -2
  12. package/dist/audio/index.js +44 -1
  13. package/dist/{chat-view-W6KcdjJY.js → chat-view-BwKpF0MN.js} +27 -17
  14. package/dist/{client-config-CzvWmw4X.js → client-config-DcMCWmkO.js} +1 -1
  15. package/dist/components/button.js +1 -1
  16. package/dist/components/chat-view.js +1 -2
  17. package/dist/components/controls.js +2 -2
  18. package/dist/components/form-fields.d.ts +24 -5
  19. package/dist/components/form-types.d.ts +32 -0
  20. package/dist/components/form.d.ts +1 -1
  21. package/dist/components/message-list.js +1 -2
  22. package/dist/components/session-state-dot.d.ts +30 -18
  23. package/dist/components/sidebar-layout.js +1 -1
  24. package/dist/components/start-screen.js +2 -2
  25. package/dist/components/tool-call-block.js +1 -2
  26. package/dist/components/tool-config-context.d.ts +21 -4
  27. package/dist/components/workflow-fields.d.ts +36 -12
  28. package/dist/components/workflow-pending-note.d.ts +30 -12
  29. package/dist/context-BF0KsI9X.js +473 -0
  30. package/dist/context.js +1 -381
  31. package/dist/default-client/assets/audio-CtBvSS3L.js +1 -0
  32. package/dist/default-client/assets/{capture-processor-Cx1AdMHL.js → capture-processor-BZXisGjZ.js} +1 -1
  33. package/dist/default-client/assets/index-BkjCv4MX.css +2 -0
  34. package/dist/default-client/assets/index-DUQoaxdq.js +127 -0
  35. package/dist/default-client/assets/{playback-processor-CCwTknSu.js → playback-processor-BHk-iXEU.js} +1 -1
  36. package/dist/default-client/index.html +2 -2
  37. package/dist/default-client.d.ts +1 -3
  38. package/dist/define-client.d.ts +30 -28
  39. package/dist/define-client.js +84 -43
  40. package/dist/dictation-transcriber.d.ts +49 -0
  41. package/dist/{eyebrow-UfmSz9yy.js → eyebrow-Bp4y1rZ9.js} +1 -1
  42. package/dist/{hooks-DN4gHYsj.js → hooks-1CoQY_Fc.js} +2 -2
  43. package/dist/hooks.js +1 -2
  44. package/dist/index.d.ts +11 -8
  45. package/dist/index.js +849 -263
  46. package/dist/internal.d.ts +1 -1
  47. package/dist/internal.js +6 -6
  48. package/dist/{message-list-BsaBkBgo.js → message-list-BBHLK05X.js} +3 -3
  49. package/dist/route-fetch.d.ts +7 -1
  50. package/dist/session/index.js +1 -1
  51. package/dist/{session-3lgPYNNO.js → session-Rud8mmU-.js} +2 -2
  52. package/dist/{tool-call-block-uXtMOUWN.js → tool-call-block-C8s6AhjS.js} +4 -4
  53. package/dist/tool-config-context-Bd-7xrfP.js +28 -0
  54. package/dist/types.d.ts +47 -2
  55. package/dist/{url-chips-oyy_Eiqh.js → url-chips-C_SHU6fq.js} +2 -2
  56. package/dist/use-dictation.d.ts +145 -0
  57. package/dist/use-route.d.ts +49 -7
  58. package/dist/use-run-key.d.ts +6 -1
  59. package/dist/{use-user-transcript-uyHhzy4d.js → use-user-transcript-lOu_uMnf.js} +1 -1
  60. package/dist/use-workflow-form.d.ts +74 -172
  61. package/dist/{use-workflow-run-DdhWmbx-.js → use-workflow-run-BTEemod0.js} +2 -2
  62. package/dist/use-workflow-runs.d.ts +8 -2
  63. package/dist/use-workflow-stream.d.ts +9 -5
  64. package/dist/workflow-def-types.d.ts +18 -2
  65. package/dist/workflow-field-kind.d.ts +59 -7
  66. package/dist/workflow-submission.d.ts +265 -0
  67. package/package.json +2 -2
  68. package/dist/default-client/assets/audio-Ct7JpSNT.js +0 -1
  69. package/dist/default-client/assets/index-BlUYCTB5.js +0 -126
  70. package/dist/default-client/assets/index-_-x5JLLa.css +0 -2
  71. package/dist/tool-config-context-Es4YUzV2.js +0 -19
@@ -4,7 +4,8 @@
4
4
  * `useWorkflowRun` (`workflow-client.ts`) watches a run you already have.
5
5
  * This is what comes before it: `useWorkflowSubmit` starts a run and hands the
6
6
  * id straight to `useWorkflowRun`. Its sibling `useWorkflows` — the listing
7
- * `<WorkflowFields>` renders a form from — is `use-workflows.ts`.
7
+ * `<WorkflowFields>` renders a form from — is `use-workflows.ts`. What it hands
8
+ * back is `WorkflowSubmission` (`workflow-submission.ts`).
8
9
  *
9
10
  * ## `useWorkflowSubmit` — a form's two halves in one hook
10
11
  *
@@ -31,168 +32,11 @@
31
32
  * `wait` here when the page really does want one request, and the run is
32
33
  * followed from the same id either way.
33
34
  */
34
- import type { AnyWorkflowDef, UploadParallelOption, UploadProgress, WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
35
- import type { FormValues } from "./components/form-types.ts";
36
- import type { WorkflowApi, WorkflowRun } from "./workflow-client.ts";
37
- import type { SubmitInputOf } from "./workflow-def-types.ts";
38
- /**
39
- * What {@link WorkflowSubmission.upload} reports while the bytes are going.
40
- *
41
- * The SDK's per-request {@link UploadProgress} plus WHICH file it describes,
42
- * because a form is allowed more than one and a bar over "the upload" would
43
- * restart at zero partway through with nothing to say why.
44
- *
45
- * @sealed
46
- * @public
47
- */
48
- export type UploadStatus = UploadProgress & {
49
- /** The file being sent, by the name the picker gave it. */
50
- name: string;
51
- /** Which file of the submission this is, counting from 1. */
52
- index: number;
53
- /** How many files this submission sends in total. */
54
- count: number;
55
- /**
56
- * Whether the person has parked this upload.
57
- *
58
- * A paused upload is not a stopped one: the windows already stored stay stored,
59
- * `loaded` holds where it got to, and resuming sends what is missing rather than
60
- * the file. So a bar rendering this reads "Paused at 62%", never "62% and
61
- * frozen" — which is what a page could otherwise only guess from a number that
62
- * stopped moving, the same ambiguity `complete` exists to remove on the run side.
63
- */
64
- paused: boolean;
65
- };
66
- /**
67
- * What {@link useWorkflowSubmit} returns.
68
- *
69
- * @see {@link WorkflowStreamSubmission} — an ALIAS of this type, returned by
70
- * `useWorkflowStream`, which is a drop-in sibling. Exactly two fields MEAN
71
- * something different there, and both differences follow from WHEN the run is
72
- * created: there, `submit()` resolves when the UPLOAD finishes rather than when
73
- * the run is accepted, and `run` is non-`undefined` from before the bytes are
74
- * in, so a page can render `<WorkflowProgress>` beside the upload bar instead
75
- * of after it. Here the run does not exist until the last byte lands.
76
- *
77
- * @sealed
78
- */
79
- export type WorkflowSubmission<R = unknown, I = unknown> = {
80
- /**
81
- * Start a run with this input. Resolves once the run EXISTS — progress
82
- * arrives through `run` — so a `<Form>`'s handler can await it to know the
83
- * submission was accepted.
84
- */
85
- submit: (input: I) => Promise<void>;
86
- /**
87
- * Start a run from a `<Form>`'s values, which are UNVALIDATED.
88
- *
89
- * The same function as {@link WorkflowSubmission.submit}, with the type the
90
- * form path can honestly offer. `FormValues` is `Record<string, unknown>`
91
- * scraped off the DOM at submit time — a `<TextField name="limit">`
92
- * contributes a string whatever the schema says — so the shape is not known
93
- * here and the SERVER is what checks it against the workflow's schema.
94
- *
95
- * Two doors rather than one loose one: `submit` takes the workflow's own
96
- * input type, so a hand-built object is checked at compile time and
97
- * `submit({ ur1: 42 })` is an error; widening it to accept `FormValues` would
98
- * have made every object satisfy it and given the typing back. Reaching for
99
- * this one is the author saying "these came from a form", which is a fact
100
- * about the values and not a cast.
101
- */
102
- submitForm: (values: FormValues) => Promise<void>;
103
- /** Clear the run and any error, putting the form back to its initial state. */
104
- reset: () => void;
105
- /**
106
- * End the current run's `sleep()` early — "file it now" — resolving how many
107
- * pending sleeps were interrupted.
108
- *
109
- * Bound to the run this submission is following, which is the point: it is
110
- * the only reason a page holding one of these hooks needed an `api` of its
111
- * own. `0` is an answer rather than a failure (the run had already moved past
112
- * its wait, or there is no run yet), so nothing here has to be guarded.
113
- */
114
- wake: () => Promise<number>;
115
- /**
116
- * Stop the current run, resolving whether this call is what ended it.
117
- *
118
- * `false` for a run that had already finished, and for no run at all — the
119
- * SDK's contract, because two tabs pressing Stop is ordinary. Distinct from
120
- * `reset()`, which puts the FORM back and leaves the run running.
121
- */
122
- cancel: () => Promise<boolean>;
123
- /** The run, once started, followed to completion. */
124
- run: WorkflowRun<R> | undefined;
125
- /**
126
- * True from `submit()` on this mount until `reset()` — did THIS page start
127
- * the run it is showing?
128
- *
129
- * A page needs it to say the right sentence and cannot derive it: a run
130
- * ADOPTED by the mount-time lookup after a reload looks exactly like one this
131
- * page started. Six templates kept a `useState(false)` next to this hook, set
132
- * it in their `onSubmit` and mirrored it in their `onClear` — shadow state
133
- * for a fact only this hook can know, since it is the thing that decides
134
- * between `submit()` and the recovery lookup. One of the six grew a fourth
135
- * branch and had to move the whole note into its own module with its own
136
- * spec, which is what a seam missing one layer down looks like.
137
- *
138
- * The RAW fact rather than a derived "recovered", deliberately: with `run`
139
- * these are three states, not two, and the third is the one a page most needs
140
- * to explain. `startedHere` is "you pressed the button"; `!startedHere &&
141
- * !run` is the mount-time lookup still going; `!startedHere && run` is a run
142
- * this browser started earlier, now in front of somebody who did not press
143
- * anything. A boolean meaning only the last of those cannot express the
144
- * middle one.
145
- *
146
- * @example
147
- * ```ts
148
- * declare const submission: import("@alexkroman1/aai-ui").WorkflowSubmission;
149
- * const note = submission.startedHere
150
- * ? "You can close this tab or reload it — this page will find the run again."
151
- * : submission.run === undefined
152
- * ? "Looking for a run this tab started earlier…"
153
- * : "Still working on the run this tab started earlier. Reloading is safe.";
154
- * ```
155
- */
156
- startedHere: boolean;
157
- /**
158
- * True from `submit()` until the run reaches a terminal status.
159
- *
160
- * The WORK, not the request: a run outlives its `POST`, and a submit button
161
- * that re-enabled on the response would invite a second submission of work
162
- * already in flight.
163
- */
164
- pending: boolean;
165
- /**
166
- * How far the submission's files have got, while any are still going.
167
- *
168
- * Undefined before the first byte and again from the moment the last one
169
- * lands, so a page can render `{upload && <UploadProgressBar upload={upload} />}`
170
- * and the bar exists exactly for as long as there is an upload to describe. A
171
- * form with no files never sets it at all.
172
- *
173
- * The wait it covers is the one `run` cannot: a run does not EXIST until its
174
- * input is stored, so `pending` is true and there is nothing to poll — which
175
- * for a 200 MB recording is minutes of a page that looks stuck.
176
- */
177
- upload: UploadStatus | undefined;
178
- /**
179
- * Park the upload where it is, stopping the bytes in flight.
180
- *
181
- * The windows already stored stay stored, so `resumeUpload()` sends what is
182
- * missing rather than the file — which is the difference between a pause a
183
- * person will actually use on a 200 MB recording and a cancel dressed up as one.
184
- *
185
- * `submit()`'s promise stays unresolved across a pause, because the submission
186
- * genuinely has not finished: the run does not exist until the last byte lands,
187
- * so resolving here would tell a `<Form>` the work was accepted when nothing has
188
- * been started. A no-op when there is no upload in flight.
189
- */
190
- pauseUpload: () => void;
191
- /** Continue a paused upload, sending only the windows the store does not have. */
192
- resumeUpload: () => void;
193
- /** The submit's own failure (a rejected input), or the watch's. */
194
- error: string | undefined;
195
- };
35
+ import type { AnyWorkflowDef, UploadParallelOption, WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
36
+ import type { WorkflowApi } from "./workflow-client.ts";
37
+ import type { SubmitInputOf, WorkflowAppLike, WorkflowDefOf, WorkflowNameOf } from "./workflow-def-types.ts";
38
+ import type { WorkflowSubmission } from "./workflow-submission.ts";
39
+ export type { UploadStatus, WorkflowSubmission } from "./workflow-submission.ts";
196
40
  /**
197
41
  * Options for {@link useWorkflowSubmit}.
198
42
  *
@@ -208,13 +52,22 @@ export type UseWorkflowSubmitOptions = {
208
52
  * load produces again — `useRunKey()`'s, minted by the hook. Pass one to
209
53
  * scope runs to something the page knows better: an ACCOUNT's own id, which
210
54
  * is what makes a run follow the person to a new device, or
211
- * `useRunKey({ storage: "local" })` for a run that outlives the tab by
212
- * design. The key is a lookup CAPABILITY (there is no per-user filtering
213
- * behind `find`), it must fit the route's 256-character bound, and anything
214
- * derived from a person's own input both collides and carries what they
215
- * typed — `use-run-key.ts` argues every alternative.
55
+ * `{ storage: "local" }` — `useRunKey({ storage: "local" })`'s key, minted
56
+ * here — for a run that outlives the tab by design. The key is a lookup
57
+ * CAPABILITY (there is no per-user filtering behind `find`), it must fit the
58
+ * route's 256-character bound, and anything derived from a person's own
59
+ * input both collides and carries what they typed — `use-run-key.ts` argues
60
+ * every alternative. What was chosen is reported back as
61
+ * `WorkflowSubmission.scope`.
62
+ *
63
+ * **An empty or whitespace key THROWS** at the hook (and the route answers
64
+ * 400): `""` is not "no key" but one key shared by every visitor whose key
65
+ * computed to it — `user?.id ?? ""` before login. Pass `undefined` until the
66
+ * key is known.
216
67
  */
217
- key?: string;
68
+ key?: string | {
69
+ readonly storage?: "session" | "local" | undefined;
70
+ };
218
71
  /**
219
72
  * On mount, adopt the newest run this `key` already has.
220
73
  *
@@ -270,15 +123,35 @@ export type UseWorkflowSubmitOptions = {
270
123
  * Passing an output type where a def belongs is now a compile error rather
271
124
  * than a silent loss of typing, which is the point.
272
125
  *
126
+ * **Or the AGENT.** `useWorkflowSubmit<typeof agentDef>("digest")` reads the
127
+ * def off the agent's own `workflows` map, and the NAME is then a literal the
128
+ * compiler checks — a typo is an error naming the keys the agent declares,
129
+ * where the def form accepts any string and 404s. See `WorkflowNameOf`; an
130
+ * app with several workflows names the one it means as a second type
131
+ * argument.
132
+ *
273
133
  * @example
274
- * ```tsx no-check
134
+ * ```tsx
135
+ * // file: agent.ts
136
+ * import { agent, workflow } from "@alexkroman1/aai";
137
+ * import { z } from "zod";
138
+ *
139
+ * export const digest = workflow({
140
+ * input: z.object({ url: z.string() }),
141
+ * output: z.object({ title: z.string() }),
142
+ * run: async ({ url }) => ({ title: url }),
143
+ * });
144
+ *
145
+ * export default agent({ name: "Digest", workflows: { digest } });
146
+ *
147
+ * // file: client.tsx
275
148
  * import { Form, SubmitButton, TextField, useWorkflowSubmit } from "@alexkroman1/aai-ui";
276
149
  * import type { digest } from "./agent.ts";
277
150
  *
278
151
  * function DigestForm() {
279
- * const { submit, run, pending, error } = useWorkflowSubmit<typeof digest>("digest");
152
+ * const { submitForm, run, pending, error } = useWorkflowSubmit<typeof digest>("digest");
280
153
  * return (
281
- * <Form onSubmit={(values) => submit(values)} error={error}>
154
+ * <Form onSubmit={(values) => submitForm(values)} error={error}>
282
155
  * <TextField name="url" label="Link" type="url" required />
283
156
  * <SubmitButton pending={pending}>Digest</SubmitButton>
284
157
  * {run?.status === "completed" && <p>{run.output.title}</p>}
@@ -287,6 +160,35 @@ export type UseWorkflowSubmitOptions = {
287
160
  * }
288
161
  * ```
289
162
  *
163
+ * @example Named through the agent, so the name is checked
164
+ * ```tsx
165
+ * // file: agent.ts
166
+ * import { agent, workflow } from "@alexkroman1/aai";
167
+ * import { z } from "zod";
168
+ *
169
+ * export const digest = workflow({
170
+ * input: z.object({ url: z.string() }),
171
+ * output: z.object({ title: z.string() }),
172
+ * run: async ({ url }) => ({ title: url }),
173
+ * });
174
+ *
175
+ * export default agent({ name: "Digest", workflows: { digest } });
176
+ *
177
+ * // file: client.tsx
178
+ * import { useWorkflowSubmit } from "@alexkroman1/aai-ui";
179
+ * import type agentDef from "./agent.ts";
180
+ *
181
+ * export function DigestForm() {
182
+ * const { submit } = useWorkflowSubmit<typeof agentDef>("digest"); // "digset" would not compile
183
+ * return (
184
+ * <button type="button" onClick={() => submit({ url: "https://example.com/a" })}>
185
+ * Digest
186
+ * </button>
187
+ * );
188
+ * }
189
+ * ```
190
+ *
290
191
  * @public
291
192
  */
193
+ export declare function useWorkflowSubmit<App extends WorkflowAppLike = never, Name extends WorkflowNameOf<App> = WorkflowNameOf<App>>(workflow: Name, options?: UseWorkflowSubmitOptions): WorkflowSubmission<WorkflowOutputOf<WorkflowDefOf<App, Name>>, SubmitInputOf<WorkflowDefOf<App, Name>>>;
292
194
  export declare function useWorkflowSubmit<D extends AnyWorkflowDef>(workflow: string, options?: UseWorkflowSubmitOptions): WorkflowSubmission<WorkflowOutputOf<D>, SubmitInputOf<D>>;
@@ -1,4 +1,4 @@
1
- import { n as pageBaseUrl } from "./_utils-Mi-SCFA1.js";
1
+ import { n as pageBaseUrl } from "./_utils-BlZBJPdj.js";
2
2
  import { errorMessage } from "@alexkroman1/aai";
3
3
  import { useCallback, useEffect, useRef, useState } from "react";
4
4
  import { omitUndefined } from "@alexkroman1/aai/utils";
@@ -694,4 +694,4 @@ function useWorkflowRun(runId, options = {}) {
694
694
  };
695
695
  }
696
696
  //#endregion
697
- export { useWorkflowProgress as a, isTerminal$1 as c, DEFAULT_PROGRESS_POLL_MS as i, MAX_MISSING_READS as n, useWorkflowApiRef as o, useWorkflowRun as r, createWorkflowApi as s, DEFAULT_WORKFLOW_POLL_MS as t };
697
+ export { useWorkflowProgress as a, createWorkflowApi as c, DEFAULT_PROGRESS_POLL_MS as i, isTerminal$1 as l, MAX_MISSING_READS as n, repeatUntil as o, useWorkflowRun as r, useWorkflowApiRef as s, DEFAULT_WORKFLOW_POLL_MS as t };
@@ -20,7 +20,9 @@
20
20
  * a page calls when its own run settles, which is exactly when the list is
21
21
  * stale.
22
22
  */
23
+ import type { WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
23
24
  import type { WorkflowApi, WorkflowRun } from "./workflow-client.ts";
25
+ import type { WorkflowAppLike, WorkflowDefOf, WorkflowNameOf, WorkflowsOf } from "./workflow-def-types.ts";
24
26
  /**
25
27
  * Options for {@link useWorkflowRuns}.
26
28
  *
@@ -62,7 +64,10 @@ export type UseWorkflowRunsResult<R = unknown> = {
62
64
  * Read a workflow's recent runs.
63
65
  *
64
66
  * @typeParam R - The workflow's output type, so a completed run's `output` is
65
- * typed rather than `unknown`. Derive it with `WorkflowOutputOf`.
67
+ * typed rather than `unknown`. Derive it with `WorkflowOutputOf` — or name
68
+ * the AGENT instead, `useWorkflowRuns<typeof agentDef>("transcribe")`, and
69
+ * both the name and the output come off its `workflows` map (see
70
+ * `WorkflowNameOf`).
66
71
  *
67
72
  * @example
68
73
  * ```tsx
@@ -76,4 +81,5 @@ export type UseWorkflowRunsResult<R = unknown> = {
76
81
  *
77
82
  * @public
78
83
  */
79
- export declare function useWorkflowRuns<R = unknown>(workflow: string | undefined, options?: UseWorkflowRunsOptions): UseWorkflowRunsResult<R>;
84
+ export declare function useWorkflowRuns<App extends WorkflowAppLike = never, Name extends WorkflowNameOf<App> = WorkflowNameOf<App>>(workflow: [App] extends [never] ? never : Name | undefined, options?: UseWorkflowRunsOptions): UseWorkflowRunsResult<WorkflowOutputOf<WorkflowDefOf<App, Name>>>;
85
+ export declare function useWorkflowRuns<R = unknown>(workflow: [WorkflowsOf<R>] extends [never] ? string | undefined : never, options?: UseWorkflowRunsOptions): UseWorkflowRunsResult<R>;
@@ -77,9 +77,9 @@
77
77
  * pause has become an abandonment.
78
78
  */
79
79
  import type { AnyWorkflowDef, UploadParallelOption, WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
80
- import type { WorkflowSubmission } from "./use-workflow-form.ts";
81
80
  import type { WorkflowApi } from "./workflow-client.ts";
82
- import type { SubmitInputOf } from "./workflow-def-types.ts";
81
+ import type { SubmitInputOf, WorkflowAppLike, WorkflowDefOf, WorkflowNameOf } from "./workflow-def-types.ts";
82
+ import type { WorkflowSubmission } from "./workflow-submission.ts";
83
83
  /**
84
84
  * Options for {@link useWorkflowStream}.
85
85
  *
@@ -130,13 +130,13 @@ export type UseWorkflowStreamOptions = {
130
130
  /**
131
131
  * What {@link useWorkflowStream} returns: a {@link WorkflowSubmission}, exactly.
132
132
  *
133
- * The same eight fields `useWorkflowSubmit` returns, of which this hook is a
133
+ * The same fields `useWorkflowSubmit` returns, of which this hook is a
134
134
  * drop-in sibling — same `<Form>`, same `<UploadProgressBar>`, same
135
- * `<WorkflowProgress>`. An ALIAS rather than a second declaration of the eight:
135
+ * `<WorkflowProgress>`. An ALIAS rather than a second declaration of them:
136
136
  * the two have to agree field for field to be drop-in, and two copies of a type
137
137
  * that have to agree are two copies that can stop agreeing.
138
138
  *
139
- * Exactly two of the fields mean something different here, and both differences
139
+ * Exactly three of the fields mean something different here, and all three
140
140
  * follow from WHEN the run is created — it exists before its bytes do:
141
141
  *
142
142
  * - `submit()` resolves when the UPLOAD finishes, not when the run is accepted;
@@ -146,6 +146,9 @@ export type UseWorkflowStreamOptions = {
146
146
  * - `run` is set from the moment the run EXISTS, which here is before the bytes
147
147
  * are in. That is what lets a page render `<WorkflowProgress>` beside the
148
148
  * upload bar rather than after it.
149
+ * - `scope` is always `"none"`: the run is reading the bytes THIS page sends,
150
+ * so a reload does not orphan it, it ENDS it — and `<WorkflowPendingNote>`
151
+ * says so instead of promising the run will be found again.
149
152
  */
150
153
  export type WorkflowStreamSubmission<R = unknown, I = unknown> = WorkflowSubmission<R, I>;
151
154
  /**
@@ -173,4 +176,5 @@ export type WorkflowStreamSubmission<R = unknown, I = unknown> = WorkflowSubmiss
173
176
  *
174
177
  * @public
175
178
  */
179
+ export declare function useWorkflowStream<App extends WorkflowAppLike = never, Name extends WorkflowNameOf<App> = WorkflowNameOf<App>>(workflow: Name, options?: UseWorkflowStreamOptions): WorkflowStreamSubmission<WorkflowOutputOf<WorkflowDefOf<App, Name>>, SubmitInputOf<WorkflowDefOf<App, Name>>>;
176
180
  export declare function useWorkflowStream<D extends AnyWorkflowDef>(workflow: string, options?: UseWorkflowStreamOptions): WorkflowStreamSubmission<WorkflowOutputOf<D>, SubmitInputOf<D>>;
@@ -1,7 +1,8 @@
1
1
  /**
2
- * The narrowing the workflow hooks apply to a DEF's input type.
2
+ * The narrowings the workflow hooks apply to a DEF's input type, and the
3
+ * readings that let a page name a workflow through its AGENT instead.
3
4
  *
4
- * It used to fall back to `unknown` so an un-parameterized
5
+ * `SubmitInputOf` used to fall back to `unknown` so an un-parameterized
5
6
  * `useWorkflowSubmit("digest")` kept compiling. It does not any more — the def
6
7
  * is required — because the fallback was the last way to get an untyped
7
8
  * `submit` back, and an escape hatch nobody needs is one somebody uses.
@@ -10,6 +11,20 @@
10
11
  * spelled a second way and nothing else, so the hooks name `WorkflowOutputOf`
11
12
  * directly — the SDK type this package already re-exports, and the one a page
12
13
  * reading the rendered signature can click through to.
14
+ *
15
+ * ## Naming a workflow through the agent
16
+ *
17
+ * A page used to need the def itself in scope — `import type { digest } from
18
+ * "./agent.ts"` — which works only when `agent.ts` exports it under a name,
19
+ * and says nothing about the STRING the page then passes: `useWorkflowSubmit<
20
+ * typeof digest>("digets")` typechecks and 404s. {@link WorkflowNameOf} and
21
+ * {@link WorkflowDefOf} read both off the agent's own `workflows` map, so a
22
+ * page writes `import type agentDef from "./agent.ts"` and the name is a
23
+ * literal the compiler knows; a typo is an error naming the keys the agent has.
24
+ * The workflows a build DISCOVERS in `workflows/` are not in that map at the
25
+ * type level — only `agent({ workflows })`'s entries are — so those pages keep
26
+ * the def form. The four readings are declared by the SDK
27
+ * (`@alexkroman1/aai/workflow-api`) and re-exported here.
13
28
  */
14
29
  import type { WorkflowInputOf } from "@alexkroman1/aai/workflow-api";
15
30
  /**
@@ -29,3 +44,4 @@ import type { WorkflowInputOf } from "@alexkroman1/aai/workflow-api";
29
44
  * @public
30
45
  */
31
46
  export type SubmitInputOf<D> = [WorkflowInputOf<D>] extends [never] ? undefined : WorkflowInputOf<D>;
47
+ export type { WorkflowAppLike, WorkflowDefOf, WorkflowNameOf, WorkflowsOf, } from "@alexkroman1/aai/workflow-api";
@@ -38,18 +38,60 @@
38
38
  * text field is — the same value over the wire — so it is a hand-written swap
39
39
  * rather than a shape the schema can ask for.
40
40
  *
41
+ * Two NON-scalar shapes do have an honest control, and are the two members
42
+ * past the scalars: `"lines"` is `<TextAreaField split="lines">` for an array
43
+ * of strings (one per line), and `"namedText"` is `<FileField read="text"
44
+ * as="namedText">` for an object of exactly `{ name: string, text: string }` —
45
+ * a draft, a config, read in the browser and journaled with the input. Both
46
+ * were the hand-written half of `document-redline-workflow`'s mixed form; a
47
+ * page may also ASK for either by name through `render`.
48
+ *
41
49
  * Open (`| (string & {})`): a control added later is a new value, so read an
42
50
  * unknown kind as `"none"`.
43
51
  *
44
52
  * @public
45
53
  */
46
- export type WorkflowFieldKind = "text" | "number" | "select" | "checkbox" | "file" | "none" | (string & {});
54
+ export type WorkflowFieldKind = "text" | "number" | "select" | "checkbox" | "file" | "lines" | "namedText" | "none" | (string & {});
55
+ /**
56
+ * The kinds a page may ask `<WorkflowFields render>` for by property name —
57
+ * the two non-scalar controls, which a schema cannot always say it wants.
58
+ *
59
+ * @public
60
+ */
61
+ export type WorkflowFieldRender = "lines" | "namedText";
62
+ /**
63
+ * The schema with a NULLABLE union unwrapped: `anyOf: [X, { type: "null" }]`
64
+ * reads as `X`, the way `type: ["string", "null"]` reads as `"string"`.
65
+ *
66
+ * Zod 4 converts `z.enum([…]).nullable()` (and any nullable whose inner schema
67
+ * carries keywords of its own) to that `anyOf`, where a bare
68
+ * `z.string().nullable()` becomes the type list — so a required nullable enum
69
+ * used to reach the type switch with no `type` at all, render NO control, and
70
+ * leave a required property out of every submission. A union with two or more
71
+ * non-null members is some other shape and is answered as itself; a schema
72
+ * that is not an object has no answer.
73
+ *
74
+ * Not exported from the package barrel, like {@link schemaTypeOf}.
75
+ */
76
+ export declare function nonNullSchemaOf(schema: unknown): Record<string, unknown> | undefined;
77
+ /**
78
+ * The choices a select renders for `schema`, or undefined when it is not a
79
+ * closed set: a non-empty `enum`, or the `const` of each member of a union of
80
+ * literals — which is how zod 4 converts `z.union([z.literal("p"),
81
+ * z.literal("q")])`, where `z.enum` and `z.literal([1, 2])` convert to `enum`.
82
+ * The values keep their own type (`[1, 2]` stays numeric), so the control can
83
+ * submit what the schema declared.
84
+ *
85
+ * Not exported from the package barrel, like {@link schemaTypeOf}.
86
+ */
87
+ export declare function schemaChoicesOf(schema: unknown): readonly unknown[] | undefined;
47
88
  /**
48
89
  * A property's declared type, taking the first non-null member of a union.
49
90
  *
50
91
  * `["string", "null"]` is how an optional-and-nullable field converts; the
51
- * control is the one the non-null half wants. Not exported from the package
52
- * barrel — the published question is the KIND, and this is the one detail
92
+ * control is the one the non-null half wants. A nullable `anyOf` is read the
93
+ * same way ({@link nonNullSchemaOf}). Not exported from the package barrel —
94
+ * the published question is the KIND, and this is the one detail
53
95
  * `<WorkflowFields>` needs past it (an integer's `step`).
54
96
  */
55
97
  export declare function schemaTypeOf(schema: unknown): string | undefined;
@@ -64,10 +106,18 @@ export declare function schemaTypeOf(schema: unknown): string | undefined;
64
106
  * person to type an id no person has. The declaration is the workflow's
65
107
  * (`workflow({ uploads: [...] })`), not the schema's, precisely because a
66
108
  * marker inside the schema would only work for the library that carried it.
67
- * 2. **Then a non-empty `enum`**, before the type switch: an enum of strings
68
- * is a `string` too, and a select is the narrower, better control.
109
+ * 2. **Then a closed set of choices**, before the type switch: a non-empty
110
+ * `enum`, or a union of `const` literals (`schemaChoicesOf`) — an enum
111
+ * of strings is a `string` too, and a select is the narrower, better
112
+ * control. A nullable union (`anyOf: [X, { type: "null" }]`) is read as `X`
113
+ * throughout, as `type: [X, "null"]` already was.
69
114
  * 3. **Then the type** — `boolean`, `number`/`integer`, `string`.
70
- * 4. **Anything else is `"none"`** rather than a guess. See
115
+ * 4. **Then the two non-scalar shapes with a control** — an array of strings
116
+ * is `"lines"`, an object of exactly `{ name: string, text: string }` is
117
+ * `"namedText"`. A page may also name either through `render`, which beats
118
+ * the schema for that property (it is the author saying what the shape
119
+ * means) but never a declared upload.
120
+ * 5. **Anything else is `"none"`** rather than a guess. See
71
121
  * {@link WorkflowFieldKind}.
72
122
  *
73
123
  * @example
@@ -90,10 +140,12 @@ export declare function schemaTypeOf(schema: unknown): string | undefined;
90
140
  * @param schema - The property's JSON Schema, as `GET workflows` reports it.
91
141
  * Anything that is not an object reads as `"none"`.
92
142
  * @param options - `upload` says the property is named in the workflow's own
93
- * `uploads` declaration, which is what step 1 above tests.
143
+ * `uploads` declaration, which is what step 1 above tests; `render` is the
144
+ * page's own choice for the property (`<WorkflowFields render>`).
94
145
  *
95
146
  * @public
96
147
  */
97
148
  export declare function fieldKindFor(schema: unknown, options?: {
98
149
  upload?: boolean | undefined;
150
+ render?: WorkflowFieldRender | undefined;
99
151
  }): WorkflowFieldKind;