@stigmer/react 0.3.3 → 0.4.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 (442) hide show
  1. package/billing/AutoRechargeCard.d.ts +38 -0
  2. package/billing/AutoRechargeCard.d.ts.map +1 -0
  3. package/billing/AutoRechargeCard.js +90 -0
  4. package/billing/AutoRechargeCard.js.map +1 -0
  5. package/billing/BillingSection.d.ts +32 -0
  6. package/billing/BillingSection.d.ts.map +1 -0
  7. package/billing/BillingSection.js +81 -0
  8. package/billing/BillingSection.js.map +1 -0
  9. package/billing/CreditBalanceCard.d.ts +25 -0
  10. package/billing/CreditBalanceCard.d.ts.map +1 -0
  11. package/billing/CreditBalanceCard.js +28 -0
  12. package/billing/CreditBalanceCard.js.map +1 -0
  13. package/billing/CreditLedgerTable.d.ts +22 -0
  14. package/billing/CreditLedgerTable.d.ts.map +1 -0
  15. package/billing/CreditLedgerTable.js +75 -0
  16. package/billing/CreditLedgerTable.js.map +1 -0
  17. package/billing/CreditPackGrid.d.ts +31 -0
  18. package/billing/CreditPackGrid.d.ts.map +1 -0
  19. package/billing/CreditPackGrid.js +35 -0
  20. package/billing/CreditPackGrid.js.map +1 -0
  21. package/billing/LowBalanceBanner.d.ts +26 -0
  22. package/billing/LowBalanceBanner.d.ts.map +1 -0
  23. package/billing/LowBalanceBanner.js +33 -0
  24. package/billing/LowBalanceBanner.js.map +1 -0
  25. package/billing/PaymentMethodCard.d.ts +35 -0
  26. package/billing/PaymentMethodCard.d.ts.map +1 -0
  27. package/billing/PaymentMethodCard.js +48 -0
  28. package/billing/PaymentMethodCard.js.map +1 -0
  29. package/billing/credit-packs.d.ts +25 -0
  30. package/billing/credit-packs.d.ts.map +1 -0
  31. package/billing/credit-packs.js +39 -0
  32. package/billing/credit-packs.js.map +1 -0
  33. package/billing/format.d.ts +39 -0
  34. package/billing/format.d.ts.map +1 -0
  35. package/billing/format.js +90 -0
  36. package/billing/format.js.map +1 -0
  37. package/billing/index.d.ts +32 -0
  38. package/billing/index.d.ts.map +1 -0
  39. package/billing/index.js +21 -0
  40. package/billing/index.js.map +1 -0
  41. package/billing/useBillingAccount.d.ts +40 -0
  42. package/billing/useBillingAccount.d.ts.map +1 -0
  43. package/billing/useBillingAccount.js +35 -0
  44. package/billing/useBillingAccount.js.map +1 -0
  45. package/billing/useBillingUsageReport.d.ts +42 -0
  46. package/billing/useBillingUsageReport.d.ts.map +1 -0
  47. package/billing/useBillingUsageReport.js +43 -0
  48. package/billing/useBillingUsageReport.js.map +1 -0
  49. package/billing/useCreateBillingPortalSession.d.ts +35 -0
  50. package/billing/useCreateBillingPortalSession.d.ts.map +1 -0
  51. package/billing/useCreateBillingPortalSession.js +50 -0
  52. package/billing/useCreateBillingPortalSession.js.map +1 -0
  53. package/billing/useCreateCheckoutSession.d.ts +54 -0
  54. package/billing/useCreateCheckoutSession.d.ts.map +1 -0
  55. package/billing/useCreateCheckoutSession.js +58 -0
  56. package/billing/useCreateCheckoutSession.js.map +1 -0
  57. package/billing/useCreditLedger.d.ts +48 -0
  58. package/billing/useCreditLedger.d.ts.map +1 -0
  59. package/billing/useCreditLedger.js +39 -0
  60. package/billing/useCreditLedger.js.map +1 -0
  61. package/billing/useCustomerModelPricing.d.ts +41 -0
  62. package/billing/useCustomerModelPricing.d.ts.map +1 -0
  63. package/billing/useCustomerModelPricing.js +37 -0
  64. package/billing/useCustomerModelPricing.js.map +1 -0
  65. package/billing/useSetAutoRechargeConfig.d.ts +50 -0
  66. package/billing/useSetAutoRechargeConfig.d.ts.map +1 -0
  67. package/billing/useSetAutoRechargeConfig.js +53 -0
  68. package/billing/useSetAutoRechargeConfig.js.map +1 -0
  69. package/composer/ComposerToolbar.js +1 -1
  70. package/composer/ComposerToolbar.js.map +1 -1
  71. package/composer/SessionComposer.d.ts +1 -1
  72. package/composer/SessionComposer.d.ts.map +1 -1
  73. package/composer/SessionComposer.js +19 -4
  74. package/composer/SessionComposer.js.map +1 -1
  75. package/composer/__tests__/SessionComposer-memo.test.d.ts +2 -0
  76. package/composer/__tests__/SessionComposer-memo.test.d.ts.map +1 -0
  77. package/composer/__tests__/SessionComposer-memo.test.js +23 -0
  78. package/composer/__tests__/SessionComposer-memo.test.js.map +1 -0
  79. package/execution/ApprovalCard.d.ts +5 -1
  80. package/execution/ApprovalCard.d.ts.map +1 -1
  81. package/execution/ApprovalCard.js +7 -3
  82. package/execution/ApprovalCard.js.map +1 -1
  83. package/execution/ExecutionPhaseBadge.d.ts +1 -1
  84. package/execution/ExecutionPhaseBadge.d.ts.map +1 -1
  85. package/execution/ExecutionPhaseBadge.js +3 -2
  86. package/execution/ExecutionPhaseBadge.js.map +1 -1
  87. package/execution/MessageEntry.d.ts +7 -3
  88. package/execution/MessageEntry.d.ts.map +1 -1
  89. package/execution/MessageEntry.js +19 -8
  90. package/execution/MessageEntry.js.map +1 -1
  91. package/execution/MessageThread.d.ts +84 -3
  92. package/execution/MessageThread.d.ts.map +1 -1
  93. package/execution/MessageThread.js +113 -65
  94. package/execution/MessageThread.js.map +1 -1
  95. package/execution/SetupProgress.d.ts +1 -1
  96. package/execution/SetupProgress.d.ts.map +1 -1
  97. package/execution/SetupProgress.js +3 -3
  98. package/execution/SetupProgress.js.map +1 -1
  99. package/execution/SubAgentSection.d.ts +5 -1
  100. package/execution/SubAgentSection.d.ts.map +1 -1
  101. package/execution/SubAgentSection.js +13 -7
  102. package/execution/SubAgentSection.js.map +1 -1
  103. package/execution/ThreadSkeleton.d.ts +22 -0
  104. package/execution/ThreadSkeleton.d.ts.map +1 -0
  105. package/execution/ThreadSkeleton.js +26 -0
  106. package/execution/ThreadSkeleton.js.map +1 -0
  107. package/execution/ToolCallGroup.d.ts +16 -1
  108. package/execution/ToolCallGroup.d.ts.map +1 -1
  109. package/execution/ToolCallGroup.js +31 -3
  110. package/execution/ToolCallGroup.js.map +1 -1
  111. package/execution/UsageWidget.d.ts +1 -1
  112. package/execution/__tests__/message-entry.test.d.ts +2 -0
  113. package/execution/__tests__/message-entry.test.d.ts.map +1 -0
  114. package/execution/__tests__/message-entry.test.js +178 -0
  115. package/execution/__tests__/message-entry.test.js.map +1 -0
  116. package/execution/__tests__/thread-keys.test.d.ts +2 -0
  117. package/execution/__tests__/thread-keys.test.d.ts.map +1 -0
  118. package/execution/__tests__/thread-keys.test.js +289 -0
  119. package/execution/__tests__/thread-keys.test.js.map +1 -0
  120. package/execution/__tests__/thread-memoization.test.d.ts +2 -0
  121. package/execution/__tests__/thread-memoization.test.d.ts.map +1 -0
  122. package/execution/__tests__/thread-memoization.test.js +262 -0
  123. package/execution/__tests__/thread-memoization.test.js.map +1 -0
  124. package/execution/__tests__/thread-skeleton.test.d.ts +2 -0
  125. package/execution/__tests__/thread-skeleton.test.d.ts.map +1 -0
  126. package/execution/__tests__/thread-skeleton.test.js +35 -0
  127. package/execution/__tests__/thread-skeleton.test.js.map +1 -0
  128. package/execution/__tests__/useExecutionStream.test.js +73 -10
  129. package/execution/__tests__/useExecutionStream.test.js.map +1 -1
  130. package/execution/__tests__/useSessionVariables-stability.test.d.ts +2 -0
  131. package/execution/__tests__/useSessionVariables-stability.test.d.ts.map +1 -0
  132. package/execution/__tests__/useSessionVariables-stability.test.js +69 -0
  133. package/execution/__tests__/useSessionVariables-stability.test.js.map +1 -0
  134. package/execution/__tests__/virtualized-thread.test.d.ts +2 -0
  135. package/execution/__tests__/virtualized-thread.test.d.ts.map +1 -0
  136. package/execution/__tests__/virtualized-thread.test.js +274 -0
  137. package/execution/__tests__/virtualized-thread.test.js.map +1 -0
  138. package/execution/index.d.ts +2 -0
  139. package/execution/index.d.ts.map +1 -1
  140. package/execution/index.js +1 -0
  141. package/execution/index.js.map +1 -1
  142. package/execution/useExecutionStream.d.ts +35 -10
  143. package/execution/useExecutionStream.d.ts.map +1 -1
  144. package/execution/useExecutionStream.js +79 -40
  145. package/execution/useExecutionStream.js.map +1 -1
  146. package/execution/useSessionVariables.d.ts.map +1 -1
  147. package/execution/useSessionVariables.js +4 -3
  148. package/execution/useSessionVariables.js.map +1 -1
  149. package/github/useGitHubConnection.d.ts.map +1 -1
  150. package/github/useGitHubConnection.js +5 -4
  151. package/github/useGitHubConnection.js.map +1 -1
  152. package/identity-account/index.d.ts +2 -0
  153. package/identity-account/index.d.ts.map +1 -0
  154. package/identity-account/index.js +2 -0
  155. package/identity-account/index.js.map +1 -0
  156. package/identity-account/useIdentityAccountGate.d.ts +81 -0
  157. package/identity-account/useIdentityAccountGate.d.ts.map +1 -0
  158. package/identity-account/useIdentityAccountGate.js +100 -0
  159. package/identity-account/useIdentityAccountGate.js.map +1 -0
  160. package/index.d.ts +10 -4
  161. package/index.d.ts.map +1 -1
  162. package/index.js +8 -2
  163. package/index.js.map +1 -1
  164. package/internal/FetchCacheProvider.d.ts +44 -0
  165. package/internal/FetchCacheProvider.d.ts.map +1 -0
  166. package/internal/FetchCacheProvider.js +61 -0
  167. package/internal/FetchCacheProvider.js.map +1 -0
  168. package/internal/JumpToLatestButton.d.ts +14 -0
  169. package/internal/JumpToLatestButton.d.ts.map +1 -0
  170. package/internal/JumpToLatestButton.js +19 -0
  171. package/internal/JumpToLatestButton.js.map +1 -0
  172. package/internal/ThreadItemWrapper.d.ts +20 -0
  173. package/internal/ThreadItemWrapper.d.ts.map +1 -0
  174. package/internal/ThreadItemWrapper.js +44 -0
  175. package/internal/ThreadItemWrapper.js.map +1 -0
  176. package/internal/VirtualizedThread.d.ts +25 -0
  177. package/internal/VirtualizedThread.d.ts.map +1 -0
  178. package/internal/VirtualizedThread.js +58 -0
  179. package/internal/VirtualizedThread.js.map +1 -0
  180. package/internal/__tests__/fetch-cache.test.d.ts +2 -0
  181. package/internal/__tests__/fetch-cache.test.d.ts.map +1 -0
  182. package/internal/__tests__/fetch-cache.test.js +182 -0
  183. package/internal/__tests__/fetch-cache.test.js.map +1 -0
  184. package/internal/__tests__/stream-controller.test.d.ts +2 -0
  185. package/internal/__tests__/stream-controller.test.d.ts.map +1 -0
  186. package/internal/__tests__/stream-controller.test.js +294 -0
  187. package/internal/__tests__/stream-controller.test.js.map +1 -0
  188. package/internal/__tests__/thread-animation.test.d.ts +2 -0
  189. package/internal/__tests__/thread-animation.test.d.ts.map +1 -0
  190. package/internal/__tests__/thread-animation.test.js +79 -0
  191. package/internal/__tests__/thread-animation.test.js.map +1 -0
  192. package/internal/__tests__/useAutoScroll.test.d.ts +2 -0
  193. package/internal/__tests__/useAutoScroll.test.d.ts.map +1 -0
  194. package/internal/__tests__/useAutoScroll.test.js +188 -0
  195. package/internal/__tests__/useAutoScroll.test.js.map +1 -0
  196. package/internal/__tests__/useFetch-cache.test.d.ts +2 -0
  197. package/internal/__tests__/useFetch-cache.test.d.ts.map +1 -0
  198. package/internal/__tests__/useFetch-cache.test.js +137 -0
  199. package/internal/__tests__/useFetch-cache.test.js.map +1 -0
  200. package/internal/dev/__tests__/use-key-stability.test.d.ts +2 -0
  201. package/internal/dev/__tests__/use-key-stability.test.d.ts.map +1 -0
  202. package/internal/dev/__tests__/use-key-stability.test.js +72 -0
  203. package/internal/dev/__tests__/use-key-stability.test.js.map +1 -0
  204. package/internal/dev/__tests__/use-render-tracer.test.d.ts +2 -0
  205. package/internal/dev/__tests__/use-render-tracer.test.d.ts.map +1 -0
  206. package/internal/dev/__tests__/use-render-tracer.test.js +55 -0
  207. package/internal/dev/__tests__/use-render-tracer.test.js.map +1 -0
  208. package/internal/dev/dom-counter.d.ts +14 -0
  209. package/internal/dev/dom-counter.d.ts.map +1 -0
  210. package/internal/dev/dom-counter.js +39 -0
  211. package/internal/dev/dom-counter.js.map +1 -0
  212. package/internal/dev/index.d.ts +6 -0
  213. package/internal/dev/index.d.ts.map +1 -0
  214. package/internal/dev/index.js +6 -0
  215. package/internal/dev/index.js.map +1 -0
  216. package/internal/dev/profiler-wrapper.d.ts +16 -0
  217. package/internal/dev/profiler-wrapper.d.ts.map +1 -0
  218. package/internal/dev/profiler-wrapper.js +31 -0
  219. package/internal/dev/profiler-wrapper.js.map +1 -0
  220. package/internal/dev/use-key-stability.d.ts +22 -0
  221. package/internal/dev/use-key-stability.d.ts.map +1 -0
  222. package/internal/dev/use-key-stability.js +67 -0
  223. package/internal/dev/use-key-stability.js.map +1 -0
  224. package/internal/dev/use-render-tracer.d.ts +13 -0
  225. package/internal/dev/use-render-tracer.d.ts.map +1 -0
  226. package/internal/dev/use-render-tracer.js +57 -0
  227. package/internal/dev/use-render-tracer.js.map +1 -0
  228. package/internal/dev/use-stream-rate.d.ts +23 -0
  229. package/internal/dev/use-stream-rate.d.ts.map +1 -0
  230. package/internal/dev/use-stream-rate.js +94 -0
  231. package/internal/dev/use-stream-rate.js.map +1 -0
  232. package/internal/fetch-cache.d.ts +72 -0
  233. package/internal/fetch-cache.d.ts.map +1 -0
  234. package/internal/fetch-cache.js +118 -0
  235. package/internal/fetch-cache.js.map +1 -0
  236. package/internal/store/__tests__/conversation-store.test.d.ts +2 -0
  237. package/internal/store/__tests__/conversation-store.test.d.ts.map +1 -0
  238. package/internal/store/__tests__/conversation-store.test.js +200 -0
  239. package/internal/store/__tests__/conversation-store.test.js.map +1 -0
  240. package/internal/store/__tests__/structural-share.test.d.ts +2 -0
  241. package/internal/store/__tests__/structural-share.test.d.ts.map +1 -0
  242. package/internal/store/__tests__/structural-share.test.js +368 -0
  243. package/internal/store/__tests__/structural-share.test.js.map +1 -0
  244. package/internal/store/conversation-store.d.ts +62 -0
  245. package/internal/store/conversation-store.d.ts.map +1 -0
  246. package/internal/store/conversation-store.js +95 -0
  247. package/internal/store/conversation-store.js.map +1 -0
  248. package/internal/store/index.d.ts +31 -0
  249. package/internal/store/index.d.ts.map +1 -0
  250. package/internal/store/index.js +54 -0
  251. package/internal/store/index.js.map +1 -0
  252. package/internal/store/structural-share.d.ts +13 -0
  253. package/internal/store/structural-share.d.ts.map +1 -0
  254. package/internal/store/structural-share.js +240 -0
  255. package/internal/store/structural-share.js.map +1 -0
  256. package/internal/stream-controller.d.ts +85 -0
  257. package/internal/stream-controller.d.ts.map +1 -0
  258. package/internal/stream-controller.js +146 -0
  259. package/internal/stream-controller.js.map +1 -0
  260. package/internal/useAutoScroll.d.ts +32 -0
  261. package/internal/useAutoScroll.d.ts.map +1 -0
  262. package/internal/useAutoScroll.js +97 -0
  263. package/internal/useAutoScroll.js.map +1 -0
  264. package/internal/useFetch.d.ts +14 -0
  265. package/internal/useFetch.d.ts.map +1 -1
  266. package/internal/useFetch.js +32 -2
  267. package/internal/useFetch.js.map +1 -1
  268. package/package.json +7 -5
  269. package/session/__tests__/useNewSessionFlow.test.js +16 -0
  270. package/session/__tests__/useNewSessionFlow.test.js.map +1 -1
  271. package/session/__tests__/usePersistedModel.test.d.ts +2 -0
  272. package/session/__tests__/usePersistedModel.test.d.ts.map +1 -0
  273. package/session/__tests__/usePersistedModel.test.js +82 -0
  274. package/session/__tests__/usePersistedModel.test.js.map +1 -0
  275. package/session/__tests__/useSession.test.d.ts +2 -0
  276. package/session/__tests__/useSession.test.d.ts.map +1 -0
  277. package/session/__tests__/useSession.test.js +130 -0
  278. package/session/__tests__/useSession.test.js.map +1 -0
  279. package/session/useNewSessionFlow.d.ts.map +1 -1
  280. package/session/useNewSessionFlow.js +12 -6
  281. package/session/useNewSessionFlow.js.map +1 -1
  282. package/session/usePersistedModel.d.ts +3 -0
  283. package/session/usePersistedModel.d.ts.map +1 -1
  284. package/session/usePersistedModel.js +27 -2
  285. package/session/usePersistedModel.js.map +1 -1
  286. package/session/useSession.d.ts.map +1 -1
  287. package/session/useSession.js +1 -1
  288. package/session/useSession.js.map +1 -1
  289. package/session/useSessionConversation.d.ts.map +1 -1
  290. package/session/useSessionConversation.js +9 -1
  291. package/session/useSessionConversation.js.map +1 -1
  292. package/session/useSessionExecutions.d.ts.map +1 -1
  293. package/session/useSessionExecutions.js +1 -1
  294. package/session/useSessionExecutions.js.map +1 -1
  295. package/session/useSessionPageFlow.js +1 -1
  296. package/session/useSessionPageFlow.js.map +1 -1
  297. package/session/useSessionUsage.d.ts +24 -40
  298. package/session/useSessionUsage.d.ts.map +1 -1
  299. package/session/useSessionUsage.js +64 -97
  300. package/session/useSessionUsage.js.map +1 -1
  301. package/settings/BillingSection.d.ts +3 -0
  302. package/settings/BillingSection.d.ts.map +1 -0
  303. package/settings/BillingSection.js +3 -0
  304. package/settings/BillingSection.js.map +1 -0
  305. package/settings/index.d.ts +2 -0
  306. package/settings/index.d.ts.map +1 -1
  307. package/settings/index.js +1 -0
  308. package/settings/index.js.map +1 -1
  309. package/settings/settings-nav.js +1 -1
  310. package/settings/settings-nav.js.map +1 -1
  311. package/src/billing/AutoRechargeCard.tsx +274 -0
  312. package/src/billing/BillingSection.tsx +255 -0
  313. package/src/billing/CreditBalanceCard.tsx +81 -0
  314. package/src/billing/CreditLedgerTable.tsx +281 -0
  315. package/src/billing/CreditPackGrid.tsx +132 -0
  316. package/src/billing/LowBalanceBanner.tsx +67 -0
  317. package/src/billing/PaymentMethodCard.tsx +133 -0
  318. package/src/billing/credit-packs.ts +54 -0
  319. package/src/billing/format.ts +97 -0
  320. package/src/billing/index.ts +51 -0
  321. package/src/billing/useBillingAccount.ts +64 -0
  322. package/src/billing/useBillingUsageReport.ts +73 -0
  323. package/src/billing/useCreateBillingPortalSession.ts +76 -0
  324. package/src/billing/useCreateCheckoutSession.ts +101 -0
  325. package/src/billing/useCreditLedger.ts +79 -0
  326. package/src/billing/useCustomerModelPricing.ts +67 -0
  327. package/src/billing/useSetAutoRechargeConfig.ts +90 -0
  328. package/src/composer/ComposerToolbar.tsx +1 -1
  329. package/src/composer/SessionComposer.tsx +22 -4
  330. package/src/composer/__tests__/SessionComposer-memo.test.ts +26 -0
  331. package/src/execution/ApprovalCard.tsx +7 -3
  332. package/src/execution/ExecutionPhaseBadge.tsx +3 -2
  333. package/src/execution/MessageEntry.tsx +27 -16
  334. package/src/execution/MessageThread.tsx +308 -131
  335. package/src/execution/SetupProgress.tsx +3 -3
  336. package/src/execution/SubAgentSection.tsx +14 -6
  337. package/src/execution/ThreadSkeleton.tsx +73 -0
  338. package/src/execution/ToolCallGroup.tsx +36 -3
  339. package/src/execution/UsageWidget.tsx +1 -1
  340. package/src/execution/__tests__/message-entry.test.tsx +236 -0
  341. package/src/execution/__tests__/thread-keys.test.ts +409 -0
  342. package/src/execution/__tests__/thread-memoization.test.ts +320 -0
  343. package/src/execution/__tests__/thread-skeleton.test.tsx +44 -0
  344. package/src/execution/__tests__/useExecutionStream.test.tsx +109 -12
  345. package/src/execution/__tests__/useSessionVariables-stability.test.ts +95 -0
  346. package/src/execution/__tests__/virtualized-thread.test.tsx +401 -0
  347. package/src/execution/index.ts +3 -0
  348. package/src/execution/useExecutionStream.ts +123 -48
  349. package/src/execution/useSessionVariables.ts +17 -12
  350. package/src/github/useGitHubConnection.ts +18 -13
  351. package/src/identity-account/index.ts +5 -0
  352. package/src/identity-account/useIdentityAccountGate.ts +163 -0
  353. package/src/index.ts +73 -0
  354. package/src/internal/FetchCacheProvider.tsx +74 -0
  355. package/src/internal/JumpToLatestButton.tsx +61 -0
  356. package/src/internal/ThreadItemWrapper.tsx +65 -0
  357. package/src/internal/VirtualizedThread.tsx +162 -0
  358. package/src/internal/__tests__/fetch-cache.test.ts +230 -0
  359. package/src/internal/__tests__/stream-controller.test.ts +395 -0
  360. package/src/internal/__tests__/thread-animation.test.tsx +121 -0
  361. package/src/internal/__tests__/useAutoScroll.test.tsx +261 -0
  362. package/src/internal/__tests__/useFetch-cache.test.ts +214 -0
  363. package/src/internal/dev/__tests__/use-key-stability.test.ts +124 -0
  364. package/src/internal/dev/__tests__/use-render-tracer.test.ts +78 -0
  365. package/src/internal/dev/dom-counter.ts +47 -0
  366. package/src/internal/dev/index.ts +5 -0
  367. package/src/internal/dev/profiler-wrapper.tsx +52 -0
  368. package/src/internal/dev/use-key-stability.ts +86 -0
  369. package/src/internal/dev/use-render-tracer.ts +70 -0
  370. package/src/internal/dev/use-stream-rate.ts +138 -0
  371. package/src/internal/fetch-cache.ts +155 -0
  372. package/src/internal/store/__tests__/conversation-store.test.ts +257 -0
  373. package/src/internal/store/__tests__/structural-share.test.ts +454 -0
  374. package/src/internal/store/conversation-store.ts +128 -0
  375. package/src/internal/store/index.ts +68 -0
  376. package/src/internal/store/structural-share.ts +318 -0
  377. package/src/internal/stream-controller.ts +201 -0
  378. package/src/internal/useAutoScroll.ts +121 -0
  379. package/src/internal/useFetch.ts +51 -2
  380. package/src/session/__tests__/useNewSessionFlow.test.tsx +22 -0
  381. package/src/session/__tests__/usePersistedModel.test.tsx +117 -0
  382. package/src/session/__tests__/useSession.test.tsx +187 -0
  383. package/src/session/useNewSessionFlow.ts +12 -6
  384. package/src/session/usePersistedModel.ts +28 -2
  385. package/src/session/useSession.ts +1 -0
  386. package/src/session/useSessionConversation.ts +11 -2
  387. package/src/session/useSessionExecutions.ts +1 -0
  388. package/src/session/useSessionPageFlow.ts +1 -1
  389. package/src/session/useSessionUsage.ts +102 -123
  390. package/src/settings/BillingSection.tsx +4 -0
  391. package/src/settings/index.ts +2 -0
  392. package/src/settings/settings-nav.ts +1 -1
  393. package/src/styles.css +31 -0
  394. package/src/usage/AgentBreakdownList.tsx +147 -0
  395. package/src/usage/CreditRunwayIndicator.tsx +71 -0
  396. package/src/usage/ExportButton.tsx +115 -0
  397. package/src/usage/HarnessSplitCard.tsx +103 -0
  398. package/src/usage/OrgUsagePanel.tsx +109 -45
  399. package/src/usage/index.ts +15 -0
  400. package/src/usage/useExportCSV.ts +115 -0
  401. package/src/usage/useOrgUsageReport.ts +2 -1
  402. package/src/workspace/__tests__/useWorkspaceEntries-stability.test.ts +76 -0
  403. package/src/workspace/useWorkspaceEntries.ts +16 -11
  404. package/styles.css +1 -1
  405. package/usage/AgentBreakdownList.d.ts +21 -0
  406. package/usage/AgentBreakdownList.d.ts.map +1 -0
  407. package/usage/AgentBreakdownList.js +44 -0
  408. package/usage/AgentBreakdownList.js.map +1 -0
  409. package/usage/CreditRunwayIndicator.d.ts +21 -0
  410. package/usage/CreditRunwayIndicator.d.ts.map +1 -0
  411. package/usage/CreditRunwayIndicator.js +38 -0
  412. package/usage/CreditRunwayIndicator.js.map +1 -0
  413. package/usage/ExportButton.d.ts +20 -0
  414. package/usage/ExportButton.d.ts.map +1 -0
  415. package/usage/ExportButton.js +36 -0
  416. package/usage/ExportButton.js.map +1 -0
  417. package/usage/HarnessSplitCard.d.ts +17 -0
  418. package/usage/HarnessSplitCard.d.ts.map +1 -0
  419. package/usage/HarnessSplitCard.js +38 -0
  420. package/usage/HarnessSplitCard.js.map +1 -0
  421. package/usage/OrgUsagePanel.d.ts.map +1 -1
  422. package/usage/OrgUsagePanel.js +30 -22
  423. package/usage/OrgUsagePanel.js.map +1 -1
  424. package/usage/index.d.ts +10 -0
  425. package/usage/index.d.ts.map +1 -1
  426. package/usage/index.js +5 -0
  427. package/usage/index.js.map +1 -1
  428. package/usage/useExportCSV.d.ts +23 -0
  429. package/usage/useExportCSV.d.ts.map +1 -0
  430. package/usage/useExportCSV.js +81 -0
  431. package/usage/useExportCSV.js.map +1 -0
  432. package/usage/useOrgUsageReport.d.ts +2 -1
  433. package/usage/useOrgUsageReport.d.ts.map +1 -1
  434. package/usage/useOrgUsageReport.js +2 -1
  435. package/usage/useOrgUsageReport.js.map +1 -1
  436. package/workspace/__tests__/useWorkspaceEntries-stability.test.d.ts +2 -0
  437. package/workspace/__tests__/useWorkspaceEntries-stability.test.d.ts.map +1 -0
  438. package/workspace/__tests__/useWorkspaceEntries-stability.test.js +57 -0
  439. package/workspace/__tests__/useWorkspaceEntries-stability.test.js.map +1 -0
  440. package/workspace/useWorkspaceEntries.d.ts.map +1 -1
  441. package/workspace/useWorkspaceEntries.js +5 -4
  442. package/workspace/useWorkspaceEntries.js.map +1 -1
@@ -0,0 +1,454 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { create } from "@bufbuild/protobuf";
3
+ import {
4
+ AgentExecutionSchema,
5
+ AgentExecutionStatusSchema,
6
+ type AgentExecution,
7
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
8
+ import { AgentExecutionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
9
+ import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
10
+ import {
11
+ AgentMessageSchema,
12
+ ToolCallSchema,
13
+ type AgentMessage,
14
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
15
+ import { SubAgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
16
+ import { PendingApprovalSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
17
+ import {
18
+ ExecutionPhase,
19
+ MessageType,
20
+ ToolCallStatus,
21
+ SubAgentStatus,
22
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
23
+ import { structuralShare } from "../structural-share";
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Helpers
27
+ // ---------------------------------------------------------------------------
28
+
29
+ function msg(
30
+ type: MessageType,
31
+ content: string,
32
+ opts?: {
33
+ toolCalls?: ReturnType<typeof tc>[];
34
+ isStreaming?: boolean;
35
+ timestamp?: string;
36
+ },
37
+ ): AgentMessage {
38
+ const m = create(AgentMessageSchema);
39
+ m.type = type;
40
+ m.content = content;
41
+ if (opts?.toolCalls) m.toolCalls = opts.toolCalls;
42
+ if (opts?.isStreaming) m.isStreaming = true;
43
+ if (opts?.timestamp) m.timestamp = opts.timestamp;
44
+ return m;
45
+ }
46
+
47
+ function tc(
48
+ id: string,
49
+ name: string,
50
+ opts?: { status?: ToolCallStatus; result?: string; isStreaming?: boolean },
51
+ ) {
52
+ const t = create(ToolCallSchema);
53
+ t.id = id;
54
+ t.name = name;
55
+ t.status = opts?.status ?? ToolCallStatus.TOOL_CALL_COMPLETED;
56
+ if (opts?.result) t.result = opts.result;
57
+ if (opts?.isStreaming) t.isStreaming = true;
58
+ return t;
59
+ }
60
+
61
+ function subAgent(
62
+ id: string,
63
+ opts?: {
64
+ status?: SubAgentStatus;
65
+ messages?: AgentMessage[];
66
+ output?: string;
67
+ },
68
+ ) {
69
+ const sa = create(SubAgentExecutionSchema);
70
+ sa.id = id;
71
+ sa.name = `agent-${id}`;
72
+ sa.status = opts?.status ?? SubAgentStatus.SUB_AGENT_IN_PROGRESS;
73
+ if (opts?.messages) sa.messages = opts.messages;
74
+ if (opts?.output) sa.output = opts.output;
75
+ return sa;
76
+ }
77
+
78
+ function approval(toolCallId: string, toolName: string) {
79
+ const a = create(PendingApprovalSchema);
80
+ a.toolCallId = toolCallId;
81
+ a.toolName = toolName;
82
+ return a;
83
+ }
84
+
85
+ function exec(opts: {
86
+ id?: string;
87
+ phase?: ExecutionPhase;
88
+ messages?: AgentMessage[];
89
+ subAgents?: ReturnType<typeof subAgent>[];
90
+ approvals?: ReturnType<typeof approval>[];
91
+ }): AgentExecution {
92
+ const e = create(AgentExecutionSchema);
93
+ const meta = create(ApiResourceMetadataSchema);
94
+ meta.id = opts.id ?? "exec-1";
95
+ e.metadata = meta;
96
+ const spec = create(AgentExecutionSpecSchema);
97
+ e.spec = spec;
98
+ const status = create(AgentExecutionStatusSchema);
99
+ status.phase = opts.phase ?? ExecutionPhase.EXECUTION_IN_PROGRESS;
100
+ if (opts.messages) status.messages = opts.messages;
101
+ if (opts.subAgents) status.subAgentExecutions = opts.subAgents;
102
+ if (opts.approvals) status.pendingApprovals = opts.approvals;
103
+ e.status = status;
104
+ return e;
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Tests
109
+ // ---------------------------------------------------------------------------
110
+
111
+ describe("structuralShare", () => {
112
+ describe("first snapshot (prev is null)", () => {
113
+ it("returns next unchanged", () => {
114
+ const next = exec({ messages: [msg(MessageType.MESSAGE_HUMAN, "hi")] });
115
+ expect(structuralShare(null, next)).toBe(next);
116
+ });
117
+ });
118
+
119
+ describe("identical snapshots", () => {
120
+ it("returns prev reference when nothing changed", () => {
121
+ const snapshot = exec({
122
+ messages: [
123
+ msg(MessageType.MESSAGE_HUMAN, "hello"),
124
+ msg(MessageType.MESSAGE_AI, "world"),
125
+ ],
126
+ });
127
+ const next = exec({
128
+ messages: [
129
+ msg(MessageType.MESSAGE_HUMAN, "hello"),
130
+ msg(MessageType.MESSAGE_AI, "world"),
131
+ ],
132
+ });
133
+ const result = structuralShare(snapshot, next);
134
+ expect(result).toBe(snapshot);
135
+ });
136
+ });
137
+
138
+ describe("message-level sharing", () => {
139
+ it("reuses references for unchanged messages at the prefix", () => {
140
+ const m1 = msg(MessageType.MESSAGE_HUMAN, "hello");
141
+ const m2 = msg(MessageType.MESSAGE_AI, "complete response");
142
+ const prev = exec({ messages: [m1, m2] });
143
+
144
+ const m3 = msg(MessageType.MESSAGE_AI, "streaming...", {
145
+ isStreaming: true,
146
+ });
147
+ const next = exec({
148
+ messages: [
149
+ msg(MessageType.MESSAGE_HUMAN, "hello"),
150
+ msg(MessageType.MESSAGE_AI, "complete response"),
151
+ m3,
152
+ ],
153
+ });
154
+
155
+ const result = structuralShare(prev, next);
156
+ expect(result).not.toBe(prev);
157
+ expect(result.status!.messages[0]).toBe(m1);
158
+ expect(result.status!.messages[1]).toBe(m2);
159
+ expect(result.status!.messages[2]).toBe(m3);
160
+ });
161
+
162
+ it("produces new reference for a message whose content changed", () => {
163
+ const m1 = msg(MessageType.MESSAGE_HUMAN, "hello");
164
+ const prev = exec({
165
+ messages: [m1, msg(MessageType.MESSAGE_AI, "partial")],
166
+ });
167
+ const next = exec({
168
+ messages: [
169
+ msg(MessageType.MESSAGE_HUMAN, "hello"),
170
+ msg(MessageType.MESSAGE_AI, "partial text growing"),
171
+ ],
172
+ });
173
+
174
+ const result = structuralShare(prev, next);
175
+ expect(result.status!.messages[0]).toBe(m1);
176
+ expect(result.status!.messages[1]).not.toBe(prev.status!.messages[1]);
177
+ expect(result.status!.messages[1].content).toBe("partial text growing");
178
+ });
179
+
180
+ it("produces new reference when isStreaming flag changes", () => {
181
+ const prev = exec({
182
+ messages: [
183
+ msg(MessageType.MESSAGE_AI, "done text", { isStreaming: true }),
184
+ ],
185
+ });
186
+ const next = exec({
187
+ messages: [
188
+ msg(MessageType.MESSAGE_AI, "done text", { isStreaming: false }),
189
+ ],
190
+ });
191
+
192
+ const result = structuralShare(prev, next);
193
+ expect(result).not.toBe(prev);
194
+ expect(result.status!.messages[0]).not.toBe(prev.status!.messages[0]);
195
+ });
196
+
197
+ it("handles empty to non-empty messages transition", () => {
198
+ const prev = exec({ messages: [] });
199
+ const next = exec({
200
+ messages: [msg(MessageType.MESSAGE_HUMAN, "first")],
201
+ });
202
+
203
+ const result = structuralShare(prev, next);
204
+ expect(result).not.toBe(prev);
205
+ expect(result.status!.messages.length).toBe(1);
206
+ });
207
+
208
+ it("returns prev when both have empty messages", () => {
209
+ const prev = exec({ messages: [] });
210
+ const next = exec({ messages: [] });
211
+ expect(structuralShare(prev, next)).toBe(prev);
212
+ });
213
+ });
214
+
215
+ describe("tool call sharing within messages", () => {
216
+ it("preserves unchanged tool call references by id", () => {
217
+ const tc1 = tc("tc-1", "read_file", { result: "file content" });
218
+ const tc2 = tc("tc-2", "write_file", {
219
+ status: ToolCallStatus.TOOL_CALL_RUNNING,
220
+ isStreaming: true,
221
+ });
222
+
223
+ const prev = exec({
224
+ messages: [
225
+ msg(MessageType.MESSAGE_AI, "using tools", { toolCalls: [tc1, tc2] }),
226
+ ],
227
+ });
228
+
229
+ const tc2Updated = tc("tc-2", "write_file", {
230
+ status: ToolCallStatus.TOOL_CALL_COMPLETED,
231
+ result: "written",
232
+ });
233
+ const next = exec({
234
+ messages: [
235
+ msg(MessageType.MESSAGE_AI, "using tools", {
236
+ toolCalls: [
237
+ tc("tc-1", "read_file", { result: "file content" }),
238
+ tc2Updated,
239
+ ],
240
+ }),
241
+ ],
242
+ });
243
+
244
+ const result = structuralShare(prev, next);
245
+ const resultTcs = result.status!.messages[0].toolCalls;
246
+ expect(resultTcs[0]).toBe(tc1);
247
+ expect(resultTcs[1]).not.toBe(tc2);
248
+ expect(resultTcs[1].status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
249
+ });
250
+
251
+ it("handles new tool calls being appended", () => {
252
+ const tc1 = tc("tc-1", "read_file", { result: "ok" });
253
+ const prev = exec({
254
+ messages: [
255
+ msg(MessageType.MESSAGE_AI, "tools", { toolCalls: [tc1] }),
256
+ ],
257
+ });
258
+
259
+ const next = exec({
260
+ messages: [
261
+ msg(MessageType.MESSAGE_AI, "tools", {
262
+ toolCalls: [
263
+ tc("tc-1", "read_file", { result: "ok" }),
264
+ tc("tc-2", "write_file"),
265
+ ],
266
+ }),
267
+ ],
268
+ });
269
+
270
+ const result = structuralShare(prev, next);
271
+ const resultTcs = result.status!.messages[0].toolCalls;
272
+ expect(resultTcs[0]).toBe(tc1);
273
+ expect(resultTcs.length).toBe(2);
274
+ });
275
+ });
276
+
277
+ describe("sub-agent sharing", () => {
278
+ it("reuses unchanged sub-agent references by id", () => {
279
+ const sa1 = subAgent("sa-1", {
280
+ status: SubAgentStatus.SUB_AGENT_COMPLETED,
281
+ messages: [msg(MessageType.MESSAGE_AI, "sub done")],
282
+ output: "result",
283
+ });
284
+ const prev = exec({ subAgents: [sa1] });
285
+
286
+ const next = exec({
287
+ subAgents: [
288
+ subAgent("sa-1", {
289
+ status: SubAgentStatus.SUB_AGENT_COMPLETED,
290
+ messages: [msg(MessageType.MESSAGE_AI, "sub done")],
291
+ output: "result",
292
+ }),
293
+ ],
294
+ });
295
+
296
+ const result = structuralShare(prev, next);
297
+ expect(result.status!.subAgentExecutions[0]).toBe(sa1);
298
+ });
299
+
300
+ it("produces new reference for updated sub-agent but shares its inner messages", () => {
301
+ const innerMsg = msg(MessageType.MESSAGE_AI, "thinking");
302
+ const sa = subAgent("sa-1", {
303
+ status: SubAgentStatus.SUB_AGENT_IN_PROGRESS,
304
+ messages: [innerMsg],
305
+ });
306
+ const prev = exec({ subAgents: [sa] });
307
+
308
+ const next = exec({
309
+ subAgents: [
310
+ subAgent("sa-1", {
311
+ status: SubAgentStatus.SUB_AGENT_IN_PROGRESS,
312
+ messages: [
313
+ msg(MessageType.MESSAGE_AI, "thinking"),
314
+ msg(MessageType.MESSAGE_AI, "more thinking"),
315
+ ],
316
+ }),
317
+ ],
318
+ });
319
+
320
+ const result = structuralShare(prev, next);
321
+ const resultSa = result.status!.subAgentExecutions[0];
322
+ expect(resultSa).not.toBe(sa);
323
+ expect(resultSa.messages[0]).toBe(innerMsg);
324
+ expect(resultSa.messages.length).toBe(2);
325
+ });
326
+
327
+ it("handles new sub-agent appearing", () => {
328
+ const sa1 = subAgent("sa-1", {
329
+ status: SubAgentStatus.SUB_AGENT_COMPLETED,
330
+ });
331
+ const prev = exec({ subAgents: [sa1] });
332
+
333
+ const next = exec({
334
+ subAgents: [
335
+ subAgent("sa-1", {
336
+ status: SubAgentStatus.SUB_AGENT_COMPLETED,
337
+ }),
338
+ subAgent("sa-2", {
339
+ status: SubAgentStatus.SUB_AGENT_IN_PROGRESS,
340
+ }),
341
+ ],
342
+ });
343
+
344
+ const result = structuralShare(prev, next);
345
+ expect(result.status!.subAgentExecutions[0]).toBe(sa1);
346
+ expect(result.status!.subAgentExecutions.length).toBe(2);
347
+ });
348
+ });
349
+
350
+ describe("pending approvals sharing", () => {
351
+ it("reuses prev array when approvals are unchanged", () => {
352
+ const a1 = approval("tc-1", "dangerous_tool");
353
+ const prev = exec({ approvals: [a1] });
354
+
355
+ const next = exec({
356
+ approvals: [approval("tc-1", "dangerous_tool")],
357
+ });
358
+
359
+ const result = structuralShare(prev, next);
360
+ expect(result.status!.pendingApprovals).toBe(
361
+ prev.status!.pendingApprovals,
362
+ );
363
+ });
364
+
365
+ it("uses new array when approvals change", () => {
366
+ const prev = exec({ approvals: [approval("tc-1", "tool1")] });
367
+ const next = exec({
368
+ approvals: [approval("tc-1", "tool1"), approval("tc-2", "tool2")],
369
+ });
370
+
371
+ const result = structuralShare(prev, next);
372
+ expect(result.status!.pendingApprovals).not.toBe(
373
+ prev.status!.pendingApprovals,
374
+ );
375
+ });
376
+
377
+ it("uses new array when an approval is removed", () => {
378
+ const prev = exec({
379
+ approvals: [approval("tc-1", "tool1"), approval("tc-2", "tool2")],
380
+ });
381
+ const next = exec({ approvals: [approval("tc-1", "tool1")] });
382
+
383
+ const result = structuralShare(prev, next);
384
+ expect(result.status!.pendingApprovals).not.toBe(
385
+ prev.status!.pendingApprovals,
386
+ );
387
+ });
388
+ });
389
+
390
+ describe("phase changes", () => {
391
+ it("produces new reference when phase changes", () => {
392
+ const prev = exec({ phase: ExecutionPhase.EXECUTION_IN_PROGRESS });
393
+ const next = exec({ phase: ExecutionPhase.EXECUTION_COMPLETED });
394
+
395
+ const result = structuralShare(prev, next);
396
+ expect(result).not.toBe(prev);
397
+ expect(result.status!.phase).toBe(ExecutionPhase.EXECUTION_COMPLETED);
398
+ });
399
+ });
400
+
401
+ describe("realistic streaming scenario", () => {
402
+ it("only the streaming tail produces new references during token streaming", () => {
403
+ const humanMsg = msg(MessageType.MESSAGE_HUMAN, "Explain React hooks");
404
+ const completedAi = msg(MessageType.MESSAGE_AI, "React hooks are...", {
405
+ toolCalls: [tc("tc-1", "read_docs", { result: "hooks docs" })],
406
+ });
407
+
408
+ const prev = exec({
409
+ messages: [
410
+ humanMsg,
411
+ completedAi,
412
+ msg(MessageType.MESSAGE_AI, "Let me explain fur", {
413
+ isStreaming: true,
414
+ }),
415
+ ],
416
+ });
417
+
418
+ const next = exec({
419
+ messages: [
420
+ msg(MessageType.MESSAGE_HUMAN, "Explain React hooks"),
421
+ msg(MessageType.MESSAGE_AI, "React hooks are...", {
422
+ toolCalls: [tc("tc-1", "read_docs", { result: "hooks docs" })],
423
+ }),
424
+ msg(MessageType.MESSAGE_AI, "Let me explain further. Hooks are", {
425
+ isStreaming: true,
426
+ }),
427
+ ],
428
+ });
429
+
430
+ const result = structuralShare(prev, next);
431
+
432
+ expect(result.status!.messages[0]).toBe(humanMsg);
433
+ expect(result.status!.messages[1]).toBe(completedAi);
434
+ expect(result.status!.messages[2]).not.toBe(prev.status!.messages[2]);
435
+ expect(result.status!.messages[2].content).toBe(
436
+ "Let me explain further. Hooks are",
437
+ );
438
+ });
439
+ });
440
+
441
+ describe("missing status", () => {
442
+ it("returns next when prev has no status", () => {
443
+ const prev = create(AgentExecutionSchema);
444
+ const next = exec({ messages: [msg(MessageType.MESSAGE_AI, "hi")] });
445
+ expect(structuralShare(prev, next)).toBe(next);
446
+ });
447
+
448
+ it("returns next when next has no status", () => {
449
+ const prev = exec({ messages: [msg(MessageType.MESSAGE_AI, "hi")] });
450
+ const next = create(AgentExecutionSchema);
451
+ expect(structuralShare(prev, next)).toBe(next);
452
+ });
453
+ });
454
+ });
@@ -0,0 +1,128 @@
1
+ import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
2
+ import { structuralShare } from "./structural-share";
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // Stream state
6
+ // ---------------------------------------------------------------------------
7
+
8
+ export type StreamState =
9
+ | { readonly stage: "idle" }
10
+ | { readonly stage: "connecting"; readonly executionId: string }
11
+ | { readonly stage: "streaming"; readonly executionId: string }
12
+ | { readonly stage: "complete"; readonly executionId: string }
13
+ | {
14
+ readonly stage: "error";
15
+ readonly executionId: string;
16
+ readonly error: Error;
17
+ };
18
+
19
+ const IDLE_STATE: StreamState = { stage: "idle" };
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // ConversationStore
23
+ // ---------------------------------------------------------------------------
24
+
25
+ type Listener = () => void;
26
+
27
+ /**
28
+ * Framework-agnostic store that holds the active execution snapshot
29
+ * with structural sharing. Implements the contract required by
30
+ * React's `useSyncExternalStore`.
31
+ *
32
+ * - `ingestSnapshot` applies structural sharing so unchanged nested
33
+ * entities keep their previous reference.
34
+ * - Listeners are notified only when state actually changes.
35
+ * - `getExecution` and `getStreamState` return stable references
36
+ * suitable as `useSyncExternalStore` snapshot selectors.
37
+ */
38
+ export class ConversationStore {
39
+ private _execution: AgentExecution | null = null;
40
+ private _streamState: StreamState = IDLE_STATE;
41
+ private _listeners = new Set<Listener>();
42
+
43
+ // -- Ingestion -----------------------------------------------------------
44
+
45
+ /**
46
+ * Ingest a new execution snapshot. Applies structural sharing
47
+ * against the previous snapshot and notifies listeners only if
48
+ * the resulting reference changed.
49
+ */
50
+ ingestSnapshot(snapshot: AgentExecution): void {
51
+ const shared = structuralShare(this._execution, snapshot);
52
+ if (shared === this._execution) return;
53
+ this._execution = shared;
54
+ this._notify();
55
+ }
56
+
57
+ /**
58
+ * Transition the stream lifecycle state. Notifies listeners only
59
+ * when the stage or executionId actually changes.
60
+ */
61
+ setStreamState(state: StreamState): void {
62
+ if (streamStateEqual(this._streamState, state)) return;
63
+ this._streamState = state;
64
+ this._notify();
65
+ }
66
+
67
+ /**
68
+ * Reset to initial state. Used when the session identity changes
69
+ * or the hook unmounts.
70
+ */
71
+ reset(): void {
72
+ const wasIdle =
73
+ this._execution === null && this._streamState.stage === "idle";
74
+ this._execution = null;
75
+ this._streamState = IDLE_STATE;
76
+ if (!wasIdle) this._notify();
77
+ }
78
+
79
+ // -- useSyncExternalStore contract ---------------------------------------
80
+
81
+ /**
82
+ * Subscribe a listener that is called whenever any store state
83
+ * changes. Returns an unsubscribe function.
84
+ */
85
+ subscribe = (listener: Listener): (() => void) => {
86
+ this._listeners.add(listener);
87
+ return () => {
88
+ this._listeners.delete(listener);
89
+ };
90
+ };
91
+
92
+ /** Stable snapshot selector for the current execution. */
93
+ getExecution = (): AgentExecution | null => {
94
+ return this._execution;
95
+ };
96
+
97
+ /** Stable snapshot selector for the stream lifecycle state. */
98
+ getStreamState = (): StreamState => {
99
+ return this._streamState;
100
+ };
101
+
102
+ // -- Internal ------------------------------------------------------------
103
+
104
+ private _notify(): void {
105
+ for (const listener of this._listeners) {
106
+ listener();
107
+ }
108
+ }
109
+ }
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // Helpers
113
+ // ---------------------------------------------------------------------------
114
+
115
+ function streamStateEqual(a: StreamState, b: StreamState): boolean {
116
+ if (a.stage !== b.stage) return false;
117
+ if (a.stage === "idle") return true;
118
+ if (
119
+ a.stage === "error" &&
120
+ b.stage === "error" &&
121
+ a.executionId === b.executionId &&
122
+ a.error === b.error
123
+ )
124
+ return true;
125
+ if ("executionId" in a && "executionId" in b)
126
+ return a.executionId === b.executionId;
127
+ return false;
128
+ }
@@ -0,0 +1,68 @@
1
+ "use client";
2
+
3
+ import { createContext, useContext, useRef, useSyncExternalStore } from "react";
4
+ import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
5
+ import { ConversationStore, type StreamState } from "./conversation-store";
6
+
7
+ export { ConversationStore, type StreamState } from "./conversation-store";
8
+ export { structuralShare } from "./structural-share";
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Context
12
+ // ---------------------------------------------------------------------------
13
+
14
+ /**
15
+ * Internal context for the conversation store. Not exported from the
16
+ * public SDK barrel — used only within SDK hooks and components.
17
+ */
18
+ export const ConversationStoreContext =
19
+ createContext<ConversationStore | null>(null);
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Hooks
23
+ // ---------------------------------------------------------------------------
24
+
25
+ /**
26
+ * Access the conversation store from context.
27
+ * Throws if called outside a `ConversationStoreContext.Provider`.
28
+ */
29
+ export function useConversationStore(): ConversationStore {
30
+ const store = useContext(ConversationStoreContext);
31
+ if (!store) {
32
+ throw new Error(
33
+ "useConversationStore must be used within a ConversationStoreContext.Provider",
34
+ );
35
+ }
36
+ return store;
37
+ }
38
+
39
+ /**
40
+ * Create or reuse a `ConversationStore` instance. The store is
41
+ * created once and preserved across re-renders via ref.
42
+ */
43
+ export function useConversationStoreRef(): ConversationStore {
44
+ const ref = useRef<ConversationStore | null>(null);
45
+ if (!ref.current) {
46
+ ref.current = new ConversationStore();
47
+ }
48
+ return ref.current;
49
+ }
50
+
51
+ /**
52
+ * Subscribe to the execution snapshot from the conversation store.
53
+ * Returns a stable reference when the execution is unchanged
54
+ * (structural sharing ensures this).
55
+ */
56
+ export function useStoreExecution(
57
+ store: ConversationStore,
58
+ ): AgentExecution | null {
59
+ return useSyncExternalStore(store.subscribe, store.getExecution);
60
+ }
61
+
62
+ /**
63
+ * Subscribe to the stream lifecycle state from the conversation store.
64
+ * Returns a stable reference when the state is unchanged.
65
+ */
66
+ export function useStoreStreamState(store: ConversationStore): StreamState {
67
+ return useSyncExternalStore(store.subscribe, store.getStreamState);
68
+ }