@agent-native/core 0.113.0 → 0.114.1

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 (1638) hide show
  1. package/agent-native.eject.json +164 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +20 -0
  4. package/corpus/core/README.md +61 -174
  5. package/corpus/core/agent-native.eject.json +164 -0
  6. package/corpus/core/docs/content/agent-native-toolkit.mdx +38 -0
  7. package/corpus/core/docs/content/package-lifecycle.mdx +54 -4
  8. package/corpus/core/package.json +15 -2
  9. package/corpus/core/src/cli/eject.ts +1594 -0
  10. package/corpus/core/src/cli/index.ts +16 -0
  11. package/corpus/core/src/client/build-compatibility.ts +77 -0
  12. package/corpus/core/src/client/index.ts +4 -0
  13. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +8 -2
  14. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +7 -2
  15. package/corpus/core/src/client/resources/ResourcesPanel.tsx +17 -3
  16. package/corpus/core/src/client/resources/index.ts +19 -0
  17. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +9 -1
  18. package/corpus/core/src/client/resources/runtime.ts +1 -0
  19. package/corpus/core/src/client/route-chunk-recovery/index.ts +1 -0
  20. package/corpus/core/src/client/setup-connections/catalog.ts +6 -0
  21. package/corpus/core/src/client/setup-connections/index.ts +1 -0
  22. package/corpus/core/src/client/setup-connections/runtime.ts +1 -0
  23. package/corpus/core/src/client/use-action.ts +32 -1
  24. package/corpus/core/src/connections/catalog.ts +41 -24
  25. package/corpus/core/src/connections/index.ts +1 -0
  26. package/corpus/core/src/connections/runtime.ts +1 -0
  27. package/corpus/core/src/deploy/build.ts +4 -1
  28. package/corpus/core/src/eject/provider-api-definitions.ts +193 -0
  29. package/corpus/core/src/eject/remote-mcp-presets.ts +137 -0
  30. package/corpus/core/src/eject/setup-readiness-ui.tsx +29 -0
  31. package/corpus/core/src/eject/workspace-connections.ts +92 -0
  32. package/corpus/core/src/index.ts +1 -0
  33. package/corpus/core/src/integrations/adapter-overrides.ts +12 -0
  34. package/corpus/core/src/integrations/eject/messaging-adapters.ts +85 -0
  35. package/corpus/core/src/integrations/index.ts +5 -1
  36. package/corpus/core/src/integrations/plugin.ts +34 -12
  37. package/corpus/core/src/integrations/runtime.ts +1 -0
  38. package/corpus/core/src/integrations/types.ts +3 -1
  39. package/corpus/core/src/org/context.ts +56 -30
  40. package/corpus/core/src/package-lifecycle/eject-manifest.ts +345 -0
  41. package/corpus/core/src/package-lifecycle/index.ts +1 -0
  42. package/corpus/core/src/provider-api/index.ts +46 -12
  43. package/corpus/core/src/provider-api/runtime.ts +1 -0
  44. package/corpus/core/src/server/action-routes.ts +52 -2
  45. package/corpus/core/src/server/auth-plugin.ts +9 -4
  46. package/corpus/core/src/server/better-auth-instance.ts +5 -1
  47. package/corpus/core/src/setup-connections/index.ts +1 -0
  48. package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
  49. package/corpus/core/src/shared/merge-by-id.ts +14 -0
  50. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +15 -13
  51. package/corpus/core/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  52. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +9 -6
  53. package/corpus/core/src/templates/default/AGENTS.md +6 -5
  54. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +15 -13
  55. package/corpus/core/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  56. package/corpus/core/src/templates/headless/AGENTS.md +5 -4
  57. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +15 -13
  58. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +3 -2
  59. package/corpus/core/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  60. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +9 -6
  61. package/corpus/core/src/templates/workspace-core/AGENTS.md +4 -4
  62. package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -4
  63. package/corpus/core/src/vite/client.ts +42 -2
  64. package/corpus/templates/analytics/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  65. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +9 -6
  66. package/corpus/templates/assets/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  67. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +9 -6
  68. package/corpus/templates/brain/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  69. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +9 -6
  70. package/corpus/templates/brain/actions/remediate-legacy-capture-audiences.ts +167 -0
  71. package/corpus/templates/brain/app/lib/brain-chat-readiness.ts +6 -0
  72. package/corpus/templates/brain/app/routes/_index.tsx +8 -0
  73. package/corpus/templates/brain/app/routes.ts +1 -0
  74. package/corpus/templates/brain/changelog/2026-07-19-ask-starts-immediately-when-builder-s-managed-ai-connection-.md +6 -0
  75. package/corpus/templates/brain/changelog/2026-07-19-slack-and-granola-backfills-now-process-captures-concurrentl.md +6 -0
  76. package/corpus/templates/brain/changelog/2026-07-19-source-review-settings-now-control-knowledge-approval.md +6 -0
  77. package/corpus/templates/brain/changelog/2026-07-19-the-manage-agent-page-now-opens-correctly-from-brain-navigat.md +6 -0
  78. package/corpus/templates/brain/server/db/schema.ts +3 -0
  79. package/corpus/templates/brain/server/lib/brain.ts +41 -2
  80. package/corpus/templates/brain/server/lib/connectors.ts +379 -113
  81. package/corpus/templates/brain/server/lib/meeting-audience.ts +38 -0
  82. package/corpus/templates/brain/server/plugins/db.ts +10 -0
  83. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +6 -4
  84. package/corpus/templates/calendar/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  85. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +9 -6
  86. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +15 -13
  87. package/corpus/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  88. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +9 -6
  89. package/corpus/templates/chat/AGENTS.md +3 -2
  90. package/corpus/templates/clips/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  91. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +9 -6
  92. package/corpus/templates/content/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  93. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +9 -6
  94. package/corpus/templates/content/AGENTS.md +2 -0
  95. package/corpus/templates/content/actions/_content-database-personal-view.ts +49 -5
  96. package/corpus/templates/content/actions/_content-document-access.ts +21 -0
  97. package/corpus/templates/content/actions/_content-favorites.ts +91 -0
  98. package/corpus/templates/content/actions/_content-files.ts +79 -23
  99. package/corpus/templates/content/actions/_content-sidebar-state.ts +24 -0
  100. package/corpus/templates/content/actions/_content-space-access.ts +15 -17
  101. package/corpus/templates/content/actions/_content-space-catalog-guards.ts +20 -0
  102. package/corpus/templates/content/actions/_content-spaces.ts +364 -167
  103. package/corpus/templates/content/actions/_database-source-utils.ts +8 -0
  104. package/corpus/templates/content/actions/_database-utils.ts +249 -15
  105. package/corpus/templates/content/actions/_delete-content-space.ts +84 -0
  106. package/corpus/templates/content/actions/_files-system-properties.ts +499 -0
  107. package/corpus/templates/content/actions/_local-file-documents.ts +0 -1
  108. package/corpus/templates/content/actions/_property-utils.ts +18 -9
  109. package/corpus/templates/content/actions/bind-content-database-source-field.ts +3 -0
  110. package/corpus/templates/content/actions/configure-document-property.ts +3 -0
  111. package/corpus/templates/content/actions/create-content-database.ts +2 -2
  112. package/corpus/templates/content/actions/create-content-space.ts +34 -0
  113. package/corpus/templates/content/actions/create-document.ts +4 -1
  114. package/corpus/templates/content/actions/delete-content-space.ts +19 -0
  115. package/corpus/templates/content/actions/delete-database-items.ts +28 -1
  116. package/corpus/templates/content/actions/delete-document-property.ts +3 -0
  117. package/corpus/templates/content/actions/delete-document.ts +39 -2
  118. package/corpus/templates/content/actions/duplicate-database-item.ts +6 -0
  119. package/corpus/templates/content/actions/duplicate-database-items.ts +6 -0
  120. package/corpus/templates/content/actions/duplicate-document-property.ts +3 -0
  121. package/corpus/templates/content/actions/get-content-database.ts +11 -2
  122. package/corpus/templates/content/actions/get-content-sidebar-state.ts +23 -0
  123. package/corpus/templates/content/actions/get-document.ts +32 -7
  124. package/corpus/templates/content/actions/import-content-source.ts +33 -1
  125. package/corpus/templates/content/actions/list-content-spaces.ts +34 -2
  126. package/corpus/templates/content/actions/list-documents.ts +39 -7
  127. package/corpus/templates/content/actions/reorder-document-property.ts +9 -0
  128. package/corpus/templates/content/actions/set-document-property.ts +41 -23
  129. package/corpus/templates/content/actions/share-local-file-document.ts +15 -0
  130. package/corpus/templates/content/actions/submit-content-database-form.ts +7 -0
  131. package/corpus/templates/content/actions/sync-local-folder-source.ts +14 -0
  132. package/corpus/templates/content/actions/update-content-database-view.ts +1 -0
  133. package/corpus/templates/content/actions/update-content-sidebar-state.ts +27 -0
  134. package/corpus/templates/content/actions/update-document.ts +158 -66
  135. package/corpus/templates/content/app/components/EmptyState.tsx +4 -57
  136. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +8 -1
  137. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +519 -178
  138. package/corpus/templates/content/app/components/editor/DocumentInfoPanel.tsx +39 -0
  139. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
  140. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +266 -7
  141. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +430 -152
  142. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +467 -66
  143. package/corpus/templates/content/app/components/editor/database/view-config.ts +9 -3
  144. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +720 -196
  145. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +173 -1
  146. package/corpus/templates/content/app/components/sidebar/document-sidebar-sections.ts +1 -1
  147. package/corpus/templates/content/app/components/sidebar/select-content-space.ts +91 -16
  148. package/corpus/templates/content/app/entry.client.tsx +5 -1
  149. package/corpus/templates/content/app/hooks/use-content-database.ts +84 -3
  150. package/corpus/templates/content/app/hooks/use-content-spaces.ts +60 -2
  151. package/corpus/templates/content/app/hooks/use-create-page.ts +30 -0
  152. package/corpus/templates/content/app/hooks/use-documents.ts +270 -19
  153. package/corpus/templates/content/app/i18n-data.ts +243 -20
  154. package/corpus/templates/content/app/lib/local-folder-picker-safety.ts +54 -0
  155. package/corpus/templates/content/app/lib/local-folder-picker-support.ts +18 -0
  156. package/corpus/templates/content/app/routes/_app.favorites.tsx +30 -0
  157. package/corpus/templates/content/app/routes/_app.local-files.tsx +18 -6
  158. package/corpus/templates/content/changelog/2026-07-17-workspace-files-now-stay-in-a-loading-state-until-automatic-.md +6 -0
  159. package/corpus/templates/content/changelog/2026-07-17-workspace-switching-now-opens-the-selected-files-database-pr.md +6 -0
  160. package/corpus/templates/content/changelog/2026-07-17-workspaces-now-expand-above-their-own-files-list-without-dup.md +6 -0
  161. package/corpus/templates/content/changelog/2026-07-18-create-named-workspaces-each-with-its-own-private-files-data.md +6 -0
  162. package/corpus/templates/content/changelog/2026-07-18-favorites-align-with-workspace-and-file-rows-in-the-sidebar.md +6 -0
  163. package/corpus/templates/content/changelog/2026-07-18-local-folder-selection-no-longer-invokes-the-unsafe-native-p.md +6 -0
  164. package/corpus/templates/content/changelog/2026-07-18-made-content-workspaces-independently-expandable-restored-or.md +6 -0
  165. package/corpus/templates/content/changelog/2026-07-18-page-details-now-live-in-a-shared-info-and-comments-rail-dat.md +6 -0
  166. package/corpus/templates/content/changelog/2026-07-18-workspace-database-views-now-control-sidebar-workspace-navig.md +6 -0
  167. package/corpus/templates/content/changelog/2026-07-18-workspace-navigation-now-aligns-favorites-with-workspace-pag.md +6 -0
  168. package/corpus/templates/content/changelog/2026-07-19-favorites-now-open-as-a-table-and-compact-breadcrumbs-make-w.md +6 -0
  169. package/corpus/templates/content/changelog/2026-07-19-files-databases-now-start-unfiltered-sidebar-rows-exactly-fo.md +6 -0
  170. package/corpus/templates/content/changelog/2026-07-19-sidebar-page-trees-now-open-only-when-expanded-remember-thei.md +6 -0
  171. package/corpus/templates/content/changelog/2026-07-19-workspace-file-databases-now-use-the-workspace-name-open-as-.md +6 -0
  172. package/corpus/templates/content/changelog/2026-07-19-workspace-navigation-now-stays-stable-on-hover-uses-folder-i.md +6 -0
  173. package/corpus/templates/content/changelog/2026-07-19-workspace-rows-now-use-folder-icons-and-deleting-a-user-crea.md +6 -0
  174. package/corpus/templates/content/changelog/2026-07-19-workspaces-can-be-created-without-leaving-the-workspaces-dat.md +6 -0
  175. package/corpus/templates/content/e2e/global-setup.ts +3 -2
  176. package/corpus/templates/content/parity/matrix.md +28 -28
  177. package/corpus/templates/content/parity/matrix.ts +8 -2
  178. package/corpus/templates/content/server/db/index.ts +1 -0
  179. package/corpus/templates/content/server/db/schema.ts +10 -0
  180. package/corpus/templates/content/server/lib/documents.ts +12 -7
  181. package/corpus/templates/content/server/plugins/db.ts +17 -0
  182. package/corpus/templates/content/shared/api.ts +9 -0
  183. package/corpus/templates/content/shared/database-form.ts +11 -2
  184. package/corpus/templates/content/vite.config.ts +1 -0
  185. package/corpus/templates/design/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  186. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +9 -6
  187. package/corpus/templates/dispatch/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  188. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +9 -6
  189. package/corpus/templates/forms/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  190. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +9 -6
  191. package/corpus/templates/macros/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  192. package/corpus/templates/mail/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  193. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +9 -6
  194. package/corpus/templates/plan/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  195. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +9 -6
  196. package/corpus/templates/slides/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  197. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +9 -6
  198. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +15 -13
  199. package/corpus/templates/tasks/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  200. package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +9 -6
  201. package/corpus/toolkit/CHANGELOG.md +6 -0
  202. package/corpus/toolkit/agent-native.eject.json +411 -0
  203. package/corpus/toolkit/package.json +5 -2
  204. package/dist/cli/eject.d.ts +21 -0
  205. package/dist/cli/eject.d.ts.map +1 -0
  206. package/dist/cli/eject.js +1145 -0
  207. package/dist/cli/eject.js.map +1 -0
  208. package/dist/cli/index.js +15 -0
  209. package/dist/cli/index.js.map +1 -1
  210. package/dist/client/build-compatibility.d.ts +11 -0
  211. package/dist/client/build-compatibility.d.ts.map +1 -0
  212. package/dist/client/build-compatibility.js +56 -0
  213. package/dist/client/build-compatibility.js.map +1 -0
  214. package/dist/client/index.d.ts +1 -1
  215. package/dist/client/index.d.ts.map +1 -1
  216. package/dist/client/index.js +1 -1
  217. package/dist/client/index.js.map +1 -1
  218. package/dist/client/resources/McpConnectionSuggestion.d.ts +4 -3
  219. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  220. package/dist/client/resources/McpConnectionSuggestion.js +3 -3
  221. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  222. package/dist/client/resources/McpIntegrationDialog.d.ts +4 -3
  223. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  224. package/dist/client/resources/McpIntegrationDialog.js +2 -2
  225. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  226. package/dist/client/resources/ResourcesPanel.d.ts +4 -1
  227. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  228. package/dist/client/resources/ResourcesPanel.js +9 -7
  229. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  230. package/dist/client/resources/index.d.ts +3 -0
  231. package/dist/client/resources/index.d.ts.map +1 -1
  232. package/dist/client/resources/index.js +3 -0
  233. package/dist/client/resources/index.js.map +1 -1
  234. package/dist/client/resources/mcp-integration-catalog.d.ts +2 -1
  235. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  236. package/dist/client/resources/mcp-integration-catalog.js +6 -2
  237. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  238. package/dist/client/resources/runtime.d.ts +2 -0
  239. package/dist/client/resources/runtime.d.ts.map +1 -0
  240. package/dist/client/resources/runtime.js +2 -0
  241. package/dist/client/resources/runtime.js.map +1 -0
  242. package/dist/client/route-chunk-recovery/index.d.ts +1 -0
  243. package/dist/client/route-chunk-recovery/index.d.ts.map +1 -1
  244. package/dist/client/route-chunk-recovery/index.js +1 -0
  245. package/dist/client/route-chunk-recovery/index.js.map +1 -1
  246. package/dist/client/setup-connections/catalog.d.ts +2 -0
  247. package/dist/client/setup-connections/catalog.d.ts.map +1 -0
  248. package/dist/client/setup-connections/catalog.js +7 -0
  249. package/dist/client/setup-connections/catalog.js.map +1 -0
  250. package/dist/client/setup-connections/index.d.ts +1 -0
  251. package/dist/client/setup-connections/index.d.ts.map +1 -1
  252. package/dist/client/setup-connections/index.js +1 -0
  253. package/dist/client/setup-connections/index.js.map +1 -1
  254. package/dist/client/setup-connections/runtime.d.ts +2 -0
  255. package/dist/client/setup-connections/runtime.d.ts.map +1 -0
  256. package/dist/client/setup-connections/runtime.js +2 -0
  257. package/dist/client/setup-connections/runtime.js.map +1 -0
  258. package/dist/client/use-action.d.ts.map +1 -1
  259. package/dist/client/use-action.js +19 -1
  260. package/dist/client/use-action.js.map +1 -1
  261. package/dist/collab/awareness.d.ts +2 -2
  262. package/dist/collab/awareness.d.ts.map +1 -1
  263. package/dist/collab/struct-routes.d.ts +1 -1
  264. package/dist/connections/catalog.d.ts +5 -3
  265. package/dist/connections/catalog.d.ts.map +1 -1
  266. package/dist/connections/catalog.js +16 -8
  267. package/dist/connections/catalog.js.map +1 -1
  268. package/dist/connections/index.d.ts +1 -1
  269. package/dist/connections/index.d.ts.map +1 -1
  270. package/dist/connections/index.js +1 -1
  271. package/dist/connections/index.js.map +1 -1
  272. package/dist/connections/runtime.d.ts +2 -0
  273. package/dist/connections/runtime.d.ts.map +1 -0
  274. package/dist/connections/runtime.js +2 -0
  275. package/dist/connections/runtime.js.map +1 -0
  276. package/dist/deploy/build.js +2 -1
  277. package/dist/deploy/build.js.map +1 -1
  278. package/dist/eject/provider-api-definitions.d.ts +34 -0
  279. package/dist/eject/provider-api-definitions.d.ts.map +1 -0
  280. package/dist/eject/provider-api-definitions.js +88 -0
  281. package/dist/eject/provider-api-definitions.js.map +1 -0
  282. package/dist/eject/remote-mcp-presets.d.ts +17 -0
  283. package/dist/eject/remote-mcp-presets.d.ts.map +1 -0
  284. package/dist/eject/remote-mcp-presets.js +81 -0
  285. package/dist/eject/remote-mcp-presets.js.map +1 -0
  286. package/dist/eject/setup-readiness-ui.d.ts +7 -0
  287. package/dist/eject/setup-readiness-ui.d.ts.map +1 -0
  288. package/dist/eject/setup-readiness-ui.js +13 -0
  289. package/dist/eject/setup-readiness-ui.js.map +1 -0
  290. package/dist/eject/workspace-connections.d.ts +11 -0
  291. package/dist/eject/workspace-connections.d.ts.map +1 -0
  292. package/dist/eject/workspace-connections.js +47 -0
  293. package/dist/eject/workspace-connections.js.map +1 -0
  294. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  295. package/dist/index.d.ts +1 -1
  296. package/dist/index.d.ts.map +1 -1
  297. package/dist/index.js +1 -1
  298. package/dist/index.js.map +1 -1
  299. package/dist/integrations/adapter-overrides.d.ts +3 -0
  300. package/dist/integrations/adapter-overrides.d.ts.map +1 -0
  301. package/dist/integrations/adapter-overrides.js +7 -0
  302. package/dist/integrations/adapter-overrides.js.map +1 -0
  303. package/dist/integrations/eject/messaging-adapters.d.ts +12 -0
  304. package/dist/integrations/eject/messaging-adapters.d.ts.map +1 -0
  305. package/dist/integrations/eject/messaging-adapters.js +49 -0
  306. package/dist/integrations/eject/messaging-adapters.js.map +1 -0
  307. package/dist/integrations/index.d.ts +3 -2
  308. package/dist/integrations/index.d.ts.map +1 -1
  309. package/dist/integrations/index.js +2 -1
  310. package/dist/integrations/index.js.map +1 -1
  311. package/dist/integrations/plugin.d.ts +32 -1
  312. package/dist/integrations/plugin.d.ts.map +1 -1
  313. package/dist/integrations/plugin.js +19 -12
  314. package/dist/integrations/plugin.js.map +1 -1
  315. package/dist/integrations/runtime.d.ts +2 -0
  316. package/dist/integrations/runtime.d.ts.map +1 -0
  317. package/dist/integrations/runtime.js +2 -0
  318. package/dist/integrations/runtime.js.map +1 -0
  319. package/dist/integrations/types.d.ts +3 -1
  320. package/dist/integrations/types.d.ts.map +1 -1
  321. package/dist/integrations/types.js.map +1 -1
  322. package/dist/notifications/routes.d.ts +2 -2
  323. package/dist/observability/routes.d.ts +5 -5
  324. package/dist/org/context.d.ts +4 -2
  325. package/dist/org/context.d.ts.map +1 -1
  326. package/dist/org/context.js +44 -22
  327. package/dist/org/context.js.map +1 -1
  328. package/dist/package-lifecycle/eject-manifest.d.ts +43 -0
  329. package/dist/package-lifecycle/eject-manifest.d.ts.map +1 -0
  330. package/dist/package-lifecycle/eject-manifest.js +219 -0
  331. package/dist/package-lifecycle/eject-manifest.js.map +1 -0
  332. package/dist/package-lifecycle/index.d.ts +1 -0
  333. package/dist/package-lifecycle/index.d.ts.map +1 -1
  334. package/dist/package-lifecycle/index.js +1 -0
  335. package/dist/package-lifecycle/index.js.map +1 -1
  336. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  337. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  338. package/dist/provider-api/index.d.ts +6 -2
  339. package/dist/provider-api/index.d.ts.map +1 -1
  340. package/dist/provider-api/index.js +25 -12
  341. package/dist/provider-api/index.js.map +1 -1
  342. package/dist/provider-api/runtime.d.ts +2 -0
  343. package/dist/provider-api/runtime.d.ts.map +1 -0
  344. package/dist/provider-api/runtime.js +2 -0
  345. package/dist/provider-api/runtime.js.map +1 -0
  346. package/dist/resources/handlers.d.ts +1 -1
  347. package/dist/server/action-routes.d.ts.map +1 -1
  348. package/dist/server/action-routes.js +32 -2
  349. package/dist/server/action-routes.js.map +1 -1
  350. package/dist/server/auth-plugin.d.ts.map +1 -1
  351. package/dist/server/auth-plugin.js +9 -5
  352. package/dist/server/auth-plugin.js.map +1 -1
  353. package/dist/server/better-auth-instance.d.ts.map +1 -1
  354. package/dist/server/better-auth-instance.js +4 -1
  355. package/dist/server/better-auth-instance.js.map +1 -1
  356. package/dist/setup-connections/index.d.ts +1 -1
  357. package/dist/setup-connections/index.d.ts.map +1 -1
  358. package/dist/setup-connections/index.js +1 -1
  359. package/dist/setup-connections/index.js.map +1 -1
  360. package/dist/shared/mcp-embed-headers.d.ts +1 -1
  361. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  362. package/dist/shared/mcp-embed-headers.js +1 -1
  363. package/dist/shared/mcp-embed-headers.js.map +1 -1
  364. package/dist/shared/merge-by-id.d.ts +5 -0
  365. package/dist/shared/merge-by-id.d.ts.map +1 -0
  366. package/dist/shared/merge-by-id.js +7 -0
  367. package/dist/shared/merge-by-id.js.map +1 -0
  368. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +15 -13
  369. package/dist/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  370. package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +9 -6
  371. package/dist/templates/chat/AGENTS.md +3 -2
  372. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +15 -13
  373. package/dist/templates/default/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  374. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +9 -6
  375. package/dist/templates/default/AGENTS.md +6 -5
  376. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +15 -13
  377. package/dist/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  378. package/dist/templates/headless/AGENTS.md +5 -4
  379. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +15 -13
  380. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +3 -2
  381. package/dist/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  382. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +9 -6
  383. package/dist/templates/workspace-core/AGENTS.md +4 -4
  384. package/dist/templates/workspace-root/AGENTS.md +4 -4
  385. package/dist/vite/client.d.ts +6 -0
  386. package/dist/vite/client.d.ts.map +1 -1
  387. package/dist/vite/client.js +30 -2
  388. package/dist/vite/client.js.map +1 -1
  389. package/docs/content/agent-native-toolkit.mdx +38 -0
  390. package/docs/content/package-lifecycle.mdx +54 -4
  391. package/package.json +15 -2
  392. package/src/a2a/agent-card.ts +83 -0
  393. package/src/a2a/artifact-response.ts +1648 -0
  394. package/src/a2a/auth-policy.ts +66 -0
  395. package/src/a2a/caller-auth.ts +102 -0
  396. package/src/a2a/client.ts +876 -0
  397. package/src/a2a/correlation.ts +50 -0
  398. package/src/a2a/handlers.ts +1285 -0
  399. package/src/a2a/index.ts +50 -0
  400. package/src/a2a/invoke.ts +348 -0
  401. package/src/a2a/response-text.ts +53 -0
  402. package/src/a2a/server.ts +586 -0
  403. package/src/a2a/task-store.ts +917 -0
  404. package/src/a2a/types.ts +221 -0
  405. package/src/a2a-claims.ts +52 -0
  406. package/src/action-change-marker.ts +74 -0
  407. package/src/action-ui.ts +38 -0
  408. package/src/action.ts +1406 -0
  409. package/src/adapters/cli/index.ts +6 -0
  410. package/src/adapters/cli/registry.ts +73 -0
  411. package/src/adapters/cli/shell-adapter.ts +92 -0
  412. package/src/adapters/cli/types.ts +27 -0
  413. package/src/agent/action-continuation-guidance.ts +38 -0
  414. package/src/agent/app-model-defaults.ts +201 -0
  415. package/src/agent/context-xray/actions/context-evict.ts +56 -0
  416. package/src/agent/context-xray/actions/context-manifest-get.ts +75 -0
  417. package/src/agent/context-xray/actions/context-pin.ts +56 -0
  418. package/src/agent/context-xray/actions/context-preview-get.ts +134 -0
  419. package/src/agent/context-xray/actions/context-report.ts +75 -0
  420. package/src/agent/context-xray/actions/context-restore.ts +51 -0
  421. package/src/agent/context-xray/actions/errors.ts +40 -0
  422. package/src/agent/context-xray/apply-directives.ts +137 -0
  423. package/src/agent/context-xray/directives-store.ts +178 -0
  424. package/src/agent/context-xray/identity.ts +37 -0
  425. package/src/agent/context-xray/manifest.ts +284 -0
  426. package/src/agent/context-xray/migrations.ts +32 -0
  427. package/src/agent/context-xray/plugin.ts +23 -0
  428. package/src/agent/context-xray/schema.ts +17 -0
  429. package/src/agent/context-xray/segments.ts +194 -0
  430. package/src/agent/context-xray/tokenize.ts +93 -0
  431. package/src/agent/default-model.ts +5 -0
  432. package/src/agent/durable-background.ts +547 -0
  433. package/src/agent/engine/ai-sdk-engine.ts +565 -0
  434. package/src/agent/engine/anthropic-engine.ts +320 -0
  435. package/src/agent/engine/builder-engine.ts +1110 -0
  436. package/src/agent/engine/builder-gateway-headers.ts +44 -0
  437. package/src/agent/engine/builtin.ts +122 -0
  438. package/src/agent/engine/context-directives-transform.ts +73 -0
  439. package/src/agent/engine/continuation-dispatch-retry.ts +168 -0
  440. package/src/agent/engine/credential-errors.ts +69 -0
  441. package/src/agent/engine/index.ts +54 -0
  442. package/src/agent/engine/openai-compatible-endpoint.ts +25 -0
  443. package/src/agent/engine/output-tokens.ts +181 -0
  444. package/src/agent/engine/provider-env-vars.ts +69 -0
  445. package/src/agent/engine/registry.ts +853 -0
  446. package/src/agent/engine/tool-call-journal-seed.ts +85 -0
  447. package/src/agent/engine/translate-ai-sdk.ts +407 -0
  448. package/src/agent/engine/translate-anthropic.ts +611 -0
  449. package/src/agent/engine/types.ts +310 -0
  450. package/src/agent/harness/acp-adapter.ts +893 -0
  451. package/src/agent/harness/acp-builtin.ts +70 -0
  452. package/src/agent/harness/ai-sdk-adapter.ts +509 -0
  453. package/src/agent/harness/background.ts +365 -0
  454. package/src/agent/harness/builtin.ts +50 -0
  455. package/src/agent/harness/index.ts +86 -0
  456. package/src/agent/harness/lifecycle.ts +498 -0
  457. package/src/agent/harness/registry.ts +97 -0
  458. package/src/agent/harness/runner.ts +182 -0
  459. package/src/agent/harness/store.ts +466 -0
  460. package/src/agent/harness/translate.ts +130 -0
  461. package/src/agent/harness/types.ts +129 -0
  462. package/src/agent/index.ts +32 -0
  463. package/src/agent/loop-settings.ts +186 -0
  464. package/src/agent/model-config.ts +363 -0
  465. package/src/agent/observational-memory/compactor.ts +78 -0
  466. package/src/agent/observational-memory/config.ts +78 -0
  467. package/src/agent/observational-memory/index.ts +79 -0
  468. package/src/agent/observational-memory/internal-run.ts +89 -0
  469. package/src/agent/observational-memory/message-text.ts +49 -0
  470. package/src/agent/observational-memory/migrations.ts +44 -0
  471. package/src/agent/observational-memory/observer.ts +128 -0
  472. package/src/agent/observational-memory/plugin.ts +35 -0
  473. package/src/agent/observational-memory/prompts.ts +53 -0
  474. package/src/agent/observational-memory/read.ts +131 -0
  475. package/src/agent/observational-memory/reflector.ts +119 -0
  476. package/src/agent/observational-memory/schema.ts +48 -0
  477. package/src/agent/observational-memory/store.ts +275 -0
  478. package/src/agent/observational-memory/types.ts +65 -0
  479. package/src/agent/processors.ts +209 -0
  480. package/src/agent/production-agent.ts +8254 -0
  481. package/src/agent/run-loop-with-resume.ts +394 -0
  482. package/src/agent/run-manager.ts +1825 -0
  483. package/src/agent/run-ownership.ts +75 -0
  484. package/src/agent/run-store.ts +2601 -0
  485. package/src/agent/runtime-context.ts +169 -0
  486. package/src/agent/thread-data-builder.ts +1584 -0
  487. package/src/agent/tool-call-journal.ts +368 -0
  488. package/src/agent/tool-error-redaction.ts +52 -0
  489. package/src/agent/tool-result-images.ts +178 -0
  490. package/src/agent/tool-search.ts +376 -0
  491. package/src/agent/types.ts +372 -0
  492. package/src/agent-native/index.ts +198 -0
  493. package/src/agent-web/config.ts +253 -0
  494. package/src/agent-web/generator.ts +382 -0
  495. package/src/agent-web/index.ts +36 -0
  496. package/src/appearance/actions/change-appearance.ts +35 -0
  497. package/src/application-state/emitter.ts +81 -0
  498. package/src/application-state/handlers.ts +121 -0
  499. package/src/application-state/index.ts +44 -0
  500. package/src/application-state/script-helpers.ts +155 -0
  501. package/src/application-state/store.ts +274 -0
  502. package/src/assets/branding/agent-native.icon/Assets/background.svg +3 -0
  503. package/src/assets/branding/agent-native.icon/Assets/foreground.svg +12 -0
  504. package/src/assets/branding/agent-native.icon/icon.json +49 -0
  505. package/src/assets/branding/favicon.png +0 -0
  506. package/src/assets/branding/favicon.svg +1 -0
  507. package/src/assets/branding/icon-on-dark.svg +10 -0
  508. package/src/assets/branding/icon-on-light.svg +10 -0
  509. package/src/assets/branding/mac-app-icon.svg +1 -0
  510. package/src/assets/branding/slack-bot/agent-native-1024.png +0 -0
  511. package/src/assets/branding/slack-bot/agent-native-512.png +0 -0
  512. package/src/assets/branding/tray-icon.svg +6 -0
  513. package/src/assets/branding/wordmark-on-dark.svg +21 -0
  514. package/src/assets/branding/wordmark-on-light.svg +21 -0
  515. package/src/assets/fonts/LICENSE_LIBERATION +96 -0
  516. package/src/assets/fonts/LICENSE_NOTO_NASKH_ARABIC +93 -0
  517. package/src/assets/fonts/LiberationSans-Bold.ttf +0 -0
  518. package/src/assets/fonts/LiberationSans-Regular.ttf +0 -0
  519. package/src/assets/fonts/NotoNaskhArabic-Variable.ttf +0 -0
  520. package/src/audit/actions/export-audit-events.ts +162 -0
  521. package/src/audit/actions/get-audit-event.ts +24 -0
  522. package/src/audit/actions/list-audit-events.ts +66 -0
  523. package/src/audit/cleanup-job.ts +100 -0
  524. package/src/audit/config.ts +90 -0
  525. package/src/audit/index.ts +43 -0
  526. package/src/audit/record.ts +180 -0
  527. package/src/audit/redact.ts +109 -0
  528. package/src/audit/store.ts +346 -0
  529. package/src/audit/types.ts +141 -0
  530. package/src/automation/index.ts +802 -0
  531. package/src/brand-kit/brand-signals.ts +124 -0
  532. package/src/brand-kit/fig/index.ts +64 -0
  533. package/src/brand-kit/index.ts +72 -0
  534. package/src/brand-kit/types.ts +113 -0
  535. package/src/browser-sessions/actions.ts +302 -0
  536. package/src/browser-sessions/routes.ts +234 -0
  537. package/src/browser-sessions/store.ts +679 -0
  538. package/src/browser-sessions/types.ts +84 -0
  539. package/src/changelog/parse.ts +328 -0
  540. package/src/chat-threads/emitter.ts +22 -0
  541. package/src/chat-threads/schema.ts +43 -0
  542. package/src/chat-threads/store.ts +1311 -0
  543. package/src/checkpoints/index.ts +15 -0
  544. package/src/checkpoints/service.ts +142 -0
  545. package/src/checkpoints/store.ts +153 -0
  546. package/src/cli/add.ts +425 -0
  547. package/src/cli/agent.ts +424 -0
  548. package/src/cli/agents.ts +122 -0
  549. package/src/cli/app-skill.ts +1455 -0
  550. package/src/cli/atomic-json-file.ts +324 -0
  551. package/src/cli/audit-agent-web.ts +324 -0
  552. package/src/cli/changelog.ts +199 -0
  553. package/src/cli/claude-code-participant.ts +515 -0
  554. package/src/cli/code-agent-commands.ts +270 -0
  555. package/src/cli/code-agent-connector.ts +1109 -0
  556. package/src/cli/code-agent-executor.ts +1970 -0
  557. package/src/cli/code-agent-output-smoother.ts +140 -0
  558. package/src/cli/code-agent-runs.concurrent-worker.ts +33 -0
  559. package/src/cli/code-agent-runs.ts +548 -0
  560. package/src/cli/code.ts +1805 -0
  561. package/src/cli/codex-cli-participant.ts +496 -0
  562. package/src/cli/connect.ts +2714 -0
  563. package/src/cli/content-local.ts +442 -0
  564. package/src/cli/context-xray-local.ts +2193 -0
  565. package/src/cli/create-workspace.ts +30 -0
  566. package/src/cli/create.ts +2247 -0
  567. package/src/cli/deploy-build.ts +50 -0
  568. package/src/cli/design-connect.ts +3187 -0
  569. package/src/cli/doctor.ts +472 -0
  570. package/src/cli/eject.ts +1594 -0
  571. package/src/cli/eval.ts +134 -0
  572. package/src/cli/gateway-helpers.ts +70 -0
  573. package/src/cli/index.ts +1217 -0
  574. package/src/cli/info.ts +105 -0
  575. package/src/cli/invoke.ts +288 -0
  576. package/src/cli/mcp-config-writers.ts +857 -0
  577. package/src/cli/mcp.ts +594 -0
  578. package/src/cli/migrate.ts +1813 -0
  579. package/src/cli/migration-codemod.ts +646 -0
  580. package/src/cli/multi-frontier-runs.ts +1952 -0
  581. package/src/cli/package-lifecycle.ts +823 -0
  582. package/src/cli/plan-blocks.ts +143 -0
  583. package/src/cli/plan-local.ts +3189 -0
  584. package/src/cli/plan-publish-store.ts +138 -0
  585. package/src/cli/pr-visual-recap-workflow.ts +2 -0
  586. package/src/cli/recap.ts +5 -0
  587. package/src/cli/setup-agents.ts +120 -0
  588. package/src/cli/skills-content/assets-skill.ts +83 -0
  589. package/src/cli/skills-content/canvas.ts +153 -0
  590. package/src/cli/skills-content/connection.ts +52 -0
  591. package/src/cli/skills-content/content-skill.ts +120 -0
  592. package/src/cli/skills-content/design-exploration-skill.ts +118 -0
  593. package/src/cli/skills-content/design-visual-edit-skill.ts +228 -0
  594. package/src/cli/skills-content/document-quality.ts +196 -0
  595. package/src/cli/skills-content/exemplar.ts +69 -0
  596. package/src/cli/skills-content/help.ts +77 -0
  597. package/src/cli/skills-content/index.ts +22 -0
  598. package/src/cli/skills-content/local-files.ts +100 -0
  599. package/src/cli/skills-content/plan-setup-auth.ts +80 -0
  600. package/src/cli/skills-content/visual-plan-skill.ts +493 -0
  601. package/src/cli/skills-content/visual-recap-skill.ts +553 -0
  602. package/src/cli/skills-content/visualize-repo-skill.ts +93 -0
  603. package/src/cli/skills-content/wireframe.ts +349 -0
  604. package/src/cli/skills.ts +4340 -0
  605. package/src/cli/sync-builder-starter-manifest.ts +631 -0
  606. package/src/cli/telemetry.ts +136 -0
  607. package/src/cli/templates-meta.ts +269 -0
  608. package/src/cli/upgrade.ts +956 -0
  609. package/src/cli/visualize-repo.ts +715 -0
  610. package/src/cli/workspace-dev.ts +1486 -0
  611. package/src/cli/workspacify.ts +258 -0
  612. package/src/client/AgentAskPopover.tsx +89 -0
  613. package/src/client/AgentChatHome.tsx +66 -0
  614. package/src/client/AgentNative.tsx +161 -0
  615. package/src/client/AgentNativeEmbedded.tsx +288 -0
  616. package/src/client/AgentNativeFrame.tsx +151 -0
  617. package/src/client/AgentPanel.tsx +3437 -0
  618. package/src/client/AgentTaskCard.tsx +273 -0
  619. package/src/client/AppearancePicker.tsx +79 -0
  620. package/src/client/AssistantChat.tsx +5793 -0
  621. package/src/client/ClientOnly.tsx +22 -0
  622. package/src/client/CommandMenu.tsx +726 -0
  623. package/src/client/ConnectBuilderCard.tsx +390 -0
  624. package/src/client/DefaultSpinner.tsx +47 -0
  625. package/src/client/ErrorBoundary.tsx +359 -0
  626. package/src/client/ErrorReportActions.tsx +69 -0
  627. package/src/client/FeedbackButton.tsx +553 -0
  628. package/src/client/HighlightedCodeBlock.tsx +173 -0
  629. package/src/client/IframeEmbed.tsx +151 -0
  630. package/src/client/KeepTabOpenNotice.tsx +181 -0
  631. package/src/client/MultiTabAssistantChat.tsx +2576 -0
  632. package/src/client/NewWorkspaceAppFlow.tsx +525 -0
  633. package/src/client/PoweredByBadge.tsx +284 -0
  634. package/src/client/RunStuckBanner.tsx +431 -0
  635. package/src/client/StarfieldBackground.tsx +466 -0
  636. package/src/client/Turnstile.tsx +125 -0
  637. package/src/client/active-run-state.ts +139 -0
  638. package/src/client/agent-chat/index.ts +279 -0
  639. package/src/client/agent-chat-adapter.ts +3692 -0
  640. package/src/client/agent-chat.ts +1233 -0
  641. package/src/client/agent-engine-key.ts +122 -0
  642. package/src/client/agent-page/AgentContextTab.tsx +487 -0
  643. package/src/client/agent-page/AgentEmptyState.tsx +44 -0
  644. package/src/client/agent-page/AgentJobsTab.tsx +441 -0
  645. package/src/client/agent-page/AgentTabFrame.tsx +39 -0
  646. package/src/client/agent-page/AgentTabsPage.tsx +1096 -0
  647. package/src/client/agent-page/types.ts +18 -0
  648. package/src/client/agent-page/use-jobs.ts +150 -0
  649. package/src/client/agent-sidebar-state.ts +166 -0
  650. package/src/client/analytics/index.ts +40 -0
  651. package/src/client/analytics-session.ts +70 -0
  652. package/src/client/analytics.ts +1757 -0
  653. package/src/client/api-path.ts +124 -0
  654. package/src/client/app-providers.tsx +230 -0
  655. package/src/client/appearance.ts +130 -0
  656. package/src/client/application-state.ts +154 -0
  657. package/src/client/assistant-ui-recovery.tsx +205 -0
  658. package/src/client/automation/index.ts +4 -0
  659. package/src/client/automation.ts +22 -0
  660. package/src/client/blocks/AiEditableField.tsx +30 -0
  661. package/src/client/blocks/BlockView.tsx +145 -0
  662. package/src/client/blocks/RegistryBlockDataProvider.tsx +121 -0
  663. package/src/client/blocks/SchemaBlockEditor.tsx +457 -0
  664. package/src/client/blocks/agent.ts +95 -0
  665. package/src/client/blocks/code-block-direction.ts +21 -0
  666. package/src/client/blocks/index.ts +308 -0
  667. package/src/client/blocks/library/AnnotatedCodeBlock.tsx +710 -0
  668. package/src/client/blocks/library/ApiEndpointBlock.tsx +1120 -0
  669. package/src/client/blocks/library/DataModelBlock.tsx +775 -0
  670. package/src/client/blocks/library/DiffBlock.tsx +1854 -0
  671. package/src/client/blocks/library/FileTreeBlock.tsx +868 -0
  672. package/src/client/blocks/library/HighlightedCode.tsx +260 -0
  673. package/src/client/blocks/library/JsonExplorerBlock.tsx +608 -0
  674. package/src/client/blocks/library/MermaidBlock.tsx +362 -0
  675. package/src/client/blocks/library/OpenApiSpecBlock.tsx +998 -0
  676. package/src/client/blocks/library/annotated-code.config.ts +101 -0
  677. package/src/client/blocks/library/annotation-rail.tsx +1020 -0
  678. package/src/client/blocks/library/api-endpoint.config.ts +207 -0
  679. package/src/client/blocks/library/block-copy.ts +399 -0
  680. package/src/client/blocks/library/callout.config.ts +57 -0
  681. package/src/client/blocks/library/callout.tsx +149 -0
  682. package/src/client/blocks/library/checklist.config.ts +56 -0
  683. package/src/client/blocks/library/checklist.tsx +208 -0
  684. package/src/client/blocks/library/code-filename-label.tsx +59 -0
  685. package/src/client/blocks/library/code-highlight.tsx +178 -0
  686. package/src/client/blocks/library/code-tabs.config.ts +70 -0
  687. package/src/client/blocks/library/code-tabs.tsx +606 -0
  688. package/src/client/blocks/library/code.config.ts +69 -0
  689. package/src/client/blocks/library/code.tsx +440 -0
  690. package/src/client/blocks/library/columns.config.ts +85 -0
  691. package/src/client/blocks/library/columns.tsx +334 -0
  692. package/src/client/blocks/library/data-model.config.ts +152 -0
  693. package/src/client/blocks/library/dev-doc-ui.tsx +191 -0
  694. package/src/client/blocks/library/diagram.config.ts +222 -0
  695. package/src/client/blocks/library/diagram.tsx +958 -0
  696. package/src/client/blocks/library/diff.config.ts +115 -0
  697. package/src/client/blocks/library/file-tree.config.ts +92 -0
  698. package/src/client/blocks/library/html.config.ts +79 -0
  699. package/src/client/blocks/library/html.tsx +258 -0
  700. package/src/client/blocks/library/json-explorer.config.ts +74 -0
  701. package/src/client/blocks/library/mermaid.config.ts +49 -0
  702. package/src/client/blocks/library/narrow-container.tsx +37 -0
  703. package/src/client/blocks/library/openapi-spec.config.ts +66 -0
  704. package/src/client/blocks/library/question-form.config.ts +127 -0
  705. package/src/client/blocks/library/question-form.tsx +944 -0
  706. package/src/client/blocks/library/sanitize-html.ts +343 -0
  707. package/src/client/blocks/library/server-specs.ts +338 -0
  708. package/src/client/blocks/library/specs.tsx +308 -0
  709. package/src/client/blocks/library/table.config.ts +61 -0
  710. package/src/client/blocks/library/table.tsx +449 -0
  711. package/src/client/blocks/library/tabs.config.ts +96 -0
  712. package/src/client/blocks/library/tabs.tsx +665 -0
  713. package/src/client/blocks/library/wireframe-icons.ts +210 -0
  714. package/src/client/blocks/library/wireframe-kit.tsx +1850 -0
  715. package/src/client/blocks/library/wireframe.config.ts +539 -0
  716. package/src/client/blocks/library/wireframe.tsx +535 -0
  717. package/src/client/blocks/mdx.ts +364 -0
  718. package/src/client/blocks/provider.tsx +51 -0
  719. package/src/client/blocks/registry.ts +83 -0
  720. package/src/client/blocks/schema-form/introspect.ts +201 -0
  721. package/src/client/blocks/server.ts +170 -0
  722. package/src/client/blocks/types.ts +415 -0
  723. package/src/client/browser-session-bridge.ts +548 -0
  724. package/src/client/browser-tab-id.ts +36 -0
  725. package/src/client/build-compatibility.ts +77 -0
  726. package/src/client/builder-frame.ts +194 -0
  727. package/src/client/builder-mark.tsx +21 -0
  728. package/src/client/changelog/Changelog.tsx +333 -0
  729. package/src/client/changelog/index.ts +1 -0
  730. package/src/client/chat/ChatHistoryList.tsx +7 -0
  731. package/src/client/chat/attachment-adapters.ts +426 -0
  732. package/src/client/chat/connectors.ts +1579 -0
  733. package/src/client/chat/index.ts +160 -0
  734. package/src/client/chat/markdown-renderer.tsx +693 -0
  735. package/src/client/chat/message-components.tsx +1326 -0
  736. package/src/client/chat/repo-helpers.ts +281 -0
  737. package/src/client/chat/run-recovery.tsx +994 -0
  738. package/src/client/chat/runtime.ts +1810 -0
  739. package/src/client/chat/tool-call-display.tsx +1270 -0
  740. package/src/client/chat/tool-render-registry.tsx +144 -0
  741. package/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  742. package/src/client/chat/use-reconnect-reader-owner.ts +28 -0
  743. package/src/client/chat/widgets/DataChartRenderer.tsx +242 -0
  744. package/src/client/chat/widgets/DataChartWidget.tsx +51 -0
  745. package/src/client/chat/widgets/DataInsightsWidget.tsx +59 -0
  746. package/src/client/chat/widgets/DataTableWidget.tsx +240 -0
  747. package/src/client/chat/widgets/InlineExtensionWidget.tsx +60 -0
  748. package/src/client/chat/widgets/builtin-tool-renderers.tsx +213 -0
  749. package/src/client/chat/widgets/data-widget-types.ts +1 -0
  750. package/src/client/chat/widgets/inline-extension-result.ts +86 -0
  751. package/src/client/chat-model-groups.ts +171 -0
  752. package/src/client/chat-thread-url.ts +11 -0
  753. package/src/client/chat-view-transition.ts +213 -0
  754. package/src/client/client-action.ts +21 -0
  755. package/src/client/client-bootstrap.ts +7 -0
  756. package/src/client/client-surface.ts +41 -0
  757. package/src/client/clipboard.ts +89 -0
  758. package/src/client/code-agent-chat-adapter.ts +537 -0
  759. package/src/client/collab/index.ts +60 -0
  760. package/src/client/command-navigation/index.ts +15 -0
  761. package/src/client/comments-review/index.ts +1 -0
  762. package/src/client/components/AgentPresenceChip.tsx +4 -0
  763. package/src/client/components/ApiKeySettings.tsx +309 -0
  764. package/src/client/components/CodeAgentIndicator.tsx +59 -0
  765. package/src/client/components/CodeRequiredDialog.tsx +470 -0
  766. package/src/client/components/LiveCursorOverlay.tsx +5 -0
  767. package/src/client/components/MissingKeyCard.tsx +61 -0
  768. package/src/client/components/PresenceBar.tsx +4 -0
  769. package/src/client/components/RecentEditHighlights.tsx +4 -0
  770. package/src/client/components/RemoteSelectionRings.tsx +5 -0
  771. package/src/client/components/icons/AgentNativeIcon.tsx +46 -0
  772. package/src/client/components/ui/dialog.tsx +1 -0
  773. package/src/client/components/ui/dropdown-menu.tsx +1 -0
  774. package/src/client/components/ui/hover-card.tsx +1 -0
  775. package/src/client/components/ui/message-scroller.tsx +131 -0
  776. package/src/client/components/ui/popover.tsx +1 -0
  777. package/src/client/components/ui/sheet.tsx +1 -0
  778. package/src/client/components/ui/tooltip.tsx +1 -0
  779. package/src/client/composer/index.ts +11 -0
  780. package/src/client/composer/runtime-adapters.tsx +123 -0
  781. package/src/client/composer/use-mention-search.ts +7 -0
  782. package/src/client/composer/wired-components.tsx +53 -0
  783. package/src/client/context-xray/ContextMeter.tsx +124 -0
  784. package/src/client/context-xray/ContextSegmentRow.tsx +27 -0
  785. package/src/client/context-xray/ContextTreemap.tsx +24 -0
  786. package/src/client/context-xray/ContextXRayPanel.tsx +59 -0
  787. package/src/client/context-xray/SegmentProvenancePopover.tsx +18 -0
  788. package/src/client/context-xray/format.ts +27 -0
  789. package/src/client/conversation/AgentConversation.tsx +555 -0
  790. package/src/client/conversation/code-agent-transcript.ts +283 -0
  791. package/src/client/conversation/index.ts +22 -0
  792. package/src/client/conversation/types.ts +85 -0
  793. package/src/client/conversation/use-near-bottom-autoscroll.ts +278 -0
  794. package/src/client/create-query-client.ts +86 -0
  795. package/src/client/db-admin/DataGrid.tsx +551 -0
  796. package/src/client/db-admin/DbAdminPage.tsx +218 -0
  797. package/src/client/db-admin/DevDatabaseLink.tsx +16 -0
  798. package/src/client/db-admin/EditableCell.tsx +451 -0
  799. package/src/client/db-admin/FilterBar.tsx +203 -0
  800. package/src/client/db-admin/ResultsGrid.tsx +114 -0
  801. package/src/client/db-admin/RowSidePanel.tsx +337 -0
  802. package/src/client/db-admin/SqlEditor.tsx +840 -0
  803. package/src/client/db-admin/TableBrowser.tsx +212 -0
  804. package/src/client/db-admin/TableEditor.tsx +760 -0
  805. package/src/client/db-admin/cell-format.ts +246 -0
  806. package/src/client/db-admin/changeset.ts +296 -0
  807. package/src/client/db-admin/export-utils.ts +78 -0
  808. package/src/client/db-admin/index.ts +33 -0
  809. package/src/client/db-admin/sql-storage.ts +134 -0
  810. package/src/client/db-admin/storage.ts +68 -0
  811. package/src/client/db-admin/useAgentSync.ts +226 -0
  812. package/src/client/db-admin/useDbAdmin.ts +294 -0
  813. package/src/client/dev-overlay/DevOverlay.tsx +576 -0
  814. package/src/client/dev-overlay/builtins.ts +40 -0
  815. package/src/client/dev-overlay/index.ts +23 -0
  816. package/src/client/dev-overlay/registry.ts +67 -0
  817. package/src/client/dev-overlay/types.ts +64 -0
  818. package/src/client/dev-overlay/use-dev-option.ts +78 -0
  819. package/src/client/dev-overlay/use-dev-overlay-shortcut.ts +31 -0
  820. package/src/client/dynamic-suggestions.ts +455 -0
  821. package/src/client/embed-auth.ts +544 -0
  822. package/src/client/embed.ts +54 -0
  823. package/src/client/error-capture.ts +690 -0
  824. package/src/client/error-format.ts +211 -0
  825. package/src/client/error-reporting.ts +100 -0
  826. package/src/client/extensions/AgentNativeExtensionFrame.e2e-host.tsx +136 -0
  827. package/src/client/extensions/AgentNativeExtensionFrame.tsx +708 -0
  828. package/src/client/extensions/EmbeddedExtension.tsx +604 -0
  829. package/src/client/extensions/ExtensionEditor.tsx +450 -0
  830. package/src/client/extensions/ExtensionQueryErrorState.tsx +47 -0
  831. package/src/client/extensions/ExtensionSlot.tsx +345 -0
  832. package/src/client/extensions/ExtensionViewer.tsx +1502 -0
  833. package/src/client/extensions/ExtensionViewerPage.tsx +32 -0
  834. package/src/client/extensions/ExtensionsListPage.tsx +432 -0
  835. package/src/client/extensions/ExtensionsSidebarSection.tsx +1259 -0
  836. package/src/client/extensions/InlineExtensionFrame.tsx +660 -0
  837. package/src/client/extensions/agent-native-extension-runtime.ts +495 -0
  838. package/src/client/extensions/delete-extension.ts +76 -0
  839. package/src/client/extensions/extension-load-error.ts +26 -0
  840. package/src/client/extensions/extension-order.ts +49 -0
  841. package/src/client/extensions/extension-popularity.ts +61 -0
  842. package/src/client/extensions/iframe-bridge.ts +377 -0
  843. package/src/client/extensions/index.ts +84 -0
  844. package/src/client/extensions/portable-extension.ts +712 -0
  845. package/src/client/feature-flags/FeatureFlagsPanel.tsx +519 -0
  846. package/src/client/feature-flags/helpers.ts +77 -0
  847. package/src/client/feature-flags/index.ts +13 -0
  848. package/src/client/feature-flags/types.ts +29 -0
  849. package/src/client/feature-flags/use-feature-flag.ts +26 -0
  850. package/src/client/feedback-context.ts +90 -0
  851. package/src/client/frame-protocol.ts +168 -0
  852. package/src/client/frame.ts +329 -0
  853. package/src/client/guided-questions.tsx +1152 -0
  854. package/src/client/history/VersionHistoryPanel.tsx +175 -0
  855. package/src/client/history/index.ts +21 -0
  856. package/src/client/history/use-history.ts +114 -0
  857. package/src/client/hooks/index.ts +46 -0
  858. package/src/client/host/index.ts +170 -0
  859. package/src/client/host-bridge.ts +1272 -0
  860. package/src/client/host-tools.ts +190 -0
  861. package/src/client/i18n.tsx +798 -0
  862. package/src/client/index.ts +370 -0
  863. package/src/client/integrations/IntegrationCard.tsx +186 -0
  864. package/src/client/integrations/IntegrationsPanel.tsx +633 -0
  865. package/src/client/integrations/api.ts +295 -0
  866. package/src/client/integrations/index.ts +29 -0
  867. package/src/client/integrations/useIntegrationStatus.ts +52 -0
  868. package/src/client/mcp-app-host.ts +720 -0
  869. package/src/client/mcp-apps/McpAppRenderer.tsx +760 -0
  870. package/src/client/navigation/index.ts +54 -0
  871. package/src/client/notifications/NotificationsBell.tsx +383 -0
  872. package/src/client/notifications/index.ts +1 -0
  873. package/src/client/observability/ObservabilityDashboard.tsx +890 -0
  874. package/src/client/observability/ThumbsFeedback.tsx +160 -0
  875. package/src/client/observability/index.ts +20 -0
  876. package/src/client/observability/useObservability.ts +266 -0
  877. package/src/client/onboarding/OnboardingBanner.tsx +73 -0
  878. package/src/client/onboarding/OnboardingPanel.tsx +1036 -0
  879. package/src/client/onboarding/SetupButton.tsx +64 -0
  880. package/src/client/onboarding/index.ts +25 -0
  881. package/src/client/onboarding/use-onboarding.ts +164 -0
  882. package/src/client/onboarding/use-preview-mode.ts +40 -0
  883. package/src/client/org/InvitationBanner.tsx +148 -0
  884. package/src/client/org/OrgSwitcher.tsx +754 -0
  885. package/src/client/org/RequireActiveOrg.tsx +337 -0
  886. package/src/client/org/TeamPage.tsx +1432 -0
  887. package/src/client/org/hooks.ts +359 -0
  888. package/src/client/org/index.ts +70 -0
  889. package/src/client/org/workspace-app-links.ts +367 -0
  890. package/src/client/org-team/index.ts +1 -0
  891. package/src/client/progress/RunsTray.tsx +680 -0
  892. package/src/client/progress/index.ts +1 -0
  893. package/src/client/require-session.tsx +142 -0
  894. package/src/client/resources/BuiltinCapabilityDetail.tsx +258 -0
  895. package/src/client/resources/McpConnectionSuggestion.tsx +276 -0
  896. package/src/client/resources/McpIntegrationDialog.tsx +808 -0
  897. package/src/client/resources/McpServerDetail.tsx +230 -0
  898. package/src/client/resources/ResourceEditor.tsx +872 -0
  899. package/src/client/resources/ResourceTree.tsx +860 -0
  900. package/src/client/resources/ResourcesPanel.tsx +1960 -0
  901. package/src/client/resources/index.ts +25 -0
  902. package/src/client/resources/mcp-integration-catalog.ts +771 -0
  903. package/src/client/resources/mcp-integration-logos.ts +108 -0
  904. package/src/client/resources/runtime.ts +1 -0
  905. package/src/client/resources/use-builtin-capabilities.ts +113 -0
  906. package/src/client/resources/use-mcp-servers.ts +217 -0
  907. package/src/client/resources/use-resources.ts +402 -0
  908. package/src/client/review/ReviewCommentComposer.tsx +123 -0
  909. package/src/client/review/ReviewStatusBadge.tsx +39 -0
  910. package/src/client/review/ReviewThreadPanel.tsx +625 -0
  911. package/src/client/review/index.ts +38 -0
  912. package/src/client/review/use-review.ts +186 -0
  913. package/src/client/route-chunk-recovery/index.ts +2 -0
  914. package/src/client/route-chunk-recovery.ts +331 -0
  915. package/src/client/route-state.ts +455 -0
  916. package/src/client/route-warmup.tsx +543 -0
  917. package/src/client/session-replay-iframe.e2e-host.tsx +100 -0
  918. package/src/client/session-replay.ts +3417 -0
  919. package/src/client/settings/AgentsSection.tsx +441 -0
  920. package/src/client/settings/AutomationsSection.tsx +516 -0
  921. package/src/client/settings/BackgroundAgentSection.tsx +189 -0
  922. package/src/client/settings/BrowserSection.tsx +110 -0
  923. package/src/client/settings/DemoModeSection.tsx +48 -0
  924. package/src/client/settings/SecretsSection.tsx +875 -0
  925. package/src/client/settings/SettingsPanel.tsx +3162 -0
  926. package/src/client/settings/SettingsSection.tsx +283 -0
  927. package/src/client/settings/SettingsTabsPage.tsx +592 -0
  928. package/src/client/settings/UsageSection.tsx +401 -0
  929. package/src/client/settings/VoiceTranscriptionSection.tsx +960 -0
  930. package/src/client/settings/agent-settings-search.ts +220 -0
  931. package/src/client/settings/index.ts +27 -0
  932. package/src/client/settings/useBuilderStatus.ts +1055 -0
  933. package/src/client/setup-connections/BuilderConnectCard.tsx +89 -0
  934. package/src/client/setup-connections/ProviderReadinessBadge.tsx +73 -0
  935. package/src/client/setup-connections/SetupConnectionsPage.tsx +94 -0
  936. package/src/client/setup-connections/catalog.ts +6 -0
  937. package/src/client/setup-connections/index.ts +47 -0
  938. package/src/client/setup-connections/runtime.ts +1 -0
  939. package/src/client/sharing/ShareButton.tsx +1748 -0
  940. package/src/client/sharing/ShareDialog.tsx +846 -0
  941. package/src/client/sharing/VisibilityBadge.tsx +4 -0
  942. package/src/client/sharing/index.ts +2 -0
  943. package/src/client/sse-event-processor.ts +2002 -0
  944. package/src/client/terminal/AgentTerminal.tsx +488 -0
  945. package/src/client/terminal/index.ts +7 -0
  946. package/src/client/theme.ts +27 -0
  947. package/src/client/tombstone/agent-presence-chip.ts +17 -0
  948. package/src/client/tombstone/editor.ts +265 -0
  949. package/src/client/tombstone/live-cursor-overlay.ts +21 -0
  950. package/src/client/tombstone/presence-bar.ts +17 -0
  951. package/src/client/tombstone/recent-edit-highlights.ts +17 -0
  952. package/src/client/tombstone/remote-selection-rings.ts +21 -0
  953. package/src/client/tombstone/rich-markdown-editor.ts +265 -0
  954. package/src/client/tombstone/ui-dialog.ts +49 -0
  955. package/src/client/tombstone/ui-dropdown-menu.ts +69 -0
  956. package/src/client/tombstone/ui-hover-card.ts +21 -0
  957. package/src/client/tombstone/ui-popover.ts +25 -0
  958. package/src/client/tombstone/ui-sheet.ts +49 -0
  959. package/src/client/tombstone/ui-tooltip.ts +29 -0
  960. package/src/client/tombstone/visual-style-controls.ts +61 -0
  961. package/src/client/tool-cells/BashCell.tsx +164 -0
  962. package/src/client/tool-cells/EditCell.tsx +303 -0
  963. package/src/client/tool-cells/FilesChangedSummary.tsx +208 -0
  964. package/src/client/tool-cells/WriteCell.tsx +145 -0
  965. package/src/client/tool-cells/index.ts +7 -0
  966. package/src/client/tool-display.ts +41 -0
  967. package/src/client/track.ts +57 -0
  968. package/src/client/transcription/BuilderTranscriptionCta.tsx +120 -0
  969. package/src/client/transcription/use-live-transcription.ts +292 -0
  970. package/src/client/ui/index.ts +55 -0
  971. package/src/client/uploads/index.ts +6 -0
  972. package/src/client/uploads/upload-editor-image.ts +79 -0
  973. package/src/client/uploads/use-upload-resource.ts +24 -0
  974. package/src/client/url-scrub.ts +51 -0
  975. package/src/client/use-action.ts +797 -0
  976. package/src/client/use-agent-chat-context.ts +63 -0
  977. package/src/client/use-agent-chat-home-handoff.ts +207 -0
  978. package/src/client/use-agent-chat.ts +53 -0
  979. package/src/client/use-agent-engine-configured.ts +211 -0
  980. package/src/client/use-avatar.ts +127 -0
  981. package/src/client/use-change-version.ts +150 -0
  982. package/src/client/use-chat-models.ts +252 -0
  983. package/src/client/use-chat-threads.ts +1262 -0
  984. package/src/client/use-db-sync.ts +1112 -0
  985. package/src/client/use-demo-mode-status.ts +30 -0
  986. package/src/client/use-dev-mode.ts +177 -0
  987. package/src/client/use-external-value.ts +40 -0
  988. package/src/client/use-pausing-interval.ts +65 -0
  989. package/src/client/use-pinch-zoom.ts +202 -0
  990. package/src/client/use-run-stuck-detection.ts +427 -0
  991. package/src/client/use-send-to-agent-chat.ts +85 -0
  992. package/src/client/use-session.ts +114 -0
  993. package/src/client/utils.ts +7 -0
  994. package/src/client/visual-style-controls.tsx +1 -0
  995. package/src/client/vite-dev-recovery-script.ts +226 -0
  996. package/src/client/voice-provider-status.ts +44 -0
  997. package/src/client/widgets/index.ts +41 -0
  998. package/src/code-agents/background-controller.ts +398 -0
  999. package/src/code-agents/background-run.ts +156 -0
  1000. package/src/code-agents/index.ts +95 -0
  1001. package/src/code-agents/prompt-attachments.ts +39 -0
  1002. package/src/code-agents/transcript-normalizer.ts +750 -0
  1003. package/src/code-agents/transcript-order.ts +73 -0
  1004. package/src/coding-tools/index.ts +742 -0
  1005. package/src/coding-tools/run-code.ts +1662 -0
  1006. package/src/coding-tools/sandbox/adapter.ts +82 -0
  1007. package/src/coding-tools/sandbox/background.ts +406 -0
  1008. package/src/coding-tools/sandbox/executions-store.ts +517 -0
  1009. package/src/coding-tools/sandbox/index.ts +132 -0
  1010. package/src/coding-tools/sandbox/local-child-process-adapter.ts +217 -0
  1011. package/src/collab/agent-identity.ts +5 -0
  1012. package/src/collab/agent-presence.ts +341 -0
  1013. package/src/collab/awareness-store.ts +196 -0
  1014. package/src/collab/awareness.ts +317 -0
  1015. package/src/collab/client-struct.ts +366 -0
  1016. package/src/collab/client.ts +1205 -0
  1017. package/src/collab/emitter.ts +31 -0
  1018. package/src/collab/follow-mode.ts +107 -0
  1019. package/src/collab/index.ts +151 -0
  1020. package/src/collab/json-to-yjs.ts +504 -0
  1021. package/src/collab/presence.ts +207 -0
  1022. package/src/collab/recent-edits.ts +215 -0
  1023. package/src/collab/routes.ts +191 -0
  1024. package/src/collab/storage.ts +228 -0
  1025. package/src/collab/struct-routes.ts +133 -0
  1026. package/src/collab/text-to-yjs.ts +79 -0
  1027. package/src/collab/undo.ts +432 -0
  1028. package/src/collab/xml-ops.ts +68 -0
  1029. package/src/collab/ydoc-manager.ts +544 -0
  1030. package/src/command-navigation/actions.ts +100 -0
  1031. package/src/command-navigation/index.ts +12 -0
  1032. package/src/comments-review/index.ts +1 -0
  1033. package/src/connections/catalog.ts +451 -0
  1034. package/src/connections/index.ts +48 -0
  1035. package/src/connections/reader.ts +911 -0
  1036. package/src/connections/runtime.ts +1 -0
  1037. package/src/credentials/index.ts +187 -0
  1038. package/src/data-programs/actions.ts +335 -0
  1039. package/src/data-programs/contract.ts +284 -0
  1040. package/src/data-programs/execute.ts +693 -0
  1041. package/src/data-programs/index.ts +72 -0
  1042. package/src/data-programs/schema.ts +148 -0
  1043. package/src/data-programs/store.ts +755 -0
  1044. package/src/data-widgets/index.ts +376 -0
  1045. package/src/db/client.ts +1627 -0
  1046. package/src/db/create-get-db.ts +579 -0
  1047. package/src/db/ddl-guard.ts +302 -0
  1048. package/src/db/drizzle-config.ts +190 -0
  1049. package/src/db/ensure-additive-columns.ts +430 -0
  1050. package/src/db/index.ts +57 -0
  1051. package/src/db/migrations.ts +691 -0
  1052. package/src/db/request-telemetry.ts +154 -0
  1053. package/src/db/runtime-diagnostics.ts +331 -0
  1054. package/src/db/schema.ts +121 -0
  1055. package/src/db/widen-columns.ts +75 -0
  1056. package/src/db-admin/agent-tools.ts +202 -0
  1057. package/src/db-admin/index.ts +26 -0
  1058. package/src/db-admin/operations.ts +803 -0
  1059. package/src/db-admin/routes.ts +174 -0
  1060. package/src/db-admin/types.ts +110 -0
  1061. package/src/demo/browser-state.ts +47 -0
  1062. package/src/demo/fetch-interceptor.ts +175 -0
  1063. package/src/demo/redact.ts +575 -0
  1064. package/src/deploy/build.ts +3938 -0
  1065. package/src/deploy/immutable-assets.ts +65 -0
  1066. package/src/deploy/route-discovery.ts +458 -0
  1067. package/src/deploy/workspace-core.ts +282 -0
  1068. package/src/deploy/workspace-deploy.ts +1488 -0
  1069. package/src/eject/provider-api-definitions.ts +193 -0
  1070. package/src/eject/remote-mcp-presets.ts +137 -0
  1071. package/src/eject/setup-readiness-ui.tsx +29 -0
  1072. package/src/eject/workspace-connections.ts +92 -0
  1073. package/src/embedding/agent.ts +159 -0
  1074. package/src/embedding/bridge.ts +297 -0
  1075. package/src/embedding/index.ts +43 -0
  1076. package/src/embedding/protocol.ts +185 -0
  1077. package/src/embedding/react.tsx +319 -0
  1078. package/src/embeddings/index.ts +233 -0
  1079. package/src/eval/agent-runner.ts +210 -0
  1080. package/src/eval/define-eval.ts +55 -0
  1081. package/src/eval/index.ts +49 -0
  1082. package/src/eval/report.ts +75 -0
  1083. package/src/eval/runner.ts +369 -0
  1084. package/src/eval/scorer.ts +244 -0
  1085. package/src/eval/types.ts +188 -0
  1086. package/src/event-bus/bus.ts +140 -0
  1087. package/src/event-bus/index.ts +3 -0
  1088. package/src/event-bus/registry.ts +79 -0
  1089. package/src/event-bus/types.ts +29 -0
  1090. package/src/extensions/actions.ts +1636 -0
  1091. package/src/extensions/change-marker.ts +54 -0
  1092. package/src/extensions/content-patch.ts +468 -0
  1093. package/src/extensions/fetch-tool.ts +461 -0
  1094. package/src/extensions/html-shell.ts +803 -0
  1095. package/src/extensions/local.ts +462 -0
  1096. package/src/extensions/path.ts +40 -0
  1097. package/src/extensions/proxy-security.ts +171 -0
  1098. package/src/extensions/routes.ts +1080 -0
  1099. package/src/extensions/schema.ts +269 -0
  1100. package/src/extensions/session-replay-iframe.ts +131 -0
  1101. package/src/extensions/slots/routes.ts +126 -0
  1102. package/src/extensions/slots/schema.ts +87 -0
  1103. package/src/extensions/slots/store.ts +450 -0
  1104. package/src/extensions/store.ts +1347 -0
  1105. package/src/extensions/theme.ts +114 -0
  1106. package/src/extensions/url-safety.ts +316 -0
  1107. package/src/extensions/web-content.ts +663 -0
  1108. package/src/extensions/web-search-tool.ts +437 -0
  1109. package/src/feature-flags/a2a-action-route.ts +56 -0
  1110. package/src/feature-flags/actions/get-feature-flags.ts +24 -0
  1111. package/src/feature-flags/actions/list-feature-flags.ts +69 -0
  1112. package/src/feature-flags/actions/set-feature-flag.ts +89 -0
  1113. package/src/feature-flags/index.ts +21 -0
  1114. package/src/feature-flags/permissions.ts +53 -0
  1115. package/src/feature-flags/plugin.ts +44 -0
  1116. package/src/feature-flags/registry.ts +96 -0
  1117. package/src/feature-flags/store.ts +176 -0
  1118. package/src/file-upload/actions/upload-image.ts +213 -0
  1119. package/src/file-upload/builder.ts +431 -0
  1120. package/src/file-upload/index.ts +24 -0
  1121. package/src/file-upload/pre-upload-attachments.ts +305 -0
  1122. package/src/file-upload/registry.ts +125 -0
  1123. package/src/file-upload/types.ts +89 -0
  1124. package/src/guards/db-tool-scoping.ts +129 -0
  1125. package/src/guards/index.ts +23 -0
  1126. package/src/guards/no-drizzle-push.ts +116 -0
  1127. package/src/guards/no-env-credentials.ts +229 -0
  1128. package/src/guards/no-env-mutation.ts +114 -0
  1129. package/src/guards/no-localhost-fallback.ts +124 -0
  1130. package/src/guards/no-unscoped-credentials.ts +227 -0
  1131. package/src/guards/no-unscoped-queries.ts +834 -0
  1132. package/src/guards/scan-utils.ts +105 -0
  1133. package/src/guards/types.ts +30 -0
  1134. package/src/history/actions/create-resource-version.ts +92 -0
  1135. package/src/history/actions/get-resource-version.ts +60 -0
  1136. package/src/history/actions/list-resource-history.ts +53 -0
  1137. package/src/history/actions/list-resource-versions.ts +43 -0
  1138. package/src/history/actions/restore-resource-version.ts +96 -0
  1139. package/src/history/index.ts +26 -0
  1140. package/src/history/registry.ts +111 -0
  1141. package/src/history/store.ts +379 -0
  1142. package/src/history/types.ts +69 -0
  1143. package/src/index.browser.ts +155 -0
  1144. package/src/index.ts +408 -0
  1145. package/src/ingestion/docx.ts +158 -0
  1146. package/src/ingestion/figma-node-to-html.ts +1860 -0
  1147. package/src/ingestion/figma.ts +548 -0
  1148. package/src/ingestion/index.ts +107 -0
  1149. package/src/ingestion/media.ts +264 -0
  1150. package/src/ingestion/notion.ts +121 -0
  1151. package/src/ingestion/office.ts +213 -0
  1152. package/src/ingestion/orchestration.ts +160 -0
  1153. package/src/ingestion/pptx.ts +331 -0
  1154. package/src/ingestion/selection.ts +81 -0
  1155. package/src/ingestion/website.ts +151 -0
  1156. package/src/integrations/a2a-continuation-marker.ts +2 -0
  1157. package/src/integrations/a2a-continuation-processor.ts +888 -0
  1158. package/src/integrations/a2a-continuations-store.ts +643 -0
  1159. package/src/integrations/adapter-overrides.ts +12 -0
  1160. package/src/integrations/adapters/discord.ts +364 -0
  1161. package/src/integrations/adapters/email.ts +1164 -0
  1162. package/src/integrations/adapters/google-docs.ts +371 -0
  1163. package/src/integrations/adapters/index.ts +29 -0
  1164. package/src/integrations/adapters/microsoft-teams.ts +413 -0
  1165. package/src/integrations/adapters/slack.ts +1914 -0
  1166. package/src/integrations/adapters/telegram.ts +386 -0
  1167. package/src/integrations/adapters/whatsapp.ts +358 -0
  1168. package/src/integrations/awaiting-input-store.ts +130 -0
  1169. package/src/integrations/catalog.ts +571 -0
  1170. package/src/integrations/computer-supervision-store.ts +423 -0
  1171. package/src/integrations/computer-supervision.ts +213 -0
  1172. package/src/integrations/config-store.ts +131 -0
  1173. package/src/integrations/controls-store.ts +187 -0
  1174. package/src/integrations/eject/messaging-adapters.ts +85 -0
  1175. package/src/integrations/google-docs-poller.ts +671 -0
  1176. package/src/integrations/identity-links-store.ts +210 -0
  1177. package/src/integrations/identity.ts +196 -0
  1178. package/src/integrations/index.ts +220 -0
  1179. package/src/integrations/installations-store.ts +677 -0
  1180. package/src/integrations/integration-memory.ts +187 -0
  1181. package/src/integrations/internal-token.ts +106 -0
  1182. package/src/integrations/pending-tasks-retry-job.ts +286 -0
  1183. package/src/integrations/pending-tasks-store.ts +468 -0
  1184. package/src/integrations/plugin.ts +3048 -0
  1185. package/src/integrations/remote-commands-store.ts +690 -0
  1186. package/src/integrations/remote-devices-store.ts +492 -0
  1187. package/src/integrations/remote-json-safety.ts +127 -0
  1188. package/src/integrations/remote-push-delivery-job.ts +48 -0
  1189. package/src/integrations/remote-push-delivery.ts +370 -0
  1190. package/src/integrations/remote-push-store.ts +664 -0
  1191. package/src/integrations/remote-retry-job.ts +55 -0
  1192. package/src/integrations/remote-run-events-store.ts +222 -0
  1193. package/src/integrations/remote-types.ts +186 -0
  1194. package/src/integrations/runtime.ts +1 -0
  1195. package/src/integrations/scope-store.ts +498 -0
  1196. package/src/integrations/slack-manifest.ts +78 -0
  1197. package/src/integrations/slack-oauth.ts +344 -0
  1198. package/src/integrations/task-queue-stats.ts +144 -0
  1199. package/src/integrations/thread-mapping-store.ts +134 -0
  1200. package/src/integrations/types.ts +485 -0
  1201. package/src/integrations/usage-budget-store.ts +906 -0
  1202. package/src/integrations/webhook-delivery.ts +55 -0
  1203. package/src/integrations/webhook-handler.ts +1939 -0
  1204. package/src/jobs/actions/list-recurring-jobs.ts +105 -0
  1205. package/src/jobs/actions/manage-recurring-job.ts +85 -0
  1206. package/src/jobs/cron.ts +126 -0
  1207. package/src/jobs/index.ts +9 -0
  1208. package/src/jobs/scheduler.ts +703 -0
  1209. package/src/jobs/tools.ts +367 -0
  1210. package/src/local-artifacts/index.ts +1372 -0
  1211. package/src/localization/actions/get-localization-preference.ts +24 -0
  1212. package/src/localization/actions/set-localization-preference.ts +32 -0
  1213. package/src/localization/default-messages.ts +1009 -0
  1214. package/src/localization/index.ts +2 -0
  1215. package/src/localization/server.ts +131 -0
  1216. package/src/localization/shared.ts +208 -0
  1217. package/src/mcp/actions/call-mcp-tool.ts +19 -0
  1218. package/src/mcp/actions/create-org-service-token.ts +87 -0
  1219. package/src/mcp/actions/list-mcp-tools.ts +18 -0
  1220. package/src/mcp/actions/list-org-service-tokens.ts +44 -0
  1221. package/src/mcp/actions/revoke-org-service-token.ts +30 -0
  1222. package/src/mcp/actions/service-token-access.ts +121 -0
  1223. package/src/mcp/ask-app-inline-tasks.ts +125 -0
  1224. package/src/mcp/build-server.ts +2356 -0
  1225. package/src/mcp/builtin-tools.ts +1506 -0
  1226. package/src/mcp/connect-route.ts +1460 -0
  1227. package/src/mcp/connect-store.ts +680 -0
  1228. package/src/mcp/embed-app.ts +2051 -0
  1229. package/src/mcp/embed-route.ts +84 -0
  1230. package/src/mcp/external-agent-policy.ts +18 -0
  1231. package/src/mcp/index.ts +47 -0
  1232. package/src/mcp/oauth-route.ts +1016 -0
  1233. package/src/mcp/oauth-store.ts +581 -0
  1234. package/src/mcp/oauth-token.ts +227 -0
  1235. package/src/mcp/org-directory.ts +343 -0
  1236. package/src/mcp/route-paths.ts +34 -0
  1237. package/src/mcp/screen-memory-stdio.ts +290 -0
  1238. package/src/mcp/server.ts +507 -0
  1239. package/src/mcp/stdio.ts +328 -0
  1240. package/src/mcp/workspace-resolve.ts +261 -0
  1241. package/src/mcp-client/app-api.ts +136 -0
  1242. package/src/mcp-client/app-result.ts +64 -0
  1243. package/src/mcp-client/builtin-capabilities.ts +146 -0
  1244. package/src/mcp-client/builtin-store.ts +93 -0
  1245. package/src/mcp-client/config.ts +281 -0
  1246. package/src/mcp-client/errors.ts +54 -0
  1247. package/src/mcp-client/hub-client.ts +172 -0
  1248. package/src/mcp-client/hub-routes.ts +198 -0
  1249. package/src/mcp-client/index.ts +504 -0
  1250. package/src/mcp-client/manager.ts +968 -0
  1251. package/src/mcp-client/oauth-client.ts +462 -0
  1252. package/src/mcp-client/oauth-routes.ts +307 -0
  1253. package/src/mcp-client/remote-store.ts +674 -0
  1254. package/src/mcp-client/remote-url.ts +97 -0
  1255. package/src/mcp-client/routes.ts +1093 -0
  1256. package/src/mcp-client/screen-memory-local.ts +461 -0
  1257. package/src/mcp-client/tool-policy.ts +182 -0
  1258. package/src/mcp-client/visibility.ts +56 -0
  1259. package/src/mcp-client/workspace-servers.ts +379 -0
  1260. package/src/navigation/index.ts +170 -0
  1261. package/src/notifications/actions.ts +151 -0
  1262. package/src/notifications/channels.ts +410 -0
  1263. package/src/notifications/index.ts +22 -0
  1264. package/src/notifications/registry.ts +216 -0
  1265. package/src/notifications/routes.ts +106 -0
  1266. package/src/notifications/store.ts +236 -0
  1267. package/src/notifications/types.ts +52 -0
  1268. package/src/oauth-tokens/google-refresh.ts +175 -0
  1269. package/src/oauth-tokens/index.ts +15 -0
  1270. package/src/oauth-tokens/store.ts +384 -0
  1271. package/src/observability/cleanup-job.ts +124 -0
  1272. package/src/observability/evals.ts +507 -0
  1273. package/src/observability/experiments.ts +359 -0
  1274. package/src/observability/feedback.ts +332 -0
  1275. package/src/observability/hosted-model-experiment.ts +118 -0
  1276. package/src/observability/index.ts +62 -0
  1277. package/src/observability/plugin.ts +31 -0
  1278. package/src/observability/routes.ts +431 -0
  1279. package/src/observability/sentiment.ts +261 -0
  1280. package/src/observability/store.ts +1347 -0
  1281. package/src/observability/traces.ts +789 -0
  1282. package/src/observability/tracing.ts +157 -0
  1283. package/src/observability/tracking-identity.ts +55 -0
  1284. package/src/observability/types.ts +211 -0
  1285. package/src/onboarding/default-steps.ts +428 -0
  1286. package/src/onboarding/index.ts +22 -0
  1287. package/src/onboarding/plugin.ts +262 -0
  1288. package/src/onboarding/registry.ts +47 -0
  1289. package/src/onboarding/types.ts +96 -0
  1290. package/src/org/accept-pending.ts +98 -0
  1291. package/src/org/auto-join-domain.ts +113 -0
  1292. package/src/org/context.ts +640 -0
  1293. package/src/org/free-email-providers.ts +124 -0
  1294. package/src/org/handlers.ts +1153 -0
  1295. package/src/org/index.ts +63 -0
  1296. package/src/org/migrations.ts +105 -0
  1297. package/src/org/permissions.ts +30 -0
  1298. package/src/org/plugin.ts +255 -0
  1299. package/src/org/schema.ts +28 -0
  1300. package/src/org/types.ts +57 -0
  1301. package/src/org-team/index.ts +1 -0
  1302. package/src/package-lifecycle/deprecated-imports.ts +179 -0
  1303. package/src/package-lifecycle/eject-manifest.ts +345 -0
  1304. package/src/package-lifecycle/index.ts +7 -0
  1305. package/src/package-lifecycle/manifest.ts +120 -0
  1306. package/src/package-lifecycle/migration-manifest.ts +159 -0
  1307. package/src/package-lifecycle/migration-message.ts +6 -0
  1308. package/src/package-lifecycle/tombstone.ts +58 -0
  1309. package/src/package-lifecycle/upgrade-error.ts +37 -0
  1310. package/src/private-blob/index.ts +18 -0
  1311. package/src/private-blob/registry.ts +242 -0
  1312. package/src/private-blob/types.ts +55 -0
  1313. package/src/progress/actions.ts +179 -0
  1314. package/src/progress/index.ts +16 -0
  1315. package/src/progress/registry.ts +127 -0
  1316. package/src/progress/routes.ts +89 -0
  1317. package/src/progress/store.ts +353 -0
  1318. package/src/progress/types.ts +59 -0
  1319. package/src/provider-api/actions/custom-provider-registration.ts +197 -0
  1320. package/src/provider-api/actions/delete-staged-dataset.ts +5 -0
  1321. package/src/provider-api/actions/github-repo-files.ts +266 -0
  1322. package/src/provider-api/actions/list-staged-datasets.ts +5 -0
  1323. package/src/provider-api/actions/provider-api-audit.ts +88 -0
  1324. package/src/provider-api/actions/provider-api.ts +460 -0
  1325. package/src/provider-api/actions/query-staged-dataset.ts +5 -0
  1326. package/src/provider-api/actions/staged-datasets.ts +359 -0
  1327. package/src/provider-api/corpus-jobs-store.ts +522 -0
  1328. package/src/provider-api/corpus-jobs.ts +1817 -0
  1329. package/src/provider-api/custom-registry.ts +456 -0
  1330. package/src/provider-api/github-repo.ts +675 -0
  1331. package/src/provider-api/gong.ts +108 -0
  1332. package/src/provider-api/index.ts +5444 -0
  1333. package/src/provider-api/quota-governor.ts +562 -0
  1334. package/src/provider-api/runtime.ts +1 -0
  1335. package/src/provider-api/staged-datasets-aggregate.ts +304 -0
  1336. package/src/provider-api/staged-datasets-store.ts +441 -0
  1337. package/src/provider-api/staging.ts +483 -0
  1338. package/src/resources/agents.ts +65 -0
  1339. package/src/resources/emitter.ts +54 -0
  1340. package/src/resources/handlers.ts +728 -0
  1341. package/src/resources/index.ts +4 -0
  1342. package/src/resources/metadata.ts +252 -0
  1343. package/src/resources/script-helpers.ts +160 -0
  1344. package/src/resources/store.ts +1618 -0
  1345. package/src/review/actions/consume-review-feedback.ts +48 -0
  1346. package/src/review/actions/create-review-comment.ts +108 -0
  1347. package/src/review/actions/delete-review-comment.ts +67 -0
  1348. package/src/review/actions/get-review-feedback.ts +49 -0
  1349. package/src/review/actions/list-review-comments.ts +87 -0
  1350. package/src/review/actions/reply-review-comment.ts +118 -0
  1351. package/src/review/actions/resolve-review-thread.ts +94 -0
  1352. package/src/review/actions/send-review-thread-to-agent.ts +62 -0
  1353. package/src/review/actions/set-review-status.ts +58 -0
  1354. package/src/review/identity.ts +101 -0
  1355. package/src/review/index.ts +45 -0
  1356. package/src/review/mentions.ts +44 -0
  1357. package/src/review/registry.ts +111 -0
  1358. package/src/review/store.ts +997 -0
  1359. package/src/review/types.ts +101 -0
  1360. package/src/router/index.ts +24 -0
  1361. package/src/scripts/agent-engines/list-agent-engines.ts +130 -0
  1362. package/src/scripts/agent-engines/manage-agent-engine.ts +197 -0
  1363. package/src/scripts/agent-engines/set-agent-engine.ts +84 -0
  1364. package/src/scripts/agent-engines/test-agent-engine.ts +174 -0
  1365. package/src/scripts/call-agent.ts +792 -0
  1366. package/src/scripts/chat/index.ts +8 -0
  1367. package/src/scripts/chat/open-chat.ts +56 -0
  1368. package/src/scripts/chat/search-chats.ts +121 -0
  1369. package/src/scripts/core-scripts.ts +22 -0
  1370. package/src/scripts/db/check-scoping.ts +212 -0
  1371. package/src/scripts/db/exec.ts +791 -0
  1372. package/src/scripts/db/index.ts +19 -0
  1373. package/src/scripts/db/migrate-encrypt-credentials.ts +223 -0
  1374. package/src/scripts/db/migrate-encrypt-oauth-tokens.ts +213 -0
  1375. package/src/scripts/db/migrate-user-api-keys.ts +257 -0
  1376. package/src/scripts/db/patch.ts +820 -0
  1377. package/src/scripts/db/query.ts +299 -0
  1378. package/src/scripts/db/reset-dev-owner.ts +285 -0
  1379. package/src/scripts/db/safety.ts +286 -0
  1380. package/src/scripts/db/schema.ts +364 -0
  1381. package/src/scripts/db/scoping.ts +341 -0
  1382. package/src/scripts/db/sqlite-client.ts +78 -0
  1383. package/src/scripts/db/tool-mode.ts +23 -0
  1384. package/src/scripts/db/tool-schemas.ts +31 -0
  1385. package/src/scripts/db/wipe-leaked-builder-keys.ts +201 -0
  1386. package/src/scripts/dev/index.ts +296 -0
  1387. package/src/scripts/dev/list-files.ts +119 -0
  1388. package/src/scripts/dev/read-file.ts +77 -0
  1389. package/src/scripts/dev/search-files.ts +151 -0
  1390. package/src/scripts/dev/shell.ts +111 -0
  1391. package/src/scripts/dev/write-file.ts +56 -0
  1392. package/src/scripts/dev-session.ts +96 -0
  1393. package/src/scripts/docs/index.ts +8 -0
  1394. package/src/scripts/docs/search.ts +274 -0
  1395. package/src/scripts/docs/source-search.ts +363 -0
  1396. package/src/scripts/index.ts +15 -0
  1397. package/src/scripts/manage-agent-loop-settings.ts +84 -0
  1398. package/src/scripts/parse-args.ts +46 -0
  1399. package/src/scripts/resources/delete-memory.ts +67 -0
  1400. package/src/scripts/resources/delete.ts +69 -0
  1401. package/src/scripts/resources/effective.ts +71 -0
  1402. package/src/scripts/resources/index.ts +18 -0
  1403. package/src/scripts/resources/list.ts +103 -0
  1404. package/src/scripts/resources/migrate-learnings.ts +40 -0
  1405. package/src/scripts/resources/read.ts +107 -0
  1406. package/src/scripts/resources/save-memory.ts +99 -0
  1407. package/src/scripts/resources/write.ts +158 -0
  1408. package/src/scripts/runner.ts +339 -0
  1409. package/src/scripts/utils.ts +130 -0
  1410. package/src/search/index.ts +413 -0
  1411. package/src/search-utils/index.ts +112 -0
  1412. package/src/secrets/crypto.ts +228 -0
  1413. package/src/secrets/index.ts +65 -0
  1414. package/src/secrets/onboarding.ts +101 -0
  1415. package/src/secrets/register-framework-secrets.ts +228 -0
  1416. package/src/secrets/register.ts +129 -0
  1417. package/src/secrets/routes.ts +697 -0
  1418. package/src/secrets/schema.ts +52 -0
  1419. package/src/secrets/storage.ts +561 -0
  1420. package/src/secrets/substitution.ts +305 -0
  1421. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +150 -0
  1422. package/src/server/action-change.ts +66 -0
  1423. package/src/server/action-discovery.ts +774 -0
  1424. package/src/server/action-routes.ts +658 -0
  1425. package/src/server/agent-access.ts +72 -0
  1426. package/src/server/agent-chat/action-filters-a2a.ts +339 -0
  1427. package/src/server/agent-chat/browser-team-tools.ts +510 -0
  1428. package/src/server/agent-chat/context-tools.ts +599 -0
  1429. package/src/server/agent-chat/framework-prompts.ts +467 -0
  1430. package/src/server/agent-chat/lazy-fs.ts +11 -0
  1431. package/src/server/agent-chat/mcp-glue.ts +91 -0
  1432. package/src/server/agent-chat/plugin-options.ts +379 -0
  1433. package/src/server/agent-chat/process-run-failure.ts +62 -0
  1434. package/src/server/agent-chat/prompt-resources.ts +1004 -0
  1435. package/src/server/agent-chat/recurring-jobs-runtime.ts +80 -0
  1436. package/src/server/agent-chat/request-surface.ts +71 -0
  1437. package/src/server/agent-chat/run-code-tools.ts +67 -0
  1438. package/src/server/agent-chat/script-entries.ts +796 -0
  1439. package/src/server/agent-chat/shared-thread.ts +301 -0
  1440. package/src/server/agent-chat/skill-frontmatter.ts +41 -0
  1441. package/src/server/agent-chat-plugin.ts +5930 -0
  1442. package/src/server/agent-discovery.ts +706 -0
  1443. package/src/server/agent-engine-api-key-route.ts +236 -0
  1444. package/src/server/agent-run-context.ts +204 -0
  1445. package/src/server/agent-teams-run-queue.ts +344 -0
  1446. package/src/server/agent-teams.ts +2257 -0
  1447. package/src/server/agents-bundle.ts +464 -0
  1448. package/src/server/analytics.ts +105 -0
  1449. package/src/server/app-base-path.ts +79 -0
  1450. package/src/server/app-name.ts +53 -0
  1451. package/src/server/app-url.ts +184 -0
  1452. package/src/server/attachment-actions.ts +276 -0
  1453. package/src/server/attribution.ts +214 -0
  1454. package/src/server/auth-marketing.ts +260 -0
  1455. package/src/server/auth-plugin.ts +32 -0
  1456. package/src/server/auth.ts +3803 -0
  1457. package/src/server/better-auth-instance.ts +1201 -0
  1458. package/src/server/builder-browser.ts +1701 -0
  1459. package/src/server/builder-design-systems.ts +668 -0
  1460. package/src/server/builder-space.ts +176 -0
  1461. package/src/server/captcha.ts +63 -0
  1462. package/src/server/capture-error.ts +64 -0
  1463. package/src/server/cli-capture.ts +141 -0
  1464. package/src/server/collab-plugin.ts +391 -0
  1465. package/src/server/complete-text.ts +231 -0
  1466. package/src/server/cookie-namespace.ts +159 -0
  1467. package/src/server/core-routes-plugin.ts +4122 -0
  1468. package/src/server/cors-origins.ts +60 -0
  1469. package/src/server/create-server.ts +268 -0
  1470. package/src/server/credential-provider.ts +1202 -0
  1471. package/src/server/csrf.ts +229 -0
  1472. package/src/server/date-utils.ts +42 -0
  1473. package/src/server/deep-link.ts +119 -0
  1474. package/src/server/derived-secret.ts +32 -0
  1475. package/src/server/design-token-utils.ts +1032 -0
  1476. package/src/server/desktop-sso.ts +83 -0
  1477. package/src/server/edge.ts +69 -0
  1478. package/src/server/email-actions.ts +218 -0
  1479. package/src/server/email-template.ts +192 -0
  1480. package/src/server/email-templates.ts +148 -0
  1481. package/src/server/email.ts +219 -0
  1482. package/src/server/embed-route.ts +283 -0
  1483. package/src/server/embed-session.ts +805 -0
  1484. package/src/server/embedded.ts +252 -0
  1485. package/src/server/entry-server.tsx +154 -0
  1486. package/src/server/framework-request-handler.ts +848 -0
  1487. package/src/server/fusion-app.ts +447 -0
  1488. package/src/server/google-auth-mode.ts +34 -0
  1489. package/src/server/google-auth-plugin.ts +496 -0
  1490. package/src/server/google-oauth-credentials.ts +128 -0
  1491. package/src/server/google-oauth.ts +972 -0
  1492. package/src/server/google-realtime-session.ts +182 -0
  1493. package/src/server/h3-helpers.ts +174 -0
  1494. package/src/server/http-response-telemetry.ts +396 -0
  1495. package/src/server/identity-sso-store.ts +304 -0
  1496. package/src/server/identity-sso.ts +514 -0
  1497. package/src/server/index.ts +593 -0
  1498. package/src/server/missing-key.ts +36 -0
  1499. package/src/server/oauth-helpers.ts +44 -0
  1500. package/src/server/oauth-public-origin.ts +44 -0
  1501. package/src/server/oauth-return-url.ts +120 -0
  1502. package/src/server/og-fonts-data.ts +15 -0
  1503. package/src/server/og-fonts.ts +75 -0
  1504. package/src/server/onboarding-html.ts +4040 -0
  1505. package/src/server/open-route.ts +311 -0
  1506. package/src/server/org-admin.ts +28 -0
  1507. package/src/server/poll-events.ts +88 -0
  1508. package/src/server/poll.ts +1224 -0
  1509. package/src/server/prompts/framework-core-compact.ts +107 -0
  1510. package/src/server/prompts/framework-core.ts +143 -0
  1511. package/src/server/prompts/index.ts +16 -0
  1512. package/src/server/prompts/model-overlays.ts +54 -0
  1513. package/src/server/prompts/shared-rules.ts +104 -0
  1514. package/src/server/realtime-voice.ts +967 -0
  1515. package/src/server/recap-image-route.ts +242 -0
  1516. package/src/server/recap-image-store.ts +185 -0
  1517. package/src/server/request-context.ts +416 -0
  1518. package/src/server/request-origin.ts +67 -0
  1519. package/src/server/resources-plugin.ts +119 -0
  1520. package/src/server/schema-prompt.ts +429 -0
  1521. package/src/server/scoped-key-storage.ts +223 -0
  1522. package/src/server/security-headers.ts +170 -0
  1523. package/src/server/self-dispatch.ts +224 -0
  1524. package/src/server/sentry-config.ts +73 -0
  1525. package/src/server/sentry-plugin.ts +138 -0
  1526. package/src/server/sentry.ts +444 -0
  1527. package/src/server/short-lived-token.ts +170 -0
  1528. package/src/server/social-og-image.ts +454 -0
  1529. package/src/server/sse.ts +102 -0
  1530. package/src/server/ssr-handler.ts +466 -0
  1531. package/src/server/transcribe-voice.ts +1076 -0
  1532. package/src/server/voice-providers-status.ts +118 -0
  1533. package/src/server/workspace-oauth.ts +31 -0
  1534. package/src/server/workspace-provider-oauth.ts +970 -0
  1535. package/src/session-replay-iframe-protocol.ts +58 -0
  1536. package/src/settings/handlers.ts +44 -0
  1537. package/src/settings/index.ts +34 -0
  1538. package/src/settings/org-settings.ts +83 -0
  1539. package/src/settings/script-helpers.ts +24 -0
  1540. package/src/settings/store.ts +247 -0
  1541. package/src/settings/user-settings.ts +47 -0
  1542. package/src/setup-connections/index.ts +90 -0
  1543. package/src/setup-connections/onboarding.ts +47 -0
  1544. package/src/shared/agent-access.ts +112 -0
  1545. package/src/shared/agent-chat.ts +124 -0
  1546. package/src/shared/agent-env.ts +46 -0
  1547. package/src/shared/agent-readable-resource.ts +111 -0
  1548. package/src/shared/agent-sidebar-url.ts +39 -0
  1549. package/src/shared/cache-control.ts +25 -0
  1550. package/src/shared/cloudflare-globals.d.ts +34 -0
  1551. package/src/shared/context-xray.ts +172 -0
  1552. package/src/shared/embed-auth.ts +6 -0
  1553. package/src/shared/index.ts +83 -0
  1554. package/src/shared/llm-connection.ts +42 -0
  1555. package/src/shared/markdown-block-split.ts +129 -0
  1556. package/src/shared/mcp-connect-content.ts +130 -0
  1557. package/src/shared/mcp-embed-headers.ts +175 -0
  1558. package/src/shared/mcp-integration-config.ts +101 -0
  1559. package/src/shared/merge-by-id.ts +14 -0
  1560. package/src/shared/oauth-state.ts +39 -0
  1561. package/src/shared/reasoning-effort.ts +228 -0
  1562. package/src/shared/route-warmup-config.ts +128 -0
  1563. package/src/shared/runtime.ts +31 -0
  1564. package/src/shared/social-meta.ts +82 -0
  1565. package/src/shared/streaming-text-smoothing.ts +184 -0
  1566. package/src/shared/truncate.ts +13 -0
  1567. package/src/shared/workspace-app-audience.ts +177 -0
  1568. package/src/shared/workspace-app-id.ts +54 -0
  1569. package/src/sharing/access.ts +585 -0
  1570. package/src/sharing/actions/create-agent-resource-link.ts +91 -0
  1571. package/src/sharing/actions/extension-change.ts +22 -0
  1572. package/src/sharing/actions/list-resource-shares.ts +93 -0
  1573. package/src/sharing/actions/set-resource-visibility.ts +91 -0
  1574. package/src/sharing/actions/share-resource.ts +322 -0
  1575. package/src/sharing/actions/unshare-resource.ts +72 -0
  1576. package/src/sharing/index.ts +35 -0
  1577. package/src/sharing/registry.ts +201 -0
  1578. package/src/sharing/schema.ts +99 -0
  1579. package/src/styles/agent-conversation.css +766 -0
  1580. package/src/styles/agent-native.css +938 -0
  1581. package/src/styles/blocks.css +1717 -0
  1582. package/src/styles/chat-history-list.css +1 -0
  1583. package/src/styles/rich-markdown-editor.css +1 -0
  1584. package/src/tailwind.preset.ts +140 -0
  1585. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1586. package/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1587. package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +9 -6
  1588. package/src/templates/chat/AGENTS.md +3 -2
  1589. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1590. package/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1591. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +9 -6
  1592. package/src/templates/default/AGENTS.md +6 -5
  1593. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1594. package/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1595. package/src/templates/headless/AGENTS.md +5 -4
  1596. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1597. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +3 -2
  1598. package/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1599. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +9 -6
  1600. package/src/templates/workspace-core/AGENTS.md +4 -4
  1601. package/src/templates/workspace-root/AGENTS.md +4 -4
  1602. package/src/terminal/cli-registry.ts +57 -0
  1603. package/src/terminal/index.ts +22 -0
  1604. package/src/terminal/pty-server.ts +389 -0
  1605. package/src/terminal/terminal-plugin.ts +265 -0
  1606. package/src/testing.ts +23 -0
  1607. package/src/tracking/index.ts +10 -0
  1608. package/src/tracking/providers.ts +422 -0
  1609. package/src/tracking/registry.ts +102 -0
  1610. package/src/tracking/route.ts +108 -0
  1611. package/src/tracking/types.ts +16 -0
  1612. package/src/transcription/builder-transcription.ts +118 -0
  1613. package/src/triggers/actions/list-automations.ts +99 -0
  1614. package/src/triggers/actions/manage-automation.ts +78 -0
  1615. package/src/triggers/actions.ts +333 -0
  1616. package/src/triggers/condition-evaluator.ts +163 -0
  1617. package/src/triggers/dispatcher.ts +536 -0
  1618. package/src/triggers/index.ts +13 -0
  1619. package/src/triggers/routes.ts +322 -0
  1620. package/src/triggers/types.ts +42 -0
  1621. package/src/types/pglite.d.ts +26 -0
  1622. package/src/usage/store.ts +698 -0
  1623. package/src/vite/action-types-plugin.ts +481 -0
  1624. package/src/vite/agent-web-plugin.ts +78 -0
  1625. package/src/vite/agents-bundle-plugin.ts +185 -0
  1626. package/src/vite/client.ts +3056 -0
  1627. package/src/vite/index.ts +21 -0
  1628. package/src/voice/index.ts +18 -0
  1629. package/src/voice/voice-cleanup-prompt.ts +38 -0
  1630. package/src/voice/voice-context.ts +217 -0
  1631. package/src/voice/voice-replacements.ts +75 -0
  1632. package/src/workspace-connections/credentials.ts +603 -0
  1633. package/src/workspace-connections/index.ts +72 -0
  1634. package/src/workspace-connections/lifecycle.ts +43 -0
  1635. package/src/workspace-connections/store.ts +1943 -0
  1636. package/src/workspace-files/index.ts +18 -0
  1637. package/src/workspace-files/store.ts +339 -0
  1638. package/src/workspace-files/tool.ts +266 -0
@@ -0,0 +1,2576 @@
1
+ import { IconPlus, IconHistory, IconX } from "@tabler/icons-react";
2
+ import React, { useState, useRef, useEffect, useCallback } from "react";
3
+
4
+ import { DEFAULT_MODEL } from "../agent/default-model.js";
5
+ import {
6
+ DEFAULT_REASONING_EFFORT,
7
+ isReasoningEffort,
8
+ resolveReasoningEffortSelection,
9
+ type ReasoningEffort,
10
+ } from "../shared/reasoning-effort.js";
11
+ import {
12
+ AGENT_CHAT_CLEAR_CONTEXT_MESSAGE_TYPE,
13
+ AGENT_CHAT_REMOVE_CONTEXT_MESSAGE_TYPE,
14
+ AGENT_CHAT_SET_CONTEXT_MESSAGE_TYPE,
15
+ appendAgentChatContextToMessage,
16
+ claimAgentChatOpenRequest,
17
+ claimAgentChatSubmit,
18
+ drainBufferedAgentChatOpenRequests,
19
+ drainBufferedAgentChatSubmits,
20
+ getAgentChatContextState,
21
+ isAgentChatSubmitCancelled,
22
+ normalizeAgentChatContextItem,
23
+ parseSubmitChatMessage,
24
+ removeAgentChatContextItem,
25
+ reportAgentChatSubmitResult,
26
+ setAgentChatContextItem,
27
+ type AgentChatContextItem,
28
+ } from "./agent-chat.js";
29
+ import { agentNativePath, appPath } from "./api-path.js";
30
+ import {
31
+ AssistantChat,
32
+ type AssistantChatProps,
33
+ type AssistantChatHandle,
34
+ } from "./AssistantChat.js";
35
+ import {
36
+ buildChatModelGroups,
37
+ type EngineModelGroup,
38
+ } from "./chat-model-groups.js";
39
+ import {
40
+ ChatHistoryList,
41
+ type ChatHistoryItem,
42
+ type ChatHistorySection,
43
+ } from "./chat/ChatHistoryList.js";
44
+ import {
45
+ Popover,
46
+ PopoverAnchor,
47
+ PopoverContent,
48
+ } from "./components/ui/popover.js";
49
+ import {
50
+ Tooltip,
51
+ TooltipContent,
52
+ TooltipProvider,
53
+ TooltipTrigger,
54
+ } from "./components/ui/tooltip.js";
55
+ import { isTrustedFrameMessage } from "./frame.js";
56
+ import { KeepTabOpenNotice } from "./KeepTabOpenNotice.js";
57
+ import { RunStuckBanner } from "./RunStuckBanner.js";
58
+ import { callAction } from "./use-action.js";
59
+ import { useChangeVersion } from "./use-change-version.js";
60
+ import {
61
+ useChatThreads,
62
+ type ChatThreadScope,
63
+ type ChatThreadSummary,
64
+ } from "./use-chat-threads.js";
65
+ import { cn } from "./utils.js";
66
+
67
+ interface ModelSelection {
68
+ model: string;
69
+ engine?: string;
70
+ effort?: ReasoningEffort;
71
+ }
72
+
73
+ interface PendingSend {
74
+ message: string;
75
+ images?: string[];
76
+ submit: boolean;
77
+ trackInRunsTray?: boolean;
78
+ requestMode?: "act" | "plan";
79
+ /** Correlates with `AGENT_CHAT_SUBMIT_RESULT_EVENT` — see agent-chat.ts. */
80
+ submitMessageId?: string;
81
+ }
82
+
83
+ /**
84
+ * A send queued until its target thread is ready. `threadId: null` targets the
85
+ * first thread to become active (cold start); a concrete id is a thread whose
86
+ * chat ref hasn't mounted yet. Drained by the flush effect.
87
+ */
88
+ interface PendingDelivery {
89
+ threadId: string | null;
90
+ send: PendingSend;
91
+ }
92
+
93
+ /** The single path that hands a queued send to a mounted chat ref. */
94
+ function deliverPendingSend(ref: AssistantChatHandle, send: PendingSend): void {
95
+ if (isAgentChatSubmitCancelled(send.submitMessageId)) return;
96
+ if (!send.submit) {
97
+ ref.prefillMessage(send.message);
98
+ return;
99
+ }
100
+ if (send.trackInRunsTray || send.requestMode || send.submitMessageId) {
101
+ ref.sendMessage(send.message, send.images, {
102
+ ...(send.trackInRunsTray ? { trackInRunsTray: true } : {}),
103
+ ...(send.requestMode ? { requestMode: send.requestMode } : {}),
104
+ ...(send.submitMessageId
105
+ ? { submitMessageId: send.submitMessageId }
106
+ : {}),
107
+ });
108
+ } else {
109
+ ref.sendMessage(send.message, send.images);
110
+ }
111
+ }
112
+
113
+ const MODEL_SELECTION_STORAGE_KEY = "agent-native:chat-models:selection";
114
+
115
+ function readStoredModelSelection(key: string): ModelSelection | undefined {
116
+ if (typeof window === "undefined") return undefined;
117
+ try {
118
+ const raw = window.localStorage.getItem(key);
119
+ if (!raw) return undefined;
120
+ const parsed = JSON.parse(raw) as Partial<ModelSelection>;
121
+ if (typeof parsed.model !== "string" || !parsed.model.trim()) {
122
+ return undefined;
123
+ }
124
+ const selection: ModelSelection = {
125
+ model: parsed.model,
126
+ effort: resolveReasoningEffortSelection(
127
+ parsed.model,
128
+ isReasoningEffort(parsed.effort) ? parsed.effort : undefined,
129
+ ),
130
+ };
131
+ if (typeof parsed.engine === "string") selection.engine = parsed.engine;
132
+ return selection;
133
+ } catch {
134
+ return undefined;
135
+ }
136
+ }
137
+
138
+ function writeStoredModelSelection(key: string, selection: ModelSelection) {
139
+ if (typeof window === "undefined") return;
140
+ try {
141
+ window.localStorage.setItem(key, JSON.stringify(selection));
142
+ } catch {}
143
+ }
144
+
145
+ function resolveModelSelection(
146
+ selection: ModelSelection | undefined,
147
+ groups: EngineModelGroup[],
148
+ ): ModelSelection | undefined {
149
+ if (!selection?.model) return undefined;
150
+ if (groups.length === 0) {
151
+ return {
152
+ model: selection.model,
153
+ effort: resolveReasoningEffortSelection(
154
+ selection.model,
155
+ selection.effort,
156
+ ),
157
+ };
158
+ }
159
+ const preferredGroup = groups.find(
160
+ (group) =>
161
+ group.engine === selection.engine &&
162
+ group.models.includes(selection.model),
163
+ );
164
+ const fallbackGroup = groups.find((group) =>
165
+ group.models.includes(selection.model),
166
+ );
167
+ if (groups.length > 0 && !preferredGroup && !fallbackGroup) {
168
+ return undefined;
169
+ }
170
+ const engine =
171
+ preferredGroup?.engine ?? fallbackGroup?.engine ?? selection.engine;
172
+ if (!engine && groups.length > 0) return undefined;
173
+
174
+ const effort = resolveReasoningEffortSelection(
175
+ selection.model,
176
+ selection.effort,
177
+ );
178
+ const resolved: ModelSelection = { model: selection.model, effort };
179
+ if (engine) resolved.engine = engine;
180
+ return resolved;
181
+ }
182
+
183
+ // ─── Skeleton Loader ─────────────────────────────────────────────────────────
184
+
185
+ function ChatSkeleton({
186
+ header,
187
+ headerOnly = false,
188
+ }: {
189
+ header?: React.ReactNode;
190
+ headerOnly?: boolean;
191
+ }) {
192
+ return (
193
+ <div
194
+ className={cn(
195
+ "flex flex-col min-h-0",
196
+ headerOnly ? "shrink-0" : "flex-1 h-full",
197
+ )}
198
+ >
199
+ {header ?? (
200
+ <div className="flex items-center px-1 py-1 border-b border-border shrink-0 gap-0.5">
201
+ <div className="h-[22px] w-20 rounded-md bg-muted animate-pulse" />
202
+ <div className="ms-auto flex gap-0.5">
203
+ <div className="h-[22px] w-[22px] rounded-md bg-muted animate-pulse" />
204
+ <div className="h-[22px] w-[22px] rounded-md bg-muted animate-pulse" />
205
+ </div>
206
+ </div>
207
+ )}
208
+ {!headerOnly && (
209
+ <div className="flex-1 flex flex-col gap-3 p-4">
210
+ <div className="flex justify-center py-8">
211
+ <div className="h-10 w-10 rounded-full bg-muted animate-pulse" />
212
+ </div>
213
+ <div className="h-3 w-32 rounded bg-muted animate-pulse mx-auto" />
214
+ </div>
215
+ )}
216
+ </div>
217
+ );
218
+ }
219
+
220
+ // ─── Resource context ────────────────────────────────────────────────────────
221
+
222
+ function formatScopeType(type: string) {
223
+ return type.replace(/[-_]+/g, " ");
224
+ }
225
+
226
+ // ─── History Popover ─────────────────────────────────────────────────────────
227
+
228
+ function formatThreadTime(ts: number): string {
229
+ const d = new Date(ts);
230
+ const now = new Date();
231
+ const diffMs = now.getTime() - d.getTime();
232
+ const diffDays = Math.floor(diffMs / 86400000);
233
+ if (diffDays === 0)
234
+ return d.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
235
+ if (diffDays === 1) return "Yesterday";
236
+ if (diffDays < 7) return d.toLocaleDateString([], { weekday: "short" });
237
+ return d.toLocaleDateString([], { month: "short", day: "numeric" });
238
+ }
239
+
240
+ function HistoryPopover({
241
+ threads,
242
+ openTabIds,
243
+ activeThreadId,
244
+ hasMoreThreads = false,
245
+ isLoadingMoreThreads = false,
246
+ loadError,
247
+ onSelect,
248
+ onClose,
249
+ onLoadMore,
250
+ onSearch,
251
+ onTogglePin,
252
+ onRename,
253
+ }: {
254
+ threads: ChatThreadSummary[];
255
+ openTabIds: Set<string>;
256
+ activeThreadId: string | null;
257
+ hasMoreThreads?: boolean;
258
+ isLoadingMoreThreads?: boolean;
259
+ loadError?: string | null;
260
+ onSelect: (id: string) => void;
261
+ onClose: () => void;
262
+ onLoadMore?: () => void;
263
+ onSearch?: (query: string) => Promise<ChatThreadSummary[]>;
264
+ /** Presence enables the pin/unpin row action. Receives the thread's
265
+ * current pinned state so the caller can flip it. */
266
+ onTogglePin?: (id: string, pinned: boolean) => void;
267
+ /** Presence enables the inline rename row action. */
268
+ onRename?: (id: string, nextTitle: string) => void;
269
+ }) {
270
+ const [search, setSearch] = useState("");
271
+ const [searchResults, setSearchResults] = useState<
272
+ ChatThreadSummary[] | null
273
+ >(null);
274
+ const [isSearching, setIsSearching] = useState(false);
275
+ const inputRef = useRef<HTMLInputElement>(null);
276
+ const debounceRef = useRef<ReturnType<typeof setTimeout>>(undefined);
277
+
278
+ useEffect(() => {
279
+ inputRef.current?.focus();
280
+ }, []);
281
+
282
+ // Debounced server-side search
283
+ const searchIdRef = useRef(0);
284
+ useEffect(() => {
285
+ if (debounceRef.current) clearTimeout(debounceRef.current);
286
+ const q = search.trim();
287
+ if (!q) {
288
+ searchIdRef.current++;
289
+ setSearchResults(null);
290
+ setIsSearching(false);
291
+ return;
292
+ }
293
+ setIsSearching(true);
294
+ const id = ++searchIdRef.current;
295
+ debounceRef.current = setTimeout(async () => {
296
+ if (onSearch) {
297
+ const results = await onSearch(q);
298
+ if (id !== searchIdRef.current) return;
299
+ setSearchResults(results);
300
+ } else {
301
+ // Fallback to client-side filtering
302
+ setSearchResults(null);
303
+ }
304
+ setIsSearching(false);
305
+ }, 250);
306
+ return () => {
307
+ if (debounceRef.current) clearTimeout(debounceRef.current);
308
+ };
309
+ }, [search, onSearch]);
310
+
311
+ // Hide empty threads from the history list — except the currently-active
312
+ // one. The active thread always belongs in the list so the user can see
313
+ // they're in it (the previous filter dropped a brand-new chat the user
314
+ // had just opened, making them think their chat had vanished).
315
+ const visibleThreads = threads.filter(
316
+ (t) => t.messageCount > 0 || t.id === activeThreadId,
317
+ );
318
+
319
+ const filtered = search.trim()
320
+ ? (searchResults ?? visibleThreads).filter(
321
+ (t) => t.messageCount > 0 || t.id === activeThreadId,
322
+ )
323
+ : visibleThreads;
324
+
325
+ // Pinned threads always float to the top of `threads` already (see
326
+ // `sortThreadSummaries` in use-chat-threads.ts and the matching server
327
+ // ORDER BY), but pulling them into their own labeled section — instead of
328
+ // just relying on sort order within "All chats" — makes the pin affordance
329
+ // visible at a glance, matching common chat-history UX.
330
+ const pinnedThreads = filtered.filter((t) => t.pinnedAt != null);
331
+ const unpinnedThreads = filtered.filter((t) => t.pinnedAt == null);
332
+
333
+ const toHistoryItem = (thread: ChatThreadSummary): ChatHistoryItem => {
334
+ const isActive = thread.id === activeThreadId;
335
+ const title = thread.title || thread.preview || "Chat";
336
+ return {
337
+ id: thread.id,
338
+ title,
339
+ titleText: title,
340
+ subtitle:
341
+ thread.preview && thread.title !== thread.preview
342
+ ? thread.preview
343
+ : undefined,
344
+ timestamp: isActive
345
+ ? "Active"
346
+ : openTabIds.has(thread.id)
347
+ ? "Open"
348
+ : formatThreadTime(thread.updatedAt),
349
+ pinned: thread.pinnedAt != null,
350
+ };
351
+ };
352
+
353
+ const historySections: ChatHistorySection[] = [
354
+ ...(pinnedThreads.length > 0
355
+ ? [
356
+ {
357
+ id: "pinned",
358
+ label: "Pinned",
359
+ items: pinnedThreads.map(toHistoryItem),
360
+ },
361
+ ]
362
+ : []),
363
+ { id: "all", items: unpinnedThreads.map(toHistoryItem) },
364
+ ];
365
+
366
+ return (
367
+ <Popover open onOpenChange={(open) => !open && onClose()}>
368
+ <PopoverAnchor asChild>
369
+ <span aria-hidden className="absolute end-2 top-0 h-px w-px" />
370
+ </PopoverAnchor>
371
+ <PopoverContent
372
+ align="end"
373
+ side="bottom"
374
+ sideOffset={0}
375
+ onOpenAutoFocus={(event) => {
376
+ event.preventDefault();
377
+ inputRef.current?.focus();
378
+ }}
379
+ className="w-72 rounded-lg p-0"
380
+ >
381
+ <ChatHistoryList
382
+ sections={historySections}
383
+ activeId={activeThreadId}
384
+ onSelect={(id) => {
385
+ onSelect(id);
386
+ onClose();
387
+ }}
388
+ onTogglePin={
389
+ onTogglePin
390
+ ? (id) => {
391
+ const isPinned =
392
+ threads.find((t) => t.id === id)?.pinnedAt != null;
393
+ onTogglePin(id, !isPinned);
394
+ }
395
+ : undefined
396
+ }
397
+ onRename={onRename}
398
+ searchValue={search}
399
+ onSearchChange={setSearch}
400
+ searchPlaceholder="Search chats..."
401
+ searchInputRef={inputRef}
402
+ loading={isSearching}
403
+ loadingLabel="Searching..."
404
+ error={loadError && !search.trim() ? loadError : undefined}
405
+ emptyLabel="No chats yet"
406
+ emptySearchLabel="No matching chats"
407
+ footer={
408
+ !search.trim() && hasMoreThreads ? (
409
+ <button
410
+ type="button"
411
+ onClick={() => onLoadMore?.()}
412
+ disabled={isLoadingMoreThreads}
413
+ className="mx-1 mt-1 flex w-[calc(100%-0.5rem)] items-center justify-center rounded-md px-3 py-2 text-xs text-muted-foreground hover:bg-accent hover:text-foreground disabled:cursor-default disabled:opacity-60"
414
+ >
415
+ {isLoadingMoreThreads ? "Loading..." : "Load older chats"}
416
+ </button>
417
+ ) : undefined
418
+ }
419
+ />
420
+ </PopoverContent>
421
+ </Popover>
422
+ );
423
+ }
424
+
425
+ // ─── Help Popover ────────────────────────────────────────────────────────────
426
+
427
+ function HelpPopover({ onClose }: { onClose: () => void }) {
428
+ useEffect(() => {
429
+ const handler = (e: KeyboardEvent) => {
430
+ if (e.key === "Escape") onClose();
431
+ };
432
+ window.addEventListener("keydown", handler);
433
+ return () => window.removeEventListener("keydown", handler);
434
+ }, [onClose]);
435
+
436
+ const commands = [
437
+ {
438
+ name: "/clear",
439
+ description: "Start a new chat (keeps current chat in history)",
440
+ },
441
+ { name: "/new", description: "Same as /clear" },
442
+ { name: "/history", description: "Browse all chats" },
443
+ { name: "/plan", description: "Switch to read-only planning" },
444
+ { name: "/act", description: "Switch back to acting" },
445
+ { name: "/help", description: "Show this list of commands" },
446
+ { name: "@", description: "Mention files, agents, or resources" },
447
+ ];
448
+
449
+ return (
450
+ <>
451
+ <div className="fixed inset-0 z-40" onClick={onClose} />
452
+ <div className="absolute end-2 top-0 z-50 w-72 rounded-lg border border-border bg-popover shadow-lg">
453
+ <div className="flex items-center justify-between px-3 py-2 border-b border-border">
454
+ <span className="text-xs font-medium text-foreground">
455
+ Available Commands
456
+ </span>
457
+ <button
458
+ onClick={onClose}
459
+ aria-label="Close help"
460
+ className="flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:text-foreground"
461
+ >
462
+ <IconX size={12} />
463
+ </button>
464
+ </div>
465
+ <div className="py-1">
466
+ {commands.map((cmd) => (
467
+ <div key={cmd.name} className="px-3 py-1.5">
468
+ <div className="text-xs font-medium text-foreground">
469
+ {cmd.name}
470
+ </div>
471
+ <div className="text-[11px] text-muted-foreground">
472
+ {cmd.description}
473
+ </div>
474
+ </div>
475
+ ))}
476
+ </div>
477
+ </div>
478
+ </>
479
+ );
480
+ }
481
+
482
+ // ─── Types ──────────────────────────────────────────────────────────────────
483
+
484
+ export interface ChatTab {
485
+ id: string;
486
+ label: string;
487
+ status: "idle" | "running" | "completed";
488
+ /** If this tab is a sub-agent, the parent thread ID */
489
+ parentThreadId?: string;
490
+ /** Short name for sub-agent tabs (e.g. "Research", "Draft email") */
491
+ subAgentName?: string;
492
+ }
493
+
494
+ type AgentTeamRunStatus =
495
+ | "queued"
496
+ | "running"
497
+ | "paused"
498
+ | "needs-approval"
499
+ | "completed"
500
+ | "errored"
501
+ | "unknown";
502
+
503
+ interface AgentTeamRunSummary {
504
+ title?: string;
505
+ status?: AgentTeamRunStatus;
506
+ sourceRecord?: {
507
+ type?: string;
508
+ threadId?: unknown;
509
+ parentThreadId?: unknown;
510
+ name?: unknown;
511
+ };
512
+ metadata?: Record<string, unknown>;
513
+ }
514
+
515
+ interface AgentTeamTabInfo {
516
+ threadId: string;
517
+ parentThreadId: string;
518
+ name: string;
519
+ status: AgentTeamRunStatus;
520
+ }
521
+
522
+ function readString(value: unknown): string {
523
+ return typeof value === "string" ? value.trim() : "";
524
+ }
525
+
526
+ function requestModeFromExecMode(
527
+ value: AssistantChatProps["execMode"],
528
+ ): "act" | "plan" | undefined {
529
+ if (value === "plan") return "plan";
530
+ if (value === "build") return "act";
531
+ return undefined;
532
+ }
533
+
534
+ function isActiveAgentTeamStatus(status?: AgentTeamRunStatus): boolean {
535
+ return (
536
+ status === "queued" ||
537
+ status === "running" ||
538
+ status === "paused" ||
539
+ status === "needs-approval"
540
+ );
541
+ }
542
+
543
+ function chatTabStatusFromAgentTeamStatus(
544
+ status?: AgentTeamRunStatus,
545
+ ): ChatTab["status"] | undefined {
546
+ if (!status) return undefined;
547
+ return isActiveAgentTeamStatus(status) ? "running" : "completed";
548
+ }
549
+
550
+ const STALE_THREAD_THRESHOLD_MS = 12 * 60 * 60 * 1000;
551
+ const DEFAULT_THREAD_URL_PARAM = "thread";
552
+ const THREAD_URL_CHANGED_EVENT = "agent-chat:url-thread-changed";
553
+ const hasOwn = Object.prototype.hasOwnProperty;
554
+
555
+ // The history patch is installed once and shared via a ref count so that
556
+ // multiple synced chats (or a remount) don't restore a stale `pushState`
557
+ // reference and silently drop a wrapper installed by another instance.
558
+ let historyPatchRefCount = 0;
559
+ let restoreHistoryPatch: (() => void) | null = null;
560
+
561
+ function installHistoryThreadUrlPatch(): () => void {
562
+ if (typeof window === "undefined") return () => {};
563
+ historyPatchRefCount += 1;
564
+ if (historyPatchRefCount === 1) {
565
+ const originalPushState = window.history.pushState;
566
+ const originalReplaceState = window.history.replaceState;
567
+ const dispatchUrlChange = () => {
568
+ window.dispatchEvent(new Event(THREAD_URL_CHANGED_EVENT));
569
+ };
570
+ window.history.pushState = function pushState(...args) {
571
+ const result = originalPushState.apply(this, args);
572
+ dispatchUrlChange();
573
+ return result;
574
+ };
575
+ window.history.replaceState = function replaceState(...args) {
576
+ const result = originalReplaceState.apply(this, args);
577
+ dispatchUrlChange();
578
+ return result;
579
+ };
580
+ restoreHistoryPatch = () => {
581
+ window.history.pushState = originalPushState;
582
+ window.history.replaceState = originalReplaceState;
583
+ };
584
+ }
585
+ return () => {
586
+ historyPatchRefCount = Math.max(0, historyPatchRefCount - 1);
587
+ if (historyPatchRefCount === 0) {
588
+ restoreHistoryPatch?.();
589
+ restoreHistoryPatch = null;
590
+ }
591
+ };
592
+ }
593
+
594
+ export interface ChatThreadUrlSyncOptions {
595
+ /** Query-string parameter used by the generic URL adapter. Default: `thread`. */
596
+ paramName?: string;
597
+ /**
598
+ * Route-owned thread id. Pass `null` for the create route and a string for
599
+ * thread routes like `/chat/:threadId`.
600
+ */
601
+ routeThreadId?: string | null;
602
+ /** Build the URL path for a thread id, or for create mode when id is null. */
603
+ getPath?: (threadId: string | null) => string;
604
+ /** Optional router navigation callback used with `getPath`. */
605
+ navigate?: (path: string, options?: { replace?: boolean }) => void;
606
+ }
607
+
608
+ function normalizeUrlThreadId(value: string | null | undefined): string | null {
609
+ if (typeof value !== "string") return null;
610
+ const trimmed = value.trim();
611
+ return trimmed || null;
612
+ }
613
+
614
+ function resolveThreadUrlSync(
615
+ value: MultiTabAssistantChatProps["threadUrlSync"],
616
+ ): {
617
+ enabled: boolean;
618
+ paramName: string;
619
+ routeThreadId?: string | null;
620
+ getPath?: (threadId: string | null) => string;
621
+ navigate?: (path: string, options?: { replace?: boolean }) => void;
622
+ } {
623
+ if (!value) return { enabled: false, paramName: DEFAULT_THREAD_URL_PARAM };
624
+ if (value === true) {
625
+ return { enabled: true, paramName: DEFAULT_THREAD_URL_PARAM };
626
+ }
627
+ return {
628
+ enabled: true,
629
+ paramName: value.paramName?.trim() || DEFAULT_THREAD_URL_PARAM,
630
+ ...(hasOwn.call(value, "routeThreadId")
631
+ ? { routeThreadId: normalizeUrlThreadId(value.routeThreadId) }
632
+ : {}),
633
+ ...(value.getPath ? { getPath: value.getPath } : {}),
634
+ ...(value.navigate ? { navigate: value.navigate } : {}),
635
+ };
636
+ }
637
+
638
+ function readUrlThreadId(paramName: string): string | null {
639
+ if (typeof window === "undefined") return null;
640
+ try {
641
+ const params = new URLSearchParams(window.location.search);
642
+ return normalizeUrlThreadId(
643
+ params.get(paramName) ??
644
+ (paramName === DEFAULT_THREAD_URL_PARAM
645
+ ? params.get("threadId")
646
+ : null),
647
+ );
648
+ } catch {
649
+ return null;
650
+ }
651
+ }
652
+
653
+ function runToAgentTeamTabInfo(
654
+ run: AgentTeamRunSummary,
655
+ ): AgentTeamTabInfo | null {
656
+ if (run.sourceRecord?.type && run.sourceRecord.type !== "agent-team-task") {
657
+ return null;
658
+ }
659
+ const metadata = run.metadata ?? {};
660
+ const threadId =
661
+ readString(run.sourceRecord?.threadId) || readString(metadata.threadId);
662
+ const parentThreadId =
663
+ readString(run.sourceRecord?.parentThreadId) ||
664
+ readString(metadata.parentThreadId);
665
+ if (!threadId || !parentThreadId || threadId === parentThreadId) return null;
666
+ const name =
667
+ readString(run.sourceRecord?.name) ||
668
+ readString(metadata.name) ||
669
+ readString(run.title) ||
670
+ "Sub-agent";
671
+ return {
672
+ threadId,
673
+ parentThreadId,
674
+ name,
675
+ status: run.status ?? "unknown",
676
+ };
677
+ }
678
+
679
+ export interface MultiTabAssistantChatHeaderProps {
680
+ tabs: ChatTab[];
681
+ activeTabId: string;
682
+ activeTabMessageCount: number;
683
+ setActiveTabId: (tabId: string) => void;
684
+ addTab: () => void;
685
+ closeTab: (tabId: string) => void;
686
+ closeOtherTabs: (tabId: string) => void;
687
+ closeAllTabs: () => void;
688
+ clearActiveTab: () => void;
689
+ /** Open the history popover */
690
+ showHistory?: boolean;
691
+ toggleHistory?: () => void;
692
+ /** Number of open tabs (useful for triggering scroll on tab count change) */
693
+ tabCount: number;
694
+ }
695
+
696
+ // ─── Component ──────────────────────────────────────────────────────────────
697
+
698
+ export type MultiTabAssistantChatProps = Omit<
699
+ AssistantChatProps,
700
+ "tabId" | "threadId"
701
+ > & {
702
+ /** Show the tab bar. Default: true */
703
+ showTabBar?: boolean;
704
+ /** Optional custom single-row header renderer */
705
+ renderHeader?: (props: MultiTabAssistantChatHeaderProps) => React.ReactNode;
706
+ /** Optional overlay actions renderer for the active tab */
707
+ renderOverlay?: (props: MultiTabAssistantChatHeaderProps) => React.ReactNode;
708
+ /** Hide the chat content while keeping the header visible. Used when CLI/resources mode is active. */
709
+ contentHidden?: boolean;
710
+ /** Namespace for localStorage keys — used to isolate chat state per app in the frame. */
711
+ storageKey?: string;
712
+ /** Restore the previously active thread and open tabs from localStorage. */
713
+ restoreActiveThread?: boolean;
714
+ /** Stable browser tab id used for tab-scoped app-state context. */
715
+ browserTabId?: string;
716
+ /**
717
+ * Keep the active thread in URL state. `true` uses the generic `?thread=id`
718
+ * adapter; passing `routeThreadId` + `getPath` lets an app bind chats to
719
+ * route params such as `/chat/:threadId`.
720
+ */
721
+ threadUrlSync?: boolean | ChatThreadUrlSyncOptions;
722
+ /** Ambient resource context to show as a composer chip. */
723
+ scope?: ChatThreadScope | null;
724
+ /** @deprecated Scope context is now rendered in the composer. */
725
+ showScopeBadge?: boolean;
726
+ };
727
+
728
+ export function MultiTabAssistantChat({
729
+ showTabBar = true,
730
+ renderHeader,
731
+ renderOverlay,
732
+ contentHidden = false,
733
+ apiUrl = agentNativePath("/_agent-native/agent-chat"),
734
+ storageKey,
735
+ restoreActiveThread = true,
736
+ browserTabId,
737
+ threadUrlSync = false,
738
+ scope = null,
739
+ ...props
740
+ }: MultiTabAssistantChatProps) {
741
+ const {
742
+ enabled: threadUrlSyncEnabled,
743
+ paramName: threadUrlParamName,
744
+ routeThreadId,
745
+ getPath: getThreadPath,
746
+ navigate: navigateThreadUrl,
747
+ } = resolveThreadUrlSync(threadUrlSync);
748
+ const threadRouteControlsActiveThread =
749
+ threadUrlSyncEnabled &&
750
+ threadUrlSync !== true &&
751
+ typeof threadUrlSync === "object" &&
752
+ hasOwn.call(threadUrlSync, "routeThreadId");
753
+ const [urlThreadId, setUrlThreadId] = useState<string | null>(() =>
754
+ threadUrlSyncEnabled
755
+ ? threadRouteControlsActiveThread
756
+ ? (routeThreadId ?? readUrlThreadId(threadUrlParamName))
757
+ : readUrlThreadId(threadUrlParamName)
758
+ : null,
759
+ );
760
+ const [deepLinkedThreadId] = useState<string | null>(() =>
761
+ threadUrlSyncEnabled ? null : readUrlThreadId(DEFAULT_THREAD_URL_PARAM),
762
+ );
763
+ const [activeDeepLinkedThreadId, setActiveDeepLinkedThreadId] =
764
+ useState(deepLinkedThreadId);
765
+ const urlThreadIdRef = useRef(urlThreadId);
766
+ urlThreadIdRef.current = urlThreadId;
767
+
768
+ useEffect(() => {
769
+ if (!threadUrlSyncEnabled || threadRouteControlsActiveThread) return;
770
+ const update = () => setUrlThreadId(readUrlThreadId(threadUrlParamName));
771
+ const uninstallHistoryPatch = installHistoryThreadUrlPatch();
772
+ update();
773
+ window.addEventListener("popstate", update);
774
+ window.addEventListener(THREAD_URL_CHANGED_EVENT, update);
775
+ return () => {
776
+ uninstallHistoryPatch();
777
+ window.removeEventListener("popstate", update);
778
+ window.removeEventListener(THREAD_URL_CHANGED_EVENT, update);
779
+ };
780
+ }, [
781
+ threadRouteControlsActiveThread,
782
+ threadUrlParamName,
783
+ threadUrlSyncEnabled,
784
+ ]);
785
+
786
+ useEffect(() => {
787
+ if (!threadUrlSyncEnabled || !threadRouteControlsActiveThread) return;
788
+ setUrlThreadId(routeThreadId ?? readUrlThreadId(threadUrlParamName));
789
+ }, [
790
+ routeThreadId,
791
+ threadRouteControlsActiveThread,
792
+ threadUrlParamName,
793
+ threadUrlSyncEnabled,
794
+ ]);
795
+
796
+ useEffect(() => {
797
+ if (threadUrlSyncEnabled) return;
798
+ const update = () =>
799
+ setActiveDeepLinkedThreadId(readUrlThreadId(DEFAULT_THREAD_URL_PARAM));
800
+ const uninstallHistoryPatch = installHistoryThreadUrlPatch();
801
+ update();
802
+ window.addEventListener("popstate", update);
803
+ window.addEventListener(THREAD_URL_CHANGED_EVENT, update);
804
+ return () => {
805
+ uninstallHistoryPatch();
806
+ window.removeEventListener("popstate", update);
807
+ window.removeEventListener(THREAD_URL_CHANGED_EVENT, update);
808
+ };
809
+ }, [threadUrlSyncEnabled]);
810
+
811
+ const writeThreadUrl = useCallback(
812
+ (threadId: string | null, options: { replace?: boolean } = {}): void => {
813
+ if (!threadUrlSyncEnabled || typeof window === "undefined") return;
814
+ try {
815
+ const normalizedThreadId = normalizeUrlThreadId(threadId);
816
+ let next: string;
817
+ if (getThreadPath) {
818
+ next = getThreadPath(normalizedThreadId);
819
+ } else {
820
+ const url = new URL(window.location.href);
821
+ if (normalizedThreadId) {
822
+ url.searchParams.set(threadUrlParamName, normalizedThreadId);
823
+ } else {
824
+ url.searchParams.delete(threadUrlParamName);
825
+ }
826
+ if (threadUrlParamName !== "threadId") {
827
+ url.searchParams.delete("threadId");
828
+ }
829
+ next = `${url.pathname}${url.search}${url.hash}`;
830
+ }
831
+ const current = `${window.location.pathname}${window.location.search}${window.location.hash}`;
832
+ if (next === current) {
833
+ setUrlThreadId(normalizedThreadId);
834
+ return;
835
+ }
836
+ if (getThreadPath && navigateThreadUrl) {
837
+ navigateThreadUrl(next, { replace: options.replace === true });
838
+ setUrlThreadId(normalizedThreadId);
839
+ return;
840
+ }
841
+ const method = options.replace ? "replaceState" : "pushState";
842
+ // `getThreadPath` returns a router-local path (no app basename). When we
843
+ // fall back to the raw History API instead of a router navigate, resolve
844
+ // the basename so deep-link reloads work in mounted apps.
845
+ const historyTarget = getThreadPath ? appPath(next) : next;
846
+ window.history[method](window.history.state, "", historyTarget);
847
+ setUrlThreadId(normalizedThreadId);
848
+ window.dispatchEvent(new Event(THREAD_URL_CHANGED_EVENT));
849
+ const popstate =
850
+ typeof PopStateEvent === "function"
851
+ ? new PopStateEvent("popstate", { state: window.history.state })
852
+ : new Event("popstate");
853
+ window.dispatchEvent(popstate);
854
+ } catch {}
855
+ },
856
+ [
857
+ getThreadPath,
858
+ navigateThreadUrl,
859
+ threadUrlParamName,
860
+ threadUrlSyncEnabled,
861
+ ],
862
+ );
863
+
864
+ const {
865
+ threads,
866
+ activeThreadId,
867
+ isLoading,
868
+ createThread,
869
+ switchThread: switchThreadState,
870
+ forkThread,
871
+ saveThreadData,
872
+ generateTitle,
873
+ searchThreads,
874
+ loadMoreThreads,
875
+ refreshThreads,
876
+ hasMoreThreads,
877
+ isLoadingMoreThreads,
878
+ threadsLoadError,
879
+ isNewThread,
880
+ pinThread,
881
+ renameThread,
882
+ } = useChatThreads(apiUrl, storageKey, null, {
883
+ restoreActiveThread,
884
+ routeThreadId: threadUrlSyncEnabled
885
+ ? urlThreadId
886
+ : (activeDeepLinkedThreadId ?? undefined),
887
+ });
888
+
889
+ const switchThread = useCallback(
890
+ (threadId: string, options: { replace?: boolean } = {}) => {
891
+ switchThreadState(threadId);
892
+ writeThreadUrl(threadId, options);
893
+ },
894
+ [switchThreadState, writeThreadUrl],
895
+ );
896
+
897
+ // Namespace all localStorage keys by storageKey when provided (for per-app isolation in frame)
898
+ const keyPrefix = storageKey ? `:${storageKey}` : "";
899
+ const modelSelectionKey = `${MODEL_SELECTION_STORAGE_KEY}${keyPrefix}`;
900
+
901
+ // Track which tabs have been focused at least once (lazy mount for sub-agent tabs)
902
+ const mountedTabsRef = useRef<Set<string>>(new Set());
903
+ const activeThreadIdRef = useRef(activeThreadId);
904
+ activeThreadIdRef.current = activeThreadId;
905
+ // Mark the active tab as mounted so it persists when switched away
906
+ if (activeThreadId) mountedTabsRef.current.add(activeThreadId);
907
+ const chatRefs = useRef<Map<string, AssistantChatHandle>>(new Map());
908
+ // Sends queued until their target thread is ready (see PendingDelivery).
909
+ const pendingDeliveries = useRef<PendingDelivery[]>([]);
910
+ const pendingContextItems = useRef<Map<string, AgentChatContextItem[]>>(
911
+ new Map(),
912
+ );
913
+ const [runningThreads, setRunningThreads] = useState<Set<string>>(new Set());
914
+ const [showHistory, setShowHistory] = useState(false);
915
+ const [pageOverlayScrolled, setPageOverlayScrolled] = useState(false);
916
+ const newThreadIds = useRef<Set<string>>(new Set());
917
+
918
+ useEffect(() => {
919
+ setPageOverlayScrolled(false);
920
+ }, [activeThreadId]);
921
+
922
+ const handlePageOverlayScroll = useCallback(
923
+ (event: React.UIEvent<HTMLDivElement>) => {
924
+ const target = event.target;
925
+ if (
926
+ !renderOverlay ||
927
+ !(target instanceof HTMLElement) ||
928
+ !target.closest(".agent-chat-scroll")
929
+ ) {
930
+ return;
931
+ }
932
+ setPageOverlayScrolled(target.scrollTop > 1);
933
+ },
934
+ [renderOverlay],
935
+ );
936
+
937
+ // ─── Model state ─────────────────────────────────────────────────────────
938
+ const [availableModels, setAvailableModels] = useState<EngineModelGroup[]>(
939
+ [],
940
+ );
941
+ const [modelListLoading, setModelListLoading] = useState(true);
942
+ const [defaultModel, setDefaultModel] = useState<string>(DEFAULT_MODEL);
943
+ const threadModelRef = useRef<
944
+ Map<string, { model: string; engine?: string; effort?: ReasoningEffort }>
945
+ >(new Map());
946
+ const [persistedModelSelection, setPersistedModelSelection] = useState<
947
+ ModelSelection | undefined
948
+ >(() => readStoredModelSelection(modelSelectionKey));
949
+ const [modelSelectionVersion, setModelSelectionVersion] = useState(0);
950
+
951
+ useEffect(() => {
952
+ setPersistedModelSelection(readStoredModelSelection(modelSelectionKey));
953
+ }, [modelSelectionKey]);
954
+
955
+ const bumpModelSelectionVersion = useCallback(() => {
956
+ setModelSelectionVersion((version) => version + 1);
957
+ }, []);
958
+ const postMessageSubmissionsDisabled = props.composerDisabled === true;
959
+
960
+ const setContextInTab = useCallback(
961
+ (
962
+ threadId: string,
963
+ item: AgentChatContextItem,
964
+ options?: { focus?: boolean },
965
+ ) => {
966
+ const ref = chatRefs.current.get(threadId);
967
+ if (ref) {
968
+ ref.setComposerContextItem(item, options);
969
+ return;
970
+ }
971
+ const existing = pendingContextItems.current.get(threadId) ?? [];
972
+ const index = existing.findIndex((current) => current.key === item.key);
973
+ const next =
974
+ index === -1
975
+ ? [...existing, item]
976
+ : existing.map((current, currentIndex) =>
977
+ currentIndex === index ? item : current,
978
+ );
979
+ pendingContextItems.current.set(threadId, next);
980
+ },
981
+ [],
982
+ );
983
+
984
+ const removeContextInTab = useCallback((threadId: string, key: string) => {
985
+ const ref = chatRefs.current.get(threadId);
986
+ if (ref) {
987
+ ref.removeComposerContextItem(key);
988
+ return;
989
+ }
990
+ const existing = pendingContextItems.current.get(threadId);
991
+ if (!existing) return;
992
+ const next = existing.filter((item) => item.key !== key);
993
+ if (next.length === 0) {
994
+ pendingContextItems.current.delete(threadId);
995
+ } else {
996
+ pendingContextItems.current.set(threadId, next);
997
+ }
998
+ }, []);
999
+
1000
+ const clearContextInTab = useCallback((threadId: string) => {
1001
+ const ref = chatRefs.current.get(threadId);
1002
+ if (ref) {
1003
+ ref.clearComposerContextItems();
1004
+ return;
1005
+ }
1006
+ pendingContextItems.current.delete(threadId);
1007
+ }, []);
1008
+
1009
+ const resolveThreadModelSelection = useCallback(
1010
+ (threadId: string) =>
1011
+ resolveModelSelection(
1012
+ threadModelRef.current.get(threadId) ?? persistedModelSelection,
1013
+ availableModels,
1014
+ ),
1015
+ [availableModels, persistedModelSelection, modelSelectionVersion],
1016
+ );
1017
+
1018
+ const persistModelSelection = useCallback(
1019
+ (selection: ModelSelection) => {
1020
+ setPersistedModelSelection(selection);
1021
+ writeStoredModelSelection(modelSelectionKey, selection);
1022
+ },
1023
+ [modelSelectionKey],
1024
+ );
1025
+
1026
+ const handleModelChange = useCallback(
1027
+ (model: string, engine: string) => {
1028
+ const threadId = activeThreadIdRef.current;
1029
+ if (!threadId) return;
1030
+ const existing = threadModelRef.current.get(threadId);
1031
+ const effort = resolveReasoningEffortSelection(model, existing?.effort);
1032
+ const selection = { model, engine, effort };
1033
+ threadModelRef.current.set(threadId, selection);
1034
+ persistModelSelection(selection);
1035
+ bumpModelSelectionVersion();
1036
+ },
1037
+ [bumpModelSelectionVersion, persistModelSelection],
1038
+ );
1039
+
1040
+ const handleEffortChange = useCallback(
1041
+ (effort: ReasoningEffort) => {
1042
+ const threadId = activeThreadIdRef.current;
1043
+ if (!threadId) return;
1044
+ const existing = resolveThreadModelSelection(threadId);
1045
+ const model = existing?.model ?? defaultModel;
1046
+ const engine =
1047
+ existing?.engine ??
1048
+ availableModels.find((group) => group.models.includes(model))?.engine ??
1049
+ availableModels[0]?.engine;
1050
+ const selection: ModelSelection = { model, effort };
1051
+ if (engine) selection.engine = engine;
1052
+ threadModelRef.current.set(threadId, selection);
1053
+ persistModelSelection(selection);
1054
+ bumpModelSelectionVersion();
1055
+ },
1056
+ [
1057
+ availableModels,
1058
+ bumpModelSelectionVersion,
1059
+ defaultModel,
1060
+ persistModelSelection,
1061
+ resolveThreadModelSelection,
1062
+ ],
1063
+ );
1064
+
1065
+ const refreshEngines = useCallback(() => {
1066
+ setModelListLoading(true);
1067
+ Promise.all([
1068
+ callAction("manage-agent-engine" as any, { action: "list" } as any).catch(
1069
+ () => null,
1070
+ ),
1071
+ fetch(agentNativePath("/_agent-native/env-status"))
1072
+ .then((r) => (r.ok ? r.json() : []))
1073
+ .catch(() => []),
1074
+ fetch(agentNativePath("/_agent-native/builder/status"))
1075
+ .then((r) => (r.ok ? r.json() : null))
1076
+ .catch(() => null),
1077
+ ])
1078
+ .then(([enginesData, envKeys, builderStatus]) => {
1079
+ if (!enginesData?.engines) return;
1080
+ const configuredKeys = new Set(
1081
+ (envKeys as Array<{ key: string; configured: boolean }>)
1082
+ .filter((k) => k.configured)
1083
+ .map((k) => k.key),
1084
+ );
1085
+ const builderConnected = builderStatus?.configured === true;
1086
+ const currentEngineName: string | undefined =
1087
+ enginesData.current?.engine;
1088
+ const currentModel: string | undefined = enginesData.current?.model;
1089
+
1090
+ const groups = buildChatModelGroups({
1091
+ engines: enginesData.engines,
1092
+ configuredKeys,
1093
+ builderConnected,
1094
+ currentEngineName,
1095
+ currentModel,
1096
+ });
1097
+ setAvailableModels(groups);
1098
+ setDefaultModel(currentModel ?? DEFAULT_MODEL);
1099
+ })
1100
+ .catch(() => {})
1101
+ .finally(() => setModelListLoading(false));
1102
+ }, []);
1103
+
1104
+ useEffect(() => {
1105
+ refreshEngines();
1106
+ window.addEventListener("agent-engine:configured-changed", refreshEngines);
1107
+ return () =>
1108
+ window.removeEventListener(
1109
+ "agent-engine:configured-changed",
1110
+ refreshEngines,
1111
+ );
1112
+ }, [refreshEngines]);
1113
+
1114
+ // Parent-child thread mapping — persisted to localStorage.
1115
+ // Maps childThreadId → parentThreadId for sub-agent tabs.
1116
+ const PARENT_MAP_KEY = `agent-chat-parent-map${keyPrefix}`;
1117
+ const [parentMap, setParentMap] = useState<Record<string, string>>(() => {
1118
+ try {
1119
+ const saved = localStorage.getItem(PARENT_MAP_KEY);
1120
+ if (saved) return JSON.parse(saved);
1121
+ } catch {}
1122
+ return {};
1123
+ });
1124
+ const parentMapRef = useRef(parentMap);
1125
+ parentMapRef.current = parentMap;
1126
+ const dismissedSubAgentTabsRef = useRef<Set<string>>(new Set());
1127
+
1128
+ // Persist parent map to localStorage
1129
+ useEffect(() => {
1130
+ try {
1131
+ localStorage.setItem(PARENT_MAP_KEY, JSON.stringify(parentMap));
1132
+ } catch {}
1133
+ }, [parentMap, PARENT_MAP_KEY]);
1134
+
1135
+ // Sub-agent display names — persisted to localStorage.
1136
+ // Maps childThreadId → short name (e.g. "Research", "Draft email").
1137
+ const SUB_AGENT_NAMES_KEY = `agent-chat-sub-agent-names${keyPrefix}`;
1138
+ const [subAgentNames, setSubAgentNames] = useState<Record<string, string>>(
1139
+ () => {
1140
+ try {
1141
+ const saved = localStorage.getItem(SUB_AGENT_NAMES_KEY);
1142
+ if (saved) return JSON.parse(saved);
1143
+ } catch {}
1144
+ return {};
1145
+ },
1146
+ );
1147
+ const subAgentNamesRef = useRef(subAgentNames);
1148
+ subAgentNamesRef.current = subAgentNames;
1149
+ const [subAgentStatuses, setSubAgentStatuses] = useState<
1150
+ Record<string, AgentTeamRunStatus>
1151
+ >({});
1152
+
1153
+ useEffect(() => {
1154
+ try {
1155
+ localStorage.setItem(SUB_AGENT_NAMES_KEY, JSON.stringify(subAgentNames));
1156
+ } catch {}
1157
+ }, [subAgentNames, SUB_AGENT_NAMES_KEY]);
1158
+
1159
+ // Open tabs — persisted to localStorage so they survive refresh.
1160
+ const OPEN_TABS_KEY = `agent-chat-open-tabs${keyPrefix}`;
1161
+ const [openTabIds, setOpenTabIds] = useState<string[]>(() => {
1162
+ if (!restoreActiveThread && activeThreadId) {
1163
+ for (const id of [activeThreadId]) mountedTabsRef.current.add(id);
1164
+ return [activeThreadId];
1165
+ }
1166
+ try {
1167
+ const saved = localStorage.getItem(OPEN_TABS_KEY);
1168
+ if (saved) {
1169
+ const parsed = JSON.parse(saved);
1170
+ if (Array.isArray(parsed) && parsed.length > 0) {
1171
+ // Mark restored tabs as mounted
1172
+ for (const id of parsed) mountedTabsRef.current.add(id);
1173
+ return parsed;
1174
+ }
1175
+ }
1176
+ } catch {}
1177
+ return [];
1178
+ });
1179
+ const openTabIdsRef = useRef(openTabIds);
1180
+ openTabIdsRef.current = openTabIds;
1181
+ const initializedRef = useRef(false);
1182
+
1183
+ const openTabsKeyRef = useRef(OPEN_TABS_KEY);
1184
+
1185
+ useEffect(() => {
1186
+ const nextScope = scope;
1187
+ if (!nextScope) return;
1188
+ const type = formatScopeType(nextScope.type);
1189
+ const title =
1190
+ nextScope.label?.trim() ||
1191
+ type.replace(/^./, (character) => character.toUpperCase());
1192
+ const key = nextScope.contextKey || "agent-current-resource-context";
1193
+ const marker = `Resource context: ${nextScope.type}:${nextScope.id}`;
1194
+ const existing = getAgentChatContextState().items.find(
1195
+ (item) => item.key === key,
1196
+ );
1197
+ let ownsContextItem = false;
1198
+ if (!existing || existing.context.startsWith(marker)) {
1199
+ setAgentChatContextItem({
1200
+ key,
1201
+ title,
1202
+ context: [
1203
+ marker,
1204
+ `The user is currently viewing this ${type}.`,
1205
+ nextScope.label ? `Resource name: ${nextScope.label}` : "",
1206
+ `Resource id: ${nextScope.id}`,
1207
+ typeof window !== "undefined"
1208
+ ? `Current URL: ${window.location.pathname}${window.location.search}`
1209
+ : "",
1210
+ ]
1211
+ .filter(Boolean)
1212
+ .join("\n"),
1213
+ openSidebar: false,
1214
+ focus: false,
1215
+ });
1216
+ ownsContextItem = true;
1217
+ }
1218
+ return () => {
1219
+ const current = getAgentChatContextState().items.find(
1220
+ (item) => item.key === key,
1221
+ );
1222
+ if (ownsContextItem && current?.context.startsWith(marker)) {
1223
+ removeAgentChatContextItem(key);
1224
+ }
1225
+ };
1226
+ }, [scope?.contextKey, scope?.id, scope?.label, scope?.type]);
1227
+
1228
+ // Persist open tab IDs to localStorage (exclude sub-agent tabs — they're session-only)
1229
+ useEffect(() => {
1230
+ if (openTabsKeyRef.current !== OPEN_TABS_KEY) return;
1231
+ const mainTabs = openTabIds.filter((id) => !parentMap[id]);
1232
+ if (mainTabs.length > 0) {
1233
+ try {
1234
+ localStorage.setItem(OPEN_TABS_KEY, JSON.stringify(mainTabs));
1235
+ } catch {}
1236
+ }
1237
+ }, [openTabIds, parentMap, OPEN_TABS_KEY]);
1238
+
1239
+ // Initialize open tabs once threads load — validate saved tabs still exist
1240
+ useEffect(() => {
1241
+ if (initializedRef.current || !activeThreadId || threads.length === 0)
1242
+ return;
1243
+ initializedRef.current = true;
1244
+ const threadIds = new Set(threads.map((t) => t.id));
1245
+ const threadMap = new Map(threads.map((t) => [t.id, t]));
1246
+
1247
+ // Hide tabs that have had no activity for more than 12 hours. Stale tabs
1248
+ // are removed from the sidebar on load but remain accessible via history.
1249
+ const now = Date.now();
1250
+ const isStale = (id: string) => {
1251
+ const thread = threadMap.get(id);
1252
+ return thread
1253
+ ? now - thread.updatedAt > STALE_THREAD_THRESHOLD_MS
1254
+ : false;
1255
+ };
1256
+
1257
+ // If the active thread is a sub-agent, switch to its parent or the most recent main thread
1258
+ if (parentMap[activeThreadId]) {
1259
+ const parent = parentMap[activeThreadId];
1260
+ if (parent && threadIds.has(parent)) {
1261
+ switchThread(parent);
1262
+ } else {
1263
+ // Fall back to most recent main thread
1264
+ const mainThread = threads.find((t) => !parentMap[t.id]);
1265
+ if (mainThread) switchThread(mainThread.id);
1266
+ }
1267
+ }
1268
+
1269
+ setOpenTabIds((prev) => {
1270
+ // Filter out tabs that no longer exist, sub-agent tabs, or stale tabs (>12h inactive)
1271
+ const valid = prev.filter(
1272
+ (id) => threadIds.has(id) && !parentMap[id] && !isStale(id),
1273
+ );
1274
+ // Ensure active thread is included (only if it's not a sub-agent and not stale)
1275
+ if (
1276
+ !parentMap[activeThreadId] &&
1277
+ !valid.includes(activeThreadId) &&
1278
+ !isStale(activeThreadId)
1279
+ ) {
1280
+ valid.push(activeThreadId);
1281
+ }
1282
+ return valid;
1283
+ });
1284
+
1285
+ // If active thread is stale, start fresh
1286
+ if (!parentMap[activeThreadId] && isStale(activeThreadId)) {
1287
+ createThread().then((id) => {
1288
+ if (id) writeThreadUrl(null);
1289
+ });
1290
+ }
1291
+ }, [
1292
+ activeThreadId,
1293
+ threads,
1294
+ parentMap,
1295
+ switchThread,
1296
+ createThread,
1297
+ writeThreadUrl,
1298
+ ]);
1299
+
1300
+ // Ensure active thread is always in open tabs.
1301
+ // Use functional update to check inside the setter — avoids race with the
1302
+ // initialization effect that may have already added the ID in the same batch.
1303
+ //
1304
+ // Re-check after tab-list resets so the sidebar cannot end up with a live
1305
+ // active thread but no mounted chat.
1306
+ useEffect(() => {
1307
+ if (!activeThreadId || openTabIds.includes(activeThreadId)) return;
1308
+ if (parentMap[activeThreadId]) return;
1309
+
1310
+ const activeThread = threads.find((thread) => thread.id === activeThreadId);
1311
+ if (
1312
+ activeThread &&
1313
+ Date.now() - activeThread.updatedAt > STALE_THREAD_THRESHOLD_MS
1314
+ ) {
1315
+ return;
1316
+ }
1317
+
1318
+ setOpenTabIds((prev) =>
1319
+ prev.includes(activeThreadId) ? prev : [...prev, activeThreadId],
1320
+ );
1321
+ }, [activeThreadId, openTabIds, parentMap, threads]);
1322
+
1323
+ // Ensure at least one tab is always open — auto-create if sidebar is empty.
1324
+ // Skipped when an active thread already exists (e.g. the hook generated an
1325
+ // optimistic id for a brand-new session); the activeThreadId effect above
1326
+ // adds it to openTabIds without spinning up a duplicate thread.
1327
+ const autoCreatingRef = useRef(false);
1328
+ useEffect(() => {
1329
+ if (isLoading || autoCreatingRef.current) return;
1330
+ if (openTabIds.length === 0 && !activeThreadId) {
1331
+ autoCreatingRef.current = true;
1332
+ createThread().then((id) => {
1333
+ autoCreatingRef.current = false;
1334
+ if (id) {
1335
+ newThreadIds.current.add(id);
1336
+ setOpenTabIds([id]);
1337
+ writeThreadUrl(null, { replace: true });
1338
+ }
1339
+ });
1340
+ }
1341
+ }, [isLoading, openTabIds, activeThreadId, createThread, writeThreadUrl]);
1342
+
1343
+ useEffect(() => {
1344
+ let stopped = false;
1345
+ let timer: ReturnType<typeof setTimeout> | null = null;
1346
+ const runsUrl = `${apiUrl.replace(/\/$/, "")}/runs/list?goalId=agent-team`;
1347
+
1348
+ async function hydrateAgentTeamTabs() {
1349
+ try {
1350
+ const res = await fetch(runsUrl);
1351
+ if (res.ok) {
1352
+ const data = (await res.json()) as { runs?: AgentTeamRunSummary[] };
1353
+ const infos = Array.isArray(data.runs)
1354
+ ? data.runs
1355
+ .map(runToAgentTeamTabInfo)
1356
+ .filter((info): info is AgentTeamTabInfo => Boolean(info))
1357
+ : [];
1358
+
1359
+ setSubAgentStatuses((prev) => {
1360
+ let changed = false;
1361
+ const next: Record<string, AgentTeamRunStatus> = {};
1362
+ for (const info of infos) {
1363
+ next[info.threadId] = info.status;
1364
+ if (prev[info.threadId] !== info.status) changed = true;
1365
+ }
1366
+ if (Object.keys(prev).length !== Object.keys(next).length) {
1367
+ changed = true;
1368
+ }
1369
+ return changed ? next : prev;
1370
+ });
1371
+
1372
+ const openSet = new Set(openTabIdsRef.current);
1373
+ const candidates = infos.filter(
1374
+ (info) =>
1375
+ !dismissedSubAgentTabsRef.current.has(info.threadId) &&
1376
+ (openSet.has(info.parentThreadId) || openSet.has(info.threadId)),
1377
+ );
1378
+
1379
+ if (candidates.length > 0) {
1380
+ const shouldRefreshThreads = candidates.some(
1381
+ (info) =>
1382
+ !openSet.has(info.threadId) && openSet.has(info.parentThreadId),
1383
+ );
1384
+ const candidateParents = new Map(
1385
+ candidates.map((info) => [info.threadId, info.parentThreadId]),
1386
+ );
1387
+ setParentMap((prev) => {
1388
+ let next = prev;
1389
+ for (const info of candidates) {
1390
+ if (next[info.threadId] === info.parentThreadId) continue;
1391
+ next =
1392
+ next === prev
1393
+ ? { ...prev, [info.threadId]: info.parentThreadId }
1394
+ : { ...next, [info.threadId]: info.parentThreadId };
1395
+ }
1396
+ return next;
1397
+ });
1398
+ setSubAgentNames((prev) => {
1399
+ let next = prev;
1400
+ for (const info of candidates) {
1401
+ if (!info.name || next[info.threadId] === info.name) continue;
1402
+ next =
1403
+ next === prev
1404
+ ? { ...prev, [info.threadId]: info.name }
1405
+ : { ...next, [info.threadId]: info.name };
1406
+ }
1407
+ return next;
1408
+ });
1409
+
1410
+ setOpenTabIds((prev) => {
1411
+ let next = prev;
1412
+ for (const info of candidates) {
1413
+ if (next.includes(info.threadId)) continue;
1414
+ const parentIdx = next.indexOf(info.parentThreadId);
1415
+ if (parentIdx === -1) continue;
1416
+ if (next === prev) next = [...prev];
1417
+ let insertIdx = parentIdx + 1;
1418
+ while (insertIdx < next.length) {
1419
+ const siblingParent =
1420
+ parentMapRef.current[next[insertIdx]] ||
1421
+ candidateParents.get(next[insertIdx]);
1422
+ if (siblingParent !== info.parentThreadId) break;
1423
+ insertIdx++;
1424
+ }
1425
+ next.splice(insertIdx, 0, info.threadId);
1426
+ }
1427
+ return next;
1428
+ });
1429
+ if (shouldRefreshThreads) {
1430
+ refreshThreads();
1431
+ }
1432
+ }
1433
+ }
1434
+ } catch {
1435
+ // Best effort: task cards and manual history still work if this poll fails.
1436
+ } finally {
1437
+ if (!stopped) {
1438
+ timer = setTimeout(hydrateAgentTeamTabs, 3000);
1439
+ }
1440
+ }
1441
+ }
1442
+
1443
+ hydrateAgentTeamTabs();
1444
+ return () => {
1445
+ stopped = true;
1446
+ if (timer) clearTimeout(timer);
1447
+ };
1448
+ }, [apiUrl, refreshThreads]);
1449
+
1450
+ // Focus the composer when switching tabs
1451
+ useEffect(() => {
1452
+ if (!activeThreadId) return;
1453
+ // Small delay to ensure the tab is visible before focusing
1454
+ const t = setTimeout(() => {
1455
+ chatRefs.current.get(activeThreadId)?.focusComposer();
1456
+ }, 50);
1457
+ return () => clearTimeout(t);
1458
+ }, [activeThreadId]);
1459
+
1460
+ // Ref callback: scroll the active tab into view in the overflow container.
1461
+ // Uses getBoundingClientRect for reliable positioning regardless of offsetParent.
1462
+ // A margin keeps the active tab from sitting flush against either container
1463
+ // edge — at the right edge it was landing directly under the +/history/menu
1464
+ // buttons, which visually clipped the tab label.
1465
+ const activeTabRefCb = useCallback((el: HTMLElement | null) => {
1466
+ if (!el) return;
1467
+ const container = el.parentElement;
1468
+ if (!container) return;
1469
+ const MARGIN = 24;
1470
+ requestAnimationFrame(() => {
1471
+ const containerRect = container.getBoundingClientRect();
1472
+ const tabRect = el.getBoundingClientRect();
1473
+ if (tabRect.left < containerRect.left + MARGIN) {
1474
+ container.scrollLeft += tabRect.left - containerRect.left - MARGIN;
1475
+ } else if (tabRect.right > containerRect.right - MARGIN) {
1476
+ container.scrollLeft += tabRect.right - containerRect.right + MARGIN;
1477
+ }
1478
+ });
1479
+ }, []);
1480
+
1481
+ const [messageCounts, setMessageCounts] = useState<Record<string, number>>(
1482
+ () => Object.fromEntries(threads.map((t) => [t.id, t.messageCount ?? 0])),
1483
+ );
1484
+
1485
+ // Sync message counts from threads when they load
1486
+ useEffect(() => {
1487
+ if (threads.length > 0) {
1488
+ setMessageCounts((prev) => {
1489
+ const next = { ...prev };
1490
+ for (const t of threads) {
1491
+ if (!(t.id in next)) {
1492
+ next[t.id] = t.messageCount ?? 0;
1493
+ }
1494
+ }
1495
+ return next;
1496
+ });
1497
+ }
1498
+ }, [threads]);
1499
+
1500
+ // Listen for builder.submitChat postMessages
1501
+ useEffect(() => {
1502
+ const handler = (event: MessageEvent) => {
1503
+ if (!isTrustedFrameMessage(event)) return;
1504
+ if (event.data?.type === AGENT_CHAT_SET_CONTEXT_MESSAGE_TYPE) {
1505
+ const item = normalizeAgentChatContextItem(event.data.data);
1506
+ if (!item) return;
1507
+ const openSidebar = event.data.data?.openSidebar as boolean | undefined;
1508
+ if (openSidebar !== false) {
1509
+ window.dispatchEvent(new CustomEvent("agent-panel:open"));
1510
+ }
1511
+ if (postMessageSubmissionsDisabled) return;
1512
+ const currentTabId = activeThreadIdRef.current;
1513
+ if (!currentTabId) return;
1514
+ // Focus defaults to true; a caller opts out with `focus: false` for
1515
+ // passive context (e.g. a canvas selection) so staging never steals
1516
+ // focus from an in-progress inline editor.
1517
+ const focus = (event.data.data?.focus as boolean | undefined) !== false;
1518
+ setContextInTab(currentTabId, item, { focus });
1519
+ return;
1520
+ }
1521
+ if (event.data?.type === AGENT_CHAT_REMOVE_CONTEXT_MESSAGE_TYPE) {
1522
+ const key =
1523
+ typeof event.data.data?.key === "string"
1524
+ ? event.data.data.key.trim()
1525
+ : "";
1526
+ if (!key) return;
1527
+ const openSidebar = event.data.data?.openSidebar as boolean | undefined;
1528
+ if (openSidebar === true) {
1529
+ window.dispatchEvent(new CustomEvent("agent-panel:open"));
1530
+ }
1531
+ if (postMessageSubmissionsDisabled) return;
1532
+ const currentTabId = activeThreadIdRef.current;
1533
+ if (!currentTabId) return;
1534
+ removeContextInTab(currentTabId, key);
1535
+ return;
1536
+ }
1537
+ if (event.data?.type === AGENT_CHAT_CLEAR_CONTEXT_MESSAGE_TYPE) {
1538
+ const openSidebar = event.data.data?.openSidebar as boolean | undefined;
1539
+ if (openSidebar === true) {
1540
+ window.dispatchEvent(new CustomEvent("agent-panel:open"));
1541
+ }
1542
+ if (postMessageSubmissionsDisabled) return;
1543
+ const currentTabId = activeThreadIdRef.current;
1544
+ if (!currentTabId) return;
1545
+ clearContextInTab(currentTabId);
1546
+ return;
1547
+ }
1548
+ const parsed = parseSubmitChatMessage(event);
1549
+ if (!parsed) return;
1550
+ // Dedup the live post against the cold-start replay; first one wins.
1551
+ if (!claimAgentChatSubmit(parsed.submitMessageId)) return;
1552
+ const {
1553
+ message,
1554
+ context,
1555
+ openSidebar,
1556
+ model,
1557
+ effort,
1558
+ newTab,
1559
+ background,
1560
+ submit,
1561
+ images,
1562
+ submitMessageId,
1563
+ } = parsed;
1564
+ const requestedTabId = parsed.tabId;
1565
+ const requestMode =
1566
+ parsed.requestMode ?? requestModeFromExecMode(props.execMode);
1567
+
1568
+ // Make sure the sidebar is visible to show the response, unless the
1569
+ // caller explicitly opted out or it's a background send.
1570
+ if (openSidebar !== false && !background) {
1571
+ window.dispatchEvent(new CustomEvent("agent-panel:open"));
1572
+ }
1573
+ if (postMessageSubmissionsDisabled) {
1574
+ reportAgentChatSubmitResult(
1575
+ submitMessageId,
1576
+ false,
1577
+ "composer-disabled",
1578
+ );
1579
+ return;
1580
+ }
1581
+
1582
+ // Plan mode is sent as request metadata by the chat adapter. Keep the
1583
+ // user-visible message clean so mode instructions never enter history.
1584
+ const fullMessage = context
1585
+ ? appendAgentChatContextToMessage(message, context)
1586
+ : message;
1587
+
1588
+ const send: PendingSend = {
1589
+ message: fullMessage,
1590
+ images,
1591
+ submit,
1592
+ ...(background ? { trackInRunsTray: true } : {}),
1593
+ ...(requestMode ? { requestMode } : {}),
1594
+ ...(submitMessageId ? { submitMessageId } : {}),
1595
+ };
1596
+
1597
+ const sendToTab = (threadId: string) => {
1598
+ if (isAgentChatSubmitCancelled(submitMessageId)) return;
1599
+ // If a model override was specified, apply it only if we recognize it
1600
+ if (model) {
1601
+ const matchedGroup = availableModels.find((g) =>
1602
+ g.models.includes(model),
1603
+ );
1604
+ if (matchedGroup) {
1605
+ const selectedEffort = resolveReasoningEffortSelection(
1606
+ model,
1607
+ isReasoningEffort(effort) ? effort : undefined,
1608
+ );
1609
+ threadModelRef.current.set(threadId, {
1610
+ model,
1611
+ engine: matchedGroup.engine,
1612
+ effort: selectedEffort,
1613
+ });
1614
+ bumpModelSelectionVersion();
1615
+ }
1616
+ }
1617
+
1618
+ const ref = chatRefs.current.get(threadId);
1619
+ if (ref) {
1620
+ deliverPendingSend(ref, send);
1621
+ } else {
1622
+ pendingDeliveries.current.push({ threadId, send });
1623
+ }
1624
+ };
1625
+
1626
+ if (newTab) {
1627
+ const previousTabId = activeThreadIdRef.current;
1628
+ createThread(requestedTabId)
1629
+ .then((newId) => {
1630
+ if (isAgentChatSubmitCancelled(submitMessageId)) return;
1631
+ if (!newId) {
1632
+ reportAgentChatSubmitResult(
1633
+ submitMessageId,
1634
+ false,
1635
+ "thread-create-failed",
1636
+ );
1637
+ return;
1638
+ }
1639
+ newThreadIds.current.add(newId);
1640
+ if (background) {
1641
+ mountedTabsRef.current.add(newId);
1642
+ }
1643
+ setOpenTabIds((prev) =>
1644
+ prev.includes(newId) ? prev : [...prev, newId],
1645
+ );
1646
+ if (!background) {
1647
+ writeThreadUrl(newId);
1648
+ }
1649
+ sendToTab(newId);
1650
+ if (background && previousTabId) {
1651
+ switchThreadState(previousTabId);
1652
+ }
1653
+ })
1654
+ .catch(() => {
1655
+ reportAgentChatSubmitResult(
1656
+ submitMessageId,
1657
+ false,
1658
+ "thread-create-failed",
1659
+ );
1660
+ });
1661
+ } else {
1662
+ const currentTabId = activeThreadIdRef.current;
1663
+ if (currentTabId) {
1664
+ sendToTab(currentTabId);
1665
+ } else {
1666
+ // Cold start: no thread yet. Queue for the first active thread (the
1667
+ // bootstrap effect creates it) rather than racing a second create.
1668
+ pendingDeliveries.current.push({ threadId: null, send });
1669
+ }
1670
+ }
1671
+ };
1672
+ window.addEventListener("message", handler);
1673
+ return () => window.removeEventListener("message", handler);
1674
+ }, [
1675
+ availableModels,
1676
+ bumpModelSelectionVersion,
1677
+ clearContextInTab,
1678
+ createThread,
1679
+ postMessageSubmissionsDisabled,
1680
+ props.execMode,
1681
+ removeContextInTab,
1682
+ setContextInTab,
1683
+ switchThread,
1684
+ switchThreadState,
1685
+ writeThreadUrl,
1686
+ ]);
1687
+
1688
+ // Replay submits posted before this lazy panel's listener attached. Dedup in
1689
+ // the handler keeps a live + replayed message single.
1690
+ useEffect(() => {
1691
+ const buffered = drainBufferedAgentChatSubmits();
1692
+ for (const data of buffered) {
1693
+ window.dispatchEvent(
1694
+ new MessageEvent("message", {
1695
+ data: { type: "agentNative.submitChat", data },
1696
+ origin: window.location.origin,
1697
+ }),
1698
+ );
1699
+ }
1700
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1701
+ }, []);
1702
+
1703
+ // Flush queued context items and sends once their thread's ref is mounted
1704
+ // (re-runs on ref mount via openTabIds and on cold-start target via
1705
+ // activeThreadId).
1706
+ useEffect(() => {
1707
+ for (const [tabId, items] of pendingContextItems.current) {
1708
+ const ref = chatRefs.current.get(tabId);
1709
+ if (!ref) continue;
1710
+ for (const item of items) ref.setComposerContextItem(item);
1711
+ pendingContextItems.current.delete(tabId);
1712
+ }
1713
+
1714
+ if (pendingDeliveries.current.length === 0) return;
1715
+ const active = activeThreadIdRef.current;
1716
+ const remaining: PendingDelivery[] = [];
1717
+ for (const delivery of pendingDeliveries.current) {
1718
+ if (isAgentChatSubmitCancelled(delivery.send.submitMessageId)) continue;
1719
+ const threadId = delivery.threadId ?? active ?? null;
1720
+ const ref = threadId ? chatRefs.current.get(threadId) : null;
1721
+ if (threadId && ref) {
1722
+ const { send } = delivery;
1723
+ setTimeout(() => deliverPendingSend(ref, send), 50);
1724
+ } else {
1725
+ // Not ready — keep it, pinning the resolved threadId once known.
1726
+ remaining.push(threadId ? { threadId, send: delivery.send } : delivery);
1727
+ }
1728
+ }
1729
+ pendingDeliveries.current = remaining;
1730
+ }, [openTabIds, activeThreadId]);
1731
+
1732
+ // Listen for chatRunning completion events
1733
+ useEffect(() => {
1734
+ const handler = (e: Event) => {
1735
+ const detail = (e as CustomEvent).detail;
1736
+ if (!detail) return;
1737
+ const { isRunning, tabId } = detail;
1738
+ if (!tabId) return;
1739
+
1740
+ setRunningThreads((prev) => {
1741
+ const next = new Set(prev);
1742
+ if (isRunning) {
1743
+ next.add(tabId);
1744
+ } else {
1745
+ next.delete(tabId);
1746
+ }
1747
+ return next;
1748
+ });
1749
+ };
1750
+ window.addEventListener("agentNative.chatRunning", handler);
1751
+ return () => window.removeEventListener("agentNative.chatRunning", handler);
1752
+ }, []);
1753
+
1754
+ const addTab = useCallback(async () => {
1755
+ const id = await createThread();
1756
+ if (id) {
1757
+ newThreadIds.current.add(id);
1758
+ writeThreadUrl(null);
1759
+ }
1760
+ return id;
1761
+ }, [createThread, writeThreadUrl]);
1762
+
1763
+ const cleanupClosedTab = useCallback((tabId: string) => {
1764
+ if (parentMapRef.current[tabId]) {
1765
+ dismissedSubAgentTabsRef.current.add(tabId);
1766
+ }
1767
+ chatRefs.current.delete(tabId);
1768
+ pendingDeliveries.current = pendingDeliveries.current.filter(
1769
+ (d) => d.threadId !== tabId,
1770
+ );
1771
+ pendingContextItems.current.delete(tabId);
1772
+ newThreadIds.current.delete(tabId);
1773
+ threadModelRef.current.delete(tabId);
1774
+ // Clean up parent map and sub-agent names
1775
+ setParentMap((prev) => {
1776
+ if (!(tabId in prev)) return prev;
1777
+ const { [tabId]: _, ...rest } = prev;
1778
+ return rest;
1779
+ });
1780
+ setSubAgentNames((prev) => {
1781
+ if (!(tabId in prev)) return prev;
1782
+ const { [tabId]: _, ...rest } = prev;
1783
+ return rest;
1784
+ });
1785
+ setSubAgentStatuses((prev) => {
1786
+ if (!(tabId in prev)) return prev;
1787
+ const { [tabId]: _, ...rest } = prev;
1788
+ return rest;
1789
+ });
1790
+ }, []);
1791
+
1792
+ const closeTab = useCallback(
1793
+ (tabId: string) => {
1794
+ setOpenTabIds((prev) => {
1795
+ if (prev.length <= 1) {
1796
+ // Last tab — create a new one and replace the old tab atomically
1797
+ createThread().then((newId) => {
1798
+ if (newId) {
1799
+ newThreadIds.current.add(newId);
1800
+ setOpenTabIds([newId]);
1801
+ writeThreadUrl(null);
1802
+ }
1803
+ });
1804
+ return prev; // Keep old tab until new one is ready
1805
+ }
1806
+ const next = prev.filter((id) => id !== tabId);
1807
+ if (tabId === activeThreadIdRef.current && next.length > 0) {
1808
+ const idx = prev.indexOf(tabId);
1809
+ switchThread(next[Math.min(idx, next.length - 1)]);
1810
+ }
1811
+ return next;
1812
+ });
1813
+ cleanupClosedTab(tabId);
1814
+ },
1815
+ [switchThread, createThread, cleanupClosedTab, writeThreadUrl],
1816
+ );
1817
+
1818
+ const closeOtherTabs = useCallback(
1819
+ (tabId: string) => {
1820
+ for (const id of openTabIdsRef.current) {
1821
+ if (id !== tabId && parentMapRef.current[id]) {
1822
+ dismissedSubAgentTabsRef.current.add(id);
1823
+ }
1824
+ }
1825
+ setOpenTabIds([tabId]);
1826
+ if (activeThreadIdRef.current !== tabId) {
1827
+ switchThread(tabId);
1828
+ }
1829
+ // Clean up refs for closed tabs
1830
+ for (const key of chatRefs.current.keys()) {
1831
+ if (key !== tabId) {
1832
+ if (parentMapRef.current[key]) {
1833
+ dismissedSubAgentTabsRef.current.add(key);
1834
+ }
1835
+ chatRefs.current.delete(key);
1836
+ pendingDeliveries.current = pendingDeliveries.current.filter(
1837
+ (d) => d.threadId !== key,
1838
+ );
1839
+ pendingContextItems.current.delete(key);
1840
+ newThreadIds.current.delete(key);
1841
+ threadModelRef.current.delete(key);
1842
+ }
1843
+ }
1844
+ // Clean up parent map and sub-agent names — only keep entries for the surviving tab
1845
+ setParentMap((prev) => {
1846
+ if (tabId in prev) return { [tabId]: prev[tabId] };
1847
+ return {};
1848
+ });
1849
+ setSubAgentNames((prev) => {
1850
+ if (tabId in prev) return { [tabId]: prev[tabId] };
1851
+ return {};
1852
+ });
1853
+ setSubAgentStatuses((prev) => {
1854
+ if (tabId in prev) return { [tabId]: prev[tabId] };
1855
+ return {};
1856
+ });
1857
+ },
1858
+ [switchThread],
1859
+ );
1860
+
1861
+ const closeAllTabs = useCallback(async () => {
1862
+ const id = await createThread();
1863
+ if (id) {
1864
+ newThreadIds.current.add(id);
1865
+ setOpenTabIds([id]);
1866
+ switchThreadState(id);
1867
+ writeThreadUrl(null);
1868
+ dismissedSubAgentTabsRef.current.clear();
1869
+ // Clean up all old refs
1870
+ chatRefs.current.clear();
1871
+ pendingDeliveries.current = [];
1872
+ pendingContextItems.current.clear();
1873
+ threadModelRef.current.clear();
1874
+ setParentMap({});
1875
+ setSubAgentNames({});
1876
+ setSubAgentStatuses({});
1877
+ }
1878
+ }, [createThread, switchThreadState, writeThreadUrl]);
1879
+
1880
+ // Keyboard shortcuts dispatched from AgentPanel based on the active mode
1881
+ useEffect(() => {
1882
+ const handleCloseCurrent = () => {
1883
+ const id = activeThreadIdRef.current;
1884
+ if (id) closeTab(id);
1885
+ };
1886
+ const handleCloseAll = () => {
1887
+ void closeAllTabs();
1888
+ };
1889
+ const handleNewChat = () => {
1890
+ void addTab();
1891
+ };
1892
+ window.addEventListener("agent-chat:close-current-tab", handleCloseCurrent);
1893
+ window.addEventListener("agent-chat:close-all-tabs", handleCloseAll);
1894
+ window.addEventListener("agent-chat:new-chat", handleNewChat);
1895
+ return () => {
1896
+ window.removeEventListener(
1897
+ "agent-chat:close-current-tab",
1898
+ handleCloseCurrent,
1899
+ );
1900
+ window.removeEventListener("agent-chat:close-all-tabs", handleCloseAll);
1901
+ window.removeEventListener("agent-chat:new-chat", handleNewChat);
1902
+ };
1903
+ }, [closeTab, closeAllTabs, addTab]);
1904
+
1905
+ useEffect(() => {
1906
+ const handleOpenThread = (event: Event) => {
1907
+ const detail = (event as CustomEvent).detail as
1908
+ | {
1909
+ threadId?: unknown;
1910
+ newThread?: unknown;
1911
+ onlyIfActiveThreadId?: unknown;
1912
+ openRequestId?: unknown;
1913
+ }
1914
+ | undefined;
1915
+ const threadId =
1916
+ typeof detail?.threadId === "string" ? detail.threadId : "";
1917
+ if (!detail || !threadId) return;
1918
+ if (!claimAgentChatOpenRequest(detail.openRequestId)) return;
1919
+
1920
+ const onlyIfActiveThreadId =
1921
+ typeof detail.onlyIfActiveThreadId === "string"
1922
+ ? detail.onlyIfActiveThreadId.trim()
1923
+ : "";
1924
+ const activeThreadId = activeThreadIdRef.current;
1925
+ if (
1926
+ onlyIfActiveThreadId &&
1927
+ activeThreadId &&
1928
+ activeThreadId !== onlyIfActiveThreadId
1929
+ ) {
1930
+ return;
1931
+ }
1932
+
1933
+ if (detail?.newThread === true) {
1934
+ newThreadIds.current.add(threadId);
1935
+ void createThread(threadId).then((createdId) => {
1936
+ if (!createdId) return;
1937
+ setOpenTabIds((prev) =>
1938
+ prev.includes(createdId) ? prev : [...prev, createdId],
1939
+ );
1940
+ writeThreadUrl(null);
1941
+ });
1942
+ return;
1943
+ }
1944
+ setOpenTabIds((prev) =>
1945
+ prev.includes(threadId) ? prev : [...prev, threadId],
1946
+ );
1947
+ switchThread(threadId);
1948
+ };
1949
+
1950
+ window.addEventListener("agent-chat:open-thread", handleOpenThread);
1951
+ return () =>
1952
+ window.removeEventListener("agent-chat:open-thread", handleOpenThread);
1953
+ }, [createThread, switchThread, writeThreadUrl]);
1954
+
1955
+ const clearActiveTab = useCallback(() => {
1956
+ const tabIdToClear = activeThreadIdRef.current;
1957
+ void addTab().then((newTabId) => {
1958
+ if (!tabIdToClear || !newTabId || tabIdToClear === newTabId) return;
1959
+ setOpenTabIds((prev) => {
1960
+ const next = prev.filter((id) => id !== tabIdToClear);
1961
+ return next.includes(newTabId) ? next : [...next, newTabId];
1962
+ });
1963
+ cleanupClosedTab(tabIdToClear);
1964
+ });
1965
+ }, [addTab, cleanupClosedTab]);
1966
+
1967
+ const openFromHistory = useCallback(
1968
+ (threadId: string) => {
1969
+ if (!openTabIds.includes(threadId)) {
1970
+ setOpenTabIds((prev) => [...prev, threadId]);
1971
+ }
1972
+ switchThread(threadId);
1973
+ },
1974
+ [openTabIds, switchThread],
1975
+ );
1976
+
1977
+ // Listen for agent-task-open events (from AgentTaskCard "Open" button)
1978
+ useEffect(() => {
1979
+ function handleOpenTask(e: Event) {
1980
+ const detail = (e as CustomEvent).detail;
1981
+ const threadId = detail?.threadId;
1982
+ if (!threadId) return;
1983
+ if (!claimAgentChatOpenRequest(detail.openRequestId)) return;
1984
+ dismissedSubAgentTabsRef.current.delete(threadId);
1985
+ // Prefer an explicit parent (RunsTray/background hydration knows it);
1986
+ // inline task cards fall back to the active orchestrator thread.
1987
+ const explicitParentId =
1988
+ typeof detail?.parentThreadId === "string"
1989
+ ? detail.parentThreadId.trim()
1990
+ : "";
1991
+ const parentId = explicitParentId || activeThreadIdRef.current;
1992
+ if (parentId && parentId !== threadId) {
1993
+ setParentMap((prev) =>
1994
+ prev[threadId] === parentId
1995
+ ? prev
1996
+ : { ...prev, [threadId]: parentId },
1997
+ );
1998
+ }
1999
+ // Store the sub-agent name/description for the tab label
2000
+ const name = detail.name || detail.description || "";
2001
+ if (name) {
2002
+ setSubAgentNames((prev) =>
2003
+ prev[threadId] === name ? prev : { ...prev, [threadId]: name },
2004
+ );
2005
+ }
2006
+ // Refresh thread list so the new sub-agent thread appears with its title
2007
+ refreshThreads();
2008
+ // Open the sub-agent thread as a tab — insert after parent for visual grouping
2009
+ if (!openTabIds.includes(threadId)) {
2010
+ setOpenTabIds((prev) => {
2011
+ if (parentId) {
2012
+ const parentIdx = prev.indexOf(parentId);
2013
+ if (parentIdx !== -1) {
2014
+ // Insert after the parent (and any existing children of that parent)
2015
+ const next = [...prev];
2016
+ let insertIdx = parentIdx + 1;
2017
+ // Skip past any existing children of the same parent
2018
+ while (
2019
+ insertIdx < next.length &&
2020
+ parentMap[next[insertIdx]] === parentId
2021
+ ) {
2022
+ insertIdx++;
2023
+ }
2024
+ next.splice(insertIdx, 0, threadId);
2025
+ return next;
2026
+ }
2027
+ }
2028
+ return [...prev, threadId];
2029
+ });
2030
+ }
2031
+ switchThread(threadId);
2032
+ }
2033
+ window.addEventListener("agent-task-open", handleOpenTask);
2034
+ return () => window.removeEventListener("agent-task-open", handleOpenTask);
2035
+ }, [openTabIds, switchThread, refreshThreads, parentMap]);
2036
+
2037
+ // Replay thread/task opens requested before this lazy panel's listeners
2038
+ // attached. Live events claim their id; replay drains only unclaimed requests.
2039
+ useEffect(() => {
2040
+ const buffered = drainBufferedAgentChatOpenRequests();
2041
+ for (const request of buffered) {
2042
+ window.dispatchEvent(
2043
+ new CustomEvent(request.eventType, { detail: request.detail }),
2044
+ );
2045
+ }
2046
+ }, []);
2047
+
2048
+ // Watch for agent-issued chat-command in application-state. The shared
2049
+ // DB-sync transport advances this key-specific version, so the command gets
2050
+ // one initial read and one read per actual write instead of a 2s loop.
2051
+ const lastChatCommandRef = useRef(0);
2052
+ const chatCommandVersion = useChangeVersion("app-state:chat-command");
2053
+ useEffect(() => {
2054
+ let stopped = false;
2055
+
2056
+ async function readChatCommand() {
2057
+ if (stopped) return;
2058
+ try {
2059
+ const res = await fetch(
2060
+ agentNativePath("/_agent-native/application-state/chat-command"),
2061
+ );
2062
+ if (res.ok) {
2063
+ const data = await res.json();
2064
+ if (
2065
+ data?.value?.command === "open-thread" &&
2066
+ data.value.threadId &&
2067
+ data.value.timestamp > lastChatCommandRef.current
2068
+ ) {
2069
+ lastChatCommandRef.current = data.value.timestamp;
2070
+ const threadId = data.value.threadId as string;
2071
+ // Open the thread as a tab and focus it
2072
+ setOpenTabIds((prev) =>
2073
+ prev.includes(threadId) ? prev : [...prev, threadId],
2074
+ );
2075
+ switchThread(threadId);
2076
+ // Clear the command
2077
+ fetch(
2078
+ agentNativePath("/_agent-native/application-state/chat-command"),
2079
+ {
2080
+ method: "DELETE",
2081
+ headers: { "X-Agent-Native-CSRF": "1" },
2082
+ },
2083
+ ).catch(() => {});
2084
+ }
2085
+ }
2086
+ } catch {}
2087
+ }
2088
+
2089
+ void readChatCommand();
2090
+ return () => {
2091
+ stopped = true;
2092
+ };
2093
+ }, [chatCommandVersion, switchThread]);
2094
+
2095
+ const handleGenerateTitle = useCallback(
2096
+ (threadId: string, message: string) => {
2097
+ generateTitle(threadId, message).then((title) => {
2098
+ if (title) {
2099
+ // Persist the generated title to the server
2100
+ saveThreadData(threadId, {
2101
+ threadData: "",
2102
+ title,
2103
+ preview: message.slice(0, 120),
2104
+ titleSource: "generated",
2105
+ });
2106
+ }
2107
+ });
2108
+ },
2109
+ [generateTitle, saveThreadData],
2110
+ );
2111
+
2112
+ const handleSaveThread = useCallback(
2113
+ (
2114
+ threadId: string,
2115
+ data: {
2116
+ threadData: string;
2117
+ title: string;
2118
+ preview: string;
2119
+ messageCount: number;
2120
+ },
2121
+ ) => {
2122
+ saveThreadData(threadId, data);
2123
+ if (
2124
+ data.messageCount > 0 &&
2125
+ threadId === activeThreadIdRef.current &&
2126
+ urlThreadIdRef.current !== threadId
2127
+ ) {
2128
+ writeThreadUrl(threadId);
2129
+ }
2130
+ },
2131
+ [saveThreadData, writeThreadUrl],
2132
+ );
2133
+
2134
+ // ─── Slash command handler ──────────────────────────────────────────
2135
+ const [helpVisible, setHelpVisible] = useState(false);
2136
+
2137
+ const handleSlashCommand = useCallback(
2138
+ (command: string) => {
2139
+ switch (command) {
2140
+ case "clear":
2141
+ case "new":
2142
+ addTab();
2143
+ break;
2144
+ case "history":
2145
+ setShowHistory(true);
2146
+ break;
2147
+ case "plan":
2148
+ props.onExecModeChange?.("plan");
2149
+ break;
2150
+ case "act":
2151
+ props.onExecModeChange?.("build");
2152
+ break;
2153
+ case "help":
2154
+ setHelpVisible(true);
2155
+ break;
2156
+ }
2157
+ },
2158
+ [addTab, props.onExecModeChange],
2159
+ );
2160
+
2161
+ const handleForkChat = useCallback(
2162
+ async (sourceThreadId: string) => {
2163
+ const sourceSnapshot =
2164
+ chatRefs.current.get(sourceThreadId)?.exportThreadSnapshot() ?? null;
2165
+ const forkedId = await forkThread(sourceThreadId, sourceSnapshot);
2166
+ if (!forkedId) return false;
2167
+ setOpenTabIds((prev) => {
2168
+ const idx = prev.indexOf(sourceThreadId);
2169
+ if (idx !== -1) {
2170
+ const next = [...prev];
2171
+ next.splice(idx + 1, 0, forkedId);
2172
+ return next;
2173
+ }
2174
+ return [...prev, forkedId];
2175
+ });
2176
+ switchThread(forkedId);
2177
+ return true;
2178
+ },
2179
+ [forkThread, switchThread],
2180
+ );
2181
+
2182
+ // Build tabs from open thread IDs. During the first thread-list fetch,
2183
+ // `activeThreadId` is seeded synchronously so the chat can mount before
2184
+ // persisted open tabs have been reconciled.
2185
+ const visibleOpenTabIds =
2186
+ activeThreadId && !openTabIds.includes(activeThreadId)
2187
+ ? [...openTabIds, activeThreadId]
2188
+ : openTabIds;
2189
+ const threadMap = new Map(threads.map((t) => [t.id, t]));
2190
+ const tabs: ChatTab[] = visibleOpenTabIds
2191
+ .filter((id) => threadMap.has(id) || id === activeThreadId)
2192
+ .map((id) => {
2193
+ const t = threadMap.get(id);
2194
+ const agentTeamStatus = chatTabStatusFromAgentTeamStatus(
2195
+ subAgentStatuses[id],
2196
+ );
2197
+ return {
2198
+ id,
2199
+ label: t?.title || t?.preview?.slice(0, 30) || "New chat",
2200
+ status:
2201
+ agentTeamStatus ??
2202
+ (runningThreads.has(id)
2203
+ ? ("running" as const)
2204
+ : (messageCounts[id] ?? t?.messageCount ?? 0) > 0
2205
+ ? ("completed" as const)
2206
+ : ("idle" as const)),
2207
+ parentThreadId: parentMap[id],
2208
+ subAgentName: subAgentNames[id],
2209
+ };
2210
+ });
2211
+
2212
+ // Include sub-agent tabs that aren't in threadMap yet (just created, not refreshed)
2213
+ for (const id of visibleOpenTabIds) {
2214
+ if (!tabs.some((t) => t.id === id)) {
2215
+ tabs.push({
2216
+ id,
2217
+ label:
2218
+ subAgentNames[id] || (parentMap[id] ? "Sub-agent..." : "New chat"),
2219
+ status:
2220
+ chatTabStatusFromAgentTeamStatus(subAgentStatuses[id]) ??
2221
+ ("running" as const),
2222
+ parentThreadId: parentMap[id],
2223
+ subAgentName: subAgentNames[id],
2224
+ });
2225
+ }
2226
+ }
2227
+
2228
+ const headerProps: MultiTabAssistantChatHeaderProps = {
2229
+ tabs,
2230
+ activeTabId: activeThreadId ?? "",
2231
+ activeTabMessageCount: activeThreadId
2232
+ ? (messageCounts[activeThreadId] ?? 0)
2233
+ : 0,
2234
+ setActiveTabId: switchThread,
2235
+ addTab,
2236
+ closeTab,
2237
+ closeOtherTabs,
2238
+ closeAllTabs,
2239
+ clearActiveTab,
2240
+ showHistory,
2241
+ toggleHistory: () => setShowHistory((v) => !v),
2242
+ tabCount: visibleOpenTabIds.length,
2243
+ };
2244
+
2245
+ // Wait for the first thread-list pass only when there is no synchronously
2246
+ // seeded active thread. Suggestion loading and thread-list reconciliation
2247
+ // should not block the chat shell from mounting.
2248
+ if (isLoading && !activeThreadId) {
2249
+ return (
2250
+ <ChatSkeleton
2251
+ header={renderHeader?.(headerProps)}
2252
+ headerOnly={contentHidden}
2253
+ />
2254
+ );
2255
+ }
2256
+
2257
+ return (
2258
+ <div className="flex flex-1 flex-col h-full min-h-0 overflow-x-hidden">
2259
+ {/* Tailwind group-hover/tab doesn't work in core package — inject directly */}
2260
+ <style
2261
+ dangerouslySetInnerHTML={{
2262
+ __html:
2263
+ ".agent-tab-close{opacity:0}.agent-tab:hover .agent-tab-close{opacity:1}" +
2264
+ ".agent-tabs-scroll{scrollbar-width:none;-ms-overflow-style:none;}" +
2265
+ ".agent-tabs-scroll::-webkit-scrollbar{display:none;}",
2266
+ }}
2267
+ />
2268
+ {renderHeader
2269
+ ? renderHeader(headerProps)
2270
+ : showTabBar
2271
+ ? (() => {
2272
+ const activeTab = tabs.find((t) => t.id === activeThreadId);
2273
+ const focusParentId = activeTab?.parentThreadId || activeThreadId;
2274
+ const childTabs = tabs.filter(
2275
+ (t) => t.parentThreadId === focusParentId,
2276
+ );
2277
+ const hasSubTabs = childTabs.length > 0;
2278
+ const mainTabs = tabs.filter((t) => !t.parentThreadId);
2279
+
2280
+ return (
2281
+ <>
2282
+ <div className="flex items-center px-1 py-1 border-b border-border shrink-0 gap-0.5">
2283
+ <div className="agent-tabs-scroll flex items-center gap-0.5 min-w-0 overflow-x-auto flex-1">
2284
+ {mainTabs.map((tab) => {
2285
+ const isActive =
2286
+ tab.id === activeThreadId ||
2287
+ (tab.id === focusParentId &&
2288
+ activeTab?.parentThreadId === tab.id);
2289
+ return (
2290
+ <div
2291
+ key={tab.id}
2292
+ ref={isActive ? activeTabRefCb : undefined}
2293
+ className={cn(
2294
+ "agent-tab relative flex items-center rounded-md text-[11px] font-medium shrink-0 max-w-[130px]",
2295
+ isActive
2296
+ ? "bg-accent text-foreground ring-1 ring-inset ring-border/60 shadow-sm"
2297
+ : "text-muted-foreground hover:text-foreground hover:bg-accent/50",
2298
+ )}
2299
+ >
2300
+ <button
2301
+ type="button"
2302
+ onClick={() => switchThread(tab.id)}
2303
+ className="flex items-center gap-1 px-2.5 py-1.5 min-w-0 flex-1 text-start"
2304
+ >
2305
+ <span className="truncate pe-1">{tab.label}</span>
2306
+ {tab.status === "running" && (
2307
+ <span className="w-1.5 h-1.5 rounded-full bg-muted-foreground/50 shrink-0 animate-pulse" />
2308
+ )}
2309
+ </button>
2310
+ <button
2311
+ type="button"
2312
+ aria-label="Close tab"
2313
+ onClick={(e) => {
2314
+ e.stopPropagation();
2315
+ e.preventDefault();
2316
+ closeTab(tab.id);
2317
+ }}
2318
+ className="agent-tab-close flex items-center justify-end text-muted-foreground hover:!text-foreground"
2319
+ style={{
2320
+ position: "absolute",
2321
+ right: 0,
2322
+ top: 0,
2323
+ bottom: 0,
2324
+ width: 28,
2325
+ paddingRight: 6,
2326
+ borderRadius: "0 6px 6px 0",
2327
+ background:
2328
+ "linear-gradient(to right, transparent, hsl(var(--accent)) 40%)",
2329
+ }}
2330
+ >
2331
+ <IconX size={12} />
2332
+ </button>
2333
+ </div>
2334
+ );
2335
+ })}
2336
+ </div>
2337
+ <TooltipProvider delayDuration={200}>
2338
+ <div className="flex items-center gap-px shrink-0 ms-auto">
2339
+ <Tooltip>
2340
+ <TooltipTrigger asChild>
2341
+ <button
2342
+ onClick={addTab}
2343
+ aria-label="New chat"
2344
+ className="flex h-6 w-6 items-center justify-center rounded text-muted-foreground/60 hover:text-foreground hover:bg-accent/50"
2345
+ >
2346
+ <IconPlus size={12} />
2347
+ </button>
2348
+ </TooltipTrigger>
2349
+ <TooltipContent>New chat</TooltipContent>
2350
+ </Tooltip>
2351
+ <Tooltip>
2352
+ <TooltipTrigger asChild>
2353
+ <button
2354
+ onClick={() => setShowHistory(!showHistory)}
2355
+ aria-label="All chats"
2356
+ className={cn(
2357
+ "flex h-6 w-6 items-center justify-center rounded text-muted-foreground/60 hover:text-foreground hover:bg-accent/50",
2358
+ showHistory && "bg-accent text-foreground",
2359
+ )}
2360
+ >
2361
+ <IconHistory size={12} />
2362
+ </button>
2363
+ </TooltipTrigger>
2364
+ <TooltipContent>All chats</TooltipContent>
2365
+ </Tooltip>
2366
+ </div>
2367
+ </TooltipProvider>
2368
+ </div>
2369
+ {hasSubTabs && (
2370
+ <div className="flex items-center px-1 py-0.5 border-b border-border shrink-0 gap-0.5 bg-muted/30">
2371
+ <div className="agent-tabs-scroll flex items-center gap-0.5 min-w-0 overflow-x-auto flex-1">
2372
+ <button
2373
+ onClick={() => switchThread(focusParentId!)}
2374
+ className={cn(
2375
+ "flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium cursor-pointer",
2376
+ activeThreadId === focusParentId
2377
+ ? "bg-accent text-foreground"
2378
+ : "text-muted-foreground hover:bg-accent hover:text-foreground",
2379
+ )}
2380
+ >
2381
+ Main
2382
+ </button>
2383
+ {childTabs.map((tab) => (
2384
+ <div
2385
+ key={tab.id}
2386
+ ref={
2387
+ tab.id === activeThreadId
2388
+ ? activeTabRefCb
2389
+ : undefined
2390
+ }
2391
+ className={cn(
2392
+ "agent-tab relative flex shrink-0 items-center rounded-md text-[10px] font-medium max-w-[130px]",
2393
+ tab.id === activeThreadId
2394
+ ? "bg-accent text-foreground"
2395
+ : "text-muted-foreground hover:bg-accent hover:text-foreground",
2396
+ )}
2397
+ >
2398
+ <button
2399
+ type="button"
2400
+ onClick={() => switchThread(tab.id)}
2401
+ className="flex items-center gap-1 px-2 py-1 min-w-0 flex-1 text-start"
2402
+ >
2403
+ <span className="truncate pe-1">
2404
+ {tab.subAgentName || tab.label}
2405
+ </span>
2406
+ {tab.status === "running" && (
2407
+ <span className="w-1 h-1 rounded-full bg-muted-foreground/50 shrink-0 animate-pulse" />
2408
+ )}
2409
+ </button>
2410
+ <button
2411
+ type="button"
2412
+ aria-label="Close tab"
2413
+ onClick={(e) => {
2414
+ e.stopPropagation();
2415
+ e.preventDefault();
2416
+ closeTab(tab.id);
2417
+ }}
2418
+ className="agent-tab-close flex items-center justify-end text-muted-foreground hover:!text-foreground"
2419
+ style={{
2420
+ position: "absolute",
2421
+ right: 0,
2422
+ top: 0,
2423
+ bottom: 0,
2424
+ width: 24,
2425
+ paddingRight: 4,
2426
+ borderRadius: "0 6px 6px 0",
2427
+ background:
2428
+ "linear-gradient(to right, transparent, hsl(var(--accent)) 40%)",
2429
+ }}
2430
+ >
2431
+ <IconX size={12} />
2432
+ </button>
2433
+ </div>
2434
+ ))}
2435
+ </div>
2436
+ </div>
2437
+ )}
2438
+ </>
2439
+ );
2440
+ })()
2441
+ : null}
2442
+
2443
+ {/* Chat content with optional overlay */}
2444
+ <div
2445
+ className="relative flex-1 flex flex-col min-h-0"
2446
+ data-agent-page-chat-scrolled={
2447
+ renderOverlay && pageOverlayScrolled ? "" : undefined
2448
+ }
2449
+ onScrollCapture={renderOverlay ? handlePageOverlayScroll : undefined}
2450
+ >
2451
+ {renderOverlay ? renderOverlay(headerProps) : null}
2452
+
2453
+ {/* History popover — rendered inside relative container so positioning works */}
2454
+ {showHistory && (
2455
+ <HistoryPopover
2456
+ threads={threads}
2457
+ openTabIds={new Set(openTabIds)}
2458
+ activeThreadId={activeThreadId}
2459
+ hasMoreThreads={hasMoreThreads}
2460
+ isLoadingMoreThreads={isLoadingMoreThreads}
2461
+ loadError={threadsLoadError}
2462
+ onSelect={openFromHistory}
2463
+ onClose={() => setShowHistory(false)}
2464
+ onLoadMore={loadMoreThreads}
2465
+ onSearch={searchThreads}
2466
+ onTogglePin={pinThread}
2467
+ onRename={renameThread}
2468
+ />
2469
+ )}
2470
+
2471
+ {/* Help popover — shown by /help slash command */}
2472
+ {helpVisible && <HelpPopover onClose={() => setHelpVisible(false)} />}
2473
+
2474
+ {/* Render tabs that have been activated at least once, hide inactive ones to preserve state.
2475
+ Sub-agent tabs are only mounted when first focused — prevents stale restore from running
2476
+ while the component is display:none before the user switches to it. */}
2477
+ {[...new Set(visibleOpenTabIds)]
2478
+ .filter(
2479
+ (tabId) =>
2480
+ tabId === activeThreadId || mountedTabsRef.current.has(tabId),
2481
+ )
2482
+ .map((tabId) => {
2483
+ const modelSelection = resolveThreadModelSelection(tabId);
2484
+ const tabDynamicSuggestions =
2485
+ tabId === activeThreadId && !contentHidden
2486
+ ? props.dynamicSuggestions
2487
+ : false;
2488
+ return (
2489
+ <div
2490
+ key={tabId}
2491
+ className="flex-1 min-h-0 flex-col"
2492
+ style={{
2493
+ display:
2494
+ contentHidden || tabId !== activeThreadId ? "none" : "flex",
2495
+ }}
2496
+ >
2497
+ <KeepTabOpenNotice
2498
+ threadId={tabId}
2499
+ enabled={tabId === activeThreadId}
2500
+ apiUrl={apiUrl}
2501
+ />
2502
+ <RunStuckBanner
2503
+ threadId={tabId}
2504
+ enabled={tabId === activeThreadId}
2505
+ apiUrl={apiUrl}
2506
+ autoRetry
2507
+ autoRetryOwnerId={browserTabId}
2508
+ hasInFlightWork={() =>
2509
+ chatRefs.current.get(tabId)?.hasInFlightWork() ?? false
2510
+ }
2511
+ onRetry={() => {
2512
+ const handle = chatRefs.current.get(tabId);
2513
+ handle?.sendRecoveryMessage(
2514
+ "Continue from where you left off and finish my last request. Do not repeat completed work.",
2515
+ "continue",
2516
+ );
2517
+ }}
2518
+ />
2519
+ <AssistantChat
2520
+ {...props}
2521
+ dynamicSuggestions={tabDynamicSuggestions}
2522
+ ref={(handle) => {
2523
+ if (handle) {
2524
+ chatRefs.current.set(tabId, handle);
2525
+ } else {
2526
+ chatRefs.current.delete(tabId);
2527
+ }
2528
+ }}
2529
+ threadId={tabId}
2530
+ tabId={tabId}
2531
+ browserTabId={browserTabId}
2532
+ isActiveComposer={tabId === activeThreadId}
2533
+ apiUrl={apiUrl}
2534
+ isNewThread={
2535
+ newThreadIds.current.has(tabId) || isNewThread(tabId)
2536
+ }
2537
+ onMessageCountChange={(count) =>
2538
+ setMessageCounts((prev) =>
2539
+ prev[tabId] === count
2540
+ ? prev
2541
+ : { ...prev, [tabId]: count },
2542
+ )
2543
+ }
2544
+ onSaveThread={handleSaveThread}
2545
+ onGenerateTitle={handleGenerateTitle}
2546
+ onSlashCommand={handleSlashCommand}
2547
+ selectedModel={modelSelection?.model}
2548
+ selectedEngine={modelSelection?.engine}
2549
+ selectedEffort={
2550
+ modelSelection?.effort ?? DEFAULT_REASONING_EFFORT
2551
+ }
2552
+ composerSlot={props.composerSlot}
2553
+ defaultModel={defaultModel}
2554
+ availableModels={availableModels}
2555
+ modelListLoading={modelListLoading}
2556
+ onModelChange={handleModelChange}
2557
+ onEffortChange={handleEffortChange}
2558
+ onForkChat={() => handleForkChat(tabId)}
2559
+ // Sub-agent tabs are read-only: sending a new message from the
2560
+ // sub-agent tab would start a fresh run on that thread and kill
2561
+ // the in-flight team chunk. Disable the composer and show a
2562
+ // hint so users know to send via the orchestrator chat instead.
2563
+ composerDisabled={Boolean(parentMap[tabId])}
2564
+ composerDisabledPlaceholder={
2565
+ parentMap[tabId]
2566
+ ? "Send messages to the orchestrator chat — this sub-agent runs automatically"
2567
+ : undefined
2568
+ }
2569
+ />
2570
+ </div>
2571
+ );
2572
+ })}
2573
+ </div>
2574
+ </div>
2575
+ );
2576
+ }