@runtypelabs/persona 4.4.2 → 4.6.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 (46) hide show
  1. package/dist/animations/glyph-cycle.d.cts +1 -1
  2. package/dist/animations/glyph-cycle.d.ts +1 -1
  3. package/dist/animations/{types-C6tFDxKy.d.cts → types-8RICZWQe.d.cts} +6 -0
  4. package/dist/animations/{types-C6tFDxKy.d.ts → types-8RICZWQe.d.ts} +6 -0
  5. package/dist/animations/wipe.d.cts +1 -1
  6. package/dist/animations/wipe.d.ts +1 -1
  7. package/dist/chunk-DFBSCFYN.js +1 -0
  8. package/dist/codegen.cjs +1 -1
  9. package/dist/codegen.js +1 -1
  10. package/dist/index.cjs +50 -50
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +286 -11
  13. package/dist/index.d.ts +286 -11
  14. package/dist/index.global.js +39 -39
  15. package/dist/index.global.js.map +1 -1
  16. package/dist/index.js +51 -51
  17. package/dist/index.js.map +1 -1
  18. package/dist/launcher.global.js.map +1 -1
  19. package/dist/markdown-parsers-entry-NVFT3TE6.js +1 -0
  20. package/dist/runtype-tts-entry-HFUV2UF7.js +1 -0
  21. package/dist/session-reconnect-U77QFUR7.js +1 -0
  22. package/dist/smart-dom-reader.d.cts +147 -8
  23. package/dist/smart-dom-reader.d.ts +147 -8
  24. package/dist/theme-editor-preview.cjs +48 -48
  25. package/dist/theme-editor-preview.d.cts +187 -9
  26. package/dist/theme-editor-preview.d.ts +187 -9
  27. package/dist/theme-editor-preview.js +48 -48
  28. package/dist/theme-editor.cjs +1 -1
  29. package/dist/theme-editor.d.cts +147 -8
  30. package/dist/theme-editor.d.ts +147 -8
  31. package/dist/theme-editor.js +1 -1
  32. package/package.json +2 -2
  33. package/src/client.ts +48 -7
  34. package/src/defaults.ts +9 -1
  35. package/src/generated/runtype-openapi-contract.ts +6 -0
  36. package/src/index-core.ts +5 -0
  37. package/src/reconnect-wake.test.ts +162 -0
  38. package/src/reconnect.test.ts +430 -0
  39. package/src/session-reconnect.ts +282 -0
  40. package/src/session.ts +408 -5
  41. package/src/types.ts +165 -9
  42. package/src/ui.scroll-additive.test.ts +451 -0
  43. package/src/ui.scroll.test.ts +8 -2
  44. package/src/ui.stream-animation-update.test.ts +99 -0
  45. package/src/ui.ts +371 -41
  46. package/src/utils/constants.ts +3 -1
@@ -1053,12 +1053,15 @@ type RuntypeExecutionStreamEvent = ({
1053
1053
  seq: number;
1054
1054
  type: "approval_complete";
1055
1055
  }) | ({
1056
+ awaitReason?: string;
1056
1057
  awaitedAt?: string;
1058
+ crawlId?: string;
1057
1059
  executionId: string;
1058
1060
  origin?: "webmcp" | "sdk";
1059
1061
  pageOrigin?: string;
1060
1062
  parameters?: Record<string, unknown>;
1061
1063
  seq: number;
1064
+ stepId?: string;
1062
1065
  toolCallId?: string;
1063
1066
  toolId?: string;
1064
1067
  toolName?: string;
@@ -1147,13 +1150,16 @@ type RuntypeFlowSSEEvent = {
1147
1150
  type: "flow_error";
1148
1151
  upgradeUrl?: string;
1149
1152
  }) | ({
1153
+ awaitReason?: string;
1150
1154
  awaitedAt: string;
1155
+ crawlId?: string;
1151
1156
  executionId?: string;
1152
1157
  flowId: string;
1153
1158
  origin?: "webmcp" | "sdk";
1154
1159
  pageOrigin?: string;
1155
1160
  parameters?: Record<string, unknown>;
1156
1161
  seq?: number;
1162
+ stepId?: string;
1157
1163
  toolCallId?: string;
1158
1164
  toolId?: string;
1159
1165
  toolName?: string;
@@ -1693,6 +1699,27 @@ type AgentWidgetWebMcpConfig = {
1693
1699
  */
1694
1700
  onConfirm?: WebMcpConfirmHandler;
1695
1701
  };
1702
+ /**
1703
+ * The coordinates needed to resume a durable agent turn after the SSE
1704
+ * connection drops (any resumable, server-persisted execution, e.g. Claude
1705
+ * Managed agents or async/background runs). Held on the session while a
1706
+ * resumable stream is in flight
1707
+ * and surfaced to the host via {@link AgentWidgetConfig.onExecutionState} so it
1708
+ * can persist `{ executionId, lastEventId }` next to its own `conversationId`
1709
+ * for the tab-reload path.
1710
+ *
1711
+ * `conversationId` is intentionally absent: it is host-owned (it lives in the
1712
+ * host's `reconnectStream`/`customFetch` closure; the widget never sees it).
1713
+ */
1714
+ type ResumableHandle = {
1715
+ /** The durable turn to reconnect to (from `agentMetadata.executionId`). */
1716
+ executionId: string;
1717
+ /** Highest SSE `id:` seq applied: the `?after=` reconnect cursor. */
1718
+ lastEventId: string;
1719
+ /** The open assistant message being streamed into, kept open on resume. */
1720
+ assistantMessageId: string;
1721
+ status: 'running';
1722
+ };
1696
1723
  /**
1697
1724
  * Metadata attached to messages created during agent execution.
1698
1725
  */
@@ -1975,6 +2002,22 @@ type AgentWidgetControllerEventMap = {
1975
2002
  approval: AgentWidgetApproval;
1976
2003
  decision: string;
1977
2004
  };
2005
+ /** A durable stream dropped; the widget is about to reconnect. */
2006
+ "stream:paused": {
2007
+ executionId: string;
2008
+ after: string;
2009
+ };
2010
+ /** A reconnect attempt is in flight (`attempt` is 1-based). */
2011
+ "stream:resuming": {
2012
+ executionId: string;
2013
+ after: string;
2014
+ attempt: number;
2015
+ };
2016
+ /** The durable turn resumed and reached its terminal after a reconnect. */
2017
+ "stream:resumed": {
2018
+ executionId: string;
2019
+ after: string;
2020
+ };
1978
2021
  };
1979
2022
  /**
1980
2023
  * Layout for the artifact split / drawer (CSS lengths unless noted).
@@ -2133,25 +2176,74 @@ type AgentWidgetArtifactsFeature = {
2133
2176
  /**
2134
2177
  * How the transcript scrolls while an assistant response streams in.
2135
2178
  *
2136
- * - `"follow"` (default): keep the newest content pinned to the bottom of the
2137
- * viewport, pausing when the user scrolls up and resuming when they return
2138
- * to the bottom.
2139
- * - `"anchor-top"`: on send, scroll the user's message near the top of the
2140
- * viewport and hold it there while the response streams in beneath it
2141
- * (ChatGPT-style). The transcript never auto-scrolls during streaming.
2179
+ * - `"anchor-top"` (default): on send, scroll the user's message near the top
2180
+ * of the viewport and hold it there while the response streams in beneath it
2181
+ * (ChatGPT-style). When a turn has no user send to anchor to (a proactive
2182
+ * greeting, an injected assistant message, a resubmit, or first-load
2183
+ * streaming), it falls back to `"follow"` for that turn so content never
2184
+ * streams in off-screen.
2185
+ * - `"follow"`: keep the newest content pinned to the bottom of the viewport,
2186
+ * pausing when the user scrolls up and resuming when they return to the
2187
+ * bottom. This was the default before 4.x.
2142
2188
  * - `"none"`: never auto-scroll; the scroll-to-bottom affordance is the only
2143
2189
  * way back to the latest content.
2144
2190
  */
2145
2191
  type AgentWidgetScrollMode = "follow" | "anchor-top" | "none";
2192
+ /**
2193
+ * Where the transcript lands when a *saved* conversation is reopened (restored
2194
+ * from the storage adapter / `initialMessages`), as opposed to a fresh send.
2195
+ *
2196
+ * - `"bottom"` (default): jump to the absolute end of the transcript, matching
2197
+ * the historical behavior.
2198
+ * - `"last-user-turn"`: pin the last user message near the top of the viewport
2199
+ * (the last point the reader was actively driving the conversation) so a long
2200
+ * restored thread opens at a readable place rather than at the very bottom.
2201
+ */
2202
+ type AgentWidgetScrollRestorePosition = "bottom" | "last-user-turn";
2146
2203
  type AgentWidgetScrollBehaviorFeature = {
2147
- /** Scroll behavior during streamed responses. @default "follow" */
2204
+ /** Scroll behavior during streamed responses. @default "anchor-top" */
2148
2205
  mode?: AgentWidgetScrollMode;
2149
2206
  /**
2150
2207
  * Gap (px) kept between the anchored user message and the top of the
2151
- * viewport in `"anchor-top"` mode.
2208
+ * viewport in `"anchor-top"` mode. Also used as the gap for
2209
+ * `restorePosition: "last-user-turn"`.
2152
2210
  * @default 16
2153
2211
  */
2154
2212
  anchorTopOffset?: number;
2213
+ /**
2214
+ * Where to land when a saved conversation reopens. Additive and opt-in: the
2215
+ * default preserves the historical "jump to the bottom" behavior.
2216
+ * @default "bottom"
2217
+ */
2218
+ restorePosition?: AgentWidgetScrollRestorePosition;
2219
+ /**
2220
+ * When true, interactions beyond text selection — keyboard navigation
2221
+ * (PageUp/PageDown/Home/End/arrows) inside the transcript and focusing a
2222
+ * link or other interactive element within it — also pause auto-follow in
2223
+ * `"follow"` mode. Treats "the reader is doing something here" as intent to
2224
+ * stay put, not just "the reader dragged a selection". Opt-in; default keeps
2225
+ * only the existing wheel/scroll/selection triggers.
2226
+ * @default false
2227
+ */
2228
+ pauseOnInteraction?: boolean;
2229
+ /**
2230
+ * When true, the scroll-to-bottom affordance also surfaces new-content and
2231
+ * still-streaming activity while the reader is pinned away from the latest
2232
+ * content in `"anchor-top"` mode. Lets the reader know a response is arriving
2233
+ * offscreen below. Defaults on alongside the `"anchor-top"` default; set
2234
+ * `false` to keep the count + streaming hint silent while pinned.
2235
+ * @default true
2236
+ */
2237
+ showActivityWhilePinned?: boolean;
2238
+ /**
2239
+ * When true, Persona maintains a visually-hidden `aria-live="polite"` region
2240
+ * that announces important transcript events — a response starting, a
2241
+ * response finishing, and "N new messages below" while the reader is scrolled
2242
+ * away — at a comfortable cadence (never token-by-token). Opt-in so existing
2243
+ * embeds don't suddenly gain screen-reader announcements.
2244
+ * @default false
2245
+ */
2246
+ announce?: boolean;
2155
2247
  };
2156
2248
  type AgentWidgetScrollToBottomFeature = {
2157
2249
  /**
@@ -3034,6 +3126,10 @@ type AgentWidgetStatusIndicatorConfig = {
3034
3126
  connectingText?: string;
3035
3127
  connectedText?: string;
3036
3128
  errorText?: string;
3129
+ /** Status text while a dropped durable stream is awaiting reconnect. */
3130
+ pausedText?: string;
3131
+ /** Status text while a reconnect attempt is in flight. */
3132
+ resumingText?: string;
3037
3133
  };
3038
3134
  type AgentWidgetVoiceRecognitionConfig = {
3039
3135
  enabled?: boolean;
@@ -5124,6 +5220,65 @@ type AgentWidgetConfig = {
5124
5220
  * ```
5125
5221
  */
5126
5222
  customFetch?: AgentWidgetCustomFetch;
5223
+ /**
5224
+ * Durable-session reconnect transport (host-owned, symmetric to
5225
+ * {@link customFetch}). When a durable agent stream drops mid-turn (any
5226
+ * resumable, server-persisted execution, e.g. Claude Managed agents or
5227
+ * async/background runs), the widget calls this to fetch the read-only
5228
+ * reconnect stream and pipes its body through the normal event pipeline to
5229
+ * resume from where it left off.
5230
+ *
5231
+ * The host closure owns `agentId` / `conversationId` / base URL / auth and
5232
+ * builds the events request, e.g.:
5233
+ *
5234
+ * ```typescript
5235
+ * reconnectStream: ({ executionId, after, signal }) =>
5236
+ * fetch(
5237
+ * `${baseUrl}/v1/agents/${agentId}/executions/${executionId}` +
5238
+ * `/events?conversationId=${conversationId}&after=${after}`,
5239
+ * { headers: { Authorization: `Bearer ${token}`, "X-Persona-Version": ver }, signal }
5240
+ * )
5241
+ * ```
5242
+ *
5243
+ * Resolve with a `text/event-stream` `Response`. Throw or resolve non-ok to
5244
+ * signal "this attempt failed" (the widget backs off and retries, then gives
5245
+ * up after the bounded attempts). Reconnect only ever arms on the durable
5246
+ * lane (streams carrying SSE `id:` lines); without this hook a drop finalizes
5247
+ * exactly as before.
5248
+ */
5249
+ reconnectStream?: (ctx: {
5250
+ executionId: string;
5251
+ after: string;
5252
+ signal: AbortSignal;
5253
+ }) => Promise<Response>;
5254
+ /**
5255
+ * Tuning for the auto-reconnect backoff. Defaults to ~5 attempts over ~30s
5256
+ * (`backoffMs: [1000, 2000, 4000, 8000, 8000]`).
5257
+ */
5258
+ reconnect?: {
5259
+ /** Max reconnect attempts before giving up and finalizing. @default backoffMs.length */
5260
+ maxAttempts?: number;
5261
+ /** Per-attempt delay (ms) before each retry. @default [1000, 2000, 4000, 8000, 8000] */
5262
+ backoffMs?: number[];
5263
+ };
5264
+ /**
5265
+ * Called whenever the durable resume handle changes: created when a durable
5266
+ * turn starts streaming, updated as the cursor advances (throttled), and
5267
+ * `null` when the turn finishes, errors, or is torn down. Persist
5268
+ * `{ executionId, lastEventId }` next to your `conversationId` and pass it
5269
+ * back via {@link resume} on the next mount to survive a tab reload.
5270
+ */
5271
+ onExecutionState?: (handle: ResumableHandle | null) => void;
5272
+ /**
5273
+ * Resume a durable turn on boot (tab-reload path). When present alongside
5274
+ * {@link reconnectStream}, the widget enters `resuming` immediately on mount
5275
+ * and reconnects from `after`, replaying everything past the cursor into the
5276
+ * restored conversation.
5277
+ */
5278
+ resume?: {
5279
+ executionId: string;
5280
+ after: string;
5281
+ };
5127
5282
  /**
5128
5283
  * Custom SSE event parser for non-standard streaming response formats.
5129
5284
  *
@@ -5666,9 +5821,27 @@ type AgentWidgetEvent = {
5666
5821
  } | {
5667
5822
  type: "status";
5668
5823
  status: "connecting" | "connected" | "error" | "idle";
5824
+ /**
5825
+ * Set on the `idle` emitted from a graceful execution terminal
5826
+ * (`execution_complete`). Distinguishes a real finish from the plain
5827
+ * `idle` the dispatch wrappers emit in their `finally` on a dropped
5828
+ * connection. The durable-reconnect drop detection keys off this.
5829
+ */
5830
+ terminal?: boolean;
5669
5831
  } | {
5670
5832
  type: "error";
5671
5833
  error: Error;
5834
+ }
5835
+ /**
5836
+ * Durable-session reconnect cursor. Carries the SSE `id:` line (the durable
5837
+ * row seq) of a fully-parsed frame so the session can track `lastEventId`
5838
+ * and resume from `?after=<id>` after a drop. Only emitted on the durable
5839
+ * lane (any resumable execution that stamps `id:` lines, e.g. Claude Managed
5840
+ * agents or async/background runs).
5841
+ */
5842
+ | {
5843
+ type: "cursor";
5844
+ id: string;
5672
5845
  } | {
5673
5846
  type: "artifact_start";
5674
5847
  id: string;
@@ -5689,7 +5862,7 @@ type AgentWidgetEvent = {
5689
5862
  id: string;
5690
5863
  };
5691
5864
 
5692
- type AgentWidgetSessionStatus = "idle" | "connecting" | "connected" | "error";
5865
+ type AgentWidgetSessionStatus = "idle" | "connecting" | "connected" | "error" | "paused" | "resuming";
5693
5866
 
5694
5867
  /**
5695
5868
  * Feedback UI components for CSAT and NPS collection
@@ -5746,6 +5919,11 @@ type Controller = {
5746
5919
  clearChat: () => void;
5747
5920
  setMessage: (message: string) => boolean;
5748
5921
  submitMessage: (message?: string) => boolean;
5922
+ /**
5923
+ * Manually retry a dropped durable stream (e.g. from a "Reconnect" button).
5924
+ * No-op unless a resumable durable turn dropped and `reconnectStream` is set.
5925
+ */
5926
+ reconnect: () => void;
5749
5927
  startVoiceRecognition: () => boolean;
5750
5928
  stopVoiceRecognition: () => boolean;
5751
5929
  /**
@@ -1053,12 +1053,15 @@ type RuntypeExecutionStreamEvent = ({
1053
1053
  seq: number;
1054
1054
  type: "approval_complete";
1055
1055
  }) | ({
1056
+ awaitReason?: string;
1056
1057
  awaitedAt?: string;
1058
+ crawlId?: string;
1057
1059
  executionId: string;
1058
1060
  origin?: "webmcp" | "sdk";
1059
1061
  pageOrigin?: string;
1060
1062
  parameters?: Record<string, unknown>;
1061
1063
  seq: number;
1064
+ stepId?: string;
1062
1065
  toolCallId?: string;
1063
1066
  toolId?: string;
1064
1067
  toolName?: string;
@@ -1147,13 +1150,16 @@ type RuntypeFlowSSEEvent = {
1147
1150
  type: "flow_error";
1148
1151
  upgradeUrl?: string;
1149
1152
  }) | ({
1153
+ awaitReason?: string;
1150
1154
  awaitedAt: string;
1155
+ crawlId?: string;
1151
1156
  executionId?: string;
1152
1157
  flowId: string;
1153
1158
  origin?: "webmcp" | "sdk";
1154
1159
  pageOrigin?: string;
1155
1160
  parameters?: Record<string, unknown>;
1156
1161
  seq?: number;
1162
+ stepId?: string;
1157
1163
  toolCallId?: string;
1158
1164
  toolId?: string;
1159
1165
  toolName?: string;
@@ -1693,6 +1699,27 @@ type AgentWidgetWebMcpConfig = {
1693
1699
  */
1694
1700
  onConfirm?: WebMcpConfirmHandler;
1695
1701
  };
1702
+ /**
1703
+ * The coordinates needed to resume a durable agent turn after the SSE
1704
+ * connection drops (any resumable, server-persisted execution, e.g. Claude
1705
+ * Managed agents or async/background runs). Held on the session while a
1706
+ * resumable stream is in flight
1707
+ * and surfaced to the host via {@link AgentWidgetConfig.onExecutionState} so it
1708
+ * can persist `{ executionId, lastEventId }` next to its own `conversationId`
1709
+ * for the tab-reload path.
1710
+ *
1711
+ * `conversationId` is intentionally absent: it is host-owned (it lives in the
1712
+ * host's `reconnectStream`/`customFetch` closure; the widget never sees it).
1713
+ */
1714
+ type ResumableHandle = {
1715
+ /** The durable turn to reconnect to (from `agentMetadata.executionId`). */
1716
+ executionId: string;
1717
+ /** Highest SSE `id:` seq applied: the `?after=` reconnect cursor. */
1718
+ lastEventId: string;
1719
+ /** The open assistant message being streamed into, kept open on resume. */
1720
+ assistantMessageId: string;
1721
+ status: 'running';
1722
+ };
1696
1723
  /**
1697
1724
  * Metadata attached to messages created during agent execution.
1698
1725
  */
@@ -1975,6 +2002,22 @@ type AgentWidgetControllerEventMap = {
1975
2002
  approval: AgentWidgetApproval;
1976
2003
  decision: string;
1977
2004
  };
2005
+ /** A durable stream dropped; the widget is about to reconnect. */
2006
+ "stream:paused": {
2007
+ executionId: string;
2008
+ after: string;
2009
+ };
2010
+ /** A reconnect attempt is in flight (`attempt` is 1-based). */
2011
+ "stream:resuming": {
2012
+ executionId: string;
2013
+ after: string;
2014
+ attempt: number;
2015
+ };
2016
+ /** The durable turn resumed and reached its terminal after a reconnect. */
2017
+ "stream:resumed": {
2018
+ executionId: string;
2019
+ after: string;
2020
+ };
1978
2021
  };
1979
2022
  /**
1980
2023
  * Layout for the artifact split / drawer (CSS lengths unless noted).
@@ -2133,25 +2176,74 @@ type AgentWidgetArtifactsFeature = {
2133
2176
  /**
2134
2177
  * How the transcript scrolls while an assistant response streams in.
2135
2178
  *
2136
- * - `"follow"` (default): keep the newest content pinned to the bottom of the
2137
- * viewport, pausing when the user scrolls up and resuming when they return
2138
- * to the bottom.
2139
- * - `"anchor-top"`: on send, scroll the user's message near the top of the
2140
- * viewport and hold it there while the response streams in beneath it
2141
- * (ChatGPT-style). The transcript never auto-scrolls during streaming.
2179
+ * - `"anchor-top"` (default): on send, scroll the user's message near the top
2180
+ * of the viewport and hold it there while the response streams in beneath it
2181
+ * (ChatGPT-style). When a turn has no user send to anchor to (a proactive
2182
+ * greeting, an injected assistant message, a resubmit, or first-load
2183
+ * streaming), it falls back to `"follow"` for that turn so content never
2184
+ * streams in off-screen.
2185
+ * - `"follow"`: keep the newest content pinned to the bottom of the viewport,
2186
+ * pausing when the user scrolls up and resuming when they return to the
2187
+ * bottom. This was the default before 4.x.
2142
2188
  * - `"none"`: never auto-scroll; the scroll-to-bottom affordance is the only
2143
2189
  * way back to the latest content.
2144
2190
  */
2145
2191
  type AgentWidgetScrollMode = "follow" | "anchor-top" | "none";
2192
+ /**
2193
+ * Where the transcript lands when a *saved* conversation is reopened (restored
2194
+ * from the storage adapter / `initialMessages`), as opposed to a fresh send.
2195
+ *
2196
+ * - `"bottom"` (default): jump to the absolute end of the transcript, matching
2197
+ * the historical behavior.
2198
+ * - `"last-user-turn"`: pin the last user message near the top of the viewport
2199
+ * (the last point the reader was actively driving the conversation) so a long
2200
+ * restored thread opens at a readable place rather than at the very bottom.
2201
+ */
2202
+ type AgentWidgetScrollRestorePosition = "bottom" | "last-user-turn";
2146
2203
  type AgentWidgetScrollBehaviorFeature = {
2147
- /** Scroll behavior during streamed responses. @default "follow" */
2204
+ /** Scroll behavior during streamed responses. @default "anchor-top" */
2148
2205
  mode?: AgentWidgetScrollMode;
2149
2206
  /**
2150
2207
  * Gap (px) kept between the anchored user message and the top of the
2151
- * viewport in `"anchor-top"` mode.
2208
+ * viewport in `"anchor-top"` mode. Also used as the gap for
2209
+ * `restorePosition: "last-user-turn"`.
2152
2210
  * @default 16
2153
2211
  */
2154
2212
  anchorTopOffset?: number;
2213
+ /**
2214
+ * Where to land when a saved conversation reopens. Additive and opt-in: the
2215
+ * default preserves the historical "jump to the bottom" behavior.
2216
+ * @default "bottom"
2217
+ */
2218
+ restorePosition?: AgentWidgetScrollRestorePosition;
2219
+ /**
2220
+ * When true, interactions beyond text selection — keyboard navigation
2221
+ * (PageUp/PageDown/Home/End/arrows) inside the transcript and focusing a
2222
+ * link or other interactive element within it — also pause auto-follow in
2223
+ * `"follow"` mode. Treats "the reader is doing something here" as intent to
2224
+ * stay put, not just "the reader dragged a selection". Opt-in; default keeps
2225
+ * only the existing wheel/scroll/selection triggers.
2226
+ * @default false
2227
+ */
2228
+ pauseOnInteraction?: boolean;
2229
+ /**
2230
+ * When true, the scroll-to-bottom affordance also surfaces new-content and
2231
+ * still-streaming activity while the reader is pinned away from the latest
2232
+ * content in `"anchor-top"` mode. Lets the reader know a response is arriving
2233
+ * offscreen below. Defaults on alongside the `"anchor-top"` default; set
2234
+ * `false` to keep the count + streaming hint silent while pinned.
2235
+ * @default true
2236
+ */
2237
+ showActivityWhilePinned?: boolean;
2238
+ /**
2239
+ * When true, Persona maintains a visually-hidden `aria-live="polite"` region
2240
+ * that announces important transcript events — a response starting, a
2241
+ * response finishing, and "N new messages below" while the reader is scrolled
2242
+ * away — at a comfortable cadence (never token-by-token). Opt-in so existing
2243
+ * embeds don't suddenly gain screen-reader announcements.
2244
+ * @default false
2245
+ */
2246
+ announce?: boolean;
2155
2247
  };
2156
2248
  type AgentWidgetScrollToBottomFeature = {
2157
2249
  /**
@@ -3034,6 +3126,10 @@ type AgentWidgetStatusIndicatorConfig = {
3034
3126
  connectingText?: string;
3035
3127
  connectedText?: string;
3036
3128
  errorText?: string;
3129
+ /** Status text while a dropped durable stream is awaiting reconnect. */
3130
+ pausedText?: string;
3131
+ /** Status text while a reconnect attempt is in flight. */
3132
+ resumingText?: string;
3037
3133
  };
3038
3134
  type AgentWidgetVoiceRecognitionConfig = {
3039
3135
  enabled?: boolean;
@@ -5124,6 +5220,65 @@ type AgentWidgetConfig = {
5124
5220
  * ```
5125
5221
  */
5126
5222
  customFetch?: AgentWidgetCustomFetch;
5223
+ /**
5224
+ * Durable-session reconnect transport (host-owned, symmetric to
5225
+ * {@link customFetch}). When a durable agent stream drops mid-turn (any
5226
+ * resumable, server-persisted execution, e.g. Claude Managed agents or
5227
+ * async/background runs), the widget calls this to fetch the read-only
5228
+ * reconnect stream and pipes its body through the normal event pipeline to
5229
+ * resume from where it left off.
5230
+ *
5231
+ * The host closure owns `agentId` / `conversationId` / base URL / auth and
5232
+ * builds the events request, e.g.:
5233
+ *
5234
+ * ```typescript
5235
+ * reconnectStream: ({ executionId, after, signal }) =>
5236
+ * fetch(
5237
+ * `${baseUrl}/v1/agents/${agentId}/executions/${executionId}` +
5238
+ * `/events?conversationId=${conversationId}&after=${after}`,
5239
+ * { headers: { Authorization: `Bearer ${token}`, "X-Persona-Version": ver }, signal }
5240
+ * )
5241
+ * ```
5242
+ *
5243
+ * Resolve with a `text/event-stream` `Response`. Throw or resolve non-ok to
5244
+ * signal "this attempt failed" (the widget backs off and retries, then gives
5245
+ * up after the bounded attempts). Reconnect only ever arms on the durable
5246
+ * lane (streams carrying SSE `id:` lines); without this hook a drop finalizes
5247
+ * exactly as before.
5248
+ */
5249
+ reconnectStream?: (ctx: {
5250
+ executionId: string;
5251
+ after: string;
5252
+ signal: AbortSignal;
5253
+ }) => Promise<Response>;
5254
+ /**
5255
+ * Tuning for the auto-reconnect backoff. Defaults to ~5 attempts over ~30s
5256
+ * (`backoffMs: [1000, 2000, 4000, 8000, 8000]`).
5257
+ */
5258
+ reconnect?: {
5259
+ /** Max reconnect attempts before giving up and finalizing. @default backoffMs.length */
5260
+ maxAttempts?: number;
5261
+ /** Per-attempt delay (ms) before each retry. @default [1000, 2000, 4000, 8000, 8000] */
5262
+ backoffMs?: number[];
5263
+ };
5264
+ /**
5265
+ * Called whenever the durable resume handle changes: created when a durable
5266
+ * turn starts streaming, updated as the cursor advances (throttled), and
5267
+ * `null` when the turn finishes, errors, or is torn down. Persist
5268
+ * `{ executionId, lastEventId }` next to your `conversationId` and pass it
5269
+ * back via {@link resume} on the next mount to survive a tab reload.
5270
+ */
5271
+ onExecutionState?: (handle: ResumableHandle | null) => void;
5272
+ /**
5273
+ * Resume a durable turn on boot (tab-reload path). When present alongside
5274
+ * {@link reconnectStream}, the widget enters `resuming` immediately on mount
5275
+ * and reconnects from `after`, replaying everything past the cursor into the
5276
+ * restored conversation.
5277
+ */
5278
+ resume?: {
5279
+ executionId: string;
5280
+ after: string;
5281
+ };
5127
5282
  /**
5128
5283
  * Custom SSE event parser for non-standard streaming response formats.
5129
5284
  *
@@ -5666,9 +5821,27 @@ type AgentWidgetEvent = {
5666
5821
  } | {
5667
5822
  type: "status";
5668
5823
  status: "connecting" | "connected" | "error" | "idle";
5824
+ /**
5825
+ * Set on the `idle` emitted from a graceful execution terminal
5826
+ * (`execution_complete`). Distinguishes a real finish from the plain
5827
+ * `idle` the dispatch wrappers emit in their `finally` on a dropped
5828
+ * connection. The durable-reconnect drop detection keys off this.
5829
+ */
5830
+ terminal?: boolean;
5669
5831
  } | {
5670
5832
  type: "error";
5671
5833
  error: Error;
5834
+ }
5835
+ /**
5836
+ * Durable-session reconnect cursor. Carries the SSE `id:` line (the durable
5837
+ * row seq) of a fully-parsed frame so the session can track `lastEventId`
5838
+ * and resume from `?after=<id>` after a drop. Only emitted on the durable
5839
+ * lane (any resumable execution that stamps `id:` lines, e.g. Claude Managed
5840
+ * agents or async/background runs).
5841
+ */
5842
+ | {
5843
+ type: "cursor";
5844
+ id: string;
5672
5845
  } | {
5673
5846
  type: "artifact_start";
5674
5847
  id: string;
@@ -5689,7 +5862,7 @@ type AgentWidgetEvent = {
5689
5862
  id: string;
5690
5863
  };
5691
5864
 
5692
- type AgentWidgetSessionStatus = "idle" | "connecting" | "connected" | "error";
5865
+ type AgentWidgetSessionStatus = "idle" | "connecting" | "connected" | "error" | "paused" | "resuming";
5693
5866
 
5694
5867
  /**
5695
5868
  * Feedback UI components for CSAT and NPS collection
@@ -5746,6 +5919,11 @@ type Controller = {
5746
5919
  clearChat: () => void;
5747
5920
  setMessage: (message: string) => boolean;
5748
5921
  submitMessage: (message?: string) => boolean;
5922
+ /**
5923
+ * Manually retry a dropped durable stream (e.g. from a "Reconnect" button).
5924
+ * No-op unless a resumable durable turn dropped and `reconnectStream` is set.
5925
+ */
5926
+ reconnect: () => void;
5749
5927
  startVoiceRecognition: () => boolean;
5750
5928
  stopVoiceRecognition: () => boolean;
5751
5929
  /**