@opengeni/react 1.0.1 → 1.0.2-canary.37202341988001

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 (632) hide show
  1. package/README.md +660 -21
  2. package/dist/accounts.d.ts +64 -0
  3. package/dist/accounts.js +822 -0
  4. package/dist/accounts.js.map +1 -0
  5. package/dist/approvals.d.ts +2 -1
  6. package/dist/artifacts-document.js +3 -2
  7. package/dist/artifacts-presentation.js +3 -2
  8. package/dist/artifacts-spreadsheet.js +2 -2
  9. package/dist/artifacts.d.ts +4 -1
  10. package/dist/artifacts.js +518 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-SHYKQRNX.js +16 -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-UGBTNB3L.js +11 -0
  16. package/dist/chat-interactive-block-UGBTNB3L.js.map +1 -0
  17. package/dist/chunk-26ZNDDLZ.js +453 -0
  18. package/dist/chunk-26ZNDDLZ.js.map +1 -0
  19. package/dist/chunk-3CTRFMAK.js +359 -0
  20. package/dist/chunk-3CTRFMAK.js.map +1 -0
  21. package/dist/chunk-447JLCBU.js +209 -0
  22. package/dist/chunk-447JLCBU.js.map +1 -0
  23. package/dist/chunk-4RVYOY4O.js +379 -0
  24. package/dist/chunk-4RVYOY4O.js.map +1 -0
  25. package/dist/chunk-5CVXZA3Y.js +292 -0
  26. package/dist/chunk-5CVXZA3Y.js.map +1 -0
  27. package/dist/chunk-5J4FOW6Q.js +108 -0
  28. package/dist/chunk-5J4FOW6Q.js.map +1 -0
  29. package/dist/chunk-742CZ3L3.js +481 -0
  30. package/dist/chunk-742CZ3L3.js.map +1 -0
  31. package/dist/chunk-A2PI6UMY.js +41 -0
  32. package/dist/chunk-A2PI6UMY.js.map +1 -0
  33. package/dist/{chunk-7WCLAEFV.js → chunk-A4UJB2MM.js} +37 -27
  34. package/dist/chunk-A4UJB2MM.js.map +1 -0
  35. package/dist/chunk-B3V6TG77.js +41 -0
  36. package/dist/chunk-B3V6TG77.js.map +1 -0
  37. package/dist/chunk-BRM6FVZA.js +302 -0
  38. package/dist/chunk-BRM6FVZA.js.map +1 -0
  39. package/dist/chunk-C5X5AJXK.js +182 -0
  40. package/dist/chunk-C5X5AJXK.js.map +1 -0
  41. package/dist/{chunk-6KLX2RH5.js → chunk-DO544OSV.js} +1075 -79
  42. package/dist/chunk-DO544OSV.js.map +1 -0
  43. package/dist/{chunk-R3AZOAB5.js → chunk-DYWBUX5Q.js} +29 -123
  44. package/dist/chunk-DYWBUX5Q.js.map +1 -0
  45. package/dist/{chunk-HA46CYQK.js → chunk-EESD3PY3.js} +792 -537
  46. package/dist/chunk-EESD3PY3.js.map +1 -0
  47. package/dist/{chunk-5UQPNLIO.js → chunk-EN3YTHKR.js} +4117 -3896
  48. package/dist/chunk-EN3YTHKR.js.map +1 -0
  49. package/dist/chunk-ERGYJIBB.js +21 -0
  50. package/dist/chunk-ERGYJIBB.js.map +1 -0
  51. package/dist/chunk-FZCP527Y.js +116 -0
  52. package/dist/chunk-FZCP527Y.js.map +1 -0
  53. package/dist/chunk-GIMRELBW.js +14 -0
  54. package/dist/chunk-GIMRELBW.js.map +1 -0
  55. package/dist/chunk-GYVRFZDY.js +2733 -0
  56. package/dist/chunk-GYVRFZDY.js.map +1 -0
  57. package/dist/{chunk-LLOLUHVG.js → chunk-HDJWDK7W.js} +1358 -2746
  58. package/dist/chunk-HDJWDK7W.js.map +1 -0
  59. package/dist/chunk-I7IWRQLN.js +1608 -0
  60. package/dist/chunk-I7IWRQLN.js.map +1 -0
  61. package/dist/chunk-IT4BJUGF.js +13055 -0
  62. package/dist/chunk-IT4BJUGF.js.map +1 -0
  63. package/dist/chunk-IWIDV7SB.js +1 -0
  64. package/dist/chunk-IWIDV7SB.js.map +1 -0
  65. package/dist/chunk-J2QWVSQY.js +312 -0
  66. package/dist/chunk-J2QWVSQY.js.map +1 -0
  67. package/dist/chunk-J6DBS4T3.js +371 -0
  68. package/dist/chunk-J6DBS4T3.js.map +1 -0
  69. package/dist/{chunk-B6WPZSTT.js → chunk-JIQYUGVL.js} +1331 -1163
  70. package/dist/chunk-JIQYUGVL.js.map +1 -0
  71. package/dist/chunk-JT4JW7BC.js +54 -0
  72. package/dist/chunk-JT4JW7BC.js.map +1 -0
  73. package/dist/chunk-K3HQAKQX.js +24 -0
  74. package/dist/chunk-K3HQAKQX.js.map +1 -0
  75. package/dist/{chunk-PEI6RANI.js → chunk-PNY3JKBJ.js} +309 -74
  76. package/dist/chunk-PNY3JKBJ.js.map +1 -0
  77. package/dist/chunk-RHREZ7BO.js +11 -0
  78. package/dist/chunk-RHREZ7BO.js.map +1 -0
  79. package/dist/chunk-RLUSC2WA.js +299 -0
  80. package/dist/chunk-RLUSC2WA.js.map +1 -0
  81. package/dist/{chunk-IGC6A2ZI.js → chunk-RSI7XYXL.js} +777 -246
  82. package/dist/chunk-RSI7XYXL.js.map +1 -0
  83. package/dist/chunk-SCOTPE2I.js +589 -0
  84. package/dist/chunk-SCOTPE2I.js.map +1 -0
  85. package/dist/{chunk-C5ZPSSS5.js → chunk-TKOTKRWY.js} +5 -4
  86. package/dist/{chunk-C5ZPSSS5.js.map → chunk-TKOTKRWY.js.map} +1 -1
  87. package/dist/chunk-TMYGL6X5.js +742 -0
  88. package/dist/chunk-TMYGL6X5.js.map +1 -0
  89. package/dist/chunk-UGLEYEMP.js +33 -0
  90. package/dist/chunk-UGLEYEMP.js.map +1 -0
  91. package/dist/chunk-UK4TINKT.js +27 -0
  92. package/dist/chunk-UK4TINKT.js.map +1 -0
  93. package/dist/chunk-UTRTG6LH.js +220 -0
  94. package/dist/chunk-UTRTG6LH.js.map +1 -0
  95. package/dist/chunk-WEHMPOXK.js +39 -0
  96. package/dist/chunk-WEHMPOXK.js.map +1 -0
  97. package/dist/chunk-WGXVEJO5.js +319 -0
  98. package/dist/chunk-WGXVEJO5.js.map +1 -0
  99. package/dist/chunk-WRHIZYZF.js +988 -0
  100. package/dist/chunk-WRHIZYZF.js.map +1 -0
  101. package/dist/{chunk-HUIKIDM5.js → chunk-WUISZ3WU.js} +223 -115
  102. package/dist/chunk-WUISZ3WU.js.map +1 -0
  103. package/dist/chunk-XCHWDJ22.js +107 -0
  104. package/dist/chunk-XCHWDJ22.js.map +1 -0
  105. package/dist/{chunk-KCGXPP5V.js → chunk-Y2PRMYLC.js} +11 -6
  106. package/dist/chunk-Y2PRMYLC.js.map +1 -0
  107. package/dist/chunk-YBXQDQFX.js +1772 -0
  108. package/dist/chunk-YBXQDQFX.js.map +1 -0
  109. package/dist/chunk-YM2DE7BQ.js +3124 -0
  110. package/dist/chunk-YM2DE7BQ.js.map +1 -0
  111. package/dist/{chunk-KZ73RL76.js → chunk-YQEAA6LT.js} +7 -3
  112. package/dist/chunk-YQEAA6LT.js.map +1 -0
  113. package/dist/chunk-YV4L3ILF.js +9 -0
  114. package/dist/chunk-YV4L3ILF.js.map +1 -0
  115. package/dist/chunk-ZYRGEKWS.js +216 -0
  116. package/dist/chunk-ZYRGEKWS.js.map +1 -0
  117. package/dist/client.d.ts +7 -4
  118. package/dist/clipboard.js +1 -0
  119. package/dist/commands/types.d.ts +2 -0
  120. package/dist/components/anthropic-mark.d.ts +3 -0
  121. package/dist/components/approval-surface.d.ts +15 -0
  122. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  123. package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
  124. package/dist/components/artifacts/artifact-surface.d.ts +3 -1
  125. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  126. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  127. package/dist/components/artifacts/document-editor.d.ts +4 -2
  128. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  129. package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
  130. package/dist/components/artifacts/editable-document.d.ts +1 -1
  131. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  132. package/dist/components/artifacts/editable-spreadsheet.d.ts +2 -1
  133. package/dist/components/artifacts/index.d.ts +8 -1
  134. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  135. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  136. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  137. package/dist/components/artifacts/published-html-artifact-frame.d.ts +48 -3
  138. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  139. package/dist/components/artifacts/site-view.d.ts +23 -0
  140. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  141. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  142. package/dist/components/browser-select-control.d.ts +16 -0
  143. package/dist/components/browser-viewer.d.ts +10 -1
  144. package/dist/components/chat-composer.d.ts +21 -3
  145. package/dist/components/child-session-link.d.ts +5 -0
  146. package/dist/components/claude-mark.d.ts +3 -0
  147. package/dist/components/code-editor.d.ts +1 -4
  148. package/dist/components/composer.d.ts +45 -4
  149. package/dist/components/computer-viewer.d.ts +4 -1
  150. package/dist/components/copy-button.d.ts +3 -1
  151. package/dist/components/desktop-viewer.d.ts +1 -1
  152. package/dist/components/enrollment-consent.d.ts +6 -3
  153. package/dist/components/file-browser.d.ts +10 -1
  154. package/dist/components/fleet-tile.d.ts +2 -2
  155. package/dist/components/grok-mark.d.ts +26 -0
  156. package/dist/components/human-input-form.d.ts +21 -2
  157. package/dist/components/human-input-surface.d.ts +6 -3
  158. package/dist/components/machine-card.d.ts +4 -1
  159. package/dist/components/machines/machine-detail.d.ts +4 -1
  160. package/dist/components/machines/machine-operation-policy.d.ts +11 -0
  161. package/dist/components/machines-dashboard.d.ts +3 -1
  162. package/dist/components/markdown-table-layout.d.ts +12 -0
  163. package/dist/components/markdown.d.ts +47 -3
  164. package/dist/components/message-timeline.d.ts +72 -9
  165. package/dist/components/model-mark.d.ts +29 -0
  166. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  167. package/dist/components/model-policy-picker.d.ts +62 -13
  168. package/dist/components/open-geni-chat.d.ts +58 -0
  169. package/dist/components/open-geni-links.d.ts +68 -0
  170. package/dist/components/openrouter-mark.d.ts +6 -0
  171. package/dist/components/pierre-file.d.ts +1 -1
  172. package/dist/components/preview-loading.d.ts +2 -0
  173. package/dist/components/queue-item-content.d.ts +9 -0
  174. package/dist/components/sandbox-files.d.ts +13 -2
  175. package/dist/components/sandbox-workspace.d.ts +43 -3
  176. package/dist/components/session-capability-frame.d.ts +35 -0
  177. package/dist/components/session-chrome.d.ts +66 -8
  178. package/dist/components/session-commands-panel.d.ts +6 -0
  179. package/dist/components/session-commands.d.ts +6 -0
  180. package/dist/components/session-connection-request.d.ts +8 -0
  181. package/dist/components/session-conversation.d.ts +89 -0
  182. package/dist/components/session-list.d.ts +36 -0
  183. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  184. package/dist/components/session-proxy-scope.d.ts +21 -0
  185. package/dist/components/timeline-anchor.d.ts +24 -0
  186. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  187. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  188. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  189. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  190. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  191. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  192. package/dist/components/timeline-annotations.d.ts +13 -3
  193. package/dist/components/timeline-reading-progress.d.ts +11 -0
  194. package/dist/components/timeline-search.d.ts +34 -0
  195. package/dist/components/timeline-settlement.d.ts +16 -0
  196. package/dist/components/tip-follow.d.ts +16 -0
  197. package/dist/components/usage-limit-notice.d.ts +49 -0
  198. package/dist/components/usage-member-list.d.ts +91 -0
  199. package/dist/components/usage-meter.d.ts +73 -0
  200. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  201. package/dist/components/user-message-body.d.ts +10 -1
  202. package/dist/components/workspace-dock.d.ts +6 -2
  203. package/dist/composer.d.ts +5 -4
  204. package/dist/composer.js +15 -9
  205. package/dist/computer-viewer-6SRGWRUX.js +19 -0
  206. package/dist/computer-viewer-6SRGWRUX.js.map +1 -0
  207. package/dist/connect-account-identity.d.ts +8 -0
  208. package/dist/connect-accounts.d.ts +15 -0
  209. package/dist/connect-chooser.d.ts +18 -0
  210. package/dist/connect-panel.d.ts +18 -0
  211. package/dist/connect-setup.d.ts +16 -0
  212. package/dist/connect.d.ts +21 -0
  213. package/dist/connect.js +2129 -0
  214. package/dist/connect.js.map +1 -0
  215. package/dist/connection-catalog.d.ts +38 -0
  216. package/dist/connection-discovery.d.ts +12 -0
  217. package/dist/connection-installed.d.ts +17 -0
  218. package/dist/connection-logo.d.ts +9 -0
  219. package/dist/connection-service-logo.d.ts +8 -0
  220. package/dist/connection-service-presentation.d.ts +13 -0
  221. package/dist/connection-skeleton.d.ts +5 -0
  222. package/dist/connection-type-picker.d.ts +6 -0
  223. package/dist/conversation-timeline.d.ts +5 -0
  224. package/dist/desktop.d.ts +7 -0
  225. package/dist/desktop.js +26 -0
  226. package/dist/desktop.js.map +1 -0
  227. package/dist/device-authorization.d.ts +23 -0
  228. package/dist/diffs.d.ts +8 -0
  229. package/dist/diffs.js +14 -0
  230. package/dist/diffs.js.map +1 -0
  231. package/dist/discovery-cache.d.ts +5 -0
  232. package/dist/editor.d.ts +7 -0
  233. package/dist/editor.js +21 -0
  234. package/dist/editor.js.map +1 -0
  235. package/dist/embedded-session-client.d.ts +23 -0
  236. package/dist/file-node-visibility.d.ts +15 -0
  237. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-YZ3ZKWMM.js} +2 -1
  238. package/dist/fleet-decision-row-YZ3ZKWMM.js.map +1 -0
  239. package/dist/hooks/channel-cache.d.ts +23 -0
  240. package/dist/hooks/latest-question.d.ts +25 -0
  241. package/dist/hooks/shared-machines-list.d.ts +14 -0
  242. package/dist/hooks/use-attached-browsers.d.ts +2 -1
  243. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  244. package/dist/hooks/use-browser-session.d.ts +12 -1
  245. package/dist/hooks/use-channels.d.ts +1 -0
  246. package/dist/hooks/use-codex-accounts.d.ts +25 -7
  247. package/dist/hooks/use-composer.d.ts +45 -9
  248. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  249. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  250. package/dist/hooks/use-computer-session.d.ts +2 -0
  251. package/dist/hooks/use-connect.d.ts +22 -0
  252. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  253. package/dist/hooks/use-file-attachments.d.ts +21 -2
  254. package/dist/hooks/use-machine-chip.d.ts +3 -3
  255. package/dist/hooks/use-machines.d.ts +19 -1
  256. package/dist/hooks/use-sandbox-files.d.ts +5 -1
  257. package/dist/hooks/use-session-background-commands.d.ts +14 -0
  258. package/dist/hooks/use-session-events.d.ts +30 -8
  259. package/dist/hooks/use-session-lineage.d.ts +4 -0
  260. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  261. package/dist/hooks/use-session.d.ts +6 -0
  262. package/dist/hooks/use-turn-queue.d.ts +12 -0
  263. package/dist/hooks/use-usage.d.ts +40 -0
  264. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  265. package/dist/hooks/use-workspace-sessions.d.ts +27 -5
  266. package/dist/human-input.d.ts +3 -1
  267. package/dist/identity-link-accounts.d.ts +11 -0
  268. package/dist/identity-link-consent.d.ts +18 -0
  269. package/dist/index.d.ts +60 -17
  270. package/dist/index.js +2238 -6201
  271. package/dist/index.js.map +1 -1
  272. package/dist/interaction.d.ts +1 -1
  273. package/dist/interaction.js +35 -184
  274. package/dist/interaction.js.map +1 -1
  275. package/dist/latest-question-HTRIS4KJ.js +117 -0
  276. package/dist/latest-question-HTRIS4KJ.js.map +1 -0
  277. package/dist/lib/error-message.d.ts +7 -0
  278. package/dist/lib/format.d.ts +36 -2
  279. package/dist/lib/host-theme.d.ts +70 -0
  280. package/dist/lib/interaction-errors.d.ts +6 -0
  281. package/dist/lib/menu-styles.d.ts +22 -0
  282. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  283. package/dist/lib/workbench-peers.d.ts +36 -0
  284. package/dist/lib/xterm-theme.d.ts +7 -5
  285. package/dist/machines.d.ts +4 -2
  286. package/dist/machines.js +14 -4
  287. package/dist/markdown-table-layout-QXSLK4BY.js +106 -0
  288. package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
  289. package/dist/mcp-connection-status.d.ts +14 -0
  290. package/dist/model-policy-picker-menu-M54ISBMN.js +14 -0
  291. package/dist/model-policy-picker-menu-M54ISBMN.js.map +1 -0
  292. package/dist/model-policy.d.ts +19 -3
  293. package/dist/model-policy.js +9 -1
  294. package/dist/older-history.d.ts +30 -0
  295. package/dist/platform-activity-row-627BFZ46.js +182 -0
  296. package/dist/platform-activity-row-627BFZ46.js.map +1 -0
  297. package/dist/plugin-details.d.ts +14 -0
  298. package/dist/plugin-discovery.d.ts +25 -0
  299. package/dist/provider.d.ts +13 -1
  300. package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-ZHFI5JBP.js} +131 -44
  301. package/dist/queue-surface-implementation-ZHFI5JBP.js.map +1 -0
  302. package/dist/realtime/realtime-control.d.ts +6 -3
  303. package/dist/realtime.js +133 -74
  304. package/dist/realtime.js.map +1 -1
  305. package/dist/sandbox-files-GORZOUUJ.js +20 -0
  306. package/dist/sandbox-files-GORZOUUJ.js.map +1 -0
  307. package/dist/session-auth-recommendation.d.ts +5 -0
  308. package/dist/session-capability-policy.d.ts +12 -0
  309. package/dist/session-ui.d.ts +30 -2
  310. package/dist/session-ui.js +85 -7
  311. package/dist/session-ui.js.map +1 -1
  312. package/dist/session.d.ts +8 -2
  313. package/dist/session.js +30 -19
  314. package/dist/sites-ui.d.ts +34 -0
  315. package/dist/sites.d.ts +3 -0
  316. package/dist/sites.js +11 -0
  317. package/dist/sites.js.map +1 -0
  318. package/dist/skill-discovery.d.ts +47 -0
  319. package/dist/terminal.d.ts +8 -0
  320. package/dist/terminal.js +31 -0
  321. package/dist/terminal.js.map +1 -0
  322. package/dist/timeline/activity-rail.d.ts +11 -2
  323. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  324. package/dist/timeline/compaction-copy.d.ts +10 -0
  325. package/dist/timeline/entrance.d.ts +13 -1
  326. package/dist/timeline/genie-loading.d.ts +34 -0
  327. package/dist/timeline/index.d.ts +6 -2
  328. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  329. package/dist/timeline/platform-activity-row.d.ts +14 -0
  330. package/dist/timeline/presented-image.d.ts +6 -0
  331. package/dist/timeline/projection.d.ts +31 -2
  332. package/dist/timeline/registry.d.ts +2 -0
  333. package/dist/timeline/retained-image.d.ts +18 -0
  334. package/dist/timeline/rolling-activity.d.ts +11 -0
  335. package/dist/timeline/screenshot-lightbox.d.ts +16 -1
  336. package/dist/timeline/shared.d.ts +8 -3
  337. package/dist/timeline/startup-preference.d.ts +3 -0
  338. package/dist/timeline/startup-timings.d.ts +4 -0
  339. package/dist/timeline/tool-display-name.d.ts +2 -1
  340. package/dist/timeline/turn-summary.d.ts +34 -3
  341. package/dist/timeline/types.d.ts +147 -7
  342. package/dist/timeline-annotation-markers-GNDHTGBD.js +165 -0
  343. package/dist/timeline-annotation-markers-GNDHTGBD.js.map +1 -0
  344. package/dist/timeline-annotation-selection-DMLMM2TX.js +241 -0
  345. package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
  346. package/dist/timeline-annotations-dialog-ELRDBHTS.js +273 -0
  347. package/dist/timeline-annotations-dialog-ELRDBHTS.js.map +1 -0
  348. package/dist/types/machines.d.ts +2 -2
  349. package/dist/usage/allowance-copy.d.ts +25 -0
  350. package/dist/usage/summary.d.ts +35 -0
  351. package/dist/usage.d.ts +13 -0
  352. package/dist/usage.js +1074 -0
  353. package/dist/usage.js.map +1 -0
  354. package/package.json +44 -4
  355. package/src/accounts.tsx +1072 -0
  356. package/src/approvals.ts +8 -1
  357. package/src/artifacts.ts +42 -0
  358. package/src/assets/README.md +8 -0
  359. package/src/assets/gmail.ico +0 -0
  360. package/src/assets/outlook.ico +0 -0
  361. package/src/capability-catalog-row.tsx +94 -0
  362. package/src/capability-logo-fallback.ts +22 -0
  363. package/src/client.ts +22 -13
  364. package/src/commands/registry.ts +18 -15
  365. package/src/commands/types.ts +2 -0
  366. package/src/components/anthropic-mark.tsx +10 -0
  367. package/src/components/approval-surface.tsx +171 -37
  368. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  369. package/src/components/artifacts/artifact-sandbox.tsx +185 -0
  370. package/src/components/artifacts/artifact-surface.tsx +39 -19
  371. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  372. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  373. package/src/components/artifacts/document-editor.tsx +141 -16
  374. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  375. package/src/components/artifacts/editable-artifact-view.tsx +187 -0
  376. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  377. package/src/components/artifacts/editable-document.tsx +37 -36
  378. package/src/components/artifacts/editable-presentation.tsx +36 -18
  379. package/src/components/artifacts/editable-spreadsheet.tsx +5 -2
  380. package/src/components/artifacts/index.ts +44 -0
  381. package/src/components/artifacts/inline-html-document.ts +24 -0
  382. package/src/components/artifacts/latest-task-runner.ts +49 -0
  383. package/src/components/artifacts/presentation-editor.tsx +323 -67
  384. package/src/components/artifacts/published-html-artifact-frame.tsx +338 -5
  385. package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
  386. package/src/components/artifacts/site-view.tsx +116 -0
  387. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  388. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  389. package/src/components/artifacts/spreadsheet-grid.tsx +12 -13
  390. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  391. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  392. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  393. package/src/components/browser-select-control.tsx +312 -0
  394. package/src/components/browser-viewer.tsx +1054 -314
  395. package/src/components/chat-composer.tsx +131 -85
  396. package/src/components/child-session-link.tsx +27 -0
  397. package/src/components/claude-mark.tsx +10 -0
  398. package/src/components/code-editor.tsx +13 -16
  399. package/src/components/composer-transcription-control.tsx +7 -5
  400. package/src/components/composer.tsx +376 -49
  401. package/src/components/computer-viewer.tsx +1041 -329
  402. package/src/components/copy-button.tsx +13 -5
  403. package/src/components/desktop-viewer.tsx +1 -1
  404. package/src/components/enrollment-consent.tsx +65 -7
  405. package/src/components/enrollment-device-flow.tsx +1 -1
  406. package/src/components/file-browser.tsx +158 -34
  407. package/src/components/fleet-tile.tsx +8 -16
  408. package/src/components/generated-video-player.tsx +4 -2
  409. package/src/components/grok-mark.tsx +33 -0
  410. package/src/components/human-input-form.tsx +455 -114
  411. package/src/components/human-input-surface.tsx +18 -7
  412. package/src/components/interaction-intervention-banner.tsx +2 -2
  413. package/src/components/machine-card.tsx +119 -4
  414. package/src/components/machine-dock-bar.tsx +1 -1
  415. package/src/components/machine-input-display.ts +23 -2
  416. package/src/components/machines/machine-detail.tsx +52 -2
  417. package/src/components/machines/machine-operation-policy.tsx +179 -0
  418. package/src/components/machines-dashboard.tsx +8 -17
  419. package/src/components/markdown-table-layout.ts +132 -0
  420. package/src/components/markdown.tsx +473 -44
  421. package/src/components/message-timeline.tsx +2754 -665
  422. package/src/components/model-mark.tsx +90 -0
  423. package/src/components/model-picker.tsx +15 -4
  424. package/src/components/model-policy-picker-menu.tsx +424 -0
  425. package/src/components/model-policy-picker.tsx +337 -381
  426. package/src/components/open-geni-chat.tsx +338 -0
  427. package/src/components/open-geni-links.tsx +179 -0
  428. package/src/components/openrouter-mark.tsx +13 -0
  429. package/src/components/pierre-diff.tsx +41 -16
  430. package/src/components/pierre-file.tsx +36 -11
  431. package/src/components/preview-loading.tsx +154 -0
  432. package/src/components/queue-item-content.ts +14 -0
  433. package/src/components/queue-surface-implementation.tsx +132 -42
  434. package/src/components/queue-surface-state.tsx +3 -1
  435. package/src/components/sandbox-files.tsx +267 -35
  436. package/src/components/sandbox-terminal.tsx +48 -11
  437. package/src/components/sandbox-workspace.tsx +337 -135
  438. package/src/components/session-capability-frame.tsx +192 -0
  439. package/src/components/session-chrome.tsx +1027 -328
  440. package/src/components/session-commands-panel.tsx +126 -0
  441. package/src/components/session-commands.tsx +18 -0
  442. package/src/components/session-connection-request.tsx +97 -0
  443. package/src/components/session-conversation.tsx +526 -0
  444. package/src/components/session-list.tsx +250 -0
  445. package/src/components/session-mcp-capability-card.tsx +680 -0
  446. package/src/components/session-proxy-scope.tsx +92 -0
  447. package/src/components/session-status.tsx +1 -1
  448. package/src/components/timeline-anchor.tsx +119 -0
  449. package/src/components/timeline-annotation-chrome.tsx +196 -0
  450. package/src/components/timeline-annotation-layout.ts +268 -0
  451. package/src/components/timeline-annotation-markers.tsx +185 -0
  452. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  453. package/src/components/timeline-annotation-selection.tsx +106 -54
  454. package/src/components/timeline-annotation-shared.ts +245 -0
  455. package/src/components/timeline-annotations-dialog.tsx +185 -128
  456. package/src/components/timeline-annotations.tsx +189 -45
  457. package/src/components/timeline-reading-progress.ts +80 -0
  458. package/src/components/timeline-search.tsx +168 -0
  459. package/src/components/timeline-settlement.ts +60 -0
  460. package/src/components/tip-follow.ts +70 -7
  461. package/src/components/tooltip.tsx +38 -5
  462. package/src/components/usage-limit-notice.tsx +179 -0
  463. package/src/components/usage-member-list.tsx +792 -0
  464. package/src/components/usage-meter.tsx +382 -0
  465. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  466. package/src/components/user-message-body.tsx +194 -49
  467. package/src/components/workspace-dock.tsx +141 -175
  468. package/src/composer.ts +6 -1
  469. package/src/connect-account-identity.tsx +34 -0
  470. package/src/connect-accounts.tsx +233 -0
  471. package/src/connect-chooser.tsx +336 -0
  472. package/src/connect-panel.tsx +99 -0
  473. package/src/connect-setup.tsx +307 -0
  474. package/src/connect.ts +60 -0
  475. package/src/connection-assets.d.ts +4 -0
  476. package/src/connection-catalog.tsx +162 -0
  477. package/src/connection-discovery.tsx +235 -0
  478. package/src/connection-installed.tsx +51 -0
  479. package/src/connection-logo.tsx +37 -0
  480. package/src/connection-service-logo.tsx +55 -0
  481. package/src/connection-service-presentation.ts +46 -0
  482. package/src/connection-skeleton.tsx +16 -0
  483. package/src/connection-type-picker.tsx +36 -0
  484. package/src/conversation-timeline.ts +92 -0
  485. package/src/desktop.ts +24 -0
  486. package/src/device-authorization.tsx +98 -0
  487. package/src/diffs.ts +16 -0
  488. package/src/discovery-cache.ts +42 -0
  489. package/src/editor.ts +13 -0
  490. package/src/embedded-session-client.ts +104 -0
  491. package/src/file-node-visibility.ts +66 -0
  492. package/src/hooks/channel-cache.ts +104 -0
  493. package/src/hooks/internal.ts +3 -2
  494. package/src/hooks/latest-question.ts +164 -0
  495. package/src/hooks/shared-machines-list.ts +239 -0
  496. package/src/hooks/use-attached-browsers.ts +5 -1
  497. package/src/hooks/use-available-models.ts +20 -14
  498. package/src/hooks/use-browser-frame-stream.ts +25 -3
  499. package/src/hooks/use-browser-session.ts +271 -71
  500. package/src/hooks/use-browser-sessions.ts +7 -1
  501. package/src/hooks/use-channels.ts +32 -10
  502. package/src/hooks/use-codex-accounts.ts +78 -21
  503. package/src/hooks/use-composer.ts +1034 -320
  504. package/src/hooks/use-computer-frame-stream.ts +39 -16
  505. package/src/hooks/use-computer-input-posture.ts +94 -0
  506. package/src/hooks/use-computer-session.ts +110 -32
  507. package/src/hooks/use-computer-sessions.ts +8 -1
  508. package/src/hooks/use-connect.ts +23 -0
  509. package/src/hooks/use-desktop-stream.ts +19 -28
  510. package/src/hooks/use-file-attachments.ts +118 -10
  511. package/src/hooks/use-goal.ts +36 -9
  512. package/src/hooks/use-human-input.ts +31 -4
  513. package/src/hooks/use-last-started-turn-policy.ts +15 -13
  514. package/src/hooks/use-machine-chip.ts +23 -6
  515. package/src/hooks/use-machines.ts +104 -6
  516. package/src/hooks/use-sandbox-files.ts +253 -150
  517. package/src/hooks/use-sandbox-git.ts +58 -29
  518. package/src/hooks/use-session-background-commands.ts +67 -0
  519. package/src/hooks/use-session-capabilities.ts +21 -2
  520. package/src/hooks/use-session-events.ts +759 -433
  521. package/src/hooks/use-session-lineage.ts +28 -6
  522. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  523. package/src/hooks/use-session.ts +75 -16
  524. package/src/hooks/use-slash-commands.ts +6 -11
  525. package/src/hooks/use-turn-queue.ts +113 -13
  526. package/src/hooks/use-usage.ts +100 -0
  527. package/src/hooks/use-video-artifact-playback.ts +1 -1
  528. package/src/hooks/use-voice-input.ts +12 -1
  529. package/src/hooks/use-workspace-capture.ts +3 -2
  530. package/src/hooks/use-workspace-edit.ts +23 -5
  531. package/src/hooks/use-workspace-sessions.ts +99 -11
  532. package/src/human-input.ts +12 -1
  533. package/src/identity-link-accounts.tsx +148 -0
  534. package/src/identity-link-consent.tsx +192 -0
  535. package/src/index.ts +157 -12
  536. package/src/interaction.ts +1 -0
  537. package/src/lib/error-message.ts +37 -0
  538. package/src/lib/format.ts +150 -14
  539. package/src/lib/host-theme.ts +511 -0
  540. package/src/lib/interaction-errors.ts +33 -0
  541. package/src/lib/menu-styles.ts +44 -0
  542. package/src/lib/pierre-diffs-loader.ts +53 -0
  543. package/src/lib/workbench-peers.ts +62 -0
  544. package/src/lib/xterm-theme.ts +23 -21
  545. package/src/machines.ts +9 -1
  546. package/src/mcp-connection-status.ts +35 -0
  547. package/src/model-policy.ts +223 -69
  548. package/src/older-history.ts +87 -0
  549. package/src/plugin-details.tsx +185 -0
  550. package/src/plugin-discovery.tsx +196 -0
  551. package/src/provider.tsx +55 -14
  552. package/src/realtime/dropdown-menu.tsx +19 -12
  553. package/src/realtime/realtime-control.tsx +133 -46
  554. package/src/session-auth-recommendation.ts +48 -0
  555. package/src/session-capability-policy.ts +83 -0
  556. package/src/session-context.ts +4 -3
  557. package/src/session-ui.ts +66 -2
  558. package/src/session.ts +18 -1
  559. package/src/sites-ui.tsx +402 -0
  560. package/src/sites.ts +3 -0
  561. package/src/skill-discovery.tsx +208 -0
  562. package/src/terminal.ts +26 -0
  563. package/src/timeline/activity-rail.tsx +171 -80
  564. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  565. package/src/timeline/compaction-copy.ts +42 -0
  566. package/src/timeline/entrance.tsx +28 -3
  567. package/src/timeline/fleet-decision-projection.ts +2 -1
  568. package/src/timeline/fleet-decision-row.tsx +1 -0
  569. package/src/timeline/genie-loading.tsx +136 -0
  570. package/src/timeline/index.ts +11 -0
  571. package/src/timeline/knowledge-receipt.tsx +100 -0
  572. package/src/timeline/parsers.ts +2 -2
  573. package/src/timeline/platform-activity-row.tsx +216 -0
  574. package/src/timeline/presented-image.ts +49 -0
  575. package/src/timeline/projection.ts +1609 -84
  576. package/src/timeline/registry.ts +15 -3
  577. package/src/timeline/retained-image.ts +97 -0
  578. package/src/timeline/rolling-activity.tsx +92 -0
  579. package/src/timeline/screenshot-lightbox.tsx +115 -17
  580. package/src/timeline/shared.tsx +47 -15
  581. package/src/timeline/startup-preference.ts +33 -0
  582. package/src/timeline/startup-timings.tsx +145 -0
  583. package/src/timeline/tool-display-name.ts +8 -6
  584. package/src/timeline/tool-renderers.tsx +497 -128
  585. package/src/timeline/turn-summary.tsx +218 -44
  586. package/src/timeline/types.ts +192 -7
  587. package/src/types/machines.ts +10 -0
  588. package/src/usage/allowance-copy.ts +64 -0
  589. package/src/usage/summary.ts +93 -0
  590. package/src/usage.ts +50 -0
  591. package/styles/compiled.css +2098 -757
  592. package/styles/connect.css +284 -0
  593. package/styles/connect.d.ts +1 -0
  594. package/styles/effective-tokens.css +1 -0
  595. package/styles/index.css +201 -9
  596. package/styles/responsive.css +27 -1
  597. package/styles/session-capability.css +44 -0
  598. package/styles/tokens.css +135 -65
  599. package/dist/chunk-5UQPNLIO.js.map +0 -1
  600. package/dist/chunk-6KLX2RH5.js.map +0 -1
  601. package/dist/chunk-7WCLAEFV.js.map +0 -1
  602. package/dist/chunk-B6WPZSTT.js.map +0 -1
  603. package/dist/chunk-FK6VG4LL.js +0 -90
  604. package/dist/chunk-FK6VG4LL.js.map +0 -1
  605. package/dist/chunk-HA46CYQK.js.map +0 -1
  606. package/dist/chunk-HUIKIDM5.js.map +0 -1
  607. package/dist/chunk-IGC6A2ZI.js.map +0 -1
  608. package/dist/chunk-KCGXPP5V.js.map +0 -1
  609. package/dist/chunk-KZ73RL76.js.map +0 -1
  610. package/dist/chunk-LAKLF4PA.js +0 -141
  611. package/dist/chunk-LAKLF4PA.js.map +0 -1
  612. package/dist/chunk-LLOLUHVG.js.map +0 -1
  613. package/dist/chunk-MKPIAGVL.js +0 -465
  614. package/dist/chunk-MKPIAGVL.js.map +0 -1
  615. package/dist/chunk-PEI6RANI.js.map +0 -1
  616. package/dist/chunk-R3AZOAB5.js.map +0 -1
  617. package/dist/chunk-WSK7G5LE.js +0 -170
  618. package/dist/chunk-WSK7G5LE.js.map +0 -1
  619. package/dist/chunk-XBZWOM2K.js +0 -218
  620. package/dist/chunk-XBZWOM2K.js.map +0 -1
  621. package/dist/chunk-Y7OEDUJ5.js +0 -8810
  622. package/dist/chunk-Y7OEDUJ5.js.map +0 -1
  623. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  624. package/dist/hooks/use-packs.d.ts +0 -32
  625. package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
  626. package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
  627. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  628. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  629. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  630. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  631. package/src/hooks/use-packs.ts +0 -157
  632. /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-SHYKQRNX.js.map} +0 -0
@@ -1,13 +1,26 @@
1
+ import {
2
+ COMPOSER_MODEL_UNAVAILABLE_MESSAGE,
3
+ ComposerReconciliationRequiredError,
4
+ ComposerStateError,
5
+ ComposerWorkspaceControlUnavailableError,
6
+ composerSubmissionCanRetry,
7
+ composerSubmissionErrorMessage
8
+ } from "./chunk-UTRTG6LH.js";
1
9
  import {
2
10
  useSessionEventTrigger
3
- } from "./chunk-KZ73RL76.js";
11
+ } from "./chunk-YQEAA6LT.js";
12
+ import {
13
+ normalizeError,
14
+ useErrorMessage
15
+ } from "./chunk-UGLEYEMP.js";
4
16
  import {
5
17
  useEmbeddedSession
6
- } from "./chunk-C5ZPSSS5.js";
18
+ } from "./chunk-TKOTKRWY.js";
7
19
 
8
20
  // src/hooks/use-composer.ts
9
21
  import {
10
- DEFAULT_FILE_RESOURCE_MOUNT_ROOT
22
+ DEFAULT_FILE_RESOURCE_MOUNT_ROOT,
23
+ OpenGeniApiError
11
24
  } from "@opengeni/sdk";
12
25
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
13
26
  var PENDING_COMPOSER_STORAGE_PREFIX = "opengeni.pending-composer.v1:";
@@ -46,14 +59,28 @@ function restoreOptimisticSendOperations(key) {
46
59
  }
47
60
  return stored.map(({ hasMcpCredentialUpdates, ...operation }) => ({
48
61
  ...operation,
62
+ delivery: "send",
63
+ destination: operation.destination === "queue" ? "queue" : "chat",
49
64
  newerShadow: operation.newerShadow ?? { text: "", resources: [], annotations: [] },
50
65
  state: operation.state === "sending" || operation.state === "queued" ? "sending" : operation.state,
51
66
  outcomeUnknown: operation.state === "sending" || operation.state === "queued" ? true : operation.outcomeUnknown,
52
- error: operation.state === "sending" ? "Delivery was interrupted; retry to reconcile this message." : operation.error,
67
+ correlationId: restoredCorrelationId(operation.correlationId),
68
+ error: restoredErrorReference(
69
+ operation.correlationId,
70
+ hasMcpCredentialUpdates && (operation.state === "sending" || operation.outcomeUnknown) ? composerSubmissionErrorMessage(new ComposerReconciliationRequiredError()) : operation.state === "sending" ? "Delivery was interrupted; retry to reconcile this message." : operation.outcomeUnknown ? "The request could not be confirmed. Check its status before retrying." : operation.error ? composerSubmissionErrorMessage(new Error(operation.error)) : void 0
71
+ ),
72
+ retryable: operation.state === "sending" || operation.outcomeUnknown ? true : operation.retryable ?? (operation.error ? composerSubmissionCanRetry(new Error(operation.error)) : true),
53
73
  input: operation.input,
54
74
  canRetry: !hasMcpCredentialUpdates
55
75
  }));
56
76
  }
77
+ function restoredCorrelationId(value) {
78
+ return typeof value === "string" && /^[\w.:-]{1,128}$/u.test(value) ? value : void 0;
79
+ }
80
+ function restoredErrorReference(reference, message) {
81
+ const correlationId = restoredCorrelationId(reference);
82
+ return message && correlationId && message !== COMPOSER_MODEL_UNAVAILABLE_MESSAGE ? `${message} Reference: ${correlationId}.` : message;
83
+ }
57
84
  function rememberOptimisticSendOperations(key, operations) {
58
85
  if (!key) return;
59
86
  const stored = operations.filter((operation) => operation.state !== "queued").map((operation) => {
@@ -65,6 +92,14 @@ function rememberOptimisticSendOperations(key, operations) {
65
92
  hasMcpCredentialUpdates: input.mcpCredentialUpdates !== void 0
66
93
  };
67
94
  });
95
+ if (stored.length === 0) {
96
+ optimisticSendOperations.delete(key);
97
+ try {
98
+ pendingComposerStorage()?.removeItem(optimisticSendStorageKey(key));
99
+ } catch {
100
+ }
101
+ return;
102
+ }
68
103
  optimisticSendOperations.set(key, stored);
69
104
  try {
70
105
  pendingComposerStorage()?.setItem(optimisticSendStorageKey(key), JSON.stringify(stored));
@@ -157,7 +192,8 @@ function rememberPendingComposerOperation(key, operation) {
157
192
  newerShadow: {
158
193
  text: operation.newerShadow.text,
159
194
  resources: [...operation.newerShadow.resources],
160
- annotations: cloneAnnotations(operation.newerShadow.annotations)
195
+ annotations: cloneAnnotations(operation.newerShadow.annotations),
196
+ ...operation.newerShadow.policy ? { policy: { ...operation.newerShadow.policy } } : {}
161
197
  }
162
198
  };
163
199
  pendingComposerOperations.set(key, stored);
@@ -201,6 +237,18 @@ function steeringAcceptedEvent(steering, events) {
201
237
  (event) => event.type === "user.message" && steering.clientEventId !== null && event.clientEventId === steering.clientEventId
202
238
  );
203
239
  }
240
+ function promptTurnIdForTrigger(triggerEventId, events) {
241
+ if (!triggerEventId) return null;
242
+ const queued = events.find((event) => {
243
+ if (event.type !== "turn.queued") return false;
244
+ const payload2 = event.payload;
245
+ return typeof payload2 === "object" && payload2 !== null && "triggerEventId" in payload2 && payload2.triggerEventId === triggerEventId;
246
+ });
247
+ if (!queued) return null;
248
+ if (queued.turnId) return queued.turnId;
249
+ const payload = queued.payload;
250
+ return typeof payload === "object" && payload !== null && "turnId" in payload && typeof payload.turnId === "string" ? payload.turnId : null;
251
+ }
204
252
  function steeringSettledByEvents(steering, events) {
205
253
  const acceptedEventId = steering.triggerEventId ?? steeringAcceptedEvent(steering, events)?.id ?? null;
206
254
  return events.some((event) => {
@@ -212,9 +260,57 @@ function steeringSettledByEvents(steering, events) {
212
260
  return typeof payload === "object" && payload !== null && "triggerEventId" in payload && payload.triggerEventId === acceptedEventId;
213
261
  });
214
262
  }
263
+ function reconcileOptimisticSendFromEvents(operation, events) {
264
+ const accepted = events.find(
265
+ (event) => event.type === "user.message" && event.clientEventId === operation.clientEventId
266
+ );
267
+ const triggerEventId = operation.triggerEventId ?? accepted?.id ?? null;
268
+ const turnId = operation.turnId ?? promptTurnIdForTrigger(triggerEventId, events);
269
+ const acceptedRouting = promptRoutingFromAcceptedEvent(accepted ?? null);
270
+ const destination = acceptedRouting === "queued_for_execution" ? "queue" : acceptedRouting === "accepted_for_execution" || acceptedRouting === "accepted_for_steering" ? "chat" : operation.destination;
271
+ const needsAdmissionUpdate = accepted !== void 0 && (operation.state !== "queued" || operation.destination !== destination || operation.triggerEventId !== triggerEventId || operation.turnId !== turnId || operation.error !== void 0 || operation.outcomeUnknown !== false);
272
+ const reconciled = needsAdmissionUpdate ? {
273
+ ...operation,
274
+ state: "queued",
275
+ destination,
276
+ triggerEventId,
277
+ turnId,
278
+ error: void 0,
279
+ outcomeUnknown: false
280
+ } : operation;
281
+ const withdrawnFromQueue = events.some((event) => {
282
+ if (event.type !== "session.queue.changed" || !turnId) return false;
283
+ const payload = event.payload;
284
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return false;
285
+ const record = payload;
286
+ return record.turnId === turnId && (record.operation === "edit" || record.operation === "delete");
287
+ });
288
+ return {
289
+ operation: reconciled,
290
+ admitted: accepted !== void 0,
291
+ // Edit/Delete atomically withdraw the queued turn. Keeping its optimistic
292
+ // send alive after that point lets its old `newerShadow` become the newest
293
+ // composer draft again when a later turn settles, duplicating submitted
294
+ // text. The queue mutation is the durable terminal fact for this send.
295
+ settled: withdrawnFromQueue || steeringSettledByEvents(
296
+ {
297
+ phase: "accepted",
298
+ text: reconciled.text,
299
+ clientEventId: reconciled.clientEventId,
300
+ triggerEventId: reconciled.triggerEventId ?? null,
301
+ turnId: reconciled.turnId ?? null
302
+ },
303
+ events
304
+ )
305
+ };
306
+ }
215
307
  function useComposer(sessionId, options = {}) {
216
308
  const { client, workspaceId, registerSessionReconciler } = useEmbeddedSession(options);
309
+ const formatError = useErrorMessage();
217
310
  const durableDrafts = options.draftPersistence !== "disabled";
311
+ if (!durableDrafts && !options.initialPolicy) {
312
+ throw new Error("useComposer requires initialPolicy when draft persistence is disabled");
313
+ }
218
314
  const targetKey = `${workspaceId}\0${sessionId ?? ""}\0${durableDrafts ? "durable" : "disabled"}`;
219
315
  const pendingOperationKey = pendingComposerOperationKey(workspaceId, sessionId);
220
316
  const initialPendingOperation = restorePendingComposerOperation(pendingOperationKey);
@@ -230,21 +326,27 @@ function useComposer(sessionId, options = {}) {
230
326
  const [optimisticSends, setOptimisticSends] = useState(initialOptimisticSends);
231
327
  const [steering, setSteering] = useState(
232
328
  () => initialPendingOperation?.delivery === "steer" ? {
233
- phase: "submitting",
329
+ phase: "failed",
234
330
  text: initialPendingOperation.input.text,
235
331
  clientEventId: initialPendingOperation.input.clientEventId ?? null,
236
332
  triggerEventId: null,
237
- turnId: null
333
+ turnId: null,
334
+ error: "Not confirmed. Retry to check the same direction change.",
335
+ outcomeUnknown: true
238
336
  } : null
239
337
  );
240
338
  const [pausing, setPausing] = useState(false);
241
- const [controlStopping, setControlStopping] = useState(null);
339
+ const [acceptedControl, setAcceptedControl] = useState(null);
242
340
  const [resuming, setResuming] = useState(false);
243
341
  const [error, setError] = useState(null);
342
+ const [draftReadError, setDraftReadError] = useState(null);
244
343
  const [draft, setDraft] = useState(null);
245
344
  const [draftLoading, setDraftLoading] = useState(Boolean(sessionId) && durableDrafts);
246
345
  const [draftSaving, setDraftSaving] = useState(false);
247
346
  const [draftConflict, setDraftConflict] = useState(null);
347
+ const [policy, setPolicy] = useState(
348
+ () => initialShadow?.policy ?? options.initialPolicy ?? null
349
+ );
248
350
  const [restoredResources, setRestoredResources] = useState(
249
351
  () => initialShadow?.resources ?? []
250
352
  );
@@ -254,36 +356,52 @@ function useComposer(sessionId, options = {}) {
254
356
  const optimisticCallbackIdsRef = useRef(/* @__PURE__ */ new Set());
255
357
  const steeringSettlementEventsRef = useRef([]);
256
358
  const steeringRef = useRef(steering);
359
+ const steeringOccurredAtRef = useRef((/* @__PURE__ */ new Date()).toISOString());
257
360
  const pendingClientEventId = useRef(
258
361
  initialPendingOperation?.input.clientEventId ?? null
259
362
  );
260
363
  const valueRef = useRef(initialShadow?.text ?? "");
261
364
  const annotationsRef = useRef(initialShadow?.annotations ?? []);
365
+ const policyRef = useRef(
366
+ initialShadow?.policy ?? options.initialPolicy ?? null
367
+ );
262
368
  const draftRef = useRef(null);
263
369
  const restoredResourcesRef = useRef(initialShadow?.resources ?? []);
264
370
  const localEditRevision = useRef(initialShadow ? 1 : 0);
265
371
  const targetGeneration = useRef(0);
266
372
  const draftReadGeneration = useRef(0);
373
+ const draftReadInFlightRef = useRef(null);
374
+ const draftReadAbortRef = useRef(null);
375
+ const draftReadRetryRef = useRef({ targetKey, failures: 0, timer: null });
267
376
  const lastSavedSignature = useRef(null);
268
377
  const saveChain = useRef(Promise.resolve());
269
378
  const onSent = options.onSent;
270
379
  const onSubmitted = options.onSubmitted;
271
- const onDraftApplied = options.onDraftApplied;
272
- const onDraftAppliedRef = useRef(onDraftApplied);
273
- useLayoutEffect(() => {
274
- onDraftAppliedRef.current = onDraftApplied;
275
- }, [onDraftApplied]);
380
+ const onDeliveryErrorRef = useRef(options.onDeliveryError);
381
+ onDeliveryErrorRef.current = options.onDeliveryError;
276
382
  useLayoutEffect(() => {
277
383
  steeringRef.current = steering;
278
384
  }, [steering]);
279
385
  const sendExtrasRef = useRef(options.sendExtras);
280
386
  sendExtrasRef.current = options.sendExtras;
387
+ const sendDestinationRef = useRef(options.sendDestination);
388
+ sendDestinationRef.current = options.sendDestination;
281
389
  const sendBlockedRef = useRef(options.sendBlocked);
282
390
  sendBlockedRef.current = options.sendBlocked;
391
+ const effectiveControlRef = useRef(
392
+ acceptedControl ?? options.effectiveControl ?? null
393
+ );
394
+ effectiveControlRef.current = acceptedControl ?? options.effectiveControl ?? null;
283
395
  const liveExtrasVersion = JSON.stringify(resolveSendExtras(options.sendExtras));
284
396
  const targetKeyRef = useRef(targetKey);
285
397
  useLayoutEffect(() => {
286
398
  if (targetKeyRef.current === targetKey) return;
399
+ if (draftReadRetryRef.current.timer !== null) {
400
+ clearTimeout(draftReadRetryRef.current.timer);
401
+ }
402
+ draftReadAbortRef.current?.abort();
403
+ draftReadAbortRef.current = null;
404
+ draftReadRetryRef.current = { targetKey, failures: 0, timer: null };
287
405
  targetKeyRef.current = targetKey;
288
406
  targetGeneration.current += 1;
289
407
  draftReadGeneration.current += 1;
@@ -298,6 +416,7 @@ function useComposer(sessionId, options = {}) {
298
416
  localEditRevision.current = shadow ? 1 : 0;
299
417
  valueRef.current = shadow?.text ?? "";
300
418
  annotationsRef.current = shadow?.annotations ?? [];
419
+ policyRef.current = shadow?.policy ?? options.initialPolicy ?? null;
301
420
  draftRef.current = null;
302
421
  restoredResourcesRef.current = shadow?.resources ?? [];
303
422
  lastSavedSignature.current = null;
@@ -305,28 +424,45 @@ function useComposer(sessionId, options = {}) {
305
424
  setStateTargetKey(targetKey);
306
425
  setValue(shadow?.text ?? "");
307
426
  setAnnotations(shadow?.annotations ?? []);
427
+ setPolicy(policyRef.current);
308
428
  setAnnotationReviewTargetId(null);
309
429
  setSending(false);
310
430
  setOptimisticSends(restoredOptimisticSends);
311
431
  setSteering(
312
432
  pendingOperationRef.current?.delivery === "steer" ? {
313
- phase: "submitting",
433
+ phase: "failed",
314
434
  text: pendingOperationRef.current.input.text,
315
435
  clientEventId: pendingOperationRef.current.input.clientEventId ?? null,
316
436
  triggerEventId: null,
317
- turnId: null
437
+ turnId: null,
438
+ error: "Not confirmed. Retry to check the same direction change.",
439
+ outcomeUnknown: true
318
440
  } : null
319
441
  );
320
442
  setPausing(false);
321
- setControlStopping(null);
443
+ setAcceptedControl(null);
322
444
  setResuming(false);
323
445
  setError(null);
446
+ setDraftReadError(null);
324
447
  setDraft(null);
325
448
  setDraftLoading(Boolean(sessionId) && durableDrafts);
326
449
  setDraftSaving(false);
327
450
  setDraftConflict(null);
328
451
  setRestoredResources(shadow?.resources ?? []);
329
- }, [durableDrafts, pendingOperationKey, sessionId, targetKey]);
452
+ }, [durableDrafts, options.initialPolicy, pendingOperationKey, sessionId, targetKey]);
453
+ useEffect(
454
+ () => () => {
455
+ if (draftReadRetryRef.current.timer !== null) {
456
+ clearTimeout(draftReadRetryRef.current.timer);
457
+ }
458
+ targetGeneration.current += 1;
459
+ draftReadGeneration.current += 1;
460
+ draftReadInFlightRef.current = null;
461
+ draftReadAbortRef.current?.abort();
462
+ draftReadAbortRef.current = null;
463
+ },
464
+ []
465
+ );
330
466
  const setOptimisticDraftShadow = useCallback(
331
467
  (shadow) => {
332
468
  if (optimisticSendsRef.current.length === 0) return;
@@ -335,7 +471,8 @@ function useComposer(sessionId, options = {}) {
335
471
  newerShadow: {
336
472
  text: shadow.text,
337
473
  resources: [...shadow.resources],
338
- annotations: cloneAnnotations(shadow.annotations)
474
+ annotations: cloneAnnotations(shadow.annotations),
475
+ ...shadow.policy ? { policy: { ...shadow.policy } } : {}
339
476
  }
340
477
  }));
341
478
  optimisticSendsRef.current = next;
@@ -348,15 +485,18 @@ function useComposer(sessionId, options = {}) {
348
485
  (next) => {
349
486
  if (targetKeyRef.current !== targetKey) return;
350
487
  if (!durableDrafts) {
488
+ const nextPolicy2 = policyFromDraft(next);
351
489
  localEditRevision.current += 1;
352
490
  valueRef.current = next.text;
353
491
  annotationsRef.current = next.annotations ?? [];
492
+ policyRef.current = nextPolicy2;
354
493
  restoredResourcesRef.current = next.resources;
355
494
  draftRef.current = null;
356
495
  lastSavedSignature.current = null;
357
496
  setDraft(null);
358
497
  setValue(next.text);
359
498
  setAnnotations(next.annotations ?? []);
499
+ setPolicy(nextPolicy2);
360
500
  setRestoredResources(next.resources);
361
501
  pendingOperationRef.current = updatePendingComposerShadow(
362
502
  pendingOperationKey,
@@ -367,7 +507,8 @@ function useComposer(sessionId, options = {}) {
367
507
  next.resources,
368
508
  resolveSendExtras(sendExtrasRef.current).resources ?? []
369
509
  ),
370
- annotations: next.annotations ?? []
510
+ annotations: next.annotations ?? [],
511
+ policy: nextPolicy2
371
512
  }
372
513
  );
373
514
  setOptimisticDraftShadow({
@@ -376,13 +517,16 @@ function useComposer(sessionId, options = {}) {
376
517
  next.resources,
377
518
  resolveSendExtras(sendExtrasRef.current).resources ?? []
378
519
  ),
379
- annotations: next.annotations ?? []
520
+ annotations: next.annotations ?? [],
521
+ policy: nextPolicy2
380
522
  });
381
523
  setDraftConflict(null);
382
524
  return;
383
525
  }
526
+ const nextPolicy = policyFromDraft(next);
384
527
  valueRef.current = next.text;
385
528
  annotationsRef.current = next.annotations ?? [];
529
+ policyRef.current = nextPolicy;
386
530
  draftRef.current = next;
387
531
  restoredResourcesRef.current = next.resources;
388
532
  lastSavedSignature.current = draftSignature(draftPayload(next));
@@ -390,6 +534,7 @@ function useComposer(sessionId, options = {}) {
390
534
  setDraft(next);
391
535
  setValue(next.text);
392
536
  setAnnotations(next.annotations ?? []);
537
+ setPolicy(nextPolicy);
393
538
  setRestoredResources(next.resources);
394
539
  pendingOperationRef.current = updatePendingComposerShadow(
395
540
  pendingOperationKey,
@@ -400,7 +545,8 @@ function useComposer(sessionId, options = {}) {
400
545
  next.resources,
401
546
  resolveSendExtras(sendExtrasRef.current).resources ?? []
402
547
  ),
403
- annotations: next.annotations ?? []
548
+ annotations: next.annotations ?? [],
549
+ policy: nextPolicy
404
550
  }
405
551
  );
406
552
  setOptimisticDraftShadow({
@@ -409,10 +555,10 @@ function useComposer(sessionId, options = {}) {
409
555
  next.resources,
410
556
  resolveSendExtras(sendExtrasRef.current).resources ?? []
411
557
  ),
412
- annotations: next.annotations ?? []
558
+ annotations: next.annotations ?? [],
559
+ policy: nextPolicy
413
560
  });
414
561
  setDraftConflict(null);
415
- onDraftAppliedRef.current?.(next);
416
562
  },
417
563
  [durableDrafts, pendingOperationKey, setOptimisticDraftShadow, targetKey]
418
564
  );
@@ -421,34 +567,69 @@ function useComposer(sessionId, options = {}) {
421
567
  if (targetKeyRef.current !== targetKey) return;
422
568
  if (!sessionId || !durableDrafts) {
423
569
  setDraftLoading(false);
570
+ setDraftReadError(null);
424
571
  return;
425
572
  }
573
+ let retry = draftReadRetryRef.current;
574
+ if (retry.targetKey !== targetKey) {
575
+ if (retry.timer !== null) clearTimeout(retry.timer);
576
+ retry = { targetKey, failures: 0, timer: null };
577
+ draftReadRetryRef.current = retry;
578
+ }
579
+ const scheduleRetry = () => {
580
+ if (retry.timer !== null) return;
581
+ retry.timer = setTimeout(
582
+ () => {
583
+ if (draftReadRetryRef.current !== retry || targetKeyRef.current !== targetKey) return;
584
+ retry.timer = null;
585
+ void loadDraft(false);
586
+ },
587
+ Math.min(25e3, 1e3 * 2 ** (retry.failures - 1)) * (0.8 + Math.random() * 0.4)
588
+ );
589
+ };
590
+ if (!replaceLocal && retry.timer !== null) return;
591
+ if (draftReadInFlightRef.current === targetKey) return;
592
+ if (retry.timer !== null) {
593
+ clearTimeout(retry.timer);
594
+ retry.timer = null;
595
+ }
596
+ draftReadInFlightRef.current = targetKey;
426
597
  const generation = targetGeneration.current;
427
598
  const readTicket = ++draftReadGeneration.current;
599
+ const requestAbort = new AbortController();
600
+ draftReadAbortRef.current?.abort();
601
+ draftReadAbortRef.current = requestAbort;
428
602
  const localAtStart = localEditRevision.current;
429
603
  const baseAtStart = draftRef.current;
430
- const extrasAtStart = resolveSendExtras(sendExtrasRef.current);
431
- const localSignatureAtStart = baseAtStart ? draftSignature(
604
+ const policyAtStart = policyRef.current;
605
+ const localSignatureAtStart = baseAtStart ? policyAtStart ? draftSignature(
432
606
  composerDraftPayload(
433
607
  baseAtStart,
434
608
  valueRef.current,
435
609
  restoredResourcesRef.current,
436
610
  annotationsRef.current,
437
- extrasAtStart
611
+ policyAtStart,
612
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
438
613
  )
439
- ) : null;
614
+ ) : null : null;
440
615
  const localWasDirtyAtStart = localSignatureAtStart === null ? localAtStart !== 0 : localSignatureAtStart !== lastSavedSignature.current;
441
616
  const showLoading = replaceLocal || draftRef.current === null;
442
617
  if (showLoading) {
443
618
  setDraftLoading(true);
444
619
  }
445
620
  try {
446
- const fetched = await client.getComposerDraft(workspaceId, sessionId);
621
+ const fetched = await client.getComposerDraft(workspaceId, sessionId, {
622
+ signal: requestAbort.signal
623
+ });
447
624
  if (generation !== targetGeneration.current || targetKeyRef.current !== targetKey || readTicket !== draftReadGeneration.current) {
448
625
  return;
449
626
  }
627
+ if (retry.timer !== null) clearTimeout(retry.timer);
628
+ retry.failures = 0;
629
+ retry.timer = null;
630
+ setDraftReadError(null);
450
631
  const currentRevision = draftRef.current?.revision ?? -1;
451
- if (fetched.revision >= currentRevision) {
632
+ if (replaceLocal || fetched.revision > currentRevision) {
452
633
  draftRef.current = fetched;
453
634
  setDraft(fetched);
454
635
  setDraftConflict(null);
@@ -457,33 +638,58 @@ function useComposer(sessionId, options = {}) {
457
638
  valueRef.current = shadow.text;
458
639
  restoredResourcesRef.current = shadow.resources;
459
640
  annotationsRef.current = shadow.annotations;
641
+ if (shadow.policy) policyRef.current = shadow.policy;
460
642
  localEditRevision.current ||= 1;
461
643
  setValue(shadow.text);
462
644
  setRestoredResources(shadow.resources);
463
645
  setAnnotations(shadow.annotations);
646
+ if (shadow.policy) setPolicy(shadow.policy);
464
647
  } else if (replaceLocal || !localWasDirtyAtStart && localAtStart === localEditRevision.current) {
465
- const extrasNow = resolveSendExtras(sendExtrasRef.current);
466
- const pickerChangedDuringFetch = extrasNow.model !== extrasAtStart.model || extrasNow.reasoningEffort !== extrasAtStart.reasoningEffort || extrasNow.latencyMode !== extrasAtStart.latencyMode;
648
+ const fetchedPolicy = policyFromDraft(fetched);
467
649
  valueRef.current = fetched.text;
468
650
  restoredResourcesRef.current = fetched.resources;
469
651
  annotationsRef.current = fetched.annotations ?? [];
652
+ policyRef.current = fetchedPolicy;
470
653
  lastSavedSignature.current = draftSignature(draftPayload(fetched));
471
654
  setValue(fetched.text);
472
655
  setRestoredResources(fetched.resources);
473
656
  setAnnotations(fetched.annotations ?? []);
474
- if (replaceLocal || !pickerChangedDuringFetch) {
475
- onDraftAppliedRef.current?.(fetched);
657
+ setPolicy(fetchedPolicy);
658
+ } else {
659
+ lastSavedSignature.current = draftSignature(draftPayload(fetched));
660
+ if (!policyRef.current) {
661
+ const fetchedPolicy = policyFromDraft(fetched);
662
+ policyRef.current = fetchedPolicy;
663
+ setPolicy(fetchedPolicy);
476
664
  }
477
665
  }
478
666
  }
479
667
  } catch (cause) {
480
- if (generation === targetGeneration.current && targetKeyRef.current === targetKey && readTicket === draftReadGeneration.current) {
481
- setError(asError(cause));
668
+ if (!requestAbort.signal.aborted && generation === targetGeneration.current && targetKeyRef.current === targetKey && readTicket === draftReadGeneration.current) {
669
+ const problem = asError(cause);
670
+ const timedOut = problem.name === "TimeoutError";
671
+ setDraftReadError(
672
+ timedOut ? new ComposerStateError("Draft sync timed out. Retrying\u2026", { cause }) : problem
673
+ );
674
+ if (timedOut || cause instanceof TypeError || cause && typeof cause === "object" && "retryable" in cause && cause.retryable === true) {
675
+ retry.failures += 1;
676
+ scheduleRetry();
677
+ } else {
678
+ if (retry.timer !== null) clearTimeout(retry.timer);
679
+ retry.failures = 0;
680
+ retry.timer = null;
681
+ }
482
682
  }
483
683
  } finally {
484
684
  if (generation === targetGeneration.current && targetKeyRef.current === targetKey && readTicket === draftReadGeneration.current) {
485
685
  setDraftLoading(false);
486
686
  }
687
+ if (draftReadInFlightRef.current === targetKey) {
688
+ draftReadInFlightRef.current = null;
689
+ }
690
+ if (draftReadAbortRef.current === requestAbort) {
691
+ draftReadAbortRef.current = null;
692
+ }
487
693
  }
488
694
  },
489
695
  [client, durableDrafts, sessionId, targetKey, workspaceId]
@@ -580,23 +786,38 @@ function useComposer(sessionId, options = {}) {
580
786
  setSteering(null);
581
787
  }, [options.events, steering]);
582
788
  useEffect(() => {
583
- if (!controlStopping) return;
789
+ if (!acceptedControl) return;
584
790
  const effectiveControl = options.effectiveControl;
585
- if (!effectiveControl || effectiveControl.controlVersion < controlStopping.controlVersion) {
791
+ if (!effectiveControl || effectiveControl.controlVersion < acceptedControl.controlVersion) {
586
792
  return;
587
793
  }
588
- if (effectiveControl.controlVersion === controlStopping.controlVersion && effectiveControl.controlEtag === controlStopping.controlEtag && effectiveControl.settlement !== null) {
589
- return;
590
- }
591
- setControlStopping((current) => current === controlStopping ? null : current);
592
- }, [controlStopping, options.effectiveControl]);
794
+ setAcceptedControl((current) => current === acceptedControl ? null : current);
795
+ }, [acceptedControl, options.effectiveControl]);
593
796
  const currentDraftPayload = useCallback(() => {
594
797
  if (!durableDrafts || targetKeyRef.current !== targetKey) return null;
595
798
  const base = draftRef.current;
596
- if (!base) return null;
597
- const extras = resolveSendExtras(sendExtrasRef.current);
598
- return composerDraftPayload(base, value, restoredResources, annotations, extras);
799
+ const currentPolicy = policyRef.current;
800
+ if (!base || !currentPolicy) return null;
801
+ return composerDraftPayload(
802
+ base,
803
+ value,
804
+ restoredResources,
805
+ annotations,
806
+ currentPolicy,
807
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
808
+ );
599
809
  }, [annotations, durableDrafts, restoredResources, targetKey, value]);
810
+ const adoptDraftBase = useCallback(
811
+ (next) => {
812
+ if (targetKeyRef.current !== targetKey) return;
813
+ draftRef.current = next;
814
+ setDraft(next);
815
+ lastSavedSignature.current = draftSignature(draftPayload(next));
816
+ setDraftConflict(null);
817
+ setError(null);
818
+ },
819
+ [targetKey]
820
+ );
600
821
  const persistPayload = useCallback(
601
822
  async (payload) => {
602
823
  const ownedTargetKey = targetKey;
@@ -619,27 +840,11 @@ function useComposer(sessionId, options = {}) {
619
840
  }
620
841
  setDraftSaving(true);
621
842
  try {
622
- const saved = await saveComposerDraftWithStaleRetry({
623
- client,
624
- workspaceId,
625
- sessionId,
626
- request,
627
- onAdoptRemote: (remote) => {
628
- draftRef.current = remote;
629
- setDraft(remote);
630
- }
631
- });
843
+ const saved = await client.saveComposerDraft(workspaceId, sessionId, request);
632
844
  if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
633
845
  return;
634
846
  }
635
- draftRef.current = saved;
636
- setDraft(saved);
637
- lastSavedSignature.current = draftSignature({
638
- ...request,
639
- expectedRevision: saved.revision
640
- });
641
- setDraftConflict(null);
642
- setError(null);
847
+ adoptDraftBase(saved);
643
848
  success = true;
644
849
  } catch (cause) {
645
850
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
@@ -657,7 +862,7 @@ function useComposer(sessionId, options = {}) {
657
862
  await saveChain.current;
658
863
  return success;
659
864
  },
660
- [client, durableDrafts, sessionId, targetKey, workspaceId]
865
+ [adoptDraftBase, client, durableDrafts, sessionId, targetKey, workspaceId]
661
866
  );
662
867
  const replaceOptimisticSends = useCallback(
663
868
  (update) => {
@@ -682,15 +887,40 @@ function useComposer(sessionId, options = {}) {
682
887
  [onSent, replaceOptimisticSends]
683
888
  );
684
889
  useEffect(() => {
685
- const acceptedIds = new Set(
686
- (options.events ?? []).filter((event) => event.type === "user.message" && event.clientEventId).map((event) => event.clientEventId)
890
+ const events = options.events ?? [];
891
+ if (events.length === 0 || optimisticSendsRef.current.length === 0) return;
892
+ const reconciled = optimisticSendsRef.current.map(
893
+ (operation) => reconcileOptimisticSendFromEvents(operation, events)
687
894
  );
688
- if (acceptedIds.size === 0) return;
689
- const accepted = optimisticSendsRef.current.filter(
690
- (operation) => acceptedIds.has(operation.clientEventId)
895
+ const settledIds = new Set(
896
+ reconciled.filter((item) => item.settled).map((item) => item.operation.clientEventId)
691
897
  );
692
- for (const operation of accepted) markOptimisticAccepted(operation);
693
- }, [markOptimisticAccepted, options.events]);
898
+ const changed = reconciled.some(
899
+ (item, index) => item.operation !== optimisticSendsRef.current[index] && !settledIds.has(item.operation.clientEventId)
900
+ );
901
+ for (const item of reconciled) {
902
+ if (item.admitted && !optimisticCallbackIdsRef.current.has(item.operation.clientEventId)) {
903
+ optimisticCallbackIdsRef.current.add(item.operation.clientEventId);
904
+ onSent?.(item.operation.input.text, item.operation.input);
905
+ }
906
+ if (item.settled) markOptimisticAccepted(item.operation);
907
+ }
908
+ if (changed) {
909
+ replaceOptimisticSends(
910
+ (current) => current.map(
911
+ (operation) => reconciled.find((item) => item.operation.clientEventId === operation.clientEventId)?.operation ?? operation
912
+ ).filter((operation) => !settledIds.has(operation.clientEventId))
913
+ );
914
+ }
915
+ if (durableDrafts && reconciled.some((item) => item.admitted)) void loadDraft(false);
916
+ }, [
917
+ durableDrafts,
918
+ loadDraft,
919
+ markOptimisticAccepted,
920
+ onSent,
921
+ options.events,
922
+ replaceOptimisticSends
923
+ ]);
694
924
  const processOptimisticSends = useCallback(() => {
695
925
  if (!sessionId || optimisticProcessorBusyRef.current) return;
696
926
  const currentOperations = optimisticSendsRef.current;
@@ -703,29 +933,75 @@ function useComposer(sessionId, options = {}) {
703
933
  const ownedGeneration = targetGeneration.current;
704
934
  optimisticProcessorBusyRef.current = true;
705
935
  void (async () => {
936
+ let mutationFailureObserved = false;
937
+ const markFailed = (cause, outcomeUnknown) => {
938
+ if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
939
+ return;
940
+ }
941
+ const problem = asError(cause);
942
+ replaceOptimisticSends(
943
+ (current) => current.map(
944
+ (candidate) => candidate.clientEventId === operation.clientEventId ? {
945
+ ...candidate,
946
+ state: "failed",
947
+ error: formatError(
948
+ cause,
949
+ outcomeUnknown && !isOutcomeUnknownError(problem) && !(problem instanceof ComposerReconciliationRequiredError) ? `The request could not be confirmed. Check its status before retrying.${problem instanceof OpenGeniApiError && problem.correlationId ? ` Reference: ${problem.correlationId}.` : ""}` : composerSubmissionErrorMessage(problem)
950
+ ),
951
+ retryable: outcomeUnknown || composerSubmissionCanRetry(problem),
952
+ outcomeUnknown,
953
+ correlationId: problem instanceof OpenGeniApiError ? problem.correlationId : candidate.correlationId
954
+ } : candidate
955
+ )
956
+ );
957
+ };
706
958
  try {
707
959
  if (operation.outcomeUnknown) {
708
- const events = await client.listEvents(workspaceId, sessionId, {
709
- includeTypes: ["user.message"],
710
- limit: 100,
711
- payloadMode: "none"
712
- });
713
- if (events.some(
714
- (event) => event.type === "user.message" && event.clientEventId === operation.clientEventId
715
- )) {
716
- markOptimisticAccepted(operation);
960
+ let events;
961
+ try {
962
+ events = await client.listEvents(workspaceId, sessionId, {
963
+ includeTypes: [
964
+ "user.message",
965
+ "turn.queued",
966
+ "turn.started",
967
+ "turn.completed",
968
+ "turn.failed",
969
+ "turn.cancelled",
970
+ "turn.superseded"
971
+ ],
972
+ limit: 250,
973
+ payloadMode: "full"
974
+ });
975
+ } catch (cause) {
976
+ markFailed(cause, true);
977
+ return;
978
+ }
979
+ const reconciled = reconcileOptimisticSendFromEvents(operation, events);
980
+ if (reconciled.admitted) {
981
+ if (durableDrafts) await loadDraft(false);
982
+ if (reconciled.settled) {
983
+ markOptimisticAccepted(reconciled.operation);
984
+ } else {
985
+ replaceOptimisticSends(
986
+ (current) => current.map(
987
+ (candidate) => candidate.clientEventId === operation.clientEventId ? reconciled.operation : candidate
988
+ )
989
+ );
990
+ if (!optimisticCallbackIdsRef.current.has(operation.clientEventId)) {
991
+ optimisticCallbackIdsRef.current.add(operation.clientEventId);
992
+ onSent?.(reconciled.operation.input.text, reconciled.operation.input);
993
+ }
994
+ }
717
995
  return;
718
996
  }
719
997
  if (!operation.canRetry) {
720
- throw new Error(
721
- "OpenGeni cannot safely retry this uncertain request after remount; reconcile the session before sending again."
722
- );
998
+ throw new ComposerReconciliationRequiredError();
723
999
  }
724
1000
  }
725
1001
  let expectedDraftRevision;
726
1002
  if (durableDrafts && operation.draftPayload) {
727
1003
  if (!await persistPayload(operation.draftPayload)) {
728
- throw new Error("The message draft could not be saved before delivery.");
1004
+ throw new ComposerStateError("The message draft could not be saved before delivery.");
729
1005
  }
730
1006
  expectedDraftRevision = draftRef.current?.revision;
731
1007
  }
@@ -736,16 +1012,59 @@ function useComposer(sessionId, options = {}) {
736
1012
  ...operation.input,
737
1013
  ...expectedDraftRevision !== void 0 ? { expectedDraftRevision } : {}
738
1014
  };
739
- await client.sendMessage(workspaceId, sessionId, wireInput);
1015
+ let acceptedResult = null;
1016
+ let acceptedEvent = null;
1017
+ if (durableDrafts) {
1018
+ if (!operation.draftPayload || expectedDraftRevision === void 0) {
1019
+ throw new ComposerStateError("The durable composer draft is not ready for delivery.");
1020
+ }
1021
+ const result = await client.submitComposerDraft(workspaceId, sessionId, {
1022
+ text: operation.draftPayload.text,
1023
+ annotations: operation.draftPayload.annotations,
1024
+ resources: operation.draftPayload.resources,
1025
+ model: operation.draftPayload.model,
1026
+ reasoningEffort: operation.draftPayload.reasoningEffort,
1027
+ latencyMode: operation.draftPayload.latencyMode,
1028
+ expectedDraftRevision,
1029
+ clientEventId: operation.clientEventId,
1030
+ delivery: "send",
1031
+ ...wireInput.controlEtag ? { controlEtag: wireInput.controlEtag } : {},
1032
+ ...wireInput.modelContext ? { modelContext: wireInput.modelContext } : {},
1033
+ ...wireInput.mcpCredentialUpdates ? { mcpCredentialUpdates: wireInput.mcpCredentialUpdates } : {},
1034
+ ...wireInput.connectionAccounts ? { connectionAccounts: wireInput.connectionAccounts } : {},
1035
+ ...wireInput.personalResourceAttachment ? { personalResourceAttachment: wireInput.personalResourceAttachment } : {}
1036
+ }).catch((cause) => {
1037
+ mutationFailureObserved = true;
1038
+ throw cause;
1039
+ });
1040
+ acceptedResult = result;
1041
+ adoptDraftBase(result.draft);
1042
+ } else {
1043
+ acceptedEvent = await client.sendMessage(workspaceId, sessionId, wireInput).catch((cause) => {
1044
+ mutationFailureObserved = true;
1045
+ throw cause;
1046
+ });
1047
+ }
740
1048
  if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
741
1049
  return;
742
1050
  }
743
- if (options.events === void 0) {
1051
+ const acceptedRouting = acceptedResult?.routing ?? promptRoutingFromAcceptedEvent(acceptedEvent);
1052
+ const acceptedDestination = acceptedRouting === "queued_for_execution" ? "queue" : acceptedRouting === "accepted_for_execution" || acceptedRouting === "accepted_for_steering" ? "chat" : operation.destination;
1053
+ if (options.events === void 0 && acceptedDestination === "chat") {
744
1054
  markOptimisticAccepted({ ...operation, input: wireInput });
745
1055
  } else {
746
1056
  replaceOptimisticSends(
747
1057
  (current) => current.map(
748
- (candidate) => candidate.clientEventId === operation.clientEventId ? { ...candidate, input: wireInput, state: "queued", error: void 0 } : candidate
1058
+ (candidate) => candidate.clientEventId === operation.clientEventId ? {
1059
+ ...candidate,
1060
+ input: wireInput,
1061
+ destination: acceptedDestination,
1062
+ turnId: acceptedResult?.turn.id ?? candidate.turnId,
1063
+ triggerEventId: acceptedResult?.accepted.id ?? acceptedEvent?.id ?? candidate.triggerEventId,
1064
+ appliedQueueVersion: acceptedResult?.receipt?.appliedQueueVersion ?? candidate.appliedQueueVersion,
1065
+ state: "queued",
1066
+ error: void 0
1067
+ } : candidate
749
1068
  )
750
1069
  );
751
1070
  }
@@ -753,36 +1072,17 @@ function useComposer(sessionId, options = {}) {
753
1072
  optimisticCallbackIdsRef.current.add(operation.clientEventId);
754
1073
  onSent?.(wireInput.text, wireInput);
755
1074
  }
756
- if (durableDrafts && draftRef.current) {
757
- const cleared = {
758
- ...draftRef.current,
759
- revision: 0,
760
- text: "",
761
- resources: [],
762
- annotations: [],
763
- sourceTurnId: null,
764
- sourceTurnVersion: null,
765
- updatedAt: null
766
- };
767
- draftRef.current = cleared;
768
- setDraft(cleared);
769
- lastSavedSignature.current = draftSignature(draftPayload(cleared));
770
- }
771
1075
  } catch (cause) {
772
- const problem = asError(cause);
773
- const outcomeUnknown = isOutcomeUnknownError(cause) || operation.outcomeUnknown === true;
774
- if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
775
- replaceOptimisticSends(
776
- (current) => current.map(
777
- (candidate) => candidate.clientEventId === operation.clientEventId ? {
778
- ...candidate,
779
- state: "failed",
780
- error: problem.message,
781
- outcomeUnknown
782
- } : candidate
783
- )
784
- );
1076
+ const current = optimisticSendsRef.current.find(
1077
+ (candidate) => candidate.clientEventId === operation.clientEventId
1078
+ );
1079
+ if (!current || current.state === "queued" && current.outcomeUnknown === false) {
1080
+ return;
785
1081
  }
1082
+ const problem = asError(cause);
1083
+ onDeliveryErrorRef.current?.(problem, operation.input, "send");
1084
+ const outcomeUnknown = operation.outcomeUnknown && !mutationFailureObserved ? true : isOutcomeUnknownError(cause);
1085
+ markFailed(cause, outcomeUnknown);
786
1086
  } finally {
787
1087
  optimisticProcessorBusyRef.current = false;
788
1088
  if (targetKeyRef.current === ownedTargetKey) {
@@ -791,9 +1091,12 @@ function useComposer(sessionId, options = {}) {
791
1091
  }
792
1092
  })();
793
1093
  }, [
1094
+ adoptDraftBase,
794
1095
  client,
795
1096
  durableDrafts,
1097
+ formatError,
796
1098
  markOptimisticAccepted,
1099
+ loadDraft,
797
1100
  onSent,
798
1101
  options.events,
799
1102
  persistPayload,
@@ -814,9 +1117,10 @@ function useComposer(sessionId, options = {}) {
814
1117
  restoredResourcesRef.current,
815
1118
  resolveSendExtras(sendExtrasRef.current).resources ?? []
816
1119
  ),
817
- annotations: annotationsRef.current
1120
+ annotations: annotationsRef.current,
1121
+ ...policyRef.current ? { policy: policyRef.current } : {}
818
1122
  };
819
- if (pending.newerShadow.text !== shadow.text || JSON.stringify(pending.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(pending.newerShadow.annotations) !== JSON.stringify(shadow.annotations)) {
1123
+ if (pending.newerShadow.text !== shadow.text || JSON.stringify(pending.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(pending.newerShadow.annotations) !== JSON.stringify(shadow.annotations) || JSON.stringify(pending.newerShadow.policy) !== JSON.stringify(shadow.policy)) {
820
1124
  pendingOperationRef.current = updatePendingComposerShadow(
821
1125
  pendingOperationKey,
822
1126
  pending,
@@ -833,9 +1137,10 @@ function useComposer(sessionId, options = {}) {
833
1137
  restoredResourcesRef.current,
834
1138
  resolveSendExtras(sendExtrasRef.current).resources ?? []
835
1139
  ),
836
- annotations: annotationsRef.current
1140
+ annotations: annotationsRef.current,
1141
+ ...policyRef.current ? { policy: policyRef.current } : {}
837
1142
  };
838
- if (optimistic.newerShadow.text !== shadow.text || JSON.stringify(optimistic.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(optimistic.newerShadow.annotations) !== JSON.stringify(shadow.annotations)) {
1143
+ if (optimistic.newerShadow.text !== shadow.text || JSON.stringify(optimistic.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(optimistic.newerShadow.annotations) !== JSON.stringify(shadow.annotations) || JSON.stringify(optimistic.newerShadow.policy) !== JSON.stringify(shadow.policy)) {
839
1144
  setOptimisticDraftShadow(shadow);
840
1145
  }
841
1146
  }
@@ -875,12 +1180,13 @@ function useComposer(sessionId, options = {}) {
875
1180
  const rawText = explicit ?? draftAtSend;
876
1181
  const hasText = rawText.trim().length > 0;
877
1182
  const hasAnnotations = annotationsAtSend.length > 0;
1183
+ const currentPolicy = policyRef.current;
878
1184
  const annotationsComplete2 = annotationsAtSend.every(
879
1185
  (annotation) => annotation.note.trim().length > 0
880
1186
  );
881
1187
  const extras = pending ? {} : resolveSendExtras(sendExtrasRef.current);
882
1188
  const hasResources = restoredResources.length > 0 || (extras.resources?.length ?? 0) > 0;
883
- if (!pending && (!annotationsComplete2 || !hasText && !hasResources && !hasAnnotations) || !sessionId || sending || sendBlockedRef.current?.() === true || targetKeyRef.current !== ownedTargetKey) {
1189
+ if (!pending && (!annotationsComplete2 || !hasText && !hasResources && !hasAnnotations) || !sessionId || !currentPolicy || sending || sendBlockedRef.current?.() === true || targetKeyRef.current !== ownedTargetKey) {
884
1190
  return false;
885
1191
  }
886
1192
  const clearPending = () => {
@@ -894,22 +1200,6 @@ function useComposer(sessionId, options = {}) {
894
1200
  const draftWasUnchanged = valueRef.current === operation.draftAtSend;
895
1201
  const resourcesWereUnchanged = JSON.stringify(restoredResourcesRef.current) === JSON.stringify(operation.resourcesAtSend);
896
1202
  const annotationsWereUnchanged = JSON.stringify(annotationsRef.current) === JSON.stringify(operation.annotationsAtSend);
897
- const previousDraft = draftRef.current;
898
- if (previousDraft) {
899
- const cleared = {
900
- ...previousDraft,
901
- revision: 0,
902
- text: "",
903
- resources: [],
904
- annotations: [],
905
- sourceTurnId: null,
906
- sourceTurnVersion: null,
907
- updatedAt: null
908
- };
909
- draftRef.current = cleared;
910
- setDraft(cleared);
911
- lastSavedSignature.current = draftSignature(draftPayload(cleared));
912
- }
913
1203
  if (resourcesWereUnchanged) {
914
1204
  restoredResourcesRef.current = [];
915
1205
  setRestoredResources([]);
@@ -926,6 +1216,30 @@ function useComposer(sessionId, options = {}) {
926
1216
  onSent?.(operation.input.text, operation.input);
927
1217
  };
928
1218
  const deliver = async (operation) => {
1219
+ if (durableDrafts) {
1220
+ const input = operation.input;
1221
+ if (input.expectedDraftRevision === void 0 || input.clientEventId === void 0 || input.model === void 0 || input.reasoningEffort === void 0 || input.latencyMode === void 0) {
1222
+ throw new ComposerStateError("The durable composer draft is not ready for delivery.");
1223
+ }
1224
+ const result = await client.submitComposerDraft(workspaceId, sessionId, {
1225
+ text: input.text,
1226
+ annotations: input.annotations ?? [],
1227
+ resources: input.resources ?? [],
1228
+ model: input.model,
1229
+ reasoningEffort: input.reasoningEffort,
1230
+ latencyMode: input.latencyMode,
1231
+ expectedDraftRevision: input.expectedDraftRevision,
1232
+ clientEventId: input.clientEventId,
1233
+ delivery: operation.delivery,
1234
+ ...input.controlEtag ? { controlEtag: input.controlEtag } : {},
1235
+ ...input.modelContext ? { modelContext: input.modelContext } : {},
1236
+ ...input.mcpCredentialUpdates ? { mcpCredentialUpdates: input.mcpCredentialUpdates } : {},
1237
+ ...input.connectionAccounts ? { connectionAccounts: input.connectionAccounts } : {},
1238
+ ...input.personalResourceAttachment ? { personalResourceAttachment: input.personalResourceAttachment } : {}
1239
+ });
1240
+ adoptDraftBase(result.draft);
1241
+ return result;
1242
+ }
929
1243
  if (operation.delivery === "steer") {
930
1244
  return await client.steerMessage(workspaceId, sessionId, operation.input);
931
1245
  }
@@ -933,6 +1247,9 @@ function useComposer(sessionId, options = {}) {
933
1247
  return null;
934
1248
  };
935
1249
  if (delivery === "steer") {
1250
+ if (steeringRef.current?.clientEventId !== pending?.input.clientEventId) {
1251
+ steeringOccurredAtRef.current = (/* @__PURE__ */ new Date()).toISOString();
1252
+ }
936
1253
  setSteering({
937
1254
  phase: "submitting",
938
1255
  text: rawText,
@@ -957,7 +1274,20 @@ function useComposer(sessionId, options = {}) {
957
1274
  ) ?? null;
958
1275
  } catch (cause) {
959
1276
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
960
- setError(asError(cause));
1277
+ const problem = asError(cause);
1278
+ setError(problem);
1279
+ if (pending.delivery === "steer") {
1280
+ keepSteering = true;
1281
+ setSteering({
1282
+ phase: "failed",
1283
+ text: pending.input.text,
1284
+ clientEventId: pending.input.clientEventId ?? null,
1285
+ triggerEventId: null,
1286
+ turnId: null,
1287
+ error: "Not confirmed. Retry.",
1288
+ outcomeUnknown: true
1289
+ });
1290
+ }
961
1291
  }
962
1292
  return false;
963
1293
  }
@@ -965,6 +1295,7 @@ function useComposer(sessionId, options = {}) {
965
1295
  return false;
966
1296
  }
967
1297
  if (acceptedEvent) {
1298
+ if (durableDrafts) await loadDraft(false);
968
1299
  if (pending.delivery === "steer") {
969
1300
  keepSteering = true;
970
1301
  setSteering({
@@ -979,11 +1310,7 @@ function useComposer(sessionId, options = {}) {
979
1310
  return true;
980
1311
  }
981
1312
  if (!pending.canRetry) {
982
- setError(
983
- new Error(
984
- "OpenGeni cannot safely retry this uncertain request after remount; reconcile the session before sending again."
985
- )
986
- );
1313
+ setError(new ComposerReconciliationRequiredError());
987
1314
  return false;
988
1315
  }
989
1316
  try {
@@ -1000,9 +1327,26 @@ function useComposer(sessionId, options = {}) {
1000
1327
  });
1001
1328
  }
1002
1329
  } catch (cause) {
1003
- if (pending.delivery === "steer") keepSteering = true;
1330
+ const problem = asError(cause);
1331
+ const outcomeUnknown = isOutcomeUnknownError(cause);
1332
+ onDeliveryErrorRef.current?.(problem, pending.input, pending.delivery);
1333
+ if (!outcomeUnknown) {
1334
+ clearPending();
1335
+ keepSteering = false;
1336
+ } else if (pending.delivery === "steer") {
1337
+ keepSteering = true;
1338
+ setSteering({
1339
+ phase: "failed",
1340
+ text: pending.input.text,
1341
+ clientEventId: pending.input.clientEventId ?? null,
1342
+ triggerEventId: null,
1343
+ turnId: null,
1344
+ error: "Not confirmed. Retry.",
1345
+ outcomeUnknown: true
1346
+ });
1347
+ }
1004
1348
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
1005
- setError(asError(cause));
1349
+ setError(problem);
1006
1350
  }
1007
1351
  return false;
1008
1352
  }
@@ -1020,8 +1364,10 @@ function useComposer(sessionId, options = {}) {
1020
1364
  return false;
1021
1365
  }
1022
1366
  pendingClientEventId.current ??= generateClientEventId();
1367
+ const effectiveControl = effectiveControlRef.current;
1023
1368
  const input = composeSendInput(sendText, pendingClientEventId.current, extras, {
1024
- ...options.effectiveControl?.controlEtag ? { controlEtag: options.effectiveControl.controlEtag } : {},
1369
+ ...currentPolicy,
1370
+ ...effectiveControl?.controlEtag ? { controlEtag: effectiveControl.controlEtag } : {},
1025
1371
  ...durableDrafts && draftRef.current ? { expectedDraftRevision: draftRef.current.revision } : {},
1026
1372
  resources: mergeResources(restoredResources, extras.resources ?? []),
1027
1373
  annotations: cloneAnnotations(annotationsAtSend)
@@ -1035,7 +1381,8 @@ function useComposer(sessionId, options = {}) {
1035
1381
  newerShadow: {
1036
1382
  text: draftAtSend,
1037
1383
  resources: mergeResources(restoredResources, extras.resources ?? []),
1038
- annotations: cloneAnnotations(annotationsAtSend)
1384
+ annotations: cloneAnnotations(annotationsAtSend),
1385
+ policy: currentPolicy
1039
1386
  },
1040
1387
  clearDraftOnAccept: explicit === void 0,
1041
1388
  canRetry: true
@@ -1065,10 +1412,20 @@ function useComposer(sessionId, options = {}) {
1065
1412
  });
1066
1413
  }
1067
1414
  } catch (cause) {
1415
+ onDeliveryErrorRef.current?.(asError(cause), operation.input, operation.delivery);
1068
1416
  if (!isOutcomeUnknownError(cause)) {
1069
1417
  clearPending();
1070
1418
  } else if (delivery === "steer") {
1071
1419
  keepSteering = true;
1420
+ setSteering({
1421
+ phase: "failed",
1422
+ text: operation.input.text,
1423
+ clientEventId: operation.input.clientEventId ?? null,
1424
+ triggerEventId: null,
1425
+ turnId: null,
1426
+ error: "Not confirmed. Retry.",
1427
+ outcomeUnknown: true
1428
+ });
1072
1429
  }
1073
1430
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
1074
1431
  setError(asError(cause));
@@ -1092,15 +1449,16 @@ function useComposer(sessionId, options = {}) {
1092
1449
  currentDraftPayload,
1093
1450
  durableDrafts,
1094
1451
  onSent,
1095
- options.effectiveControl?.controlEtag,
1096
1452
  persistPayload,
1097
1453
  restoredResources,
1098
1454
  annotations,
1455
+ adoptDraftBase,
1099
1456
  sending,
1100
1457
  sessionId,
1101
1458
  targetKey,
1102
1459
  value,
1103
- workspaceId
1460
+ workspaceId,
1461
+ loadDraft
1104
1462
  ]
1105
1463
  );
1106
1464
  const send = useCallback(
@@ -1110,6 +1468,7 @@ function useComposer(sessionId, options = {}) {
1110
1468
  }
1111
1469
  const rawText = explicit ?? valueRef.current;
1112
1470
  const annotationsAtSend = cloneAnnotations(annotationsRef.current);
1471
+ const currentPolicy = policyRef.current;
1113
1472
  const hasText = rawText.trim().length > 0;
1114
1473
  const hasAnnotations = annotationsAtSend.length > 0;
1115
1474
  const annotationsComplete2 = annotationsAtSend.every(
@@ -1117,19 +1476,26 @@ function useComposer(sessionId, options = {}) {
1117
1476
  );
1118
1477
  const extras = resolveSendExtras(sendExtrasRef.current);
1119
1478
  const resources = mergeResources(restoredResourcesRef.current, extras.resources ?? []);
1120
- if (!sessionId || sending || !annotationsComplete2 || !hasText && !hasAnnotations && resources.length === 0 || sendBlockedRef.current?.() === true || targetKeyRef.current !== targetKey) {
1479
+ if (!sessionId || !currentPolicy || sending || !annotationsComplete2 || !hasText && !hasAnnotations && resources.length === 0 || sendBlockedRef.current?.() === true || targetKeyRef.current !== targetKey) {
1121
1480
  return false;
1122
1481
  }
1123
1482
  const sendText = hasText ? rawText : hasAnnotations ? "" : FILE_ONLY_MESSAGE_TEXT;
1124
1483
  const clientEventId = generateClientEventId();
1484
+ const effectiveControl = effectiveControlRef.current;
1125
1485
  const input = composeSendInput(sendText, clientEventId, extras, {
1126
- ...options.effectiveControl?.controlEtag ? { controlEtag: options.effectiveControl.controlEtag } : {},
1486
+ ...currentPolicy,
1487
+ ...effectiveControl?.controlEtag ? { controlEtag: effectiveControl.controlEtag } : {},
1127
1488
  resources,
1128
1489
  annotations: annotationsAtSend
1129
1490
  });
1130
1491
  const currentPayload = currentDraftPayload();
1492
+ const hasEarlierUnsettledSend = optimisticSendsRef.current.some(
1493
+ (candidate) => candidate.state !== "failed" || candidate.outcomeUnknown === true
1494
+ );
1131
1495
  const operation = {
1132
1496
  clientEventId,
1497
+ delivery: "send",
1498
+ destination: effectiveControl?.state === "paused" || hasEarlierUnsettledSend ? "queue" : sendDestinationRef.current?.() ?? "chat",
1133
1499
  text: sendText,
1134
1500
  annotations: annotationsAtSend,
1135
1501
  resources,
@@ -1140,14 +1506,11 @@ function useComposer(sessionId, options = {}) {
1140
1506
  newerShadow: {
1141
1507
  text: explicit === void 0 ? "" : valueRef.current,
1142
1508
  resources: explicit === void 0 ? [] : [...restoredResourcesRef.current],
1143
- annotations: explicit === void 0 ? [] : cloneAnnotations(annotationsRef.current)
1509
+ annotations: explicit === void 0 ? [] : cloneAnnotations(annotationsRef.current),
1510
+ policy: currentPolicy
1144
1511
  },
1145
1512
  canRetry: true
1146
1513
  };
1147
- replaceOptimisticSends((current) => [...current, operation]);
1148
- queueMicrotask(processOptimisticSends);
1149
- setError(null);
1150
- onSubmitted?.(sendText, input);
1151
1514
  if (explicit === void 0) {
1152
1515
  valueRef.current = "";
1153
1516
  annotationsRef.current = [];
@@ -1158,13 +1521,16 @@ function useComposer(sessionId, options = {}) {
1158
1521
  setAnnotationReviewTargetId(null);
1159
1522
  setRestoredResources([]);
1160
1523
  }
1524
+ replaceOptimisticSends((current) => [...current, operation]);
1525
+ queueMicrotask(processOptimisticSends);
1526
+ setError(null);
1527
+ onSubmitted?.(sendText, input);
1161
1528
  return true;
1162
1529
  },
1163
1530
  [
1164
1531
  currentDraftPayload,
1165
1532
  dispatch,
1166
1533
  onSubmitted,
1167
- options.effectiveControl?.controlEtag,
1168
1534
  processOptimisticSends,
1169
1535
  replaceOptimisticSends,
1170
1536
  sending,
@@ -1175,6 +1541,12 @@ function useComposer(sessionId, options = {}) {
1175
1541
  const steer = useCallback(async (text) => await dispatch("steer", text), [dispatch]);
1176
1542
  const retryOptimisticMessage = useCallback(
1177
1543
  (clientEventId) => {
1544
+ if (sendBlockedRef.current?.() === true) return;
1545
+ const currentSteering = steeringRef.current;
1546
+ if (currentSteering?.phase === "failed" && currentSteering.clientEventId === clientEventId) {
1547
+ void dispatch("steer");
1548
+ return;
1549
+ }
1178
1550
  replaceOptimisticSends(
1179
1551
  (current) => current.map((operation) => {
1180
1552
  if (operation.clientEventId !== clientEventId || operation.state !== "failed") {
@@ -1183,26 +1555,33 @@ function useComposer(sessionId, options = {}) {
1183
1555
  if (operation.outcomeUnknown) {
1184
1556
  return { ...operation, state: "sending", error: void 0 };
1185
1557
  }
1558
+ if (operation.retryable === false) return operation;
1186
1559
  const nextClientEventId = generateClientEventId();
1187
- const retryExtras = resolveSendExtras(sendExtrasRef.current);
1188
- const retryInput = composeSendInput(operation.text, nextClientEventId, retryExtras, {
1189
- ...options.effectiveControl?.controlEtag ? { controlEtag: options.effectiveControl.controlEtag } : {},
1190
- resources: operation.resources,
1191
- annotations: operation.annotations
1192
- });
1560
+ const currentPersonalResourceAttachment = resolveSendExtras(
1561
+ sendExtrasRef.current
1562
+ ).personalResourceAttachment;
1563
+ const retryInput = composeSendInput(
1564
+ operation.text,
1565
+ nextClientEventId,
1566
+ {
1567
+ ...operation.input,
1568
+ ...currentPersonalResourceAttachment ? { personalResourceAttachment: currentPersonalResourceAttachment } : {}
1569
+ },
1570
+ {
1571
+ ...effectiveControlRef.current?.controlEtag ? { controlEtag: effectiveControlRef.current.controlEtag } : {},
1572
+ resources: operation.resources,
1573
+ annotations: operation.annotations
1574
+ }
1575
+ );
1193
1576
  return {
1194
1577
  ...operation,
1195
1578
  clientEventId: nextClientEventId,
1196
1579
  input: retryInput,
1197
- draftPayload: operation.draftPayload ? {
1198
- ...operation.draftPayload,
1199
- model: retryExtras.model ?? operation.draftPayload.model,
1200
- reasoningEffort: retryExtras.reasoningEffort ?? operation.draftPayload.reasoningEffort,
1201
- latencyMode: retryExtras.latencyMode ?? operation.draftPayload.latencyMode
1202
- } : null,
1580
+ draftPayload: operation.draftPayload,
1203
1581
  occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
1204
1582
  state: "sending",
1205
1583
  error: void 0,
1584
+ retryable: void 0,
1206
1585
  outcomeUnknown: false,
1207
1586
  canRetry: true
1208
1587
  };
@@ -1210,15 +1589,23 @@ function useComposer(sessionId, options = {}) {
1210
1589
  );
1211
1590
  queueMicrotask(processOptimisticSends);
1212
1591
  },
1213
- [options.effectiveControl?.controlEtag, processOptimisticSends, replaceOptimisticSends]
1592
+ [dispatch, processOptimisticSends, replaceOptimisticSends]
1214
1593
  );
1215
1594
  const removeOptimisticMessage = useCallback(
1216
1595
  (clientEventId) => {
1596
+ if (steeringRef.current?.clientEventId === clientEventId) {
1597
+ pendingOperationRef.current = null;
1598
+ pendingClientEventId.current = null;
1599
+ forgetPendingComposerOperation(pendingComposerOperationKey(workspaceId, sessionId));
1600
+ setSteering(null);
1601
+ setError(null);
1602
+ return;
1603
+ }
1217
1604
  replaceOptimisticSends(
1218
1605
  (current) => current.filter((operation) => operation.clientEventId !== clientEventId)
1219
1606
  );
1220
1607
  },
1221
- [replaceOptimisticSends]
1608
+ [replaceOptimisticSends, sessionId, workspaceId]
1222
1609
  );
1223
1610
  const hasReadyResources = restoredResources.length > 0 || (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;
1224
1611
  const hasPendingOperation = pendingOperationRef.current !== null;
@@ -1233,21 +1620,21 @@ function useComposer(sessionId, options = {}) {
1233
1620
  setPausing(true);
1234
1621
  setError(null);
1235
1622
  try {
1236
- const result = await client.pauseSession(workspaceId, sessionId, {
1237
- ...reason !== void 0 ? { reason } : {},
1238
- ...options.effectiveControl?.controlEtag ? { expectedControlEtag: options.effectiveControl.controlEtag } : {}
1239
- });
1623
+ const clientEventId = generateClientEventId();
1624
+ const effectiveControl = effectiveControlRef.current;
1625
+ const result = await replayOutcomeUnknown(
1626
+ () => client.pauseSession(workspaceId, sessionId, {
1627
+ clientEventId,
1628
+ ...reason !== void 0 ? { reason } : {},
1629
+ ...effectiveControl?.controlEtag ? { expectedControlEtag: effectiveControl.controlEtag } : {}
1630
+ })
1631
+ );
1240
1632
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
1241
- setControlStopping(
1242
- result.interruptionCount > 0 && result.effectiveControl.state === "paused" && result.effectiveControl.settlement !== null ? {
1243
- controlVersion: result.effectiveControl.controlVersion,
1244
- controlEtag: result.effectiveControl.controlEtag
1245
- } : null
1246
- );
1633
+ setAcceptedControl(result.effectiveControl);
1247
1634
  }
1248
1635
  } catch (cause) {
1249
1636
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
1250
- setError(cause instanceof Error ? cause : new Error(String(cause)));
1637
+ setError(normalizeError(cause));
1251
1638
  }
1252
1639
  } finally {
1253
1640
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
@@ -1255,7 +1642,7 @@ function useComposer(sessionId, options = {}) {
1255
1642
  }
1256
1643
  }
1257
1644
  },
1258
- [client, workspaceId, sessionId, pausing, options.effectiveControl?.controlEtag, targetKey]
1645
+ [client, workspaceId, sessionId, pausing, targetKey]
1259
1646
  );
1260
1647
  const resume = useCallback(
1261
1648
  async (reason) => {
@@ -1265,13 +1652,21 @@ function useComposer(sessionId, options = {}) {
1265
1652
  setResuming(true);
1266
1653
  setError(null);
1267
1654
  try {
1268
- await client.resumeSession(workspaceId, sessionId, {
1269
- ...reason !== void 0 ? { reason } : {},
1270
- ...options.effectiveControl?.controlEtag ? { expectedControlEtag: options.effectiveControl.controlEtag } : {}
1271
- });
1655
+ const clientEventId = generateClientEventId();
1656
+ const effectiveControl = effectiveControlRef.current;
1657
+ const result = await replayOutcomeUnknown(
1658
+ () => client.resumeSession(workspaceId, sessionId, {
1659
+ clientEventId,
1660
+ ...reason !== void 0 ? { reason } : {},
1661
+ ...effectiveControl?.controlEtag ? { expectedControlEtag: effectiveControl.controlEtag } : {}
1662
+ })
1663
+ );
1664
+ if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
1665
+ setAcceptedControl(result.effectiveControl);
1666
+ }
1272
1667
  } catch (cause) {
1273
1668
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
1274
- setError(cause instanceof Error ? cause : new Error(String(cause)));
1669
+ setError(normalizeError(cause));
1275
1670
  }
1276
1671
  } finally {
1277
1672
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
@@ -1279,7 +1674,7 @@ function useComposer(sessionId, options = {}) {
1279
1674
  }
1280
1675
  }
1281
1676
  },
1282
- [client, workspaceId, sessionId, resuming, options.effectiveControl?.controlEtag, targetKey]
1677
+ [client, workspaceId, sessionId, resuming, targetKey]
1283
1678
  );
1284
1679
  const resumeScope = useCallback(
1285
1680
  async (option) => {
@@ -1290,31 +1685,44 @@ function useComposer(sessionId, options = {}) {
1290
1685
  setError(null);
1291
1686
  try {
1292
1687
  if (option.scope === "workspace") {
1293
- const workspaceBlocker = options.effectiveControl?.blockers.find(
1688
+ const workspaceBlocker = effectiveControlRef.current?.blockers.find(
1294
1689
  (blocker) => blocker.kind === "workspace"
1295
1690
  );
1296
1691
  if (!client.setWorkspaceInferenceState) {
1297
- throw new Error(
1298
- "@opengeni/react: workspace-scoped resume requires setWorkspaceInferenceState."
1299
- );
1692
+ throw new ComposerWorkspaceControlUnavailableError();
1300
1693
  }
1301
- await client.setWorkspaceInferenceState(workspaceId, {
1302
- action: "resume",
1303
- clientEventId: generateClientEventId(),
1304
- ...workspaceBlocker ? { expectedRevision: workspaceBlocker.revision } : {}
1305
- });
1694
+ const clientEventId = generateClientEventId();
1695
+ await replayOutcomeUnknown(
1696
+ () => client.setWorkspaceInferenceState(workspaceId, {
1697
+ action: "resume",
1698
+ clientEventId,
1699
+ ...workspaceBlocker ? { expectedRevision: workspaceBlocker.revision } : {}
1700
+ })
1701
+ );
1306
1702
  } else if (option.scope === "session" && option.targetId) {
1307
1703
  const target = await client.getQueue(workspaceId, option.targetId);
1308
1704
  if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
1309
1705
  return;
1310
1706
  }
1311
- await client.resumeSession(workspaceId, option.targetId, {
1312
- expectedControlEtag: target.effectiveControl.controlEtag
1313
- });
1707
+ const clientEventId = generateClientEventId();
1708
+ await replayOutcomeUnknown(
1709
+ () => client.resumeSession(workspaceId, option.targetId, {
1710
+ clientEventId,
1711
+ expectedControlEtag: target.effectiveControl.controlEtag
1712
+ })
1713
+ );
1314
1714
  } else {
1315
- await client.resumeSession(workspaceId, sessionId, {
1316
- ...options.effectiveControl?.controlEtag ? { expectedControlEtag: options.effectiveControl.controlEtag } : {}
1317
- });
1715
+ const clientEventId = generateClientEventId();
1716
+ const effectiveControl = effectiveControlRef.current;
1717
+ const result = await replayOutcomeUnknown(
1718
+ () => client.resumeSession(workspaceId, sessionId, {
1719
+ clientEventId,
1720
+ ...effectiveControl?.controlEtag ? { expectedControlEtag: effectiveControl.controlEtag } : {}
1721
+ })
1722
+ );
1723
+ if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
1724
+ setAcceptedControl(result.effectiveControl);
1725
+ }
1318
1726
  }
1319
1727
  } catch (cause) {
1320
1728
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
@@ -1326,7 +1734,7 @@ function useComposer(sessionId, options = {}) {
1326
1734
  }
1327
1735
  }
1328
1736
  },
1329
- [client, options.effectiveControl, resuming, sessionId, targetKey, workspaceId]
1737
+ [client, resuming, sessionId, targetKey, workspaceId]
1330
1738
  );
1331
1739
  const updateValue = useCallback(
1332
1740
  (next) => {
@@ -1342,7 +1750,8 @@ function useComposer(sessionId, options = {}) {
1342
1750
  restoredResourcesRef.current,
1343
1751
  resolveSendExtras(sendExtrasRef.current).resources ?? []
1344
1752
  ),
1345
- annotations: annotationsRef.current
1753
+ annotations: annotationsRef.current,
1754
+ policy: policyRef.current ?? void 0
1346
1755
  }
1347
1756
  );
1348
1757
  setOptimisticDraftShadow({
@@ -1351,7 +1760,8 @@ function useComposer(sessionId, options = {}) {
1351
1760
  restoredResourcesRef.current,
1352
1761
  resolveSendExtras(sendExtrasRef.current).resources ?? []
1353
1762
  ),
1354
- annotations: annotationsRef.current
1763
+ annotations: annotationsRef.current,
1764
+ policy: policyRef.current ?? void 0
1355
1765
  });
1356
1766
  setValue(next);
1357
1767
  },
@@ -1371,7 +1781,8 @@ function useComposer(sessionId, options = {}) {
1371
1781
  restoredResourcesRef.current,
1372
1782
  resolveSendExtras(sendExtrasRef.current).resources ?? []
1373
1783
  ),
1374
- annotations: next
1784
+ annotations: next,
1785
+ policy: policyRef.current ?? void 0
1375
1786
  }
1376
1787
  );
1377
1788
  setOptimisticDraftShadow({
@@ -1380,7 +1791,8 @@ function useComposer(sessionId, options = {}) {
1380
1791
  restoredResourcesRef.current,
1381
1792
  resolveSendExtras(sendExtrasRef.current).resources ?? []
1382
1793
  ),
1383
- annotations: next
1794
+ annotations: next,
1795
+ policy: policyRef.current ?? void 0
1384
1796
  });
1385
1797
  setAnnotations(next);
1386
1798
  setAnnotationReviewTargetId(reviewTargetId);
@@ -1390,7 +1802,7 @@ function useComposer(sessionId, options = {}) {
1390
1802
  const addAnnotation = useCallback(
1391
1803
  (annotation) => {
1392
1804
  if (annotationsRef.current.length >= 12) {
1393
- setError(new Error("A message can include at most 12 timeline annotations."));
1805
+ setError(new ComposerStateError("A message can include at most 12 timeline annotations."));
1394
1806
  return;
1395
1807
  }
1396
1808
  const next = [...annotationsRef.current, annotation];
@@ -1417,6 +1829,64 @@ function useComposer(sessionId, options = {}) {
1417
1829
  const clearAnnotationReviewTarget = useCallback(() => {
1418
1830
  setAnnotationReviewTargetId(null);
1419
1831
  }, []);
1832
+ const requestAnnotationReview = useCallback((id) => {
1833
+ const current = annotationsRef.current;
1834
+ if (current.length === 0) {
1835
+ setAnnotationReviewTargetId(null);
1836
+ return;
1837
+ }
1838
+ if (id && current.some((annotation) => annotation.id === id)) {
1839
+ setAnnotationReviewTargetId(id);
1840
+ return;
1841
+ }
1842
+ const incomplete = current.find((annotation) => annotation.note.trim().length === 0);
1843
+ setAnnotationReviewTargetId(incomplete?.id ?? current[0].id);
1844
+ }, []);
1845
+ const updatePolicy = useCallback(
1846
+ (next) => {
1847
+ if (targetKeyRef.current !== targetKey) return;
1848
+ localEditRevision.current += 1;
1849
+ policyRef.current = next;
1850
+ const shadow = {
1851
+ text: valueRef.current,
1852
+ resources: mergeResources(
1853
+ restoredResourcesRef.current,
1854
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
1855
+ ),
1856
+ annotations: annotationsRef.current,
1857
+ policy: next
1858
+ };
1859
+ pendingOperationRef.current = updatePendingComposerShadow(
1860
+ pendingOperationKey,
1861
+ pendingOperationRef.current,
1862
+ shadow
1863
+ );
1864
+ setOptimisticDraftShadow(shadow);
1865
+ setPolicy(next);
1866
+ },
1867
+ [pendingOperationKey, setOptimisticDraftShadow, targetKey]
1868
+ );
1869
+ const updateModel = useCallback(
1870
+ (model) => {
1871
+ const current = policyRef.current;
1872
+ if (current) updatePolicy({ ...current, model });
1873
+ },
1874
+ [updatePolicy]
1875
+ );
1876
+ const updateReasoningEffort = useCallback(
1877
+ (reasoningEffort) => {
1878
+ const current = policyRef.current;
1879
+ if (current) updatePolicy({ ...current, reasoningEffort });
1880
+ },
1881
+ [updatePolicy]
1882
+ );
1883
+ const updateLatencyMode = useCallback(
1884
+ (latencyMode) => {
1885
+ const current = policyRef.current;
1886
+ if (current) updatePolicy({ ...current, latencyMode });
1887
+ },
1888
+ [updatePolicy]
1889
+ );
1420
1890
  const removeRestoredResource = useCallback(
1421
1891
  (index) => {
1422
1892
  if (targetKeyRef.current !== targetKey) return;
@@ -1429,13 +1899,15 @@ function useComposer(sessionId, options = {}) {
1429
1899
  {
1430
1900
  text: valueRef.current,
1431
1901
  resources: mergeResources(next, resolveSendExtras(sendExtrasRef.current).resources ?? []),
1432
- annotations: annotationsRef.current
1902
+ annotations: annotationsRef.current,
1903
+ policy: policyRef.current ?? void 0
1433
1904
  }
1434
1905
  );
1435
1906
  setOptimisticDraftShadow({
1436
1907
  text: valueRef.current,
1437
1908
  resources: mergeResources(next, resolveSendExtras(sendExtrasRef.current).resources ?? []),
1438
- annotations: annotationsRef.current
1909
+ annotations: annotationsRef.current,
1910
+ policy: policyRef.current ?? void 0
1439
1911
  });
1440
1912
  setRestoredResources(next);
1441
1913
  },
@@ -1446,6 +1918,34 @@ function useComposer(sessionId, options = {}) {
1446
1918
  const extras = resolveSendExtras(sendExtrasRef.current);
1447
1919
  return valueRef.current.length > 0 || annotationsRef.current.length > 0 || restoredResourcesRef.current.length > 0 || (extras.resources?.length ?? 0) > 0 || current?.sourceTurnId !== null && current?.sourceTurnId !== void 0;
1448
1920
  }, []);
1921
+ const restoreOptimisticMessage = useCallback(
1922
+ (clientEventId) => {
1923
+ if (targetKeyRef.current !== targetKey || draftLoading || pendingOperationRef.current || hasDraftContent())
1924
+ return;
1925
+ const operation = optimisticSendsRef.current.find(
1926
+ (candidate) => candidate.clientEventId === clientEventId
1927
+ );
1928
+ if (!operation || operation.state !== "failed" || operation.outcomeUnknown) return;
1929
+ localEditRevision.current += 1;
1930
+ valueRef.current = operation.text;
1931
+ restoredResourcesRef.current = [...operation.resources];
1932
+ annotationsRef.current = cloneAnnotations(operation.annotations);
1933
+ setValue(operation.text);
1934
+ setRestoredResources(restoredResourcesRef.current);
1935
+ setAnnotations(annotationsRef.current);
1936
+ setError(null);
1937
+ setOptimisticDraftShadow({
1938
+ text: operation.text,
1939
+ resources: restoredResourcesRef.current,
1940
+ annotations: annotationsRef.current,
1941
+ policy: policyRef.current ?? void 0
1942
+ });
1943
+ replaceOptimisticSends(
1944
+ (current) => current.filter((candidate) => candidate.clientEventId !== clientEventId)
1945
+ );
1946
+ },
1947
+ [draftLoading, hasDraftContent, replaceOptimisticSends, setOptimisticDraftShadow, targetKey]
1948
+ );
1449
1949
  const resolveDraftConflict = useCallback(
1450
1950
  async (choice) => {
1451
1951
  const ownedTargetKey = targetKey;
@@ -1480,14 +1980,37 @@ function useComposer(sessionId, options = {}) {
1480
1980
  );
1481
1981
  const identityMatches = stateTargetKey === targetKey;
1482
1982
  const visibleSteering = identityMatches ? steering : null;
1983
+ const visibleOptimisticMessages = identityMatches ? [
1984
+ ...optimisticSends.map(
1985
+ ({ input: _input, draftPayload: _payload, canRetry: _retry, ...item }) => item
1986
+ ),
1987
+ ...visibleSteering?.clientEventId ? [
1988
+ {
1989
+ clientEventId: visibleSteering.clientEventId,
1990
+ delivery: "steer",
1991
+ destination: "chat",
1992
+ text: visibleSteering.text,
1993
+ annotations: pendingOperationRef.current?.delivery === "steer" ? pendingOperationRef.current.annotationsAtSend : [],
1994
+ resources: pendingOperationRef.current?.delivery === "steer" ? pendingOperationRef.current.resourcesAtSend : [],
1995
+ occurredAt: steeringOccurredAtRef.current,
1996
+ state: visibleSteering.phase === "submitting" ? "sending" : visibleSteering.phase === "failed" ? "failed" : "queued",
1997
+ turnId: visibleSteering.turnId,
1998
+ triggerEventId: visibleSteering.triggerEventId,
1999
+ ...visibleSteering.error ? { error: visibleSteering.error } : {},
2000
+ ...visibleSteering.outcomeUnknown !== void 0 ? { outcomeUnknown: visibleSteering.outcomeUnknown } : {}
2001
+ }
2002
+ ] : []
2003
+ ] : [];
1483
2004
  const reloadDraft = useCallback(async () => await loadDraft(true), [loadDraft]);
1484
2005
  const clearError = useCallback(() => {
1485
2006
  if (targetKeyRef.current !== targetKey) return;
1486
2007
  setError(null);
2008
+ setDraftReadError(null);
1487
2009
  setDraftConflict(null);
1488
2010
  }, [targetKey]);
2011
+ const visibleValue = identityMatches ? valueRef.current : "";
1489
2012
  return {
1490
- value: identityMatches ? value : "",
2013
+ value: visibleValue,
1491
2014
  setValue: updateValue,
1492
2015
  annotations: identityMatches ? annotations : [],
1493
2016
  addAnnotation,
@@ -1495,35 +2018,40 @@ function useComposer(sessionId, options = {}) {
1495
2018
  removeAnnotation,
1496
2019
  annotationReviewTargetId: identityMatches ? annotationReviewTargetId : null,
1497
2020
  clearAnnotationReviewTarget,
2021
+ requestAnnotationReview,
1498
2022
  hasDraftContent,
1499
2023
  send,
1500
- optimisticMessages: identityMatches ? optimisticSends.map(
1501
- ({ input: _input, draftPayload: _payload, canRetry: _retry, ...item }) => item
1502
- ) : [],
2024
+ optimisticMessages: visibleOptimisticMessages,
1503
2025
  retryOptimisticMessage,
2026
+ restoreOptimisticMessage: !draftLoading && !pendingOperationRef.current && !hasDraftContent() ? restoreOptimisticMessage : void 0,
1504
2027
  removeOptimisticMessage,
1505
2028
  steer,
1506
2029
  steering: visibleSteering,
1507
- stoppingAttempt: identityMatches ? controlStopping ? "current" : visibleSteering?.phase === "accepted" && visibleSteering.stoppingPreviousAttempt === true ? "previous" : null : null,
2030
+ stoppingAttempt: identityMatches ? visibleSteering?.phase === "accepted" && visibleSteering.stoppingPreviousAttempt === true ? "previous" : null : null,
1508
2031
  sending: identityMatches ? sending : false,
1509
- canSend: identityMatches && Boolean(sessionId) && !sending && sendBlockedRef.current?.() !== true && annotationsComplete && (hasPendingOperation || value.trim().length > 0 || hasReadyResources || annotations.length > 0),
2032
+ canSend: identityMatches && Boolean(sessionId) && !sending && !draftLoading && policy !== null && sendBlockedRef.current?.() !== true && annotationsComplete && (hasPendingOperation || visibleValue.trim().length > 0 || hasReadyResources || annotations.length > 0),
1510
2033
  pause,
1511
2034
  pausing: identityMatches ? pausing : false,
1512
2035
  resume,
1513
2036
  resumeScope,
1514
2037
  resuming: identityMatches ? resuming : false,
2038
+ effectiveControl: identityMatches ? effectiveControlRef.current : null,
1515
2039
  draft: identityMatches ? draft : null,
1516
2040
  draftRevision: identityMatches ? draft?.revision ?? 0 : 0,
1517
2041
  draftLoading: identityMatches ? draftLoading : Boolean(sessionId) && durableDrafts,
1518
2042
  draftSaving: identityMatches ? draftSaving : false,
1519
2043
  draftConflict: identityMatches ? draftConflict : null,
2044
+ policy: identityMatches ? policy : null,
2045
+ setModel: updateModel,
2046
+ setReasoningEffort: updateReasoningEffort,
2047
+ setLatencyMode: updateLatencyMode,
1520
2048
  draftPersistence: durableDrafts ? "durable" : "disabled",
1521
2049
  applyDraft,
1522
2050
  reloadDraft,
1523
2051
  resolveDraftConflict,
1524
2052
  restoredResources: identityMatches ? restoredResources : [],
1525
2053
  removeRestoredResource,
1526
- error: identityMatches ? error : null,
2054
+ error: identityMatches ? error ?? draftReadError : null,
1527
2055
  clearError
1528
2056
  };
1529
2057
  }
@@ -1552,31 +2080,27 @@ function generateClientEventId() {
1552
2080
  function isOutcomeUnknownError(cause) {
1553
2081
  return typeof cause === "object" && cause !== null && cause.outcomeUnknown === true;
1554
2082
  }
2083
+ async function replayOutcomeUnknown(command) {
2084
+ try {
2085
+ return await command();
2086
+ } catch (cause) {
2087
+ if (!isOutcomeUnknownError(cause)) throw cause;
2088
+ return await command();
2089
+ }
2090
+ }
1555
2091
  function asError(cause) {
1556
- return cause instanceof Error ? cause : new Error(String(cause));
2092
+ return normalizeError(cause);
1557
2093
  }
1558
- function isDraftConflictError(error) {
1559
- const apiError = error;
1560
- if (apiError.status !== 409 || apiError.outcomeUnknown === true) return false;
1561
- const code = apiError.code;
1562
- if (code === void 0 || code === "DRAFT_CHANGED" || code === "conflict" || code === "idempotency_conflict") {
1563
- return true;
2094
+ function promptRoutingFromAcceptedEvent(event) {
2095
+ if (typeof event?.payload !== "object" || event.payload === null || Array.isArray(event.payload)) {
2096
+ return null;
1564
2097
  }
1565
- return /draft changed/i.test(error.message);
2098
+ const routing = event.payload.routing;
2099
+ return routing === "accepted_for_execution" || routing === "queued_for_execution" || routing === "accepted_for_steering" ? routing : null;
1566
2100
  }
1567
- async function saveComposerDraftWithStaleRetry(input) {
1568
- try {
1569
- return await input.client.saveComposerDraft(input.workspaceId, input.sessionId, input.request);
1570
- } catch (cause) {
1571
- const problem = asError(cause);
1572
- if (!isDraftConflictError(problem)) throw problem;
1573
- const remote = await input.client.getComposerDraft(input.workspaceId, input.sessionId);
1574
- input.onAdoptRemote(remote);
1575
- return await input.client.saveComposerDraft(input.workspaceId, input.sessionId, {
1576
- ...input.request,
1577
- expectedRevision: remote.revision
1578
- });
1579
- }
2101
+ function isDraftConflictError(error) {
2102
+ const apiError = error;
2103
+ return apiError.status === 409 && apiError.outcomeUnknown !== true && apiError.code === "DRAFT_CHANGED";
1580
2104
  }
1581
2105
  function draftPayload(draft) {
1582
2106
  return {
@@ -1586,18 +2110,25 @@ function draftPayload(draft) {
1586
2110
  annotations: draft.annotations ?? [],
1587
2111
  model: draft.model,
1588
2112
  reasoningEffort: draft.reasoningEffort,
1589
- latencyMode: draft.latencyMode ?? "standard"
2113
+ latencyMode: draft.latencyMode
2114
+ };
2115
+ }
2116
+ function policyFromDraft(draft) {
2117
+ return {
2118
+ model: draft.model,
2119
+ reasoningEffort: draft.reasoningEffort,
2120
+ latencyMode: draft.latencyMode
1590
2121
  };
1591
2122
  }
1592
- function composerDraftPayload(base, text, restoredResources, annotations, extras) {
2123
+ function composerDraftPayload(base, text, restoredResources, annotations, policy, additionalResources) {
1593
2124
  return {
1594
2125
  expectedRevision: base.revision,
1595
2126
  text,
1596
- resources: mergeResources(restoredResources, extras.resources ?? []),
2127
+ resources: mergeResources(restoredResources, additionalResources),
1597
2128
  annotations,
1598
- model: extras.model ?? base.model,
1599
- reasoningEffort: extras.reasoningEffort ?? base.reasoningEffort,
1600
- latencyMode: extras.latencyMode ?? base.latencyMode ?? "standard"
2129
+ model: policy.model,
2130
+ reasoningEffort: policy.reasoningEffort,
2131
+ latencyMode: policy.latencyMode
1601
2132
  };
1602
2133
  }
1603
2134
  function draftSignature(payload) {
@@ -1621,4 +2152,4 @@ export {
1621
2152
  shouldSubmitOnKey,
1622
2153
  shouldSteerOnKey
1623
2154
  };
1624
- //# sourceMappingURL=chunk-IGC6A2ZI.js.map
2155
+ //# sourceMappingURL=chunk-RSI7XYXL.js.map