@athenaintel/react 0.23.3 → 0.24.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 (288) hide show
  1. package/README.md +6 -0
  2. package/dist/assets/AssetPanel.cjs +1 -1
  3. package/dist/assets/AssetPanel.cjs.map +1 -1
  4. package/dist/assets/AssetPanel.js +1 -1
  5. package/dist/assets/AssetPanel.js.map +1 -1
  6. package/dist/assets/AthenaAssetEmbed.cjs +1 -1
  7. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  8. package/dist/assets/AthenaAssetEmbed.js +1 -1
  9. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  10. package/dist/chat/AthenaChat.cjs +15 -23
  11. package/dist/chat/AthenaChat.cjs.map +1 -1
  12. package/dist/chat/AthenaChat.d.ts +9 -4
  13. package/dist/chat/AthenaChat.js +15 -23
  14. package/dist/chat/AthenaChat.js.map +1 -1
  15. package/dist/chat/StatewireApprovalCard.cjs +3 -18
  16. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  17. package/dist/chat/StatewireApprovalCard.js +3 -18
  18. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  19. package/dist/chat/StatewireClientToolBridge.cjs +2 -16
  20. package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
  21. package/dist/chat/StatewireClientToolBridge.js +2 -16
  22. package/dist/chat/StatewireClientToolBridge.js.map +1 -1
  23. package/dist/chat/StatewireQueuedMessages.cjs +5 -16
  24. package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
  25. package/dist/chat/StatewireQueuedMessages.js +5 -16
  26. package/dist/chat/StatewireQueuedMessages.js.map +1 -1
  27. package/dist/chat/WaitingOnYouBanner.cjs +3 -18
  28. package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
  29. package/dist/chat/WaitingOnYouBanner.js +3 -18
  30. package/dist/chat/WaitingOnYouBanner.js.map +1 -1
  31. package/dist/chat/run-activity.cjs +0 -16
  32. package/dist/chat/run-activity.cjs.map +1 -1
  33. package/dist/chat/run-activity.js +0 -16
  34. package/dist/chat/run-activity.js.map +1 -1
  35. package/dist/chat/statewire-client-tools.cjs +1 -17
  36. package/dist/chat/statewire-client-tools.cjs.map +1 -1
  37. package/dist/chat/statewire-client-tools.js +1 -17
  38. package/dist/chat/statewire-client-tools.js.map +1 -1
  39. package/dist/chat/super-grouping/activity-timeline.cjs +0 -16
  40. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  41. package/dist/chat/super-grouping/activity-timeline.js +0 -16
  42. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  43. package/dist/chat/tiptap-text.cjs +1 -17
  44. package/dist/chat/tiptap-text.cjs.map +1 -1
  45. package/dist/chat/tiptap-text.js +1 -17
  46. package/dist/chat/tiptap-text.js.map +1 -1
  47. package/dist/chat/use-athena-run-live.cjs +0 -15
  48. package/dist/chat/use-athena-run-live.cjs.map +1 -1
  49. package/dist/chat/use-athena-run-live.js +0 -15
  50. package/dist/chat/use-athena-run-live.js.map +1 -1
  51. package/dist/chat/use-statewire-approval-request.cjs +4 -16
  52. package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
  53. package/dist/chat/use-statewire-approval-request.d.ts +2 -0
  54. package/dist/chat/use-statewire-approval-request.js +4 -16
  55. package/dist/chat/use-statewire-approval-request.js.map +1 -1
  56. package/dist/chat-ui/composer/tiptap-composer.cjs +1 -16
  57. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  58. package/dist/chat-ui/composer/tiptap-composer.js +1 -16
  59. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  60. package/dist/chat-ui/index.cjs +0 -16
  61. package/dist/chat-ui/index.cjs.map +1 -1
  62. package/dist/chat-ui/index.js +0 -16
  63. package/dist/chat-ui/index.js.map +1 -1
  64. package/dist/chat-ui/mentions/mention-chip.cjs +1 -16
  65. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  66. package/dist/chat-ui/mentions/mention-chip.js +1 -16
  67. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  68. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs +4 -6
  69. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs.map +1 -1
  70. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js +4 -6
  71. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js.map +1 -1
  72. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +2 -9
  73. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  74. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +2 -9
  75. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  76. package/dist/chat-ui/messages/message-components.cjs +5 -19
  77. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  78. package/dist/chat-ui/messages/message-components.js +5 -19
  79. package/dist/chat-ui/messages/message-components.js.map +1 -1
  80. package/dist/chat-ui/messages/runtime-message.cjs +1 -16
  81. package/dist/chat-ui/messages/runtime-message.cjs.map +1 -1
  82. package/dist/chat-ui/messages/runtime-message.js +1 -16
  83. package/dist/chat-ui/messages/runtime-message.js.map +1 -1
  84. package/dist/chat-ui/messages/statewire-continue-run.cjs +3 -15
  85. package/dist/chat-ui/messages/statewire-continue-run.cjs.map +1 -1
  86. package/dist/chat-ui/messages/statewire-continue-run.js +3 -15
  87. package/dist/chat-ui/messages/statewire-continue-run.js.map +1 -1
  88. package/dist/chat-ui/messages/user-edit-composer.cjs +0 -16
  89. package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
  90. package/dist/chat-ui/messages/user-edit-composer.js +0 -16
  91. package/dist/chat-ui/messages/user-edit-composer.js.map +1 -1
  92. package/dist/chat-ui/messages/wake-marker.cjs +1 -16
  93. package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
  94. package/dist/chat-ui/messages/wake-marker.js +1 -16
  95. package/dist/chat-ui/messages/wake-marker.js.map +1 -1
  96. package/dist/chat-ui/statewire.cjs +0 -16
  97. package/dist/chat-ui/statewire.cjs.map +1 -1
  98. package/dist/chat-ui/statewire.js +0 -16
  99. package/dist/chat-ui/statewire.js.map +1 -1
  100. package/dist/chat-ui/thread/statewire-history-edge.cjs +2 -17
  101. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  102. package/dist/chat-ui/thread/statewire-history-edge.js +2 -17
  103. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  104. package/dist/dictation/DictationStrip.cjs +2 -1
  105. package/dist/dictation/DictationStrip.cjs.map +1 -1
  106. package/dist/dictation/DictationStrip.d.ts +2 -0
  107. package/dist/dictation/DictationStrip.js +2 -1
  108. package/dist/dictation/DictationStrip.js.map +1 -1
  109. package/dist/dictation/dictation-engine.cjs.map +1 -1
  110. package/dist/dictation/dictation-engine.d.ts +8 -0
  111. package/dist/dictation/dictation-engine.js.map +1 -1
  112. package/dist/dictation/recorded-dictation-engine.cjs +153 -0
  113. package/dist/dictation/recorded-dictation-engine.cjs.map +1 -0
  114. package/dist/dictation/recorded-dictation-engine.d.ts +66 -0
  115. package/dist/dictation/recorded-dictation-engine.js +153 -0
  116. package/dist/dictation/recorded-dictation-engine.js.map +1 -0
  117. package/dist/dictation/use-athena-dictation-engine.cjs +64 -0
  118. package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -0
  119. package/dist/dictation/use-athena-dictation-engine.d.ts +25 -0
  120. package/dist/dictation/use-athena-dictation-engine.js +64 -0
  121. package/dist/dictation/use-athena-dictation-engine.js.map +1 -0
  122. package/dist/dictation/use-dictation.cjs +17 -6
  123. package/dist/dictation/use-dictation.cjs.map +1 -1
  124. package/dist/dictation/use-dictation.d.ts +20 -4
  125. package/dist/dictation/use-dictation.js +17 -6
  126. package/dist/dictation/use-dictation.js.map +1 -1
  127. package/dist/index.cjs +28 -39
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.ts +4 -1
  130. package/dist/index.js +10 -21
  131. package/dist/index.js.map +1 -1
  132. package/dist/packages/agent-runtime/src/edit-command.cjs.map +1 -1
  133. package/dist/packages/agent-runtime/src/edit-command.js.map +1 -1
  134. package/dist/packages/agent-runtime/src/errors.cjs +18 -0
  135. package/dist/packages/agent-runtime/src/errors.cjs.map +1 -1
  136. package/dist/packages/agent-runtime/src/errors.js +19 -1
  137. package/dist/packages/agent-runtime/src/errors.js.map +1 -1
  138. package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs +1 -0
  139. package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  140. package/dist/packages/agent-runtime/src/generated/runconfig-contract.js +1 -0
  141. package/dist/packages/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  142. package/dist/packages/agent-runtime/src/interrupts.cjs +61 -12
  143. package/dist/packages/agent-runtime/src/interrupts.cjs.map +1 -1
  144. package/dist/packages/agent-runtime/src/interrupts.js +61 -12
  145. package/dist/packages/agent-runtime/src/interrupts.js.map +1 -1
  146. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs +49 -0
  147. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  148. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js +49 -0
  149. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  150. package/dist/packages/agent-runtime/src/thread-status.js +1 -1
  151. package/dist/packages/agent-runtime/src/tool-metadata.cjs +1 -37
  152. package/dist/packages/agent-runtime/src/tool-metadata.cjs.map +1 -1
  153. package/dist/packages/agent-runtime/src/tool-metadata.js +1 -37
  154. package/dist/packages/agent-runtime/src/tool-metadata.js.map +1 -1
  155. package/dist/packages/agent-runtime/src/use-deep-agent-config.cjs +0 -1
  156. package/dist/packages/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
  157. package/dist/packages/agent-runtime/src/use-deep-agent-config.js +0 -1
  158. package/dist/packages/agent-runtime/src/use-deep-agent-config.js.map +1 -1
  159. package/dist/packages/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  160. package/dist/packages/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  161. package/dist/packages/react/package.json.cjs +1 -1
  162. package/dist/packages/react/package.json.js +1 -1
  163. package/dist/provider/AthenaProvider.cjs +3 -17
  164. package/dist/provider/AthenaProvider.cjs.map +1 -1
  165. package/dist/provider/AthenaProvider.js +3 -17
  166. package/dist/provider/AthenaProvider.js.map +1 -1
  167. package/dist/runtime/statewire-lifecycle.cjs +0 -16
  168. package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
  169. package/dist/runtime/statewire-lifecycle.js +0 -16
  170. package/dist/runtime/statewire-lifecycle.js.map +1 -1
  171. package/dist/runtime/useAthenaStatewireRuntime.cjs +3 -17
  172. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  173. package/dist/runtime/useAthenaStatewireRuntime.js +3 -17
  174. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  175. package/dist/threads/statewire-thread-list.cjs +4 -17
  176. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  177. package/dist/threads/statewire-thread-list.js +4 -17
  178. package/dist/threads/statewire-thread-list.js.map +1 -1
  179. package/dist/threads/use-rest-conversation-history.cjs +2 -16
  180. package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
  181. package/dist/threads/use-rest-conversation-history.js +2 -16
  182. package/dist/threads/use-rest-conversation-history.js.map +1 -1
  183. package/dist/threads/use-statewire-conversation-history.cjs +2 -16
  184. package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
  185. package/dist/threads/use-statewire-conversation-history.js +2 -16
  186. package/dist/threads/use-statewire-conversation-history.js.map +1 -1
  187. package/dist/toolkits/index.cjs +0 -7
  188. package/dist/toolkits/index.cjs.map +1 -1
  189. package/dist/toolkits/index.d.ts +0 -2
  190. package/dist/toolkits/index.js +0 -7
  191. package/dist/toolkits/index.js.map +1 -1
  192. package/dist/tools/index.cjs +4 -20
  193. package/dist/tools/index.cjs.map +1 -1
  194. package/dist/tools/index.js +1 -17
  195. package/dist/tools/index.js.map +1 -1
  196. package/dist/tools/misc-tool-uis.cjs +2 -17
  197. package/dist/tools/misc-tool-uis.cjs.map +1 -1
  198. package/dist/tools/misc-tool-uis.js +2 -17
  199. package/dist/tools/misc-tool-uis.js.map +1 -1
  200. package/dist/tools/primitives.cjs +1 -16
  201. package/dist/tools/primitives.cjs.map +1 -1
  202. package/dist/tools/primitives.js +1 -16
  203. package/dist/tools/primitives.js.map +1 -1
  204. package/dist/tools/tool-fallback.cjs +2 -17
  205. package/dist/tools/tool-fallback.cjs.map +1 -1
  206. package/dist/tools/tool-fallback.js +2 -17
  207. package/dist/tools/tool-fallback.js.map +1 -1
  208. package/dist/tools/voice-update-tool-ui.cjs +1 -17
  209. package/dist/tools/voice-update-tool-ui.cjs.map +1 -1
  210. package/dist/tools/voice-update-tool-ui.js +1 -17
  211. package/dist/tools/voice-update-tool-ui.js.map +1 -1
  212. package/package.json +1 -1
  213. package/dist/node_modules/qrcode-generator/dist/qrcode.cjs +0 -32
  214. package/dist/node_modules/qrcode-generator/dist/qrcode.cjs.map +0 -1
  215. package/dist/node_modules/qrcode-generator/dist/qrcode.js +0 -31
  216. package/dist/node_modules/qrcode-generator/dist/qrcode.js.map +0 -1
  217. package/dist/node_modules/zod/v4/classic/errors.cjs +0 -44
  218. package/dist/node_modules/zod/v4/classic/errors.cjs.map +0 -1
  219. package/dist/node_modules/zod/v4/classic/errors.js +0 -44
  220. package/dist/node_modules/zod/v4/classic/errors.js.map +0 -1
  221. package/dist/node_modules/zod/v4/classic/iso.cjs +0 -43
  222. package/dist/node_modules/zod/v4/classic/iso.cjs.map +0 -1
  223. package/dist/node_modules/zod/v4/classic/iso.js +0 -43
  224. package/dist/node_modules/zod/v4/classic/iso.js.map +0 -1
  225. package/dist/node_modules/zod/v4/classic/parse.cjs +0 -29
  226. package/dist/node_modules/zod/v4/classic/parse.cjs.map +0 -1
  227. package/dist/node_modules/zod/v4/classic/parse.js +0 -29
  228. package/dist/node_modules/zod/v4/classic/parse.js.map +0 -1
  229. package/dist/node_modules/zod/v4/classic/schemas.cjs +0 -871
  230. package/dist/node_modules/zod/v4/classic/schemas.cjs.map +0 -1
  231. package/dist/node_modules/zod/v4/classic/schemas.js +0 -871
  232. package/dist/node_modules/zod/v4/classic/schemas.js.map +0 -1
  233. package/dist/node_modules/zod/v4/core/api.cjs +0 -570
  234. package/dist/node_modules/zod/v4/core/api.cjs.map +0 -1
  235. package/dist/node_modules/zod/v4/core/api.js +0 -570
  236. package/dist/node_modules/zod/v4/core/api.js.map +0 -1
  237. package/dist/node_modules/zod/v4/core/checks.cjs +0 -411
  238. package/dist/node_modules/zod/v4/core/checks.cjs.map +0 -1
  239. package/dist/node_modules/zod/v4/core/checks.js +0 -411
  240. package/dist/node_modules/zod/v4/core/checks.js.map +0 -1
  241. package/dist/node_modules/zod/v4/core/core.cjs +0 -77
  242. package/dist/node_modules/zod/v4/core/core.cjs.map +0 -1
  243. package/dist/node_modules/zod/v4/core/core.js +0 -77
  244. package/dist/node_modules/zod/v4/core/core.js.map +0 -1
  245. package/dist/node_modules/zod/v4/core/doc.cjs +0 -38
  246. package/dist/node_modules/zod/v4/core/doc.cjs.map +0 -1
  247. package/dist/node_modules/zod/v4/core/doc.js +0 -38
  248. package/dist/node_modules/zod/v4/core/doc.js.map +0 -1
  249. package/dist/node_modules/zod/v4/core/errors.cjs +0 -76
  250. package/dist/node_modules/zod/v4/core/errors.cjs.map +0 -1
  251. package/dist/node_modules/zod/v4/core/errors.js +0 -76
  252. package/dist/node_modules/zod/v4/core/errors.js.map +0 -1
  253. package/dist/node_modules/zod/v4/core/json-schema-processors.cjs +0 -312
  254. package/dist/node_modules/zod/v4/core/json-schema-processors.cjs.map +0 -1
  255. package/dist/node_modules/zod/v4/core/json-schema-processors.js +0 -312
  256. package/dist/node_modules/zod/v4/core/json-schema-processors.js.map +0 -1
  257. package/dist/node_modules/zod/v4/core/parse.cjs +0 -96
  258. package/dist/node_modules/zod/v4/core/parse.cjs.map +0 -1
  259. package/dist/node_modules/zod/v4/core/parse.js +0 -96
  260. package/dist/node_modules/zod/v4/core/parse.js.map +0 -1
  261. package/dist/node_modules/zod/v4/core/regexes.cjs +0 -86
  262. package/dist/node_modules/zod/v4/core/regexes.cjs.map +0 -1
  263. package/dist/node_modules/zod/v4/core/regexes.js +0 -86
  264. package/dist/node_modules/zod/v4/core/regexes.js.map +0 -1
  265. package/dist/node_modules/zod/v4/core/registries.cjs +0 -52
  266. package/dist/node_modules/zod/v4/core/registries.cjs.map +0 -1
  267. package/dist/node_modules/zod/v4/core/registries.js +0 -52
  268. package/dist/node_modules/zod/v4/core/registries.js.map +0 -1
  269. package/dist/node_modules/zod/v4/core/schemas.cjs +0 -1412
  270. package/dist/node_modules/zod/v4/core/schemas.cjs.map +0 -1
  271. package/dist/node_modules/zod/v4/core/schemas.js +0 -1413
  272. package/dist/node_modules/zod/v4/core/schemas.js.map +0 -1
  273. package/dist/node_modules/zod/v4/core/to-json-schema.cjs +0 -370
  274. package/dist/node_modules/zod/v4/core/to-json-schema.cjs.map +0 -1
  275. package/dist/node_modules/zod/v4/core/to-json-schema.js +0 -370
  276. package/dist/node_modules/zod/v4/core/to-json-schema.js.map +0 -1
  277. package/dist/node_modules/zod/v4/core/util.cjs +0 -444
  278. package/dist/node_modules/zod/v4/core/util.cjs.map +0 -1
  279. package/dist/node_modules/zod/v4/core/util.js +0 -444
  280. package/dist/node_modules/zod/v4/core/util.js.map +0 -1
  281. package/dist/node_modules/zod/v4/core/versions.cjs +0 -9
  282. package/dist/node_modules/zod/v4/core/versions.cjs.map +0 -1
  283. package/dist/node_modules/zod/v4/core/versions.js +0 -9
  284. package/dist/node_modules/zod/v4/core/versions.js.map +0 -1
  285. package/dist/packages/agent-runtime/src/thread-handoff.cjs +0 -85
  286. package/dist/packages/agent-runtime/src/thread-handoff.cjs.map +0 -1
  287. package/dist/packages/agent-runtime/src/thread-handoff.js +0 -85
  288. package/dist/packages/agent-runtime/src/thread-handoff.js.map +0 -1
@@ -1,30 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const react$1 = require("@assistant-ui/react");
4
- const runconfigContract = require("../packages/agent-runtime/src/generated/runconfig-contract.cjs");
5
4
  const react = require("react");
6
- require("@assistant-ui/tap");
7
- require("statewire");
8
- const errors = require("../packages/agent-runtime/src/errors.cjs");
9
- require("../packages/agent-runtime/src/statewire-suspended.cjs");
10
- require("../packages/agent-runtime/src/conversation-list.cjs");
11
- require("@tanstack/react-query");
12
- require("../packages/agent-runtime/src/statewire-state.cjs");
13
- require("../packages/agent-runtime/src/messages.cjs");
14
- require("@assistant-ui/store");
15
- require("../packages/agent-runtime/src/quota-safe-local-storage-session.cjs");
16
- require("../packages/agent-runtime/src/statewire-attach-observer.cjs");
17
- require("../packages/agent-runtime/src/thread-status.cjs");
18
- require("@assistant-ui/react-statewire");
19
- const useDeepAgentRuntime = require("../packages/agent-runtime/src/use-deep-agent-runtime.cjs");
20
- require("@assistant-ui/core");
21
- require("../packages/agent-runtime/src/thread-handoff.cjs");
22
5
  const AthenaAuthContext = require("../auth/AthenaAuthContext.cjs");
23
6
  const statewireClientTools = require("../chat/statewire-client-tools.cjs");
24
7
  const athenaDiagnostics = require("../diagnostics/athena-diagnostics.cjs");
25
8
  const statewireAuthHeaders = require("./statewire-auth-headers.cjs");
26
9
  const statewireSessionKey = require("./statewire-session-key.cjs");
27
10
  const statewireRunConfig = require("./statewire-run-config.cjs");
11
+ const runconfigContract = require("../packages/agent-runtime/src/generated/runconfig-contract.cjs");
12
+ const useDeepAgentRuntime = require("../packages/agent-runtime/src/use-deep-agent-runtime.cjs");
13
+ const errors = require("../packages/agent-runtime/src/errors.cjs");
28
14
  const ATHENA_SDK_MESSAGE_WINDOW = {
29
15
  size: runconfigContract.DEEP_AGENT_DEFAULT_MESSAGE_WINDOW
30
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useAthenaStatewireRuntime.cjs","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n useClient: useSdkClient,\n onStateChange: () => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange,\n onRunningChange,\n // The runConfig getter is pulled at command-send time through the core's\n // per-render ref, so it reads the latest props — consumers commonly pass\n // fresh array literals per render, which must not thrash the registration\n // (no `key`: the provider registers once per client).\n runConfig: {\n get: () =>\n buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n }),\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":["DEEP_AGENT_DEFAULT_MESSAGE_WINDOW","useMemo","collectStatewireClientTools","resolveAgentProp","useContext","AthenaAuthContext","useRef","athenaDiagnostics","Tools","useAui","useDeepAgentRuntime","resolveStatewireAuthHeaders","statewireSessionKey","buildStatewireRunConfig","statewireClientToolWireEntries","isStatewireChannelTeardown","logUnhandledStatewireError"],"mappings":"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"}
1
+ {"version":3,"file":"useAthenaStatewireRuntime.cjs","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n useClient: useSdkClient,\n onStateChange: () => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange,\n onRunningChange,\n // The runConfig getter is pulled at command-send time through the core's\n // per-render ref, so it reads the latest props — consumers commonly pass\n // fresh array literals per render, which must not thrash the registration\n // (no `key`: the provider registers once per client).\n runConfig: {\n get: () =>\n buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n }),\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":["DEEP_AGENT_DEFAULT_MESSAGE_WINDOW","useMemo","collectStatewireClientTools","resolveAgentProp","useContext","AthenaAuthContext","useRef","athenaDiagnostics","Tools","useAui","useDeepAgentRuntime","resolveStatewireAuthHeaders","statewireSessionKey","buildStatewireRunConfig","statewireClientToolWireEntries","isStatewireChannelTeardown","logUnhandledStatewireError"],"mappings":"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"}
@@ -1,22 +1,5 @@
1
1
  import { Tools, useAui } from "@assistant-ui/react";
2
- import { DEEP_AGENT_DEFAULT_MESSAGE_WINDOW } from "../packages/agent-runtime/src/generated/runconfig-contract.js";
3
2
  import { useContext, useRef, useMemo } from "react";
4
- import "@assistant-ui/tap";
5
- import "statewire";
6
- import { isStatewireChannelTeardown } from "../packages/agent-runtime/src/errors.js";
7
- import "../packages/agent-runtime/src/statewire-suspended.js";
8
- import "../packages/agent-runtime/src/conversation-list.js";
9
- import "@tanstack/react-query";
10
- import "../packages/agent-runtime/src/statewire-state.js";
11
- import "../packages/agent-runtime/src/messages.js";
12
- import "@assistant-ui/store";
13
- import "../packages/agent-runtime/src/quota-safe-local-storage-session.js";
14
- import "../packages/agent-runtime/src/statewire-attach-observer.js";
15
- import "../packages/agent-runtime/src/thread-status.js";
16
- import "@assistant-ui/react-statewire";
17
- import { useDeepAgentRuntime, logUnhandledStatewireError } from "../packages/agent-runtime/src/use-deep-agent-runtime.js";
18
- import "@assistant-ui/core";
19
- import "../packages/agent-runtime/src/thread-handoff.js";
20
3
  import { AthenaAuthContext } from "../auth/AthenaAuthContext.js";
21
4
  import { collectStatewireClientTools, statewireClientToolWireEntries } from "../chat/statewire-client-tools.js";
22
5
  import { athenaDiagnostics } from "../diagnostics/athena-diagnostics.js";
@@ -24,6 +7,9 @@ import { resolveStatewireAuthHeaders } from "./statewire-auth-headers.js";
24
7
  import { statewireSessionKey } from "./statewire-session-key.js";
25
8
  import { resolveAgentProp, buildStatewireRunConfig } from "./statewire-run-config.js";
26
9
  import { DEFAULT_STATEWIRE_MODEL } from "./statewire-run-config.js";
10
+ import { DEEP_AGENT_DEFAULT_MESSAGE_WINDOW } from "../packages/agent-runtime/src/generated/runconfig-contract.js";
11
+ import { useDeepAgentRuntime, logUnhandledStatewireError } from "../packages/agent-runtime/src/use-deep-agent-runtime.js";
12
+ import { isStatewireChannelTeardown } from "../packages/agent-runtime/src/errors.js";
27
13
  const ATHENA_SDK_MESSAGE_WINDOW = {
28
14
  size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW
29
15
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useAthenaStatewireRuntime.js","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n useClient: useSdkClient,\n onStateChange: () => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange,\n onRunningChange,\n // The runConfig getter is pulled at command-send time through the core's\n // per-render ref, so it reads the latest props — consumers commonly pass\n // fresh array literals per render, which must not thrash the registration\n // (no `key`: the provider registers once per client).\n runConfig: {\n get: () =>\n buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n }),\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useAthenaStatewireRuntime.js","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n useClient: useSdkClient,\n onStateChange: () => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange,\n onRunningChange,\n // The runConfig getter is pulled at command-send time through the core's\n // per-render ref, so it reads the latest props — consumers commonly pass\n // fresh array literals per render, which must not thrash the registration\n // (no `key`: the provider registers once per client).\n runConfig: {\n get: () =>\n buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n }),\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":[],"mappings":"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"}
@@ -1,25 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
- require("../packages/agent-runtime/src/generated/runconfig-contract.cjs");
5
- const react = require("react");
6
- const conversationIndex = require("../packages/agent-runtime/src/conversation-index.cjs");
7
- const conversationList = require("../packages/agent-runtime/src/conversation-list.cjs");
8
- const useConversationList = require("../packages/agent-runtime/src/use-conversation-list.cjs");
9
- require("../packages/agent-runtime/src/statewire-state.cjs");
10
- require("../packages/agent-runtime/src/messages.cjs");
11
- require("statewire");
12
- require("@assistant-ui/store");
13
- require("../packages/agent-runtime/src/quota-safe-local-storage-session.cjs");
14
- require("../packages/agent-runtime/src/statewire-suspended.cjs");
15
- require("@assistant-ui/tap");
16
- require("../packages/agent-runtime/src/statewire-attach-observer.cjs");
17
- require("../packages/agent-runtime/src/thread-status.cjs");
18
- require("@assistant-ui/react-statewire");
19
- require("@assistant-ui/core");
20
- require("../packages/agent-runtime/src/thread-handoff.cjs");
21
4
  const reactQuery = require("@tanstack/react-query");
22
5
  const react$1 = require("@assistant-ui/react");
6
+ const react = require("react");
23
7
  const AthenaAuthContext = require("../auth/AthenaAuthContext.cjs");
24
8
  const statewireAuthHeaders = require("../runtime/statewire-auth-headers.cjs");
25
9
  const api = require("./api.cjs");
@@ -32,6 +16,9 @@ const title = require("./title.cjs");
32
16
  const useThreadArchive = require("./use-thread-archive.cjs");
33
17
  const useThreadFavorite = require("./use-thread-favorite.cjs");
34
18
  const useThreadRename = require("./use-thread-rename.cjs");
19
+ const conversationList = require("../packages/agent-runtime/src/conversation-list.cjs");
20
+ const useConversationList = require("../packages/agent-runtime/src/use-conversation-list.cjs");
21
+ const conversationIndex = require("../packages/agent-runtime/src/conversation-index.cjs");
35
22
  const AthenaStatewireThreadListContext = react.createContext(null);
36
23
  function useAthenaStatewireThreadList() {
37
24
  return react.useContext(AthenaStatewireThreadListContext);
@@ -1 +1 @@
1
- {"version":3,"file":"statewire-thread-list.cjs","sources":["../../src/threads/statewire-thread-list.tsx"],"sourcesContent":["import {\n type ConversationAttention,\n type ConversationAttentionSource,\n type ConversationIndexEntry,\n type ConversationListFilter,\n type ConversationPullRequest,\n type ConversationSummary,\n type ConversationWake,\n conversationIndexUrlFromStatewireUrl,\n type DeepAgentHeadersResolver,\n type DeepAgentThreadSnapshotCache,\n deriveConversationAttention,\n summaryFromConversationIndexEntry,\n useConversationIndex,\n useConversationList,\n} from '@athenaintel/agent-runtime';\nimport { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';\nimport { useAuiState } from '@assistant-ui/react';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n resolveStatewireAuthToken,\n} from '../runtime/statewire-auth-headers';\nimport { fetchAccountIdentity, getThreadState } from './api';\nimport { createRestConversationListFetcher } from './conversation-list-fetcher';\nimport { credentialShape, sameCredentialShape } from './credential-shape';\nimport { mintThreadId } from './mint-thread-id';\nimport { useAthenaStatewireThreadId } from './thread-id-context';\nimport { createThreadPrefetcher } from './thread-prefetcher';\nimport { isSerializedContentPartsTitle, normalizeThreadTitle } from './title';\nimport { useThreadArchive } from './use-thread-archive';\nimport {\n type ThreadFavoriteTarget,\n useThreadFavorite,\n withFavoriteOverride,\n withFavoriteOverrides,\n} from './use-thread-favorite';\nimport {\n type ThreadRenameTarget,\n useThreadRename,\n withTitleOverride,\n withTitleOverrides,\n} from './use-thread-rename';\n\n/**\n * One row of the thread list — the fields a Devin-style session list renders\n * (`SessionList`), all read from the shared conversation-list contract. The\n * attention fields are `null` on a server that does not derive them; the\n * pull-request state is `null` until the list has fetched it (or when the\n * provider opted out of it).\n */\nexport interface AthenaStatewireThreadSummary {\n id: string;\n title: string | null;\n /**\n * What the session asks of the viewer: the server-derived state when\n * reported, else the client fallback from the status planes\n * (`deriveConversationAttention`).\n */\n attention: ConversationAttention | null;\n /** One line (≤ 80 chars) of what the viewer should do next, when the server derives one. */\n nextAction: string | null;\n attentionSource: ConversationAttentionSource | null;\n /**\n * Whether the viewer pinned the session. Toggled through\n * `AthenaStatewireThreadListState.setFavorited`; a toggle in flight is\n * reflected here at once and held until the list sources report it.\n */\n isFavorited: boolean;\n isUnread: boolean;\n /** Canonical status_v2 planes, or `null` on an older server. */\n sessionStatus: string | null;\n runStatus: string | null;\n /** Channel the session was started from (e.g. `web`, `github`, `api`). */\n startChannel: string | null;\n /** Client app that created the session (SESSION_APP_ID_GUIDE). */\n appId: string | null;\n /** Trigger marker (`manual` remains user-initiated; other values are automated). */\n triggerType: string | null;\n /** Pull requests the session opened with their live GitHub state. */\n pullRequests: ConversationPullRequest[] | null;\n /** The last wake of a resting session. */\n lastWake: ConversationWake | null;\n /** ISO 8601 timestamp of the last update (the list's sort key). */\n updatedAt: string;\n}\n\n/**\n * Thread-list state. The list is the persisted Agora session list; the ACTIVE\n * thread is a plain id the statewire runtime attaches to — switching threads\n * remounts the statewire session against the new `…/v2/threads/{id}` URL\n * (the same model the mobile app uses).\n */\nexport interface AthenaStatewireThreadListState {\n /** The rows the current `search` lists, newest first. */\n threads: AthenaStatewireThreadSummary[];\n isLoading: boolean;\n /** True while the live first page (or a history page) is being fetched. */\n isFetching: boolean;\n /**\n * True once the live first page has answered at least once for the current\n * search and identity. Until then an empty `threads` means \"not known\n * yet\" (no credential resolved, first page in flight), not \"no sessions\":\n * `SessionList` shows skeleton rows, never the empty state.\n */\n hasResolvedFirstPage: boolean;\n activeThreadId: string;\n /**\n * The active thread's row, independent of what `threads` currently lists:\n * a search that hides the row, or a page that has not fetched it, must not\n * make the active chat's attention disappear. Resolved from the listed row,\n * else the pushed index entry folded over the last row seen, else that\n * last row; `null` for a never-started chat the backend does not know yet.\n */\n activeThread: AthenaStatewireThreadSummary | null;\n /** True while the active thread is a locally-minted chat with no server history. */\n isNewChat: boolean;\n selectThread: (threadId: string) => void;\n /**\n * Warm the provider's snapshot cache with a thread's REST state ahead of a\n * `selectThread`, so the switch paints the transcript on its first frame\n * instead of the loading scrim while the statewire attach lands.\n * `SessionList` calls it after a 120 ms hover dwell and on row focus.\n * Fetches once per thread per identity, deduplicates requests in flight,\n * runs at most two at a time and ignores failures; a no-op for the active\n * thread, a thread the cache already holds, or a provider without a cache.\n */\n prefetchThread: (threadId: string) => void;\n newThread: () => void;\n refresh: () => void;\n /**\n * Server-side title search (`search` on the REST thread list). An empty\n * string lists everything; the search covers the viewer's whole authorized\n * history, not just the live page.\n */\n search: string;\n setSearch: (search: string) => void;\n /** Whether another page of older sessions can be fetched. */\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n /** Fetch the next page of older sessions (frozen history pages, never replayed). */\n fetchNextPage: () => void;\n /**\n * Pin or unpin a session (`POST /api/conversations/threads/favorite`). The\n * row flips at once and moves between the `Pinned` and `Recent` groups; the\n * server's answer is written back, and a failure restores the previous\n * state. Writes for one thread are serialized: a toggle while that\n * thread's write is in flight records the value and sends at most one\n * follow-up write once the first has answered.\n */\n setFavorited: (target: ThreadFavoriteTarget) => void;\n /** True while any pin toggle is in flight. */\n favoritePending: boolean;\n /** The sessions whose pin toggle is in flight; `SessionList` disables their pin control. */\n favoritePendingThreadIds: ReadonlySet<string>;\n /**\n * Whether the backend offers the favorite route. `false` once it answered\n * 404 / 405 (an agora that predates the route): `SessionList` then shows\n * the read-only pin and no toggle, and `setFavorited` keeps failing.\n */\n favoriteToggleAvailable: boolean;\n /**\n * Rename a session for every viewer (`POST /api/conversations/threads/rename`).\n * The row shows the new title at once; the server's stored title is\n * written back, and a failure restores the previous one. Same-thread\n * writes are serialized like the pin's.\n */\n renameThread: (target: ThreadRenameTarget) => void;\n /** The sessions whose rename is in flight; `SessionList` keeps their editor closed. */\n renamePendingThreadIds: ReadonlySet<string>;\n /**\n * Whether the backend offers the rename route. `false` once it answered\n * 404 / 405 (an agora that predates the route): `SessionList` then offers\n * no Rename action, and `renameThread` keeps failing.\n */\n renameAvailable: boolean;\n /**\n * Archive a session (`POST /api/conversations/threads/archive`). The row\n * leaves the list at once and stays hidden until both list sources stop\n * reporting it; a failure brings it back. Archiving the active session\n * moves the chat to a new one once the server has confirmed.\n */\n archiveThread: (threadId: string) => void;\n /** The sessions whose archive is in flight. */\n archivePendingThreadIds: ReadonlySet<string>;\n /** True while any archive is in flight. */\n archivePending: boolean;\n /**\n * Whether the backend offers the archive route. `false` once it answered\n * 404 / 405: `SessionList` then offers no Archive action.\n */\n archiveAvailable: boolean;\n /**\n * Where titles come from. `'index'` once the signed-in user's live\n * conversation index has replicated — titles and newly created threads then\n * arrive as pushed updates; `'poll'` while it has not (no signed-in\n * principal, e.g. API-key mode, or before its snapshot), when a\n * freshly-started thread's title is picked up by the bounded REST poll.\n */\n titleSource: 'index' | 'poll';\n}\n\nexport const AthenaStatewireThreadListContext =\n createContext<AthenaStatewireThreadListState | null>(null);\n\n/** Read the statewire thread-list state, or null outside that mode. */\nexport function useAthenaStatewireThreadList(): AthenaStatewireThreadListState | null {\n return useContext(AthenaStatewireThreadListContext);\n}\n\n/** Trigger a re-fetch of the thread list. `null` outside `enableThreadList` mode. */\nexport function useRefreshThreadList(): (() => void) | null {\n return useAthenaStatewireThreadList()?.refresh ?? null;\n}\n\n/**\n * Project one contract row onto the thread-list row. Exported for hosts (and\n * tests) that build rows from a `ConversationSummary` of their own.\n */\nexport function threadSummaryFromConversation(\n conversation: ConversationSummary,\n): AthenaStatewireThreadSummary {\n return {\n id: conversation.threadId,\n title: normalizeThreadTitle(conversation.title) ?? null,\n attention: deriveConversationAttention(conversation),\n nextAction: conversation.nextAction ?? null,\n attentionSource: conversation.attentionSource ?? null,\n isFavorited: conversation.isFavorited ?? false,\n isUnread: conversation.isUnread,\n sessionStatus: conversation.sessionStatus,\n runStatus: conversation.runStatus,\n startChannel: conversation.sourceChannel,\n appId: conversation.appId,\n triggerType: conversation.triggerType,\n pullRequests: conversation.pullRequests ?? null,\n lastWake: conversation.lastWake ?? null,\n updatedAt: conversation.updatedAt,\n };\n}\n\n/**\n * The statewire thread list reads one live page through the shared\n * conversation-list contract; the REST default page size predates the shared\n * pager and is preserved here.\n */\nconst THREAD_LIST_PAGE_SIZE = 50;\n\nfunction StatewireThreadListState({\n backendUrl,\n syncUrl,\n apiKey,\n token,\n getToken,\n appId,\n initialThreadId,\n includePullRequests,\n snapshotCache,\n children,\n}: {\n backendUrl: string;\n syncUrl?: string;\n apiKey?: string;\n token?: string | null;\n getToken?: AthenaStatewireTokenGetter;\n appId?: string;\n initialThreadId?: string;\n includePullRequests: boolean;\n snapshotCache?: DeepAgentThreadSnapshotCache;\n children: ReactNode;\n}) {\n const [active, setActive] = useState<{ id: string; isNew: boolean }>(() =>\n initialThreadId\n ? { id: initialThreadId, isNew: false }\n : { id: mintThreadId(), isNew: true },\n );\n const [search, setSearch] = useState('');\n\n const tokenRef = useRef(token);\n tokenRef.current = token;\n const apiKeyRef = useRef(apiKey);\n apiKeyRef.current = apiKey;\n const getTokenRef = useRef(getToken);\n getTokenRef.current = getToken;\n\n // The cache must be keyed by WHO is asking. Keying on `backendUrl`/`appId`\n // alone let a token swap to a different user read the previous user's thread\n // titles out of the cache. The principal is a non-secret user id, so no\n // credential enters the key (or React Query's devtools). The shared pager\n // never serves placeholder rows across keys, so another principal's list is\n // never shown while the new one loads.\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n // A live token getter is a credential too: a `getToken`-only host\n // authenticates its chat, so its list must not stay empty.\n const hasAuth = !!(apiKey || token || getToken);\n\n // Resolved per request with the attach's token semantics (getter first,\n // host-held token as the fallback) so a rotated token is never stale.\n const getAuth = useCallback(\n async () => ({\n apiKey: apiKeyRef.current,\n token: await resolveStatewireAuthToken(\n { apiKey: apiKeyRef.current, token: tokenRef.current, getToken: getTokenRef.current },\n { staleAuth: false },\n ),\n }),\n [],\n );\n const fetchPage = useMemo(\n () => createRestConversationListFetcher({ backendUrl, includePullRequests, getAuth }),\n [backendUrl, includePullRequests, getAuth],\n );\n const trimmedSearch = search.trim();\n const filter = useMemo<ConversationListFilter>(\n () => ({\n ...(appId ? { appId } : {}),\n ...(trimmedSearch ? { search: trimmedSearch } : {}),\n }),\n [appId, trimmedSearch],\n );\n const list = useConversationList({\n fetchPage,\n filter,\n pageSize: THREAD_LIST_PAGE_SIZE,\n // Pull-request opt-in changes what a cached row holds, so it is part of\n // the cache identity.\n scopeKey: `${backendUrl}::${principal}::${hasAuth ? 'auth' : 'anon'}::${\n includePullRequests ? 'prs' : 'no-prs'\n }`,\n enabled: hasAuth,\n });\n\n // Live rows ride the signed-in user's conversation index — the same push\n // channel the conversation-history panel renders from: the host replicates\n // title, lifecycle, attention and creation changes as ops, so a\n // freshly-started thread's server-generated title (or a session flipping to\n // \"needs you\") lands without polling. The index is one instance per\n // `(workspace, user)` in agora's ids, so the pair is resolved from the\n // backend once a principal is known and the index only attaches once both\n // halves are; API-key-only hosts keep the bounded REST poll\n // (`titleSource: 'poll'`).\n const indexHeaders = useCallback<DeepAgentHeadersResolver>(\n (ctx) =>\n resolveStatewireAuthHeaders(\n { apiKey: apiKeyRef.current, token: tokenRef.current, getToken: getTokenRef.current },\n ctx,\n ),\n [],\n );\n // The workspace half is the CREDENTIAL's: a scoped credential (sandbox,\n // preview, Office session) pins its own workspace, so swapping one for\n // another under the same principal must re-resolve the pair. The query is\n // therefore keyed by a credential generation — a counter that advances\n // whenever the host's credentials change — so no secret enters the key.\n const credentialsRef = useRef(credentialShape({ apiKey, token, getToken }));\n const credentialGenerationRef = useRef(0);\n const currentCredentials = credentialShape({ apiKey, token, getToken });\n if (!sameCredentialShape(credentialsRef.current, currentCredentials)) {\n credentialsRef.current = currentCredentials;\n credentialGenerationRef.current += 1;\n }\n const credentialGeneration = credentialGenerationRef.current;\n const identityEnabled = syncUrl !== undefined && principal.length > 0 && hasAuth;\n const identity = useQuery({\n // Keyed by the non-secret principal and credential generation, never the\n // credential itself.\n queryKey: ['athena-sdk', 'account-identity', backendUrl, principal, credentialGeneration],\n queryFn: async ({ signal }) =>\n fetchAccountIdentity(\n backendUrl,\n {\n apiKey: apiKeyRef.current,\n token: await resolveStatewireAuthToken(\n { apiKey: apiKeyRef.current, token: tokenRef.current, getToken: getTokenRef.current },\n { staleAuth: false },\n ),\n },\n { signal },\n ),\n enabled: identityEnabled,\n staleTime: Number.POSITIVE_INFINITY,\n });\n const indexWorkspaceId = identity.data?.workspaceId ?? '';\n const indexUserId = identity.data?.userId ?? '';\n const indexEnabled = identityEnabled && indexWorkspaceId.length > 0 && indexUserId.length > 0;\n const index = useConversationIndex({\n baseUrl: syncUrl === undefined ? '' : conversationIndexUrlFromStatewireUrl(syncUrl),\n workspaceId: indexWorkspaceId || 'pending-workspace',\n userId: indexUserId || 'pending-user',\n headers: indexHeaders,\n enabled: indexEnabled,\n });\n const indexByThread = useMemo(() => {\n const entries = new Map<string, ConversationIndexEntry>();\n for (const entry of index.entries ?? []) entries.set(entry.thread_id, entry);\n return entries;\n }, [index.entries]);\n\n // Each fetched row folds its pushed index entry through the shared\n // `summaryFromConversationIndexEntry`, so titles, lifecycle and attention\n // update live while the fields the index never carries (pull requests,\n // the last wake) keep their fetched values. A pushed title that normalizes\n // to nothing falls back to the fetched one.\n const mergedConversations = useMemo(\n () =>\n list.conversations.map((conversation) => {\n const entry = indexByThread.get(conversation.threadId);\n if (!entry) return conversation;\n const merged = summaryFromConversationIndexEntry(entry, conversation);\n return normalizeThreadTitle(merged.title) === undefined\n ? { ...merged, title: conversation.title }\n : merged;\n }),\n [list.conversations, indexByThread],\n );\n // A pin toggle sits over the fold: the row flips at once, and a pushed\n // index entry that predates the write cannot clobber it. The override drops\n // once both sources report the toggled value.\n const listPatchConversation = list.patchConversation;\n const favorite = useThreadFavorite({\n backendUrl,\n principalId: principal,\n getAuth,\n rows: mergedConversations,\n onServerTruth: ({ threadId, isFavorited }) =>\n listPatchConversation(threadId, { isFavorited }),\n });\n const favoriteOverrides = favorite.overrides;\n // A rename sits over the fold the same way: the row shows the new title\n // at once, and a pushed index entry that predates the write cannot restore\n // the old one. The override drops once both sources report the new title.\n const rename = useThreadRename({\n backendUrl,\n principalId: principal,\n getAuth,\n rows: mergedConversations,\n onServerTruth: ({ threadId, title }) => listPatchConversation(threadId, { title }),\n });\n const titleOverrides = rename.overrides;\n\n // An archive hides the row at once and keeps it hidden until neither list\n // source reports it any more — the cached page is patched on the server's\n // answer, but the pushed index may still carry the row until the publish\n // that follows the commit lands. A failure drops the id and the row comes\n // back from the still-cached page: no refetch needed. Scoping, the\n // one-write-per-thread guard and the route-missing fallback live in the hook.\n const listRemoveConversation = list.removeConversation;\n const archive = useThreadArchive({\n backendUrl,\n principalId: principal,\n getAuth,\n onArchived: (threadId) => {\n listRemoveConversation(threadId);\n // The archived session cannot stay the active chat: the server no\n // longer lists it, so the chat moves to a fresh one.\n setActive((current) =>\n current.id === threadId ? { id: mintThreadId(), isNew: true } : current,\n );\n },\n });\n const hiddenThreadIds = archive.hiddenThreadIds;\n const archiveRelease = archive.release;\n // A hidden row is released once both sources have forgotten it, so a\n // session archived elsewhere and then restored is never masked here.\n useEffect(() => {\n if (hiddenThreadIds.size === 0) return;\n const forgotten = [...hiddenThreadIds].filter(\n (threadId) =>\n !mergedConversations.some((conversation) => conversation.threadId === threadId) &&\n !indexByThread.has(threadId),\n );\n if (forgotten.length > 0) archiveRelease(forgotten);\n }, [hiddenThreadIds, mergedConversations, indexByThread, archiveRelease]);\n\n const data = useMemo(\n () =>\n withTitleOverrides(\n withFavoriteOverrides(mergedConversations, favoriteOverrides),\n titleOverrides,\n )\n .filter((conversation) => !hiddenThreadIds.has(conversation.threadId))\n .map(threadSummaryFromConversation),\n [mergedConversations, favoriteOverrides, titleOverrides, hiddenThreadIds],\n );\n const isLoading = list.isLoading;\n\n // The active thread's row must survive a search that filters it out of\n // the page (the banner above the chat reads it): the listed row when there\n // is one, else the pushed index entry folded over the last row seen for\n // this thread (so pull requests survive the fold), else that last row.\n const lastActiveConversationRef = useRef<ConversationSummary | null>(null);\n const activeConversation = useMemo<ConversationSummary | null>(() => {\n const listed = mergedConversations.find((conversation) => conversation.threadId === active.id);\n if (listed) return listed;\n const remembered =\n lastActiveConversationRef.current?.threadId === active.id\n ? lastActiveConversationRef.current\n : undefined;\n const entry = indexByThread.get(active.id);\n if (entry) return summaryFromConversationIndexEntry(entry, remembered);\n return remembered ?? null;\n }, [mergedConversations, indexByThread, active.id]);\n if (activeConversation !== null) lastActiveConversationRef.current = activeConversation;\n const activeThread = useMemo(\n () =>\n activeConversation\n ? threadSummaryFromConversation(\n withTitleOverride(\n withFavoriteOverride(activeConversation, favoriteOverrides),\n titleOverrides,\n ),\n )\n : null,\n [activeConversation, favoriteOverrides, titleOverrides],\n );\n\n const listRefresh = list.refresh;\n const refresh = useCallback(() => {\n void listRefresh();\n }, [listRefresh]);\n const listFetchNextPage = list.fetchNextPage;\n const fetchNextPage = useCallback(() => {\n void listFetchNextPage();\n }, [listFetchNextPage]);\n\n // A thread the index knows — created here on first send, or elsewhere —\n // that the REST page does not list yet: refresh once per such id so the row\n // appears without the user pressing refresh. Rows for other app ids belong\n // to other lists and never trigger one.\n const refreshedForRef = useRef<Set<string>>(new Set());\n useEffect(() => {\n if (index.entries === null) return;\n const listed = new Set(list.conversations.map((conversation) => conversation.threadId));\n let pending = false;\n for (const entry of index.entries) {\n if (appId && entry.app_id !== appId) continue;\n if (listed.has(entry.thread_id) || refreshedForRef.current.has(entry.thread_id)) continue;\n refreshedForRef.current.add(entry.thread_id);\n pending = true;\n }\n if (pending) void listRefresh();\n }, [index.entries, list.conversations, appId, listRefresh]);\n\n const selectThread = useCallback((threadId: string) => {\n if (!threadId) return;\n setActive((current) =>\n current.id === threadId ? current : { id: threadId, isNew: false },\n );\n }, []);\n\n // The hover prefetcher is one per (backend, principal, credential\n // generation): a credential swap clears the provider's snapshot cache, so\n // the attempt ledger resets with it and a late answer from the previous\n // identity is never remembered under the new one.\n const prefetchScope = `${backendUrl}::${principal}::${credentialGeneration}`;\n const prefetchScopeRef = useRef(prefetchScope);\n prefetchScopeRef.current = prefetchScope;\n const prefetcher = useMemo(() => {\n if (!snapshotCache) return null;\n const scope = prefetchScope;\n return createThreadPrefetcher({\n cache: snapshotCache,\n fetchState: async (threadId) =>\n getThreadState(backendUrl, await getAuth(), threadId, { skipCache: false }),\n isCurrent: () => prefetchScopeRef.current === scope,\n });\n }, [snapshotCache, prefetchScope, backendUrl, getAuth]);\n const activeIdRef = useRef(active.id);\n activeIdRef.current = active.id;\n const prefetchThread = useCallback(\n (threadId: string) => {\n if (!prefetcher || !threadId || threadId === activeIdRef.current) return;\n prefetcher.prefetch(threadId);\n },\n [prefetcher],\n );\n\n const newThread = useCallback(() => {\n setActive({ id: mintThreadId(), isNew: true });\n }, []);\n\n // A minted thread stops being \"new\" once the backend lists it — on the\n // fetched page or in the pushed index (a search may keep it off the page):\n // until then `useAthenaThreadManager` reports a null id, so URL sync cannot\n // name it.\n const isPersisted =\n data.some((thread) => thread.id === active.id) || indexByThread.has(active.id);\n useEffect(() => {\n if (isPersisted) {\n setActive((current) => (current.isNew ? { ...current, isNew: false } : current));\n }\n }, [isPersisted]);\n\n const titleSource: AthenaStatewireThreadListState['titleSource'] =\n index.entries !== null ? 'index' : 'poll';\n\n const value = useMemo<AthenaStatewireThreadListState>(\n () => ({\n threads: data,\n isLoading,\n isFetching: list.isFetching,\n hasResolvedFirstPage: list.hasResolvedFirstPage,\n activeThreadId: active.id,\n activeThread,\n isNewChat: active.isNew,\n selectThread,\n prefetchThread,\n newThread,\n refresh,\n search,\n setSearch,\n hasNextPage: list.hasNextPage,\n isFetchingNextPage: list.isFetchingNextPage,\n fetchNextPage,\n setFavorited: favorite.setFavorited,\n favoritePending: favorite.isPending,\n favoritePendingThreadIds: favorite.pendingThreadIds,\n favoriteToggleAvailable: favorite.isAvailable,\n renameThread: rename.rename,\n renamePendingThreadIds: rename.pendingThreadIds,\n renameAvailable: rename.isAvailable,\n archiveThread: archive.archive,\n archivePendingThreadIds: archive.pendingThreadIds,\n archivePending: archive.isPending,\n archiveAvailable: archive.isAvailable,\n titleSource,\n }),\n [\n data,\n isLoading,\n list.isFetching,\n list.hasResolvedFirstPage,\n active.id,\n activeThread,\n active.isNew,\n selectThread,\n prefetchThread,\n newThread,\n refresh,\n search,\n list.hasNextPage,\n list.isFetchingNextPage,\n fetchNextPage,\n favorite.setFavorited,\n favorite.isPending,\n favorite.pendingThreadIds,\n favorite.isAvailable,\n rename.rename,\n rename.pendingThreadIds,\n rename.isAvailable,\n archive.archive,\n archive.pendingThreadIds,\n archive.isPending,\n archive.isAvailable,\n titleSource,\n ],\n );\n\n return (\n <AthenaStatewireThreadListContext.Provider value={value}>\n {children}\n </AthenaStatewireThreadListContext.Provider>\n );\n}\n\n/**\n * Provides the statewire thread-list state, with an SDK-scoped QueryClient so\n * consumers do not need their own QueryClientProvider. `syncUrl` (the\n * `…/v2/threads` mount) locates the conversation index beside it; without it\n * titles fall back to the REST poll. `includePullRequests` (default `true`)\n * asks the list for live pull-request state so `SessionList` can render its\n * chips; a host that never shows them turns it off to spare the server the\n * lookup. `snapshotCache` is the provider's thread snapshot cache — the one\n * the runtime seeds a switched-to thread from — which `prefetchThread` warms;\n * without it prefetching is a no-op.\n */\nexport function AthenaStatewireThreadListProvider({\n backendUrl,\n syncUrl,\n apiKey,\n token,\n getToken,\n appId,\n initialThreadId,\n includePullRequests = true,\n snapshotCache,\n children,\n}: {\n backendUrl: string;\n syncUrl?: string;\n apiKey?: string;\n token?: string | null;\n getToken?: AthenaStatewireTokenGetter;\n appId?: string;\n initialThreadId?: string;\n includePullRequests?: boolean;\n snapshotCache?: DeepAgentThreadSnapshotCache;\n children: ReactNode;\n}) {\n const [queryClient] = useState(() => new QueryClient());\n return (\n <QueryClientProvider client={queryClient}>\n <StatewireThreadListState\n backendUrl={backendUrl}\n syncUrl={syncUrl}\n apiKey={apiKey}\n token={token}\n getToken={getToken}\n appId={appId}\n initialThreadId={initialThreadId}\n includePullRequests={includePullRequests}\n snapshotCache={snapshotCache}\n >\n {children}\n </StatewireThreadListState>\n </QueryClientProvider>\n );\n}\n\n/** How long after a thread's first message the title poll starts (exported for tests). */\nexport const TITLE_POLL_DELAY_MS = 5000;\nconst TITLE_POLL_INTERVAL_MS = 2000;\nconst TITLE_POLL_MAX_DURATION_MS = 60_000;\n\n/**\n * Fallback for hosts without a live conversation index (`titleSource: 'poll'`,\n * i.e. no signed-in principal): refreshes the thread list until a\n * freshly-started thread's server-generated title appears. Idle while the\n * index carries titles. Mount inside the statewire runtime scope (needs aui\n * state).\n *\n * The thread is read from the statewire scope, not the list: the scope\n * publishes the id together with the client it belongs to, so the messages\n * observed here are always the named thread's (the list's selection moves\n * one commit ahead of the client during a switch).\n */\nexport function StatewireThreadTitlePoller(): null {\n const list = useAthenaStatewireThreadList();\n const activeThreadId = useAthenaStatewireThreadId();\n const hasMessages = useAuiState((s) => (s.optional.thread?.messages.length ?? 0) > 0);\n\n const titleSource = list?.titleSource ?? 'poll';\n const entry = list?.threads.find((thread) => thread.id === activeThreadId);\n const title = entry?.title?.trim() ?? '';\n const hasTitle = title.length > 0 && !isSerializedContentPartsTitle(title);\n\n // The poller stays mounted across thread switches, so the visit is tracked\n // by hand: one poll per visit — no restart when the visited thread's\n // messages or title flip underneath it — and a re-selected thread polls\n // again, as it did when every switch remounted the poller. The record is\n // replaced whenever the attached thread changes, whether or not a poll\n // started for it, so a visit to a thread that needs no poll can never make\n // the next visit to a previous thread look already polled.\n const visitRef = useRef<{ threadId: string; polled: boolean } | null>(null);\n const refreshRef = useRef(list?.refresh);\n refreshRef.current = list?.refresh;\n\n useEffect(() => {\n if (visitRef.current?.threadId !== activeThreadId) {\n visitRef.current = { threadId: activeThreadId, polled: false };\n }\n const visit = visitRef.current;\n if (!hasMessages || hasTitle || titleSource === 'index') return;\n if (visit.polled) return;\n visit.polled = true;\n\n let intervalId: ReturnType<typeof setInterval> | null = null;\n const startId = setTimeout(() => {\n intervalId = setInterval(() => refreshRef.current?.(), TITLE_POLL_INTERVAL_MS);\n }, TITLE_POLL_DELAY_MS);\n const stopId = setTimeout(() => {\n if (intervalId !== null) clearInterval(intervalId);\n }, TITLE_POLL_MAX_DURATION_MS);\n\n return () => {\n clearTimeout(startId);\n clearTimeout(stopId);\n if (intervalId !== null) clearInterval(intervalId);\n };\n }, [activeThreadId, hasMessages, hasTitle, titleSource]);\n\n return null;\n}\n"],"names":["createContext","useContext","normalizeThreadTitle","deriveConversationAttention","useState","mintThreadId","useRef","AthenaAuthContext","useCallback","resolveStatewireAuthToken","useMemo","createRestConversationListFetcher","useConversationList","resolveStatewireAuthHeaders","credentialShape","sameCredentialShape","useQuery","fetchAccountIdentity","useConversationIndex","conversationIndexUrlFromStatewireUrl","summaryFromConversationIndexEntry","useThreadFavorite","useThreadRename","title","useThreadArchive","useEffect","withTitleOverrides","withFavoriteOverrides","_a","withTitleOverride","withFavoriteOverride","createThreadPrefetcher","getThreadState","jsx","QueryClient","QueryClientProvider","useAthenaStatewireThreadId","useAuiState","isSerializedContentPartsTitle"],"mappings":"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"}
1
+ {"version":3,"file":"statewire-thread-list.cjs","sources":["../../src/threads/statewire-thread-list.tsx"],"sourcesContent":["import {\n type ConversationAttention,\n type ConversationAttentionSource,\n type ConversationIndexEntry,\n type ConversationListFilter,\n type ConversationPullRequest,\n type ConversationSummary,\n type ConversationWake,\n conversationIndexUrlFromStatewireUrl,\n type DeepAgentHeadersResolver,\n type DeepAgentThreadSnapshotCache,\n deriveConversationAttention,\n summaryFromConversationIndexEntry,\n useConversationIndex,\n useConversationList,\n} from '@athenaintel/agent-runtime';\nimport { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';\nimport { useAuiState } from '@assistant-ui/react';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n resolveStatewireAuthToken,\n} from '../runtime/statewire-auth-headers';\nimport { fetchAccountIdentity, getThreadState } from './api';\nimport { createRestConversationListFetcher } from './conversation-list-fetcher';\nimport { credentialShape, sameCredentialShape } from './credential-shape';\nimport { mintThreadId } from './mint-thread-id';\nimport { useAthenaStatewireThreadId } from './thread-id-context';\nimport { createThreadPrefetcher } from './thread-prefetcher';\nimport { isSerializedContentPartsTitle, normalizeThreadTitle } from './title';\nimport { useThreadArchive } from './use-thread-archive';\nimport {\n type ThreadFavoriteTarget,\n useThreadFavorite,\n withFavoriteOverride,\n withFavoriteOverrides,\n} from './use-thread-favorite';\nimport {\n type ThreadRenameTarget,\n useThreadRename,\n withTitleOverride,\n withTitleOverrides,\n} from './use-thread-rename';\n\n/**\n * One row of the thread list — the fields a Devin-style session list renders\n * (`SessionList`), all read from the shared conversation-list contract. The\n * attention fields are `null` on a server that does not derive them; the\n * pull-request state is `null` until the list has fetched it (or when the\n * provider opted out of it).\n */\nexport interface AthenaStatewireThreadSummary {\n id: string;\n title: string | null;\n /**\n * What the session asks of the viewer: the server-derived state when\n * reported, else the client fallback from the status planes\n * (`deriveConversationAttention`).\n */\n attention: ConversationAttention | null;\n /** One line (≤ 80 chars) of what the viewer should do next, when the server derives one. */\n nextAction: string | null;\n attentionSource: ConversationAttentionSource | null;\n /**\n * Whether the viewer pinned the session. Toggled through\n * `AthenaStatewireThreadListState.setFavorited`; a toggle in flight is\n * reflected here at once and held until the list sources report it.\n */\n isFavorited: boolean;\n isUnread: boolean;\n /** Canonical status_v2 planes, or `null` on an older server. */\n sessionStatus: string | null;\n runStatus: string | null;\n /** Channel the session was started from (e.g. `web`, `github`, `api`). */\n startChannel: string | null;\n /** Client app that created the session (SESSION_APP_ID_GUIDE). */\n appId: string | null;\n /** Trigger marker (`manual` remains user-initiated; other values are automated). */\n triggerType: string | null;\n /** Pull requests the session opened with their live GitHub state. */\n pullRequests: ConversationPullRequest[] | null;\n /** The last wake of a resting session. */\n lastWake: ConversationWake | null;\n /** ISO 8601 timestamp of the last update (the list's sort key). */\n updatedAt: string;\n}\n\n/**\n * Thread-list state. The list is the persisted Agora session list; the ACTIVE\n * thread is a plain id the statewire runtime attaches to — switching threads\n * remounts the statewire session against the new `…/v2/threads/{id}` URL\n * (the same model the mobile app uses).\n */\nexport interface AthenaStatewireThreadListState {\n /** The rows the current `search` lists, newest first. */\n threads: AthenaStatewireThreadSummary[];\n isLoading: boolean;\n /** True while the live first page (or a history page) is being fetched. */\n isFetching: boolean;\n /**\n * True once the live first page has answered at least once for the current\n * search and identity. Until then an empty `threads` means \"not known\n * yet\" (no credential resolved, first page in flight), not \"no sessions\":\n * `SessionList` shows skeleton rows, never the empty state.\n */\n hasResolvedFirstPage: boolean;\n activeThreadId: string;\n /**\n * The active thread's row, independent of what `threads` currently lists:\n * a search that hides the row, or a page that has not fetched it, must not\n * make the active chat's attention disappear. Resolved from the listed row,\n * else the pushed index entry folded over the last row seen, else that\n * last row; `null` for a never-started chat the backend does not know yet.\n */\n activeThread: AthenaStatewireThreadSummary | null;\n /** True while the active thread is a locally-minted chat with no server history. */\n isNewChat: boolean;\n selectThread: (threadId: string) => void;\n /**\n * Warm the provider's snapshot cache with a thread's REST state ahead of a\n * `selectThread`, so the switch paints the transcript on its first frame\n * instead of the loading scrim while the statewire attach lands.\n * `SessionList` calls it after a 120 ms hover dwell and on row focus.\n * Fetches once per thread per identity, deduplicates requests in flight,\n * runs at most two at a time and ignores failures; a no-op for the active\n * thread, a thread the cache already holds, or a provider without a cache.\n */\n prefetchThread: (threadId: string) => void;\n newThread: () => void;\n refresh: () => void;\n /**\n * Server-side title search (`search` on the REST thread list). An empty\n * string lists everything; the search covers the viewer's whole authorized\n * history, not just the live page.\n */\n search: string;\n setSearch: (search: string) => void;\n /** Whether another page of older sessions can be fetched. */\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n /** Fetch the next page of older sessions (frozen history pages, never replayed). */\n fetchNextPage: () => void;\n /**\n * Pin or unpin a session (`POST /api/conversations/threads/favorite`). The\n * row flips at once and moves between the `Pinned` and `Recent` groups; the\n * server's answer is written back, and a failure restores the previous\n * state. Writes for one thread are serialized: a toggle while that\n * thread's write is in flight records the value and sends at most one\n * follow-up write once the first has answered.\n */\n setFavorited: (target: ThreadFavoriteTarget) => void;\n /** True while any pin toggle is in flight. */\n favoritePending: boolean;\n /** The sessions whose pin toggle is in flight; `SessionList` disables their pin control. */\n favoritePendingThreadIds: ReadonlySet<string>;\n /**\n * Whether the backend offers the favorite route. `false` once it answered\n * 404 / 405 (an agora that predates the route): `SessionList` then shows\n * the read-only pin and no toggle, and `setFavorited` keeps failing.\n */\n favoriteToggleAvailable: boolean;\n /**\n * Rename a session for every viewer (`POST /api/conversations/threads/rename`).\n * The row shows the new title at once; the server's stored title is\n * written back, and a failure restores the previous one. Same-thread\n * writes are serialized like the pin's.\n */\n renameThread: (target: ThreadRenameTarget) => void;\n /** The sessions whose rename is in flight; `SessionList` keeps their editor closed. */\n renamePendingThreadIds: ReadonlySet<string>;\n /**\n * Whether the backend offers the rename route. `false` once it answered\n * 404 / 405 (an agora that predates the route): `SessionList` then offers\n * no Rename action, and `renameThread` keeps failing.\n */\n renameAvailable: boolean;\n /**\n * Archive a session (`POST /api/conversations/threads/archive`). The row\n * leaves the list at once and stays hidden until both list sources stop\n * reporting it; a failure brings it back. Archiving the active session\n * moves the chat to a new one once the server has confirmed.\n */\n archiveThread: (threadId: string) => void;\n /** The sessions whose archive is in flight. */\n archivePendingThreadIds: ReadonlySet<string>;\n /** True while any archive is in flight. */\n archivePending: boolean;\n /**\n * Whether the backend offers the archive route. `false` once it answered\n * 404 / 405: `SessionList` then offers no Archive action.\n */\n archiveAvailable: boolean;\n /**\n * Where titles come from. `'index'` once the signed-in user's live\n * conversation index has replicated — titles and newly created threads then\n * arrive as pushed updates; `'poll'` while it has not (no signed-in\n * principal, e.g. API-key mode, or before its snapshot), when a\n * freshly-started thread's title is picked up by the bounded REST poll.\n */\n titleSource: 'index' | 'poll';\n}\n\nexport const AthenaStatewireThreadListContext =\n createContext<AthenaStatewireThreadListState | null>(null);\n\n/** Read the statewire thread-list state, or null outside that mode. */\nexport function useAthenaStatewireThreadList(): AthenaStatewireThreadListState | null {\n return useContext(AthenaStatewireThreadListContext);\n}\n\n/** Trigger a re-fetch of the thread list. `null` outside `enableThreadList` mode. */\nexport function useRefreshThreadList(): (() => void) | null {\n return useAthenaStatewireThreadList()?.refresh ?? null;\n}\n\n/**\n * Project one contract row onto the thread-list row. Exported for hosts (and\n * tests) that build rows from a `ConversationSummary` of their own.\n */\nexport function threadSummaryFromConversation(\n conversation: ConversationSummary,\n): AthenaStatewireThreadSummary {\n return {\n id: conversation.threadId,\n title: normalizeThreadTitle(conversation.title) ?? null,\n attention: deriveConversationAttention(conversation),\n nextAction: conversation.nextAction ?? null,\n attentionSource: conversation.attentionSource ?? null,\n isFavorited: conversation.isFavorited ?? false,\n isUnread: conversation.isUnread,\n sessionStatus: conversation.sessionStatus,\n runStatus: conversation.runStatus,\n startChannel: conversation.sourceChannel,\n appId: conversation.appId,\n triggerType: conversation.triggerType,\n pullRequests: conversation.pullRequests ?? null,\n lastWake: conversation.lastWake ?? null,\n updatedAt: conversation.updatedAt,\n };\n}\n\n/**\n * The statewire thread list reads one live page through the shared\n * conversation-list contract; the REST default page size predates the shared\n * pager and is preserved here.\n */\nconst THREAD_LIST_PAGE_SIZE = 50;\n\nfunction StatewireThreadListState({\n backendUrl,\n syncUrl,\n apiKey,\n token,\n getToken,\n appId,\n initialThreadId,\n includePullRequests,\n snapshotCache,\n children,\n}: {\n backendUrl: string;\n syncUrl?: string;\n apiKey?: string;\n token?: string | null;\n getToken?: AthenaStatewireTokenGetter;\n appId?: string;\n initialThreadId?: string;\n includePullRequests: boolean;\n snapshotCache?: DeepAgentThreadSnapshotCache;\n children: ReactNode;\n}) {\n const [active, setActive] = useState<{ id: string; isNew: boolean }>(() =>\n initialThreadId\n ? { id: initialThreadId, isNew: false }\n : { id: mintThreadId(), isNew: true },\n );\n const [search, setSearch] = useState('');\n\n const tokenRef = useRef(token);\n tokenRef.current = token;\n const apiKeyRef = useRef(apiKey);\n apiKeyRef.current = apiKey;\n const getTokenRef = useRef(getToken);\n getTokenRef.current = getToken;\n\n // The cache must be keyed by WHO is asking. Keying on `backendUrl`/`appId`\n // alone let a token swap to a different user read the previous user's thread\n // titles out of the cache. The principal is a non-secret user id, so no\n // credential enters the key (or React Query's devtools). The shared pager\n // never serves placeholder rows across keys, so another principal's list is\n // never shown while the new one loads.\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n // A live token getter is a credential too: a `getToken`-only host\n // authenticates its chat, so its list must not stay empty.\n const hasAuth = !!(apiKey || token || getToken);\n\n // Resolved per request with the attach's token semantics (getter first,\n // host-held token as the fallback) so a rotated token is never stale.\n const getAuth = useCallback(\n async () => ({\n apiKey: apiKeyRef.current,\n token: await resolveStatewireAuthToken(\n { apiKey: apiKeyRef.current, token: tokenRef.current, getToken: getTokenRef.current },\n { staleAuth: false },\n ),\n }),\n [],\n );\n const fetchPage = useMemo(\n () => createRestConversationListFetcher({ backendUrl, includePullRequests, getAuth }),\n [backendUrl, includePullRequests, getAuth],\n );\n const trimmedSearch = search.trim();\n const filter = useMemo<ConversationListFilter>(\n () => ({\n ...(appId ? { appId } : {}),\n ...(trimmedSearch ? { search: trimmedSearch } : {}),\n }),\n [appId, trimmedSearch],\n );\n const list = useConversationList({\n fetchPage,\n filter,\n pageSize: THREAD_LIST_PAGE_SIZE,\n // Pull-request opt-in changes what a cached row holds, so it is part of\n // the cache identity.\n scopeKey: `${backendUrl}::${principal}::${hasAuth ? 'auth' : 'anon'}::${\n includePullRequests ? 'prs' : 'no-prs'\n }`,\n enabled: hasAuth,\n });\n\n // Live rows ride the signed-in user's conversation index — the same push\n // channel the conversation-history panel renders from: the host replicates\n // title, lifecycle, attention and creation changes as ops, so a\n // freshly-started thread's server-generated title (or a session flipping to\n // \"needs you\") lands without polling. The index is one instance per\n // `(workspace, user)` in agora's ids, so the pair is resolved from the\n // backend once a principal is known and the index only attaches once both\n // halves are; API-key-only hosts keep the bounded REST poll\n // (`titleSource: 'poll'`).\n const indexHeaders = useCallback<DeepAgentHeadersResolver>(\n (ctx) =>\n resolveStatewireAuthHeaders(\n { apiKey: apiKeyRef.current, token: tokenRef.current, getToken: getTokenRef.current },\n ctx,\n ),\n [],\n );\n // The workspace half is the CREDENTIAL's: a scoped credential (sandbox,\n // preview, Office session) pins its own workspace, so swapping one for\n // another under the same principal must re-resolve the pair. The query is\n // therefore keyed by a credential generation — a counter that advances\n // whenever the host's credentials change — so no secret enters the key.\n const credentialsRef = useRef(credentialShape({ apiKey, token, getToken }));\n const credentialGenerationRef = useRef(0);\n const currentCredentials = credentialShape({ apiKey, token, getToken });\n if (!sameCredentialShape(credentialsRef.current, currentCredentials)) {\n credentialsRef.current = currentCredentials;\n credentialGenerationRef.current += 1;\n }\n const credentialGeneration = credentialGenerationRef.current;\n const identityEnabled = syncUrl !== undefined && principal.length > 0 && hasAuth;\n const identity = useQuery({\n // Keyed by the non-secret principal and credential generation, never the\n // credential itself.\n queryKey: ['athena-sdk', 'account-identity', backendUrl, principal, credentialGeneration],\n queryFn: async ({ signal }) =>\n fetchAccountIdentity(\n backendUrl,\n {\n apiKey: apiKeyRef.current,\n token: await resolveStatewireAuthToken(\n { apiKey: apiKeyRef.current, token: tokenRef.current, getToken: getTokenRef.current },\n { staleAuth: false },\n ),\n },\n { signal },\n ),\n enabled: identityEnabled,\n staleTime: Number.POSITIVE_INFINITY,\n });\n const indexWorkspaceId = identity.data?.workspaceId ?? '';\n const indexUserId = identity.data?.userId ?? '';\n const indexEnabled = identityEnabled && indexWorkspaceId.length > 0 && indexUserId.length > 0;\n const index = useConversationIndex({\n baseUrl: syncUrl === undefined ? '' : conversationIndexUrlFromStatewireUrl(syncUrl),\n workspaceId: indexWorkspaceId || 'pending-workspace',\n userId: indexUserId || 'pending-user',\n headers: indexHeaders,\n enabled: indexEnabled,\n });\n const indexByThread = useMemo(() => {\n const entries = new Map<string, ConversationIndexEntry>();\n for (const entry of index.entries ?? []) entries.set(entry.thread_id, entry);\n return entries;\n }, [index.entries]);\n\n // Each fetched row folds its pushed index entry through the shared\n // `summaryFromConversationIndexEntry`, so titles, lifecycle and attention\n // update live while the fields the index never carries (pull requests,\n // the last wake) keep their fetched values. A pushed title that normalizes\n // to nothing falls back to the fetched one.\n const mergedConversations = useMemo(\n () =>\n list.conversations.map((conversation) => {\n const entry = indexByThread.get(conversation.threadId);\n if (!entry) return conversation;\n const merged = summaryFromConversationIndexEntry(entry, conversation);\n return normalizeThreadTitle(merged.title) === undefined\n ? { ...merged, title: conversation.title }\n : merged;\n }),\n [list.conversations, indexByThread],\n );\n // A pin toggle sits over the fold: the row flips at once, and a pushed\n // index entry that predates the write cannot clobber it. The override drops\n // once both sources report the toggled value.\n const listPatchConversation = list.patchConversation;\n const favorite = useThreadFavorite({\n backendUrl,\n principalId: principal,\n getAuth,\n rows: mergedConversations,\n onServerTruth: ({ threadId, isFavorited }) =>\n listPatchConversation(threadId, { isFavorited }),\n });\n const favoriteOverrides = favorite.overrides;\n // A rename sits over the fold the same way: the row shows the new title\n // at once, and a pushed index entry that predates the write cannot restore\n // the old one. The override drops once both sources report the new title.\n const rename = useThreadRename({\n backendUrl,\n principalId: principal,\n getAuth,\n rows: mergedConversations,\n onServerTruth: ({ threadId, title }) => listPatchConversation(threadId, { title }),\n });\n const titleOverrides = rename.overrides;\n\n // An archive hides the row at once and keeps it hidden until neither list\n // source reports it any more — the cached page is patched on the server's\n // answer, but the pushed index may still carry the row until the publish\n // that follows the commit lands. A failure drops the id and the row comes\n // back from the still-cached page: no refetch needed. Scoping, the\n // one-write-per-thread guard and the route-missing fallback live in the hook.\n const listRemoveConversation = list.removeConversation;\n const archive = useThreadArchive({\n backendUrl,\n principalId: principal,\n getAuth,\n onArchived: (threadId) => {\n listRemoveConversation(threadId);\n // The archived session cannot stay the active chat: the server no\n // longer lists it, so the chat moves to a fresh one.\n setActive((current) =>\n current.id === threadId ? { id: mintThreadId(), isNew: true } : current,\n );\n },\n });\n const hiddenThreadIds = archive.hiddenThreadIds;\n const archiveRelease = archive.release;\n // A hidden row is released once both sources have forgotten it, so a\n // session archived elsewhere and then restored is never masked here.\n useEffect(() => {\n if (hiddenThreadIds.size === 0) return;\n const forgotten = [...hiddenThreadIds].filter(\n (threadId) =>\n !mergedConversations.some((conversation) => conversation.threadId === threadId) &&\n !indexByThread.has(threadId),\n );\n if (forgotten.length > 0) archiveRelease(forgotten);\n }, [hiddenThreadIds, mergedConversations, indexByThread, archiveRelease]);\n\n const data = useMemo(\n () =>\n withTitleOverrides(\n withFavoriteOverrides(mergedConversations, favoriteOverrides),\n titleOverrides,\n )\n .filter((conversation) => !hiddenThreadIds.has(conversation.threadId))\n .map(threadSummaryFromConversation),\n [mergedConversations, favoriteOverrides, titleOverrides, hiddenThreadIds],\n );\n const isLoading = list.isLoading;\n\n // The active thread's row must survive a search that filters it out of\n // the page (the banner above the chat reads it): the listed row when there\n // is one, else the pushed index entry folded over the last row seen for\n // this thread (so pull requests survive the fold), else that last row.\n const lastActiveConversationRef = useRef<ConversationSummary | null>(null);\n const activeConversation = useMemo<ConversationSummary | null>(() => {\n const listed = mergedConversations.find((conversation) => conversation.threadId === active.id);\n if (listed) return listed;\n const remembered =\n lastActiveConversationRef.current?.threadId === active.id\n ? lastActiveConversationRef.current\n : undefined;\n const entry = indexByThread.get(active.id);\n if (entry) return summaryFromConversationIndexEntry(entry, remembered);\n return remembered ?? null;\n }, [mergedConversations, indexByThread, active.id]);\n if (activeConversation !== null) lastActiveConversationRef.current = activeConversation;\n const activeThread = useMemo(\n () =>\n activeConversation\n ? threadSummaryFromConversation(\n withTitleOverride(\n withFavoriteOverride(activeConversation, favoriteOverrides),\n titleOverrides,\n ),\n )\n : null,\n [activeConversation, favoriteOverrides, titleOverrides],\n );\n\n const listRefresh = list.refresh;\n const refresh = useCallback(() => {\n void listRefresh();\n }, [listRefresh]);\n const listFetchNextPage = list.fetchNextPage;\n const fetchNextPage = useCallback(() => {\n void listFetchNextPage();\n }, [listFetchNextPage]);\n\n // A thread the index knows — created here on first send, or elsewhere —\n // that the REST page does not list yet: refresh once per such id so the row\n // appears without the user pressing refresh. Rows for other app ids belong\n // to other lists and never trigger one.\n const refreshedForRef = useRef<Set<string>>(new Set());\n useEffect(() => {\n if (index.entries === null) return;\n const listed = new Set(list.conversations.map((conversation) => conversation.threadId));\n let pending = false;\n for (const entry of index.entries) {\n if (appId && entry.app_id !== appId) continue;\n if (listed.has(entry.thread_id) || refreshedForRef.current.has(entry.thread_id)) continue;\n refreshedForRef.current.add(entry.thread_id);\n pending = true;\n }\n if (pending) void listRefresh();\n }, [index.entries, list.conversations, appId, listRefresh]);\n\n const selectThread = useCallback((threadId: string) => {\n if (!threadId) return;\n setActive((current) =>\n current.id === threadId ? current : { id: threadId, isNew: false },\n );\n }, []);\n\n // The hover prefetcher is one per (backend, principal, credential\n // generation): a credential swap clears the provider's snapshot cache, so\n // the attempt ledger resets with it and a late answer from the previous\n // identity is never remembered under the new one.\n const prefetchScope = `${backendUrl}::${principal}::${credentialGeneration}`;\n const prefetchScopeRef = useRef(prefetchScope);\n prefetchScopeRef.current = prefetchScope;\n const prefetcher = useMemo(() => {\n if (!snapshotCache) return null;\n const scope = prefetchScope;\n return createThreadPrefetcher({\n cache: snapshotCache,\n fetchState: async (threadId) =>\n getThreadState(backendUrl, await getAuth(), threadId, { skipCache: false }),\n isCurrent: () => prefetchScopeRef.current === scope,\n });\n }, [snapshotCache, prefetchScope, backendUrl, getAuth]);\n const activeIdRef = useRef(active.id);\n activeIdRef.current = active.id;\n const prefetchThread = useCallback(\n (threadId: string) => {\n if (!prefetcher || !threadId || threadId === activeIdRef.current) return;\n prefetcher.prefetch(threadId);\n },\n [prefetcher],\n );\n\n const newThread = useCallback(() => {\n setActive({ id: mintThreadId(), isNew: true });\n }, []);\n\n // A minted thread stops being \"new\" once the backend lists it — on the\n // fetched page or in the pushed index (a search may keep it off the page):\n // until then `useAthenaThreadManager` reports a null id, so URL sync cannot\n // name it.\n const isPersisted =\n data.some((thread) => thread.id === active.id) || indexByThread.has(active.id);\n useEffect(() => {\n if (isPersisted) {\n setActive((current) => (current.isNew ? { ...current, isNew: false } : current));\n }\n }, [isPersisted]);\n\n const titleSource: AthenaStatewireThreadListState['titleSource'] =\n index.entries !== null ? 'index' : 'poll';\n\n const value = useMemo<AthenaStatewireThreadListState>(\n () => ({\n threads: data,\n isLoading,\n isFetching: list.isFetching,\n hasResolvedFirstPage: list.hasResolvedFirstPage,\n activeThreadId: active.id,\n activeThread,\n isNewChat: active.isNew,\n selectThread,\n prefetchThread,\n newThread,\n refresh,\n search,\n setSearch,\n hasNextPage: list.hasNextPage,\n isFetchingNextPage: list.isFetchingNextPage,\n fetchNextPage,\n setFavorited: favorite.setFavorited,\n favoritePending: favorite.isPending,\n favoritePendingThreadIds: favorite.pendingThreadIds,\n favoriteToggleAvailable: favorite.isAvailable,\n renameThread: rename.rename,\n renamePendingThreadIds: rename.pendingThreadIds,\n renameAvailable: rename.isAvailable,\n archiveThread: archive.archive,\n archivePendingThreadIds: archive.pendingThreadIds,\n archivePending: archive.isPending,\n archiveAvailable: archive.isAvailable,\n titleSource,\n }),\n [\n data,\n isLoading,\n list.isFetching,\n list.hasResolvedFirstPage,\n active.id,\n activeThread,\n active.isNew,\n selectThread,\n prefetchThread,\n newThread,\n refresh,\n search,\n list.hasNextPage,\n list.isFetchingNextPage,\n fetchNextPage,\n favorite.setFavorited,\n favorite.isPending,\n favorite.pendingThreadIds,\n favorite.isAvailable,\n rename.rename,\n rename.pendingThreadIds,\n rename.isAvailable,\n archive.archive,\n archive.pendingThreadIds,\n archive.isPending,\n archive.isAvailable,\n titleSource,\n ],\n );\n\n return (\n <AthenaStatewireThreadListContext.Provider value={value}>\n {children}\n </AthenaStatewireThreadListContext.Provider>\n );\n}\n\n/**\n * Provides the statewire thread-list state, with an SDK-scoped QueryClient so\n * consumers do not need their own QueryClientProvider. `syncUrl` (the\n * `…/v2/threads` mount) locates the conversation index beside it; without it\n * titles fall back to the REST poll. `includePullRequests` (default `true`)\n * asks the list for live pull-request state so `SessionList` can render its\n * chips; a host that never shows them turns it off to spare the server the\n * lookup. `snapshotCache` is the provider's thread snapshot cache — the one\n * the runtime seeds a switched-to thread from — which `prefetchThread` warms;\n * without it prefetching is a no-op.\n */\nexport function AthenaStatewireThreadListProvider({\n backendUrl,\n syncUrl,\n apiKey,\n token,\n getToken,\n appId,\n initialThreadId,\n includePullRequests = true,\n snapshotCache,\n children,\n}: {\n backendUrl: string;\n syncUrl?: string;\n apiKey?: string;\n token?: string | null;\n getToken?: AthenaStatewireTokenGetter;\n appId?: string;\n initialThreadId?: string;\n includePullRequests?: boolean;\n snapshotCache?: DeepAgentThreadSnapshotCache;\n children: ReactNode;\n}) {\n const [queryClient] = useState(() => new QueryClient());\n return (\n <QueryClientProvider client={queryClient}>\n <StatewireThreadListState\n backendUrl={backendUrl}\n syncUrl={syncUrl}\n apiKey={apiKey}\n token={token}\n getToken={getToken}\n appId={appId}\n initialThreadId={initialThreadId}\n includePullRequests={includePullRequests}\n snapshotCache={snapshotCache}\n >\n {children}\n </StatewireThreadListState>\n </QueryClientProvider>\n );\n}\n\n/** How long after a thread's first message the title poll starts (exported for tests). */\nexport const TITLE_POLL_DELAY_MS = 5000;\nconst TITLE_POLL_INTERVAL_MS = 2000;\nconst TITLE_POLL_MAX_DURATION_MS = 60_000;\n\n/**\n * Fallback for hosts without a live conversation index (`titleSource: 'poll'`,\n * i.e. no signed-in principal): refreshes the thread list until a\n * freshly-started thread's server-generated title appears. Idle while the\n * index carries titles. Mount inside the statewire runtime scope (needs aui\n * state).\n *\n * The thread is read from the statewire scope, not the list: the scope\n * publishes the id together with the client it belongs to, so the messages\n * observed here are always the named thread's (the list's selection moves\n * one commit ahead of the client during a switch).\n */\nexport function StatewireThreadTitlePoller(): null {\n const list = useAthenaStatewireThreadList();\n const activeThreadId = useAthenaStatewireThreadId();\n const hasMessages = useAuiState((s) => (s.optional.thread?.messages.length ?? 0) > 0);\n\n const titleSource = list?.titleSource ?? 'poll';\n const entry = list?.threads.find((thread) => thread.id === activeThreadId);\n const title = entry?.title?.trim() ?? '';\n const hasTitle = title.length > 0 && !isSerializedContentPartsTitle(title);\n\n // The poller stays mounted across thread switches, so the visit is tracked\n // by hand: one poll per visit — no restart when the visited thread's\n // messages or title flip underneath it — and a re-selected thread polls\n // again, as it did when every switch remounted the poller. The record is\n // replaced whenever the attached thread changes, whether or not a poll\n // started for it, so a visit to a thread that needs no poll can never make\n // the next visit to a previous thread look already polled.\n const visitRef = useRef<{ threadId: string; polled: boolean } | null>(null);\n const refreshRef = useRef(list?.refresh);\n refreshRef.current = list?.refresh;\n\n useEffect(() => {\n if (visitRef.current?.threadId !== activeThreadId) {\n visitRef.current = { threadId: activeThreadId, polled: false };\n }\n const visit = visitRef.current;\n if (!hasMessages || hasTitle || titleSource === 'index') return;\n if (visit.polled) return;\n visit.polled = true;\n\n let intervalId: ReturnType<typeof setInterval> | null = null;\n const startId = setTimeout(() => {\n intervalId = setInterval(() => refreshRef.current?.(), TITLE_POLL_INTERVAL_MS);\n }, TITLE_POLL_DELAY_MS);\n const stopId = setTimeout(() => {\n if (intervalId !== null) clearInterval(intervalId);\n }, TITLE_POLL_MAX_DURATION_MS);\n\n return () => {\n clearTimeout(startId);\n clearTimeout(stopId);\n if (intervalId !== null) clearInterval(intervalId);\n };\n }, [activeThreadId, hasMessages, hasTitle, titleSource]);\n\n return null;\n}\n"],"names":["createContext","useContext","normalizeThreadTitle","deriveConversationAttention","useState","mintThreadId","useRef","AthenaAuthContext","useCallback","resolveStatewireAuthToken","useMemo","createRestConversationListFetcher","useConversationList","resolveStatewireAuthHeaders","credentialShape","sameCredentialShape","useQuery","fetchAccountIdentity","useConversationIndex","conversationIndexUrlFromStatewireUrl","summaryFromConversationIndexEntry","useThreadFavorite","useThreadRename","title","useThreadArchive","useEffect","withTitleOverrides","withFavoriteOverrides","_a","withTitleOverride","withFavoriteOverride","createThreadPrefetcher","getThreadState","jsx","QueryClient","QueryClientProvider","useAthenaStatewireThreadId","useAuiState","isSerializedContentPartsTitle"],"mappings":"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"}
@@ -1,23 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import "../packages/agent-runtime/src/generated/runconfig-contract.js";
3
- import { useContext, createContext, useState, useRef, useCallback, useMemo, useEffect } from "react";
4
- import { useConversationIndex, conversationIndexUrlFromStatewireUrl } from "../packages/agent-runtime/src/conversation-index.js";
5
- import { deriveConversationAttention, summaryFromConversationIndexEntry } from "../packages/agent-runtime/src/conversation-list.js";
6
- import { useConversationList } from "../packages/agent-runtime/src/use-conversation-list.js";
7
- import "../packages/agent-runtime/src/statewire-state.js";
8
- import "../packages/agent-runtime/src/messages.js";
9
- import "statewire";
10
- import "@assistant-ui/store";
11
- import "../packages/agent-runtime/src/quota-safe-local-storage-session.js";
12
- import "../packages/agent-runtime/src/statewire-suspended.js";
13
- import "@assistant-ui/tap";
14
- import "../packages/agent-runtime/src/statewire-attach-observer.js";
15
- import "../packages/agent-runtime/src/thread-status.js";
16
- import "@assistant-ui/react-statewire";
17
- import "@assistant-ui/core";
18
- import "../packages/agent-runtime/src/thread-handoff.js";
19
2
  import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
20
3
  import { useAuiState } from "@assistant-ui/react";
4
+ import { useContext, createContext, useState, useRef, useCallback, useMemo, useEffect } from "react";
21
5
  import { AthenaAuthContext } from "../auth/AthenaAuthContext.js";
22
6
  import { resolveStatewireAuthToken, resolveStatewireAuthHeaders } from "../runtime/statewire-auth-headers.js";
23
7
  import { fetchAccountIdentity, getThreadState } from "./api.js";
@@ -30,6 +14,9 @@ import { normalizeThreadTitle, isSerializedContentPartsTitle } from "./title.js"
30
14
  import { useThreadArchive } from "./use-thread-archive.js";
31
15
  import { useThreadFavorite, withFavoriteOverrides, withFavoriteOverride } from "./use-thread-favorite.js";
32
16
  import { useThreadRename, withTitleOverrides, withTitleOverride } from "./use-thread-rename.js";
17
+ import { deriveConversationAttention, summaryFromConversationIndexEntry } from "../packages/agent-runtime/src/conversation-list.js";
18
+ import { useConversationList } from "../packages/agent-runtime/src/use-conversation-list.js";
19
+ import { useConversationIndex, conversationIndexUrlFromStatewireUrl } from "../packages/agent-runtime/src/conversation-index.js";
33
20
  const AthenaStatewireThreadListContext = createContext(null);
34
21
  function useAthenaStatewireThreadList() {
35
22
  return useContext(AthenaStatewireThreadListContext);