@athenaintel/react 0.43.0 → 0.50.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 (746) hide show
  1. package/README.md +258 -8
  2. package/dist/agent-runtime/src/answer-label.cjs +137 -0
  3. package/dist/agent-runtime/src/answer-label.cjs.map +1 -0
  4. package/dist/agent-runtime/src/answer-label.d.ts +104 -0
  5. package/dist/agent-runtime/src/answer-label.js +137 -0
  6. package/dist/agent-runtime/src/answer-label.js.map +1 -0
  7. package/dist/agent-runtime/src/answer-rows.cjs +180 -0
  8. package/dist/agent-runtime/src/answer-rows.cjs.map +1 -0
  9. package/dist/agent-runtime/src/answer-rows.d.ts +86 -0
  10. package/dist/agent-runtime/src/answer-rows.js +180 -0
  11. package/dist/agent-runtime/src/answer-rows.js.map +1 -0
  12. package/dist/agent-runtime/src/call-recap.cjs +319 -0
  13. package/dist/agent-runtime/src/call-recap.cjs.map +1 -0
  14. package/dist/agent-runtime/src/call-recap.d.ts +142 -0
  15. package/dist/agent-runtime/src/call-recap.js +319 -0
  16. package/dist/agent-runtime/src/call-recap.js.map +1 -0
  17. package/dist/agent-runtime/src/chat-outbox-store.cjs +1 -0
  18. package/dist/agent-runtime/src/chat-outbox-store.cjs.map +1 -1
  19. package/dist/agent-runtime/src/chat-outbox-store.d.ts +7 -0
  20. package/dist/agent-runtime/src/chat-outbox-store.js +1 -0
  21. package/dist/agent-runtime/src/chat-outbox-store.js.map +1 -1
  22. package/dist/agent-runtime/src/chat-outbox.cjs +46 -5
  23. package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -1
  24. package/dist/agent-runtime/src/chat-outbox.d.ts +29 -0
  25. package/dist/agent-runtime/src/chat-outbox.js +46 -5
  26. package/dist/agent-runtime/src/chat-outbox.js.map +1 -1
  27. package/dist/agent-runtime/src/client-tool-bridge.cjs +15 -15
  28. package/dist/agent-runtime/src/client-tool-bridge.cjs.map +1 -1
  29. package/dist/agent-runtime/src/conversation-index.cjs +8 -8
  30. package/dist/agent-runtime/src/conversation-index.cjs.map +1 -1
  31. package/dist/agent-runtime/src/conversation-index.d.ts +7 -0
  32. package/dist/agent-runtime/src/conversation-index.js.map +1 -1
  33. package/dist/agent-runtime/src/conversation-list.cjs +2 -1
  34. package/dist/agent-runtime/src/conversation-list.cjs.map +1 -1
  35. package/dist/agent-runtime/src/conversation-list.d.ts +19 -3
  36. package/dist/agent-runtime/src/conversation-list.js +2 -1
  37. package/dist/agent-runtime/src/conversation-list.js.map +1 -1
  38. package/dist/agent-runtime/src/decision-checks.cjs +207 -0
  39. package/dist/agent-runtime/src/decision-checks.cjs.map +1 -0
  40. package/dist/agent-runtime/src/decision-checks.d.ts +142 -0
  41. package/dist/agent-runtime/src/decision-checks.js +207 -0
  42. package/dist/agent-runtime/src/decision-checks.js.map +1 -0
  43. package/dist/agent-runtime/src/desktop-handoff.d.ts +12 -0
  44. package/dist/agent-runtime/src/errors.cjs +18 -0
  45. package/dist/agent-runtime/src/errors.cjs.map +1 -1
  46. package/dist/agent-runtime/src/errors.d.ts +7 -0
  47. package/dist/agent-runtime/src/errors.js +18 -0
  48. package/dist/agent-runtime/src/errors.js.map +1 -1
  49. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +12 -0
  50. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  51. package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +6 -6
  52. package/dist/agent-runtime/src/generated/runconfig-contract.js +12 -0
  53. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  54. package/dist/agent-runtime/src/handoff-arrival.cjs +60 -0
  55. package/dist/agent-runtime/src/handoff-arrival.cjs.map +1 -0
  56. package/dist/agent-runtime/src/handoff-arrival.d.ts +46 -0
  57. package/dist/agent-runtime/src/handoff-arrival.js +60 -0
  58. package/dist/agent-runtime/src/handoff-arrival.js.map +1 -0
  59. package/dist/agent-runtime/src/index.d.ts +16 -9
  60. package/dist/agent-runtime/src/interrupts.cjs +71 -19
  61. package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
  62. package/dist/agent-runtime/src/interrupts.d.ts +40 -3
  63. package/dist/agent-runtime/src/interrupts.js +56 -4
  64. package/dist/agent-runtime/src/interrupts.js.map +1 -1
  65. package/dist/agent-runtime/src/lane-history.cjs +8 -8
  66. package/dist/agent-runtime/src/lane-history.cjs.map +1 -1
  67. package/dist/agent-runtime/src/messages.cjs +43 -8
  68. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  69. package/dist/agent-runtime/src/messages.d.ts +25 -3
  70. package/dist/agent-runtime/src/messages.js +43 -8
  71. package/dist/agent-runtime/src/messages.js.map +1 -1
  72. package/dist/agent-runtime/src/model-context.cjs +3 -2
  73. package/dist/agent-runtime/src/model-context.cjs.map +1 -1
  74. package/dist/agent-runtime/src/model-context.d.ts +6 -1
  75. package/dist/agent-runtime/src/model-context.js +3 -2
  76. package/dist/agent-runtime/src/model-context.js.map +1 -1
  77. package/dist/agent-runtime/src/offline-status.cjs +36 -0
  78. package/dist/agent-runtime/src/offline-status.cjs.map +1 -0
  79. package/dist/agent-runtime/src/offline-status.d.ts +118 -3
  80. package/dist/agent-runtime/src/offline-status.js +36 -0
  81. package/dist/agent-runtime/src/offline-status.js.map +1 -0
  82. package/dist/agent-runtime/src/queue.cjs +0 -9
  83. package/dist/agent-runtime/src/queue.cjs.map +1 -1
  84. package/dist/agent-runtime/src/queue.js +0 -9
  85. package/dist/agent-runtime/src/queue.js.map +1 -1
  86. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +9 -9
  87. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  88. package/dist/agent-runtime/src/runtime-catalog.cjs +42 -0
  89. package/dist/agent-runtime/src/runtime-catalog.cjs.map +1 -0
  90. package/dist/agent-runtime/src/runtime-catalog.d.ts +35 -0
  91. package/dist/agent-runtime/src/runtime-catalog.js +42 -0
  92. package/dist/agent-runtime/src/runtime-catalog.js.map +1 -0
  93. package/dist/agent-runtime/src/runtime-messages.cjs.map +1 -1
  94. package/dist/agent-runtime/src/runtime-messages.d.ts +1 -1
  95. package/dist/agent-runtime/src/runtime-messages.js.map +1 -1
  96. package/dist/agent-runtime/src/runtime.d.ts +41 -0
  97. package/dist/agent-runtime/src/send-recovery.cjs +37 -3
  98. package/dist/agent-runtime/src/send-recovery.cjs.map +1 -1
  99. package/dist/agent-runtime/src/send-recovery.d.ts +19 -0
  100. package/dist/agent-runtime/src/send-recovery.js +37 -3
  101. package/dist/agent-runtime/src/send-recovery.js.map +1 -1
  102. package/dist/agent-runtime/src/statewire-suspended.cjs +3 -3
  103. package/dist/agent-runtime/src/statewire-suspended.cjs.map +1 -1
  104. package/dist/agent-runtime/src/subagents.cjs +32 -2
  105. package/dist/agent-runtime/src/subagents.cjs.map +1 -1
  106. package/dist/agent-runtime/src/subagents.d.ts +9 -0
  107. package/dist/agent-runtime/src/subagents.js +30 -0
  108. package/dist/agent-runtime/src/subagents.js.map +1 -1
  109. package/dist/agent-runtime/src/thread-driver.cjs +67 -0
  110. package/dist/agent-runtime/src/thread-driver.cjs.map +1 -0
  111. package/dist/agent-runtime/src/thread-driver.d.ts +49 -0
  112. package/dist/agent-runtime/src/thread-driver.js +67 -0
  113. package/dist/agent-runtime/src/thread-driver.js.map +1 -0
  114. package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +172 -0
  115. package/dist/agent-runtime/src/thread-handoff-protocol.d.ts +868 -0
  116. package/dist/agent-runtime/src/thread-handoff-qr.d.ts +11 -0
  117. package/dist/agent-runtime/src/thread-handoff.d.ts +3 -364
  118. package/dist/agent-runtime/src/thread-status.cjs +3 -3
  119. package/dist/agent-runtime/src/thread-status.cjs.map +1 -1
  120. package/dist/agent-runtime/src/tool-metadata.cjs +210 -25
  121. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  122. package/dist/agent-runtime/src/tool-metadata.d.ts +12 -0
  123. package/dist/agent-runtime/src/tool-metadata.js +210 -25
  124. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  125. package/dist/agent-runtime/src/tool-names.cjs +2 -0
  126. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  127. package/dist/agent-runtime/src/tool-names.d.ts +2 -0
  128. package/dist/agent-runtime/src/tool-names.js +2 -0
  129. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  130. package/dist/agent-runtime/src/types.d.ts +10 -2
  131. package/dist/agent-runtime/src/use-conversation-list.cjs +14 -13
  132. package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
  133. package/dist/agent-runtime/src/use-conversation-list.d.ts +6 -0
  134. package/dist/agent-runtime/src/use-conversation-list.js +3 -2
  135. package/dist/agent-runtime/src/use-conversation-list.js.map +1 -1
  136. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +45 -20
  137. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -1
  138. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +10 -3
  139. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +27 -2
  140. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
  141. package/dist/agent-runtime/src/use-deep-agent-config.cjs +14 -14
  142. package/dist/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
  143. package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs +6 -6
  144. package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
  145. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +40 -22
  146. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  147. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +17 -0
  148. package/dist/agent-runtime/src/use-deep-agent-runtime.js +24 -6
  149. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  150. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +45 -45
  151. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  152. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +588 -130
  153. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
  154. package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +162 -10
  155. package/dist/agent-runtime/src/use-deep-agent-voice.js +529 -71
  156. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
  157. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +26 -26
  158. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
  159. package/dist/agent-runtime/src/use-historical-edit-attachments.cjs +4 -4
  160. package/dist/agent-runtime/src/use-historical-edit-attachments.cjs.map +1 -1
  161. package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +34 -26
  162. package/dist/agent-runtime/src/voice-earcon.cjs +139 -0
  163. package/dist/agent-runtime/src/voice-earcon.cjs.map +1 -0
  164. package/dist/agent-runtime/src/voice-earcon.d.ts +38 -0
  165. package/dist/agent-runtime/src/voice-earcon.js +139 -0
  166. package/dist/agent-runtime/src/voice-earcon.js.map +1 -0
  167. package/dist/agent-runtime/src/voice-media.cjs +117 -0
  168. package/dist/agent-runtime/src/voice-media.cjs.map +1 -0
  169. package/dist/agent-runtime/src/voice-media.d.ts +63 -0
  170. package/dist/agent-runtime/src/voice-media.js +117 -0
  171. package/dist/agent-runtime/src/voice-media.js.map +1 -0
  172. package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
  173. package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
  174. package/dist/agent-runtime/src/voice-presentation.js +2 -0
  175. package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
  176. package/dist/agent-runtime/src/voice-wire-types.d.ts +32 -0
  177. package/dist/assets/AssetPanel.cjs +11 -11
  178. package/dist/assets/AssetPanel.cjs.map +1 -1
  179. package/dist/assets/AthenaAssetEmbed.cjs +11 -9
  180. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  181. package/dist/assets/AthenaAssetEmbed.d.ts +18 -5
  182. package/dist/assets/AthenaAssetEmbed.js +4 -2
  183. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  184. package/dist/assets/AthenaLayout.cjs +16 -16
  185. package/dist/assets/AthenaLayout.cjs.map +1 -1
  186. package/dist/assets/use-asset-content.cjs +4 -4
  187. package/dist/assets/use-asset-content.cjs.map +1 -1
  188. package/dist/assets/use-asset-embed.cjs +14 -7
  189. package/dist/assets/use-asset-embed.cjs.map +1 -1
  190. package/dist/assets/use-asset-embed.d.ts +23 -6
  191. package/dist/assets/use-asset-embed.js +10 -3
  192. package/dist/assets/use-asset-embed.js.map +1 -1
  193. package/dist/auth/AthenaAuthContext.cjs +3 -3
  194. package/dist/auth/AthenaAuthContext.cjs.map +1 -1
  195. package/dist/auth/AthenaAuthProvider.cjs +8 -8
  196. package/dist/auth/AthenaAuthProvider.cjs.map +1 -1
  197. package/dist/auth/AthenaCredentialSourceContext.cjs +5 -5
  198. package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
  199. package/dist/auth/AthenaSSOProvider.cjs +14 -14
  200. package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
  201. package/dist/auth/credential-source.cjs +26 -13
  202. package/dist/auth/credential-source.cjs.map +1 -1
  203. package/dist/auth/credential-source.d.ts +8 -0
  204. package/dist/auth/credential-source.js +26 -13
  205. package/dist/auth/credential-source.js.map +1 -1
  206. package/dist/catalog/agent-model-options.cjs +25 -17
  207. package/dist/catalog/agent-model-options.cjs.map +1 -1
  208. package/dist/catalog/agent-model-options.d.ts +38 -5
  209. package/dist/catalog/agent-model-options.js +25 -17
  210. package/dist/catalog/agent-model-options.js.map +1 -1
  211. package/dist/catalog/channel-refusal.cjs +36 -0
  212. package/dist/catalog/channel-refusal.cjs.map +1 -0
  213. package/dist/catalog/channel-refusal.d.ts +29 -0
  214. package/dist/catalog/channel-refusal.js +36 -0
  215. package/dist/catalog/channel-refusal.js.map +1 -0
  216. package/dist/catalog/chat-pickers.cjs +60 -24
  217. package/dist/catalog/chat-pickers.cjs.map +1 -1
  218. package/dist/catalog/chat-pickers.d.ts +12 -2
  219. package/dist/catalog/chat-pickers.js +56 -20
  220. package/dist/catalog/chat-pickers.js.map +1 -1
  221. package/dist/catalog/runtime-catalog.cjs +89 -23
  222. package/dist/catalog/runtime-catalog.cjs.map +1 -1
  223. package/dist/catalog/runtime-catalog.d.ts +8 -2
  224. package/dist/catalog/runtime-catalog.js +83 -17
  225. package/dist/catalog/runtime-catalog.js.map +1 -1
  226. package/dist/catalog/use-athena-chat-mode.cjs +12 -12
  227. package/dist/catalog/use-athena-chat-mode.cjs.map +1 -1
  228. package/dist/chat/AthenaChat.cjs +155 -67
  229. package/dist/chat/AthenaChat.cjs.map +1 -1
  230. package/dist/chat/AthenaChat.d.ts +42 -2
  231. package/dist/chat/AthenaChat.js +106 -18
  232. package/dist/chat/AthenaChat.js.map +1 -1
  233. package/dist/chat/AthenaChatErrorBoundary.cjs +3 -3
  234. package/dist/chat/AthenaChatErrorBoundary.cjs.map +1 -1
  235. package/dist/chat/DrivingOnChip.cjs +23 -0
  236. package/dist/chat/DrivingOnChip.cjs.map +1 -0
  237. package/dist/chat/DrivingOnChip.d.ts +17 -0
  238. package/dist/chat/DrivingOnChip.js +23 -0
  239. package/dist/chat/DrivingOnChip.js.map +1 -0
  240. package/dist/chat/StatewireApprovalCard.cjs +166 -37
  241. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  242. package/dist/chat/StatewireApprovalCard.d.ts +91 -2
  243. package/dist/chat/StatewireApprovalCard.js +156 -27
  244. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  245. package/dist/chat/StatewireClientToolBridge.cjs +2 -2
  246. package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
  247. package/dist/chat/StatewireQueuedMessages.cjs +81 -69
  248. package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
  249. package/dist/chat/StatewireQueuedMessages.d.ts +25 -13
  250. package/dist/chat/StatewireQueuedMessages.js +73 -61
  251. package/dist/chat/StatewireQueuedMessages.js.map +1 -1
  252. package/dist/chat/WaitingOnYouBanner.cjs +9 -5
  253. package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
  254. package/dist/chat/WaitingOnYouBanner.js +7 -3
  255. package/dist/chat/WaitingOnYouBanner.js.map +1 -1
  256. package/dist/chat/athena-chat-welcome.cjs +2 -2
  257. package/dist/chat/athena-chat-welcome.cjs.map +1 -1
  258. package/dist/chat/athena-citation-links.cjs +5 -5
  259. package/dist/chat/athena-citation-links.cjs.map +1 -1
  260. package/dist/chat/athena-composer-controls.cjs +26 -16
  261. package/dist/chat/athena-composer-controls.cjs.map +1 -1
  262. package/dist/chat/athena-composer-controls.d.ts +6 -0
  263. package/dist/chat/athena-composer-controls.js +26 -16
  264. package/dist/chat/athena-composer-controls.js.map +1 -1
  265. package/dist/chat/athena-turn-end-status.cjs +42 -0
  266. package/dist/chat/athena-turn-end-status.cjs.map +1 -0
  267. package/dist/chat/athena-turn-end-status.d.ts +24 -0
  268. package/dist/chat/athena-turn-end-status.js +42 -0
  269. package/dist/chat/athena-turn-end-status.js.map +1 -0
  270. package/dist/chat/browser-decision-check.cjs +131 -0
  271. package/dist/chat/browser-decision-check.cjs.map +1 -0
  272. package/dist/chat/browser-decision-check.d.ts +61 -0
  273. package/dist/chat/browser-decision-check.js +131 -0
  274. package/dist/chat/browser-decision-check.js.map +1 -0
  275. package/dist/chat/chat-outbox-rows.cjs +3 -3
  276. package/dist/chat/chat-outbox-rows.cjs.map +1 -1
  277. package/dist/chat/chat-voice-controls.cjs +96 -29
  278. package/dist/chat/chat-voice-controls.cjs.map +1 -1
  279. package/dist/chat/chat-voice-controls.d.ts +42 -3
  280. package/dist/chat/chat-voice-controls.js +92 -25
  281. package/dist/chat/chat-voice-controls.js.map +1 -1
  282. package/dist/chat/composer-keyboard-hint.cjs +5 -5
  283. package/dist/chat/composer-keyboard-hint.cjs.map +1 -1
  284. package/dist/chat/device-operation.cjs +29 -0
  285. package/dist/chat/device-operation.cjs.map +1 -0
  286. package/dist/chat/device-operation.d.ts +34 -0
  287. package/dist/chat/device-operation.js +29 -0
  288. package/dist/chat/device-operation.js.map +1 -0
  289. package/dist/chat/super-grouping/CollapsibleGroup.cjs +14 -14
  290. package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
  291. package/dist/chat/super-grouping/GroupedMessageParts.cjs +4 -4
  292. package/dist/chat/super-grouping/GroupedMessageParts.cjs.map +1 -1
  293. package/dist/chat/super-grouping/SuperGroupingCard.cjs +52 -36
  294. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  295. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +19 -4
  296. package/dist/chat/super-grouping/SuperGroupingCard.js +29 -13
  297. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  298. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +32 -32
  299. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
  300. package/dist/chat/super-grouping/SuperGroupingTranscript.js +3 -3
  301. package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
  302. package/dist/chat/super-grouping/ToolTimeline.cjs +73 -40
  303. package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
  304. package/dist/chat/super-grouping/ToolTimeline.d.ts +10 -2
  305. package/dist/chat/super-grouping/ToolTimeline.js +69 -36
  306. package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
  307. package/dist/chat/super-grouping/activity-timeline.cjs +47 -12
  308. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  309. package/dist/chat/super-grouping/activity-timeline.d.ts +21 -0
  310. package/dist/chat/super-grouping/activity-timeline.js +47 -12
  311. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  312. package/dist/chat/super-grouping/grouping-function.cjs +4 -0
  313. package/dist/chat/super-grouping/grouping-function.cjs.map +1 -1
  314. package/dist/chat/super-grouping/grouping-function.d.ts +7 -0
  315. package/dist/chat/super-grouping/grouping-function.js +5 -1
  316. package/dist/chat/super-grouping/grouping-function.js.map +1 -1
  317. package/dist/chat/super-grouping/index.cjs +6 -0
  318. package/dist/chat/super-grouping/index.cjs.map +1 -1
  319. package/dist/chat/super-grouping/index.d.ts +5 -2
  320. package/dist/chat/super-grouping/index.js +7 -1
  321. package/dist/chat/super-grouping/index.js.map +1 -1
  322. package/dist/chat/super-grouping/tool-part-placement.cjs +17 -0
  323. package/dist/chat/super-grouping/tool-part-placement.cjs.map +1 -0
  324. package/dist/chat/super-grouping/tool-part-placement.d.ts +22 -0
  325. package/dist/chat/super-grouping/tool-part-placement.js +17 -0
  326. package/dist/chat/super-grouping/tool-part-placement.js.map +1 -0
  327. package/dist/chat/thread-scroll-to-bottom.cjs +2 -2
  328. package/dist/chat/thread-scroll-to-bottom.cjs.map +1 -1
  329. package/dist/chat/thread-scroll-to-bottom.d.ts +10 -7
  330. package/dist/chat/thread-scroll-to-bottom.js +2 -2
  331. package/dist/chat/thread-scroll-to-bottom.js.map +1 -1
  332. package/dist/chat/tooltip-icon-button.cjs +2 -2
  333. package/dist/chat/tooltip-icon-button.cjs.map +1 -1
  334. package/dist/chat/use-athena-voice-live.cjs +11 -0
  335. package/dist/chat/use-athena-voice-live.cjs.map +1 -0
  336. package/dist/chat/use-athena-voice-live.d.ts +11 -0
  337. package/dist/chat/use-athena-voice-live.js +11 -0
  338. package/dist/chat/use-athena-voice-live.js.map +1 -0
  339. package/dist/chat/use-statewire-approval-request.cjs +56 -24
  340. package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
  341. package/dist/chat/use-statewire-approval-request.d.ts +33 -4
  342. package/dist/chat/use-statewire-approval-request.js +41 -9
  343. package/dist/chat/use-statewire-approval-request.js.map +1 -1
  344. package/dist/chat-ui/auth/sign-in-card.cjs +2 -2
  345. package/dist/chat-ui/auth/sign-in-card.cjs.map +1 -1
  346. package/dist/chat-ui/composer/tiptap-composer.cjs +138 -107
  347. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  348. package/dist/chat-ui/composer/tiptap-composer.d.ts +20 -4
  349. package/dist/chat-ui/composer/tiptap-composer.js +85 -54
  350. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  351. package/dist/chat-ui/header/conversation-history-panel.cjs +49 -23
  352. package/dist/chat-ui/header/conversation-history-panel.cjs.map +1 -1
  353. package/dist/chat-ui/header/conversation-history-panel.d.ts +12 -1
  354. package/dist/chat-ui/header/conversation-history-panel.js +38 -12
  355. package/dist/chat-ui/header/conversation-history-panel.js.map +1 -1
  356. package/dist/chat-ui/index.cjs +21 -0
  357. package/dist/chat-ui/index.cjs.map +1 -1
  358. package/dist/chat-ui/index.d.ts +8 -1
  359. package/dist/chat-ui/index.js +21 -0
  360. package/dist/chat-ui/index.js.map +1 -1
  361. package/dist/chat-ui/mentions/mention-chip.cjs +4 -4
  362. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  363. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs +10 -9
  364. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs.map +1 -1
  365. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js +3 -2
  366. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js.map +1 -1
  367. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs +2 -2
  368. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs.map +1 -1
  369. package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs +29 -6
  370. package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs.map +1 -1
  371. package/dist/chat-ui/mentions/suggestions/components/menu-list.d.ts +7 -1
  372. package/dist/chat-ui/mentions/suggestions/components/menu-list.js +25 -2
  373. package/dist/chat-ui/mentions/suggestions/components/menu-list.js.map +1 -1
  374. package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs +2 -2
  375. package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs.map +1 -1
  376. package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs +2 -2
  377. package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs.map +1 -1
  378. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +3 -3
  379. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  380. package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs +56 -2
  381. package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs.map +1 -1
  382. package/dist/chat-ui/mentions/suggestions/data/orchestrator.d.ts +12 -0
  383. package/dist/chat-ui/mentions/suggestions/data/orchestrator.js +56 -2
  384. package/dist/chat-ui/mentions/suggestions/data/orchestrator.js.map +1 -1
  385. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +24 -3
  386. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  387. package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +7 -0
  388. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +24 -3
  389. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  390. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +35 -13
  391. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs.map +1 -1
  392. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.d.ts +15 -1
  393. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +28 -6
  394. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
  395. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs +9 -6
  396. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs.map +1 -1
  397. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.d.ts +3 -0
  398. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js +5 -2
  399. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js.map +1 -1
  400. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +45 -10
  401. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
  402. package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +24 -1
  403. package/dist/chat-ui/mentions/use-account-workspace-id.js +46 -11
  404. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
  405. package/dist/chat-ui/mentions/use-member-avatar.cjs +4 -4
  406. package/dist/chat-ui/mentions/use-member-avatar.cjs.map +1 -1
  407. package/dist/chat-ui/mentions/use-mention-asset.cjs +3 -3
  408. package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -1
  409. package/dist/chat-ui/messages/answer-label.cjs +42 -0
  410. package/dist/chat-ui/messages/answer-label.cjs.map +1 -0
  411. package/dist/chat-ui/messages/answer-label.d.ts +33 -0
  412. package/dist/chat-ui/messages/answer-label.js +42 -0
  413. package/dist/chat-ui/messages/answer-label.js.map +1 -0
  414. package/dist/chat-ui/messages/arrival-animation.cjs +13 -0
  415. package/dist/chat-ui/messages/arrival-animation.cjs.map +1 -0
  416. package/dist/chat-ui/messages/arrival-animation.d.ts +14 -0
  417. package/dist/chat-ui/messages/arrival-animation.js +13 -0
  418. package/dist/chat-ui/messages/arrival-animation.js.map +1 -0
  419. package/dist/chat-ui/messages/continue-pill.cjs +5 -5
  420. package/dist/chat-ui/messages/continue-pill.cjs.map +1 -1
  421. package/dist/chat-ui/messages/from-the-call-card.cjs +124 -0
  422. package/dist/chat-ui/messages/from-the-call-card.cjs.map +1 -0
  423. package/dist/chat-ui/messages/from-the-call-card.d.ts +17 -0
  424. package/dist/chat-ui/messages/from-the-call-card.js +124 -0
  425. package/dist/chat-ui/messages/from-the-call-card.js.map +1 -0
  426. package/dist/chat-ui/messages/handoff-arrival-divider.cjs +44 -0
  427. package/dist/chat-ui/messages/handoff-arrival-divider.cjs.map +1 -0
  428. package/dist/chat-ui/messages/handoff-arrival-divider.d.ts +17 -0
  429. package/dist/chat-ui/messages/handoff-arrival-divider.js +44 -0
  430. package/dist/chat-ui/messages/handoff-arrival-divider.js.map +1 -0
  431. package/dist/chat-ui/messages/message-actions-config.cjs +3 -3
  432. package/dist/chat-ui/messages/message-actions-config.cjs.map +1 -1
  433. package/dist/chat-ui/messages/message-components.cjs +8 -4
  434. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  435. package/dist/chat-ui/messages/message-components.js +5 -1
  436. package/dist/chat-ui/messages/message-components.js.map +1 -1
  437. package/dist/chat-ui/messages/message-images.cjs +66 -0
  438. package/dist/chat-ui/messages/message-images.cjs.map +1 -0
  439. package/dist/chat-ui/messages/message-images.d.ts +16 -0
  440. package/dist/chat-ui/messages/message-images.js +66 -0
  441. package/dist/chat-ui/messages/message-images.js.map +1 -0
  442. package/dist/chat-ui/messages/user-edit-composer.cjs +2 -2
  443. package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
  444. package/dist/chat-ui/messages/wake-marker.cjs +3 -3
  445. package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
  446. package/dist/chat-ui/rich-text/chat-link.cjs +3 -2
  447. package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
  448. package/dist/chat-ui/rich-text/chat-link.d.ts +4 -0
  449. package/dist/chat-ui/rich-text/chat-link.js +4 -3
  450. package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
  451. package/dist/chat-ui/rich-text/chat-message-body.cjs +9 -8
  452. package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
  453. package/dist/chat-ui/rich-text/chat-message-body.d.ts +12 -0
  454. package/dist/chat-ui/rich-text/chat-message-body.js +2 -1
  455. package/dist/chat-ui/rich-text/chat-message-body.js.map +1 -1
  456. package/dist/chat-ui/rich-text/chat-node-views.cjs +6 -6
  457. package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
  458. package/dist/chat-ui/rich-text/dom-output-spec.cjs +2 -2
  459. package/dist/chat-ui/rich-text/dom-output-spec.cjs.map +1 -1
  460. package/dist/chat-ui/statewire.cjs +3 -0
  461. package/dist/chat-ui/statewire.cjs.map +1 -1
  462. package/dist/chat-ui/statewire.d.ts +2 -1
  463. package/dist/chat-ui/statewire.js +3 -0
  464. package/dist/chat-ui/statewire.js.map +1 -1
  465. package/dist/chat-ui/thread/chat-thread-shell.cjs +45 -14
  466. package/dist/chat-ui/thread/chat-thread-shell.cjs.map +1 -1
  467. package/dist/chat-ui/thread/chat-thread-shell.d.ts +16 -2
  468. package/dist/chat-ui/thread/chat-thread-shell.js +37 -6
  469. package/dist/chat-ui/thread/chat-thread-shell.js.map +1 -1
  470. package/dist/chat-ui/thread/composer-send-or-stop.cjs +30 -20
  471. package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
  472. package/dist/chat-ui/thread/composer-send-or-stop.d.ts +8 -0
  473. package/dist/chat-ui/thread/composer-send-or-stop.js +29 -19
  474. package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
  475. package/dist/chat-ui/thread/statewire-history-edge.cjs +20 -21
  476. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  477. package/dist/chat-ui/thread/statewire-history-edge.js +3 -4
  478. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  479. package/dist/chat-ui/thread/thread-loading-overlay.cjs +5 -5
  480. package/dist/chat-ui/thread/thread-loading-overlay.cjs.map +1 -1
  481. package/dist/collab/client.cjs +52 -3
  482. package/dist/collab/client.cjs.map +1 -1
  483. package/dist/collab/client.d.ts +27 -0
  484. package/dist/collab/client.js +52 -3
  485. package/dist/collab/client.js.map +1 -1
  486. package/dist/collab/document-status.cjs +150 -0
  487. package/dist/collab/document-status.cjs.map +1 -0
  488. package/dist/collab/document-status.d.ts +68 -0
  489. package/dist/collab/document-status.js +150 -0
  490. package/dist/collab/document-status.js.map +1 -0
  491. package/dist/collab/index.cjs +7 -0
  492. package/dist/collab/index.cjs.map +1 -1
  493. package/dist/collab/index.d.ts +6 -1
  494. package/dist/collab/index.js +7 -0
  495. package/dist/collab/index.js.map +1 -1
  496. package/dist/collab/presence-react.cjs +11 -11
  497. package/dist/collab/presence-react.cjs.map +1 -1
  498. package/dist/collab/react.cjs +6 -6
  499. package/dist/collab/react.cjs.map +1 -1
  500. package/dist/composer/AttachmentContext.cjs +24 -11
  501. package/dist/composer/AttachmentContext.cjs.map +1 -1
  502. package/dist/composer/AttachmentContext.js +18 -5
  503. package/dist/composer/AttachmentContext.js.map +1 -1
  504. package/dist/composer/ComposerAttachmentPreview.cjs +78 -23
  505. package/dist/composer/ComposerAttachmentPreview.cjs.map +1 -1
  506. package/dist/composer/ComposerAttachmentPreview.d.ts +5 -3
  507. package/dist/composer/ComposerAttachmentPreview.js +79 -24
  508. package/dist/composer/ComposerAttachmentPreview.js.map +1 -1
  509. package/dist/composer/ComposerDropZone.cjs +7 -7
  510. package/dist/composer/ComposerDropZone.cjs.map +1 -1
  511. package/dist/composer/FileUploadButton.cjs +37 -22
  512. package/dist/composer/FileUploadButton.cjs.map +1 -1
  513. package/dist/composer/FileUploadButton.d.ts +6 -0
  514. package/dist/composer/FileUploadButton.js +34 -19
  515. package/dist/composer/FileUploadButton.js.map +1 -1
  516. package/dist/composer/QuoteContext.cjs +8 -8
  517. package/dist/composer/QuoteContext.cjs.map +1 -1
  518. package/dist/composer/composer-handoff.cjs +4 -4
  519. package/dist/composer/composer-handoff.cjs.map +1 -1
  520. package/dist/composer/index.d.ts +1 -1
  521. package/dist/composer/useAppendToComposer.cjs +4 -4
  522. package/dist/composer/useAppendToComposer.cjs.map +1 -1
  523. package/dist/composer/useAttachFiles.cjs +23 -6
  524. package/dist/composer/useAttachFiles.cjs.map +1 -1
  525. package/dist/composer/useAttachFiles.d.ts +15 -7
  526. package/dist/composer/useAttachFiles.js +22 -5
  527. package/dist/composer/useAttachFiles.js.map +1 -1
  528. package/dist/composer/useComposerAttachment.cjs +4 -4
  529. package/dist/composer/useComposerAttachment.cjs.map +1 -1
  530. package/dist/composer/useFileUpload.cjs +21 -16
  531. package/dist/composer/useFileUpload.cjs.map +1 -1
  532. package/dist/composer/useFileUpload.d.ts +12 -0
  533. package/dist/composer/useFileUpload.js +12 -7
  534. package/dist/composer/useFileUpload.js.map +1 -1
  535. package/dist/composer/useReadComposerDraft.cjs +27 -8
  536. package/dist/composer/useReadComposerDraft.cjs.map +1 -1
  537. package/dist/composer/useReadComposerDraft.d.ts +23 -1
  538. package/dist/composer/useReadComposerDraft.js +27 -8
  539. package/dist/composer/useReadComposerDraft.js.map +1 -1
  540. package/dist/composer/useSendMessage.cjs +4 -4
  541. package/dist/composer/useSendMessage.cjs.map +1 -1
  542. package/dist/diagnostics/useAthenaDiagnostics.cjs +4 -4
  543. package/dist/diagnostics/useAthenaDiagnostics.cjs.map +1 -1
  544. package/dist/dictation/audio-level-history.cjs +3 -3
  545. package/dist/dictation/audio-level-history.cjs.map +1 -1
  546. package/dist/dictation/dictation-controls.cjs +24 -20
  547. package/dist/dictation/dictation-controls.cjs.map +1 -1
  548. package/dist/dictation/dictation-controls.d.ts +6 -1
  549. package/dist/dictation/dictation-controls.js +24 -20
  550. package/dist/dictation/dictation-controls.js.map +1 -1
  551. package/dist/dictation/use-athena-dictation-engine.cjs +3 -3
  552. package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -1
  553. package/dist/dictation/use-dictation.cjs +22 -22
  554. package/dist/dictation/use-dictation.cjs.map +1 -1
  555. package/dist/index.cjs +29 -2
  556. package/dist/index.cjs.map +1 -1
  557. package/dist/index.d.ts +18 -4
  558. package/dist/index.js +30 -3
  559. package/dist/index.js.map +1 -1
  560. package/dist/keryx-http/src/receive-only-socket.cjs +40 -0
  561. package/dist/keryx-http/src/receive-only-socket.cjs.map +1 -0
  562. package/dist/keryx-http/src/receive-only-socket.d.ts +27 -0
  563. package/dist/keryx-http/src/receive-only-socket.js +40 -0
  564. package/dist/keryx-http/src/receive-only-socket.js.map +1 -0
  565. package/dist/keryx-http/src/unconfirmed-update-attributions.cjs +190 -0
  566. package/dist/keryx-http/src/unconfirmed-update-attributions.cjs.map +1 -0
  567. package/dist/keryx-http/src/unconfirmed-update-attributions.d.ts +132 -0
  568. package/dist/keryx-http/src/unconfirmed-update-attributions.js +190 -0
  569. package/dist/keryx-http/src/unconfirmed-update-attributions.js.map +1 -0
  570. package/dist/keryx-http/src/update-attributions.cjs +141 -0
  571. package/dist/keryx-http/src/update-attributions.cjs.map +1 -0
  572. package/dist/keryx-http/src/update-attributions.d.ts +107 -0
  573. package/dist/keryx-http/src/update-attributions.js +141 -0
  574. package/dist/keryx-http/src/update-attributions.js.map +1 -0
  575. package/dist/lib/owner-document.cjs +6 -6
  576. package/dist/lib/owner-document.cjs.map +1 -1
  577. package/dist/lib/use-athena-rest-query.cjs +4 -4
  578. package/dist/lib/use-athena-rest-query.cjs.map +1 -1
  579. package/dist/lib/use-document-active.cjs +4 -4
  580. package/dist/lib/use-document-active.cjs.map +1 -1
  581. package/dist/lib/use-prefers-reduced-motion.cjs +2 -2
  582. package/dist/lib/use-prefers-reduced-motion.cjs.map +1 -1
  583. package/dist/offline/offline-history.cjs +7 -7
  584. package/dist/offline/offline-history.cjs.map +1 -1
  585. package/dist/provider/AthenaContext.cjs +3 -3
  586. package/dist/provider/AthenaContext.cjs.map +1 -1
  587. package/dist/provider/AthenaProvider.cjs +120 -79
  588. package/dist/provider/AthenaProvider.cjs.map +1 -1
  589. package/dist/provider/AthenaProvider.d.ts +11 -1
  590. package/dist/provider/AthenaProvider.js +44 -3
  591. package/dist/provider/AthenaProvider.js.map +1 -1
  592. package/dist/provider/PostHogProvider.cjs +2 -2
  593. package/dist/provider/PostHogProvider.cjs.map +1 -1
  594. package/dist/provider/agent-selection-context.cjs +2 -2
  595. package/dist/provider/agent-selection-context.cjs.map +1 -1
  596. package/dist/provider/chat-mode-context.cjs +2 -2
  597. package/dist/provider/chat-mode-context.cjs.map +1 -1
  598. package/dist/provider/session-persistence-context.cjs +10 -0
  599. package/dist/provider/session-persistence-context.cjs.map +1 -0
  600. package/dist/provider/session-persistence-context.d.ts +15 -0
  601. package/dist/provider/session-persistence-context.js +10 -0
  602. package/dist/provider/session-persistence-context.js.map +1 -0
  603. package/dist/provider/statewire-history-context.cjs +4 -4
  604. package/dist/provider/statewire-history-context.cjs.map +1 -1
  605. package/dist/provider/statewire-lifecycle-context.cjs +3 -3
  606. package/dist/provider/statewire-lifecycle-context.cjs.map +1 -1
  607. package/dist/provider/statewire-window-context.cjs +3 -3
  608. package/dist/provider/statewire-window-context.cjs.map +1 -1
  609. package/dist/provider/theme-style-context.cjs +3 -3
  610. package/dist/provider/theme-style-context.cjs.map +1 -1
  611. package/dist/react/package.json.cjs +1 -1
  612. package/dist/react/package.json.js +1 -1
  613. package/dist/runtime/StatewireThreadConfigLaneSync.cjs +10 -10
  614. package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
  615. package/dist/runtime/auth-refusal-restart.cjs +7 -7
  616. package/dist/runtime/auth-refusal-restart.cjs.map +1 -1
  617. package/dist/runtime/auth.cjs +13 -13
  618. package/dist/runtime/auth.cjs.map +1 -1
  619. package/dist/runtime/statewire-lifecycle.cjs +1 -0
  620. package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
  621. package/dist/runtime/statewire-lifecycle.d.ts +3 -1
  622. package/dist/runtime/statewire-lifecycle.js +2 -1
  623. package/dist/runtime/statewire-lifecycle.js.map +1 -1
  624. package/dist/runtime/statewire-server-lane-context.cjs +2 -2
  625. package/dist/runtime/statewire-server-lane-context.cjs.map +1 -1
  626. package/dist/runtime/statewire-session-lane.cjs +4 -4
  627. package/dist/runtime/statewire-session-lane.cjs.map +1 -1
  628. package/dist/runtime/useAthenaStatewireRuntime.cjs +10 -8
  629. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  630. package/dist/runtime/useAthenaStatewireRuntime.d.ts +2 -0
  631. package/dist/runtime/useAthenaStatewireRuntime.js +2 -0
  632. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  633. package/dist/styles.css +1 -1
  634. package/dist/threads/Inbox.cjs +8 -8
  635. package/dist/threads/Inbox.cjs.map +1 -1
  636. package/dist/threads/SessionList.cjs +9 -9
  637. package/dist/threads/SessionList.cjs.map +1 -1
  638. package/dist/threads/SessionsPage.cjs +11 -11
  639. package/dist/threads/SessionsPage.cjs.map +1 -1
  640. package/dist/threads/api.cjs.map +1 -1
  641. package/dist/threads/api.d.ts +15 -0
  642. package/dist/threads/api.js.map +1 -1
  643. package/dist/threads/conversation-list-fetcher.cjs +13 -5
  644. package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
  645. package/dist/threads/conversation-list-fetcher.d.ts +4 -1
  646. package/dist/threads/conversation-list-fetcher.js +13 -5
  647. package/dist/threads/conversation-list-fetcher.js.map +1 -1
  648. package/dist/threads/index-triggered-refresh.cjs +10 -10
  649. package/dist/threads/index-triggered-refresh.cjs.map +1 -1
  650. package/dist/threads/mark-viewed-thread-read.cjs +12 -12
  651. package/dist/threads/mark-viewed-thread-read.cjs.map +1 -1
  652. package/dist/threads/offline-session-list.cjs +3 -3
  653. package/dist/threads/offline-session-list.cjs.map +1 -1
  654. package/dist/threads/session-list-tab-share.cjs +5 -5
  655. package/dist/threads/session-list-tab-share.cjs.map +1 -1
  656. package/dist/threads/statewire-thread-list.cjs +79 -57
  657. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  658. package/dist/threads/statewire-thread-list.d.ts +20 -8
  659. package/dist/threads/statewire-thread-list.js +28 -6
  660. package/dist/threads/statewire-thread-list.js.map +1 -1
  661. package/dist/threads/thread-id-context.cjs +5 -5
  662. package/dist/threads/thread-id-context.cjs.map +1 -1
  663. package/dist/threads/use-athena-session-attention.cjs +2 -2
  664. package/dist/threads/use-athena-session-attention.cjs.map +1 -1
  665. package/dist/threads/use-athena-sessions.cjs +37 -15
  666. package/dist/threads/use-athena-sessions.cjs.map +1 -1
  667. package/dist/threads/use-athena-sessions.d.ts +10 -5
  668. package/dist/threads/use-athena-sessions.js +28 -6
  669. package/dist/threads/use-athena-sessions.js.map +1 -1
  670. package/dist/threads/use-athena-thread-model.cjs +3 -3
  671. package/dist/threads/use-athena-thread-model.cjs.map +1 -1
  672. package/dist/threads/use-rest-conversation-history.cjs +3 -3
  673. package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
  674. package/dist/threads/use-rest-conversation-history.d.ts +1 -0
  675. package/dist/threads/use-statewire-conversation-history.cjs +8 -8
  676. package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
  677. package/dist/threads/use-thread-archive.cjs +9 -9
  678. package/dist/threads/use-thread-archive.cjs.map +1 -1
  679. package/dist/threads/use-thread-favorite.cjs +2 -2
  680. package/dist/threads/use-thread-favorite.cjs.map +1 -1
  681. package/dist/threads/use-thread-field-override.cjs +20 -20
  682. package/dist/threads/use-thread-field-override.cjs.map +1 -1
  683. package/dist/threads/use-thread-read-state.cjs +4 -4
  684. package/dist/threads/use-thread-read-state.cjs.map +1 -1
  685. package/dist/threads/use-thread-rename.cjs +2 -2
  686. package/dist/threads/use-thread-rename.cjs.map +1 -1
  687. package/dist/threads/useAthenaThreadManager.cjs +2 -2
  688. package/dist/threads/useAthenaThreadManager.cjs.map +1 -1
  689. package/dist/tools/NestedPtcMessages.cjs +6 -6
  690. package/dist/tools/NestedPtcMessages.cjs.map +1 -1
  691. package/dist/tools/append-document-tool-ui.cjs +7 -7
  692. package/dist/tools/append-document-tool-ui.cjs.map +1 -1
  693. package/dist/tools/file-tool-uis.cjs +2 -2
  694. package/dist/tools/file-tool-uis.cjs.map +1 -1
  695. package/dist/tools/misc-tool-uis.cjs +2 -2
  696. package/dist/tools/misc-tool-uis.cjs.map +1 -1
  697. package/dist/tools/primitives.cjs +6 -6
  698. package/dist/tools/primitives.cjs.map +1 -1
  699. package/dist/tools/read-asset-tool-ui.cjs +6 -6
  700. package/dist/tools/read-asset-tool-ui.cjs.map +1 -1
  701. package/dist/tools/subagent-task-tool-ui.cjs +21 -21
  702. package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
  703. package/dist/tools/test-recording-tool-uis.cjs +16 -16
  704. package/dist/tools/test-recording-tool-uis.cjs.map +1 -1
  705. package/dist/tools/todo-plan-store.cjs +4 -4
  706. package/dist/tools/todo-plan-store.cjs.map +1 -1
  707. package/dist/tools/tool-appearance.cjs +3 -3
  708. package/dist/tools/tool-appearance.cjs.map +1 -1
  709. package/dist/tools/tool-fallback.cjs +14 -14
  710. package/dist/tools/tool-fallback.cjs.map +1 -1
  711. package/dist/tools/tool-uis.cjs +74 -74
  712. package/dist/tools/tool-uis.cjs.map +1 -1
  713. package/dist/tools/use-elapsed-seconds.cjs +3 -3
  714. package/dist/tools/use-elapsed-seconds.cjs.map +1 -1
  715. package/dist/tools/write-todos-tool-ui.cjs +9 -9
  716. package/dist/tools/write-todos-tool-ui.cjs.map +1 -1
  717. package/dist/ui/image-viewer.cjs +382 -0
  718. package/dist/ui/image-viewer.cjs.map +1 -0
  719. package/dist/ui/image-viewer.d.ts +50 -0
  720. package/dist/ui/image-viewer.js +382 -0
  721. package/dist/ui/image-viewer.js.map +1 -0
  722. package/dist/voice/chat.cjs +6 -0
  723. package/dist/voice/chat.cjs.map +1 -1
  724. package/dist/voice/chat.d.ts +1 -1
  725. package/dist/voice/chat.js +8 -2
  726. package/dist/voice/livekit-join.cjs +52 -101
  727. package/dist/voice/livekit-join.cjs.map +1 -1
  728. package/dist/voice/livekit-join.d.ts +1 -6
  729. package/dist/voice/livekit-join.js +52 -101
  730. package/dist/voice/livekit-join.js.map +1 -1
  731. package/dist/voice/livekit.cjs.map +1 -1
  732. package/dist/voice/livekit.d.ts +11 -1
  733. package/dist/voice/livekit.js.map +1 -1
  734. package/dist/voice/use-athena-voice-session.cjs +34 -34
  735. package/dist/voice/use-athena-voice-session.cjs.map +1 -1
  736. package/dist/workbench/ComputerLiveDesktop.cjs +13 -13
  737. package/dist/workbench/ComputerLiveDesktop.cjs.map +1 -1
  738. package/dist/workbench/SessionWorkbench.cjs +22 -22
  739. package/dist/workbench/SessionWorkbench.cjs.map +1 -1
  740. package/dist/workbench/session-workbench-context.cjs +3 -3
  741. package/dist/workbench/session-workbench-context.cjs.map +1 -1
  742. package/dist/workbench/session-workbench-panes.cjs +8 -8
  743. package/dist/workbench/session-workbench-panes.cjs.map +1 -1
  744. package/dist/workbench/workbench-layout-context.cjs +3 -3
  745. package/dist/workbench/workbench-layout-context.cjs.map +1 -1
  746. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"QuoteContext.cjs","sources":["../../src/composer/QuoteContext.tsx"],"sourcesContent":["import {\n createContext,\n type RefObject,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport { useStore } from 'zustand';\nimport { createStore, type StoreApi } from 'zustand/vanilla';\n\nexport interface QuoteData {\n /** The selected/quoted text. */\n text: string;\n /** Title of the source (e.g., asset title, document name). */\n sourceTitle?: string;\n /** Asset ID of the source (for attribution). */\n sourceAssetId?: string;\n /** Message ID of the source message (when quoting from chat). */\n sourceMessageId?: string;\n /** Role of the source message ('assistant' | 'user'). */\n sourceRole?: string;\n}\n\ninterface QuoteContextValue {\n quote: QuoteData | null;\n setQuote: (quote: QuoteData | null) => void;\n clearQuote: () => void;\n}\n\nconst QuoteCtx = createContext<QuoteContextValue | null>(null);\n\ninterface QuoteStoreState {\n quote: QuoteData | null;\n}\n\n/**\n * A composer's pending quote, kept outside React (`createQuoteStore`), like\n * `AttachmentStore`: one per chat when a host shows several.\n */\nexport type QuoteStore = StoreApi<QuoteStoreState>;\n\n/** An empty `QuoteStore`, for `<QuoteProvider store>`. */\nexport function createQuoteStore(): QuoteStore {\n return createStore<QuoteStoreState>(() => ({ quote: null }));\n}\n\n/**\n * The composer's pending quote. Like \\`AttachmentProvider\\`, a `store` makes\n * it that store's, and without one it reuses a provider already mounted\n * above, so a host can keep the quote across a remounting \\`AthenaChat\\`.\n */\nexport function QuoteProvider({ children, store }: { children: ReactNode; store?: QuoteStore }) {\n const outer = useContext(QuoteCtx);\n if (store) return <StoreQuoteProvider store={store}>{children}</StoreQuoteProvider>;\n if (outer) return <>{children}</>;\n return <OwnQuoteProvider>{children}</OwnQuoteProvider>;\n}\n\nfunction OwnQuoteProvider({ children }: { children: ReactNode }) {\n const [store] = useState(createQuoteStore);\n return <StoreQuoteProvider store={store}>{children}</StoreQuoteProvider>;\n}\n\nfunction StoreQuoteProvider({ children, store }: { children: ReactNode; store: QuoteStore }) {\n const quote = useStore(store, (state) => state.quote);\n const actions = useMemo(\n () => ({\n setQuote: (next: QuoteData | null) => store.setState({ quote: next }),\n clearQuote: () => store.setState({ quote: null }),\n }),\n [store],\n );\n const value = useMemo(() => ({ quote, ...actions }), [quote, actions]);\n\n return (\n <QuoteCtx.Provider value={value}>\n {children}\n </QuoteCtx.Provider>\n );\n}\n\nexport function useQuote(): QuoteContextValue {\n const ctx = useContext(QuoteCtx);\n if (!ctx) {\n throw new Error('[AthenaSDK] useQuote must be used within <QuoteProvider>');\n }\n return ctx;\n}\n\n/**\n * Whether a message came from a frame embedded directly in this window, for\n * any origin: the window of one of this document's iframes (an identity\n * comparison, safe cross-origin), or, for a frame inside a shadow root, a\n * window whose `parent` is this window (`parent` is readable on a\n * cross-origin window). A message port, a worker, this window itself, a\n * grandchild frame or an unrelated window is refused. `win` is the window the\n * message came to (default: this one), e.g. a popped-out chat's.\n */\nexport function isDirectChildFrame(\n source: MessageEventSource | null,\n win: Window = window,\n): boolean {\n if (!source || source === win) return false;\n for (const frame of win.document.querySelectorAll('iframe')) {\n if (frame.contentWindow === source) return true;\n }\n try {\n return Reflect.get(source, 'parent') === win;\n } catch {\n return false;\n }\n}\n\n/** `AthenaChat`'s thread root: the chats `useQuoteFromPostMessage` tells apart. */\nconst CHAT_ROOT_SELECTOR = '.aui-thread-root';\n\n/**\n * The chat the person last focused in each window, which takes a quote that\n * names no chat (a selection outside every chat, an embedded frame's text)\n * when that window shows several. A focus, not data: no state of the chats\n * themselves.\n */\nconst lastFocusedChatRoots = new WeakMap<Document, Element>();\n\n/** The element a node is, or sits in; duck-typed, since a pop-out window's nodes are another realm's. */\nfunction elementOf(node: Node | null | undefined): Element | null {\n if (!node) return null;\n return node.nodeType === 1 ? (node as Element) : node.parentElement;\n}\n\nexport interface QuoteFromPostMessageOptions {\n /**\n * An element inside the chat this composer belongs to. With several chats in\n * one window, a ⌘L selection goes to the chat it was made in, and one made\n * outside every chat (or an embedded frame's text) to the chat the person\n * last focused; the keys and an embedded frame's messages are heard in this\n * element's own window, a pop-out included. Without it, every quote is this\n * composer's, as before.\n */\n scope?: RefObject<Element | null>;\n}\n\n/**\n * Listens for:\n * 1. Cmd+L / Ctrl+L keydown — grabs the current text selection and sets it as a quote.\n * `preventDefault` stops the browser from focusing the URL bar.\n * 2. PostMessage events from child iframes (asset panels, embedded content)\n * with type `athena-add-to-composer`, only from a frame embedded directly\n * in this window ({@link isDirectChildFrame}).\n *\n * Mount this once per composer inside AthenaProvider (`AthenaChat` does).\n */\nexport function useQuoteFromPostMessage({ scope }: QuoteFromPostMessageOptions = {}) {\n const { setQuote } = useQuote();\n\n useEffect(() => {\n const doc = scope?.current?.ownerDocument ?? document;\n const win = doc.defaultView ?? window;\n const chatRoot = () => scope?.current?.closest(CHAT_ROOT_SELECTOR) ?? null;\n // Whether this composer takes a quote made at `anchor` (null: one that names no chat).\n const takes = (anchor: Node | null) => {\n const mine = chatRoot();\n if (!mine) return true;\n const owner = elementOf(anchor)?.closest(CHAT_ROOT_SELECTOR) ?? null;\n if (owner) return owner === mine;\n const remembered = lastFocusedChatRoots.get(doc);\n const focused = remembered?.isConnected ? remembered : doc.querySelector(CHAT_ROOT_SELECTOR);\n return focused === mine;\n };\n\n const handleFocusIn = (event: FocusEvent) => {\n const mine = chatRoot();\n const target = event.target as Node | null;\n if (mine && target && typeof target.nodeType === 'number' && mine.contains(target)) {\n lastFocusedChatRoots.set(doc, mine);\n }\n };\n\n // ── Cmd+L / Ctrl+L keyboard handler ──────────────────────────────\n const handleKeydown = (e: KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'l') {\n const sel = doc.getSelection();\n const selection = sel?.toString()?.trim();\n\n if (selection && selection.length > 0 && takes(sel?.anchorNode ?? null)) {\n e.preventDefault();\n\n // Walk up from the selection anchor to find the message container.\n // assistant-ui message roots have data-role=\"assistant\" or data-role=\"user\".\n let messageId: string | undefined;\n let role: string | undefined;\n let node = elementOf(sel?.anchorNode);\n while (node && node !== doc.body) {\n const dataRole = node.getAttribute('data-role');\n if (dataRole === 'assistant' || dataRole === 'user') {\n role = dataRole;\n // assistant-ui sets data-message-id on message roots\n messageId = node.getAttribute('data-message-id') ?? undefined;\n break;\n }\n node = node.parentElement;\n }\n\n setQuote({ text: selection, sourceRole: role, sourceMessageId: messageId });\n }\n }\n };\n\n // ── PostMessage handler (from iframes) ───────────────────────────\n // Accepts messages from any origin, but only from a frame embedded\n // directly in this window: the SDK consumer controls which iframes are\n // embedded, and that is the trust boundary. A popup, an opener or another\n // tab holding a reference to this window cannot stage composer text.\n const handleMessage = (event: MessageEvent) => {\n const data = event.data;\n if (\n data &&\n typeof data === 'object' &&\n data.type === 'athena-add-to-composer' &&\n typeof data.text === 'string' &&\n data.text.trim().length > 0 &&\n isDirectChildFrame(event.source, win) &&\n takes(null)\n ) {\n setQuote({\n text: data.text,\n sourceTitle: data.sourceTitle,\n sourceAssetId: data.sourceAssetId,\n });\n }\n };\n\n doc.addEventListener('keydown', handleKeydown, true); // capture phase to beat the browser\n doc.addEventListener('focusin', handleFocusIn, true);\n win.addEventListener('message', handleMessage);\n\n return () => {\n doc.removeEventListener('keydown', handleKeydown, true);\n doc.removeEventListener('focusin', handleFocusIn, true);\n win.removeEventListener('message', handleMessage);\n };\n }, [scope, setQuote]);\n}\n"],"names":["createContext","createStore","useContext","jsx","Fragment","useState","useStore","useMemo","useEffect","_a"],"mappings":"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"}
1
+ {"version":3,"file":"QuoteContext.cjs","sources":["../../src/composer/QuoteContext.tsx"],"sourcesContent":["import {\n createContext,\n type RefObject,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport { useStore } from 'zustand';\nimport { createStore, type StoreApi } from 'zustand/vanilla';\n\nexport interface QuoteData {\n /** The selected/quoted text. */\n text: string;\n /** Title of the source (e.g., asset title, document name). */\n sourceTitle?: string;\n /** Asset ID of the source (for attribution). */\n sourceAssetId?: string;\n /** Message ID of the source message (when quoting from chat). */\n sourceMessageId?: string;\n /** Role of the source message ('assistant' | 'user'). */\n sourceRole?: string;\n}\n\ninterface QuoteContextValue {\n quote: QuoteData | null;\n setQuote: (quote: QuoteData | null) => void;\n clearQuote: () => void;\n}\n\nconst QuoteCtx = createContext<QuoteContextValue | null>(null);\n\ninterface QuoteStoreState {\n quote: QuoteData | null;\n}\n\n/**\n * A composer's pending quote, kept outside React (`createQuoteStore`), like\n * `AttachmentStore`: one per chat when a host shows several.\n */\nexport type QuoteStore = StoreApi<QuoteStoreState>;\n\n/** An empty `QuoteStore`, for `<QuoteProvider store>`. */\nexport function createQuoteStore(): QuoteStore {\n return createStore<QuoteStoreState>(() => ({ quote: null }));\n}\n\n/**\n * The composer's pending quote. Like \\`AttachmentProvider\\`, a `store` makes\n * it that store's, and without one it reuses a provider already mounted\n * above, so a host can keep the quote across a remounting \\`AthenaChat\\`.\n */\nexport function QuoteProvider({ children, store }: { children: ReactNode; store?: QuoteStore }) {\n const outer = useContext(QuoteCtx);\n if (store) return <StoreQuoteProvider store={store}>{children}</StoreQuoteProvider>;\n if (outer) return <>{children}</>;\n return <OwnQuoteProvider>{children}</OwnQuoteProvider>;\n}\n\nfunction OwnQuoteProvider({ children }: { children: ReactNode }) {\n const [store] = useState(createQuoteStore);\n return <StoreQuoteProvider store={store}>{children}</StoreQuoteProvider>;\n}\n\nfunction StoreQuoteProvider({ children, store }: { children: ReactNode; store: QuoteStore }) {\n const quote = useStore(store, (state) => state.quote);\n const actions = useMemo(\n () => ({\n setQuote: (next: QuoteData | null) => store.setState({ quote: next }),\n clearQuote: () => store.setState({ quote: null }),\n }),\n [store],\n );\n const value = useMemo(() => ({ quote, ...actions }), [quote, actions]);\n\n return (\n <QuoteCtx.Provider value={value}>\n {children}\n </QuoteCtx.Provider>\n );\n}\n\nexport function useQuote(): QuoteContextValue {\n const ctx = useContext(QuoteCtx);\n if (!ctx) {\n throw new Error('[AthenaSDK] useQuote must be used within <QuoteProvider>');\n }\n return ctx;\n}\n\n/**\n * Whether a message came from a frame embedded directly in this window, for\n * any origin: the window of one of this document's iframes (an identity\n * comparison, safe cross-origin), or, for a frame inside a shadow root, a\n * window whose `parent` is this window (`parent` is readable on a\n * cross-origin window). A message port, a worker, this window itself, a\n * grandchild frame or an unrelated window is refused. `win` is the window the\n * message came to (default: this one), e.g. a popped-out chat's.\n */\nexport function isDirectChildFrame(\n source: MessageEventSource | null,\n win: Window = window,\n): boolean {\n if (!source || source === win) return false;\n for (const frame of win.document.querySelectorAll('iframe')) {\n if (frame.contentWindow === source) return true;\n }\n try {\n return Reflect.get(source, 'parent') === win;\n } catch {\n return false;\n }\n}\n\n/** `AthenaChat`'s thread root: the chats `useQuoteFromPostMessage` tells apart. */\nconst CHAT_ROOT_SELECTOR = '.aui-thread-root';\n\n/**\n * The chat the person last focused in each window, which takes a quote that\n * names no chat (a selection outside every chat, an embedded frame's text)\n * when that window shows several. A focus, not data: no state of the chats\n * themselves.\n */\nconst lastFocusedChatRoots = new WeakMap<Document, Element>();\n\n/** The element a node is, or sits in; duck-typed, since a pop-out window's nodes are another realm's. */\nfunction elementOf(node: Node | null | undefined): Element | null {\n if (!node) return null;\n return node.nodeType === 1 ? (node as Element) : node.parentElement;\n}\n\nexport interface QuoteFromPostMessageOptions {\n /**\n * An element inside the chat this composer belongs to. With several chats in\n * one window, a ⌘L selection goes to the chat it was made in, and one made\n * outside every chat (or an embedded frame's text) to the chat the person\n * last focused; the keys and an embedded frame's messages are heard in this\n * element's own window, a pop-out included. Without it, every quote is this\n * composer's, as before.\n */\n scope?: RefObject<Element | null>;\n}\n\n/**\n * Listens for:\n * 1. Cmd+L / Ctrl+L keydown — grabs the current text selection and sets it as a quote.\n * `preventDefault` stops the browser from focusing the URL bar.\n * 2. PostMessage events from child iframes (asset panels, embedded content)\n * with type `athena-add-to-composer`, only from a frame embedded directly\n * in this window ({@link isDirectChildFrame}).\n *\n * Mount this once per composer inside AthenaProvider (`AthenaChat` does).\n */\nexport function useQuoteFromPostMessage({ scope }: QuoteFromPostMessageOptions = {}) {\n const { setQuote } = useQuote();\n\n useEffect(() => {\n const doc = scope?.current?.ownerDocument ?? document;\n const win = doc.defaultView ?? window;\n const chatRoot = () => scope?.current?.closest(CHAT_ROOT_SELECTOR) ?? null;\n // Whether this composer takes a quote made at `anchor` (null: one that names no chat).\n const takes = (anchor: Node | null) => {\n const mine = chatRoot();\n if (!mine) return true;\n const owner = elementOf(anchor)?.closest(CHAT_ROOT_SELECTOR) ?? null;\n if (owner) return owner === mine;\n const remembered = lastFocusedChatRoots.get(doc);\n const focused = remembered?.isConnected ? remembered : doc.querySelector(CHAT_ROOT_SELECTOR);\n return focused === mine;\n };\n\n const handleFocusIn = (event: FocusEvent) => {\n const mine = chatRoot();\n const target = event.target as Node | null;\n if (mine && target && typeof target.nodeType === 'number' && mine.contains(target)) {\n lastFocusedChatRoots.set(doc, mine);\n }\n };\n\n // ── Cmd+L / Ctrl+L keyboard handler ──────────────────────────────\n const handleKeydown = (e: KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'l') {\n const sel = doc.getSelection();\n const selection = sel?.toString()?.trim();\n\n if (selection && selection.length > 0 && takes(sel?.anchorNode ?? null)) {\n e.preventDefault();\n\n // Walk up from the selection anchor to find the message container.\n // assistant-ui message roots have data-role=\"assistant\" or data-role=\"user\".\n let messageId: string | undefined;\n let role: string | undefined;\n let node = elementOf(sel?.anchorNode);\n while (node && node !== doc.body) {\n const dataRole = node.getAttribute('data-role');\n if (dataRole === 'assistant' || dataRole === 'user') {\n role = dataRole;\n // assistant-ui sets data-message-id on message roots\n messageId = node.getAttribute('data-message-id') ?? undefined;\n break;\n }\n node = node.parentElement;\n }\n\n setQuote({ text: selection, sourceRole: role, sourceMessageId: messageId });\n }\n }\n };\n\n // ── PostMessage handler (from iframes) ───────────────────────────\n // Accepts messages from any origin, but only from a frame embedded\n // directly in this window: the SDK consumer controls which iframes are\n // embedded, and that is the trust boundary. A popup, an opener or another\n // tab holding a reference to this window cannot stage composer text.\n const handleMessage = (event: MessageEvent) => {\n const data = event.data;\n if (\n data &&\n typeof data === 'object' &&\n data.type === 'athena-add-to-composer' &&\n typeof data.text === 'string' &&\n data.text.trim().length > 0 &&\n isDirectChildFrame(event.source, win) &&\n takes(null)\n ) {\n setQuote({\n text: data.text,\n sourceTitle: data.sourceTitle,\n sourceAssetId: data.sourceAssetId,\n });\n }\n };\n\n doc.addEventListener('keydown', handleKeydown, true); // capture phase to beat the browser\n doc.addEventListener('focusin', handleFocusIn, true);\n win.addEventListener('message', handleMessage);\n\n return () => {\n doc.removeEventListener('keydown', handleKeydown, true);\n doc.removeEventListener('focusin', handleFocusIn, true);\n win.removeEventListener('message', handleMessage);\n };\n }, [scope, setQuote]);\n}\n"],"names":["createContext","createStore","useContext","jsx","Fragment","useState","useStore","useMemo","useEffect","_a"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const react$1 = require("react");
3
+ const require$$0 = require("react");
4
4
  const react = require("@assistant-ui/react");
5
5
  const athenaDiagnostics = require("../diagnostics/athena-diagnostics.cjs");
6
6
  const errors = require("../diagnostics/errors.cjs");
@@ -40,13 +40,13 @@ function takeRestoredAttachments({
40
40
  (_b = store == null ? void 0 : store.restoredAttachments) == null ? void 0 : _b.delete(threadId);
41
41
  return kept.filter((attachment) => assetIdsInDraft.has(attachment.assetId));
42
42
  }
43
- const ComposerHandoffContext = react$1.createContext(null);
43
+ const ComposerHandoffContext = require$$0.createContext(null);
44
44
  function useComposerHandoffStore() {
45
- return react$1.useContext(ComposerHandoffContext);
45
+ return require$$0.useContext(ComposerHandoffContext);
46
46
  }
47
47
  function useFocusComposer() {
48
48
  const store = useComposerHandoffStore();
49
- return react$1.useCallback(() => {
49
+ return require$$0.useCallback(() => {
50
50
  if (store) focusComposer({ store });
51
51
  }, [store]);
52
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"composer-handoff.cjs","sources":["../../src/composer/composer-handoff.ts"],"sourcesContent":["/**\n * Composer handoff: writes to the chat composer from host UI that lives\n * outside `<AthenaChat>` (a sidebar, an agenda card, a workflow button).\n *\n * Two problems it solves for `useAppendToComposer` / `useSendMessage`:\n *\n * 1. A write before the chat is ready is lost. While the thread list is still\n * resolving the active thread, or the thread's history is still loading,\n * the composer the hooks write to belongs to a mount that is about to be\n * replaced (thread-list mode keys the statewire subtree by thread), and\n * the draft goes with it. The store below lives ABOVE that mount, so a\n * write made too early waits here and the ready mount drains it.\n * 2. A prefilled draft should put the caret after the text so the user can\n * keep typing or dictating. The Tiptap editor mirrors runtime text on a\n * later tick; the `focusOnNextMirror` flag asks it to focus at the end\n * right after that mirror lands, instead of the host guessing a delay.\n *\n * Every queued write is bound to the statewire thread it was made for and\n * drains only into that thread's mount; a thread switch, an identity change\n * or a provider unmount drops what waits with a `composer_write_dropped`\n * error, never into another user's or another thread's composer.\n */\nimport { createContext, useCallback, useContext } from 'react';\nimport { useAuiState } from '@assistant-ui/react';\nimport type { ChatOutboxAttachment } from '@athenaintel/agent-runtime';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { AthenaSdkError } from '../diagnostics/errors';\nimport { useStatewireSessionLanePending } from '../runtime/statewire-session-lane';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\n\n/** The slice of the assistant-ui client the handoff writes to. */\nexport interface ComposerTarget {\n composer: {\n getState: () => { text: string };\n setText: (text: string) => void;\n send: (options?: { steer?: boolean }) => unknown;\n };\n}\n\nexport interface ComposerWrite {\n text: string;\n /** Replace the draft instead of appending on a new line. */\n replace: boolean;\n /** Submit right after writing. */\n send: boolean;\n /** Put the caret at the end of the draft once the editor shows it. */\n focus: boolean;\n /** The statewire thread the write was made for; it drains only into that thread's mount. */\n threadId: string | null;\n /** Settled once the write has been applied (and, for `send`, with the send's outcome). */\n resolve?: (outcome: Promise<void> | void) => void;\n /** Settled with `composer_write_dropped` when the write can no longer land. */\n reject?: (error: AthenaSdkError) => void;\n}\n\nexport interface ComposerHandoffStore {\n /** Writes waiting for a ready composer, oldest first. Adjacent plain appends fold together. */\n pending: ComposerWrite[];\n /** Set by a `focus` write; the editor consumes it after mirroring the draft. */\n focusOnNextMirror: boolean;\n /** Registered by the mounted editor: place the caret at the end of the draft. */\n focusEnd: (() => void) | null;\n /** Set by `useFocusComposer` before the editor mounted; the editor consumes it when it does. */\n focusOnMount: boolean;\n /**\n * Per thread, the attachments of messages the chat outbox gave back to the composer (Cancel, or\n * Edit on one that couldn't be sent): files already in Athena, back in the draft as mentions. A\n * message held again from that draft names those still in it, so the outbox asks Athena about\n * them again before it goes ({@link rememberRestoredAttachments}, {@link takeRestoredAttachments}).\n */\n restoredAttachments?: Map<string, ChatOutboxAttachment[]>;\n}\n\nexport function createComposerHandoffStore(): ComposerHandoffStore {\n return {\n pending: [],\n focusOnNextMirror: false,\n focusEnd: null,\n focusOnMount: false,\n restoredAttachments: new Map(),\n };\n}\n\n/** A held message given back to `threadId`'s composer: remember the attachments it carried. */\nexport function rememberRestoredAttachments({\n store,\n threadId,\n attachments,\n}: {\n store: ComposerHandoffStore;\n threadId: string;\n attachments: readonly ChatOutboxAttachment[];\n}): void {\n if (attachments.length === 0) return;\n store.restoredAttachments ??= new Map();\n const kept = store.restoredAttachments.get(threadId) ?? [];\n const known = new Set(kept.map((attachment) => attachment.assetId));\n store.restoredAttachments.set(threadId, [\n ...kept,\n ...attachments.filter((attachment) => !known.has(attachment.assetId)),\n ]);\n}\n\n/**\n * The remembered attachments of `threadId`'s draft whose mentions it still holds, for the message\n * leaving it now; the composer forgets them all (sent, held again, or removed from the draft).\n */\nexport function takeRestoredAttachments({\n store,\n threadId,\n assetIdsInDraft,\n}: {\n store: ComposerHandoffStore | null;\n threadId: string;\n assetIdsInDraft: ReadonlySet<string>;\n}): ChatOutboxAttachment[] {\n const kept = store?.restoredAttachments?.get(threadId);\n if (!kept) return [];\n store?.restoredAttachments?.delete(threadId);\n return kept.filter((attachment) => assetIdsInDraft.has(attachment.assetId));\n}\n\nexport const ComposerHandoffContext = createContext<ComposerHandoffStore | null>(null);\n\n/** The provider's handoff store, or null outside `AthenaProvider`. */\nexport function useComposerHandoffStore(): ComposerHandoffStore | null {\n return useContext(ComposerHandoffContext);\n}\n\n/**\n * Puts the caret at the end of the composer's draft and leaves the draft as it is; asked before the\n * editor has mounted, it focuses the editor as it mounts. For a host that shows the chat again and\n * wants typing to land in it (a launcher window a shortcut brings back).\n */\nexport function useFocusComposer(): () => void {\n const store = useComposerHandoffStore();\n return useCallback(() => {\n if (store) focusComposer({ store });\n }, [store]);\n}\n\n/** The caret to the end of the draft now, or, with no editor mounted yet, as one mounts. */\nexport function focusComposer({ store }: { store: ComposerHandoffStore }): void {\n if (store.focusEnd) store.focusEnd();\n else store.focusOnMount = true;\n}\n\n/**\n * Whether a composer write lands now: in thread-list mode the list has\n * resolved which thread is active, that thread's history has loaded, and the\n * chat's session lane is known (the sign-in provider above has resolved who is\n * signed in; see `StatewireSessionLane`). Until then the composer the hooks\n * write to is the one of a mount that is about to be replaced, and the draft\n * goes with it, or a send would go into a parked lane that refuses it unsent.\n *\n * Deliberately not the socket status: a never-started chat sits in\n * `standby` until its first send and must still take a prefill.\n */\nexport function useComposerReady(): boolean {\n const list = useAthenaStatewireThreadList();\n const threadLoading = useAuiState((s) => s.optional.thread?.isLoading ?? false);\n const lanePending = useStatewireSessionLanePending();\n return !(list?.isLoading ?? false) && !threadLoading && !lanePending;\n}\n\n/** The draft after `write`: `replace` (or an empty draft) takes the text as is. */\nexport function mergeComposerDraft({\n current,\n write,\n}: {\n current: string;\n write: Pick<ComposerWrite, 'text' | 'replace'>;\n}): string {\n if (write.replace || !current) return write.text;\n return `${current}\\n${write.text}`;\n}\n\n/**\n * Write into the live composer. Returns the send's outcome for a `send`\n * write so callers can await it.\n */\nexport function applyComposerWrite({\n target,\n store,\n write,\n}: {\n target: ComposerTarget;\n store: ComposerHandoffStore | null;\n write: ComposerWrite;\n}): Promise<void> | void {\n const current = target.composer.getState().text ?? '';\n const next = mergeComposerDraft({ current, write });\n target.composer.setText(next);\n if (write.focus && store) {\n // An unchanged draft never re-mirrors, so focus at once; otherwise the\n // editor focuses itself right after it has shown the new text.\n if (next === current) store.focusEnd?.();\n else store.focusOnNextMirror = true;\n }\n athenaDiagnostics.emit('composer.handoff', {\n level: 'debug',\n data: { phase: 'applied', send: write.send, focus: write.focus, chars: next.length },\n });\n if (write.send) {\n return Promise.resolve(target.composer.send({ steer: false })).then(() => undefined);\n }\n return undefined;\n}\n\n/**\n * Hold a write until the composer is ready. Writes keep their order; a plain\n * append folds into a directly preceding plain append for the same thread\n * (one draft, not two), while a replace or a send is kept as its own step so\n * no message is lost and every send settles on its own.\n */\nexport function queueComposerWrite({\n store,\n write,\n}: {\n store: ComposerHandoffStore;\n write: ComposerWrite;\n}): void {\n const last = store.pending[store.pending.length - 1];\n const foldable =\n last !== undefined &&\n !last.send &&\n !write.send &&\n !write.replace &&\n last.threadId === write.threadId &&\n last.resolve === undefined &&\n write.resolve === undefined;\n if (foldable) {\n last.text = mergeComposerDraft({ current: last.text, write });\n last.focus = last.focus || write.focus;\n } else {\n store.pending.push(write);\n }\n athenaDiagnostics.emit('composer.handoff', {\n level: 'debug',\n data: { phase: 'deferred', send: write.send, focus: write.focus, queued: store.pending.length },\n });\n}\n\nfunction dropWrite({ write, reason }: { write: ComposerWrite; reason: string }): void {\n const error = new AthenaSdkError({\n code: 'composer_write_dropped',\n message: `A composer ${write.send ? 'send' : 'draft'} queued before the chat was ready was dropped: ${reason}.`,\n hint: 'Make the write again from the chat that is active now.',\n context: { threadId: write.threadId, send: write.send },\n });\n athenaDiagnostics.emit('composer.handoff', {\n level: 'warn',\n error,\n data: { phase: 'dropped', send: write.send, reason, threadId: write.threadId },\n });\n write.reject?.(error);\n}\n\n/**\n * Deliver the pending writes, in order, into a now-ready composer. A write\n * made for another thread is dropped (rejected), never applied here.\n */\nexport function drainComposerHandoff({\n store,\n target,\n threadId,\n}: {\n store: ComposerHandoffStore;\n target: ComposerTarget;\n /** The statewire thread of the mount that is draining. */\n threadId: string | null;\n}): void {\n const writes = store.pending;\n if (writes.length === 0) return;\n store.pending = [];\n for (const write of writes) {\n if (write.threadId !== null && threadId !== null && write.threadId !== threadId) {\n dropWrite({ write, reason: `it was made for thread ${write.threadId}, thread ${threadId} is active` });\n continue;\n }\n const outcome = applyComposerWrite({ target, store, write });\n write.resolve?.(outcome);\n }\n}\n\n/** Drop every pending write (identity changed, provider unmounted). */\nexport function clearComposerHandoff({\n store,\n reason,\n}: {\n store: ComposerHandoffStore;\n reason: string;\n}): void {\n // Another identity, or no provider: the attachments given back belong to drafts that are gone.\n store.restoredAttachments?.clear();\n const writes = store.pending;\n if (writes.length === 0) return;\n store.pending = [];\n for (const write of writes) dropWrite({ write, reason });\n}\n"],"names":["createContext","useContext","useCallback","useAthenaStatewireThreadList","useAuiState","useStatewireSessionLanePending","athenaDiagnostics","AthenaSdkError"],"mappings":"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"}
1
+ {"version":3,"file":"composer-handoff.cjs","sources":["../../src/composer/composer-handoff.ts"],"sourcesContent":["/**\n * Composer handoff: writes to the chat composer from host UI that lives\n * outside `<AthenaChat>` (a sidebar, an agenda card, a workflow button).\n *\n * Two problems it solves for `useAppendToComposer` / `useSendMessage`:\n *\n * 1. A write before the chat is ready is lost. While the thread list is still\n * resolving the active thread, or the thread's history is still loading,\n * the composer the hooks write to belongs to a mount that is about to be\n * replaced (thread-list mode keys the statewire subtree by thread), and\n * the draft goes with it. The store below lives ABOVE that mount, so a\n * write made too early waits here and the ready mount drains it.\n * 2. A prefilled draft should put the caret after the text so the user can\n * keep typing or dictating. The Tiptap editor mirrors runtime text on a\n * later tick; the `focusOnNextMirror` flag asks it to focus at the end\n * right after that mirror lands, instead of the host guessing a delay.\n *\n * Every queued write is bound to the statewire thread it was made for and\n * drains only into that thread's mount; a thread switch, an identity change\n * or a provider unmount drops what waits with a `composer_write_dropped`\n * error, never into another user's or another thread's composer.\n */\nimport { createContext, useCallback, useContext } from 'react';\nimport { useAuiState } from '@assistant-ui/react';\nimport type { ChatOutboxAttachment } from '@athenaintel/agent-runtime';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { AthenaSdkError } from '../diagnostics/errors';\nimport { useStatewireSessionLanePending } from '../runtime/statewire-session-lane';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\n\n/** The slice of the assistant-ui client the handoff writes to. */\nexport interface ComposerTarget {\n composer: {\n getState: () => { text: string };\n setText: (text: string) => void;\n send: (options?: { steer?: boolean }) => unknown;\n };\n}\n\nexport interface ComposerWrite {\n text: string;\n /** Replace the draft instead of appending on a new line. */\n replace: boolean;\n /** Submit right after writing. */\n send: boolean;\n /** Put the caret at the end of the draft once the editor shows it. */\n focus: boolean;\n /** The statewire thread the write was made for; it drains only into that thread's mount. */\n threadId: string | null;\n /** Settled once the write has been applied (and, for `send`, with the send's outcome). */\n resolve?: (outcome: Promise<void> | void) => void;\n /** Settled with `composer_write_dropped` when the write can no longer land. */\n reject?: (error: AthenaSdkError) => void;\n}\n\nexport interface ComposerHandoffStore {\n /** Writes waiting for a ready composer, oldest first. Adjacent plain appends fold together. */\n pending: ComposerWrite[];\n /** Set by a `focus` write; the editor consumes it after mirroring the draft. */\n focusOnNextMirror: boolean;\n /** Registered by the mounted editor: place the caret at the end of the draft. */\n focusEnd: (() => void) | null;\n /** Set by `useFocusComposer` before the editor mounted; the editor consumes it when it does. */\n focusOnMount: boolean;\n /**\n * Per thread, the attachments of messages the chat outbox gave back to the composer (Cancel, or\n * Edit on one that couldn't be sent): files already in Athena, back in the draft as mentions. A\n * message held again from that draft names those still in it, so the outbox asks Athena about\n * them again before it goes ({@link rememberRestoredAttachments}, {@link takeRestoredAttachments}).\n */\n restoredAttachments?: Map<string, ChatOutboxAttachment[]>;\n}\n\nexport function createComposerHandoffStore(): ComposerHandoffStore {\n return {\n pending: [],\n focusOnNextMirror: false,\n focusEnd: null,\n focusOnMount: false,\n restoredAttachments: new Map(),\n };\n}\n\n/** A held message given back to `threadId`'s composer: remember the attachments it carried. */\nexport function rememberRestoredAttachments({\n store,\n threadId,\n attachments,\n}: {\n store: ComposerHandoffStore;\n threadId: string;\n attachments: readonly ChatOutboxAttachment[];\n}): void {\n if (attachments.length === 0) return;\n store.restoredAttachments ??= new Map();\n const kept = store.restoredAttachments.get(threadId) ?? [];\n const known = new Set(kept.map((attachment) => attachment.assetId));\n store.restoredAttachments.set(threadId, [\n ...kept,\n ...attachments.filter((attachment) => !known.has(attachment.assetId)),\n ]);\n}\n\n/**\n * The remembered attachments of `threadId`'s draft whose mentions it still holds, for the message\n * leaving it now; the composer forgets them all (sent, held again, or removed from the draft).\n */\nexport function takeRestoredAttachments({\n store,\n threadId,\n assetIdsInDraft,\n}: {\n store: ComposerHandoffStore | null;\n threadId: string;\n assetIdsInDraft: ReadonlySet<string>;\n}): ChatOutboxAttachment[] {\n const kept = store?.restoredAttachments?.get(threadId);\n if (!kept) return [];\n store?.restoredAttachments?.delete(threadId);\n return kept.filter((attachment) => assetIdsInDraft.has(attachment.assetId));\n}\n\nexport const ComposerHandoffContext = createContext<ComposerHandoffStore | null>(null);\n\n/** The provider's handoff store, or null outside `AthenaProvider`. */\nexport function useComposerHandoffStore(): ComposerHandoffStore | null {\n return useContext(ComposerHandoffContext);\n}\n\n/**\n * Puts the caret at the end of the composer's draft and leaves the draft as it is; asked before the\n * editor has mounted, it focuses the editor as it mounts. For a host that shows the chat again and\n * wants typing to land in it (a launcher window a shortcut brings back).\n */\nexport function useFocusComposer(): () => void {\n const store = useComposerHandoffStore();\n return useCallback(() => {\n if (store) focusComposer({ store });\n }, [store]);\n}\n\n/** The caret to the end of the draft now, or, with no editor mounted yet, as one mounts. */\nexport function focusComposer({ store }: { store: ComposerHandoffStore }): void {\n if (store.focusEnd) store.focusEnd();\n else store.focusOnMount = true;\n}\n\n/**\n * Whether a composer write lands now: in thread-list mode the list has\n * resolved which thread is active, that thread's history has loaded, and the\n * chat's session lane is known (the sign-in provider above has resolved who is\n * signed in; see `StatewireSessionLane`). Until then the composer the hooks\n * write to is the one of a mount that is about to be replaced, and the draft\n * goes with it, or a send would go into a parked lane that refuses it unsent.\n *\n * Deliberately not the socket status: a never-started chat sits in\n * `standby` until its first send and must still take a prefill.\n */\nexport function useComposerReady(): boolean {\n const list = useAthenaStatewireThreadList();\n const threadLoading = useAuiState((s) => s.optional.thread?.isLoading ?? false);\n const lanePending = useStatewireSessionLanePending();\n return !(list?.isLoading ?? false) && !threadLoading && !lanePending;\n}\n\n/** The draft after `write`: `replace` (or an empty draft) takes the text as is. */\nexport function mergeComposerDraft({\n current,\n write,\n}: {\n current: string;\n write: Pick<ComposerWrite, 'text' | 'replace'>;\n}): string {\n if (write.replace || !current) return write.text;\n return `${current}\\n${write.text}`;\n}\n\n/**\n * Write into the live composer. Returns the send's outcome for a `send`\n * write so callers can await it.\n */\nexport function applyComposerWrite({\n target,\n store,\n write,\n}: {\n target: ComposerTarget;\n store: ComposerHandoffStore | null;\n write: ComposerWrite;\n}): Promise<void> | void {\n const current = target.composer.getState().text ?? '';\n const next = mergeComposerDraft({ current, write });\n target.composer.setText(next);\n if (write.focus && store) {\n // An unchanged draft never re-mirrors, so focus at once; otherwise the\n // editor focuses itself right after it has shown the new text.\n if (next === current) store.focusEnd?.();\n else store.focusOnNextMirror = true;\n }\n athenaDiagnostics.emit('composer.handoff', {\n level: 'debug',\n data: { phase: 'applied', send: write.send, focus: write.focus, chars: next.length },\n });\n if (write.send) {\n return Promise.resolve(target.composer.send({ steer: false })).then(() => undefined);\n }\n return undefined;\n}\n\n/**\n * Hold a write until the composer is ready. Writes keep their order; a plain\n * append folds into a directly preceding plain append for the same thread\n * (one draft, not two), while a replace or a send is kept as its own step so\n * no message is lost and every send settles on its own.\n */\nexport function queueComposerWrite({\n store,\n write,\n}: {\n store: ComposerHandoffStore;\n write: ComposerWrite;\n}): void {\n const last = store.pending[store.pending.length - 1];\n const foldable =\n last !== undefined &&\n !last.send &&\n !write.send &&\n !write.replace &&\n last.threadId === write.threadId &&\n last.resolve === undefined &&\n write.resolve === undefined;\n if (foldable) {\n last.text = mergeComposerDraft({ current: last.text, write });\n last.focus = last.focus || write.focus;\n } else {\n store.pending.push(write);\n }\n athenaDiagnostics.emit('composer.handoff', {\n level: 'debug',\n data: { phase: 'deferred', send: write.send, focus: write.focus, queued: store.pending.length },\n });\n}\n\nfunction dropWrite({ write, reason }: { write: ComposerWrite; reason: string }): void {\n const error = new AthenaSdkError({\n code: 'composer_write_dropped',\n message: `A composer ${write.send ? 'send' : 'draft'} queued before the chat was ready was dropped: ${reason}.`,\n hint: 'Make the write again from the chat that is active now.',\n context: { threadId: write.threadId, send: write.send },\n });\n athenaDiagnostics.emit('composer.handoff', {\n level: 'warn',\n error,\n data: { phase: 'dropped', send: write.send, reason, threadId: write.threadId },\n });\n write.reject?.(error);\n}\n\n/**\n * Deliver the pending writes, in order, into a now-ready composer. A write\n * made for another thread is dropped (rejected), never applied here.\n */\nexport function drainComposerHandoff({\n store,\n target,\n threadId,\n}: {\n store: ComposerHandoffStore;\n target: ComposerTarget;\n /** The statewire thread of the mount that is draining. */\n threadId: string | null;\n}): void {\n const writes = store.pending;\n if (writes.length === 0) return;\n store.pending = [];\n for (const write of writes) {\n if (write.threadId !== null && threadId !== null && write.threadId !== threadId) {\n dropWrite({ write, reason: `it was made for thread ${write.threadId}, thread ${threadId} is active` });\n continue;\n }\n const outcome = applyComposerWrite({ target, store, write });\n write.resolve?.(outcome);\n }\n}\n\n/** Drop every pending write (identity changed, provider unmounted). */\nexport function clearComposerHandoff({\n store,\n reason,\n}: {\n store: ComposerHandoffStore;\n reason: string;\n}): void {\n // Another identity, or no provider: the attachments given back belong to drafts that are gone.\n store.restoredAttachments?.clear();\n const writes = store.pending;\n if (writes.length === 0) return;\n store.pending = [];\n for (const write of writes) dropWrite({ write, reason });\n}\n"],"names":["createContext","useContext","useCallback","useAthenaStatewireThreadList","useAuiState","useStatewireSessionLanePending","athenaDiagnostics","AthenaSdkError"],"mappings":"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"}
@@ -3,7 +3,7 @@ export type { AppendToComposerOptions } from './useAppendToComposer';
3
3
  export { useSendMessage } from './useSendMessage';
4
4
  export type { SendMessageOptions } from './useSendMessage';
5
5
  export { useComposerReady, useFocusComposer } from './composer-handoff';
6
- export { useReadComposerDraft } from './useReadComposerDraft';
6
+ export { useReadComposerDraft, useTryReadComposerDraft } from './useReadComposerDraft';
7
7
  export { useComposerAttachment } from './useComposerAttachment';
8
8
  export { useFileUpload } from './useFileUpload';
9
9
  export type { UploadedAsset, UploadProgress, UseFileUploadReturn } from './useFileUpload';
@@ -1,17 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const react$1 = require("react");
3
+ const require$$0 = require("react");
4
4
  const react = require("@assistant-ui/react");
5
5
  const threadIdContext = require("../threads/thread-id-context.cjs");
6
6
  const composerHandoff = require("./composer-handoff.cjs");
7
7
  function useAppendToComposer() {
8
8
  const aui = react.useAui();
9
9
  const store = composerHandoff.useComposerHandoffStore();
10
- const threadId = react$1.useContext(threadIdContext.AthenaStatewireThreadIdContext);
10
+ const threadId = require$$0.useContext(threadIdContext.AthenaStatewireThreadIdContext);
11
11
  const ready = composerHandoff.useComposerReady();
12
- const readyRef = react$1.useRef(ready);
12
+ const readyRef = require$$0.useRef(ready);
13
13
  readyRef.current = ready;
14
- return react$1.useCallback(
14
+ return require$$0.useCallback(
15
15
  (text, opts) => {
16
16
  const write = {
17
17
  text,
@@ -1 +1 @@
1
- {"version":3,"file":"useAppendToComposer.cjs","sources":["../../src/composer/useAppendToComposer.ts"],"sourcesContent":["import { useCallback, useContext, useRef } from 'react';\nimport { useAui } from '@assistant-ui/react';\nimport { AthenaStatewireThreadIdContext } from '../threads/thread-id-context';\nimport {\n applyComposerWrite,\n queueComposerWrite,\n useComposerHandoffStore,\n useComposerReady,\n type ComposerWrite,\n} from './composer-handoff';\n\nexport interface AppendToComposerOptions {\n /** Replace the current draft instead of appending on a new line. */\n replace?: boolean;\n /**\n * Focus the composer with the caret after the text once the editor shows\n * it — for a prefilled draft the user is meant to finish by typing or\n * dictating. Defaults to false.\n */\n focus?: boolean;\n}\n\n/**\n * Hook to programmatically append text to the composer without sending it.\n *\n * Safe to call at any time: a write made before the chat is ready (the\n * thread list still resolving the active thread, or the thread's history\n * still loading) waits in the provider and lands once the composer is\n * ready, instead of being lost with the mount it was written into. A\n * never-started chat is ready without a live socket. The write is bound to\n * the thread it was made for: if the user switches threads first, it is\n * dropped (a `composer.handoff` diagnostic says so), never written into\n * another thread.\n *\n * Use `useSendMessage()` for workflow shortcuts or other UI that should\n * immediately submit a prompt.\n *\n * Usage:\n * const append = useAppendToComposer();\n * append(\"some text to add\");\n * append(\"quoted text\", { replace: true }); // replaces existing text\n * append(\"Here is what happened: \", { replace: true, focus: true }); // caret after the text\n */\nexport function useAppendToComposer() {\n const aui = useAui();\n const store = useComposerHandoffStore();\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const ready = useComposerReady();\n // The callback stays identity-stable across readiness changes.\n const readyRef = useRef(ready);\n readyRef.current = ready;\n\n return useCallback(\n (text: string, opts?: AppendToComposerOptions) => {\n const write: ComposerWrite = {\n text,\n replace: opts?.replace ?? false,\n send: false,\n focus: opts?.focus ?? false,\n threadId,\n };\n if (store && !readyRef.current) {\n queueComposerWrite({ store, write });\n return;\n }\n applyComposerWrite({ target: aui, store, write });\n },\n [aui, store, threadId],\n );\n}\n"],"names":["useAui","useComposerHandoffStore","useContext","AthenaStatewireThreadIdContext","useComposerReady","useRef","useCallback","queueComposerWrite","applyComposerWrite"],"mappings":";;;;;;AA2CO,SAAS,sBAAsB;AACpC,QAAM,MAAMA,MAAAA,OAAA;AACZ,QAAM,QAAQC,gBAAAA,wBAAA;AACd,QAAM,WAAWC,QAAAA,WAAWC,8CAA8B;AAC1D,QAAM,QAAQC,gBAAAA,iBAAA;AAEd,QAAM,WAAWC,QAAAA,OAAO,KAAK;AAC7B,WAAS,UAAU;AAEnB,SAAOC,QAAAA;AAAAA,IACL,CAAC,MAAc,SAAmC;AAChD,YAAM,QAAuB;AAAA,QAC3B;AAAA,QACA,UAAS,6BAAM,YAAW;AAAA,QAC1B,MAAM;AAAA,QACN,QAAO,6BAAM,UAAS;AAAA,QACtB;AAAA,MAAA;AAEF,UAAI,SAAS,CAAC,SAAS,SAAS;AAC9BC,2CAAmB,EAAE,OAAO,OAAO;AACnC;AAAA,MACF;AACAC,sBAAAA,mBAAmB,EAAE,QAAQ,KAAK,OAAO,OAAO;AAAA,IAClD;AAAA,IACA,CAAC,KAAK,OAAO,QAAQ;AAAA,EAAA;AAEzB;;"}
1
+ {"version":3,"file":"useAppendToComposer.cjs","sources":["../../src/composer/useAppendToComposer.ts"],"sourcesContent":["import { useCallback, useContext, useRef } from 'react';\nimport { useAui } from '@assistant-ui/react';\nimport { AthenaStatewireThreadIdContext } from '../threads/thread-id-context';\nimport {\n applyComposerWrite,\n queueComposerWrite,\n useComposerHandoffStore,\n useComposerReady,\n type ComposerWrite,\n} from './composer-handoff';\n\nexport interface AppendToComposerOptions {\n /** Replace the current draft instead of appending on a new line. */\n replace?: boolean;\n /**\n * Focus the composer with the caret after the text once the editor shows\n * it — for a prefilled draft the user is meant to finish by typing or\n * dictating. Defaults to false.\n */\n focus?: boolean;\n}\n\n/**\n * Hook to programmatically append text to the composer without sending it.\n *\n * Safe to call at any time: a write made before the chat is ready (the\n * thread list still resolving the active thread, or the thread's history\n * still loading) waits in the provider and lands once the composer is\n * ready, instead of being lost with the mount it was written into. A\n * never-started chat is ready without a live socket. The write is bound to\n * the thread it was made for: if the user switches threads first, it is\n * dropped (a `composer.handoff` diagnostic says so), never written into\n * another thread.\n *\n * Use `useSendMessage()` for workflow shortcuts or other UI that should\n * immediately submit a prompt.\n *\n * Usage:\n * const append = useAppendToComposer();\n * append(\"some text to add\");\n * append(\"quoted text\", { replace: true }); // replaces existing text\n * append(\"Here is what happened: \", { replace: true, focus: true }); // caret after the text\n */\nexport function useAppendToComposer() {\n const aui = useAui();\n const store = useComposerHandoffStore();\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const ready = useComposerReady();\n // The callback stays identity-stable across readiness changes.\n const readyRef = useRef(ready);\n readyRef.current = ready;\n\n return useCallback(\n (text: string, opts?: AppendToComposerOptions) => {\n const write: ComposerWrite = {\n text,\n replace: opts?.replace ?? false,\n send: false,\n focus: opts?.focus ?? false,\n threadId,\n };\n if (store && !readyRef.current) {\n queueComposerWrite({ store, write });\n return;\n }\n applyComposerWrite({ target: aui, store, write });\n },\n [aui, store, threadId],\n );\n}\n"],"names":["useAui","useComposerHandoffStore","useContext","AthenaStatewireThreadIdContext","useComposerReady","useRef","useCallback","queueComposerWrite","applyComposerWrite"],"mappings":";;;;;;AA2CO,SAAS,sBAAsB;AACpC,QAAM,MAAMA,MAAAA,OAAA;AACZ,QAAM,QAAQC,gBAAAA,wBAAA;AACd,QAAM,WAAWC,WAAAA,WAAWC,8CAA8B;AAC1D,QAAM,QAAQC,gBAAAA,iBAAA;AAEd,QAAM,WAAWC,WAAAA,OAAO,KAAK;AAC7B,WAAS,UAAU;AAEnB,SAAOC,WAAAA;AAAAA,IACL,CAAC,MAAc,SAAmC;AAChD,YAAM,QAAuB;AAAA,QAC3B;AAAA,QACA,UAAS,6BAAM,YAAW;AAAA,QAC1B,MAAM;AAAA,QACN,QAAO,6BAAM,UAAS;AAAA,QACtB;AAAA,MAAA;AAEF,UAAI,SAAS,CAAC,SAAS,SAAS;AAC9BC,2CAAmB,EAAE,OAAO,OAAO;AACnC;AAAA,MACF;AACAC,sBAAAA,mBAAmB,EAAE,QAAQ,KAAK,OAAO,OAAO;AAAA,IAClD;AAAA,IACA,CAAC,KAAK,OAAO,QAAQ;AAAA,EAAA;AAEzB;;"}
@@ -1,25 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const react = require("react");
3
+ const require$$0 = require("react");
4
+ const offlineStatus = require("../agent-runtime/src/offline-status.cjs");
4
5
  const athenaDiagnostics = require("../diagnostics/athena-diagnostics.cjs");
5
6
  const AttachmentContext = require("./AttachmentContext.cjs");
6
7
  const useFileUpload = require("./useFileUpload.cjs");
7
8
  const useDeepAgentChatOutbox = require("../agent-runtime/src/use-deep-agent-chat-outbox.cjs");
8
- const OFFLINE_FILE_ATTACH_MESSAGE = "Files can't be attached while Athena can't be reached. Messages you send now go out when it's back — attach the file then.";
9
9
  const ATTACH_FAILURE_MESSAGE = {
10
10
  paperclip: "Failed to attach the selected files",
11
11
  drop: "Failed to attach the dropped files",
12
12
  paste: "Failed to attach the pasted images"
13
13
  };
14
+ function withPicturePreviews({
15
+ assets,
16
+ files
17
+ }) {
18
+ if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") return assets;
19
+ const unclaimed = [...files];
20
+ const positional = assets.length === files.length;
21
+ const claim = (file) => {
22
+ const at = file === void 0 ? -1 : unclaimed.indexOf(file);
23
+ return at === -1 ? void 0 : unclaimed.splice(at, 1)[0];
24
+ };
25
+ return assets.map((asset, index) => {
26
+ const file = asset.fileIndex !== void 0 ? claim(files[asset.fileIndex]) : claim(unclaimed.find((candidate) => candidate.name === asset.fileName)) ?? (positional ? claim(files[index]) : void 0);
27
+ if (!file || !file.type.startsWith("image/")) return asset;
28
+ return { ...asset, previewUrl: URL.createObjectURL(file) };
29
+ });
30
+ }
14
31
  function useAttachFiles() {
15
32
  const { upload, isUploading, error, clearError } = useFileUpload.useFileUpload();
16
33
  const { addAttachments, setIsUploading, setNotice } = AttachmentContext.useAttachments();
17
34
  const outbox = useDeepAgentChatOutbox.useDeepAgentChatOutboxContext();
18
- const attachFiles = react.useCallback(
35
+ const attachFiles = require$$0.useCallback(
19
36
  async (files, source) => {
20
37
  if (files.length === 0) return [];
21
38
  if (outbox && !outbox.reachability.get()) {
22
- setNotice(OFFLINE_FILE_ATTACH_MESSAGE);
39
+ setNotice(offlineStatus.attachmentNeedsConnection({ kind: "file", messagesWait: true }));
23
40
  athenaDiagnostics.athenaDiagnostics.emit("composer.attachment.refused_offline", {
24
41
  level: "info",
25
42
  data: { source, count: files.length }
@@ -29,7 +46,7 @@ function useAttachFiles() {
29
46
  setNotice(null);
30
47
  setIsUploading(true);
31
48
  try {
32
- const assets = await upload([...files]);
49
+ const assets = withPicturePreviews({ assets: await upload([...files]), files });
33
50
  if (assets.length > 0) addAttachments(assets);
34
51
  return assets;
35
52
  } catch (error2) {
@@ -48,6 +65,6 @@ function useAttachFiles() {
48
65
  );
49
66
  return { attachFiles, isUploading, error, clearError };
50
67
  }
51
- exports.OFFLINE_FILE_ATTACH_MESSAGE = OFFLINE_FILE_ATTACH_MESSAGE;
52
68
  exports.useAttachFiles = useAttachFiles;
69
+ exports.withPicturePreviews = withPicturePreviews;
53
70
  //# sourceMappingURL=useAttachFiles.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAttachFiles.cjs","sources":["../../src/composer/useAttachFiles.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useDeepAgentChatOutboxContext } from '@athenaintel/agent-runtime';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { useAttachments } from './AttachmentContext';\nimport { useFileUpload, type UploadedAsset } from './useFileUpload';\n\n/**\n * What the composer says when a file is picked, pasted or dropped while Athena can't be reached\n * (the same words as Olympus's): the upload cannot happen, and a message sent now waits in the chat\n * outbox with only the files that were already uploaded.\n */\nexport const OFFLINE_FILE_ATTACH_MESSAGE =\n \"Files can't be attached while Athena can't be reached. Messages you send now go out when it's back — attach the file then.\";\n\n/** Which intake the files came through — carried on the diagnostics event. */\nexport type AttachFilesSource = 'paperclip' | 'drop' | 'paste';\n\nconst ATTACH_FAILURE_MESSAGE: Record<AttachFilesSource, string> = {\n paperclip: 'Failed to attach the selected files',\n drop: 'Failed to attach the dropped files',\n paste: 'Failed to attach the pasted images',\n};\n\nexport interface UseAttachFilesReturn {\n /**\n * Upload files as Athena assets and add them to the attachment pills.\n * Resolves to the assets attached; a failed upload resolves to `[]` after\n * recording `composer.attachment.error` on the diagnostics bus (and in\n * `error`).\n */\n attachFiles: (files: readonly File[], source: AttachFilesSource) => Promise<UploadedAsset[]>;\n /** This intake's own upload in flight. */\n isUploading: boolean;\n /** Last failure of this intake, for its own affordance. */\n error: string | null;\n clearError: () => void;\n}\n\n/**\n * The one intake path for the attachment pills: the paperclip, the drop zone\n * and the composer's paste all upload through here, so a failure reaches the\n * diagnostics bus the same way and the shared `isUploading` flag — which\n * parks every submit path — is set for exactly the upload's duration.\n *\n * While the chat's outbox (a host's `chatOutbox`) says Athena can't be\n * reached, a file is not attached: its upload could only fail, and a message\n * that waits to be sent carries only files already uploaded. The composer\n * says so (`notice`, {@link OFFLINE_FILE_ATTACH_MESSAGE}).\n */\nexport function useAttachFiles(): UseAttachFilesReturn {\n const { upload, isUploading, error, clearError } = useFileUpload();\n const { addAttachments, setIsUploading, setNotice } = useAttachments();\n const outbox = useDeepAgentChatOutboxContext();\n\n const attachFiles = useCallback(\n async (files: readonly File[], source: AttachFilesSource): Promise<UploadedAsset[]> => {\n if (files.length === 0) return [];\n if (outbox && !outbox.reachability.get()) {\n setNotice(OFFLINE_FILE_ATTACH_MESSAGE);\n athenaDiagnostics.emit('composer.attachment.refused_offline', {\n level: 'info',\n data: { source, count: files.length },\n });\n return [];\n }\n setNotice(null);\n setIsUploading(true);\n try {\n const assets = await upload([...files]);\n if (assets.length > 0) addAttachments(assets);\n return assets;\n } catch (error) {\n athenaDiagnostics.error(\n 'composer.attachment.error',\n error,\n { code: 'attachment_failed', message: ATTACH_FAILURE_MESSAGE[source] },\n { source, count: files.length },\n );\n return [];\n } finally {\n setIsUploading(false);\n }\n },\n [addAttachments, outbox, setIsUploading, setNotice, upload],\n );\n\n return { attachFiles, isUploading, error, clearError };\n}\n"],"names":["useFileUpload","useAttachments","useDeepAgentChatOutboxContext","useCallback","athenaDiagnostics","error"],"mappings":";;;;;;;AAWO,MAAM,8BACX;AAKF,MAAM,yBAA4D;AAAA,EAChE,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AACT;AA4BO,SAAS,iBAAuC;AACrD,QAAM,EAAE,QAAQ,aAAa,OAAO,WAAA,IAAeA,cAAAA,cAAA;AACnD,QAAM,EAAE,gBAAgB,gBAAgB,UAAA,IAAcC,kBAAAA,eAAA;AACtD,QAAM,SAASC,uBAAAA,8BAAA;AAEf,QAAM,cAAcC,MAAAA;AAAAA,IAClB,OAAO,OAAwB,WAAwD;AACrF,UAAI,MAAM,WAAW,EAAG,QAAO,CAAA;AAC/B,UAAI,UAAU,CAAC,OAAO,aAAa,OAAO;AACxC,kBAAU,2BAA2B;AACrCC,0BAAAA,kBAAkB,KAAK,uCAAuC;AAAA,UAC5D,OAAO;AAAA,UACP,MAAM,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO,CACrC;AACD,eAAO,CAAA;AAAA,MACT;AACA,gBAAU,IAAI;AACd,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,CAAC,GAAG,KAAK,CAAC;AACtC,YAAI,OAAO,SAAS,EAAG,gBAAe,MAAM;AAC5C,eAAO;AAAA,MACT,SAASC,QAAO;AACdD,0BAAAA,kBAAkB;AAAA,UAChB;AAAA,UACAC;AAAAA,UACA,EAAE,MAAM,qBAAqB,SAAS,uBAAuB,MAAM,EAAA;AAAA,UACnE,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO;AAEhC,eAAO,CAAA;AAAA,MACT,UAAA;AACE,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,QAAQ,gBAAgB,WAAW,MAAM;AAAA,EAAA;AAG5D,SAAO,EAAE,aAAa,aAAa,OAAO,WAAA;AAC5C;;;"}
1
+ {"version":3,"file":"useAttachFiles.cjs","sources":["../../src/composer/useAttachFiles.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useDeepAgentChatOutboxContext } from '@athenaintel/agent-runtime';\nimport { attachmentNeedsConnection } from '@athenaintel/agent-runtime/offline-status';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { useAttachments } from './AttachmentContext';\nimport { useFileUpload, type UploadedAsset } from './useFileUpload';\n\n/** Which intake the files came through — carried on the diagnostics event. */\nexport type AttachFilesSource = 'paperclip' | 'drop' | 'paste';\n\nconst ATTACH_FAILURE_MESSAGE: Record<AttachFilesSource, string> = {\n paperclip: 'Failed to attach the selected files',\n drop: 'Failed to attach the dropped files',\n paste: 'Failed to attach the pasted images',\n};\n\nexport interface UseAttachFilesReturn {\n /**\n * Upload files as Athena assets and add them to the attachment pills.\n * Resolves to the assets attached; a failed upload resolves to `[]` after\n * recording `composer.attachment.error` on the diagnostics bus (and in\n * `error`).\n */\n attachFiles: (files: readonly File[], source: AttachFilesSource) => Promise<UploadedAsset[]>;\n /** This intake's own upload in flight. */\n isUploading: boolean;\n /** Last failure of this intake, for its own affordance. */\n error: string | null;\n clearError: () => void;\n}\n\n/**\n * `assets` with a local preview of each picture among `files`, so the draft\n * shows the picture itself and opens it full screen before anything is sent.\n * Each asset takes the file the upload says it came from (`fileIndex`); from a\n * server that does not say, the file of the same name, else the one at the\n * same position when every file came back. Other files, and a browser without\n * object URLs, keep the name pill.\n */\nexport function withPicturePreviews({\n assets,\n files,\n}: {\n assets: UploadedAsset[];\n files: readonly File[];\n}): UploadedAsset[] {\n if (typeof URL === 'undefined' || typeof URL.createObjectURL !== 'function') return assets;\n const unclaimed = [...files];\n const positional = assets.length === files.length;\n const claim = (file: File | undefined): File | undefined => {\n const at = file === undefined ? -1 : unclaimed.indexOf(file);\n return at === -1 ? undefined : unclaimed.splice(at, 1)[0];\n };\n return assets.map((asset, index) => {\n const file =\n asset.fileIndex !== undefined\n ? claim(files[asset.fileIndex])\n : (claim(unclaimed.find((candidate) => candidate.name === asset.fileName)) ??\n (positional ? claim(files[index]) : undefined));\n if (!file || !file.type.startsWith('image/')) return asset;\n return { ...asset, previewUrl: URL.createObjectURL(file) };\n });\n}\n\n/**\n * The one intake path for the attachment pills: the paperclip, the drop zone\n * and the composer's paste all upload through here, so a failure reaches the\n * diagnostics bus the same way and the shared `isUploading` flag — which\n * parks every submit path — is set for exactly the upload's duration.\n *\n * While the chat's outbox (a host's `chatOutbox`) says Athena can't be\n * reached, a file is not attached: its upload could only fail, and a message\n * that waits to be sent carries only files already uploaded. The composer\n * says so (`notice`) in the words every Athena app uses\n * (`attachmentNeedsConnection`, `@athenaintel/agent-runtime/offline-status`):\n * the message still goes, since the outbox keeps it.\n */\nexport function useAttachFiles(): UseAttachFilesReturn {\n const { upload, isUploading, error, clearError } = useFileUpload();\n const { addAttachments, setIsUploading, setNotice } = useAttachments();\n const outbox = useDeepAgentChatOutboxContext();\n\n const attachFiles = useCallback(\n async (files: readonly File[], source: AttachFilesSource): Promise<UploadedAsset[]> => {\n if (files.length === 0) return [];\n if (outbox && !outbox.reachability.get()) {\n setNotice(attachmentNeedsConnection({ kind: 'file', messagesWait: true }));\n athenaDiagnostics.emit('composer.attachment.refused_offline', {\n level: 'info',\n data: { source, count: files.length },\n });\n return [];\n }\n setNotice(null);\n setIsUploading(true);\n try {\n const assets = withPicturePreviews({ assets: await upload([...files]), files });\n if (assets.length > 0) addAttachments(assets);\n return assets;\n } catch (error) {\n athenaDiagnostics.error(\n 'composer.attachment.error',\n error,\n { code: 'attachment_failed', message: ATTACH_FAILURE_MESSAGE[source] },\n { source, count: files.length },\n );\n return [];\n } finally {\n setIsUploading(false);\n }\n },\n [addAttachments, outbox, setIsUploading, setNotice, upload],\n );\n\n return { attachFiles, isUploading, error, clearError };\n}\n"],"names":["useFileUpload","useAttachments","useDeepAgentChatOutboxContext","useCallback","attachmentNeedsConnection","athenaDiagnostics","error"],"mappings":";;;;;;;;AAUA,MAAM,yBAA4D;AAAA,EAChE,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AACT;AAyBO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGoB;AAClB,MAAI,OAAO,QAAQ,eAAe,OAAO,IAAI,oBAAoB,WAAY,QAAO;AACpF,QAAM,YAAY,CAAC,GAAG,KAAK;AAC3B,QAAM,aAAa,OAAO,WAAW,MAAM;AAC3C,QAAM,QAAQ,CAAC,SAA6C;AAC1D,UAAM,KAAK,SAAS,SAAY,KAAK,UAAU,QAAQ,IAAI;AAC3D,WAAO,OAAO,KAAK,SAAY,UAAU,OAAO,IAAI,CAAC,EAAE,CAAC;AAAA,EAC1D;AACA,SAAO,OAAO,IAAI,CAAC,OAAO,UAAU;AAClC,UAAM,OACJ,MAAM,cAAc,SAChB,MAAM,MAAM,MAAM,SAAS,CAAC,IAC3B,MAAM,UAAU,KAAK,CAAC,cAAc,UAAU,SAAS,MAAM,QAAQ,CAAC,MACtE,aAAa,MAAM,MAAM,KAAK,CAAC,IAAI;AAC1C,QAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,WAAW,QAAQ,EAAG,QAAO;AACrD,WAAO,EAAE,GAAG,OAAO,YAAY,IAAI,gBAAgB,IAAI,EAAA;AAAA,EACzD,CAAC;AACH;AAeO,SAAS,iBAAuC;AACrD,QAAM,EAAE,QAAQ,aAAa,OAAO,WAAA,IAAeA,cAAAA,cAAA;AACnD,QAAM,EAAE,gBAAgB,gBAAgB,UAAA,IAAcC,kBAAAA,eAAA;AACtD,QAAM,SAASC,uBAAAA,8BAAA;AAEf,QAAM,cAAcC,WAAAA;AAAAA,IAClB,OAAO,OAAwB,WAAwD;AACrF,UAAI,MAAM,WAAW,EAAG,QAAO,CAAA;AAC/B,UAAI,UAAU,CAAC,OAAO,aAAa,OAAO;AACxC,kBAAUC,cAAAA,0BAA0B,EAAE,MAAM,QAAQ,cAAc,KAAA,CAAM,CAAC;AACzEC,0BAAAA,kBAAkB,KAAK,uCAAuC;AAAA,UAC5D,OAAO;AAAA,UACP,MAAM,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO,CACrC;AACD,eAAO,CAAA;AAAA,MACT;AACA,gBAAU,IAAI;AACd,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,SAAS,oBAAoB,EAAE,QAAQ,MAAM,OAAO,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO;AAC9E,YAAI,OAAO,SAAS,EAAG,gBAAe,MAAM;AAC5C,eAAO;AAAA,MACT,SAASC,QAAO;AACdD,0BAAAA,kBAAkB;AAAA,UAChB;AAAA,UACAC;AAAAA,UACA,EAAE,MAAM,qBAAqB,SAAS,uBAAuB,MAAM,EAAA;AAAA,UACnE,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO;AAEhC,eAAO,CAAA;AAAA,MACT,UAAA;AACE,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,QAAQ,gBAAgB,WAAW,MAAM;AAAA,EAAA;AAG5D,SAAO,EAAE,aAAa,aAAa,OAAO,WAAA;AAC5C;;;"}
@@ -1,10 +1,4 @@
1
1
  import { type UploadedAsset } from './useFileUpload';
2
- /**
3
- * What the composer says when a file is picked, pasted or dropped while Athena can't be reached
4
- * (the same words as Olympus's): the upload cannot happen, and a message sent now waits in the chat
5
- * outbox with only the files that were already uploaded.
6
- */
7
- export declare const OFFLINE_FILE_ATTACH_MESSAGE = "Files can't be attached while Athena can't be reached. Messages you send now go out when it's back \u2014 attach the file then.";
8
2
  /** Which intake the files came through — carried on the diagnostics event. */
9
3
  export type AttachFilesSource = 'paperclip' | 'drop' | 'paste';
10
4
  export interface UseAttachFilesReturn {
@@ -21,6 +15,18 @@ export interface UseAttachFilesReturn {
21
15
  error: string | null;
22
16
  clearError: () => void;
23
17
  }
18
+ /**
19
+ * `assets` with a local preview of each picture among `files`, so the draft
20
+ * shows the picture itself and opens it full screen before anything is sent.
21
+ * Each asset takes the file the upload says it came from (`fileIndex`); from a
22
+ * server that does not say, the file of the same name, else the one at the
23
+ * same position when every file came back. Other files, and a browser without
24
+ * object URLs, keep the name pill.
25
+ */
26
+ export declare function withPicturePreviews({ assets, files, }: {
27
+ assets: UploadedAsset[];
28
+ files: readonly File[];
29
+ }): UploadedAsset[];
24
30
  /**
25
31
  * The one intake path for the attachment pills: the paperclip, the drop zone
26
32
  * and the composer's paste all upload through here, so a failure reaches the
@@ -30,6 +36,8 @@ export interface UseAttachFilesReturn {
30
36
  * While the chat's outbox (a host's `chatOutbox`) says Athena can't be
31
37
  * reached, a file is not attached: its upload could only fail, and a message
32
38
  * that waits to be sent carries only files already uploaded. The composer
33
- * says so (`notice`, {@link OFFLINE_FILE_ATTACH_MESSAGE}).
39
+ * says so (`notice`) in the words every Athena app uses
40
+ * (`attachmentNeedsConnection`, `@athenaintel/agent-runtime/offline-status`):
41
+ * the message still goes, since the outbox keeps it.
34
42
  */
35
43
  export declare function useAttachFiles(): UseAttachFilesReturn;
@@ -1,14 +1,31 @@
1
1
  import { useCallback } from "react";
2
+ import { attachmentNeedsConnection } from "../agent-runtime/src/offline-status.js";
2
3
  import { athenaDiagnostics } from "../diagnostics/athena-diagnostics.js";
3
4
  import { useAttachments } from "./AttachmentContext.js";
4
5
  import { useFileUpload } from "./useFileUpload.js";
5
6
  import { useDeepAgentChatOutboxContext } from "../agent-runtime/src/use-deep-agent-chat-outbox.js";
6
- const OFFLINE_FILE_ATTACH_MESSAGE = "Files can't be attached while Athena can't be reached. Messages you send now go out when it's back — attach the file then.";
7
7
  const ATTACH_FAILURE_MESSAGE = {
8
8
  paperclip: "Failed to attach the selected files",
9
9
  drop: "Failed to attach the dropped files",
10
10
  paste: "Failed to attach the pasted images"
11
11
  };
12
+ function withPicturePreviews({
13
+ assets,
14
+ files
15
+ }) {
16
+ if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") return assets;
17
+ const unclaimed = [...files];
18
+ const positional = assets.length === files.length;
19
+ const claim = (file) => {
20
+ const at = file === void 0 ? -1 : unclaimed.indexOf(file);
21
+ return at === -1 ? void 0 : unclaimed.splice(at, 1)[0];
22
+ };
23
+ return assets.map((asset, index) => {
24
+ const file = asset.fileIndex !== void 0 ? claim(files[asset.fileIndex]) : claim(unclaimed.find((candidate) => candidate.name === asset.fileName)) ?? (positional ? claim(files[index]) : void 0);
25
+ if (!file || !file.type.startsWith("image/")) return asset;
26
+ return { ...asset, previewUrl: URL.createObjectURL(file) };
27
+ });
28
+ }
12
29
  function useAttachFiles() {
13
30
  const { upload, isUploading, error, clearError } = useFileUpload();
14
31
  const { addAttachments, setIsUploading, setNotice } = useAttachments();
@@ -17,7 +34,7 @@ function useAttachFiles() {
17
34
  async (files, source) => {
18
35
  if (files.length === 0) return [];
19
36
  if (outbox && !outbox.reachability.get()) {
20
- setNotice(OFFLINE_FILE_ATTACH_MESSAGE);
37
+ setNotice(attachmentNeedsConnection({ kind: "file", messagesWait: true }));
21
38
  athenaDiagnostics.emit("composer.attachment.refused_offline", {
22
39
  level: "info",
23
40
  data: { source, count: files.length }
@@ -27,7 +44,7 @@ function useAttachFiles() {
27
44
  setNotice(null);
28
45
  setIsUploading(true);
29
46
  try {
30
- const assets = await upload([...files]);
47
+ const assets = withPicturePreviews({ assets: await upload([...files]), files });
31
48
  if (assets.length > 0) addAttachments(assets);
32
49
  return assets;
33
50
  } catch (error2) {
@@ -47,7 +64,7 @@ function useAttachFiles() {
47
64
  return { attachFiles, isUploading, error, clearError };
48
65
  }
49
66
  export {
50
- OFFLINE_FILE_ATTACH_MESSAGE,
51
- useAttachFiles
67
+ useAttachFiles,
68
+ withPicturePreviews
52
69
  };
53
70
  //# sourceMappingURL=useAttachFiles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAttachFiles.js","sources":["../../src/composer/useAttachFiles.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useDeepAgentChatOutboxContext } from '@athenaintel/agent-runtime';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { useAttachments } from './AttachmentContext';\nimport { useFileUpload, type UploadedAsset } from './useFileUpload';\n\n/**\n * What the composer says when a file is picked, pasted or dropped while Athena can't be reached\n * (the same words as Olympus's): the upload cannot happen, and a message sent now waits in the chat\n * outbox with only the files that were already uploaded.\n */\nexport const OFFLINE_FILE_ATTACH_MESSAGE =\n \"Files can't be attached while Athena can't be reached. Messages you send now go out when it's back — attach the file then.\";\n\n/** Which intake the files came through — carried on the diagnostics event. */\nexport type AttachFilesSource = 'paperclip' | 'drop' | 'paste';\n\nconst ATTACH_FAILURE_MESSAGE: Record<AttachFilesSource, string> = {\n paperclip: 'Failed to attach the selected files',\n drop: 'Failed to attach the dropped files',\n paste: 'Failed to attach the pasted images',\n};\n\nexport interface UseAttachFilesReturn {\n /**\n * Upload files as Athena assets and add them to the attachment pills.\n * Resolves to the assets attached; a failed upload resolves to `[]` after\n * recording `composer.attachment.error` on the diagnostics bus (and in\n * `error`).\n */\n attachFiles: (files: readonly File[], source: AttachFilesSource) => Promise<UploadedAsset[]>;\n /** This intake's own upload in flight. */\n isUploading: boolean;\n /** Last failure of this intake, for its own affordance. */\n error: string | null;\n clearError: () => void;\n}\n\n/**\n * The one intake path for the attachment pills: the paperclip, the drop zone\n * and the composer's paste all upload through here, so a failure reaches the\n * diagnostics bus the same way and the shared `isUploading` flag — which\n * parks every submit path — is set for exactly the upload's duration.\n *\n * While the chat's outbox (a host's `chatOutbox`) says Athena can't be\n * reached, a file is not attached: its upload could only fail, and a message\n * that waits to be sent carries only files already uploaded. The composer\n * says so (`notice`, {@link OFFLINE_FILE_ATTACH_MESSAGE}).\n */\nexport function useAttachFiles(): UseAttachFilesReturn {\n const { upload, isUploading, error, clearError } = useFileUpload();\n const { addAttachments, setIsUploading, setNotice } = useAttachments();\n const outbox = useDeepAgentChatOutboxContext();\n\n const attachFiles = useCallback(\n async (files: readonly File[], source: AttachFilesSource): Promise<UploadedAsset[]> => {\n if (files.length === 0) return [];\n if (outbox && !outbox.reachability.get()) {\n setNotice(OFFLINE_FILE_ATTACH_MESSAGE);\n athenaDiagnostics.emit('composer.attachment.refused_offline', {\n level: 'info',\n data: { source, count: files.length },\n });\n return [];\n }\n setNotice(null);\n setIsUploading(true);\n try {\n const assets = await upload([...files]);\n if (assets.length > 0) addAttachments(assets);\n return assets;\n } catch (error) {\n athenaDiagnostics.error(\n 'composer.attachment.error',\n error,\n { code: 'attachment_failed', message: ATTACH_FAILURE_MESSAGE[source] },\n { source, count: files.length },\n );\n return [];\n } finally {\n setIsUploading(false);\n }\n },\n [addAttachments, outbox, setIsUploading, setNotice, upload],\n );\n\n return { attachFiles, isUploading, error, clearError };\n}\n"],"names":["error"],"mappings":";;;;;AAWO,MAAM,8BACX;AAKF,MAAM,yBAA4D;AAAA,EAChE,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AACT;AA4BO,SAAS,iBAAuC;AACrD,QAAM,EAAE,QAAQ,aAAa,OAAO,WAAA,IAAe,cAAA;AACnD,QAAM,EAAE,gBAAgB,gBAAgB,UAAA,IAAc,eAAA;AACtD,QAAM,SAAS,8BAAA;AAEf,QAAM,cAAc;AAAA,IAClB,OAAO,OAAwB,WAAwD;AACrF,UAAI,MAAM,WAAW,EAAG,QAAO,CAAA;AAC/B,UAAI,UAAU,CAAC,OAAO,aAAa,OAAO;AACxC,kBAAU,2BAA2B;AACrC,0BAAkB,KAAK,uCAAuC;AAAA,UAC5D,OAAO;AAAA,UACP,MAAM,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO,CACrC;AACD,eAAO,CAAA;AAAA,MACT;AACA,gBAAU,IAAI;AACd,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,CAAC,GAAG,KAAK,CAAC;AACtC,YAAI,OAAO,SAAS,EAAG,gBAAe,MAAM;AAC5C,eAAO;AAAA,MACT,SAASA,QAAO;AACd,0BAAkB;AAAA,UAChB;AAAA,UACAA;AAAAA,UACA,EAAE,MAAM,qBAAqB,SAAS,uBAAuB,MAAM,EAAA;AAAA,UACnE,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO;AAEhC,eAAO,CAAA;AAAA,MACT,UAAA;AACE,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,QAAQ,gBAAgB,WAAW,MAAM;AAAA,EAAA;AAG5D,SAAO,EAAE,aAAa,aAAa,OAAO,WAAA;AAC5C;"}
1
+ {"version":3,"file":"useAttachFiles.js","sources":["../../src/composer/useAttachFiles.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useDeepAgentChatOutboxContext } from '@athenaintel/agent-runtime';\nimport { attachmentNeedsConnection } from '@athenaintel/agent-runtime/offline-status';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { useAttachments } from './AttachmentContext';\nimport { useFileUpload, type UploadedAsset } from './useFileUpload';\n\n/** Which intake the files came through — carried on the diagnostics event. */\nexport type AttachFilesSource = 'paperclip' | 'drop' | 'paste';\n\nconst ATTACH_FAILURE_MESSAGE: Record<AttachFilesSource, string> = {\n paperclip: 'Failed to attach the selected files',\n drop: 'Failed to attach the dropped files',\n paste: 'Failed to attach the pasted images',\n};\n\nexport interface UseAttachFilesReturn {\n /**\n * Upload files as Athena assets and add them to the attachment pills.\n * Resolves to the assets attached; a failed upload resolves to `[]` after\n * recording `composer.attachment.error` on the diagnostics bus (and in\n * `error`).\n */\n attachFiles: (files: readonly File[], source: AttachFilesSource) => Promise<UploadedAsset[]>;\n /** This intake's own upload in flight. */\n isUploading: boolean;\n /** Last failure of this intake, for its own affordance. */\n error: string | null;\n clearError: () => void;\n}\n\n/**\n * `assets` with a local preview of each picture among `files`, so the draft\n * shows the picture itself and opens it full screen before anything is sent.\n * Each asset takes the file the upload says it came from (`fileIndex`); from a\n * server that does not say, the file of the same name, else the one at the\n * same position when every file came back. Other files, and a browser without\n * object URLs, keep the name pill.\n */\nexport function withPicturePreviews({\n assets,\n files,\n}: {\n assets: UploadedAsset[];\n files: readonly File[];\n}): UploadedAsset[] {\n if (typeof URL === 'undefined' || typeof URL.createObjectURL !== 'function') return assets;\n const unclaimed = [...files];\n const positional = assets.length === files.length;\n const claim = (file: File | undefined): File | undefined => {\n const at = file === undefined ? -1 : unclaimed.indexOf(file);\n return at === -1 ? undefined : unclaimed.splice(at, 1)[0];\n };\n return assets.map((asset, index) => {\n const file =\n asset.fileIndex !== undefined\n ? claim(files[asset.fileIndex])\n : (claim(unclaimed.find((candidate) => candidate.name === asset.fileName)) ??\n (positional ? claim(files[index]) : undefined));\n if (!file || !file.type.startsWith('image/')) return asset;\n return { ...asset, previewUrl: URL.createObjectURL(file) };\n });\n}\n\n/**\n * The one intake path for the attachment pills: the paperclip, the drop zone\n * and the composer's paste all upload through here, so a failure reaches the\n * diagnostics bus the same way and the shared `isUploading` flag — which\n * parks every submit path — is set for exactly the upload's duration.\n *\n * While the chat's outbox (a host's `chatOutbox`) says Athena can't be\n * reached, a file is not attached: its upload could only fail, and a message\n * that waits to be sent carries only files already uploaded. The composer\n * says so (`notice`) in the words every Athena app uses\n * (`attachmentNeedsConnection`, `@athenaintel/agent-runtime/offline-status`):\n * the message still goes, since the outbox keeps it.\n */\nexport function useAttachFiles(): UseAttachFilesReturn {\n const { upload, isUploading, error, clearError } = useFileUpload();\n const { addAttachments, setIsUploading, setNotice } = useAttachments();\n const outbox = useDeepAgentChatOutboxContext();\n\n const attachFiles = useCallback(\n async (files: readonly File[], source: AttachFilesSource): Promise<UploadedAsset[]> => {\n if (files.length === 0) return [];\n if (outbox && !outbox.reachability.get()) {\n setNotice(attachmentNeedsConnection({ kind: 'file', messagesWait: true }));\n athenaDiagnostics.emit('composer.attachment.refused_offline', {\n level: 'info',\n data: { source, count: files.length },\n });\n return [];\n }\n setNotice(null);\n setIsUploading(true);\n try {\n const assets = withPicturePreviews({ assets: await upload([...files]), files });\n if (assets.length > 0) addAttachments(assets);\n return assets;\n } catch (error) {\n athenaDiagnostics.error(\n 'composer.attachment.error',\n error,\n { code: 'attachment_failed', message: ATTACH_FAILURE_MESSAGE[source] },\n { source, count: files.length },\n );\n return [];\n } finally {\n setIsUploading(false);\n }\n },\n [addAttachments, outbox, setIsUploading, setNotice, upload],\n );\n\n return { attachFiles, isUploading, error, clearError };\n}\n"],"names":["error"],"mappings":";;;;;;AAUA,MAAM,yBAA4D;AAAA,EAChE,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AACT;AAyBO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGoB;AAClB,MAAI,OAAO,QAAQ,eAAe,OAAO,IAAI,oBAAoB,WAAY,QAAO;AACpF,QAAM,YAAY,CAAC,GAAG,KAAK;AAC3B,QAAM,aAAa,OAAO,WAAW,MAAM;AAC3C,QAAM,QAAQ,CAAC,SAA6C;AAC1D,UAAM,KAAK,SAAS,SAAY,KAAK,UAAU,QAAQ,IAAI;AAC3D,WAAO,OAAO,KAAK,SAAY,UAAU,OAAO,IAAI,CAAC,EAAE,CAAC;AAAA,EAC1D;AACA,SAAO,OAAO,IAAI,CAAC,OAAO,UAAU;AAClC,UAAM,OACJ,MAAM,cAAc,SAChB,MAAM,MAAM,MAAM,SAAS,CAAC,IAC3B,MAAM,UAAU,KAAK,CAAC,cAAc,UAAU,SAAS,MAAM,QAAQ,CAAC,MACtE,aAAa,MAAM,MAAM,KAAK,CAAC,IAAI;AAC1C,QAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,WAAW,QAAQ,EAAG,QAAO;AACrD,WAAO,EAAE,GAAG,OAAO,YAAY,IAAI,gBAAgB,IAAI,EAAA;AAAA,EACzD,CAAC;AACH;AAeO,SAAS,iBAAuC;AACrD,QAAM,EAAE,QAAQ,aAAa,OAAO,WAAA,IAAe,cAAA;AACnD,QAAM,EAAE,gBAAgB,gBAAgB,UAAA,IAAc,eAAA;AACtD,QAAM,SAAS,8BAAA;AAEf,QAAM,cAAc;AAAA,IAClB,OAAO,OAAwB,WAAwD;AACrF,UAAI,MAAM,WAAW,EAAG,QAAO,CAAA;AAC/B,UAAI,UAAU,CAAC,OAAO,aAAa,OAAO;AACxC,kBAAU,0BAA0B,EAAE,MAAM,QAAQ,cAAc,KAAA,CAAM,CAAC;AACzE,0BAAkB,KAAK,uCAAuC;AAAA,UAC5D,OAAO;AAAA,UACP,MAAM,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO,CACrC;AACD,eAAO,CAAA;AAAA,MACT;AACA,gBAAU,IAAI;AACd,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,SAAS,oBAAoB,EAAE,QAAQ,MAAM,OAAO,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO;AAC9E,YAAI,OAAO,SAAS,EAAG,gBAAe,MAAM;AAC5C,eAAO;AAAA,MACT,SAASA,QAAO;AACd,0BAAkB;AAAA,UAChB;AAAA,UACAA;AAAAA,UACA,EAAE,MAAM,qBAAqB,SAAS,uBAAuB,MAAM,EAAA;AAAA,UACnE,EAAE,QAAQ,OAAO,MAAM,OAAA;AAAA,QAAO;AAEhC,eAAO,CAAA;AAAA,MACT,UAAA;AACE,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,QAAQ,gBAAgB,WAAW,MAAM;AAAA,EAAA;AAG5D,SAAO,EAAE,aAAa,aAAa,OAAO,WAAA;AAC5C;"}
@@ -1,22 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const react$1 = require("react");
3
+ const require$$0 = require("react");
4
4
  const react = require("@assistant-ui/react");
5
5
  function useComposerAttachment() {
6
6
  const aui = react.useAui();
7
- const addFile = react$1.useCallback(
7
+ const addFile = require$$0.useCallback(
8
8
  (file) => {
9
9
  aui.composer.addAttachment(file);
10
10
  },
11
11
  [aui]
12
12
  );
13
- const addContent = react$1.useCallback(
13
+ const addContent = require$$0.useCallback(
14
14
  (name, content) => {
15
15
  aui.composer.addAttachment({ name, content });
16
16
  },
17
17
  [aui]
18
18
  );
19
- const clear = react$1.useCallback(() => {
19
+ const clear = require$$0.useCallback(() => {
20
20
  aui.composer.clearAttachments();
21
21
  }, [aui]);
22
22
  return { addFile, addContent, clear };
@@ -1 +1 @@
1
- {"version":3,"file":"useComposerAttachment.cjs","sources":["../../src/composer/useComposerAttachment.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useAui } from '@assistant-ui/react';\n\n/**\n * Hook for programmatic composer file attachment control.\n *\n * Usage:\n * const { addFile, addContent, clear } = useComposerAttachment();\n * addFile(fileObject);\n * addContent(\"data.csv\", \"col1,col2\\n1,2\");\n * clear();\n */\nexport function useComposerAttachment() {\n const aui = useAui();\n\n const addFile = useCallback(\n (file: File) => {\n aui.composer.addAttachment(file);\n },\n [aui],\n );\n\n const addContent = useCallback(\n (name: string, content: string) => {\n aui.composer.addAttachment({ name, content } as unknown as File);\n },\n [aui],\n );\n\n const clear = useCallback(() => {\n aui.composer.clearAttachments();\n }, [aui]);\n\n return { addFile, addContent, clear };\n}\n"],"names":["useAui","useCallback"],"mappings":";;;;AAYO,SAAS,wBAAwB;AACtC,QAAM,MAAMA,MAAAA,OAAA;AAEZ,QAAM,UAAUC,QAAAA;AAAAA,IACd,CAAC,SAAe;AACd,UAAI,SAAS,cAAc,IAAI;AAAA,IACjC;AAAA,IACA,CAAC,GAAG;AAAA,EAAA;AAGN,QAAM,aAAaA,QAAAA;AAAAA,IACjB,CAAC,MAAc,YAAoB;AACjC,UAAI,SAAS,cAAc,EAAE,MAAM,SAA4B;AAAA,IACjE;AAAA,IACA,CAAC,GAAG;AAAA,EAAA;AAGN,QAAM,QAAQA,QAAAA,YAAY,MAAM;AAC9B,QAAI,SAAS,iBAAA;AAAA,EACf,GAAG,CAAC,GAAG,CAAC;AAER,SAAO,EAAE,SAAS,YAAY,MAAA;AAChC;;"}
1
+ {"version":3,"file":"useComposerAttachment.cjs","sources":["../../src/composer/useComposerAttachment.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useAui } from '@assistant-ui/react';\n\n/**\n * Hook for programmatic composer file attachment control.\n *\n * Usage:\n * const { addFile, addContent, clear } = useComposerAttachment();\n * addFile(fileObject);\n * addContent(\"data.csv\", \"col1,col2\\n1,2\");\n * clear();\n */\nexport function useComposerAttachment() {\n const aui = useAui();\n\n const addFile = useCallback(\n (file: File) => {\n aui.composer.addAttachment(file);\n },\n [aui],\n );\n\n const addContent = useCallback(\n (name: string, content: string) => {\n aui.composer.addAttachment({ name, content } as unknown as File);\n },\n [aui],\n );\n\n const clear = useCallback(() => {\n aui.composer.clearAttachments();\n }, [aui]);\n\n return { addFile, addContent, clear };\n}\n"],"names":["useAui","useCallback"],"mappings":";;;;AAYO,SAAS,wBAAwB;AACtC,QAAM,MAAMA,MAAAA,OAAA;AAEZ,QAAM,UAAUC,WAAAA;AAAAA,IACd,CAAC,SAAe;AACd,UAAI,SAAS,cAAc,IAAI;AAAA,IACjC;AAAA,IACA,CAAC,GAAG;AAAA,EAAA;AAGN,QAAM,aAAaA,WAAAA;AAAAA,IACjB,CAAC,MAAc,YAAoB;AACjC,UAAI,SAAS,cAAc,EAAE,MAAM,SAA4B;AAAA,IACjE;AAAA,IACA,CAAC,GAAG;AAAA,EAAA;AAGN,QAAM,QAAQA,WAAAA,YAAY,MAAM;AAC9B,QAAI,SAAS,iBAAA;AAAA,EACf,GAAG,CAAC,GAAG,CAAC;AAER,SAAO,EAAE,SAAS,YAAY,MAAA;AAChC;;"}
@@ -1,25 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const react = require("react");
3
+ const require$$0 = require("react");
4
4
  const AthenaContext = require("../provider/AthenaContext.cjs");
5
5
  const MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024;
6
6
  function useFileUpload() {
7
7
  const config = AthenaContext.useAthenaConfig();
8
- const configRef = react.useRef(config);
8
+ const configRef = require$$0.useRef(config);
9
9
  configRef.current = config;
10
10
  const { backendUrl, apiKey } = config;
11
- const [isUploading, setIsUploading] = react.useState(false);
12
- const [progress, setProgress] = react.useState(null);
13
- const [error, setError] = react.useState(null);
14
- const xhrRef = react.useRef(null);
15
- react.useEffect(() => {
11
+ const [isUploading, setIsUploading] = require$$0.useState(false);
12
+ const [progress, setProgress] = require$$0.useState(null);
13
+ const [error, setError] = require$$0.useState(null);
14
+ const xhrRef = require$$0.useRef(null);
15
+ require$$0.useEffect(() => {
16
16
  return () => {
17
17
  var _a;
18
18
  (_a = xhrRef.current) == null ? void 0 : _a.abort();
19
19
  };
20
20
  }, []);
21
- const clearError = react.useCallback(() => setError(null), []);
22
- const upload = react.useCallback(
21
+ const clearError = require$$0.useCallback(() => setError(null), []);
22
+ const upload = require$$0.useCallback(
23
23
  async (files) => {
24
24
  var _a;
25
25
  if (files.length === 0) return [];
@@ -70,13 +70,18 @@ function useFileUpload() {
70
70
  if (xhr.status >= 200 && xhr.status < 300) {
71
71
  try {
72
72
  const data = JSON.parse(xhr.responseText);
73
- const assets = (data.success ?? []).map((a) => ({
74
- id: a.id,
75
- title: a.title ?? a.file_name,
76
- fileName: a.file_name,
77
- fileSize: a.file_size,
78
- mediaType: a.media_type
79
- }));
73
+ const fileIndexes = data.success_file_indexes;
74
+ const assets = (data.success ?? []).map((a, at) => {
75
+ const fileIndex = Array.isArray(fileIndexes) ? fileIndexes[at] : void 0;
76
+ return {
77
+ id: a.id,
78
+ title: a.title ?? a.file_name,
79
+ fileName: a.file_name,
80
+ fileSize: a.file_size,
81
+ mediaType: a.media_type,
82
+ ...typeof fileIndex === "number" && { fileIndex }
83
+ };
84
+ });
80
85
  resolve({ success: assets, errors: data.errors ?? [] });
81
86
  } catch {
82
87
  reject(new Error("Failed to parse upload response"));
@@ -1 +1 @@
1
- {"version":3,"file":"useFileUpload.cjs","sources":["../../src/composer/useFileUpload.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useAthenaConfig } from '../provider/AthenaContext';\n\nexport interface UploadedAsset {\n id: string;\n title: string;\n fileName: string;\n fileSize: number;\n mediaType: string;\n}\n\nexport interface UploadProgress {\n current: number;\n total: number;\n fileName: string;\n /** 0–1 normalized progress for the current file */\n percent: number;\n}\n\nexport interface UseFileUploadReturn {\n /** Upload one or more files to Athena. Returns the created asset(s). */\n upload: (files: File[]) => Promise<UploadedAsset[]>;\n /** Whether an upload is currently in progress. */\n isUploading: boolean;\n /** Upload progress info (null when idle). */\n progress: UploadProgress | null;\n /** Last upload error (null when no error). */\n error: string | null;\n /** Clear the error state. */\n clearError: () => void;\n}\n\nconst MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024; // 5 GB\n\n/**\n * Hook for uploading files to the Athena platform via the Athena upload endpoint.\n * Files become Athena assets (documents, spreadsheets, PDFs, images, etc.).\n *\n * Usage:\n * const { upload, isUploading, progress, error } = useFileUpload();\n * const assets = await upload(fileList);\n */\nexport function useFileUpload(): UseFileUploadReturn {\n const config = useAthenaConfig();\n // Keep config in a ref so upload() always reads the latest token at call\n // time. AthenaConfig's token is a getter that returns the current value\n // from PropelAuth, and reading via the ref avoids capturing stale\n // destructured values in the useCallback closure.\n const configRef = useRef(config);\n configRef.current = config;\n const { backendUrl, apiKey } = config;\n const [isUploading, setIsUploading] = useState(false);\n const [progress, setProgress] = useState<UploadProgress | null>(null);\n const [error, setError] = useState<string | null>(null);\n const xhrRef = useRef<XMLHttpRequest | null>(null);\n\n // Abort any in-flight upload when the component unmounts\n useEffect(() => {\n return () => {\n xhrRef.current?.abort();\n };\n }, []);\n\n const clearError = useCallback(() => setError(null), []);\n\n const upload = useCallback(\n async (files: File[]): Promise<UploadedAsset[]> => {\n if (files.length === 0) return [];\n\n // Validate file sizes\n for (const file of files) {\n if (file.size > MAX_FILE_SIZE) {\n const msg = `File \"${file.name}\" exceeds the maximum size of 5 GB.`;\n setError(msg);\n throw new Error(msg);\n }\n }\n\n setIsUploading(true);\n setError(null);\n setProgress({ current: 0, total: files.length, fileName: files[0]?.name ?? '', percent: 0 });\n\n try {\n const formData = new FormData();\n for (const file of files) {\n formData.append('files', file, file.name);\n }\n\n // Derive the upload URL from the configured Athena backend URL.\n // If backendUrl points at a nested Athena endpoint, trim it back to the API base first.\n const baseUrl = backendUrl.replace(/\\/api\\/assistant-ui\\/?$/, '');\n const uploadUrl = `${baseUrl}/api/upload/`;\n\n // Read the current token at call time so rotated tokens are picked up.\n const currentToken = configRef.current.token;\n const headers: Record<string, string> = {};\n if (currentToken) {\n headers['Authorization'] = `Bearer ${currentToken}`;\n } else if (apiKey) {\n headers['X-API-KEY'] = apiKey;\n }\n\n const xhr = new XMLHttpRequest();\n xhrRef.current = xhr;\n\n const result = await new Promise<{ success: UploadedAsset[]; errors: Array<{ file: { filename: string }; error: string }> }>((resolve, reject) => {\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n const percent = e.loaded / e.total;\n // Estimate which file we're on based on progress\n const fileIndex = Math.min(\n Math.floor(percent * files.length),\n files.length - 1,\n );\n setProgress({\n current: fileIndex + 1,\n total: files.length,\n fileName: files[fileIndex]?.name ?? '',\n percent,\n });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const data = JSON.parse(xhr.responseText);\n const assets: UploadedAsset[] = (data.success ?? []).map((a: Record<string, unknown>) => ({\n id: a.id as string,\n title: (a.title ?? a.file_name) as string,\n fileName: a.file_name as string,\n fileSize: a.file_size as number,\n mediaType: a.media_type as string,\n }));\n resolve({ success: assets, errors: data.errors ?? [] });\n } catch {\n reject(new Error('Failed to parse upload response'));\n }\n } else if (xhr.status === 401 || xhr.status === 403) {\n reject(new Error('Authentication failed. Check your API key or token.'));\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => reject(new Error('Network error during upload')));\n xhr.addEventListener('abort', () => reject(new Error('Upload was cancelled')));\n\n xhr.open('POST', uploadUrl);\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value);\n }\n xhr.withCredentials = !currentToken && !apiKey;\n xhr.send(formData);\n });\n\n if (result.errors.length > 0) {\n const errMsg = result.errors.map((e) => `${e.file.filename}: ${e.error}`).join('; ');\n if (result.success.length === 0) {\n setError(errMsg);\n throw new Error(errMsg);\n }\n // Partial success — set error but still return successful uploads\n setError(errMsg);\n }\n\n return result.success;\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Upload failed';\n setError(msg);\n throw err;\n } finally {\n xhrRef.current = null;\n setIsUploading(false);\n setProgress(null);\n }\n },\n [backendUrl, apiKey],\n );\n\n return { upload, isUploading, progress, error, clearError };\n}\n"],"names":["useAthenaConfig","useRef","useState","useEffect","useCallback","_a"],"mappings":";;;;AAgCA,MAAM,gBAAgB,IAAI,OAAO,OAAO;AAUjC,SAAS,gBAAqC;AACnD,QAAM,SAASA,cAAAA,gBAAA;AAKf,QAAM,YAAYC,MAAAA,OAAO,MAAM;AAC/B,YAAU,UAAU;AACpB,QAAM,EAAE,YAAY,OAAA,IAAW;AAC/B,QAAM,CAAC,aAAa,cAAc,IAAIC,MAAAA,SAAS,KAAK;AACpD,QAAM,CAAC,UAAU,WAAW,IAAIA,MAAAA,SAAgC,IAAI;AACpE,QAAM,CAAC,OAAO,QAAQ,IAAIA,MAAAA,SAAwB,IAAI;AACtD,QAAM,SAASD,MAAAA,OAA8B,IAAI;AAGjDE,QAAAA,UAAU,MAAM;AACd,WAAO,MAAM;;AACX,mBAAO,YAAP,mBAAgB;AAAA,IAClB;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,QAAM,aAAaC,MAAAA,YAAY,MAAM,SAAS,IAAI,GAAG,CAAA,CAAE;AAEvD,QAAM,SAASA,MAAAA;AAAAA,IACb,OAAO,UAA4C;;AACjD,UAAI,MAAM,WAAW,EAAG,QAAO,CAAA;AAG/B,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,OAAO,eAAe;AAC7B,gBAAM,MAAM,SAAS,KAAK,IAAI;AAC9B,mBAAS,GAAG;AACZ,gBAAM,IAAI,MAAM,GAAG;AAAA,QACrB;AAAA,MACF;AAEA,qBAAe,IAAI;AACnB,eAAS,IAAI;AACb,kBAAY,EAAE,SAAS,GAAG,OAAO,MAAM,QAAQ,YAAU,WAAM,CAAC,MAAP,mBAAU,SAAQ,IAAI,SAAS,GAAG;AAE3F,UAAI;AACF,cAAM,WAAW,IAAI,SAAA;AACrB,mBAAW,QAAQ,OAAO;AACxB,mBAAS,OAAO,SAAS,MAAM,KAAK,IAAI;AAAA,QAC1C;AAIA,cAAM,UAAU,WAAW,QAAQ,2BAA2B,EAAE;AAChE,cAAM,YAAY,GAAG,OAAO;AAG5B,cAAM,eAAe,UAAU,QAAQ;AACvC,cAAM,UAAkC,CAAA;AACxC,YAAI,cAAc;AAChB,kBAAQ,eAAe,IAAI,UAAU,YAAY;AAAA,QACnD,WAAW,QAAQ;AACjB,kBAAQ,WAAW,IAAI;AAAA,QACzB;AAEA,cAAM,MAAM,IAAI,eAAA;AAChB,eAAO,UAAU;AAEjB,cAAM,SAAS,MAAM,IAAI,QAAoG,CAAC,SAAS,WAAW;AAChJ,cAAI,OAAO,iBAAiB,YAAY,CAAC,MAAM;;AAC7C,gBAAI,EAAE,kBAAkB;AACtB,oBAAM,UAAU,EAAE,SAAS,EAAE;AAE7B,oBAAM,YAAY,KAAK;AAAA,gBACrB,KAAK,MAAM,UAAU,MAAM,MAAM;AAAA,gBACjC,MAAM,SAAS;AAAA,cAAA;AAEjB,0BAAY;AAAA,gBACV,SAAS,YAAY;AAAA,gBACrB,OAAO,MAAM;AAAA,gBACb,YAAUC,MAAA,MAAM,SAAS,MAAf,gBAAAA,IAAkB,SAAQ;AAAA,gBACpC;AAAA,cAAA,CACD;AAAA,YACH;AAAA,UACF,CAAC;AAED,cAAI,iBAAiB,QAAQ,MAAM;AACjC,gBAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AACzC,kBAAI;AACF,sBAAM,OAAO,KAAK,MAAM,IAAI,YAAY;AACxC,sBAAM,UAA2B,KAAK,WAAW,CAAA,GAAI,IAAI,CAAC,OAAgC;AAAA,kBACxF,IAAI,EAAE;AAAA,kBACN,OAAQ,EAAE,SAAS,EAAE;AAAA,kBACrB,UAAU,EAAE;AAAA,kBACZ,UAAU,EAAE;AAAA,kBACZ,WAAW,EAAE;AAAA,gBAAA,EACb;AACF,wBAAQ,EAAE,SAAS,QAAQ,QAAQ,KAAK,UAAU,CAAA,GAAI;AAAA,cACxD,QAAQ;AACN,uBAAO,IAAI,MAAM,iCAAiC,CAAC;AAAA,cACrD;AAAA,YACF,WAAW,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AACnD,qBAAO,IAAI,MAAM,qDAAqD,CAAC;AAAA,YACzE,OAAO;AACL,qBAAO,IAAI,MAAM,6BAA6B,IAAI,MAAM,EAAE,CAAC;AAAA,YAC7D;AAAA,UACF,CAAC;AAED,cAAI,iBAAiB,SAAS,MAAM,OAAO,IAAI,MAAM,6BAA6B,CAAC,CAAC;AACpF,cAAI,iBAAiB,SAAS,MAAM,OAAO,IAAI,MAAM,sBAAsB,CAAC,CAAC;AAE7E,cAAI,KAAK,QAAQ,SAAS;AAC1B,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,gBAAI,iBAAiB,KAAK,KAAK;AAAA,UACjC;AACA,cAAI,kBAAkB,CAAC,gBAAgB,CAAC;AACxC,cAAI,KAAK,QAAQ;AAAA,QACnB,CAAC;AAED,YAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,gBAAM,SAAS,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,QAAQ,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI;AACnF,cAAI,OAAO,QAAQ,WAAW,GAAG;AAC/B,qBAAS,MAAM;AACf,kBAAM,IAAI,MAAM,MAAM;AAAA,UACxB;AAEA,mBAAS,MAAM;AAAA,QACjB;AAEA,eAAO,OAAO;AAAA,MAChB,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,iBAAS,GAAG;AACZ,cAAM;AAAA,MACR,UAAA;AACE,eAAO,UAAU;AACjB,uBAAe,KAAK;AACpB,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,IACA,CAAC,YAAY,MAAM;AAAA,EAAA;AAGrB,SAAO,EAAE,QAAQ,aAAa,UAAU,OAAO,WAAA;AACjD;;"}
1
+ {"version":3,"file":"useFileUpload.cjs","sources":["../../src/composer/useFileUpload.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useAthenaConfig } from '../provider/AthenaContext';\n\nexport interface UploadedAsset {\n id: string;\n title: string;\n fileName: string;\n fileSize: number;\n mediaType: string;\n /**\n * The position, in the batch `upload` was given, of the file this asset was\n * uploaded from (the upload's `success_file_indexes`; absent from a server\n * that does not send them).\n */\n fileIndex?: number;\n /**\n * A local `blob:` URL of the picture this attachment was uploaded from, for\n * the composer's thumbnail and full-screen viewer. Set by the composer's\n * intake for image files, and revoked when the draft lets the attachment go.\n */\n previewUrl?: string;\n}\n\nexport interface UploadProgress {\n current: number;\n total: number;\n fileName: string;\n /** 0–1 normalized progress for the current file */\n percent: number;\n}\n\nexport interface UseFileUploadReturn {\n /** Upload one or more files to Athena. Returns the created asset(s). */\n upload: (files: File[]) => Promise<UploadedAsset[]>;\n /** Whether an upload is currently in progress. */\n isUploading: boolean;\n /** Upload progress info (null when idle). */\n progress: UploadProgress | null;\n /** Last upload error (null when no error). */\n error: string | null;\n /** Clear the error state. */\n clearError: () => void;\n}\n\nconst MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024; // 5 GB\n\n/**\n * Hook for uploading files to the Athena platform via the Athena upload endpoint.\n * Files become Athena assets (documents, spreadsheets, PDFs, images, etc.).\n *\n * Usage:\n * const { upload, isUploading, progress, error } = useFileUpload();\n * const assets = await upload(fileList);\n */\nexport function useFileUpload(): UseFileUploadReturn {\n const config = useAthenaConfig();\n // Keep config in a ref so upload() always reads the latest token at call\n // time. AthenaConfig's token is a getter that returns the current value\n // from PropelAuth, and reading via the ref avoids capturing stale\n // destructured values in the useCallback closure.\n const configRef = useRef(config);\n configRef.current = config;\n const { backendUrl, apiKey } = config;\n const [isUploading, setIsUploading] = useState(false);\n const [progress, setProgress] = useState<UploadProgress | null>(null);\n const [error, setError] = useState<string | null>(null);\n const xhrRef = useRef<XMLHttpRequest | null>(null);\n\n // Abort any in-flight upload when the component unmounts\n useEffect(() => {\n return () => {\n xhrRef.current?.abort();\n };\n }, []);\n\n const clearError = useCallback(() => setError(null), []);\n\n const upload = useCallback(\n async (files: File[]): Promise<UploadedAsset[]> => {\n if (files.length === 0) return [];\n\n // Validate file sizes\n for (const file of files) {\n if (file.size > MAX_FILE_SIZE) {\n const msg = `File \"${file.name}\" exceeds the maximum size of 5 GB.`;\n setError(msg);\n throw new Error(msg);\n }\n }\n\n setIsUploading(true);\n setError(null);\n setProgress({ current: 0, total: files.length, fileName: files[0]?.name ?? '', percent: 0 });\n\n try {\n const formData = new FormData();\n for (const file of files) {\n formData.append('files', file, file.name);\n }\n\n // Derive the upload URL from the configured Athena backend URL.\n // If backendUrl points at a nested Athena endpoint, trim it back to the API base first.\n const baseUrl = backendUrl.replace(/\\/api\\/assistant-ui\\/?$/, '');\n const uploadUrl = `${baseUrl}/api/upload/`;\n\n // Read the current token at call time so rotated tokens are picked up.\n const currentToken = configRef.current.token;\n const headers: Record<string, string> = {};\n if (currentToken) {\n headers['Authorization'] = `Bearer ${currentToken}`;\n } else if (apiKey) {\n headers['X-API-KEY'] = apiKey;\n }\n\n const xhr = new XMLHttpRequest();\n xhrRef.current = xhr;\n\n const result = await new Promise<{ success: UploadedAsset[]; errors: Array<{ file: { filename: string }; error: string }> }>((resolve, reject) => {\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n const percent = e.loaded / e.total;\n // Estimate which file we're on based on progress\n const fileIndex = Math.min(\n Math.floor(percent * files.length),\n files.length - 1,\n );\n setProgress({\n current: fileIndex + 1,\n total: files.length,\n fileName: files[fileIndex]?.name ?? '',\n percent,\n });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const data = JSON.parse(xhr.responseText);\n const fileIndexes: unknown = data.success_file_indexes;\n const assets: UploadedAsset[] = (data.success ?? []).map((a: Record<string, unknown>, at: number) => {\n const fileIndex = Array.isArray(fileIndexes) ? fileIndexes[at] : undefined;\n return {\n id: a.id as string,\n title: (a.title ?? a.file_name) as string,\n fileName: a.file_name as string,\n fileSize: a.file_size as number,\n mediaType: a.media_type as string,\n ...(typeof fileIndex === 'number' && { fileIndex }),\n };\n });\n resolve({ success: assets, errors: data.errors ?? [] });\n } catch {\n reject(new Error('Failed to parse upload response'));\n }\n } else if (xhr.status === 401 || xhr.status === 403) {\n reject(new Error('Authentication failed. Check your API key or token.'));\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => reject(new Error('Network error during upload')));\n xhr.addEventListener('abort', () => reject(new Error('Upload was cancelled')));\n\n xhr.open('POST', uploadUrl);\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value);\n }\n xhr.withCredentials = !currentToken && !apiKey;\n xhr.send(formData);\n });\n\n if (result.errors.length > 0) {\n const errMsg = result.errors.map((e) => `${e.file.filename}: ${e.error}`).join('; ');\n if (result.success.length === 0) {\n setError(errMsg);\n throw new Error(errMsg);\n }\n // Partial success — set error but still return successful uploads\n setError(errMsg);\n }\n\n return result.success;\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Upload failed';\n setError(msg);\n throw err;\n } finally {\n xhrRef.current = null;\n setIsUploading(false);\n setProgress(null);\n }\n },\n [backendUrl, apiKey],\n );\n\n return { upload, isUploading, progress, error, clearError };\n}\n"],"names":["useAthenaConfig","useRef","useState","useEffect","useCallback","_a"],"mappings":";;;;AA4CA,MAAM,gBAAgB,IAAI,OAAO,OAAO;AAUjC,SAAS,gBAAqC;AACnD,QAAM,SAASA,cAAAA,gBAAA;AAKf,QAAM,YAAYC,WAAAA,OAAO,MAAM;AAC/B,YAAU,UAAU;AACpB,QAAM,EAAE,YAAY,OAAA,IAAW;AAC/B,QAAM,CAAC,aAAa,cAAc,IAAIC,WAAAA,SAAS,KAAK;AACpD,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAAA,SAAgC,IAAI;AACpE,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAAA,SAAwB,IAAI;AACtD,QAAM,SAASD,WAAAA,OAA8B,IAAI;AAGjDE,aAAAA,UAAU,MAAM;AACd,WAAO,MAAM;;AACX,mBAAO,YAAP,mBAAgB;AAAA,IAClB;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,QAAM,aAAaC,WAAAA,YAAY,MAAM,SAAS,IAAI,GAAG,CAAA,CAAE;AAEvD,QAAM,SAASA,WAAAA;AAAAA,IACb,OAAO,UAA4C;;AACjD,UAAI,MAAM,WAAW,EAAG,QAAO,CAAA;AAG/B,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,OAAO,eAAe;AAC7B,gBAAM,MAAM,SAAS,KAAK,IAAI;AAC9B,mBAAS,GAAG;AACZ,gBAAM,IAAI,MAAM,GAAG;AAAA,QACrB;AAAA,MACF;AAEA,qBAAe,IAAI;AACnB,eAAS,IAAI;AACb,kBAAY,EAAE,SAAS,GAAG,OAAO,MAAM,QAAQ,YAAU,WAAM,CAAC,MAAP,mBAAU,SAAQ,IAAI,SAAS,GAAG;AAE3F,UAAI;AACF,cAAM,WAAW,IAAI,SAAA;AACrB,mBAAW,QAAQ,OAAO;AACxB,mBAAS,OAAO,SAAS,MAAM,KAAK,IAAI;AAAA,QAC1C;AAIA,cAAM,UAAU,WAAW,QAAQ,2BAA2B,EAAE;AAChE,cAAM,YAAY,GAAG,OAAO;AAG5B,cAAM,eAAe,UAAU,QAAQ;AACvC,cAAM,UAAkC,CAAA;AACxC,YAAI,cAAc;AAChB,kBAAQ,eAAe,IAAI,UAAU,YAAY;AAAA,QACnD,WAAW,QAAQ;AACjB,kBAAQ,WAAW,IAAI;AAAA,QACzB;AAEA,cAAM,MAAM,IAAI,eAAA;AAChB,eAAO,UAAU;AAEjB,cAAM,SAAS,MAAM,IAAI,QAAoG,CAAC,SAAS,WAAW;AAChJ,cAAI,OAAO,iBAAiB,YAAY,CAAC,MAAM;;AAC7C,gBAAI,EAAE,kBAAkB;AACtB,oBAAM,UAAU,EAAE,SAAS,EAAE;AAE7B,oBAAM,YAAY,KAAK;AAAA,gBACrB,KAAK,MAAM,UAAU,MAAM,MAAM;AAAA,gBACjC,MAAM,SAAS;AAAA,cAAA;AAEjB,0BAAY;AAAA,gBACV,SAAS,YAAY;AAAA,gBACrB,OAAO,MAAM;AAAA,gBACb,YAAUC,MAAA,MAAM,SAAS,MAAf,gBAAAA,IAAkB,SAAQ;AAAA,gBACpC;AAAA,cAAA,CACD;AAAA,YACH;AAAA,UACF,CAAC;AAED,cAAI,iBAAiB,QAAQ,MAAM;AACjC,gBAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AACzC,kBAAI;AACF,sBAAM,OAAO,KAAK,MAAM,IAAI,YAAY;AACxC,sBAAM,cAAuB,KAAK;AAClC,sBAAM,UAA2B,KAAK,WAAW,CAAA,GAAI,IAAI,CAAC,GAA4B,OAAe;AACnG,wBAAM,YAAY,MAAM,QAAQ,WAAW,IAAI,YAAY,EAAE,IAAI;AACjE,yBAAO;AAAA,oBACL,IAAI,EAAE;AAAA,oBACN,OAAQ,EAAE,SAAS,EAAE;AAAA,oBACrB,UAAU,EAAE;AAAA,oBACZ,UAAU,EAAE;AAAA,oBACZ,WAAW,EAAE;AAAA,oBACb,GAAI,OAAO,cAAc,YAAY,EAAE,UAAA;AAAA,kBAAU;AAAA,gBAErD,CAAC;AACD,wBAAQ,EAAE,SAAS,QAAQ,QAAQ,KAAK,UAAU,CAAA,GAAI;AAAA,cACxD,QAAQ;AACN,uBAAO,IAAI,MAAM,iCAAiC,CAAC;AAAA,cACrD;AAAA,YACF,WAAW,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AACnD,qBAAO,IAAI,MAAM,qDAAqD,CAAC;AAAA,YACzE,OAAO;AACL,qBAAO,IAAI,MAAM,6BAA6B,IAAI,MAAM,EAAE,CAAC;AAAA,YAC7D;AAAA,UACF,CAAC;AAED,cAAI,iBAAiB,SAAS,MAAM,OAAO,IAAI,MAAM,6BAA6B,CAAC,CAAC;AACpF,cAAI,iBAAiB,SAAS,MAAM,OAAO,IAAI,MAAM,sBAAsB,CAAC,CAAC;AAE7E,cAAI,KAAK,QAAQ,SAAS;AAC1B,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,gBAAI,iBAAiB,KAAK,KAAK;AAAA,UACjC;AACA,cAAI,kBAAkB,CAAC,gBAAgB,CAAC;AACxC,cAAI,KAAK,QAAQ;AAAA,QACnB,CAAC;AAED,YAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,gBAAM,SAAS,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,QAAQ,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI;AACnF,cAAI,OAAO,QAAQ,WAAW,GAAG;AAC/B,qBAAS,MAAM;AACf,kBAAM,IAAI,MAAM,MAAM;AAAA,UACxB;AAEA,mBAAS,MAAM;AAAA,QACjB;AAEA,eAAO,OAAO;AAAA,MAChB,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,iBAAS,GAAG;AACZ,cAAM;AAAA,MACR,UAAA;AACE,eAAO,UAAU;AACjB,uBAAe,KAAK;AACpB,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,IACA,CAAC,YAAY,MAAM;AAAA,EAAA;AAGrB,SAAO,EAAE,QAAQ,aAAa,UAAU,OAAO,WAAA;AACjD;;"}