@opengeni/react 1.0.1 → 2.2.0-canary.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 (174) hide show
  1. package/README.md +33 -10
  2. package/dist/artifacts-spreadsheet.js +1 -1
  3. package/dist/artifacts.js +1 -1
  4. package/dist/browser-viewer-GXUICIAG.js +14 -0
  5. package/dist/{chunk-R3AZOAB5.js → chunk-4MDLEHXL.js} +9 -115
  6. package/dist/chunk-4MDLEHXL.js.map +1 -0
  7. package/dist/{chunk-Y7OEDUJ5.js → chunk-5RZN3DD5.js} +1014 -420
  8. package/dist/chunk-5RZN3DD5.js.map +1 -0
  9. package/dist/chunk-5YK2ZDIG.js +116 -0
  10. package/dist/chunk-5YK2ZDIG.js.map +1 -0
  11. package/dist/chunk-H5YGYNXS.js +329 -0
  12. package/dist/chunk-H5YGYNXS.js.map +1 -0
  13. package/dist/{chunk-7WCLAEFV.js → chunk-ICA6R6TW.js} +2 -2
  14. package/dist/{chunk-7WCLAEFV.js.map → chunk-ICA6R6TW.js.map} +1 -1
  15. package/dist/{chunk-IGC6A2ZI.js → chunk-JOAVA2TW.js} +589 -217
  16. package/dist/chunk-JOAVA2TW.js.map +1 -0
  17. package/dist/{chunk-5UQPNLIO.js → chunk-LTCHJ4MS.js} +9 -9
  18. package/dist/chunk-LTCHJ4MS.js.map +1 -0
  19. package/dist/{chunk-C5ZPSSS5.js → chunk-NEXLLTP4.js} +2 -1
  20. package/dist/{chunk-C5ZPSSS5.js.map → chunk-NEXLLTP4.js.map} +1 -1
  21. package/dist/chunk-QGBJ6GHG.js +2300 -0
  22. package/dist/chunk-QGBJ6GHG.js.map +1 -0
  23. package/dist/{chunk-B6WPZSTT.js → chunk-UOLJWT5Y.js} +78 -16
  24. package/dist/chunk-UOLJWT5Y.js.map +1 -0
  25. package/dist/{chunk-MKPIAGVL.js → chunk-W6NFJXSA.js} +8 -19
  26. package/dist/chunk-W6NFJXSA.js.map +1 -0
  27. package/dist/{chunk-XBZWOM2K.js → chunk-X4A66EWZ.js} +8 -3
  28. package/dist/chunk-X4A66EWZ.js.map +1 -0
  29. package/dist/chunk-X4JAFD5R.js +3907 -0
  30. package/dist/chunk-X4JAFD5R.js.map +1 -0
  31. package/dist/{chunk-6KLX2RH5.js → chunk-XSA2QAKP.js} +334 -19
  32. package/dist/chunk-XSA2QAKP.js.map +1 -0
  33. package/dist/{chunk-HA46CYQK.js → chunk-XXWH2JLC.js} +792 -206
  34. package/dist/chunk-XXWH2JLC.js.map +1 -0
  35. package/dist/client.d.ts +2 -2
  36. package/dist/components/browser-viewer.d.ts +7 -1
  37. package/dist/components/computer-viewer.d.ts +4 -1
  38. package/dist/components/enrollment-consent.d.ts +6 -3
  39. package/dist/components/file-browser.d.ts +7 -1
  40. package/dist/components/human-input-form.d.ts +1 -1
  41. package/dist/components/human-input-surface.d.ts +1 -1
  42. package/dist/components/machine-card.d.ts +4 -1
  43. package/dist/components/machines/machine-detail.d.ts +4 -1
  44. package/dist/components/machines/machine-operation-policy.d.ts +11 -0
  45. package/dist/components/machines-dashboard.d.ts +3 -1
  46. package/dist/components/markdown.d.ts +20 -1
  47. package/dist/components/message-timeline.d.ts +1 -1
  48. package/dist/components/model-policy-picker.d.ts +2 -0
  49. package/dist/components/pierre-file.d.ts +1 -1
  50. package/dist/components/sandbox-files.d.ts +8 -2
  51. package/dist/components/sandbox-workspace.d.ts +33 -3
  52. package/dist/components/session-chrome.d.ts +15 -3
  53. package/dist/components/workspace-dock.d.ts +6 -2
  54. package/dist/composer.js +5 -5
  55. package/dist/computer-viewer-ZOP4Q7A7.js +16 -0
  56. package/dist/computer-viewer-ZOP4Q7A7.js.map +1 -0
  57. package/dist/hooks/channel-cache.d.ts +23 -0
  58. package/dist/hooks/shared-machines-list.d.ts +14 -0
  59. package/dist/hooks/use-attached-browsers.d.ts +2 -1
  60. package/dist/hooks/use-channels.d.ts +1 -0
  61. package/dist/hooks/use-composer.d.ts +37 -9
  62. package/dist/hooks/use-machine-chip.d.ts +3 -3
  63. package/dist/hooks/use-machines.d.ts +19 -1
  64. package/dist/hooks/use-sandbox-files.d.ts +1 -0
  65. package/dist/hooks/use-session-background-commands.d.ts +14 -0
  66. package/dist/hooks/use-turn-queue.d.ts +12 -0
  67. package/dist/hooks/use-workspace-sessions.d.ts +1 -0
  68. package/dist/index.d.ts +7 -5
  69. package/dist/index.js +1096 -623
  70. package/dist/index.js.map +1 -1
  71. package/dist/interaction.js +29 -181
  72. package/dist/interaction.js.map +1 -1
  73. package/dist/lib/interaction-errors.d.ts +3 -0
  74. package/dist/machines.d.ts +4 -2
  75. package/dist/machines.js +10 -2
  76. package/dist/model-policy.d.ts +1 -1
  77. package/dist/model-policy.js +1 -1
  78. package/dist/platform-activity-row-BJHUHXAT.js +169 -0
  79. package/dist/platform-activity-row-BJHUHXAT.js.map +1 -0
  80. package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-BSKUWHRI.js} +76 -16
  81. package/dist/queue-surface-implementation-BSKUWHRI.js.map +1 -0
  82. package/dist/realtime/realtime-control.d.ts +6 -3
  83. package/dist/realtime.js +36 -14
  84. package/dist/realtime.js.map +1 -1
  85. package/dist/session-ui.d.ts +1 -1
  86. package/dist/session-ui.js +6 -2
  87. package/dist/session.d.ts +2 -2
  88. package/dist/session.js +4 -4
  89. package/dist/timeline/index.d.ts +1 -1
  90. package/dist/timeline/platform-activity-row.d.ts +15 -0
  91. package/dist/timeline/screenshot-lightbox.d.ts +1 -1
  92. package/dist/timeline/shared.d.ts +4 -2
  93. package/dist/timeline/types.d.ts +48 -5
  94. package/dist/types/machines.d.ts +2 -2
  95. package/package.json +3 -3
  96. package/src/client.ts +12 -1
  97. package/src/components/artifacts/editable-spreadsheet.tsx +1 -1
  98. package/src/components/browser-viewer.tsx +361 -58
  99. package/src/components/chat-composer.tsx +1 -1
  100. package/src/components/composer.tsx +6 -6
  101. package/src/components/computer-viewer.tsx +368 -115
  102. package/src/components/enrollment-consent.tsx +64 -6
  103. package/src/components/file-browser.tsx +117 -2
  104. package/src/components/human-input-form.tsx +91 -55
  105. package/src/components/human-input-surface.tsx +1 -1
  106. package/src/components/machine-card.tsx +111 -0
  107. package/src/components/machine-input-display.ts +15 -0
  108. package/src/components/machines/machine-detail.tsx +47 -0
  109. package/src/components/machines/machine-operation-policy.tsx +179 -0
  110. package/src/components/machines-dashboard.tsx +6 -0
  111. package/src/components/markdown.tsx +174 -20
  112. package/src/components/message-timeline.tsx +162 -17
  113. package/src/components/model-policy-picker.tsx +9 -17
  114. package/src/components/pierre-file.tsx +1 -1
  115. package/src/components/queue-surface-implementation.tsx +82 -16
  116. package/src/components/sandbox-files.tsx +135 -19
  117. package/src/components/sandbox-workspace.tsx +204 -92
  118. package/src/components/session-chrome.tsx +415 -208
  119. package/src/components/session-status.tsx +1 -1
  120. package/src/components/user-message-body.tsx +168 -48
  121. package/src/components/workspace-dock.tsx +141 -175
  122. package/src/hooks/channel-cache.ts +104 -0
  123. package/src/hooks/shared-machines-list.ts +239 -0
  124. package/src/hooks/use-attached-browsers.ts +5 -1
  125. package/src/hooks/use-browser-frame-stream.ts +6 -1
  126. package/src/hooks/use-browser-session.ts +6 -4
  127. package/src/hooks/use-browser-sessions.ts +7 -1
  128. package/src/hooks/use-channels.ts +32 -10
  129. package/src/hooks/use-composer.ts +760 -291
  130. package/src/hooks/use-computer-frame-stream.ts +14 -9
  131. package/src/hooks/use-computer-session.ts +16 -14
  132. package/src/hooks/use-computer-sessions.ts +8 -1
  133. package/src/hooks/use-last-started-turn-policy.ts +1 -1
  134. package/src/hooks/use-machine-chip.ts +23 -6
  135. package/src/hooks/use-machines.ts +104 -6
  136. package/src/hooks/use-sandbox-files.ts +195 -140
  137. package/src/hooks/use-sandbox-git.ts +58 -29
  138. package/src/hooks/use-session-background-commands.ts +56 -0
  139. package/src/hooks/use-session-capabilities.ts +18 -0
  140. package/src/hooks/use-turn-queue.ts +111 -12
  141. package/src/hooks/use-workspace-sessions.ts +5 -1
  142. package/src/index.ts +26 -4
  143. package/src/lib/interaction-errors.ts +18 -0
  144. package/src/machines.ts +9 -1
  145. package/src/model-policy.ts +10 -2
  146. package/src/realtime/realtime-control.tsx +53 -17
  147. package/src/session-context.ts +1 -0
  148. package/src/session-ui.ts +6 -1
  149. package/src/session.ts +9 -1
  150. package/src/timeline/activity-rail.tsx +20 -75
  151. package/src/timeline/index.ts +4 -0
  152. package/src/timeline/platform-activity-row.tsx +201 -0
  153. package/src/timeline/projection.ts +476 -23
  154. package/src/timeline/screenshot-lightbox.tsx +48 -14
  155. package/src/timeline/shared.tsx +8 -2
  156. package/src/timeline/tool-renderers.tsx +104 -6
  157. package/src/timeline/turn-summary.tsx +6 -1
  158. package/src/timeline/types.ts +75 -2
  159. package/src/types/machines.ts +10 -0
  160. package/styles/compiled.css +115 -104
  161. package/dist/chunk-5UQPNLIO.js.map +0 -1
  162. package/dist/chunk-6KLX2RH5.js.map +0 -1
  163. package/dist/chunk-B6WPZSTT.js.map +0 -1
  164. package/dist/chunk-HA46CYQK.js.map +0 -1
  165. package/dist/chunk-IGC6A2ZI.js.map +0 -1
  166. package/dist/chunk-LLOLUHVG.js +0 -5937
  167. package/dist/chunk-LLOLUHVG.js.map +0 -1
  168. package/dist/chunk-MKPIAGVL.js.map +0 -1
  169. package/dist/chunk-R3AZOAB5.js.map +0 -1
  170. package/dist/chunk-XBZWOM2K.js.map +0 -1
  171. package/dist/chunk-Y7OEDUJ5.js.map +0 -1
  172. package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
  173. package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
  174. /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-GXUICIAG.js.map} +0 -0
@@ -3,7 +3,7 @@ import {
3
3
  groupTimeline,
4
4
  mcpToolLeaf,
5
5
  toolDisplayName
6
- } from "./chunk-6KLX2RH5.js";
6
+ } from "./chunk-XSA2QAKP.js";
7
7
  import {
8
8
  EmptyQueueStateSurface,
9
9
  TimelineAnnotationsChip,
@@ -19,6 +19,7 @@ import {
19
19
  usePortalTokenStyle
20
20
  } from "./chunk-VZTQ73XT.js";
21
21
  import {
22
+ formatBytes,
22
23
  formatClockTime,
23
24
  formatRelativeTime,
24
25
  stringifyPayload,
@@ -37,7 +38,7 @@ import {
37
38
  import { Loader2Icon } from "lucide-react";
38
39
  import { lazy, Suspense } from "react";
39
40
  import { jsx, jsxs } from "react/jsx-runtime";
40
- var loadQueueSurface = () => import("./queue-surface-implementation-2KVJTYXH.js");
41
+ var loadQueueSurface = () => import("./queue-surface-implementation-BSKUWHRI.js");
41
42
  var QueueSurface = createQueueSurface(loadQueueSurface);
42
43
  function createQueueSurface(loadImplementation) {
43
44
  const LazyQueueSurface = lazy(async () => ({
@@ -80,6 +81,7 @@ import {
80
81
  ArrowDownIcon,
81
82
  ArrowUpIcon,
82
83
  BotIcon,
84
+ CheckIcon,
83
85
  InboxIcon,
84
86
  ListOrderedIcon,
85
87
  Loader2Icon as Loader2Icon2,
@@ -92,17 +94,11 @@ import {
92
94
  ZapIcon
93
95
  } from "lucide-react";
94
96
  import { AnimatePresence, motion, useReducedMotion } from "motion/react";
95
- import {
96
- useEffect,
97
- useId,
98
- useLayoutEffect,
99
- useMemo,
100
- useRef,
101
- useState
102
- } from "react";
97
+ import { useEffect, useId, useMemo, useRef, useState } from "react";
103
98
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
104
99
  var GOAL_LABEL = {
105
100
  pursuing: "Pursuing",
101
+ waiting: "Waiting",
106
102
  scheduled: "Scheduled",
107
103
  blocked: "Blocked",
108
104
  held: "Held",
@@ -110,6 +106,40 @@ var GOAL_LABEL = {
110
106
  invariant_broken: "Needs attention",
111
107
  completed: "Done"
112
108
  };
109
+ var GOAL_PAUSED_REASON_SUFFIX = {
110
+ max_auto_continuations: "cap",
111
+ limits: "budget",
112
+ user_pause: "manually",
113
+ api: "manually",
114
+ agent: "agent"
115
+ };
116
+ var GOAL_PAUSED_REASON_EXPLANATION = {
117
+ max_auto_continuations: "Paused at the automatic continuation cap. New input (a child result, an agent message, or your prompt) resumes it; you can also resume it here.",
118
+ limits: "Paused because budget or usage limits block another run. Resume once limits allow.",
119
+ user_pause: "Paused manually by a person or an API call. Resume to let the goal continue on its own.",
120
+ api: "Paused manually by a person or an API call. Resume to let the goal continue on its own.",
121
+ agent: "Paused by the agent: it is waiting on a human decision before continuing."
122
+ };
123
+ function sessionChromeGoalPillLabel(state, record) {
124
+ if (state !== "paused") return GOAL_LABEL[state];
125
+ const suffix = record?.pausedReason ? GOAL_PAUSED_REASON_SUFFIX[record.pausedReason] : void 0;
126
+ return suffix ? `Paused \xB7 ${suffix}` : "Paused";
127
+ }
128
+ function sessionChromeGoalPillExplanation(state, record) {
129
+ const continuation = record?.continuation ?? null;
130
+ if (state === "paused") {
131
+ return record?.pausedReason ? GOAL_PAUSED_REASON_EXPLANATION[record.pausedReason] ?? null : null;
132
+ }
133
+ if (state === "scheduled" && continuation?.reason === "backoff_pending") {
134
+ return continuation.nextAttemptAt ? `Next goal check at ${formatClockTime(continuation.nextAttemptAt)}.` : "Next goal check is scheduled.";
135
+ }
136
+ if (state === "held" && continuation?.reason === "held_for_input") {
137
+ const reason = continuation.holdReason?.trim();
138
+ const until = continuation.nextAttemptAt ? ` until ${formatClockTime(continuation.nextAttemptAt)}` : "";
139
+ return `Waiting for input${reason ? `: ${reason}` : ""}${until}. A child result, an agent message, or your prompt wakes it sooner.`;
140
+ }
141
+ return null;
142
+ }
113
143
  function queuedTurnPresentation(turn) {
114
144
  const realtimeDelegation = objectValue(turn.metadata.realtimeDelegation);
115
145
  const inputTranscript = realtimeDelegation?.inputTranscript;
@@ -132,11 +162,11 @@ function sessionChromeGoalPillState(goalStatus, continuation) {
132
162
  if (goalStatus === "paused") return "paused";
133
163
  if (!continuation) return "invariant_broken";
134
164
  if (continuation.state === "running") {
135
- return continuation.reason === "goal_turn_running" ? "pursuing" : continuation.reason === "human_turn_running" ? "blocked" : "invariant_broken";
165
+ return continuation.reason === "goal_turn_running" ? "pursuing" : continuation.reason === "human_turn_running" ? "waiting" : "invariant_broken";
136
166
  }
137
167
  if (continuation.state === "scheduled") return "scheduled";
138
168
  if (continuation.state === "blocked") {
139
- return continuation.reason === "workstream_paused" ? "held" : "blocked";
169
+ return continuation.reason === "workstream_paused" || continuation.reason === "held_for_input" ? "held" : "blocked";
140
170
  }
141
171
  return "invariant_broken";
142
172
  }
@@ -167,6 +197,16 @@ function pendingKindLabel(kind) {
167
197
  switch (kind) {
168
198
  case "child_terminal_result":
169
199
  return "Child result";
200
+ case "child_requires_action":
201
+ return "Child needs input";
202
+ case "child_requires_action_resolved":
203
+ return "Child unblocked";
204
+ case "child_paused":
205
+ return "Child paused";
206
+ case "child_waiting_capacity":
207
+ return "Child waiting";
208
+ case "child_progress":
209
+ return "Child progress";
170
210
  case "agent_steer_instruction":
171
211
  return "Steer";
172
212
  case "scheduled_occurrence":
@@ -210,29 +250,22 @@ function SessionChrome({
210
250
  const record = goal?.goal ?? null;
211
251
  const incoming = queue.pendingInputs;
212
252
  const turns = queue.queue;
213
- const composerSteering = composer?.steering ?? null;
214
- const { steering, queuedTurns } = useMemo(() => {
215
- const pendingQueueSteer = turns.find((turn) => queue.pendingByTurn[turn.id] === "steer") ?? null;
216
- const durableQueueSteer = !pendingQueueSteer && turns[0] && isSteeringTurn(turns[0]) ? turns[0] : null;
217
- const currentSteering = composerSteering?.phase === "submitting" ? composerSteering : pendingQueueSteer ? {
218
- phase: "submitting",
219
- text: queuedTurnPresentation(pendingQueueSteer).text,
220
- turnId: pendingQueueSteer.id
221
- } : durableQueueSteer ? {
222
- phase: "accepted",
223
- text: queuedTurnPresentation(durableQueueSteer).text,
224
- turnId: durableQueueSteer.id
225
- } : composerSteering;
226
- const currentTurnId = currentSteering?.turnId ?? null;
227
- return {
228
- steering: currentSteering,
229
- queuedTurns: currentTurnId ? turns.filter((turn) => turn.id !== currentTurnId) : turns
230
- };
231
- }, [composerSteering, queue.pendingByTurn, turns]);
253
+ const queueMutationFor = queue.mutationFor;
254
+ const queuedTurns = useMemo(
255
+ () => turns.filter((turn) => !isSteeringTurn(turn) && queueMutationFor(turn.id) !== "steer"),
256
+ [queueMutationFor, turns]
257
+ );
258
+ const queuedTurnIds = useMemo(() => new Set(queuedTurns.map((turn) => turn.id)), [queuedTurns]);
259
+ const optimisticQueued = useMemo(
260
+ () => (composer?.optimisticMessages ?? []).filter(
261
+ (message) => message.delivery === "send" && message.destination === "queue" && (!message.turnId || !queuedTurnIds.has(message.turnId)) && !(message.turnId && message.appliedQueueVersion !== null && message.appliedQueueVersion !== void 0 && queue.snapshot && queue.snapshot.version >= message.appliedQueueVersion)
262
+ ),
263
+ [composer?.optimisticMessages, queue.snapshot, queuedTurnIds]
264
+ );
232
265
  const stoppingKind = composer?.stoppingAttempt ?? (queue.stoppingPreviousAttempt ? queue.effectiveControl?.state === "paused" ? "current" : "previous" : null);
233
266
  const stopping = stoppingKind !== null;
234
267
  const canMutateQueue = !readOnly && composer !== void 0;
235
- const liveGoal = record?.status === "active" && record.continuation?.state === "running" && record.continuation.reason === "goal_turn_running";
268
+ const liveGoal = record?.status === "active";
236
269
  const elapsed = useLiveElapsed(
237
270
  record?.createdAt,
238
271
  Boolean(liveGoal),
@@ -253,38 +286,33 @@ function SessionChrome({
253
286
  icon: /* @__PURE__ */ jsx2(InboxIcon, { className: "size-3" })
254
287
  });
255
288
  }
256
- if (steering || stopping) {
257
- rows.push({
258
- id: "steering",
259
- label: stopping ? stoppingKind === "current" ? "Stopping current work\u2026" : "Stopping previous work\u2026" : "Changing direction\u2026",
260
- ...steering?.text ? { detail: steering.text } : {},
261
- tone: stopping ? "waiting" : "accent",
262
- icon: steering?.phase === "submitting" || stopping ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3" })
263
- });
264
- }
265
- if (queuedTurns.length > 0) {
289
+ const queuedCount = queuedTurns.length + optimisticQueued.length;
290
+ const queueProblem = queue.mutationError ?? queue.error;
291
+ if (queuedCount > 0 || queueProblem) {
266
292
  const presentations = queuedTurns.map(queuedTurnPresentation);
267
293
  const first = presentations[0];
268
- const allVoiceRequests = presentations.every(({ kind }) => kind === "realtime_voice");
269
- const onlyVoiceHandoff = presentations.length === 1 && first?.kind === "realtime_voice_handoff";
294
+ const allVoiceRequests = optimisticQueued.length === 0 && presentations.length > 0 && presentations.every(({ kind }) => kind === "realtime_voice");
295
+ const onlyVoiceHandoff = optimisticQueued.length === 0 && presentations.length === 1 && first?.kind === "realtime_voice_handoff";
270
296
  const voiceOnly = allVoiceRequests || onlyVoiceHandoff;
271
- const detail = first?.text;
297
+ const detail = queueProblem ? queue.mutationError ? "Action not confirmed" : "Queue unavailable" : first?.text ?? optimisticQueued[0]?.text;
272
298
  rows.push({
273
299
  id: "queue",
274
- label: allVoiceRequests ? queuedTurns.length === 1 ? "Voice request queued" : `${queuedTurns.length} voice requests queued` : onlyVoiceHandoff ? "Voice handoff queued" : `${queuedTurns.length} queued prompt${queuedTurns.length === 1 ? "" : "s"}`,
300
+ label: queueProblem ? queuedCount > 0 ? `${queuedCount} queued \xB7 needs attention` : "Queue needs attention" : allVoiceRequests ? queuedCount === 1 ? "Voice request queued" : `${queuedCount} voice requests queued` : onlyVoiceHandoff ? "Voice handoff queued" : `${queuedCount} queued prompt${queuedCount === 1 ? "" : "s"}`,
275
301
  ...detail ? { detail } : {},
276
- tone: "neutral",
277
- icon: voiceOnly ? /* @__PURE__ */ jsx2(AudioLinesIcon, { className: "size-3" }) : /* @__PURE__ */ jsx2(ListOrderedIcon, { className: "size-3" })
302
+ tone: queueProblem ? "waiting" : "neutral",
303
+ icon: queueProblem ? /* @__PURE__ */ jsx2(TriangleAlertIcon, { className: "size-3" }) : voiceOnly ? /* @__PURE__ */ jsx2(AudioLinesIcon, { className: "size-3" }) : /* @__PURE__ */ jsx2(ListOrderedIcon, { className: "size-3" })
278
304
  });
279
305
  }
280
306
  if (record && goalState) {
281
- const waiting = goalState === "blocked" || goalState === "held" || goalState === "paused";
307
+ const waiting = goalState === "waiting" || goalState === "blocked" || goalState === "held" || goalState === "paused";
308
+ const explanation = sessionChromeGoalPillExplanation(goalState, record);
282
309
  rows.push({
283
310
  id: "goal",
284
- label: GOAL_LABEL[goalState],
311
+ label: sessionChromeGoalPillLabel(goalState, record),
285
312
  detail: elapsed ? `${elapsed} \xB7 ${record.text}` : record.text,
313
+ ...explanation ? { title: explanation } : {},
286
314
  tone: waiting ? "waiting" : goalState === "pursuing" || goalState === "scheduled" ? "accent" : "neutral",
287
- icon: goalState === "blocked" || goalState === "invariant_broken" ? /* @__PURE__ */ jsx2(TriangleAlertIcon, { className: "size-3" }) : goalState === "paused" || goalState === "held" ? /* @__PURE__ */ jsx2(PauseIcon, { className: "size-3" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3" })
315
+ icon: goalState === "blocked" || goalState === "invariant_broken" ? /* @__PURE__ */ jsx2(TriangleAlertIcon, { className: "size-3" }) : goalState === "waiting" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : goalState === "paused" || goalState === "held" ? /* @__PURE__ */ jsx2(PauseIcon, { className: "size-3" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3" })
288
316
  });
289
317
  }
290
318
  if (agentsSignal && agentsSignal.count > 0) {
@@ -303,11 +331,11 @@ function SessionChrome({
303
331
  elapsed,
304
332
  goalState,
305
333
  incoming,
334
+ optimisticQueued,
335
+ queue.error,
336
+ queue.mutationError,
306
337
  queuedTurns,
307
- record,
308
- steering,
309
- stopping,
310
- stoppingKind
338
+ record
311
339
  ]);
312
340
  const [activeUncontrolled, setActiveUncontrolled] = useState(
313
341
  defaultActive
@@ -317,12 +345,20 @@ function SessionChrome({
317
345
  if (activeControlled === void 0) setActiveUncontrolled(next);
318
346
  onActiveChange?.(next);
319
347
  };
348
+ const optimisticQueueKeys = optimisticQueued.map((message) => message.clientEventId).join(",");
349
+ const previousOptimisticQueueKeys = useRef(optimisticQueueKeys);
350
+ const [queueArrivalNonce, setQueueArrivalNonce] = useState(0);
351
+ useEffect(() => {
352
+ const previous = new Set(previousOptimisticQueueKeys.current.split(",").filter(Boolean));
353
+ const arrived = optimisticQueued.some((message) => !previous.has(message.clientEventId));
354
+ previousOptimisticQueueKeys.current = optimisticQueueKeys;
355
+ if (!arrived) return;
356
+ setQueueArrivalNonce((current) => current + 1);
357
+ }, [optimisticQueueKeys, optimisticQueued]);
320
358
  const [replaceDraftFor, setReplaceDraftFor] = useState(null);
321
359
  const chipRefs = useRef({});
322
360
  const railRef = useRef(null);
323
- const panelBodyRef = useRef(null);
324
361
  const [pill, setPill] = useState({ left: 0, top: 0, width: 0, height: 0, opacity: 0 });
325
- const [panelHeight, setPanelHeight] = useState(0);
326
362
  const signalIds = signals.map((signal) => signal.id).join(",");
327
363
  useEffect(() => {
328
364
  if (active && !signalIds.split(",").includes(active)) {
@@ -369,40 +405,21 @@ function SessionChrome({
369
405
  };
370
406
  }, [active, signals]);
371
407
  const open = active !== null;
372
- useLayoutEffect(() => {
373
- if (!open) {
374
- setPanelHeight(0);
375
- return;
376
- }
377
- const node = panelBodyRef.current;
378
- if (!node) return;
379
- setPanelHeight(node.offsetHeight);
380
- }, [open, active, incoming, queuedTurns, record, goalState, agentsPanel, agentsSignal, steering]);
381
- useEffect(() => {
382
- if (!open) return;
383
- const node = panelBodyRef.current;
384
- if (!node || typeof ResizeObserver === "undefined") return;
385
- const observer = new ResizeObserver(() => {
386
- setPanelHeight(node.offsetHeight);
387
- });
388
- observer.observe(node);
389
- return () => observer.disconnect();
390
- }, [open, active]);
391
- if (signals.length === 0) return null;
408
+ if (signals.length === 0 && !stopping) return null;
392
409
  const shellDuration = reduceMotion ? 0 : 0.22;
393
410
  const crossfadeDuration = reduceMotion ? 0 : 0.18;
394
411
  const ease = [0.22, 1, 0.36, 1];
395
- const panelBody = active === "incoming" ? /* @__PURE__ */ jsx2(IncomingPanel, { inputs: incoming, onDismiss: onDismissIncoming }) : active === "steering" && (steering || stopping) ? /* @__PURE__ */ jsx2(
396
- SteeringPanel,
397
- {
398
- phase: stopping ? "stopping" : steering?.phase ?? "accepted",
399
- stoppingKind,
400
- text: steering?.text
401
- }
402
- ) : active === "queue" ? /* @__PURE__ */ jsx2(
412
+ const panelBody = active === "incoming" ? /* @__PURE__ */ jsx2(IncomingPanel, { inputs: incoming, onDismiss: onDismissIncoming }) : active === "queue" ? /* @__PURE__ */ jsx2(
403
413
  QueuePanel,
404
414
  {
405
415
  turns: queuedTurns,
416
+ optimistic: optimisticQueued,
417
+ loadError: queue.error,
418
+ mutationError: queue.mutationError,
419
+ onRefresh: queue.refresh,
420
+ onClearMutationError: queue.clearMutationError,
421
+ onRetryOptimistic: composer?.retryOptimisticMessage,
422
+ onRemoveOptimistic: composer?.removeOptimisticMessage,
406
423
  readOnly: !canMutateQueue,
407
424
  mutationFor: queue.mutationFor,
408
425
  replaceDraftFor,
@@ -410,20 +427,26 @@ function SessionChrome({
410
427
  onConfirmReplace: canMutateQueue && composer && replaceDraftFor ? () => {
411
428
  const turnId = replaceDraftFor;
412
429
  setReplaceDraftFor(null);
413
- void queue.editTurn(turnId, {
414
- expectedDraftRevision: composer.draftRevision,
415
- replaceDraft: true
416
- });
430
+ void (async () => {
431
+ const checkedOut = await queue.editTurn(turnId, {
432
+ expectedDraftRevision: composer.draftRevision,
433
+ replaceDraft: true
434
+ });
435
+ if (checkedOut) composer.applyDraft(checkedOut);
436
+ })();
417
437
  } : void 0,
418
438
  onEdit: canMutateQueue && composer ? (turn) => {
419
439
  requestQueueDraftEdit(
420
440
  composer,
421
441
  () => setReplaceDraftFor(turn.id),
422
442
  () => {
423
- void queue.editTurn(turn.id, {
424
- expectedDraftRevision: composer.draftRevision,
425
- replaceDraft: false
426
- });
443
+ void (async () => {
444
+ const checkedOut = await queue.editTurn(turn.id, {
445
+ expectedDraftRevision: composer.draftRevision,
446
+ replaceDraft: false
447
+ });
448
+ if (checkedOut) composer.applyDraft(checkedOut);
449
+ })();
427
450
  }
428
451
  );
429
452
  } : void 0,
@@ -514,6 +537,7 @@ function SessionChrome({
514
537
  "aria-label": selected ? `Close ${signal.label}` : void 0,
515
538
  "data-testid": `session-chrome-${signal.id}`,
516
539
  "data-og-session-chrome-signal": signal.id,
540
+ title: signal.title,
517
541
  onClick: () => setActive(selected ? null : signal.id),
518
542
  className: cn(
519
543
  "group relative z-[1] inline-flex min-h-[var(--og-session-chrome-chip-min-height)] max-w-full items-center gap-1 rounded-og-md py-1 text-left text-og-xs outline-hidden",
@@ -527,6 +551,18 @@ function SessionChrome({
527
551
  paddingInline: "var(--og-session-chrome-chip-pad-x)"
528
552
  },
529
553
  children: [
554
+ signal.id === "queue" && queueArrivalNonce > 0 && !reduceMotion ? /* @__PURE__ */ jsx2(
555
+ motion.span,
556
+ {
557
+ "aria-hidden": "true",
558
+ "data-testid": "session-chrome-queue-arrival",
559
+ className: "pointer-events-none absolute inset-0 rounded-og-md bg-og-accent-soft",
560
+ initial: { opacity: 0 },
561
+ animate: { opacity: [0, 0.38, 0] },
562
+ transition: { duration: 0.72, times: [0, 0.18, 1], ease }
563
+ },
564
+ queueArrivalNonce
565
+ ) : null,
530
566
  /* @__PURE__ */ jsx2("span", { className: cn("shrink-0", toneClass(signal.tone, selected)), children: signal.icon }),
531
567
  /* @__PURE__ */ jsx2("span", { className: "shrink-0 font-medium text-og-fg", children: signal.label }),
532
568
  signal.detail ? /* @__PURE__ */ jsxs2(Fragment, { children: [
@@ -546,28 +582,50 @@ function SessionChrome({
546
582
  },
547
583
  signal.id
548
584
  );
549
- })
585
+ }),
586
+ stopping ? /* @__PURE__ */ jsxs2(
587
+ "span",
588
+ {
589
+ role: "status",
590
+ "aria-live": "polite",
591
+ className: "inline-flex min-h-[var(--og-session-chrome-chip-min-height)] items-center gap-1.5 px-1.5 text-og-xs text-og-fg-muted",
592
+ "data-testid": "session-chrome-stopping",
593
+ children: [
594
+ /* @__PURE__ */ jsx2(
595
+ Loader2Icon2,
596
+ {
597
+ "aria-hidden": "true",
598
+ className: "size-3 animate-og-spin motion-reduce:animate-none"
599
+ }
600
+ ),
601
+ stoppingKind === "current" ? "Current work stopping" : "Previous work stopping"
602
+ ]
603
+ }
604
+ ) : null
550
605
  ]
551
606
  }
552
607
  )
553
608
  }
554
609
  ),
555
610
  /* @__PURE__ */ jsx2(
556
- motion.div,
611
+ "div",
557
612
  {
558
613
  id: panelId,
559
614
  "data-og-session-chrome-panel-shell": "",
560
- initial: false,
561
- animate: {
562
- height: open ? panelHeight : 0,
563
- opacity: open ? 1 : 0
615
+ "aria-hidden": !open,
616
+ inert: !open ? true : void 0,
617
+ className: "grid overflow-hidden motion-reduce:transition-none",
618
+ style: {
619
+ gridTemplateRows: open ? "1fr" : "0fr",
620
+ opacity: open ? 1 : 0,
621
+ pointerEvents: open ? "auto" : "none",
622
+ transitionProperty: "grid-template-rows, opacity",
623
+ transitionDuration: "var(--og-session-chrome-duration)",
624
+ transitionTimingFunction: "var(--_og-session-chrome-ease)"
564
625
  },
565
- transition: { duration: shellDuration, ease },
566
- className: "overflow-hidden",
567
- children: /* @__PURE__ */ jsx2(
626
+ children: /* @__PURE__ */ jsx2("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ jsx2(
568
627
  "div",
569
628
  {
570
- ref: panelBodyRef,
571
629
  className: "relative overflow-y-auto overscroll-contain border-t border-og-border/50",
572
630
  style: {
573
631
  maxHeight: "var(--og-session-chrome-panel-max-height)",
@@ -593,7 +651,7 @@ function SessionChrome({
593
651
  active
594
652
  ) : null })
595
653
  }
596
- )
654
+ ) })
597
655
  }
598
656
  )
599
657
  ]
@@ -645,30 +703,15 @@ function IncomingPanel({
645
703
  }
646
704
  );
647
705
  }
648
- function SteeringPanel({
649
- phase,
650
- stoppingKind,
651
- text
652
- }) {
653
- return /* @__PURE__ */ jsxs2(
654
- "div",
655
- {
656
- className: "flex items-start gap-2 rounded-og-sm px-1.5 py-1",
657
- role: "status",
658
- "aria-live": "polite",
659
- "data-og-session-chrome-panel": "steering",
660
- children: [
661
- /* @__PURE__ */ jsx2("span", { className: "mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full bg-og-accent-soft text-og-accent", children: phase === "submitting" || phase === "stopping" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin", "aria-hidden": "true" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3", "aria-hidden": "true" }) }),
662
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
663
- text ? /* @__PURE__ */ jsx2("p", { className: "truncate text-og-xs font-medium leading-4 text-og-fg", children: text }) : null,
664
- /* @__PURE__ */ jsx2("p", { className: cn(text && "mt-0.5", "text-[10px] leading-4 text-og-fg-muted"), children: phase === "submitting" ? "Sending your latest direction\u2026" : phase === "stopping" ? stoppingKind === "previous" ? "Direction saved. Waiting for the previous command to stop safely." : "Waiting for the current command to stop safely." : "Direction accepted. The agent will continue from it." })
665
- ] })
666
- ]
667
- }
668
- );
669
- }
670
706
  function QueuePanel({
671
707
  turns,
708
+ optimistic,
709
+ loadError,
710
+ mutationError,
711
+ onRefresh,
712
+ onClearMutationError,
713
+ onRetryOptimistic,
714
+ onRemoveOptimistic,
672
715
  readOnly,
673
716
  mutationFor,
674
717
  replaceDraftFor,
@@ -679,120 +722,228 @@ function QueuePanel({
679
722
  onRemove,
680
723
  onMove
681
724
  }) {
682
- return /* @__PURE__ */ jsx2(
725
+ const reduceMotion = useReducedMotion();
726
+ const turnIdsKey = turns.map((turn) => turn.id).join(",");
727
+ const [interactiveTurnIds, setInteractiveTurnIds] = useState(
728
+ () => /* @__PURE__ */ new Set()
729
+ );
730
+ useEffect(() => {
731
+ const visibleTurnIds = new Set(turnIdsKey ? turnIdsKey.split(",") : []);
732
+ setInteractiveTurnIds((current) => {
733
+ const retained = new Set([...current].filter((turnId) => visibleTurnIds.has(turnId)));
734
+ return retained.size === current.size ? current : retained;
735
+ });
736
+ if (visibleTurnIds.size === 0) return;
737
+ const timer = setTimeout(
738
+ () => setInteractiveTurnIds((current) => /* @__PURE__ */ new Set([...current, ...visibleTurnIds])),
739
+ reduceMotion ? 0 : 240
740
+ );
741
+ return () => clearTimeout(timer);
742
+ }, [reduceMotion, turnIdsKey]);
743
+ return /* @__PURE__ */ jsxs2(
683
744
  "ol",
684
745
  {
685
746
  className: "flex flex-col gap-0.5",
686
747
  "aria-label": "Queued prompts",
687
748
  "data-og-session-chrome-panel": "queue",
688
- children: turns.map((turn, index) => {
689
- const presentation = queuedTurnPresentation(turn);
690
- const voice = presentation.kind !== "prompt";
691
- const pending = mutationFor(turn.id);
692
- const beforeUp = index > 0 ? turns[index - 1]?.id ?? null : null;
693
- const beforeDown = index < turns.length - 1 ? turns[index + 2]?.id ?? null : null;
694
- const showActions = !readOnly && (onEdit || onSteer || onRemove || onMove);
695
- const confirmingReplace = replaceDraftFor === turn.id;
696
- return /* @__PURE__ */ jsxs2(
697
- "li",
698
- {
699
- "data-queue-turn-id": turn.id,
700
- className: "group flex flex-col gap-1 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--_og-session-chrome-row-hover)]",
701
- children: [
702
- /* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-1.5", children: [
703
- voice ? /* @__PURE__ */ jsx2(
704
- AudioLinesIcon,
705
- {
706
- "aria-hidden": "true",
707
- className: "mt-0.5 size-3 shrink-0 text-og-accent"
708
- }
709
- ) : /* @__PURE__ */ jsx2("span", { className: "mt-px shrink-0 font-og-mono text-[10px] leading-4 text-og-fg-subtle", children: index + 1 }),
710
- /* @__PURE__ */ jsx2("p", { className: "min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg", children: presentation.text }),
711
- showActions ? /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100 max-sm:opacity-100", children: [
712
- onMove && turns.length > 1 ? /* @__PURE__ */ jsxs2(Fragment, { children: [
713
- /* @__PURE__ */ jsx2(
749
+ children: [
750
+ turns.map((turn, index) => {
751
+ const presentation = queuedTurnPresentation(turn);
752
+ const voice = presentation.kind !== "prompt";
753
+ const pending = mutationFor(turn.id);
754
+ const settling = !interactiveTurnIds.has(turn.id);
755
+ const beforeUp = index > 0 ? turns[index - 1]?.id ?? null : null;
756
+ const beforeDown = index < turns.length - 1 ? turns[index + 2]?.id ?? null : null;
757
+ const showActions = !readOnly && (onEdit || onSteer || onRemove || onMove);
758
+ const confirmingReplace = replaceDraftFor === turn.id;
759
+ return /* @__PURE__ */ jsxs2(
760
+ "li",
761
+ {
762
+ "data-queue-turn-id": turn.id,
763
+ className: "group flex flex-col gap-1 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--_og-session-chrome-row-hover)]",
764
+ children: [
765
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-1.5", children: [
766
+ voice ? /* @__PURE__ */ jsx2(
767
+ AudioLinesIcon,
768
+ {
769
+ "aria-hidden": "true",
770
+ className: "mt-0.5 size-3 shrink-0 text-og-accent"
771
+ }
772
+ ) : /* @__PURE__ */ jsx2("span", { className: "mt-px shrink-0 font-og-mono text-[10px] leading-4 text-og-fg-subtle", children: index + 1 }),
773
+ /* @__PURE__ */ jsx2("p", { className: "min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg", children: presentation.text }),
774
+ showActions ? /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100 max-sm:opacity-100", children: [
775
+ onMove && turns.length > 1 ? /* @__PURE__ */ jsxs2(Fragment, { children: [
776
+ /* @__PURE__ */ jsx2(
777
+ IconAction,
778
+ {
779
+ label: `Move queued prompt ${index + 1} up`,
780
+ tip: "Move up",
781
+ disabled: settling || pending !== null || index === 0,
782
+ onClick: () => onMove(turn.id, beforeUp),
783
+ children: /* @__PURE__ */ jsx2(ArrowUpIcon, { className: "size-3" })
784
+ }
785
+ ),
786
+ /* @__PURE__ */ jsx2(
787
+ IconAction,
788
+ {
789
+ label: `Move queued prompt ${index + 1} down`,
790
+ tip: "Move down",
791
+ disabled: settling || pending !== null || index >= turns.length - 1,
792
+ onClick: () => onMove(turn.id, beforeDown),
793
+ children: /* @__PURE__ */ jsx2(ArrowDownIcon, { className: "size-3" })
794
+ }
795
+ )
796
+ ] }) : null,
797
+ onSteer ? /* @__PURE__ */ jsx2(
798
+ IconAction,
799
+ {
800
+ label: `Steer queued prompt ${index + 1}`,
801
+ tip: QUEUE_STEER_TIP,
802
+ disabled: settling || pending !== null,
803
+ onClick: () => onSteer(turn.id),
804
+ children: pending === "steer" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3" })
805
+ }
806
+ ) : null,
807
+ onEdit ? /* @__PURE__ */ jsx2(
714
808
  IconAction,
715
809
  {
716
- label: `Move queued prompt ${index + 1} up`,
717
- tip: "Move up",
718
- disabled: pending !== null || index === 0,
719
- onClick: () => onMove(turn.id, beforeUp),
720
- children: /* @__PURE__ */ jsx2(ArrowUpIcon, { className: "size-3" })
810
+ label: `Edit queued prompt ${index + 1}`,
811
+ tip: QUEUE_EDIT_TIP,
812
+ disabled: settling || pending !== null,
813
+ onClick: () => onEdit(turn),
814
+ children: pending === "edit" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(PencilIcon, { className: "size-3" })
815
+ }
816
+ ) : null,
817
+ onRemove ? /* @__PURE__ */ jsx2(
818
+ IconAction,
819
+ {
820
+ label: `Remove queued prompt ${index + 1}`,
821
+ tip: QUEUE_DELETE_TIP,
822
+ disabled: settling || pending !== null,
823
+ onClick: () => onRemove(turn.id),
824
+ danger: true,
825
+ children: pending === "delete" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(Trash2Icon, { className: "size-3" })
826
+ }
827
+ ) : null
828
+ ] }) : null
829
+ ] }),
830
+ confirmingReplace ? /* @__PURE__ */ jsxs2("div", { className: "rounded-og-sm border border-og-status-waiting/30 bg-og-status-waiting/10 p-2 text-og-xs text-og-fg", children: [
831
+ /* @__PURE__ */ jsx2("p", { children: "Your composer already has a draft. Replace it with this queued prompt?" }),
832
+ /* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-og-fg-muted", children: "The current draft will be permanently discarded; this queued prompt is preserved until you confirm." }),
833
+ /* @__PURE__ */ jsxs2("div", { className: "mt-2 flex justify-end gap-1.5", children: [
834
+ /* @__PURE__ */ jsx2(
835
+ "button",
836
+ {
837
+ type: "button",
838
+ className: "rounded-og-sm px-2 py-1 font-medium hover:bg-og-surface-3/70 focus-visible:ring-2 focus-visible:ring-og-accent/40",
839
+ onClick: onCancelReplace,
840
+ children: "Keep current draft"
721
841
  }
722
842
  ),
723
843
  /* @__PURE__ */ jsx2(
724
- IconAction,
844
+ "button",
725
845
  {
726
- label: `Move queued prompt ${index + 1} down`,
727
- tip: "Move down",
728
- disabled: pending !== null || index >= turns.length - 1,
729
- onClick: () => onMove(turn.id, beforeDown),
730
- children: /* @__PURE__ */ jsx2(ArrowDownIcon, { className: "size-3" })
846
+ type: "button",
847
+ className: "rounded-og-sm bg-og-accent px-2 py-1 font-medium text-og-accent-fg hover:opacity-90 focus-visible:ring-2 focus-visible:ring-og-accent/40",
848
+ onClick: onConfirmReplace,
849
+ children: "Replace and edit"
731
850
  }
732
851
  )
733
- ] }) : null,
734
- onSteer ? /* @__PURE__ */ jsx2(
735
- IconAction,
736
- {
737
- label: `Steer queued prompt ${index + 1}`,
738
- tip: QUEUE_STEER_TIP,
739
- disabled: pending !== null,
740
- onClick: () => onSteer(turn.id),
741
- children: pending === "steer" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3" })
742
- }
743
- ) : null,
744
- onEdit ? /* @__PURE__ */ jsx2(
745
- IconAction,
746
- {
747
- label: `Edit queued prompt ${index + 1}`,
748
- tip: QUEUE_EDIT_TIP,
749
- disabled: pending !== null,
750
- onClick: () => onEdit(turn),
751
- children: pending === "edit" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(PencilIcon, { className: "size-3" })
752
- }
753
- ) : null,
754
- onRemove ? /* @__PURE__ */ jsx2(
755
- IconAction,
756
- {
757
- label: `Remove queued prompt ${index + 1}`,
758
- tip: QUEUE_DELETE_TIP,
759
- disabled: pending !== null,
760
- onClick: () => onRemove(turn.id),
761
- danger: true,
762
- children: pending === "delete" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(Trash2Icon, { className: "size-3" })
763
- }
764
- ) : null
852
+ ] })
765
853
  ] }) : null
766
- ] }),
767
- confirmingReplace ? /* @__PURE__ */ jsxs2("div", { className: "rounded-og-sm border border-og-status-waiting/30 bg-og-status-waiting/10 p-2 text-og-xs text-og-fg", children: [
768
- /* @__PURE__ */ jsx2("p", { children: "Your composer already has a draft. Replace it with this queued prompt?" }),
769
- /* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-og-fg-muted", children: "The current draft will be permanently discarded; this queued prompt is preserved until you confirm." }),
770
- /* @__PURE__ */ jsxs2("div", { className: "mt-2 flex justify-end gap-1.5", children: [
771
- /* @__PURE__ */ jsx2(
772
- "button",
773
- {
774
- type: "button",
775
- className: "rounded-og-sm px-2 py-1 font-medium hover:bg-og-surface-3/70 focus-visible:ring-2 focus-visible:ring-og-accent/40",
776
- onClick: onCancelReplace,
777
- children: "Keep current draft"
778
- }
779
- ),
780
- /* @__PURE__ */ jsx2(
781
- "button",
782
- {
783
- type: "button",
784
- className: "rounded-og-sm bg-og-accent px-2 py-1 font-medium text-og-accent-fg hover:opacity-90 focus-visible:ring-2 focus-visible:ring-og-accent/40",
785
- onClick: onConfirmReplace,
786
- children: "Replace and edit"
787
- }
788
- )
789
- ] })
790
- ] }) : null
854
+ ]
855
+ },
856
+ turn.id
857
+ );
858
+ }),
859
+ /* @__PURE__ */ jsx2(AnimatePresence, { initial: false, children: optimistic.map((message, index) => /* @__PURE__ */ jsxs2(
860
+ motion.li,
861
+ {
862
+ "aria-live": "polite",
863
+ "data-optimistic-queue-message": message.clientEventId,
864
+ initial: reduceMotion ? false : { opacity: 0 },
865
+ animate: { opacity: 1 },
866
+ transition: { duration: reduceMotion ? 0 : 0.12, ease: [0.22, 1, 0.36, 1] },
867
+ className: cn(
868
+ "flex min-h-6 items-center gap-1.5 rounded-og-sm px-1.5 py-1",
869
+ message.state === "failed" ? "bg-og-danger/8 text-og-danger" : "bg-og-accent-soft/45"
870
+ ),
871
+ children: [
872
+ /* @__PURE__ */ jsx2("span", { className: "shrink-0 font-og-mono text-[10px] leading-4 text-og-fg-subtle", children: turns.length + index + 1 }),
873
+ /* @__PURE__ */ jsx2("p", { className: "min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg", children: message.text }),
874
+ /* @__PURE__ */ jsx2("span", { className: "sr-only", children: message.state === "failed" ? "Not confirmed" : message.state === "sending" ? "Placing in queue" : "Queued" }),
875
+ message.state === "failed" ? /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-1 text-[10px]", children: [
876
+ onRetryOptimistic ? /* @__PURE__ */ jsx2(
877
+ "button",
878
+ {
879
+ type: "button",
880
+ className: "rounded-og-sm px-1.5 py-1 font-medium hover:bg-og-surface-2 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
881
+ onClick: () => onRetryOptimistic(message.clientEventId),
882
+ children: "Retry"
883
+ }
884
+ ) : null,
885
+ onRemoveOptimistic ? /* @__PURE__ */ jsx2(
886
+ "button",
887
+ {
888
+ type: "button",
889
+ "aria-label": "Dismiss unconfirmed queued prompt",
890
+ className: "rounded-og-sm p-1 text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg pointer-coarse:min-h-11 pointer-coarse:min-w-11",
891
+ onClick: () => onRemoveOptimistic(message.clientEventId),
892
+ children: /* @__PURE__ */ jsx2(XIcon, { className: "size-3" })
893
+ }
894
+ ) : null
895
+ ] }) : message.state === "sending" ? /* @__PURE__ */ jsx2(
896
+ Loader2Icon2,
897
+ {
898
+ "aria-hidden": "true",
899
+ className: "size-3 shrink-0 animate-og-spin text-og-accent motion-reduce:animate-none"
900
+ }
901
+ ) : /* @__PURE__ */ jsx2(CheckIcon, { "aria-hidden": "true", className: "size-3 shrink-0 text-og-accent" })
791
902
  ]
792
903
  },
793
- turn.id
794
- );
795
- })
904
+ message.clientEventId
905
+ )) }),
906
+ loadError ? /* @__PURE__ */ jsxs2(
907
+ "li",
908
+ {
909
+ role: "alert",
910
+ className: "flex items-center gap-1.5 rounded-og-sm bg-og-danger/8 px-1.5 py-1 text-og-xs text-og-danger",
911
+ children: [
912
+ /* @__PURE__ */ jsx2(TriangleAlertIcon, { className: "size-3 shrink-0" }),
913
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1", children: "Queue unavailable." }),
914
+ /* @__PURE__ */ jsx2(
915
+ "button",
916
+ {
917
+ type: "button",
918
+ className: "rounded-og-sm px-1.5 py-1 font-medium hover:bg-og-surface-2 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
919
+ onClick: () => void onRefresh(),
920
+ children: "Retry"
921
+ }
922
+ )
923
+ ]
924
+ }
925
+ ) : null,
926
+ mutationError ? /* @__PURE__ */ jsxs2(
927
+ "li",
928
+ {
929
+ role: "alert",
930
+ className: "flex items-center gap-1.5 rounded-og-sm bg-og-danger/8 px-1.5 py-1 text-og-xs text-og-danger",
931
+ children: [
932
+ /* @__PURE__ */ jsx2(TriangleAlertIcon, { className: "size-3 shrink-0" }),
933
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1", children: "Not confirmed. Check the queue before retrying." }),
934
+ /* @__PURE__ */ jsx2(
935
+ "button",
936
+ {
937
+ type: "button",
938
+ className: "rounded-og-sm px-1.5 py-1 font-medium hover:bg-og-surface-2 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
939
+ onClick: onClearMutationError,
940
+ children: "Dismiss"
941
+ }
942
+ )
943
+ ]
944
+ }
945
+ ) : null
946
+ ]
796
947
  }
797
948
  );
798
949
  }
@@ -805,9 +956,10 @@ function GoalPanel({
805
956
  const record = goal.goal;
806
957
  if (!record) return null;
807
958
  const canToggle = !readOnly && (record.status === "active" || record.status === "paused");
959
+ const explanation = sessionChromeGoalPillExplanation(state, record);
808
960
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-1.5", "data-og-session-chrome-panel": "goal", children: [
809
961
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-1.5 text-[10px] font-medium uppercase tracking-wider text-og-fg-subtle", children: [
810
- /* @__PURE__ */ jsx2("span", { children: GOAL_LABEL[state] }),
962
+ /* @__PURE__ */ jsx2("span", { children: sessionChromeGoalPillLabel(state, record) }),
811
963
  elapsed ? /* @__PURE__ */ jsxs2("span", { className: "tabular-nums normal-case tracking-normal text-og-fg-muted", children: [
812
964
  "\xB7 ",
813
965
  elapsed
@@ -823,12 +975,20 @@ function GoalPanel({
823
975
  " ",
824
976
  record.successCriteria
825
977
  ] }) : null,
978
+ explanation ? /* @__PURE__ */ jsx2(
979
+ "p",
980
+ {
981
+ "data-og-session-chrome-goal-explanation": true,
982
+ className: "text-og-xs leading-4 text-og-fg-muted",
983
+ children: explanation
984
+ }
985
+ ) : null,
826
986
  record.continuation?.lastError ? /* @__PURE__ */ jsx2("p", { className: "rounded-og-sm bg-og-status-waiting/10 px-1.5 py-1 text-og-xs leading-4 text-og-status-waiting", children: record.continuation.lastError }) : null,
827
987
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center justify-between gap-1.5 pt-0.5", children: [
828
988
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap gap-1 text-[10px] text-og-fg-muted", children: [
829
989
  /* @__PURE__ */ jsxs2("span", { className: "rounded bg-og-surface-3/70 px-1 py-px", children: [
830
990
  record.autoContinuations,
831
- " auto-continues"
991
+ " consecutive unattended continues"
832
992
  ] }),
833
993
  /* @__PURE__ */ jsxs2("span", { className: "rounded bg-og-surface-3/70 px-1 py-px", children: [
834
994
  record.noProgressStreak,
@@ -909,7 +1069,7 @@ var defaultHumanInputFormMessages = {
909
1069
  title: "Input required",
910
1070
  /** Multi-question chrome has no default subtitle; hosts may still override. */
911
1071
  description: "",
912
- submit: "Continue",
1072
+ submit: "Send answers",
913
1073
  skip: "Skip",
914
1074
  submitting: "Submitting\u2026",
915
1075
  other: "Other",
@@ -931,7 +1091,10 @@ var defaultHumanInputFormMessages = {
931
1091
  return null;
932
1092
  }
933
1093
  };
934
- function HumanInputForm({
1094
+ function HumanInputForm(props) {
1095
+ return /* @__PURE__ */ jsx3(HumanInputRequestForm, { ...props }, props.request.id);
1096
+ }
1097
+ function HumanInputRequestForm({
935
1098
  request,
936
1099
  onSubmit,
937
1100
  submitting = false,
@@ -966,15 +1129,6 @@ function HumanInputForm({
966
1129
  const submissionInFlight = useRef2(false);
967
1130
  const submissionGeneration = useRef2(0);
968
1131
  const busy = submitting || submittingInternally;
969
- useEffect2(() => {
970
- submissionGeneration.current += 1;
971
- submissionInFlight.current = false;
972
- setDrafts(initialDrafts(request.questions));
973
- setValidationErrors({});
974
- setSubmissionError(null);
975
- setSubmittingInternally(false);
976
- setCollapsed(defaultCollapsed);
977
- }, [request.id, request.questions, defaultCollapsed]);
978
1132
  useEffect2(() => {
979
1133
  if (collapsed) {
980
1134
  setOverflowBelow(false);
@@ -1163,6 +1317,8 @@ function HumanInputForm({
1163
1317
  QuestionControls,
1164
1318
  {
1165
1319
  question,
1320
+ questionNumber: null,
1321
+ labelledBy: titleId,
1166
1322
  draft: drafts[question.id] ?? emptyDraft(),
1167
1323
  fieldId: `${formId}-${index}`,
1168
1324
  error: validationErrors[question.id],
@@ -1185,6 +1341,8 @@ function HumanInputForm({
1185
1341
  QuestionControls,
1186
1342
  {
1187
1343
  question,
1344
+ questionNumber: index + 1,
1345
+ labelledBy: void 0,
1188
1346
  draft: drafts[question.id] ?? emptyDraft(),
1189
1347
  fieldId: `${formId}-${index}`,
1190
1348
  error: validationErrors[question.id],
@@ -1239,7 +1397,7 @@ function HumanInputForm({
1239
1397
  {
1240
1398
  type: "submit",
1241
1399
  disabled: busy,
1242
- className: "inline-flex min-h-9 items-center rounded-og-md bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg transition-colors hover:bg-og-accent-strong disabled:opacity-50",
1400
+ className: "inline-flex min-h-9 items-center rounded-og-md bg-og-accent-deep px-3 py-1.5 text-og-sm font-medium text-og-accent-fg transition hover:brightness-110 disabled:opacity-50",
1243
1401
  children: busy ? messages.submitting : resolvedSubmitLabel
1244
1402
  }
1245
1403
  )
@@ -1250,6 +1408,8 @@ function HumanInputForm({
1250
1408
  }
1251
1409
  function QuestionControls({
1252
1410
  question,
1411
+ questionNumber,
1412
+ labelledBy,
1253
1413
  draft,
1254
1414
  fieldId,
1255
1415
  error,
@@ -1263,11 +1423,19 @@ function QuestionControls({
1263
1423
  }) {
1264
1424
  const errorId = `${fieldId}-error`;
1265
1425
  const helpId = `${fieldId}-help`;
1426
+ const labelId = `${fieldId}-label`;
1427
+ const promptId = `${fieldId}-prompt`;
1428
+ const otherChoiceId = `${fieldId}-other-choice`;
1429
+ const otherLabelId = `${fieldId}-other-label`;
1430
+ const otherTextId = `${fieldId}-other-text`;
1431
+ const visibleLabel = question.label ?? question.prompt;
1432
+ const controlLabelId = showPromptChrome ? labelId : labelledBy;
1266
1433
  const hint = question.kind === "multi_select" ? messages.selectionHint(
1267
1434
  question.validation?.minSelections,
1268
1435
  question.validation?.maxSelections
1269
1436
  ) : null;
1270
1437
  const describedBy = [
1438
+ question.label && showPromptChrome ? promptId : null,
1271
1439
  question.helpText && showPromptChrome ? helpId : null,
1272
1440
  hint ? `${fieldId}-hint` : null,
1273
1441
  error ? errorId : null
@@ -1277,15 +1445,21 @@ function QuestionControls({
1277
1445
  /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap items-baseline gap-x-2", children: /* @__PURE__ */ jsxs3(
1278
1446
  "label",
1279
1447
  {
1448
+ id: labelId,
1280
1449
  htmlFor: question.kind === "text" ? fieldId : void 0,
1281
1450
  className: "text-og-sm font-medium text-og-fg",
1282
1451
  children: [
1283
- question.label ?? question.prompt,
1452
+ questionNumber === null ? null : /* @__PURE__ */ jsxs3("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
1453
+ questionNumber,
1454
+ "."
1455
+ ] }),
1456
+ questionNumber === null ? null : " ",
1457
+ visibleLabel,
1284
1458
  question.required && !allowSkip ? /* @__PURE__ */ jsx3("span", { "aria-hidden": true, className: "ml-1 text-og-status-failed", children: "*" }) : !question.required ? /* @__PURE__ */ jsx3("span", { className: "ml-1.5 text-og-xs font-normal text-og-fg-subtle", children: messages.optional }) : null
1285
1459
  ]
1286
1460
  }
1287
1461
  ) }),
1288
- question.label ? /* @__PURE__ */ jsx3("p", { className: "text-og-sm text-og-fg-muted", children: question.prompt }) : null,
1462
+ question.label ? /* @__PURE__ */ jsx3("p", { id: promptId, className: "text-og-sm text-og-fg-muted", children: question.prompt }) : null,
1289
1463
  question.helpText ? /* @__PURE__ */ jsx3("p", { id: helpId, className: "text-og-xs text-og-fg-subtle", children: question.helpText }) : null,
1290
1464
  hint ? /* @__PURE__ */ jsx3("p", { id: `${fieldId}-hint`, className: "text-og-xs text-og-fg-subtle", children: hint }) : null
1291
1465
  ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
@@ -1303,6 +1477,7 @@ function QuestionControls({
1303
1477
  values: event.target.value ? [event.target.value] : []
1304
1478
  })),
1305
1479
  "aria-invalid": Boolean(error),
1480
+ "aria-labelledby": controlLabelId,
1306
1481
  "aria-describedby": describedBy,
1307
1482
  autoFocus,
1308
1483
  rows: 2,
@@ -1312,6 +1487,7 @@ function QuestionControls({
1312
1487
  "div",
1313
1488
  {
1314
1489
  role: question.kind === "single_select" ? "radiogroup" : "group",
1490
+ "aria-labelledby": controlLabelId,
1315
1491
  "aria-describedby": describedBy,
1316
1492
  className: "flex flex-col gap-0.5",
1317
1493
  children: [
@@ -1349,8 +1525,8 @@ function QuestionControls({
1349
1525
  option.id
1350
1526
  );
1351
1527
  }),
1352
- question.allowOther ? /* @__PURE__ */ jsxs3(
1353
- "label",
1528
+ /* @__PURE__ */ jsxs3(
1529
+ "div",
1354
1530
  {
1355
1531
  className: cn(
1356
1532
  "flex items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
@@ -1360,8 +1536,10 @@ function QuestionControls({
1360
1536
  /* @__PURE__ */ jsx3(
1361
1537
  "input",
1362
1538
  {
1539
+ id: otherChoiceId,
1363
1540
  type: question.kind === "single_select" ? "radio" : "checkbox",
1364
1541
  name: question.kind === "single_select" ? fieldId : void 0,
1542
+ "aria-labelledby": otherLabelId,
1365
1543
  checked: draft.otherSelected,
1366
1544
  autoFocus: autoFocus && firstOption && question.options.length === 0,
1367
1545
  onChange: (event) => onUpdate((current) => ({
@@ -1373,10 +1551,24 @@ function QuestionControls({
1373
1551
  }
1374
1552
  ),
1375
1553
  /* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1", children: [
1376
- /* @__PURE__ */ jsx3("span", { className: "block text-og-sm font-medium", children: messages.other }),
1554
+ /* @__PURE__ */ jsx3(
1555
+ "label",
1556
+ {
1557
+ id: otherLabelId,
1558
+ htmlFor: otherChoiceId,
1559
+ className: "block text-og-sm font-medium",
1560
+ children: messages.other
1561
+ }
1562
+ ),
1563
+ /* @__PURE__ */ jsxs3("label", { htmlFor: otherTextId, className: "sr-only", children: [
1564
+ messages.other,
1565
+ " answer for ",
1566
+ visibleLabel
1567
+ ] }),
1377
1568
  /* @__PURE__ */ jsx3(
1378
1569
  "input",
1379
1570
  {
1571
+ id: otherTextId,
1380
1572
  type: "text",
1381
1573
  value: draft.other,
1382
1574
  disabled: !draft.otherSelected || busy,
@@ -1391,7 +1583,7 @@ function QuestionControls({
1391
1583
  ] })
1392
1584
  ]
1393
1585
  }
1394
- ) : null
1586
+ )
1395
1587
  ]
1396
1588
  }
1397
1589
  ),
@@ -1405,9 +1597,10 @@ function answersFromDrafts(questions, drafts, messageOverrides = {}) {
1405
1597
  for (const question of questions) {
1406
1598
  const draft = drafts[question.id] ?? emptyDraft();
1407
1599
  const values = question.kind === "text" ? draft.values.filter(Boolean) : draft.values;
1408
- const other = draft.otherSelected ? draft.other.trim() : "";
1409
- const supplied = values.length + (other ? 1 : 0);
1410
- if (question.kind !== "text" && draft.otherSelected && !other) {
1600
+ const other = draft.otherSelected ? draft.other : "";
1601
+ const hasOther = Boolean(other.trim());
1602
+ const supplied = values.length + (hasOther ? 1 : 0);
1603
+ if (question.kind !== "text" && draft.otherSelected && !hasOther) {
1411
1604
  errors[question.id] = messages.otherRequired;
1412
1605
  continue;
1413
1606
  }
@@ -1431,7 +1624,7 @@ function answersFromDrafts(questions, drafts, messageOverrides = {}) {
1431
1624
  answers.push({
1432
1625
  questionId: question.id,
1433
1626
  values,
1434
- ...other ? { other } : {}
1627
+ ...hasOther ? { other } : {}
1435
1628
  });
1436
1629
  }
1437
1630
  }
@@ -2018,7 +2211,7 @@ function useForcedDefaultOpen() {
2018
2211
  }
2019
2212
 
2020
2213
  // src/timeline/screenshot-lightbox.tsx
2021
- import { XIcon as XIcon2 } from "lucide-react";
2214
+ import { DownloadIcon, XIcon as XIcon2 } from "lucide-react";
2022
2215
  import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion/react";
2023
2216
  import { createContext as createContext2, useCallback, useContext as useContext2, useMemo as useMemo3, useState as useState3 } from "react";
2024
2217
  import { Dialog } from "radix-ui";
@@ -2044,9 +2237,14 @@ function LightboxRoot({ children }) {
2044
2237
  const [tokenSource, setTokenSource] = useState3(null);
2045
2238
  const portalStyle = usePortalTokenStyle(tokenSource);
2046
2239
  const open = useCallback(
2047
- (src, caption, source, label = "Screenshot") => {
2240
+ (src, caption, source, label = "Screenshot", downloadFilename) => {
2048
2241
  setTokenSource(source ?? null);
2049
- setState(caption ? { src, caption, label } : { src, label });
2242
+ setState({
2243
+ src,
2244
+ label,
2245
+ ...caption ? { caption } : {},
2246
+ ...downloadFilename ? { downloadFilename } : {}
2247
+ });
2050
2248
  },
2051
2249
  []
2052
2250
  );
@@ -2103,18 +2301,34 @@ function LightboxRoot({ children }) {
2103
2301
  className: "min-h-0 max-h-[82vh] w-auto max-w-full rounded-og-md border border-white/10 object-contain shadow-og-lg"
2104
2302
  }
2105
2303
  ),
2106
- /* @__PURE__ */ jsx6(
2107
- Dialog.Close,
2108
- {
2109
- className: cn(
2110
- "absolute -right-3 -top-3 inline-flex size-9 items-center justify-center rounded-full",
2111
- "border border-white/15 bg-black/60 text-white/70 backdrop-blur",
2112
- "transition-colors hover:border-white/30 hover:text-white"
2113
- ),
2114
- "aria-label": "Close",
2115
- children: /* @__PURE__ */ jsx6(XIcon2, { className: "size-4" })
2116
- }
2117
- )
2304
+ /* @__PURE__ */ jsxs4("div", { className: "absolute -right-3 -top-3 flex items-center gap-2", children: [
2305
+ state.downloadFilename ? /* @__PURE__ */ jsx6(
2306
+ "a",
2307
+ {
2308
+ href: state.src,
2309
+ download: state.downloadFilename,
2310
+ className: cn(
2311
+ "inline-flex size-9 items-center justify-center rounded-full",
2312
+ "border border-white/15 bg-black/60 text-white/70 backdrop-blur",
2313
+ "transition-colors hover:border-white/30 hover:text-white"
2314
+ ),
2315
+ "aria-label": `Download ${state.downloadFilename}`,
2316
+ children: /* @__PURE__ */ jsx6(DownloadIcon, { className: "size-4" })
2317
+ }
2318
+ ) : null,
2319
+ /* @__PURE__ */ jsx6(
2320
+ Dialog.Close,
2321
+ {
2322
+ className: cn(
2323
+ "inline-flex size-9 items-center justify-center rounded-full",
2324
+ "border border-white/15 bg-black/60 text-white/70 backdrop-blur",
2325
+ "transition-colors hover:border-white/30 hover:text-white"
2326
+ ),
2327
+ "aria-label": "Close",
2328
+ children: /* @__PURE__ */ jsx6(XIcon2, { className: "size-4" })
2329
+ }
2330
+ )
2331
+ ] })
2118
2332
  ] }),
2119
2333
  state.caption ? /* @__PURE__ */ jsx6("figcaption", { className: "max-w-2xl text-center font-og-mono text-og-xs text-white/55", children: state.caption }) : /* @__PURE__ */ jsx6("figcaption", { className: "font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35", children: "Esc or click outside to close" })
2120
2334
  ] })
@@ -2364,7 +2578,8 @@ function Thumbnail({
2364
2578
  caption,
2365
2579
  alt = "screenshot",
2366
2580
  expandLabel = "Expand screenshot",
2367
- lightboxLabel = "Screenshot"
2581
+ lightboxLabel = "Screenshot",
2582
+ downloadFilename
2368
2583
  }) {
2369
2584
  const lightbox = useLightboxOptional();
2370
2585
  const [failed, setFailed] = useState4(false);
@@ -2389,7 +2604,7 @@ function Thumbnail({
2389
2604
  type: "button",
2390
2605
  onClick: (event) => {
2391
2606
  event.stopPropagation();
2392
- lightbox.open(src, caption, event.currentTarget, lightboxLabel);
2607
+ lightbox.open(src, caption, event.currentTarget, lightboxLabel, downloadFilename);
2393
2608
  },
2394
2609
  onKeyDown: (event) => {
2395
2610
  if (event.key === "Enter" || event.key === " ") {
@@ -2411,7 +2626,8 @@ function ScreenshotFigure({
2411
2626
  caption,
2412
2627
  alt = "screenshot",
2413
2628
  expandLabel = "Expand screenshot",
2414
- lightboxLabel = "Screenshot"
2629
+ lightboxLabel = "Screenshot",
2630
+ downloadFilename
2415
2631
  }) {
2416
2632
  const lightbox = useLightboxOptional();
2417
2633
  const [failed, setFailed] = useState4(false);
@@ -2430,7 +2646,7 @@ function ScreenshotFigure({
2430
2646
  "button",
2431
2647
  {
2432
2648
  type: "button",
2433
- onClick: (event) => lightbox.open(src, caption, event.currentTarget, lightboxLabel),
2649
+ onClick: (event) => lightbox.open(src, caption, event.currentTarget, lightboxLabel, downloadFilename),
2434
2650
  className: surface,
2435
2651
  "aria-label": expandLabel,
2436
2652
  children: img
@@ -2593,12 +2809,16 @@ function PlainPatch({ diff }) {
2593
2809
  }
2594
2810
 
2595
2811
  // src/timeline/tool-renderers.tsx
2812
+ import {
2813
+ parseSandboxFileArtifactReceipt
2814
+ } from "@opengeni/sdk";
2596
2815
  import {
2597
2816
  BoxIcon,
2598
2817
  BrainCircuitIcon,
2599
2818
  CalendarClockIcon,
2600
2819
  CameraIcon as CameraIcon2,
2601
2820
  CameraOffIcon as CameraOffIcon2,
2821
+ DownloadIcon as DownloadIcon2,
2602
2822
  FileDiffIcon,
2603
2823
  FileSearchIcon,
2604
2824
  FolderGitIcon,
@@ -3326,6 +3546,7 @@ function RetainedSessionImageDisclosure({
3326
3546
  cancelled
3327
3547
  }) {
3328
3548
  const state = useRetainedImageObjectUrl(artifact, load);
3549
+ const downloadFilename = retainedImageFilename(artifact);
3329
3550
  return /* @__PURE__ */ jsxs7(
3330
3551
  ActivityDisclosure,
3331
3552
  {
@@ -3342,7 +3563,8 @@ function RetainedSessionImageDisclosure({
3342
3563
  caption,
3343
3564
  alt: caption,
3344
3565
  expandLabel: `Expand ${noun}`,
3345
- lightboxLabel
3566
+ lightboxLabel,
3567
+ downloadFilename
3346
3568
  }
3347
3569
  ) : state.kind === "loading" ? /* @__PURE__ */ jsx10(MediaSkeleton, {}) : /* @__PURE__ */ jsx10(MediaEmpty, {}),
3348
3570
  children: [
@@ -3353,7 +3575,8 @@ function RetainedSessionImageDisclosure({
3353
3575
  caption,
3354
3576
  alt: caption,
3355
3577
  expandLabel: `Expand ${noun}`,
3356
- lightboxLabel
3578
+ lightboxLabel,
3579
+ downloadFilename
3357
3580
  }
3358
3581
  ) : state.kind === "loading" ? /* @__PURE__ */ jsxs7(BodyNote, { children: [
3359
3582
  "Loading the retained ",
@@ -3433,6 +3656,77 @@ function GeneratedVideoRenderer({ item }) {
3433
3656
  }
3434
3657
  );
3435
3658
  }
3659
+ function SandboxFilePublishRenderer({ item, loadRetainedArtifact }) {
3660
+ const { text: output, isError } = unwrapMcpOutput(item.output);
3661
+ const receipt = parseSandboxFileArtifactReceipt(output);
3662
+ const [downloadState, setDownloadState] = useState8("idle");
3663
+ if (item.status === "running") {
3664
+ return /* @__PURE__ */ jsx10(
3665
+ ActivityDisclosure,
3666
+ {
3667
+ icon: /* @__PURE__ */ jsx10(DownloadIcon2, { className: ICON_SIZE }),
3668
+ iconTone: "running",
3669
+ title: "Publishing file",
3670
+ running: true,
3671
+ preview: /* @__PURE__ */ jsx10(RunningPreview, { children: "retaining workspace bytes\u2026" })
3672
+ }
3673
+ );
3674
+ }
3675
+ if (!receipt || isError || item.status === "failed") {
3676
+ return /* @__PURE__ */ jsx10(GenericRenderer, { item });
3677
+ }
3678
+ const download = async () => {
3679
+ if (!loadRetainedArtifact) {
3680
+ setDownloadState("error");
3681
+ return;
3682
+ }
3683
+ setDownloadState("loading");
3684
+ let objectUrl = null;
3685
+ try {
3686
+ const source = await loadRetainedArtifact(receipt.artifact, new AbortController().signal);
3687
+ if (!source) throw new Error("artifact unavailable");
3688
+ const url = source instanceof Uint8Array ? objectUrl = URL.createObjectURL(
3689
+ new Blob([source], {
3690
+ type: receipt.artifact.contentType
3691
+ })
3692
+ ) : source.url;
3693
+ const anchor = document.createElement("a");
3694
+ anchor.href = url;
3695
+ anchor.download = receipt.filename;
3696
+ anchor.rel = "noopener";
3697
+ anchor.click();
3698
+ setDownloadState("idle");
3699
+ } catch {
3700
+ setDownloadState("error");
3701
+ } finally {
3702
+ const urlToRevoke = objectUrl;
3703
+ if (urlToRevoke) setTimeout(() => URL.revokeObjectURL(urlToRevoke), 0);
3704
+ }
3705
+ };
3706
+ return /* @__PURE__ */ jsx10(
3707
+ ActivityDisclosure,
3708
+ {
3709
+ icon: /* @__PURE__ */ jsx10(DownloadIcon2, { className: ICON_SIZE }),
3710
+ iconTone: "accent",
3711
+ title: `Published ${receipt.filename}`,
3712
+ defaultOpen: true,
3713
+ preview: formatBytes(receipt.artifact.originalBytes),
3714
+ children: /* @__PURE__ */ jsxs7(
3715
+ "button",
3716
+ {
3717
+ type: "button",
3718
+ onClick: () => void download(),
3719
+ disabled: downloadState === "loading",
3720
+ className: "inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2.5 py-1.5 text-og-sm font-medium text-og-fg transition-colors hover:border-og-border-strong hover:bg-og-surface-2 disabled:cursor-wait disabled:opacity-60",
3721
+ children: [
3722
+ /* @__PURE__ */ jsx10(DownloadIcon2, { className: "size-3.5" }),
3723
+ downloadState === "loading" ? "Preparing\u2026" : downloadState === "error" ? "Retry download" : "Download"
3724
+ ]
3725
+ }
3726
+ )
3727
+ }
3728
+ );
3729
+ }
3436
3730
  function GeneratedImageDisclosure({
3437
3731
  receipt,
3438
3732
  load,
@@ -3490,6 +3784,10 @@ function GeneratedImageDisclosure({
3490
3784
  }
3491
3785
  );
3492
3786
  }
3787
+ function retainedImageFilename(artifact) {
3788
+ const extension = artifact.contentType === "image/jpeg" ? "jpg" : artifact.contentType === "image/webp" ? "webp" : "png";
3789
+ return `${artifact.kind}-${artifact.artifactId}.${extension}`;
3790
+ }
3493
3791
  function webSearchQueryFromArguments(args) {
3494
3792
  if (typeof args === "string") {
3495
3793
  const trimmed = args.trim();
@@ -4321,14 +4619,14 @@ function GenericRenderer({ item }) {
4321
4619
  }
4322
4620
  function goalToolPreview(name, args) {
4323
4621
  const leaf = mcpToolLeaf(name);
4324
- if (leaf !== "goal_set" && leaf !== "goal_update" && leaf !== "goal_complete" && leaf !== "goal_pause") {
4622
+ if (leaf !== "goal_set" && leaf !== "goal_update" && leaf !== "goal_complete" && leaf !== "goal_pause" && leaf !== "goal_wait") {
4325
4623
  return null;
4326
4624
  }
4327
4625
  const record = args && typeof args === "object" ? args : null;
4328
4626
  if (!record) {
4329
4627
  return null;
4330
4628
  }
4331
- const text = typeof record.text === "string" ? record.text : typeof record.evidence === "string" ? record.evidence : typeof record.rationale === "string" ? record.rationale : typeof record.progressNote === "string" ? record.progressNote : null;
4629
+ const text = typeof record.text === "string" ? record.text : typeof record.evidence === "string" ? record.evidence : typeof record.rationale === "string" ? record.rationale : typeof record.reason === "string" ? record.reason : typeof record.progressNote === "string" ? record.progressNote : null;
4332
4630
  return text ? truncatePreview(text, 90) : null;
4333
4631
  }
4334
4632
  function truncatePreview(text, max) {
@@ -4372,6 +4670,7 @@ var BASE_ENTRIES = [
4372
4670
  { match: "name", name: "generate_video", render: GeneratedVideoRenderer },
4373
4671
  { match: "name", name: "tool_search", render: ToolSearchRenderer },
4374
4672
  { match: "name", name: "view_image", render: ViewImageRenderer },
4673
+ { match: "name", name: "sandbox_file_publish", render: SandboxFilePublishRenderer },
4375
4674
  { match: "name", name: "environment_set_variable", render: SecretSetRenderer },
4376
4675
  { match: "name", name: "variable_set_set_variable", render: SecretSetRenderer },
4377
4676
  { match: "name", name: "search_documents", render: DocsSearchRenderer },
@@ -4386,7 +4685,7 @@ function createDefaultToolRegistry(options = {}) {
4386
4685
  }
4387
4686
 
4388
4687
  // src/components/copy-button.tsx
4389
- import { CheckIcon, CopyIcon } from "lucide-react";
4688
+ import { CheckIcon as CheckIcon2, CopyIcon } from "lucide-react";
4390
4689
  import { useEffect as useEffect7, useRef as useRef5, useState as useState9 } from "react";
4391
4690
  import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4392
4691
  var COPIED_MS = 1600;
@@ -4458,7 +4757,7 @@ function CopyButton({
4458
4757
  copied && "opacity-100 text-og-accent",
4459
4758
  className
4460
4759
  ),
4461
- children: copied ? /* @__PURE__ */ jsx11(CheckIcon, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx11(CopyIcon, { className: "size-3.5", "aria-hidden": true })
4760
+ children: copied ? /* @__PURE__ */ jsx11(CheckIcon2, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx11(CopyIcon, { className: "size-3.5", "aria-hidden": true })
4462
4761
  }
4463
4762
  ) }),
4464
4763
  /* @__PURE__ */ jsx11(TooltipContent, { side: "top", children: tip })
@@ -4501,11 +4800,14 @@ import {
4501
4800
  isValidElement,
4502
4801
  memo,
4503
4802
  useEffect as useEffect8,
4803
+ useMemo as useMemo4,
4504
4804
  useReducer,
4505
4805
  useRef as useRef6,
4506
4806
  useState as useState10
4507
4807
  } from "react";
4508
- import ReactMarkdown from "react-markdown";
4808
+ import ReactMarkdown, {
4809
+ defaultUrlTransform
4810
+ } from "react-markdown";
4509
4811
  import remarkGfm from "remark-gfm";
4510
4812
 
4511
4813
  // src/lib/motion.ts
@@ -4789,7 +5091,7 @@ function rehypeStreamReveal(options) {
4789
5091
 
4790
5092
  // src/components/markdown.tsx
4791
5093
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
4792
- var components = {
5094
+ var baseComponents = {
4793
5095
  h1: ({ children, ...props }) => /* @__PURE__ */ jsx12(
4794
5096
  "h1",
4795
5097
  {
@@ -4818,16 +5120,6 @@ var components = {
4818
5120
  p: ({ children, ...props }) => /* @__PURE__ */ jsx12("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
4819
5121
  strong: ({ children, ...props }) => /* @__PURE__ */ jsx12("strong", { className: "font-semibold text-og-fg", ...props, children }),
4820
5122
  em: ({ children, ...props }) => /* @__PURE__ */ jsx12("em", { className: "italic", ...props, children }),
4821
- a: ({ children, ...props }) => /* @__PURE__ */ jsx12(
4822
- "a",
4823
- {
4824
- className: "break-words font-medium text-og-accent-strong underline-offset-2 hover:underline",
4825
- target: "_blank",
4826
- rel: "noreferrer noopener",
4827
- ...props,
4828
- children
4829
- }
4830
- ),
4831
5123
  ul: ({ children, ...props }) => /* @__PURE__ */ jsx12(
4832
5124
  "ul",
4833
5125
  {
@@ -4905,15 +5197,125 @@ var components = {
4905
5197
  children
4906
5198
  }
4907
5199
  ),
4908
- img: ({ alt, ...props }) => /* @__PURE__ */ jsx12(
5200
+ img: ({ alt, src, ...props }) => src ? /* @__PURE__ */ jsx12(
4909
5201
  "img",
4910
5202
  {
4911
5203
  alt: alt ?? "",
5204
+ src,
4912
5205
  className: "my-3 max-w-full rounded-og-md border border-og-border",
4913
5206
  ...props
4914
5207
  }
4915
- )
5208
+ ) : alt ? /* @__PURE__ */ jsx12("span", { className: "text-og-fg-subtle", "aria-disabled": "true", children: alt }) : null
4916
5209
  };
5210
+ var MARKDOWN_LINK_CLASS = "break-words font-medium text-og-accent-strong underline-offset-2 hover:underline";
5211
+ function markdownComponents(onSandboxFile) {
5212
+ return {
5213
+ ...baseComponents,
5214
+ a: ({ children, href, ...props }) => {
5215
+ const location = sandboxFileLocationFromHref(href);
5216
+ if (location !== null) {
5217
+ return /* @__PURE__ */ jsx12(SandboxMarkdownLink, { location, onSandboxFile, children });
5218
+ }
5219
+ if (isSandboxHref(href) || !href) {
5220
+ return /* @__PURE__ */ jsx12(
5221
+ "span",
5222
+ {
5223
+ className: "break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2",
5224
+ "aria-disabled": "true",
5225
+ title: isSandboxHref(href) ? "This sandbox file reference is invalid" : "This link is unavailable",
5226
+ children
5227
+ }
5228
+ );
5229
+ }
5230
+ return /* @__PURE__ */ jsx12(
5231
+ "a",
5232
+ {
5233
+ className: MARKDOWN_LINK_CLASS,
5234
+ target: "_blank",
5235
+ rel: "noreferrer noopener",
5236
+ href,
5237
+ ...props,
5238
+ children
5239
+ }
5240
+ );
5241
+ }
5242
+ };
5243
+ }
5244
+ function SandboxMarkdownLink({
5245
+ location,
5246
+ onSandboxFile,
5247
+ children
5248
+ }) {
5249
+ const [state, setState] = useState10("idle");
5250
+ const { path, line } = location;
5251
+ if (!onSandboxFile) {
5252
+ return /* @__PURE__ */ jsx12(
5253
+ "span",
5254
+ {
5255
+ className: "break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2",
5256
+ "aria-disabled": "true",
5257
+ title: "This sandbox file requires a session-aware handler",
5258
+ children
5259
+ }
5260
+ );
5261
+ }
5262
+ const idleTitle = line !== null ? `Open ${path} at line ${line}` : `Open ${path}`;
5263
+ return /* @__PURE__ */ jsxs9(
5264
+ "button",
5265
+ {
5266
+ type: "button",
5267
+ className: cn(
5268
+ MARKDOWN_LINK_CLASS,
5269
+ "inline-flex min-h-7 cursor-pointer items-center disabled:cursor-wait disabled:opacity-70 pointer-coarse:min-h-11"
5270
+ ),
5271
+ disabled: state === "loading",
5272
+ "aria-busy": state === "loading",
5273
+ title: state === "error" ? "Couldn't open this file. Select to retry." : idleTitle,
5274
+ onClick: () => {
5275
+ setState("loading");
5276
+ void Promise.resolve(onSandboxFile(path, line ?? void 0)).then(
5277
+ () => setState("idle"),
5278
+ () => setState("error")
5279
+ );
5280
+ },
5281
+ children: [
5282
+ children,
5283
+ state === "loading" ? " (opening\u2026)" : state === "error" ? " (retry)" : null
5284
+ ]
5285
+ }
5286
+ );
5287
+ }
5288
+ var SANDBOX_SCHEME = "sandbox:";
5289
+ var LEGACY_WORKSPACE_PREFIX = "/workspace/";
5290
+ var TRAILING_LINE = /:([0-9]+)$/u;
5291
+ var TRAILING_INVALID_LINE = /:-(?:[0-9]+)$|:[0-9]+-[0-9]+$/u;
5292
+ var CONTROL_CHARACTER = /[\u0000-\u001f\u007f]/u;
5293
+ function isSandboxHref(href) {
5294
+ return href?.startsWith(SANDBOX_SCHEME) ?? false;
5295
+ }
5296
+ function sandboxFileLocationFromHref(href) {
5297
+ if (!href) return null;
5298
+ const encodedLocation = isSandboxHref(href) ? href.slice(SANDBOX_SCHEME.length) : href.startsWith(LEGACY_WORKSPACE_PREFIX) ? href : null;
5299
+ if (!encodedLocation || encodedLocation.includes("?") || encodedLocation.includes("#")) {
5300
+ return null;
5301
+ }
5302
+ if (TRAILING_INVALID_LINE.test(encodedLocation)) return null;
5303
+ const lineMatch = TRAILING_LINE.exec(encodedLocation);
5304
+ const encodedPath = lineMatch ? encodedLocation.slice(0, -lineMatch[0].length) : encodedLocation;
5305
+ const line = lineMatch?.[1] ? Number(lineMatch[1]) : null;
5306
+ if (line !== null && (!Number.isSafeInteger(line) || line < 1)) return null;
5307
+ if (!encodedPath) return null;
5308
+ try {
5309
+ const path = decodeURIComponent(encodedPath);
5310
+ return path && !CONTROL_CHARACTER.test(path) ? { path, line } : null;
5311
+ } catch {
5312
+ return null;
5313
+ }
5314
+ }
5315
+ function sandboxFilePathFromHref(href) {
5316
+ return sandboxFileLocationFromHref(href)?.path ?? null;
5317
+ }
5318
+ var markdownUrlTransform = (url, key, node) => key === "href" && node.tagName === "a" && isSandboxHref(url) ? url : defaultUrlTransform(url);
4917
5319
  var REVEAL_LINGER_MS = 480 * MOTION_INSPECT_SCALE;
4918
5320
  var MARKDOWN_SETTLE_MS = 480 * MOTION_INSPECT_SCALE;
4919
5321
  function nodeText(node) {
@@ -4984,7 +5386,7 @@ function MarkdownTable({ children, className, ...props }) {
4984
5386
  ) })
4985
5387
  ] });
4986
5388
  }
4987
- function MarkdownImpl({ children, className, streaming = false }) {
5389
+ function MarkdownImpl({ children, className, streaming = false, onSandboxFile }) {
4988
5390
  const revealRef = useRef6(null);
4989
5391
  const bodyRef = useRef6(null);
4990
5392
  const [, bump] = useReducer((n) => n + 1, 0);
@@ -5047,6 +5449,7 @@ function MarkdownImpl({ children, className, streaming = false }) {
5047
5449
  return () => clearTimeout(timer);
5048
5450
  }, [streaming]);
5049
5451
  const parseText = streaming || revealActive ? softenStreamingMarkdown(children) : children;
5452
+ const components = useMemo4(() => markdownComponents(onSandboxFile), [onSandboxFile]);
5050
5453
  return /* @__PURE__ */ jsx12(TooltipProvider, { delayDuration: 400, children: /* @__PURE__ */ jsx12(
5051
5454
  "div",
5052
5455
  {
@@ -5062,6 +5465,7 @@ function MarkdownImpl({ children, className, streaming = false }) {
5062
5465
  remarkPlugins: [remarkGfm],
5063
5466
  rehypePlugins,
5064
5467
  components,
5468
+ urlTransform: markdownUrlTransform,
5065
5469
  children: parseText
5066
5470
  }
5067
5471
  )
@@ -5071,14 +5475,8 @@ function MarkdownImpl({ children, className, streaming = false }) {
5071
5475
  var Markdown = memo(MarkdownImpl);
5072
5476
 
5073
5477
  // src/timeline/activity-rail.tsx
5074
- import {
5075
- ArrowRightIcon,
5076
- BotIcon as BotIcon2,
5077
- BrainCircuitIcon as BrainCircuitIcon2,
5078
- BrainIcon,
5079
- SquareTerminalIcon
5080
- } from "lucide-react";
5081
- import { lazy as lazy3, Suspense as Suspense3, useLayoutEffect as useLayoutEffect2, useRef as useRef8 } from "react";
5478
+ import { ArrowRightIcon, BotIcon as BotIcon2, BrainCircuitIcon as BrainCircuitIcon2 } from "lucide-react";
5479
+ import { lazy as lazy3, Suspense as Suspense3, useLayoutEffect, useRef as useRef8 } from "react";
5082
5480
  import { jsx as rowJsx, jsxs as rowJsxs } from "react/jsx-runtime";
5083
5481
 
5084
5482
  // src/timeline/entrance.tsx
@@ -5105,6 +5503,7 @@ function useSeenActivityIds() {
5105
5503
  // src/timeline/activity-rail.tsx
5106
5504
  import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
5107
5505
  var LazyFleetDecisionRow = lazy3(() => import("./fleet-decision-row-GGCAT4E4.js"));
5506
+ var LazyPlatformActivityRow = lazy3(() => import("./platform-activity-row-BJHUHXAT.js"));
5108
5507
  function familyOf(item) {
5109
5508
  if (item.kind === "tool-call") {
5110
5509
  return item.name === "exec_command" || item.name === "write_stdin" ? "terminal" : item.name;
@@ -5138,7 +5537,7 @@ function ActivityRail({
5138
5537
  }
5139
5538
  }
5140
5539
  }
5141
- useLayoutEffect2(() => {
5540
+ useLayoutEffect(() => {
5142
5541
  previousIdsRef.current = new Set(items.map((item) => item.id));
5143
5542
  if (seenIds) {
5144
5543
  for (const item of items) {
@@ -5190,7 +5589,22 @@ function assertNever(item) {
5190
5589
  function renderActivity(item, toolRegistry, onOpenSession, onMemoryClick, loadRetainedScreenshot, loadRetainedArtifact) {
5191
5590
  switch (item.kind) {
5192
5591
  case "reasoning":
5193
- return /* @__PURE__ */ jsx13(ReasoningRow, { item });
5592
+ case "sandbox":
5593
+ case "startup-phase":
5594
+ return /* @__PURE__ */ jsx13(Suspense3, { fallback: null, children: /* @__PURE__ */ jsx13(
5595
+ LazyPlatformActivityRow,
5596
+ {
5597
+ item,
5598
+ d: ActivityDisclosure,
5599
+ p: PayloadBlock,
5600
+ t: toolDisplayName,
5601
+ b: BotIcon2,
5602
+ m: Markdown,
5603
+ r: truncate,
5604
+ j: rowJsx,
5605
+ s: rowJsxs
5606
+ }
5607
+ ) });
5194
5608
  case "tool-call": {
5195
5609
  const Renderer = toolRegistry.resolve(item);
5196
5610
  return /* @__PURE__ */ jsx13(ToolCallTruncationProvider, { value: item.truncation ?? null, children: /* @__PURE__ */ jsx13(
@@ -5204,8 +5618,6 @@ function renderActivity(item, toolRegistry, onOpenSession, onMemoryClick, loadRe
5204
5618
  }
5205
5619
  case "worker":
5206
5620
  return /* @__PURE__ */ jsx13(WorkerRow, { item, onOpenSession });
5207
- case "sandbox":
5208
- return /* @__PURE__ */ jsx13(SandboxRow, { item });
5209
5621
  case "memory":
5210
5622
  return /* @__PURE__ */ jsx13(MemoryRow, { item, onMemoryClick });
5211
5623
  case "fleet-decision":
@@ -5223,19 +5635,6 @@ function renderActivity(item, toolRegistry, onOpenSession, onMemoryClick, loadRe
5223
5635
  return assertNever(item);
5224
5636
  }
5225
5637
  }
5226
- function ReasoningRow({ item }) {
5227
- return /* @__PURE__ */ jsx13(
5228
- ActivityDisclosure,
5229
- {
5230
- icon: /* @__PURE__ */ jsx13(BrainIcon, { className: "size-3.5" }),
5231
- iconTone: "muted",
5232
- title: item.streaming ? "Thinking" : /* @__PURE__ */ jsx13("span", { className: "font-normal italic text-og-fg-subtle", children: "Thought" }),
5233
- running: item.streaming,
5234
- preview: truncate(item.text, 110),
5235
- children: /* @__PURE__ */ jsx13("div", { className: "text-og-base leading-6 text-og-fg-muted [&_strong]:text-og-fg-muted", children: /* @__PURE__ */ jsx13(Markdown, { streaming: item.streaming, children: item.text }) })
5236
- }
5237
- );
5238
- }
5239
5638
  var MEMORY_KIND_LABEL = {
5240
5639
  preference: "Preference",
5241
5640
  semantic: "Fact",
@@ -5301,35 +5700,6 @@ function MemoryRow({
5301
5700
  }
5302
5701
  );
5303
5702
  }
5304
- function sandboxRowTitle(item) {
5305
- if (item.name === "sandbox.provision") {
5306
- if (item.status === "failed") return "Sandbox didn\u2019t start";
5307
- if (item.status === "running") return "Starting sandbox";
5308
- if (item.origin === "resumed") return "Sandbox reattached";
5309
- if (item.origin === "restored") return "Sandbox restored";
5310
- if (item.origin === "created") return "Sandbox created";
5311
- return "Sandbox ready";
5312
- }
5313
- return toolDisplayName(item.name);
5314
- }
5315
- function SandboxRow({ item }) {
5316
- return /* @__PURE__ */ jsxs10(
5317
- ActivityDisclosure,
5318
- {
5319
- icon: /* @__PURE__ */ jsx13(SquareTerminalIcon, { className: "size-3.5" }),
5320
- iconTone: item.status === "failed" ? "failed" : item.status === "running" ? "running" : "muted",
5321
- title: sandboxRowTitle(item),
5322
- running: item.status === "running",
5323
- failed: item.status === "failed",
5324
- cancelled: item.status === "cancelled",
5325
- preview: item.command ?? void 0,
5326
- children: [
5327
- item.command ? /* @__PURE__ */ jsx13(PayloadBlock, { label: "Command", value: item.command }) : null,
5328
- item.output ? /* @__PURE__ */ jsx13(PayloadBlock, { label: "Output", value: item.output }) : null
5329
- ]
5330
- }
5331
- );
5332
- }
5333
5703
  function WorkerRow({
5334
5704
  item,
5335
5705
  onOpenSession
@@ -5396,7 +5766,7 @@ import {
5396
5766
  createContext as createContext8,
5397
5767
  useContext as useContext8,
5398
5768
  useEffect as useEffect9,
5399
- useMemo as useMemo4,
5769
+ useMemo as useMemo5,
5400
5770
  useRef as useRef9,
5401
5771
  useState as useState11
5402
5772
  } from "react";
@@ -5561,7 +5931,7 @@ function TurnSummary({
5561
5931
  const [allowEnterAnimation] = useState11(
5562
5932
  () => Boolean(enter && !bare && !initialSettle && !restingOpen)
5563
5933
  );
5564
- const context = useMemo4(
5934
+ const context = useMemo5(
5565
5935
  () => createTurnSummaryContext(
5566
5936
  items,
5567
5937
  outcome,
@@ -5571,11 +5941,11 @@ function TurnSummary({
5571
5941
  ),
5572
5942
  [items, outcome, failureText, durationMs, settling, settlePhase, contextCompactionCount]
5573
5943
  );
5574
- const facetDefinitions = useMemo4(
5944
+ const facetDefinitions = useMemo5(
5575
5945
  () => resolveTurnSummaryFacets(facetConfiguration),
5576
5946
  [facetConfiguration]
5577
5947
  );
5578
- const facets = useMemo4(
5948
+ const facets = useMemo5(
5579
5949
  () => facetDefinitions.flatMap((facet) => {
5580
5950
  try {
5581
5951
  const result = facet.summarize(context);
@@ -5708,7 +6078,7 @@ function createTurnSummaryContext(items, outcome, failureText, durationMs, conte
5708
6078
  if (item.kind === "reasoning") {
5709
6079
  return !item.streaming;
5710
6080
  }
5711
- if (item.kind === "tool-call" || item.kind === "worker" || item.kind === "sandbox") {
6081
+ if (item.kind === "tool-call" || item.kind === "worker" || item.kind === "sandbox" || item.kind === "startup-phase") {
5712
6082
  return item.status !== "running";
5713
6083
  }
5714
6084
  return true;
@@ -5854,7 +6224,7 @@ import {
5854
6224
  useCallback as useCallback2,
5855
6225
  useContext as useContext9,
5856
6226
  useId as useId3,
5857
- useLayoutEffect as useLayoutEffect3,
6227
+ useLayoutEffect as useLayoutEffect2,
5858
6228
  useRef as useRef10,
5859
6229
  useState as useState12
5860
6230
  } from "react";
@@ -5938,6 +6308,64 @@ function collectInteractionBoundaries(root) {
5938
6308
  function isFullyInsideVisiblePreview(rect, clipRect) {
5939
6309
  return rect.width > 0 && rect.height > 0 && rect.top >= clipRect.top - 1 && rect.bottom <= clipRect.bottom + 1 && rect.left >= clipRect.left - 1 && rect.right <= clipRect.right + 1;
5940
6310
  }
6311
+ var sharedResizeObservers = /* @__PURE__ */ new WeakMap();
6312
+ var disclosureMeasurementJobs = /* @__PURE__ */ new Map();
6313
+ var disclosureMeasurementQueued = false;
6314
+ function scheduleDisclosureMeasurement(view, key, job) {
6315
+ disclosureMeasurementJobs.set(key, job);
6316
+ if (!disclosureMeasurementQueued) {
6317
+ disclosureMeasurementQueued = true;
6318
+ view.queueMicrotask(() => {
6319
+ disclosureMeasurementQueued = false;
6320
+ const pending = [...disclosureMeasurementJobs.values()];
6321
+ disclosureMeasurementJobs.clear();
6322
+ const decisions = pending.map(({ read }) => read());
6323
+ for (let index = 0; index < pending.length; index += 1) {
6324
+ pending[index].write(decisions[index]);
6325
+ }
6326
+ });
6327
+ }
6328
+ return () => disclosureMeasurementJobs.delete(key);
6329
+ }
6330
+ function observeSharedResize(element, callback) {
6331
+ const view = element.ownerDocument.defaultView;
6332
+ if (!view || typeof ResizeObserver === "undefined") {
6333
+ return null;
6334
+ }
6335
+ let state = sharedResizeObservers.get(view);
6336
+ if (!state) {
6337
+ const callbacks = /* @__PURE__ */ new Map();
6338
+ const handleWindowResize = () => {
6339
+ for (const registered of new Set(callbacks.values())) registered();
6340
+ };
6341
+ const observer = new ResizeObserver((entries) => {
6342
+ if (entries.length === 0) {
6343
+ handleWindowResize();
6344
+ } else {
6345
+ for (const entry of entries) {
6346
+ callbacks.get(entry.target)?.();
6347
+ }
6348
+ }
6349
+ });
6350
+ view.addEventListener("resize", handleWindowResize);
6351
+ state = { callbacks, observer, handleWindowResize };
6352
+ sharedResizeObservers.set(view, state);
6353
+ }
6354
+ state.callbacks.set(element, callback);
6355
+ state.observer.observe(element);
6356
+ return () => {
6357
+ if (state.callbacks.get(element) !== callback) {
6358
+ return;
6359
+ }
6360
+ state.callbacks.delete(element);
6361
+ state.observer.unobserve(element);
6362
+ if (state.callbacks.size === 0) {
6363
+ state.observer.disconnect();
6364
+ view.removeEventListener("resize", state.handleWindowResize);
6365
+ sharedResizeObservers.delete(view);
6366
+ }
6367
+ };
6368
+ }
5941
6369
  var UserMessageDisclosureContext = createContext9(null);
5942
6370
  function UserMessageDisclosureProvider({
5943
6371
  value,
@@ -5954,15 +6382,31 @@ function UserMessageBody({ messageId, text, children, className }) {
5954
6382
  const [expanded, setExpanded] = useState12(
5955
6383
  () => disclosure?.expandedByMessageId.get(messageId) ?? false
5956
6384
  );
5957
- const [collapsible, setCollapsible] = useState12(() => userMessageLikelyNeedsDisclosure(text));
6385
+ const collapsibleRef = useRef10(userMessageLikelyNeedsDisclosure(text));
6386
+ const expandedRef = useRef10(expanded);
6387
+ expandedRef.current = expanded;
5958
6388
  const rootRef = useRef10(null);
5959
6389
  const clipRef = useRef10(null);
5960
6390
  const contentRef = useRef10(null);
5961
6391
  const thresholdRef = useRef10(null);
6392
+ const fadeRef = useRef10(null);
6393
+ const disclosureControlRef = useRef10(null);
5962
6394
  const pendingRestoreRef = useRef10(null);
5963
6395
  const managedInertDescendantsRef = useRef10(/* @__PURE__ */ new Set());
6396
+ const measurementKeyRef = useRef10({});
5964
6397
  const contentId = `og-user-message-${useId3().replace(/:/g, "")}`;
6398
+ const collapsible = collapsibleRef.current;
5965
6399
  const collapsed = collapsible && !expanded;
6400
+ const syncDisclosurePresentation = useCallback2((nextCollapsible) => {
6401
+ collapsibleRef.current = nextCollapsible;
6402
+ const nextCollapsed = nextCollapsible && !expandedRef.current;
6403
+ const clip = clipRef.current;
6404
+ clip?.classList.toggle("max-h-56", nextCollapsed);
6405
+ clip?.classList.toggle("overflow-hidden", nextCollapsed);
6406
+ clip?.classList.toggle("sm:max-h-72", nextCollapsed);
6407
+ if (fadeRef.current) fadeRef.current.hidden = !nextCollapsed;
6408
+ if (disclosureControlRef.current) disclosureControlRef.current.hidden = !nextCollapsible;
6409
+ }, []);
5966
6410
  const restoreManagedInertDescendants = useCallback2(() => {
5967
6411
  for (const descendant of managedInertDescendantsRef.current) {
5968
6412
  if (descendant.hasAttribute("data-og-user-message-managed-inert")) {
@@ -5974,7 +6418,7 @@ function UserMessageBody({ messageId, text, children, className }) {
5974
6418
  }, []);
5975
6419
  const syncCollapsedInteractivity = useCallback2(() => {
5976
6420
  restoreManagedInertDescendants();
5977
- if (!collapsed) {
6421
+ if (!collapsibleRef.current || expandedRef.current) {
5978
6422
  return;
5979
6423
  }
5980
6424
  const clip = clipRef.current;
@@ -5998,51 +6442,71 @@ function UserMessageBody({ messageId, text, children, className }) {
5998
6442
  descendant.setAttribute("data-og-user-message-managed-inert", "");
5999
6443
  managedInertDescendantsRef.current.add(descendant);
6000
6444
  }
6001
- }, [collapsed, restoreManagedInertDescendants]);
6002
- const measure = useCallback2(() => {
6445
+ }, [restoreManagedInertDescendants]);
6446
+ const readCollapsible = useCallback2(() => {
6003
6447
  const content = contentRef.current;
6004
6448
  const threshold = thresholdRef.current;
6005
6449
  if (!content || !threshold) {
6006
- return;
6450
+ return userMessageLikelyNeedsDisclosure(text);
6007
6451
  }
6008
6452
  const renderedHeight = Math.max(content.scrollHeight, content.getBoundingClientRect().height);
6009
6453
  const collapseHeight = Math.max(
6010
6454
  threshold.offsetHeight,
6011
6455
  threshold.getBoundingClientRect().height
6012
6456
  );
6013
- setCollapsible(
6014
- renderedHeight > 0 && collapseHeight > 0 ? renderedHeight > collapseHeight + 1 : userMessageLikelyNeedsDisclosure(text)
6015
- );
6457
+ return renderedHeight > 0 && collapseHeight > 0 ? renderedHeight > collapseHeight + 1 : userMessageLikelyNeedsDisclosure(text);
6016
6458
  }, [text]);
6017
- useLayoutEffect3(() => {
6018
- measure();
6459
+ const measure = useCallback2(() => {
6460
+ const view = rootRef.current?.ownerDocument.defaultView;
6461
+ if (!view) {
6462
+ syncDisclosurePresentation(readCollapsible());
6463
+ syncCollapsedInteractivity();
6464
+ return () => void 0;
6465
+ }
6466
+ return scheduleDisclosureMeasurement(view, measurementKeyRef.current, {
6467
+ read: readCollapsible,
6468
+ write: (nextCollapsible) => {
6469
+ syncDisclosurePresentation(nextCollapsible);
6470
+ syncCollapsedInteractivity();
6471
+ }
6472
+ });
6473
+ }, [readCollapsible, syncCollapsedInteractivity, syncDisclosurePresentation]);
6474
+ useLayoutEffect2(() => {
6475
+ const cancelPendingMeasurement = measure();
6019
6476
  const content = contentRef.current;
6020
6477
  const threshold = thresholdRef.current;
6021
- const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => {
6478
+ const onResize = () => {
6022
6479
  measure();
6023
- syncCollapsedInteractivity();
6024
- });
6025
- if (content) {
6026
- observer?.observe(content);
6027
- }
6028
- if (threshold) {
6029
- observer?.observe(threshold);
6030
- }
6480
+ };
6481
+ const stopObservingContent = content ? observeSharedResize(content, onResize) : null;
6482
+ const stopObservingThreshold = threshold ? observeSharedResize(threshold, onResize) : null;
6483
+ const observerAvailable = stopObservingContent !== null || stopObservingThreshold !== null;
6031
6484
  const handleResize = () => {
6032
6485
  measure();
6033
- syncCollapsedInteractivity();
6034
6486
  };
6035
- window.addEventListener("resize", handleResize);
6487
+ if (!observerAvailable) {
6488
+ window.addEventListener("resize", handleResize);
6489
+ }
6036
6490
  return () => {
6037
- observer?.disconnect();
6038
- window.removeEventListener("resize", handleResize);
6491
+ cancelPendingMeasurement();
6492
+ stopObservingContent?.();
6493
+ stopObservingThreshold?.();
6494
+ if (!observerAvailable) {
6495
+ window.removeEventListener("resize", handleResize);
6496
+ }
6039
6497
  };
6040
6498
  }, [measure, syncCollapsedInteractivity]);
6041
- useLayoutEffect3(() => {
6499
+ useLayoutEffect2(() => {
6500
+ syncDisclosurePresentation(collapsibleRef.current);
6042
6501
  syncCollapsedInteractivity();
6043
6502
  return restoreManagedInertDescendants;
6044
- });
6045
- useLayoutEffect3(() => {
6503
+ }, [
6504
+ expanded,
6505
+ restoreManagedInertDescendants,
6506
+ syncCollapsedInteractivity,
6507
+ syncDisclosurePresentation
6508
+ ]);
6509
+ useLayoutEffect2(() => {
6046
6510
  const restore = pendingRestoreRef.current;
6047
6511
  pendingRestoreRef.current = null;
6048
6512
  restore?.();
@@ -6091,21 +6555,25 @@ function UserMessageBody({ messageId, text, children, className }) {
6091
6555
  children
6092
6556
  }
6093
6557
  ),
6094
- collapsed ? /* @__PURE__ */ jsx15(
6558
+ /* @__PURE__ */ jsx15(
6095
6559
  "span",
6096
6560
  {
6561
+ ref: fadeRef,
6097
6562
  "aria-hidden": "true",
6563
+ hidden: !collapsed,
6098
6564
  "data-og-user-message-fade": "",
6099
6565
  className: "pointer-events-none absolute inset-x-0 bottom-0 h-16 bg-gradient-to-t from-og-surface-2 via-og-surface-2/90 to-transparent"
6100
6566
  }
6101
- ) : null
6567
+ )
6102
6568
  ]
6103
6569
  }
6104
6570
  ),
6105
- collapsible ? /* @__PURE__ */ jsx15(
6571
+ /* @__PURE__ */ jsx15(
6106
6572
  "button",
6107
6573
  {
6574
+ ref: disclosureControlRef,
6108
6575
  type: "button",
6576
+ hidden: !collapsible,
6109
6577
  "aria-controls": contentId,
6110
6578
  "aria-expanded": expanded,
6111
6579
  "data-og-user-message-disclosure": "",
@@ -6113,7 +6581,7 @@ function UserMessageBody({ messageId, text, children, className }) {
6113
6581
  onClick: (event) => toggle(event.currentTarget),
6114
6582
  children: expanded ? "Show less" : "Show more"
6115
6583
  }
6116
- ) : null
6584
+ )
6117
6585
  ]
6118
6586
  }
6119
6587
  );
@@ -6197,7 +6665,7 @@ function GeneratedVideoPlayer({
6197
6665
  import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
6198
6666
  var SESSION_STATUS_META = {
6199
6667
  queued: {
6200
- label: "Queued",
6668
+ label: "Starting",
6201
6669
  dotClassName: "bg-og-status-queued",
6202
6670
  badgeClassName: "text-og-fg-muted border-og-border bg-og-status-queued/10",
6203
6671
  pulse: true
@@ -6286,10 +6754,11 @@ import {
6286
6754
  ArrowUpToLineIcon,
6287
6755
  BotIcon as BotIcon3,
6288
6756
  CheckCircle2Icon,
6289
- CheckIcon as CheckIcon2,
6757
+ CheckIcon as CheckIcon3,
6290
6758
  ChevronRightIcon as ChevronRightIcon3,
6291
6759
  PauseCircleIcon,
6292
6760
  PauseIcon as PauseIcon2,
6761
+ MessageCircleQuestionIcon as MessageCircleQuestionIcon3,
6293
6762
  PencilLineIcon,
6294
6763
  PlayIcon as PlayIcon2,
6295
6764
  RefreshCwIcon,
@@ -6308,8 +6777,8 @@ import {
6308
6777
  memo as memo2,
6309
6778
  useCallback as useCallback3,
6310
6779
  useEffect as useEffect11,
6311
- useLayoutEffect as useLayoutEffect4,
6312
- useMemo as useMemo5,
6780
+ useLayoutEffect as useLayoutEffect3,
6781
+ useMemo as useMemo6,
6313
6782
  useRef as useRef11,
6314
6783
  useState as useState14
6315
6784
  } from "react";
@@ -6588,7 +7057,12 @@ var MACHINE_INPUT_META = {
6588
7057
  agent_message: "Agent update",
6589
7058
  agent_steer_instruction: "Agent direction",
6590
7059
  child_terminal_result: "Agent finished",
6591
- media_generation_result: "Video update"
7060
+ media_generation_result: "Video update",
7061
+ child_requires_action: "Agent needs input",
7062
+ child_requires_action_resolved: "Agent unblocked",
7063
+ child_paused: "Agent paused",
7064
+ child_waiting_capacity: "Agent waiting for capacity",
7065
+ child_progress: "Agent progress"
6592
7066
  };
6593
7067
  function machineInputBatchLabel(members) {
6594
7068
  if (members.length === 0) return "Updates";
@@ -6612,6 +7086,16 @@ function machineInputBatchLabel(members) {
6612
7086
  return n === 1 ? "Agent direction" : `${n} agent directions`;
6613
7087
  case "media_generation_result":
6614
7088
  return n === 1 ? "Video ready" : `${n} video updates`;
7089
+ case "child_requires_action":
7090
+ return n === 1 ? "Agent needs input" : `${n} agents need input`;
7091
+ case "child_requires_action_resolved":
7092
+ return n === 1 ? "Agent unblocked" : `${n} agents unblocked`;
7093
+ case "child_paused":
7094
+ return n === 1 ? "Agent paused" : `${n} agents paused`;
7095
+ case "child_waiting_capacity":
7096
+ return n === 1 ? "Agent waiting for capacity" : `${n} agents waiting for capacity`;
7097
+ case "child_progress":
7098
+ return n === 1 ? "Agent progress" : `${n} agent progress notes`;
6615
7099
  }
6616
7100
  }
6617
7101
  const parts = [...counts.entries()].map(([kind, count]) => {
@@ -6714,15 +7198,15 @@ function MessageTimeline({
6714
7198
  emptyState,
6715
7199
  className
6716
7200
  }) {
6717
- const resolvedItems = useMemo5(() => {
7201
+ const resolvedItems = useMemo6(() => {
6718
7202
  const projected = items ?? buildTimeline(events ?? []);
6719
7203
  if (!shouldRenderAuthNeeded) {
6720
7204
  return projected;
6721
7205
  }
6722
7206
  return projected.filter((item) => item.kind !== "auth-needed" || shouldRenderAuthNeeded(item));
6723
7207
  }, [items, events, shouldRenderAuthNeeded]);
6724
- const allGroups = useMemo5(() => groupTimeline(resolvedItems), [resolvedItems]);
6725
- const annotationSources = useMemo5(() => {
7208
+ const allGroups = useMemo6(() => groupTimeline(resolvedItems), [resolvedItems]);
7209
+ const annotationSources = useMemo6(() => {
6726
7210
  const sources = /* @__PURE__ */ new Map();
6727
7211
  for (const item of resolvedItems) {
6728
7212
  if ((item.kind === "user-message" || item.kind === "agent-message" || item.kind === "tool-call") && item.annotationSource) {
@@ -6743,7 +7227,7 @@ function MessageTimeline({
6743
7227
  const olderLoadGateRef = useRef11("armed");
6744
7228
  const resizeFollowRafRef = useRef11(null);
6745
7229
  const firstGroupKey = allGroups[0] ? timelineGroupKey(allGroups[0]) : null;
6746
- const [revealed, setRevealed] = useState14(false);
7230
+ const [revealed, setRevealed] = useState14(resolvedItems[0]?.id === "c");
6747
7231
  const pinnedRef = useRef11(true);
6748
7232
  const hasNewerRef = useRef11(hasNewer);
6749
7233
  hasNewerRef.current = hasNewer;
@@ -6958,7 +7442,7 @@ function MessageTimeline({
6958
7442
  },
6959
7443
  [applyPinned, autoFollow, snapToBottom, syncScrollBaseline, writeScrollTop]
6960
7444
  );
6961
- const userMessageDisclosureContext = useMemo5(
7445
+ const userMessageDisclosureContext = useMemo6(
6962
7446
  () => ({
6963
7447
  expandedByMessageId: userMessageDisclosureMemoryRef.current,
6964
7448
  beginChange: beginUserMessageDisclosureChange
@@ -7056,7 +7540,7 @@ function MessageTimeline({
7056
7540
  driveFollowRef.current = driveFollow;
7057
7541
  useEffect11(() => stopFollow, [stopFollow]);
7058
7542
  useEffect11(() => () => cancelLeaveFallback(), [cancelLeaveFallback]);
7059
- useLayoutEffect4(() => {
7543
+ useLayoutEffect3(() => {
7060
7544
  const node = scrollRef.current;
7061
7545
  if (!node) {
7062
7546
  return;
@@ -7137,7 +7621,7 @@ function MessageTimeline({
7137
7621
  groupOffsetByKeyRef.current = nextOffsetByKey;
7138
7622
  }
7139
7623
  });
7140
- useLayoutEffect4(() => {
7624
+ useLayoutEffect3(() => {
7141
7625
  if (revealed || allGroups.length === 0) {
7142
7626
  return;
7143
7627
  }
@@ -7171,7 +7655,7 @@ function MessageTimeline({
7171
7655
  }
7172
7656
  };
7173
7657
  }, [revealed, allGroups.length, autoFollow, snapToBottom]);
7174
- useLayoutEffect4(() => {
7658
+ useLayoutEffect3(() => {
7175
7659
  if (allGroups.length > 0) {
7176
7660
  return;
7177
7661
  }
@@ -7199,7 +7683,7 @@ function MessageTimeline({
7199
7683
  seenActivityIdsRef.current.clear();
7200
7684
  applyPinned(true);
7201
7685
  }, [allGroups.length, revealed, applyPinned]);
7202
- useLayoutEffect4(() => {
7686
+ useLayoutEffect3(() => {
7203
7687
  previousBulkFirstKeyRef.current = firstGroupKey;
7204
7688
  if (!bulkRender) {
7205
7689
  return;
@@ -7634,7 +8118,7 @@ function MessageTimeline({
7634
8118
  }
7635
8119
  function useStableTimelineGroupKeys(allGroups) {
7636
8120
  const previousRef = useRef11([]);
7637
- const keyedGroups = useMemo5(() => {
8121
+ const keyedGroups = useMemo6(() => {
7638
8122
  const previousByItemId = /* @__PURE__ */ new Map();
7639
8123
  for (const previous of previousRef.current) {
7640
8124
  for (const itemId of timelineGroupItemIds(previous.group)) {
@@ -7663,7 +8147,7 @@ function useStableTimelineGroupKeys(allGroups) {
7663
8147
  return { group, key };
7664
8148
  });
7665
8149
  }, [allGroups]);
7666
- useLayoutEffect4(() => {
8150
+ useLayoutEffect3(() => {
7667
8151
  previousRef.current = keyedGroups;
7668
8152
  }, [keyedGroups]);
7669
8153
  return keyedGroups;
@@ -7914,7 +8398,7 @@ function useLiveSettleFold(folded) {
7914
8398
  if (!previousFoldedRef.current && folded) {
7915
8399
  latchedRef.current = true;
7916
8400
  }
7917
- useLayoutEffect4(() => {
8401
+ useLayoutEffect3(() => {
7918
8402
  previousFoldedRef.current = folded;
7919
8403
  });
7920
8404
  return latchedRef.current;
@@ -7922,7 +8406,7 @@ function useLiveSettleFold(folded) {
7922
8406
  function timelineGroupKey(group) {
7923
8407
  switch (group.kind) {
7924
8408
  case "item":
7925
- return group.item.id;
8409
+ return group.item.kind === "user-message" && group.item.reconciliationKey ? group.item.reconciliationKey : group.item.id;
7926
8410
  case "activity":
7927
8411
  return group.id;
7928
8412
  case "turn":
@@ -8082,6 +8566,8 @@ function TimelineRow({
8082
8566
  switch (item.kind) {
8083
8567
  case "user-message":
8084
8568
  return /* @__PURE__ */ jsx18(UserMessageRow, { item, renderMessageText });
8569
+ case "human-input":
8570
+ return /* @__PURE__ */ jsx18(HumanInputConversationRow, { item });
8085
8571
  case "agent-message":
8086
8572
  return /* @__PURE__ */ jsx18(AgentMessageRow, { item, renderMessageText });
8087
8573
  case "worker-completion":
@@ -8177,7 +8663,7 @@ function UserMessageRow({
8177
8663
  renderMessageText
8178
8664
  }) {
8179
8665
  const enter = useEntranceAnimation();
8180
- const deliveryLabel = item.delivery?.state === "sending" ? "Sending\u2026" : item.delivery?.state === "queued" ? "Queued" : item.delivery?.state === "failed" ? "Not sent" : null;
8666
+ const deliveryFailed = item.delivery?.state === "failed";
8181
8667
  return /* @__PURE__ */ jsx18("div", { className: cn(enter && "animate-og-enter", "flex justify-end"), children: /* @__PURE__ */ jsxs14("div", { className: "flex max-w-[85%] min-w-0 flex-col items-end gap-1", children: [
8182
8668
  /* @__PURE__ */ jsx18(
8183
8669
  CopyHoverFrame,
@@ -8199,29 +8685,127 @@ ${annotation.note}`).join("\n\n"),
8199
8685
  ] })
8200
8686
  }
8201
8687
  ),
8202
- deliveryLabel ? /* @__PURE__ */ jsxs14("div", { className: "flex max-w-full items-center gap-2 px-1 text-og-xs text-og-fg-subtle", children: [
8203
- /* @__PURE__ */ jsx18("span", { title: item.delivery?.error, children: deliveryLabel }),
8204
- item.delivery?.state === "failed" && item.delivery.onRetry ? /* @__PURE__ */ jsx18(
8205
- "button",
8206
- {
8207
- type: "button",
8208
- className: "font-medium text-og-fg underline decoration-og-border underline-offset-2 hover:text-og-fg-strong",
8209
- onClick: item.delivery.onRetry,
8210
- children: "Retry"
8211
- }
8212
- ) : null,
8213
- item.delivery?.state === "failed" && item.delivery.onRemove ? /* @__PURE__ */ jsx18(
8214
- "button",
8215
- {
8216
- type: "button",
8217
- className: "font-medium text-og-fg-subtle underline decoration-og-border underline-offset-2 hover:text-og-fg",
8218
- onClick: item.delivery.onRemove,
8219
- children: "Remove"
8220
- }
8221
- ) : null
8222
- ] }) : null
8688
+ deliveryFailed ? /* @__PURE__ */ jsxs14(
8689
+ "div",
8690
+ {
8691
+ role: "status",
8692
+ className: "flex max-w-full items-center gap-2 px-1 text-og-xs text-og-status-failed",
8693
+ children: [
8694
+ /* @__PURE__ */ jsxs14("span", { className: "inline-flex items-center gap-1", title: item.delivery?.error, children: [
8695
+ /* @__PURE__ */ jsx18(TriangleAlertIcon3, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
8696
+ /* @__PURE__ */ jsx18("span", { children: "Message not sent" })
8697
+ ] }),
8698
+ item.delivery?.onRetry ? /* @__PURE__ */ jsx18(
8699
+ "button",
8700
+ {
8701
+ type: "button",
8702
+ className: "font-medium text-og-status-failed underline decoration-og-status-failed/50 underline-offset-2 hover:text-og-fg",
8703
+ onClick: item.delivery.onRetry,
8704
+ children: "Retry"
8705
+ }
8706
+ ) : null,
8707
+ item.delivery?.onRemove ? /* @__PURE__ */ jsx18(
8708
+ "button",
8709
+ {
8710
+ type: "button",
8711
+ className: "font-medium text-og-fg-subtle underline decoration-og-border underline-offset-2 hover:text-og-fg",
8712
+ onClick: item.delivery.onRemove,
8713
+ children: "Remove"
8714
+ }
8715
+ ) : null
8716
+ ]
8717
+ }
8718
+ ) : null
8223
8719
  ] }) });
8224
8720
  }
8721
+ function HumanInputConversationRow({ item }) {
8722
+ const enter = useEntranceAnimation();
8723
+ const multipleQuestions = Math.max(item.questions.length, item.answers.length) > 1;
8724
+ const questionNumberById = new Map(
8725
+ item.questions.map((question, index) => [question.id, index + 1])
8726
+ );
8727
+ const settledLabel = item.response.outcome === "answered" ? "You answered" : item.response.outcome === "skipped" ? "Skipped" : item.response.outcome === "expired" ? "Expired" : "Cancelled";
8728
+ const copyText = humanInputConversationCopyText(item, settledLabel);
8729
+ return /* @__PURE__ */ jsxs14(
8730
+ "div",
8731
+ {
8732
+ className: cn(enter && "animate-og-enter", "flex w-full flex-col gap-2.5"),
8733
+ "data-human-input-history": item.requestId,
8734
+ children: [
8735
+ /* @__PURE__ */ jsxs14("div", { className: "flex max-w-[90%] items-start gap-3 rounded-og-lg rounded-bl-og-xs border border-og-border bg-og-surface-1 px-3.5 py-3 sm:max-w-[82%]", children: [
8736
+ /* @__PURE__ */ jsx18("span", { className: "mt-0.5 inline-flex size-8 shrink-0 items-center justify-center rounded-og-md bg-og-status-waiting/10 text-og-status-waiting", children: /* @__PURE__ */ jsx18(MessageCircleQuestionIcon3, { "aria-hidden": "true", className: "size-4" }) }),
8737
+ /* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1", children: [
8738
+ /* @__PURE__ */ jsx18("p", { className: "text-og-xs font-medium text-og-fg-subtle", children: "Agent asked" }),
8739
+ /* @__PURE__ */ jsx18("div", { className: "mt-1.5 space-y-3", children: item.questions.length > 0 ? item.questions.map((question, index) => /* @__PURE__ */ jsxs14("div", { children: [
8740
+ question.label ? /* @__PURE__ */ jsxs14("p", { className: "text-og-sm font-semibold text-og-fg", children: [
8741
+ multipleQuestions ? /* @__PURE__ */ jsxs14("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
8742
+ index + 1,
8743
+ "."
8744
+ ] }) : null,
8745
+ multipleQuestions ? " " : null,
8746
+ question.label
8747
+ ] }) : null,
8748
+ /* @__PURE__ */ jsxs14(
8749
+ "p",
8750
+ {
8751
+ className: cn(
8752
+ "text-og-md leading-6 text-og-fg",
8753
+ question.label && "mt-0.5 text-og-sm text-og-fg-muted"
8754
+ ),
8755
+ children: [
8756
+ !question.label && multipleQuestions ? /* @__PURE__ */ jsxs14("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
8757
+ index + 1,
8758
+ "."
8759
+ ] }) : null,
8760
+ !question.label && multipleQuestions ? " " : null,
8761
+ question.prompt
8762
+ ]
8763
+ }
8764
+ )
8765
+ ] }, question.id)) : /* @__PURE__ */ jsx18("p", { className: "text-og-sm text-og-fg-muted", children: "The agent requested structured input." }) })
8766
+ ] })
8767
+ ] }),
8768
+ /* @__PURE__ */ jsx18("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx18(
8769
+ CopyHoverFrame,
8770
+ {
8771
+ copyText,
8772
+ label: "Copy answer",
8773
+ className: "w-fit max-w-[90%] min-w-0 sm:max-w-[82%]",
8774
+ trailing: /* @__PURE__ */ jsx18(MessageFooterTime, { occurredAt: item.occurredAt }),
8775
+ children: /* @__PURE__ */ jsxs14("div", { className: "w-fit max-w-full min-w-0 rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-og-md leading-6 text-og-fg", children: [
8776
+ /* @__PURE__ */ jsx18("p", { className: "text-og-xs font-medium text-og-fg-subtle", children: settledLabel }),
8777
+ item.response.outcome === "answered" ? /* @__PURE__ */ jsx18("div", { className: "mt-1.5 space-y-3", children: item.answers.length > 0 ? item.answers.map((answer, answerIndex) => /* @__PURE__ */ jsxs14("div", { children: [
8778
+ multipleQuestions ? /* @__PURE__ */ jsxs14("p", { className: "text-og-sm font-semibold text-og-fg", children: [
8779
+ /* @__PURE__ */ jsxs14("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
8780
+ questionNumberById.get(answer.questionId) ?? answerIndex + 1,
8781
+ "."
8782
+ ] }),
8783
+ " ",
8784
+ answer.label
8785
+ ] }) : null,
8786
+ /* @__PURE__ */ jsx18("div", { className: cn("text-og-md text-og-fg", multipleQuestions && "mt-0.5"), children: answer.values.length > 1 ? /* @__PURE__ */ jsx18("ul", { className: "list-disc space-y-0.5 pl-5", children: answer.values.map((value) => /* @__PURE__ */ jsx18("li", { children: value }, `${answer.questionId}-${value}`)) }) : /* @__PURE__ */ jsx18("p", { children: answer.values[0] || "Answered" }) })
8787
+ ] }, answer.questionId)) : /* @__PURE__ */ jsx18("p", { children: "Answered" }) }) : null
8788
+ ] })
8789
+ }
8790
+ ) })
8791
+ ]
8792
+ }
8793
+ );
8794
+ }
8795
+ function humanInputConversationCopyText(item, settledLabel) {
8796
+ const questions = item.questions.map(
8797
+ (question, index) => `${item.questions.length > 1 ? `${index + 1}. ` : ""}${question.label || "Question"}: ${question.prompt}`
8798
+ ).join("\n\n");
8799
+ const questionNumberById = new Map(
8800
+ item.questions.map((question, index) => [question.id, index + 1])
8801
+ );
8802
+ const answers = item.answers.map(
8803
+ (answer, index) => `${item.questions.length > 1 ? `${questionNumberById.get(answer.questionId) ?? index + 1}. ` : ""}${answer.label}: ${answer.values.join(", ") || "Answered"}`
8804
+ ).join("\n\n");
8805
+ return [questions, `${settledLabel}${answers ? `
8806
+
8807
+ ${answers}` : ""}`].filter(Boolean).join("\n\n");
8808
+ }
8225
8809
  function AgentMessageRow({
8226
8810
  item,
8227
8811
  renderMessageText
@@ -8380,7 +8964,7 @@ var GOAL_META = {
8380
8964
  completed: {
8381
8965
  label: "Goal completed",
8382
8966
  pill: "border-og-status-idle/30 bg-og-status-idle/10 text-og-status-idle",
8383
- icon: CheckIcon2
8967
+ icon: CheckIcon3
8384
8968
  },
8385
8969
  paused: {
8386
8970
  label: "Goal paused",
@@ -8389,6 +8973,11 @@ var GOAL_META = {
8389
8973
  },
8390
8974
  resumed: { label: "Goal resumed", pill: NEUTRAL_PILL, icon: PlayIcon2 },
8391
8975
  cleared: { label: "Goal cleared", pill: NEUTRAL_PILL, icon: Trash2Icon2 },
8976
+ held: {
8977
+ label: "Goal held",
8978
+ pill: "border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting",
8979
+ icon: PauseCircleIcon
8980
+ },
8392
8981
  continuation: { label: "Continuing toward the goal", pill: NEUTRAL_PILL, icon: ArrowRightIcon2 }
8393
8982
  };
8394
8983
  function GoalRow({ item }) {
@@ -8752,6 +9341,8 @@ function authReasonLine(reason) {
8752
9341
 
8753
9342
  export {
8754
9343
  QueueSurface,
9344
+ sessionChromeGoalPillLabel,
9345
+ sessionChromeGoalPillExplanation,
8755
9346
  sessionChromeGoalPillState,
8756
9347
  SessionChrome,
8757
9348
  defaultHumanInputFormMessages,
@@ -8792,8 +9383,11 @@ export {
8792
9383
  PierreDiff,
8793
9384
  defaultToolRegistry,
8794
9385
  createDefaultToolRegistry,
9386
+ prefersReducedMotion,
8795
9387
  CopyButton,
8796
9388
  CopyHoverFrame,
9389
+ sandboxFileLocationFromHref,
9390
+ sandboxFilePathFromHref,
8797
9391
  Markdown,
8798
9392
  ActivityRail,
8799
9393
  BUILT_IN_TURN_SUMMARY_FACET_IDS,
@@ -8807,4 +9401,4 @@ export {
8807
9401
  MessageTimeline,
8808
9402
  TimelineRow
8809
9403
  };
8810
- //# sourceMappingURL=chunk-Y7OEDUJ5.js.map
9404
+ //# sourceMappingURL=chunk-5RZN3DD5.js.map