@athenaintel/react 0.57.1 → 0.59.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 (811) hide show
  1. package/README.md +778 -9
  2. package/dist/agent-runtime/src/addressed-agents.cjs +16 -0
  3. package/dist/agent-runtime/src/addressed-agents.cjs.map +1 -0
  4. package/dist/agent-runtime/src/addressed-agents.d.ts +30 -0
  5. package/dist/agent-runtime/src/addressed-agents.js +16 -0
  6. package/dist/agent-runtime/src/addressed-agents.js.map +1 -0
  7. package/dist/agent-runtime/src/answer-label.cjs +4 -3
  8. package/dist/agent-runtime/src/answer-label.cjs.map +1 -1
  9. package/dist/agent-runtime/src/answer-label.d.ts +13 -6
  10. package/dist/agent-runtime/src/answer-label.js +4 -3
  11. package/dist/agent-runtime/src/answer-label.js.map +1 -1
  12. package/dist/agent-runtime/src/chat-outbox-attachments.cjs.map +1 -1
  13. package/dist/agent-runtime/src/chat-outbox-attachments.d.ts +1 -1
  14. package/dist/agent-runtime/src/chat-outbox-attachments.js.map +1 -1
  15. package/dist/agent-runtime/src/chat-outbox-entry.cjs +101 -0
  16. package/dist/agent-runtime/src/chat-outbox-entry.cjs.map +1 -0
  17. package/dist/agent-runtime/src/chat-outbox-entry.d.ts +99 -0
  18. package/dist/agent-runtime/src/chat-outbox-entry.js +101 -0
  19. package/dist/agent-runtime/src/chat-outbox-entry.js.map +1 -0
  20. package/dist/agent-runtime/src/chat-outbox-legacy.cjs +252 -0
  21. package/dist/agent-runtime/src/chat-outbox-legacy.cjs.map +1 -0
  22. package/dist/agent-runtime/src/chat-outbox-legacy.d.ts +96 -0
  23. package/dist/agent-runtime/src/chat-outbox-legacy.js +252 -0
  24. package/dist/agent-runtime/src/chat-outbox-legacy.js.map +1 -0
  25. package/dist/agent-runtime/src/chat-outbox-policy.cjs +30 -0
  26. package/dist/agent-runtime/src/chat-outbox-policy.cjs.map +1 -0
  27. package/dist/agent-runtime/src/chat-outbox-policy.d.ts +42 -0
  28. package/dist/agent-runtime/src/chat-outbox-policy.js +30 -0
  29. package/dist/agent-runtime/src/chat-outbox-policy.js.map +1 -0
  30. package/dist/agent-runtime/src/chat-outbox-storage.cjs +306 -0
  31. package/dist/agent-runtime/src/chat-outbox-storage.cjs.map +1 -0
  32. package/dist/agent-runtime/src/chat-outbox-storage.d.ts +194 -0
  33. package/dist/agent-runtime/src/chat-outbox-storage.js +306 -0
  34. package/dist/agent-runtime/src/chat-outbox-storage.js.map +1 -0
  35. package/dist/agent-runtime/src/chat-outbox-thread.cjs +21 -94
  36. package/dist/agent-runtime/src/chat-outbox-thread.cjs.map +1 -1
  37. package/dist/agent-runtime/src/chat-outbox-thread.d.ts +22 -18
  38. package/dist/agent-runtime/src/chat-outbox-thread.js +21 -94
  39. package/dist/agent-runtime/src/chat-outbox-thread.js.map +1 -1
  40. package/dist/agent-runtime/src/chat-outbox.cjs +492 -547
  41. package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -1
  42. package/dist/agent-runtime/src/chat-outbox.d.ts +110 -142
  43. package/dist/agent-runtime/src/chat-outbox.js +492 -547
  44. package/dist/agent-runtime/src/chat-outbox.js.map +1 -1
  45. package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
  46. package/dist/agent-runtime/src/composer-markdown.d.ts +1 -1
  47. package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
  48. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +3 -1
  49. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
  50. package/dist/agent-runtime/src/deep-agent-transport-recipe.d.ts +8 -1
  51. package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -1
  52. package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
  53. package/dist/agent-runtime/src/dictation-preferences.d.ts +356 -0
  54. package/dist/agent-runtime/src/dictation-record.d.ts +279 -0
  55. package/dist/agent-runtime/src/dictation-session.d.ts +106 -7
  56. package/dist/agent-runtime/src/dictation-snippets.d.ts +9 -0
  57. package/dist/agent-runtime/src/dictation-transfer.d.ts +142 -0
  58. package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
  59. package/dist/agent-runtime/src/edit-command.d.ts +1 -1
  60. package/dist/agent-runtime/src/edit-command.js.map +1 -1
  61. package/dist/agent-runtime/src/errors.cjs +1 -0
  62. package/dist/agent-runtime/src/errors.cjs.map +1 -1
  63. package/dist/agent-runtime/src/errors.js +1 -0
  64. package/dist/agent-runtime/src/errors.js.map +1 -1
  65. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +24 -0
  66. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  67. package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +3 -3
  68. package/dist/agent-runtime/src/generated/runconfig-contract.js +24 -0
  69. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  70. package/dist/agent-runtime/src/index.d.ts +14 -8
  71. package/dist/agent-runtime/src/lane-follow.cjs +289 -0
  72. package/dist/agent-runtime/src/lane-follow.cjs.map +1 -0
  73. package/dist/agent-runtime/src/lane-follow.js +289 -0
  74. package/dist/agent-runtime/src/lane-follow.js.map +1 -0
  75. package/dist/agent-runtime/src/lane-images.cjs +387 -0
  76. package/dist/agent-runtime/src/lane-images.cjs.map +1 -0
  77. package/dist/agent-runtime/src/lane-images.js +387 -0
  78. package/dist/agent-runtime/src/lane-images.js.map +1 -0
  79. package/dist/agent-runtime/src/message-window.js +1 -1
  80. package/dist/agent-runtime/src/messages.cjs +19 -1
  81. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  82. package/dist/agent-runtime/src/messages.d.ts +8 -0
  83. package/dist/agent-runtime/src/messages.js +21 -3
  84. package/dist/agent-runtime/src/messages.js.map +1 -1
  85. package/dist/agent-runtime/src/named-agents.cjs +301 -0
  86. package/dist/agent-runtime/src/named-agents.cjs.map +1 -0
  87. package/dist/agent-runtime/src/named-agents.d.ts +246 -0
  88. package/dist/agent-runtime/src/named-agents.js +301 -0
  89. package/dist/agent-runtime/src/named-agents.js.map +1 -0
  90. package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
  91. package/dist/agent-runtime/src/offline-status.d.ts +66 -2
  92. package/dist/agent-runtime/src/offline-status.js.map +1 -1
  93. package/dist/agent-runtime/src/ptc-subcalls.cjs +41 -0
  94. package/dist/agent-runtime/src/ptc-subcalls.cjs.map +1 -0
  95. package/dist/agent-runtime/src/ptc-subcalls.js +41 -0
  96. package/dist/agent-runtime/src/ptc-subcalls.js.map +1 -0
  97. package/dist/agent-runtime/src/queue.cjs +2 -2
  98. package/dist/agent-runtime/src/queue.cjs.map +1 -1
  99. package/dist/agent-runtime/src/queue.d.ts +20 -25
  100. package/dist/agent-runtime/src/queue.js +2 -2
  101. package/dist/agent-runtime/src/queue.js.map +1 -1
  102. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +314 -84
  103. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  104. package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +137 -40
  105. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +318 -88
  106. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  107. package/dist/agent-runtime/src/run-send.cjs +54 -0
  108. package/dist/agent-runtime/src/run-send.cjs.map +1 -0
  109. package/dist/agent-runtime/src/run-send.d.ts +51 -0
  110. package/dist/agent-runtime/src/run-send.js +54 -0
  111. package/dist/agent-runtime/src/run-send.js.map +1 -0
  112. package/dist/agent-runtime/src/running-tool-placeholder.cjs +6 -0
  113. package/dist/agent-runtime/src/running-tool-placeholder.cjs.map +1 -1
  114. package/dist/agent-runtime/src/running-tool-placeholder.js +6 -0
  115. package/dist/agent-runtime/src/running-tool-placeholder.js.map +1 -1
  116. package/dist/agent-runtime/src/runtime.d.ts +9 -5
  117. package/dist/agent-runtime/src/sealed-idb.cjs +64 -0
  118. package/dist/agent-runtime/src/sealed-idb.cjs.map +1 -1
  119. package/dist/agent-runtime/src/sealed-idb.d.ts +16 -0
  120. package/dist/agent-runtime/src/sealed-idb.js +64 -0
  121. package/dist/agent-runtime/src/sealed-idb.js.map +1 -1
  122. package/dist/agent-runtime/src/send-recovery.cjs +90 -118
  123. package/dist/agent-runtime/src/send-recovery.cjs.map +1 -1
  124. package/dist/agent-runtime/src/send-recovery.d.ts +25 -29
  125. package/dist/agent-runtime/src/send-recovery.js +90 -118
  126. package/dist/agent-runtime/src/send-recovery.js.map +1 -1
  127. package/dist/agent-runtime/src/statewire-diagnostics.d.ts +4 -1
  128. package/dist/agent-runtime/src/statewire-held-sends.cjs +191 -0
  129. package/dist/agent-runtime/src/statewire-held-sends.cjs.map +1 -0
  130. package/dist/agent-runtime/src/statewire-held-sends.d.ts +119 -0
  131. package/dist/agent-runtime/src/statewire-held-sends.js +191 -0
  132. package/dist/agent-runtime/src/statewire-held-sends.js.map +1 -0
  133. package/dist/agent-runtime/src/statewire-state.cjs +4 -0
  134. package/dist/agent-runtime/src/statewire-state.cjs.map +1 -1
  135. package/dist/agent-runtime/src/statewire-state.js +4 -0
  136. package/dist/agent-runtime/src/statewire-state.js.map +1 -1
  137. package/dist/agent-runtime/src/statewire-transport.cjs +8 -2
  138. package/dist/agent-runtime/src/statewire-transport.cjs.map +1 -1
  139. package/dist/agent-runtime/src/statewire-transport.d.ts +14 -5
  140. package/dist/agent-runtime/src/statewire-transport.js +8 -2
  141. package/dist/agent-runtime/src/statewire-transport.js.map +1 -1
  142. package/dist/agent-runtime/src/subagent-transcripts.cjs +1 -23
  143. package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
  144. package/dist/agent-runtime/src/subagent-transcripts.js +3 -25
  145. package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
  146. package/dist/agent-runtime/src/subagents.cjs +22 -29
  147. package/dist/agent-runtime/src/subagents.cjs.map +1 -1
  148. package/dist/agent-runtime/src/subagents.js +23 -30
  149. package/dist/agent-runtime/src/subagents.js.map +1 -1
  150. package/dist/agent-runtime/src/thread-extras.cjs +27 -19
  151. package/dist/agent-runtime/src/thread-extras.cjs.map +1 -1
  152. package/dist/agent-runtime/src/thread-extras.d.ts +19 -6
  153. package/dist/agent-runtime/src/thread-extras.js +27 -19
  154. package/dist/agent-runtime/src/thread-extras.js.map +1 -1
  155. package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +8 -8
  156. package/dist/agent-runtime/src/tool-metadata.cjs +12 -0
  157. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  158. package/dist/agent-runtime/src/tool-metadata.js +12 -0
  159. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  160. package/dist/agent-runtime/src/tool-names.cjs +21 -0
  161. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  162. package/dist/agent-runtime/src/tool-names.d.ts +8 -0
  163. package/dist/agent-runtime/src/tool-names.js +21 -0
  164. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  165. package/dist/agent-runtime/src/typed-interrupt-kinds.cjs +247 -0
  166. package/dist/agent-runtime/src/typed-interrupt-kinds.cjs.map +1 -0
  167. package/dist/agent-runtime/src/typed-interrupt-kinds.d.ts +173 -0
  168. package/dist/agent-runtime/src/typed-interrupt-kinds.js +247 -0
  169. package/dist/agent-runtime/src/typed-interrupt-kinds.js.map +1 -0
  170. package/dist/agent-runtime/src/typed-interrupts.cjs +48 -0
  171. package/dist/agent-runtime/src/typed-interrupts.cjs.map +1 -0
  172. package/dist/agent-runtime/src/typed-interrupts.d.ts +75 -0
  173. package/dist/agent-runtime/src/typed-interrupts.js +48 -0
  174. package/dist/agent-runtime/src/typed-interrupts.js.map +1 -0
  175. package/dist/agent-runtime/src/types.d.ts +1 -1
  176. package/dist/agent-runtime/src/use-conversation-list.cjs +1 -0
  177. package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
  178. package/dist/agent-runtime/src/use-conversation-list.d.ts +7 -0
  179. package/dist/agent-runtime/src/use-conversation-list.js +1 -0
  180. package/dist/agent-runtime/src/use-conversation-list.js.map +1 -1
  181. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +46 -29
  182. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -1
  183. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +14 -22
  184. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +46 -29
  185. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
  186. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +78 -14
  187. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  188. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +34 -7
  189. package/dist/agent-runtime/src/use-deep-agent-runtime.js +79 -15
  190. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  191. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +16 -1
  192. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  193. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +7 -2
  194. package/dist/agent-runtime/src/use-deep-agent-thread.js +16 -1
  195. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  196. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +30 -4
  197. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
  198. package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +22 -4
  199. package/dist/agent-runtime/src/use-deep-agent-voice.js +30 -4
  200. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
  201. package/dist/agent-runtime/src/withdrawn-turns.d.ts +5 -4
  202. package/dist/agent-runtime/src/word-device-fit.d.ts +174 -0
  203. package/dist/agent-runtime/src/work-in.d.ts +127 -0
  204. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  205. package/dist/assets/AthenaAssetEmbed.d.ts +6 -1
  206. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  207. package/dist/assets/asset-panel-store.cjs +13 -5
  208. package/dist/assets/asset-panel-store.cjs.map +1 -1
  209. package/dist/assets/asset-panel-store.d.ts +33 -2
  210. package/dist/assets/asset-panel-store.js +13 -5
  211. package/dist/assets/asset-panel-store.js.map +1 -1
  212. package/dist/auth/AthenaCredentialSourceContext.cjs +11 -0
  213. package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
  214. package/dist/auth/AthenaCredentialSourceContext.d.ts +6 -0
  215. package/dist/auth/AthenaCredentialSourceContext.js +11 -0
  216. package/dist/auth/AthenaCredentialSourceContext.js.map +1 -1
  217. package/dist/auth/account-identity.cjs +13 -2
  218. package/dist/auth/account-identity.cjs.map +1 -1
  219. package/dist/auth/account-identity.d.ts +9 -0
  220. package/dist/auth/account-identity.js +13 -2
  221. package/dist/auth/account-identity.js.map +1 -1
  222. package/dist/auth/credential-source.cjs +20 -4
  223. package/dist/auth/credential-source.cjs.map +1 -1
  224. package/dist/auth/credential-source.d.ts +9 -0
  225. package/dist/auth/credential-source.js +20 -4
  226. package/dist/auth/credential-source.js.map +1 -1
  227. package/dist/catalog/chat-pickers.cjs +31 -0
  228. package/dist/catalog/chat-pickers.cjs.map +1 -1
  229. package/dist/catalog/chat-pickers.d.ts +17 -0
  230. package/dist/catalog/chat-pickers.js +33 -2
  231. package/dist/catalog/chat-pickers.js.map +1 -1
  232. package/dist/catalog/runtime-catalog.cjs +63 -3
  233. package/dist/catalog/runtime-catalog.cjs.map +1 -1
  234. package/dist/catalog/runtime-catalog.d.ts +63 -3
  235. package/dist/catalog/runtime-catalog.js +64 -4
  236. package/dist/catalog/runtime-catalog.js.map +1 -1
  237. package/dist/chat/AthenaChat.cjs +337 -99
  238. package/dist/chat/AthenaChat.cjs.map +1 -1
  239. package/dist/chat/AthenaChat.d.ts +80 -4
  240. package/dist/chat/AthenaChat.js +337 -99
  241. package/dist/chat/AthenaChat.js.map +1 -1
  242. package/dist/chat/StatewireApprovalCard.cjs +35 -5
  243. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  244. package/dist/chat/StatewireApprovalCard.d.ts +55 -2
  245. package/dist/chat/StatewireApprovalCard.js +37 -7
  246. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  247. package/dist/chat/StatewireQueuedMessages.cjs +17 -2
  248. package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
  249. package/dist/chat/StatewireQueuedMessages.d.ts +8 -45
  250. package/dist/chat/StatewireQueuedMessages.js +18 -3
  251. package/dist/chat/StatewireQueuedMessages.js.map +1 -1
  252. package/dist/chat/chat-agent-mentions.cjs +70 -0
  253. package/dist/chat/chat-agent-mentions.cjs.map +1 -0
  254. package/dist/chat/chat-agent-mentions.d.ts +13 -0
  255. package/dist/chat/chat-agent-mentions.js +70 -0
  256. package/dist/chat/chat-agent-mentions.js.map +1 -0
  257. package/dist/chat/composer-actions.cjs +12 -0
  258. package/dist/chat/composer-actions.cjs.map +1 -0
  259. package/dist/chat/composer-actions.d.ts +22 -0
  260. package/dist/chat/composer-actions.js +12 -0
  261. package/dist/chat/composer-actions.js.map +1 -0
  262. package/dist/chat/follow-up-suggestions.cjs +185 -0
  263. package/dist/chat/follow-up-suggestions.cjs.map +1 -0
  264. package/dist/chat/follow-up-suggestions.d.ts +64 -0
  265. package/dist/chat/follow-up-suggestions.js +185 -0
  266. package/dist/chat/follow-up-suggestions.js.map +1 -0
  267. package/dist/chat/super-grouping/ToolTimeline.cjs +4 -3
  268. package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
  269. package/dist/chat/super-grouping/ToolTimeline.d.ts +7 -3
  270. package/dist/chat/super-grouping/ToolTimeline.js +4 -3
  271. package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
  272. package/dist/chat/turn-changes.cjs +284 -0
  273. package/dist/chat/turn-changes.cjs.map +1 -0
  274. package/dist/chat/turn-changes.d.ts +130 -0
  275. package/dist/chat/turn-changes.js +284 -0
  276. package/dist/chat/turn-changes.js.map +1 -0
  277. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.cjs +31 -0
  278. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.cjs.map +1 -0
  279. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.d.ts +31 -0
  280. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.js +31 -0
  281. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.js.map +1 -0
  282. package/dist/chat/typed-interrupts/approval-cards.cjs +250 -0
  283. package/dist/chat/typed-interrupts/approval-cards.cjs.map +1 -0
  284. package/dist/chat/typed-interrupts/approval-cards.d.ts +22 -0
  285. package/dist/chat/typed-interrupts/approval-cards.js +250 -0
  286. package/dist/chat/typed-interrupts/approval-cards.js.map +1 -0
  287. package/dist/chat/typed-interrupts/form-cards.cjs +289 -0
  288. package/dist/chat/typed-interrupts/form-cards.cjs.map +1 -0
  289. package/dist/chat/typed-interrupts/form-cards.d.ts +6 -0
  290. package/dist/chat/typed-interrupts/form-cards.js +289 -0
  291. package/dist/chat/typed-interrupts/form-cards.js.map +1 -0
  292. package/dist/chat/typed-interrupts/interrupt-card-shell.cjs +182 -0
  293. package/dist/chat/typed-interrupts/interrupt-card-shell.cjs.map +1 -0
  294. package/dist/chat/typed-interrupts/interrupt-card-shell.d.ts +47 -0
  295. package/dist/chat/typed-interrupts/interrupt-card-shell.js +182 -0
  296. package/dist/chat/typed-interrupts/interrupt-card-shell.js.map +1 -0
  297. package/dist/chat/typed-interrupts/json-schema-form.cjs +388 -0
  298. package/dist/chat/typed-interrupts/json-schema-form.cjs.map +1 -0
  299. package/dist/chat/typed-interrupts/json-schema-form.d.ts +33 -0
  300. package/dist/chat/typed-interrupts/json-schema-form.js +388 -0
  301. package/dist/chat/typed-interrupts/json-schema-form.js.map +1 -0
  302. package/dist/chat/typed-interrupts/questionnaire-card.cjs +449 -0
  303. package/dist/chat/typed-interrupts/questionnaire-card.cjs.map +1 -0
  304. package/dist/chat/typed-interrupts/questionnaire-card.d.ts +20 -0
  305. package/dist/chat/typed-interrupts/questionnaire-card.js +449 -0
  306. package/dist/chat/typed-interrupts/questionnaire-card.js.map +1 -0
  307. package/dist/chat/typed-interrupts/request-file-card.cjs +159 -0
  308. package/dist/chat/typed-interrupts/request-file-card.cjs.map +1 -0
  309. package/dist/chat/typed-interrupts/request-file-card.d.ts +2 -0
  310. package/dist/chat/typed-interrupts/request-file-card.js +159 -0
  311. package/dist/chat/typed-interrupts/request-file-card.js.map +1 -0
  312. package/dist/chat/typed-interrupts/toolkit-selection-card.cjs +189 -0
  313. package/dist/chat/typed-interrupts/toolkit-selection-card.cjs.map +1 -0
  314. package/dist/chat/typed-interrupts/toolkit-selection-card.d.ts +23 -0
  315. package/dist/chat/typed-interrupts/toolkit-selection-card.js +189 -0
  316. package/dist/chat/typed-interrupts/toolkit-selection-card.js.map +1 -0
  317. package/dist/chat/typed-interrupts/typed-interrupt-body.cjs +26 -0
  318. package/dist/chat/typed-interrupts/typed-interrupt-body.cjs.map +1 -0
  319. package/dist/chat/typed-interrupts/typed-interrupt-body.d.ts +3 -0
  320. package/dist/chat/typed-interrupts/typed-interrupt-body.js +26 -0
  321. package/dist/chat/typed-interrupts/typed-interrupt-body.js.map +1 -0
  322. package/dist/chat/typed-interrupts/typed-interrupt-graphql.cjs +105 -0
  323. package/dist/chat/typed-interrupts/typed-interrupt-graphql.cjs.map +1 -0
  324. package/dist/chat/typed-interrupts/typed-interrupt-graphql.d.ts +29 -0
  325. package/dist/chat/typed-interrupts/typed-interrupt-graphql.js +105 -0
  326. package/dist/chat/typed-interrupts/typed-interrupt-graphql.js.map +1 -0
  327. package/dist/chat/typed-interrupts/typed-interrupt-notice.cjs +70 -0
  328. package/dist/chat/typed-interrupts/typed-interrupt-notice.cjs.map +1 -0
  329. package/dist/chat/typed-interrupts/typed-interrupt-notice.d.ts +45 -0
  330. package/dist/chat/typed-interrupts/typed-interrupt-notice.js +70 -0
  331. package/dist/chat/typed-interrupts/typed-interrupt-notice.js.map +1 -0
  332. package/dist/chat/typed-interrupts/typed-interrupt-panel.cjs +76 -0
  333. package/dist/chat/typed-interrupts/typed-interrupt-panel.cjs.map +1 -0
  334. package/dist/chat/typed-interrupts/typed-interrupt-panel.d.ts +11 -0
  335. package/dist/chat/typed-interrupts/typed-interrupt-panel.js +76 -0
  336. package/dist/chat/typed-interrupts/typed-interrupt-panel.js.map +1 -0
  337. package/dist/chat/typed-interrupts/typed-interrupt-types.d.ts +46 -0
  338. package/dist/chat/typed-interrupts/use-interrupt-draft.cjs +106 -0
  339. package/dist/chat/typed-interrupts/use-interrupt-draft.cjs.map +1 -0
  340. package/dist/chat/typed-interrupts/use-interrupt-draft.d.ts +29 -0
  341. package/dist/chat/typed-interrupts/use-interrupt-draft.js +106 -0
  342. package/dist/chat/typed-interrupts/use-interrupt-draft.js.map +1 -0
  343. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.cjs +231 -0
  344. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.cjs.map +1 -0
  345. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.d.ts +66 -0
  346. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.js +231 -0
  347. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.js.map +1 -0
  348. package/dist/chat-ui/composer/composer-named-agents.cjs +13 -0
  349. package/dist/chat-ui/composer/composer-named-agents.cjs.map +1 -0
  350. package/dist/chat-ui/composer/composer-named-agents.d.ts +20 -0
  351. package/dist/chat-ui/composer/composer-named-agents.js +13 -0
  352. package/dist/chat-ui/composer/composer-named-agents.js.map +1 -0
  353. package/dist/chat-ui/composer/slash-command-menu.cjs +143 -0
  354. package/dist/chat-ui/composer/slash-command-menu.cjs.map +1 -0
  355. package/dist/chat-ui/composer/slash-command-menu.d.ts +19 -0
  356. package/dist/chat-ui/composer/slash-command-menu.js +143 -0
  357. package/dist/chat-ui/composer/slash-command-menu.js.map +1 -0
  358. package/dist/chat-ui/composer/slash-commands-extension.cjs +51 -0
  359. package/dist/chat-ui/composer/slash-commands-extension.cjs.map +1 -0
  360. package/dist/chat-ui/composer/slash-commands-extension.d.ts +39 -0
  361. package/dist/chat-ui/composer/slash-commands-extension.js +51 -0
  362. package/dist/chat-ui/composer/slash-commands-extension.js.map +1 -0
  363. package/dist/chat-ui/composer/slash-commands.cjs +74 -0
  364. package/dist/chat-ui/composer/slash-commands.cjs.map +1 -0
  365. package/dist/chat-ui/composer/slash-commands.d.ts +82 -0
  366. package/dist/chat-ui/composer/slash-commands.js +74 -0
  367. package/dist/chat-ui/composer/slash-commands.js.map +1 -0
  368. package/dist/chat-ui/composer/tiptap-composer.cjs +135 -9
  369. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  370. package/dist/chat-ui/composer/tiptap-composer.d.ts +61 -2
  371. package/dist/chat-ui/composer/tiptap-composer.js +135 -9
  372. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  373. package/dist/chat-ui/index.cjs +3 -0
  374. package/dist/chat-ui/index.cjs.map +1 -1
  375. package/dist/chat-ui/index.d.ts +3 -2
  376. package/dist/chat-ui/index.js +3 -0
  377. package/dist/chat-ui/index.js.map +1 -1
  378. package/dist/chat-ui/mentions/mention-chip.cjs +1 -1
  379. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  380. package/dist/chat-ui/mentions/mention-chip.js +2 -2
  381. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  382. package/dist/chat-ui/mentions/mention-extension.cjs +8 -1
  383. package/dist/chat-ui/mentions/mention-extension.cjs.map +1 -1
  384. package/dist/chat-ui/mentions/mention-extension.js +8 -1
  385. package/dist/chat-ui/mentions/mention-extension.js.map +1 -1
  386. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.cjs +1 -0
  387. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.cjs.map +1 -1
  388. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.js +1 -0
  389. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.js.map +1 -1
  390. package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs +2 -0
  391. package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs.map +1 -1
  392. package/dist/chat-ui/mentions/suggestions/components/mention-icon.js +3 -1
  393. package/dist/chat-ui/mentions/suggestions/components/mention-icon.js.map +1 -1
  394. package/dist/chat-ui/mentions/suggestions/components/menu-item.cjs +1 -1
  395. package/dist/chat-ui/mentions/suggestions/components/menu-item.cjs.map +1 -1
  396. package/dist/chat-ui/mentions/suggestions/components/menu-item.js +1 -1
  397. package/dist/chat-ui/mentions/suggestions/components/menu-item.js.map +1 -1
  398. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +36 -0
  399. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  400. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +42 -0
  401. package/dist/chat-ui/mentions/suggestions/data/api-client.js +36 -0
  402. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  403. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +235 -19
  404. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  405. package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +88 -10
  406. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +236 -20
  407. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  408. package/dist/chat-ui/mentions/suggestions/data/types.cjs.map +1 -1
  409. package/dist/chat-ui/mentions/suggestions/data/types.d.ts +27 -1
  410. package/dist/chat-ui/mentions/suggestions/data/types.js.map +1 -1
  411. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +56 -5
  412. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs.map +1 -1
  413. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.d.ts +26 -6
  414. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +57 -6
  415. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
  416. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.cjs +34 -17
  417. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.cjs.map +1 -1
  418. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.d.ts +19 -1
  419. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.js +35 -18
  420. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.js.map +1 -1
  421. package/dist/chat-ui/statewire.d.ts +1 -1
  422. package/dist/chat-ui/thread/statewire-history-edge.cjs +15 -0
  423. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  424. package/dist/chat-ui/thread/statewire-history-edge.d.ts +4 -1
  425. package/dist/chat-ui/thread/statewire-history-edge.js +15 -0
  426. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  427. package/dist/collab/client.cjs +17 -5
  428. package/dist/collab/client.cjs.map +1 -1
  429. package/dist/collab/client.d.ts +22 -7
  430. package/dist/collab/client.js +17 -5
  431. package/dist/collab/client.js.map +1 -1
  432. package/dist/composer/ComposerAttachedReferences.cjs +119 -0
  433. package/dist/composer/ComposerAttachedReferences.cjs.map +1 -0
  434. package/dist/composer/ComposerAttachedReferences.d.ts +26 -0
  435. package/dist/composer/ComposerAttachedReferences.js +119 -0
  436. package/dist/composer/ComposerAttachedReferences.js.map +1 -0
  437. package/dist/composer/ComposerNamedAgents.cjs +63 -0
  438. package/dist/composer/ComposerNamedAgents.cjs.map +1 -0
  439. package/dist/composer/ComposerNamedAgents.d.ts +16 -0
  440. package/dist/composer/ComposerNamedAgents.js +63 -0
  441. package/dist/composer/ComposerNamedAgents.js.map +1 -0
  442. package/dist/composer/attached-references.cjs +159 -0
  443. package/dist/composer/attached-references.cjs.map +1 -0
  444. package/dist/composer/attached-references.d.ts +86 -0
  445. package/dist/composer/attached-references.js +159 -0
  446. package/dist/composer/attached-references.js.map +1 -0
  447. package/dist/composer/build-composed-message.cjs +14 -7
  448. package/dist/composer/build-composed-message.cjs.map +1 -1
  449. package/dist/composer/build-composed-message.d.ts +6 -1
  450. package/dist/composer/build-composed-message.js +14 -7
  451. package/dist/composer/build-composed-message.js.map +1 -1
  452. package/dist/composer/composer-handoff.cjs +6 -2
  453. package/dist/composer/composer-handoff.cjs.map +1 -1
  454. package/dist/composer/composer-handoff.d.ts +7 -1
  455. package/dist/composer/composer-handoff.js +6 -2
  456. package/dist/composer/composer-handoff.js.map +1 -1
  457. package/dist/composer/folder-upload.cjs +149 -0
  458. package/dist/composer/folder-upload.cjs.map +1 -0
  459. package/dist/composer/folder-upload.d.ts +79 -0
  460. package/dist/composer/folder-upload.js +149 -0
  461. package/dist/composer/folder-upload.js.map +1 -0
  462. package/dist/composer/index.d.ts +1 -1
  463. package/dist/composer/useAttachToChat.cjs +35 -0
  464. package/dist/composer/useAttachToChat.cjs.map +1 -0
  465. package/dist/composer/useAttachToChat.d.ts +54 -0
  466. package/dist/composer/useAttachToChat.js +35 -0
  467. package/dist/composer/useAttachToChat.js.map +1 -0
  468. package/dist/composer/useAttachedReferencesComposerProps.cjs +19 -0
  469. package/dist/composer/useAttachedReferencesComposerProps.cjs.map +1 -0
  470. package/dist/composer/useAttachedReferencesComposerProps.d.ts +12 -0
  471. package/dist/composer/useAttachedReferencesComposerProps.js +19 -0
  472. package/dist/composer/useAttachedReferencesComposerProps.js.map +1 -0
  473. package/dist/composer/useFileUpload.cjs +95 -7
  474. package/dist/composer/useFileUpload.cjs.map +1 -1
  475. package/dist/composer/useFileUpload.d.ts +21 -2
  476. package/dist/composer/useFileUpload.js +95 -7
  477. package/dist/composer/useFileUpload.js.map +1 -1
  478. package/dist/data/athena-api-error.cjs +125 -0
  479. package/dist/data/athena-api-error.cjs.map +1 -0
  480. package/dist/data/athena-api-error.d.ts +96 -0
  481. package/dist/data/athena-api-error.js +125 -0
  482. package/dist/data/athena-api-error.js.map +1 -0
  483. package/dist/data/athena-data-client.cjs +106 -0
  484. package/dist/data/athena-data-client.cjs.map +1 -0
  485. package/dist/data/athena-data-client.d.ts +74 -0
  486. package/dist/data/athena-data-client.js +106 -0
  487. package/dist/data/athena-data-client.js.map +1 -0
  488. package/dist/data/athena-member.cjs +93 -0
  489. package/dist/data/athena-member.cjs.map +1 -0
  490. package/dist/data/athena-member.d.ts +125 -0
  491. package/dist/data/athena-member.js +93 -0
  492. package/dist/data/athena-member.js.map +1 -0
  493. package/dist/data/athena-request.cjs +458 -0
  494. package/dist/data/athena-request.cjs.map +1 -0
  495. package/dist/data/athena-request.d.ts +120 -0
  496. package/dist/data/athena-request.js +458 -0
  497. package/dist/data/athena-request.js.map +1 -0
  498. package/dist/data/use-athena-fetch.cjs +14 -0
  499. package/dist/data/use-athena-fetch.cjs.map +1 -0
  500. package/dist/data/use-athena-fetch.d.ts +19 -0
  501. package/dist/data/use-athena-fetch.js +14 -0
  502. package/dist/data/use-athena-fetch.js.map +1 -0
  503. package/dist/data/use-athena-graphql.cjs +66 -0
  504. package/dist/data/use-athena-graphql.cjs.map +1 -0
  505. package/dist/data/use-athena-graphql.d.ts +56 -0
  506. package/dist/data/use-athena-graphql.js +66 -0
  507. package/dist/data/use-athena-graphql.js.map +1 -0
  508. package/dist/data/use-athena-rest.cjs +33 -0
  509. package/dist/data/use-athena-rest.cjs.map +1 -0
  510. package/dist/data/use-athena-rest.d.ts +21 -0
  511. package/dist/data/use-athena-rest.js +33 -0
  512. package/dist/data/use-athena-rest.js.map +1 -0
  513. package/dist/data/use-semantic-query.cjs +44 -0
  514. package/dist/data/use-semantic-query.cjs.map +1 -0
  515. package/dist/data/use-semantic-query.d.ts +92 -0
  516. package/dist/data/use-semantic-query.js +44 -0
  517. package/dist/data/use-semantic-query.js.map +1 -0
  518. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  519. package/dist/diagnostics/athena-diagnostics.d.ts +5 -1
  520. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  521. package/dist/diagnostics/errors.cjs +7 -0
  522. package/dist/diagnostics/errors.cjs.map +1 -1
  523. package/dist/diagnostics/errors.d.ts +7 -0
  524. package/dist/diagnostics/errors.js +7 -0
  525. package/dist/diagnostics/errors.js.map +1 -1
  526. package/dist/index.cjs +155 -11
  527. package/dist/index.cjs.map +1 -1
  528. package/dist/index.d.ts +72 -13
  529. package/dist/index.js +148 -4
  530. package/dist/index.js.map +1 -1
  531. package/dist/keryx-http/src/initial-sync.cjs +64 -16
  532. package/dist/keryx-http/src/initial-sync.cjs.map +1 -1
  533. package/dist/keryx-http/src/initial-sync.d.ts +31 -1
  534. package/dist/keryx-http/src/initial-sync.js +64 -16
  535. package/dist/keryx-http/src/initial-sync.js.map +1 -1
  536. package/dist/keryx-http/src/own-awareness.cjs +20 -0
  537. package/dist/keryx-http/src/own-awareness.cjs.map +1 -0
  538. package/dist/keryx-http/src/own-awareness.d.ts +50 -0
  539. package/dist/keryx-http/src/own-awareness.js +20 -0
  540. package/dist/keryx-http/src/own-awareness.js.map +1 -0
  541. package/dist/keryx-http/src/update-attributions.cjs +26 -1
  542. package/dist/keryx-http/src/update-attributions.cjs.map +1 -1
  543. package/dist/keryx-http/src/update-attributions.d.ts +10 -1
  544. package/dist/keryx-http/src/update-attributions.js +26 -1
  545. package/dist/keryx-http/src/update-attributions.js.map +1 -1
  546. package/dist/offline/chat-outbox.cjs +262 -26
  547. package/dist/offline/chat-outbox.cjs.map +1 -1
  548. package/dist/offline/chat-outbox.d.ts +90 -12
  549. package/dist/offline/chat-outbox.js +263 -27
  550. package/dist/offline/chat-outbox.js.map +1 -1
  551. package/dist/provider/AthenaProvider.cjs +63 -19
  552. package/dist/provider/AthenaProvider.cjs.map +1 -1
  553. package/dist/provider/AthenaProvider.d.ts +24 -8
  554. package/dist/provider/AthenaProvider.js +66 -22
  555. package/dist/provider/AthenaProvider.js.map +1 -1
  556. package/dist/react/package.json.cjs +1 -1
  557. package/dist/react/package.json.js +1 -1
  558. package/dist/references/src/anchors/types.cjs +5 -0
  559. package/dist/references/src/anchors/types.cjs.map +1 -1
  560. package/dist/references/src/anchors/types.js +5 -0
  561. package/dist/references/src/anchors/types.js.map +1 -1
  562. package/dist/references/src/attachable.cjs +149 -0
  563. package/dist/references/src/attachable.cjs.map +1 -0
  564. package/dist/references/src/attachable.d.ts +87 -0
  565. package/dist/references/src/attachable.js +149 -0
  566. package/dist/references/src/attachable.js.map +1 -0
  567. package/dist/runtime/StatewirePlanModeLaneSync.cjs +93 -0
  568. package/dist/runtime/StatewirePlanModeLaneSync.cjs.map +1 -0
  569. package/dist/runtime/StatewirePlanModeLaneSync.d.ts +34 -0
  570. package/dist/runtime/StatewirePlanModeLaneSync.js +93 -0
  571. package/dist/runtime/StatewirePlanModeLaneSync.js.map +1 -0
  572. package/dist/runtime/StatewireThreadConfigLaneSync.cjs +2 -0
  573. package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
  574. package/dist/runtime/StatewireThreadConfigLaneSync.d.ts +4 -0
  575. package/dist/runtime/StatewireThreadConfigLaneSync.js +2 -0
  576. package/dist/runtime/StatewireThreadConfigLaneSync.js.map +1 -1
  577. package/dist/runtime/statewire-plan-mode.cjs +71 -0
  578. package/dist/runtime/statewire-plan-mode.cjs.map +1 -0
  579. package/dist/runtime/statewire-plan-mode.d.ts +88 -0
  580. package/dist/runtime/statewire-plan-mode.js +71 -0
  581. package/dist/runtime/statewire-plan-mode.js.map +1 -0
  582. package/dist/runtime/statewire-run-config.cjs +18 -1
  583. package/dist/runtime/statewire-run-config.cjs.map +1 -1
  584. package/dist/runtime/statewire-run-config.d.ts +20 -0
  585. package/dist/runtime/statewire-run-config.js +18 -1
  586. package/dist/runtime/statewire-run-config.js.map +1 -1
  587. package/dist/runtime/statewire-session-key.cjs +11 -5
  588. package/dist/runtime/statewire-session-key.cjs.map +1 -1
  589. package/dist/runtime/statewire-session-key.d.ts +22 -10
  590. package/dist/runtime/statewire-session-key.js +11 -5
  591. package/dist/runtime/statewire-session-key.js.map +1 -1
  592. package/dist/runtime/useAthenaStatewireRuntime.cjs +65 -8
  593. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  594. package/dist/runtime/useAthenaStatewireRuntime.d.ts +26 -10
  595. package/dist/runtime/useAthenaStatewireRuntime.js +67 -10
  596. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  597. package/dist/search/useAthenaAssets.cjs +394 -0
  598. package/dist/search/useAthenaAssets.cjs.map +1 -0
  599. package/dist/search/useAthenaAssets.d.ts +186 -0
  600. package/dist/search/useAthenaAssets.js +394 -0
  601. package/dist/search/useAthenaAssets.js.map +1 -0
  602. package/dist/sheet-range/index.cjs +4 -0
  603. package/dist/sheet-range/index.cjs.map +1 -1
  604. package/dist/sheet-range/index.d.ts +4 -2
  605. package/dist/sheet-range/index.js +4 -0
  606. package/dist/sheet-range/index.js.map +1 -1
  607. package/dist/sheet-range/query-range.cjs +102 -0
  608. package/dist/sheet-range/query-range.cjs.map +1 -0
  609. package/dist/sheet-range/query-range.d.ts +46 -0
  610. package/dist/sheet-range/query-range.js +102 -0
  611. package/dist/sheet-range/query-range.js.map +1 -0
  612. package/dist/styles.css +1 -1
  613. package/dist/subagents/index.cjs +49 -0
  614. package/dist/subagents/index.cjs.map +1 -0
  615. package/dist/subagents/index.d.ts +16 -0
  616. package/dist/subagents/index.js +49 -0
  617. package/dist/subagents/index.js.map +1 -0
  618. package/dist/subagents/lane-follow.cjs +19 -0
  619. package/dist/subagents/lane-follow.cjs.map +1 -0
  620. package/dist/subagents/lane-follow.d.ts +9 -0
  621. package/dist/subagents/lane-follow.js +19 -0
  622. package/dist/subagents/lane-follow.js.map +1 -0
  623. package/dist/subagents/lane-model.cjs +178 -0
  624. package/dist/subagents/lane-model.cjs.map +1 -0
  625. package/dist/subagents/lane-model.d.ts +140 -0
  626. package/dist/subagents/lane-model.js +178 -0
  627. package/dist/subagents/lane-model.js.map +1 -0
  628. package/dist/subagents/lane-parts.cjs +517 -0
  629. package/dist/subagents/lane-parts.cjs.map +1 -0
  630. package/dist/subagents/lane-parts.d.ts +130 -0
  631. package/dist/subagents/lane-parts.js +517 -0
  632. package/dist/subagents/lane-parts.js.map +1 -0
  633. package/dist/subagents/subagent-lane-group.cjs +215 -0
  634. package/dist/subagents/subagent-lane-group.cjs.map +1 -0
  635. package/dist/subagents/subagent-lane-group.d.ts +67 -0
  636. package/dist/subagents/subagent-lane-group.js +215 -0
  637. package/dist/subagents/subagent-lane-group.js.map +1 -0
  638. package/dist/subagents/subagent-transcript-drawer.cjs +431 -0
  639. package/dist/subagents/subagent-transcript-drawer.cjs.map +1 -0
  640. package/dist/subagents/subagent-transcript-drawer.d.ts +78 -0
  641. package/dist/subagents/subagent-transcript-drawer.js +431 -0
  642. package/dist/subagents/subagent-transcript-drawer.js.map +1 -0
  643. package/dist/subagents/task-subagent-group.cjs +115 -0
  644. package/dist/subagents/task-subagent-group.cjs.map +1 -0
  645. package/dist/subagents/task-subagent-group.d.ts +36 -0
  646. package/dist/subagents/task-subagent-group.js +115 -0
  647. package/dist/subagents/task-subagent-group.js.map +1 -0
  648. package/dist/subagents/use-omitted-images-in-view.cjs +68 -0
  649. package/dist/subagents/use-omitted-images-in-view.cjs.map +1 -0
  650. package/dist/subagents/use-omitted-images-in-view.d.ts +21 -0
  651. package/dist/subagents/use-omitted-images-in-view.js +68 -0
  652. package/dist/subagents/use-omitted-images-in-view.js.map +1 -0
  653. package/dist/threads/Inbox.cjs +2 -2
  654. package/dist/threads/Inbox.cjs.map +1 -1
  655. package/dist/threads/SessionList.cjs +27 -24
  656. package/dist/threads/SessionList.cjs.map +1 -1
  657. package/dist/threads/SessionList.js +22 -19
  658. package/dist/threads/SessionList.js.map +1 -1
  659. package/dist/threads/SessionsPage.cjs +13 -7
  660. package/dist/threads/SessionsPage.cjs.map +1 -1
  661. package/dist/threads/SessionsPage.d.ts +10 -1
  662. package/dist/threads/SessionsPage.js +9 -3
  663. package/dist/threads/SessionsPage.js.map +1 -1
  664. package/dist/threads/live-session-rows.cjs +207 -0
  665. package/dist/threads/live-session-rows.cjs.map +1 -0
  666. package/dist/threads/live-session-rows.d.ts +175 -0
  667. package/dist/threads/live-session-rows.js +207 -0
  668. package/dist/threads/live-session-rows.js.map +1 -0
  669. package/dist/threads/session-list-model.cjs.map +1 -1
  670. package/dist/threads/session-list-model.d.ts +2 -1
  671. package/dist/threads/session-list-model.js.map +1 -1
  672. package/dist/threads/session-row-parts.cjs +3 -3
  673. package/dist/threads/session-row-parts.cjs.map +1 -1
  674. package/dist/threads/sessions-page-model.cjs +13 -5
  675. package/dist/threads/sessions-page-model.cjs.map +1 -1
  676. package/dist/threads/sessions-page-model.d.ts +7 -0
  677. package/dist/threads/sessions-page-model.js +11 -3
  678. package/dist/threads/sessions-page-model.js.map +1 -1
  679. package/dist/threads/sessions-page-storage.cjs +8 -8
  680. package/dist/threads/sessions-page-storage.cjs.map +1 -1
  681. package/dist/threads/sessions-page-storage.d.ts +5 -1
  682. package/dist/threads/sessions-page-storage.js +8 -8
  683. package/dist/threads/sessions-page-storage.js.map +1 -1
  684. package/dist/threads/statewire-thread-list.cjs +173 -20
  685. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  686. package/dist/threads/statewire-thread-list.d.ts +44 -1
  687. package/dist/threads/statewire-thread-list.js +174 -21
  688. package/dist/threads/statewire-thread-list.js.map +1 -1
  689. package/dist/threads/use-athena-sessions.cjs +1 -0
  690. package/dist/threads/use-athena-sessions.cjs.map +1 -1
  691. package/dist/threads/use-athena-sessions.d.ts +7 -0
  692. package/dist/threads/use-athena-sessions.js +1 -0
  693. package/dist/threads/use-athena-sessions.js.map +1 -1
  694. package/dist/threads/use-athena-thread-agent.cjs +31 -0
  695. package/dist/threads/use-athena-thread-agent.cjs.map +1 -0
  696. package/dist/threads/use-athena-thread-agent.d.ts +38 -0
  697. package/dist/threads/use-athena-thread-agent.js +31 -0
  698. package/dist/threads/use-athena-thread-agent.js.map +1 -0
  699. package/dist/threads/use-athena-thread-plan-mode.cjs +18 -0
  700. package/dist/threads/use-athena-thread-plan-mode.cjs.map +1 -0
  701. package/dist/threads/use-athena-thread-plan-mode.d.ts +18 -0
  702. package/dist/threads/use-athena-thread-plan-mode.js +18 -0
  703. package/dist/threads/use-athena-thread-plan-mode.js.map +1 -0
  704. package/dist/threads/use-rest-conversation-history.d.ts +1 -0
  705. package/dist/tools/agent-creations.cjs +97 -0
  706. package/dist/tools/agent-creations.cjs.map +1 -0
  707. package/dist/tools/agent-creations.d.ts +38 -0
  708. package/dist/tools/agent-creations.js +97 -0
  709. package/dist/tools/agent-creations.js.map +1 -0
  710. package/dist/tools/agent-highlights.cjs +100 -0
  711. package/dist/tools/agent-highlights.cjs.map +1 -0
  712. package/dist/tools/agent-highlights.d.ts +57 -0
  713. package/dist/tools/agent-highlights.js +100 -0
  714. package/dist/tools/agent-highlights.js.map +1 -0
  715. package/dist/tools/append-document-tool-ui.cjs +1 -0
  716. package/dist/tools/append-document-tool-ui.cjs.map +1 -1
  717. package/dist/tools/append-document-tool-ui.d.ts +7 -0
  718. package/dist/tools/append-document-tool-ui.js +2 -1
  719. package/dist/tools/append-document-tool-ui.js.map +1 -1
  720. package/dist/tools/auto-open-tools.cjs +144 -71
  721. package/dist/tools/auto-open-tools.cjs.map +1 -1
  722. package/dist/tools/auto-open-tools.d.ts +131 -1
  723. package/dist/tools/auto-open-tools.js +145 -72
  724. package/dist/tools/auto-open-tools.js.map +1 -1
  725. package/dist/tools/browser-tool-uis.cjs +594 -0
  726. package/dist/tools/browser-tool-uis.cjs.map +1 -0
  727. package/dist/tools/browser-tool-uis.d.ts +8 -0
  728. package/dist/tools/browser-tool-uis.js +594 -0
  729. package/dist/tools/browser-tool-uis.js.map +1 -0
  730. package/dist/tools/computer-asset-tool-uis.cjs +313 -0
  731. package/dist/tools/computer-asset-tool-uis.cjs.map +1 -0
  732. package/dist/tools/computer-asset-tool-uis.d.ts +5 -0
  733. package/dist/tools/computer-asset-tool-uis.js +313 -0
  734. package/dist/tools/computer-asset-tool-uis.js.map +1 -0
  735. package/dist/tools/document-edit-tool-uis.cjs +218 -0
  736. package/dist/tools/document-edit-tool-uis.cjs.map +1 -0
  737. package/dist/tools/document-edit-tool-uis.d.ts +40 -0
  738. package/dist/tools/document-edit-tool-uis.js +218 -0
  739. package/dist/tools/document-edit-tool-uis.js.map +1 -0
  740. package/dist/tools/drive-tool-uis.cjs +425 -0
  741. package/dist/tools/drive-tool-uis.cjs.map +1 -0
  742. package/dist/tools/drive-tool-uis.d.ts +120 -0
  743. package/dist/tools/drive-tool-uis.js +425 -0
  744. package/dist/tools/drive-tool-uis.js.map +1 -0
  745. package/dist/tools/email-calendar-tool-uis.cjs +789 -0
  746. package/dist/tools/email-calendar-tool-uis.cjs.map +1 -0
  747. package/dist/tools/email-calendar-tool-uis.d.ts +129 -0
  748. package/dist/tools/email-calendar-tool-uis.js +789 -0
  749. package/dist/tools/email-calendar-tool-uis.js.map +1 -0
  750. package/dist/tools/ontology-tool-uis.cjs +83 -0
  751. package/dist/tools/ontology-tool-uis.cjs.map +1 -0
  752. package/dist/tools/ontology-tool-uis.d.ts +9 -0
  753. package/dist/tools/ontology-tool-uis.js +83 -0
  754. package/dist/tools/ontology-tool-uis.js.map +1 -0
  755. package/dist/tools/orchestration-tool-uis.cjs +586 -0
  756. package/dist/tools/orchestration-tool-uis.cjs.map +1 -0
  757. package/dist/tools/orchestration-tool-uis.d.ts +141 -0
  758. package/dist/tools/orchestration-tool-uis.js +586 -0
  759. package/dist/tools/orchestration-tool-uis.js.map +1 -0
  760. package/dist/tools/presentation-edit-tool-uis.cjs +516 -0
  761. package/dist/tools/presentation-edit-tool-uis.cjs.map +1 -0
  762. package/dist/tools/presentation-edit-tool-uis.d.ts +73 -0
  763. package/dist/tools/presentation-edit-tool-uis.js +516 -0
  764. package/dist/tools/presentation-edit-tool-uis.js.map +1 -0
  765. package/dist/tools/project-tool-uis.cjs +213 -0
  766. package/dist/tools/project-tool-uis.cjs.map +1 -0
  767. package/dist/tools/project-tool-uis.d.ts +14 -0
  768. package/dist/tools/project-tool-uis.js +213 -0
  769. package/dist/tools/project-tool-uis.js.map +1 -0
  770. package/dist/tools/sandbox-tool-uis.cjs +491 -0
  771. package/dist/tools/sandbox-tool-uis.cjs.map +1 -0
  772. package/dist/tools/sandbox-tool-uis.d.ts +116 -0
  773. package/dist/tools/sandbox-tool-uis.js +491 -0
  774. package/dist/tools/sandbox-tool-uis.js.map +1 -0
  775. package/dist/tools/sheet-query-tool-ui.cjs +138 -0
  776. package/dist/tools/sheet-query-tool-ui.cjs.map +1 -0
  777. package/dist/tools/sheet-query-tool-ui.d.ts +15 -0
  778. package/dist/tools/sheet-query-tool-ui.js +138 -0
  779. package/dist/tools/sheet-query-tool-ui.js.map +1 -0
  780. package/dist/tools/studio-screenshot-tool-uis.cjs +262 -0
  781. package/dist/tools/studio-screenshot-tool-uis.cjs.map +1 -0
  782. package/dist/tools/studio-screenshot-tool-uis.d.ts +52 -0
  783. package/dist/tools/studio-screenshot-tool-uis.js +262 -0
  784. package/dist/tools/studio-screenshot-tool-uis.js.map +1 -0
  785. package/dist/tools/subagent-task-tool-ui.cjs +24 -475
  786. package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
  787. package/dist/tools/subagent-task-tool-ui.d.ts +19 -103
  788. package/dist/tools/subagent-task-tool-ui.js +28 -479
  789. package/dist/tools/subagent-task-tool-ui.js.map +1 -1
  790. package/dist/tools/tool-summary.cjs +36 -0
  791. package/dist/tools/tool-summary.cjs.map +1 -1
  792. package/dist/tools/tool-summary.js +36 -0
  793. package/dist/tools/tool-summary.js.map +1 -1
  794. package/dist/tools/tool-uis.cjs +181 -53
  795. package/dist/tools/tool-uis.cjs.map +1 -1
  796. package/dist/tools/tool-uis.d.ts +40 -0
  797. package/dist/tools/tool-uis.js +183 -55
  798. package/dist/tools/tool-uis.js.map +1 -1
  799. package/dist/typed-interrupts/index.cjs +15 -0
  800. package/dist/typed-interrupts/index.cjs.map +1 -0
  801. package/dist/typed-interrupts/index.d.ts +20 -0
  802. package/dist/typed-interrupts/index.js +15 -0
  803. package/dist/typed-interrupts/index.js.map +1 -0
  804. package/dist/workbench/session-workbench-panes.cjs +6 -6
  805. package/dist/workbench/session-workbench-panes.cjs.map +1 -1
  806. package/package.json +28 -6
  807. package/dist/agent-runtime/src/chat-outbox-store.cjs +0 -510
  808. package/dist/agent-runtime/src/chat-outbox-store.cjs.map +0 -1
  809. package/dist/agent-runtime/src/chat-outbox-store.d.ts +0 -210
  810. package/dist/agent-runtime/src/chat-outbox-store.js +0 -510
  811. package/dist/agent-runtime/src/chat-outbox-store.js.map +0 -1
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const ADDRESSED_AGENTS_METADATA_KEY = "addressedAgents";
4
+ function withAddressedAgents(metadata, agents) {
5
+ if (agents === void 0) return metadata === void 0 ? void 0 : { ...metadata };
6
+ return { ...metadata, [ADDRESSED_AGENTS_METADATA_KEY]: [...agents] };
7
+ }
8
+ function readAddressedAgents(metadata) {
9
+ if (typeof metadata !== "object" || metadata === null) return void 0;
10
+ const value = metadata[ADDRESSED_AGENTS_METADATA_KEY];
11
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
12
+ }
13
+ exports.ADDRESSED_AGENTS_METADATA_KEY = ADDRESSED_AGENTS_METADATA_KEY;
14
+ exports.readAddressedAgents = readAddressedAgents;
15
+ exports.withAddressedAgents = withAddressedAgents;
16
+ //# sourceMappingURL=addressed-agents.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addressed-agents.cjs","sources":["../../../../agent-runtime/src/addressed-agents.ts"],"sourcesContent":["/**\n * The agents a message names, carried on the message itself (`message.metadata.addressedAgents`).\n *\n * agora reads a message's own list ahead of the run config's (`agent_refs.py`,\n * `ADDRESSED_AGENTS_METADATA_KEY`), so every message keeps the agents it was typed with: a send that\n * waits in the outbox, is retried, or is posted again after a reload names its own agents, never\n * those of whatever the conversation's ambient context says at the time. The list is a host's agent\n * refs (`collab_agent:<asset id>`, `assistant`, `assistant:<principal id>`), in the order they\n * answer; `[]` names none. agora checks every ref; the client never gates on them.\n */\n\n/** The message metadata key agora reads a message's agents from. */\nexport const ADDRESSED_AGENTS_METADATA_KEY = \"addressedAgents\";\n\n/** The most agents one message may name (agora's `MAX_ADDRESSED_AGENTS`). */\nexport const MAX_ADDRESSED_AGENTS = 8;\n\n/** `metadata` with the message's agents set; `agents` `undefined` leaves the key out. */\nexport function withAddressedAgents(\n metadata: Readonly<Record<string, unknown>> | undefined,\n agents: readonly string[] | undefined,\n): Record<string, unknown> | undefined {\n if (agents === undefined) return metadata === undefined ? undefined : { ...metadata };\n return { ...metadata, [ADDRESSED_AGENTS_METADATA_KEY]: [...agents] };\n}\n\n/** The agents a message's metadata names, or `undefined` when it names none of its own. */\nexport function readAddressedAgents(metadata: unknown): readonly string[] | undefined {\n if (typeof metadata !== \"object\" || metadata === null) return undefined;\n const value = (metadata as Record<string, unknown>)[ADDRESSED_AGENTS_METADATA_KEY];\n return Array.isArray(value) && value.every((item) => typeof item === \"string\") ? value : undefined;\n}\n\ntype MessageMetadataGetter = () =>\n | Record<string, unknown>\n | undefined\n | Promise<Record<string, unknown> | undefined>;\n\n/**\n * A runtime's `getMessageMetadata` (`useDeepAgentThread`) that puts the agents the composer names\n * on every message it submits, on top of the host's own metadata. `agents` is read synchronously\n * at submission (the composer's chips as they are when Send is pressed); `undefined` leaves the\n * message without a list of its own.\n */\nexport function withAddressedAgentsMetadata({\n agents,\n getMessageMetadata,\n}: {\n agents: () => readonly string[] | undefined;\n getMessageMetadata?: MessageMetadataGetter | undefined;\n}): MessageMetadataGetter {\n return () => {\n const named = agents();\n const captured = getMessageMetadata?.();\n if (named === undefined) return captured;\n const merge = (host: Record<string, unknown> | undefined) => withAddressedAgents(host, named);\n return captured instanceof Promise ? captured.then(merge) : merge(captured);\n };\n}\n"],"names":[],"mappings":";;AAYO,MAAM,gCAAgC;AAMtC,SAAS,oBACd,UACA,QACqC;AACrC,MAAI,WAAW,OAAW,QAAO,aAAa,SAAY,SAAY,EAAE,GAAG,SAAA;AAC3E,SAAO,EAAE,GAAG,UAAU,CAAC,6BAA6B,GAAG,CAAC,GAAG,MAAM,EAAA;AACnE;AAGO,SAAS,oBAAoB,UAAkD;AACpF,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,QAAM,QAAS,SAAqC,6BAA6B;AACjF,SAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,IAAI,QAAQ;AAC3F;;;;"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The agents a message names, carried on the message itself (`message.metadata.addressedAgents`).
3
+ *
4
+ * agora reads a message's own list ahead of the run config's (`agent_refs.py`,
5
+ * `ADDRESSED_AGENTS_METADATA_KEY`), so every message keeps the agents it was typed with: a send that
6
+ * waits in the outbox, is retried, or is posted again after a reload names its own agents, never
7
+ * those of whatever the conversation's ambient context says at the time. The list is a host's agent
8
+ * refs (`collab_agent:<asset id>`, `assistant`, `assistant:<principal id>`), in the order they
9
+ * answer; `[]` names none. agora checks every ref; the client never gates on them.
10
+ */
11
+ /** The message metadata key agora reads a message's agents from. */
12
+ export declare const ADDRESSED_AGENTS_METADATA_KEY = "addressedAgents";
13
+ /** The most agents one message may name (agora's `MAX_ADDRESSED_AGENTS`). */
14
+ export declare const MAX_ADDRESSED_AGENTS = 8;
15
+ /** `metadata` with the message's agents set; `agents` `undefined` leaves the key out. */
16
+ export declare function withAddressedAgents(metadata: Readonly<Record<string, unknown>> | undefined, agents: readonly string[] | undefined): Record<string, unknown> | undefined;
17
+ /** The agents a message's metadata names, or `undefined` when it names none of its own. */
18
+ export declare function readAddressedAgents(metadata: unknown): readonly string[] | undefined;
19
+ type MessageMetadataGetter = () => Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined>;
20
+ /**
21
+ * A runtime's `getMessageMetadata` (`useDeepAgentThread`) that puts the agents the composer names
22
+ * on every message it submits, on top of the host's own metadata. `agents` is read synchronously
23
+ * at submission (the composer's chips as they are when Send is pressed); `undefined` leaves the
24
+ * message without a list of its own.
25
+ */
26
+ export declare function withAddressedAgentsMetadata({ agents, getMessageMetadata, }: {
27
+ agents: () => readonly string[] | undefined;
28
+ getMessageMetadata?: MessageMetadataGetter | undefined;
29
+ }): MessageMetadataGetter;
30
+ export {};
@@ -0,0 +1,16 @@
1
+ const ADDRESSED_AGENTS_METADATA_KEY = "addressedAgents";
2
+ function withAddressedAgents(metadata, agents) {
3
+ if (agents === void 0) return metadata === void 0 ? void 0 : { ...metadata };
4
+ return { ...metadata, [ADDRESSED_AGENTS_METADATA_KEY]: [...agents] };
5
+ }
6
+ function readAddressedAgents(metadata) {
7
+ if (typeof metadata !== "object" || metadata === null) return void 0;
8
+ const value = metadata[ADDRESSED_AGENTS_METADATA_KEY];
9
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
10
+ }
11
+ export {
12
+ ADDRESSED_AGENTS_METADATA_KEY,
13
+ readAddressedAgents,
14
+ withAddressedAgents
15
+ };
16
+ //# sourceMappingURL=addressed-agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addressed-agents.js","sources":["../../../../agent-runtime/src/addressed-agents.ts"],"sourcesContent":["/**\n * The agents a message names, carried on the message itself (`message.metadata.addressedAgents`).\n *\n * agora reads a message's own list ahead of the run config's (`agent_refs.py`,\n * `ADDRESSED_AGENTS_METADATA_KEY`), so every message keeps the agents it was typed with: a send that\n * waits in the outbox, is retried, or is posted again after a reload names its own agents, never\n * those of whatever the conversation's ambient context says at the time. The list is a host's agent\n * refs (`collab_agent:<asset id>`, `assistant`, `assistant:<principal id>`), in the order they\n * answer; `[]` names none. agora checks every ref; the client never gates on them.\n */\n\n/** The message metadata key agora reads a message's agents from. */\nexport const ADDRESSED_AGENTS_METADATA_KEY = \"addressedAgents\";\n\n/** The most agents one message may name (agora's `MAX_ADDRESSED_AGENTS`). */\nexport const MAX_ADDRESSED_AGENTS = 8;\n\n/** `metadata` with the message's agents set; `agents` `undefined` leaves the key out. */\nexport function withAddressedAgents(\n metadata: Readonly<Record<string, unknown>> | undefined,\n agents: readonly string[] | undefined,\n): Record<string, unknown> | undefined {\n if (agents === undefined) return metadata === undefined ? undefined : { ...metadata };\n return { ...metadata, [ADDRESSED_AGENTS_METADATA_KEY]: [...agents] };\n}\n\n/** The agents a message's metadata names, or `undefined` when it names none of its own. */\nexport function readAddressedAgents(metadata: unknown): readonly string[] | undefined {\n if (typeof metadata !== \"object\" || metadata === null) return undefined;\n const value = (metadata as Record<string, unknown>)[ADDRESSED_AGENTS_METADATA_KEY];\n return Array.isArray(value) && value.every((item) => typeof item === \"string\") ? value : undefined;\n}\n\ntype MessageMetadataGetter = () =>\n | Record<string, unknown>\n | undefined\n | Promise<Record<string, unknown> | undefined>;\n\n/**\n * A runtime's `getMessageMetadata` (`useDeepAgentThread`) that puts the agents the composer names\n * on every message it submits, on top of the host's own metadata. `agents` is read synchronously\n * at submission (the composer's chips as they are when Send is pressed); `undefined` leaves the\n * message without a list of its own.\n */\nexport function withAddressedAgentsMetadata({\n agents,\n getMessageMetadata,\n}: {\n agents: () => readonly string[] | undefined;\n getMessageMetadata?: MessageMetadataGetter | undefined;\n}): MessageMetadataGetter {\n return () => {\n const named = agents();\n const captured = getMessageMetadata?.();\n if (named === undefined) return captured;\n const merge = (host: Record<string, unknown> | undefined) => withAddressedAgents(host, named);\n return captured instanceof Promise ? captured.then(merge) : merge(captured);\n };\n}\n"],"names":[],"mappings":"AAYO,MAAM,gCAAgC;AAMtC,SAAS,oBACd,UACA,QACqC;AACrC,MAAI,WAAW,OAAW,QAAO,aAAa,SAAY,SAAY,EAAE,GAAG,SAAA;AAC3E,SAAO,EAAE,GAAG,UAAU,CAAC,6BAA6B,GAAG,CAAC,GAAG,MAAM,EAAA;AACnE;AAGO,SAAS,oBAAoB,UAAkD;AACpF,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,QAAM,QAAS,SAAqC,6BAA6B;AACjF,SAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,IAAI,QAAQ;AAC3F;"}
@@ -86,14 +86,15 @@ function showsAnswerLabel({
86
86
  answers,
87
87
  threadShowsLabels,
88
88
  viewerId,
89
- labelsOtherAgents = false
89
+ labelsOtherAgents = false,
90
+ conversationAgent = null
90
91
  }) {
91
92
  if (answers.length === 0) return false;
92
93
  if (threadShowsLabels) return true;
93
94
  if (viewerId === null) return false;
94
95
  if (labelsOtherAgents) {
95
- const ownAssistant = `${ASSISTANT_AGENT_PREFIX}${viewerId}`;
96
- if (answers.some((answer) => answer.agent !== ownAssistant)) return true;
96
+ const expected = conversationAgent ?? `${ASSISTANT_AGENT_PREFIX}${viewerId}`;
97
+ if (answers.some((answer) => answer.agent !== expected)) return true;
97
98
  }
98
99
  return answers.some((answer) => isPersonPrincipal(answer.for_id) && answer.for_id !== viewerId);
99
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"answer-label.cjs","sources":["../../../../agent-runtime/src/answer-label.ts"],"sourcesContent":["import { getExternalStoreMessages, type ThreadMessage } from '@assistant-ui/core';\nimport type { LangChainMessage } from '@assistant-ui/react-langgraph';\n\n/**\n * `metadata.custom` key naming the agent that answered an AI message and whom\n * its run worked for (identity v7 D13: \"each answer is labelled with its\n * agent, 'for <author>'\").\n *\n * The backend stamps it on every answer a deep-agent run's model produces\n * (`agora/.../conversation_agents/answer_label.py`), under the\n * `additional_kwargs.metadata` bag the converter exposes as\n * `message.metadata.custom`, and mirrors it onto the live wire once the\n * model's turn lands. Only the server writes it. Answers written before the\n * stamp existed carry none, and get no label.\n */\nexport const ATHENA_ANSWERED_BY_KEY = 'answered_by';\n\n/** The agent that answered and whom its run worked for, as the backend stamps them. */\nexport interface DeepAgentAnsweredBy {\n /** `collab_agent:<asset id>` for a team agent, `assistant:<principal id>` for someone's own assistant. */\n agent: string;\n /** The collab agent's name when it answered; `null` for an assistant, which clients name. */\n agent_name: string | null;\n /** Whom the run worked for: a person (`user_…`), an agent's or automation's own run, or nobody (`null`). */\n for_id: string | null;\n /** That person's display name when it answered, else `null`. */\n for_name: string | null;\n}\n\n/** What a label calls someone's own assistant: the managed default agent's product name. */\nexport const ATHENA_ASSISTANT_NAME = 'Athena';\n\nconst ASSISTANT_AGENT_PREFIX = 'assistant:';\nconst PERSON_PRINCIPAL_PREFIX = 'user_';\nconst UNNAMED_AGENT_NAME = 'Agent';\nconst LABEL_SEPARATOR = ' · ';\nconst NO_ANSWERS: readonly DeepAgentAnsweredBy[] = Object.freeze([]);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst optionalId = (value: unknown): string | null =>\n typeof value === 'string' && value.length > 0 ? value : null;\n\nconst optionalName = (value: unknown): string | null => {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n};\n\n/**\n * Parse an `answered_by` stamp off a wire value.\n *\n * A stamp without a string `agent` is no stamp at all; absent or malformed\n * optional fields read as `null`, so a partly malformed stamp still names its\n * agent and never names a person it can't.\n */\nexport function readAnsweredBy(value: unknown): DeepAgentAnsweredBy | null {\n if (!isRecord(value)) return null;\n const agent = optionalId(value.agent);\n if (agent === null) return null;\n return {\n agent,\n agent_name: optionalName(value.agent_name),\n for_id: optionalId(value.for_id),\n for_name: optionalName(value.for_name),\n };\n}\n\n/**\n * The run id an answer's row carries when the deep-agent conversion split a\n * turn several answerers wrote into one row per answerer (`answer-rows.ts`):\n * one per agent and principal.\n */\nconst ANSWER_ROW_RUN_ID_PREFIX = 'answered_by:';\n\n/** The row run id of an answer by `agent` for `forId` (see `withAnswerRows`). */\nexport function answerRowRunId(agent: string, forId: string | null): string {\n return `${ANSWER_ROW_RUN_ID_PREFIX}${agent}|${forId ?? ''}`;\n}\n\n/**\n * Whether a converted row is one of a turn the conversion split by answerer.\n * Reads `metadata` optionally, as `collectMessageAnswers` does: a message\n * another runtime (or a test) builds may carry none.\n */\nfunction isSplitAnswerRow(message: ThreadMessage): boolean {\n const runId = message.role === 'assistant' ? message.metadata?.runId : undefined;\n return typeof runId === 'string' && runId.startsWith(ANSWER_ROW_RUN_ID_PREFIX);\n}\n\nconst isSameAnswerer = (a: DeepAgentAnsweredBy, b: DeepAgentAnsweredBy): boolean =>\n a.agent === b.agent && a.for_id === b.for_id;\n\nconst isPersonPrincipal = (id: string | null): id is string =>\n id !== null && id.startsWith(PERSON_PRINCIPAL_PREFIX);\n\n/** The `answered_by` stamp an AI message as the wire carries it holds; `null` for any other message. */\nexport function readLangChainAnswer(\n source: LangChainMessage | undefined\n): DeepAgentAnsweredBy | null {\n if (source?.type !== 'ai') return null;\n const bag = source.additional_kwargs?.metadata;\n return isRecord(bag) ? readAnsweredBy(bag[ATHENA_ANSWERED_BY_KEY]) : null;\n}\n\nfunction collectMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n if (message.role !== 'assistant') return NO_ANSWERS;\n const sources = getExternalStoreMessages<LangChainMessage>(message);\n if (sources.length === 0) {\n const joined = readAnsweredBy(message.metadata?.custom?.[ATHENA_ANSWERED_BY_KEY]);\n return joined === null ? NO_ANSWERS : [joined];\n }\n let answers: DeepAgentAnsweredBy[] | null = null;\n for (const source of sources) {\n const answer = readLangChainAnswer(source);\n if (answer === null || answers?.some((seen) => isSameAnswerer(seen, answer))) continue;\n answers ??= [];\n answers.push(answer);\n }\n return answers ?? NO_ANSWERS;\n}\n\nconst answersByMessage = new WeakMap<ThreadMessage, readonly DeepAgentAnsweredBy[]>();\n\n/**\n * The answers one thread message holds: each agent that answered in it and\n * whom it worked for, in the order they answered, one entry per agent and\n * principal.\n *\n * Read off the message's bound source messages, not its joined\n * `metadata.custom`: assistant-ui joins consecutive AI messages into one\n * turn, and its joined metadata keeps only the last stamp. The deep-agent\n * conversion gives each agent that answers one message in turn (D13 several\n * agents, one message) a row of its own (`answer-rows.ts`), so a row\n * normally holds one answer; a conversion without that split (another\n * pipeline, a stamp that never landed) still names every agent of the row.\n * A message with no bound sources (another runtime) falls back to the joined\n * value. Cached per message object: a settled message keeps its object\n * across a streamed token, so a thread-wide scan per token reads only the\n * message that changed.\n */\nexport function readMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n const cached = answersByMessage.get(message);\n if (cached !== undefined) return cached;\n const answers = collectMessageAnswers(message);\n answersByMessage.set(message, answers);\n return answers;\n}\n\n/**\n * The thread-wide half of the label decision: whether the transcript's\n * answers name two or more agents, or two or more principals they worked\n * for. Then every answer is labelled; a 1:1 chat with one agent working for\n * one person looks as it did before labels. Unstamped answers count for\n * nothing.\n *\n * It decides over the messages the client holds (on a windowed wire, the\n * pages loaded so far), as the human-author avatars do: a page of older\n * history that brings another agent or person turns the labels on. Each\n * label still names its own answer's stamp, so loading history never changes\n * what an answer is attributed to, only whether the line shows.\n *\n * A turn the conversion split into one row per answerer turns the labels on\n * too, before the next agent's stamp lands: while several agents answer one\n * message, the host's record already says a second agent is answering, so\n * the first agent's answer is labelled from the moment the second one's row\n * appears.\n */\nexport function threadShowsAnswerLabels(messages: readonly ThreadMessage[]): boolean {\n let first: DeepAgentAnsweredBy | null = null;\n for (const message of messages) {\n if (isSplitAnswerRow(message)) return true;\n for (const answer of readMessageAnswers(message)) {\n if (first === null) {\n first = answer;\n } else if (!isSameAnswerer(first, answer)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Whether a message's answers are labelled: always once the thread's answers\n * name several agents or principals (`threadShowsLabels`), and otherwise when\n * one of them worked for a person other than the viewer. With\n * `labelsOtherAgents`, also when one of them was written by any agent other\n * than the viewer's own assistant: a surface where the person names a team\n * agent for one message (Olympus's composer chips) shows who answered it even\n * in a 1:1 chat, where the answer would otherwise read as Athena's. Without a\n * known viewer both viewer rules are off, so a 1:1 chat never flashes labels\n * while the viewer loads.\n */\nexport function showsAnswerLabel({\n answers,\n threadShowsLabels,\n viewerId,\n labelsOtherAgents = false,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n threadShowsLabels: boolean;\n viewerId: string | null;\n /** Label an answer written by any agent other than the viewer's own assistant. */\n labelsOtherAgents?: boolean;\n}): boolean {\n if (answers.length === 0) return false;\n if (threadShowsLabels) return true;\n if (viewerId === null) return false;\n if (labelsOtherAgents) {\n const ownAssistant = `${ASSISTANT_AGENT_PREFIX}${viewerId}`;\n if (answers.some((answer) => answer.agent !== ownAssistant)) return true;\n }\n return answers.some((answer) => isPersonPrincipal(answer.for_id) && answer.for_id !== viewerId);\n}\n\nfunction answererName(answer: DeepAgentAnsweredBy): string {\n if (answer.agent_name !== null) return answer.agent_name;\n return answer.agent.startsWith(ASSISTANT_AGENT_PREFIX)\n ? ATHENA_ASSISTANT_NAME\n : UNNAMED_AGENT_NAME;\n}\n\nfunction forWhomName(answer: DeepAgentAnsweredBy, viewerId: string | null): string | null {\n if (answer.for_id !== null && answer.for_id === viewerId) return 'you';\n if (answer.for_name !== null && isPersonPrincipal(answer.for_id)) return answer.for_name;\n return null;\n}\n\nfunction joinNames(names: readonly string[]): string {\n if (names.length <= 1) return names[0] ?? '';\n return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;\n}\n\n/**\n * The label's words: who answered, then whom for. \"Finance · for you\",\n * \"Athena · for Priya Shah\", \"Finance\" (a run that worked for nobody, or for\n * an agent's own run). The agent is the collab agent's name, else\n * {@link ATHENA_ASSISTANT_NAME} for someone's own assistant, else \"Agent\".\n * Several agents answering for the same principal read \"Finance and Legal ·\n * for you\"; answers for different principals are listed apart, even when the\n * people share a name (\"Finance · for Alex, Legal · for Alex\"). `null` when\n * the message holds no answers.\n */\nexport function answerLabelText({\n answers,\n viewerId,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n viewerId: string | null;\n}): string | null {\n if (answers.length === 0) return null;\n // One group per principal (nobody is one too), never per displayed name: two\n // people who share a name stay two recipients.\n const groups: { forId: string | null; names: string[]; forWhom: string | null }[] = [];\n for (const answer of answers) {\n const name = answererName(answer);\n const forWhom = forWhomName(answer, viewerId);\n const group = groups.find((candidate) => candidate.forId === answer.for_id);\n if (group === undefined) {\n groups.push({ forId: answer.for_id, names: [name], forWhom });\n continue;\n }\n if (!group.names.includes(name)) group.names.push(name);\n // A recipient one answer left unnamed takes the name a later answer for\n // the same principal carries. The first name found wins: answers stamped\n // under two names for one id (a rename between runs) read as the first.\n group.forWhom ??= forWhom;\n }\n return groups\n .map(({ names, forWhom }) =>\n forWhom === null ? joinNames(names) : `${joinNames(names)}${LABEL_SEPARATOR}for ${forWhom}`\n )\n .join(', ');\n}\n"],"names":["getExternalStoreMessages"],"mappings":"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"}
1
+ {"version":3,"file":"answer-label.cjs","sources":["../../../../agent-runtime/src/answer-label.ts"],"sourcesContent":["import { getExternalStoreMessages, type ThreadMessage } from '@assistant-ui/core';\nimport type { LangChainMessage } from '@assistant-ui/react-langgraph';\n\n/**\n * `metadata.custom` key naming the agent that answered an AI message and whom\n * its run worked for (identity v7 D13: \"each answer is labelled with its\n * agent, 'for <author>'\").\n *\n * The backend stamps it on every answer a deep-agent run's model produces\n * (`agora/.../conversation_agents/answer_label.py`), under the\n * `additional_kwargs.metadata` bag the converter exposes as\n * `message.metadata.custom`, and mirrors it onto the live wire once the\n * model's turn lands. Only the server writes it. Answers written before the\n * stamp existed carry none, and get no label.\n */\nexport const ATHENA_ANSWERED_BY_KEY = 'answered_by';\n\n/** The agent that answered and whom its run worked for, as the backend stamps them. */\nexport interface DeepAgentAnsweredBy {\n /** `collab_agent:<asset id>` for a team agent, `assistant:<principal id>` for someone's own assistant. */\n agent: string;\n /** The collab agent's name when it answered; `null` for an assistant, which clients name. */\n agent_name: string | null;\n /** Whom the run worked for: a person (`user_…`), an agent's or automation's own run, or nobody (`null`). */\n for_id: string | null;\n /** That person's display name when it answered, else `null`. */\n for_name: string | null;\n}\n\n/** What a label calls someone's own assistant: the managed default agent's product name. */\nexport const ATHENA_ASSISTANT_NAME = 'Athena';\n\nconst ASSISTANT_AGENT_PREFIX = 'assistant:';\nconst PERSON_PRINCIPAL_PREFIX = 'user_';\nconst UNNAMED_AGENT_NAME = 'Agent';\nconst LABEL_SEPARATOR = ' · ';\nconst NO_ANSWERS: readonly DeepAgentAnsweredBy[] = Object.freeze([]);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst optionalId = (value: unknown): string | null =>\n typeof value === 'string' && value.length > 0 ? value : null;\n\nconst optionalName = (value: unknown): string | null => {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n};\n\n/**\n * Parse an `answered_by` stamp off a wire value.\n *\n * A stamp without a string `agent` is no stamp at all; absent or malformed\n * optional fields read as `null`, so a partly malformed stamp still names its\n * agent and never names a person it can't.\n */\nexport function readAnsweredBy(value: unknown): DeepAgentAnsweredBy | null {\n if (!isRecord(value)) return null;\n const agent = optionalId(value.agent);\n if (agent === null) return null;\n return {\n agent,\n agent_name: optionalName(value.agent_name),\n for_id: optionalId(value.for_id),\n for_name: optionalName(value.for_name),\n };\n}\n\n/**\n * The run id an answer's row carries when the deep-agent conversion split a\n * turn several answerers wrote into one row per answerer (`answer-rows.ts`):\n * one per agent and principal.\n */\nconst ANSWER_ROW_RUN_ID_PREFIX = 'answered_by:';\n\n/** The row run id of an answer by `agent` for `forId` (see `withAnswerRows`). */\nexport function answerRowRunId(agent: string, forId: string | null): string {\n return `${ANSWER_ROW_RUN_ID_PREFIX}${agent}|${forId ?? ''}`;\n}\n\n/**\n * Whether a converted row is one of a turn the conversion split by answerer.\n * Reads `metadata` optionally, as `collectMessageAnswers` does: a message\n * another runtime (or a test) builds may carry none.\n */\nfunction isSplitAnswerRow(message: ThreadMessage): boolean {\n const runId = message.role === 'assistant' ? message.metadata?.runId : undefined;\n return typeof runId === 'string' && runId.startsWith(ANSWER_ROW_RUN_ID_PREFIX);\n}\n\nconst isSameAnswerer = (a: DeepAgentAnsweredBy, b: DeepAgentAnsweredBy): boolean =>\n a.agent === b.agent && a.for_id === b.for_id;\n\nconst isPersonPrincipal = (id: string | null): id is string =>\n id !== null && id.startsWith(PERSON_PRINCIPAL_PREFIX);\n\n/** The `answered_by` stamp an AI message as the wire carries it holds; `null` for any other message. */\nexport function readLangChainAnswer(\n source: LangChainMessage | undefined\n): DeepAgentAnsweredBy | null {\n if (source?.type !== 'ai') return null;\n const bag = source.additional_kwargs?.metadata;\n return isRecord(bag) ? readAnsweredBy(bag[ATHENA_ANSWERED_BY_KEY]) : null;\n}\n\nfunction collectMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n if (message.role !== 'assistant') return NO_ANSWERS;\n const sources = getExternalStoreMessages<LangChainMessage>(message);\n if (sources.length === 0) {\n const joined = readAnsweredBy(message.metadata?.custom?.[ATHENA_ANSWERED_BY_KEY]);\n return joined === null ? NO_ANSWERS : [joined];\n }\n let answers: DeepAgentAnsweredBy[] | null = null;\n for (const source of sources) {\n const answer = readLangChainAnswer(source);\n if (answer === null || answers?.some((seen) => isSameAnswerer(seen, answer))) continue;\n answers ??= [];\n answers.push(answer);\n }\n return answers ?? NO_ANSWERS;\n}\n\nconst answersByMessage = new WeakMap<ThreadMessage, readonly DeepAgentAnsweredBy[]>();\n\n/**\n * The answers one thread message holds: each agent that answered in it and\n * whom it worked for, in the order they answered, one entry per agent and\n * principal.\n *\n * Read off the message's bound source messages, not its joined\n * `metadata.custom`: assistant-ui joins consecutive AI messages into one\n * turn, and its joined metadata keeps only the last stamp. The deep-agent\n * conversion gives each agent that answers one message in turn (D13 several\n * agents, one message) a row of its own (`answer-rows.ts`), so a row\n * normally holds one answer; a conversion without that split (another\n * pipeline, a stamp that never landed) still names every agent of the row.\n * A message with no bound sources (another runtime) falls back to the joined\n * value. Cached per message object: a settled message keeps its object\n * across a streamed token, so a thread-wide scan per token reads only the\n * message that changed.\n */\nexport function readMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n const cached = answersByMessage.get(message);\n if (cached !== undefined) return cached;\n const answers = collectMessageAnswers(message);\n answersByMessage.set(message, answers);\n return answers;\n}\n\n/**\n * The thread-wide half of the label decision: whether the transcript's\n * answers name two or more agents, or two or more principals they worked\n * for. Then every answer is labelled; a 1:1 chat with one agent working for\n * one person looks as it did before labels. Unstamped answers count for\n * nothing.\n *\n * It decides over the messages the client holds (on a windowed wire, the\n * pages loaded so far), as the human-author avatars do: a page of older\n * history that brings another agent or person turns the labels on. Each\n * label still names its own answer's stamp, so loading history never changes\n * what an answer is attributed to, only whether the line shows.\n *\n * A turn the conversion split into one row per answerer turns the labels on\n * too, before the next agent's stamp lands: while several agents answer one\n * message, the host's record already says a second agent is answering, so\n * the first agent's answer is labelled from the moment the second one's row\n * appears.\n */\nexport function threadShowsAnswerLabels(messages: readonly ThreadMessage[]): boolean {\n let first: DeepAgentAnsweredBy | null = null;\n for (const message of messages) {\n if (isSplitAnswerRow(message)) return true;\n for (const answer of readMessageAnswers(message)) {\n if (first === null) {\n first = answer;\n } else if (!isSameAnswerer(first, answer)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Whether a message's answers are labelled: always once the thread's answers\n * name several agents or principals (`threadShowsLabels`), and otherwise when\n * one of them worked for a person other than the viewer. With\n * `labelsOtherAgents`, also when one of them was written by an agent other\n * than the conversation's own (`conversationAgent`, else the viewer's own\n * assistant): a surface where the person names a team agent for one message\n * (Olympus's composer chips) shows who answered it even in a 1:1 chat, where\n * the answer would otherwise read as the conversation agent's. A 1:1 chat with\n * the conversation's agent, a collab agent included, shows nothing. Without a\n * known viewer both viewer rules are off, so a 1:1 chat never flashes labels\n * while the viewer loads.\n */\nexport function showsAnswerLabel({\n answers,\n threadShowsLabels,\n viewerId,\n labelsOtherAgents = false,\n conversationAgent = null,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n threadShowsLabels: boolean;\n viewerId: string | null;\n /** Label an answer written by any agent other than the conversation's own. */\n labelsOtherAgents?: boolean;\n /**\n * The agent key the conversation is with (`collab_agent:<asset id>`, as its\n * header shows it); `null` (the default) for the viewer's own assistant.\n */\n conversationAgent?: string | null;\n}): boolean {\n if (answers.length === 0) return false;\n if (threadShowsLabels) return true;\n if (viewerId === null) return false;\n if (labelsOtherAgents) {\n const expected = conversationAgent ?? `${ASSISTANT_AGENT_PREFIX}${viewerId}`;\n if (answers.some((answer) => answer.agent !== expected)) return true;\n }\n return answers.some((answer) => isPersonPrincipal(answer.for_id) && answer.for_id !== viewerId);\n}\n\nfunction answererName(answer: DeepAgentAnsweredBy): string {\n if (answer.agent_name !== null) return answer.agent_name;\n return answer.agent.startsWith(ASSISTANT_AGENT_PREFIX)\n ? ATHENA_ASSISTANT_NAME\n : UNNAMED_AGENT_NAME;\n}\n\nfunction forWhomName(answer: DeepAgentAnsweredBy, viewerId: string | null): string | null {\n if (answer.for_id !== null && answer.for_id === viewerId) return 'you';\n if (answer.for_name !== null && isPersonPrincipal(answer.for_id)) return answer.for_name;\n return null;\n}\n\nfunction joinNames(names: readonly string[]): string {\n if (names.length <= 1) return names[0] ?? '';\n return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;\n}\n\n/**\n * The label's words: who answered, then whom for. \"Finance · for you\",\n * \"Athena · for Priya Shah\", \"Finance\" (a run that worked for nobody, or for\n * an agent's own run). The agent is the collab agent's name, else\n * {@link ATHENA_ASSISTANT_NAME} for someone's own assistant, else \"Agent\".\n * Several agents answering for the same principal read \"Finance and Legal ·\n * for you\"; answers for different principals are listed apart, even when the\n * people share a name (\"Finance · for Alex, Legal · for Alex\"). `null` when\n * the message holds no answers.\n */\nexport function answerLabelText({\n answers,\n viewerId,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n viewerId: string | null;\n}): string | null {\n if (answers.length === 0) return null;\n // One group per principal (nobody is one too), never per displayed name: two\n // people who share a name stay two recipients.\n const groups: { forId: string | null; names: string[]; forWhom: string | null }[] = [];\n for (const answer of answers) {\n const name = answererName(answer);\n const forWhom = forWhomName(answer, viewerId);\n const group = groups.find((candidate) => candidate.forId === answer.for_id);\n if (group === undefined) {\n groups.push({ forId: answer.for_id, names: [name], forWhom });\n continue;\n }\n if (!group.names.includes(name)) group.names.push(name);\n // A recipient one answer left unnamed takes the name a later answer for\n // the same principal carries. The first name found wins: answers stamped\n // under two names for one id (a rename between runs) read as the first.\n group.forWhom ??= forWhom;\n }\n return groups\n .map(({ names, forWhom }) =>\n forWhom === null ? joinNames(names) : `${joinNames(names)}${LABEL_SEPARATOR}for ${forWhom}`\n )\n .join(', ');\n}\n"],"names":["getExternalStoreMessages"],"mappings":"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"}
@@ -80,19 +80,26 @@ export declare function threadShowsAnswerLabels(messages: readonly ThreadMessage
80
80
  * Whether a message's answers are labelled: always once the thread's answers
81
81
  * name several agents or principals (`threadShowsLabels`), and otherwise when
82
82
  * one of them worked for a person other than the viewer. With
83
- * `labelsOtherAgents`, also when one of them was written by any agent other
84
- * than the viewer's own assistant: a surface where the person names a team
85
- * agent for one message (Olympus's composer chips) shows who answered it even
86
- * in a 1:1 chat, where the answer would otherwise read as Athena's. Without a
83
+ * `labelsOtherAgents`, also when one of them was written by an agent other
84
+ * than the conversation's own (`conversationAgent`, else the viewer's own
85
+ * assistant): a surface where the person names a team agent for one message
86
+ * (Olympus's composer chips) shows who answered it even in a 1:1 chat, where
87
+ * the answer would otherwise read as the conversation agent's. A 1:1 chat with
88
+ * the conversation's agent, a collab agent included, shows nothing. Without a
87
89
  * known viewer both viewer rules are off, so a 1:1 chat never flashes labels
88
90
  * while the viewer loads.
89
91
  */
90
- export declare function showsAnswerLabel({ answers, threadShowsLabels, viewerId, labelsOtherAgents, }: {
92
+ export declare function showsAnswerLabel({ answers, threadShowsLabels, viewerId, labelsOtherAgents, conversationAgent, }: {
91
93
  answers: readonly DeepAgentAnsweredBy[];
92
94
  threadShowsLabels: boolean;
93
95
  viewerId: string | null;
94
- /** Label an answer written by any agent other than the viewer's own assistant. */
96
+ /** Label an answer written by any agent other than the conversation's own. */
95
97
  labelsOtherAgents?: boolean;
98
+ /**
99
+ * The agent key the conversation is with (`collab_agent:<asset id>`, as its
100
+ * header shows it); `null` (the default) for the viewer's own assistant.
101
+ */
102
+ conversationAgent?: string | null;
96
103
  }): boolean;
97
104
  /**
98
105
  * The label's words: who answered, then whom for. "Finance · for you",
@@ -84,14 +84,15 @@ function showsAnswerLabel({
84
84
  answers,
85
85
  threadShowsLabels,
86
86
  viewerId,
87
- labelsOtherAgents = false
87
+ labelsOtherAgents = false,
88
+ conversationAgent = null
88
89
  }) {
89
90
  if (answers.length === 0) return false;
90
91
  if (threadShowsLabels) return true;
91
92
  if (viewerId === null) return false;
92
93
  if (labelsOtherAgents) {
93
- const ownAssistant = `${ASSISTANT_AGENT_PREFIX}${viewerId}`;
94
- if (answers.some((answer) => answer.agent !== ownAssistant)) return true;
94
+ const expected = conversationAgent ?? `${ASSISTANT_AGENT_PREFIX}${viewerId}`;
95
+ if (answers.some((answer) => answer.agent !== expected)) return true;
95
96
  }
96
97
  return answers.some((answer) => isPersonPrincipal(answer.for_id) && answer.for_id !== viewerId);
97
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"answer-label.js","sources":["../../../../agent-runtime/src/answer-label.ts"],"sourcesContent":["import { getExternalStoreMessages, type ThreadMessage } from '@assistant-ui/core';\nimport type { LangChainMessage } from '@assistant-ui/react-langgraph';\n\n/**\n * `metadata.custom` key naming the agent that answered an AI message and whom\n * its run worked for (identity v7 D13: \"each answer is labelled with its\n * agent, 'for <author>'\").\n *\n * The backend stamps it on every answer a deep-agent run's model produces\n * (`agora/.../conversation_agents/answer_label.py`), under the\n * `additional_kwargs.metadata` bag the converter exposes as\n * `message.metadata.custom`, and mirrors it onto the live wire once the\n * model's turn lands. Only the server writes it. Answers written before the\n * stamp existed carry none, and get no label.\n */\nexport const ATHENA_ANSWERED_BY_KEY = 'answered_by';\n\n/** The agent that answered and whom its run worked for, as the backend stamps them. */\nexport interface DeepAgentAnsweredBy {\n /** `collab_agent:<asset id>` for a team agent, `assistant:<principal id>` for someone's own assistant. */\n agent: string;\n /** The collab agent's name when it answered; `null` for an assistant, which clients name. */\n agent_name: string | null;\n /** Whom the run worked for: a person (`user_…`), an agent's or automation's own run, or nobody (`null`). */\n for_id: string | null;\n /** That person's display name when it answered, else `null`. */\n for_name: string | null;\n}\n\n/** What a label calls someone's own assistant: the managed default agent's product name. */\nexport const ATHENA_ASSISTANT_NAME = 'Athena';\n\nconst ASSISTANT_AGENT_PREFIX = 'assistant:';\nconst PERSON_PRINCIPAL_PREFIX = 'user_';\nconst UNNAMED_AGENT_NAME = 'Agent';\nconst LABEL_SEPARATOR = ' · ';\nconst NO_ANSWERS: readonly DeepAgentAnsweredBy[] = Object.freeze([]);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst optionalId = (value: unknown): string | null =>\n typeof value === 'string' && value.length > 0 ? value : null;\n\nconst optionalName = (value: unknown): string | null => {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n};\n\n/**\n * Parse an `answered_by` stamp off a wire value.\n *\n * A stamp without a string `agent` is no stamp at all; absent or malformed\n * optional fields read as `null`, so a partly malformed stamp still names its\n * agent and never names a person it can't.\n */\nexport function readAnsweredBy(value: unknown): DeepAgentAnsweredBy | null {\n if (!isRecord(value)) return null;\n const agent = optionalId(value.agent);\n if (agent === null) return null;\n return {\n agent,\n agent_name: optionalName(value.agent_name),\n for_id: optionalId(value.for_id),\n for_name: optionalName(value.for_name),\n };\n}\n\n/**\n * The run id an answer's row carries when the deep-agent conversion split a\n * turn several answerers wrote into one row per answerer (`answer-rows.ts`):\n * one per agent and principal.\n */\nconst ANSWER_ROW_RUN_ID_PREFIX = 'answered_by:';\n\n/** The row run id of an answer by `agent` for `forId` (see `withAnswerRows`). */\nexport function answerRowRunId(agent: string, forId: string | null): string {\n return `${ANSWER_ROW_RUN_ID_PREFIX}${agent}|${forId ?? ''}`;\n}\n\n/**\n * Whether a converted row is one of a turn the conversion split by answerer.\n * Reads `metadata` optionally, as `collectMessageAnswers` does: a message\n * another runtime (or a test) builds may carry none.\n */\nfunction isSplitAnswerRow(message: ThreadMessage): boolean {\n const runId = message.role === 'assistant' ? message.metadata?.runId : undefined;\n return typeof runId === 'string' && runId.startsWith(ANSWER_ROW_RUN_ID_PREFIX);\n}\n\nconst isSameAnswerer = (a: DeepAgentAnsweredBy, b: DeepAgentAnsweredBy): boolean =>\n a.agent === b.agent && a.for_id === b.for_id;\n\nconst isPersonPrincipal = (id: string | null): id is string =>\n id !== null && id.startsWith(PERSON_PRINCIPAL_PREFIX);\n\n/** The `answered_by` stamp an AI message as the wire carries it holds; `null` for any other message. */\nexport function readLangChainAnswer(\n source: LangChainMessage | undefined\n): DeepAgentAnsweredBy | null {\n if (source?.type !== 'ai') return null;\n const bag = source.additional_kwargs?.metadata;\n return isRecord(bag) ? readAnsweredBy(bag[ATHENA_ANSWERED_BY_KEY]) : null;\n}\n\nfunction collectMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n if (message.role !== 'assistant') return NO_ANSWERS;\n const sources = getExternalStoreMessages<LangChainMessage>(message);\n if (sources.length === 0) {\n const joined = readAnsweredBy(message.metadata?.custom?.[ATHENA_ANSWERED_BY_KEY]);\n return joined === null ? NO_ANSWERS : [joined];\n }\n let answers: DeepAgentAnsweredBy[] | null = null;\n for (const source of sources) {\n const answer = readLangChainAnswer(source);\n if (answer === null || answers?.some((seen) => isSameAnswerer(seen, answer))) continue;\n answers ??= [];\n answers.push(answer);\n }\n return answers ?? NO_ANSWERS;\n}\n\nconst answersByMessage = new WeakMap<ThreadMessage, readonly DeepAgentAnsweredBy[]>();\n\n/**\n * The answers one thread message holds: each agent that answered in it and\n * whom it worked for, in the order they answered, one entry per agent and\n * principal.\n *\n * Read off the message's bound source messages, not its joined\n * `metadata.custom`: assistant-ui joins consecutive AI messages into one\n * turn, and its joined metadata keeps only the last stamp. The deep-agent\n * conversion gives each agent that answers one message in turn (D13 several\n * agents, one message) a row of its own (`answer-rows.ts`), so a row\n * normally holds one answer; a conversion without that split (another\n * pipeline, a stamp that never landed) still names every agent of the row.\n * A message with no bound sources (another runtime) falls back to the joined\n * value. Cached per message object: a settled message keeps its object\n * across a streamed token, so a thread-wide scan per token reads only the\n * message that changed.\n */\nexport function readMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n const cached = answersByMessage.get(message);\n if (cached !== undefined) return cached;\n const answers = collectMessageAnswers(message);\n answersByMessage.set(message, answers);\n return answers;\n}\n\n/**\n * The thread-wide half of the label decision: whether the transcript's\n * answers name two or more agents, or two or more principals they worked\n * for. Then every answer is labelled; a 1:1 chat with one agent working for\n * one person looks as it did before labels. Unstamped answers count for\n * nothing.\n *\n * It decides over the messages the client holds (on a windowed wire, the\n * pages loaded so far), as the human-author avatars do: a page of older\n * history that brings another agent or person turns the labels on. Each\n * label still names its own answer's stamp, so loading history never changes\n * what an answer is attributed to, only whether the line shows.\n *\n * A turn the conversion split into one row per answerer turns the labels on\n * too, before the next agent's stamp lands: while several agents answer one\n * message, the host's record already says a second agent is answering, so\n * the first agent's answer is labelled from the moment the second one's row\n * appears.\n */\nexport function threadShowsAnswerLabels(messages: readonly ThreadMessage[]): boolean {\n let first: DeepAgentAnsweredBy | null = null;\n for (const message of messages) {\n if (isSplitAnswerRow(message)) return true;\n for (const answer of readMessageAnswers(message)) {\n if (first === null) {\n first = answer;\n } else if (!isSameAnswerer(first, answer)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Whether a message's answers are labelled: always once the thread's answers\n * name several agents or principals (`threadShowsLabels`), and otherwise when\n * one of them worked for a person other than the viewer. With\n * `labelsOtherAgents`, also when one of them was written by any agent other\n * than the viewer's own assistant: a surface where the person names a team\n * agent for one message (Olympus's composer chips) shows who answered it even\n * in a 1:1 chat, where the answer would otherwise read as Athena's. Without a\n * known viewer both viewer rules are off, so a 1:1 chat never flashes labels\n * while the viewer loads.\n */\nexport function showsAnswerLabel({\n answers,\n threadShowsLabels,\n viewerId,\n labelsOtherAgents = false,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n threadShowsLabels: boolean;\n viewerId: string | null;\n /** Label an answer written by any agent other than the viewer's own assistant. */\n labelsOtherAgents?: boolean;\n}): boolean {\n if (answers.length === 0) return false;\n if (threadShowsLabels) return true;\n if (viewerId === null) return false;\n if (labelsOtherAgents) {\n const ownAssistant = `${ASSISTANT_AGENT_PREFIX}${viewerId}`;\n if (answers.some((answer) => answer.agent !== ownAssistant)) return true;\n }\n return answers.some((answer) => isPersonPrincipal(answer.for_id) && answer.for_id !== viewerId);\n}\n\nfunction answererName(answer: DeepAgentAnsweredBy): string {\n if (answer.agent_name !== null) return answer.agent_name;\n return answer.agent.startsWith(ASSISTANT_AGENT_PREFIX)\n ? ATHENA_ASSISTANT_NAME\n : UNNAMED_AGENT_NAME;\n}\n\nfunction forWhomName(answer: DeepAgentAnsweredBy, viewerId: string | null): string | null {\n if (answer.for_id !== null && answer.for_id === viewerId) return 'you';\n if (answer.for_name !== null && isPersonPrincipal(answer.for_id)) return answer.for_name;\n return null;\n}\n\nfunction joinNames(names: readonly string[]): string {\n if (names.length <= 1) return names[0] ?? '';\n return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;\n}\n\n/**\n * The label's words: who answered, then whom for. \"Finance · for you\",\n * \"Athena · for Priya Shah\", \"Finance\" (a run that worked for nobody, or for\n * an agent's own run). The agent is the collab agent's name, else\n * {@link ATHENA_ASSISTANT_NAME} for someone's own assistant, else \"Agent\".\n * Several agents answering for the same principal read \"Finance and Legal ·\n * for you\"; answers for different principals are listed apart, even when the\n * people share a name (\"Finance · for Alex, Legal · for Alex\"). `null` when\n * the message holds no answers.\n */\nexport function answerLabelText({\n answers,\n viewerId,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n viewerId: string | null;\n}): string | null {\n if (answers.length === 0) return null;\n // One group per principal (nobody is one too), never per displayed name: two\n // people who share a name stay two recipients.\n const groups: { forId: string | null; names: string[]; forWhom: string | null }[] = [];\n for (const answer of answers) {\n const name = answererName(answer);\n const forWhom = forWhomName(answer, viewerId);\n const group = groups.find((candidate) => candidate.forId === answer.for_id);\n if (group === undefined) {\n groups.push({ forId: answer.for_id, names: [name], forWhom });\n continue;\n }\n if (!group.names.includes(name)) group.names.push(name);\n // A recipient one answer left unnamed takes the name a later answer for\n // the same principal carries. The first name found wins: answers stamped\n // under two names for one id (a rename between runs) read as the first.\n group.forWhom ??= forWhom;\n }\n return groups\n .map(({ names, forWhom }) =>\n forWhom === null ? joinNames(names) : `${joinNames(names)}${LABEL_SEPARATOR}for ${forWhom}`\n )\n .join(', ');\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"answer-label.js","sources":["../../../../agent-runtime/src/answer-label.ts"],"sourcesContent":["import { getExternalStoreMessages, type ThreadMessage } from '@assistant-ui/core';\nimport type { LangChainMessage } from '@assistant-ui/react-langgraph';\n\n/**\n * `metadata.custom` key naming the agent that answered an AI message and whom\n * its run worked for (identity v7 D13: \"each answer is labelled with its\n * agent, 'for <author>'\").\n *\n * The backend stamps it on every answer a deep-agent run's model produces\n * (`agora/.../conversation_agents/answer_label.py`), under the\n * `additional_kwargs.metadata` bag the converter exposes as\n * `message.metadata.custom`, and mirrors it onto the live wire once the\n * model's turn lands. Only the server writes it. Answers written before the\n * stamp existed carry none, and get no label.\n */\nexport const ATHENA_ANSWERED_BY_KEY = 'answered_by';\n\n/** The agent that answered and whom its run worked for, as the backend stamps them. */\nexport interface DeepAgentAnsweredBy {\n /** `collab_agent:<asset id>` for a team agent, `assistant:<principal id>` for someone's own assistant. */\n agent: string;\n /** The collab agent's name when it answered; `null` for an assistant, which clients name. */\n agent_name: string | null;\n /** Whom the run worked for: a person (`user_…`), an agent's or automation's own run, or nobody (`null`). */\n for_id: string | null;\n /** That person's display name when it answered, else `null`. */\n for_name: string | null;\n}\n\n/** What a label calls someone's own assistant: the managed default agent's product name. */\nexport const ATHENA_ASSISTANT_NAME = 'Athena';\n\nconst ASSISTANT_AGENT_PREFIX = 'assistant:';\nconst PERSON_PRINCIPAL_PREFIX = 'user_';\nconst UNNAMED_AGENT_NAME = 'Agent';\nconst LABEL_SEPARATOR = ' · ';\nconst NO_ANSWERS: readonly DeepAgentAnsweredBy[] = Object.freeze([]);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst optionalId = (value: unknown): string | null =>\n typeof value === 'string' && value.length > 0 ? value : null;\n\nconst optionalName = (value: unknown): string | null => {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n};\n\n/**\n * Parse an `answered_by` stamp off a wire value.\n *\n * A stamp without a string `agent` is no stamp at all; absent or malformed\n * optional fields read as `null`, so a partly malformed stamp still names its\n * agent and never names a person it can't.\n */\nexport function readAnsweredBy(value: unknown): DeepAgentAnsweredBy | null {\n if (!isRecord(value)) return null;\n const agent = optionalId(value.agent);\n if (agent === null) return null;\n return {\n agent,\n agent_name: optionalName(value.agent_name),\n for_id: optionalId(value.for_id),\n for_name: optionalName(value.for_name),\n };\n}\n\n/**\n * The run id an answer's row carries when the deep-agent conversion split a\n * turn several answerers wrote into one row per answerer (`answer-rows.ts`):\n * one per agent and principal.\n */\nconst ANSWER_ROW_RUN_ID_PREFIX = 'answered_by:';\n\n/** The row run id of an answer by `agent` for `forId` (see `withAnswerRows`). */\nexport function answerRowRunId(agent: string, forId: string | null): string {\n return `${ANSWER_ROW_RUN_ID_PREFIX}${agent}|${forId ?? ''}`;\n}\n\n/**\n * Whether a converted row is one of a turn the conversion split by answerer.\n * Reads `metadata` optionally, as `collectMessageAnswers` does: a message\n * another runtime (or a test) builds may carry none.\n */\nfunction isSplitAnswerRow(message: ThreadMessage): boolean {\n const runId = message.role === 'assistant' ? message.metadata?.runId : undefined;\n return typeof runId === 'string' && runId.startsWith(ANSWER_ROW_RUN_ID_PREFIX);\n}\n\nconst isSameAnswerer = (a: DeepAgentAnsweredBy, b: DeepAgentAnsweredBy): boolean =>\n a.agent === b.agent && a.for_id === b.for_id;\n\nconst isPersonPrincipal = (id: string | null): id is string =>\n id !== null && id.startsWith(PERSON_PRINCIPAL_PREFIX);\n\n/** The `answered_by` stamp an AI message as the wire carries it holds; `null` for any other message. */\nexport function readLangChainAnswer(\n source: LangChainMessage | undefined\n): DeepAgentAnsweredBy | null {\n if (source?.type !== 'ai') return null;\n const bag = source.additional_kwargs?.metadata;\n return isRecord(bag) ? readAnsweredBy(bag[ATHENA_ANSWERED_BY_KEY]) : null;\n}\n\nfunction collectMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n if (message.role !== 'assistant') return NO_ANSWERS;\n const sources = getExternalStoreMessages<LangChainMessage>(message);\n if (sources.length === 0) {\n const joined = readAnsweredBy(message.metadata?.custom?.[ATHENA_ANSWERED_BY_KEY]);\n return joined === null ? NO_ANSWERS : [joined];\n }\n let answers: DeepAgentAnsweredBy[] | null = null;\n for (const source of sources) {\n const answer = readLangChainAnswer(source);\n if (answer === null || answers?.some((seen) => isSameAnswerer(seen, answer))) continue;\n answers ??= [];\n answers.push(answer);\n }\n return answers ?? NO_ANSWERS;\n}\n\nconst answersByMessage = new WeakMap<ThreadMessage, readonly DeepAgentAnsweredBy[]>();\n\n/**\n * The answers one thread message holds: each agent that answered in it and\n * whom it worked for, in the order they answered, one entry per agent and\n * principal.\n *\n * Read off the message's bound source messages, not its joined\n * `metadata.custom`: assistant-ui joins consecutive AI messages into one\n * turn, and its joined metadata keeps only the last stamp. The deep-agent\n * conversion gives each agent that answers one message in turn (D13 several\n * agents, one message) a row of its own (`answer-rows.ts`), so a row\n * normally holds one answer; a conversion without that split (another\n * pipeline, a stamp that never landed) still names every agent of the row.\n * A message with no bound sources (another runtime) falls back to the joined\n * value. Cached per message object: a settled message keeps its object\n * across a streamed token, so a thread-wide scan per token reads only the\n * message that changed.\n */\nexport function readMessageAnswers(message: ThreadMessage): readonly DeepAgentAnsweredBy[] {\n const cached = answersByMessage.get(message);\n if (cached !== undefined) return cached;\n const answers = collectMessageAnswers(message);\n answersByMessage.set(message, answers);\n return answers;\n}\n\n/**\n * The thread-wide half of the label decision: whether the transcript's\n * answers name two or more agents, or two or more principals they worked\n * for. Then every answer is labelled; a 1:1 chat with one agent working for\n * one person looks as it did before labels. Unstamped answers count for\n * nothing.\n *\n * It decides over the messages the client holds (on a windowed wire, the\n * pages loaded so far), as the human-author avatars do: a page of older\n * history that brings another agent or person turns the labels on. Each\n * label still names its own answer's stamp, so loading history never changes\n * what an answer is attributed to, only whether the line shows.\n *\n * A turn the conversion split into one row per answerer turns the labels on\n * too, before the next agent's stamp lands: while several agents answer one\n * message, the host's record already says a second agent is answering, so\n * the first agent's answer is labelled from the moment the second one's row\n * appears.\n */\nexport function threadShowsAnswerLabels(messages: readonly ThreadMessage[]): boolean {\n let first: DeepAgentAnsweredBy | null = null;\n for (const message of messages) {\n if (isSplitAnswerRow(message)) return true;\n for (const answer of readMessageAnswers(message)) {\n if (first === null) {\n first = answer;\n } else if (!isSameAnswerer(first, answer)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Whether a message's answers are labelled: always once the thread's answers\n * name several agents or principals (`threadShowsLabels`), and otherwise when\n * one of them worked for a person other than the viewer. With\n * `labelsOtherAgents`, also when one of them was written by an agent other\n * than the conversation's own (`conversationAgent`, else the viewer's own\n * assistant): a surface where the person names a team agent for one message\n * (Olympus's composer chips) shows who answered it even in a 1:1 chat, where\n * the answer would otherwise read as the conversation agent's. A 1:1 chat with\n * the conversation's agent, a collab agent included, shows nothing. Without a\n * known viewer both viewer rules are off, so a 1:1 chat never flashes labels\n * while the viewer loads.\n */\nexport function showsAnswerLabel({\n answers,\n threadShowsLabels,\n viewerId,\n labelsOtherAgents = false,\n conversationAgent = null,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n threadShowsLabels: boolean;\n viewerId: string | null;\n /** Label an answer written by any agent other than the conversation's own. */\n labelsOtherAgents?: boolean;\n /**\n * The agent key the conversation is with (`collab_agent:<asset id>`, as its\n * header shows it); `null` (the default) for the viewer's own assistant.\n */\n conversationAgent?: string | null;\n}): boolean {\n if (answers.length === 0) return false;\n if (threadShowsLabels) return true;\n if (viewerId === null) return false;\n if (labelsOtherAgents) {\n const expected = conversationAgent ?? `${ASSISTANT_AGENT_PREFIX}${viewerId}`;\n if (answers.some((answer) => answer.agent !== expected)) return true;\n }\n return answers.some((answer) => isPersonPrincipal(answer.for_id) && answer.for_id !== viewerId);\n}\n\nfunction answererName(answer: DeepAgentAnsweredBy): string {\n if (answer.agent_name !== null) return answer.agent_name;\n return answer.agent.startsWith(ASSISTANT_AGENT_PREFIX)\n ? ATHENA_ASSISTANT_NAME\n : UNNAMED_AGENT_NAME;\n}\n\nfunction forWhomName(answer: DeepAgentAnsweredBy, viewerId: string | null): string | null {\n if (answer.for_id !== null && answer.for_id === viewerId) return 'you';\n if (answer.for_name !== null && isPersonPrincipal(answer.for_id)) return answer.for_name;\n return null;\n}\n\nfunction joinNames(names: readonly string[]): string {\n if (names.length <= 1) return names[0] ?? '';\n return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;\n}\n\n/**\n * The label's words: who answered, then whom for. \"Finance · for you\",\n * \"Athena · for Priya Shah\", \"Finance\" (a run that worked for nobody, or for\n * an agent's own run). The agent is the collab agent's name, else\n * {@link ATHENA_ASSISTANT_NAME} for someone's own assistant, else \"Agent\".\n * Several agents answering for the same principal read \"Finance and Legal ·\n * for you\"; answers for different principals are listed apart, even when the\n * people share a name (\"Finance · for Alex, Legal · for Alex\"). `null` when\n * the message holds no answers.\n */\nexport function answerLabelText({\n answers,\n viewerId,\n}: {\n answers: readonly DeepAgentAnsweredBy[];\n viewerId: string | null;\n}): string | null {\n if (answers.length === 0) return null;\n // One group per principal (nobody is one too), never per displayed name: two\n // people who share a name stay two recipients.\n const groups: { forId: string | null; names: string[]; forWhom: string | null }[] = [];\n for (const answer of answers) {\n const name = answererName(answer);\n const forWhom = forWhomName(answer, viewerId);\n const group = groups.find((candidate) => candidate.forId === answer.for_id);\n if (group === undefined) {\n groups.push({ forId: answer.for_id, names: [name], forWhom });\n continue;\n }\n if (!group.names.includes(name)) group.names.push(name);\n // A recipient one answer left unnamed takes the name a later answer for\n // the same principal carries. The first name found wins: answers stamped\n // under two names for one id (a rename between runs) read as the first.\n group.forWhom ??= forWhom;\n }\n return groups\n .map(({ names, forWhom }) =>\n forWhom === null ? joinNames(names) : `${joinNames(names)}${LABEL_SEPARATOR}for ${forWhom}`\n )\n .join(', ');\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-outbox-attachments.cjs","sources":["../../../../agent-runtime/src/chat-outbox-attachments.ts"],"sourcesContent":["import type { ChatOutboxAttachment } from \"./chat-outbox-store\";\n\n/**\n * Whether a waiting message's attachments can still be opened, asked of Athena right before the\n * message goes (`chat-outbox.ts`). A held message carries only files that had finished uploading\n * before Athena went out of reach, but one may be deleted, or stop being shared with the person,\n * while it waits: the message must not go with a reference Athena no longer lets them open.\n *\n * Each file is read through agora's permission-checked `GET /api/v0/assets/{id}`\n * (`get_asset_access_context_or_http`: `get_asset_with_permission_check` in the asset's workspace)\n * as the signed-in person. Nothing here grants anything: the run reads every attachment through\n * the same gates again when it uses it.\n */\n\n/** What Athena answered about a waiting message's attachments. */\nexport type ChatOutboxAttachmentVerdict =\n /** Every one is still there and still the person's to open. */\n | \"ok\"\n /** At least one is gone (deleted, or in the trash) or no longer the person's to open. */\n | \"refused\"\n /** Athena could not say: a read failed, timed out, or its credential was refused. */\n | \"unknown\";\n\n/** Asks Athena about a waiting message's attachments. */\nexport type ChatOutboxAttachmentCheck = (\n attachments: readonly ChatOutboxAttachment[],\n) => Promise<ChatOutboxAttachmentVerdict>;\n\n/** agora's permission-checked read of one asset, relative to its API base. */\nexport function chatOutboxAttachmentPath(assetId: string): string {\n return `/api/v0/assets/${encodeURIComponent(assetId)}`;\n}\n\n/** As much of a `fetch` response as the check reads. */\nexport interface ChatOutboxAssetReadResponse {\n status: number;\n json(): Promise<unknown>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nasync function verdictOf(response: ChatOutboxAssetReadResponse): Promise<ChatOutboxAttachmentVerdict> {\n // 404: the asset is gone (or never was); 403: it is no longer the person's to open.\n if (response.status === 403 || response.status === 404) return \"refused\";\n if (response.status < 200 || response.status >= 300) return \"unknown\";\n // A body that does not read (cut off, or not agora's JSON) never says whether the file is in\n // the trash: that is no answer.\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return \"unknown\";\n }\n if (!isRecord(body)) return \"unknown\";\n // An archived asset is in the trash: deleted, as far as a message is concerned.\n return body.is_archived === true ? \"refused\" : \"ok\";\n}\n\n/**\n * The check a host hands its chat outbox: each attachment read once, in turn, through `readAsset`\n * (`GET {agora}{chatOutboxAttachmentPath(id)}` with the person's credential, renewed once on a\n * refused token where the host can, under the host's own request timeout). `refused` as soon as\n * one is refused; `unknown` when none was refused but one could not be read; else `ok`.\n */\nexport function createChatOutboxAttachmentCheck({\n readAsset,\n}: {\n readAsset: (assetId: string) => Promise<ChatOutboxAssetReadResponse>;\n}): ChatOutboxAttachmentCheck {\n return async (attachments) => {\n let unknown = false;\n for (const assetId of new Set(attachments.map((attachment) => attachment.assetId))) {\n let verdict: ChatOutboxAttachmentVerdict;\n try {\n verdict = await verdictOf(await readAsset(assetId));\n } catch {\n verdict = \"unknown\";\n }\n if (verdict === \"refused\") return \"refused\";\n if (verdict === \"unknown\") unknown = true;\n }\n return unknown ? \"unknown\" : \"ok\";\n };\n}\n"],"names":[],"mappings":";;AA6BO,SAAS,yBAAyB,SAAyB;AAChE,SAAO,kBAAkB,mBAAmB,OAAO,CAAC;AACtD;AAQA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,eAAe,UAAU,UAA6E;AAEpG,MAAI,SAAS,WAAW,OAAO,SAAS,WAAW,IAAK,QAAO;AAC/D,MAAI,SAAS,SAAS,OAAO,SAAS,UAAU,IAAK,QAAO;AAG5D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,KAAA;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAE5B,SAAO,KAAK,gBAAgB,OAAO,YAAY;AACjD;AAQO,SAAS,gCAAgC;AAAA,EAC9C;AACF,GAE8B;AAC5B,SAAO,OAAO,gBAAgB;AAC5B,QAAI,UAAU;AACd,eAAW,WAAW,IAAI,IAAI,YAAY,IAAI,CAAC,eAAe,WAAW,OAAO,CAAC,GAAG;AAClF,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,UAAU,MAAM,UAAU,OAAO,CAAC;AAAA,MACpD,QAAQ;AACN,kBAAU;AAAA,MACZ;AACA,UAAI,YAAY,UAAW,QAAO;AAClC,UAAI,YAAY,UAAW,WAAU;AAAA,IACvC;AACA,WAAO,UAAU,YAAY;AAAA,EAC/B;AACF;;;"}
1
+ {"version":3,"file":"chat-outbox-attachments.cjs","sources":["../../../../agent-runtime/src/chat-outbox-attachments.ts"],"sourcesContent":["import type { ChatOutboxAttachment } from \"./chat-outbox-entry\";\n\n/**\n * Whether a waiting message's attachments can still be opened, asked of Athena right before the\n * message goes (`chat-outbox.ts`). A held message carries only files that had finished uploading\n * before Athena went out of reach, but one may be deleted, or stop being shared with the person,\n * while it waits: the message must not go with a reference Athena no longer lets them open.\n *\n * Each file is read through agora's permission-checked `GET /api/v0/assets/{id}`\n * (`get_asset_access_context_or_http`: `get_asset_with_permission_check` in the asset's workspace)\n * as the signed-in person. Nothing here grants anything: the run reads every attachment through\n * the same gates again when it uses it.\n */\n\n/** What Athena answered about a waiting message's attachments. */\nexport type ChatOutboxAttachmentVerdict =\n /** Every one is still there and still the person's to open. */\n | \"ok\"\n /** At least one is gone (deleted, or in the trash) or no longer the person's to open. */\n | \"refused\"\n /** Athena could not say: a read failed, timed out, or its credential was refused. */\n | \"unknown\";\n\n/** Asks Athena about a waiting message's attachments. */\nexport type ChatOutboxAttachmentCheck = (\n attachments: readonly ChatOutboxAttachment[],\n) => Promise<ChatOutboxAttachmentVerdict>;\n\n/** agora's permission-checked read of one asset, relative to its API base. */\nexport function chatOutboxAttachmentPath(assetId: string): string {\n return `/api/v0/assets/${encodeURIComponent(assetId)}`;\n}\n\n/** As much of a `fetch` response as the check reads. */\nexport interface ChatOutboxAssetReadResponse {\n status: number;\n json(): Promise<unknown>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nasync function verdictOf(response: ChatOutboxAssetReadResponse): Promise<ChatOutboxAttachmentVerdict> {\n // 404: the asset is gone (or never was); 403: it is no longer the person's to open.\n if (response.status === 403 || response.status === 404) return \"refused\";\n if (response.status < 200 || response.status >= 300) return \"unknown\";\n // A body that does not read (cut off, or not agora's JSON) never says whether the file is in\n // the trash: that is no answer.\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return \"unknown\";\n }\n if (!isRecord(body)) return \"unknown\";\n // An archived asset is in the trash: deleted, as far as a message is concerned.\n return body.is_archived === true ? \"refused\" : \"ok\";\n}\n\n/**\n * The check a host hands its chat outbox: each attachment read once, in turn, through `readAsset`\n * (`GET {agora}{chatOutboxAttachmentPath(id)}` with the person's credential, renewed once on a\n * refused token where the host can, under the host's own request timeout). `refused` as soon as\n * one is refused; `unknown` when none was refused but one could not be read; else `ok`.\n */\nexport function createChatOutboxAttachmentCheck({\n readAsset,\n}: {\n readAsset: (assetId: string) => Promise<ChatOutboxAssetReadResponse>;\n}): ChatOutboxAttachmentCheck {\n return async (attachments) => {\n let unknown = false;\n for (const assetId of new Set(attachments.map((attachment) => attachment.assetId))) {\n let verdict: ChatOutboxAttachmentVerdict;\n try {\n verdict = await verdictOf(await readAsset(assetId));\n } catch {\n verdict = \"unknown\";\n }\n if (verdict === \"refused\") return \"refused\";\n if (verdict === \"unknown\") unknown = true;\n }\n return unknown ? \"unknown\" : \"ok\";\n };\n}\n"],"names":[],"mappings":";;AA6BO,SAAS,yBAAyB,SAAyB;AAChE,SAAO,kBAAkB,mBAAmB,OAAO,CAAC;AACtD;AAQA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,eAAe,UAAU,UAA6E;AAEpG,MAAI,SAAS,WAAW,OAAO,SAAS,WAAW,IAAK,QAAO;AAC/D,MAAI,SAAS,SAAS,OAAO,SAAS,UAAU,IAAK,QAAO;AAG5D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,KAAA;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAE5B,SAAO,KAAK,gBAAgB,OAAO,YAAY;AACjD;AAQO,SAAS,gCAAgC;AAAA,EAC9C;AACF,GAE8B;AAC5B,SAAO,OAAO,gBAAgB;AAC5B,QAAI,UAAU;AACd,eAAW,WAAW,IAAI,IAAI,YAAY,IAAI,CAAC,eAAe,WAAW,OAAO,CAAC,GAAG;AAClF,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,UAAU,MAAM,UAAU,OAAO,CAAC;AAAA,MACpD,QAAQ;AACN,kBAAU;AAAA,MACZ;AACA,UAAI,YAAY,UAAW,QAAO;AAClC,UAAI,YAAY,UAAW,WAAU;AAAA,IACvC;AACA,WAAO,UAAU,YAAY;AAAA,EAC/B;AACF;;;"}
@@ -1,4 +1,4 @@
1
- import type { ChatOutboxAttachment } from "./chat-outbox-store";
1
+ import type { ChatOutboxAttachment } from "./chat-outbox-entry";
2
2
  /**
3
3
  * Whether a waiting message's attachments can still be opened, asked of Athena right before the
4
4
  * message goes (`chat-outbox.ts`). A held message carries only files that had finished uploading
@@ -1 +1 @@
1
- {"version":3,"file":"chat-outbox-attachments.js","sources":["../../../../agent-runtime/src/chat-outbox-attachments.ts"],"sourcesContent":["import type { ChatOutboxAttachment } from \"./chat-outbox-store\";\n\n/**\n * Whether a waiting message's attachments can still be opened, asked of Athena right before the\n * message goes (`chat-outbox.ts`). A held message carries only files that had finished uploading\n * before Athena went out of reach, but one may be deleted, or stop being shared with the person,\n * while it waits: the message must not go with a reference Athena no longer lets them open.\n *\n * Each file is read through agora's permission-checked `GET /api/v0/assets/{id}`\n * (`get_asset_access_context_or_http`: `get_asset_with_permission_check` in the asset's workspace)\n * as the signed-in person. Nothing here grants anything: the run reads every attachment through\n * the same gates again when it uses it.\n */\n\n/** What Athena answered about a waiting message's attachments. */\nexport type ChatOutboxAttachmentVerdict =\n /** Every one is still there and still the person's to open. */\n | \"ok\"\n /** At least one is gone (deleted, or in the trash) or no longer the person's to open. */\n | \"refused\"\n /** Athena could not say: a read failed, timed out, or its credential was refused. */\n | \"unknown\";\n\n/** Asks Athena about a waiting message's attachments. */\nexport type ChatOutboxAttachmentCheck = (\n attachments: readonly ChatOutboxAttachment[],\n) => Promise<ChatOutboxAttachmentVerdict>;\n\n/** agora's permission-checked read of one asset, relative to its API base. */\nexport function chatOutboxAttachmentPath(assetId: string): string {\n return `/api/v0/assets/${encodeURIComponent(assetId)}`;\n}\n\n/** As much of a `fetch` response as the check reads. */\nexport interface ChatOutboxAssetReadResponse {\n status: number;\n json(): Promise<unknown>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nasync function verdictOf(response: ChatOutboxAssetReadResponse): Promise<ChatOutboxAttachmentVerdict> {\n // 404: the asset is gone (or never was); 403: it is no longer the person's to open.\n if (response.status === 403 || response.status === 404) return \"refused\";\n if (response.status < 200 || response.status >= 300) return \"unknown\";\n // A body that does not read (cut off, or not agora's JSON) never says whether the file is in\n // the trash: that is no answer.\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return \"unknown\";\n }\n if (!isRecord(body)) return \"unknown\";\n // An archived asset is in the trash: deleted, as far as a message is concerned.\n return body.is_archived === true ? \"refused\" : \"ok\";\n}\n\n/**\n * The check a host hands its chat outbox: each attachment read once, in turn, through `readAsset`\n * (`GET {agora}{chatOutboxAttachmentPath(id)}` with the person's credential, renewed once on a\n * refused token where the host can, under the host's own request timeout). `refused` as soon as\n * one is refused; `unknown` when none was refused but one could not be read; else `ok`.\n */\nexport function createChatOutboxAttachmentCheck({\n readAsset,\n}: {\n readAsset: (assetId: string) => Promise<ChatOutboxAssetReadResponse>;\n}): ChatOutboxAttachmentCheck {\n return async (attachments) => {\n let unknown = false;\n for (const assetId of new Set(attachments.map((attachment) => attachment.assetId))) {\n let verdict: ChatOutboxAttachmentVerdict;\n try {\n verdict = await verdictOf(await readAsset(assetId));\n } catch {\n verdict = \"unknown\";\n }\n if (verdict === \"refused\") return \"refused\";\n if (verdict === \"unknown\") unknown = true;\n }\n return unknown ? \"unknown\" : \"ok\";\n };\n}\n"],"names":[],"mappings":"AA6BO,SAAS,yBAAyB,SAAyB;AAChE,SAAO,kBAAkB,mBAAmB,OAAO,CAAC;AACtD;AAQA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,eAAe,UAAU,UAA6E;AAEpG,MAAI,SAAS,WAAW,OAAO,SAAS,WAAW,IAAK,QAAO;AAC/D,MAAI,SAAS,SAAS,OAAO,SAAS,UAAU,IAAK,QAAO;AAG5D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,KAAA;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAE5B,SAAO,KAAK,gBAAgB,OAAO,YAAY;AACjD;AAQO,SAAS,gCAAgC;AAAA,EAC9C;AACF,GAE8B;AAC5B,SAAO,OAAO,gBAAgB;AAC5B,QAAI,UAAU;AACd,eAAW,WAAW,IAAI,IAAI,YAAY,IAAI,CAAC,eAAe,WAAW,OAAO,CAAC,GAAG;AAClF,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,UAAU,MAAM,UAAU,OAAO,CAAC;AAAA,MACpD,QAAQ;AACN,kBAAU;AAAA,MACZ;AACA,UAAI,YAAY,UAAW,QAAO;AAClC,UAAI,YAAY,UAAW,WAAU;AAAA,IACvC;AACA,WAAO,UAAU,YAAY;AAAA,EAC/B;AACF;"}
1
+ {"version":3,"file":"chat-outbox-attachments.js","sources":["../../../../agent-runtime/src/chat-outbox-attachments.ts"],"sourcesContent":["import type { ChatOutboxAttachment } from \"./chat-outbox-entry\";\n\n/**\n * Whether a waiting message's attachments can still be opened, asked of Athena right before the\n * message goes (`chat-outbox.ts`). A held message carries only files that had finished uploading\n * before Athena went out of reach, but one may be deleted, or stop being shared with the person,\n * while it waits: the message must not go with a reference Athena no longer lets them open.\n *\n * Each file is read through agora's permission-checked `GET /api/v0/assets/{id}`\n * (`get_asset_access_context_or_http`: `get_asset_with_permission_check` in the asset's workspace)\n * as the signed-in person. Nothing here grants anything: the run reads every attachment through\n * the same gates again when it uses it.\n */\n\n/** What Athena answered about a waiting message's attachments. */\nexport type ChatOutboxAttachmentVerdict =\n /** Every one is still there and still the person's to open. */\n | \"ok\"\n /** At least one is gone (deleted, or in the trash) or no longer the person's to open. */\n | \"refused\"\n /** Athena could not say: a read failed, timed out, or its credential was refused. */\n | \"unknown\";\n\n/** Asks Athena about a waiting message's attachments. */\nexport type ChatOutboxAttachmentCheck = (\n attachments: readonly ChatOutboxAttachment[],\n) => Promise<ChatOutboxAttachmentVerdict>;\n\n/** agora's permission-checked read of one asset, relative to its API base. */\nexport function chatOutboxAttachmentPath(assetId: string): string {\n return `/api/v0/assets/${encodeURIComponent(assetId)}`;\n}\n\n/** As much of a `fetch` response as the check reads. */\nexport interface ChatOutboxAssetReadResponse {\n status: number;\n json(): Promise<unknown>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nasync function verdictOf(response: ChatOutboxAssetReadResponse): Promise<ChatOutboxAttachmentVerdict> {\n // 404: the asset is gone (or never was); 403: it is no longer the person's to open.\n if (response.status === 403 || response.status === 404) return \"refused\";\n if (response.status < 200 || response.status >= 300) return \"unknown\";\n // A body that does not read (cut off, or not agora's JSON) never says whether the file is in\n // the trash: that is no answer.\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return \"unknown\";\n }\n if (!isRecord(body)) return \"unknown\";\n // An archived asset is in the trash: deleted, as far as a message is concerned.\n return body.is_archived === true ? \"refused\" : \"ok\";\n}\n\n/**\n * The check a host hands its chat outbox: each attachment read once, in turn, through `readAsset`\n * (`GET {agora}{chatOutboxAttachmentPath(id)}` with the person's credential, renewed once on a\n * refused token where the host can, under the host's own request timeout). `refused` as soon as\n * one is refused; `unknown` when none was refused but one could not be read; else `ok`.\n */\nexport function createChatOutboxAttachmentCheck({\n readAsset,\n}: {\n readAsset: (assetId: string) => Promise<ChatOutboxAssetReadResponse>;\n}): ChatOutboxAttachmentCheck {\n return async (attachments) => {\n let unknown = false;\n for (const assetId of new Set(attachments.map((attachment) => attachment.assetId))) {\n let verdict: ChatOutboxAttachmentVerdict;\n try {\n verdict = await verdictOf(await readAsset(assetId));\n } catch {\n verdict = \"unknown\";\n }\n if (verdict === \"refused\") return \"refused\";\n if (verdict === \"unknown\") unknown = true;\n }\n return unknown ? \"unknown\" : \"ok\";\n };\n}\n"],"names":[],"mappings":"AA6BO,SAAS,yBAAyB,SAAyB;AAChE,SAAO,kBAAkB,mBAAmB,OAAO,CAAC;AACtD;AAQA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,eAAe,UAAU,UAA6E;AAEpG,MAAI,SAAS,WAAW,OAAO,SAAS,WAAW,IAAK,QAAO;AAC/D,MAAI,SAAS,SAAS,OAAO,SAAS,UAAU,IAAK,QAAO;AAG5D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,KAAA;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAE5B,SAAO,KAAK,gBAAgB,OAAO,YAAY;AACjD;AAQO,SAAS,gCAAgC;AAAA,EAC9C;AACF,GAE8B;AAC5B,SAAO,OAAO,gBAAgB;AAC5B,QAAI,UAAU;AACd,eAAW,WAAW,IAAI,IAAI,YAAY,IAAI,CAAC,eAAe,WAAW,OAAO,CAAC,GAAG;AAClF,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,UAAU,MAAM,UAAU,OAAO,CAAC;AAAA,MACpD,QAAQ;AACN,kBAAU;AAAA,MACZ;AACA,UAAI,YAAY,UAAW,QAAO;AAClC,UAAI,YAAY,UAAW,WAAU;AAAA,IACvC;AACA,WAAO,UAAU,YAAY;AAAA,EAC/B;AACF;"}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const chatOutboxPolicy = require("./chat-outbox-policy.cjs");
4
+ const statewireHeldSends = require("./statewire-held-sends.cjs");
5
+ const CHAT_OUTBOX_LOCAL_META_KIND = "athena-chat-outbox";
6
+ const LEGACY_CHAT_OUTBOX_SOURCE = "athena-chat-outbox:v1";
7
+ function isRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ function readChatOutboxLocalMeta(localMeta) {
11
+ if (!isRecord(localMeta)) return {};
12
+ const meta = {};
13
+ if (localMeta.kind === CHAT_OUTBOX_LOCAL_META_KIND) meta.kind = CHAT_OUTBOX_LOCAL_META_KIND;
14
+ if (typeof localMeta.threadId === "string") meta.threadId = localMeta.threadId;
15
+ if (typeof localMeta.queuedAt === "number" && Number.isFinite(localMeta.queuedAt)) meta.queuedAt = localMeta.queuedAt;
16
+ if (typeof localMeta.newChat === "boolean") meta.newChat = localMeta.newChat;
17
+ if (typeof localMeta.composerMarkdown === "string") meta.composerMarkdown = localMeta.composerMarkdown;
18
+ if (typeof localMeta.composerHtml === "string") meta.composerHtml = localMeta.composerHtml;
19
+ const attachments = readAttachments(localMeta.attachments);
20
+ if (attachments) meta.attachments = attachments;
21
+ if (typeof localMeta.countdownEndsAt === "number") meta.countdownEndsAt = localMeta.countdownEndsAt;
22
+ if (typeof localMeta.countdownFrom === "number") meta.countdownFrom = localMeta.countdownFrom;
23
+ if (localMeta.migratedFrom === LEGACY_CHAT_OUTBOX_SOURCE) meta.migratedFrom = LEGACY_CHAT_OUTBOX_SOURCE;
24
+ if (typeof localMeta.legacyId === "string") meta.legacyId = localMeta.legacyId;
25
+ const error = statewireHeldSends.heldSendFailure(localMeta);
26
+ if (error) meta.error = error;
27
+ return meta;
28
+ }
29
+ function withoutTransientLocalMeta(localMeta) {
30
+ if (!isRecord(localMeta)) return localMeta;
31
+ const { countdownEndsAt: _ends, countdownFrom: _from, error: _error, ...rest } = localMeta;
32
+ return Object.keys(rest).length > 0 ? rest : void 0;
33
+ }
34
+ function readAttachments(value) {
35
+ if (!Array.isArray(value)) return void 0;
36
+ const attachments = [];
37
+ for (const attachment of value) {
38
+ if (!isRecord(attachment) || typeof attachment.assetId !== "string" || attachment.assetId.length === 0) continue;
39
+ attachments.push({
40
+ assetId: attachment.assetId,
41
+ title: typeof attachment.title === "string" ? attachment.title : "",
42
+ ...typeof attachment.mediaType === "string" && { mediaType: attachment.mediaType }
43
+ });
44
+ }
45
+ return attachments.length > 0 ? attachments : void 0;
46
+ }
47
+ function readFiles(value) {
48
+ if (!Array.isArray(value)) return void 0;
49
+ const files = [];
50
+ for (const file of value) {
51
+ if (!isRecord(file) || typeof file.url !== "string" || typeof file.mediaType !== "string") continue;
52
+ files.push({
53
+ url: file.url,
54
+ mediaType: file.mediaType,
55
+ ...typeof file.filename === "string" && { filename: file.filename }
56
+ });
57
+ }
58
+ return files.length > 0 ? files : void 0;
59
+ }
60
+ function runSendMessage(command) {
61
+ if (!chatOutboxPolicy.isMessageRunCommand(command)) return null;
62
+ const params = command.params[0];
63
+ if (!isRecord(params) || !isRecord(params.message)) return null;
64
+ const { id, parts, metadata } = params.message;
65
+ if (typeof id !== "string") return null;
66
+ return {
67
+ id,
68
+ parts: Array.isArray(parts) ? parts : [],
69
+ ...isRecord(metadata) && { metadata }
70
+ };
71
+ }
72
+ function chatOutboxEntryOf(entry, threadId) {
73
+ const message = runSendMessage(entry.command);
74
+ if (message === null) return null;
75
+ const meta = readChatOutboxLocalMeta(entry.localMeta);
76
+ const text = message.parts.flatMap((part) => isRecord(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("\n\n");
77
+ const files = readFiles(message.parts.filter((part) => isRecord(part) && part.type === "file"));
78
+ return {
79
+ id: message.id,
80
+ outboxId: entry.id,
81
+ threadId: meta.threadId ?? threadId,
82
+ text,
83
+ queuedAt: meta.queuedAt ?? entry.ts,
84
+ newChat: meta.newChat ?? false,
85
+ durable: entry.durable,
86
+ ...meta.composerMarkdown !== void 0 && { composerMarkdown: meta.composerMarkdown },
87
+ ...meta.composerHtml !== void 0 && { composerHtml: meta.composerHtml },
88
+ ...message.metadata !== void 0 && { metadata: message.metadata },
89
+ ...files && { files },
90
+ ...meta.attachments && { attachments: meta.attachments }
91
+ };
92
+ }
93
+ exports.CHAT_OUTBOX_LOCAL_META_KIND = CHAT_OUTBOX_LOCAL_META_KIND;
94
+ exports.LEGACY_CHAT_OUTBOX_SOURCE = LEGACY_CHAT_OUTBOX_SOURCE;
95
+ exports.chatOutboxEntryOf = chatOutboxEntryOf;
96
+ exports.readAttachments = readAttachments;
97
+ exports.readChatOutboxLocalMeta = readChatOutboxLocalMeta;
98
+ exports.readFiles = readFiles;
99
+ exports.runSendMessage = runSendMessage;
100
+ exports.withoutTransientLocalMeta = withoutTransientLocalMeta;
101
+ //# sourceMappingURL=chat-outbox-entry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-outbox-entry.cjs","sources":["../../../../agent-runtime/src/chat-outbox-entry.ts"],"sourcesContent":["import type { StatewireClient } from \"statewire\";\nimport { isMessageRunCommand } from \"./chat-outbox-policy\";\nimport { heldSendFailure } from \"./statewire-held-sends\";\n\n/**\n * A chat message waiting in statewire's outbox, as the chat outbox shows it.\n *\n * The outbox entry is the record: its command is the `run/*` send that carries the message (text and\n * files in `message.parts`, metadata on `message.metadata`), and its client-only `localMeta` keeps\n * what the person's device needs and the server never sees ({@link ChatOutboxLocalMeta}). Both are\n * persisted with the thread's statewire session (sealed on the device where the host keeps copies).\n */\n\n/** An already-uploaded file a waiting message refers to (never a file picked while offline). */\nexport interface ChatOutboxFile {\n /** A server-backed URL (an asset's image route); never a `blob:` or `data:` URL. */\n url: string;\n mediaType: string;\n filename?: string;\n}\n\n/**\n * A file already in Athena that a waiting message carries: an upload that finished before Athena\n * went out of reach. Its reference rides the message's text, as a sent message's does; this copy\n * names it so the outbox can ask Athena, right before the message goes, that the file is still there\n * and still the person's to open (`ChatOutboxOptions.checkAttachments`).\n */\nexport interface ChatOutboxAttachment {\n assetId: string;\n /** Its name, as the composer showed it. */\n title: string;\n mediaType?: string;\n}\n\n/** Marks a `localMeta` written by the chat outbox. */\nexport const CHAT_OUTBOX_LOCAL_META_KIND = \"athena-chat-outbox\";\n\n/** The legacy store a migrated entry came from (`chat-outbox-legacy.ts`). */\nexport const LEGACY_CHAT_OUTBOX_SOURCE = \"athena-chat-outbox:v1\";\n\n/** What an outbox entry of a chat message keeps on the device (`OutboxEntry.localMeta`). */\nexport interface ChatOutboxLocalMeta {\n kind?: typeof CHAT_OUTBOX_LOCAL_META_KIND;\n threadId?: string;\n /** When it was typed (epoch ms): a message that waited more than a day asks before it goes. */\n queuedAt?: number;\n /** Typed into a chat that had never started: reopening that chat finds it again. */\n newChat?: boolean;\n /** The composer draft the text was serialized from, for giving it back exactly as typed. */\n composerMarkdown?: string;\n /** The draft as an HTML composer holds it (the phone's), given back exactly on Cancel or Edit. */\n composerHtml?: string;\n /** The files already in Athena the message carries, asked about right before it goes. */\n attachments?: ChatOutboxAttachment[];\n /** When the running countdown sends it (epoch ms). */\n countdownEndsAt?: number;\n /** When that countdown started (epoch ms): a tab coming to the front starts an older one over. */\n countdownFrom?: number;\n /** The legacy store it was migrated from, and its id there. */\n migratedFrom?: typeof LEGACY_CHAT_OUTBOX_SOURCE;\n legacyId?: string;\n /** Why it could not be sent (`statewire-held-sends.ts`); set, the row says \"Couldn't send\". */\n error?: StatewireClient.SendFailure;\n}\n\nexport interface ChatOutboxEntry {\n /**\n * The message id, minted when the message was typed. It is sent under it, so a send whose answer\n * was lost never posts twice: the thread's host refuses an id it already holds.\n */\n id: string;\n /** The statewire outbox entry that carries it (`undefined` while the session is still loading). */\n outboxId?: string;\n threadId: string;\n /** The text exactly as it will be sent (what the model reads). */\n text: string;\n composerMarkdown?: string;\n composerHtml?: string;\n /** The message metadata frozen when it was typed (its composer markdown, the agents it names, …). */\n metadata?: Record<string, unknown>;\n files?: ChatOutboxFile[];\n attachments?: ChatOutboxAttachment[];\n /** When it was typed (epoch ms). */\n queuedAt: number;\n newChat: boolean;\n /** Kept on the device (`false`: in page memory only, gone if the page closes). */\n durable: boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** The chat outbox's view of an entry's `localMeta` (fields of the wrong type are dropped). */\nexport function readChatOutboxLocalMeta(localMeta: unknown): ChatOutboxLocalMeta {\n if (!isRecord(localMeta)) return {};\n const meta: ChatOutboxLocalMeta = {};\n if (localMeta.kind === CHAT_OUTBOX_LOCAL_META_KIND) meta.kind = CHAT_OUTBOX_LOCAL_META_KIND;\n if (typeof localMeta.threadId === \"string\") meta.threadId = localMeta.threadId;\n if (typeof localMeta.queuedAt === \"number\" && Number.isFinite(localMeta.queuedAt)) meta.queuedAt = localMeta.queuedAt;\n if (typeof localMeta.newChat === \"boolean\") meta.newChat = localMeta.newChat;\n if (typeof localMeta.composerMarkdown === \"string\") meta.composerMarkdown = localMeta.composerMarkdown;\n if (typeof localMeta.composerHtml === \"string\") meta.composerHtml = localMeta.composerHtml;\n const attachments = readAttachments(localMeta.attachments);\n if (attachments) meta.attachments = attachments;\n if (typeof localMeta.countdownEndsAt === \"number\") meta.countdownEndsAt = localMeta.countdownEndsAt;\n if (typeof localMeta.countdownFrom === \"number\") meta.countdownFrom = localMeta.countdownFrom;\n if (localMeta.migratedFrom === LEGACY_CHAT_OUTBOX_SOURCE) meta.migratedFrom = LEGACY_CHAT_OUTBOX_SOURCE;\n if (typeof localMeta.legacyId === \"string\") meta.legacyId = localMeta.legacyId;\n const error = heldSendFailure(localMeta);\n if (error) meta.error = error;\n return meta;\n}\n\n/** `localMeta` without the countdown and the failure: what a send that goes again carries. */\nexport function withoutTransientLocalMeta(localMeta: unknown): unknown {\n if (!isRecord(localMeta)) return localMeta;\n const { countdownEndsAt: _ends, countdownFrom: _from, error: _error, ...rest } = localMeta;\n return Object.keys(rest).length > 0 ? rest : undefined;\n}\n\nexport function readAttachments(value: unknown): ChatOutboxAttachment[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const attachments: ChatOutboxAttachment[] = [];\n for (const attachment of value) {\n if (!isRecord(attachment) || typeof attachment.assetId !== \"string\" || attachment.assetId.length === 0) continue;\n attachments.push({\n assetId: attachment.assetId,\n title: typeof attachment.title === \"string\" ? attachment.title : \"\",\n ...(typeof attachment.mediaType === \"string\" && { mediaType: attachment.mediaType }),\n });\n }\n return attachments.length > 0 ? attachments : undefined;\n}\n\nexport function readFiles(value: unknown): ChatOutboxFile[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const files: ChatOutboxFile[] = [];\n for (const file of value) {\n if (!isRecord(file) || typeof file.url !== \"string\" || typeof file.mediaType !== \"string\") continue;\n files.push({\n url: file.url,\n mediaType: file.mediaType,\n ...(typeof file.filename === \"string\" && { filename: file.filename }),\n });\n }\n return files.length > 0 ? files : undefined;\n}\n\n/** The user message a message-carrying run send carries (`params[0].message`). */\nexport function runSendMessage(\n command: { method: string; params: readonly unknown[] },\n): { id: string; parts: unknown[]; metadata?: Record<string, unknown> } | null {\n if (!isMessageRunCommand(command)) return null;\n const params = command.params[0];\n if (!isRecord(params) || !isRecord(params.message)) return null;\n const { id, parts, metadata } = params.message;\n if (typeof id !== \"string\") return null;\n return {\n id,\n parts: Array.isArray(parts) ? parts : [],\n ...(isRecord(metadata) && { metadata }),\n };\n}\n\n/**\n * The chat message an outbox entry carries, or `null` when it carries none (not a\n * message-carrying run send). `threadId` names the thread whose session holds it.\n */\nexport function chatOutboxEntryOf(entry: StatewireClient.OutboxEntry, threadId: string): ChatOutboxEntry | null {\n const message = runSendMessage(entry.command);\n if (message === null) return null;\n const meta = readChatOutboxLocalMeta(entry.localMeta);\n const text = message.parts\n .flatMap((part) => (isRecord(part) && part.type === \"text\" && typeof part.text === \"string\" ? [part.text] : []))\n .join(\"\\n\\n\");\n const files = readFiles(message.parts.filter((part) => isRecord(part) && part.type === \"file\"));\n return {\n id: message.id,\n outboxId: entry.id,\n threadId: meta.threadId ?? threadId,\n text,\n queuedAt: meta.queuedAt ?? entry.ts,\n newChat: meta.newChat ?? false,\n durable: entry.durable,\n ...(meta.composerMarkdown !== undefined && { composerMarkdown: meta.composerMarkdown }),\n ...(meta.composerHtml !== undefined && { composerHtml: meta.composerHtml }),\n ...(message.metadata !== undefined && { metadata: message.metadata }),\n ...(files && { files }),\n ...(meta.attachments && { attachments: meta.attachments }),\n };\n}\n"],"names":["heldSendFailure","isMessageRunCommand"],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import type { StatewireClient } from "statewire";
2
+ /**
3
+ * A chat message waiting in statewire's outbox, as the chat outbox shows it.
4
+ *
5
+ * The outbox entry is the record: its command is the `run/*` send that carries the message (text and
6
+ * files in `message.parts`, metadata on `message.metadata`), and its client-only `localMeta` keeps
7
+ * what the person's device needs and the server never sees ({@link ChatOutboxLocalMeta}). Both are
8
+ * persisted with the thread's statewire session (sealed on the device where the host keeps copies).
9
+ */
10
+ /** An already-uploaded file a waiting message refers to (never a file picked while offline). */
11
+ export interface ChatOutboxFile {
12
+ /** A server-backed URL (an asset's image route); never a `blob:` or `data:` URL. */
13
+ url: string;
14
+ mediaType: string;
15
+ filename?: string;
16
+ }
17
+ /**
18
+ * A file already in Athena that a waiting message carries: an upload that finished before Athena
19
+ * went out of reach. Its reference rides the message's text, as a sent message's does; this copy
20
+ * names it so the outbox can ask Athena, right before the message goes, that the file is still there
21
+ * and still the person's to open (`ChatOutboxOptions.checkAttachments`).
22
+ */
23
+ export interface ChatOutboxAttachment {
24
+ assetId: string;
25
+ /** Its name, as the composer showed it. */
26
+ title: string;
27
+ mediaType?: string;
28
+ }
29
+ /** Marks a `localMeta` written by the chat outbox. */
30
+ export declare const CHAT_OUTBOX_LOCAL_META_KIND = "athena-chat-outbox";
31
+ /** The legacy store a migrated entry came from (`chat-outbox-legacy.ts`). */
32
+ export declare const LEGACY_CHAT_OUTBOX_SOURCE = "athena-chat-outbox:v1";
33
+ /** What an outbox entry of a chat message keeps on the device (`OutboxEntry.localMeta`). */
34
+ export interface ChatOutboxLocalMeta {
35
+ kind?: typeof CHAT_OUTBOX_LOCAL_META_KIND;
36
+ threadId?: string;
37
+ /** When it was typed (epoch ms): a message that waited more than a day asks before it goes. */
38
+ queuedAt?: number;
39
+ /** Typed into a chat that had never started: reopening that chat finds it again. */
40
+ newChat?: boolean;
41
+ /** The composer draft the text was serialized from, for giving it back exactly as typed. */
42
+ composerMarkdown?: string;
43
+ /** The draft as an HTML composer holds it (the phone's), given back exactly on Cancel or Edit. */
44
+ composerHtml?: string;
45
+ /** The files already in Athena the message carries, asked about right before it goes. */
46
+ attachments?: ChatOutboxAttachment[];
47
+ /** When the running countdown sends it (epoch ms). */
48
+ countdownEndsAt?: number;
49
+ /** When that countdown started (epoch ms): a tab coming to the front starts an older one over. */
50
+ countdownFrom?: number;
51
+ /** The legacy store it was migrated from, and its id there. */
52
+ migratedFrom?: typeof LEGACY_CHAT_OUTBOX_SOURCE;
53
+ legacyId?: string;
54
+ /** Why it could not be sent (`statewire-held-sends.ts`); set, the row says "Couldn't send". */
55
+ error?: StatewireClient.SendFailure;
56
+ }
57
+ export interface ChatOutboxEntry {
58
+ /**
59
+ * The message id, minted when the message was typed. It is sent under it, so a send whose answer
60
+ * was lost never posts twice: the thread's host refuses an id it already holds.
61
+ */
62
+ id: string;
63
+ /** The statewire outbox entry that carries it (`undefined` while the session is still loading). */
64
+ outboxId?: string;
65
+ threadId: string;
66
+ /** The text exactly as it will be sent (what the model reads). */
67
+ text: string;
68
+ composerMarkdown?: string;
69
+ composerHtml?: string;
70
+ /** The message metadata frozen when it was typed (its composer markdown, the agents it names, …). */
71
+ metadata?: Record<string, unknown>;
72
+ files?: ChatOutboxFile[];
73
+ attachments?: ChatOutboxAttachment[];
74
+ /** When it was typed (epoch ms). */
75
+ queuedAt: number;
76
+ newChat: boolean;
77
+ /** Kept on the device (`false`: in page memory only, gone if the page closes). */
78
+ durable: boolean;
79
+ }
80
+ /** The chat outbox's view of an entry's `localMeta` (fields of the wrong type are dropped). */
81
+ export declare function readChatOutboxLocalMeta(localMeta: unknown): ChatOutboxLocalMeta;
82
+ /** `localMeta` without the countdown and the failure: what a send that goes again carries. */
83
+ export declare function withoutTransientLocalMeta(localMeta: unknown): unknown;
84
+ export declare function readAttachments(value: unknown): ChatOutboxAttachment[] | undefined;
85
+ export declare function readFiles(value: unknown): ChatOutboxFile[] | undefined;
86
+ /** The user message a message-carrying run send carries (`params[0].message`). */
87
+ export declare function runSendMessage(command: {
88
+ method: string;
89
+ params: readonly unknown[];
90
+ }): {
91
+ id: string;
92
+ parts: unknown[];
93
+ metadata?: Record<string, unknown>;
94
+ } | null;
95
+ /**
96
+ * The chat message an outbox entry carries, or `null` when it carries none (not a
97
+ * message-carrying run send). `threadId` names the thread whose session holds it.
98
+ */
99
+ export declare function chatOutboxEntryOf(entry: StatewireClient.OutboxEntry, threadId: string): ChatOutboxEntry | null;