@circuitwall/jarela 2.2.0 → 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 (683) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +4 -3
  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 +204 -163
  136. package/.next/standalone/.next/server/app/api/v1/models/route.js +548 -546
  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 +71 -68
  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 +1170 -719
  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 +4 -3
  221. package/.next/standalone/.next/server/chunks/{424.js → 1388.js} +345 -991
  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 +45 -45
  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 +10695 -10695
  233. package/.next/standalone/.next/server/chunks/3524.js +5 -33
  234. package/.next/standalone/.next/server/chunks/3566.js +1 -1
  235. package/.next/standalone/.next/server/chunks/4189.js +946 -0
  236. package/.next/standalone/.next/server/chunks/{9590.js → 423.js} +116 -49
  237. package/.next/standalone/.next/server/chunks/4433.js +146 -146
  238. package/.next/standalone/.next/server/chunks/4508.js +3 -3
  239. package/.next/standalone/.next/server/chunks/4588.js +1 -0
  240. package/.next/standalone/.next/server/chunks/46.js +116 -46
  241. package/.next/standalone/.next/server/chunks/466.js +100 -13
  242. package/.next/standalone/.next/server/chunks/4868.js +206 -206
  243. package/.next/standalone/.next/server/chunks/4992.js +13 -0
  244. package/.next/standalone/.next/server/chunks/5120.js +963 -0
  245. package/.next/standalone/.next/server/chunks/5701.js +1 -1
  246. package/.next/standalone/.next/server/chunks/5900.js +1 -1
  247. package/.next/standalone/.next/server/chunks/6210.js +1 -0
  248. package/.next/standalone/.next/server/chunks/6213.js +1 -1
  249. package/.next/standalone/.next/server/chunks/6649.js +3 -3
  250. package/.next/standalone/.next/server/chunks/6703.js +3 -3
  251. package/.next/standalone/.next/server/chunks/7445.js +1 -0
  252. package/.next/standalone/.next/server/chunks/8067.js +12 -0
  253. package/.next/standalone/.next/server/chunks/8461.js +14 -9
  254. package/.next/standalone/.next/server/chunks/8558.js +1 -1
  255. package/.next/standalone/.next/server/chunks/8724.js +1 -1
  256. package/.next/standalone/.next/server/chunks/8849.js +91 -91
  257. package/.next/standalone/.next/server/chunks/9032.js +6 -5
  258. package/.next/standalone/.next/server/chunks/{2563.js → 9164.js} +33106 -31420
  259. package/.next/standalone/.next/server/chunks/9237.js +396 -396
  260. package/.next/standalone/.next/server/chunks/{9640.js → 9304.js} +1628 -573
  261. package/.next/standalone/.next/server/chunks/9406.js +1 -1
  262. package/.next/standalone/.next/server/chunks/9824.js +98 -98
  263. package/.next/standalone/.next/server/chunks/9826.js +1 -0
  264. package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
  265. package/.next/standalone/.next/server/middleware.js +519 -442
  266. package/.next/standalone/.next/server/pages/404.html +2 -2
  267. package/.next/standalone/.next/server/pages/500.html +1 -1
  268. package/.next/standalone/.next/server/preview-props.json +3 -3
  269. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  270. package/.next/standalone/.next/static/chunks/{1395-f201e3e2e1f57715.js → 1395-e4a99912b8f83044.js} +101 -14
  271. package/.next/standalone/.next/static/chunks/{4576-13f7546a145a3624.js → 7045-8bc2f14e430ca661.js} +58 -2
  272. package/.next/standalone/.next/static/chunks/app/_global-error/{page-36cb8b428b38b26a.js → page-6fc5f8e744c81802.js} +1 -1
  273. package/.next/standalone/.next/static/chunks/app/api/v1/access/[identity]/{route-36cb8b428b38b26a.js → route-6fc5f8e744c81802.js} +1 -1
  274. package/.next/standalone/.next/static/chunks/app/api/v1/access/{route-36cb8b428b38b26a.js → route-6fc5f8e744c81802.js} +1 -1
  275. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/compact/{route-36cb8b428b38b26a.js → route-6fc5f8e744c81802.js} +1 -1
  276. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/display-filters/route-6fc5f8e744c81802.js +17 -0
  277. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/route-6fc5f8e744c81802.js +17 -0
  278. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/thread/route-6fc5f8e744c81802.js +17 -0
  279. package/.next/standalone/.next/static/chunks/app/api/v1/agents/route-6fc5f8e744c81802.js +17 -0
  280. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/[hostname]/route-6fc5f8e744c81802.js +17 -0
  281. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/route-6fc5f8e744c81802.js +17 -0
  282. package/.next/standalone/.next/static/chunks/app/api/v1/artifacts/lifecycle/route-6fc5f8e744c81802.js +17 -0
  283. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/files/route-6fc5f8e744c81802.js +17 -0
  284. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/images/route-6fc5f8e744c81802.js +17 -0
  285. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/chats/route-6fc5f8e744c81802.js +17 -0
  286. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/[remote_jid]/route-6fc5f8e744c81802.js +17 -0
  287. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/route-6fc5f8e744c81802.js +17 -0
  288. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/lookup/route-6fc5f8e744c81802.js +17 -0
  289. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/pair/route-6fc5f8e744c81802.js +17 -0
  290. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/route-6fc5f8e744c81802.js +17 -0
  291. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/[route_id]/route-6fc5f8e744c81802.js +17 -0
  292. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/route-6fc5f8e744c81802.js +17 -0
  293. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/status/route-6fc5f8e744c81802.js +17 -0
  294. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/kinds/route-6fc5f8e744c81802.js +17 -0
  295. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/route-6fc5f8e744c81802.js +17 -0
  296. package/.next/standalone/.next/static/chunks/app/api/v1/builtin-tools/route-6fc5f8e744c81802.js +17 -0
  297. package/.next/standalone/.next/static/chunks/app/api/v1/config/route-6fc5f8e744c81802.js +17 -0
  298. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/[id]/route-6fc5f8e744c81802.js +17 -0
  299. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/route-6fc5f8e744c81802.js +17 -0
  300. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/currency/route-6fc5f8e744c81802.js +17 -0
  301. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/metrics/route-6fc5f8e744c81802.js +17 -0
  302. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing/route-6fc5f8e744c81802.js +17 -0
  303. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing-task/route-6fc5f8e744c81802.js +17 -0
  304. package/.next/standalone/.next/static/chunks/app/api/v1/delegations/codex/[job_id]/route-6fc5f8e744c81802.js +17 -0
  305. package/.next/standalone/.next/static/chunks/app/api/v1/documents/search/route-6fc5f8e744c81802.js +17 -0
  306. package/.next/standalone/.next/static/chunks/app/api/v1/documents/settings/route-6fc5f8e744c81802.js +17 -0
  307. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/reindex/route-6fc5f8e744c81802.js +17 -0
  308. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/route-6fc5f8e744c81802.js +17 -0
  309. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/route-6fc5f8e744c81802.js +17 -0
  310. package/.next/standalone/.next/static/chunks/app/api/v1/env/route-6fc5f8e744c81802.js +17 -0
  311. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/allowlist/route-6fc5f8e744c81802.js +17 -0
  312. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/route-6fc5f8e744c81802.js +17 -0
  313. package/.next/standalone/.next/static/chunks/app/api/v1/events/route-6fc5f8e744c81802.js +17 -0
  314. package/.next/standalone/.next/static/chunks/app/api/v1/events/test/route-6fc5f8e744c81802.js +17 -0
  315. package/.next/standalone/.next/static/chunks/app/api/v1/extension/agents/route-6fc5f8e744c81802.js +17 -0
  316. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/activate/route-6fc5f8e744c81802.js +17 -0
  317. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/foreground/route-6fc5f8e744c81802.js +17 -0
  318. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/history/route-6fc5f8e744c81802.js +17 -0
  319. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/poll/route-6fc5f8e744c81802.js +17 -0
  320. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/progress/route-6fc5f8e744c81802.js +17 -0
  321. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/result/route-6fc5f8e744c81802.js +17 -0
  322. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/retry/route-6fc5f8e744c81802.js +17 -0
  323. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/status/route-6fc5f8e744c81802.js +17 -0
  324. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/tabs/route-6fc5f8e744c81802.js +17 -0
  325. package/.next/standalone/.next/static/chunks/app/api/v1/extension/fill/route-6fc5f8e744c81802.js +17 -0
  326. package/.next/standalone/.next/static/chunks/app/api/v1/extension/refine/route-6fc5f8e744c81802.js +17 -0
  327. package/.next/standalone/.next/static/chunks/app/api/v1/extension/turn/route-6fc5f8e744c81802.js +17 -0
  328. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/route-6fc5f8e744c81802.js +17 -0
  329. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/config/route-6fc5f8e744c81802.js +17 -0
  330. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/route-6fc5f8e744c81802.js +17 -0
  331. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/secrets/route-6fc5f8e744c81802.js +17 -0
  332. package/.next/standalone/.next/static/chunks/app/api/v1/files/[name]/route-6fc5f8e744c81802.js +17 -0
  333. package/.next/standalone/.next/static/chunks/app/api/v1/fs/browse/route-6fc5f8e744c81802.js +17 -0
  334. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/[id]/route-6fc5f8e744c81802.js +17 -0
  335. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/default/route-6fc5f8e744c81802.js +17 -0
  336. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/route-6fc5f8e744c81802.js +17 -0
  337. package/.next/standalone/.next/static/chunks/app/api/v1/health/probes/route-6fc5f8e744c81802.js +17 -0
  338. package/.next/standalone/.next/static/chunks/app/api/v1/health/route-6fc5f8e744c81802.js +17 -0
  339. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/route-6fc5f8e744c81802.js +17 -0
  340. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/test/route-6fc5f8e744c81802.js +17 -0
  341. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/callback/route-6fc5f8e744c81802.js +17 -0
  342. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/start/route-6fc5f8e744c81802.js +17 -0
  343. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/status/route-6fc5f8e744c81802.js +17 -0
  344. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/callback/route-6fc5f8e744c81802.js +17 -0
  345. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/start/route-6fc5f8e744c81802.js +17 -0
  346. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/status/route-6fc5f8e744c81802.js +17 -0
  347. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/route-6fc5f8e744c81802.js +17 -0
  348. package/.next/standalone/.next/static/chunks/app/api/v1/lifecycle/adoption/route-6fc5f8e744c81802.js +17 -0
  349. package/.next/standalone/.next/static/chunks/app/api/v1/local-file/route-6fc5f8e744c81802.js +17 -0
  350. package/.next/standalone/.next/static/chunks/app/api/v1/logs/route-6fc5f8e744c81802.js +17 -0
  351. package/.next/standalone/.next/static/chunks/app/api/v1/maps/embed/route-6fc5f8e744c81802.js +17 -0
  352. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/[name]/route-6fc5f8e744c81802.js +17 -0
  353. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/registry/route-6fc5f8e744c81802.js +17 -0
  354. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/route-6fc5f8e744c81802.js +17 -0
  355. package/.next/standalone/.next/static/chunks/app/api/v1/memory/[namespace]/[key]/route-6fc5f8e744c81802.js +17 -0
  356. package/.next/standalone/.next/static/chunks/app/api/v1/memory/policy/route-6fc5f8e744c81802.js +17 -0
  357. package/.next/standalone/.next/static/chunks/app/api/v1/memory/route-6fc5f8e744c81802.js +17 -0
  358. package/.next/standalone/.next/static/chunks/app/api/v1/memory/search/route-6fc5f8e744c81802.js +17 -0
  359. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/compact-threads/route-6fc5f8e744c81802.js +17 -0
  360. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/route-6fc5f8e744c81802.js +17 -0
  361. package/.next/standalone/.next/static/chunks/app/api/v1/models/route-6fc5f8e744c81802.js +17 -0
  362. package/.next/standalone/.next/static/chunks/app/api/v1/packages/catalog/route-6fc5f8e744c81802.js +17 -0
  363. package/.next/standalone/.next/static/chunks/app/api/v1/packages/defaults/[id]/route-6fc5f8e744c81802.js +17 -0
  364. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/[id]/route-6fc5f8e744c81802.js +17 -0
  365. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/route-6fc5f8e744c81802.js +17 -0
  366. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/enabled/route-6fc5f8e744c81802.js +17 -0
  367. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/route-6fc5f8e744c81802.js +17 -0
  368. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/route-6fc5f8e744c81802.js +17 -0
  369. package/.next/standalone/.next/static/chunks/app/api/v1/packages/reload/route-6fc5f8e744c81802.js +17 -0
  370. package/.next/standalone/.next/static/chunks/app/api/v1/packages/route-6fc5f8e744c81802.js +17 -0
  371. package/.next/standalone/.next/static/chunks/app/api/v1/page-capture/route-6fc5f8e744c81802.js +17 -0
  372. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/approve/route-6fc5f8e744c81802.js +17 -0
  373. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/deny/route-6fc5f8e744c81802.js +17 -0
  374. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/route-6fc5f8e744c81802.js +17 -0
  375. package/.next/standalone/.next/static/chunks/app/api/v1/profile/location/route-6fc5f8e744c81802.js +17 -0
  376. package/.next/standalone/.next/static/chunks/app/api/v1/profile/route-6fc5f8e744c81802.js +17 -0
  377. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/models/route-6fc5f8e744c81802.js +17 -0
  378. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/probe/route-6fc5f8e744c81802.js +17 -0
  379. package/.next/standalone/.next/static/chunks/app/api/v1/providers/github-copilot/auth/route-6fc5f8e744c81802.js +17 -0
  380. package/.next/standalone/.next/static/chunks/app/api/v1/providers/route-6fc5f8e744c81802.js +17 -0
  381. package/.next/standalone/.next/static/chunks/app/api/v1/proxy-config/route-6fc5f8e744c81802.js +17 -0
  382. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/init/route-6fc5f8e744c81802.js +17 -0
  383. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/route-6fc5f8e744c81802.js +17 -0
  384. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/route-6fc5f8e744c81802.js +17 -0
  385. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/run/route-6fc5f8e744c81802.js +17 -0
  386. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/route-6fc5f8e744c81802.js +17 -0
  387. package/.next/standalone/.next/static/chunks/app/api/v1/security/idle-timeout/route-6fc5f8e744c81802.js +17 -0
  388. package/.next/standalone/.next/static/chunks/app/api/v1/security/pin/route-6fc5f8e744c81802.js +17 -0
  389. package/.next/standalone/.next/static/chunks/app/api/v1/security/state/route-6fc5f8e744c81802.js +17 -0
  390. package/.next/standalone/.next/static/chunks/app/api/v1/security/unlock/route-6fc5f8e744c81802.js +17 -0
  391. package/.next/standalone/.next/static/chunks/app/api/v1/security/verify-pin/route-6fc5f8e744c81802.js +17 -0
  392. package/.next/standalone/.next/static/chunks/app/api/v1/setup/test-key/route-6fc5f8e744c81802.js +17 -0
  393. package/.next/standalone/.next/static/chunks/app/api/v1/skills/[id]/route-6fc5f8e744c81802.js +17 -0
  394. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/[id]/route-6fc5f8e744c81802.js +17 -0
  395. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/route-6fc5f8e744c81802.js +17 -0
  396. package/.next/standalone/.next/static/chunks/app/api/v1/skills/route-6fc5f8e744c81802.js +17 -0
  397. package/.next/standalone/.next/static/chunks/app/api/v1/system/abort/route-6fc5f8e744c81802.js +17 -0
  398. package/.next/standalone/.next/static/chunks/app/api/v1/system/restart/route-6fc5f8e744c81802.js +17 -0
  399. package/.next/standalone/.next/static/chunks/app/api/v1/tailscale/route-6fc5f8e744c81802.js +17 -0
  400. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/[agent_id]/route-6fc5f8e744c81802.js +17 -0
  401. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/route-6fc5f8e744c81802.js +17 -0
  402. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/activity/route-6fc5f8e744c81802.js +17 -0
  403. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/context-pin/route-6fc5f8e744c81802.js +17 -0
  404. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/route-6fc5f8e744c81802.js +17 -0
  405. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/run/route-6fc5f8e744c81802.js +17 -0
  406. package/.next/standalone/.next/static/chunks/app/api/v1/threads/route-6fc5f8e744c81802.js +17 -0
  407. package/.next/standalone/.next/static/chunks/app/api/v1/tools/route-6fc5f8e744c81802.js +17 -0
  408. package/.next/standalone/.next/static/chunks/app/api/v1/update/apply/route-6fc5f8e744c81802.js +17 -0
  409. package/.next/standalone/.next/static/chunks/app/api/v1/update/route-6fc5f8e744c81802.js +17 -0
  410. package/.next/standalone/.next/static/chunks/app/api/v1/voice/transcribe/route-6fc5f8e744c81802.js +17 -0
  411. package/.next/standalone/.next/static/chunks/app/api/v1/voice/tts/route-6fc5f8e744c81802.js +17 -0
  412. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/route-6fc5f8e744c81802.js +17 -0
  413. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/run/route-6fc5f8e744c81802.js +17 -0
  414. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/reaction-scripts/route-6fc5f8e744c81802.js +17 -0
  415. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/route-6fc5f8e744c81802.js +17 -0
  416. package/.next/standalone/.next/static/chunks/app/manifest.webmanifest/route-6fc5f8e744c81802.js +17 -0
  417. package/.next/standalone/.next/static/chunks/app/{page-c6e972a7fd13dae8.js → page-213a623b37226452.js} +1012 -604
  418. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-6fc5f8e744c81802.js +17 -0
  419. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-6fc5f8e744c81802.js +17 -0
  420. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-6fc5f8e744c81802.js +17 -0
  421. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-6fc5f8e744c81802.js +17 -0
  422. package/.next/standalone/.next/static/css/{d80058f0b9b41c09.css → 312542a5725ba0d5.css} +2 -2
  423. package/.next/standalone/docs/adoption/changesets.json +309 -0
  424. package/.next/standalone/lib/skills/builtins/memory-organization/SKILL.md +16 -0
  425. package/.next/standalone/package.json +3 -3
  426. package/CHANGELOG.md +33 -0
  427. package/api/client.models.test.ts +31 -0
  428. package/api/client.ts +25 -1
  429. package/api/types.ts +37 -0
  430. package/app/api/v1/lifecycle/adoption/route.ts +14 -2
  431. package/app/api/v1/models/[name]/compact-threads/route.ts +14 -11
  432. package/app/api/v1/models/[name]/route.test.ts +89 -0
  433. package/app/api/v1/models/[name]/route.ts +54 -3
  434. package/app/api/v1/models/route.ts +4 -2
  435. package/app/api/v1/providers/[provider]/models/route.test.ts +53 -0
  436. package/app/api/v1/providers/[provider]/models/route.ts +27 -16
  437. package/app/api/v1/threads/[thread_id]/activity/route.ts +19 -0
  438. package/app/api/v1/threads/[thread_id]/context-pin/route.test.ts +1 -0
  439. package/app/api/v1/threads/[thread_id]/context-pin/route.ts +2 -1
  440. package/app/api/v1/threads/[thread_id]/route.ts +5 -1
  441. package/components/agents/agent-editor/AdvancedSection.tsx +8 -2
  442. package/components/agents/agent-editor/ModelSection.tsx +6 -3
  443. package/components/chat/ChatView.tsx +52 -11
  444. package/components/chat/ContextBoundary.test.tsx +68 -1
  445. package/components/chat/ContextBoundary.tsx +92 -13
  446. package/components/chat/MessageList.test.tsx +31 -0
  447. package/components/chat/MessageList.tsx +49 -28
  448. package/components/chat/ToolList.test.tsx +92 -16
  449. package/components/chat/ToolList.tsx +59 -4
  450. package/components/chat/chat-helpers.test.tsx +24 -1
  451. package/components/chat/chat-helpers.ts +47 -4
  452. package/components/chat/useThreadActivity.test.tsx +113 -0
  453. package/components/chat/useThreadActivity.ts +94 -0
  454. package/components/chat/useThreadData.ts +16 -16
  455. package/components/chat/workflow-step-retry.ts +25 -0
  456. package/components/models/ModelEditor.tsx +1 -1
  457. package/components/models/ModelsPanel.tsx +34 -8
  458. package/components/models/model-editor/GitHubCopilotAuth.tsx +1 -1
  459. package/components/models/model-editor/save-helpers.ts +2 -2
  460. package/components/models/model-editor/useModelEditorForm.ts +1 -1
  461. package/components/models/model-editor/useModelSaveHandlers.ts +1 -1
  462. package/components/setup/wizard/StepCredentials.tsx +1 -1
  463. package/components/setup/wizard/StepModel.tsx +3 -8
  464. package/components/ui/BootScreen.tsx +17 -0
  465. package/components/ui/WorkflowChecklist.tsx +71 -33
  466. package/hooks/useModels.ts +17 -1
  467. package/hooks/useSSE.ts +28 -3
  468. package/lib/agents/compaction-pipeline.test.ts +202 -0
  469. package/lib/agents/compaction-pipeline.ts +483 -0
  470. package/lib/agents/conversation-summary.ts +37 -21
  471. package/lib/agents/effective-model.test.ts +45 -0
  472. package/lib/agents/effective-model.ts +11 -5
  473. package/lib/agents/llm.ts +2 -2
  474. package/lib/agents/prepare/history-window.test.ts +18 -0
  475. package/lib/agents/prepare/history-window.ts +11 -2
  476. package/lib/agents/prepare/request.ts +4 -0
  477. package/lib/agents/prepare/system-prompt.test.ts +39 -0
  478. package/lib/agents/prepare/system-prompt.ts +8 -3
  479. package/lib/agents/prompt-registry.test.ts +5 -140
  480. package/lib/agents/prompt-registry.ts +45 -1
  481. package/lib/agents/prompt-variants.ts +146 -0
  482. package/lib/agents/run-registry.test.ts +22 -0
  483. package/lib/agents/run-registry.ts +29 -0
  484. package/lib/agents/run-thread.retry.test.ts +67 -1
  485. package/lib/agents/run-thread.ts +96 -6
  486. package/lib/agents/thread-activity.test.ts +31 -0
  487. package/lib/agents/thread-activity.ts +27 -0
  488. package/lib/agents/thread-compaction-state.test.ts +82 -0
  489. package/lib/agents/thread-compaction-state.ts +121 -0
  490. package/lib/agents/thread-compaction.test.ts +83 -4
  491. package/lib/agents/thread-compaction.ts +34 -11
  492. package/lib/agents/warm-summary-background.test.ts +220 -7
  493. package/lib/agents/warm-summary-background.ts +329 -149
  494. package/lib/agents/warm-topics.test.ts +37 -0
  495. package/lib/agents/warm-topics.ts +297 -0
  496. package/lib/agents/workflow-step-retry.test.ts +96 -0
  497. package/lib/agents/workflow-step-retry.ts +216 -0
  498. package/lib/api/browser-control.ts +0 -3
  499. package/lib/db/migrations.ts +15 -0
  500. package/lib/env/config.ts +2 -0
  501. package/lib/env/schema.ts +12 -0
  502. package/lib/health/probes.test.ts +8 -11
  503. package/lib/health/probes.ts +5 -31
  504. package/lib/lifecycle/changeset-build.test.ts +93 -0
  505. package/lib/lifecycle/changeset-build.ts +210 -0
  506. package/lib/lifecycle/changesets.test.ts +101 -0
  507. package/lib/lifecycle/changesets.ts +166 -0
  508. package/lib/lifecycle/surface-collect.test.ts +88 -0
  509. package/lib/lifecycle/surface-collect.ts +64 -0
  510. package/lib/lifecycle/surface-snapshot.test.ts +104 -0
  511. package/lib/lifecycle/surface-snapshot.ts +210 -0
  512. package/lib/memory/record.ts +0 -2
  513. package/lib/models/editor-payload.ts +1 -1
  514. package/lib/providers/external.ts +0 -2
  515. package/lib/providers/github-copilot-auth.ts +2 -3
  516. package/lib/providers/github-copilot.test.ts +27 -0
  517. package/lib/providers/github-copilot.ts +21 -44
  518. package/lib/skills/builtins/memory-organization/SKILL.md +16 -0
  519. package/lib/stores/integrations.test.ts +7 -0
  520. package/lib/stores/integrations.ts +4 -4
  521. package/lib/stores/model-config.test.ts +88 -0
  522. package/lib/stores/model-config.ts +90 -8
  523. package/lib/stores/threads.test.ts +9 -0
  524. package/lib/stores/threads.ts +21 -11
  525. package/lib/stores/version-adoption.test.ts +96 -0
  526. package/lib/stores/version-adoption.ts +239 -26
  527. package/lib/stores/workflow-progress.ts +3 -0
  528. package/lib/tools/communications/ms-todo.ts +0 -7
  529. package/lib/tools/general/memory.ts +1 -1
  530. package/lib/tools/general/workflow-progress.ts +2 -0
  531. package/lib/tools/runtime/catalog.ts +1 -25
  532. package/lib/triggers/registry.ts +0 -4
  533. package/package.json +3 -3
  534. package/scripts/install-to-system.ps1 +39 -11
  535. package/scripts/install-to-system.sh +37 -3
  536. package/.next/standalone/.next/server/chunks/3979.js +0 -581
  537. package/.next/standalone/.next/server/chunks/5936.js +0 -594
  538. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/display-filters/route-36cb8b428b38b26a.js +0 -17
  539. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/route-36cb8b428b38b26a.js +0 -17
  540. package/.next/standalone/.next/static/chunks/app/api/v1/agents/[id]/thread/route-36cb8b428b38b26a.js +0 -17
  541. package/.next/standalone/.next/static/chunks/app/api/v1/agents/route-36cb8b428b38b26a.js +0 -17
  542. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/[hostname]/route-36cb8b428b38b26a.js +0 -17
  543. package/.next/standalone/.next/static/chunks/app/api/v1/allowed-sites/route-36cb8b428b38b26a.js +0 -17
  544. package/.next/standalone/.next/static/chunks/app/api/v1/artifacts/lifecycle/route-36cb8b428b38b26a.js +0 -17
  545. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/files/route-36cb8b428b38b26a.js +0 -17
  546. package/.next/standalone/.next/static/chunks/app/api/v1/attachments/images/route-36cb8b428b38b26a.js +0 -17
  547. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/chats/route-36cb8b428b38b26a.js +0 -17
  548. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/[remote_jid]/route-36cb8b428b38b26a.js +0 -17
  549. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/ignores/route-36cb8b428b38b26a.js +0 -17
  550. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/lookup/route-36cb8b428b38b26a.js +0 -17
  551. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/pair/route-36cb8b428b38b26a.js +0 -17
  552. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/route-36cb8b428b38b26a.js +0 -17
  553. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/[route_id]/route-36cb8b428b38b26a.js +0 -17
  554. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/routes/route-36cb8b428b38b26a.js +0 -17
  555. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/[id]/status/route-36cb8b428b38b26a.js +0 -17
  556. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/kinds/route-36cb8b428b38b26a.js +0 -17
  557. package/.next/standalone/.next/static/chunks/app/api/v1/bridges/route-36cb8b428b38b26a.js +0 -17
  558. package/.next/standalone/.next/static/chunks/app/api/v1/builtin-tools/route-36cb8b428b38b26a.js +0 -17
  559. package/.next/standalone/.next/static/chunks/app/api/v1/config/route-36cb8b428b38b26a.js +0 -17
  560. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/[id]/route-36cb8b428b38b26a.js +0 -17
  561. package/.next/standalone/.next/static/chunks/app/api/v1/credentials/route-36cb8b428b38b26a.js +0 -17
  562. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/currency/route-36cb8b428b38b26a.js +0 -17
  563. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/metrics/route-36cb8b428b38b26a.js +0 -17
  564. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing/route-36cb8b428b38b26a.js +0 -17
  565. package/.next/standalone/.next/static/chunks/app/api/v1/dashboard/pricing-task/route-36cb8b428b38b26a.js +0 -17
  566. package/.next/standalone/.next/static/chunks/app/api/v1/delegations/codex/[job_id]/route-36cb8b428b38b26a.js +0 -17
  567. package/.next/standalone/.next/static/chunks/app/api/v1/documents/search/route-36cb8b428b38b26a.js +0 -17
  568. package/.next/standalone/.next/static/chunks/app/api/v1/documents/settings/route-36cb8b428b38b26a.js +0 -17
  569. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/reindex/route-36cb8b428b38b26a.js +0 -17
  570. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/[id]/route-36cb8b428b38b26a.js +0 -17
  571. package/.next/standalone/.next/static/chunks/app/api/v1/documents/sources/route-36cb8b428b38b26a.js +0 -17
  572. package/.next/standalone/.next/static/chunks/app/api/v1/env/route-36cb8b428b38b26a.js +0 -17
  573. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/allowlist/route-36cb8b428b38b26a.js +0 -17
  574. package/.next/standalone/.next/static/chunks/app/api/v1/env-sync/route-36cb8b428b38b26a.js +0 -17
  575. package/.next/standalone/.next/static/chunks/app/api/v1/events/route-36cb8b428b38b26a.js +0 -17
  576. package/.next/standalone/.next/static/chunks/app/api/v1/events/test/route-36cb8b428b38b26a.js +0 -17
  577. package/.next/standalone/.next/static/chunks/app/api/v1/extension/agents/route-36cb8b428b38b26a.js +0 -17
  578. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/activate/route-36cb8b428b38b26a.js +0 -17
  579. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/foreground/route-36cb8b428b38b26a.js +0 -17
  580. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/history/route-36cb8b428b38b26a.js +0 -17
  581. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/poll/route-36cb8b428b38b26a.js +0 -17
  582. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/progress/route-36cb8b428b38b26a.js +0 -17
  583. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/result/route-36cb8b428b38b26a.js +0 -17
  584. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/retry/route-36cb8b428b38b26a.js +0 -17
  585. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/status/route-36cb8b428b38b26a.js +0 -17
  586. package/.next/standalone/.next/static/chunks/app/api/v1/extension/browser/tabs/route-36cb8b428b38b26a.js +0 -17
  587. package/.next/standalone/.next/static/chunks/app/api/v1/extension/fill/route-36cb8b428b38b26a.js +0 -17
  588. package/.next/standalone/.next/static/chunks/app/api/v1/extension/refine/route-36cb8b428b38b26a.js +0 -17
  589. package/.next/standalone/.next/static/chunks/app/api/v1/extension/turn/route-36cb8b428b38b26a.js +0 -17
  590. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/route-36cb8b428b38b26a.js +0 -17
  591. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/config/route-36cb8b428b38b26a.js +0 -17
  592. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/route-36cb8b428b38b26a.js +0 -17
  593. package/.next/standalone/.next/static/chunks/app/api/v1/extensions/tools/[name]/secrets/route-36cb8b428b38b26a.js +0 -17
  594. package/.next/standalone/.next/static/chunks/app/api/v1/files/[name]/route-36cb8b428b38b26a.js +0 -17
  595. package/.next/standalone/.next/static/chunks/app/api/v1/fs/browse/route-36cb8b428b38b26a.js +0 -17
  596. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/[id]/route-36cb8b428b38b26a.js +0 -17
  597. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/default/route-36cb8b428b38b26a.js +0 -17
  598. package/.next/standalone/.next/static/chunks/app/api/v1/harnesses/route-36cb8b428b38b26a.js +0 -17
  599. package/.next/standalone/.next/static/chunks/app/api/v1/health/probes/route-36cb8b428b38b26a.js +0 -17
  600. package/.next/standalone/.next/static/chunks/app/api/v1/health/route-36cb8b428b38b26a.js +0 -17
  601. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/route-36cb8b428b38b26a.js +0 -17
  602. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/[name]/test/route-36cb8b428b38b26a.js +0 -17
  603. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/callback/route-36cb8b428b38b26a.js +0 -17
  604. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/start/route-36cb8b428b38b26a.js +0 -17
  605. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/gmail/oauth/status/route-36cb8b428b38b26a.js +0 -17
  606. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/callback/route-36cb8b428b38b26a.js +0 -17
  607. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/start/route-36cb8b428b38b26a.js +0 -17
  608. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/outlook/oauth/status/route-36cb8b428b38b26a.js +0 -17
  609. package/.next/standalone/.next/static/chunks/app/api/v1/integrations/route-36cb8b428b38b26a.js +0 -17
  610. package/.next/standalone/.next/static/chunks/app/api/v1/lifecycle/adoption/route-36cb8b428b38b26a.js +0 -17
  611. package/.next/standalone/.next/static/chunks/app/api/v1/local-file/route-36cb8b428b38b26a.js +0 -17
  612. package/.next/standalone/.next/static/chunks/app/api/v1/logs/route-36cb8b428b38b26a.js +0 -17
  613. package/.next/standalone/.next/static/chunks/app/api/v1/maps/embed/route-36cb8b428b38b26a.js +0 -17
  614. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/[name]/route-36cb8b428b38b26a.js +0 -17
  615. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/registry/route-36cb8b428b38b26a.js +0 -17
  616. package/.next/standalone/.next/static/chunks/app/api/v1/mcp-servers/route-36cb8b428b38b26a.js +0 -17
  617. package/.next/standalone/.next/static/chunks/app/api/v1/memory/[namespace]/[key]/route-36cb8b428b38b26a.js +0 -17
  618. package/.next/standalone/.next/static/chunks/app/api/v1/memory/policy/route-36cb8b428b38b26a.js +0 -17
  619. package/.next/standalone/.next/static/chunks/app/api/v1/memory/route-36cb8b428b38b26a.js +0 -17
  620. package/.next/standalone/.next/static/chunks/app/api/v1/memory/search/route-36cb8b428b38b26a.js +0 -17
  621. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/compact-threads/route-36cb8b428b38b26a.js +0 -17
  622. package/.next/standalone/.next/static/chunks/app/api/v1/models/[name]/route-36cb8b428b38b26a.js +0 -17
  623. package/.next/standalone/.next/static/chunks/app/api/v1/models/route-36cb8b428b38b26a.js +0 -17
  624. package/.next/standalone/.next/static/chunks/app/api/v1/packages/catalog/route-36cb8b428b38b26a.js +0 -17
  625. package/.next/standalone/.next/static/chunks/app/api/v1/packages/defaults/[id]/route-36cb8b428b38b26a.js +0 -17
  626. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/[id]/route-36cb8b428b38b26a.js +0 -17
  627. package/.next/standalone/.next/static/chunks/app/api/v1/packages/install/route-36cb8b428b38b26a.js +0 -17
  628. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/enabled/route-36cb8b428b38b26a.js +0 -17
  629. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/[name]/route-36cb8b428b38b26a.js +0 -17
  630. package/.next/standalone/.next/static/chunks/app/api/v1/packages/manifests/route-36cb8b428b38b26a.js +0 -17
  631. package/.next/standalone/.next/static/chunks/app/api/v1/packages/reload/route-36cb8b428b38b26a.js +0 -17
  632. package/.next/standalone/.next/static/chunks/app/api/v1/packages/route-36cb8b428b38b26a.js +0 -17
  633. package/.next/standalone/.next/static/chunks/app/api/v1/page-capture/route-36cb8b428b38b26a.js +0 -17
  634. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/approve/route-36cb8b428b38b26a.js +0 -17
  635. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/[id]/deny/route-36cb8b428b38b26a.js +0 -17
  636. package/.next/standalone/.next/static/chunks/app/api/v1/pending-actions/route-36cb8b428b38b26a.js +0 -17
  637. package/.next/standalone/.next/static/chunks/app/api/v1/profile/location/route-36cb8b428b38b26a.js +0 -17
  638. package/.next/standalone/.next/static/chunks/app/api/v1/profile/route-36cb8b428b38b26a.js +0 -17
  639. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/models/route-36cb8b428b38b26a.js +0 -17
  640. package/.next/standalone/.next/static/chunks/app/api/v1/providers/[provider]/probe/route-36cb8b428b38b26a.js +0 -17
  641. package/.next/standalone/.next/static/chunks/app/api/v1/providers/github-copilot/auth/route-36cb8b428b38b26a.js +0 -17
  642. package/.next/standalone/.next/static/chunks/app/api/v1/providers/route-36cb8b428b38b26a.js +0 -17
  643. package/.next/standalone/.next/static/chunks/app/api/v1/proxy-config/route-36cb8b428b38b26a.js +0 -17
  644. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/init/route-36cb8b428b38b26a.js +0 -17
  645. package/.next/standalone/.next/static/chunks/app/api/v1/redaction/route-36cb8b428b38b26a.js +0 -17
  646. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/route-36cb8b428b38b26a.js +0 -17
  647. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/[id]/run/route-36cb8b428b38b26a.js +0 -17
  648. package/.next/standalone/.next/static/chunks/app/api/v1/scheduled-tasks/route-36cb8b428b38b26a.js +0 -17
  649. package/.next/standalone/.next/static/chunks/app/api/v1/security/idle-timeout/route-36cb8b428b38b26a.js +0 -17
  650. package/.next/standalone/.next/static/chunks/app/api/v1/security/pin/route-36cb8b428b38b26a.js +0 -17
  651. package/.next/standalone/.next/static/chunks/app/api/v1/security/state/route-36cb8b428b38b26a.js +0 -17
  652. package/.next/standalone/.next/static/chunks/app/api/v1/security/unlock/route-36cb8b428b38b26a.js +0 -17
  653. package/.next/standalone/.next/static/chunks/app/api/v1/security/verify-pin/route-36cb8b428b38b26a.js +0 -17
  654. package/.next/standalone/.next/static/chunks/app/api/v1/setup/test-key/route-36cb8b428b38b26a.js +0 -17
  655. package/.next/standalone/.next/static/chunks/app/api/v1/skills/[id]/route-36cb8b428b38b26a.js +0 -17
  656. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/[id]/route-36cb8b428b38b26a.js +0 -17
  657. package/.next/standalone/.next/static/chunks/app/api/v1/skills/repos/route-36cb8b428b38b26a.js +0 -17
  658. package/.next/standalone/.next/static/chunks/app/api/v1/skills/route-36cb8b428b38b26a.js +0 -17
  659. package/.next/standalone/.next/static/chunks/app/api/v1/system/abort/route-36cb8b428b38b26a.js +0 -17
  660. package/.next/standalone/.next/static/chunks/app/api/v1/system/restart/route-36cb8b428b38b26a.js +0 -17
  661. package/.next/standalone/.next/static/chunks/app/api/v1/tailscale/route-36cb8b428b38b26a.js +0 -17
  662. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/[agent_id]/route-36cb8b428b38b26a.js +0 -17
  663. package/.next/standalone/.next/static/chunks/app/api/v1/tasks/route-36cb8b428b38b26a.js +0 -17
  664. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/context-pin/route-36cb8b428b38b26a.js +0 -17
  665. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/route-36cb8b428b38b26a.js +0 -17
  666. package/.next/standalone/.next/static/chunks/app/api/v1/threads/[thread_id]/run/route-36cb8b428b38b26a.js +0 -17
  667. package/.next/standalone/.next/static/chunks/app/api/v1/threads/route-36cb8b428b38b26a.js +0 -17
  668. package/.next/standalone/.next/static/chunks/app/api/v1/tools/route-36cb8b428b38b26a.js +0 -17
  669. package/.next/standalone/.next/static/chunks/app/api/v1/update/apply/route-36cb8b428b38b26a.js +0 -17
  670. package/.next/standalone/.next/static/chunks/app/api/v1/update/route-36cb8b428b38b26a.js +0 -17
  671. package/.next/standalone/.next/static/chunks/app/api/v1/voice/transcribe/route-36cb8b428b38b26a.js +0 -17
  672. package/.next/standalone/.next/static/chunks/app/api/v1/voice/tts/route-36cb8b428b38b26a.js +0 -17
  673. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/route-36cb8b428b38b26a.js +0 -17
  674. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/[id]/run/route-36cb8b428b38b26a.js +0 -17
  675. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/reaction-scripts/route-36cb8b428b38b26a.js +0 -17
  676. package/.next/standalone/.next/static/chunks/app/api/v1/watchers/route-36cb8b428b38b26a.js +0 -17
  677. package/.next/standalone/.next/static/chunks/app/manifest.webmanifest/route-36cb8b428b38b26a.js +0 -17
  678. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-36cb8b428b38b26a.js +0 -17
  679. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-36cb8b428b38b26a.js +0 -17
  680. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-36cb8b428b38b26a.js +0 -17
  681. package/.next/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-36cb8b428b38b26a.js +0 -17
  682. /package/.next/standalone/.next/static/{e2NV1wk6mWg3SIeELXevg → bMRK5y3ruT7c3WtBfCQOG}/_buildManifest.js +0 -0
  683. /package/.next/standalone/.next/static/{e2NV1wk6mWg3SIeELXevg → bMRK5y3ruT7c3WtBfCQOG}/_ssgManifest.js +0 -0
@@ -92,14 +92,14 @@ function useTheme() {
92
92
  /***/ 39852:
93
93
  /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
94
94
 
95
- Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96513));
95
+ Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 54986));
96
96
  ;
97
97
  Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 12283));
98
98
 
99
99
 
100
100
  /***/ }),
101
101
 
102
- /***/ 96513:
102
+ /***/ 54986:
103
103
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
104
104
 
105
105
  "use strict";
@@ -826,40 +826,8 @@ function useUrlSync() {
826
826
  };
827
827
  }
828
828
 
829
- ;// ./lib/agents/effective-model.ts
830
- /**
831
- * Resolve which `ModelConfig` will actually be used for an agent at runtime.
832
- *
833
- * Mirrors what `lib/agents/llm.ts` does server-side: when an agent has
834
- * `model_config_name` set, that wins; otherwise the workspace-wide default
835
- * model is used. Both client (BridgeEditor, AgentEditor capability hints)
836
- * and server need the same logic — this is the single source of truth.
837
- *
838
- * Returns `null` only when neither the requested config nor the default
839
- * exists in the provided list (typically: no models configured yet).
840
- */ function resolveAgentModel(agent, models) {
841
- const defaultModel = models.find((m)=>m.is_default) ?? models[0] ?? null;
842
- if (!agent?.model_config_name) return defaultModel;
843
- return models.find((m)=>m.name === agent.model_config_name) ?? defaultModel;
844
- }
845
- /**
846
- * Diagnose whether an agent has a runnable model RIGHT NOW. Used by the
847
- * Scheduled Tasks and Watchers panels to surface model-availability issues
848
- * before an unattended run silently no-ops with `no_model`.
849
- */ function agentModelStatus(agent, models) {
850
- if (!agent) return {
851
- state: "no-agent"
852
- };
853
- const effectiveModel = resolveAgentModel(agent, models);
854
- if (effectiveModel) return {
855
- state: "ok",
856
- model: effectiveModel
857
- };
858
- return {
859
- state: "no-model"
860
- };
861
- }
862
-
829
+ // EXTERNAL MODULE: ./lib/agents/effective-model.ts
830
+ var effective_model = __webpack_require__(53036);
863
831
  ;// ./hooks/useConfigurationIssues.ts
864
832
  /* __next_internal_client_entry_do_not_use__ useConfigurationIssues auto */
865
833
 
@@ -915,7 +883,7 @@ function useUrlSync() {
915
883
  pushIssue("no-default-model", "info", "No default model set", "Agents without an explicit model will fail. Pick one default.", "?tab=models", "Open Models →");
916
884
  }
917
885
  for (const a of agents){
918
- const status = agentModelStatus(a, models);
886
+ const status = (0,effective_model/* agentModelStatus */.xu)(a, models);
919
887
  if (status.state === "no-model") {
920
888
  pushIssue(`agent-no-model:${a.id}`, "error", `Agent "${a.name}" has no model`, "Pick a model or set a workspace default.", `?tab=agents&item=${encodeURIComponent(a.id)}`, "Fix in Agents →");
921
889
  }
@@ -1245,6 +1213,26 @@ function useSSE(onDone) {
1245
1213
  // Cleared on every new start()/attach().
1246
1214
  const [authError, setAuthError] = (0,react.useState)(null);
1247
1215
  const abortRef = (0,react.useRef)(null);
1216
+ // Synchronous view of whether start()/attach() owns a live stream, and when
1217
+ // the last one settled. React's `streaming` lags a render behind, so the
1218
+ // activity poller reads this to avoid aborting a stream that just opened
1219
+ // or re-attaching a run whose stream has only just ended.
1220
+ const liveRef = (0,react.useRef)({
1221
+ busy: false,
1222
+ settledAt: 0
1223
+ });
1224
+ const markLive = (0,react.useCallback)(()=>{
1225
+ liveRef.current.busy = true;
1226
+ }, []);
1227
+ const markSettled = (0,react.useCallback)((ctrl)=>{
1228
+ if (ctrl && abortRef.current !== ctrl) return;
1229
+ liveRef.current = {
1230
+ busy: false,
1231
+ settledAt: Date.now()
1232
+ };
1233
+ }, []);
1234
+ const isLive = (0,react.useCallback)(()=>liveRef.current.busy, []);
1235
+ const lastSettledAt = (0,react.useCallback)(()=>liveRef.current.settledAt, []);
1248
1236
  const threadIdRef = (0,react.useRef)(null);
1249
1237
  // ADR-0080 — id of the steering message currently armed for a possible
1250
1238
  // continuation break, or null. Set eagerly (before the steer PATCH
@@ -1406,6 +1394,7 @@ function useSSE(onDone) {
1406
1394
  abortRef.current?.abort();
1407
1395
  const ctrl = new AbortController();
1408
1396
  abortRef.current = ctrl;
1397
+ markLive();
1409
1398
  threadIdRef.current = threadId;
1410
1399
  resetBuffer();
1411
1400
  setStreaming(true);
@@ -1453,10 +1442,13 @@ function useSSE(onDone) {
1453
1442
  // them.
1454
1443
  setStreaming(false);
1455
1444
  closeActivity();
1445
+ markSettled(ctrl);
1456
1446
  }
1457
1447
  }, [
1458
1448
  closeActivity,
1459
1449
  consume,
1450
+ markLive,
1451
+ markSettled,
1460
1452
  openActivity,
1461
1453
  resetBuffer
1462
1454
  ]);
@@ -1481,11 +1473,13 @@ function useSSE(onDone) {
1481
1473
  // start()/attach() — same pattern as the `done` branch in consume().
1482
1474
  closeActivity();
1483
1475
  abortRef.current?.abort();
1476
+ markSettled(null);
1484
1477
  steeredContinuationIdRef.current = null;
1485
1478
  onDone?.();
1486
1479
  }, [
1487
1480
  closeActivity,
1488
1481
  flushPending,
1482
+ markSettled,
1489
1483
  onDone
1490
1484
  ]);
1491
1485
  // Attach to an in-flight run for the given thread (server-side run kept
@@ -1499,6 +1493,7 @@ function useSSE(onDone) {
1499
1493
  abortRef.current?.abort();
1500
1494
  const ctrl = new AbortController();
1501
1495
  abortRef.current = ctrl;
1496
+ markLive();
1502
1497
  threadIdRef.current = threadId;
1503
1498
  resetBuffer();
1504
1499
  setStreaming(true);
@@ -1526,10 +1521,13 @@ function useSSE(onDone) {
1526
1521
  // hangs in the composer and the "Reconnecting…" badge never clears.
1527
1522
  setStreaming(false);
1528
1523
  closeActivity();
1524
+ markSettled(ctrl);
1529
1525
  }
1530
1526
  }, [
1531
1527
  closeActivity,
1532
1528
  consume,
1529
+ markLive,
1530
+ markSettled,
1533
1531
  onDone,
1534
1532
  openActivity,
1535
1533
  resetBuffer
@@ -1574,6 +1572,8 @@ function useSSE(onDone) {
1574
1572
  start,
1575
1573
  stop,
1576
1574
  attach,
1575
+ isLive,
1576
+ lastSettledAt,
1577
1577
  clearStreamingContent,
1578
1578
  clearToolEvents,
1579
1579
  armSteeredContinuation,
@@ -1593,6 +1593,8 @@ function useSSE(onDone) {
1593
1593
  start,
1594
1594
  stop,
1595
1595
  attach,
1596
+ isLive,
1597
+ lastSettledAt,
1596
1598
  clearStreamingContent,
1597
1599
  clearToolEvents,
1598
1600
  armSteeredContinuation,
@@ -1813,6 +1815,8 @@ function readLegacyGlobal() {
1813
1815
  };
1814
1816
  }
1815
1817
 
1818
+ // EXTERNAL MODULE: ./lib/ui/error-report.ts
1819
+ var error_report = __webpack_require__(11856);
1816
1820
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/shield-alert.mjs
1817
1821
  var shield_alert = __webpack_require__(69203);
1818
1822
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/chevron-up.mjs
@@ -3050,9 +3054,24 @@ var loader_circle = __webpack_require__(92571);
3050
3054
  var triangle_alert = __webpack_require__(11012);
3051
3055
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/minus.mjs
3052
3056
  var minus = __webpack_require__(36565);
3057
+ // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/rotate-ccw.mjs
3058
+ var rotate_ccw = __webpack_require__(92298);
3053
3059
  ;// ./components/ui/WorkflowChecklist.tsx
3054
3060
 
3055
3061
 
3062
+ const RETRYABLE_STATUSES = new Set([
3063
+ "done",
3064
+ "needs_attention",
3065
+ "skipped"
3066
+ ]);
3067
+ function isWorkflowItemRetryable(item) {
3068
+ return RETRYABLE_STATUSES.has(item.status);
3069
+ }
3070
+ function statusLabel(status) {
3071
+ if (status === "done") return "verified";
3072
+ if (status === "needs_attention") return "needs attention";
3073
+ return status;
3074
+ }
3056
3075
  function StatusIcon({ status }) {
3057
3076
  if (status === "done") return /*#__PURE__*/ (0,jsx_runtime.jsx)(check/* default */.A, {
3058
3077
  className: "h-3 w-3",
@@ -3082,11 +3101,15 @@ function statusClass(status) {
3082
3101
  if (status === "skipped") return "border-border/60 bg-surface text-fg-faint";
3083
3102
  return "border-border/60 bg-surface text-fg-faint";
3084
3103
  }
3085
- function WorkflowChecklist({ eyebrow, title, phaseLabel, summary, items, error, compact = false, children }) {
3104
+ function itemTooltip(item) {
3105
+ const note = item.status === "done" ? item.validation_evidence : item.reason;
3106
+ return note ? `${item.label}\n${statusLabel(item.status)}: ${note}` : item.label;
3107
+ }
3108
+ function WorkflowChecklist({ eyebrow, title, phaseLabel, summary, items, error, compact = false, onRetryItem, canRetryItem, retryDisabled = false, children }) {
3086
3109
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
3087
3110
  className: compact ? "flex flex-col gap-1.5" : "absolute inset-x-0 top-0 flex flex-col gap-2 transition-opacity duration-300",
3088
3111
  children: [
3089
- /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
3112
+ !compact && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
3090
3113
  className: "text-[10px] text-fg-faint uppercase tracking-wider text-center",
3091
3114
  children: eyebrow
3092
3115
  }),
@@ -3106,99 +3129,59 @@ function WorkflowChecklist({ eyebrow, title, phaseLabel, summary, items, error,
3106
3129
  })
3107
3130
  ]
3108
3131
  }),
3109
- /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
3132
+ !compact && summary && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
3110
3133
  className: "mt-1 text-[11px] leading-snug text-fg-muted line-clamp-2",
3111
3134
  children: summary
3112
3135
  }),
3113
- /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
3114
- className: compact ? "mt-1.5 flex max-h-32 flex-col gap-1 overflow-y-auto pr-1" : "mt-2 flex max-h-32 flex-col gap-1 overflow-y-auto pr-1",
3115
- children: items.map((item)=>/*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
3116
- className: compact ? "rounded border border-border/30 bg-surface-2/40 px-1.5 py-1 text-[10px] leading-tight text-fg-muted" : "text-[10px] leading-tight text-fg-muted",
3136
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("ul", {
3137
+ className: compact ? "mt-1.5 flex max-h-48 flex-col gap-0.5 overflow-y-auto pr-1" : "mt-2 flex max-h-32 flex-col gap-1 overflow-y-auto pr-1",
3138
+ children: items.map((item)=>{
3139
+ const retryable = !!onRetryItem && isWorkflowItemRetryable(item) && (canRetryItem ? canRetryItem(item) : true);
3140
+ return /*#__PURE__*/ (0,jsx_runtime.jsxs)("li", {
3141
+ className: "group flex items-center gap-1.5 text-[10px] leading-tight text-fg-muted",
3117
3142
  children: [
3118
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
3119
- className: "flex items-start gap-1.5",
3120
- children: [
3121
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
3122
- "aria-label": item.status,
3123
- className: [
3124
- "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border",
3125
- statusClass(item.status)
3126
- ].join(" "),
3127
- children: /*#__PURE__*/ (0,jsx_runtime.jsx)(StatusIcon, {
3128
- status: item.status
3129
- })
3130
- }),
3131
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
3132
- className: compact ? "min-w-0 flex-1 truncate" : "line-clamp-2",
3133
- title: item.label,
3134
- children: item.label
3135
- })
3136
- ]
3143
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
3144
+ role: "img",
3145
+ "aria-label": statusLabel(item.status),
3146
+ className: [
3147
+ "flex h-4 w-4 shrink-0 items-center justify-center rounded border",
3148
+ statusClass(item.status)
3149
+ ].join(" "),
3150
+ children: /*#__PURE__*/ (0,jsx_runtime.jsx)(StatusIcon, {
3151
+ status: item.status
3152
+ })
3153
+ }),
3154
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
3155
+ className: compact ? "min-w-0 flex-1 truncate" : "min-w-0 flex-1 line-clamp-2",
3156
+ title: itemTooltip(item),
3157
+ children: item.label
3137
3158
  }),
3138
- (item.input || item.output || item.validation || item.validation_evidence) && /*#__PURE__*/ (0,jsx_runtime.jsxs)("details", {
3139
- className: "mt-1 pl-5",
3159
+ (item.attempts ?? 0) > 1 && /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
3160
+ className: "shrink-0 text-[9px] tabular-nums text-fg-faint",
3161
+ title: `Attempt ${item.attempts}`,
3140
3162
  children: [
3141
- /*#__PURE__*/ (0,jsx_runtime.jsx)("summary", {
3142
- className: "cursor-pointer text-fg-faint",
3143
- children: "Step contract"
3144
- }),
3145
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("dl", {
3146
- className: "mt-1 grid grid-cols-[auto_minmax(0,1fr)] gap-x-2 gap-y-1",
3147
- children: [
3148
- item.input && /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
3149
- children: [
3150
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dt", {
3151
- className: "text-fg-faint",
3152
- children: "Input"
3153
- }),
3154
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dd", {
3155
- className: "break-words",
3156
- children: item.input
3157
- })
3158
- ]
3159
- }),
3160
- item.output && /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
3161
- children: [
3162
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dt", {
3163
- className: "text-fg-faint",
3164
- children: "Output"
3165
- }),
3166
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dd", {
3167
- className: "break-words",
3168
- children: item.output
3169
- })
3170
- ]
3171
- }),
3172
- item.validation && /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
3173
- children: [
3174
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dt", {
3175
- className: "text-fg-faint",
3176
- children: "Validation"
3177
- }),
3178
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dd", {
3179
- className: "break-words",
3180
- children: item.validation
3181
- })
3182
- ]
3183
- }),
3184
- item.validation_evidence && /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
3185
- children: [
3186
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dt", {
3187
- className: "text-fg-faint",
3188
- children: "Evidence"
3189
- }),
3190
- /*#__PURE__*/ (0,jsx_runtime.jsx)("dd", {
3191
- className: "break-words",
3192
- children: item.validation_evidence
3193
- })
3194
- ]
3195
- })
3196
- ]
3197
- })
3163
+ "attempt ",
3164
+ item.attempts
3198
3165
  ]
3166
+ }),
3167
+ retryable && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
3168
+ type: "button",
3169
+ onClick: ()=>onRetryItem(item),
3170
+ disabled: retryDisabled,
3171
+ "aria-label": `Retry ${item.label}`,
3172
+ title: `Retry ${item.label}`,
3173
+ className: [
3174
+ "flex h-4 w-4 shrink-0 items-center justify-center rounded text-fg-faint hover:bg-surface-3 hover:text-fg disabled:opacity-40",
3175
+ item.status === "needs_attention" ? "" : "opacity-0 focus:opacity-100 group-hover:opacity-100"
3176
+ ].join(" "),
3177
+ children: /*#__PURE__*/ (0,jsx_runtime.jsx)(rotate_ccw/* default */.A, {
3178
+ className: "h-3 w-3",
3179
+ "aria-hidden": true
3180
+ })
3199
3181
  })
3200
3182
  ]
3201
- }, item.id))
3183
+ }, item.id);
3184
+ })
3202
3185
  }),
3203
3186
  error && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
3204
3187
  className: "mt-2 text-[10px] leading-tight text-red-400",
@@ -3211,6 +3194,21 @@ function WorkflowChecklist({ eyebrow, title, phaseLabel, summary, items, error,
3211
3194
  });
3212
3195
  }
3213
3196
 
3197
+ ;// ./components/chat/workflow-step-retry.ts
3198
+
3199
+ /** Sends a retry request for one workflow step; null when the surface cannot send messages. */ const WorkflowStepRetryContext = (0,react.createContext)(null);
3200
+ function useWorkflowStepRetry() {
3201
+ return (0,react.useContext)(WorkflowStepRetryContext);
3202
+ }
3203
+ function workflowStepRetryMessage({ workflowId, itemId, label }) {
3204
+ const progressUpdate = workflowId === "version_adoption" ? `Call \`workflow_progress\` with \`workflow_id: "version_adoption"\`, \`item_id: "${itemId}"\`, and \`status: "checking"\`` : `Call \`workflow_progress\` for workflow \`${workflowId}\` with the complete items snapshot, setting this step to \`checking\``;
3205
+ return [
3206
+ `Retry workflow step "${label}" (item \`${itemId}\`) in workflow \`${workflowId}\`.`,
3207
+ `${progressUpdate}, then redo the step from its stated input and run its validation again.`,
3208
+ "Finally mark it `done` with newly observed `validation_evidence`, or `needs_attention` with the reason. Leave the other steps unchanged."
3209
+ ].join(" ");
3210
+ }
3211
+
3214
3212
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/clock.mjs
3215
3213
  var clock = __webpack_require__(6923);
3216
3214
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/message-circle.mjs
@@ -3399,6 +3397,7 @@ var ProviderLogo = __webpack_require__(85516);
3399
3397
 
3400
3398
 
3401
3399
 
3400
+
3402
3401
  // Distinct lucide glyph per internal tool family so the chat transcript
3403
3402
  // is glanceable — operator can tell a file write from a web fetch from a
3404
3403
  // schedule from a memory read without reading the tool name.
@@ -3836,7 +3835,34 @@ function groupByCallId(events) {
3836
3835
  }
3837
3836
  g.absorbed = true;
3838
3837
  }
3839
- return order.map((id)=>map.get(id)).filter((g)=>!g.absorbed);
3838
+ const groups = order.map((id)=>map.get(id)).filter((g)=>!g.absorbed);
3839
+ annotateWorkflowAttempts(groups);
3840
+ return groups;
3841
+ }
3842
+ // Counts each workflow step's transitions into `checking` across the
3843
+ // message's workflow_progress calls, so auto-retried steps show "attempt N".
3844
+ // Rejected updates (ok:false) changed nothing and are not counted.
3845
+ function annotateWorkflowAttempts(groups) {
3846
+ const lastStatus = new Map();
3847
+ const attempts = new Map();
3848
+ for (const group of groups){
3849
+ if (group.name !== "workflow_progress") continue;
3850
+ if (coerceObject(unwrapLangChainSerializable(group.result))?.ok === false) continue;
3851
+ const view = workflowViewFor(group);
3852
+ if (!view) continue;
3853
+ const counts = {
3854
+ ...attempts.get(view.workflow_id) ?? {}
3855
+ };
3856
+ for (const item of view.items){
3857
+ const key = `${view.workflow_id}:${item.id}`;
3858
+ if (item.status === "checking" && lastStatus.get(key) !== "checking") {
3859
+ counts[item.id] = (counts[item.id] ?? 0) + 1;
3860
+ }
3861
+ lastStatus.set(key, item.status);
3862
+ }
3863
+ attempts.set(view.workflow_id, counts);
3864
+ group.workflowAttempts = counts;
3865
+ }
3840
3866
  }
3841
3867
  function ToolCallCard({ group, startedAt }) {
3842
3868
  const [open, setOpen] = (0,react.useState)(false);
@@ -3949,23 +3975,27 @@ function ToolCallCard({ group, startedAt }) {
3949
3975
  /*#__PURE__*/ (0,jsx_runtime.jsx)(WorkflowProgressDetails, {
3950
3976
  group: group
3951
3977
  }),
3952
- hasVisibleArgs(group.args) ? /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3953
- label: "arguments",
3954
- value: group.args
3955
- }) : hasArgs ? /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3956
- label: "arguments (inferred from result)",
3957
- value: effectiveArgs
3958
- }) : null,
3959
- group.status !== "running" && group.status !== "async" && (isToolResultRefEnvelope(group.result) ? /*#__PURE__*/ (0,jsx_runtime.jsx)(ToolResultRefDetails, {
3960
- value: group.result
3961
- }) : /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3962
- label: group.status === "error" ? "error" : "result",
3963
- value: group.result,
3964
- tone: group.status === "error" ? "error" : "default"
3965
- })),
3966
- group.status === "async" && /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3967
- label: "background handoff",
3968
- value: group.result
3978
+ !hasWorkflowView(group) && /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
3979
+ children: [
3980
+ hasVisibleArgs(group.args) ? /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3981
+ label: "arguments",
3982
+ value: group.args
3983
+ }) : hasArgs ? /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3984
+ label: "arguments (inferred from result)",
3985
+ value: effectiveArgs
3986
+ }) : null,
3987
+ group.status !== "running" && group.status !== "async" && (isToolResultRefEnvelope(group.result) ? /*#__PURE__*/ (0,jsx_runtime.jsx)(ToolResultRefDetails, {
3988
+ value: group.result
3989
+ }) : /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3990
+ label: group.status === "error" ? "error" : "result",
3991
+ value: group.result,
3992
+ tone: group.status === "error" ? "error" : "default"
3993
+ })),
3994
+ group.status === "async" && /*#__PURE__*/ (0,jsx_runtime.jsx)(DetailSection, {
3995
+ label: "background handoff",
3996
+ value: group.result
3997
+ })
3998
+ ]
3969
3999
  })
3970
4000
  ]
3971
4001
  })
@@ -4100,18 +4130,47 @@ function ToolResultRefDetails({ value }) {
4100
4130
  ]
4101
4131
  });
4102
4132
  }
4103
- function WorkflowProgressDetails({ group }) {
4133
+ function workflowViewFor(group) {
4104
4134
  if (group.name !== "workflow_progress") return null;
4105
- const workflow = workflowProgressFrom(group.result) ?? workflowProgressPreviewFrom(group.args);
4135
+ const view = workflowProgressFrom(group.result) ?? workflowProgressPreviewFrom(group.args);
4136
+ const result = coerceObject(unwrapLangChainSerializable(group.result));
4137
+ const attempts = group.workflowAttempts;
4138
+ const withAttempts = view && attempts ? {
4139
+ ...view,
4140
+ items: view.items.map((item)=>attempts[item.id] ? {
4141
+ ...item,
4142
+ attempts: attempts[item.id]
4143
+ } : item)
4144
+ } : view;
4145
+ if (withAttempts && result?.ok === false && typeof result.error === "string") {
4146
+ return {
4147
+ ...withAttempts,
4148
+ error: `Update rejected: ${result.error}`
4149
+ };
4150
+ }
4151
+ return withAttempts;
4152
+ }
4153
+ /** Workflow rows show only their work items; raw payloads stay visible when the call failed. */ function hasWorkflowView(group) {
4154
+ return group.status !== "error" && workflowViewFor(group) !== null;
4155
+ }
4156
+ function WorkflowProgressDetails({ group }) {
4157
+ const retryStep = useWorkflowStepRetry();
4158
+ const workflow = workflowViewFor(group);
4106
4159
  if (!workflow) return null;
4160
+ const workflowId = workflow.workflow_id;
4107
4161
  return /*#__PURE__*/ (0,jsx_runtime.jsx)(WorkflowChecklist, {
4108
4162
  compact: true,
4109
4163
  eyebrow: "workflow",
4110
- title: workflow.workflow_id.replace(/[_-]/g, " "),
4164
+ title: workflowId.replace(/[_-]/g, " "),
4111
4165
  phaseLabel: workflow.phase ?? "in progress",
4112
4166
  summary: workflow.summary ?? "",
4113
4167
  items: workflow.items,
4114
- error: workflow.error
4168
+ error: workflow.error,
4169
+ onRetryItem: retryStep ? (item)=>retryStep({
4170
+ workflowId,
4171
+ itemId: item.id,
4172
+ label: item.label
4173
+ }) : undefined
4115
4174
  });
4116
4175
  }
4117
4176
  function workflowProgressFrom(payload) {
@@ -5097,8 +5156,6 @@ var shield_check = __webpack_require__(50981);
5097
5156
  var copy = __webpack_require__(99314);
5098
5157
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/link-2.mjs
5099
5158
  var link_2 = __webpack_require__(51128);
5100
- // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/rotate-ccw.mjs
5101
- var rotate_ccw = __webpack_require__(92298);
5102
5159
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/pause.mjs
5103
5160
  var pause = __webpack_require__(79267);
5104
5161
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/play.mjs
@@ -8477,7 +8534,7 @@ function StatusDot({ tone = "neutral", size = "xs", pulse, className, style, lab
8477
8534
  }
8478
8535
 
8479
8536
  ;// ./components/chat/ContextBoundary.tsx
8480
- /* __next_internal_client_entry_do_not_use__ WarmSummaryCard,ContextBoundaryDivider auto */
8537
+ /* __next_internal_client_entry_do_not_use__ WarmSummaryCard,ContextBoundaryDivider,topicsFromSummarySections auto */
8481
8538
  // Inline visual artefacts for ADR-0042: the warm-summary card and the
8482
8539
  // context-boundary divider that sits below it. Rendered by MessageList in
8483
8540
  // the message stream — between summarised history (above) and the active
@@ -8489,17 +8546,25 @@ function StatusDot({ tone = "neutral", size = "xs", pulse, className, style, lab
8489
8546
 
8490
8547
 
8491
8548
 
8492
- function WarmSummaryCard({ olderCount, summary, summaryBeforeSeq, hotSinceSeq, computedAt, streaming, topics }) {
8549
+ const CHANNEL_LABELS = {
8550
+ bridge: "Bridge",
8551
+ watcher: "Watchers",
8552
+ scheduled_task: "Scheduled tasks"
8553
+ };
8554
+ function WarmSummaryCard({ olderCount, summary, summaryBeforeSeq, hotSinceSeq, computedAt, streaming, topics, channelSummaries = [] }) {
8493
8555
  const [expanded, setExpanded] = (0,react.useState)(false);
8494
- const fresh = !!summary && hotSinceSeq != null && summaryBeforeSeq === hotSinceSeq;
8556
+ const committed = hotSinceSeq != null && summaryBeforeSeq === hotSinceSeq;
8557
+ const fresh = !!summary && committed;
8495
8558
  const stale = !!summary && !fresh;
8496
8559
  const computing = stale && streaming;
8497
- const summaryTopics = summary && topics && topics.length > 0 ? topics : null;
8560
+ // Summaries stored before topic segmentation still read as topics: their
8561
+ // markdown sections render through the same collapsible rows.
8562
+ const summaryTopics = summary ? topics && topics.length > 0 ? topics : topicsFromSummarySections(summary) : null;
8498
8563
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
8499
8564
  className: [
8500
8565
  "relative my-4 rounded-2xl border bg-gradient-to-br shadow-sm",
8501
8566
  "from-accent/[0.06] via-surface-2 to-surface-2",
8502
- fresh ? "border-accent/30" : "border-border"
8567
+ fresh || committed ? "border-accent/30" : "border-border"
8503
8568
  ].join(" "),
8504
8569
  children: [
8505
8570
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
@@ -8544,6 +8609,9 @@ function WarmSummaryCard({ olderCount, summary, summaryBeforeSeq, hotSinceSeq, c
8544
8609
  children: /*#__PURE__*/ (0,jsx_runtime.jsx)(lib/* Markdown */.oz, {
8545
8610
  children: stripWarmHeader(summary)
8546
8611
  })
8612
+ }) : !summary && committed ? channelSummaries.length === 0 && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
8613
+ className: "text-xs text-fg-faint italic",
8614
+ children: "No earlier chat messages needed summarising."
8547
8615
  }) : !summary ? /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
8548
8616
  className: "flex items-center gap-2 text-xs text-fg-faint italic",
8549
8617
  children: [
@@ -8557,6 +8625,9 @@ function WarmSummaryCard({ olderCount, summary, summaryBeforeSeq, hotSinceSeq, c
8557
8625
  })
8558
8626
  ]
8559
8627
  }) : null,
8628
+ channelSummaries.map((channel)=>/*#__PURE__*/ (0,jsx_runtime.jsx)(ChannelSummarySection, {
8629
+ channel: channel
8630
+ }, channel.channel)),
8560
8631
  stale && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
8561
8632
  className: "mt-2 inline-flex items-center gap-2 text-[11px] text-fg-faint",
8562
8633
  children: [
@@ -8598,6 +8669,32 @@ function WarmSummaryCard({ olderCount, summary, summaryBeforeSeq, hotSinceSeq, c
8598
8669
  ]
8599
8670
  });
8600
8671
  }
8672
+ function ChannelSummarySection({ channel }) {
8673
+ const topics = channel.topics && channel.topics.length > 0 ? channel.topics : topicsFromSummarySections(channel.summary) ?? [
8674
+ {
8675
+ title: "Recap",
8676
+ start_at: "",
8677
+ end_at: "",
8678
+ recap: stripWarmHeader(channel.summary),
8679
+ facts: []
8680
+ }
8681
+ ];
8682
+ return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
8683
+ className: "mt-2",
8684
+ children: [
8685
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
8686
+ className: "mb-1 text-[9px] uppercase tracking-wide text-fg-faint",
8687
+ children: CHANNEL_LABELS[channel.channel] ?? channel.channel
8688
+ }),
8689
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
8690
+ className: "flex flex-col gap-1",
8691
+ children: topics.map((topic, i)=>/*#__PURE__*/ (0,jsx_runtime.jsx)(TopicSegmentRow, {
8692
+ topic: topic
8693
+ }, `${channel.channel}-${topic.title}-${i}`))
8694
+ })
8695
+ ]
8696
+ });
8697
+ }
8601
8698
  function TopicSegmentRow({ topic }) {
8602
8699
  const [open, setOpen] = (0,react.useState)(false);
8603
8700
  const range = formatTopicRange(topic.start_at, topic.end_at);
@@ -8625,13 +8722,20 @@ function TopicSegmentRow({ topic }) {
8625
8722
  range
8626
8723
  ]
8627
8724
  }),
8725
+ typeof topic.message_count === "number" && topic.message_count > 0 && /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
8726
+ className: "text-fg-faint shrink-0",
8727
+ children: [
8728
+ "\xb7 ",
8729
+ topic.message_count,
8730
+ " ",
8731
+ topic.message_count === 1 ? "msg" : "msgs"
8732
+ ]
8733
+ }),
8628
8734
  topic.facts.length > 0 && /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
8629
8735
  className: "ml-auto shrink-0 text-[9px] uppercase tracking-wide text-accent",
8630
8736
  children: [
8631
8737
  topic.facts.length,
8632
- " ",
8633
- topic.facts.length === 1 ? "fact" : "facts",
8634
- " saved"
8738
+ " memorized"
8635
8739
  ]
8636
8740
  })
8637
8741
  ]
@@ -8651,22 +8755,34 @@ function TopicSegmentRow({ topic }) {
8651
8755
  children: topic.recap
8652
8756
  })
8653
8757
  }),
8654
- topic.facts.length > 0 && /*#__PURE__*/ (0,jsx_runtime.jsx)("ul", {
8655
- className: "space-y-0.5",
8656
- children: topic.facts.map((fact, i)=>/*#__PURE__*/ (0,jsx_runtime.jsxs)("li", {
8657
- className: "text-[11px] text-fg-faint",
8658
- children: [
8659
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
8660
- className: "font-medium text-fg-muted",
8758
+ topic.facts.length > 0 && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
8759
+ children: [
8760
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
8761
+ className: "text-[9px] uppercase tracking-wide text-fg-faint",
8762
+ children: "Memorized"
8763
+ }),
8764
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("ul", {
8765
+ className: "space-y-0.5",
8766
+ children: topic.facts.map((fact, i)=>/*#__PURE__*/ (0,jsx_runtime.jsxs)("li", {
8767
+ className: "text-[11px] text-fg-faint",
8661
8768
  children: [
8662
- fact.subject,
8663
- ":"
8769
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
8770
+ className: "font-medium text-fg-muted",
8771
+ children: [
8772
+ fact.subject,
8773
+ ":"
8774
+ ]
8775
+ }),
8776
+ " ",
8777
+ fact.content,
8778
+ fact.key && /*#__PURE__*/ (0,jsx_runtime.jsx)("code", {
8779
+ className: "ml-1 text-[10px] text-fg-faint",
8780
+ children: fact.key
8781
+ })
8664
8782
  ]
8665
- }),
8666
- " ",
8667
- fact.content
8668
- ]
8669
- }, `${fact.subject}-${i}`))
8783
+ }, `${fact.key ?? fact.subject}-${i}`))
8784
+ })
8785
+ ]
8670
8786
  })
8671
8787
  ]
8672
8788
  })
@@ -8799,7 +8915,38 @@ function ContextBoundary_formatBytes(n) {
8799
8915
  // `buildWarmSummary` prepends a couple of plain-text header lines that read
8800
8916
  // awkwardly inside a card that already has its own header. Strip them.
8801
8917
  function stripWarmHeader(raw) {
8802
- return raw.replace(/^--- Warm context summary ---\n/, "").replace(/^Compressed recap of earlier messages outside the hot window:\n/, "").trimStart();
8918
+ return raw.replace(/\r\n/g, "\n").replace(/^\s*(<!--[\s\S]*?-->\s*)+/, "").replace(/^--- Warm context summary ---\n/, "").replace(/^Compressed recap of [^\n]*:\n/, "").trimStart();
8919
+ }
8920
+ /**
8921
+ * Splits a markdown summary into topic segments at its headings. Returns
8922
+ * null when there are fewer than two sections, so short or unstructured
8923
+ * summaries keep the plain prose rendering.
8924
+ */ function topicsFromSummarySections(raw) {
8925
+ const sections = [];
8926
+ let title = null;
8927
+ let body = [];
8928
+ const flush = ()=>{
8929
+ const recap = body.join("\n").trim();
8930
+ if (title !== null || recap) sections.push({
8931
+ title: title ?? "Overview",
8932
+ start_at: "",
8933
+ end_at: "",
8934
+ recap,
8935
+ facts: []
8936
+ });
8937
+ };
8938
+ for (const line of stripWarmHeader(raw).split("\n")){
8939
+ const heading = /^#{1,3}\s+(.+?)\s*#*\s*$/.exec(line);
8940
+ if (heading) {
8941
+ flush();
8942
+ title = heading[1];
8943
+ body = [];
8944
+ } else {
8945
+ body.push(line);
8946
+ }
8947
+ }
8948
+ flush();
8949
+ return sections.length >= 2 ? sections : null;
8803
8950
  }
8804
8951
  function summaryLong(raw) {
8805
8952
  // Heuristic: more than 6 lines or > 600 chars after the header strip.
@@ -8832,11 +8979,13 @@ function formatRelative(iso) {
8832
8979
 
8833
8980
 
8834
8981
 
8982
+
8835
8983
  const ALL_FILTERS_SHOWN = Object.fromEntries(MESSAGE_FILTER_KEYS.map((k)=>[
8836
8984
  k,
8837
8985
  true
8838
8986
  ]));
8839
- function MessageList({ threadId, messages, steeredSegments, notices, agentConfig, userProfile, streamingContent, thinkingContent, toolEvents, hasMore, loadingMore, onLoadMore, queuedMessages, onRemoveQueued, hotSinceSeq, warmSummary, warmSummaryBeforeSeq, warmSummaryComputedAt, warmSummarySourceMessages, warmSummarySourceChars, warmSummaryTopics, warmSummaryPending = false, compactionPending = false, onSetContextPin, streaming, contextWindowTokens, onRetryMessage, filters = ALL_FILTERS_SHOWN, onToggleFilter: toggle = ()=>{}, onResetFilters: reset = ()=>{} }) {
8987
+ const NO_CHANNEL_SUMMARIES = [];
8988
+ function MessageList({ threadId, messages, steeredSegments, agentConfig, userProfile, streamingContent, thinkingContent, toolEvents, hasMore, loadingMore, onLoadMore, queuedMessages, onRemoveQueued, hotSinceSeq, warmSummary, warmSummaryBeforeSeq, warmSummaryComputedAt, warmSummarySourceMessages, warmSummarySourceChars, warmSummaryTopics, warmChannelSummaries = NO_CHANNEL_SUMMARIES, warmSummaryPending = false, compactionPending = false, onSetContextPin, streaming, contextWindowTokens, onRetryMessage, filters = ALL_FILTERS_SHOWN, onToggleFilter: toggle = ()=>{}, onResetFilters: reset = ()=>{} }) {
8840
8989
  const hostRef = (0,react.useRef)(null);
8841
8990
  const maskRegionRef = (0,react.useRef)(null);
8842
8991
  const scrollRef = (0,react.useRef)(null);
@@ -8861,6 +9010,9 @@ function MessageList({ threadId, messages, steeredSegments, notices, agentConfig
8861
9010
  const [pendingHotSinceSeq, setPendingHotSinceSeq] = (0,react.useState)(null);
8862
9011
  const [topControlsOpen, setTopControlsOpen] = (0,react.useState)(false);
8863
9012
  const [summaryPopoverOpen, setSummaryPopoverOpen] = (0,react.useState)(false);
9013
+ const retryWorkflowStep = (0,react.useMemo)(()=>onRetryMessage ? (request)=>onRetryMessage(workflowStepRetryMessage(request), []) : null, [
9014
+ onRetryMessage
9015
+ ]);
8864
9016
  // Apply category filter. Messages with no `category` (NULL = ordinary
8865
9017
  // chat) are always shown; tagged messages are gated by their toggle.
8866
9018
  // The `tool_use` and `thinking` filters do NOT remove whole messages —
@@ -9230,7 +9382,11 @@ function MessageList({ threadId, messages, steeredSegments, notices, agentConfig
9230
9382
  const nextHotCount = pendingBoundaryIndex < 0 ? null : visibleMessages.length - pendingBoundaryIndex;
9231
9383
  const removesFromRecent = currentHotCount !== null && nextHotCount !== null ? nextHotCount < currentHotCount : false;
9232
9384
  const hasWarmSummary = !!warmSummary;
9385
+ // A committed boundary whose chat range had nothing to summarise (e.g. a
9386
+ // bridge-only agent): the recap, if any, lives in the channel summaries.
9387
+ const summaryCommittedEmpty = !hasWarmSummary && effectiveHotSinceSeq !== null && warmSummaryBeforeSeq === effectiveHotSinceSeq;
9233
9388
  const summaryFresh = hasWarmSummary && effectiveHotSinceSeq !== null && warmSummaryBeforeSeq === effectiveHotSinceSeq;
9389
+ const summaryReady = summaryFresh || summaryCommittedEmpty;
9234
9390
  const summaryUpdating = hasWarmSummary && !summaryFresh && !!streaming;
9235
9391
  const summaryStale = hasWarmSummary && !summaryFresh && !summaryUpdating;
9236
9392
  (0,react.useEffect)(()=>{
@@ -9331,10 +9487,29 @@ function MessageList({ threadId, messages, steeredSegments, notices, agentConfig
9331
9487
  }
9332
9488
  boundaryAnchorRef.current = null;
9333
9489
  }, []);
9490
+ // While a programmatic smooth scroll (locate boundary, deep link) animates
9491
+ // away from the bottom, its first frames are still "near bottom". Without
9492
+ // this lock, scroll sync re-arms bottom-follow and the post-render snap
9493
+ // cancels the animation, so the target is never reached.
9494
+ const programmaticScrollUntilRef = (0,react.useRef)(0);
9334
9495
  const syncScrollButton = (0,react.useCallback)((el)=>{
9335
9496
  const isAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 100;
9336
- atBottomRef.current = isAtBottom;
9337
- setShowScrollButton(!isAtBottom && hasScrollTarget);
9497
+ const locked = Date.now() < programmaticScrollUntilRef.current;
9498
+ atBottomRef.current = isAtBottom && !locked;
9499
+ setShowScrollButton(!atBottomRef.current && hasScrollTarget);
9500
+ }, [
9501
+ hasScrollTarget
9502
+ ]);
9503
+ const scrollTargetIntoView = (0,react.useCallback)((target)=>{
9504
+ programmaticScrollUntilRef.current = Date.now() + PROGRAMMATIC_SCROLL_LOCK_MS;
9505
+ atBottomRef.current = false;
9506
+ setShowScrollButton(hasScrollTarget);
9507
+ target.scrollIntoView({
9508
+ behavior: "smooth",
9509
+ block: "center"
9510
+ });
9511
+ target.classList.add("jarela-deep-link-flash");
9512
+ window.setTimeout(()=>target.classList.remove("jarela-deep-link-flash"), 1600);
9338
9513
  }, [
9339
9514
  hasScrollTarget
9340
9515
  ]);
@@ -9463,14 +9638,7 @@ function MessageList({ threadId, messages, steeredSegments, notices, agentConfig
9463
9638
  const safe = id.replace(/"/g, '\\"');
9464
9639
  const el = root.querySelector(`[data-message-id="${safe}"]`);
9465
9640
  if (!el) return;
9466
- atBottomRef.current = false;
9467
- setShowScrollButton(hasScrollTarget);
9468
- el.scrollIntoView({
9469
- behavior: "smooth",
9470
- block: "center"
9471
- });
9472
- el.classList.add("jarela-deep-link-flash");
9473
- setTimeout(()=>el.classList.remove("jarela-deep-link-flash"), 1600);
9641
+ scrollTargetIntoView(el);
9474
9642
  // Strip the hash so the next streaming message / list-length change
9475
9643
  // doesn't yank the view back to this anchor. replaceState avoids
9476
9644
  // triggering a hashchange event (which would re-enter this handler).
@@ -9483,7 +9651,7 @@ function MessageList({ threadId, messages, steeredSegments, notices, agentConfig
9483
9651
  return ()=>window.removeEventListener("hashchange", scrollToHashTarget);
9484
9652
  }, [
9485
9653
  messages.length,
9486
- hasScrollTarget
9654
+ scrollTargetIntoView
9487
9655
  ]);
9488
9656
  // Handle orientation changes and resizes to maintain scroll position
9489
9657
  (0,react.useEffect)(()=>{
@@ -9514,419 +9682,411 @@ function MessageList({ threadId, messages, steeredSegments, notices, agentConfig
9514
9682
  if (!root) return;
9515
9683
  const boundary = effectiveHotSinceSeq !== null ? document.getElementById(`context-boundary-${effectiveHotSinceSeq}`) : root.querySelector("[data-focus-boundary='1']");
9516
9684
  if (!boundary) return;
9517
- atBottomRef.current = false;
9518
- setShowScrollButton(hasScrollTarget);
9519
- boundary.scrollIntoView({
9520
- behavior: "smooth",
9521
- block: "center"
9522
- });
9685
+ scrollTargetIntoView(boundary);
9523
9686
  }
9524
- return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9525
- ref: hostRef,
9526
- className: "flex-1 flex flex-col min-h-0 relative",
9527
- children: [
9528
- visibleMessages.length > 0 && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9529
- className: "shrink-0 px-4 pt-[calc(var(--app-safe-top)+3rem)] pb-1",
9530
- children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9531
- className: "w-full border-b border-border/45 bg-surface/30 px-2 py-1 backdrop-blur-sm",
9687
+ return /*#__PURE__*/ (0,jsx_runtime.jsx)(WorkflowStepRetryContext.Provider, {
9688
+ value: retryWorkflowStep,
9689
+ children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9690
+ ref: hostRef,
9691
+ className: "flex-1 flex flex-col min-h-0 relative",
9692
+ children: [
9693
+ visibleMessages.length > 0 && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9694
+ className: "shrink-0 px-4 pt-[calc(var(--app-safe-top)+3rem)] pb-1",
9695
+ children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9696
+ className: "w-full border-b border-border/45 bg-surface/30 px-2 py-1 backdrop-blur-sm",
9697
+ children: [
9698
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
9699
+ type: "button",
9700
+ onClick: ()=>setTopControlsOpen((v)=>!v),
9701
+ "aria-expanded": topControlsOpen,
9702
+ className: "w-full flex items-center gap-2 py-0.5 text-[11px] text-fg-faint hover:text-fg transition-colors",
9703
+ children: [
9704
+ /*#__PURE__*/ (0,jsx_runtime.jsx)(CollapseChevron, {
9705
+ open: topControlsOpen,
9706
+ size: 10
9707
+ }),
9708
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9709
+ className: "font-semibold uppercase tracking-[0.16em]",
9710
+ children: "Filters & focus"
9711
+ }),
9712
+ hiddenCount > 0 && /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
9713
+ className: "ml-auto text-[10px] text-fg-faint",
9714
+ "aria-live": "polite",
9715
+ children: [
9716
+ hiddenCount,
9717
+ " hidden"
9718
+ ]
9719
+ })
9720
+ ]
9721
+ }),
9722
+ topControlsOpen && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9723
+ className: "mt-1 flex items-center gap-1.5 flex-wrap py-1",
9724
+ children: [
9725
+ availableChips.map((key)=>{
9726
+ const on = filters[key];
9727
+ const Icon = on ? eye/* default */.A : eye_off/* default */.A;
9728
+ return /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
9729
+ type: "button",
9730
+ onClick: ()=>toggle(key),
9731
+ className: [
9732
+ "inline-flex items-center gap-1 rounded-none border px-2 py-0.5 text-[10px] leading-4 transition-colors",
9733
+ on ? "border-border/70 bg-surface-2/70 text-fg-muted hover:text-fg" : "border-border/35 bg-transparent text-fg-faint line-through decoration-fg-faint/60 hover:text-fg-muted"
9734
+ ].join(" "),
9735
+ title: // ADR-0044 — for the three channels the model's own
9736
+ // context is scoped by, the chip's meaning is dual:
9737
+ // it doesn't just show/hide rows here, it also
9738
+ // decides whether that channel's history is folded
9739
+ // into the next turn the agent sees.
9740
+ CHANNEL_SCOPED_FILTER_KEYS.has(key) ? on ? `Hide + exclude ${CHIP_LABELS[key]} from the next turn` : `Show + include ${CHIP_LABELS[key]} in the next turn` : on ? `Hide ${CHIP_LABELS[key]} messages` : `Show ${CHIP_LABELS[key]} messages`,
9741
+ "aria-pressed": on,
9742
+ children: [
9743
+ /*#__PURE__*/ (0,jsx_runtime.jsx)(Icon, {
9744
+ size: 10
9745
+ }),
9746
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9747
+ children: CHIP_LABELS[key]
9748
+ })
9749
+ ]
9750
+ }, key);
9751
+ }),
9752
+ onSetContextPin && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9753
+ type: "button",
9754
+ onClick: scrollToBoundaryLine,
9755
+ disabled: !hasContextPin,
9756
+ className: "control-tap ml-auto rounded-none border border-border/60 bg-surface-2/70 px-2 py-0.5 text-[10px] leading-4 text-fg-faint transition-colors hover:border-accent/40 hover:text-fg disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-border/60 disabled:hover:text-fg-faint",
9757
+ title: hasContextPin ? "Locate the focus boundary in the message list" : "Set a focus boundary first (drag the divider or pin a message) to enable this",
9758
+ children: "Locate boundary line"
9759
+ })
9760
+ ]
9761
+ })
9762
+ ]
9763
+ })
9764
+ }),
9765
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9766
+ ref: maskRegionRef,
9767
+ className: "relative flex-1 min-h-0 overflow-hidden",
9532
9768
  children: [
9533
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
9534
- type: "button",
9535
- onClick: ()=>setTopControlsOpen((v)=>!v),
9536
- "aria-expanded": topControlsOpen,
9537
- className: "w-full flex items-center gap-2 py-0.5 text-[11px] text-fg-faint hover:text-fg transition-colors",
9769
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9770
+ ref: scrollRef,
9771
+ onScroll: handleScroll,
9772
+ className: "flex-1 h-full overflow-y-auto overflow-x-hidden px-4 py-4 panel-scrollbar",
9773
+ style: {
9774
+ // Scroll-anchor jumps (deep-link to a message) land below the
9775
+ // floating header, not under it.
9776
+ scrollPaddingTop: "calc(3rem + var(--app-safe-top))"
9777
+ },
9538
9778
  children: [
9539
- /*#__PURE__*/ (0,jsx_runtime.jsx)(CollapseChevron, {
9540
- open: topControlsOpen,
9541
- size: 10
9779
+ hasMore && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9780
+ className: "text-center py-1.5 text-[11px] text-fg-faint select-none",
9781
+ children: loadingMore ? "Loading earlier messages…" : "Scroll up for earlier messages"
9542
9782
  }),
9543
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9544
- className: "font-semibold uppercase tracking-[0.16em]",
9545
- children: "Filters & focus"
9546
- }),
9547
- hiddenCount > 0 && /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
9548
- className: "ml-auto text-[10px] text-fg-faint",
9549
- "aria-live": "polite",
9783
+ compactionPending && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9784
+ className: "my-2 flex items-center justify-center gap-2 rounded-lg border border-border bg-surface-2/70 px-3 py-1.5 text-[11px] text-fg-faint select-none",
9550
9785
  children: [
9551
- hiddenCount,
9552
- " hidden"
9786
+ /*#__PURE__*/ (0,jsx_runtime.jsx)(StatusDot, {
9787
+ tone: "accent",
9788
+ size: "sm",
9789
+ pulse: true
9790
+ }),
9791
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9792
+ children: "Summarising earlier messages… this turn still sees the full history."
9793
+ })
9553
9794
  ]
9554
- })
9555
- ]
9556
- }),
9557
- topControlsOpen && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9558
- className: "mt-1 flex items-center gap-1.5 flex-wrap py-1",
9559
- children: [
9560
- availableChips.map((key)=>{
9561
- const on = filters[key];
9562
- const Icon = on ? eye/* default */.A : eye_off/* default */.A;
9563
- return /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
9564
- type: "button",
9565
- onClick: ()=>toggle(key),
9566
- className: [
9567
- "inline-flex items-center gap-1 rounded-none border px-2 py-0.5 text-[10px] leading-4 transition-colors",
9568
- on ? "border-border/70 bg-surface-2/70 text-fg-muted hover:text-fg" : "border-border/35 bg-transparent text-fg-faint line-through decoration-fg-faint/60 hover:text-fg-muted"
9569
- ].join(" "),
9570
- title: // ADR-0044 — for the three channels the model's own
9571
- // context is scoped by, the chip's meaning is dual:
9572
- // it doesn't just show/hide rows here, it also
9573
- // decides whether that channel's history is folded
9574
- // into the next turn the agent sees.
9575
- CHANNEL_SCOPED_FILTER_KEYS.has(key) ? on ? `Hide + exclude ${CHIP_LABELS[key]} from the next turn` : `Show + include ${CHIP_LABELS[key]} in the next turn` : on ? `Hide ${CHIP_LABELS[key]} messages` : `Show ${CHIP_LABELS[key]} messages`,
9576
- "aria-pressed": on,
9795
+ }),
9796
+ visibleMessages.length === 0 && !streamingContent && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9797
+ className: "flex items-center justify-center h-full text-fg-faint text-sm select-none",
9798
+ children: messages.length === 0 ? /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9799
+ children: "Send a message to begin"
9800
+ }) : /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9801
+ className: "flex flex-col items-center gap-2 text-center px-4",
9577
9802
  children: [
9578
- /*#__PURE__*/ (0,jsx_runtime.jsx)(Icon, {
9579
- size: 10
9803
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
9804
+ children: [
9805
+ hiddenCount,
9806
+ " message",
9807
+ hiddenCount === 1 ? " is" : "s are",
9808
+ " hidden by filters"
9809
+ ]
9580
9810
  }),
9581
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9582
- children: CHIP_LABELS[key]
9811
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9812
+ type: "button",
9813
+ onClick: reset,
9814
+ className: "control-tap text-xs px-2.5 py-1 rounded-md border border-border bg-surface-2 text-fg-muted hover:text-fg hover:bg-surface-3 transition-colors",
9815
+ children: "Show all messages"
9583
9816
  })
9584
9817
  ]
9585
- }, key);
9818
+ })
9586
9819
  }),
9587
- onSetContextPin && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9588
- type: "button",
9589
- onClick: scrollToBoundaryLine,
9590
- disabled: !hasContextPin,
9591
- className: "control-tap ml-auto rounded-none border border-border/60 bg-surface-2/70 px-2 py-0.5 text-[10px] leading-4 text-fg-faint transition-colors hover:border-accent/40 hover:text-fg disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-border/60 disabled:hover:text-fg-faint",
9592
- title: hasContextPin ? "Locate the focus boundary in the message list" : "Set a focus boundary first (drag the divider or pin a message) to enable this",
9593
- children: "Locate boundary line"
9820
+ (()=>{
9821
+ // ADR-0042. The boundary divider + warm summary card live INSIDE the
9822
+ // message stream so they scroll with content (not above as a fixed
9823
+ // banner). `boundaryIndex` is the index of the first hot message in
9824
+ // the visible list; everything before it is older-than-pin and gets
9825
+ // covered by the warm summary card sitting above the divider.
9826
+ //
9827
+ const hasPin = effectiveHotSinceSeq !== null;
9828
+ const boundaryIndex = hasPin ? boundaryIndexFor(effectiveHotSinceSeq) : -1;
9829
+ const pinAfterAll = hasPin && visibleMessages.length > 0 && boundaryIndex === visibleMessages.length;
9830
+ // The pin is the boundary's source of truth. Summary data can arrive
9831
+ // later (or be unavailable on an older thread), but hiding the line
9832
+ // in that interval makes a valid focus selection look like it vanished.
9833
+ const hasBoundary = hasPin && boundaryIndex >= 0;
9834
+ const olderInVisible = pinAfterAll ? visibleMessages.length : hasBoundary ? boundaryIndex : 0;
9835
+ // "+ N more we don't know about yet" — older pages are likely unloaded.
9836
+ const olderCountLabel = olderInVisible + (hasMore ? 1 : 0);
9837
+ const attachedActivities = new Map();
9838
+ const hiddenActivityIds = new Set();
9839
+ for(let i = 0; i < visibleMessages.length - 1; i++){
9840
+ const activityMessage = visibleMessages[i];
9841
+ const activity = activityMessage.metadata?.automation_activity;
9842
+ if (!activity) continue;
9843
+ const related = visibleMessages[i + 1];
9844
+ const matches = !related.metadata?.automation_activity && (activity.source_kind === "bridge" ? related.role === "user" && related.metadata?.bridge_conversation?.key === activity.source_id : related.role === "assistant" && related.category === activity.source_kind);
9845
+ if (!matches) continue;
9846
+ attachedActivities.set(related.id, activity);
9847
+ hiddenActivityIds.add(activityMessage.id);
9848
+ }
9849
+ const previousVisibleRoles = new Map();
9850
+ let previousVisibleRole = null;
9851
+ for (const message of visibleMessages){
9852
+ previousVisibleRoles.set(message.id, previousVisibleRole);
9853
+ if (!hiddenActivityIds.has(message.id)) previousVisibleRole = message.role;
9854
+ }
9855
+ const renderBoundary = (key)=>/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9856
+ id: effectiveHotSinceSeq !== null ? `context-boundary-${effectiveHotSinceSeq}` : undefined,
9857
+ "data-focus-boundary": "1",
9858
+ "data-boundary-seq": effectiveHotSinceSeq ?? undefined,
9859
+ children: /*#__PURE__*/ (0,jsx_runtime.jsx)(ContextBoundaryDivider, {
9860
+ sourceMessages: warmSummarySourceMessages ?? null,
9861
+ sourceChars: warmSummarySourceChars ?? null,
9862
+ summaryChars: warmSummary ? warmSummary.length : null,
9863
+ lineStats: lineStatsForHotSince(effectiveHotSinceSeq),
9864
+ updating: warmSummaryPending && !summaryFresh,
9865
+ draggable: !!onSetContextPin,
9866
+ hidden: isDraggingFocus,
9867
+ disabled: !!streaming,
9868
+ onClick: handleBoundaryClick,
9869
+ onPointerDown: handleBoundaryPointerDown,
9870
+ onPointerMove: handleBoundaryPointerMove,
9871
+ onPointerUp: handleBoundaryPointerUp,
9872
+ onPointerCancel: handleBoundaryPointerCancel
9873
+ })
9874
+ }, key);
9875
+ const nodes = visibleMessages.flatMap((msg, i)=>{
9876
+ const out = [];
9877
+ if (hasBoundary && !pinAfterAll && i === boundaryIndex) {
9878
+ out.push(renderBoundary(`boundary-${msg.id}`));
9879
+ }
9880
+ if (hiddenActivityIds.has(msg.id)) return out;
9881
+ const previousRole = previousVisibleRoles.get(msg.id);
9882
+ const startsTurn = previousRole == null || previousRole !== msg.role;
9883
+ const steeredSegment = steeredSegments?.find((segment)=>segment.id === msg.id);
9884
+ if (steeredSegment) {
9885
+ out.push(/*#__PURE__*/ (0,jsx_runtime.jsx)(StreamingBubble, {
9886
+ content: steeredSegment.content,
9887
+ threadId: threadId ?? null,
9888
+ agentConfig: agentConfig ?? null,
9889
+ showAvatar: i === 0 || visibleMessages[i - 1].role !== "assistant"
9890
+ }, `steered-${steeredSegment.id}`));
9891
+ }
9892
+ out.push(/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9893
+ id: typeof msg.seq === "number" ? String(msg.seq) : `msg-${msg.id}`,
9894
+ "data-message-id": msg.id,
9895
+ "data-hot-candidate": "1",
9896
+ "data-message-seq": msg.seq,
9897
+ "data-created-at": msg.created_at,
9898
+ className: startsTurn && i > 0 ? "mt-3" : undefined,
9899
+ children: /*#__PURE__*/ (0,jsx_runtime.jsx)(MessageBubble, {
9900
+ message: msg,
9901
+ attachedActivity: attachedActivities.get(msg.id),
9902
+ threadId: threadId ?? null,
9903
+ agentConfig: agentConfig,
9904
+ userProfile: userProfile,
9905
+ showAvatar: startsTurn,
9906
+ showToolEvents: filters.tool_use,
9907
+ contextWindowTokens: contextWindowTokens ?? null,
9908
+ isLatest: i === visibleMessages.length - 1 && !streamingContent,
9909
+ onRetry: onRetryMessage
9910
+ })
9911
+ }, msg.id));
9912
+ return out;
9913
+ });
9914
+ if (hasBoundary && pinAfterAll) nodes.push(renderBoundary("boundary-tail"));
9915
+ return nodes;
9916
+ })(),
9917
+ /*#__PURE__*/ (0,jsx_runtime.jsx)(LiveTurnActivity, {
9918
+ thinkingContent: thinkingContent,
9919
+ streamingContent: streamingContent,
9920
+ toolEvents: toolEvents,
9921
+ filters: filters,
9922
+ threadId: threadId ?? null,
9923
+ agentConfig: agentConfig ?? null,
9924
+ showStreamingAvatar: messages.length === 0 || messages[messages.length - 1].role !== "assistant",
9925
+ streaming: streaming
9926
+ }),
9927
+ queuedMessages && queuedMessages.length > 0 && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9928
+ className: "flex flex-col gap-1 mt-2 mb-1",
9929
+ children: queuedMessages.map((q)=>/*#__PURE__*/ (0,jsx_runtime.jsx)(QueuedBubble, {
9930
+ item: q,
9931
+ onRemove: onRemoveQueued
9932
+ }, q.id))
9594
9933
  })
9595
9934
  ]
9935
+ }),
9936
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9937
+ ref: dragMaskRef,
9938
+ className: "pointer-events-none absolute left-0 right-0 top-0 z-40 opacity-0 transition-opacity duration-75",
9939
+ style: {
9940
+ transform: "translateY(0px)",
9941
+ height: "0px",
9942
+ background: "linear-gradient(to top, rgba(82,82,91,0.24) 0%, rgba(82,82,91,0.2) 22%, rgba(82,82,91,0.14) 48%, rgba(82,82,91,0.08) 72%, rgba(82,82,91,0.03) 88%, rgba(82,82,91,0) 100%)",
9943
+ borderBottom: "0",
9944
+ backdropFilter: "grayscale(0.5) saturate(0.18) contrast(0.98)",
9945
+ WebkitBackdropFilter: "grayscale(0.5) saturate(0.18) contrast(0.98)",
9946
+ maskImage: "linear-gradient(to top, black 0%, rgba(0,0,0,0.88) 72%, rgba(0,0,0,0.32) 90%, transparent 100%)",
9947
+ WebkitMaskImage: "linear-gradient(to top, black 0%, rgba(0,0,0,0.88) 72%, rgba(0,0,0,0.32) 90%, transparent 100%)"
9948
+ }
9596
9949
  })
9597
9950
  ]
9598
- })
9599
- }),
9600
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9601
- ref: maskRegionRef,
9602
- className: "relative flex-1 min-h-0 overflow-hidden",
9603
- children: [
9604
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9605
- ref: scrollRef,
9606
- onScroll: handleScroll,
9607
- className: "flex-1 h-full overflow-y-auto overflow-x-hidden px-4 py-4 panel-scrollbar",
9951
+ }),
9952
+ showScrollButton && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9953
+ onClick: scrollToBottom,
9954
+ style: {
9955
+ bottom: "calc(1rem + var(--app-safe-bottom))"
9956
+ },
9957
+ className: "absolute right-4 p-2 rounded-full bg-accent/40 hover:bg-accent/80 text-white backdrop-blur-sm shadow-md transition-all animate-in fade-in slide-in-from-bottom-2 duration-200 z-20",
9958
+ title: "Auto-scroll paused — resume at latest message",
9959
+ "aria-label": "Resume auto-scroll to latest message",
9960
+ children: /*#__PURE__*/ (0,jsx_runtime.jsx)(arrow_down/* default */.A, {
9961
+ size: 18
9962
+ })
9963
+ }),
9964
+ isDraggingFocus && /*#__PURE__*/ (0,jsx_runtime.jsx)(jsx_runtime.Fragment, {
9965
+ children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9966
+ ref: dragGuideRef,
9967
+ className: "pointer-events-none absolute left-4 right-4 z-50 opacity-0",
9608
9968
  style: {
9609
- // Scroll-anchor jumps (deep-link to a message) land below the
9610
- // floating header, not under it.
9611
- scrollPaddingTop: "calc(3rem + var(--app-safe-top))"
9969
+ transform: "translateY(0px)"
9612
9970
  },
9613
9971
  children: [
9614
- hasMore && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9615
- className: "text-center py-1.5 text-[11px] text-fg-faint select-none",
9616
- children: loadingMore ? "Loading earlier messages…" : "Scroll up for earlier messages"
9617
- }),
9618
- compactionPending && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9619
- className: "my-2 flex items-center justify-center gap-2 rounded-lg border border-border bg-surface-2/70 px-3 py-1.5 text-[11px] text-fg-faint select-none",
9620
- children: [
9621
- /*#__PURE__*/ (0,jsx_runtime.jsx)(StatusDot, {
9622
- tone: "accent",
9623
- size: "sm",
9624
- pulse: true
9625
- }),
9626
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9627
- children: "Summarising earlier messages… this turn still sees the full history."
9628
- })
9629
- ]
9972
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9973
+ className: "h-[2px] bg-gradient-to-r from-transparent via-accent to-transparent opacity-95 shadow-[0_0_8px_rgba(59,130,246,0.55)]"
9630
9974
  }),
9631
- visibleMessages.length === 0 && !streamingContent && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9632
- className: "flex items-center justify-center h-full text-fg-faint text-sm select-none",
9633
- children: messages.length === 0 ? /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9634
- children: "Send a message to begin"
9635
- }) : /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9636
- className: "flex flex-col items-center gap-2 text-center px-4",
9975
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9976
+ ref: dragGuideStatsRef,
9977
+ className: "absolute right-1 top-1/2 -translate-y-1/2 text-[10px] text-fg-faint bg-surface/75 px-1.5 rounded border border-border/60",
9978
+ children: lineStatsForHotSince(effectiveHotSinceSeq)
9979
+ })
9980
+ ]
9981
+ })
9982
+ }),
9983
+ summaryPopoverOpen && /*#__PURE__*/ (0,jsx_runtime.jsx)(Dialog/* Dialog */.l, {
9984
+ open: true,
9985
+ onClose: ()=>setSummaryPopoverOpen(false),
9986
+ title: "Earlier messages summary",
9987
+ size: "xl",
9988
+ align: "top",
9989
+ padded: false,
9990
+ children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9991
+ className: "p-4 space-y-3",
9992
+ children: [
9993
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9994
+ className: "flex items-center gap-2",
9995
+ children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
9996
+ className: [
9997
+ "text-[10px] px-1.5 py-px rounded border inline-flex items-center gap-1",
9998
+ summaryUpdating ? "border-accent/40 bg-accent/10 text-accent" : summaryReady ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400" : summaryStale ? "border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-400" : "border-border bg-surface-2 text-fg-faint"
9999
+ ].join(" "),
9637
10000
  children: [
9638
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
9639
- children: [
9640
- hiddenCount,
9641
- " message",
9642
- hiddenCount === 1 ? " is" : "s are",
9643
- " hidden by filters"
9644
- ]
10001
+ summaryUpdating && /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
10002
+ className: "h-2 w-2 rounded-full bg-accent animate-pulse",
10003
+ "aria-label": "Summary updating"
9645
10004
  }),
9646
- /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9647
- type: "button",
9648
- onClick: reset,
9649
- className: "control-tap text-xs px-2.5 py-1 rounded-md border border-border bg-surface-2 text-fg-muted hover:text-fg hover:bg-surface-3 transition-colors",
9650
- children: "Show all messages"
10005
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
10006
+ children: summaryUpdating ? "updating" : summaryReady ? "ready" : summaryStale ? "needs refresh" : "pending"
9651
10007
  })
9652
10008
  ]
9653
10009
  })
9654
10010
  }),
9655
- (()=>{
9656
- // ADR-0042. The boundary divider + warm summary card live INSIDE the
9657
- // message stream so they scroll with content (not above as a fixed
9658
- // banner). `boundaryIndex` is the index of the first hot message in
9659
- // the visible list; everything before it is older-than-pin and gets
9660
- // covered by the warm summary card sitting above the divider.
9661
- //
9662
- const hasPin = effectiveHotSinceSeq !== null;
9663
- const boundaryIndex = hasPin ? boundaryIndexFor(effectiveHotSinceSeq) : -1;
9664
- const pinAfterAll = hasPin && visibleMessages.length > 0 && boundaryIndex === visibleMessages.length;
9665
- // The pin is the boundary's source of truth. Summary data can arrive
9666
- // later (or be unavailable on an older thread), but hiding the line
9667
- // in that interval makes a valid focus selection look like it vanished.
9668
- const hasBoundary = hasPin && boundaryIndex >= 0;
9669
- const olderInVisible = pinAfterAll ? visibleMessages.length : hasBoundary ? boundaryIndex : 0;
9670
- // "+ N more we don't know about yet" — older pages are likely unloaded.
9671
- const olderCountLabel = olderInVisible + (hasMore ? 1 : 0);
9672
- const attachedActivities = new Map();
9673
- const hiddenActivityIds = new Set();
9674
- for(let i = 0; i < visibleMessages.length - 1; i++){
9675
- const activityMessage = visibleMessages[i];
9676
- const activity = activityMessage.metadata?.automation_activity;
9677
- if (!activity) continue;
9678
- const related = visibleMessages[i + 1];
9679
- const matches = !related.metadata?.automation_activity && (activity.source_kind === "bridge" ? related.role === "user" && related.metadata?.bridge_conversation?.key === activity.source_id : related.role === "assistant" && related.category === activity.source_kind);
9680
- if (!matches) continue;
9681
- attachedActivities.set(related.id, activity);
9682
- hiddenActivityIds.add(activityMessage.id);
9683
- }
9684
- const previousVisibleRoles = new Map();
9685
- let previousVisibleRole = null;
9686
- for (const message of visibleMessages){
9687
- previousVisibleRoles.set(message.id, previousVisibleRole);
9688
- if (!hiddenActivityIds.has(message.id)) previousVisibleRole = message.role;
9689
- }
9690
- const renderBoundary = (key)=>/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9691
- id: effectiveHotSinceSeq !== null ? `context-boundary-${effectiveHotSinceSeq}` : undefined,
9692
- "data-focus-boundary": "1",
9693
- "data-boundary-seq": effectiveHotSinceSeq ?? undefined,
9694
- children: /*#__PURE__*/ (0,jsx_runtime.jsx)(ContextBoundaryDivider, {
9695
- sourceMessages: warmSummarySourceMessages ?? null,
9696
- sourceChars: warmSummarySourceChars ?? null,
9697
- summaryChars: warmSummary ? warmSummary.length : null,
9698
- lineStats: lineStatsForHotSince(effectiveHotSinceSeq),
9699
- updating: warmSummaryPending && !summaryFresh,
9700
- draggable: !!onSetContextPin,
9701
- hidden: isDraggingFocus,
9702
- disabled: !!streaming,
9703
- onClick: handleBoundaryClick,
9704
- onPointerDown: handleBoundaryPointerDown,
9705
- onPointerMove: handleBoundaryPointerMove,
9706
- onPointerUp: handleBoundaryPointerUp,
9707
- onPointerCancel: handleBoundaryPointerCancel
9708
- })
9709
- }, key);
9710
- const nodes = visibleMessages.flatMap((msg, i)=>{
9711
- const out = [];
9712
- if (hasBoundary && !pinAfterAll && i === boundaryIndex) {
9713
- out.push(renderBoundary(`boundary-${msg.id}`));
9714
- }
9715
- if (hiddenActivityIds.has(msg.id)) return out;
9716
- const previousRole = previousVisibleRoles.get(msg.id);
9717
- const startsTurn = previousRole == null || previousRole !== msg.role;
9718
- const steeredSegment = steeredSegments?.find((segment)=>segment.id === msg.id);
9719
- if (steeredSegment) {
9720
- out.push(/*#__PURE__*/ (0,jsx_runtime.jsx)(StreamingBubble, {
9721
- content: steeredSegment.content,
9722
- threadId: threadId ?? null,
9723
- agentConfig: agentConfig ?? null,
9724
- showAvatar: i === 0 || visibleMessages[i - 1].role !== "assistant"
9725
- }, `steered-${steeredSegment.id}`));
9726
- }
9727
- out.push(/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9728
- id: typeof msg.seq === "number" ? String(msg.seq) : `msg-${msg.id}`,
9729
- "data-message-id": msg.id,
9730
- "data-hot-candidate": "1",
9731
- "data-message-seq": msg.seq,
9732
- "data-created-at": msg.created_at,
9733
- className: startsTurn && i > 0 ? "mt-3" : undefined,
9734
- children: /*#__PURE__*/ (0,jsx_runtime.jsx)(MessageBubble, {
9735
- message: msg,
9736
- attachedActivity: attachedActivities.get(msg.id),
9737
- threadId: threadId ?? null,
9738
- agentConfig: agentConfig,
9739
- userProfile: userProfile,
9740
- showAvatar: startsTurn,
9741
- showToolEvents: filters.tool_use,
9742
- contextWindowTokens: contextWindowTokens ?? null,
9743
- isLatest: i === visibleMessages.length - 1 && !streamingContent,
9744
- onRetry: onRetryMessage
9745
- })
9746
- }, msg.id));
9747
- return out;
9748
- });
9749
- if (hasBoundary && pinAfterAll) nodes.push(renderBoundary("boundary-tail"));
9750
- return nodes;
9751
- })(),
9752
- /*#__PURE__*/ (0,jsx_runtime.jsx)(LiveTurnActivity, {
9753
- thinkingContent: thinkingContent,
9754
- streamingContent: streamingContent,
9755
- toolEvents: toolEvents,
9756
- filters: filters,
9757
- threadId: threadId ?? null,
9758
- agentConfig: agentConfig ?? null,
9759
- showStreamingAvatar: messages.length === 0 || messages[messages.length - 1].role !== "assistant",
9760
- streaming: streaming
9761
- }),
9762
- queuedMessages && queuedMessages.length > 0 && /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9763
- className: "flex flex-col gap-1 mt-2 mb-1",
9764
- children: queuedMessages.map((q)=>/*#__PURE__*/ (0,jsx_runtime.jsx)(QueuedBubble, {
9765
- item: q,
9766
- onRemove: onRemoveQueued
9767
- }, q.id))
9768
- }),
9769
- notices?.map((n)=>/*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9770
- className: "flex justify-center my-3",
9771
- children: /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9772
- className: "text-xs italic text-fg-faint bg-surface-2 px-3 py-1 rounded-full border border-border",
9773
- children: n.text
9774
- })
9775
- }, n.id))
10011
+ !summaryUpdating && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
10012
+ className: "text-[11px] text-fg-faint",
10013
+ children: summaryFresh ? "Showing the latest summary for messages above the boundary line." : summaryCommittedEmpty ? warmChannelSummaries.length > 0 ? "No chat messages above the boundary line; automation activity there is summarised below." : "Nothing above the boundary line needed summarising." : summaryStale ? "This summary is from an older focus and will refresh after the next reply." : "No summary yet. It will appear after the next reply."
10014
+ }),
10015
+ /*#__PURE__*/ (0,jsx_runtime.jsx)(WarmSummaryCard, {
10016
+ olderCount: countOlderForHotSince(effectiveHotSinceSeq) + (hasMore ? 1 : 0),
10017
+ summary: warmSummary ?? null,
10018
+ summaryBeforeSeq: warmSummaryBeforeSeq ?? null,
10019
+ hotSinceSeq: effectiveHotSinceSeq,
10020
+ computedAt: warmSummaryComputedAt ?? null,
10021
+ streaming: !!streaming,
10022
+ topics: warmSummaryTopics ?? null,
10023
+ channelSummaries: warmChannelSummaries
10024
+ })
9776
10025
  ]
9777
- }),
9778
- /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9779
- ref: dragMaskRef,
9780
- className: "pointer-events-none absolute left-0 right-0 top-0 z-40 opacity-0 transition-opacity duration-75",
9781
- style: {
9782
- transform: "translateY(0px)",
9783
- height: "0px",
9784
- background: "linear-gradient(to top, rgba(82,82,91,0.24) 0%, rgba(82,82,91,0.2) 22%, rgba(82,82,91,0.14) 48%, rgba(82,82,91,0.08) 72%, rgba(82,82,91,0.03) 88%, rgba(82,82,91,0) 100%)",
9785
- borderBottom: "0",
9786
- backdropFilter: "grayscale(0.5) saturate(0.18) contrast(0.98)",
9787
- WebkitBackdropFilter: "grayscale(0.5) saturate(0.18) contrast(0.98)",
9788
- maskImage: "linear-gradient(to top, black 0%, rgba(0,0,0,0.88) 72%, rgba(0,0,0,0.32) 90%, transparent 100%)",
9789
- WebkitMaskImage: "linear-gradient(to top, black 0%, rgba(0,0,0,0.88) 72%, rgba(0,0,0,0.32) 90%, transparent 100%)"
9790
- }
9791
10026
  })
9792
- ]
9793
- }),
9794
- showScrollButton && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9795
- onClick: scrollToBottom,
9796
- style: {
9797
- bottom: "calc(1rem + var(--app-safe-bottom))"
9798
- },
9799
- className: "absolute right-4 p-2 rounded-full bg-accent/40 hover:bg-accent/80 text-white backdrop-blur-sm shadow-md transition-all animate-in fade-in slide-in-from-bottom-2 duration-200 z-20",
9800
- title: "Auto-scroll paused — resume at latest message",
9801
- "aria-label": "Resume auto-scroll to latest message",
9802
- children: /*#__PURE__*/ (0,jsx_runtime.jsx)(arrow_down/* default */.A, {
9803
- size: 18
9804
- })
9805
- }),
9806
- isDraggingFocus && /*#__PURE__*/ (0,jsx_runtime.jsx)(jsx_runtime.Fragment, {
9807
- children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9808
- ref: dragGuideRef,
9809
- className: "pointer-events-none absolute left-4 right-4 z-50 opacity-0",
9810
- style: {
9811
- transform: "translateY(0px)"
10027
+ }),
10028
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)(Dialog/* Dialog */.l, {
10029
+ open: confirmOpen,
10030
+ onClose: ()=>{
10031
+ setConfirmOpen(false);
10032
+ setPendingHotSinceSeq(null);
9812
10033
  },
10034
+ size: "sm",
10035
+ align: "center",
10036
+ dismissOnBackdrop: false,
9813
10037
  children: [
9814
- /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9815
- className: "h-[2px] bg-gradient-to-r from-transparent via-accent to-transparent opacity-95 shadow-[0_0_8px_rgba(59,130,246,0.55)]"
10038
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("h4", {
10039
+ className: "text-sm font-semibold text-fg",
10040
+ children: "Move conversation focus here?"
9816
10041
  }),
9817
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9818
- ref: dragGuideStatsRef,
9819
- className: "absolute right-1 top-1/2 -translate-y-1/2 text-[10px] text-fg-faint bg-surface/75 px-1.5 rounded border border-border/60",
9820
- children: lineStatsForHotSince(effectiveHotSinceSeq)
9821
- })
9822
- ]
9823
- })
9824
- }),
9825
- summaryPopoverOpen && /*#__PURE__*/ (0,jsx_runtime.jsx)(Dialog/* Dialog */.l, {
9826
- open: true,
9827
- onClose: ()=>setSummaryPopoverOpen(false),
9828
- title: "Earlier messages summary",
9829
- size: "xl",
9830
- align: "top",
9831
- padded: false,
9832
- children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9833
- className: "p-4 space-y-3",
9834
- children: [
9835
- /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9836
- className: "flex items-center gap-2",
9837
- children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
9838
- className: [
9839
- "text-[10px] px-1.5 py-px rounded border inline-flex items-center gap-1",
9840
- summaryUpdating ? "border-accent/40 bg-accent/10 text-accent" : summaryFresh ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400" : summaryStale ? "border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-400" : "border-border bg-surface-2 text-fg-faint"
9841
- ].join(" "),
9842
- children: [
9843
- summaryUpdating && /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9844
- className: "h-2 w-2 rounded-full bg-accent animate-pulse",
9845
- "aria-label": "Summary updating"
9846
- }),
9847
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
9848
- children: summaryUpdating ? "updating" : summaryFresh ? "ready" : summaryStale ? "needs refresh" : "pending"
9849
- })
9850
- ]
9851
- })
10042
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
10043
+ className: "text-xs text-fg-muted leading-relaxed",
10044
+ children: "Start a new conversation context from this point. New replies will prioritize recent messages below this line."
9852
10045
  }),
9853
- !summaryUpdating && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
10046
+ nextHotCount !== null && /*#__PURE__*/ (0,jsx_runtime.jsxs)("p", {
9854
10047
  className: "text-[11px] text-fg-faint",
9855
- children: summaryFresh ? "Showing the latest summary for messages above the boundary line." : summaryStale ? "This summary is from an older focus and will refresh after the next reply." : "No summary yet. It will appear after the next reply."
10048
+ children: [
10049
+ "Recent in focus: ",
10050
+ nextHotCount,
10051
+ " loaded message",
10052
+ nextHotCount === 1 ? "" : "s",
10053
+ "; earlier loaded summary: ",
10054
+ Math.max(0, visibleMessages.length - nextHotCount),
10055
+ "."
10056
+ ]
9856
10057
  }),
9857
- /*#__PURE__*/ (0,jsx_runtime.jsx)(WarmSummaryCard, {
9858
- olderCount: countOlderForHotSince(effectiveHotSinceSeq) + (hasMore ? 1 : 0),
9859
- summary: warmSummary ?? null,
9860
- summaryBeforeSeq: warmSummaryBeforeSeq ?? null,
9861
- hotSinceSeq: effectiveHotSinceSeq,
9862
- computedAt: warmSummaryComputedAt ?? null,
9863
- streaming: !!streaming,
9864
- topics: warmSummaryTopics ?? null
10058
+ removesFromRecent && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
10059
+ className: "text-[11px] text-amber-600 dark:text-amber-400",
10060
+ children: "This reduces recent in-focus messages. You can drag upward later to add history back."
10061
+ }),
10062
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
10063
+ className: "flex justify-end gap-2 pt-1",
10064
+ children: [
10065
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
10066
+ type: "button",
10067
+ onClick: ()=>{
10068
+ setConfirmOpen(false);
10069
+ setPendingHotSinceSeq(null);
10070
+ },
10071
+ className: "px-3 py-1.5 text-xs text-fg-subtle hover:text-fg transition-colors",
10072
+ children: "Cancel"
10073
+ }),
10074
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
10075
+ type: "button",
10076
+ onClick: ()=>{
10077
+ if (pendingHotSinceSeq !== null && onSetContextPin) onSetContextPin(pendingHotSinceSeq);
10078
+ setConfirmOpen(false);
10079
+ setPendingHotSinceSeq(null);
10080
+ },
10081
+ className: "px-3 py-1.5 rounded-md text-xs border border-accent/40 bg-accent text-white hover:opacity-95 transition-opacity",
10082
+ children: "Move focus"
10083
+ })
10084
+ ]
9865
10085
  })
9866
10086
  ]
9867
10087
  })
9868
- }),
9869
- /*#__PURE__*/ (0,jsx_runtime.jsxs)(Dialog/* Dialog */.l, {
9870
- open: confirmOpen,
9871
- onClose: ()=>{
9872
- setConfirmOpen(false);
9873
- setPendingHotSinceSeq(null);
9874
- },
9875
- size: "sm",
9876
- align: "center",
9877
- dismissOnBackdrop: false,
9878
- children: [
9879
- /*#__PURE__*/ (0,jsx_runtime.jsx)("h4", {
9880
- className: "text-sm font-semibold text-fg",
9881
- children: "Move conversation focus here?"
9882
- }),
9883
- /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
9884
- className: "text-xs text-fg-muted leading-relaxed",
9885
- children: "Start a new conversation context from this point. New replies will prioritize recent messages below this line."
9886
- }),
9887
- nextHotCount !== null && /*#__PURE__*/ (0,jsx_runtime.jsxs)("p", {
9888
- className: "text-[11px] text-fg-faint",
9889
- children: [
9890
- "Recent in focus: ",
9891
- nextHotCount,
9892
- " loaded message",
9893
- nextHotCount === 1 ? "" : "s",
9894
- "; earlier loaded summary: ",
9895
- Math.max(0, visibleMessages.length - nextHotCount),
9896
- "."
9897
- ]
9898
- }),
9899
- removesFromRecent && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
9900
- className: "text-[11px] text-amber-600 dark:text-amber-400",
9901
- children: "This reduces recent in-focus messages. You can drag upward later to add history back."
9902
- }),
9903
- /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9904
- className: "flex justify-end gap-2 pt-1",
9905
- children: [
9906
- /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9907
- type: "button",
9908
- onClick: ()=>{
9909
- setConfirmOpen(false);
9910
- setPendingHotSinceSeq(null);
9911
- },
9912
- className: "px-3 py-1.5 text-xs text-fg-subtle hover:text-fg transition-colors",
9913
- children: "Cancel"
9914
- }),
9915
- /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
9916
- type: "button",
9917
- onClick: ()=>{
9918
- if (pendingHotSinceSeq !== null && onSetContextPin) onSetContextPin(pendingHotSinceSeq);
9919
- setConfirmOpen(false);
9920
- setPendingHotSinceSeq(null);
9921
- },
9922
- className: "px-3 py-1.5 rounded-md text-xs border border-accent/40 bg-accent text-white hover:opacity-95 transition-opacity",
9923
- children: "Move focus"
9924
- })
9925
- ]
9926
- })
9927
- ]
9928
- })
9929
- ]
10088
+ ]
10089
+ })
9930
10090
  });
9931
10091
  }
9932
10092
  // ADR-0044 — the subset of MESSAGE_FILTER_KEYS that also map to a
@@ -9938,6 +10098,7 @@ const CHANNEL_SCOPED_FILTER_KEYS = new Set([
9938
10098
  "watcher",
9939
10099
  "bridge"
9940
10100
  ]);
10101
+ const PROGRAMMATIC_SCROLL_LOCK_MS = 1500;
9941
10102
  const CHIP_LABELS = {
9942
10103
  scheduled_task: "scheduled",
9943
10104
  watcher: "watcher",
@@ -10107,7 +10268,46 @@ function QueuedBubble({ item, onRemove }) {
10107
10268
  }
10108
10269
 
10109
10270
  ;// ./components/chat/chat-helpers.ts
10110
- /* __next_internal_client_entry_do_not_use__ isUnconfirmed,appendUnique,applyThreadMeta,makeQueuedId,parseWarmSummaryTopics auto */ // Append-with-reconcile. Merges server-persisted rows into the local list
10271
+ /* __next_internal_client_entry_do_not_use__ compactionOutcomeToast,isUnconfirmed,appendUnique,applyThreadMeta,makeQueuedId,parseWarmSummaryTopics auto */ // Maps the /compact response to the toast the user sees. The server's reason
10272
+ // decides the text: "nothing to compact" means the thread is empty, anything
10273
+ // else means there were messages but no summary came out of them.
10274
+ function compactionOutcomeToast(result) {
10275
+ if (result.compacted) {
10276
+ const n = result.message_count ?? 0;
10277
+ return {
10278
+ kind: "success",
10279
+ title: "Context compacted",
10280
+ body: n > 0 ? `Summarised ${n} message${n === 1 ? "" : "s"} into warm context.` : "Started a fresh context window."
10281
+ };
10282
+ }
10283
+ if (result.reason === "nothing to compact") {
10284
+ return {
10285
+ kind: "info",
10286
+ title: "Nothing to compact",
10287
+ body: "This conversation has no messages yet."
10288
+ };
10289
+ }
10290
+ if (result.reason === "already compacting") {
10291
+ return {
10292
+ kind: "info",
10293
+ title: "Already compacting",
10294
+ body: "A compaction for this conversation is still running."
10295
+ };
10296
+ }
10297
+ if (result.reason === "timed out") {
10298
+ return {
10299
+ kind: "error",
10300
+ title: "Compaction timed out",
10301
+ body: "The summary took too long and was discarded. Context is unchanged."
10302
+ };
10303
+ }
10304
+ return {
10305
+ kind: "info",
10306
+ title: "Nothing was compacted",
10307
+ body: "There was too little to summarise, or the model returned no usable summary. Context is unchanged."
10308
+ };
10309
+ }
10310
+ // Append-with-reconcile. Merges server-persisted rows into the local list
10111
10311
  // with three rules, applied in order for each incoming message:
10112
10312
  //
10113
10313
  // 1. Already present by server id → update in place (handles the
@@ -10192,10 +10392,12 @@ function applyThreadMeta(meta, payload) {
10192
10392
  meta.setWarmSummarySourceMessages(payload.warm_summary_source_messages ?? null);
10193
10393
  meta.setWarmSummarySourceChars(payload.warm_summary_source_chars ?? null);
10194
10394
  meta.setWarmSummaryTopics?.(payload.warm_summary_topics ?? null);
10395
+ meta.setWarmChannelSummaries?.(payload.warm_channel_summaries ?? []);
10195
10396
  meta.setContextWindowTokens(payload.context_window_tokens ?? null);
10196
10397
  const summaryFresh = hotSinceSeq !== null && summaryBeforeSeq === hotSinceSeq;
10197
10398
  meta.setWarmSummaryPending?.(hotSinceSeq !== null && !summaryFresh);
10198
10399
  meta.setCompactionPending?.(payload.pending_hot_since_seq != null);
10400
+ meta.setManualCompactionPending?.(payload.manual_compaction_pending === true);
10199
10401
  }
10200
10402
  function makeQueuedId(prefix = "q") {
10201
10403
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
@@ -10211,8 +10413,6 @@ function makeQueuedId(prefix = "q") {
10211
10413
  }
10212
10414
  }
10213
10415
 
10214
- // EXTERNAL MODULE: ./lib/ui/error-report.ts
10215
- var error_report = __webpack_require__(11856);
10216
10416
  ;// ./lib/ui/error-message.ts
10217
10417
  /* __next_internal_client_entry_do_not_use__ friendlyErrorTitle,reportError auto */ // Centralized human-friendly error-title mapping. Used by pushErrorToast
10218
10418
  // callers so the headline a user sees is consistent across the UI:
@@ -10543,7 +10743,6 @@ function useThreadCrossDeviceSync({ threadId, streamingRef, messagesRef, setMess
10543
10743
 
10544
10744
  function useThreadData({ threadId, attach }) {
10545
10745
  const [messages, setMessages] = (0,react.useState)([]);
10546
- const [notices, setNotices] = (0,react.useState)([]);
10547
10746
  const [hasMore, setHasMore] = (0,react.useState)(false);
10548
10747
  const [loadingMore, setLoadingMore] = (0,react.useState)(false);
10549
10748
  const [messagesLoading, setMessagesLoading] = (0,react.useState)(false);
@@ -10557,8 +10756,10 @@ function useThreadData({ threadId, attach }) {
10557
10756
  const [warmSummarySourceMessages, setWarmSummarySourceMessages] = (0,react.useState)(null);
10558
10757
  const [warmSummarySourceChars, setWarmSummarySourceChars] = (0,react.useState)(null);
10559
10758
  const [warmSummaryTopics, setWarmSummaryTopics] = (0,react.useState)(null);
10759
+ const [warmChannelSummaries, setWarmChannelSummaries] = (0,react.useState)([]);
10560
10760
  const [warmSummaryPending, setWarmSummaryPending] = (0,react.useState)(false);
10561
10761
  const [compactionPending, setCompactionPending] = (0,react.useState)(false);
10762
+ const [manualCompactionPending, setManualCompactionPending] = (0,react.useState)(false);
10562
10763
  const [contextWindowTokens, setContextWindowTokens] = (0,react.useState)(null);
10563
10764
  const messagesRef = (0,react.useRef)([]);
10564
10765
  messagesRef.current = messages;
@@ -10575,22 +10776,14 @@ function useThreadData({ threadId, attach }) {
10575
10776
  setContextWindowTokens,
10576
10777
  setWarmSummaryPending,
10577
10778
  setCompactionPending,
10578
- setWarmSummaryTopics
10779
+ setManualCompactionPending,
10780
+ setWarmSummaryTopics,
10781
+ setWarmChannelSummaries
10579
10782
  };
10580
- const addNotice = (0,react.useCallback)((text)=>{
10581
- setNotices((p)=>[
10582
- ...p,
10583
- {
10584
- id: `notice-${Date.now()}`,
10585
- text
10586
- }
10587
- ]);
10588
- }, []);
10589
10783
  (0,react.useEffect)(()=>{
10590
10784
  if (!threadId) {
10591
10785
  setMetadataThreadId(null);
10592
10786
  setMessages([]);
10593
- setNotices([]);
10594
10787
  setHasMore(false);
10595
10788
  setMessagesLoading(false);
10596
10789
  setHotSince(null);
@@ -10602,8 +10795,10 @@ function useThreadData({ threadId, attach }) {
10602
10795
  setWarmSummarySourceMessages(null);
10603
10796
  setWarmSummarySourceChars(null);
10604
10797
  setWarmSummaryTopics(null);
10798
+ setWarmChannelSummaries([]);
10605
10799
  setWarmSummaryPending(false);
10606
10800
  setCompactionPending(false);
10801
+ setManualCompactionPending(false);
10607
10802
  setContextWindowTokens(null);
10608
10803
  return;
10609
10804
  }
@@ -10621,8 +10816,10 @@ function useThreadData({ threadId, attach }) {
10621
10816
  setWarmSummarySourceMessages(null);
10622
10817
  setWarmSummarySourceChars(null);
10623
10818
  setWarmSummaryTopics(null);
10819
+ setWarmChannelSummaries([]);
10624
10820
  setWarmSummaryPending(false);
10625
10821
  setCompactionPending(false);
10822
+ setManualCompactionPending(false);
10626
10823
  setContextWindowTokens(null);
10627
10824
  client/* api */.FH.threads.get(threadId).then((d)=>{
10628
10825
  if (cancelled) return;
@@ -10668,6 +10865,7 @@ function useThreadData({ threadId, attach }) {
10668
10865
  setWarmSummarySourceMessages(updated.warm_summary_source_messages);
10669
10866
  setWarmSummarySourceChars(updated.warm_summary_source_chars);
10670
10867
  setWarmSummaryTopics(updated.warm_summary_topics);
10868
+ setWarmChannelSummaries(updated.warm_channel_summaries ?? []);
10671
10869
  setCompactionPending(updated.pending_hot_since_seq != null);
10672
10870
  const summaryFresh = updated.hot_since_seq != null && updated.warm_summary_before_seq === updated.hot_since_seq;
10673
10871
  if (!updated.pending_hot_since_seq && (!updated.hot_since_seq || summaryFresh)) {
@@ -10685,7 +10883,7 @@ function useThreadData({ threadId, attach }) {
10685
10883
  if (!threadId) return;
10686
10884
  const summaryFresh = hotSinceSeq !== null && warmSummaryBeforeSeq === hotSinceSeq;
10687
10885
  const summaryStale = warmSummaryPending && hotSinceSeq !== null && !summaryFresh;
10688
- if (!summaryStale && !compactionPending) {
10886
+ if (!summaryStale && !compactionPending && !manualCompactionPending) {
10689
10887
  if (warmSummaryPending && hotSinceSeq !== null && summaryFresh) setWarmSummaryPending(false);
10690
10888
  return;
10691
10889
  }
@@ -10711,6 +10909,7 @@ function useThreadData({ threadId, attach }) {
10711
10909
  threadId,
10712
10910
  warmSummaryPending,
10713
10911
  compactionPending,
10912
+ manualCompactionPending,
10714
10913
  hotSince,
10715
10914
  hotSinceSeq,
10716
10915
  warmSummaryBefore,
@@ -10748,9 +10947,6 @@ function useThreadData({ threadId, attach }) {
10748
10947
  messages,
10749
10948
  setMessages,
10750
10949
  messagesRef,
10751
- notices,
10752
- setNotices,
10753
- addNotice,
10754
10950
  hasMore,
10755
10951
  setHasMore,
10756
10952
  loadingMore,
@@ -10765,8 +10961,10 @@ function useThreadData({ threadId, attach }) {
10765
10961
  warmSummarySourceMessages,
10766
10962
  warmSummarySourceChars,
10767
10963
  warmSummaryTopics,
10964
+ warmChannelSummaries,
10768
10965
  warmSummaryPending,
10769
10966
  compactionPending,
10967
+ manualCompactionPending,
10770
10968
  contextWindowTokens,
10771
10969
  metaApplier,
10772
10970
  loadOlder,
@@ -10774,6 +10972,96 @@ function useThreadData({ threadId, attach }) {
10774
10972
  };
10775
10973
  }
10776
10974
 
10975
+ ;// ./components/chat/useThreadActivity.ts
10976
+ /* __next_internal_client_entry_do_not_use__ useThreadActivity auto */
10977
+
10978
+
10979
+ const BUSY_POLL_MS = 1500;
10980
+ const IDLE_POLL_MS = 5000;
10981
+ // A run's stream ends a moment before the registry marks it finished; a
10982
+ // snapshot inside this window may still report the run that just ended.
10983
+ const SETTLE_GRACE_MS = 2000;
10984
+ /**
10985
+ * Poll what the thread is doing on the server and keep the chat in step:
10986
+ * re-attach to a turn started elsewhere (scheduler, watcher, bridge, another
10987
+ * device), restore compaction flags after a remount, and refresh the thread
10988
+ * metadata once a compaction finishes.
10989
+ */ function useThreadActivity({ threadId, attach, isLive, lastSettledAt, metaApplier }) {
10990
+ const [activity, setActivity] = (0,react.useState)(null);
10991
+ const deps = (0,react.useRef)({
10992
+ attach,
10993
+ isLive,
10994
+ lastSettledAt,
10995
+ metaApplier
10996
+ });
10997
+ deps.current = {
10998
+ attach,
10999
+ isLive,
11000
+ lastSettledAt,
11001
+ metaApplier
11002
+ };
11003
+ (0,react.useEffect)(()=>{
11004
+ setActivity(null);
11005
+ if (!threadId) return;
11006
+ let cancelled = false;
11007
+ let timer = null;
11008
+ let hadCompaction = false;
11009
+ const schedule = (ms)=>{
11010
+ if (!cancelled) timer = window.setTimeout(tick, ms);
11011
+ };
11012
+ async function tick() {
11013
+ if (cancelled || !threadId) return;
11014
+ if (typeof document !== "undefined" && document.hidden) {
11015
+ schedule(IDLE_POLL_MS);
11016
+ return;
11017
+ }
11018
+ let next;
11019
+ try {
11020
+ next = await client/* api */.FH.threads.activity(threadId);
11021
+ } catch {
11022
+ schedule(IDLE_POLL_MS);
11023
+ return;
11024
+ }
11025
+ if (cancelled) return;
11026
+ setActivity(next);
11027
+ const d = deps.current;
11028
+ const serverRunning = next.run !== null || next.queue_depth > 0;
11029
+ const recentlySettled = Date.now() - d.lastSettledAt() < SETTLE_GRACE_MS;
11030
+ if (serverRunning && !d.isLive() && !recentlySettled) {
11031
+ d.attach(threadId).catch(()=>{});
11032
+ }
11033
+ if (next.compaction) {
11034
+ if (next.compaction.kind !== "refresh") d.metaApplier.setCompactionPending?.(true);
11035
+ if (next.compaction.kind === "manual") d.metaApplier.setManualCompactionPending?.(true);
11036
+ hadCompaction = true;
11037
+ } else if (hadCompaction) {
11038
+ hadCompaction = false;
11039
+ // The compaction just finished. Clear the flags from the snapshot
11040
+ // itself so a failed refresh below can't leave the chat locked, then
11041
+ // pull the new boundary and recap.
11042
+ d.metaApplier.setCompactionPending?.(false);
11043
+ d.metaApplier.setManualCompactionPending?.(false);
11044
+ client/* api */.FH.threads.get(threadId, {
11045
+ limit: 1
11046
+ }).then((meta)=>{
11047
+ if (!cancelled) applyThreadMeta(deps.current.metaApplier, meta);
11048
+ }).catch(()=>{});
11049
+ }
11050
+ schedule(next.busy ? BUSY_POLL_MS : IDLE_POLL_MS);
11051
+ }
11052
+ // The thread load attaches to any in-flight run itself; give it a beat
11053
+ // so this poller doesn't race it with a second attach.
11054
+ schedule(BUSY_POLL_MS);
11055
+ return ()=>{
11056
+ cancelled = true;
11057
+ if (timer !== null) window.clearTimeout(timer);
11058
+ };
11059
+ }, [
11060
+ threadId
11061
+ ]);
11062
+ return activity;
11063
+ }
11064
+
10777
11065
  ;// ./components/chat/useUserProfileAndAgent.ts
10778
11066
  /* __next_internal_client_entry_do_not_use__ useUserProfileAndAgent auto */
10779
11067
 
@@ -10981,6 +11269,9 @@ function useChatSubmitHandlers({ agentId, steerRun, attachments, setAttachments,
10981
11269
 
10982
11270
 
10983
11271
 
11272
+
11273
+
11274
+
10984
11275
 
10985
11276
  function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSent }) {
10986
11277
  const { state } = (0,AppContext/* useAppContext */.U)();
@@ -11037,6 +11328,19 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11037
11328
  attachRef.current = sse.attach;
11038
11329
  clearStreamingRef.current = sse.clearStreamingContent;
11039
11330
  clearToolEventsRef.current = sse.clearToolEvents;
11331
+ // `compacting` lives in this component, which remounts per agent; the
11332
+ // server flag keeps a /compact started before an agent switch visible.
11333
+ const sessionCompacting = compacting || thread.manualCompactionPending;
11334
+ const activity = useThreadActivity({
11335
+ threadId,
11336
+ attach: stableAttach,
11337
+ isLive: sse.isLive,
11338
+ lastSettledAt: sse.lastSettledAt,
11339
+ metaApplier: thread.metaApplier
11340
+ });
11341
+ // Run phases come through the attached stream; background compaction
11342
+ // outside a run has no stream, so label it from the polled activity.
11343
+ const backgroundCompaction = !sse.streaming && !sessionCompacting ? activity?.compaction?.kind ?? null : null;
11040
11344
  useChatErrorReporting({
11041
11345
  sessionError,
11042
11346
  streamError: sse.error,
@@ -11046,6 +11350,8 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11046
11350
  });
11047
11351
  const streamingRef = (0,react.useRef)(false);
11048
11352
  streamingRef.current = sse.streaming;
11353
+ const currentThreadIdRef = (0,react.useRef)(threadId);
11354
+ currentThreadIdRef.current = threadId;
11049
11355
  // Auto compaction starts server-side during a run; poll so the banner shows live.
11050
11356
  (0,react.useEffect)(()=>{
11051
11357
  if (!threadId || !sse.streaming) return;
@@ -11076,10 +11382,13 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11076
11382
  });
11077
11383
  useTrackLoading(!!sessionLoading);
11078
11384
  useTrackLoading(sse.streaming);
11079
- useTrackLoading(compacting);
11385
+ useTrackLoading(sessionCompacting);
11080
11386
  useTrackLoading(thread.loadingMore);
11081
11387
  useTrackLoading(thread.messagesLoading);
11082
11388
  useTrackLoading(agentConfigLoading);
11389
+ useActivityWhile(sessionCompacting, "Compacting session…");
11390
+ useActivityWhile(backgroundCompaction === "auto", "Compacting earlier messages…");
11391
+ useActivityWhile(backgroundCompaction === "refresh", "Updating summary…");
11083
11392
  useActivityWhile(thread.messagesLoading, "Loading chat history…");
11084
11393
  useActivityWhile(agentConfigLoading, "Loading agent…");
11085
11394
  useActivityWhile(profileLoading, "Loading profile…");
@@ -11183,19 +11492,35 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11183
11492
  const queue = useChatQueue({
11184
11493
  threadId,
11185
11494
  streaming: sse.streaming,
11186
- compacting,
11495
+ compacting: sessionCompacting,
11187
11496
  launchRun
11188
11497
  });
11189
11498
  queueApiRef.current = queue;
11190
11499
  drainQueueRef.current = queue.drainQueueRef.current;
11191
11500
  async function handleCompact() {
11192
11501
  if (!agentId) return;
11502
+ const notifyCompaction = (result)=>{
11503
+ const toast = compactionOutcomeToast(result);
11504
+ (0,ui_toasts/* pushToast */.Iz)({
11505
+ ...toast,
11506
+ source: "system",
11507
+ sourceLabel: "Chat",
11508
+ agent_id: agentId,
11509
+ thread_id: threadId,
11510
+ ttl: 5000,
11511
+ dedupeKey: `compact:${agentId}`
11512
+ });
11513
+ };
11193
11514
  setCompacting(true);
11194
11515
  try {
11195
11516
  const result = await client/* api */.FH.agents.compact(agentId, {
11196
11517
  resetContext: true
11197
11518
  });
11198
- if (result.compacted) {
11519
+ // The thread may have changed while compaction ran; never apply its
11520
+ // result to a different thread's view.
11521
+ const compactedThreadId = threadId;
11522
+ const stillCurrent = ()=>compactedThreadId !== null && currentThreadIdRef.current === compactedThreadId;
11523
+ if (result.compacted && compactedThreadId !== null && stillCurrent()) {
11199
11524
  // Server moved the hot/warm pin to just after the last existing
11200
11525
  // message and persisted the warm summary. Mirror that in-place so
11201
11526
  // the warm card shows the fresh summary without wiping the visible
@@ -11207,16 +11532,29 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11207
11532
  thread.metaApplier.setWarmSummary(result.warm_summary ?? null);
11208
11533
  thread.metaApplier.setWarmSummaryBefore(result.warm_summary_before ?? null);
11209
11534
  thread.metaApplier.setWarmSummaryBeforeSeq(result.warm_summary_before_seq ?? null);
11210
- thread.metaApplier.setWarmSummaryBeforeSeq(result.warm_summary_before_seq ?? null);
11211
11535
  thread.metaApplier.setWarmSummaryComputedAt(result.warm_summary_computed_at ?? null);
11212
11536
  thread.metaApplier.setWarmSummarySourceMessages(result.warm_summary_source_messages ?? null);
11213
11537
  thread.metaApplier.setWarmSummarySourceChars(result.warm_summary_source_chars ?? null);
11214
11538
  thread.metaApplier.setWarmSummaryTopics?.(parseWarmSummaryTopics(result.warm_summary_topics));
11215
- } else {
11216
- thread.addNotice("Nothing to compact yet — send some messages first.");
11539
+ // The compact response carries only the chat recap; channel recaps
11540
+ // (bridge, watcher, scheduled task) come with the thread metadata.
11541
+ void client/* api */.FH.threads.get(compactedThreadId, {
11542
+ limit: 1
11543
+ }).then((d)=>{
11544
+ if (stillCurrent()) applyThreadMeta(thread.metaApplier, d);
11545
+ }).catch(()=>{});
11217
11546
  }
11547
+ notifyCompaction(result);
11218
11548
  } catch (err) {
11219
- thread.addNotice(`Compaction failed: ${String(err)}`);
11549
+ (0,error_report/* pushErrorToast */.uS)({
11550
+ title: "Compaction failed",
11551
+ error: err,
11552
+ context: {
11553
+ panel: "chat",
11554
+ action: "compact",
11555
+ agent_id: agentId
11556
+ }
11557
+ });
11220
11558
  } finally{
11221
11559
  setCompacting(false);
11222
11560
  queue.drainQueueRef.current();
@@ -11242,7 +11580,6 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11242
11580
  threadId: threadId,
11243
11581
  messages: thread.messages,
11244
11582
  steeredSegments: sse.steeredSegments,
11245
- notices: thread.notices,
11246
11583
  agentConfig: agentConfig,
11247
11584
  userProfile: userProfile,
11248
11585
  // streamingContent stays visible past `streaming=false` so the bubble
@@ -11269,8 +11606,9 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11269
11606
  warmSummarySourceMessages: thread.warmSummarySourceMessages,
11270
11607
  warmSummarySourceChars: thread.warmSummarySourceChars,
11271
11608
  warmSummaryTopics: thread.warmSummaryTopics,
11609
+ warmChannelSummaries: thread.warmChannelSummaries,
11272
11610
  warmSummaryPending: thread.warmSummaryPending,
11273
- compactionPending: thread.compactionPending || compacting,
11611
+ compactionPending: thread.compactionPending || sessionCompacting,
11274
11612
  onSetContextPin: thread.setContextPin,
11275
11613
  streaming: sse.streaming,
11276
11614
  contextWindowTokens: thread.contextWindowTokens,
@@ -11298,7 +11636,7 @@ function ChatView({ threadId, agentId, sessionLoading, sessionError, onMessageSe
11298
11636
  onVoiceTranscript: handleVoiceTranscript,
11299
11637
  disabled: !agentId,
11300
11638
  placeholder: composerPlaceholder({
11301
- compacting,
11639
+ compacting: sessionCompacting,
11302
11640
  sessionLoading: !!sessionLoading,
11303
11641
  streaming: sse.streaming
11304
11642
  })
@@ -11315,6 +11653,8 @@ var plus = __webpack_require__(2125);
11315
11653
  var arrow_up_right = __webpack_require__(9751);
11316
11654
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/star.mjs
11317
11655
  var star = __webpack_require__(95697);
11656
+ // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/power-off.mjs
11657
+ var power_off = __webpack_require__(18402);
11318
11658
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/trash.mjs
11319
11659
  var trash = __webpack_require__(25879);
11320
11660
  ;// ./components/ui/PanelHeader.tsx
@@ -11396,6 +11736,24 @@ function useModels() {
11396
11736
  }, [
11397
11737
  refreshModels
11398
11738
  ]);
11739
+ const setDefault = (0,react.useCallback)(async (name)=>{
11740
+ const m = await client/* api */.FH.models.patch(name, {
11741
+ is_default: true
11742
+ });
11743
+ await refreshModels();
11744
+ return m;
11745
+ }, [
11746
+ refreshModels
11747
+ ]);
11748
+ const setEnabled = (0,react.useCallback)(async (name, enabled)=>{
11749
+ const m = await client/* api */.FH.models.patch(name, {
11750
+ enabled
11751
+ });
11752
+ await refreshModels();
11753
+ return m;
11754
+ }, [
11755
+ refreshModels
11756
+ ]);
11399
11757
  const remove = (0,react.useCallback)(async (name)=>{
11400
11758
  await client/* api */.FH.models.delete(name);
11401
11759
  await refreshModels();
@@ -11433,6 +11791,8 @@ function useModels() {
11433
11791
  refresh,
11434
11792
  create,
11435
11793
  update,
11794
+ setDefault,
11795
+ setEnabled,
11436
11796
  remove,
11437
11797
  assign,
11438
11798
  unassign
@@ -11447,6 +11807,8 @@ function useModels() {
11447
11807
  refresh,
11448
11808
  create,
11449
11809
  update,
11810
+ setDefault,
11811
+ setEnabled,
11450
11812
  remove,
11451
11813
  assign,
11452
11814
  unassign
@@ -11957,7 +12319,7 @@ const PROVIDER_COLORS = {
11957
12319
  "github-copilot": "bg-purple-900/40 text-purple-300 border-purple-700"
11958
12320
  };
11959
12321
  function ModelsPanel() {
11960
- const { models, assignments, loading, create, update, remove, refresh } = useModels();
12322
+ const { models, assignments, loading, create, update, setDefault, setEnabled, remove, refresh } = useModels();
11961
12323
  const { agents, loading: agentsLoading } = useAgents();
11962
12324
  const strategyOverrides = agents.filter((agent)=>agent.usage_strategy != null);
11963
12325
  const [editing, setEditing] = (0,react.useState)(null);
@@ -12005,12 +12367,20 @@ function ModelsPanel() {
12005
12367
  refresh();
12006
12368
  }
12007
12369
  async function handleSetDefault(m) {
12008
- await update(m.name, {
12009
- provider: m.provider,
12010
- model_id: m.model_id,
12011
- params: m.params,
12012
- is_default: true
12013
- });
12370
+ setDeleteError(null);
12371
+ try {
12372
+ await setDefault(m.name);
12373
+ } catch (e) {
12374
+ setDeleteError(`Could not set "${m.name}" as default: ${(0,utils_error/* errorMessage */.g)(e)}`);
12375
+ }
12376
+ }
12377
+ async function handleToggleEnabled(m) {
12378
+ setDeleteError(null);
12379
+ try {
12380
+ await setEnabled(m.name, !m.enabled);
12381
+ } catch (e) {
12382
+ setDeleteError(`Could not ${m.enabled ? "disable" : "enable"} "${m.name}": ${(0,utils_error/* errorMessage */.g)(e)}`);
12383
+ }
12014
12384
  }
12015
12385
  async function handleRemove(name) {
12016
12386
  const affectedAgents = assignments.filter((assignment)=>assignment.model_config_name === name).map((assignment)=>agents.find((agent)=>agent.id === assignment.agent_id)?.name ?? assignment.agent_id);
@@ -12286,7 +12656,7 @@ function ModelsPanel() {
12286
12656
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
12287
12657
  "data-deep-link-id": m.name,
12288
12658
  onClick: ()=>setEditing(m),
12289
- className: "flex items-center gap-3 py-2.5 border-b border-border/60 group cursor-pointer hover:bg-surface-3/30 transition-colors",
12659
+ className: `flex items-center gap-3 py-2.5 border-b border-border/60 group cursor-pointer hover:bg-surface-3/30 transition-colors ${m.enabled ? "" : "opacity-60"}`,
12290
12660
  children: [
12291
12661
  /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
12292
12662
  className: "shrink-0 text-fg-subtle",
@@ -12302,13 +12672,17 @@ function ModelsPanel() {
12302
12672
  className: "flex items-center gap-2 mb-0.5",
12303
12673
  children: [
12304
12674
  /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
12305
- className: "text-sm font-medium text-fg",
12675
+ className: `text-sm font-medium ${m.enabled ? "text-fg" : "text-fg-subtle line-through"}`,
12306
12676
  children: m.name
12307
12677
  }),
12308
12678
  m.is_default && /*#__PURE__*/ (0,jsx_runtime.jsx)(star/* default */.A, {
12309
12679
  size: 11,
12310
12680
  className: "text-yellow-700 dark:text-yellow-400 fill-yellow-400 shrink-0"
12311
12681
  }),
12682
+ !m.enabled && /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
12683
+ className: "text-xs px-1.5 py-0.5 rounded border bg-surface-2 text-fg-muted border-border",
12684
+ children: "disabled"
12685
+ }),
12312
12686
  /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
12313
12687
  className: `text-xs px-1.5 py-0.5 rounded border ${PROVIDER_COLORS[m.provider] ?? "bg-surface-2 text-fg-muted border-border"}`,
12314
12688
  children: m.provider
@@ -12331,10 +12705,10 @@ function ModelsPanel() {
12331
12705
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
12332
12706
  className: "flex gap-1 opacity-40 group-hover:opacity-100 pointer-coarse:opacity-100 transition-opacity shrink-0",
12333
12707
  children: [
12334
- !m.is_default && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
12708
+ !m.is_default && m.enabled && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
12335
12709
  onClick: (e)=>{
12336
12710
  e.stopPropagation();
12337
- handleSetDefault(m);
12711
+ void handleSetDefault(m);
12338
12712
  },
12339
12713
  className: "p-1 text-fg-subtle hover:text-yellow-700 dark:hover:text-yellow-400 transition-colors",
12340
12714
  title: "Set as default",
@@ -12342,6 +12716,21 @@ function ModelsPanel() {
12342
12716
  size: 13
12343
12717
  })
12344
12718
  }),
12719
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
12720
+ onClick: (e)=>{
12721
+ e.stopPropagation();
12722
+ void handleToggleEnabled(m);
12723
+ },
12724
+ className: "p-1 text-fg-subtle hover:text-fg transition-colors",
12725
+ title: m.enabled ? "Disable; hide from model selection" : "Enable; show in model selection",
12726
+ "aria-label": m.enabled ? `Disable ${m.name}` : `Enable ${m.name}`,
12727
+ "aria-pressed": !m.enabled,
12728
+ children: m.enabled ? /*#__PURE__*/ (0,jsx_runtime.jsx)(power/* default */.A, {
12729
+ size: 13
12730
+ }) : /*#__PURE__*/ (0,jsx_runtime.jsx)(power_off/* default */.A, {
12731
+ size: 13
12732
+ })
12733
+ }),
12345
12734
  /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
12346
12735
  onClick: (e)=>{
12347
12736
  e.stopPropagation();
@@ -19679,7 +20068,7 @@ function RouteTable({ bridge_id, module }) {
19679
20068
  client/* api */.FH.models.list().then(setModels).catch(()=>{});
19680
20069
  }, []);
19681
20070
  /** Vision capability of an agent (resolves via its model_config_name, with default fallback). */ function agentVisionState(a) {
19682
- const cfg = resolveAgentModel(a, models);
20071
+ const cfg = (0,effective_model/* resolveAgentModel */.Fu)(a, models);
19683
20072
  if (!cfg) return {
19684
20073
  supported: false,
19685
20074
  classified: false,
@@ -24780,7 +25169,7 @@ function WatcherCard({ watcher, agent, agents, models, onCancel, onRunNow, onCha
24780
25169
  const overdue = !watcher.last_error && new Date(watcher.next_run_at).getTime() < Date.now() - 60000;
24781
25170
  // Pre-flight model availability for the assigned agent; only relevant
24782
25171
  // when the watcher reacts via an agent prompt (not a pure script).
24783
- const modelStatus = watcher.reaction_kind === "agent_prompt" ? agentModelStatus(agent ?? null, models) : null;
25172
+ const modelStatus = watcher.reaction_kind === "agent_prompt" ? (0,effective_model/* agentModelStatus */.xu)(agent ?? null, models) : null;
24784
25173
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
24785
25174
  "data-deep-link-id": watcher.id,
24786
25175
  className: "mb-2 rounded-lg border border-border bg-surface-2 overflow-hidden",
@@ -25512,7 +25901,7 @@ function TaskCard({ task, agent, agents, models, onCancel, onRunNow, onChanged }
25512
25901
  collapseSeconds: true
25513
25902
  });
25514
25903
  const overdue = !task.last_error && new Date(task.next_run_at).getTime() < Date.now() - 60000;
25515
- const modelStatus = task.reaction_kind === "agent_prompt" ? agentModelStatus(agent ?? null, models) : null;
25904
+ const modelStatus = task.reaction_kind === "agent_prompt" ? (0,effective_model/* agentModelStatus */.xu)(agent ?? null, models) : null;
25516
25905
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
25517
25906
  "data-deep-link-id": task.id,
25518
25907
  className: "mb-2 rounded-lg border border-border bg-surface-2 overflow-hidden group",
@@ -29981,6 +30370,22 @@ function BootScreen({ agents, agentsLoaded, activeAgentId, onPickAgent, suppress
29981
30370
  setAdoptionBusy(null);
29982
30371
  }
29983
30372
  }
30373
+ async function handleAdoptionItemRetry(itemId) {
30374
+ if (adoptionBusy || adoption?.status === "running") return;
30375
+ setAdoptionBusy("retry");
30376
+ try {
30377
+ const next = await client/* api */.FH.lifecycle.adoption.retryItem(itemId);
30378
+ setAdoption(next);
30379
+ adoptionRunStartedRef.current = null;
30380
+ } catch {
30381
+ setAdoption((prev)=>prev ? {
30382
+ ...prev,
30383
+ error: "Could not retry that step."
30384
+ } : prev);
30385
+ } finally{
30386
+ setAdoptionBusy(null);
30387
+ }
30388
+ }
29984
30389
  // The agent rendered in the centered tile. During `loading` and
29985
30390
  // `pick` it's the default (so the user sees the same artwork as soon
29986
30391
  // as agents resolve). During `opening` it's whatever was picked.
@@ -30123,6 +30528,9 @@ function BootScreen({ agents, agentsLoaded, activeAgentId, onPickAgent, suppress
30123
30528
  summary: adoptionLiveLabel ?? adoption.summary,
30124
30529
  items: adoption.checklist,
30125
30530
  error: adoption.error,
30531
+ onRetryItem: (item)=>void handleAdoptionItemRetry(item.id),
30532
+ canRetryItem: (item)=>item.id !== "fetch-changes",
30533
+ retryDisabled: adoptionBusy !== null || adoption.status === "running",
30126
30534
  children: [
30127
30535
  adoption.status === "done" && /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
30128
30536
  className: "mt-2 rounded-lg border border-border/50 bg-surface px-2 py-1 text-[10px] leading-snug text-fg-muted",
@@ -33483,9 +33891,9 @@ function AppShell() {
33483
33891
  },
33484
33892
  /******/ __webpack_require__ => { // webpackRuntimeModules
33485
33893
  /******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
33486
- /******/ __webpack_require__.O(0, [1973,8463,8095,4576,1395,8441,5254,7358], () => (__webpack_exec__(39852)));
33894
+ /******/ __webpack_require__.O(0, [1973,8463,8095,7045,1395,8441,5254,7358], () => (__webpack_exec__(39852)));
33487
33895
  /******/ var __webpack_exports__ = __webpack_require__.O();
33488
33896
  /******/ _N_E = __webpack_exports__;
33489
33897
  /******/ }
33490
33898
  ]);
33491
- //# sourceMappingURL=page-c6e972a7fd13dae8.js.map
33899
+ //# sourceMappingURL=page-213a623b37226452.js.map