@opengeni/react 1.0.1 → 2.3.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-5YK2ZDIG.js +116 -0
  8. package/dist/chunk-5YK2ZDIG.js.map +1 -0
  9. package/dist/chunk-H5YGYNXS.js +329 -0
  10. package/dist/chunk-H5YGYNXS.js.map +1 -0
  11. package/dist/{chunk-7WCLAEFV.js → chunk-ICA6R6TW.js} +2 -2
  12. package/dist/{chunk-7WCLAEFV.js.map → chunk-ICA6R6TW.js.map} +1 -1
  13. package/dist/{chunk-IGC6A2ZI.js → chunk-JOAVA2TW.js} +589 -217
  14. package/dist/chunk-JOAVA2TW.js.map +1 -0
  15. package/dist/{chunk-Y7OEDUJ5.js → chunk-LS4POUTY.js} +1057 -426
  16. package/dist/chunk-LS4POUTY.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-6KLX2RH5.js → chunk-RSXJN73N.js} +365 -21
  24. package/dist/chunk-RSXJN73N.js.map +1 -0
  25. package/dist/{chunk-B6WPZSTT.js → chunk-SE4W4WQ3.js} +78 -16
  26. package/dist/chunk-SE4W4WQ3.js.map +1 -0
  27. package/dist/{chunk-MKPIAGVL.js → chunk-W6NFJXSA.js} +8 -19
  28. package/dist/chunk-W6NFJXSA.js.map +1 -0
  29. package/dist/{chunk-XBZWOM2K.js → chunk-X4A66EWZ.js} +8 -3
  30. package/dist/chunk-X4A66EWZ.js.map +1 -0
  31. package/dist/chunk-X4JAFD5R.js +3907 -0
  32. package/dist/chunk-X4JAFD5R.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 +50 -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 +103 -59
  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 +215 -18
  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 +529 -25
  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 +77 -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-RSXJN73N.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(
714
798
  IconAction,
715
799
  {
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" })
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(
808
+ IconAction,
809
+ {
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,29 +1423,48 @@ 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
1274
1442
  ].filter(Boolean).join(" ") || void 0;
1443
+ const selectOtherDraft = (current) => ({
1444
+ ...current,
1445
+ otherSelected: true,
1446
+ ...question.kind === "single_select" ? { values: [] } : {}
1447
+ });
1275
1448
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1276
1449
  showPromptChrome ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
1277
1450
  /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap items-baseline gap-x-2", children: /* @__PURE__ */ jsxs3(
1278
1451
  "label",
1279
1452
  {
1453
+ id: labelId,
1280
1454
  htmlFor: question.kind === "text" ? fieldId : void 0,
1281
1455
  className: "text-og-sm font-medium text-og-fg",
1282
1456
  children: [
1283
- question.label ?? question.prompt,
1457
+ questionNumber === null ? null : /* @__PURE__ */ jsxs3("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
1458
+ questionNumber,
1459
+ "."
1460
+ ] }),
1461
+ questionNumber === null ? null : " ",
1462
+ visibleLabel,
1284
1463
  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
1464
  ]
1286
1465
  }
1287
1466
  ) }),
1288
- question.label ? /* @__PURE__ */ jsx3("p", { className: "text-og-sm text-og-fg-muted", children: question.prompt }) : null,
1467
+ question.label ? /* @__PURE__ */ jsx3("p", { id: promptId, className: "text-og-sm text-og-fg-muted", children: question.prompt }) : null,
1289
1468
  question.helpText ? /* @__PURE__ */ jsx3("p", { id: helpId, className: "text-og-xs text-og-fg-subtle", children: question.helpText }) : null,
1290
1469
  hint ? /* @__PURE__ */ jsx3("p", { id: `${fieldId}-hint`, className: "text-og-xs text-og-fg-subtle", children: hint }) : null
1291
1470
  ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
@@ -1303,6 +1482,7 @@ function QuestionControls({
1303
1482
  values: event.target.value ? [event.target.value] : []
1304
1483
  })),
1305
1484
  "aria-invalid": Boolean(error),
1485
+ "aria-labelledby": controlLabelId,
1306
1486
  "aria-describedby": describedBy,
1307
1487
  autoFocus,
1308
1488
  rows: 2,
@@ -1312,6 +1492,7 @@ function QuestionControls({
1312
1492
  "div",
1313
1493
  {
1314
1494
  role: question.kind === "single_select" ? "radiogroup" : "group",
1495
+ "aria-labelledby": controlLabelId,
1315
1496
  "aria-describedby": describedBy,
1316
1497
  className: "flex flex-col gap-0.5",
1317
1498
  children: [
@@ -1349,8 +1530,8 @@ function QuestionControls({
1349
1530
  option.id
1350
1531
  );
1351
1532
  }),
1352
- question.allowOther ? /* @__PURE__ */ jsxs3(
1353
- "label",
1533
+ /* @__PURE__ */ jsxs3(
1534
+ "div",
1354
1535
  {
1355
1536
  className: cn(
1356
1537
  "flex items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
@@ -1360,8 +1541,10 @@ function QuestionControls({
1360
1541
  /* @__PURE__ */ jsx3(
1361
1542
  "input",
1362
1543
  {
1544
+ id: otherChoiceId,
1363
1545
  type: question.kind === "single_select" ? "radio" : "checkbox",
1364
1546
  name: question.kind === "single_select" ? fieldId : void 0,
1547
+ "aria-labelledby": otherLabelId,
1365
1548
  checked: draft.otherSelected,
1366
1549
  autoFocus: autoFocus && firstOption && question.options.length === 0,
1367
1550
  onChange: (event) => onUpdate((current) => ({
@@ -1373,25 +1556,44 @@ function QuestionControls({
1373
1556
  }
1374
1557
  ),
1375
1558
  /* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1", children: [
1376
- /* @__PURE__ */ jsx3("span", { className: "block text-og-sm font-medium", children: messages.other }),
1559
+ /* @__PURE__ */ jsx3(
1560
+ "label",
1561
+ {
1562
+ id: otherLabelId,
1563
+ htmlFor: otherChoiceId,
1564
+ className: "block text-og-sm font-medium",
1565
+ children: messages.other
1566
+ }
1567
+ ),
1568
+ /* @__PURE__ */ jsxs3("label", { htmlFor: otherTextId, className: "sr-only", children: [
1569
+ messages.other,
1570
+ " answer for ",
1571
+ visibleLabel
1572
+ ] }),
1377
1573
  /* @__PURE__ */ jsx3(
1378
1574
  "input",
1379
1575
  {
1576
+ id: otherTextId,
1380
1577
  type: "text",
1381
1578
  value: draft.other,
1382
- disabled: !draft.otherSelected || busy,
1579
+ disabled: busy,
1383
1580
  placeholder: "Type a value\u2026",
1384
- onChange: (event) => onUpdate((current) => ({
1385
- ...current,
1386
- other: event.target.value
1387
- })),
1581
+ onClick: () => onUpdate(selectOtherDraft),
1582
+ onFocus: () => onUpdate(selectOtherDraft),
1583
+ onChange: (event) => {
1584
+ const other = event.target.value;
1585
+ onUpdate((current) => ({
1586
+ ...selectOtherDraft(current),
1587
+ other
1588
+ }));
1589
+ },
1388
1590
  className: "mt-1.5 w-full rounded-og-sm border border-og-border bg-og-surface-1 px-2 py-1.5 text-og-sm text-og-fg outline-hidden focus:border-og-accent disabled:opacity-50"
1389
1591
  }
1390
1592
  )
1391
1593
  ] })
1392
1594
  ]
1393
1595
  }
1394
- ) : null
1596
+ )
1395
1597
  ]
1396
1598
  }
1397
1599
  ),
@@ -1405,9 +1607,10 @@ function answersFromDrafts(questions, drafts, messageOverrides = {}) {
1405
1607
  for (const question of questions) {
1406
1608
  const draft = drafts[question.id] ?? emptyDraft();
1407
1609
  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) {
1610
+ const other = draft.otherSelected ? draft.other : "";
1611
+ const hasOther = Boolean(other.trim());
1612
+ const supplied = values.length + (hasOther ? 1 : 0);
1613
+ if (question.kind !== "text" && draft.otherSelected && !hasOther) {
1411
1614
  errors[question.id] = messages.otherRequired;
1412
1615
  continue;
1413
1616
  }
@@ -1431,7 +1634,7 @@ function answersFromDrafts(questions, drafts, messageOverrides = {}) {
1431
1634
  answers.push({
1432
1635
  questionId: question.id,
1433
1636
  values,
1434
- ...other ? { other } : {}
1637
+ ...hasOther ? { other } : {}
1435
1638
  });
1436
1639
  }
1437
1640
  }
@@ -2018,7 +2221,7 @@ function useForcedDefaultOpen() {
2018
2221
  }
2019
2222
 
2020
2223
  // src/timeline/screenshot-lightbox.tsx
2021
- import { XIcon as XIcon2 } from "lucide-react";
2224
+ import { DownloadIcon, XIcon as XIcon2 } from "lucide-react";
2022
2225
  import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion/react";
2023
2226
  import { createContext as createContext2, useCallback, useContext as useContext2, useMemo as useMemo3, useState as useState3 } from "react";
2024
2227
  import { Dialog } from "radix-ui";
@@ -2044,9 +2247,14 @@ function LightboxRoot({ children }) {
2044
2247
  const [tokenSource, setTokenSource] = useState3(null);
2045
2248
  const portalStyle = usePortalTokenStyle(tokenSource);
2046
2249
  const open = useCallback(
2047
- (src, caption, source, label = "Screenshot") => {
2250
+ (src, caption, source, label = "Screenshot", downloadFilename) => {
2048
2251
  setTokenSource(source ?? null);
2049
- setState(caption ? { src, caption, label } : { src, label });
2252
+ setState({
2253
+ src,
2254
+ label,
2255
+ ...caption ? { caption } : {},
2256
+ ...downloadFilename ? { downloadFilename } : {}
2257
+ });
2050
2258
  },
2051
2259
  []
2052
2260
  );
@@ -2103,18 +2311,34 @@ function LightboxRoot({ children }) {
2103
2311
  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
2312
  }
2105
2313
  ),
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
- )
2314
+ /* @__PURE__ */ jsxs4("div", { className: "absolute -right-3 -top-3 flex items-center gap-2", children: [
2315
+ state.downloadFilename ? /* @__PURE__ */ jsx6(
2316
+ "a",
2317
+ {
2318
+ href: state.src,
2319
+ download: state.downloadFilename,
2320
+ className: cn(
2321
+ "inline-flex size-9 items-center justify-center rounded-full",
2322
+ "border border-white/15 bg-black/60 text-white/70 backdrop-blur",
2323
+ "transition-colors hover:border-white/30 hover:text-white"
2324
+ ),
2325
+ "aria-label": `Download ${state.downloadFilename}`,
2326
+ children: /* @__PURE__ */ jsx6(DownloadIcon, { className: "size-4" })
2327
+ }
2328
+ ) : null,
2329
+ /* @__PURE__ */ jsx6(
2330
+ Dialog.Close,
2331
+ {
2332
+ className: cn(
2333
+ "inline-flex size-9 items-center justify-center rounded-full",
2334
+ "border border-white/15 bg-black/60 text-white/70 backdrop-blur",
2335
+ "transition-colors hover:border-white/30 hover:text-white"
2336
+ ),
2337
+ "aria-label": "Close",
2338
+ children: /* @__PURE__ */ jsx6(XIcon2, { className: "size-4" })
2339
+ }
2340
+ )
2341
+ ] })
2118
2342
  ] }),
2119
2343
  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
2344
  ] })
@@ -2364,7 +2588,8 @@ function Thumbnail({
2364
2588
  caption,
2365
2589
  alt = "screenshot",
2366
2590
  expandLabel = "Expand screenshot",
2367
- lightboxLabel = "Screenshot"
2591
+ lightboxLabel = "Screenshot",
2592
+ downloadFilename
2368
2593
  }) {
2369
2594
  const lightbox = useLightboxOptional();
2370
2595
  const [failed, setFailed] = useState4(false);
@@ -2389,7 +2614,7 @@ function Thumbnail({
2389
2614
  type: "button",
2390
2615
  onClick: (event) => {
2391
2616
  event.stopPropagation();
2392
- lightbox.open(src, caption, event.currentTarget, lightboxLabel);
2617
+ lightbox.open(src, caption, event.currentTarget, lightboxLabel, downloadFilename);
2393
2618
  },
2394
2619
  onKeyDown: (event) => {
2395
2620
  if (event.key === "Enter" || event.key === " ") {
@@ -2411,7 +2636,8 @@ function ScreenshotFigure({
2411
2636
  caption,
2412
2637
  alt = "screenshot",
2413
2638
  expandLabel = "Expand screenshot",
2414
- lightboxLabel = "Screenshot"
2639
+ lightboxLabel = "Screenshot",
2640
+ downloadFilename
2415
2641
  }) {
2416
2642
  const lightbox = useLightboxOptional();
2417
2643
  const [failed, setFailed] = useState4(false);
@@ -2430,7 +2656,7 @@ function ScreenshotFigure({
2430
2656
  "button",
2431
2657
  {
2432
2658
  type: "button",
2433
- onClick: (event) => lightbox.open(src, caption, event.currentTarget, lightboxLabel),
2659
+ onClick: (event) => lightbox.open(src, caption, event.currentTarget, lightboxLabel, downloadFilename),
2434
2660
  className: surface,
2435
2661
  "aria-label": expandLabel,
2436
2662
  children: img
@@ -2593,12 +2819,16 @@ function PlainPatch({ diff }) {
2593
2819
  }
2594
2820
 
2595
2821
  // src/timeline/tool-renderers.tsx
2822
+ import {
2823
+ parseSandboxFileArtifactReceipt
2824
+ } from "@opengeni/sdk";
2596
2825
  import {
2597
2826
  BoxIcon,
2598
2827
  BrainCircuitIcon,
2599
2828
  CalendarClockIcon,
2600
2829
  CameraIcon as CameraIcon2,
2601
2830
  CameraOffIcon as CameraOffIcon2,
2831
+ DownloadIcon as DownloadIcon2,
2602
2832
  FileDiffIcon,
2603
2833
  FileSearchIcon,
2604
2834
  FolderGitIcon,
@@ -3326,6 +3556,7 @@ function RetainedSessionImageDisclosure({
3326
3556
  cancelled
3327
3557
  }) {
3328
3558
  const state = useRetainedImageObjectUrl(artifact, load);
3559
+ const downloadFilename = retainedImageFilename(artifact);
3329
3560
  return /* @__PURE__ */ jsxs7(
3330
3561
  ActivityDisclosure,
3331
3562
  {
@@ -3342,7 +3573,8 @@ function RetainedSessionImageDisclosure({
3342
3573
  caption,
3343
3574
  alt: caption,
3344
3575
  expandLabel: `Expand ${noun}`,
3345
- lightboxLabel
3576
+ lightboxLabel,
3577
+ downloadFilename
3346
3578
  }
3347
3579
  ) : state.kind === "loading" ? /* @__PURE__ */ jsx10(MediaSkeleton, {}) : /* @__PURE__ */ jsx10(MediaEmpty, {}),
3348
3580
  children: [
@@ -3353,7 +3585,8 @@ function RetainedSessionImageDisclosure({
3353
3585
  caption,
3354
3586
  alt: caption,
3355
3587
  expandLabel: `Expand ${noun}`,
3356
- lightboxLabel
3588
+ lightboxLabel,
3589
+ downloadFilename
3357
3590
  }
3358
3591
  ) : state.kind === "loading" ? /* @__PURE__ */ jsxs7(BodyNote, { children: [
3359
3592
  "Loading the retained ",
@@ -3433,6 +3666,77 @@ function GeneratedVideoRenderer({ item }) {
3433
3666
  }
3434
3667
  );
3435
3668
  }
3669
+ function SandboxFilePublishRenderer({ item, loadRetainedArtifact }) {
3670
+ const { text: output, isError } = unwrapMcpOutput(item.output);
3671
+ const receipt = parseSandboxFileArtifactReceipt(output);
3672
+ const [downloadState, setDownloadState] = useState8("idle");
3673
+ if (item.status === "running") {
3674
+ return /* @__PURE__ */ jsx10(
3675
+ ActivityDisclosure,
3676
+ {
3677
+ icon: /* @__PURE__ */ jsx10(DownloadIcon2, { className: ICON_SIZE }),
3678
+ iconTone: "running",
3679
+ title: "Publishing file",
3680
+ running: true,
3681
+ preview: /* @__PURE__ */ jsx10(RunningPreview, { children: "retaining workspace bytes\u2026" })
3682
+ }
3683
+ );
3684
+ }
3685
+ if (!receipt || isError || item.status === "failed") {
3686
+ return /* @__PURE__ */ jsx10(GenericRenderer, { item });
3687
+ }
3688
+ const download = async () => {
3689
+ if (!loadRetainedArtifact) {
3690
+ setDownloadState("error");
3691
+ return;
3692
+ }
3693
+ setDownloadState("loading");
3694
+ let objectUrl = null;
3695
+ try {
3696
+ const source = await loadRetainedArtifact(receipt.artifact, new AbortController().signal);
3697
+ if (!source) throw new Error("artifact unavailable");
3698
+ const url = source instanceof Uint8Array ? objectUrl = URL.createObjectURL(
3699
+ new Blob([source], {
3700
+ type: receipt.artifact.contentType
3701
+ })
3702
+ ) : source.url;
3703
+ const anchor = document.createElement("a");
3704
+ anchor.href = url;
3705
+ anchor.download = receipt.filename;
3706
+ anchor.rel = "noopener";
3707
+ anchor.click();
3708
+ setDownloadState("idle");
3709
+ } catch {
3710
+ setDownloadState("error");
3711
+ } finally {
3712
+ const urlToRevoke = objectUrl;
3713
+ if (urlToRevoke) setTimeout(() => URL.revokeObjectURL(urlToRevoke), 0);
3714
+ }
3715
+ };
3716
+ return /* @__PURE__ */ jsx10(
3717
+ ActivityDisclosure,
3718
+ {
3719
+ icon: /* @__PURE__ */ jsx10(DownloadIcon2, { className: ICON_SIZE }),
3720
+ iconTone: "accent",
3721
+ title: `Published ${receipt.filename}`,
3722
+ defaultOpen: true,
3723
+ preview: formatBytes(receipt.artifact.originalBytes),
3724
+ children: /* @__PURE__ */ jsxs7(
3725
+ "button",
3726
+ {
3727
+ type: "button",
3728
+ onClick: () => void download(),
3729
+ disabled: downloadState === "loading",
3730
+ 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",
3731
+ children: [
3732
+ /* @__PURE__ */ jsx10(DownloadIcon2, { className: "size-3.5" }),
3733
+ downloadState === "loading" ? "Preparing\u2026" : downloadState === "error" ? "Retry download" : "Download"
3734
+ ]
3735
+ }
3736
+ )
3737
+ }
3738
+ );
3739
+ }
3436
3740
  function GeneratedImageDisclosure({
3437
3741
  receipt,
3438
3742
  load,
@@ -3490,6 +3794,10 @@ function GeneratedImageDisclosure({
3490
3794
  }
3491
3795
  );
3492
3796
  }
3797
+ function retainedImageFilename(artifact) {
3798
+ const extension = artifact.contentType === "image/jpeg" ? "jpg" : artifact.contentType === "image/webp" ? "webp" : "png";
3799
+ return `${artifact.kind}-${artifact.artifactId}.${extension}`;
3800
+ }
3493
3801
  function webSearchQueryFromArguments(args) {
3494
3802
  if (typeof args === "string") {
3495
3803
  const trimmed = args.trim();
@@ -4321,14 +4629,14 @@ function GenericRenderer({ item }) {
4321
4629
  }
4322
4630
  function goalToolPreview(name, args) {
4323
4631
  const leaf = mcpToolLeaf(name);
4324
- if (leaf !== "goal_set" && leaf !== "goal_update" && leaf !== "goal_complete" && leaf !== "goal_pause") {
4632
+ if (leaf !== "goal_set" && leaf !== "goal_update" && leaf !== "goal_complete" && leaf !== "goal_pause" && leaf !== "goal_wait") {
4325
4633
  return null;
4326
4634
  }
4327
4635
  const record = args && typeof args === "object" ? args : null;
4328
4636
  if (!record) {
4329
4637
  return null;
4330
4638
  }
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;
4639
+ 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
4640
  return text ? truncatePreview(text, 90) : null;
4333
4641
  }
4334
4642
  function truncatePreview(text, max) {
@@ -4372,6 +4680,7 @@ var BASE_ENTRIES = [
4372
4680
  { match: "name", name: "generate_video", render: GeneratedVideoRenderer },
4373
4681
  { match: "name", name: "tool_search", render: ToolSearchRenderer },
4374
4682
  { match: "name", name: "view_image", render: ViewImageRenderer },
4683
+ { match: "name", name: "sandbox_file_publish", render: SandboxFilePublishRenderer },
4375
4684
  { match: "name", name: "environment_set_variable", render: SecretSetRenderer },
4376
4685
  { match: "name", name: "variable_set_set_variable", render: SecretSetRenderer },
4377
4686
  { match: "name", name: "search_documents", render: DocsSearchRenderer },
@@ -4386,7 +4695,7 @@ function createDefaultToolRegistry(options = {}) {
4386
4695
  }
4387
4696
 
4388
4697
  // src/components/copy-button.tsx
4389
- import { CheckIcon, CopyIcon } from "lucide-react";
4698
+ import { CheckIcon as CheckIcon2, CopyIcon } from "lucide-react";
4390
4699
  import { useEffect as useEffect7, useRef as useRef5, useState as useState9 } from "react";
4391
4700
  import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4392
4701
  var COPIED_MS = 1600;
@@ -4458,7 +4767,7 @@ function CopyButton({
4458
4767
  copied && "opacity-100 text-og-accent",
4459
4768
  className
4460
4769
  ),
4461
- children: copied ? /* @__PURE__ */ jsx11(CheckIcon, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx11(CopyIcon, { className: "size-3.5", "aria-hidden": true })
4770
+ children: copied ? /* @__PURE__ */ jsx11(CheckIcon2, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx11(CopyIcon, { className: "size-3.5", "aria-hidden": true })
4462
4771
  }
4463
4772
  ) }),
4464
4773
  /* @__PURE__ */ jsx11(TooltipContent, { side: "top", children: tip })
@@ -4501,11 +4810,14 @@ import {
4501
4810
  isValidElement,
4502
4811
  memo,
4503
4812
  useEffect as useEffect8,
4813
+ useMemo as useMemo4,
4504
4814
  useReducer,
4505
4815
  useRef as useRef6,
4506
4816
  useState as useState10
4507
4817
  } from "react";
4508
- import ReactMarkdown from "react-markdown";
4818
+ import ReactMarkdown, {
4819
+ defaultUrlTransform
4820
+ } from "react-markdown";
4509
4821
  import remarkGfm from "remark-gfm";
4510
4822
 
4511
4823
  // src/lib/motion.ts
@@ -4789,7 +5101,7 @@ function rehypeStreamReveal(options) {
4789
5101
 
4790
5102
  // src/components/markdown.tsx
4791
5103
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
4792
- var components = {
5104
+ var baseComponents = {
4793
5105
  h1: ({ children, ...props }) => /* @__PURE__ */ jsx12(
4794
5106
  "h1",
4795
5107
  {
@@ -4818,16 +5130,6 @@ var components = {
4818
5130
  p: ({ children, ...props }) => /* @__PURE__ */ jsx12("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
4819
5131
  strong: ({ children, ...props }) => /* @__PURE__ */ jsx12("strong", { className: "font-semibold text-og-fg", ...props, children }),
4820
5132
  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
5133
  ul: ({ children, ...props }) => /* @__PURE__ */ jsx12(
4832
5134
  "ul",
4833
5135
  {
@@ -4905,15 +5207,125 @@ var components = {
4905
5207
  children
4906
5208
  }
4907
5209
  ),
4908
- img: ({ alt, ...props }) => /* @__PURE__ */ jsx12(
5210
+ img: ({ alt, src, ...props }) => src ? /* @__PURE__ */ jsx12(
4909
5211
  "img",
4910
5212
  {
4911
5213
  alt: alt ?? "",
5214
+ src,
4912
5215
  className: "my-3 max-w-full rounded-og-md border border-og-border",
4913
5216
  ...props
4914
5217
  }
4915
- )
5218
+ ) : alt ? /* @__PURE__ */ jsx12("span", { className: "text-og-fg-subtle", "aria-disabled": "true", children: alt }) : null
4916
5219
  };
5220
+ var MARKDOWN_LINK_CLASS = "break-words font-medium text-og-accent-strong underline-offset-2 hover:underline";
5221
+ function markdownComponents(onSandboxFile) {
5222
+ return {
5223
+ ...baseComponents,
5224
+ a: ({ children, href, ...props }) => {
5225
+ const location = sandboxFileLocationFromHref(href);
5226
+ if (location !== null) {
5227
+ return /* @__PURE__ */ jsx12(SandboxMarkdownLink, { location, onSandboxFile, children });
5228
+ }
5229
+ if (isSandboxHref(href) || !href) {
5230
+ return /* @__PURE__ */ jsx12(
5231
+ "span",
5232
+ {
5233
+ className: "break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2",
5234
+ "aria-disabled": "true",
5235
+ title: isSandboxHref(href) ? "This sandbox file reference is invalid" : "This link is unavailable",
5236
+ children
5237
+ }
5238
+ );
5239
+ }
5240
+ return /* @__PURE__ */ jsx12(
5241
+ "a",
5242
+ {
5243
+ className: MARKDOWN_LINK_CLASS,
5244
+ target: "_blank",
5245
+ rel: "noreferrer noopener",
5246
+ href,
5247
+ ...props,
5248
+ children
5249
+ }
5250
+ );
5251
+ }
5252
+ };
5253
+ }
5254
+ function SandboxMarkdownLink({
5255
+ location,
5256
+ onSandboxFile,
5257
+ children
5258
+ }) {
5259
+ const [state, setState] = useState10("idle");
5260
+ const { path, line } = location;
5261
+ if (!onSandboxFile) {
5262
+ return /* @__PURE__ */ jsx12(
5263
+ "span",
5264
+ {
5265
+ className: "break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2",
5266
+ "aria-disabled": "true",
5267
+ title: "This sandbox file requires a session-aware handler",
5268
+ children
5269
+ }
5270
+ );
5271
+ }
5272
+ const idleTitle = line !== null ? `Open ${path} at line ${line}` : `Open ${path}`;
5273
+ return /* @__PURE__ */ jsxs9(
5274
+ "button",
5275
+ {
5276
+ type: "button",
5277
+ className: cn(
5278
+ MARKDOWN_LINK_CLASS,
5279
+ "inline-flex min-h-7 cursor-pointer items-center disabled:cursor-wait disabled:opacity-70 pointer-coarse:min-h-11"
5280
+ ),
5281
+ disabled: state === "loading",
5282
+ "aria-busy": state === "loading",
5283
+ title: state === "error" ? "Couldn't open this file. Select to retry." : idleTitle,
5284
+ onClick: () => {
5285
+ setState("loading");
5286
+ void Promise.resolve(onSandboxFile(path, line ?? void 0)).then(
5287
+ () => setState("idle"),
5288
+ () => setState("error")
5289
+ );
5290
+ },
5291
+ children: [
5292
+ children,
5293
+ state === "loading" ? " (opening\u2026)" : state === "error" ? " (retry)" : null
5294
+ ]
5295
+ }
5296
+ );
5297
+ }
5298
+ var SANDBOX_SCHEME = "sandbox:";
5299
+ var LEGACY_WORKSPACE_PREFIX = "/workspace/";
5300
+ var TRAILING_LINE = /:([0-9]+)$/u;
5301
+ var TRAILING_INVALID_LINE = /:-(?:[0-9]+)$|:[0-9]+-[0-9]+$/u;
5302
+ var CONTROL_CHARACTER = /[\u0000-\u001f\u007f]/u;
5303
+ function isSandboxHref(href) {
5304
+ return href?.startsWith(SANDBOX_SCHEME) ?? false;
5305
+ }
5306
+ function sandboxFileLocationFromHref(href) {
5307
+ if (!href) return null;
5308
+ const encodedLocation = isSandboxHref(href) ? href.slice(SANDBOX_SCHEME.length) : href.startsWith(LEGACY_WORKSPACE_PREFIX) ? href : null;
5309
+ if (!encodedLocation || encodedLocation.includes("?") || encodedLocation.includes("#")) {
5310
+ return null;
5311
+ }
5312
+ if (TRAILING_INVALID_LINE.test(encodedLocation)) return null;
5313
+ const lineMatch = TRAILING_LINE.exec(encodedLocation);
5314
+ const encodedPath = lineMatch ? encodedLocation.slice(0, -lineMatch[0].length) : encodedLocation;
5315
+ const line = lineMatch?.[1] ? Number(lineMatch[1]) : null;
5316
+ if (line !== null && (!Number.isSafeInteger(line) || line < 1)) return null;
5317
+ if (!encodedPath) return null;
5318
+ try {
5319
+ const path = decodeURIComponent(encodedPath);
5320
+ return path && !CONTROL_CHARACTER.test(path) ? { path, line } : null;
5321
+ } catch {
5322
+ return null;
5323
+ }
5324
+ }
5325
+ function sandboxFilePathFromHref(href) {
5326
+ return sandboxFileLocationFromHref(href)?.path ?? null;
5327
+ }
5328
+ var markdownUrlTransform = (url, key, node) => key === "href" && node.tagName === "a" && isSandboxHref(url) ? url : defaultUrlTransform(url);
4917
5329
  var REVEAL_LINGER_MS = 480 * MOTION_INSPECT_SCALE;
4918
5330
  var MARKDOWN_SETTLE_MS = 480 * MOTION_INSPECT_SCALE;
4919
5331
  function nodeText(node) {
@@ -4984,7 +5396,7 @@ function MarkdownTable({ children, className, ...props }) {
4984
5396
  ) })
4985
5397
  ] });
4986
5398
  }
4987
- function MarkdownImpl({ children, className, streaming = false }) {
5399
+ function MarkdownImpl({ children, className, streaming = false, onSandboxFile }) {
4988
5400
  const revealRef = useRef6(null);
4989
5401
  const bodyRef = useRef6(null);
4990
5402
  const [, bump] = useReducer((n) => n + 1, 0);
@@ -5047,6 +5459,7 @@ function MarkdownImpl({ children, className, streaming = false }) {
5047
5459
  return () => clearTimeout(timer);
5048
5460
  }, [streaming]);
5049
5461
  const parseText = streaming || revealActive ? softenStreamingMarkdown(children) : children;
5462
+ const components = useMemo4(() => markdownComponents(onSandboxFile), [onSandboxFile]);
5050
5463
  return /* @__PURE__ */ jsx12(TooltipProvider, { delayDuration: 400, children: /* @__PURE__ */ jsx12(
5051
5464
  "div",
5052
5465
  {
@@ -5062,6 +5475,7 @@ function MarkdownImpl({ children, className, streaming = false }) {
5062
5475
  remarkPlugins: [remarkGfm],
5063
5476
  rehypePlugins,
5064
5477
  components,
5478
+ urlTransform: markdownUrlTransform,
5065
5479
  children: parseText
5066
5480
  }
5067
5481
  )
@@ -5071,14 +5485,8 @@ function MarkdownImpl({ children, className, streaming = false }) {
5071
5485
  var Markdown = memo(MarkdownImpl);
5072
5486
 
5073
5487
  // 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";
5488
+ import { ArrowRightIcon, BotIcon as BotIcon2, BrainCircuitIcon as BrainCircuitIcon2 } from "lucide-react";
5489
+ import { lazy as lazy3, Suspense as Suspense3, useLayoutEffect, useRef as useRef8 } from "react";
5082
5490
  import { jsx as rowJsx, jsxs as rowJsxs } from "react/jsx-runtime";
5083
5491
 
5084
5492
  // src/timeline/entrance.tsx
@@ -5105,6 +5513,7 @@ function useSeenActivityIds() {
5105
5513
  // src/timeline/activity-rail.tsx
5106
5514
  import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
5107
5515
  var LazyFleetDecisionRow = lazy3(() => import("./fleet-decision-row-GGCAT4E4.js"));
5516
+ var LazyPlatformActivityRow = lazy3(() => import("./platform-activity-row-BJHUHXAT.js"));
5108
5517
  function familyOf(item) {
5109
5518
  if (item.kind === "tool-call") {
5110
5519
  return item.name === "exec_command" || item.name === "write_stdin" ? "terminal" : item.name;
@@ -5138,7 +5547,7 @@ function ActivityRail({
5138
5547
  }
5139
5548
  }
5140
5549
  }
5141
- useLayoutEffect2(() => {
5550
+ useLayoutEffect(() => {
5142
5551
  previousIdsRef.current = new Set(items.map((item) => item.id));
5143
5552
  if (seenIds) {
5144
5553
  for (const item of items) {
@@ -5190,7 +5599,22 @@ function assertNever(item) {
5190
5599
  function renderActivity(item, toolRegistry, onOpenSession, onMemoryClick, loadRetainedScreenshot, loadRetainedArtifact) {
5191
5600
  switch (item.kind) {
5192
5601
  case "reasoning":
5193
- return /* @__PURE__ */ jsx13(ReasoningRow, { item });
5602
+ case "sandbox":
5603
+ case "startup-phase":
5604
+ return /* @__PURE__ */ jsx13(Suspense3, { fallback: null, children: /* @__PURE__ */ jsx13(
5605
+ LazyPlatformActivityRow,
5606
+ {
5607
+ item,
5608
+ d: ActivityDisclosure,
5609
+ p: PayloadBlock,
5610
+ t: toolDisplayName,
5611
+ b: BotIcon2,
5612
+ m: Markdown,
5613
+ r: truncate,
5614
+ j: rowJsx,
5615
+ s: rowJsxs
5616
+ }
5617
+ ) });
5194
5618
  case "tool-call": {
5195
5619
  const Renderer = toolRegistry.resolve(item);
5196
5620
  return /* @__PURE__ */ jsx13(ToolCallTruncationProvider, { value: item.truncation ?? null, children: /* @__PURE__ */ jsx13(
@@ -5204,8 +5628,6 @@ function renderActivity(item, toolRegistry, onOpenSession, onMemoryClick, loadRe
5204
5628
  }
5205
5629
  case "worker":
5206
5630
  return /* @__PURE__ */ jsx13(WorkerRow, { item, onOpenSession });
5207
- case "sandbox":
5208
- return /* @__PURE__ */ jsx13(SandboxRow, { item });
5209
5631
  case "memory":
5210
5632
  return /* @__PURE__ */ jsx13(MemoryRow, { item, onMemoryClick });
5211
5633
  case "fleet-decision":
@@ -5223,19 +5645,6 @@ function renderActivity(item, toolRegistry, onOpenSession, onMemoryClick, loadRe
5223
5645
  return assertNever(item);
5224
5646
  }
5225
5647
  }
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
5648
  var MEMORY_KIND_LABEL = {
5240
5649
  preference: "Preference",
5241
5650
  semantic: "Fact",
@@ -5301,35 +5710,6 @@ function MemoryRow({
5301
5710
  }
5302
5711
  );
5303
5712
  }
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
5713
  function WorkerRow({
5334
5714
  item,
5335
5715
  onOpenSession
@@ -5396,7 +5776,7 @@ import {
5396
5776
  createContext as createContext8,
5397
5777
  useContext as useContext8,
5398
5778
  useEffect as useEffect9,
5399
- useMemo as useMemo4,
5779
+ useMemo as useMemo5,
5400
5780
  useRef as useRef9,
5401
5781
  useState as useState11
5402
5782
  } from "react";
@@ -5561,7 +5941,7 @@ function TurnSummary({
5561
5941
  const [allowEnterAnimation] = useState11(
5562
5942
  () => Boolean(enter && !bare && !initialSettle && !restingOpen)
5563
5943
  );
5564
- const context = useMemo4(
5944
+ const context = useMemo5(
5565
5945
  () => createTurnSummaryContext(
5566
5946
  items,
5567
5947
  outcome,
@@ -5571,11 +5951,11 @@ function TurnSummary({
5571
5951
  ),
5572
5952
  [items, outcome, failureText, durationMs, settling, settlePhase, contextCompactionCount]
5573
5953
  );
5574
- const facetDefinitions = useMemo4(
5954
+ const facetDefinitions = useMemo5(
5575
5955
  () => resolveTurnSummaryFacets(facetConfiguration),
5576
5956
  [facetConfiguration]
5577
5957
  );
5578
- const facets = useMemo4(
5958
+ const facets = useMemo5(
5579
5959
  () => facetDefinitions.flatMap((facet) => {
5580
5960
  try {
5581
5961
  const result = facet.summarize(context);
@@ -5708,7 +6088,7 @@ function createTurnSummaryContext(items, outcome, failureText, durationMs, conte
5708
6088
  if (item.kind === "reasoning") {
5709
6089
  return !item.streaming;
5710
6090
  }
5711
- if (item.kind === "tool-call" || item.kind === "worker" || item.kind === "sandbox") {
6091
+ if (item.kind === "tool-call" || item.kind === "worker" || item.kind === "sandbox" || item.kind === "startup-phase") {
5712
6092
  return item.status !== "running";
5713
6093
  }
5714
6094
  return true;
@@ -5854,7 +6234,7 @@ import {
5854
6234
  useCallback as useCallback2,
5855
6235
  useContext as useContext9,
5856
6236
  useId as useId3,
5857
- useLayoutEffect as useLayoutEffect3,
6237
+ useLayoutEffect as useLayoutEffect2,
5858
6238
  useRef as useRef10,
5859
6239
  useState as useState12
5860
6240
  } from "react";
@@ -5938,6 +6318,64 @@ function collectInteractionBoundaries(root) {
5938
6318
  function isFullyInsideVisiblePreview(rect, clipRect) {
5939
6319
  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
6320
  }
6321
+ var sharedResizeObservers = /* @__PURE__ */ new WeakMap();
6322
+ var disclosureMeasurementJobs = /* @__PURE__ */ new Map();
6323
+ var disclosureMeasurementQueued = false;
6324
+ function scheduleDisclosureMeasurement(view, key, job) {
6325
+ disclosureMeasurementJobs.set(key, job);
6326
+ if (!disclosureMeasurementQueued) {
6327
+ disclosureMeasurementQueued = true;
6328
+ view.queueMicrotask(() => {
6329
+ disclosureMeasurementQueued = false;
6330
+ const pending = [...disclosureMeasurementJobs.values()];
6331
+ disclosureMeasurementJobs.clear();
6332
+ const decisions = pending.map(({ read }) => read());
6333
+ for (let index = 0; index < pending.length; index += 1) {
6334
+ pending[index].write(decisions[index]);
6335
+ }
6336
+ });
6337
+ }
6338
+ return () => disclosureMeasurementJobs.delete(key);
6339
+ }
6340
+ function observeSharedResize(element, callback) {
6341
+ const view = element.ownerDocument.defaultView;
6342
+ if (!view || typeof ResizeObserver === "undefined") {
6343
+ return null;
6344
+ }
6345
+ let state = sharedResizeObservers.get(view);
6346
+ if (!state) {
6347
+ const callbacks = /* @__PURE__ */ new Map();
6348
+ const handleWindowResize = () => {
6349
+ for (const registered of new Set(callbacks.values())) registered();
6350
+ };
6351
+ const observer = new ResizeObserver((entries) => {
6352
+ if (entries.length === 0) {
6353
+ handleWindowResize();
6354
+ } else {
6355
+ for (const entry of entries) {
6356
+ callbacks.get(entry.target)?.();
6357
+ }
6358
+ }
6359
+ });
6360
+ view.addEventListener("resize", handleWindowResize);
6361
+ state = { callbacks, observer, handleWindowResize };
6362
+ sharedResizeObservers.set(view, state);
6363
+ }
6364
+ state.callbacks.set(element, callback);
6365
+ state.observer.observe(element);
6366
+ return () => {
6367
+ if (state.callbacks.get(element) !== callback) {
6368
+ return;
6369
+ }
6370
+ state.callbacks.delete(element);
6371
+ state.observer.unobserve(element);
6372
+ if (state.callbacks.size === 0) {
6373
+ state.observer.disconnect();
6374
+ view.removeEventListener("resize", state.handleWindowResize);
6375
+ sharedResizeObservers.delete(view);
6376
+ }
6377
+ };
6378
+ }
5941
6379
  var UserMessageDisclosureContext = createContext9(null);
5942
6380
  function UserMessageDisclosureProvider({
5943
6381
  value,
@@ -5954,15 +6392,31 @@ function UserMessageBody({ messageId, text, children, className }) {
5954
6392
  const [expanded, setExpanded] = useState12(
5955
6393
  () => disclosure?.expandedByMessageId.get(messageId) ?? false
5956
6394
  );
5957
- const [collapsible, setCollapsible] = useState12(() => userMessageLikelyNeedsDisclosure(text));
6395
+ const collapsibleRef = useRef10(userMessageLikelyNeedsDisclosure(text));
6396
+ const expandedRef = useRef10(expanded);
6397
+ expandedRef.current = expanded;
5958
6398
  const rootRef = useRef10(null);
5959
6399
  const clipRef = useRef10(null);
5960
6400
  const contentRef = useRef10(null);
5961
6401
  const thresholdRef = useRef10(null);
6402
+ const fadeRef = useRef10(null);
6403
+ const disclosureControlRef = useRef10(null);
5962
6404
  const pendingRestoreRef = useRef10(null);
5963
6405
  const managedInertDescendantsRef = useRef10(/* @__PURE__ */ new Set());
6406
+ const measurementKeyRef = useRef10({});
5964
6407
  const contentId = `og-user-message-${useId3().replace(/:/g, "")}`;
6408
+ const collapsible = collapsibleRef.current;
5965
6409
  const collapsed = collapsible && !expanded;
6410
+ const syncDisclosurePresentation = useCallback2((nextCollapsible) => {
6411
+ collapsibleRef.current = nextCollapsible;
6412
+ const nextCollapsed = nextCollapsible && !expandedRef.current;
6413
+ const clip = clipRef.current;
6414
+ clip?.classList.toggle("max-h-56", nextCollapsed);
6415
+ clip?.classList.toggle("overflow-hidden", nextCollapsed);
6416
+ clip?.classList.toggle("sm:max-h-72", nextCollapsed);
6417
+ if (fadeRef.current) fadeRef.current.hidden = !nextCollapsed;
6418
+ if (disclosureControlRef.current) disclosureControlRef.current.hidden = !nextCollapsible;
6419
+ }, []);
5966
6420
  const restoreManagedInertDescendants = useCallback2(() => {
5967
6421
  for (const descendant of managedInertDescendantsRef.current) {
5968
6422
  if (descendant.hasAttribute("data-og-user-message-managed-inert")) {
@@ -5974,7 +6428,7 @@ function UserMessageBody({ messageId, text, children, className }) {
5974
6428
  }, []);
5975
6429
  const syncCollapsedInteractivity = useCallback2(() => {
5976
6430
  restoreManagedInertDescendants();
5977
- if (!collapsed) {
6431
+ if (!collapsibleRef.current || expandedRef.current) {
5978
6432
  return;
5979
6433
  }
5980
6434
  const clip = clipRef.current;
@@ -5998,51 +6452,71 @@ function UserMessageBody({ messageId, text, children, className }) {
5998
6452
  descendant.setAttribute("data-og-user-message-managed-inert", "");
5999
6453
  managedInertDescendantsRef.current.add(descendant);
6000
6454
  }
6001
- }, [collapsed, restoreManagedInertDescendants]);
6002
- const measure = useCallback2(() => {
6455
+ }, [restoreManagedInertDescendants]);
6456
+ const readCollapsible = useCallback2(() => {
6003
6457
  const content = contentRef.current;
6004
6458
  const threshold = thresholdRef.current;
6005
6459
  if (!content || !threshold) {
6006
- return;
6460
+ return userMessageLikelyNeedsDisclosure(text);
6007
6461
  }
6008
6462
  const renderedHeight = Math.max(content.scrollHeight, content.getBoundingClientRect().height);
6009
6463
  const collapseHeight = Math.max(
6010
6464
  threshold.offsetHeight,
6011
6465
  threshold.getBoundingClientRect().height
6012
6466
  );
6013
- setCollapsible(
6014
- renderedHeight > 0 && collapseHeight > 0 ? renderedHeight > collapseHeight + 1 : userMessageLikelyNeedsDisclosure(text)
6015
- );
6467
+ return renderedHeight > 0 && collapseHeight > 0 ? renderedHeight > collapseHeight + 1 : userMessageLikelyNeedsDisclosure(text);
6016
6468
  }, [text]);
6017
- useLayoutEffect3(() => {
6018
- measure();
6469
+ const measure = useCallback2(() => {
6470
+ const view = rootRef.current?.ownerDocument.defaultView;
6471
+ if (!view) {
6472
+ syncDisclosurePresentation(readCollapsible());
6473
+ syncCollapsedInteractivity();
6474
+ return () => void 0;
6475
+ }
6476
+ return scheduleDisclosureMeasurement(view, measurementKeyRef.current, {
6477
+ read: readCollapsible,
6478
+ write: (nextCollapsible) => {
6479
+ syncDisclosurePresentation(nextCollapsible);
6480
+ syncCollapsedInteractivity();
6481
+ }
6482
+ });
6483
+ }, [readCollapsible, syncCollapsedInteractivity, syncDisclosurePresentation]);
6484
+ useLayoutEffect2(() => {
6485
+ const cancelPendingMeasurement = measure();
6019
6486
  const content = contentRef.current;
6020
6487
  const threshold = thresholdRef.current;
6021
- const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => {
6488
+ const onResize = () => {
6022
6489
  measure();
6023
- syncCollapsedInteractivity();
6024
- });
6025
- if (content) {
6026
- observer?.observe(content);
6027
- }
6028
- if (threshold) {
6029
- observer?.observe(threshold);
6030
- }
6490
+ };
6491
+ const stopObservingContent = content ? observeSharedResize(content, onResize) : null;
6492
+ const stopObservingThreshold = threshold ? observeSharedResize(threshold, onResize) : null;
6493
+ const observerAvailable = stopObservingContent !== null || stopObservingThreshold !== null;
6031
6494
  const handleResize = () => {
6032
6495
  measure();
6033
- syncCollapsedInteractivity();
6034
6496
  };
6035
- window.addEventListener("resize", handleResize);
6497
+ if (!observerAvailable) {
6498
+ window.addEventListener("resize", handleResize);
6499
+ }
6036
6500
  return () => {
6037
- observer?.disconnect();
6038
- window.removeEventListener("resize", handleResize);
6501
+ cancelPendingMeasurement();
6502
+ stopObservingContent?.();
6503
+ stopObservingThreshold?.();
6504
+ if (!observerAvailable) {
6505
+ window.removeEventListener("resize", handleResize);
6506
+ }
6039
6507
  };
6040
6508
  }, [measure, syncCollapsedInteractivity]);
6041
- useLayoutEffect3(() => {
6509
+ useLayoutEffect2(() => {
6510
+ syncDisclosurePresentation(collapsibleRef.current);
6042
6511
  syncCollapsedInteractivity();
6043
6512
  return restoreManagedInertDescendants;
6044
- });
6045
- useLayoutEffect3(() => {
6513
+ }, [
6514
+ expanded,
6515
+ restoreManagedInertDescendants,
6516
+ syncCollapsedInteractivity,
6517
+ syncDisclosurePresentation
6518
+ ]);
6519
+ useLayoutEffect2(() => {
6046
6520
  const restore = pendingRestoreRef.current;
6047
6521
  pendingRestoreRef.current = null;
6048
6522
  restore?.();
@@ -6091,21 +6565,25 @@ function UserMessageBody({ messageId, text, children, className }) {
6091
6565
  children
6092
6566
  }
6093
6567
  ),
6094
- collapsed ? /* @__PURE__ */ jsx15(
6568
+ /* @__PURE__ */ jsx15(
6095
6569
  "span",
6096
6570
  {
6571
+ ref: fadeRef,
6097
6572
  "aria-hidden": "true",
6573
+ hidden: !collapsed,
6098
6574
  "data-og-user-message-fade": "",
6099
6575
  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
6576
  }
6101
- ) : null
6577
+ )
6102
6578
  ]
6103
6579
  }
6104
6580
  ),
6105
- collapsible ? /* @__PURE__ */ jsx15(
6581
+ /* @__PURE__ */ jsx15(
6106
6582
  "button",
6107
6583
  {
6584
+ ref: disclosureControlRef,
6108
6585
  type: "button",
6586
+ hidden: !collapsible,
6109
6587
  "aria-controls": contentId,
6110
6588
  "aria-expanded": expanded,
6111
6589
  "data-og-user-message-disclosure": "",
@@ -6113,7 +6591,7 @@ function UserMessageBody({ messageId, text, children, className }) {
6113
6591
  onClick: (event) => toggle(event.currentTarget),
6114
6592
  children: expanded ? "Show less" : "Show more"
6115
6593
  }
6116
- ) : null
6594
+ )
6117
6595
  ]
6118
6596
  }
6119
6597
  );
@@ -6197,7 +6675,7 @@ function GeneratedVideoPlayer({
6197
6675
  import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
6198
6676
  var SESSION_STATUS_META = {
6199
6677
  queued: {
6200
- label: "Queued",
6678
+ label: "Starting",
6201
6679
  dotClassName: "bg-og-status-queued",
6202
6680
  badgeClassName: "text-og-fg-muted border-og-border bg-og-status-queued/10",
6203
6681
  pulse: true
@@ -6286,10 +6764,11 @@ import {
6286
6764
  ArrowUpToLineIcon,
6287
6765
  BotIcon as BotIcon3,
6288
6766
  CheckCircle2Icon,
6289
- CheckIcon as CheckIcon2,
6767
+ CheckIcon as CheckIcon3,
6290
6768
  ChevronRightIcon as ChevronRightIcon3,
6291
6769
  PauseCircleIcon,
6292
6770
  PauseIcon as PauseIcon2,
6771
+ MessageCircleQuestionIcon as MessageCircleQuestionIcon3,
6293
6772
  PencilLineIcon,
6294
6773
  PlayIcon as PlayIcon2,
6295
6774
  RefreshCwIcon,
@@ -6308,8 +6787,8 @@ import {
6308
6787
  memo as memo2,
6309
6788
  useCallback as useCallback3,
6310
6789
  useEffect as useEffect11,
6311
- useLayoutEffect as useLayoutEffect4,
6312
- useMemo as useMemo5,
6790
+ useLayoutEffect as useLayoutEffect3,
6791
+ useMemo as useMemo6,
6313
6792
  useRef as useRef11,
6314
6793
  useState as useState14
6315
6794
  } from "react";
@@ -6588,7 +7067,12 @@ var MACHINE_INPUT_META = {
6588
7067
  agent_message: "Agent update",
6589
7068
  agent_steer_instruction: "Agent direction",
6590
7069
  child_terminal_result: "Agent finished",
6591
- media_generation_result: "Video update"
7070
+ media_generation_result: "Video update",
7071
+ child_requires_action: "Agent needs input",
7072
+ child_requires_action_resolved: "Agent unblocked",
7073
+ child_paused: "Agent paused",
7074
+ child_waiting_capacity: "Agent waiting for capacity",
7075
+ child_progress: "Agent progress"
6592
7076
  };
6593
7077
  function machineInputBatchLabel(members) {
6594
7078
  if (members.length === 0) return "Updates";
@@ -6612,6 +7096,16 @@ function machineInputBatchLabel(members) {
6612
7096
  return n === 1 ? "Agent direction" : `${n} agent directions`;
6613
7097
  case "media_generation_result":
6614
7098
  return n === 1 ? "Video ready" : `${n} video updates`;
7099
+ case "child_requires_action":
7100
+ return n === 1 ? "Agent needs input" : `${n} agents need input`;
7101
+ case "child_requires_action_resolved":
7102
+ return n === 1 ? "Agent unblocked" : `${n} agents unblocked`;
7103
+ case "child_paused":
7104
+ return n === 1 ? "Agent paused" : `${n} agents paused`;
7105
+ case "child_waiting_capacity":
7106
+ return n === 1 ? "Agent waiting for capacity" : `${n} agents waiting for capacity`;
7107
+ case "child_progress":
7108
+ return n === 1 ? "Agent progress" : `${n} agent progress notes`;
6615
7109
  }
6616
7110
  }
6617
7111
  const parts = [...counts.entries()].map(([kind, count]) => {
@@ -6714,15 +7208,15 @@ function MessageTimeline({
6714
7208
  emptyState,
6715
7209
  className
6716
7210
  }) {
6717
- const resolvedItems = useMemo5(() => {
7211
+ const resolvedItems = useMemo6(() => {
6718
7212
  const projected = items ?? buildTimeline(events ?? []);
6719
7213
  if (!shouldRenderAuthNeeded) {
6720
7214
  return projected;
6721
7215
  }
6722
7216
  return projected.filter((item) => item.kind !== "auth-needed" || shouldRenderAuthNeeded(item));
6723
7217
  }, [items, events, shouldRenderAuthNeeded]);
6724
- const allGroups = useMemo5(() => groupTimeline(resolvedItems), [resolvedItems]);
6725
- const annotationSources = useMemo5(() => {
7218
+ const allGroups = useMemo6(() => groupTimeline(resolvedItems), [resolvedItems]);
7219
+ const annotationSources = useMemo6(() => {
6726
7220
  const sources = /* @__PURE__ */ new Map();
6727
7221
  for (const item of resolvedItems) {
6728
7222
  if ((item.kind === "user-message" || item.kind === "agent-message" || item.kind === "tool-call") && item.annotationSource) {
@@ -6741,9 +7235,10 @@ function MessageTimeline({
6741
7235
  const olderPrefetchArmedRef = useRef11(false);
6742
7236
  const [olderPrefetchArmed, setOlderPrefetchArmed] = useState14(false);
6743
7237
  const olderLoadGateRef = useRef11("armed");
7238
+ const underfillLoadWindowRef = useRef11(null);
6744
7239
  const resizeFollowRafRef = useRef11(null);
6745
7240
  const firstGroupKey = allGroups[0] ? timelineGroupKey(allGroups[0]) : null;
6746
- const [revealed, setRevealed] = useState14(false);
7241
+ const [revealed, setRevealed] = useState14(resolvedItems[0]?.id === "c");
6747
7242
  const pinnedRef = useRef11(true);
6748
7243
  const hasNewerRef = useRef11(hasNewer);
6749
7244
  hasNewerRef.current = hasNewer;
@@ -6767,6 +7262,8 @@ function MessageTimeline({
6767
7262
  const groupKeyByItemIdRef = useRef11(/* @__PURE__ */ new Map());
6768
7263
  const groupOffsetByKeyRef = useRef11(/* @__PURE__ */ new Map());
6769
7264
  const firstItemId = resolvedItems[0]?.id ?? null;
7265
+ const lastItemId = resolvedItems.at(-1)?.id ?? null;
7266
+ const loadedWindowKey = JSON.stringify([firstItemId, lastItemId, resolvedItems.length]);
6770
7267
  const firstKeyChangedForBulk = previousBulkFirstKeyRef.current !== void 0 && previousBulkFirstKeyRef.current !== firstGroupKey;
6771
7268
  const bulkRender = allGroups.length > 0 && (bulkActive || firstKeyChangedForBulk);
6772
7269
  const applyPinned = useCallback3((value) => {
@@ -6958,13 +7455,29 @@ function MessageTimeline({
6958
7455
  },
6959
7456
  [applyPinned, autoFollow, snapToBottom, syncScrollBaseline, writeScrollTop]
6960
7457
  );
6961
- const userMessageDisclosureContext = useMemo5(
7458
+ const userMessageDisclosureContext = useMemo6(
6962
7459
  () => ({
6963
7460
  expandedByMessageId: userMessageDisclosureMemoryRef.current,
6964
7461
  beginChange: beginUserMessageDisclosureChange
6965
7462
  }),
6966
7463
  [beginUserMessageDisclosureChange]
6967
7464
  );
7465
+ const requestOlderIfUnderfilled = useCallback3(
7466
+ (node) => {
7467
+ if (underfillLoadWindowRef.current !== null && underfillLoadWindowRef.current !== loadedWindowKey) {
7468
+ olderLoadGateRef.current = "armed";
7469
+ }
7470
+ if (node.clientHeight <= 1 || maxScrollOf(node) > 1 || !hasOlder || loadingOlder || !onLoadOlder || underfillLoadWindowRef.current === loadedWindowKey) {
7471
+ return;
7472
+ }
7473
+ underfillLoadWindowRef.current = loadedWindowKey;
7474
+ if (olderPrefetchArmedRef.current) {
7475
+ olderLoadGateRef.current = "cooling";
7476
+ }
7477
+ onLoadOlder();
7478
+ },
7479
+ [hasOlder, loadedWindowKey, loadingOlder, onLoadOlder]
7480
+ );
6968
7481
  const driveFollowRef = useRef11(() => void 0);
6969
7482
  const driveFollow = useCallback3(
6970
7483
  (node, nowMs) => {
@@ -7056,7 +7569,7 @@ function MessageTimeline({
7056
7569
  driveFollowRef.current = driveFollow;
7057
7570
  useEffect11(() => stopFollow, [stopFollow]);
7058
7571
  useEffect11(() => () => cancelLeaveFallback(), [cancelLeaveFallback]);
7059
- useLayoutEffect4(() => {
7572
+ useLayoutEffect3(() => {
7060
7573
  const node = scrollRef.current;
7061
7574
  if (!node) {
7062
7575
  return;
@@ -7137,7 +7650,7 @@ function MessageTimeline({
7137
7650
  groupOffsetByKeyRef.current = nextOffsetByKey;
7138
7651
  }
7139
7652
  });
7140
- useLayoutEffect4(() => {
7653
+ useLayoutEffect3(() => {
7141
7654
  if (revealed || allGroups.length === 0) {
7142
7655
  return;
7143
7656
  }
@@ -7171,7 +7684,7 @@ function MessageTimeline({
7171
7684
  }
7172
7685
  };
7173
7686
  }, [revealed, allGroups.length, autoFollow, snapToBottom]);
7174
- useLayoutEffect4(() => {
7687
+ useLayoutEffect3(() => {
7175
7688
  if (allGroups.length > 0) {
7176
7689
  return;
7177
7690
  }
@@ -7196,10 +7709,17 @@ function MessageTimeline({
7196
7709
  foldMemoryRef.current.clear();
7197
7710
  userMessageDisclosureMemoryRef.current.clear();
7198
7711
  disclosureKeepsUnpinnedRef.current = false;
7712
+ underfillLoadWindowRef.current = null;
7199
7713
  seenActivityIdsRef.current.clear();
7200
7714
  applyPinned(true);
7201
7715
  }, [allGroups.length, revealed, applyPinned]);
7202
- useLayoutEffect4(() => {
7716
+ useEffect11(() => {
7717
+ const node = scrollRef.current;
7718
+ if (node) {
7719
+ requestOlderIfUnderfilled(node);
7720
+ }
7721
+ });
7722
+ useLayoutEffect3(() => {
7203
7723
  previousBulkFirstKeyRef.current = firstGroupKey;
7204
7724
  if (!bulkRender) {
7205
7725
  return;
@@ -7265,6 +7785,7 @@ function MessageTimeline({
7265
7785
  if (!current) {
7266
7786
  return;
7267
7787
  }
7788
+ requestOlderIfUnderfilled(current);
7268
7789
  if (!autoFollow || !pinnedRef.current || hasNewerRef.current) {
7269
7790
  return;
7270
7791
  }
@@ -7284,7 +7805,7 @@ function MessageTimeline({
7284
7805
  resizeFollowRafRef.current = null;
7285
7806
  }
7286
7807
  };
7287
- }, [autoFollow, driveFollow, snapToBottom]);
7808
+ }, [autoFollow, driveFollow, requestOlderIfUnderfilled, snapToBottom]);
7288
7809
  useEffect11(() => {
7289
7810
  if (hasNewer) {
7290
7811
  stopFollow();
@@ -7634,7 +8155,7 @@ function MessageTimeline({
7634
8155
  }
7635
8156
  function useStableTimelineGroupKeys(allGroups) {
7636
8157
  const previousRef = useRef11([]);
7637
- const keyedGroups = useMemo5(() => {
8158
+ const keyedGroups = useMemo6(() => {
7638
8159
  const previousByItemId = /* @__PURE__ */ new Map();
7639
8160
  for (const previous of previousRef.current) {
7640
8161
  for (const itemId of timelineGroupItemIds(previous.group)) {
@@ -7663,7 +8184,7 @@ function useStableTimelineGroupKeys(allGroups) {
7663
8184
  return { group, key };
7664
8185
  });
7665
8186
  }, [allGroups]);
7666
- useLayoutEffect4(() => {
8187
+ useLayoutEffect3(() => {
7667
8188
  previousRef.current = keyedGroups;
7668
8189
  }, [keyedGroups]);
7669
8190
  return keyedGroups;
@@ -7914,7 +8435,7 @@ function useLiveSettleFold(folded) {
7914
8435
  if (!previousFoldedRef.current && folded) {
7915
8436
  latchedRef.current = true;
7916
8437
  }
7917
- useLayoutEffect4(() => {
8438
+ useLayoutEffect3(() => {
7918
8439
  previousFoldedRef.current = folded;
7919
8440
  });
7920
8441
  return latchedRef.current;
@@ -7922,7 +8443,7 @@ function useLiveSettleFold(folded) {
7922
8443
  function timelineGroupKey(group) {
7923
8444
  switch (group.kind) {
7924
8445
  case "item":
7925
- return group.item.id;
8446
+ return group.item.kind === "user-message" && group.item.reconciliationKey ? group.item.reconciliationKey : group.item.id;
7926
8447
  case "activity":
7927
8448
  return group.id;
7928
8449
  case "turn":
@@ -8082,6 +8603,8 @@ function TimelineRow({
8082
8603
  switch (item.kind) {
8083
8604
  case "user-message":
8084
8605
  return /* @__PURE__ */ jsx18(UserMessageRow, { item, renderMessageText });
8606
+ case "human-input":
8607
+ return /* @__PURE__ */ jsx18(HumanInputConversationRow, { item });
8085
8608
  case "agent-message":
8086
8609
  return /* @__PURE__ */ jsx18(AgentMessageRow, { item, renderMessageText });
8087
8610
  case "worker-completion":
@@ -8177,7 +8700,7 @@ function UserMessageRow({
8177
8700
  renderMessageText
8178
8701
  }) {
8179
8702
  const enter = useEntranceAnimation();
8180
- const deliveryLabel = item.delivery?.state === "sending" ? "Sending\u2026" : item.delivery?.state === "queued" ? "Queued" : item.delivery?.state === "failed" ? "Not sent" : null;
8703
+ const deliveryFailed = item.delivery?.state === "failed";
8181
8704
  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
8705
  /* @__PURE__ */ jsx18(
8183
8706
  CopyHoverFrame,
@@ -8199,29 +8722,127 @@ ${annotation.note}`).join("\n\n"),
8199
8722
  ] })
8200
8723
  }
8201
8724
  ),
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
8725
+ deliveryFailed ? /* @__PURE__ */ jsxs14(
8726
+ "div",
8727
+ {
8728
+ role: "status",
8729
+ className: "flex max-w-full items-center gap-2 px-1 text-og-xs text-og-status-failed",
8730
+ children: [
8731
+ /* @__PURE__ */ jsxs14("span", { className: "inline-flex items-center gap-1", title: item.delivery?.error, children: [
8732
+ /* @__PURE__ */ jsx18(TriangleAlertIcon3, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
8733
+ /* @__PURE__ */ jsx18("span", { children: "Message not sent" })
8734
+ ] }),
8735
+ item.delivery?.onRetry ? /* @__PURE__ */ jsx18(
8736
+ "button",
8737
+ {
8738
+ type: "button",
8739
+ className: "font-medium text-og-status-failed underline decoration-og-status-failed/50 underline-offset-2 hover:text-og-fg",
8740
+ onClick: item.delivery.onRetry,
8741
+ children: "Retry"
8742
+ }
8743
+ ) : null,
8744
+ item.delivery?.onRemove ? /* @__PURE__ */ jsx18(
8745
+ "button",
8746
+ {
8747
+ type: "button",
8748
+ className: "font-medium text-og-fg-subtle underline decoration-og-border underline-offset-2 hover:text-og-fg",
8749
+ onClick: item.delivery.onRemove,
8750
+ children: "Remove"
8751
+ }
8752
+ ) : null
8753
+ ]
8754
+ }
8755
+ ) : null
8223
8756
  ] }) });
8224
8757
  }
8758
+ function HumanInputConversationRow({ item }) {
8759
+ const enter = useEntranceAnimation();
8760
+ const multipleQuestions = Math.max(item.questions.length, item.answers.length) > 1;
8761
+ const questionNumberById = new Map(
8762
+ item.questions.map((question, index) => [question.id, index + 1])
8763
+ );
8764
+ const settledLabel = item.response.outcome === "answered" ? "You answered" : item.response.outcome === "skipped" ? "Skipped" : item.response.outcome === "expired" ? "Expired" : "Cancelled";
8765
+ const copyText = humanInputConversationCopyText(item, settledLabel);
8766
+ return /* @__PURE__ */ jsxs14(
8767
+ "div",
8768
+ {
8769
+ className: cn(enter && "animate-og-enter", "flex w-full flex-col gap-2.5"),
8770
+ "data-human-input-history": item.requestId,
8771
+ children: [
8772
+ /* @__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: [
8773
+ /* @__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" }) }),
8774
+ /* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1", children: [
8775
+ /* @__PURE__ */ jsx18("p", { className: "text-og-xs font-medium text-og-fg-subtle", children: "Agent asked" }),
8776
+ /* @__PURE__ */ jsx18("div", { className: "mt-1.5 space-y-3", children: item.questions.length > 0 ? item.questions.map((question, index) => /* @__PURE__ */ jsxs14("div", { children: [
8777
+ question.label ? /* @__PURE__ */ jsxs14("p", { className: "text-og-sm font-semibold text-og-fg", children: [
8778
+ multipleQuestions ? /* @__PURE__ */ jsxs14("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
8779
+ index + 1,
8780
+ "."
8781
+ ] }) : null,
8782
+ multipleQuestions ? " " : null,
8783
+ question.label
8784
+ ] }) : null,
8785
+ /* @__PURE__ */ jsxs14(
8786
+ "p",
8787
+ {
8788
+ className: cn(
8789
+ "text-og-md leading-6 text-og-fg",
8790
+ question.label && "mt-0.5 text-og-sm text-og-fg-muted"
8791
+ ),
8792
+ children: [
8793
+ !question.label && multipleQuestions ? /* @__PURE__ */ jsxs14("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
8794
+ index + 1,
8795
+ "."
8796
+ ] }) : null,
8797
+ !question.label && multipleQuestions ? " " : null,
8798
+ question.prompt
8799
+ ]
8800
+ }
8801
+ )
8802
+ ] }, question.id)) : /* @__PURE__ */ jsx18("p", { className: "text-og-sm text-og-fg-muted", children: "The agent requested structured input." }) })
8803
+ ] })
8804
+ ] }),
8805
+ /* @__PURE__ */ jsx18("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx18(
8806
+ CopyHoverFrame,
8807
+ {
8808
+ copyText,
8809
+ label: "Copy answer",
8810
+ className: "w-fit max-w-[90%] min-w-0 sm:max-w-[82%]",
8811
+ trailing: /* @__PURE__ */ jsx18(MessageFooterTime, { occurredAt: item.occurredAt }),
8812
+ 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: [
8813
+ /* @__PURE__ */ jsx18("p", { className: "text-og-xs font-medium text-og-fg-subtle", children: settledLabel }),
8814
+ 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: [
8815
+ multipleQuestions ? /* @__PURE__ */ jsxs14("p", { className: "text-og-sm font-semibold text-og-fg", children: [
8816
+ /* @__PURE__ */ jsxs14("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
8817
+ questionNumberById.get(answer.questionId) ?? answerIndex + 1,
8818
+ "."
8819
+ ] }),
8820
+ " ",
8821
+ answer.label
8822
+ ] }) : null,
8823
+ /* @__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" }) })
8824
+ ] }, answer.questionId)) : /* @__PURE__ */ jsx18("p", { children: "Answered" }) }) : null
8825
+ ] })
8826
+ }
8827
+ ) })
8828
+ ]
8829
+ }
8830
+ );
8831
+ }
8832
+ function humanInputConversationCopyText(item, settledLabel) {
8833
+ const questions = item.questions.map(
8834
+ (question, index) => `${item.questions.length > 1 ? `${index + 1}. ` : ""}${question.label || "Question"}: ${question.prompt}`
8835
+ ).join("\n\n");
8836
+ const questionNumberById = new Map(
8837
+ item.questions.map((question, index) => [question.id, index + 1])
8838
+ );
8839
+ const answers = item.answers.map(
8840
+ (answer, index) => `${item.questions.length > 1 ? `${questionNumberById.get(answer.questionId) ?? index + 1}. ` : ""}${answer.label}: ${answer.values.join(", ") || "Answered"}`
8841
+ ).join("\n\n");
8842
+ return [questions, `${settledLabel}${answers ? `
8843
+
8844
+ ${answers}` : ""}`].filter(Boolean).join("\n\n");
8845
+ }
8225
8846
  function AgentMessageRow({
8226
8847
  item,
8227
8848
  renderMessageText
@@ -8380,7 +9001,7 @@ var GOAL_META = {
8380
9001
  completed: {
8381
9002
  label: "Goal completed",
8382
9003
  pill: "border-og-status-idle/30 bg-og-status-idle/10 text-og-status-idle",
8383
- icon: CheckIcon2
9004
+ icon: CheckIcon3
8384
9005
  },
8385
9006
  paused: {
8386
9007
  label: "Goal paused",
@@ -8389,6 +9010,11 @@ var GOAL_META = {
8389
9010
  },
8390
9011
  resumed: { label: "Goal resumed", pill: NEUTRAL_PILL, icon: PlayIcon2 },
8391
9012
  cleared: { label: "Goal cleared", pill: NEUTRAL_PILL, icon: Trash2Icon2 },
9013
+ held: {
9014
+ label: "Goal held",
9015
+ pill: "border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting",
9016
+ icon: PauseCircleIcon
9017
+ },
8392
9018
  continuation: { label: "Continuing toward the goal", pill: NEUTRAL_PILL, icon: ArrowRightIcon2 }
8393
9019
  };
8394
9020
  function GoalRow({ item }) {
@@ -8752,6 +9378,8 @@ function authReasonLine(reason) {
8752
9378
 
8753
9379
  export {
8754
9380
  QueueSurface,
9381
+ sessionChromeGoalPillLabel,
9382
+ sessionChromeGoalPillExplanation,
8755
9383
  sessionChromeGoalPillState,
8756
9384
  SessionChrome,
8757
9385
  defaultHumanInputFormMessages,
@@ -8792,8 +9420,11 @@ export {
8792
9420
  PierreDiff,
8793
9421
  defaultToolRegistry,
8794
9422
  createDefaultToolRegistry,
9423
+ prefersReducedMotion,
8795
9424
  CopyButton,
8796
9425
  CopyHoverFrame,
9426
+ sandboxFileLocationFromHref,
9427
+ sandboxFilePathFromHref,
8797
9428
  Markdown,
8798
9429
  ActivityRail,
8799
9430
  BUILT_IN_TURN_SUMMARY_FACET_IDS,
@@ -8807,4 +9438,4 @@ export {
8807
9438
  MessageTimeline,
8808
9439
  TimelineRow
8809
9440
  };
8810
- //# sourceMappingURL=chunk-Y7OEDUJ5.js.map
9441
+ //# sourceMappingURL=chunk-LS4POUTY.js.map