@circuitwall/jarela 2.2.1 → 2.3.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 (651) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +6 -5
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/routes-manifest.json +8 -0
  6. package/.next/standalone/.next/server/app/_global-error/page.js +68 -68
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page.js +76 -76
  14. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  16. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  17. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/standalone/.next/server/app/api/v1/access/[identity]/route.js +93 -93
  22. package/.next/standalone/.next/server/app/api/v1/access/route.js +169 -169
  23. package/.next/standalone/.next/server/app/api/v1/agents/[id]/compact/route.js +82 -56
  24. package/.next/standalone/.next/server/app/api/v1/agents/[id]/compact/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/v1/agents/[id]/display-filters/route.js +122 -122
  26. package/.next/standalone/.next/server/app/api/v1/agents/[id]/route.js +100 -100
  27. package/.next/standalone/.next/server/app/api/v1/agents/[id]/thread/route.js +753 -753
  28. package/.next/standalone/.next/server/app/api/v1/agents/route.js +65 -65
  29. package/.next/standalone/.next/server/app/api/v1/allowed-sites/[hostname]/route.js +364 -364
  30. package/.next/standalone/.next/server/app/api/v1/allowed-sites/route.js +802 -802
  31. package/.next/standalone/.next/server/app/api/v1/artifacts/lifecycle/route.js +2 -2
  32. package/.next/standalone/.next/server/app/api/v1/attachments/files/route.js +49 -49
  33. package/.next/standalone/.next/server/app/api/v1/attachments/images/route.js +910 -910
  34. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/chats/route.js +589 -16
  35. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/chats/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/ignores/[remote_jid]/route.js +23 -23
  37. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/ignores/route.js +30 -30
  38. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/lookup/route.js +703 -130
  39. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/lookup/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/pair/route.js +708 -135
  41. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/pair/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js +802 -229
  43. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/routes/[route_id]/route.js +739 -739
  45. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/routes/route.js +1035 -1035
  46. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/status/route.js +679 -106
  47. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/status/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/v1/bridges/kinds/route.js +804 -804
  49. package/.next/standalone/.next/server/app/api/v1/bridges/route.js +700 -700
  50. package/.next/standalone/.next/server/app/api/v1/builtin-tools/route.js +9 -9
  51. package/.next/standalone/.next/server/app/api/v1/builtin-tools/route.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/api/v1/config/route.js +85 -85
  53. package/.next/standalone/.next/server/app/api/v1/credentials/[id]/route.js +709 -709
  54. package/.next/standalone/.next/server/app/api/v1/credentials/[id]/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/v1/credentials/route.js +2 -2
  56. package/.next/standalone/.next/server/app/api/v1/credentials/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/v1/dashboard/currency/route.js +10 -10
  58. package/.next/standalone/.next/server/app/api/v1/dashboard/metrics/route.js +784 -784
  59. package/.next/standalone/.next/server/app/api/v1/dashboard/pricing/route.js +23 -23
  60. package/.next/standalone/.next/server/app/api/v1/dashboard/pricing-task/route.js +86 -86
  61. package/.next/standalone/.next/server/app/api/v1/dashboard/pricing-task/route.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/api/v1/delegations/codex/[job_id]/route.js +57 -57
  63. package/.next/standalone/.next/server/app/api/v1/delegations/codex/[job_id]/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/v1/documents/search/route.js +523 -523
  65. package/.next/standalone/.next/server/app/api/v1/documents/settings/route.js +44 -44
  66. package/.next/standalone/.next/server/app/api/v1/documents/sources/[id]/reindex/route.js +65 -65
  67. package/.next/standalone/.next/server/app/api/v1/documents/sources/[id]/reindex/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/api/v1/documents/sources/[id]/route.js +122 -122
  69. package/.next/standalone/.next/server/app/api/v1/documents/sources/[id]/route.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/api/v1/documents/sources/route.js +37 -37
  71. package/.next/standalone/.next/server/app/api/v1/documents/sources/route.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/api/v1/env/route.js +9 -9
  73. package/.next/standalone/.next/server/app/api/v1/env-sync/allowlist/route.js +368 -368
  74. package/.next/standalone/.next/server/app/api/v1/env-sync/route.js +44 -44
  75. package/.next/standalone/.next/server/app/api/v1/events/route.js +751 -178
  76. package/.next/standalone/.next/server/app/api/v1/events/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/v1/events/test/route.js +77 -77
  78. package/.next/standalone/.next/server/app/api/v1/extension/agents/route.js +763 -763
  79. package/.next/standalone/.next/server/app/api/v1/extension/agents/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/v1/extension/browser/activate/route.js +44 -44
  81. package/.next/standalone/.next/server/app/api/v1/extension/browser/foreground/route.js +9 -9
  82. package/.next/standalone/.next/server/app/api/v1/extension/browser/history/route.js +65 -65
  83. package/.next/standalone/.next/server/app/api/v1/extension/browser/poll/route.js +34 -34
  84. package/.next/standalone/.next/server/app/api/v1/extension/browser/progress/route.js +204 -204
  85. package/.next/standalone/.next/server/app/api/v1/extension/browser/result/route.js +133 -133
  86. package/.next/standalone/.next/server/app/api/v1/extension/browser/retry/route.js +106 -106
  87. package/.next/standalone/.next/server/app/api/v1/extension/browser/status/route.js +114 -114
  88. package/.next/standalone/.next/server/app/api/v1/extension/browser/tabs/route.js +134 -134
  89. package/.next/standalone/.next/server/app/api/v1/extension/fill/route.js +690 -690
  90. package/.next/standalone/.next/server/app/api/v1/extension/fill/route.js.nft.json +1 -1
  91. package/.next/standalone/.next/server/app/api/v1/extension/refine/route.js +93 -93
  92. package/.next/standalone/.next/server/app/api/v1/extension/refine/route.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/api/v1/extension/turn/route.js +9 -9
  94. package/.next/standalone/.next/server/app/api/v1/extension/turn/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/v1/extensions/route.js +185 -185
  96. package/.next/standalone/.next/server/app/api/v1/extensions/route.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/config/route.js +171 -171
  98. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/config/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/route.js +396 -396
  100. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js +212 -212
  102. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/api/v1/files/[name]/route.js +235 -235
  104. package/.next/standalone/.next/server/app/api/v1/fs/browse/route.js +26 -26
  105. package/.next/standalone/.next/server/app/api/v1/harnesses/[id]/route.js +221 -221
  106. package/.next/standalone/.next/server/app/api/v1/harnesses/default/route.js +58 -58
  107. package/.next/standalone/.next/server/app/api/v1/harnesses/route.js +72 -72
  108. package/.next/standalone/.next/server/app/api/v1/health/probes/route.js +9 -9
  109. package/.next/standalone/.next/server/app/api/v1/health/probes/route.js.nft.json +1 -1
  110. package/.next/standalone/.next/server/app/api/v1/health/route.js +772 -772
  111. package/.next/standalone/.next/server/app/api/v1/integrations/[name]/route.js +133 -133
  112. package/.next/standalone/.next/server/app/api/v1/integrations/[name]/test/route.js +9 -9
  113. package/.next/standalone/.next/server/app/api/v1/integrations/[name]/test/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/v1/integrations/gmail/oauth/callback/route.js +363 -363
  115. package/.next/standalone/.next/server/app/api/v1/integrations/gmail/oauth/start/route.js +233 -233
  116. package/.next/standalone/.next/server/app/api/v1/integrations/gmail/oauth/status/route.js +682 -682
  117. package/.next/standalone/.next/server/app/api/v1/integrations/outlook/oauth/callback/route.js +879 -879
  118. package/.next/standalone/.next/server/app/api/v1/integrations/outlook/oauth/start/route.js +108 -108
  119. package/.next/standalone/.next/server/app/api/v1/integrations/outlook/oauth/status/route.js +952 -952
  120. package/.next/standalone/.next/server/app/api/v1/integrations/route.js +216 -216
  121. package/.next/standalone/.next/server/app/api/v1/lifecycle/adoption/route.js +864 -847
  122. package/.next/standalone/.next/server/app/api/v1/lifecycle/adoption/route.js.nft.json +1 -1
  123. package/.next/standalone/.next/server/app/api/v1/local-file/route.js +26 -26
  124. package/.next/standalone/.next/server/app/api/v1/logs/route.js +70 -70
  125. package/.next/standalone/.next/server/app/api/v1/maps/embed/route.js +72 -72
  126. package/.next/standalone/.next/server/app/api/v1/mcp-servers/[name]/route.js +979 -979
  127. package/.next/standalone/.next/server/app/api/v1/mcp-servers/registry/route.js +196 -196
  128. package/.next/standalone/.next/server/app/api/v1/mcp-servers/route.js +2 -2
  129. package/.next/standalone/.next/server/app/api/v1/memory/[namespace]/[key]/route.js +381 -381
  130. package/.next/standalone/.next/server/app/api/v1/memory/policy/route.js +79 -79
  131. package/.next/standalone/.next/server/app/api/v1/memory/route.js +51 -51
  132. package/.next/standalone/.next/server/app/api/v1/memory/search/route.js +131 -131
  133. package/.next/standalone/.next/server/app/api/v1/models/[name]/compact-threads/route.js +374 -369
  134. package/.next/standalone/.next/server/app/api/v1/models/[name]/compact-threads/route.js.nft.json +1 -1
  135. package/.next/standalone/.next/server/app/api/v1/models/[name]/route.js +143 -143
  136. package/.next/standalone/.next/server/app/api/v1/models/route.js +543 -543
  137. package/.next/standalone/.next/server/app/api/v1/packages/catalog/route.js +445 -445
  138. package/.next/standalone/.next/server/app/api/v1/packages/defaults/[id]/route.js +120 -120
  139. package/.next/standalone/.next/server/app/api/v1/packages/defaults/[id]/route.js.nft.json +1 -1
  140. package/.next/standalone/.next/server/app/api/v1/packages/install/[id]/route.js +234 -234
  141. package/.next/standalone/.next/server/app/api/v1/packages/install/[id]/route.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/api/v1/packages/install/route.js +407 -407
  143. package/.next/standalone/.next/server/app/api/v1/packages/install/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/v1/packages/manifests/[name]/enabled/route.js +37 -37
  145. package/.next/standalone/.next/server/app/api/v1/packages/manifests/[name]/enabled/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/api/v1/packages/manifests/[name]/route.js +107 -107
  147. package/.next/standalone/.next/server/app/api/v1/packages/manifests/[name]/route.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/api/v1/packages/manifests/route.js +228 -228
  149. package/.next/standalone/.next/server/app/api/v1/packages/manifests/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/v1/packages/reload/route.js +9 -9
  151. package/.next/standalone/.next/server/app/api/v1/packages/reload/route.js.nft.json +1 -1
  152. package/.next/standalone/.next/server/app/api/v1/packages/route.js +148 -148
  153. package/.next/standalone/.next/server/app/api/v1/packages/route.js.nft.json +1 -1
  154. package/.next/standalone/.next/server/app/api/v1/page-capture/route.js +787 -787
  155. package/.next/standalone/.next/server/app/api/v1/page-capture/route.js.nft.json +1 -1
  156. package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/approve/route.js +507 -507
  157. package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/approve/route.js.nft.json +1 -1
  158. package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/deny/route.js +181 -181
  159. package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/deny/route.js.nft.json +1 -1
  160. package/.next/standalone/.next/server/app/api/v1/pending-actions/route.js +258 -258
  161. package/.next/standalone/.next/server/app/api/v1/pending-actions/route.js.nft.json +1 -1
  162. package/.next/standalone/.next/server/app/api/v1/profile/location/route.js +30 -30
  163. package/.next/standalone/.next/server/app/api/v1/profile/route.js +164 -164
  164. package/.next/standalone/.next/server/app/api/v1/providers/[provider]/models/route.js +44 -44
  165. package/.next/standalone/.next/server/app/api/v1/providers/[provider]/probe/route.js +9 -9
  166. package/.next/standalone/.next/server/app/api/v1/providers/github-copilot/auth/route.js +164 -164
  167. package/.next/standalone/.next/server/app/api/v1/providers/route.js +94 -94
  168. package/.next/standalone/.next/server/app/api/v1/proxy-config/route.js +450 -450
  169. package/.next/standalone/.next/server/app/api/v1/redaction/init/route.js +37 -37
  170. package/.next/standalone/.next/server/app/api/v1/redaction/route.js +58 -58
  171. package/.next/standalone/.next/server/app/api/v1/scheduled-tasks/[id]/route.js +600 -600
  172. package/.next/standalone/.next/server/app/api/v1/scheduled-tasks/[id]/run/route.js +44 -44
  173. package/.next/standalone/.next/server/app/api/v1/scheduled-tasks/[id]/run/route.js.nft.json +1 -1
  174. package/.next/standalone/.next/server/app/api/v1/scheduled-tasks/route.js +732 -732
  175. package/.next/standalone/.next/server/app/api/v1/security/idle-timeout/route.js +359 -359
  176. package/.next/standalone/.next/server/app/api/v1/security/pin/route.js +197 -197
  177. package/.next/standalone/.next/server/app/api/v1/security/state/route.js +51 -51
  178. package/.next/standalone/.next/server/app/api/v1/security/unlock/route.js +176 -176
  179. package/.next/standalone/.next/server/app/api/v1/security/verify-pin/route.js +190 -190
  180. package/.next/standalone/.next/server/app/api/v1/setup/test-key/route.js +26 -26
  181. package/.next/standalone/.next/server/app/api/v1/skills/[id]/route.js +770 -770
  182. package/.next/standalone/.next/server/app/api/v1/skills/repos/[id]/route.js +115 -115
  183. package/.next/standalone/.next/server/app/api/v1/skills/repos/route.js +327 -327
  184. package/.next/standalone/.next/server/app/api/v1/skills/route.js +870 -870
  185. package/.next/standalone/.next/server/app/api/v1/system/abort/route.js +838 -808
  186. package/.next/standalone/.next/server/app/api/v1/system/restart/route.js +177 -177
  187. package/.next/standalone/.next/server/app/api/v1/system/restart/route.js.nft.json +1 -1
  188. package/.next/standalone/.next/server/app/api/v1/tailscale/route.js +164 -164
  189. package/.next/standalone/.next/server/app/api/v1/tasks/[agent_id]/route.js +115 -115
  190. package/.next/standalone/.next/server/app/api/v1/tasks/route.js +23 -23
  191. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/activity/route.js +1429 -0
  192. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/activity/route.js.nft.json +1 -0
  193. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/activity/route_client-reference-manifest.js +1 -0
  194. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/context-pin/route.js +635 -634
  195. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/context-pin/route.js.nft.json +1 -1
  196. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/route.js +53 -439
  197. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/route.js.nft.json +1 -1
  198. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js +172 -172
  199. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js.nft.json +1 -1
  200. package/.next/standalone/.next/server/app/api/v1/threads/route.js +908 -908
  201. package/.next/standalone/.next/server/app/api/v1/tools/route.js +2 -2
  202. package/.next/standalone/.next/server/app/api/v1/tools/route.js.nft.json +1 -1
  203. package/.next/standalone/.next/server/app/api/v1/update/apply/route.js +17 -17
  204. package/.next/standalone/.next/server/app/api/v1/update/apply/route.js.nft.json +1 -1
  205. package/.next/standalone/.next/server/app/api/v1/update/route.js +570 -570
  206. package/.next/standalone/.next/server/app/api/v1/voice/transcribe/route.js +224 -224
  207. package/.next/standalone/.next/server/app/api/v1/voice/tts/route.js +975 -975
  208. package/.next/standalone/.next/server/app/api/v1/watchers/[id]/route.js +23 -23
  209. package/.next/standalone/.next/server/app/api/v1/watchers/[id]/run/route.js +72 -72
  210. package/.next/standalone/.next/server/app/api/v1/watchers/[id]/run/route.js.nft.json +1 -1
  211. package/.next/standalone/.next/server/app/api/v1/watchers/reaction-scripts/route.js +128 -128
  212. package/.next/standalone/.next/server/app/api/v1/watchers/route.js +164 -164
  213. package/.next/standalone/.next/server/app/api/v1/watchers/route.js.nft.json +1 -1
  214. package/.next/standalone/.next/server/app/icon.svg/route.js +62 -62
  215. package/.next/standalone/.next/server/app/manifest.webmanifest/route.js +436 -436
  216. package/.next/standalone/.next/server/app/page.js +1243 -854
  217. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  218. package/.next/standalone/.next/server/app/setup/page.js +91 -91
  219. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  220. package/.next/standalone/.next/server/app-paths-manifest.json +6 -5
  221. package/.next/standalone/.next/server/chunks/{424.js → 1388.js} +335 -986
  222. package/.next/standalone/.next/server/chunks/1433.js +1 -1
  223. package/.next/standalone/.next/server/chunks/1638.js +1 -2
  224. package/.next/standalone/.next/server/chunks/1738.js +1 -1
  225. package/.next/standalone/.next/server/chunks/210.js +6 -6
  226. package/.next/standalone/.next/server/chunks/2151.js +31 -1
  227. package/.next/standalone/.next/server/chunks/2207.js +1 -0
  228. package/.next/standalone/.next/server/chunks/2471.js +28 -28
  229. package/.next/standalone/.next/server/chunks/2504.js +1 -1
  230. package/.next/standalone/.next/server/chunks/2695.js +17 -17
  231. package/.next/standalone/.next/server/chunks/3042.js +14 -8
  232. package/.next/standalone/.next/server/chunks/3399.js +1 -1
  233. package/.next/standalone/.next/server/chunks/3566.js +1 -1
  234. package/.next/standalone/.next/server/chunks/4189.js +946 -0
  235. package/.next/standalone/.next/server/chunks/{9590.js → 423.js} +8 -3
  236. package/.next/standalone/.next/server/chunks/4433.js +146 -146
  237. package/.next/standalone/.next/server/chunks/4508.js +1 -1
  238. package/.next/standalone/.next/server/chunks/4588.js +1 -0
  239. package/.next/standalone/.next/server/chunks/46.js +5 -0
  240. package/.next/standalone/.next/server/chunks/466.js +12 -0
  241. package/.next/standalone/.next/server/chunks/4868.js +206 -206
  242. package/.next/standalone/.next/server/chunks/4992.js +13 -0
  243. package/.next/standalone/.next/server/chunks/5120.js +963 -0
  244. package/.next/standalone/.next/server/chunks/5701.js +1 -1
  245. package/.next/standalone/.next/server/chunks/5900.js +1 -1
  246. package/.next/standalone/.next/server/chunks/6210.js +1 -0
  247. package/.next/standalone/.next/server/chunks/6213.js +1 -1
  248. package/.next/standalone/.next/server/chunks/6649.js +2 -2
  249. package/.next/standalone/.next/server/chunks/6703.js +3 -3
  250. package/.next/standalone/.next/server/chunks/7445.js +1 -0
  251. package/.next/standalone/.next/server/chunks/8067.js +12 -0
  252. package/.next/standalone/.next/server/chunks/8461.js +14 -9
  253. package/.next/standalone/.next/server/chunks/8558.js +1 -1
  254. package/.next/standalone/.next/server/chunks/8724.js +1 -1
  255. package/.next/standalone/.next/server/chunks/8849.js +91 -91
  256. package/.next/standalone/.next/server/chunks/9032.js +6 -5
  257. package/.next/standalone/.next/server/chunks/{2563.js → 9164.js} +33173 -31461
  258. package/.next/standalone/.next/server/chunks/9237.js +396 -396
  259. package/.next/standalone/.next/server/chunks/{9640.js → 9304.js} +1628 -570
  260. package/.next/standalone/.next/server/chunks/9406.js +1 -1
  261. package/.next/standalone/.next/server/chunks/9824.js +98 -98
  262. package/.next/standalone/.next/server/chunks/9826.js +1 -0
  263. package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
  264. package/.next/standalone/.next/server/middleware.js +415 -397
  265. package/.next/standalone/.next/server/pages/404.html +2 -2
  266. package/.next/standalone/.next/server/pages/500.html +1 -1
  267. package/.next/standalone/.next/server/preview-props.json +3 -3
  268. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  269. package/.next/standalone/.next/static/chunks/{1395-a340fb0a345382a4.js → 1395-e4a99912b8f83044.js} +13 -1
  270. package/.next/standalone/.next/static/chunks/app/_global-error/{page-36cb8b428b38b26a.js → page-6fc5f8e744c81802.js} +1 -1
  271. package/.next/standalone/.next/static/chunks/app/api/v1/access/[identity]/{route-36cb8b428b38b26a.js → route-6fc5f8e744c81802.js} +1 -1
  272. package/.next/standalone/.next/static/chunks/app/api/v1/access/{route-36cb8b428b38b26a.js → route-6fc5f8e744c81802.js} +1 -1
  273. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/compact/{route-36cb8b428b38b26a.js → route-6fc5f8e744c81802.js} +1 -1
  274. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/display-filters/route-6fc5f8e744c81802.js +17 -0
  275. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/route-6fc5f8e744c81802.js +17 -0
  276. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/thread/route-6fc5f8e744c81802.js +17 -0
  277. package/.next/standalone/.next/static/chunks/app/api/v1/agents/route-6fc5f8e744c81802.js +17 -0
  278. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/[hostname]/route-6fc5f8e744c81802.js +17 -0
  279. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/route-6fc5f8e744c81802.js +17 -0
  280. package/.next/standalone/.next/static/chunks/app/api/v1/artifacts/lifecycle/route-6fc5f8e744c81802.js +17 -0
  281. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/files/route-6fc5f8e744c81802.js +17 -0
  282. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/images/route-6fc5f8e744c81802.js +17 -0
  283. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/chats/route-6fc5f8e744c81802.js +17 -0
  284. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/[remote_jid]/route-6fc5f8e744c81802.js +17 -0
  285. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/route-6fc5f8e744c81802.js +17 -0
  286. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/lookup/route-6fc5f8e744c81802.js +17 -0
  287. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/pair/route-6fc5f8e744c81802.js +17 -0
  288. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/route-6fc5f8e744c81802.js +17 -0
  289. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/[route_id]/route-6fc5f8e744c81802.js +17 -0
  290. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/route-6fc5f8e744c81802.js +17 -0
  291. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/status/route-6fc5f8e744c81802.js +17 -0
  292. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/kinds/route-6fc5f8e744c81802.js +17 -0
  293. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/route-6fc5f8e744c81802.js +17 -0
  294. package/.next/standalone/.next/static/chunks/app/api/v1/builtin-tools/route-6fc5f8e744c81802.js +17 -0
  295. package/.next/standalone/.next/static/chunks/app/api/v1/config/route-6fc5f8e744c81802.js +17 -0
  296. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/[id]/route-6fc5f8e744c81802.js +17 -0
  297. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/route-6fc5f8e744c81802.js +17 -0
  298. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/currency/route-6fc5f8e744c81802.js +17 -0
  299. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/metrics/route-6fc5f8e744c81802.js +17 -0
  300. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing/route-6fc5f8e744c81802.js +17 -0
  301. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing-task/route-6fc5f8e744c81802.js +17 -0
  302. package/.next/standalone/.next/static/chunks/app/api/v1/delegations/codex/[job_id]/route-6fc5f8e744c81802.js +17 -0
  303. package/.next/standalone/.next/static/chunks/app/api/v1/documents/search/route-6fc5f8e744c81802.js +17 -0
  304. package/.next/standalone/.next/static/chunks/app/api/v1/documents/settings/route-6fc5f8e744c81802.js +17 -0
  305. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/reindex/route-6fc5f8e744c81802.js +17 -0
  306. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/route-6fc5f8e744c81802.js +17 -0
  307. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/route-6fc5f8e744c81802.js +17 -0
  308. package/.next/standalone/.next/static/chunks/app/api/v1/env/route-6fc5f8e744c81802.js +17 -0
  309. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/allowlist/route-6fc5f8e744c81802.js +17 -0
  310. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/route-6fc5f8e744c81802.js +17 -0
  311. package/.next/standalone/.next/static/chunks/app/api/v1/events/route-6fc5f8e744c81802.js +17 -0
  312. package/.next/standalone/.next/static/chunks/app/api/v1/events/test/route-6fc5f8e744c81802.js +17 -0
  313. package/.next/standalone/.next/static/chunks/app/api/v1/extension/agents/route-6fc5f8e744c81802.js +17 -0
  314. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/activate/route-6fc5f8e744c81802.js +17 -0
  315. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/foreground/route-6fc5f8e744c81802.js +17 -0
  316. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/history/route-6fc5f8e744c81802.js +17 -0
  317. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/poll/route-6fc5f8e744c81802.js +17 -0
  318. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/progress/route-6fc5f8e744c81802.js +17 -0
  319. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/result/route-6fc5f8e744c81802.js +17 -0
  320. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/retry/route-6fc5f8e744c81802.js +17 -0
  321. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/status/route-6fc5f8e744c81802.js +17 -0
  322. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/tabs/route-6fc5f8e744c81802.js +17 -0
  323. package/.next/standalone/.next/static/chunks/app/api/v1/extension/fill/route-6fc5f8e744c81802.js +17 -0
  324. package/.next/standalone/.next/static/chunks/app/api/v1/extension/refine/route-6fc5f8e744c81802.js +17 -0
  325. package/.next/standalone/.next/static/chunks/app/api/v1/extension/turn/route-6fc5f8e744c81802.js +17 -0
  326. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/route-6fc5f8e744c81802.js +17 -0
  327. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/config/route-6fc5f8e744c81802.js +17 -0
  328. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/route-6fc5f8e744c81802.js +17 -0
  329. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/secrets/route-6fc5f8e744c81802.js +17 -0
  330. package/.next/standalone/.next/static/chunks/app/api/v1/files/[name]/route-6fc5f8e744c81802.js +17 -0
  331. package/.next/standalone/.next/static/chunks/app/api/v1/fs/browse/route-6fc5f8e744c81802.js +17 -0
  332. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/[id]/route-6fc5f8e744c81802.js +17 -0
  333. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/default/route-6fc5f8e744c81802.js +17 -0
  334. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/route-6fc5f8e744c81802.js +17 -0
  335. package/.next/standalone/.next/static/chunks/app/api/v1/health/probes/route-6fc5f8e744c81802.js +17 -0
  336. package/.next/standalone/.next/static/chunks/app/api/v1/health/route-6fc5f8e744c81802.js +17 -0
  337. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/route-6fc5f8e744c81802.js +17 -0
  338. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/test/route-6fc5f8e744c81802.js +17 -0
  339. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/callback/route-6fc5f8e744c81802.js +17 -0
  340. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/start/route-6fc5f8e744c81802.js +17 -0
  341. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/status/route-6fc5f8e744c81802.js +17 -0
  342. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/callback/route-6fc5f8e744c81802.js +17 -0
  343. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/start/route-6fc5f8e744c81802.js +17 -0
  344. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/status/route-6fc5f8e744c81802.js +17 -0
  345. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/route-6fc5f8e744c81802.js +17 -0
  346. package/.next/standalone/.next/static/chunks/app/api/v1/lifecycle/adoption/route-6fc5f8e744c81802.js +17 -0
  347. package/.next/standalone/.next/static/chunks/app/api/v1/local-file/route-6fc5f8e744c81802.js +17 -0
  348. package/.next/standalone/.next/static/chunks/app/api/v1/logs/route-6fc5f8e744c81802.js +17 -0
  349. package/.next/standalone/.next/static/chunks/app/api/v1/maps/embed/route-6fc5f8e744c81802.js +17 -0
  350. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/[name]/route-6fc5f8e744c81802.js +17 -0
  351. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/registry/route-6fc5f8e744c81802.js +17 -0
  352. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/route-6fc5f8e744c81802.js +17 -0
  353. package/.next/standalone/.next/static/chunks/app/api/v1/memory/[namespace]/[key]/route-6fc5f8e744c81802.js +17 -0
  354. package/.next/standalone/.next/static/chunks/app/api/v1/memory/policy/route-6fc5f8e744c81802.js +17 -0
  355. package/.next/standalone/.next/static/chunks/app/api/v1/memory/route-6fc5f8e744c81802.js +17 -0
  356. package/.next/standalone/.next/static/chunks/app/api/v1/memory/search/route-6fc5f8e744c81802.js +17 -0
  357. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/compact-threads/route-6fc5f8e744c81802.js +17 -0
  358. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/route-6fc5f8e744c81802.js +17 -0
  359. package/.next/standalone/.next/static/chunks/app/api/v1/models/route-6fc5f8e744c81802.js +17 -0
  360. package/.next/standalone/.next/static/chunks/app/api/v1/packages/catalog/route-6fc5f8e744c81802.js +17 -0
  361. package/.next/standalone/.next/static/chunks/app/api/v1/packages/defaults/[id]/route-6fc5f8e744c81802.js +17 -0
  362. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/[id]/route-6fc5f8e744c81802.js +17 -0
  363. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/route-6fc5f8e744c81802.js +17 -0
  364. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/enabled/route-6fc5f8e744c81802.js +17 -0
  365. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/route-6fc5f8e744c81802.js +17 -0
  366. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/route-6fc5f8e744c81802.js +17 -0
  367. package/.next/standalone/.next/static/chunks/app/api/v1/packages/reload/route-6fc5f8e744c81802.js +17 -0
  368. package/.next/standalone/.next/static/chunks/app/api/v1/packages/route-6fc5f8e744c81802.js +17 -0
  369. package/.next/standalone/.next/static/chunks/app/api/v1/page-capture/route-6fc5f8e744c81802.js +17 -0
  370. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/approve/route-6fc5f8e744c81802.js +17 -0
  371. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/deny/route-6fc5f8e744c81802.js +17 -0
  372. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/route-6fc5f8e744c81802.js +17 -0
  373. package/.next/standalone/.next/static/chunks/app/api/v1/profile/location/route-6fc5f8e744c81802.js +17 -0
  374. package/.next/standalone/.next/static/chunks/app/api/v1/profile/route-6fc5f8e744c81802.js +17 -0
  375. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/models/route-6fc5f8e744c81802.js +17 -0
  376. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/probe/route-6fc5f8e744c81802.js +17 -0
  377. package/.next/standalone/.next/static/chunks/app/api/v1/providers/github-copilot/auth/route-6fc5f8e744c81802.js +17 -0
  378. package/.next/standalone/.next/static/chunks/app/api/v1/providers/route-6fc5f8e744c81802.js +17 -0
  379. package/.next/standalone/.next/static/chunks/app/api/v1/proxy-config/route-6fc5f8e744c81802.js +17 -0
  380. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/init/route-6fc5f8e744c81802.js +17 -0
  381. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/route-6fc5f8e744c81802.js +17 -0
  382. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/route-6fc5f8e744c81802.js +17 -0
  383. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/run/route-6fc5f8e744c81802.js +17 -0
  384. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/route-6fc5f8e744c81802.js +17 -0
  385. package/.next/standalone/.next/static/chunks/app/api/v1/security/idle-timeout/route-6fc5f8e744c81802.js +17 -0
  386. package/.next/standalone/.next/static/chunks/app/api/v1/security/pin/route-6fc5f8e744c81802.js +17 -0
  387. package/.next/standalone/.next/static/chunks/app/api/v1/security/state/route-6fc5f8e744c81802.js +17 -0
  388. package/.next/standalone/.next/static/chunks/app/api/v1/security/unlock/route-6fc5f8e744c81802.js +17 -0
  389. package/.next/standalone/.next/static/chunks/app/api/v1/security/verify-pin/route-6fc5f8e744c81802.js +17 -0
  390. package/.next/standalone/.next/static/chunks/app/api/v1/setup/test-key/route-6fc5f8e744c81802.js +17 -0
  391. package/.next/standalone/.next/static/chunks/app/api/v1/skills/[id]/route-6fc5f8e744c81802.js +17 -0
  392. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/[id]/route-6fc5f8e744c81802.js +17 -0
  393. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/route-6fc5f8e744c81802.js +17 -0
  394. package/.next/standalone/.next/static/chunks/app/api/v1/skills/route-6fc5f8e744c81802.js +17 -0
  395. package/.next/standalone/.next/static/chunks/app/api/v1/system/abort/route-6fc5f8e744c81802.js +17 -0
  396. package/.next/standalone/.next/static/chunks/app/api/v1/system/restart/route-6fc5f8e744c81802.js +17 -0
  397. package/.next/standalone/.next/static/chunks/app/api/v1/tailscale/route-6fc5f8e744c81802.js +17 -0
  398. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/[agent_id]/route-6fc5f8e744c81802.js +17 -0
  399. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/route-6fc5f8e744c81802.js +17 -0
  400. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/activity/route-6fc5f8e744c81802.js +17 -0
  401. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/context-pin/route-6fc5f8e744c81802.js +17 -0
  402. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/route-6fc5f8e744c81802.js +17 -0
  403. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/run/route-6fc5f8e744c81802.js +17 -0
  404. package/.next/standalone/.next/static/chunks/app/api/v1/threads/route-6fc5f8e744c81802.js +17 -0
  405. package/.next/standalone/.next/static/chunks/app/api/v1/tools/route-6fc5f8e744c81802.js +17 -0
  406. package/.next/standalone/.next/static/chunks/app/api/v1/update/apply/route-6fc5f8e744c81802.js +17 -0
  407. package/.next/standalone/.next/static/chunks/app/api/v1/update/route-6fc5f8e744c81802.js +17 -0
  408. package/.next/standalone/.next/static/chunks/app/api/v1/voice/transcribe/route-6fc5f8e744c81802.js +17 -0
  409. package/.next/standalone/.next/static/chunks/app/api/v1/voice/tts/route-6fc5f8e744c81802.js +17 -0
  410. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/route-6fc5f8e744c81802.js +17 -0
  411. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/run/route-6fc5f8e744c81802.js +17 -0
  412. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/reaction-scripts/route-6fc5f8e744c81802.js +17 -0
  413. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/route-6fc5f8e744c81802.js +17 -0
  414. package/.next/standalone/.next/static/chunks/app/manifest.webmanifest/route-6fc5f8e744c81802.js +17 -0
  415. package/.next/standalone/.next/static/chunks/app/{page-7017f07f8a7a083c.js → page-213a623b37226452.js} +1041 -652
  416. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-6fc5f8e744c81802.js +17 -0
  417. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-6fc5f8e744c81802.js +17 -0
  418. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-6fc5f8e744c81802.js +17 -0
  419. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-6fc5f8e744c81802.js +17 -0
  420. package/.next/standalone/.next/static/css/{d80058f0b9b41c09.css → 312542a5725ba0d5.css} +2 -2
  421. package/.next/standalone/docs/adoption/changesets.json +309 -0
  422. package/.next/standalone/lib/skills/builtins/memory-organization/SKILL.md +16 -0
  423. package/.next/standalone/package.json +3 -3
  424. package/CHANGELOG.md +25 -0
  425. package/api/client.ts +9 -0
  426. package/api/types.ts +29 -0
  427. package/app/api/v1/lifecycle/adoption/route.ts +14 -2
  428. package/app/api/v1/models/[name]/compact-threads/route.ts +14 -11
  429. package/app/api/v1/threads/[thread_id]/activity/route.ts +19 -0
  430. package/app/api/v1/threads/[thread_id]/context-pin/route.test.ts +1 -0
  431. package/app/api/v1/threads/[thread_id]/context-pin/route.ts +2 -1
  432. package/app/api/v1/threads/[thread_id]/route.ts +5 -1
  433. package/components/chat/ChatView.tsx +52 -11
  434. package/components/chat/ContextBoundary.test.tsx +68 -1
  435. package/components/chat/ContextBoundary.tsx +92 -13
  436. package/components/chat/MessageList.test.tsx +31 -0
  437. package/components/chat/MessageList.tsx +49 -28
  438. package/components/chat/ToolList.test.tsx +92 -16
  439. package/components/chat/ToolList.tsx +59 -4
  440. package/components/chat/chat-helpers.test.tsx +24 -1
  441. package/components/chat/chat-helpers.ts +47 -4
  442. package/components/chat/useThreadActivity.test.tsx +113 -0
  443. package/components/chat/useThreadActivity.ts +94 -0
  444. package/components/chat/useThreadData.ts +16 -16
  445. package/components/chat/workflow-step-retry.ts +25 -0
  446. package/components/ui/BootScreen.tsx +17 -0
  447. package/components/ui/WorkflowChecklist.tsx +71 -33
  448. package/hooks/useSSE.ts +28 -3
  449. package/lib/agents/compaction-pipeline.test.ts +202 -0
  450. package/lib/agents/compaction-pipeline.ts +483 -0
  451. package/lib/agents/conversation-summary.ts +37 -21
  452. package/lib/agents/prepare/history-window.test.ts +18 -0
  453. package/lib/agents/prepare/history-window.ts +11 -2
  454. package/lib/agents/prepare/request.ts +4 -0
  455. package/lib/agents/prepare/system-prompt.test.ts +39 -0
  456. package/lib/agents/prepare/system-prompt.ts +8 -3
  457. package/lib/agents/prompt-registry.test.ts +5 -140
  458. package/lib/agents/prompt-registry.ts +45 -1
  459. package/lib/agents/prompt-variants.ts +146 -0
  460. package/lib/agents/run-registry.test.ts +22 -0
  461. package/lib/agents/run-registry.ts +29 -0
  462. package/lib/agents/run-thread.retry.test.ts +67 -1
  463. package/lib/agents/run-thread.ts +86 -1
  464. package/lib/agents/thread-activity.test.ts +31 -0
  465. package/lib/agents/thread-activity.ts +27 -0
  466. package/lib/agents/thread-compaction-state.test.ts +82 -0
  467. package/lib/agents/thread-compaction-state.ts +121 -0
  468. package/lib/agents/thread-compaction.test.ts +83 -4
  469. package/lib/agents/thread-compaction.ts +34 -11
  470. package/lib/agents/warm-summary-background.test.ts +219 -5
  471. package/lib/agents/warm-summary-background.ts +325 -142
  472. package/lib/agents/warm-topics.test.ts +37 -0
  473. package/lib/agents/warm-topics.ts +297 -0
  474. package/lib/agents/workflow-step-retry.test.ts +96 -0
  475. package/lib/agents/workflow-step-retry.ts +216 -0
  476. package/lib/api/browser-control.ts +0 -3
  477. package/lib/db/migrations.ts +5 -0
  478. package/lib/env/config.ts +2 -0
  479. package/lib/env/schema.ts +12 -0
  480. package/lib/lifecycle/changeset-build.test.ts +93 -0
  481. package/lib/lifecycle/changeset-build.ts +210 -0
  482. package/lib/lifecycle/changesets.test.ts +101 -0
  483. package/lib/lifecycle/changesets.ts +166 -0
  484. package/lib/lifecycle/surface-collect.test.ts +88 -0
  485. package/lib/lifecycle/surface-collect.ts +64 -0
  486. package/lib/lifecycle/surface-snapshot.test.ts +104 -0
  487. package/lib/lifecycle/surface-snapshot.ts +210 -0
  488. package/lib/memory/record.ts +0 -2
  489. package/lib/providers/external.ts +0 -2
  490. package/lib/skills/builtins/memory-organization/SKILL.md +16 -0
  491. package/lib/stores/threads.test.ts +9 -0
  492. package/lib/stores/threads.ts +21 -11
  493. package/lib/stores/version-adoption.test.ts +96 -0
  494. package/lib/stores/version-adoption.ts +239 -26
  495. package/lib/stores/workflow-progress.ts +3 -0
  496. package/lib/tools/communications/ms-todo.ts +0 -7
  497. package/lib/tools/general/memory.ts +1 -1
  498. package/lib/tools/general/workflow-progress.ts +2 -0
  499. package/lib/tools/runtime/catalog.ts +1 -25
  500. package/lib/triggers/registry.ts +0 -4
  501. package/package.json +3 -3
  502. package/scripts/install-to-system.ps1 +39 -11
  503. package/scripts/install-to-system.sh +37 -3
  504. package/.next/standalone/.next/server/chunks/3979.js +0 -581
  505. package/.next/standalone/.next/server/chunks/5936.js +0 -594
  506. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/display-filters/route-36cb8b428b38b26a.js +0 -17
  507. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/route-36cb8b428b38b26a.js +0 -17
  508. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/thread/route-36cb8b428b38b26a.js +0 -17
  509. package/.next/standalone/.next/static/chunks/app/api/v1/agents/route-36cb8b428b38b26a.js +0 -17
  510. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/[hostname]/route-36cb8b428b38b26a.js +0 -17
  511. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/route-36cb8b428b38b26a.js +0 -17
  512. package/.next/standalone/.next/static/chunks/app/api/v1/artifacts/lifecycle/route-36cb8b428b38b26a.js +0 -17
  513. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/files/route-36cb8b428b38b26a.js +0 -17
  514. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/images/route-36cb8b428b38b26a.js +0 -17
  515. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/chats/route-36cb8b428b38b26a.js +0 -17
  516. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/[remote_jid]/route-36cb8b428b38b26a.js +0 -17
  517. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/route-36cb8b428b38b26a.js +0 -17
  518. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/lookup/route-36cb8b428b38b26a.js +0 -17
  519. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/pair/route-36cb8b428b38b26a.js +0 -17
  520. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/route-36cb8b428b38b26a.js +0 -17
  521. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/[route_id]/route-36cb8b428b38b26a.js +0 -17
  522. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/route-36cb8b428b38b26a.js +0 -17
  523. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/status/route-36cb8b428b38b26a.js +0 -17
  524. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/kinds/route-36cb8b428b38b26a.js +0 -17
  525. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/route-36cb8b428b38b26a.js +0 -17
  526. package/.next/standalone/.next/static/chunks/app/api/v1/builtin-tools/route-36cb8b428b38b26a.js +0 -17
  527. package/.next/standalone/.next/static/chunks/app/api/v1/config/route-36cb8b428b38b26a.js +0 -17
  528. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/[id]/route-36cb8b428b38b26a.js +0 -17
  529. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/route-36cb8b428b38b26a.js +0 -17
  530. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/currency/route-36cb8b428b38b26a.js +0 -17
  531. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/metrics/route-36cb8b428b38b26a.js +0 -17
  532. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing/route-36cb8b428b38b26a.js +0 -17
  533. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing-task/route-36cb8b428b38b26a.js +0 -17
  534. package/.next/standalone/.next/static/chunks/app/api/v1/delegations/codex/[job_id]/route-36cb8b428b38b26a.js +0 -17
  535. package/.next/standalone/.next/static/chunks/app/api/v1/documents/search/route-36cb8b428b38b26a.js +0 -17
  536. package/.next/standalone/.next/static/chunks/app/api/v1/documents/settings/route-36cb8b428b38b26a.js +0 -17
  537. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/reindex/route-36cb8b428b38b26a.js +0 -17
  538. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/route-36cb8b428b38b26a.js +0 -17
  539. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/route-36cb8b428b38b26a.js +0 -17
  540. package/.next/standalone/.next/static/chunks/app/api/v1/env/route-36cb8b428b38b26a.js +0 -17
  541. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/allowlist/route-36cb8b428b38b26a.js +0 -17
  542. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/route-36cb8b428b38b26a.js +0 -17
  543. package/.next/standalone/.next/static/chunks/app/api/v1/events/route-36cb8b428b38b26a.js +0 -17
  544. package/.next/standalone/.next/static/chunks/app/api/v1/events/test/route-36cb8b428b38b26a.js +0 -17
  545. package/.next/standalone/.next/static/chunks/app/api/v1/extension/agents/route-36cb8b428b38b26a.js +0 -17
  546. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/activate/route-36cb8b428b38b26a.js +0 -17
  547. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/foreground/route-36cb8b428b38b26a.js +0 -17
  548. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/history/route-36cb8b428b38b26a.js +0 -17
  549. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/poll/route-36cb8b428b38b26a.js +0 -17
  550. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/progress/route-36cb8b428b38b26a.js +0 -17
  551. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/result/route-36cb8b428b38b26a.js +0 -17
  552. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/retry/route-36cb8b428b38b26a.js +0 -17
  553. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/status/route-36cb8b428b38b26a.js +0 -17
  554. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/tabs/route-36cb8b428b38b26a.js +0 -17
  555. package/.next/standalone/.next/static/chunks/app/api/v1/extension/fill/route-36cb8b428b38b26a.js +0 -17
  556. package/.next/standalone/.next/static/chunks/app/api/v1/extension/refine/route-36cb8b428b38b26a.js +0 -17
  557. package/.next/standalone/.next/static/chunks/app/api/v1/extension/turn/route-36cb8b428b38b26a.js +0 -17
  558. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/route-36cb8b428b38b26a.js +0 -17
  559. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/config/route-36cb8b428b38b26a.js +0 -17
  560. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/route-36cb8b428b38b26a.js +0 -17
  561. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/secrets/route-36cb8b428b38b26a.js +0 -17
  562. package/.next/standalone/.next/static/chunks/app/api/v1/files/[name]/route-36cb8b428b38b26a.js +0 -17
  563. package/.next/standalone/.next/static/chunks/app/api/v1/fs/browse/route-36cb8b428b38b26a.js +0 -17
  564. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/[id]/route-36cb8b428b38b26a.js +0 -17
  565. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/default/route-36cb8b428b38b26a.js +0 -17
  566. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/route-36cb8b428b38b26a.js +0 -17
  567. package/.next/standalone/.next/static/chunks/app/api/v1/health/probes/route-36cb8b428b38b26a.js +0 -17
  568. package/.next/standalone/.next/static/chunks/app/api/v1/health/route-36cb8b428b38b26a.js +0 -17
  569. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/route-36cb8b428b38b26a.js +0 -17
  570. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/test/route-36cb8b428b38b26a.js +0 -17
  571. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/callback/route-36cb8b428b38b26a.js +0 -17
  572. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/start/route-36cb8b428b38b26a.js +0 -17
  573. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/status/route-36cb8b428b38b26a.js +0 -17
  574. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/callback/route-36cb8b428b38b26a.js +0 -17
  575. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/start/route-36cb8b428b38b26a.js +0 -17
  576. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/status/route-36cb8b428b38b26a.js +0 -17
  577. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/route-36cb8b428b38b26a.js +0 -17
  578. package/.next/standalone/.next/static/chunks/app/api/v1/lifecycle/adoption/route-36cb8b428b38b26a.js +0 -17
  579. package/.next/standalone/.next/static/chunks/app/api/v1/local-file/route-36cb8b428b38b26a.js +0 -17
  580. package/.next/standalone/.next/static/chunks/app/api/v1/logs/route-36cb8b428b38b26a.js +0 -17
  581. package/.next/standalone/.next/static/chunks/app/api/v1/maps/embed/route-36cb8b428b38b26a.js +0 -17
  582. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/[name]/route-36cb8b428b38b26a.js +0 -17
  583. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/registry/route-36cb8b428b38b26a.js +0 -17
  584. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/route-36cb8b428b38b26a.js +0 -17
  585. package/.next/standalone/.next/static/chunks/app/api/v1/memory/[namespace]/[key]/route-36cb8b428b38b26a.js +0 -17
  586. package/.next/standalone/.next/static/chunks/app/api/v1/memory/policy/route-36cb8b428b38b26a.js +0 -17
  587. package/.next/standalone/.next/static/chunks/app/api/v1/memory/route-36cb8b428b38b26a.js +0 -17
  588. package/.next/standalone/.next/static/chunks/app/api/v1/memory/search/route-36cb8b428b38b26a.js +0 -17
  589. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/compact-threads/route-36cb8b428b38b26a.js +0 -17
  590. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/route-36cb8b428b38b26a.js +0 -17
  591. package/.next/standalone/.next/static/chunks/app/api/v1/models/route-36cb8b428b38b26a.js +0 -17
  592. package/.next/standalone/.next/static/chunks/app/api/v1/packages/catalog/route-36cb8b428b38b26a.js +0 -17
  593. package/.next/standalone/.next/static/chunks/app/api/v1/packages/defaults/[id]/route-36cb8b428b38b26a.js +0 -17
  594. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/[id]/route-36cb8b428b38b26a.js +0 -17
  595. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/route-36cb8b428b38b26a.js +0 -17
  596. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/enabled/route-36cb8b428b38b26a.js +0 -17
  597. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/route-36cb8b428b38b26a.js +0 -17
  598. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/route-36cb8b428b38b26a.js +0 -17
  599. package/.next/standalone/.next/static/chunks/app/api/v1/packages/reload/route-36cb8b428b38b26a.js +0 -17
  600. package/.next/standalone/.next/static/chunks/app/api/v1/packages/route-36cb8b428b38b26a.js +0 -17
  601. package/.next/standalone/.next/static/chunks/app/api/v1/page-capture/route-36cb8b428b38b26a.js +0 -17
  602. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/approve/route-36cb8b428b38b26a.js +0 -17
  603. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/deny/route-36cb8b428b38b26a.js +0 -17
  604. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/route-36cb8b428b38b26a.js +0 -17
  605. package/.next/standalone/.next/static/chunks/app/api/v1/profile/location/route-36cb8b428b38b26a.js +0 -17
  606. package/.next/standalone/.next/static/chunks/app/api/v1/profile/route-36cb8b428b38b26a.js +0 -17
  607. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/models/route-36cb8b428b38b26a.js +0 -17
  608. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/probe/route-36cb8b428b38b26a.js +0 -17
  609. package/.next/standalone/.next/static/chunks/app/api/v1/providers/github-copilot/auth/route-36cb8b428b38b26a.js +0 -17
  610. package/.next/standalone/.next/static/chunks/app/api/v1/providers/route-36cb8b428b38b26a.js +0 -17
  611. package/.next/standalone/.next/static/chunks/app/api/v1/proxy-config/route-36cb8b428b38b26a.js +0 -17
  612. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/init/route-36cb8b428b38b26a.js +0 -17
  613. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/route-36cb8b428b38b26a.js +0 -17
  614. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/route-36cb8b428b38b26a.js +0 -17
  615. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/run/route-36cb8b428b38b26a.js +0 -17
  616. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/route-36cb8b428b38b26a.js +0 -17
  617. package/.next/standalone/.next/static/chunks/app/api/v1/security/idle-timeout/route-36cb8b428b38b26a.js +0 -17
  618. package/.next/standalone/.next/static/chunks/app/api/v1/security/pin/route-36cb8b428b38b26a.js +0 -17
  619. package/.next/standalone/.next/static/chunks/app/api/v1/security/state/route-36cb8b428b38b26a.js +0 -17
  620. package/.next/standalone/.next/static/chunks/app/api/v1/security/unlock/route-36cb8b428b38b26a.js +0 -17
  621. package/.next/standalone/.next/static/chunks/app/api/v1/security/verify-pin/route-36cb8b428b38b26a.js +0 -17
  622. package/.next/standalone/.next/static/chunks/app/api/v1/setup/test-key/route-36cb8b428b38b26a.js +0 -17
  623. package/.next/standalone/.next/static/chunks/app/api/v1/skills/[id]/route-36cb8b428b38b26a.js +0 -17
  624. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/[id]/route-36cb8b428b38b26a.js +0 -17
  625. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/route-36cb8b428b38b26a.js +0 -17
  626. package/.next/standalone/.next/static/chunks/app/api/v1/skills/route-36cb8b428b38b26a.js +0 -17
  627. package/.next/standalone/.next/static/chunks/app/api/v1/system/abort/route-36cb8b428b38b26a.js +0 -17
  628. package/.next/standalone/.next/static/chunks/app/api/v1/system/restart/route-36cb8b428b38b26a.js +0 -17
  629. package/.next/standalone/.next/static/chunks/app/api/v1/tailscale/route-36cb8b428b38b26a.js +0 -17
  630. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/[agent_id]/route-36cb8b428b38b26a.js +0 -17
  631. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/route-36cb8b428b38b26a.js +0 -17
  632. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/context-pin/route-36cb8b428b38b26a.js +0 -17
  633. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/route-36cb8b428b38b26a.js +0 -17
  634. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/run/route-36cb8b428b38b26a.js +0 -17
  635. package/.next/standalone/.next/static/chunks/app/api/v1/threads/route-36cb8b428b38b26a.js +0 -17
  636. package/.next/standalone/.next/static/chunks/app/api/v1/tools/route-36cb8b428b38b26a.js +0 -17
  637. package/.next/standalone/.next/static/chunks/app/api/v1/update/apply/route-36cb8b428b38b26a.js +0 -17
  638. package/.next/standalone/.next/static/chunks/app/api/v1/update/route-36cb8b428b38b26a.js +0 -17
  639. package/.next/standalone/.next/static/chunks/app/api/v1/voice/transcribe/route-36cb8b428b38b26a.js +0 -17
  640. package/.next/standalone/.next/static/chunks/app/api/v1/voice/tts/route-36cb8b428b38b26a.js +0 -17
  641. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/route-36cb8b428b38b26a.js +0 -17
  642. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/run/route-36cb8b428b38b26a.js +0 -17
  643. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/reaction-scripts/route-36cb8b428b38b26a.js +0 -17
  644. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/route-36cb8b428b38b26a.js +0 -17
  645. package/.next/standalone/.next/static/chunks/app/manifest.webmanifest/route-36cb8b428b38b26a.js +0 -17
  646. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-36cb8b428b38b26a.js +0 -17
  647. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-36cb8b428b38b26a.js +0 -17
  648. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-36cb8b428b38b26a.js +0 -17
  649. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-36cb8b428b38b26a.js +0 -17
  650. /package/.next/standalone/.next/static/{NUrC9xax1sp1Q70nlFqS6 → bMRK5y3ruT7c3WtBfCQOG}/_buildManifest.js +0 -0
  651. /package/.next/standalone/.next/static/{NUrC9xax1sp1Q70nlFqS6 → bMRK5y3ruT7c3WtBfCQOG}/_ssgManifest.js +0 -0
@@ -1,7 +1,8 @@
1
1
  // @vitest-environment jsdom
2
2
  import { describe, it, expect, vi } from "vitest";
3
- import { render, screen, fireEvent, waitFor, within } from "@testing-library/react";
3
+ import { render, screen, fireEvent, waitFor } from "@testing-library/react";
4
4
  import { ToolList, type ToolEvent } from "./ToolList";
5
+ import { WorkflowStepRetryContext, workflowStepRetryMessage } from "./workflow-step-retry";
5
6
 
6
7
  const { codexJobGet, codexJobCancel } = vi.hoisted(() => ({
7
8
  codexJobGet: vi.fn(),
@@ -343,21 +344,96 @@ describe("ToolList — live progress (ADR-0073)", () => {
343
344
  render(<ToolList events={events} />);
344
345
  fireEvent.click(screen.getByText("workflow_progress"));
345
346
 
346
- expect(screen.getByText("workflow")).toBeTruthy();
347
- expect(screen.getAllByText("Fetching changes").length).toBeGreaterThan(0);
348
347
  expect(screen.getAllByText("Fetch changes").length).toBeGreaterThan(0);
349
348
  expect(screen.getAllByText("Build todo list").length).toBeGreaterThan(0);
350
- expect(screen.getByLabelText("done")).toBeTruthy();
351
- expect(screen.getByLabelText("checking")).toBeTruthy();
352
- const firstContract = screen.getAllByText("Step contract")[0];
353
- fireEvent.click(firstContract);
354
- const contract = firstContract.closest("details");
355
- expect(contract).toBeTruthy();
356
- if (!contract) throw new Error("Workflow step contract details were not rendered");
357
- expect(within(contract).getByText("Baseline tag and repository HEAD")).toBeTruthy();
358
- expect(within(contract).getByText("Paths changed since baseline")).toBeTruthy();
359
- expect(within(contract).getByText("Inspect system-computed git diff result")).toBeTruthy();
360
- expect(within(contract).getByText("git diff returned the changed paths")).toBeTruthy();
349
+ expect(screen.getByRole("img", { name: "verified" })).toBeTruthy();
350
+ expect(screen.getByRole("img", { name: "checking" })).toBeTruthy();
351
+ expect(screen.queryByText("Step contract")).toBeNull();
352
+ expect(screen.queryByText("Baseline tag and repository HEAD")).toBeNull();
353
+ expect(screen.getByText("Fetch changes").getAttribute("title")).toContain("git diff returned the changed paths");
354
+ expect(screen.queryByRole("button", { name: /^Retry / })).toBeNull();
355
+ expect(screen.queryByText("result")).toBeNull();
356
+ });
357
+
358
+ it("shows a rejected workflow update as an error instead of a silent checklist", () => {
359
+ const events: ToolEvent[] = [
360
+ {
361
+ id: "w4",
362
+ phase: "call",
363
+ name: "workflow_progress",
364
+ payload: {
365
+ workflow_id: "release_review",
366
+ items: [{ id: "run-tests", label: "Run tests", input: "Diff", output: "Results", validation: "Run suite", status: "done" }],
367
+ },
368
+ },
369
+ {
370
+ id: "w4",
371
+ phase: "result",
372
+ name: "workflow_progress",
373
+ payload: { ok: false, workflow_id: "release_review", error: "Every completed workflow item requires observed validation_evidence." },
374
+ },
375
+ ];
376
+
377
+ render(<ToolList events={events} />);
378
+ fireEvent.click(screen.getByText("workflow_progress"));
379
+
380
+ expect(screen.getByText("Update rejected: Every completed workflow item requires observed validation_evidence.")).toBeTruthy();
381
+ });
382
+
383
+ it("shows the attempt count on a workflow step that was retried", () => {
384
+ const snapshot = (id: string, status: string) => ({
385
+ workflow_id: "release_review",
386
+ items: [{ id: "run-tests", label: "Run tests", input: "Diff", output: "Results", validation: "Run suite", status }],
387
+ });
388
+ const result = (status: string) => ({
389
+ ok: true,
390
+ workflow_id: "release_review",
391
+ state: { phase: null, summary: "", error: null, checklist: snapshot("", status).items },
392
+ });
393
+ const events: ToolEvent[] = (["checking", "needs_attention", "checking"] as const).flatMap((status, i) => [
394
+ { id: `a${i}`, phase: "call" as const, name: "workflow_progress", payload: snapshot("", status) },
395
+ { id: `a${i}`, phase: "result" as const, name: "workflow_progress", payload: result(status) },
396
+ ]);
397
+
398
+ render(<ToolList events={events} />);
399
+ const rows = screen.getAllByText("workflow_progress");
400
+ fireEvent.click(rows[1]);
401
+ expect(screen.queryByText("attempt 2")).toBeNull();
402
+ fireEvent.click(rows[2]);
403
+ expect(screen.getByText("attempt 2")).toBeTruthy();
404
+ });
405
+
406
+ it("offers a per-step retry that asks the agent to redo that step", () => {
407
+ const onRetry = vi.fn();
408
+ const events: ToolEvent[] = [{
409
+ id: "w3",
410
+ phase: "call",
411
+ name: "workflow_progress",
412
+ payload: {
413
+ workflow_id: "release_review",
414
+ items: [
415
+ { id: "check-changes", label: "Review changes", input: "Diff", output: "Findings", validation: "Inspect files", validation_evidence: "Diff reviewed", status: "done" },
416
+ { id: "run-tests", label: "Run tests", input: "Findings", output: "Results", validation: "Run suite", status: "needs_attention" },
417
+ { id: "report-result", label: "Report result", input: "Results", output: "Summary", validation: "Cross-check" },
418
+ ],
419
+ },
420
+ }];
421
+
422
+ render(
423
+ <WorkflowStepRetryContext.Provider value={onRetry}>
424
+ <ToolList events={events} />
425
+ </WorkflowStepRetryContext.Provider>,
426
+ );
427
+ fireEvent.click(screen.getByText("workflow_progress"));
428
+
429
+ expect(screen.getByRole("button", { name: "Retry Review changes" })).toBeTruthy();
430
+ expect(screen.queryByRole("button", { name: "Retry Report result" })).toBeNull();
431
+ fireEvent.click(screen.getByRole("button", { name: "Retry Run tests" }));
432
+ expect(onRetry).toHaveBeenCalledWith({ workflowId: "release_review", itemId: "run-tests", label: "Run tests" });
433
+ expect(workflowStepRetryMessage({ workflowId: "release_review", itemId: "run-tests", label: "Run tests" }))
434
+ .toContain("complete items snapshot");
435
+ expect(workflowStepRetryMessage({ workflowId: "version_adoption", itemId: "adapt-settings", label: "Adapt settings" }))
436
+ .toContain('item_id: "adapt-settings"');
361
437
  });
362
438
 
363
439
  it("previews agent-created workflow items while the tool call is running", () => {
@@ -403,8 +479,8 @@ describe("ToolList — live progress (ADR-0073)", () => {
403
479
  expect(screen.getAllByText("Review changes").length).toBeGreaterThan(0);
404
480
  expect(screen.getAllByText("Run tests").length).toBeGreaterThan(0);
405
481
  expect(screen.getAllByText("Report result").length).toBeGreaterThan(0);
406
- expect(screen.getByLabelText("done")).toBeTruthy();
407
- expect(screen.getByLabelText("checking")).toBeTruthy();
482
+ expect(screen.getByRole("img", { name: "verified" })).toBeTruthy();
483
+ expect(screen.getByRole("img", { name: "checking" })).toBeTruthy();
408
484
  });
409
485
 
410
486
  it("renders an invoke_tool dispatch under the target tool's name, args and result", () => {
@@ -29,6 +29,7 @@ import {
29
29
  import { Badge } from "@/components/ui/Badge";
30
30
  import { CollapseChevron } from "@/components/ui/CollapseChevron";
31
31
  import { WorkflowChecklist, type WorkflowChecklistItemView, type WorkflowChecklistStatus } from "@/components/ui/WorkflowChecklist";
32
+ import { useWorkflowStepRetry } from "./workflow-step-retry";
32
33
  import { StructuredTurnCard } from "@/components/chat/StructuredTurnCard";
33
34
  import { MetaRow } from "@/components/ui/MetaRow";
34
35
  import { ProviderLogo, brandSlugForToolName } from "@/components/models/ProviderLogo";
@@ -263,6 +264,9 @@ interface ToolCallGroup {
263
264
  result: unknown;
264
265
  deadlineMs: number;
265
266
  status: "running" | "ok" | "error" | "async";
267
+ // workflow_progress only: per-step attempt counts so far in this message
268
+ // (how many times each item has entered `checking`).
269
+ workflowAttempts?: Readonly<Record<string, number>>;
266
270
  // True when this group's `result` arrived via a later tool_result_get
267
271
  // call rather than the original tool's direct return. Surfaces a small
268
272
  // "read" pill so it's obvious the agent reaped a background handoff.
@@ -386,7 +390,33 @@ function groupByCallId(events: ToolEvent[]): ToolCallGroup[] {
386
390
  g.absorbed = true;
387
391
  }
388
392
 
389
- return order.map((id) => map.get(id)!).filter((g) => !g.absorbed);
393
+ const groups = order.map((id) => map.get(id)!).filter((g) => !g.absorbed);
394
+ annotateWorkflowAttempts(groups);
395
+ return groups;
396
+ }
397
+
398
+ // Counts each workflow step's transitions into `checking` across the
399
+ // message's workflow_progress calls, so auto-retried steps show "attempt N".
400
+ // Rejected updates (ok:false) changed nothing and are not counted.
401
+ function annotateWorkflowAttempts(groups: ToolCallGroup[]): void {
402
+ const lastStatus = new Map<string, WorkflowChecklistStatus>();
403
+ const attempts = new Map<string, Record<string, number>>();
404
+ for (const group of groups) {
405
+ if (group.name !== "workflow_progress") continue;
406
+ if (coerceObject(unwrapLangChainSerializable(group.result))?.ok === false) continue;
407
+ const view = workflowViewFor(group);
408
+ if (!view) continue;
409
+ const counts = { ...(attempts.get(view.workflow_id) ?? {}) };
410
+ for (const item of view.items) {
411
+ const key = `${view.workflow_id}:${item.id}`;
412
+ if (item.status === "checking" && lastStatus.get(key) !== "checking") {
413
+ counts[item.id] = (counts[item.id] ?? 0) + 1;
414
+ }
415
+ lastStatus.set(key, item.status);
416
+ }
417
+ attempts.set(view.workflow_id, counts);
418
+ group.workflowAttempts = counts;
419
+ }
390
420
  }
391
421
 
392
422
  function ToolCallCard({ group, startedAt }: { group: ToolCallGroup; startedAt: number }) {
@@ -498,6 +528,7 @@ function ToolCallCard({ group, startedAt }: { group: ToolCallGroup; startedAt: n
498
528
  {open && (
499
529
  <div className="mt-0.5 rounded border border-border/40 bg-surface-2/30 px-2 py-1.5 space-y-1.5 text-[10px]">
500
530
  <WorkflowProgressDetails group={group} />
531
+ {!hasWorkflowView(group) && (<>
501
532
  {hasVisibleArgs(group.args) ? (
502
533
  <DetailSection label="arguments" value={group.args} />
503
534
  ) : hasArgs ? (
@@ -523,6 +554,7 @@ function ToolCallCard({ group, startedAt }: { group: ToolCallGroup; startedAt: n
523
554
  value={group.result}
524
555
  />
525
556
  )}
557
+ </>)}
526
558
  </div>
527
559
  )}
528
560
  </div>
@@ -617,19 +649,42 @@ function ToolResultRefDetails({ value }: { value: unknown }) {
617
649
  );
618
650
  }
619
651
 
620
- function WorkflowProgressDetails({ group }: { group: ToolCallGroup }) {
652
+ function workflowViewFor(group: ToolCallGroup): WorkflowProgressView | null {
621
653
  if (group.name !== "workflow_progress") return null;
622
- const workflow = workflowProgressFrom(group.result) ?? workflowProgressPreviewFrom(group.args);
654
+ const view = workflowProgressFrom(group.result) ?? workflowProgressPreviewFrom(group.args);
655
+ const result = coerceObject(unwrapLangChainSerializable(group.result));
656
+ const attempts = group.workflowAttempts;
657
+ const withAttempts = view && attempts
658
+ ? { ...view, items: view.items.map((item) => (attempts[item.id] ? { ...item, attempts: attempts[item.id] } : item)) }
659
+ : view;
660
+ if (withAttempts && result?.ok === false && typeof result.error === "string") {
661
+ return { ...withAttempts, error: `Update rejected: ${result.error}` };
662
+ }
663
+ return withAttempts;
664
+ }
665
+
666
+ /** Workflow rows show only their work items; raw payloads stay visible when the call failed. */
667
+ function hasWorkflowView(group: ToolCallGroup): boolean {
668
+ return group.status !== "error" && workflowViewFor(group) !== null;
669
+ }
670
+
671
+ function WorkflowProgressDetails({ group }: { group: ToolCallGroup }) {
672
+ const retryStep = useWorkflowStepRetry();
673
+ const workflow = workflowViewFor(group);
623
674
  if (!workflow) return null;
675
+ const workflowId = workflow.workflow_id;
624
676
  return (
625
677
  <WorkflowChecklist
626
678
  compact
627
679
  eyebrow="workflow"
628
- title={workflow.workflow_id.replace(/[_-]/g, " ")}
680
+ title={workflowId.replace(/[_-]/g, " ")}
629
681
  phaseLabel={workflow.phase ?? "in progress"}
630
682
  summary={workflow.summary ?? ""}
631
683
  items={workflow.items}
632
684
  error={workflow.error}
685
+ onRetryItem={retryStep
686
+ ? (item) => retryStep({ workflowId, itemId: item.id, label: item.label })
687
+ : undefined}
633
688
  />
634
689
  );
635
690
  }
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import type { Message } from "@/api/types";
3
- import { appendUnique, applyThreadMeta, type ThreadMetaApplier } from "./chat-helpers";
3
+ import { appendUnique, applyThreadMeta, compactionOutcomeToast, type ThreadMetaApplier } from "./chat-helpers";
4
4
 
5
5
  // created_at is display-only after the seq-ordering change — every fixture
6
6
  // shares one value to prove ordering doesn't depend on it. `seq` is omitted
@@ -115,10 +115,18 @@ describe("applyThreadMeta", () => {
115
115
  setWarmSummarySourceChars: push("warmSummarySourceChars") as (v: number | null) => void,
116
116
  setContextWindowTokens: push("contextWindowTokens") as (v: number | null) => void,
117
117
  setWarmSummaryPending: push("warmSummaryPending") as (v: boolean) => void,
118
+ setManualCompactionPending: push("manualCompactionPending") as (v: boolean) => void,
118
119
  },
119
120
  };
120
121
  }
121
122
 
123
+ it("restores a server-side manual /compact so a remounted view stays busy", () => {
124
+ const { meta, calls } = recorder();
125
+ applyThreadMeta(meta, { hot_since_seq: null, manual_compaction_pending: true });
126
+ applyThreadMeta(meta, { hot_since_seq: null });
127
+ expect(calls.manualCompactionPending).toEqual([true, false]);
128
+ });
129
+
122
130
  it("marks an observed hot_since as pending until its matching summary arrives", () => {
123
131
  const { meta, calls } = recorder();
124
132
 
@@ -148,3 +156,18 @@ describe("applyThreadMeta", () => {
148
156
  expect(calls.warmSummaryPending).toEqual([false]);
149
157
  });
150
158
  });
159
+
160
+ describe("compactionOutcomeToast", () => {
161
+ it("reports success with the summarised message count", () => {
162
+ expect(compactionOutcomeToast({ compacted: true, message_count: 2 })).toMatchObject({ kind: "success", body: "Summarised 2 messages into warm context." });
163
+ expect(compactionOutcomeToast({ compacted: true, message_count: 1 }).body).toBe("Summarised 1 message into warm context.");
164
+ expect(compactionOutcomeToast({ compacted: true, message_count: 0 }).body).toBe("Started a fresh context window.");
165
+ });
166
+
167
+ it("only says the conversation is empty when the server says so", () => {
168
+ expect(compactionOutcomeToast({ compacted: false, reason: "nothing to compact" }).title).toBe("Nothing to compact");
169
+ const declined = compactionOutcomeToast({ compacted: false, reason: "no summary produced" });
170
+ expect(declined.title).toBe("Nothing was compacted");
171
+ expect(declined.body).not.toMatch(/send some messages/i);
172
+ });
173
+ });
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import type { ContentPart, Message, SummaryTopicSegment } from "@/api/types";
2
+ import type { ContentPart, Message, SummaryTopicSegment, WarmChannelSummary } from "@/api/types";
3
3
 
4
4
  export interface QueuedMessage {
5
5
  id: string;
@@ -7,9 +7,46 @@ export interface QueuedMessage {
7
7
  attachments: ContentPart[];
8
8
  }
9
9
 
10
- export interface SystemNotice {
11
- id: string;
12
- text: string;
10
+ export interface CompactionOutcome {
11
+ compacted: boolean;
12
+ reason?: string;
13
+ message_count?: number;
14
+ }
15
+
16
+ export interface CompactionToast {
17
+ kind: "info" | "success" | "error";
18
+ title: string;
19
+ body: string;
20
+ }
21
+
22
+ // Maps the /compact response to the toast the user sees. The server's reason
23
+ // decides the text: "nothing to compact" means the thread is empty, anything
24
+ // else means there were messages but no summary came out of them.
25
+ export function compactionOutcomeToast(result: CompactionOutcome): CompactionToast {
26
+ if (result.compacted) {
27
+ const n = result.message_count ?? 0;
28
+ return {
29
+ kind: "success",
30
+ title: "Context compacted",
31
+ body: n > 0
32
+ ? `Summarised ${n} message${n === 1 ? "" : "s"} into warm context.`
33
+ : "Started a fresh context window.",
34
+ };
35
+ }
36
+ if (result.reason === "nothing to compact") {
37
+ return { kind: "info", title: "Nothing to compact", body: "This conversation has no messages yet." };
38
+ }
39
+ if (result.reason === "already compacting") {
40
+ return { kind: "info", title: "Already compacting", body: "A compaction for this conversation is still running." };
41
+ }
42
+ if (result.reason === "timed out") {
43
+ return { kind: "error", title: "Compaction timed out", body: "The summary took too long and was discarded. Context is unchanged." };
44
+ }
45
+ return {
46
+ kind: "info",
47
+ title: "Nothing was compacted",
48
+ body: "There was too little to summarise, or the model returned no usable summary. Context is unchanged.",
49
+ };
13
50
  }
14
51
 
15
52
  export interface ThreadMetaApplier {
@@ -22,9 +59,11 @@ export interface ThreadMetaApplier {
22
59
  setWarmSummarySourceMessages: (v: number | null) => void;
23
60
  setWarmSummarySourceChars: (v: number | null) => void;
24
61
  setWarmSummaryTopics?: (v: SummaryTopicSegment[] | null) => void;
62
+ setWarmChannelSummaries?: (v: WarmChannelSummary[]) => void;
25
63
  setContextWindowTokens: (v: number | null) => void;
26
64
  setWarmSummaryPending?: (v: boolean) => void;
27
65
  setCompactionPending?: (v: boolean) => void;
66
+ setManualCompactionPending?: (v: boolean) => void;
28
67
  }
29
68
 
30
69
  export interface ThreadGetPayload {
@@ -37,8 +76,10 @@ export interface ThreadGetPayload {
37
76
  warm_summary_source_messages?: number | null;
38
77
  warm_summary_source_chars?: number | null;
39
78
  warm_summary_topics?: SummaryTopicSegment[] | null;
79
+ warm_channel_summaries?: WarmChannelSummary[];
40
80
  pending_hot_since?: string | null;
41
81
  pending_hot_since_seq?: number | null;
82
+ manual_compaction_pending?: boolean;
42
83
  context_window_tokens?: number | null;
43
84
  }
44
85
 
@@ -128,10 +169,12 @@ export function applyThreadMeta(meta: ThreadMetaApplier, payload: ThreadGetPaylo
128
169
  meta.setWarmSummarySourceMessages(payload.warm_summary_source_messages ?? null);
129
170
  meta.setWarmSummarySourceChars(payload.warm_summary_source_chars ?? null);
130
171
  meta.setWarmSummaryTopics?.(payload.warm_summary_topics ?? null);
172
+ meta.setWarmChannelSummaries?.(payload.warm_channel_summaries ?? []);
131
173
  meta.setContextWindowTokens(payload.context_window_tokens ?? null);
132
174
  const summaryFresh = hotSinceSeq !== null && summaryBeforeSeq === hotSinceSeq;
133
175
  meta.setWarmSummaryPending?.(hotSinceSeq !== null && !summaryFresh);
134
176
  meta.setCompactionPending?.(payload.pending_hot_since_seq != null);
177
+ meta.setManualCompactionPending?.(payload.manual_compaction_pending === true);
135
178
  }
136
179
 
137
180
  export function makeQueuedId(prefix = "q"): string {
@@ -0,0 +1,113 @@
1
+ // @vitest-environment jsdom
2
+ import { act, renderHook } from "@testing-library/react";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import type { ThreadActivity } from "@/api/types";
5
+
6
+ const mocks = vi.hoisted(() => ({ activity: vi.fn(), getThread: vi.fn() }));
7
+
8
+ vi.mock("@/api/client", () => ({
9
+ api: {
10
+ threads: {
11
+ activity: (...args: unknown[]) => mocks.activity(...args),
12
+ get: (...args: unknown[]) => mocks.getThread(...args),
13
+ },
14
+ },
15
+ }));
16
+
17
+ const { useThreadActivity } = await import("./useThreadActivity");
18
+
19
+ const idle: ThreadActivity = { run: null, queue_depth: 0, compaction: null, busy: false };
20
+ const running: ThreadActivity = {
21
+ run: { phase: "thinking", label: "Thinking…", started_at: 1, agent_id: "a" },
22
+ queue_depth: 1,
23
+ compaction: null,
24
+ busy: true,
25
+ };
26
+ const compacting: ThreadActivity = {
27
+ run: null,
28
+ queue_depth: 0,
29
+ compaction: { kind: "manual", boundary_seq: 4, started_at: 1, deadline_at: 2 },
30
+ busy: true,
31
+ };
32
+
33
+ function metaApplier() {
34
+ return {
35
+ setHotSince: vi.fn(), setHotSinceSeq: vi.fn(), setWarmSummary: vi.fn(), setWarmSummaryBefore: vi.fn(),
36
+ setWarmSummaryBeforeSeq: vi.fn(), setWarmSummaryComputedAt: vi.fn(), setWarmSummarySourceMessages: vi.fn(),
37
+ setWarmSummarySourceChars: vi.fn(), setContextWindowTokens: vi.fn(), setWarmSummaryPending: vi.fn(),
38
+ setCompactionPending: vi.fn(), setManualCompactionPending: vi.fn(), setWarmSummaryTopics: vi.fn(),
39
+ setWarmChannelSummaries: vi.fn(),
40
+ };
41
+ }
42
+
43
+ async function tick(ms: number) {
44
+ await act(async () => { await vi.advanceTimersByTimeAsync(ms); });
45
+ }
46
+
47
+ describe("useThreadActivity", () => {
48
+ beforeEach(() => {
49
+ vi.useFakeTimers();
50
+ mocks.activity.mockReset();
51
+ mocks.getThread.mockReset();
52
+ mocks.getThread.mockResolvedValue({ messages: [], has_more: false });
53
+ });
54
+ afterEach(() => vi.useRealTimers());
55
+
56
+ it("attaches to a run started elsewhere when this client is not streaming", async () => {
57
+ mocks.activity.mockResolvedValue(running);
58
+ const attach = vi.fn().mockResolvedValue(undefined);
59
+ renderHook(() => useThreadActivity({
60
+ threadId: "t1", attach, isLive: () => false, lastSettledAt: () => 0, metaApplier: metaApplier(),
61
+ }));
62
+ await tick(1_500);
63
+ expect(attach).toHaveBeenCalledWith("t1");
64
+ });
65
+
66
+ it("does not attach while it owns a stream or right after one settled", async () => {
67
+ mocks.activity.mockResolvedValue(running);
68
+ const attach = vi.fn().mockResolvedValue(undefined);
69
+ let live = true;
70
+ renderHook(() => useThreadActivity({
71
+ threadId: "t1", attach, isLive: () => live, lastSettledAt: () => Date.now(), metaApplier: metaApplier(),
72
+ }));
73
+ await tick(1_500);
74
+ live = false;
75
+ await tick(1_500);
76
+ expect(attach).not.toHaveBeenCalled();
77
+ });
78
+
79
+ it("restores compaction flags and refreshes metadata once compaction ends", async () => {
80
+ mocks.activity.mockResolvedValueOnce(compacting).mockResolvedValue(idle);
81
+ const meta = metaApplier();
82
+ const { result } = renderHook(() => useThreadActivity({
83
+ threadId: "t1", attach: vi.fn(), isLive: () => false, lastSettledAt: () => 0, metaApplier: meta,
84
+ }));
85
+ await tick(1_500);
86
+ expect(result.current?.compaction?.kind).toBe("manual");
87
+ expect(meta.setCompactionPending).toHaveBeenCalledWith(true);
88
+ expect(meta.setManualCompactionPending).toHaveBeenCalledWith(true);
89
+ await tick(1_500);
90
+ expect(mocks.getThread).toHaveBeenCalledWith("t1", { limit: 1 });
91
+ expect(meta.setManualCompactionPending).toHaveBeenLastCalledWith(false);
92
+ });
93
+
94
+ it("clears compaction flags even if the metadata refresh fails", async () => {
95
+ mocks.activity.mockResolvedValueOnce(compacting).mockResolvedValue(idle);
96
+ mocks.getThread.mockRejectedValue(new Error("offline"));
97
+ const meta = metaApplier();
98
+ renderHook(() => useThreadActivity({
99
+ threadId: "t1", attach: vi.fn(), isLive: () => false, lastSettledAt: () => 0, metaApplier: meta,
100
+ }));
101
+ await tick(3_000);
102
+ expect(meta.setManualCompactionPending).toHaveBeenLastCalledWith(false);
103
+ expect(meta.setCompactionPending).toHaveBeenLastCalledWith(false);
104
+ });
105
+
106
+ it("does not poll without a thread", async () => {
107
+ renderHook(() => useThreadActivity({
108
+ threadId: null, attach: vi.fn(), isLive: () => false, lastSettledAt: () => 0, metaApplier: metaApplier(),
109
+ }));
110
+ await tick(10_000);
111
+ expect(mocks.activity).not.toHaveBeenCalled();
112
+ });
113
+ });
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { api } from "@/api/client";
4
+ import type { ThreadActivity } from "@/api/types";
5
+ import { applyThreadMeta, type ThreadMetaApplier } from "./chat-helpers";
6
+
7
+ const BUSY_POLL_MS = 1_500;
8
+ const IDLE_POLL_MS = 5_000;
9
+ // A run's stream ends a moment before the registry marks it finished; a
10
+ // snapshot inside this window may still report the run that just ended.
11
+ const SETTLE_GRACE_MS = 2_000;
12
+
13
+ interface Params {
14
+ threadId: string | null;
15
+ attach: (threadId: string) => Promise<unknown>;
16
+ /** Synchronous: does this client already own a live stream? */
17
+ isLive: () => boolean;
18
+ /** Epoch ms when this client's last stream settled. */
19
+ lastSettledAt: () => number;
20
+ metaApplier: ThreadMetaApplier;
21
+ }
22
+
23
+ /**
24
+ * Poll what the thread is doing on the server and keep the chat in step:
25
+ * re-attach to a turn started elsewhere (scheduler, watcher, bridge, another
26
+ * device), restore compaction flags after a remount, and refresh the thread
27
+ * metadata once a compaction finishes.
28
+ */
29
+ export function useThreadActivity({ threadId, attach, isLive, lastSettledAt, metaApplier }: Params): ThreadActivity | null {
30
+ const [activity, setActivity] = useState<ThreadActivity | null>(null);
31
+ const deps = useRef({ attach, isLive, lastSettledAt, metaApplier });
32
+ deps.current = { attach, isLive, lastSettledAt, metaApplier };
33
+
34
+ useEffect(() => {
35
+ setActivity(null);
36
+ if (!threadId) return;
37
+ let cancelled = false;
38
+ let timer: number | null = null;
39
+ let hadCompaction = false;
40
+
41
+ const schedule = (ms: number) => {
42
+ if (!cancelled) timer = window.setTimeout(tick, ms);
43
+ };
44
+
45
+ async function tick() {
46
+ if (cancelled || !threadId) return;
47
+ if (typeof document !== "undefined" && document.hidden) { schedule(IDLE_POLL_MS); return; }
48
+ let next: ThreadActivity;
49
+ try {
50
+ next = await api.threads.activity(threadId);
51
+ } catch {
52
+ schedule(IDLE_POLL_MS);
53
+ return;
54
+ }
55
+ if (cancelled) return;
56
+ setActivity(next);
57
+ const d = deps.current;
58
+
59
+ const serverRunning = next.run !== null || next.queue_depth > 0;
60
+ const recentlySettled = Date.now() - d.lastSettledAt() < SETTLE_GRACE_MS;
61
+ if (serverRunning && !d.isLive() && !recentlySettled) {
62
+ d.attach(threadId).catch(() => { /* best-effort */ });
63
+ }
64
+
65
+ if (next.compaction) {
66
+ if (next.compaction.kind !== "refresh") d.metaApplier.setCompactionPending?.(true);
67
+ if (next.compaction.kind === "manual") d.metaApplier.setManualCompactionPending?.(true);
68
+ hadCompaction = true;
69
+ } else if (hadCompaction) {
70
+ hadCompaction = false;
71
+ // The compaction just finished. Clear the flags from the snapshot
72
+ // itself so a failed refresh below can't leave the chat locked, then
73
+ // pull the new boundary and recap.
74
+ d.metaApplier.setCompactionPending?.(false);
75
+ d.metaApplier.setManualCompactionPending?.(false);
76
+ api.threads.get(threadId, { limit: 1 })
77
+ .then((meta) => { if (!cancelled) applyThreadMeta(deps.current.metaApplier, meta); })
78
+ .catch(() => { /* next poll retries */ });
79
+ }
80
+
81
+ schedule(next.busy ? BUSY_POLL_MS : IDLE_POLL_MS);
82
+ }
83
+
84
+ // The thread load attaches to any in-flight run itself; give it a beat
85
+ // so this poller doesn't race it with a second attach.
86
+ schedule(BUSY_POLL_MS);
87
+ return () => {
88
+ cancelled = true;
89
+ if (timer !== null) window.clearTimeout(timer);
90
+ };
91
+ }, [threadId]);
92
+
93
+ return activity;
94
+ }