@opengeni/react 0.48.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/README.md +138 -2
  2. package/dist/artifacts-document.d.ts +3 -0
  3. package/dist/artifacts-document.js +17 -0
  4. package/dist/artifacts-document.js.map +1 -0
  5. package/dist/artifacts-presentation.d.ts +3 -0
  6. package/dist/artifacts-presentation.js +17 -0
  7. package/dist/artifacts-presentation.js.map +1 -0
  8. package/dist/artifacts-spreadsheet.d.ts +3 -0
  9. package/dist/artifacts-spreadsheet.js +17 -0
  10. package/dist/artifacts-spreadsheet.js.map +1 -0
  11. package/dist/artifacts.d.ts +2 -0
  12. package/dist/artifacts.js +199 -0
  13. package/dist/artifacts.js.map +1 -0
  14. package/dist/{chunk-NJ7M2B6Z.js → chunk-5UQPNLIO.js} +16 -8
  15. package/dist/{chunk-NJ7M2B6Z.js.map → chunk-5UQPNLIO.js.map} +1 -1
  16. package/dist/{chunk-LHLYWG5R.js → chunk-6KLX2RH5.js} +461 -38
  17. package/dist/chunk-6KLX2RH5.js.map +1 -0
  18. package/dist/chunk-7WCLAEFV.js +2828 -0
  19. package/dist/chunk-7WCLAEFV.js.map +1 -0
  20. package/dist/{chunk-I4MPFDRP.js → chunk-B6WPZSTT.js} +104 -104
  21. package/dist/{chunk-I4MPFDRP.js.map → chunk-B6WPZSTT.js.map} +1 -1
  22. package/dist/{chunk-EKZH6IDG.js → chunk-C5ZPSSS5.js} +111 -1
  23. package/dist/chunk-C5ZPSSS5.js.map +1 -0
  24. package/dist/{chunk-OL6QVXGF.js → chunk-HA46CYQK.js} +152 -8
  25. package/dist/chunk-HA46CYQK.js.map +1 -0
  26. package/dist/chunk-HUIKIDM5.js +2148 -0
  27. package/dist/chunk-HUIKIDM5.js.map +1 -0
  28. package/dist/{chunk-FWXGSNXT.js → chunk-IGC6A2ZI.js} +585 -34
  29. package/dist/chunk-IGC6A2ZI.js.map +1 -0
  30. package/dist/chunk-JVYQRRC4.js +53 -0
  31. package/dist/chunk-JVYQRRC4.js.map +1 -0
  32. package/dist/chunk-KCGXPP5V.js +157 -0
  33. package/dist/chunk-KCGXPP5V.js.map +1 -0
  34. package/dist/chunk-LLOLUHVG.js +5937 -0
  35. package/dist/chunk-LLOLUHVG.js.map +1 -0
  36. package/dist/{chunk-WYA65Y3F.js → chunk-MKPIAGVL.js} +13 -3
  37. package/dist/chunk-MKPIAGVL.js.map +1 -0
  38. package/dist/chunk-PEI6RANI.js +3234 -0
  39. package/dist/chunk-PEI6RANI.js.map +1 -0
  40. package/dist/chunk-R3AZOAB5.js +933 -0
  41. package/dist/chunk-R3AZOAB5.js.map +1 -0
  42. package/dist/{chunk-O4VXOBGF.js → chunk-WSK7G5LE.js} +70 -2
  43. package/dist/chunk-WSK7G5LE.js.map +1 -0
  44. package/dist/{chunk-23EJ676W.js → chunk-XBZWOM2K.js} +9 -4
  45. package/dist/chunk-XBZWOM2K.js.map +1 -0
  46. package/dist/{chunk-XCNTXWBB.js → chunk-Y7OEDUJ5.js} +856 -338
  47. package/dist/chunk-Y7OEDUJ5.js.map +1 -0
  48. package/dist/client.d.ts +10 -2
  49. package/dist/clipboard.d.ts +1 -0
  50. package/dist/clipboard.js +7 -0
  51. package/dist/clipboard.js.map +1 -0
  52. package/dist/commands/index.d.ts +3 -3
  53. package/dist/commands/registry.d.ts +1 -1
  54. package/dist/commands/types.d.ts +1 -1
  55. package/dist/components/approval-surface.d.ts +2 -2
  56. package/dist/components/artifacts/artifact-surface.d.ts +18 -0
  57. package/dist/components/artifacts/document-editor.d.ts +172 -0
  58. package/dist/components/artifacts/editable-artifact-ui.d.ts +13 -0
  59. package/dist/components/artifacts/editable-artifact-workbench.d.ts +49 -0
  60. package/dist/components/artifacts/editable-document.d.ts +24 -0
  61. package/dist/components/artifacts/editable-presentation.d.ts +24 -0
  62. package/dist/components/artifacts/editable-spreadsheet.d.ts +32 -0
  63. package/dist/components/artifacts/index.d.ts +9 -0
  64. package/dist/components/artifacts/presentation-editor.d.ts +297 -0
  65. package/dist/components/artifacts/published-html-artifact-frame.d.ts +14 -0
  66. package/dist/components/artifacts/spreadsheet-canvas.d.ts +120 -0
  67. package/dist/components/artifacts/spreadsheet-grid.d.ts +113 -0
  68. package/dist/components/browser-input.d.ts +7 -0
  69. package/dist/components/browser-viewer.d.ts +30 -0
  70. package/dist/components/chat-composer.d.ts +8 -8
  71. package/dist/components/code-editor.d.ts +25 -3
  72. package/dist/components/command-palette.d.ts +2 -2
  73. package/dist/components/composer-transcription-control.d.ts +2 -2
  74. package/dist/components/composer.d.ts +17 -17
  75. package/dist/components/computer-viewer.d.ts +24 -0
  76. package/dist/components/copy-button.d.ts +2 -2
  77. package/dist/components/desktop-viewer.d.ts +50 -22
  78. package/dist/components/diff-view.d.ts +1 -1
  79. package/dist/components/enrollment-consent.d.ts +1 -1
  80. package/dist/components/enrollment-device-flow.d.ts +1 -1
  81. package/dist/components/file-browser.d.ts +2 -2
  82. package/dist/components/fleet-tile.d.ts +1 -1
  83. package/dist/components/generated-video-player.d.ts +10 -0
  84. package/dist/components/human-input-form.d.ts +1 -1
  85. package/dist/components/human-input-surface.d.ts +2 -2
  86. package/dist/components/interaction-intervention-banner.d.ts +11 -0
  87. package/dist/components/interactive-workbench-viewers.d.ts +2 -0
  88. package/dist/components/machine-card.d.ts +2 -2
  89. package/dist/components/machine-dock-bar.d.ts +3 -3
  90. package/dist/components/machine-health-pill.d.ts +2 -2
  91. package/dist/components/machine-input-display.d.ts +1 -1
  92. package/dist/components/machine-metrics.d.ts +2 -2
  93. package/dist/components/machine-status-pill.d.ts +4 -4
  94. package/dist/components/machines/health.d.ts +1 -1
  95. package/dist/components/machines/machine-detail.d.ts +3 -3
  96. package/dist/components/machines/metric-history-chart.d.ts +1 -1
  97. package/dist/components/machines/metric-sparkline.d.ts +2 -2
  98. package/dist/components/machines/series.d.ts +2 -2
  99. package/dist/components/machines-dashboard.d.ts +2 -2
  100. package/dist/components/markdown.d.ts +1 -1
  101. package/dist/components/message-timeline.d.ts +12 -5
  102. package/dist/components/model-picker.d.ts +2 -2
  103. package/dist/components/model-policy-picker.d.ts +7 -7
  104. package/dist/components/pierre-diff.d.ts +1 -1
  105. package/dist/components/pierre-file.d.ts +1 -1
  106. package/dist/components/queue-draft-policy.d.ts +1 -1
  107. package/dist/components/queue-surface-implementation.d.ts +3 -3
  108. package/dist/components/queue-surface-state.d.ts +4 -4
  109. package/dist/components/queue-surface.d.ts +5 -5
  110. package/dist/components/sandbox-files.d.ts +3 -3
  111. package/dist/components/sandbox-terminal.d.ts +24 -4
  112. package/dist/components/sandbox-workspace.d.ts +28 -9
  113. package/dist/components/session-chrome.d.ts +4 -4
  114. package/dist/components/session-status.d.ts +2 -2
  115. package/dist/components/timeline-annotation-selection.d.ts +9 -0
  116. package/dist/components/timeline-annotations-dialog.d.ts +16 -0
  117. package/dist/components/timeline-annotations.d.ts +13 -0
  118. package/dist/components/tooltip.d.ts +4 -4
  119. package/dist/components/user-message-body.d.ts +2 -2
  120. package/dist/components/workbench-changes.d.ts +2 -2
  121. package/dist/components/workspace-dock.d.ts +1 -1
  122. package/dist/composer.d.ts +11 -11
  123. package/dist/composer.js +7 -7
  124. package/dist/hooks/internal.d.ts +1 -1
  125. package/dist/hooks/use-attached-browsers.d.ts +21 -0
  126. package/dist/hooks/use-auth-runs.d.ts +32 -0
  127. package/dist/hooks/use-available-models.d.ts +2 -2
  128. package/dist/hooks/use-billing-usage.d.ts +1 -1
  129. package/dist/hooks/use-browser-downloads.d.ts +25 -0
  130. package/dist/hooks/use-browser-frame-stream.d.ts +28 -0
  131. package/dist/hooks/use-browser-identities.d.ts +30 -0
  132. package/dist/hooks/use-browser-session.d.ts +29 -0
  133. package/dist/hooks/use-browser-sessions.d.ts +32 -0
  134. package/dist/hooks/use-channels.d.ts +26 -0
  135. package/dist/hooks/use-codex-accounts.d.ts +2 -2
  136. package/dist/hooks/use-composer.d.ts +36 -9
  137. package/dist/hooks/use-computer-frame-stream.d.ts +24 -0
  138. package/dist/hooks/use-computer-session.d.ts +29 -0
  139. package/dist/hooks/use-computer-sessions.d.ts +28 -0
  140. package/dist/hooks/use-desktop-stream.d.ts +5 -1
  141. package/dist/hooks/use-environments.d.ts +1 -1
  142. package/dist/hooks/use-file-attachments.d.ts +1 -1
  143. package/dist/hooks/use-goal.d.ts +2 -2
  144. package/dist/hooks/use-human-input.d.ts +2 -2
  145. package/dist/hooks/use-interaction-interventions.d.ts +27 -0
  146. package/dist/hooks/use-interaction-invalidation.d.ts +19 -0
  147. package/dist/hooks/use-last-started-turn-policy.d.ts +2 -2
  148. package/dist/hooks/use-machine-chip.d.ts +2 -2
  149. package/dist/hooks/use-machines.d.ts +4 -4
  150. package/dist/hooks/use-network-routes.d.ts +25 -0
  151. package/dist/hooks/use-packs.d.ts +7 -2
  152. package/dist/hooks/use-rigs.d.ts +1 -1
  153. package/dist/hooks/use-sandbox-files.d.ts +6 -4
  154. package/dist/hooks/use-sandbox-git.d.ts +6 -5
  155. package/dist/hooks/use-sandbox-terminal.d.ts +1 -1
  156. package/dist/hooks/use-scheduled-tasks.d.ts +1 -1
  157. package/dist/hooks/use-session-capabilities.d.ts +5 -4
  158. package/dist/hooks/use-session-control.d.ts +1 -1
  159. package/dist/hooks/use-session-events.d.ts +2 -2
  160. package/dist/hooks/use-session-lineage.d.ts +1 -1
  161. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  162. package/dist/hooks/use-session.d.ts +2 -2
  163. package/dist/hooks/use-site-auth-connections.d.ts +25 -0
  164. package/dist/hooks/use-slash-commands.d.ts +1 -1
  165. package/dist/hooks/use-supergrok-accounts.d.ts +26 -0
  166. package/dist/hooks/use-terminal-stream.d.ts +11 -2
  167. package/dist/hooks/use-turn-queue.d.ts +2 -2
  168. package/dist/hooks/use-video-artifact-playback.d.ts +9 -0
  169. package/dist/hooks/use-voice-input.d.ts +1 -1
  170. package/dist/hooks/use-workspace-capture.d.ts +1 -1
  171. package/dist/hooks/use-workspace-edit.d.ts +1 -1
  172. package/dist/hooks/use-workspace-sessions.d.ts +1 -1
  173. package/dist/hooks/use-workspaces.d.ts +1 -1
  174. package/dist/index.d.ts +162 -155
  175. package/dist/index.js +1822 -1703
  176. package/dist/index.js.map +1 -1
  177. package/dist/interaction.d.ts +33 -0
  178. package/dist/interaction.js +550 -0
  179. package/dist/interaction.js.map +1 -0
  180. package/dist/interactive-workbench-viewers-TOHBXJEE.js +15 -0
  181. package/dist/interactive-workbench-viewers-TOHBXJEE.js.map +1 -0
  182. package/dist/lib/host-platform.d.ts +5 -0
  183. package/dist/lib/relay-wire.d.ts +24 -1
  184. package/dist/lib/sandbox-liveness.d.ts +9 -0
  185. package/dist/lib/terminal-capability.d.ts +5 -0
  186. package/dist/lib/xterm-theme.d.ts +1 -1
  187. package/dist/machines.d.ts +30 -30
  188. package/dist/machines.js +2 -2
  189. package/dist/model-policy.d.ts +1 -1
  190. package/dist/model-policy.js +1 -1
  191. package/dist/provider.d.ts +6 -5
  192. package/dist/{queue-surface-implementation-U5JFG7HT.js → queue-surface-implementation-2KVJTYXH.js} +100 -48
  193. package/dist/queue-surface-implementation-2KVJTYXH.js.map +1 -0
  194. package/dist/realtime/dropdown-menu.d.ts +8 -8
  195. package/dist/realtime/realtime-control.d.ts +8 -8
  196. package/dist/realtime.d.ts +4 -4
  197. package/dist/realtime.js +38 -11
  198. package/dist/realtime.js.map +1 -1
  199. package/dist/session-context.d.ts +28 -2
  200. package/dist/session-ui.d.ts +14 -14
  201. package/dist/session-ui.js +5 -4
  202. package/dist/session.d.ts +28 -28
  203. package/dist/session.js +10 -10
  204. package/dist/timeline/activity-rail.d.ts +5 -3
  205. package/dist/timeline/disclosure-context.d.ts +1 -1
  206. package/dist/timeline/fleet-decision-projection.d.ts +1 -1
  207. package/dist/timeline/fleet-decision-row.d.ts +3 -3
  208. package/dist/timeline/index.d.ts +19 -19
  209. package/dist/timeline/parsers.d.ts +4 -1
  210. package/dist/timeline/projection.d.ts +3 -3
  211. package/dist/timeline/registry.d.ts +8 -2
  212. package/dist/timeline/screenshot-lightbox.d.ts +2 -2
  213. package/dist/timeline/shared.d.ts +21 -10
  214. package/dist/timeline/tool-diff.d.ts +2 -2
  215. package/dist/timeline/tool-renderers.d.ts +1 -1
  216. package/dist/timeline/turn-summary.d.ts +3 -3
  217. package/dist/timeline/types.d.ts +44 -3
  218. package/dist/timeline-annotation-selection-3L7LHGG2.js +187 -0
  219. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +1 -0
  220. package/dist/timeline-annotations-dialog-U7EVLR75.js +196 -0
  221. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +1 -0
  222. package/package.json +36 -7
  223. package/src/artifacts-document.ts +31 -0
  224. package/src/artifacts-presentation.ts +36 -0
  225. package/src/artifacts-spreadsheet.ts +21 -0
  226. package/src/artifacts.ts +89 -0
  227. package/src/client.ts +157 -1
  228. package/src/clipboard.ts +2 -0
  229. package/src/components/artifacts/artifact-surface.tsx +93 -0
  230. package/src/components/artifacts/document-editor.tsx +2255 -0
  231. package/src/components/artifacts/editable-artifact-ui.tsx +89 -0
  232. package/src/components/artifacts/editable-artifact-workbench.tsx +203 -0
  233. package/src/components/artifacts/editable-document.tsx +657 -0
  234. package/src/components/artifacts/editable-presentation.tsx +1020 -0
  235. package/src/components/artifacts/editable-spreadsheet.tsx +733 -0
  236. package/src/components/artifacts/index.ts +104 -0
  237. package/src/components/artifacts/presentation-editor.tsx +3148 -0
  238. package/src/components/artifacts/published-html-artifact-frame.tsx +38 -0
  239. package/src/components/artifacts/spreadsheet-canvas.ts +799 -0
  240. package/src/components/artifacts/spreadsheet-grid.tsx +2129 -0
  241. package/src/components/browser-input.ts +65 -0
  242. package/src/components/browser-viewer.tsx +2702 -0
  243. package/src/components/chat-composer.tsx +13 -0
  244. package/src/components/code-editor.tsx +89 -30
  245. package/src/components/composer-transcription-control.tsx +10 -6
  246. package/src/components/computer-viewer.tsx +1636 -0
  247. package/src/components/desktop-viewer.tsx +215 -74
  248. package/src/components/generated-video-player.tsx +89 -0
  249. package/src/components/interaction-intervention-banner.tsx +99 -0
  250. package/src/components/interactive-workbench-viewers.ts +2 -0
  251. package/src/components/machine-input-display.ts +3 -0
  252. package/src/components/machines/machine-detail.tsx +1 -1
  253. package/src/components/message-timeline.tsx +289 -32
  254. package/src/components/model-policy-picker.tsx +15 -0
  255. package/src/components/queue-surface-implementation.tsx +116 -60
  256. package/src/components/sandbox-files.tsx +2 -2
  257. package/src/components/sandbox-terminal.tsx +128 -46
  258. package/src/components/sandbox-workspace.tsx +256 -90
  259. package/src/components/session-chrome.tsx +53 -13
  260. package/src/components/timeline-annotation-selection.tsx +221 -0
  261. package/src/components/timeline-annotations-dialog.tsx +213 -0
  262. package/src/components/timeline-annotations.tsx +84 -0
  263. package/src/components/workbench-changes.tsx +188 -31
  264. package/src/components/workspace-dock.tsx +59 -5
  265. package/src/hooks/use-attached-browsers.ts +154 -0
  266. package/src/hooks/use-auth-runs.ts +278 -0
  267. package/src/hooks/use-browser-downloads.ts +218 -0
  268. package/src/hooks/use-browser-frame-stream.ts +425 -0
  269. package/src/hooks/use-browser-identities.ts +266 -0
  270. package/src/hooks/use-browser-session.ts +543 -0
  271. package/src/hooks/use-browser-sessions.ts +286 -0
  272. package/src/hooks/use-channels.ts +99 -0
  273. package/src/hooks/use-composer.ts +769 -24
  274. package/src/hooks/use-computer-frame-stream.ts +434 -0
  275. package/src/hooks/use-computer-session.ts +462 -0
  276. package/src/hooks/use-computer-sessions.ts +251 -0
  277. package/src/hooks/use-desktop-stream.ts +39 -7
  278. package/src/hooks/use-interaction-interventions.ts +242 -0
  279. package/src/hooks/use-interaction-invalidation.ts +66 -0
  280. package/src/hooks/use-machine-chip.ts +15 -3
  281. package/src/hooks/use-machines.ts +33 -3
  282. package/src/hooks/use-network-routes.ts +214 -0
  283. package/src/hooks/use-packs.ts +51 -0
  284. package/src/hooks/use-sandbox-files.ts +98 -55
  285. package/src/hooks/use-sandbox-git.ts +93 -38
  286. package/src/hooks/use-sandbox-terminal.ts +3 -2
  287. package/src/hooks/use-session-capabilities.ts +59 -46
  288. package/src/hooks/use-site-auth-connections.ts +226 -0
  289. package/src/hooks/use-supergrok-accounts.ts +81 -0
  290. package/src/hooks/use-terminal-stream.ts +359 -47
  291. package/src/hooks/use-video-artifact-playback.ts +28 -0
  292. package/src/hooks/use-workspace-edit.ts +2 -1
  293. package/src/index.ts +18 -0
  294. package/src/interaction.ts +101 -0
  295. package/src/lib/host-platform.ts +10 -0
  296. package/src/lib/relay-wire.ts +47 -4
  297. package/src/lib/sandbox-liveness.ts +11 -0
  298. package/src/lib/terminal-capability.ts +10 -0
  299. package/src/model-policy.ts +19 -4
  300. package/src/provider.tsx +133 -1
  301. package/src/realtime/realtime-control.tsx +34 -6
  302. package/src/session-context.ts +156 -1
  303. package/src/timeline/activity-rail.tsx +25 -3
  304. package/src/timeline/index.ts +3 -0
  305. package/src/timeline/parsers.ts +14 -1
  306. package/src/timeline/projection.ts +269 -14
  307. package/src/timeline/registry.ts +13 -1
  308. package/src/timeline/screenshot-lightbox.tsx +19 -9
  309. package/src/timeline/shared.tsx +56 -8
  310. package/src/timeline/tool-renderers.tsx +303 -50
  311. package/src/timeline/types.ts +57 -3
  312. package/styles/compiled.css +312 -21
  313. package/styles/index.css +15 -0
  314. package/styles/responsive.css +13 -1
  315. package/dist/chunk-23EJ676W.js.map +0 -1
  316. package/dist/chunk-EKZH6IDG.js.map +0 -1
  317. package/dist/chunk-FWXGSNXT.js.map +0 -1
  318. package/dist/chunk-LHLYWG5R.js.map +0 -1
  319. package/dist/chunk-O4VXOBGF.js.map +0 -1
  320. package/dist/chunk-OL6QVXGF.js.map +0 -1
  321. package/dist/chunk-WYA65Y3F.js.map +0 -1
  322. package/dist/chunk-XCNTXWBB.js.map +0 -1
  323. package/dist/fleet-decision-projection-SLNZMS42.js +0 -241
  324. package/dist/fleet-decision-projection-SLNZMS42.js.map +0 -1
  325. package/dist/queue-surface-implementation-U5JFG7HT.js.map +0 -1
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-KZ73RL76.js";
4
4
  import {
5
5
  useEmbeddedSession
6
- } from "./chunk-EKZH6IDG.js";
6
+ } from "./chunk-C5ZPSSS5.js";
7
7
 
8
8
  // src/hooks/use-composer.ts
9
9
  import {
@@ -11,7 +11,9 @@ import {
11
11
  } from "@opengeni/sdk";
12
12
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
13
13
  var PENDING_COMPOSER_STORAGE_PREFIX = "opengeni.pending-composer.v1:";
14
+ var OPTIMISTIC_SEND_STORAGE_PREFIX = "opengeni.optimistic-sends.v1:";
14
15
  var pendingComposerOperations = /* @__PURE__ */ new Map();
16
+ var optimisticSendOperations = /* @__PURE__ */ new Map();
15
17
  function pendingComposerOperationKey(workspaceId, sessionId) {
16
18
  return sessionId ? `${workspaceId}\0${sessionId}` : null;
17
19
  }
@@ -25,6 +27,50 @@ function pendingComposerStorage() {
25
27
  function pendingComposerStorageKey(key) {
26
28
  return `${PENDING_COMPOSER_STORAGE_PREFIX}${encodeURIComponent(key)}`;
27
29
  }
30
+ function optimisticSendStorageKey(key) {
31
+ return `${OPTIMISTIC_SEND_STORAGE_PREFIX}${encodeURIComponent(key)}`;
32
+ }
33
+ function restoreOptimisticSendOperations(key) {
34
+ if (!key) return [];
35
+ let stored = optimisticSendOperations.get(key);
36
+ if (!stored) {
37
+ const storage = pendingComposerStorage();
38
+ try {
39
+ const parsed = JSON.parse(storage?.getItem(optimisticSendStorageKey(key)) ?? "[]");
40
+ stored = Array.isArray(parsed) ? parsed.filter(
41
+ (candidate) => typeof candidate === "object" && candidate !== null && typeof candidate.clientEventId === "string" && typeof candidate.text === "string" && typeof candidate.occurredAt === "string" && (candidate.state === "sending" || candidate.state === "failed") && typeof candidate.input === "object" && candidate.input !== null && typeof candidate.input.text === "string" && typeof candidate.hasMcpCredentialUpdates === "boolean"
42
+ ) : [];
43
+ } catch {
44
+ stored = [];
45
+ }
46
+ }
47
+ return stored.map(({ hasMcpCredentialUpdates, ...operation }) => ({
48
+ ...operation,
49
+ newerShadow: operation.newerShadow ?? { text: "", resources: [], annotations: [] },
50
+ state: operation.state === "sending" || operation.state === "queued" ? "sending" : operation.state,
51
+ 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,
53
+ input: operation.input,
54
+ canRetry: !hasMcpCredentialUpdates
55
+ }));
56
+ }
57
+ function rememberOptimisticSendOperations(key, operations) {
58
+ if (!key) return;
59
+ const stored = operations.filter((operation) => operation.state !== "queued").map((operation) => {
60
+ const { canRetry: _canRetry, input, ...rest } = operation;
61
+ const { mcpCredentialUpdates: _credentials, ...safeInput } = input;
62
+ return {
63
+ ...rest,
64
+ input: safeInput,
65
+ hasMcpCredentialUpdates: input.mcpCredentialUpdates !== void 0
66
+ };
67
+ });
68
+ optimisticSendOperations.set(key, stored);
69
+ try {
70
+ pendingComposerStorage()?.setItem(optimisticSendStorageKey(key), JSON.stringify(stored));
71
+ } catch {
72
+ }
73
+ }
28
74
  function resourceList(value) {
29
75
  return Array.isArray(value) && value.every((candidate) => {
30
76
  if (typeof candidate !== "object" || candidate === null) return false;
@@ -32,6 +78,22 @@ function resourceList(value) {
32
78
  return resource.kind === "file" ? typeof resource.fileId === "string" : resource.kind === "repository" && typeof resource.uri === "string" && typeof resource.ref === "string";
33
79
  });
34
80
  }
81
+ function timelineAnnotationList(value) {
82
+ return Array.isArray(value) && value.every((candidate) => {
83
+ if (typeof candidate !== "object" || candidate === null) return false;
84
+ const annotation = candidate;
85
+ const source = annotation.source;
86
+ if (typeof source !== "object" || source === null) return false;
87
+ const sourceRecord = source;
88
+ return typeof annotation.id === "string" && typeof annotation.quote === "string" && typeof annotation.note === "string" && typeof sourceRecord.eventId === "string" && typeof sourceRecord.eventType === "string" && typeof sourceRecord.sequence === "number" && (typeof sourceRecord.turnId === "string" || sourceRecord.turnId === null) && typeof sourceRecord.startOffset === "number" && typeof sourceRecord.endOffset === "number" && typeof sourceRecord.contextBefore === "string" && typeof sourceRecord.contextAfter === "string";
89
+ });
90
+ }
91
+ function cloneAnnotations(annotations) {
92
+ return annotations.map((annotation) => ({
93
+ ...annotation,
94
+ source: { ...annotation.source }
95
+ }));
96
+ }
35
97
  function readStoredPendingComposerOperation(key) {
36
98
  const storage = key ? pendingComposerStorage() : null;
37
99
  if (!storage || !key) return null;
@@ -46,10 +108,17 @@ function readStoredPendingComposerOperation(key) {
46
108
  }
47
109
  const inputRecord = input;
48
110
  const shadowRecord = shadow;
49
- if (record.delivery !== "send" && record.delivery !== "steer" || typeof record.draftAtSend !== "string" || !resourceList(record.resourcesAtSend) || typeof shadowRecord.text !== "string" || !resourceList(shadowRecord.resources) || typeof record.clearDraftOnAccept !== "boolean" || typeof record.hasMcpCredentialUpdates !== "boolean" || typeof inputRecord.text !== "string" || typeof inputRecord.clientEventId !== "string" || "mcpCredentialUpdates" in inputRecord || "resources" in inputRecord && !resourceList(inputRecord.resources)) {
111
+ if (record.delivery !== "send" && record.delivery !== "steer" || typeof record.draftAtSend !== "string" || !resourceList(record.resourcesAtSend) || record.annotationsAtSend !== void 0 && !timelineAnnotationList(record.annotationsAtSend) || typeof shadowRecord.text !== "string" || !resourceList(shadowRecord.resources) || shadowRecord.annotations !== void 0 && !timelineAnnotationList(shadowRecord.annotations) || typeof record.clearDraftOnAccept !== "boolean" || typeof record.hasMcpCredentialUpdates !== "boolean" || typeof inputRecord.text !== "string" || typeof inputRecord.clientEventId !== "string" || "mcpCredentialUpdates" in inputRecord || "resources" in inputRecord && !resourceList(inputRecord.resources) || "annotations" in inputRecord && !timelineAnnotationList(inputRecord.annotations)) {
50
112
  return null;
51
113
  }
52
- return record;
114
+ return {
115
+ ...record,
116
+ annotationsAtSend: timelineAnnotationList(record.annotationsAtSend) ? record.annotationsAtSend : [],
117
+ newerShadow: {
118
+ ...shadow,
119
+ annotations: timelineAnnotationList(shadowRecord.annotations) ? shadowRecord.annotations : []
120
+ }
121
+ };
53
122
  } catch {
54
123
  return null;
55
124
  }
@@ -70,7 +139,8 @@ function restorePendingComposerOperation(key) {
70
139
  input: stored.input,
71
140
  newerShadow: stored.newerShadow ?? {
72
141
  text: stored.draftAtSend,
73
- resources: stored.resourcesAtSend
142
+ resources: stored.resourcesAtSend,
143
+ annotations: stored.annotationsAtSend
74
144
  },
75
145
  canRetry: !stored.hasMcpCredentialUpdates
76
146
  };
@@ -86,7 +156,8 @@ function rememberPendingComposerOperation(key, operation) {
86
156
  hasMcpCredentialUpdates: operation.input.mcpCredentialUpdates !== void 0,
87
157
  newerShadow: {
88
158
  text: operation.newerShadow.text,
89
- resources: [...operation.newerShadow.resources]
159
+ resources: [...operation.newerShadow.resources],
160
+ annotations: cloneAnnotations(operation.newerShadow.annotations)
90
161
  }
91
162
  };
92
163
  pendingComposerOperations.set(key, stored);
@@ -104,7 +175,14 @@ function forgetPendingComposerOperation(key) {
104
175
  }
105
176
  function updatePendingComposerShadow(key, operation, shadow) {
106
177
  if (!key || !operation) return operation;
107
- const next = { ...operation, newerShadow: { ...shadow, resources: [...shadow.resources] } };
178
+ const next = {
179
+ ...operation,
180
+ newerShadow: {
181
+ ...shadow,
182
+ resources: [...shadow.resources],
183
+ annotations: cloneAnnotations(shadow.annotations)
184
+ }
185
+ };
108
186
  rememberPendingComposerOperation(key, next);
109
187
  return next;
110
188
  }
@@ -140,10 +218,16 @@ function useComposer(sessionId, options = {}) {
140
218
  const targetKey = `${workspaceId}\0${sessionId ?? ""}\0${durableDrafts ? "durable" : "disabled"}`;
141
219
  const pendingOperationKey = pendingComposerOperationKey(workspaceId, sessionId);
142
220
  const initialPendingOperation = restorePendingComposerOperation(pendingOperationKey);
143
- const initialShadow = initialPendingOperation?.newerShadow;
221
+ const initialOptimisticSends = restoreOptimisticSendOperations(pendingOperationKey);
222
+ const initialShadow = initialPendingOperation?.newerShadow ?? initialOptimisticSends.at(-1)?.newerShadow;
144
223
  const [value, setValue] = useState(() => initialShadow?.text ?? "");
224
+ const [annotations, setAnnotations] = useState(
225
+ () => initialShadow?.annotations ?? []
226
+ );
227
+ const [annotationReviewTargetId, setAnnotationReviewTargetId] = useState(null);
145
228
  const [stateTargetKey, setStateTargetKey] = useState(targetKey);
146
229
  const [sending, setSending] = useState(false);
230
+ const [optimisticSends, setOptimisticSends] = useState(initialOptimisticSends);
147
231
  const [steering, setSteering] = useState(
148
232
  () => initialPendingOperation?.delivery === "steer" ? {
149
233
  phase: "submitting",
@@ -154,6 +238,7 @@ function useComposer(sessionId, options = {}) {
154
238
  } : null
155
239
  );
156
240
  const [pausing, setPausing] = useState(false);
241
+ const [controlStopping, setControlStopping] = useState(null);
157
242
  const [resuming, setResuming] = useState(false);
158
243
  const [error, setError] = useState(null);
159
244
  const [draft, setDraft] = useState(null);
@@ -164,12 +249,16 @@ function useComposer(sessionId, options = {}) {
164
249
  () => initialShadow?.resources ?? []
165
250
  );
166
251
  const pendingOperationRef = useRef(initialPendingOperation);
252
+ const optimisticSendsRef = useRef(initialOptimisticSends);
253
+ const optimisticProcessorBusyRef = useRef(false);
254
+ const optimisticCallbackIdsRef = useRef(/* @__PURE__ */ new Set());
167
255
  const steeringSettlementEventsRef = useRef([]);
168
256
  const steeringRef = useRef(steering);
169
257
  const pendingClientEventId = useRef(
170
258
  initialPendingOperation?.input.clientEventId ?? null
171
259
  );
172
260
  const valueRef = useRef(initialShadow?.text ?? "");
261
+ const annotationsRef = useRef(initialShadow?.annotations ?? []);
173
262
  const draftRef = useRef(null);
174
263
  const restoredResourcesRef = useRef(initialShadow?.resources ?? []);
175
264
  const localEditRevision = useRef(initialShadow ? 1 : 0);
@@ -178,6 +267,7 @@ function useComposer(sessionId, options = {}) {
178
267
  const lastSavedSignature = useRef(null);
179
268
  const saveChain = useRef(Promise.resolve());
180
269
  const onSent = options.onSent;
270
+ const onSubmitted = options.onSubmitted;
181
271
  const onDraftApplied = options.onDraftApplied;
182
272
  const onDraftAppliedRef = useRef(onDraftApplied);
183
273
  useLayoutEffect(() => {
@@ -198,18 +288,26 @@ function useComposer(sessionId, options = {}) {
198
288
  targetGeneration.current += 1;
199
289
  draftReadGeneration.current += 1;
200
290
  pendingOperationRef.current = restorePendingComposerOperation(pendingOperationKey);
291
+ const restoredOptimisticSends = restoreOptimisticSendOperations(pendingOperationKey);
292
+ optimisticSendsRef.current = restoredOptimisticSends;
293
+ optimisticProcessorBusyRef.current = false;
294
+ optimisticCallbackIdsRef.current = /* @__PURE__ */ new Set();
201
295
  steeringSettlementEventsRef.current = [];
202
296
  pendingClientEventId.current = pendingOperationRef.current?.input.clientEventId ?? null;
203
- const shadow = pendingOperationRef.current?.newerShadow;
297
+ const shadow = pendingOperationRef.current?.newerShadow ?? restoredOptimisticSends.at(-1)?.newerShadow;
204
298
  localEditRevision.current = shadow ? 1 : 0;
205
299
  valueRef.current = shadow?.text ?? "";
300
+ annotationsRef.current = shadow?.annotations ?? [];
206
301
  draftRef.current = null;
207
302
  restoredResourcesRef.current = shadow?.resources ?? [];
208
303
  lastSavedSignature.current = null;
209
304
  saveChain.current = Promise.resolve();
210
305
  setStateTargetKey(targetKey);
211
306
  setValue(shadow?.text ?? "");
307
+ setAnnotations(shadow?.annotations ?? []);
308
+ setAnnotationReviewTargetId(null);
212
309
  setSending(false);
310
+ setOptimisticSends(restoredOptimisticSends);
213
311
  setSteering(
214
312
  pendingOperationRef.current?.delivery === "steer" ? {
215
313
  phase: "submitting",
@@ -220,6 +318,7 @@ function useComposer(sessionId, options = {}) {
220
318
  } : null
221
319
  );
222
320
  setPausing(false);
321
+ setControlStopping(null);
223
322
  setResuming(false);
224
323
  setError(null);
225
324
  setDraft(null);
@@ -228,17 +327,36 @@ function useComposer(sessionId, options = {}) {
228
327
  setDraftConflict(null);
229
328
  setRestoredResources(shadow?.resources ?? []);
230
329
  }, [durableDrafts, pendingOperationKey, sessionId, targetKey]);
330
+ const setOptimisticDraftShadow = useCallback(
331
+ (shadow) => {
332
+ if (optimisticSendsRef.current.length === 0) return;
333
+ const next = optimisticSendsRef.current.map((operation) => ({
334
+ ...operation,
335
+ newerShadow: {
336
+ text: shadow.text,
337
+ resources: [...shadow.resources],
338
+ annotations: cloneAnnotations(shadow.annotations)
339
+ }
340
+ }));
341
+ optimisticSendsRef.current = next;
342
+ rememberOptimisticSendOperations(pendingOperationKey, next);
343
+ setOptimisticSends(next);
344
+ },
345
+ [pendingOperationKey]
346
+ );
231
347
  const applyDraft = useCallback(
232
348
  (next) => {
233
349
  if (targetKeyRef.current !== targetKey) return;
234
350
  if (!durableDrafts) {
235
351
  localEditRevision.current += 1;
236
352
  valueRef.current = next.text;
353
+ annotationsRef.current = next.annotations ?? [];
237
354
  restoredResourcesRef.current = next.resources;
238
355
  draftRef.current = null;
239
356
  lastSavedSignature.current = null;
240
357
  setDraft(null);
241
358
  setValue(next.text);
359
+ setAnnotations(next.annotations ?? []);
242
360
  setRestoredResources(next.resources);
243
361
  pendingOperationRef.current = updatePendingComposerShadow(
244
362
  pendingOperationKey,
@@ -248,19 +366,30 @@ function useComposer(sessionId, options = {}) {
248
366
  resources: mergeResources(
249
367
  next.resources,
250
368
  resolveSendExtras(sendExtrasRef.current).resources ?? []
251
- )
369
+ ),
370
+ annotations: next.annotations ?? []
252
371
  }
253
372
  );
373
+ setOptimisticDraftShadow({
374
+ text: next.text,
375
+ resources: mergeResources(
376
+ next.resources,
377
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
378
+ ),
379
+ annotations: next.annotations ?? []
380
+ });
254
381
  setDraftConflict(null);
255
382
  return;
256
383
  }
257
384
  valueRef.current = next.text;
385
+ annotationsRef.current = next.annotations ?? [];
258
386
  draftRef.current = next;
259
387
  restoredResourcesRef.current = next.resources;
260
388
  lastSavedSignature.current = draftSignature(draftPayload(next));
261
389
  localEditRevision.current += 1;
262
390
  setDraft(next);
263
391
  setValue(next.text);
392
+ setAnnotations(next.annotations ?? []);
264
393
  setRestoredResources(next.resources);
265
394
  pendingOperationRef.current = updatePendingComposerShadow(
266
395
  pendingOperationKey,
@@ -270,13 +399,22 @@ function useComposer(sessionId, options = {}) {
270
399
  resources: mergeResources(
271
400
  next.resources,
272
401
  resolveSendExtras(sendExtrasRef.current).resources ?? []
273
- )
402
+ ),
403
+ annotations: next.annotations ?? []
274
404
  }
275
405
  );
406
+ setOptimisticDraftShadow({
407
+ text: next.text,
408
+ resources: mergeResources(
409
+ next.resources,
410
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
411
+ ),
412
+ annotations: next.annotations ?? []
413
+ });
276
414
  setDraftConflict(null);
277
415
  onDraftAppliedRef.current?.(next);
278
416
  },
279
- [durableDrafts, pendingOperationKey, targetKey]
417
+ [durableDrafts, pendingOperationKey, setOptimisticDraftShadow, targetKey]
280
418
  );
281
419
  const loadDraft = useCallback(
282
420
  async (replaceLocal) => {
@@ -295,6 +433,7 @@ function useComposer(sessionId, options = {}) {
295
433
  baseAtStart,
296
434
  valueRef.current,
297
435
  restoredResourcesRef.current,
436
+ annotationsRef.current,
298
437
  extrasAtStart
299
438
  )
300
439
  ) : null;
@@ -313,21 +452,25 @@ function useComposer(sessionId, options = {}) {
313
452
  draftRef.current = fetched;
314
453
  setDraft(fetched);
315
454
  setDraftConflict(null);
316
- const shadow = pendingOperationRef.current?.newerShadow;
455
+ const shadow = pendingOperationRef.current?.newerShadow ?? optimisticSendsRef.current.at(-1)?.newerShadow;
317
456
  if (shadow) {
318
457
  valueRef.current = shadow.text;
319
458
  restoredResourcesRef.current = shadow.resources;
459
+ annotationsRef.current = shadow.annotations;
320
460
  localEditRevision.current ||= 1;
321
461
  setValue(shadow.text);
322
462
  setRestoredResources(shadow.resources);
463
+ setAnnotations(shadow.annotations);
323
464
  } else if (replaceLocal || !localWasDirtyAtStart && localAtStart === localEditRevision.current) {
324
465
  const extrasNow = resolveSendExtras(sendExtrasRef.current);
325
466
  const pickerChangedDuringFetch = extrasNow.model !== extrasAtStart.model || extrasNow.reasoningEffort !== extrasAtStart.reasoningEffort || extrasNow.latencyMode !== extrasAtStart.latencyMode;
326
467
  valueRef.current = fetched.text;
327
468
  restoredResourcesRef.current = fetched.resources;
469
+ annotationsRef.current = fetched.annotations ?? [];
328
470
  lastSavedSignature.current = draftSignature(draftPayload(fetched));
329
471
  setValue(fetched.text);
330
472
  setRestoredResources(fetched.resources);
473
+ setAnnotations(fetched.annotations ?? []);
331
474
  if (replaceLocal || !pickerChangedDuringFetch) {
332
475
  onDraftAppliedRef.current?.(fetched);
333
476
  }
@@ -436,13 +579,24 @@ function useComposer(sessionId, options = {}) {
436
579
  steeringSettlementEventsRef.current = [];
437
580
  setSteering(null);
438
581
  }, [options.events, steering]);
582
+ useEffect(() => {
583
+ if (!controlStopping) return;
584
+ const effectiveControl = options.effectiveControl;
585
+ if (!effectiveControl || effectiveControl.controlVersion < controlStopping.controlVersion) {
586
+ return;
587
+ }
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]);
439
593
  const currentDraftPayload = useCallback(() => {
440
594
  if (!durableDrafts || targetKeyRef.current !== targetKey) return null;
441
595
  const base = draftRef.current;
442
596
  if (!base) return null;
443
597
  const extras = resolveSendExtras(sendExtrasRef.current);
444
- return composerDraftPayload(base, value, restoredResources, extras);
445
- }, [durableDrafts, restoredResources, targetKey, value]);
598
+ return composerDraftPayload(base, value, restoredResources, annotations, extras);
599
+ }, [annotations, durableDrafts, restoredResources, targetKey, value]);
446
600
  const persistPayload = useCallback(
447
601
  async (payload) => {
448
602
  const ownedTargetKey = targetKey;
@@ -505,6 +659,152 @@ function useComposer(sessionId, options = {}) {
505
659
  },
506
660
  [client, durableDrafts, sessionId, targetKey, workspaceId]
507
661
  );
662
+ const replaceOptimisticSends = useCallback(
663
+ (update) => {
664
+ const next = update(optimisticSendsRef.current);
665
+ optimisticSendsRef.current = next;
666
+ rememberOptimisticSendOperations(pendingOperationKey, next);
667
+ setOptimisticSends(next);
668
+ return next;
669
+ },
670
+ [pendingOperationKey]
671
+ );
672
+ const markOptimisticAccepted = useCallback(
673
+ (operation) => {
674
+ if (!optimisticCallbackIdsRef.current.has(operation.clientEventId)) {
675
+ optimisticCallbackIdsRef.current.add(operation.clientEventId);
676
+ onSent?.(operation.input.text, operation.input);
677
+ }
678
+ replaceOptimisticSends(
679
+ (current) => current.filter((candidate) => candidate.clientEventId !== operation.clientEventId)
680
+ );
681
+ },
682
+ [onSent, replaceOptimisticSends]
683
+ );
684
+ useEffect(() => {
685
+ const acceptedIds = new Set(
686
+ (options.events ?? []).filter((event) => event.type === "user.message" && event.clientEventId).map((event) => event.clientEventId)
687
+ );
688
+ if (acceptedIds.size === 0) return;
689
+ const accepted = optimisticSendsRef.current.filter(
690
+ (operation) => acceptedIds.has(operation.clientEventId)
691
+ );
692
+ for (const operation of accepted) markOptimisticAccepted(operation);
693
+ }, [markOptimisticAccepted, options.events]);
694
+ const processOptimisticSends = useCallback(() => {
695
+ if (!sessionId || optimisticProcessorBusyRef.current) return;
696
+ const currentOperations = optimisticSendsRef.current;
697
+ const operationIndex = currentOperations.findIndex(
698
+ (candidate) => candidate.state === "sending"
699
+ );
700
+ const operation = operationIndex < 0 ? void 0 : currentOperations[operationIndex];
701
+ if (!operation) return;
702
+ const ownedTargetKey = targetKey;
703
+ const ownedGeneration = targetGeneration.current;
704
+ optimisticProcessorBusyRef.current = true;
705
+ void (async () => {
706
+ try {
707
+ 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);
717
+ return;
718
+ }
719
+ if (!operation.canRetry) {
720
+ throw new Error(
721
+ "OpenGeni cannot safely retry this uncertain request after remount; reconcile the session before sending again."
722
+ );
723
+ }
724
+ }
725
+ let expectedDraftRevision;
726
+ if (durableDrafts && operation.draftPayload) {
727
+ if (!await persistPayload(operation.draftPayload)) {
728
+ throw new Error("The message draft could not be saved before delivery.");
729
+ }
730
+ expectedDraftRevision = draftRef.current?.revision;
731
+ }
732
+ if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
733
+ return;
734
+ }
735
+ const wireInput = {
736
+ ...operation.input,
737
+ ...expectedDraftRevision !== void 0 ? { expectedDraftRevision } : {}
738
+ };
739
+ await client.sendMessage(workspaceId, sessionId, wireInput);
740
+ if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
741
+ return;
742
+ }
743
+ if (options.events === void 0) {
744
+ markOptimisticAccepted({ ...operation, input: wireInput });
745
+ } else {
746
+ replaceOptimisticSends(
747
+ (current) => current.map(
748
+ (candidate) => candidate.clientEventId === operation.clientEventId ? { ...candidate, input: wireInput, state: "queued", error: void 0 } : candidate
749
+ )
750
+ );
751
+ }
752
+ if (!optimisticCallbackIdsRef.current.has(operation.clientEventId)) {
753
+ optimisticCallbackIdsRef.current.add(operation.clientEventId);
754
+ onSent?.(wireInput.text, wireInput);
755
+ }
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
+ } 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
+ );
785
+ }
786
+ } finally {
787
+ optimisticProcessorBusyRef.current = false;
788
+ if (targetKeyRef.current === ownedTargetKey) {
789
+ setOptimisticSends([...optimisticSendsRef.current]);
790
+ }
791
+ }
792
+ })();
793
+ }, [
794
+ client,
795
+ durableDrafts,
796
+ markOptimisticAccepted,
797
+ onSent,
798
+ options.events,
799
+ persistPayload,
800
+ replaceOptimisticSends,
801
+ sessionId,
802
+ targetKey,
803
+ workspaceId
804
+ ]);
805
+ useEffect(() => {
806
+ processOptimisticSends();
807
+ }, [optimisticSends, processOptimisticSends]);
508
808
  useEffect(() => {
509
809
  const pending = pendingOperationRef.current;
510
810
  if (pending) {
@@ -513,9 +813,10 @@ function useComposer(sessionId, options = {}) {
513
813
  resources: mergeResources(
514
814
  restoredResourcesRef.current,
515
815
  resolveSendExtras(sendExtrasRef.current).resources ?? []
516
- )
816
+ ),
817
+ annotations: annotationsRef.current
517
818
  };
518
- if (pending.newerShadow.text !== shadow.text || JSON.stringify(pending.newerShadow.resources) !== JSON.stringify(shadow.resources)) {
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)) {
519
820
  pendingOperationRef.current = updatePendingComposerShadow(
520
821
  pendingOperationKey,
521
822
  pending,
@@ -524,6 +825,23 @@ function useComposer(sessionId, options = {}) {
524
825
  }
525
826
  return;
526
827
  }
828
+ const optimistic = optimisticSendsRef.current.at(-1);
829
+ if (optimistic) {
830
+ const shadow = {
831
+ text: valueRef.current,
832
+ resources: mergeResources(
833
+ restoredResourcesRef.current,
834
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
835
+ ),
836
+ annotations: annotationsRef.current
837
+ };
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)) {
839
+ setOptimisticDraftShadow(shadow);
840
+ }
841
+ }
842
+ if (optimisticSendsRef.current.some((operation) => operation.state === "sending")) {
843
+ return;
844
+ }
527
845
  if (!durableDrafts || !sessionId || draftLoading || sending || !draftRef.current || draftConflict)
528
846
  return;
529
847
  const payload = currentDraftPayload();
@@ -538,6 +856,7 @@ function useComposer(sessionId, options = {}) {
538
856
  liveExtrasVersion,
539
857
  pendingOperationKey,
540
858
  persistPayload,
859
+ setOptimisticDraftShadow,
541
860
  sending,
542
861
  sessionId
543
862
  ]);
@@ -552,11 +871,16 @@ function useComposer(sessionId, options = {}) {
552
871
  pendingClientEventId.current = pending.input.clientEventId ?? null;
553
872
  }
554
873
  const draftAtSend = value;
874
+ const annotationsAtSend = annotations;
555
875
  const rawText = explicit ?? draftAtSend;
556
876
  const hasText = rawText.trim().length > 0;
877
+ const hasAnnotations = annotationsAtSend.length > 0;
878
+ const annotationsComplete2 = annotationsAtSend.every(
879
+ (annotation) => annotation.note.trim().length > 0
880
+ );
557
881
  const extras = pending ? {} : resolveSendExtras(sendExtrasRef.current);
558
882
  const hasResources = restoredResources.length > 0 || (extras.resources?.length ?? 0) > 0;
559
- if (!pending && !hasText && !hasResources || !sessionId || sending || sendBlockedRef.current?.() === true || targetKeyRef.current !== ownedTargetKey) {
883
+ if (!pending && (!annotationsComplete2 || !hasText && !hasResources && !hasAnnotations) || !sessionId || sending || sendBlockedRef.current?.() === true || targetKeyRef.current !== ownedTargetKey) {
560
884
  return false;
561
885
  }
562
886
  const clearPending = () => {
@@ -569,6 +893,7 @@ function useComposer(sessionId, options = {}) {
569
893
  clearPending();
570
894
  const draftWasUnchanged = valueRef.current === operation.draftAtSend;
571
895
  const resourcesWereUnchanged = JSON.stringify(restoredResourcesRef.current) === JSON.stringify(operation.resourcesAtSend);
896
+ const annotationsWereUnchanged = JSON.stringify(annotationsRef.current) === JSON.stringify(operation.annotationsAtSend);
572
897
  const previousDraft = draftRef.current;
573
898
  if (previousDraft) {
574
899
  const cleared = {
@@ -576,6 +901,7 @@ function useComposer(sessionId, options = {}) {
576
901
  revision: 0,
577
902
  text: "",
578
903
  resources: [],
904
+ annotations: [],
579
905
  sourceTurnId: null,
580
906
  sourceTurnVersion: null,
581
907
  updatedAt: null
@@ -588,6 +914,11 @@ function useComposer(sessionId, options = {}) {
588
914
  restoredResourcesRef.current = [];
589
915
  setRestoredResources([]);
590
916
  }
917
+ if (annotationsWereUnchanged) {
918
+ annotationsRef.current = [];
919
+ setAnnotations([]);
920
+ setAnnotationReviewTargetId(null);
921
+ }
591
922
  if (operation.clearDraftOnAccept && draftWasUnchanged) {
592
923
  valueRef.current = "";
593
924
  setValue("");
@@ -664,7 +995,8 @@ function useComposer(sessionId, options = {}) {
664
995
  text: pending.input.text,
665
996
  clientEventId: pending.input.clientEventId ?? null,
666
997
  triggerEventId: result.accepted.id,
667
- turnId: result.turn.id
998
+ turnId: result.turn.id,
999
+ stoppingPreviousAttempt: result.replay !== true && (result.interruptionCount ?? 0) > 0
668
1000
  });
669
1001
  }
670
1002
  } catch (cause) {
@@ -680,7 +1012,7 @@ function useComposer(sessionId, options = {}) {
680
1012
  settleAccepted(pending);
681
1013
  return true;
682
1014
  }
683
- const sendText = hasText ? rawText : FILE_ONLY_MESSAGE_TEXT;
1015
+ const sendText = hasText ? rawText : hasAnnotations ? "" : FILE_ONLY_MESSAGE_TEXT;
684
1016
  const currentPayload = currentDraftPayload();
685
1017
  const payload = currentPayload ? { ...currentPayload, text: sendText } : null;
686
1018
  if (payload && !await persistPayload(payload)) return false;
@@ -691,16 +1023,19 @@ function useComposer(sessionId, options = {}) {
691
1023
  const input = composeSendInput(sendText, pendingClientEventId.current, extras, {
692
1024
  ...options.effectiveControl?.controlEtag ? { controlEtag: options.effectiveControl.controlEtag } : {},
693
1025
  ...durableDrafts && draftRef.current ? { expectedDraftRevision: draftRef.current.revision } : {},
694
- resources: mergeResources(restoredResources, extras.resources ?? [])
1026
+ resources: mergeResources(restoredResources, extras.resources ?? []),
1027
+ annotations: cloneAnnotations(annotationsAtSend)
695
1028
  });
696
1029
  const operation = {
697
1030
  delivery,
698
1031
  input,
699
1032
  draftAtSend,
700
1033
  resourcesAtSend: [...restoredResources],
1034
+ annotationsAtSend: cloneAnnotations(annotationsAtSend),
701
1035
  newerShadow: {
702
1036
  text: draftAtSend,
703
- resources: mergeResources(restoredResources, extras.resources ?? [])
1037
+ resources: mergeResources(restoredResources, extras.resources ?? []),
1038
+ annotations: cloneAnnotations(annotationsAtSend)
704
1039
  },
705
1040
  clearDraftOnAccept: explicit === void 0,
706
1041
  canRetry: true
@@ -725,7 +1060,8 @@ function useComposer(sessionId, options = {}) {
725
1060
  text: sendText,
726
1061
  clientEventId: input.clientEventId ?? null,
727
1062
  triggerEventId: result.accepted.id,
728
- turnId: result.turn.id
1063
+ turnId: result.turn.id,
1064
+ stoppingPreviousAttempt: result.replay !== true && (result.interruptionCount ?? 0) > 0
729
1065
  });
730
1066
  }
731
1067
  } catch (cause) {
@@ -759,6 +1095,7 @@ function useComposer(sessionId, options = {}) {
759
1095
  options.effectiveControl?.controlEtag,
760
1096
  persistPayload,
761
1097
  restoredResources,
1098
+ annotations,
762
1099
  sending,
763
1100
  sessionId,
764
1101
  targetKey,
@@ -766,10 +1103,126 @@ function useComposer(sessionId, options = {}) {
766
1103
  workspaceId
767
1104
  ]
768
1105
  );
769
- const send = useCallback(async (text) => await dispatch("send", text), [dispatch]);
1106
+ const send = useCallback(
1107
+ async (explicit) => {
1108
+ if (pendingOperationRef.current?.delivery === "send") {
1109
+ return await dispatch("send", explicit);
1110
+ }
1111
+ const rawText = explicit ?? valueRef.current;
1112
+ const annotationsAtSend = cloneAnnotations(annotationsRef.current);
1113
+ const hasText = rawText.trim().length > 0;
1114
+ const hasAnnotations = annotationsAtSend.length > 0;
1115
+ const annotationsComplete2 = annotationsAtSend.every(
1116
+ (annotation) => annotation.note.trim().length > 0
1117
+ );
1118
+ const extras = resolveSendExtras(sendExtrasRef.current);
1119
+ const resources = mergeResources(restoredResourcesRef.current, extras.resources ?? []);
1120
+ if (!sessionId || sending || !annotationsComplete2 || !hasText && !hasAnnotations && resources.length === 0 || sendBlockedRef.current?.() === true || targetKeyRef.current !== targetKey) {
1121
+ return false;
1122
+ }
1123
+ const sendText = hasText ? rawText : hasAnnotations ? "" : FILE_ONLY_MESSAGE_TEXT;
1124
+ const clientEventId = generateClientEventId();
1125
+ const input = composeSendInput(sendText, clientEventId, extras, {
1126
+ ...options.effectiveControl?.controlEtag ? { controlEtag: options.effectiveControl.controlEtag } : {},
1127
+ resources,
1128
+ annotations: annotationsAtSend
1129
+ });
1130
+ const currentPayload = currentDraftPayload();
1131
+ const operation = {
1132
+ clientEventId,
1133
+ text: sendText,
1134
+ annotations: annotationsAtSend,
1135
+ resources,
1136
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
1137
+ state: "sending",
1138
+ input,
1139
+ draftPayload: currentPayload ? { ...currentPayload, text: sendText } : null,
1140
+ newerShadow: {
1141
+ text: explicit === void 0 ? "" : valueRef.current,
1142
+ resources: explicit === void 0 ? [] : [...restoredResourcesRef.current],
1143
+ annotations: explicit === void 0 ? [] : cloneAnnotations(annotationsRef.current)
1144
+ },
1145
+ canRetry: true
1146
+ };
1147
+ replaceOptimisticSends((current) => [...current, operation]);
1148
+ queueMicrotask(processOptimisticSends);
1149
+ setError(null);
1150
+ onSubmitted?.(sendText, input);
1151
+ if (explicit === void 0) {
1152
+ valueRef.current = "";
1153
+ annotationsRef.current = [];
1154
+ restoredResourcesRef.current = [];
1155
+ localEditRevision.current += 1;
1156
+ setValue("");
1157
+ setAnnotations([]);
1158
+ setAnnotationReviewTargetId(null);
1159
+ setRestoredResources([]);
1160
+ }
1161
+ return true;
1162
+ },
1163
+ [
1164
+ currentDraftPayload,
1165
+ dispatch,
1166
+ onSubmitted,
1167
+ options.effectiveControl?.controlEtag,
1168
+ processOptimisticSends,
1169
+ replaceOptimisticSends,
1170
+ sending,
1171
+ sessionId,
1172
+ targetKey
1173
+ ]
1174
+ );
770
1175
  const steer = useCallback(async (text) => await dispatch("steer", text), [dispatch]);
1176
+ const retryOptimisticMessage = useCallback(
1177
+ (clientEventId) => {
1178
+ replaceOptimisticSends(
1179
+ (current) => current.map((operation) => {
1180
+ if (operation.clientEventId !== clientEventId || operation.state !== "failed") {
1181
+ return operation;
1182
+ }
1183
+ if (operation.outcomeUnknown) {
1184
+ return { ...operation, state: "sending", error: void 0 };
1185
+ }
1186
+ 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
+ });
1193
+ return {
1194
+ ...operation,
1195
+ clientEventId: nextClientEventId,
1196
+ 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,
1203
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
1204
+ state: "sending",
1205
+ error: void 0,
1206
+ outcomeUnknown: false,
1207
+ canRetry: true
1208
+ };
1209
+ })
1210
+ );
1211
+ queueMicrotask(processOptimisticSends);
1212
+ },
1213
+ [options.effectiveControl?.controlEtag, processOptimisticSends, replaceOptimisticSends]
1214
+ );
1215
+ const removeOptimisticMessage = useCallback(
1216
+ (clientEventId) => {
1217
+ replaceOptimisticSends(
1218
+ (current) => current.filter((operation) => operation.clientEventId !== clientEventId)
1219
+ );
1220
+ },
1221
+ [replaceOptimisticSends]
1222
+ );
771
1223
  const hasReadyResources = restoredResources.length > 0 || (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;
772
1224
  const hasPendingOperation = pendingOperationRef.current !== null;
1225
+ const annotationsComplete = annotations.every((annotation) => annotation.note.trim().length > 0);
773
1226
  const pause = useCallback(
774
1227
  async (reason) => {
775
1228
  const ownedTargetKey = targetKey;
@@ -780,10 +1233,18 @@ function useComposer(sessionId, options = {}) {
780
1233
  setPausing(true);
781
1234
  setError(null);
782
1235
  try {
783
- await client.pauseSession(workspaceId, sessionId, {
1236
+ const result = await client.pauseSession(workspaceId, sessionId, {
784
1237
  ...reason !== void 0 ? { reason } : {},
785
1238
  ...options.effectiveControl?.controlEtag ? { expectedControlEtag: options.effectiveControl.controlEtag } : {}
786
1239
  });
1240
+ 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
+ );
1247
+ }
787
1248
  } catch (cause) {
788
1249
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
789
1250
  setError(cause instanceof Error ? cause : new Error(String(cause)));
@@ -880,13 +1341,82 @@ function useComposer(sessionId, options = {}) {
880
1341
  resources: mergeResources(
881
1342
  restoredResourcesRef.current,
882
1343
  resolveSendExtras(sendExtrasRef.current).resources ?? []
883
- )
1344
+ ),
1345
+ annotations: annotationsRef.current
884
1346
  }
885
1347
  );
1348
+ setOptimisticDraftShadow({
1349
+ text: next,
1350
+ resources: mergeResources(
1351
+ restoredResourcesRef.current,
1352
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
1353
+ ),
1354
+ annotations: annotationsRef.current
1355
+ });
886
1356
  setValue(next);
887
1357
  },
888
- [pendingOperationKey, targetKey]
1358
+ [pendingOperationKey, setOptimisticDraftShadow, targetKey]
889
1359
  );
1360
+ const updateAnnotations = useCallback(
1361
+ (next, reviewTargetId = null) => {
1362
+ if (targetKeyRef.current !== targetKey) return;
1363
+ localEditRevision.current += 1;
1364
+ annotationsRef.current = next;
1365
+ pendingOperationRef.current = updatePendingComposerShadow(
1366
+ pendingOperationKey,
1367
+ pendingOperationRef.current,
1368
+ {
1369
+ text: valueRef.current,
1370
+ resources: mergeResources(
1371
+ restoredResourcesRef.current,
1372
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
1373
+ ),
1374
+ annotations: next
1375
+ }
1376
+ );
1377
+ setOptimisticDraftShadow({
1378
+ text: valueRef.current,
1379
+ resources: mergeResources(
1380
+ restoredResourcesRef.current,
1381
+ resolveSendExtras(sendExtrasRef.current).resources ?? []
1382
+ ),
1383
+ annotations: next
1384
+ });
1385
+ setAnnotations(next);
1386
+ setAnnotationReviewTargetId(reviewTargetId);
1387
+ },
1388
+ [pendingOperationKey, setOptimisticDraftShadow, targetKey]
1389
+ );
1390
+ const addAnnotation = useCallback(
1391
+ (annotation) => {
1392
+ if (annotationsRef.current.length >= 12) {
1393
+ setError(new Error("A message can include at most 12 timeline annotations."));
1394
+ return;
1395
+ }
1396
+ const next = [...annotationsRef.current, annotation];
1397
+ updateAnnotations(next, annotation.id);
1398
+ },
1399
+ [updateAnnotations]
1400
+ );
1401
+ const updateAnnotation = useCallback(
1402
+ (id, note) => {
1403
+ updateAnnotations(
1404
+ annotationsRef.current.map(
1405
+ (annotation) => annotation.id === id ? { ...annotation, note } : annotation
1406
+ )
1407
+ );
1408
+ },
1409
+ [updateAnnotations]
1410
+ );
1411
+ const removeAnnotation = useCallback(
1412
+ (id) => {
1413
+ updateAnnotations(annotationsRef.current.filter((annotation) => annotation.id !== id));
1414
+ },
1415
+ [updateAnnotations]
1416
+ );
1417
+ const clearAnnotationReviewTarget = useCallback(() => {
1418
+ setAnnotationReviewTargetId(null);
1419
+ }, []);
890
1420
  const removeRestoredResource = useCallback(
891
1421
  (index) => {
892
1422
  if (targetKeyRef.current !== targetKey) return;
@@ -898,17 +1428,23 @@ function useComposer(sessionId, options = {}) {
898
1428
  pendingOperationRef.current,
899
1429
  {
900
1430
  text: valueRef.current,
901
- resources: mergeResources(next, resolveSendExtras(sendExtrasRef.current).resources ?? [])
1431
+ resources: mergeResources(next, resolveSendExtras(sendExtrasRef.current).resources ?? []),
1432
+ annotations: annotationsRef.current
902
1433
  }
903
1434
  );
1435
+ setOptimisticDraftShadow({
1436
+ text: valueRef.current,
1437
+ resources: mergeResources(next, resolveSendExtras(sendExtrasRef.current).resources ?? []),
1438
+ annotations: annotationsRef.current
1439
+ });
904
1440
  setRestoredResources(next);
905
1441
  },
906
- [pendingOperationKey, targetKey]
1442
+ [pendingOperationKey, setOptimisticDraftShadow, targetKey]
907
1443
  );
908
1444
  const hasDraftContent = useCallback(() => {
909
1445
  const current = draftRef.current;
910
1446
  const extras = resolveSendExtras(sendExtrasRef.current);
911
- return valueRef.current.length > 0 || restoredResourcesRef.current.length > 0 || (extras.resources?.length ?? 0) > 0 || current?.sourceTurnId !== null && current?.sourceTurnId !== void 0;
1447
+ 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;
912
1448
  }, []);
913
1449
  const resolveDraftConflict = useCallback(
914
1450
  async (choice) => {
@@ -943,6 +1479,7 @@ function useComposer(sessionId, options = {}) {
943
1479
  ]
944
1480
  );
945
1481
  const identityMatches = stateTargetKey === targetKey;
1482
+ const visibleSteering = identityMatches ? steering : null;
946
1483
  const reloadDraft = useCallback(async () => await loadDraft(true), [loadDraft]);
947
1484
  const clearError = useCallback(() => {
948
1485
  if (targetKeyRef.current !== targetKey) return;
@@ -952,12 +1489,24 @@ function useComposer(sessionId, options = {}) {
952
1489
  return {
953
1490
  value: identityMatches ? value : "",
954
1491
  setValue: updateValue,
1492
+ annotations: identityMatches ? annotations : [],
1493
+ addAnnotation,
1494
+ updateAnnotation,
1495
+ removeAnnotation,
1496
+ annotationReviewTargetId: identityMatches ? annotationReviewTargetId : null,
1497
+ clearAnnotationReviewTarget,
955
1498
  hasDraftContent,
956
1499
  send,
1500
+ optimisticMessages: identityMatches ? optimisticSends.map(
1501
+ ({ input: _input, draftPayload: _payload, canRetry: _retry, ...item }) => item
1502
+ ) : [],
1503
+ retryOptimisticMessage,
1504
+ removeOptimisticMessage,
957
1505
  steer,
958
- steering: identityMatches ? steering : null,
1506
+ steering: visibleSteering,
1507
+ stoppingAttempt: identityMatches ? controlStopping ? "current" : visibleSteering?.phase === "accepted" && visibleSteering.stoppingPreviousAttempt === true ? "previous" : null : null,
959
1508
  sending: identityMatches ? sending : false,
960
- canSend: identityMatches && Boolean(sessionId) && !sending && sendBlockedRef.current?.() !== true && (hasPendingOperation || value.trim().length > 0 || hasReadyResources),
1509
+ canSend: identityMatches && Boolean(sessionId) && !sending && sendBlockedRef.current?.() !== true && annotationsComplete && (hasPendingOperation || value.trim().length > 0 || hasReadyResources || annotations.length > 0),
961
1510
  pause,
962
1511
  pausing: identityMatches ? pausing : false,
963
1512
  resume,
@@ -981,7 +1530,7 @@ function useComposer(sessionId, options = {}) {
981
1530
  function isComposerDraftEvent(event) {
982
1531
  return event.type === "user.message" || event.type === "session.queue.changed";
983
1532
  }
984
- var FILE_ONLY_MESSAGE_TEXT = "(see attached files)";
1533
+ var FILE_ONLY_MESSAGE_TEXT = "(see attached context)";
985
1534
  function resolveSendExtras(extras) {
986
1535
  return (typeof extras === "function" ? extras() : extras) ?? {};
987
1536
  }
@@ -1034,16 +1583,18 @@ function draftPayload(draft) {
1034
1583
  expectedRevision: draft.revision,
1035
1584
  text: draft.text,
1036
1585
  resources: draft.resources,
1586
+ annotations: draft.annotations ?? [],
1037
1587
  model: draft.model,
1038
1588
  reasoningEffort: draft.reasoningEffort,
1039
1589
  latencyMode: draft.latencyMode ?? "standard"
1040
1590
  };
1041
1591
  }
1042
- function composerDraftPayload(base, text, restoredResources, extras) {
1592
+ function composerDraftPayload(base, text, restoredResources, annotations, extras) {
1043
1593
  return {
1044
1594
  expectedRevision: base.revision,
1045
1595
  text,
1046
1596
  resources: mergeResources(restoredResources, extras.resources ?? []),
1597
+ annotations,
1047
1598
  model: extras.model ?? base.model,
1048
1599
  reasoningEffort: extras.reasoningEffort ?? base.reasoningEffort,
1049
1600
  latencyMode: extras.latencyMode ?? base.latencyMode ?? "standard"
@@ -1070,4 +1621,4 @@ export {
1070
1621
  shouldSubmitOnKey,
1071
1622
  shouldSteerOnKey
1072
1623
  };
1073
- //# sourceMappingURL=chunk-FWXGSNXT.js.map
1624
+ //# sourceMappingURL=chunk-IGC6A2ZI.js.map