@opengeni/react 3.3.2 → 3.4.1-canary.38960406141001

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 (855) hide show
  1. package/README.md +769 -22
  2. package/dist/accounts.js +2 -0
  3. package/dist/accounts.js.map +1 -1
  4. package/dist/approvals.d.ts +2 -1
  5. package/dist/artifacts-document.js +5 -3
  6. package/dist/artifacts-presentation.js +5 -3
  7. package/dist/artifacts-spreadsheet.d.ts +1 -1
  8. package/dist/artifacts-spreadsheet.js +5 -3
  9. package/dist/artifacts.d.ts +5 -1
  10. package/dist/artifacts.js +536 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-ZWR6MWJ7.js +19 -0
  13. package/dist/capability-catalog-row.d.ts +20 -0
  14. package/dist/capability-logo-fallback.d.ts +3 -0
  15. package/dist/chat-interactive-block-4EUKJXUO.js +14 -0
  16. package/dist/chunk-2DDJ6YH6.js +41 -0
  17. package/dist/chunk-2DDJ6YH6.js.map +1 -0
  18. package/dist/chunk-2HVLQ26H.js +183 -0
  19. package/dist/chunk-2HVLQ26H.js.map +1 -0
  20. package/dist/{chunk-XYRDDSXF.js → chunk-2I6R3GCZ.js} +4285 -3980
  21. package/dist/chunk-2I6R3GCZ.js.map +1 -0
  22. package/dist/{chunk-JAQ5K7W6.js → chunk-2SFFYIH3.js} +1178 -166
  23. package/dist/chunk-2SFFYIH3.js.map +1 -0
  24. package/dist/chunk-3PVDYTTB.js +24 -0
  25. package/dist/chunk-3PVDYTTB.js.map +1 -0
  26. package/dist/chunk-3RJKUVCA.js +14068 -0
  27. package/dist/chunk-3RJKUVCA.js.map +1 -0
  28. package/dist/chunk-3UZCWK46.js +298 -0
  29. package/dist/chunk-3UZCWK46.js.map +1 -0
  30. package/dist/chunk-47CKUXTW.js +293 -0
  31. package/dist/chunk-47CKUXTW.js.map +1 -0
  32. package/dist/chunk-4QYP6QUI.js +109 -0
  33. package/dist/chunk-4QYP6QUI.js.map +1 -0
  34. package/dist/chunk-5EY26VZ7.js +1053 -0
  35. package/dist/chunk-5EY26VZ7.js.map +1 -0
  36. package/dist/chunk-5I4VRWBB.js +56 -0
  37. package/dist/chunk-5I4VRWBB.js.map +1 -0
  38. package/dist/chunk-5WOR7UCL.js +191 -0
  39. package/dist/chunk-5WOR7UCL.js.map +1 -0
  40. package/dist/chunk-5YJLGOM5.js +51 -0
  41. package/dist/chunk-5YJLGOM5.js.map +1 -0
  42. package/dist/chunk-6JFN3OWG.js +386 -0
  43. package/dist/chunk-6JFN3OWG.js.map +1 -0
  44. package/dist/chunk-7QJT5O4S.js +35 -0
  45. package/dist/chunk-7QJT5O4S.js.map +1 -0
  46. package/dist/chunk-A55KV72M.js +402 -0
  47. package/dist/chunk-A55KV72M.js.map +1 -0
  48. package/dist/chunk-ADWCLI4G.js +2028 -0
  49. package/dist/chunk-ADWCLI4G.js.map +1 -0
  50. package/dist/chunk-B27E3V37.js +29 -0
  51. package/dist/chunk-B27E3V37.js.map +1 -0
  52. package/dist/chunk-B7TC2A33.js +83 -0
  53. package/dist/chunk-B7TC2A33.js.map +1 -0
  54. package/dist/chunk-BLL56F7R.js +385 -0
  55. package/dist/chunk-BLL56F7R.js.map +1 -0
  56. package/dist/chunk-BOFEQC6K.js +162 -0
  57. package/dist/chunk-BOFEQC6K.js.map +1 -0
  58. package/dist/chunk-CM7LVUKC.js +35 -0
  59. package/dist/chunk-CM7LVUKC.js.map +1 -0
  60. package/dist/chunk-CORUP6JB.js +122 -0
  61. package/dist/chunk-CORUP6JB.js.map +1 -0
  62. package/dist/chunk-CSX5FFKZ.js +35 -0
  63. package/dist/chunk-CSX5FFKZ.js.map +1 -0
  64. package/dist/chunk-EGVHJKGJ.js +3125 -0
  65. package/dist/chunk-EGVHJKGJ.js.map +1 -0
  66. package/dist/{chunk-NEXLLTP4.js → chunk-G76LSA76.js} +6 -5
  67. package/dist/chunk-G76LSA76.js.map +1 -0
  68. package/dist/{chunk-PEI6RANI.js → chunk-GQMRL52F.js} +311 -75
  69. package/dist/chunk-GQMRL52F.js.map +1 -0
  70. package/dist/{chunk-ELIYWBZR.js → chunk-GUUXOISA.js} +1113 -457
  71. package/dist/chunk-GUUXOISA.js.map +1 -0
  72. package/dist/{chunk-HUIKIDM5.js → chunk-I7X2P4FU.js} +225 -116
  73. package/dist/chunk-I7X2P4FU.js.map +1 -0
  74. package/dist/chunk-IGFZFLI2.js +1390 -0
  75. package/dist/chunk-IGFZFLI2.js.map +1 -0
  76. package/dist/{chunk-4MDLEHXL.js → chunk-IMSUVYQB.js} +26 -13
  77. package/dist/chunk-IMSUVYQB.js.map +1 -0
  78. package/dist/chunk-IOYHDEP3.js +38 -0
  79. package/dist/chunk-IOYHDEP3.js.map +1 -0
  80. package/dist/chunk-IZV5FTJC.js +55 -0
  81. package/dist/chunk-IZV5FTJC.js.map +1 -0
  82. package/dist/chunk-KF33GTWN.js +343 -0
  83. package/dist/chunk-KF33GTWN.js.map +1 -0
  84. package/dist/chunk-KSGQ5ODA.js +457 -0
  85. package/dist/chunk-KSGQ5ODA.js.map +1 -0
  86. package/dist/{chunk-ZPBTI3TE.js → chunk-KZC6QRNR.js} +1513 -697
  87. package/dist/chunk-KZC6QRNR.js.map +1 -0
  88. package/dist/chunk-LJUMYUBO.js +218 -0
  89. package/dist/chunk-LJUMYUBO.js.map +1 -0
  90. package/dist/chunk-LSW2OJVV.js +380 -0
  91. package/dist/chunk-LSW2OJVV.js.map +1 -0
  92. package/dist/chunk-M357MHH3.js +2 -0
  93. package/dist/chunk-M357MHH3.js.map +1 -0
  94. package/dist/chunk-MK2TQO4Y.js +24 -0
  95. package/dist/chunk-MK2TQO4Y.js.map +1 -0
  96. package/dist/chunk-N7S72EXK.js +25 -0
  97. package/dist/chunk-N7S72EXK.js.map +1 -0
  98. package/dist/{chunk-YVCHAQZY.js → chunk-NKMYZFHA.js} +616 -621
  99. package/dist/chunk-NKMYZFHA.js.map +1 -0
  100. package/dist/chunk-NX4ADH73.js +14 -0
  101. package/dist/chunk-NX4ADH73.js.map +1 -0
  102. package/dist/chunk-O7F6UJO4.js +71 -0
  103. package/dist/chunk-O7F6UJO4.js.map +1 -0
  104. package/dist/chunk-OYQQJL3J.js +16 -0
  105. package/dist/chunk-OYQQJL3J.js.map +1 -0
  106. package/dist/{chunk-H5YGYNXS.js → chunk-P4BNUO57.js} +60 -17
  107. package/dist/chunk-P4BNUO57.js.map +1 -0
  108. package/dist/{chunk-JVYQRRC4.js → chunk-PEHTX3V7.js} +21 -1
  109. package/dist/chunk-PEHTX3V7.js.map +1 -0
  110. package/dist/chunk-PMV53IMM.js +26 -0
  111. package/dist/chunk-PMV53IMM.js.map +1 -0
  112. package/dist/{chunk-KCGXPP5V.js → chunk-PYEOPA4M.js} +13 -7
  113. package/dist/chunk-PYEOPA4M.js.map +1 -0
  114. package/dist/{chunk-KZ73RL76.js → chunk-QHUE7E4N.js} +8 -3
  115. package/dist/chunk-QHUE7E4N.js.map +1 -0
  116. package/dist/chunk-QV3DJVRZ.js +11 -0
  117. package/dist/chunk-QV3DJVRZ.js.map +1 -0
  118. package/dist/chunk-R5SBNG7S.js +810 -0
  119. package/dist/chunk-R5SBNG7S.js.map +1 -0
  120. package/dist/chunk-RI42H5IU.js +326 -0
  121. package/dist/chunk-RI42H5IU.js.map +1 -0
  122. package/dist/chunk-S2QH6EZ5.js +211 -0
  123. package/dist/chunk-S2QH6EZ5.js.map +1 -0
  124. package/dist/chunk-SHLZMAJN.js +304 -0
  125. package/dist/chunk-SHLZMAJN.js.map +1 -0
  126. package/dist/chunk-TGXK4BAZ.js +293 -0
  127. package/dist/chunk-TGXK4BAZ.js.map +1 -0
  128. package/dist/{chunk-5YK2ZDIG.js → chunk-TNEZNMSN.js} +4 -10
  129. package/dist/chunk-TNEZNMSN.js.map +1 -0
  130. package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
  131. package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
  132. package/dist/chunk-UNJPZGNK.js +63 -0
  133. package/dist/chunk-UNJPZGNK.js.map +1 -0
  134. package/dist/{chunk-IOLVN74D.js → chunk-V5ZUJT2T.js} +175 -42
  135. package/dist/chunk-V5ZUJT2T.js.map +1 -0
  136. package/dist/chunk-WBJY57A3.js +402 -0
  137. package/dist/chunk-WBJY57A3.js.map +1 -0
  138. package/dist/chunk-WIUKB3LD.js +1911 -0
  139. package/dist/chunk-WIUKB3LD.js.map +1 -0
  140. package/dist/{chunk-ICA6R6TW.js → chunk-WNN7NO2N.js} +1451 -355
  141. package/dist/chunk-WNN7NO2N.js.map +1 -0
  142. package/dist/{chunk-3AGBGTRT.js → chunk-X5UVUIMF.js} +1712 -1174
  143. package/dist/chunk-X5UVUIMF.js.map +1 -0
  144. package/dist/chunk-XDA5QJE7.js +402 -0
  145. package/dist/chunk-XDA5QJE7.js.map +1 -0
  146. package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
  147. package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
  148. package/dist/chunk-XHF7OYAN.js +1150 -0
  149. package/dist/chunk-XHF7OYAN.js.map +1 -0
  150. package/dist/chunk-YSRBFJMQ.js +43 -0
  151. package/dist/chunk-YSRBFJMQ.js.map +1 -0
  152. package/dist/chunk-ZOZAPAUO.js +174 -0
  153. package/dist/chunk-ZOZAPAUO.js.map +1 -0
  154. package/dist/chunk-ZQV5W7YC.js +809 -0
  155. package/dist/chunk-ZQV5W7YC.js.map +1 -0
  156. package/dist/chunk-ZUWF4NF7.js +13 -0
  157. package/dist/chunk-ZUWF4NF7.js.map +1 -0
  158. package/dist/client.d.ts +16 -7
  159. package/dist/clipboard.js +3 -1
  160. package/dist/commands/types.d.ts +2 -0
  161. package/dist/components/anthropic-mark.d.ts +3 -0
  162. package/dist/components/approval-surface.d.ts +19 -6
  163. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  164. package/dist/components/artifacts/artifact-sandbox.d.ts +30 -0
  165. package/dist/components/artifacts/artifact-surface.d.ts +4 -2
  166. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  167. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  168. package/dist/components/artifacts/document-editor.d.ts +4 -2
  169. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  170. package/dist/components/artifacts/editable-artifact-view.d.ts +48 -0
  171. package/dist/components/artifacts/editable-document.d.ts +1 -1
  172. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  173. package/dist/components/artifacts/editable-spreadsheet.d.ts +8 -3
  174. package/dist/components/artifacts/index.d.ts +9 -2
  175. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  176. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  177. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  178. package/dist/components/artifacts/published-html-artifact-frame.d.ts +23 -3
  179. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  180. package/dist/components/artifacts/site-view.d.ts +26 -0
  181. package/dist/components/artifacts/spreadsheet-command-queue.d.ts +20 -0
  182. package/dist/components/artifacts/spreadsheet-download.d.ts +7 -0
  183. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  184. package/dist/components/artifacts/spreadsheet-grid.d.ts +10 -3
  185. package/dist/components/artifacts/spreadsheet-resize.d.ts +50 -0
  186. package/dist/components/artifacts/spreadsheet-submissions.d.ts +9 -0
  187. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  188. package/dist/components/browser-select-control.d.ts +16 -0
  189. package/dist/components/browser-viewer.d.ts +11 -2
  190. package/dist/components/chat-composer.d.ts +21 -3
  191. package/dist/components/child-session-link.d.ts +9 -0
  192. package/dist/components/claude-mark.d.ts +3 -0
  193. package/dist/components/code-editor.d.ts +1 -4
  194. package/dist/components/composer-transcription-control.d.ts +7 -0
  195. package/dist/components/composer.d.ts +34 -67
  196. package/dist/components/computer-viewer.d.ts +1 -1
  197. package/dist/components/copy-button.d.ts +3 -1
  198. package/dist/components/desktop-viewer.d.ts +1 -1
  199. package/dist/components/grok-mark.d.ts +26 -0
  200. package/dist/components/human-input-form.d.ts +28 -32
  201. package/dist/components/human-input-surface.d.ts +7 -2
  202. package/dist/components/linkified-text.d.ts +18 -0
  203. package/dist/components/machine-input-display.d.ts +22 -1
  204. package/dist/components/machines/agent-status-icon.d.ts +6 -0
  205. package/dist/components/machines/machine-detail.d.ts +7 -1
  206. package/dist/components/machines/machine-status.d.ts +48 -0
  207. package/dist/components/markdown-table-layout.d.ts +18 -0
  208. package/dist/components/markdown.d.ts +37 -4
  209. package/dist/components/message-timeline.d.ts +86 -7
  210. package/dist/components/model-mark.d.ts +29 -0
  211. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  212. package/dist/components/model-policy-picker.d.ts +35 -28
  213. package/dist/components/new-conversation.d.ts +32 -0
  214. package/dist/components/open-geni-chat.d.ts +73 -0
  215. package/dist/components/open-geni-links.d.ts +68 -0
  216. package/dist/components/openrouter-mark.d.ts +6 -0
  217. package/dist/components/opper-mark.d.ts +7 -0
  218. package/dist/components/preview-loading.d.ts +2 -0
  219. package/dist/components/provider-recovery-notice.d.ts +16 -0
  220. package/dist/components/queue-item-content.d.ts +9 -0
  221. package/dist/components/rehype-secret-refs.d.ts +23 -0
  222. package/dist/components/remark-soft-line-breaks.d.ts +38 -0
  223. package/dist/components/sandbox-files.d.ts +3 -1
  224. package/dist/components/sandbox-workspace.d.ts +18 -0
  225. package/dist/components/secret-question-field.d.ts +31 -0
  226. package/dist/components/secret-ref-chip.d.ts +35 -0
  227. package/dist/components/session-capability-frame.d.ts +37 -0
  228. package/dist/components/session-chrome.d.ts +57 -8
  229. package/dist/components/session-commands-panel.d.ts +6 -0
  230. package/dist/components/session-commands.d.ts +6 -0
  231. package/dist/components/session-connection-request.d.ts +8 -0
  232. package/dist/components/session-conversation.d.ts +157 -0
  233. package/dist/components/session-list.d.ts +39 -0
  234. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  235. package/dist/components/session-proxy-scope.d.ts +35 -0
  236. package/dist/components/session-status.d.ts +4 -1
  237. package/dist/components/session-usage-limit-notice.d.ts +39 -0
  238. package/dist/components/timeline-anchor.d.ts +24 -0
  239. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  240. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  241. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  242. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  243. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  244. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  245. package/dist/components/timeline-annotations.d.ts +13 -3
  246. package/dist/components/timeline-reading-progress.d.ts +11 -0
  247. package/dist/components/timeline-search.d.ts +34 -0
  248. package/dist/components/timeline-settlement.d.ts +16 -0
  249. package/dist/components/tool-action-review.d.ts +47 -0
  250. package/dist/components/tool-review-history.d.ts +25 -0
  251. package/dist/components/usage-limit-notice.d.ts +49 -0
  252. package/dist/components/usage-member-list.d.ts +91 -0
  253. package/dist/components/usage-meter.d.ts +73 -0
  254. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  255. package/dist/components/user-message-body.d.ts +10 -1
  256. package/dist/composer-messages.d.ts +74 -0
  257. package/dist/composer-messages.js +9 -0
  258. package/dist/composer-messages.js.map +1 -0
  259. package/dist/composer-voice-events.d.ts +8 -0
  260. package/dist/composer.d.ts +5 -4
  261. package/dist/composer.js +26 -13
  262. package/dist/computer-viewer-GMLDXPON.js +20 -0
  263. package/dist/computer-viewer-GMLDXPON.js.map +1 -0
  264. package/dist/connect-account-identity.d.ts +8 -0
  265. package/dist/connect-accounts.d.ts +15 -0
  266. package/dist/connect-chooser.d.ts +18 -0
  267. package/dist/connect-panel.d.ts +18 -0
  268. package/dist/connect-setup.d.ts +18 -0
  269. package/dist/connect.d.ts +21 -0
  270. package/dist/connect.js +2149 -0
  271. package/dist/connect.js.map +1 -0
  272. package/dist/connection-catalog.d.ts +38 -0
  273. package/dist/connection-discovery.d.ts +12 -0
  274. package/dist/connection-installed.d.ts +17 -0
  275. package/dist/connection-logo.d.ts +9 -0
  276. package/dist/connection-service-logo.d.ts +8 -0
  277. package/dist/connection-service-presentation.d.ts +13 -0
  278. package/dist/connection-skeleton.d.ts +5 -0
  279. package/dist/connection-type-picker.d.ts +6 -0
  280. package/dist/conversation-timeline.d.ts +5 -0
  281. package/dist/desktop.d.ts +7 -0
  282. package/dist/desktop.js +27 -0
  283. package/dist/desktop.js.map +1 -0
  284. package/dist/device-authorization.d.ts +23 -0
  285. package/dist/diffs.d.ts +8 -0
  286. package/dist/diffs.js +15 -0
  287. package/dist/diffs.js.map +1 -0
  288. package/dist/discovery-cache.d.ts +5 -0
  289. package/dist/editor.d.ts +7 -0
  290. package/dist/editor.js +22 -0
  291. package/dist/editor.js.map +1 -0
  292. package/dist/embedded-new-voice-OCRNT6U5.js +18 -0
  293. package/dist/embedded-new-voice-OCRNT6U5.js.map +1 -0
  294. package/dist/embedded-voice-RPHPYVBT.js +18 -0
  295. package/dist/embedded-voice-RPHPYVBT.js.map +1 -0
  296. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-SI63O5V4.js} +4 -1
  297. package/dist/fleet-decision-row-SI63O5V4.js.map +1 -0
  298. package/dist/hooks/latest-question.d.ts +25 -0
  299. package/dist/hooks/shared-machines-list.d.ts +4 -0
  300. package/dist/hooks/shared-query.d.ts +113 -0
  301. package/dist/hooks/use-attached-browsers.d.ts +1 -1
  302. package/dist/hooks/use-auth-runs.d.ts +1 -4
  303. package/dist/hooks/use-available-models.d.ts +1 -1
  304. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  305. package/dist/hooks/use-browser-session.d.ts +12 -1
  306. package/dist/hooks/use-client-config-flags.d.ts +49 -0
  307. package/dist/hooks/use-codex-accounts.d.ts +59 -10
  308. package/dist/hooks/use-composer.d.ts +24 -2
  309. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  310. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  311. package/dist/hooks/use-computer-session.d.ts +4 -0
  312. package/dist/hooks/use-connect.d.ts +23 -0
  313. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  314. package/dist/hooks/use-file-attachments.d.ts +12 -0
  315. package/dist/hooks/use-goal.d.ts +2 -1
  316. package/dist/hooks/use-last-started-turn-policy.d.ts +5 -1
  317. package/dist/hooks/use-new-conversation.d.ts +56 -0
  318. package/dist/hooks/use-new-session-draft.d.ts +74 -0
  319. package/dist/hooks/use-realtime-voice-models.d.ts +7 -0
  320. package/dist/hooks/use-sandbox-files.d.ts +4 -1
  321. package/dist/hooks/use-session-conversation.d.ts +49 -0
  322. package/dist/hooks/use-session-events.d.ts +26 -5
  323. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  324. package/dist/hooks/use-session-model-account.d.ts +48 -0
  325. package/dist/hooks/use-supergrok-accounts.d.ts +7 -1
  326. package/dist/hooks/use-terminal-stream.d.ts +11 -5
  327. package/dist/hooks/use-usage.d.ts +40 -0
  328. package/dist/hooks/use-vaults.d.ts +53 -0
  329. package/dist/hooks/use-voice-input.d.ts +8 -1
  330. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  331. package/dist/hooks/use-workspace-sessions.d.ts +24 -5
  332. package/dist/human-input-model.d.ts +122 -0
  333. package/dist/identity-link-accounts.d.ts +11 -0
  334. package/dist/identity-link-consent.d.ts +18 -0
  335. package/dist/index.d.ts +82 -20
  336. package/dist/index.js +2340 -6603
  337. package/dist/index.js.map +1 -1
  338. package/dist/interaction.d.ts +1 -1
  339. package/dist/interaction.js +14 -24
  340. package/dist/interaction.js.map +1 -1
  341. package/dist/latest-question-R77KWSUP.js +118 -0
  342. package/dist/latest-question-R77KWSUP.js.map +1 -0
  343. package/dist/lib/clipboard.d.ts +7 -0
  344. package/dist/lib/error-message.d.ts +7 -0
  345. package/dist/lib/format.d.ts +58 -4
  346. package/dist/lib/host-theme.d.ts +77 -0
  347. package/dist/lib/interaction-errors.d.ts +3 -0
  348. package/dist/lib/menu-styles.d.ts +22 -0
  349. package/dist/lib/notify-observer.d.ts +2 -0
  350. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  351. package/dist/lib/provider-recovery.d.ts +55 -0
  352. package/dist/lib/scrollbars.d.ts +11 -0
  353. package/dist/lib/terminal-input-readiness.d.ts +11 -0
  354. package/dist/lib/transient-retry.d.ts +25 -0
  355. package/dist/lib/workbench-peers.d.ts +36 -0
  356. package/dist/lib/xterm-theme.d.ts +7 -5
  357. package/dist/machines.js +9 -5
  358. package/dist/markdown-table-layout-3PV2UAAH.js +113 -0
  359. package/dist/markdown-table-layout-3PV2UAAH.js.map +1 -0
  360. package/dist/mcp-connection-status.d.ts +14 -0
  361. package/dist/model-mark-paths.d.ts +34 -0
  362. package/dist/model-mark-paths.js +16 -0
  363. package/dist/model-mark-paths.js.map +1 -0
  364. package/dist/model-picker-model.d.ts +111 -0
  365. package/dist/model-picker-model.js +25 -0
  366. package/dist/model-picker-model.js.map +1 -0
  367. package/dist/model-policy-picker-menu-7GJ5URPR.js +17 -0
  368. package/dist/model-policy-picker-menu-7GJ5URPR.js.map +1 -0
  369. package/dist/model-policy.d.ts +30 -3
  370. package/dist/model-policy.js +14 -1
  371. package/dist/native-previews.d.ts +28 -0
  372. package/dist/native-previews.js +82 -0
  373. package/dist/native-previews.js.map +1 -0
  374. package/dist/new-session-draft.d.ts +7 -0
  375. package/dist/new-session-draft.js +639 -0
  376. package/dist/new-session-draft.js.map +1 -0
  377. package/dist/notification-text.d.ts +27 -0
  378. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
  379. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
  380. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
  381. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
  382. package/dist/older-history.d.ts +3 -2
  383. package/dist/organization-model.d.ts +32 -0
  384. package/dist/organization-model.js +65 -0
  385. package/dist/organization-model.js.map +1 -0
  386. package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-5OCKOQWZ.js} +16 -78
  387. package/dist/platform-activity-row-5OCKOQWZ.js.map +1 -0
  388. package/dist/plugin-details.d.ts +14 -0
  389. package/dist/plugin-discovery.d.ts +25 -0
  390. package/dist/preview-loading-paint.d.ts +20 -0
  391. package/dist/provider.d.ts +25 -2
  392. package/dist/queue-presentation-model.d.ts +72 -0
  393. package/dist/queue-presentation-model.js +38 -0
  394. package/dist/queue-presentation-model.js.map +1 -0
  395. package/dist/{queue-surface-implementation-BSKUWHRI.js → queue-surface-implementation-GJBH7NKO.js} +65 -265
  396. package/dist/queue-surface-implementation-GJBH7NKO.js.map +1 -0
  397. package/dist/realtime/embedded-new-voice.d.ts +1 -0
  398. package/dist/realtime/embedded-voice.d.ts +1 -0
  399. package/dist/realtime/realtime-control.d.ts +4 -65
  400. package/dist/realtime/session-realtime.d.ts +78 -0
  401. package/dist/realtime.js +25 -1333
  402. package/dist/realtime.js.map +1 -1
  403. package/dist/sandbox-files-O27IPOZW.js +21 -0
  404. package/dist/sandbox-files-O27IPOZW.js.map +1 -0
  405. package/dist/sandbox-label-model.d.ts +30 -0
  406. package/dist/sandbox-label-model.js +20 -0
  407. package/dist/sandbox-label-model.js.map +1 -0
  408. package/dist/scrollbars.d.ts +1 -0
  409. package/dist/scrollbars.js +10 -0
  410. package/dist/scrollbars.js.map +1 -0
  411. package/dist/secret-reference-label.d.ts +14 -0
  412. package/dist/secrets-ui.d.ts +57 -0
  413. package/dist/session-agents-model.d.ts +10 -0
  414. package/dist/session-agents-model.js +25 -0
  415. package/dist/session-agents-model.js.map +1 -0
  416. package/dist/session-attention-model.d.ts +8 -0
  417. package/dist/session-attention-model.js +47 -0
  418. package/dist/session-attention-model.js.map +1 -0
  419. package/dist/session-auth-recommendation.d.ts +5 -0
  420. package/dist/session-capability-policy.d.ts +31 -0
  421. package/dist/session-feedback-model.d.ts +20 -0
  422. package/dist/session-feedback-model.js +56 -0
  423. package/dist/session-feedback-model.js.map +1 -0
  424. package/dist/session-list-model.d.ts +138 -0
  425. package/dist/session-list-model.js +274 -0
  426. package/dist/session-list-model.js.map +1 -0
  427. package/dist/session-realtime-7DJOIHQW.js +21 -0
  428. package/dist/session-realtime-7DJOIHQW.js.map +1 -0
  429. package/dist/session-realtime.d.ts +7 -0
  430. package/dist/session-realtime.js +19 -0
  431. package/dist/session-realtime.js.map +1 -0
  432. package/dist/session-status-model.d.ts +36 -0
  433. package/dist/session-ui.d.ts +39 -1
  434. package/dist/session-ui.js +126 -12
  435. package/dist/session-ui.js.map +1 -1
  436. package/dist/session.d.ts +8 -2
  437. package/dist/session.js +35 -20
  438. package/dist/site-snapshot.d.ts +14 -0
  439. package/dist/sites-ui.d.ts +24 -0
  440. package/dist/sites.d.ts +3 -0
  441. package/dist/sites.js +14 -0
  442. package/dist/sites.js.map +1 -0
  443. package/dist/skill-discovery.d.ts +47 -0
  444. package/dist/terminal.d.ts +8 -0
  445. package/dist/terminal.js +32 -0
  446. package/dist/terminal.js.map +1 -0
  447. package/dist/testing/session-scenarios.d.ts +10 -0
  448. package/dist/testing/session-scenarios.js +367 -0
  449. package/dist/testing/session-scenarios.js.map +1 -0
  450. package/dist/timeline/activity-rail.d.ts +11 -2
  451. package/dist/timeline/agent-identity.d.ts +30 -0
  452. package/dist/timeline/agent-row.d.ts +31 -0
  453. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  454. package/dist/timeline/compaction-copy.d.ts +46 -0
  455. package/dist/timeline/focus-sequence.d.ts +9 -0
  456. package/dist/timeline/genie-copy.d.ts +3 -0
  457. package/dist/timeline/genie-loading.d.ts +47 -0
  458. package/dist/timeline/index.d.ts +10 -5
  459. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  460. package/dist/timeline/message-sender.d.ts +19 -0
  461. package/dist/timeline/notice-presentation.d.ts +13 -0
  462. package/dist/timeline/parsers.d.ts +11 -0
  463. package/dist/timeline/patch-apply-command.d.ts +18 -0
  464. package/dist/timeline/platform-activity-presentation.d.ts +21 -0
  465. package/dist/timeline/platform-activity-row.d.ts +1 -2
  466. package/dist/timeline/presented-image.d.ts +11 -0
  467. package/dist/timeline/projection.d.ts +31 -2
  468. package/dist/timeline/provider-logo.d.ts +15 -0
  469. package/dist/timeline/question-nav-model.d.ts +23 -0
  470. package/dist/timeline/registry.d.ts +12 -1
  471. package/dist/timeline/retained-image.d.ts +18 -0
  472. package/dist/timeline/retained-loaders.d.ts +27 -0
  473. package/dist/timeline/rolling-activity.d.ts +11 -0
  474. package/dist/timeline/screenshot-lightbox.d.ts +23 -1
  475. package/dist/timeline/session-usage-limit-row.d.ts +11 -0
  476. package/dist/timeline/shared.d.ts +4 -1
  477. package/dist/timeline/startup-dispatch-details.d.ts +5 -0
  478. package/dist/timeline/startup-preference.d.ts +3 -0
  479. package/dist/timeline/startup-timings.d.ts +4 -0
  480. package/dist/timeline/tool-display-name.d.ts +5 -2
  481. package/dist/timeline/tool-presentation.d.ts +172 -0
  482. package/dist/timeline/turn-summary-model.d.ts +95 -0
  483. package/dist/timeline/turn-summary.d.ts +20 -54
  484. package/dist/timeline/types.d.ts +179 -7
  485. package/dist/timeline/work-presentation.d.ts +60 -0
  486. package/dist/timeline-annotation-markers-U3G66KUD.js +166 -0
  487. package/dist/timeline-annotation-markers-U3G66KUD.js.map +1 -0
  488. package/dist/timeline-annotation-selection-BI7QTPTZ.js +242 -0
  489. package/dist/timeline-annotation-selection-BI7QTPTZ.js.map +1 -0
  490. package/dist/timeline-annotations-dialog-FOMHSDTE.js +274 -0
  491. package/dist/timeline-annotations-dialog-FOMHSDTE.js.map +1 -0
  492. package/dist/timeline-model.d.ts +29 -0
  493. package/dist/timeline-model.js +254 -0
  494. package/dist/timeline-model.js.map +1 -0
  495. package/dist/usage/allowance-copy.d.ts +25 -0
  496. package/dist/usage/session-usage-limit.d.ts +88 -0
  497. package/dist/usage/summary.d.ts +35 -0
  498. package/dist/usage.d.ts +17 -0
  499. package/dist/usage.js +1187 -0
  500. package/dist/usage.js.map +1 -0
  501. package/dist/voice-recording-owner.d.ts +7 -0
  502. package/package.json +106 -7
  503. package/src/approvals.ts +8 -1
  504. package/src/artifacts-spreadsheet.ts +1 -0
  505. package/src/artifacts.ts +44 -0
  506. package/src/assets/README.md +8 -0
  507. package/src/assets/gmail.ico +0 -0
  508. package/src/assets/outlook.ico +0 -0
  509. package/src/capability-catalog-row.tsx +94 -0
  510. package/src/capability-logo-fallback.ts +22 -0
  511. package/src/client.ts +20 -31
  512. package/src/commands/registry.ts +18 -15
  513. package/src/commands/types.ts +2 -0
  514. package/src/components/anthropic-mark.tsx +10 -0
  515. package/src/components/approval-surface.tsx +401 -138
  516. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  517. package/src/components/artifacts/artifact-sandbox.tsx +193 -0
  518. package/src/components/artifacts/artifact-surface.tsx +40 -20
  519. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  520. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  521. package/src/components/artifacts/document-editor.tsx +141 -16
  522. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  523. package/src/components/artifacts/editable-artifact-view.tsx +197 -0
  524. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  525. package/src/components/artifacts/editable-document.tsx +37 -36
  526. package/src/components/artifacts/editable-presentation.tsx +36 -18
  527. package/src/components/artifacts/editable-spreadsheet.tsx +543 -103
  528. package/src/components/artifacts/index.ts +45 -0
  529. package/src/components/artifacts/inline-html-document.ts +24 -0
  530. package/src/components/artifacts/latest-task-runner.ts +49 -0
  531. package/src/components/artifacts/presentation-editor.tsx +323 -67
  532. package/src/components/artifacts/published-html-artifact-frame.tsx +122 -5
  533. package/src/components/artifacts/session-artifact-viewer.tsx +378 -0
  534. package/src/components/artifacts/site-view.tsx +121 -0
  535. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  536. package/src/components/artifacts/spreadsheet-command-queue.ts +184 -0
  537. package/src/components/artifacts/spreadsheet-download.tsx +109 -0
  538. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  539. package/src/components/artifacts/spreadsheet-grid.tsx +344 -144
  540. package/src/components/artifacts/spreadsheet-resize.tsx +421 -0
  541. package/src/components/artifacts/spreadsheet-submissions.tsx +46 -0
  542. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  543. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  544. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  545. package/src/components/browser-select-control.tsx +312 -0
  546. package/src/components/browser-viewer.tsx +778 -318
  547. package/src/components/chat-composer.tsx +47 -5
  548. package/src/components/child-session-link.tsx +36 -0
  549. package/src/components/claude-mark.tsx +11 -0
  550. package/src/components/code-editor.tsx +13 -16
  551. package/src/components/composer-transcription-control.tsx +128 -30
  552. package/src/components/composer.tsx +404 -195
  553. package/src/components/computer-viewer.tsx +880 -253
  554. package/src/components/copy-button.tsx +13 -5
  555. package/src/components/desktop-viewer.tsx +1 -1
  556. package/src/components/enrollment-consent.tsx +1 -1
  557. package/src/components/enrollment-device-flow.tsx +1 -1
  558. package/src/components/file-browser.tsx +10 -14
  559. package/src/components/fleet-tile.tsx +5 -3
  560. package/src/components/generated-video-player.tsx +4 -2
  561. package/src/components/grok-mark.tsx +34 -0
  562. package/src/components/human-input-form.tsx +590 -283
  563. package/src/components/human-input-surface.tsx +11 -0
  564. package/src/components/interaction-intervention-banner.tsx +2 -2
  565. package/src/components/linkified-text.tsx +79 -0
  566. package/src/components/machine-card.tsx +35 -78
  567. package/src/components/machine-dock-bar.tsx +1 -1
  568. package/src/components/machine-input-display.ts +197 -3
  569. package/src/components/machines/agent-status-icon.tsx +31 -0
  570. package/src/components/machines/machine-detail.tsx +200 -31
  571. package/src/components/machines/machine-operation-policy.tsx +1 -1
  572. package/src/components/machines/machine-status.ts +241 -0
  573. package/src/components/machines-dashboard.tsx +2 -17
  574. package/src/components/markdown-table-layout.ts +143 -0
  575. package/src/components/markdown.tsx +466 -129
  576. package/src/components/message-timeline.tsx +2370 -667
  577. package/src/components/model-mark.tsx +102 -0
  578. package/src/components/model-picker.tsx +15 -4
  579. package/src/components/model-policy-picker-menu.tsx +371 -0
  580. package/src/components/model-policy-picker.tsx +252 -429
  581. package/src/components/new-conversation.tsx +221 -0
  582. package/src/components/open-geni-chat.tsx +309 -0
  583. package/src/components/open-geni-links.tsx +179 -0
  584. package/src/components/openrouter-mark.tsx +13 -0
  585. package/src/components/opper-mark.tsx +18 -0
  586. package/src/components/pierre-diff.tsx +41 -16
  587. package/src/components/pierre-file.tsx +35 -10
  588. package/src/components/preview-loading.tsx +109 -0
  589. package/src/components/provider-recovery-notice.tsx +49 -0
  590. package/src/components/queue-item-content.ts +14 -0
  591. package/src/components/queue-surface-implementation.tsx +51 -356
  592. package/src/components/queue-surface-state.tsx +3 -1
  593. package/src/components/rehype-secret-refs.ts +98 -0
  594. package/src/components/remark-soft-line-breaks.ts +166 -0
  595. package/src/components/sandbox-files.tsx +91 -15
  596. package/src/components/sandbox-terminal.tsx +84 -13
  597. package/src/components/sandbox-workspace.tsx +147 -51
  598. package/src/components/secret-question-field.tsx +324 -0
  599. package/src/components/secret-ref-chip.tsx +185 -0
  600. package/src/components/session-capability-frame.tsx +197 -0
  601. package/src/components/session-chrome.tsx +842 -251
  602. package/src/components/session-commands-panel.tsx +126 -0
  603. package/src/components/session-commands.tsx +18 -0
  604. package/src/components/session-connection-request.tsx +97 -0
  605. package/src/components/session-conversation.tsx +876 -0
  606. package/src/components/session-list.tsx +257 -0
  607. package/src/components/session-mcp-capability-card.tsx +680 -0
  608. package/src/components/session-proxy-scope.tsx +153 -0
  609. package/src/components/session-status.tsx +26 -17
  610. package/src/components/session-usage-limit-notice.tsx +174 -0
  611. package/src/components/timeline-anchor.tsx +119 -0
  612. package/src/components/timeline-annotation-chrome.tsx +196 -0
  613. package/src/components/timeline-annotation-layout.ts +268 -0
  614. package/src/components/timeline-annotation-markers.tsx +185 -0
  615. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  616. package/src/components/timeline-annotation-selection.tsx +106 -54
  617. package/src/components/timeline-annotation-shared.ts +245 -0
  618. package/src/components/timeline-annotations-dialog.tsx +185 -128
  619. package/src/components/timeline-annotations.tsx +189 -45
  620. package/src/components/timeline-reading-progress.ts +80 -0
  621. package/src/components/timeline-search.tsx +168 -0
  622. package/src/components/timeline-settlement.ts +60 -0
  623. package/src/components/tool-action-review.tsx +650 -0
  624. package/src/components/tool-review-history.tsx +88 -0
  625. package/src/components/usage-limit-notice.tsx +179 -0
  626. package/src/components/usage-member-list.tsx +792 -0
  627. package/src/components/usage-meter.tsx +382 -0
  628. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  629. package/src/components/user-message-body.tsx +27 -2
  630. package/src/components/workspace-dock.tsx +18 -1
  631. package/src/composer-messages.ts +150 -0
  632. package/src/composer-voice-events.ts +12 -0
  633. package/src/composer.ts +6 -1
  634. package/src/connect-account-identity.tsx +34 -0
  635. package/src/connect-accounts.tsx +233 -0
  636. package/src/connect-chooser.tsx +336 -0
  637. package/src/connect-panel.tsx +99 -0
  638. package/src/connect-setup.tsx +355 -0
  639. package/src/connect.ts +60 -0
  640. package/src/connection-assets.d.ts +4 -0
  641. package/src/connection-catalog.tsx +162 -0
  642. package/src/connection-discovery.tsx +238 -0
  643. package/src/connection-installed.tsx +51 -0
  644. package/src/connection-logo.tsx +37 -0
  645. package/src/connection-service-logo.tsx +55 -0
  646. package/src/connection-service-presentation.ts +46 -0
  647. package/src/connection-skeleton.tsx +16 -0
  648. package/src/connection-type-picker.tsx +36 -0
  649. package/src/conversation-timeline.ts +92 -0
  650. package/src/desktop.ts +24 -0
  651. package/src/device-authorization.tsx +98 -0
  652. package/src/diffs.ts +16 -0
  653. package/src/discovery-cache.ts +42 -0
  654. package/src/editor.ts +13 -0
  655. package/src/hooks/internal.ts +3 -2
  656. package/src/hooks/latest-question.ts +164 -0
  657. package/src/hooks/shared-machines-list.ts +34 -1
  658. package/src/hooks/shared-query.ts +721 -0
  659. package/src/hooks/use-attached-browsers.ts +1 -1
  660. package/src/hooks/use-auth-runs.ts +0 -27
  661. package/src/hooks/use-available-models.ts +2 -2
  662. package/src/hooks/use-browser-frame-stream.ts +19 -2
  663. package/src/hooks/use-browser-session.ts +680 -205
  664. package/src/hooks/use-browser-sessions.ts +32 -1
  665. package/src/hooks/use-client-config-flags.ts +118 -0
  666. package/src/hooks/use-codex-accounts.ts +247 -47
  667. package/src/hooks/use-composer.ts +227 -44
  668. package/src/hooks/use-computer-frame-stream.ts +25 -7
  669. package/src/hooks/use-computer-input-posture.ts +94 -0
  670. package/src/hooks/use-computer-session.ts +409 -95
  671. package/src/hooks/use-connect.ts +23 -0
  672. package/src/hooks/use-desktop-stream.ts +19 -28
  673. package/src/hooks/use-file-attachments.ts +80 -4
  674. package/src/hooks/use-goal.ts +79 -9
  675. package/src/hooks/use-last-started-turn-policy.ts +37 -11
  676. package/src/hooks/use-machines.ts +4 -0
  677. package/src/hooks/use-new-conversation.ts +374 -0
  678. package/src/hooks/use-new-session-draft.ts +813 -0
  679. package/src/hooks/use-realtime-voice-models.ts +46 -0
  680. package/src/hooks/use-sandbox-files.ts +68 -20
  681. package/src/hooks/use-session-background-commands.ts +22 -11
  682. package/src/hooks/use-session-capabilities.ts +3 -2
  683. package/src/hooks/use-session-conversation.ts +150 -0
  684. package/src/hooks/use-session-events.ts +531 -335
  685. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  686. package/src/hooks/use-session-model-account.ts +174 -0
  687. package/src/hooks/use-session.ts +30 -2
  688. package/src/hooks/use-slash-commands.ts +6 -11
  689. package/src/hooks/use-supergrok-accounts.ts +22 -8
  690. package/src/hooks/use-terminal-stream.ts +153 -27
  691. package/src/hooks/use-transcription.ts +6 -0
  692. package/src/hooks/use-turn-queue.ts +2 -1
  693. package/src/hooks/use-usage.ts +100 -0
  694. package/src/hooks/use-vaults.ts +153 -0
  695. package/src/hooks/use-video-artifact-playback.ts +1 -1
  696. package/src/hooks/use-voice-input.ts +127 -19
  697. package/src/hooks/use-workspace-capture.ts +3 -2
  698. package/src/hooks/use-workspace-edit.ts +23 -5
  699. package/src/hooks/use-workspace-sessions.ts +74 -7
  700. package/src/human-input-model.ts +359 -0
  701. package/src/identity-link-accounts.tsx +148 -0
  702. package/src/identity-link-consent.tsx +192 -0
  703. package/src/index.ts +262 -16
  704. package/src/interaction.ts +1 -0
  705. package/src/lib/clipboard.ts +29 -0
  706. package/src/lib/error-message.ts +37 -0
  707. package/src/lib/format.ts +205 -10
  708. package/src/lib/host-theme.ts +529 -0
  709. package/src/lib/interaction-errors.ts +15 -0
  710. package/src/lib/menu-styles.ts +44 -0
  711. package/src/lib/notify-observer.ts +15 -0
  712. package/src/lib/pierre-diffs-loader.ts +53 -0
  713. package/src/lib/provider-recovery.ts +243 -0
  714. package/src/lib/scrollbars.ts +30 -0
  715. package/src/lib/terminal-input-readiness.ts +51 -0
  716. package/src/lib/transient-retry.ts +99 -0
  717. package/src/lib/workbench-peers.ts +62 -0
  718. package/src/lib/xterm-theme.ts +23 -21
  719. package/src/mcp-connection-status.ts +35 -0
  720. package/src/model-mark-paths.ts +53 -0
  721. package/src/model-picker-model.ts +330 -0
  722. package/src/model-policy.ts +299 -74
  723. package/src/native-previews.ts +100 -0
  724. package/src/new-session-draft.ts +22 -0
  725. package/src/notification-text.ts +81 -0
  726. package/src/older-history.ts +22 -4
  727. package/src/organization-model.ts +118 -0
  728. package/src/plugin-details.tsx +185 -0
  729. package/src/plugin-discovery.tsx +196 -0
  730. package/src/preview-loading-paint.ts +68 -0
  731. package/src/provider.tsx +74 -15
  732. package/src/queue-presentation-model.ts +464 -0
  733. package/src/realtime/dropdown-menu.tsx +19 -12
  734. package/src/realtime/embedded-new-voice.tsx +1 -0
  735. package/src/realtime/embedded-voice.tsx +3 -0
  736. package/src/realtime/realtime-control.tsx +138 -550
  737. package/src/realtime/session-realtime.ts +566 -0
  738. package/src/sandbox-label-model.ts +53 -0
  739. package/src/scrollbars.ts +3 -0
  740. package/src/secret-reference-label.ts +43 -0
  741. package/src/secrets-ui.tsx +59 -0
  742. package/src/session-agents-model.ts +33 -0
  743. package/src/session-attention-model.ts +62 -0
  744. package/src/session-auth-recommendation.ts +48 -0
  745. package/src/session-capability-policy.ts +196 -0
  746. package/src/session-context.ts +3 -4
  747. package/src/session-feedback-model.ts +95 -0
  748. package/src/session-list-model.ts +434 -0
  749. package/src/session-realtime.ts +18 -0
  750. package/src/session-status-model.ts +99 -0
  751. package/src/session-ui.ts +98 -1
  752. package/src/session.ts +17 -1
  753. package/src/site-snapshot.ts +74 -0
  754. package/src/sites-ui.tsx +348 -0
  755. package/src/sites.ts +3 -0
  756. package/src/skill-discovery.tsx +208 -0
  757. package/src/terminal.ts +26 -0
  758. package/src/testing/session-scenarios.ts +404 -0
  759. package/src/timeline/activity-rail.tsx +242 -101
  760. package/src/timeline/agent-identity.tsx +84 -0
  761. package/src/timeline/agent-row.tsx +231 -0
  762. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  763. package/src/timeline/compaction-copy.ts +115 -0
  764. package/src/timeline/fleet-decision-projection.ts +2 -1
  765. package/src/timeline/fleet-decision-row.tsx +1 -0
  766. package/src/timeline/focus-sequence.ts +44 -0
  767. package/src/timeline/genie-copy.ts +19 -0
  768. package/src/timeline/genie-loading.tsx +143 -0
  769. package/src/timeline/index.ts +30 -2
  770. package/src/timeline/knowledge-receipt.tsx +100 -0
  771. package/src/timeline/message-sender.tsx +71 -0
  772. package/src/timeline/notice-presentation.ts +48 -0
  773. package/src/timeline/parsers.ts +42 -2
  774. package/src/timeline/patch-apply-command.tsx +135 -0
  775. package/src/timeline/platform-activity-presentation.ts +166 -0
  776. package/src/timeline/platform-activity-row.tsx +15 -90
  777. package/src/timeline/presented-image.ts +63 -0
  778. package/src/timeline/projection.ts +1742 -76
  779. package/src/timeline/provider-logo.tsx +53 -0
  780. package/src/timeline/question-nav-model.ts +28 -0
  781. package/src/timeline/registry.ts +26 -4
  782. package/src/timeline/retained-image.ts +97 -0
  783. package/src/timeline/retained-loaders.ts +91 -0
  784. package/src/timeline/rolling-activity.tsx +80 -0
  785. package/src/timeline/screenshot-lightbox.tsx +228 -5
  786. package/src/timeline/session-usage-limit-row.tsx +42 -0
  787. package/src/timeline/shared.tsx +42 -15
  788. package/src/timeline/startup-dispatch-details.tsx +36 -0
  789. package/src/timeline/startup-preference.ts +33 -0
  790. package/src/timeline/startup-timings.tsx +145 -0
  791. package/src/timeline/tool-display-name.ts +19 -7
  792. package/src/timeline/tool-presentation.ts +1316 -0
  793. package/src/timeline/tool-renderers.tsx +835 -1138
  794. package/src/timeline/turn-summary-model.ts +343 -0
  795. package/src/timeline/turn-summary.tsx +272 -365
  796. package/src/timeline/types.ts +189 -6
  797. package/src/timeline/work-presentation.ts +189 -0
  798. package/src/timeline-model.ts +143 -0
  799. package/src/usage/allowance-copy.ts +64 -0
  800. package/src/usage/session-usage-limit.ts +266 -0
  801. package/src/usage/summary.ts +93 -0
  802. package/src/usage.ts +70 -0
  803. package/src/voice-recording-owner.ts +22 -0
  804. package/styles/compiled.css +2319 -748
  805. package/styles/connect.css +290 -0
  806. package/styles/connect.d.ts +1 -0
  807. package/styles/effective-tokens.css +1 -0
  808. package/styles/index.css +309 -9
  809. package/styles/responsive.css +99 -7
  810. package/styles/session-capability.css +44 -0
  811. package/styles/tokens.css +134 -66
  812. package/dist/browser-viewer-MKKFRRRV.js +0 -14
  813. package/dist/chunk-2DZVYHVO.js +0 -470
  814. package/dist/chunk-2DZVYHVO.js.map +0 -1
  815. package/dist/chunk-3AGBGTRT.js.map +0 -1
  816. package/dist/chunk-4MDLEHXL.js.map +0 -1
  817. package/dist/chunk-5YK2ZDIG.js.map +0 -1
  818. package/dist/chunk-7EAFGICR.js +0 -302
  819. package/dist/chunk-7EAFGICR.js.map +0 -1
  820. package/dist/chunk-ELIYWBZR.js.map +0 -1
  821. package/dist/chunk-H5YGYNXS.js.map +0 -1
  822. package/dist/chunk-HUIKIDM5.js.map +0 -1
  823. package/dist/chunk-ICA6R6TW.js.map +0 -1
  824. package/dist/chunk-IOLVN74D.js.map +0 -1
  825. package/dist/chunk-JAQ5K7W6.js.map +0 -1
  826. package/dist/chunk-JVYQRRC4.js.map +0 -1
  827. package/dist/chunk-KCGXPP5V.js.map +0 -1
  828. package/dist/chunk-KZ73RL76.js.map +0 -1
  829. package/dist/chunk-NEXLLTP4.js.map +0 -1
  830. package/dist/chunk-PEI6RANI.js.map +0 -1
  831. package/dist/chunk-VTOREEXF.js +0 -142
  832. package/dist/chunk-VTOREEXF.js.map +0 -1
  833. package/dist/chunk-WSK7G5LE.js +0 -170
  834. package/dist/chunk-WSK7G5LE.js.map +0 -1
  835. package/dist/chunk-X4A66EWZ.js +0 -223
  836. package/dist/chunk-X4A66EWZ.js.map +0 -1
  837. package/dist/chunk-XYRDDSXF.js.map +0 -1
  838. package/dist/chunk-YG4QEQF5.js +0 -9557
  839. package/dist/chunk-YG4QEQF5.js.map +0 -1
  840. package/dist/chunk-YVCHAQZY.js.map +0 -1
  841. package/dist/chunk-ZPBTI3TE.js.map +0 -1
  842. package/dist/computer-viewer-FWEZISW4.js +0 -16
  843. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  844. package/dist/hooks/use-environments.d.ts +0 -41
  845. package/dist/hooks/use-packs.d.ts +0 -32
  846. package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
  847. package/dist/queue-surface-implementation-BSKUWHRI.js.map +0 -1
  848. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  849. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  850. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  851. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  852. package/src/hooks/use-environments.ts +0 -182
  853. package/src/hooks/use-packs.ts +0 -157
  854. /package/dist/{browser-viewer-MKKFRRRV.js.map → browser-viewer-ZWR6MWJ7.js.map} +0 -0
  855. /package/dist/{computer-viewer-FWEZISW4.js.map → chat-interactive-block-4EUKJXUO.js.map} +0 -0
@@ -1,3 +1,4 @@
1
+ import { ChildSessionLink } from "./child-session-link";
1
2
  /**
2
3
  * SessionChrome — compact merged session signals above the composer.
3
4
  *
@@ -25,15 +26,30 @@
25
26
  *
26
27
  * Inbox and queue stay separate segments. Queue hover actions wire to
27
28
  * `UseTurnQueueResult` (`editTurn` / `steerTurn` / `moveTurn` / `removeTurn`).
29
+ * The collapsed queue chip previews the latest queued message beside its Steer
30
+ * action; open queue rows keep Steer visible and reveal the rest on hover.
28
31
  * Inbox has no product dismiss API; pass `onDismissIncoming` when the host
29
32
  * wants a visible action (dev harness may use a local dummy).
30
33
  *
34
+ * Queue opens by default when chrome is idle and at least one authoritative
35
+ * prompt is queued. Closing the queue dismisses that session's offer until
36
+ * occupancy drains; a different session on the same chrome instance may
37
+ * offer again. An in-flight optimistic Send never opens the drawer —
38
+ * admission stays a paint-only receipt on the chip so layout does not jump
39
+ * under the pointer.
40
+ *
31
41
  * Segment switches keep the panel shell mounted and crossfade content. The
32
42
  * shell uses one CSS grid-track transition for deliberate open/close actions;
33
43
  * live queue reconciliation never feeds measurements back into layout.
34
44
  */
35
- import type { SessionGoal, SessionPendingInputPreview, SessionTurn } from "@opengeni/sdk";
45
+ import type {
46
+ SessionGoal,
47
+ SessionPendingInputPreview,
48
+ SessionStatus,
49
+ SessionTurn,
50
+ } from "@opengeni/sdk";
36
51
  import {
52
+ ActivityIcon,
37
53
  AudioLinesIcon,
38
54
  ArrowDownIcon,
39
55
  ArrowUpIcon,
@@ -46,9 +62,11 @@ import {
46
62
  PencilIcon,
47
63
  PlayIcon,
48
64
  Trash2Icon,
65
+ TerminalIcon,
49
66
  TriangleAlertIcon,
50
67
  XIcon,
51
- ZapIcon,
68
+ CornerDownRightIcon,
69
+ TargetIcon,
52
70
  } from "lucide-react";
53
71
  import { AnimatePresence, motion, useReducedMotion } from "motion/react";
54
72
  import { useEffect, useId, useMemo, useRef, useState, type ReactNode } from "react";
@@ -57,11 +75,27 @@ import type { ComposerOptimisticMessage, ComposerState } from "../hooks/use-comp
57
75
  import type { UseGoalResult } from "../hooks/use-goal";
58
76
  import type { UseTurnQueueResult } from "../hooks/use-turn-queue";
59
77
  import { cn } from "../lib/cn";
78
+ import { useErrorMessage } from "../lib/error-message";
60
79
  import { formatClockTime } from "../lib/format";
80
+ import {
81
+ countAuthoritativeQueuedTurns,
82
+ isAuthoritativeQueuedTurn,
83
+ QUEUE_REPLACE_DRAFT_COPY,
84
+ queuedTurnPresentation,
85
+ queueNeighborAnchors,
86
+ } from "../queue-presentation-model";
61
87
  import { requestQueueDraftEdit } from "./queue-draft-policy";
88
+ import { QUEUE_ITEM_CONTENT_UNAVAILABLE, queueItemContent } from "./queue-item-content";
89
+ import { TimelineAnnotationsChip, type TimelineAnnotationLike } from "./timeline-annotations";
62
90
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip";
63
91
 
64
- export type SessionChromeSignalId = "incoming" | "steering" | "queue" | "goal" | "agents";
92
+ export type SessionChromeSignalId =
93
+ | "incoming"
94
+ | "steering"
95
+ | "queue"
96
+ | "goal"
97
+ | "agents"
98
+ | "commands";
65
99
 
66
100
  export type SessionChromeSignalTone = "neutral" | "accent" | "waiting" | "running";
67
101
 
@@ -72,12 +106,24 @@ export type SessionChromeAgentsSignal = {
72
106
  };
73
107
 
74
108
  export type SessionChromeProps = {
109
+ /** Authoritative execution status; omitted by older embedding hosts. */
110
+ sessionStatus?: SessionStatus | undefined;
75
111
  queue: UseTurnQueueResult;
112
+ /** Open and focus an existing queued prompt without changing its delivery. */
113
+ queueFocusTarget?: { turnId: string; requestId: number } | undefined;
76
114
  /** Needed for queue edit → composer checkout. Omit with `readOnly`. */
77
115
  composer?: ComposerState | undefined;
116
+ /** Focus the composer after a successful queue checkout has applied its draft.
117
+ * Connect to the composer controller's `focusInput`, or a custom input ref.
118
+ * Never called for failed checkout or while replacement awaits confirmation.
119
+ */
120
+ onComposerFocus?: (() => void) | undefined;
78
121
  goal?: UseGoalResult | null | undefined;
79
122
  /** Expanded agents body (host supplies tree / list). */
80
123
  agentsPanel?: ReactNode;
124
+ /** Active commands only. The host mounts the body only when opened. */
125
+ commandsPanel?: ReactNode;
126
+ commandsCount?: number | undefined;
81
127
  /** Chip summary; when `count > 0` the agents segment appears. */
82
128
  agentsSignal?: SessionChromeAgentsSignal | undefined;
83
129
  /**
@@ -85,6 +131,8 @@ export type SessionChromeProps = {
85
131
  * (and the gallery) may still pass a handler so the action is visible.
86
132
  */
87
133
  onDismissIncoming?: ((inputId: string) => void) | undefined;
134
+ /** Open a typed child update's source through the host's normal authorized route. */
135
+ onOpenSession?: ((sessionId: string) => void) | undefined;
88
136
  readOnly?: boolean | undefined;
89
137
  className?: string | undefined;
90
138
  /** Controlled active segment; omit for uncontrolled. */
@@ -97,22 +145,19 @@ type GoalPillState =
97
145
  | "pursuing"
98
146
  | "waiting"
99
147
  | "scheduled"
148
+ | "session_failed"
100
149
  | "blocked"
101
150
  | "held"
102
151
  | "paused"
103
152
  | "invariant_broken"
104
153
  | "completed";
105
154
 
106
- type QueuedTurnPresentation = {
107
- kind: "prompt" | "realtime_voice" | "realtime_voice_handoff";
108
- text: string;
109
- };
110
-
111
155
  const GOAL_LABEL: Record<GoalPillState, string> = {
112
156
  pursuing: "Pursuing",
113
157
  waiting: "Waiting",
114
- scheduled: "Scheduled",
158
+ scheduled: "Waiting",
115
159
  blocked: "Blocked",
160
+ session_failed: "Blocked by session failure",
116
161
  held: "Held",
117
162
  paused: "Paused",
118
163
  invariant_broken: "Needs attention",
@@ -121,13 +166,21 @@ const GOAL_LABEL: Record<GoalPillState, string> = {
121
166
 
122
167
  /**
123
168
  * Short pill suffix per `pausedReason`. `max_auto_continuations` is pacing
124
- * (new input resumes it); `limits` is budget/admission; `user_pause`/`api` is
169
+ * (new input resumes it); `limits` is an unspecified legacy admission gate; `user_pause`/`api` is
125
170
  * the human's own override; `agent` is the model declaring it is blocked on a
126
171
  * human decision. Unknown or legacy reasons keep the bare "Paused".
127
172
  */
128
173
  const GOAL_PAUSED_REASON_SUFFIX: Record<string, string> = {
129
174
  max_auto_continuations: "cap",
130
- limits: "budget",
175
+ limits: "limits",
176
+ model_unavailable: "model",
177
+ model_policy: "policy",
178
+ credits: "credits",
179
+ budget: "budget",
180
+ usage_limit: "usage limit",
181
+ usage_policy: "limits",
182
+ allowance: "allowance",
183
+ session_usage_limit: "usage limit",
131
184
  user_pause: "manually",
132
185
  api: "manually",
133
186
  agent: "agent",
@@ -136,7 +189,16 @@ const GOAL_PAUSED_REASON_SUFFIX: Record<string, string> = {
136
189
  const GOAL_PAUSED_REASON_EXPLANATION: Record<string, string> = {
137
190
  max_auto_continuations:
138
191
  "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.",
139
- limits: "Paused because budget or usage limits block another run. Resume once limits allow.",
192
+ limits: "Paused by an admission limit. Resume when the blocker is resolved.",
193
+ model_unavailable:
194
+ "The selected model is unavailable. Choose an available model before resuming.",
195
+ model_policy: "The selected model is blocked by policy. Choose an allowed model before resuming.",
196
+ credits: "Insufficient Opengeni credits. Add credits before resuming.",
197
+ budget: "Monthly model spending limit reached. Resume when the spending limit allows.",
198
+ usage_limit: "Monthly agent run limit reached. Resume when the run limit allows.",
199
+ usage_policy: "The application's usage policy blocks another run. Resume when it allows.",
200
+ allowance: "Opengeni usage allowance exhausted. Resume when your allowance is available.",
201
+ session_usage_limit: "Paused at the task's usage limit. Raise or remove the limit, then resume.",
140
202
  user_pause:
141
203
  "Paused manually by a person or an API call. Resume to let the goal continue on its own.",
142
204
  api: "Paused manually by a person or an API call. Resume to let the goal continue on its own.",
@@ -144,6 +206,7 @@ const GOAL_PAUSED_REASON_EXPLANATION: Record<string, string> = {
144
206
  };
145
207
 
146
208
  type GoalPillRecord = Pick<SessionGoal, "status" | "pausedReason"> & {
209
+ rationale?: SessionGoal["rationale"];
147
210
  continuation?: SessionGoal["continuation"] | null | undefined;
148
211
  };
149
212
 
@@ -159,7 +222,7 @@ export function sessionChromeGoalPillLabel(
159
222
 
160
223
  /**
161
224
  * One human sentence explaining WHY the goal is not pursuing right now: the
162
- * pause reason, the agent's own `goal_wait` hold (reason + deadline), or the
225
+ * pause reason, the agent's own `wait_for_input` hold (reason + deadline), or the
163
226
  * next idle-backoff check time. Null when the state needs no explanation.
164
227
  */
165
228
  export function sessionChromeGoalPillExplanation(
@@ -167,55 +230,107 @@ export function sessionChromeGoalPillExplanation(
167
230
  record: GoalPillRecord | null | undefined,
168
231
  ): string | null {
169
232
  const continuation = record?.continuation ?? null;
233
+ if (state === "session_failed") {
234
+ return "Resolve the session failure, then use Continue or send a message to continue this active goal.";
235
+ }
170
236
  if (state === "paused") {
237
+ const rationale = record?.rationale?.trim();
238
+ if (rationale) return rationale;
171
239
  return record?.pausedReason
172
240
  ? (GOAL_PAUSED_REASON_EXPLANATION[record.pausedReason] ?? null)
173
241
  : null;
174
242
  }
175
- if (state === "scheduled" && continuation?.reason === "backoff_pending") {
176
- return continuation.nextAttemptAt
177
- ? `Next goal check at ${formatClockTime(continuation.nextAttemptAt)}.`
178
- : "Next goal check is scheduled.";
243
+ if (state === "scheduled") {
244
+ return continuation?.nextAttemptAt
245
+ ? `Continues at ${formatClockTime(continuation.nextAttemptAt)}.`
246
+ : "Waiting to continue automatically.";
247
+ }
248
+ if (state === "waiting" && continuation?.reason === "system_work_pending") {
249
+ return "Waiting for other session work to finish before the goal continues automatically.";
179
250
  }
180
251
  if (state === "held" && continuation?.reason === "held_for_input") {
181
252
  const reason = continuation.holdReason?.trim();
182
253
  const until = continuation.nextAttemptAt
183
254
  ? ` until ${formatClockTime(continuation.nextAttemptAt)}`
184
255
  : "";
185
- return `Waiting for input${reason ? `: ${reason}` : ""}${until}. A child result, an agent message, or your prompt wakes it sooner.`;
256
+ return `Waiting for input${reason ? `: ${reason}` : ""}${until}. Relevant session input—including a child result, background-command result, agent message, schedule, or your prompt—wakes it sooner.`;
186
257
  }
187
258
  return null;
188
259
  }
189
260
 
190
- function queuedTurnPresentation(turn: SessionTurn): QueuedTurnPresentation {
191
- const realtimeDelegation = objectValue(turn.metadata.realtimeDelegation);
192
- const inputTranscript = realtimeDelegation?.inputTranscript;
193
- if (typeof inputTranscript === "string" && inputTranscript.trim()) {
194
- return { kind: "realtime_voice", text: inputTranscript.trim() };
195
- }
196
- if (objectValue(turn.metadata.realtimeTailFlush)) {
197
- return { kind: "realtime_voice_handoff", text: "Remaining voice context" };
198
- }
199
- return { kind: "prompt", text: turn.prompt };
261
+ export { countAuthoritativeQueuedTurns };
262
+
263
+ function isOptimisticQueuedMessage(
264
+ message: ComposerOptimisticMessage,
265
+ queuedTurnIds: ReadonlySet<string>,
266
+ snapshot: UseTurnQueueResult["snapshot"],
267
+ ): boolean {
268
+ return (
269
+ message.delivery === "send" &&
270
+ message.destination === "queue" &&
271
+ (!message.turnId || !queuedTurnIds.has(message.turnId)) &&
272
+ !(
273
+ message.turnId &&
274
+ message.appliedQueueVersion !== null &&
275
+ message.appliedQueueVersion !== undefined &&
276
+ snapshot &&
277
+ snapshot.version >= message.appliedQueueVersion
278
+ )
279
+ );
200
280
  }
201
281
 
202
- function isSteeringTurn(turn: SessionTurn): boolean {
203
- return turn.metadata.delivery === "steer";
282
+ export function countOptimisticQueuedMessages(
283
+ messages: readonly ComposerOptimisticMessage[] | undefined,
284
+ queuedTurnIds: ReadonlySet<string>,
285
+ snapshot: UseTurnQueueResult["snapshot"],
286
+ ): number {
287
+ return (messages ?? []).filter((message) =>
288
+ isOptimisticQueuedMessage(message, queuedTurnIds, snapshot),
289
+ ).length;
204
290
  }
205
291
 
206
- function objectValue(value: unknown): Record<string, unknown> | null {
207
- return value !== null && typeof value === "object" && !Array.isArray(value)
208
- ? (value as Record<string, unknown>)
209
- : null;
292
+ /**
293
+ * First uncontrolled segment. An existing authoritative queue opens itself
294
+ * when the host did not pick another default; optimistic-only occupancy
295
+ * stays collapsed so a live Send does not shove a drawer under the pointer.
296
+ */
297
+ export function sessionChromeInitialActive(input: {
298
+ defaultActive: SessionChromeSignalId | null;
299
+ authoritativeQueuedCount: number;
300
+ }): SessionChromeSignalId | null {
301
+ if (input.defaultActive != null) return input.defaultActive;
302
+ return input.authoritativeQueuedCount >= 1 ? "queue" : null;
303
+ }
304
+
305
+ /**
306
+ * Whether idle chrome should offer the queue panel. A dismissed session
307
+ * stays collapsed until occupancy drains. Controlled hosts own this.
308
+ */
309
+ export function sessionChromeShouldOfferQueue(input: {
310
+ controlled: boolean;
311
+ active: SessionChromeSignalId | null;
312
+ activityOpen: boolean;
313
+ authoritativeQueuedCount: number;
314
+ suppressed: boolean;
315
+ }): boolean {
316
+ return (
317
+ !input.controlled &&
318
+ input.active === null &&
319
+ !input.activityOpen &&
320
+ input.authoritativeQueuedCount >= 1 &&
321
+ !input.suppressed
322
+ );
210
323
  }
211
324
 
212
325
  /** Select pill state from the goal's authoritative continuation projection. */
213
326
  export function sessionChromeGoalPillState(
214
327
  goalStatus: "active" | "paused" | "completed",
215
328
  continuation: SessionGoal["continuation"] | null | undefined,
329
+ sessionStatus?: SessionStatus,
216
330
  ): GoalPillState {
217
331
  if (goalStatus === "completed") return "completed";
218
332
  if (goalStatus === "paused") return "paused";
333
+ if (sessionStatus === "failed") return "session_failed";
219
334
  if (!continuation) return "invariant_broken";
220
335
  if (continuation.state === "running") {
221
336
  return continuation.reason === "goal_turn_running"
@@ -228,7 +343,13 @@ export function sessionChromeGoalPillState(
228
343
  // next evaluation at `nextAttemptAt`) is an ordinary scheduled state.
229
344
  if (continuation.state === "scheduled") return "scheduled";
230
345
  if (continuation.state === "blocked") {
231
- // `held_for_input` is the agent's own goal_wait hold (waiting for child
346
+ if (
347
+ continuation.reason === "human_turn_running" ||
348
+ continuation.reason === "system_work_pending"
349
+ ) {
350
+ return "waiting";
351
+ }
352
+ // `held_for_input` is the agent's own wait_for_input hold (waiting for child
232
353
  // results / external input until a deadline); it shares the Held pill.
233
354
  return continuation.reason === "workstream_paused" || continuation.reason === "held_for_input"
234
355
  ? "held"
@@ -288,6 +409,12 @@ function pendingKindLabel(kind: SessionPendingInputPreview["kind"]): string {
288
409
  return "Goal wake";
289
410
  case "agent_message":
290
411
  return "Update";
412
+ case "background_command_result":
413
+ return "Command result";
414
+ case "session_wait_timeout":
415
+ return "Wait ended";
416
+ case "media_generation_result":
417
+ return "Video result";
291
418
  default:
292
419
  return "Incoming";
293
420
  }
@@ -307,18 +434,28 @@ function toneClass(tone: SessionChromeSignalTone, selected: boolean): string {
307
434
  }
308
435
 
309
436
  export function SessionChrome({
437
+ sessionStatus,
310
438
  queue,
439
+ queueFocusTarget,
311
440
  composer,
441
+ onComposerFocus,
312
442
  goal,
313
443
  agentsPanel,
444
+ commandsPanel,
445
+ commandsCount = 0,
314
446
  agentsSignal,
315
447
  onDismissIncoming,
448
+ onOpenSession,
316
449
  readOnly = false,
317
450
  className,
318
451
  active: activeControlled,
319
452
  defaultActive = null,
320
453
  onActiveChange,
321
454
  }: SessionChromeProps) {
455
+ const formatError = useErrorMessage();
456
+ const [activityRequested, setActivityOpen] = useState(
457
+ Boolean(defaultActive && ["incoming", "agents", "commands"].includes(defaultActive)),
458
+ );
322
459
  const reactId = useId();
323
460
  const panelId = `og-session-chrome-panel-${reactId}`;
324
461
  const reduceMotion = useReducedMotion();
@@ -327,24 +464,14 @@ export function SessionChrome({
327
464
  const turns = queue.queue;
328
465
  const queueMutationFor = queue.mutationFor;
329
466
  const queuedTurns = useMemo(
330
- () => turns.filter((turn) => !isSteeringTurn(turn) && queueMutationFor(turn.id) !== "steer"),
467
+ () => turns.filter((turn) => isAuthoritativeQueuedTurn(turn, queueMutationFor)),
331
468
  [queueMutationFor, turns],
332
469
  );
333
470
  const queuedTurnIds = useMemo(() => new Set(queuedTurns.map((turn) => turn.id)), [queuedTurns]);
334
471
  const optimisticQueued = useMemo(
335
472
  () =>
336
- (composer?.optimisticMessages ?? []).filter(
337
- (message) =>
338
- message.delivery === "send" &&
339
- message.destination === "queue" &&
340
- (!message.turnId || !queuedTurnIds.has(message.turnId)) &&
341
- !(
342
- message.turnId &&
343
- message.appliedQueueVersion !== null &&
344
- message.appliedQueueVersion !== undefined &&
345
- queue.snapshot &&
346
- queue.snapshot.version >= message.appliedQueueVersion
347
- ),
473
+ (composer?.optimisticMessages ?? []).filter((message) =>
474
+ isOptimisticQueuedMessage(message, queuedTurnIds, queue.snapshot),
348
475
  ),
349
476
  [composer?.optimisticMessages, queue.snapshot, queuedTurnIds],
350
477
  );
@@ -358,14 +485,84 @@ export function SessionChrome({
358
485
  const stopping = stoppingKind !== null;
359
486
  const canMutateQueue = !readOnly && composer !== undefined;
360
487
 
361
- const liveGoal = record?.status === "active";
362
- const elapsed = useLiveElapsed(
363
- record?.createdAt,
364
- Boolean(liveGoal),
365
- !liveGoal ? record?.updatedAt : null,
488
+ const elapsed = useLiveElapsed(record?.createdAt, Boolean(record));
489
+ const goalState = record
490
+ ? sessionChromeGoalPillState(record.status, record.continuation, sessionStatus)
491
+ : null;
492
+
493
+ const initialAuthoritativeQueuedCount = countAuthoritativeQueuedTurns(
494
+ queue.queue,
495
+ queue.mutationFor,
496
+ );
497
+ const [activeUncontrolled, setActiveUncontrolled] = useState<SessionChromeSignalId | null>(() =>
498
+ sessionChromeInitialActive({
499
+ defaultActive,
500
+ authoritativeQueuedCount: initialAuthoritativeQueuedCount,
501
+ }),
502
+ );
503
+ const active = activeControlled !== undefined ? activeControlled : activeUncontrolled;
504
+ const rootRef = useRef<HTMLDivElement>(null);
505
+ const openedQueueTargetRef = useRef<string | null>(null);
506
+ const focusedQueueTargetRef = useRef<string | null>(null);
507
+ const queueTargetKey = queueFocusTarget
508
+ ? `${queueFocusTarget.turnId}:${queueFocusTarget.requestId}`
509
+ : null;
510
+ useEffect(() => {
511
+ if (!queueTargetKey || openedQueueTargetRef.current === queueTargetKey) return;
512
+ openedQueueTargetRef.current = queueTargetKey;
513
+ if (activeControlled === undefined) setActiveUncontrolled("queue");
514
+ onActiveChange?.("queue");
515
+ }, [queueTargetKey, activeControlled, onActiveChange]);
516
+ useEffect(() => {
517
+ if (!queueFocusTarget || active !== "queue" || focusedQueueTargetRef.current === queueTargetKey)
518
+ return;
519
+ const root = rootRef.current;
520
+ if (!root) return;
521
+ const focus = () => {
522
+ const row = Array.from(root.querySelectorAll<HTMLElement>("[data-queue-turn-id]")).find(
523
+ (element) => element.dataset.queueTurnId === queueFocusTarget.turnId,
524
+ );
525
+ if (!row) return false;
526
+ focusedQueueTargetRef.current = queueTargetKey;
527
+ row.focus({ preventScroll: true });
528
+ row.scrollIntoView?.({ block: "nearest" });
529
+ return true;
530
+ };
531
+ if (focus()) return;
532
+ const observer = new MutationObserver(() => {
533
+ if (focus()) observer.disconnect();
534
+ });
535
+ observer.observe(root, { childList: true, subtree: true });
536
+ return () => observer.disconnect();
537
+ }, [queueFocusTarget, queueTargetKey, active, queuedTurns]);
538
+ const activityOpen =
539
+ activityRequested || Boolean(active && ["incoming", "agents", "commands"].includes(active));
540
+ const activityVisibleRef = useRef(activityOpen);
541
+ activityVisibleRef.current = activityOpen;
542
+ // Two independent suppressions, both occupancy-scoped:
543
+ // - admission: a live Send while idle must not open a drawer under the pointer
544
+ // - dismiss: closing the queue remembers that session until occupancy drains
545
+ const queueOfferAdmissionSuppressedRef = useRef(
546
+ defaultActive == null &&
547
+ initialAuthoritativeQueuedCount === 0 &&
548
+ countOptimisticQueuedMessages(composer?.optimisticMessages, queuedTurnIds, queue.snapshot) >
549
+ 0,
366
550
  );
367
- const goalState = record ? sessionChromeGoalPillState(record.status, record.continuation) : null;
551
+ const queueOfferDismissedSessionIdsRef = useRef<Set<string>>(new Set());
552
+ const occupancySessionId = queuedTurns[0]?.sessionId ?? null;
553
+ const setActive = (next: SessionChromeSignalId | null) => {
554
+ if (active === "queue" && next === null) {
555
+ if (occupancySessionId) {
556
+ queueOfferDismissedSessionIdsRef.current.add(occupancySessionId);
557
+ } else {
558
+ queueOfferAdmissionSuppressedRef.current = true;
559
+ }
560
+ }
561
+ if (activeControlled === undefined) setActiveUncontrolled(next);
562
+ onActiveChange?.(next);
563
+ };
368
564
 
565
+ const hasCommandsPanel = commandsPanel != null;
369
566
  const signals = useMemo(() => {
370
567
  const rows: Array<{
371
568
  id: SessionChromeSignalId;
@@ -437,6 +634,7 @@ export function SessionChrome({
437
634
  const waiting =
438
635
  goalState === "waiting" ||
439
636
  goalState === "blocked" ||
637
+ goalState === "session_failed" ||
440
638
  goalState === "held" ||
441
639
  goalState === "paused";
442
640
  const explanation = sessionChromeGoalPillExplanation(goalState, record);
@@ -450,16 +648,7 @@ export function SessionChrome({
450
648
  : goalState === "pursuing" || goalState === "scheduled"
451
649
  ? "accent"
452
650
  : "neutral",
453
- icon:
454
- goalState === "blocked" || goalState === "invariant_broken" ? (
455
- <TriangleAlertIcon className="size-3" />
456
- ) : goalState === "waiting" ? (
457
- <Loader2Icon className="size-3 animate-og-spin" />
458
- ) : goalState === "paused" || goalState === "held" ? (
459
- <PauseIcon className="size-3" />
460
- ) : (
461
- <ZapIcon className="size-3" />
462
- ),
651
+ icon: <TargetIcon className="size-3" />,
463
652
  });
464
653
  }
465
654
  if (agentsSignal && agentsSignal.count > 0) {
@@ -472,8 +661,22 @@ export function SessionChrome({
472
661
  icon: <BotIcon className="size-3" />,
473
662
  });
474
663
  }
664
+ if (commandsCount > 0 || (active === "commands" && hasCommandsPanel)) {
665
+ rows.push({
666
+ id: "commands",
667
+ label:
668
+ commandsCount > 0
669
+ ? `${commandsCount} command${commandsCount === 1 ? "" : "s"}`
670
+ : "Commands",
671
+ tone: commandsCount > 0 ? "running" : "neutral",
672
+ icon: <TerminalIcon className="size-3" />,
673
+ });
674
+ }
475
675
  return rows;
476
676
  }, [
677
+ commandsCount,
678
+ hasCommandsPanel,
679
+ active,
477
680
  agentsSignal,
478
681
  elapsed,
479
682
  goalState,
@@ -485,14 +688,6 @@ export function SessionChrome({
485
688
  record,
486
689
  ]);
487
690
 
488
- const [activeUncontrolled, setActiveUncontrolled] = useState<SessionChromeSignalId | null>(
489
- defaultActive,
490
- );
491
- const active = activeControlled !== undefined ? activeControlled : activeUncontrolled;
492
- const setActive = (next: SessionChromeSignalId | null) => {
493
- if (activeControlled === undefined) setActiveUncontrolled(next);
494
- onActiveChange?.(next);
495
- };
496
691
  const optimisticQueueKeys = optimisticQueued.map((message) => message.clientEventId).join(",");
497
692
  const previousOptimisticQueueKeys = useRef(optimisticQueueKeys);
498
693
  const [queueArrivalNonce, setQueueArrivalNonce] = useState(0);
@@ -505,7 +700,45 @@ export function SessionChrome({
505
700
  // the pointer. A stable, paint-only receipt on the queue chip communicates
506
701
  // destination without participating in layout.
507
702
  setQueueArrivalNonce((current) => current + 1);
508
- }, [optimisticQueueKeys, optimisticQueued]);
703
+ if (activeControlled === undefined && active === null) {
704
+ queueOfferAdmissionSuppressedRef.current = true;
705
+ }
706
+ }, [active, activeControlled, optimisticQueueKeys, optimisticQueued]);
707
+ const queueOccupied = queuedTurns.length > 0 || optimisticQueued.length > 0;
708
+ useEffect(() => {
709
+ if (queueOccupied) return;
710
+ // A later wave may offer again. A prior session's dismiss must not stick
711
+ // after this instance has actually gone empty.
712
+ queueOfferAdmissionSuppressedRef.current = false;
713
+ queueOfferDismissedSessionIdsRef.current.clear();
714
+ }, [queueOccupied]);
715
+ const queueOfferSuppressed =
716
+ queueOfferAdmissionSuppressedRef.current ||
717
+ (occupancySessionId != null &&
718
+ queueOfferDismissedSessionIdsRef.current.has(occupancySessionId));
719
+ useEffect(() => {
720
+ if (
721
+ !sessionChromeShouldOfferQueue({
722
+ controlled: activeControlled !== undefined,
723
+ active,
724
+ activityOpen,
725
+ authoritativeQueuedCount: queuedTurns.length,
726
+ suppressed: queueOfferSuppressed,
727
+ })
728
+ ) {
729
+ return;
730
+ }
731
+ if (activeControlled === undefined) setActiveUncontrolled("queue");
732
+ onActiveChange?.("queue");
733
+ }, [
734
+ active,
735
+ activeControlled,
736
+ activityOpen,
737
+ occupancySessionId,
738
+ onActiveChange,
739
+ queueOfferSuppressed,
740
+ queuedTurns.length,
741
+ ]);
509
742
  const [replaceDraftFor, setReplaceDraftFor] = useState<string | null>(null);
510
743
 
511
744
  const chipRefs = useRef<Partial<Record<SessionChromeSignalId, HTMLButtonElement | null>>>({});
@@ -513,6 +746,10 @@ export function SessionChrome({
513
746
  const [pill, setPill] = useState({ left: 0, top: 0, width: 0, height: 0, opacity: 0 });
514
747
 
515
748
  const signalIds = signals.map((signal) => signal.id).join(",");
749
+ useEffect(() => {
750
+ if (!signals.some((signal) => ["incoming", "agents", "commands"].includes(signal.id)))
751
+ setActivityOpen(false);
752
+ }, [signals]);
516
753
  useEffect(() => {
517
754
  if (active && !signalIds.split(",").includes(active)) {
518
755
  if (activeControlled === undefined) setActiveUncontrolled(null);
@@ -535,7 +772,10 @@ export function SessionChrome({
535
772
  return;
536
773
  }
537
774
  const chip = chipRefs.current[active];
538
- if (!chip) return;
775
+ if (!chip) {
776
+ setPill((prev) => ({ ...prev, opacity: 0 }));
777
+ return;
778
+ }
539
779
  // Measure against the chip's own box so a wrapped multi-row rail never
540
780
  // stretches the highlight into a tall stripe across every signal.
541
781
  const railBox = rail.getBoundingClientRect();
@@ -563,6 +803,22 @@ export function SessionChrome({
563
803
  }, [active, signals]);
564
804
 
565
805
  const open = active !== null;
806
+ // Collapsed queue chip shows the latest queued message so a Send that lands
807
+ // in the queue is visible without opening the list; Steer acts on that
808
+ // message once the server has confirmed it.
809
+ const latestOptimisticQueued = optimisticQueued[optimisticQueued.length - 1];
810
+ const latestQueuedTurn = queuedTurns[queuedTurns.length - 1];
811
+ const queuePeek: { text: string | null; turnId: string | null } | null =
812
+ queue.error || queue.mutationError
813
+ ? null
814
+ : latestOptimisticQueued
815
+ ? { text: latestOptimisticQueued.text.trim() || null, turnId: null }
816
+ : latestQueuedTurn
817
+ ? {
818
+ text: queuedTurnPresentation(latestQueuedTurn).text.trim() || null,
819
+ turnId: latestQueuedTurn.id,
820
+ }
821
+ : null;
566
822
 
567
823
  if (signals.length === 0 && !stopping) return null;
568
824
 
@@ -572,7 +828,11 @@ export function SessionChrome({
572
828
 
573
829
  const panelBody =
574
830
  active === "incoming" ? (
575
- <IncomingPanel inputs={incoming} onDismiss={onDismissIncoming} />
831
+ <IncomingPanel
832
+ inputs={incoming}
833
+ onDismiss={onDismissIncoming}
834
+ onOpenSession={onOpenSession}
835
+ />
576
836
  ) : active === "queue" ? (
577
837
  <QueuePanel
578
838
  turns={queuedTurns}
@@ -582,6 +842,7 @@ export function SessionChrome({
582
842
  onRefresh={queue.refresh}
583
843
  onClearMutationError={queue.clearMutationError}
584
844
  onRetryOptimistic={composer?.retryOptimisticMessage}
845
+ onRestoreOptimistic={composer?.restoreOptimisticMessage}
585
846
  onRemoveOptimistic={composer?.removeOptimisticMessage}
586
847
  readOnly={!canMutateQueue}
587
848
  mutationFor={queue.mutationFor}
@@ -597,7 +858,10 @@ export function SessionChrome({
597
858
  expectedDraftRevision: composer.draftRevision,
598
859
  replaceDraft: true,
599
860
  });
600
- if (checkedOut) composer.applyDraft(checkedOut);
861
+ if (checkedOut) {
862
+ composer.applyDraft(checkedOut);
863
+ onComposerFocus?.();
864
+ }
601
865
  })();
602
866
  }
603
867
  : undefined
@@ -614,7 +878,10 @@ export function SessionChrome({
614
878
  expectedDraftRevision: composer.draftRevision,
615
879
  replaceDraft: false,
616
880
  });
617
- if (checkedOut) composer.applyDraft(checkedOut);
881
+ if (checkedOut) {
882
+ composer.applyDraft(checkedOut);
883
+ onComposerFocus?.();
884
+ }
618
885
  })();
619
886
  },
620
887
  );
@@ -645,6 +912,8 @@ export function SessionChrome({
645
912
  />
646
913
  ) : active === "goal" && record && goalState && goal ? (
647
914
  <GoalPanel goal={goal} state={goalState} elapsed={elapsed} readOnly={readOnly} />
915
+ ) : active === "commands" ? (
916
+ <div data-og-session-chrome-panel="commands">{commandsPanel}</div>
648
917
  ) : active === "agents" ? (
649
918
  <div data-og-session-chrome-panel="agents">
650
919
  {agentsPanel ?? <p className="text-og-xs text-og-fg-muted">No agent details.</p>}
@@ -656,6 +925,7 @@ export function SessionChrome({
656
925
  <div
657
926
  className={cn("og-session-chrome og-root w-full", className)}
658
927
  data-testid="session-chrome"
928
+ ref={rootRef}
659
929
  data-og-session-chrome=""
660
930
  data-og-session-chrome-open={open ? "true" : "false"}
661
931
  >
@@ -666,15 +936,9 @@ export function SessionChrome({
666
936
  )}
667
937
  style={{
668
938
  borderRadius: "var(--_og-session-chrome-radius)",
669
- background: open
670
- ? "var(--_og-session-chrome-surface-open)"
671
- : "var(--_og-session-chrome-surface)",
672
- borderColor: open
673
- ? "var(--_og-session-chrome-border-open)"
674
- : "var(--_og-session-chrome-border)",
675
- boxShadow: open
676
- ? "var(--og-session-chrome-shadow-open)"
677
- : "var(--og-session-chrome-shadow)",
939
+ background: "transparent",
940
+ borderColor: "transparent",
941
+ boxShadow: "none",
678
942
  transitionDuration: "var(--og-session-chrome-duration)",
679
943
  transitionTimingFunction: "var(--_og-session-chrome-ease)",
680
944
  }}
@@ -690,9 +954,9 @@ export function SessionChrome({
690
954
  >
691
955
  <div
692
956
  ref={railRef}
693
- className="relative flex flex-wrap items-center"
957
+ className="relative flex flex-nowrap items-center"
694
958
  style={{
695
- gap: "var(--og-session-chrome-chip-gap)",
959
+ gap: "10px",
696
960
  }}
697
961
  >
698
962
  <motion.div
@@ -712,71 +976,213 @@ export function SessionChrome({
712
976
  }}
713
977
  transition={{ duration: shellDuration, ease }}
714
978
  />
715
- {signals.map((signal) => {
716
- const selected = active === signal.id;
717
- return (
718
- <button
719
- key={signal.id}
720
- type="button"
721
- ref={(node) => {
722
- chipRefs.current[signal.id] = node;
723
- }}
724
- aria-expanded={selected}
725
- aria-controls={panelId}
726
- aria-label={selected ? `Close ${signal.label}` : undefined}
727
- data-testid={`session-chrome-${signal.id}`}
728
- data-og-session-chrome-signal={signal.id}
729
- title={signal.title}
730
- onClick={() => setActive(selected ? null : signal.id)}
731
- className={cn(
732
- "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",
733
- // Coarse pointers keep a 44px target (session-pins acceptance).
734
- "pointer-coarse:min-h-11",
735
- "transition-colors duration-150 motion-reduce:transition-none",
736
- "hover:text-og-fg focus-visible:bg-og-surface-3/50",
737
- selected ? "text-og-fg" : "text-og-fg-muted",
738
- )}
739
- style={{
740
- paddingInline: "var(--og-session-chrome-chip-pad-x)",
741
- }}
742
- >
743
- {signal.id === "queue" && queueArrivalNonce > 0 && !reduceMotion ? (
744
- <motion.span
745
- key={queueArrivalNonce}
746
- aria-hidden="true"
747
- data-testid="session-chrome-queue-arrival"
748
- className="pointer-events-none absolute inset-0 rounded-og-md bg-og-accent-soft"
749
- initial={{ opacity: 0 }}
750
- animate={{ opacity: [0, 0.38, 0] }}
751
- transition={{ duration: 0.72, times: [0, 0.18, 1], ease }}
752
- />
753
- ) : null}
754
- <span className={cn("shrink-0", toneClass(signal.tone, selected))}>
755
- {signal.icon}
756
- </span>
757
- <span className="shrink-0 font-medium text-og-fg">{signal.label}</span>
758
- {signal.detail ? (
759
- <>
760
- <span aria-hidden className="shrink-0 text-og-fg-subtle/60">
761
- ·
979
+ {signals
980
+ .filter((signal) => !["incoming", "agents", "commands"].includes(signal.id))
981
+ .map((signal) => {
982
+ const selected = active === signal.id;
983
+ return (
984
+ <div
985
+ key={signal.id}
986
+ role="group"
987
+ aria-label={
988
+ signal.id === "queue"
989
+ ? "Queued messages and actions"
990
+ : signal.id === "goal"
991
+ ? "Goal and actions"
992
+ : signal.label
993
+ }
994
+ className={cn(
995
+ "group/signal relative z-[1] inline-flex min-w-0 max-w-full items-center rounded-og-md",
996
+ "bg-og-surface-2/60 px-0.5",
997
+ selected && "bg-og-surface-3",
998
+ )}
999
+ >
1000
+ <button
1001
+ type="button"
1002
+ ref={(node) => {
1003
+ chipRefs.current[signal.id] = node;
1004
+ }}
1005
+ aria-expanded={selected}
1006
+ aria-controls={panelId}
1007
+ aria-label={
1008
+ signal.id === "goal"
1009
+ ? `Goal · ${goalState === "pursuing" ? "Running" : signal.label}`
1010
+ : selected
1011
+ ? `Close ${signal.label}`
1012
+ : undefined
1013
+ }
1014
+ data-testid={`session-chrome-${signal.id}`}
1015
+ data-og-session-chrome-signal={signal.id}
1016
+ title={signal.title ?? signal.label}
1017
+ onClick={() => {
1018
+ setActivityOpen(false);
1019
+ setActive(selected ? null : signal.id);
1020
+ }}
1021
+ className={cn(
1022
+ "group relative z-[1] inline-flex min-w-0 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",
1023
+ // Coarse pointers keep a 44px target (session-pins acceptance).
1024
+ "pointer-coarse:min-h-11",
1025
+ "transition-colors duration-150 motion-reduce:transition-none",
1026
+ "hover:text-og-fg focus-visible:bg-og-surface-3/50",
1027
+ selected ? "text-og-fg" : "text-og-fg-muted",
1028
+ )}
1029
+ style={{
1030
+ paddingInline: "var(--og-session-chrome-chip-pad-x)",
1031
+ }}
1032
+ >
1033
+ {signal.id === "queue" && queueArrivalNonce > 0 && !reduceMotion ? (
1034
+ <motion.span
1035
+ key={queueArrivalNonce}
1036
+ aria-hidden="true"
1037
+ data-testid="session-chrome-queue-arrival"
1038
+ className="pointer-events-none absolute inset-0 rounded-og-md bg-og-accent-soft"
1039
+ initial={{ opacity: 0 }}
1040
+ animate={{ opacity: [0, 0.38, 0] }}
1041
+ transition={{ duration: 0.72, times: [0, 0.18, 1], ease }}
1042
+ />
1043
+ ) : null}
1044
+ <span className={cn("shrink-0", toneClass(signal.tone, selected))}>
1045
+ {signal.icon}
762
1046
  </span>
763
- <span className="min-w-0 max-w-[8.5rem] truncate text-og-fg sm:max-w-[12rem]">
764
- {signal.detail}
1047
+ <span
1048
+ className={cn(
1049
+ "font-medium text-og-fg",
1050
+ signal.id === "queue" && queuePeek?.text && !selected
1051
+ ? "shrink-0"
1052
+ : "min-w-0 truncate",
1053
+ )}
1054
+ >
1055
+ {signal.id === "goal" ? "Goal · " : null}
1056
+ {signal.id === "goal"
1057
+ ? goalState === "pursuing"
1058
+ ? "Running"
1059
+ : signal.label
1060
+ : signal.id === "queue"
1061
+ ? queue.error || queue.mutationError
1062
+ ? signal.label
1063
+ : `${queuedTurns.length + optimisticQueued.length} queued`
1064
+ : signal.label}
765
1065
  </span>
766
- </>
767
- ) : null}
768
- {selected ? (
1066
+ {signal.id === "queue" && queuePeek?.text && !selected ? (
1067
+ <AnimatePresence initial={false} mode="popLayout">
1068
+ <motion.span
1069
+ key={queuePeek.text}
1070
+ data-testid="session-chrome-queue-peek"
1071
+ className="min-w-0 max-w-[min(24rem,60vw)] truncate text-og-fg-muted"
1072
+ initial={reduceMotion ? false : { opacity: 0, y: 3 }}
1073
+ animate={{ opacity: 1, y: 0 }}
1074
+ exit={{ opacity: 0, transition: { duration: crossfadeDuration } }}
1075
+ transition={{ duration: crossfadeDuration, ease }}
1076
+ >
1077
+ {queuePeek.text}
1078
+ </motion.span>
1079
+ </AnimatePresence>
1080
+ ) : null}
1081
+ </button>
1082
+ {signal.id === "goal" && goal && record && !readOnly ? (
1083
+ <div className="flex shrink-0 items-center pr-1 pl-0.5">
1084
+ {record.status === "active" || record.status === "paused" ? (
1085
+ <IconAction
1086
+ label={record.status === "paused" ? "Resume goal" : "Pause goal"}
1087
+ tip={record.status === "paused" ? "Resume goal" : "Pause goal"}
1088
+ disabled={goal.updating}
1089
+ onClick={() =>
1090
+ void (record.status === "paused"
1091
+ ? goal.resume()
1092
+ : goal.pause("Paused from session chrome"))
1093
+ }
1094
+ >
1095
+ {goal.updating ? (
1096
+ <Loader2Icon className="size-3 animate-og-spin" />
1097
+ ) : record.status === "paused" ? (
1098
+ <PlayIcon className="size-3" />
1099
+ ) : (
1100
+ <PauseIcon className="size-3" />
1101
+ )}
1102
+ </IconAction>
1103
+ ) : null}
1104
+ <IconAction
1105
+ label="Clear goal"
1106
+ tip="Clear goal"
1107
+ danger
1108
+ disabled={goal.updating}
1109
+ onClick={() => void goal.deleteGoal()}
1110
+ >
1111
+ <Trash2Icon className="size-3" />
1112
+ </IconAction>
1113
+ </div>
1114
+ ) : signal.id === "queue" && canMutateQueue && queuePeek && !selected ? (
1115
+ <div className="flex shrink-0 items-center pr-1 pl-0.5">
1116
+ <IconAction
1117
+ label="Steer latest queued message"
1118
+ analyticsAction="steer"
1119
+ text="Steer"
1120
+ tip={QUEUE_STEER_TIP}
1121
+ disabled={
1122
+ !queuePeek.turnId ||
1123
+ queue.mutating ||
1124
+ Boolean(queue.mutationFor(queuePeek.turnId))
1125
+ }
1126
+ onClick={() => {
1127
+ if (queuePeek.turnId) void queue.steerTurn(queuePeek.turnId);
1128
+ }}
1129
+ >
1130
+ {queuePeek.turnId && queue.mutationFor(queuePeek.turnId) === "steer" ? (
1131
+ <Loader2Icon className="size-3 animate-og-spin" />
1132
+ ) : (
1133
+ <CornerDownRightIcon className="size-3" />
1134
+ )}
1135
+ </IconAction>
1136
+ </div>
1137
+ ) : null}
1138
+ </div>
1139
+ );
1140
+ })}
1141
+ {signals.some((signal) => ["incoming", "agents", "commands"].includes(signal.id)) ? (
1142
+ <button
1143
+ type="button"
1144
+ aria-label="Session activity"
1145
+ aria-describedby={commandsCount > 0 ? `${panelId}-commands-count` : undefined}
1146
+ title={activityOpen ? "Close activity" : "Inbox, agents and commands"}
1147
+ aria-controls={panelId}
1148
+ aria-expanded={activityOpen}
1149
+ onClick={() => {
1150
+ setActivityOpen(!activityOpen);
1151
+ setActive(
1152
+ activityOpen
1153
+ ? null
1154
+ : commandsCount > 0 && hasCommandsPanel
1155
+ ? "commands"
1156
+ : (signals.find((signal) =>
1157
+ ["incoming", "agents", "commands"].includes(signal.id),
1158
+ )?.id ?? null),
1159
+ );
1160
+ }}
1161
+ className={cn(
1162
+ "ml-auto inline-flex min-h-8 shrink-0 items-center justify-center gap-1.5 rounded-og-md px-2 text-og-xs transition-colors outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent/40 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
1163
+ activityOpen
1164
+ ? "bg-og-surface-3 text-og-fg"
1165
+ : "text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg",
1166
+ )}
1167
+ >
1168
+ <ActivityIcon className="size-3.5" />
1169
+ <span className="sr-only">Activity</span>
1170
+ {commandsCount > 0 ? (
1171
+ <>
769
1172
  <span
770
- data-testid="session-chrome-close"
771
- className="ml-0.5 inline-flex size-4 shrink-0 items-center justify-center rounded-og-sm text-og-fg-subtle transition-colors group-hover:text-og-fg pointer-coarse:size-5"
772
- aria-hidden
773
- >
774
- <XIcon className="size-3" />
1173
+ aria-hidden="true"
1174
+ className="size-1.5 shrink-0 animate-og-pulse rounded-full bg-og-fg-muted motion-reduce:animate-none"
1175
+ />
1176
+ <span id={`${panelId}-commands-count`}>
1177
+ {commandsCount} command{commandsCount === 1 ? "" : "s"}
775
1178
  </span>
776
- ) : null}
777
- </button>
778
- );
779
- })}
1179
+ </>
1180
+ ) : null}
1181
+ {incoming.length > 0 ? (
1182
+ <span className="size-1.5 rounded-full bg-og-accent" />
1183
+ ) : null}
1184
+ </button>
1185
+ ) : null}
780
1186
  {stopping ? (
781
1187
  <span
782
1188
  role="status"
@@ -794,6 +1200,47 @@ export function SessionChrome({
794
1200
  </div>
795
1201
  </div>
796
1202
 
1203
+ <AnimatePresence initial={false}>
1204
+ {activityOpen ? (
1205
+ <motion.div
1206
+ key="activity-tabs"
1207
+ initial={{ height: 0, opacity: 0 }}
1208
+ animate={{ height: "auto", opacity: 1 }}
1209
+ exit={{ height: 0, opacity: 0 }}
1210
+ transition={{ duration: shellDuration, ease }}
1211
+ style={{ overflow: "hidden" }}
1212
+ >
1213
+ <div className="mt-1 flex items-center gap-1 rounded-t-og-lg bg-og-surface-2/50 px-2 py-1">
1214
+ {signals
1215
+ .filter((signal) => ["incoming", "agents", "commands"].includes(signal.id))
1216
+ .map((signal) => (
1217
+ <button
1218
+ key={signal.id}
1219
+ type="button"
1220
+ aria-expanded={active === signal.id}
1221
+ onClick={() => {
1222
+ if (activityVisibleRef.current) setActive(signal.id);
1223
+ }}
1224
+ className={cn(
1225
+ "inline-flex min-h-9 items-center gap-1.5 rounded-og-md px-2 text-og-xs pointer-coarse:min-h-11",
1226
+ active === signal.id
1227
+ ? "bg-og-surface-3 text-og-fg"
1228
+ : "text-og-fg-muted hover:text-og-fg",
1229
+ )}
1230
+ >
1231
+ {signal.icon}
1232
+ {signal.id === "incoming" ? `${incoming.length} incoming` : signal.label}
1233
+ </button>
1234
+ ))}
1235
+ </div>
1236
+ </motion.div>
1237
+ ) : null}
1238
+ </AnimatePresence>
1239
+ {goal?.mutationError ? (
1240
+ <p role="alert" className="px-3 pb-2 text-og-xs text-og-danger">
1241
+ Goal action not confirmed. {formatError(goal.mutationError)}
1242
+ </p>
1243
+ ) : null}
797
1244
  <div
798
1245
  id={panelId}
799
1246
  data-og-session-chrome-panel-shell=""
@@ -811,7 +1258,12 @@ export function SessionChrome({
811
1258
  >
812
1259
  <div className="min-h-0 overflow-hidden">
813
1260
  <div
814
- className="relative overflow-y-auto overscroll-contain border-t border-og-border/50"
1261
+ className={cn(
1262
+ "relative overflow-y-auto overscroll-contain",
1263
+ activityOpen
1264
+ ? "rounded-b-og-lg bg-og-surface-2/50"
1265
+ : "mt-1 rounded-og-lg bg-og-surface-2/50",
1266
+ )}
815
1267
  style={{
816
1268
  maxHeight: "var(--og-session-chrome-panel-max-height)",
817
1269
  paddingInline: "var(--og-session-chrome-panel-pad-x)",
@@ -819,7 +1271,7 @@ export function SessionChrome({
819
1271
  }}
820
1272
  >
821
1273
  <AnimatePresence initial={false}>
822
- {active && panelBody ? (
1274
+ {active && active !== "commands" && panelBody ? (
823
1275
  <motion.div
824
1276
  key={active}
825
1277
  data-og-session-chrome-panel-frame={active}
@@ -842,6 +1294,16 @@ export function SessionChrome({
842
1294
  </motion.div>
843
1295
  ) : null}
844
1296
  </AnimatePresence>
1297
+ {active === "commands" ? (
1298
+ <motion.div
1299
+ key="commands"
1300
+ initial={reduceMotion ? false : { opacity: 0 }}
1301
+ animate={{ opacity: 1 }}
1302
+ transition={{ duration: crossfadeDuration, ease }}
1303
+ >
1304
+ {panelBody}
1305
+ </motion.div>
1306
+ ) : null}
845
1307
  </div>
846
1308
  </div>
847
1309
  </div>
@@ -854,47 +1316,123 @@ export function SessionChrome({
854
1316
  function IncomingPanel({
855
1317
  inputs,
856
1318
  onDismiss,
1319
+ onOpenSession,
857
1320
  }: {
858
1321
  inputs: SessionPendingInputPreview[];
859
1322
  onDismiss?: ((inputId: string) => void) | undefined;
1323
+ onOpenSession?: ((sessionId: string) => void) | undefined;
860
1324
  }) {
1325
+ // When a sandbox is shut down or lost, every command on it reports at once.
1326
+ // One row reads better than dozens of identical ones; each result still
1327
+ // reaches the agent. Ordinary results keep their own rows.
1328
+ const lostWithSandbox = inputs.filter(isLostWithSandboxResult);
1329
+ const grouped = new Set(
1330
+ lostWithSandbox.length >= 2 ? lostWithSandbox.map((input) => input.id) : [],
1331
+ );
1332
+ const firstGrouped = lostWithSandbox.length >= 2 ? lostWithSandbox[0]!.id : null;
861
1333
  return (
862
- <ul
863
- className="flex flex-col gap-0.5"
864
- aria-label="Incoming updates"
865
- data-og-session-chrome-panel="incoming"
1334
+ <div>
1335
+ <p className="mb-2 text-og-xs text-og-fg-subtle">Waiting to be included in an agent turn.</p>
1336
+ <ul
1337
+ className="flex flex-col gap-0.5"
1338
+ aria-label="Incoming updates"
1339
+ data-og-session-chrome-panel="incoming"
1340
+ >
1341
+ {inputs.map((input) =>
1342
+ grouped.has(input.id) ? (
1343
+ input.id === firstGrouped ? (
1344
+ <CommandResultsRow key={input.id} inputs={lostWithSandbox} onDismiss={onDismiss} />
1345
+ ) : null
1346
+ ) : (
1347
+ <li
1348
+ key={input.id}
1349
+ className="group flex items-start gap-1.5 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--_og-session-chrome-row-hover)]"
1350
+ >
1351
+ <span
1352
+ className={cn(
1353
+ "mt-px shrink-0 rounded px-1 py-px text-[10px] font-medium leading-4",
1354
+ input.classification === "action_required" || input.classification === "failure"
1355
+ ? "bg-og-status-waiting/12 text-og-status-waiting"
1356
+ : "bg-og-surface-3/80 text-og-fg-muted",
1357
+ )}
1358
+ >
1359
+ {pendingKindLabel(input.kind)}
1360
+ </span>
1361
+ <div className="min-w-0 flex-1">
1362
+ <p className="break-words text-og-xs leading-4 text-og-fg">{input.summary}</p>
1363
+ <ChildSessionLink
1364
+ kind={input.kind}
1365
+ sourceId={input.sourceId}
1366
+ onOpenSession={onOpenSession}
1367
+ />
1368
+ </div>
1369
+ {onDismiss ? (
1370
+ <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">
1371
+ <IconAction
1372
+ label={`Dismiss incoming ${pendingKindLabel(input.kind)}`}
1373
+ tip="Dismiss"
1374
+ onClick={() => onDismiss(input.id)}
1375
+ danger
1376
+ >
1377
+ <Trash2Icon className="size-3" />
1378
+ </IconAction>
1379
+ </div>
1380
+ ) : null}
1381
+ </li>
1382
+ ),
1383
+ )}
1384
+ </ul>
1385
+ </div>
1386
+ );
1387
+ }
1388
+
1389
+ /** Matches the worker's notice for a command whose sandbox is gone. */
1390
+ function isLostWithSandboxResult(input: SessionPendingInputPreview): boolean {
1391
+ return (
1392
+ input.kind === "background_command_result" &&
1393
+ input.summary.includes("is no longer running because its sandbox was shut down or lost")
1394
+ );
1395
+ }
1396
+
1397
+ function commandResultsSummary(inputs: SessionPendingInputPreview[]): string {
1398
+ return `${inputs.length} background commands are no longer running because their sandbox was shut down or lost. Whether they finished is unknown.`;
1399
+ }
1400
+
1401
+ function CommandResultsRow({
1402
+ inputs,
1403
+ onDismiss,
1404
+ }: {
1405
+ inputs: SessionPendingInputPreview[];
1406
+ onDismiss?: ((inputId: string) => void) | undefined;
1407
+ }) {
1408
+ return (
1409
+ <li
1410
+ className="group flex items-start gap-1.5 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--_og-session-chrome-row-hover)]"
1411
+ data-og-session-chrome-command-results={inputs.length}
866
1412
  >
867
- {inputs.map((input) => (
868
- <li
869
- key={input.id}
870
- className="group flex items-start gap-1.5 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--_og-session-chrome-row-hover)]"
871
- >
872
- <span
873
- className={cn(
874
- "mt-px shrink-0 rounded px-1 py-px text-[10px] font-medium leading-4",
875
- input.classification === "action_required" || input.classification === "failure"
876
- ? "bg-og-status-waiting/12 text-og-status-waiting"
877
- : "bg-og-surface-3/80 text-og-fg-muted",
878
- )}
1413
+ <span className="mt-px shrink-0 rounded bg-og-status-waiting/12 px-1 py-px text-[10px] font-medium leading-4 text-og-status-waiting">
1414
+ Command results
1415
+ </span>
1416
+ <div className="min-w-0 flex-1">
1417
+ <p className="break-words text-og-xs leading-4 text-og-fg">
1418
+ {commandResultsSummary(inputs)}
1419
+ </p>
1420
+ </div>
1421
+ {onDismiss ? (
1422
+ <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">
1423
+ <IconAction
1424
+ label="Dismiss incoming command results"
1425
+ tip="Dismiss all"
1426
+ onClick={() => {
1427
+ for (const input of inputs) onDismiss(input.id);
1428
+ }}
1429
+ danger
879
1430
  >
880
- {pendingKindLabel(input.kind)}
881
- </span>
882
- <p className="min-w-0 flex-1 text-og-xs leading-4 text-og-fg">{input.summary}</p>
883
- {onDismiss ? (
884
- <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">
885
- <IconAction
886
- label={`Dismiss incoming ${pendingKindLabel(input.kind)}`}
887
- tip="Dismiss"
888
- onClick={() => onDismiss(input.id)}
889
- danger
890
- >
891
- <Trash2Icon className="size-3" />
892
- </IconAction>
893
- </div>
894
- ) : null}
895
- </li>
896
- ))}
897
- </ul>
1431
+ <Trash2Icon className="size-3" />
1432
+ </IconAction>
1433
+ </div>
1434
+ ) : null}
1435
+ </li>
898
1436
  );
899
1437
  }
900
1438
 
@@ -906,6 +1444,7 @@ function QueuePanel({
906
1444
  onRefresh,
907
1445
  onClearMutationError,
908
1446
  onRetryOptimistic,
1447
+ onRestoreOptimistic,
909
1448
  onRemoveOptimistic,
910
1449
  readOnly,
911
1450
  mutationFor,
@@ -924,6 +1463,7 @@ function QueuePanel({
924
1463
  onRefresh: () => Promise<void>;
925
1464
  onClearMutationError: () => void;
926
1465
  onRetryOptimistic?: ((clientEventId: string) => void) | undefined;
1466
+ onRestoreOptimistic?: ((clientEventId: string) => void) | undefined;
927
1467
  onRemoveOptimistic?: ((clientEventId: string) => void) | undefined;
928
1468
  readOnly: boolean;
929
1469
  mutationFor: UseTurnQueueResult["mutationFor"];
@@ -968,14 +1508,14 @@ function QueuePanel({
968
1508
  const voice = presentation.kind !== "prompt";
969
1509
  const pending = mutationFor(turn.id);
970
1510
  const settling = !interactiveTurnIds.has(turn.id);
971
- const beforeUp = index > 0 ? (turns[index - 1]?.id ?? null) : null;
972
- const beforeDown = index < turns.length - 1 ? (turns[index + 2]?.id ?? null) : null;
1511
+ const { beforeUp, beforeDown } = queueNeighborAnchors(turns, index);
973
1512
  const showActions = !readOnly && (onEdit || onSteer || onRemove || onMove);
974
1513
  const confirmingReplace = replaceDraftFor === turn.id;
975
1514
  return (
976
1515
  <li
977
1516
  key={turn.id}
978
1517
  data-queue-turn-id={turn.id}
1518
+ tabIndex={-1}
979
1519
  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)]"
980
1520
  >
981
1521
  <div className="flex items-start gap-1.5">
@@ -989,34 +1529,69 @@ function QueuePanel({
989
1529
  {index + 1}
990
1530
  </span>
991
1531
  )}
992
- <p className="min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg">
993
- {presentation.text}
994
- </p>
1532
+ <CompactQueueItemContent
1533
+ text={presentation.text}
1534
+ annotations={turn.annotations ?? []}
1535
+ />
995
1536
  {showActions ? (
996
- <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">
997
- {onMove && turns.length > 1 ? (
998
- <>
1537
+ <div className="flex shrink-0 items-center gap-0.5">
1538
+ {/* Reorder, edit and delete stay on hover; Steer is always visible. */}
1539
+ <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">
1540
+ {onMove && turns.length > 1 ? (
1541
+ <>
1542
+ <IconAction
1543
+ label={`Move queued prompt ${index + 1} up`}
1544
+ tip="Move up"
1545
+ disabled={settling || pending !== null || index === 0}
1546
+ onClick={() => onMove(turn.id, beforeUp)}
1547
+ >
1548
+ <ArrowUpIcon className="size-3" />
1549
+ </IconAction>
1550
+ <IconAction
1551
+ label={`Move queued prompt ${index + 1} down`}
1552
+ tip="Move down"
1553
+ disabled={settling || pending !== null || index >= turns.length - 1}
1554
+ onClick={() => onMove(turn.id, beforeDown)}
1555
+ >
1556
+ <ArrowDownIcon className="size-3" />
1557
+ </IconAction>
1558
+ </>
1559
+ ) : null}
1560
+ {onEdit ? (
999
1561
  <IconAction
1000
- label={`Move queued prompt ${index + 1} up`}
1001
- tip="Move up"
1002
- disabled={settling || pending !== null || index === 0}
1003
- onClick={() => onMove(turn.id, beforeUp)}
1562
+ label={`Edit queued prompt ${index + 1}`}
1563
+ tip={QUEUE_EDIT_TIP}
1564
+ disabled={settling || pending !== null}
1565
+ onClick={() => onEdit(turn)}
1004
1566
  >
1005
- <ArrowUpIcon className="size-3" />
1567
+ {pending === "edit" ? (
1568
+ <Loader2Icon className="size-3 animate-og-spin" />
1569
+ ) : (
1570
+ <PencilIcon className="size-3" />
1571
+ )}
1006
1572
  </IconAction>
1573
+ ) : null}
1574
+ {onRemove ? (
1007
1575
  <IconAction
1008
- label={`Move queued prompt ${index + 1} down`}
1009
- tip="Move down"
1010
- disabled={settling || pending !== null || index >= turns.length - 1}
1011
- onClick={() => onMove(turn.id, beforeDown)}
1576
+ label={`Remove queued prompt ${index + 1}`}
1577
+ tip={QUEUE_DELETE_TIP}
1578
+ disabled={settling || pending !== null}
1579
+ onClick={() => onRemove(turn.id)}
1580
+ danger
1012
1581
  >
1013
- <ArrowDownIcon className="size-3" />
1582
+ {pending === "delete" ? (
1583
+ <Loader2Icon className="size-3 animate-og-spin" />
1584
+ ) : (
1585
+ <Trash2Icon className="size-3" />
1586
+ )}
1014
1587
  </IconAction>
1015
- </>
1016
- ) : null}
1588
+ ) : null}
1589
+ </div>
1017
1590
  {onSteer ? (
1018
1591
  <IconAction
1019
1592
  label={`Steer queued prompt ${index + 1}`}
1593
+ analyticsAction="steer"
1594
+ text="Steer"
1020
1595
  tip={QUEUE_STEER_TIP}
1021
1596
  disabled={settling || pending !== null}
1022
1597
  onClick={() => onSteer(turn.id)}
@@ -1024,36 +1599,7 @@ function QueuePanel({
1024
1599
  {pending === "steer" ? (
1025
1600
  <Loader2Icon className="size-3 animate-og-spin" />
1026
1601
  ) : (
1027
- <ZapIcon className="size-3" />
1028
- )}
1029
- </IconAction>
1030
- ) : null}
1031
- {onEdit ? (
1032
- <IconAction
1033
- label={`Edit queued prompt ${index + 1}`}
1034
- tip={QUEUE_EDIT_TIP}
1035
- disabled={settling || pending !== null}
1036
- onClick={() => onEdit(turn)}
1037
- >
1038
- {pending === "edit" ? (
1039
- <Loader2Icon className="size-3 animate-og-spin" />
1040
- ) : (
1041
- <PencilIcon className="size-3" />
1042
- )}
1043
- </IconAction>
1044
- ) : null}
1045
- {onRemove ? (
1046
- <IconAction
1047
- label={`Remove queued prompt ${index + 1}`}
1048
- tip={QUEUE_DELETE_TIP}
1049
- disabled={settling || pending !== null}
1050
- onClick={() => onRemove(turn.id)}
1051
- danger
1052
- >
1053
- {pending === "delete" ? (
1054
- <Loader2Icon className="size-3 animate-og-spin" />
1055
- ) : (
1056
- <Trash2Icon className="size-3" />
1602
+ <CornerDownRightIcon className="size-3" />
1057
1603
  )}
1058
1604
  </IconAction>
1059
1605
  ) : null}
@@ -1062,25 +1608,22 @@ function QueuePanel({
1062
1608
  </div>
1063
1609
  {confirmingReplace ? (
1064
1610
  <div className="rounded-og-sm border border-og-status-waiting/30 bg-og-status-waiting/10 p-2 text-og-xs text-og-fg">
1065
- <p>Your composer already has a draft. Replace it with this queued prompt?</p>
1066
- <p className="mt-0.5 text-og-fg-muted">
1067
- The current draft will be permanently discarded; this queued prompt is preserved
1068
- until you confirm.
1069
- </p>
1611
+ <p>{QUEUE_REPLACE_DRAFT_COPY.title}</p>
1612
+ <p className="mt-0.5 text-og-fg-muted">{QUEUE_REPLACE_DRAFT_COPY.detail}</p>
1070
1613
  <div className="mt-2 flex justify-end gap-1.5">
1071
1614
  <button
1072
1615
  type="button"
1073
1616
  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"
1074
1617
  onClick={onCancelReplace}
1075
1618
  >
1076
- Keep current draft
1619
+ {QUEUE_REPLACE_DRAFT_COPY.keep}
1077
1620
  </button>
1078
1621
  <button
1079
1622
  type="button"
1080
- 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"
1623
+ className="rounded-og-sm border border-og-primary-border bg-og-primary text-og-primary-fg px-2 py-1 font-medium hover:bg-og-primary-hover focus-visible:ring-2 focus-visible:ring-og-accent/40"
1081
1624
  onClick={onConfirmReplace}
1082
1625
  >
1083
- Replace and edit
1626
+ {QUEUE_REPLACE_DRAFT_COPY.replace}
1084
1627
  </button>
1085
1628
  </div>
1086
1629
  </div>
@@ -1105,19 +1648,24 @@ function QueuePanel({
1105
1648
  <span className="shrink-0 font-og-mono text-[10px] leading-4 text-og-fg-subtle">
1106
1649
  {turns.length + index + 1}
1107
1650
  </span>
1108
- <p className="min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg">
1109
- {message.text}
1110
- </p>
1651
+ <div className="min-w-0 flex-1">
1652
+ <CompactQueueItemContent text={message.text} annotations={message.annotations} />
1653
+ {message.state === "failed" && message.error ? (
1654
+ <p className="break-words text-og-xs">{message.error}</p>
1655
+ ) : null}
1656
+ </div>
1111
1657
  <span className="sr-only">
1112
1658
  {message.state === "failed"
1113
- ? "Not confirmed"
1659
+ ? message.outcomeUnknown
1660
+ ? "Not confirmed"
1661
+ : "Message not sent"
1114
1662
  : message.state === "sending"
1115
1663
  ? "Placing in queue"
1116
1664
  : "Queued"}
1117
1665
  </span>
1118
1666
  {message.state === "failed" ? (
1119
1667
  <div className="flex shrink-0 items-center gap-1 text-[10px]">
1120
- {onRetryOptimistic ? (
1668
+ {message.retryable !== false && onRetryOptimistic ? (
1121
1669
  <button
1122
1670
  type="button"
1123
1671
  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"
@@ -1126,6 +1674,15 @@ function QueuePanel({
1126
1674
  Retry
1127
1675
  </button>
1128
1676
  ) : null}
1677
+ {message.retryable === false && onRestoreOptimistic ? (
1678
+ <button
1679
+ type="button"
1680
+ 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"
1681
+ onClick={() => onRestoreOptimistic(message.clientEventId)}
1682
+ >
1683
+ Edit message
1684
+ </button>
1685
+ ) : null}
1129
1686
  {onRemoveOptimistic ? (
1130
1687
  <button
1131
1688
  type="button"
@@ -1184,6 +1741,30 @@ function QueuePanel({
1184
1741
  );
1185
1742
  }
1186
1743
 
1744
+ function CompactQueueItemContent({
1745
+ text,
1746
+ annotations,
1747
+ }: {
1748
+ text: string;
1749
+ annotations: readonly TimelineAnnotationLike[];
1750
+ }) {
1751
+ const content = queueItemContent(text, annotations.length);
1752
+ return (
1753
+ <div className="flex min-w-0 flex-1 items-center gap-1.5">
1754
+ {content === "text" ? (
1755
+ <p className="min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg">{text}</p>
1756
+ ) : content === "unavailable" ? (
1757
+ <p className="min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg-muted italic">
1758
+ {QUEUE_ITEM_CONTENT_UNAVAILABLE}
1759
+ </p>
1760
+ ) : null}
1761
+ {annotations.length > 0 ? (
1762
+ <TimelineAnnotationsChip annotations={annotations} className="shrink-0" compact />
1763
+ ) : null}
1764
+ </div>
1765
+ );
1766
+ }
1767
+
1187
1768
  function GoalPanel({
1188
1769
  goal,
1189
1770
  state,
@@ -1195,6 +1776,7 @@ function GoalPanel({
1195
1776
  elapsed: string | null;
1196
1777
  readOnly: boolean;
1197
1778
  }) {
1779
+ const formatError = useErrorMessage();
1198
1780
  const record = goal.goal;
1199
1781
  if (!record) return null;
1200
1782
  const canToggle = !readOnly && (record.status === "active" || record.status === "paused");
@@ -1206,7 +1788,7 @@ function GoalPanel({
1206
1788
  <span>{sessionChromeGoalPillLabel(state, record)}</span>
1207
1789
  {elapsed ? (
1208
1790
  <span className="tabular-nums normal-case tracking-normal text-og-fg-muted">
1209
- · {elapsed}
1791
+ · Created {elapsed} ago
1210
1792
  </span>
1211
1793
  ) : null}
1212
1794
  <span className="normal-case tracking-normal text-og-fg-muted">· v{record.version}</span>
@@ -1227,7 +1809,7 @@ function GoalPanel({
1227
1809
  ) : null}
1228
1810
  {record.continuation?.lastError ? (
1229
1811
  <p className="rounded-og-sm bg-og-status-waiting/10 px-1.5 py-1 text-og-xs leading-4 text-og-status-waiting">
1230
- {record.continuation.lastError}
1812
+ {formatError(record.continuation.lastError)}
1231
1813
  </p>
1232
1814
  ) : null}
1233
1815
  <div className="flex flex-wrap items-center justify-between gap-1.5 pt-0.5">
@@ -1288,7 +1870,9 @@ const QUEUE_EDIT_TIP = "Edit in composer";
1288
1870
  const QUEUE_DELETE_TIP = "Delete this queued prompt";
1289
1871
 
1290
1872
  function IconAction({
1873
+ text,
1291
1874
  label,
1875
+ analyticsAction,
1292
1876
  tip,
1293
1877
  onClick,
1294
1878
  disabled,
@@ -1296,6 +1880,9 @@ function IconAction({
1296
1880
  children,
1297
1881
  }: {
1298
1882
  label: string;
1883
+ /** Stable, content-free control label a host's product analytics may read. */
1884
+ analyticsAction?: "steer";
1885
+ text?: string;
1299
1886
  tip: ReactNode;
1300
1887
  onClick: () => void;
1301
1888
  disabled?: boolean;
@@ -1308,16 +1895,20 @@ function IconAction({
1308
1895
  <button
1309
1896
  type="button"
1310
1897
  aria-label={label}
1898
+ data-analytics-action={analyticsAction}
1311
1899
  disabled={disabled}
1312
1900
  onClick={onClick}
1313
1901
  className={cn(
1314
- "inline-flex size-6 items-center justify-center rounded-og-sm text-og-fg-subtle outline-hidden transition-colors",
1902
+ "inline-flex size-6 items-center justify-center rounded-og-sm outline-hidden transition-colors",
1315
1903
  "hover:bg-og-surface-2 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent/40",
1316
1904
  "disabled:pointer-events-none disabled:opacity-40 pointer-coarse:size-9",
1905
+ text ? "text-og-fg" : "text-og-fg-subtle",
1906
+ text && "w-auto gap-1 px-1.5 text-og-xs pointer-coarse:w-auto",
1317
1907
  danger && "hover:text-og-danger",
1318
1908
  )}
1319
1909
  >
1320
1910
  {children}
1911
+ {text}
1321
1912
  </button>
1322
1913
  </TooltipTrigger>
1323
1914
  <TooltipContent side="top">{tip}</TooltipContent>