@alexkroman1/aai-ui 13.2.0 → 13.3.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 (41) hide show
  1. package/dist/{_colors-j8XMToi9.js → _colors-CZ6OlPbL.js} +1 -1
  2. package/dist/{_module-url-C_4gRVL0.js → _module-url-C13kAJ87.js} +1 -1
  3. package/dist/_recover-run.d.ts +11 -5
  4. package/dist/{_utils-B6498_bm.js → _utils-CyzjK0gW.js} +1 -1
  5. package/dist/{aai-logo-CXZGPSIY.js → aai-logo-CFlomZlS.js} +1 -1
  6. package/dist/audio.js +1 -1
  7. package/dist/{chat-view-DDTtrh7N.js → chat-view-Bv5VFJIE.js} +6 -6
  8. package/dist/{client-config-BT_kWID5.js → client-config-DD820zHn.js} +1 -1
  9. package/dist/client-dir.js +1 -1
  10. package/dist/components/button.js +2 -2
  11. package/dist/components/chat-view.js +1 -1
  12. package/dist/components/controls.js +2 -2
  13. package/dist/components/message-list.js +1 -1
  14. package/dist/components/sidebar-layout.js +1 -1
  15. package/dist/components/start-screen.js +4 -4
  16. package/dist/components/tool-call-block.js +1 -1
  17. package/dist/context.js +1 -1
  18. package/dist/default-client.d.ts +1 -1
  19. package/dist/define-client.js +6 -6
  20. package/dist/{eyebrow-C6ZFuiz6.js → eyebrow-UfmSz9yy.js} +1 -1
  21. package/dist/hooks.js +2 -2
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.js +1168 -1114
  24. package/dist/internal.js +5 -5
  25. package/dist/{message-list-BJYyuIcR.js → message-list-C0pL7x41.js} +7 -7
  26. package/dist/{session-core-DxBYsfHA.js → session-core-C9elBIdu.js} +11 -11
  27. package/dist/session-core.js +1 -1
  28. package/dist/{tool-call-block-tcPQAkcP.js → tool-call-block-Bunc6rCw.js} +6 -6
  29. package/dist/{tool-config-context-DzAofqi_.js → tool-config-context-Bh8p3DtG.js} +1 -1
  30. package/dist/types.js +1 -1
  31. package/dist/{url-chips-YqhCjWfQ.js → url-chips-C2u7QPv8.js} +3 -3
  32. package/dist/use-run-key.d.ts +44 -10
  33. package/dist/{use-user-transcript-C14qWFu2.js → use-user-transcript-DFTSEuZN.js} +1 -1
  34. package/dist/use-workflow-form.d.ts +31 -90
  35. package/dist/{use-workflow-progress-Cu0SxMyg.js → use-workflow-run-CXGEcM0l.js} +256 -256
  36. package/dist/use-workflow-stream.d.ts +4 -1
  37. package/dist/use-workflows.d.ts +77 -0
  38. package/dist/worklets/capture-processor.js +2 -2
  39. package/dist/worklets/playback-processor.js +2 -2
  40. package/package.json +6 -6
  41. package/dist/tsdown.config.d.ts +0 -2
package/dist/internal.js CHANGED
@@ -1,8 +1,8 @@
1
- import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-BT_kWID5.js";
1
+ import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-DD820zHn.js";
2
2
  import { SessionProvider, ThemeProvider } from "./context.js";
3
- import { n as SessionUrlChips, r as UiUrlChip, t as ApiUrlChip } from "./url-chips-YqhCjWfQ.js";
4
- import { t as TRANSCRIBING_PLACEHOLDER } from "./use-user-transcript-C14qWFu2.js";
5
- import { t as ToolConfigContext } from "./tool-config-context-DzAofqi_.js";
6
- import { i as MAX_MISSING_READS, r as DEFAULT_WORKFLOW_POLL_MS, t as DEFAULT_PROGRESS_POLL_MS } from "./use-workflow-progress-Cu0SxMyg.js";
3
+ import { n as SessionUrlChips, r as UiUrlChip, t as ApiUrlChip } from "./url-chips-C2u7QPv8.js";
4
+ import { t as TRANSCRIBING_PLACEHOLDER } from "./use-user-transcript-DFTSEuZN.js";
5
+ import { t as ToolConfigContext } from "./tool-config-context-Bh8p3DtG.js";
6
+ import { i as DEFAULT_PROGRESS_POLL_MS, n as MAX_MISSING_READS, t as DEFAULT_WORKFLOW_POLL_MS } from "./use-workflow-run-CXGEcM0l.js";
7
7
  import { VOICE_CAPTURE_CONSTRAINTS } from "./types.js";
8
8
  export { ApiUrlChip, DEFAULT_PROGRESS_POLL_MS, DEFAULT_WORKFLOW_POLL_MS, MAX_MISSING_READS, SessionProvider, SessionUrlChips, TRANSCRIBING_PLACEHOLDER, ThemeProvider, ToolConfigContext, UiUrlChip, VOICE_CAPTURE_CONSTRAINTS, buildAgentUrl, loadClientConfig };
@@ -1,14 +1,14 @@
1
1
  import { useSessionSelector, useTheme } from "./context.js";
2
- import { i as primaryTint, r as inkTint } from "./_colors-j8XMToi9.js";
3
- import { n as useUserTranscript } from "./use-user-transcript-C14qWFu2.js";
4
- import { t as ToolCallBlock } from "./tool-call-block-tcPQAkcP.js";
2
+ import { i as primaryTint, r as inkTint } from "./_colors-CZ6OlPbL.js";
3
+ import { n as useUserTranscript } from "./use-user-transcript-DFTSEuZN.js";
4
+ import { t as ToolCallBlock } from "./tool-call-block-Bunc6rCw.js";
5
5
  import clsx from "clsx";
6
6
  import { StickToBottom } from "use-stick-to-bottom";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { memo, useMemo } from "react";
9
9
  import ReactMarkdown from "react-markdown";
10
10
  import remarkGfm from "remark-gfm";
11
- //#region components/auto-scroll.tsx
11
+ //#region src/components/auto-scroll.tsx
12
12
  /** @jsxImportSource react */
13
13
  /**
14
14
  * A scroll container that stays pinned to the bottom as its content grows,
@@ -66,7 +66,7 @@ function AutoScroll({ children, className, contentClassName, scrollClassName = "
66
66
  });
67
67
  }
68
68
  //#endregion
69
- //#region use-conversation.ts
69
+ //#region src/use-conversation.ts
70
70
  /**
71
71
  * `useConversation` — the exchange, already assembled, with nothing rendered.
72
72
  *
@@ -191,7 +191,7 @@ function useConversation() {
191
191
  };
192
192
  }
193
193
  //#endregion
194
- //#region components/markdown.tsx
194
+ //#region src/components/markdown.tsx
195
195
  /** @jsxImportSource react */
196
196
  const BARE_ORDERED_MARKER = /^(\s*)(\d{1,9})([.)])\s*$/;
197
197
  const BARE_BULLET_MARKER = /^(\s*)([-*+])\s*$/;
@@ -377,7 +377,7 @@ const Markdown = memo(function Markdown({ text, variant = "default" }) {
377
377
  });
378
378
  });
379
379
  //#endregion
380
- //#region components/message-list.tsx
380
+ //#region src/components/message-list.tsx
381
381
  /** @jsxImportSource react */
382
382
  const DOT_STYLES = [
383
383
  0,
@@ -1,4 +1,4 @@
1
- import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-BT_kWID5.js";
1
+ import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-DD820zHn.js";
2
2
  import { MIC_SEND_MAX_BUFFERED_BYTES } from "./types.js";
3
3
  import { SessionEventSchema, lenientParse } from "@alexkroman1/aai/protocol";
4
4
  import { errorMessage, safeJsonParse } from "@alexkroman1/aai";
@@ -6,7 +6,7 @@ import { omitUndefined } from "@alexkroman1/aai/utils";
6
6
  import { DEFAULT_MAX_HISTORY, WS_OPEN, createEpoch, toArgsRecord } from "@alexkroman1/aai/internal";
7
7
  import ReconnectingWebSocket from "partysocket/ws";
8
8
  import { and, assign, createActor, not, setup, stateIn } from "xstate";
9
- //#region session-core-audio-setup.ts
9
+ //#region src/session-core-audio-setup.ts
10
10
  /**
11
11
  * Audio-path initialization for the voice session core.
12
12
  *
@@ -119,7 +119,7 @@ async function initAudioCapture(conn, msg, deps) {
119
119
  }
120
120
  }
121
121
  //#endregion
122
- //#region session-core-close.ts
122
+ //#region src/session-core-close.ts
123
123
  /**
124
124
  * What a socket's CLOSE means to the caller.
125
125
  *
@@ -160,7 +160,7 @@ function closeFailure(event, socketErrored) {
160
160
  return socketErrored ? "WebSocket connection error" : null;
161
161
  }
162
162
  //#endregion
163
- //#region session-core-reconnect.ts
163
+ //#region src/session-core-reconnect.ts
164
164
  /**
165
165
  * Automatic reconnection for the browser session socket, built on
166
166
  * partysocket's `ReconnectingWebSocket`. Kept out of `session-core.ts` so
@@ -209,7 +209,7 @@ function reconnectPending(socket) {
209
209
  return socket instanceof ReconnectingWebSocket && socket.shouldReconnect && socket.retryCount < RECONNECT_OPTIONS.maxRetries;
210
210
  }
211
211
  //#endregion
212
- //#region session-core-url.ts
212
+ //#region src/session-core-url.ts
213
213
  /** Build the session WebSocket URL from the platform URL and resume state. */
214
214
  function buildWsUrl(platformUrl, resume, sessionId) {
215
215
  return applyResumeParams(buildAgentUrl(platformUrl, "websocket"), resume, sessionId);
@@ -232,7 +232,7 @@ function applyResumeParams(wsUrl, resume, sessionId) {
232
232
  return wsUrl;
233
233
  }
234
234
  //#endregion
235
- //#region session-resume-store.ts
235
+ //#region src/session-resume-store.ts
236
236
  /**
237
237
  * Where a session id survives a page RELOAD.
238
238
  *
@@ -300,7 +300,7 @@ function clearStoredSessionId(platformUrl) {
300
300
  } catch {}
301
301
  }
302
302
  //#endregion
303
- //#region session-core-dial.ts
303
+ //#region src/session-core-dial.ts
304
304
  /**
305
305
  * How the next connection attempt is DIALLED, and the resume identity it dials
306
306
  * with.
@@ -383,7 +383,7 @@ function createDialer(options) {
383
383
  };
384
384
  }
385
385
  //#endregion
386
- //#region session-core-handshake.ts
386
+ //#region src/session-core-handshake.ts
387
387
  /**
388
388
  * The deadline on a socket that opened but never became a session.
389
389
  *
@@ -463,7 +463,7 @@ function createHandshakeGuard(opts) {
463
463
  };
464
464
  }
465
465
  //#endregion
466
- //#region session-core-messages.ts
466
+ //#region src/session-core-messages.ts
467
467
  /**
468
468
  * Incoming-message handling for the voice session core.
469
469
  *
@@ -798,7 +798,7 @@ function createMessageHandlers(deps) {
798
798
  };
799
799
  }
800
800
  //#endregion
801
- //#region session-core-state.ts
801
+ //#region src/session-core-state.ts
802
802
  /**
803
803
  * The browser session's {@link AgentState}, and the error beside it, as a
804
804
  * statechart.
@@ -980,7 +980,7 @@ function createSessionStateMachine() {
980
980
  };
981
981
  }
982
982
  //#endregion
983
- //#region session-core.ts
983
+ //#region src/session-core.ts
984
984
  /**
985
985
  * Framework-agnostic voice session core.
986
986
  *
@@ -1,2 +1,2 @@
1
- import { t as createSessionCore } from "./session-core-DxBYsfHA.js";
1
+ import { t as createSessionCore } from "./session-core-C9elBIdu.js";
2
2
  export { createSessionCore };
@@ -1,12 +1,12 @@
1
1
  import { useTheme } from "./context.js";
2
- import { r as inkTint } from "./_colors-j8XMToi9.js";
3
- import { t as Eyebrow } from "./eyebrow-C6ZFuiz6.js";
4
- import { i as tryParseJSON, r as truncate } from "./_utils-B6498_bm.js";
5
- import { n as useToolConfig } from "./tool-config-context-DzAofqi_.js";
2
+ import { r as inkTint } from "./_colors-CZ6OlPbL.js";
3
+ import { t as Eyebrow } from "./eyebrow-UfmSz9yy.js";
4
+ import { i as tryParseJSON, r as truncate } from "./_utils-CyzjK0gW.js";
5
+ import { n as useToolConfig } from "./tool-config-context-Bh8p3DtG.js";
6
6
  import clsx from "clsx";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { memo, useMemo, useState } from "react";
9
- //#region components/tool-call-row.tsx
9
+ //#region src/components/tool-call-row.tsx
10
10
  /** @jsxImportSource react */
11
11
  const VARIANT_CLASSES = {
12
12
  default: {
@@ -116,7 +116,7 @@ function ToolCallRow({ title, detail, pending = false, icon, variant = "default"
116
116
  });
117
117
  }
118
118
  //#endregion
119
- //#region components/tool-call-block.tsx
119
+ //#region src/components/tool-call-block.tsx
120
120
  /** @jsxImportSource react */
121
121
  function formatResult(result) {
122
122
  const parsed = tryParseJSON(result);
@@ -1,5 +1,5 @@
1
1
  import { createContext, useContext } from "react";
2
- //#region components/tool-config-context.ts
2
+ //#region src/components/tool-config-context.ts
3
3
  /**
4
4
  * Context for tool display configuration. Installed by `client()` from
5
5
  * `ClientConfig.tools`; the built-in components read it via `useToolConfig`.
package/dist/types.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CAPTURE_STOP_ACK_TIMEOUT_MS, CLIENT_AUDIO_LEAD_MS, HEARD_AUDIO_LAG_MS, MIC_BUFFER_SECONDS, MIC_SEND_MAX_BUFFERED_BYTES, MIC_SILENCE_PROBE_MS, PACER_BURST_MS, PIPELINE_PLAYBACK_GRACE_MS, PLAYBACK_BUFFER_SECONDS, PLAYBACK_CONCEAL_FADE_MS, PLAYBACK_CONCEAL_FLOOR, PLAYBACK_DONE_MAX_WAIT_MS, PLAYBACK_DONE_POLL_MS, PLAYBACK_FILL_MS, PLAYBACK_PROGRESS_INTERVAL_MS } from "@alexkroman1/aai/internal";
2
- //#region types.ts
2
+ //#region src/types.ts
3
3
  /**
4
4
  * `getUserMedia` audio constraints for every capture path in this package.
5
5
  *
@@ -1,10 +1,10 @@
1
1
  import { useSessionSelector, useTheme } from "./context.js";
2
- import { r as inkTint } from "./_colors-j8XMToi9.js";
3
- import { t as pageBaseUrl } from "./_utils-B6498_bm.js";
2
+ import { r as inkTint } from "./_colors-CZ6OlPbL.js";
3
+ import { t as pageBaseUrl } from "./_utils-CyzjK0gW.js";
4
4
  import clsx from "clsx";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useEffect, useRef, useState } from "react";
7
- //#region components/url-chips.tsx
7
+ //#region src/components/url-chips.tsx
8
8
  /** @jsxImportSource react */
9
9
  /** How long the "Copied" confirmation replaces the label after a click. */
10
10
  const COPIED_FEEDBACK_MS = 1500;
@@ -1,13 +1,22 @@
1
1
  /**
2
2
  * The handle a page keeps on the runs it started, across a reload.
3
3
  *
4
- * `useWorkflowSubmit({ key, recover: true })` is what makes a run survivable —
5
- * the run id is that hook's own state, so a refresh loses it while the run
6
- * carries on — and the `key` is deliberately the caller's to choose, because it
7
- * is a lookup CAPABILITY: there is no per-user filtering behind `find`, so the
8
- * key IS the scoping mechanism. Choosing one is easy to get wrong in three
9
- * separate ways, and six shipped templates had each written the same twenty
10
- * lines to get it right. This is those lines.
4
+ * `useWorkflowSubmit` is what makes a run survivable — the run id is that
5
+ * hook's own state, so a refresh loses it while the run carries on — and the
6
+ * `key` is what it looks the run up BY, because it is a lookup CAPABILITY:
7
+ * there is no per-user filtering behind `find`, so the key IS the scoping
8
+ * mechanism. Choosing one is easy to get wrong in three separate ways, and six
9
+ * shipped templates had each written the same twenty lines to get it right.
10
+ * This is those lines.
11
+ *
12
+ * **`useWorkflowSubmit` now mints one for itself** ({@link useDefaultRunKey}),
13
+ * so a page resumes its own run across a reload with nothing written at the
14
+ * call site — six of six page templates passed `useRunKey()` and
15
+ * `recover: true`, which is a default in the wrong place. The hook stays
16
+ * PUBLIC for the page that wants to choose: an app with accounts passes the
17
+ * ACCOUNT's own id instead, and a run then follows the person to a new device,
18
+ * which is a promise only a login can keep; a page whose run outlives the tab
19
+ * passes `useRunKey({ storage: "local" })`.
11
20
  *
12
21
  * ## Three properties, and the rejected alternatives are why each one matters
13
22
  *
@@ -42,7 +51,9 @@
42
51
  * coming back on Friday to press Stop is the ordinary case rather than an edge
43
52
  * one, and a tab-scoped key would answer that with an empty form beside a run
44
53
  * still posting somewhere. It is as far as a key can go without a login, and no
45
- * further. `podcast-digest` is that template; the other five ship the default.
54
+ * further. `podcast-digest` is that template, and the reason this hook is still
55
+ * called by name anywhere; the other five take the tab-scoped default the
56
+ * submit hook mints for them.
46
57
  *
47
58
  * ## Anything ELSE a page stores back must be VALIDATED on read
48
59
  *
@@ -77,8 +88,31 @@
77
88
  * failing to render.
78
89
  */
79
90
  /**
80
- * A lookup key for `useWorkflowSubmit({ key, recover: true })`, stable across
81
- * reloads.
91
+ * The key `useWorkflowSubmit` uses when the page named none.
92
+ *
93
+ * Two things it does that a plain `useRunKey()` at the call site cannot, and
94
+ * both are about a page that DID name one:
95
+ *
96
+ * - **It mints nothing when the caller has a key.** Minting writes to storage,
97
+ * so an unconditional `useRunKey()` inside the hook would leave a slot behind
98
+ * on every page that passes an account id and never reads it back.
99
+ * - **It stays reactive to the caller's key.** A key that arrives late — an
100
+ * account id resolved after a login — must reach the lookup, which re-asks on
101
+ * a changed key by design; freezing it into `useState` would pin the page to
102
+ * whatever it held on its first render.
103
+ *
104
+ * The minted half is still frozen for the component's life, which is what
105
+ * `useRunKey` freezes it for: a fresh key per render would record every run
106
+ * under a name the next load cannot produce.
107
+ *
108
+ * @param explicit - The caller's own key, or undefined for a page with none.
109
+ * @returns The key to record runs under and look them up by.
110
+ *
111
+ * @internal
112
+ */
113
+ export declare function useDefaultRunKey(explicit: string | undefined): string;
114
+ /**
115
+ * A lookup key for `useWorkflowSubmit({ key })`, stable across reloads.
82
116
  *
83
117
  * @param options - See the module doc for the whole argument. The storage kind
84
118
  * is read once, when the key is minted: a value that changed afterwards would
@@ -1,5 +1,5 @@
1
1
  import { useSessionSelector } from "./context.js";
2
- //#region use-user-transcript.ts
2
+ //#region src/use-user-transcript.ts
3
3
  /**
4
4
  * `useUserTranscript` — what the caller is saying RIGHT NOW, read correctly.
5
5
  *
@@ -1,11 +1,10 @@
1
1
  /**
2
- * The two hooks a FORM needs, as against the one a status view does.
2
+ * The hook a FORM needs, as against the one a status view does.
3
3
  *
4
4
  * `useWorkflowRun` (`workflow-client.ts`) watches a run you already have.
5
- * These two are what comes before it: `useWorkflows` reads the declared
6
- * workflows so `<WorkflowFields>` can render a form from a schema, and
7
- * `useWorkflowSubmit` starts a run and hands the id straight to
8
- * `useWorkflowRun`.
5
+ * This is what comes before it: `useWorkflowSubmit` starts a run and hands the
6
+ * id straight to `useWorkflowRun`. Its sibling `useWorkflows` — the listing
7
+ * `<WorkflowFields>` renders a form from — is `use-workflows.ts`.
9
8
  *
10
9
  * ## `useWorkflowSubmit` — a form's two halves in one hook
11
10
  *
@@ -32,76 +31,10 @@
32
31
  * `wait` here when the page really does want one request, and the run is
33
32
  * followed from the same id either way.
34
33
  */
35
- import type { AnyWorkflowDef, UploadParallel, UploadProgress, WorkflowOutputOf, WorkflowSummary } from "@alexkroman1/aai/workflow-api";
34
+ import type { AnyWorkflowDef, UploadParallel, UploadProgress, WorkflowOutputOf } from "@alexkroman1/aai/workflow-api";
36
35
  import type { FormValues } from "./components/form-types.ts";
37
36
  import type { WorkflowApi, WorkflowRun } from "./workflow-client.ts";
38
37
  import type { SubmitInputOf } from "./workflow-def-types.ts";
39
- /** Options for {@link useWorkflows}. */
40
- export type UseWorkflowsOptions = {
41
- /** The client to read the listing with. Defaults to one for the page's own agent. */
42
- api?: WorkflowApi;
43
- /**
44
- * Skip the lookup entirely, reporting an empty listing that is not loading.
45
- *
46
- * For a caller that may or may not need the listing and cannot decide with a
47
- * conditional hook — `<WorkflowFields>` handed a summary rather than a name is
48
- * the one in this package. It reports `loading: false`, because a skipped
49
- * lookup is finished rather than pending.
50
- */
51
- skip?: boolean;
52
- };
53
- /** What {@link useWorkflows} reports. */
54
- export type UseWorkflowsResult = {
55
- /** The agent's declared workflows, each with the JSON Schema of its input. */
56
- workflows: WorkflowSummary[];
57
- /** True until the listing lands, so a form can hold its fields back. */
58
- loading: boolean;
59
- /** The lookup's failure. Set alongside an EMPTY list, which is why it exists. */
60
- error: string | undefined;
61
- };
62
- /**
63
- * Read the agent's declared workflows.
64
- *
65
- * What `<WorkflowFields>` renders a form FROM: each summary carries the JSON
66
- * Schema of that workflow's input, converted server-side precisely so a browser
67
- * can read it.
68
- *
69
- * The failure is reported rather than swallowed, because the alternative is an
70
- * empty list — which renders as a form with no fields and reads as "this agent
71
- * declares no workflows" about an agent that was merely unreachable.
72
- *
73
- * @example
74
- * ```tsx
75
- * import { useWorkflows } from "@alexkroman1/aai-ui";
76
- *
77
- * // A page rendering its own chrome from the listing — a picker, say. A form
78
- * // for ONE workflow wants `<WorkflowFields workflow="name" />` instead,
79
- * // which does this lookup itself.
80
- * function WorkflowPicker({ onPick }: { onPick: (name: string) => void }) {
81
- * const { workflows, loading, error } = useWorkflows();
82
- * if (loading) return <p>Loading…</p>;
83
- * if (error !== undefined) return <p role="alert">{error}</p>;
84
- * return (
85
- * <ul>
86
- * {workflows.map((summary) => (
87
- * <li key={summary.name}>
88
- * <button type="button" onClick={() => onPick(summary.name)}>
89
- * {summary.description ?? summary.name}
90
- * </button>
91
- * </li>
92
- * ))}
93
- * </ul>
94
- * );
95
- * }
96
- * ```
97
- *
98
- * @param opts - See {@link UseWorkflowsOptions}.
99
- * @returns The listing, its loading flag and its failure — see
100
- * {@link UseWorkflowsResult}.
101
- *
102
- * @public
103
- */
104
- export declare function useWorkflows(opts?: UseWorkflowsOptions): UseWorkflowsResult;
105
38
  /**
106
39
  * What {@link WorkflowSubmission.upload} reports while the bytes are going.
107
40
  *
@@ -229,29 +162,37 @@ export type WorkflowSubmission<R = unknown, I = unknown> = {
229
162
  export type UseWorkflowSubmitOptions = {
230
163
  /** The client to start runs with. Defaults to one for the page's own agent. */
231
164
  api?: WorkflowApi;
232
- /** Correlation key recorded with the run, for finding it again without the id. */
165
+ /**
166
+ * Correlation key recorded with the run, for finding it again without the id.
167
+ *
168
+ * **Defaulted**, to an opaque per-page key in `sessionStorage` that the next
169
+ * load produces again — `useRunKey()`'s, minted by the hook. Pass one to
170
+ * scope runs to something the page knows better: an ACCOUNT's own id, which
171
+ * is what makes a run follow the person to a new device, or
172
+ * `useRunKey({ storage: "local" })` for a run that outlives the tab by
173
+ * design. The key is a lookup CAPABILITY (there is no per-user filtering
174
+ * behind `find`), it must fit the route's 256-character bound, and anything
175
+ * derived from a person's own input both collides and carries what they
176
+ * typed — `use-run-key.ts` argues every alternative.
177
+ */
233
178
  key?: string;
234
179
  /**
235
180
  * On mount, adopt the newest run this `key` already has.
236
181
  *
237
- * **This is what makes a reload survivable.** The run id is this hook's own
238
- * state, so a refresh loses it while the run carries on — and a page that
239
- * cannot name a run cannot show it, cancel it or wake it. With a `key` and
240
- * this flag the hook asks `find(workflow, key)` once as it mounts and follows
241
- * whatever comes back, so the answer, the progress and the controls are all
242
- * there again.
243
- *
244
- * Inert without a `key`, because the key IS the lookup. Opt-in because a
245
- * `key` on its own means only "record this with the run", which is what a
246
- * page passing an account id may well want; adopting a run is a decision
247
- * about the page.
182
+ * **This is what makes a reload survivable, and it is ON.** The run id is
183
+ * this hook's own state, so a refresh loses it while the run carries on — and
184
+ * a page that cannot name a run cannot show it, cancel it or wake it. The
185
+ * hook asks `find(workflow, key)` once as it mounts and follows whatever
186
+ * comes back, so the answer, the progress and the controls are all there
187
+ * again.
248
188
  *
249
- * The key has to be one the next load can produce, and choosing it is the
250
- * caller's: it is a lookup CAPABILITY (there is no per-user filtering behind
251
- * `find`), it must fit the route's 256-character bound, and anything derived
252
- * from a person's own input both collides and carries what they typed.
253
- * `useRunKey()` is that key, and its module argues every alternative; a page
254
- * with accounts passes the account's own id instead.
189
+ * It used to be opt-in, on the argument that a `key` alone means only "record
190
+ * this with the run" — true of `ctx.workflows.start({ key })`, where there is
191
+ * no page to put a run back on, and not of a form: six of six page templates
192
+ * passed `useRunKey()` and `recover: true` together, which is a default in
193
+ * the wrong place. `false` is the opt-out, and what it buys is a form that
194
+ * always opens empty — no lookup on mount, and a live run reachable only by
195
+ * an id the page has already lost.
255
196
  */
256
197
  recover?: boolean;
257
198
  /**