@agent-native/core 0.113.0 → 0.114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1508) hide show
  1. package/agent-native.eject.json +164 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +11 -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/index.ts +4 -0
  12. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +8 -2
  13. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +7 -2
  14. package/corpus/core/src/client/resources/ResourcesPanel.tsx +17 -3
  15. package/corpus/core/src/client/resources/index.ts +19 -0
  16. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +9 -1
  17. package/corpus/core/src/client/resources/runtime.ts +1 -0
  18. package/corpus/core/src/client/setup-connections/catalog.ts +6 -0
  19. package/corpus/core/src/client/setup-connections/index.ts +1 -0
  20. package/corpus/core/src/client/setup-connections/runtime.ts +1 -0
  21. package/corpus/core/src/connections/catalog.ts +41 -24
  22. package/corpus/core/src/connections/index.ts +1 -0
  23. package/corpus/core/src/connections/runtime.ts +1 -0
  24. package/corpus/core/src/eject/provider-api-definitions.ts +193 -0
  25. package/corpus/core/src/eject/remote-mcp-presets.ts +137 -0
  26. package/corpus/core/src/eject/setup-readiness-ui.tsx +29 -0
  27. package/corpus/core/src/eject/workspace-connections.ts +92 -0
  28. package/corpus/core/src/index.ts +1 -0
  29. package/corpus/core/src/integrations/adapter-overrides.ts +12 -0
  30. package/corpus/core/src/integrations/eject/messaging-adapters.ts +85 -0
  31. package/corpus/core/src/integrations/index.ts +5 -1
  32. package/corpus/core/src/integrations/plugin.ts +34 -12
  33. package/corpus/core/src/integrations/runtime.ts +1 -0
  34. package/corpus/core/src/integrations/types.ts +3 -1
  35. package/corpus/core/src/package-lifecycle/eject-manifest.ts +345 -0
  36. package/corpus/core/src/package-lifecycle/index.ts +1 -0
  37. package/corpus/core/src/provider-api/index.ts +46 -12
  38. package/corpus/core/src/provider-api/runtime.ts +1 -0
  39. package/corpus/core/src/setup-connections/index.ts +1 -0
  40. package/corpus/core/src/shared/merge-by-id.ts +14 -0
  41. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +15 -13
  42. package/corpus/core/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  43. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +9 -6
  44. package/corpus/core/src/templates/default/AGENTS.md +6 -5
  45. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +15 -13
  46. package/corpus/core/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  47. package/corpus/core/src/templates/headless/AGENTS.md +5 -4
  48. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +15 -13
  49. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +3 -2
  50. package/corpus/core/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  51. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +9 -6
  52. package/corpus/core/src/templates/workspace-core/AGENTS.md +4 -4
  53. package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -4
  54. package/corpus/core/src/vite/client.ts +25 -2
  55. package/corpus/templates/analytics/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  56. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +9 -6
  57. package/corpus/templates/assets/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  58. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +9 -6
  59. package/corpus/templates/brain/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  60. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +9 -6
  61. package/corpus/templates/brain/actions/remediate-legacy-capture-audiences.ts +167 -0
  62. package/corpus/templates/brain/app/lib/brain-chat-readiness.ts +6 -0
  63. package/corpus/templates/brain/app/routes/_index.tsx +8 -0
  64. package/corpus/templates/brain/app/routes.ts +1 -0
  65. package/corpus/templates/brain/changelog/2026-07-19-ask-starts-immediately-when-builder-s-managed-ai-connection-.md +6 -0
  66. package/corpus/templates/brain/changelog/2026-07-19-slack-and-granola-backfills-now-process-captures-concurrentl.md +6 -0
  67. package/corpus/templates/brain/changelog/2026-07-19-source-review-settings-now-control-knowledge-approval.md +6 -0
  68. package/corpus/templates/brain/changelog/2026-07-19-the-manage-agent-page-now-opens-correctly-from-brain-navigat.md +6 -0
  69. package/corpus/templates/brain/server/db/schema.ts +3 -0
  70. package/corpus/templates/brain/server/lib/brain.ts +41 -2
  71. package/corpus/templates/brain/server/lib/connectors.ts +379 -113
  72. package/corpus/templates/brain/server/lib/meeting-audience.ts +38 -0
  73. package/corpus/templates/brain/server/plugins/db.ts +10 -0
  74. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +6 -4
  75. package/corpus/templates/calendar/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  76. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +9 -6
  77. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +15 -13
  78. package/corpus/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  79. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +9 -6
  80. package/corpus/templates/chat/AGENTS.md +3 -2
  81. package/corpus/templates/clips/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  82. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +9 -6
  83. package/corpus/templates/content/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  84. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +9 -6
  85. package/corpus/templates/design/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  86. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +9 -6
  87. package/corpus/templates/dispatch/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  88. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +9 -6
  89. package/corpus/templates/forms/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  90. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +9 -6
  91. package/corpus/templates/macros/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  92. package/corpus/templates/mail/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  93. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +9 -6
  94. package/corpus/templates/plan/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  95. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +9 -6
  96. package/corpus/templates/slides/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  97. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +9 -6
  98. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +15 -13
  99. package/corpus/templates/tasks/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  100. package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +9 -6
  101. package/corpus/toolkit/CHANGELOG.md +6 -0
  102. package/corpus/toolkit/agent-native.eject.json +411 -0
  103. package/corpus/toolkit/package.json +5 -2
  104. package/dist/cli/eject.d.ts +21 -0
  105. package/dist/cli/eject.d.ts.map +1 -0
  106. package/dist/cli/eject.js +1145 -0
  107. package/dist/cli/eject.js.map +1 -0
  108. package/dist/cli/index.js +15 -0
  109. package/dist/cli/index.js.map +1 -1
  110. package/dist/client/index.d.ts +1 -1
  111. package/dist/client/index.d.ts.map +1 -1
  112. package/dist/client/index.js +1 -1
  113. package/dist/client/index.js.map +1 -1
  114. package/dist/client/resources/McpConnectionSuggestion.d.ts +4 -3
  115. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  116. package/dist/client/resources/McpConnectionSuggestion.js +3 -3
  117. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  118. package/dist/client/resources/McpIntegrationDialog.d.ts +4 -3
  119. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  120. package/dist/client/resources/McpIntegrationDialog.js +2 -2
  121. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  122. package/dist/client/resources/ResourcesPanel.d.ts +4 -1
  123. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  124. package/dist/client/resources/ResourcesPanel.js +9 -7
  125. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  126. package/dist/client/resources/index.d.ts +3 -0
  127. package/dist/client/resources/index.d.ts.map +1 -1
  128. package/dist/client/resources/index.js +3 -0
  129. package/dist/client/resources/index.js.map +1 -1
  130. package/dist/client/resources/mcp-integration-catalog.d.ts +2 -1
  131. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  132. package/dist/client/resources/mcp-integration-catalog.js +6 -2
  133. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  134. package/dist/client/resources/runtime.d.ts +2 -0
  135. package/dist/client/resources/runtime.d.ts.map +1 -0
  136. package/dist/client/resources/runtime.js +2 -0
  137. package/dist/client/resources/runtime.js.map +1 -0
  138. package/dist/client/setup-connections/catalog.d.ts +2 -0
  139. package/dist/client/setup-connections/catalog.d.ts.map +1 -0
  140. package/dist/client/setup-connections/catalog.js +7 -0
  141. package/dist/client/setup-connections/catalog.js.map +1 -0
  142. package/dist/client/setup-connections/index.d.ts +1 -0
  143. package/dist/client/setup-connections/index.d.ts.map +1 -1
  144. package/dist/client/setup-connections/index.js +1 -0
  145. package/dist/client/setup-connections/index.js.map +1 -1
  146. package/dist/client/setup-connections/runtime.d.ts +2 -0
  147. package/dist/client/setup-connections/runtime.d.ts.map +1 -0
  148. package/dist/client/setup-connections/runtime.js +2 -0
  149. package/dist/client/setup-connections/runtime.js.map +1 -0
  150. package/dist/collab/awareness.d.ts +2 -2
  151. package/dist/collab/awareness.d.ts.map +1 -1
  152. package/dist/collab/routes.d.ts +1 -1
  153. package/dist/connections/catalog.d.ts +5 -3
  154. package/dist/connections/catalog.d.ts.map +1 -1
  155. package/dist/connections/catalog.js +16 -8
  156. package/dist/connections/catalog.js.map +1 -1
  157. package/dist/connections/index.d.ts +1 -1
  158. package/dist/connections/index.d.ts.map +1 -1
  159. package/dist/connections/index.js +1 -1
  160. package/dist/connections/index.js.map +1 -1
  161. package/dist/connections/runtime.d.ts +2 -0
  162. package/dist/connections/runtime.d.ts.map +1 -0
  163. package/dist/connections/runtime.js +2 -0
  164. package/dist/connections/runtime.js.map +1 -0
  165. package/dist/eject/provider-api-definitions.d.ts +34 -0
  166. package/dist/eject/provider-api-definitions.d.ts.map +1 -0
  167. package/dist/eject/provider-api-definitions.js +88 -0
  168. package/dist/eject/provider-api-definitions.js.map +1 -0
  169. package/dist/eject/remote-mcp-presets.d.ts +17 -0
  170. package/dist/eject/remote-mcp-presets.d.ts.map +1 -0
  171. package/dist/eject/remote-mcp-presets.js +81 -0
  172. package/dist/eject/remote-mcp-presets.js.map +1 -0
  173. package/dist/eject/setup-readiness-ui.d.ts +7 -0
  174. package/dist/eject/setup-readiness-ui.d.ts.map +1 -0
  175. package/dist/eject/setup-readiness-ui.js +13 -0
  176. package/dist/eject/setup-readiness-ui.js.map +1 -0
  177. package/dist/eject/workspace-connections.d.ts +11 -0
  178. package/dist/eject/workspace-connections.d.ts.map +1 -0
  179. package/dist/eject/workspace-connections.js +47 -0
  180. package/dist/eject/workspace-connections.js.map +1 -0
  181. package/dist/index.d.ts +1 -1
  182. package/dist/index.d.ts.map +1 -1
  183. package/dist/index.js +1 -1
  184. package/dist/index.js.map +1 -1
  185. package/dist/integrations/adapter-overrides.d.ts +3 -0
  186. package/dist/integrations/adapter-overrides.d.ts.map +1 -0
  187. package/dist/integrations/adapter-overrides.js +7 -0
  188. package/dist/integrations/adapter-overrides.js.map +1 -0
  189. package/dist/integrations/eject/messaging-adapters.d.ts +12 -0
  190. package/dist/integrations/eject/messaging-adapters.d.ts.map +1 -0
  191. package/dist/integrations/eject/messaging-adapters.js +49 -0
  192. package/dist/integrations/eject/messaging-adapters.js.map +1 -0
  193. package/dist/integrations/index.d.ts +3 -2
  194. package/dist/integrations/index.d.ts.map +1 -1
  195. package/dist/integrations/index.js +2 -1
  196. package/dist/integrations/index.js.map +1 -1
  197. package/dist/integrations/plugin.d.ts +32 -1
  198. package/dist/integrations/plugin.d.ts.map +1 -1
  199. package/dist/integrations/plugin.js +19 -12
  200. package/dist/integrations/plugin.js.map +1 -1
  201. package/dist/integrations/runtime.d.ts +2 -0
  202. package/dist/integrations/runtime.d.ts.map +1 -0
  203. package/dist/integrations/runtime.js +2 -0
  204. package/dist/integrations/runtime.js.map +1 -0
  205. package/dist/integrations/types.d.ts +3 -1
  206. package/dist/integrations/types.d.ts.map +1 -1
  207. package/dist/integrations/types.js.map +1 -1
  208. package/dist/notifications/routes.d.ts +3 -3
  209. package/dist/package-lifecycle/eject-manifest.d.ts +43 -0
  210. package/dist/package-lifecycle/eject-manifest.d.ts.map +1 -0
  211. package/dist/package-lifecycle/eject-manifest.js +219 -0
  212. package/dist/package-lifecycle/eject-manifest.js.map +1 -0
  213. package/dist/package-lifecycle/index.d.ts +1 -0
  214. package/dist/package-lifecycle/index.d.ts.map +1 -1
  215. package/dist/package-lifecycle/index.js +1 -0
  216. package/dist/package-lifecycle/index.js.map +1 -1
  217. package/dist/progress/routes.d.ts +1 -1
  218. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  219. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  220. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  221. package/dist/provider-api/index.d.ts +6 -2
  222. package/dist/provider-api/index.d.ts.map +1 -1
  223. package/dist/provider-api/index.js +25 -12
  224. package/dist/provider-api/index.js.map +1 -1
  225. package/dist/provider-api/runtime.d.ts +2 -0
  226. package/dist/provider-api/runtime.d.ts.map +1 -0
  227. package/dist/provider-api/runtime.js +2 -0
  228. package/dist/provider-api/runtime.js.map +1 -0
  229. package/dist/secrets/routes.d.ts +9 -9
  230. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  231. package/dist/server/transcribe-voice.d.ts +1 -1
  232. package/dist/setup-connections/index.d.ts +1 -1
  233. package/dist/setup-connections/index.d.ts.map +1 -1
  234. package/dist/setup-connections/index.js +1 -1
  235. package/dist/setup-connections/index.js.map +1 -1
  236. package/dist/shared/merge-by-id.d.ts +5 -0
  237. package/dist/shared/merge-by-id.d.ts.map +1 -0
  238. package/dist/shared/merge-by-id.js +7 -0
  239. package/dist/shared/merge-by-id.js.map +1 -0
  240. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +15 -13
  241. package/dist/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  242. package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +9 -6
  243. package/dist/templates/chat/AGENTS.md +3 -2
  244. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +15 -13
  245. package/dist/templates/default/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  246. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +9 -6
  247. package/dist/templates/default/AGENTS.md +6 -5
  248. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +15 -13
  249. package/dist/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  250. package/dist/templates/headless/AGENTS.md +5 -4
  251. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +15 -13
  252. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +3 -2
  253. package/dist/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  254. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +9 -6
  255. package/dist/templates/workspace-core/AGENTS.md +4 -4
  256. package/dist/templates/workspace-root/AGENTS.md +4 -4
  257. package/dist/vite/client.d.ts.map +1 -1
  258. package/dist/vite/client.js +22 -2
  259. package/dist/vite/client.js.map +1 -1
  260. package/docs/content/agent-native-toolkit.mdx +38 -0
  261. package/docs/content/package-lifecycle.mdx +54 -4
  262. package/package.json +15 -2
  263. package/src/a2a/agent-card.ts +83 -0
  264. package/src/a2a/artifact-response.ts +1648 -0
  265. package/src/a2a/auth-policy.ts +66 -0
  266. package/src/a2a/caller-auth.ts +102 -0
  267. package/src/a2a/client.ts +876 -0
  268. package/src/a2a/correlation.ts +50 -0
  269. package/src/a2a/handlers.ts +1285 -0
  270. package/src/a2a/index.ts +50 -0
  271. package/src/a2a/invoke.ts +348 -0
  272. package/src/a2a/response-text.ts +53 -0
  273. package/src/a2a/server.ts +586 -0
  274. package/src/a2a/task-store.ts +917 -0
  275. package/src/a2a/types.ts +221 -0
  276. package/src/a2a-claims.ts +52 -0
  277. package/src/action-change-marker.ts +74 -0
  278. package/src/action-ui.ts +38 -0
  279. package/src/action.ts +1406 -0
  280. package/src/adapters/cli/index.ts +6 -0
  281. package/src/adapters/cli/registry.ts +73 -0
  282. package/src/adapters/cli/shell-adapter.ts +92 -0
  283. package/src/adapters/cli/types.ts +27 -0
  284. package/src/agent/action-continuation-guidance.ts +38 -0
  285. package/src/agent/app-model-defaults.ts +201 -0
  286. package/src/agent/context-xray/actions/context-evict.ts +56 -0
  287. package/src/agent/context-xray/actions/context-manifest-get.ts +75 -0
  288. package/src/agent/context-xray/actions/context-pin.ts +56 -0
  289. package/src/agent/context-xray/actions/context-preview-get.ts +134 -0
  290. package/src/agent/context-xray/actions/context-report.ts +75 -0
  291. package/src/agent/context-xray/actions/context-restore.ts +51 -0
  292. package/src/agent/context-xray/actions/errors.ts +40 -0
  293. package/src/agent/context-xray/apply-directives.ts +137 -0
  294. package/src/agent/context-xray/directives-store.ts +178 -0
  295. package/src/agent/context-xray/identity.ts +37 -0
  296. package/src/agent/context-xray/manifest.ts +284 -0
  297. package/src/agent/context-xray/migrations.ts +32 -0
  298. package/src/agent/context-xray/plugin.ts +23 -0
  299. package/src/agent/context-xray/schema.ts +17 -0
  300. package/src/agent/context-xray/segments.ts +194 -0
  301. package/src/agent/context-xray/tokenize.ts +93 -0
  302. package/src/agent/default-model.ts +5 -0
  303. package/src/agent/durable-background.ts +547 -0
  304. package/src/agent/engine/ai-sdk-engine.ts +565 -0
  305. package/src/agent/engine/anthropic-engine.ts +320 -0
  306. package/src/agent/engine/builder-engine.ts +1110 -0
  307. package/src/agent/engine/builder-gateway-headers.ts +44 -0
  308. package/src/agent/engine/builtin.ts +122 -0
  309. package/src/agent/engine/context-directives-transform.ts +73 -0
  310. package/src/agent/engine/continuation-dispatch-retry.ts +168 -0
  311. package/src/agent/engine/credential-errors.ts +69 -0
  312. package/src/agent/engine/index.ts +54 -0
  313. package/src/agent/engine/openai-compatible-endpoint.ts +25 -0
  314. package/src/agent/engine/output-tokens.ts +181 -0
  315. package/src/agent/engine/provider-env-vars.ts +69 -0
  316. package/src/agent/engine/registry.ts +853 -0
  317. package/src/agent/engine/tool-call-journal-seed.ts +85 -0
  318. package/src/agent/engine/translate-ai-sdk.ts +407 -0
  319. package/src/agent/engine/translate-anthropic.ts +611 -0
  320. package/src/agent/engine/types.ts +310 -0
  321. package/src/agent/harness/acp-adapter.ts +893 -0
  322. package/src/agent/harness/acp-builtin.ts +70 -0
  323. package/src/agent/harness/ai-sdk-adapter.ts +509 -0
  324. package/src/agent/harness/background.ts +365 -0
  325. package/src/agent/harness/builtin.ts +50 -0
  326. package/src/agent/harness/index.ts +86 -0
  327. package/src/agent/harness/lifecycle.ts +498 -0
  328. package/src/agent/harness/registry.ts +97 -0
  329. package/src/agent/harness/runner.ts +182 -0
  330. package/src/agent/harness/store.ts +466 -0
  331. package/src/agent/harness/translate.ts +130 -0
  332. package/src/agent/harness/types.ts +129 -0
  333. package/src/agent/index.ts +32 -0
  334. package/src/agent/loop-settings.ts +186 -0
  335. package/src/agent/model-config.ts +363 -0
  336. package/src/agent/observational-memory/compactor.ts +78 -0
  337. package/src/agent/observational-memory/config.ts +78 -0
  338. package/src/agent/observational-memory/index.ts +79 -0
  339. package/src/agent/observational-memory/internal-run.ts +89 -0
  340. package/src/agent/observational-memory/message-text.ts +49 -0
  341. package/src/agent/observational-memory/migrations.ts +44 -0
  342. package/src/agent/observational-memory/observer.ts +128 -0
  343. package/src/agent/observational-memory/plugin.ts +35 -0
  344. package/src/agent/observational-memory/prompts.ts +53 -0
  345. package/src/agent/observational-memory/read.ts +131 -0
  346. package/src/agent/observational-memory/reflector.ts +119 -0
  347. package/src/agent/observational-memory/schema.ts +48 -0
  348. package/src/agent/observational-memory/store.ts +275 -0
  349. package/src/agent/observational-memory/types.ts +65 -0
  350. package/src/agent/processors.ts +209 -0
  351. package/src/agent/production-agent.ts +8254 -0
  352. package/src/agent/run-loop-with-resume.ts +394 -0
  353. package/src/agent/run-manager.ts +1825 -0
  354. package/src/agent/run-ownership.ts +75 -0
  355. package/src/agent/run-store.ts +2601 -0
  356. package/src/agent/runtime-context.ts +169 -0
  357. package/src/agent/thread-data-builder.ts +1584 -0
  358. package/src/agent/tool-call-journal.ts +368 -0
  359. package/src/agent/tool-error-redaction.ts +52 -0
  360. package/src/agent/tool-result-images.ts +178 -0
  361. package/src/agent/tool-search.ts +376 -0
  362. package/src/agent/types.ts +372 -0
  363. package/src/agent-native/index.ts +198 -0
  364. package/src/agent-web/config.ts +253 -0
  365. package/src/agent-web/generator.ts +382 -0
  366. package/src/agent-web/index.ts +36 -0
  367. package/src/appearance/actions/change-appearance.ts +35 -0
  368. package/src/application-state/emitter.ts +81 -0
  369. package/src/application-state/handlers.ts +121 -0
  370. package/src/application-state/index.ts +44 -0
  371. package/src/application-state/script-helpers.ts +155 -0
  372. package/src/application-state/store.ts +274 -0
  373. package/src/assets/branding/agent-native.icon/Assets/background.svg +3 -0
  374. package/src/assets/branding/agent-native.icon/Assets/foreground.svg +12 -0
  375. package/src/assets/branding/agent-native.icon/icon.json +49 -0
  376. package/src/assets/branding/favicon.png +0 -0
  377. package/src/assets/branding/favicon.svg +1 -0
  378. package/src/assets/branding/icon-on-dark.svg +10 -0
  379. package/src/assets/branding/icon-on-light.svg +10 -0
  380. package/src/assets/branding/mac-app-icon.svg +1 -0
  381. package/src/assets/branding/slack-bot/agent-native-1024.png +0 -0
  382. package/src/assets/branding/slack-bot/agent-native-512.png +0 -0
  383. package/src/assets/branding/tray-icon.svg +6 -0
  384. package/src/assets/branding/wordmark-on-dark.svg +21 -0
  385. package/src/assets/branding/wordmark-on-light.svg +21 -0
  386. package/src/assets/fonts/LICENSE_LIBERATION +96 -0
  387. package/src/assets/fonts/LICENSE_NOTO_NASKH_ARABIC +93 -0
  388. package/src/assets/fonts/LiberationSans-Bold.ttf +0 -0
  389. package/src/assets/fonts/LiberationSans-Regular.ttf +0 -0
  390. package/src/assets/fonts/NotoNaskhArabic-Variable.ttf +0 -0
  391. package/src/audit/actions/export-audit-events.ts +162 -0
  392. package/src/audit/actions/get-audit-event.ts +24 -0
  393. package/src/audit/actions/list-audit-events.ts +66 -0
  394. package/src/audit/cleanup-job.ts +100 -0
  395. package/src/audit/config.ts +90 -0
  396. package/src/audit/index.ts +43 -0
  397. package/src/audit/record.ts +180 -0
  398. package/src/audit/redact.ts +109 -0
  399. package/src/audit/store.ts +346 -0
  400. package/src/audit/types.ts +141 -0
  401. package/src/automation/index.ts +802 -0
  402. package/src/brand-kit/brand-signals.ts +124 -0
  403. package/src/brand-kit/fig/index.ts +64 -0
  404. package/src/brand-kit/index.ts +72 -0
  405. package/src/brand-kit/types.ts +113 -0
  406. package/src/browser-sessions/actions.ts +302 -0
  407. package/src/browser-sessions/routes.ts +234 -0
  408. package/src/browser-sessions/store.ts +679 -0
  409. package/src/browser-sessions/types.ts +84 -0
  410. package/src/changelog/parse.ts +328 -0
  411. package/src/chat-threads/emitter.ts +22 -0
  412. package/src/chat-threads/schema.ts +43 -0
  413. package/src/chat-threads/store.ts +1311 -0
  414. package/src/checkpoints/index.ts +15 -0
  415. package/src/checkpoints/service.ts +142 -0
  416. package/src/checkpoints/store.ts +153 -0
  417. package/src/cli/add.ts +425 -0
  418. package/src/cli/agent.ts +424 -0
  419. package/src/cli/agents.ts +122 -0
  420. package/src/cli/app-skill.ts +1455 -0
  421. package/src/cli/atomic-json-file.ts +324 -0
  422. package/src/cli/audit-agent-web.ts +324 -0
  423. package/src/cli/changelog.ts +199 -0
  424. package/src/cli/claude-code-participant.ts +515 -0
  425. package/src/cli/code-agent-commands.ts +270 -0
  426. package/src/cli/code-agent-connector.ts +1109 -0
  427. package/src/cli/code-agent-executor.ts +1970 -0
  428. package/src/cli/code-agent-output-smoother.ts +140 -0
  429. package/src/cli/code-agent-runs.concurrent-worker.ts +33 -0
  430. package/src/cli/code-agent-runs.ts +548 -0
  431. package/src/cli/code.ts +1805 -0
  432. package/src/cli/codex-cli-participant.ts +496 -0
  433. package/src/cli/connect.ts +2714 -0
  434. package/src/cli/content-local.ts +442 -0
  435. package/src/cli/context-xray-local.ts +2193 -0
  436. package/src/cli/create-workspace.ts +30 -0
  437. package/src/cli/create.ts +2247 -0
  438. package/src/cli/deploy-build.ts +50 -0
  439. package/src/cli/design-connect.ts +3187 -0
  440. package/src/cli/doctor.ts +472 -0
  441. package/src/cli/eject.ts +1594 -0
  442. package/src/cli/eval.ts +134 -0
  443. package/src/cli/gateway-helpers.ts +70 -0
  444. package/src/cli/index.ts +1217 -0
  445. package/src/cli/info.ts +105 -0
  446. package/src/cli/invoke.ts +288 -0
  447. package/src/cli/mcp-config-writers.ts +857 -0
  448. package/src/cli/mcp.ts +594 -0
  449. package/src/cli/migrate.ts +1813 -0
  450. package/src/cli/migration-codemod.ts +646 -0
  451. package/src/cli/multi-frontier-runs.ts +1952 -0
  452. package/src/cli/package-lifecycle.ts +823 -0
  453. package/src/cli/plan-blocks.ts +143 -0
  454. package/src/cli/plan-local.ts +3189 -0
  455. package/src/cli/plan-publish-store.ts +138 -0
  456. package/src/cli/pr-visual-recap-workflow.ts +2 -0
  457. package/src/cli/recap.ts +5 -0
  458. package/src/cli/setup-agents.ts +120 -0
  459. package/src/cli/skills-content/assets-skill.ts +83 -0
  460. package/src/cli/skills-content/canvas.ts +153 -0
  461. package/src/cli/skills-content/connection.ts +52 -0
  462. package/src/cli/skills-content/content-skill.ts +120 -0
  463. package/src/cli/skills-content/design-exploration-skill.ts +118 -0
  464. package/src/cli/skills-content/design-visual-edit-skill.ts +228 -0
  465. package/src/cli/skills-content/document-quality.ts +196 -0
  466. package/src/cli/skills-content/exemplar.ts +69 -0
  467. package/src/cli/skills-content/help.ts +77 -0
  468. package/src/cli/skills-content/index.ts +22 -0
  469. package/src/cli/skills-content/local-files.ts +100 -0
  470. package/src/cli/skills-content/plan-setup-auth.ts +80 -0
  471. package/src/cli/skills-content/visual-plan-skill.ts +493 -0
  472. package/src/cli/skills-content/visual-recap-skill.ts +553 -0
  473. package/src/cli/skills-content/visualize-repo-skill.ts +93 -0
  474. package/src/cli/skills-content/wireframe.ts +349 -0
  475. package/src/cli/skills.ts +4340 -0
  476. package/src/cli/sync-builder-starter-manifest.ts +631 -0
  477. package/src/cli/telemetry.ts +136 -0
  478. package/src/cli/templates-meta.ts +269 -0
  479. package/src/cli/upgrade.ts +956 -0
  480. package/src/cli/visualize-repo.ts +715 -0
  481. package/src/cli/workspace-dev.ts +1486 -0
  482. package/src/cli/workspacify.ts +258 -0
  483. package/src/client/AgentAskPopover.tsx +89 -0
  484. package/src/client/AgentChatHome.tsx +66 -0
  485. package/src/client/AgentNative.tsx +161 -0
  486. package/src/client/AgentNativeEmbedded.tsx +288 -0
  487. package/src/client/AgentNativeFrame.tsx +151 -0
  488. package/src/client/AgentPanel.tsx +3437 -0
  489. package/src/client/AgentTaskCard.tsx +273 -0
  490. package/src/client/AppearancePicker.tsx +79 -0
  491. package/src/client/AssistantChat.tsx +5793 -0
  492. package/src/client/ClientOnly.tsx +22 -0
  493. package/src/client/CommandMenu.tsx +726 -0
  494. package/src/client/ConnectBuilderCard.tsx +390 -0
  495. package/src/client/DefaultSpinner.tsx +47 -0
  496. package/src/client/ErrorBoundary.tsx +359 -0
  497. package/src/client/ErrorReportActions.tsx +69 -0
  498. package/src/client/FeedbackButton.tsx +553 -0
  499. package/src/client/HighlightedCodeBlock.tsx +173 -0
  500. package/src/client/IframeEmbed.tsx +151 -0
  501. package/src/client/KeepTabOpenNotice.tsx +181 -0
  502. package/src/client/MultiTabAssistantChat.tsx +2576 -0
  503. package/src/client/NewWorkspaceAppFlow.tsx +525 -0
  504. package/src/client/PoweredByBadge.tsx +284 -0
  505. package/src/client/RunStuckBanner.tsx +431 -0
  506. package/src/client/StarfieldBackground.tsx +466 -0
  507. package/src/client/Turnstile.tsx +125 -0
  508. package/src/client/active-run-state.ts +139 -0
  509. package/src/client/agent-chat/index.ts +279 -0
  510. package/src/client/agent-chat-adapter.ts +3692 -0
  511. package/src/client/agent-chat.ts +1233 -0
  512. package/src/client/agent-engine-key.ts +122 -0
  513. package/src/client/agent-page/AgentContextTab.tsx +487 -0
  514. package/src/client/agent-page/AgentEmptyState.tsx +44 -0
  515. package/src/client/agent-page/AgentJobsTab.tsx +441 -0
  516. package/src/client/agent-page/AgentTabFrame.tsx +39 -0
  517. package/src/client/agent-page/AgentTabsPage.tsx +1096 -0
  518. package/src/client/agent-page/types.ts +18 -0
  519. package/src/client/agent-page/use-jobs.ts +150 -0
  520. package/src/client/agent-sidebar-state.ts +166 -0
  521. package/src/client/analytics/index.ts +40 -0
  522. package/src/client/analytics-session.ts +70 -0
  523. package/src/client/analytics.ts +1757 -0
  524. package/src/client/api-path.ts +124 -0
  525. package/src/client/app-providers.tsx +230 -0
  526. package/src/client/appearance.ts +130 -0
  527. package/src/client/application-state.ts +154 -0
  528. package/src/client/assistant-ui-recovery.tsx +205 -0
  529. package/src/client/automation/index.ts +4 -0
  530. package/src/client/automation.ts +22 -0
  531. package/src/client/blocks/AiEditableField.tsx +30 -0
  532. package/src/client/blocks/BlockView.tsx +145 -0
  533. package/src/client/blocks/RegistryBlockDataProvider.tsx +121 -0
  534. package/src/client/blocks/SchemaBlockEditor.tsx +457 -0
  535. package/src/client/blocks/agent.ts +95 -0
  536. package/src/client/blocks/code-block-direction.ts +21 -0
  537. package/src/client/blocks/index.ts +308 -0
  538. package/src/client/blocks/library/AnnotatedCodeBlock.tsx +710 -0
  539. package/src/client/blocks/library/ApiEndpointBlock.tsx +1120 -0
  540. package/src/client/blocks/library/DataModelBlock.tsx +775 -0
  541. package/src/client/blocks/library/DiffBlock.tsx +1854 -0
  542. package/src/client/blocks/library/FileTreeBlock.tsx +868 -0
  543. package/src/client/blocks/library/HighlightedCode.tsx +260 -0
  544. package/src/client/blocks/library/JsonExplorerBlock.tsx +608 -0
  545. package/src/client/blocks/library/MermaidBlock.tsx +362 -0
  546. package/src/client/blocks/library/OpenApiSpecBlock.tsx +998 -0
  547. package/src/client/blocks/library/annotated-code.config.ts +101 -0
  548. package/src/client/blocks/library/annotation-rail.tsx +1020 -0
  549. package/src/client/blocks/library/api-endpoint.config.ts +207 -0
  550. package/src/client/blocks/library/block-copy.ts +399 -0
  551. package/src/client/blocks/library/callout.config.ts +57 -0
  552. package/src/client/blocks/library/callout.tsx +149 -0
  553. package/src/client/blocks/library/checklist.config.ts +56 -0
  554. package/src/client/blocks/library/checklist.tsx +208 -0
  555. package/src/client/blocks/library/code-filename-label.tsx +59 -0
  556. package/src/client/blocks/library/code-highlight.tsx +178 -0
  557. package/src/client/blocks/library/code-tabs.config.ts +70 -0
  558. package/src/client/blocks/library/code-tabs.tsx +606 -0
  559. package/src/client/blocks/library/code.config.ts +69 -0
  560. package/src/client/blocks/library/code.tsx +440 -0
  561. package/src/client/blocks/library/columns.config.ts +85 -0
  562. package/src/client/blocks/library/columns.tsx +334 -0
  563. package/src/client/blocks/library/data-model.config.ts +152 -0
  564. package/src/client/blocks/library/dev-doc-ui.tsx +191 -0
  565. package/src/client/blocks/library/diagram.config.ts +222 -0
  566. package/src/client/blocks/library/diagram.tsx +958 -0
  567. package/src/client/blocks/library/diff.config.ts +115 -0
  568. package/src/client/blocks/library/file-tree.config.ts +92 -0
  569. package/src/client/blocks/library/html.config.ts +79 -0
  570. package/src/client/blocks/library/html.tsx +258 -0
  571. package/src/client/blocks/library/json-explorer.config.ts +74 -0
  572. package/src/client/blocks/library/mermaid.config.ts +49 -0
  573. package/src/client/blocks/library/narrow-container.tsx +37 -0
  574. package/src/client/blocks/library/openapi-spec.config.ts +66 -0
  575. package/src/client/blocks/library/question-form.config.ts +127 -0
  576. package/src/client/blocks/library/question-form.tsx +944 -0
  577. package/src/client/blocks/library/sanitize-html.ts +343 -0
  578. package/src/client/blocks/library/server-specs.ts +338 -0
  579. package/src/client/blocks/library/specs.tsx +308 -0
  580. package/src/client/blocks/library/table.config.ts +61 -0
  581. package/src/client/blocks/library/table.tsx +449 -0
  582. package/src/client/blocks/library/tabs.config.ts +96 -0
  583. package/src/client/blocks/library/tabs.tsx +665 -0
  584. package/src/client/blocks/library/wireframe-icons.ts +210 -0
  585. package/src/client/blocks/library/wireframe-kit.tsx +1850 -0
  586. package/src/client/blocks/library/wireframe.config.ts +539 -0
  587. package/src/client/blocks/library/wireframe.tsx +535 -0
  588. package/src/client/blocks/mdx.ts +364 -0
  589. package/src/client/blocks/provider.tsx +51 -0
  590. package/src/client/blocks/registry.ts +83 -0
  591. package/src/client/blocks/schema-form/introspect.ts +201 -0
  592. package/src/client/blocks/server.ts +170 -0
  593. package/src/client/blocks/types.ts +415 -0
  594. package/src/client/browser-session-bridge.ts +548 -0
  595. package/src/client/browser-tab-id.ts +36 -0
  596. package/src/client/builder-frame.ts +194 -0
  597. package/src/client/builder-mark.tsx +21 -0
  598. package/src/client/changelog/Changelog.tsx +333 -0
  599. package/src/client/changelog/index.ts +1 -0
  600. package/src/client/chat/ChatHistoryList.tsx +7 -0
  601. package/src/client/chat/attachment-adapters.ts +426 -0
  602. package/src/client/chat/connectors.ts +1579 -0
  603. package/src/client/chat/index.ts +160 -0
  604. package/src/client/chat/markdown-renderer.tsx +693 -0
  605. package/src/client/chat/message-components.tsx +1326 -0
  606. package/src/client/chat/repo-helpers.ts +281 -0
  607. package/src/client/chat/run-recovery.tsx +994 -0
  608. package/src/client/chat/runtime.ts +1810 -0
  609. package/src/client/chat/tool-call-display.tsx +1270 -0
  610. package/src/client/chat/tool-render-registry.tsx +144 -0
  611. package/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  612. package/src/client/chat/use-reconnect-reader-owner.ts +28 -0
  613. package/src/client/chat/widgets/DataChartRenderer.tsx +242 -0
  614. package/src/client/chat/widgets/DataChartWidget.tsx +51 -0
  615. package/src/client/chat/widgets/DataInsightsWidget.tsx +59 -0
  616. package/src/client/chat/widgets/DataTableWidget.tsx +240 -0
  617. package/src/client/chat/widgets/InlineExtensionWidget.tsx +60 -0
  618. package/src/client/chat/widgets/builtin-tool-renderers.tsx +213 -0
  619. package/src/client/chat/widgets/data-widget-types.ts +1 -0
  620. package/src/client/chat/widgets/inline-extension-result.ts +86 -0
  621. package/src/client/chat-model-groups.ts +171 -0
  622. package/src/client/chat-thread-url.ts +11 -0
  623. package/src/client/chat-view-transition.ts +213 -0
  624. package/src/client/client-action.ts +21 -0
  625. package/src/client/client-bootstrap.ts +7 -0
  626. package/src/client/client-surface.ts +41 -0
  627. package/src/client/clipboard.ts +89 -0
  628. package/src/client/code-agent-chat-adapter.ts +537 -0
  629. package/src/client/collab/index.ts +60 -0
  630. package/src/client/command-navigation/index.ts +15 -0
  631. package/src/client/comments-review/index.ts +1 -0
  632. package/src/client/components/AgentPresenceChip.tsx +4 -0
  633. package/src/client/components/ApiKeySettings.tsx +309 -0
  634. package/src/client/components/CodeAgentIndicator.tsx +59 -0
  635. package/src/client/components/CodeRequiredDialog.tsx +470 -0
  636. package/src/client/components/LiveCursorOverlay.tsx +5 -0
  637. package/src/client/components/MissingKeyCard.tsx +61 -0
  638. package/src/client/components/PresenceBar.tsx +4 -0
  639. package/src/client/components/RecentEditHighlights.tsx +4 -0
  640. package/src/client/components/RemoteSelectionRings.tsx +5 -0
  641. package/src/client/components/icons/AgentNativeIcon.tsx +46 -0
  642. package/src/client/components/ui/dialog.tsx +1 -0
  643. package/src/client/components/ui/dropdown-menu.tsx +1 -0
  644. package/src/client/components/ui/hover-card.tsx +1 -0
  645. package/src/client/components/ui/message-scroller.tsx +131 -0
  646. package/src/client/components/ui/popover.tsx +1 -0
  647. package/src/client/components/ui/sheet.tsx +1 -0
  648. package/src/client/components/ui/tooltip.tsx +1 -0
  649. package/src/client/composer/index.ts +11 -0
  650. package/src/client/composer/runtime-adapters.tsx +123 -0
  651. package/src/client/composer/use-mention-search.ts +7 -0
  652. package/src/client/composer/wired-components.tsx +53 -0
  653. package/src/client/context-xray/ContextMeter.tsx +124 -0
  654. package/src/client/context-xray/ContextSegmentRow.tsx +27 -0
  655. package/src/client/context-xray/ContextTreemap.tsx +24 -0
  656. package/src/client/context-xray/ContextXRayPanel.tsx +59 -0
  657. package/src/client/context-xray/SegmentProvenancePopover.tsx +18 -0
  658. package/src/client/context-xray/format.ts +27 -0
  659. package/src/client/conversation/AgentConversation.tsx +555 -0
  660. package/src/client/conversation/code-agent-transcript.ts +283 -0
  661. package/src/client/conversation/index.ts +22 -0
  662. package/src/client/conversation/types.ts +85 -0
  663. package/src/client/conversation/use-near-bottom-autoscroll.ts +278 -0
  664. package/src/client/create-query-client.ts +86 -0
  665. package/src/client/db-admin/DataGrid.tsx +551 -0
  666. package/src/client/db-admin/DbAdminPage.tsx +218 -0
  667. package/src/client/db-admin/DevDatabaseLink.tsx +16 -0
  668. package/src/client/db-admin/EditableCell.tsx +451 -0
  669. package/src/client/db-admin/FilterBar.tsx +203 -0
  670. package/src/client/db-admin/ResultsGrid.tsx +114 -0
  671. package/src/client/db-admin/RowSidePanel.tsx +337 -0
  672. package/src/client/db-admin/SqlEditor.tsx +840 -0
  673. package/src/client/db-admin/TableBrowser.tsx +212 -0
  674. package/src/client/db-admin/TableEditor.tsx +760 -0
  675. package/src/client/db-admin/cell-format.ts +246 -0
  676. package/src/client/db-admin/changeset.ts +296 -0
  677. package/src/client/db-admin/export-utils.ts +78 -0
  678. package/src/client/db-admin/index.ts +33 -0
  679. package/src/client/db-admin/sql-storage.ts +134 -0
  680. package/src/client/db-admin/storage.ts +68 -0
  681. package/src/client/db-admin/useAgentSync.ts +226 -0
  682. package/src/client/db-admin/useDbAdmin.ts +294 -0
  683. package/src/client/dev-overlay/DevOverlay.tsx +576 -0
  684. package/src/client/dev-overlay/builtins.ts +40 -0
  685. package/src/client/dev-overlay/index.ts +23 -0
  686. package/src/client/dev-overlay/registry.ts +67 -0
  687. package/src/client/dev-overlay/types.ts +64 -0
  688. package/src/client/dev-overlay/use-dev-option.ts +78 -0
  689. package/src/client/dev-overlay/use-dev-overlay-shortcut.ts +31 -0
  690. package/src/client/dynamic-suggestions.ts +455 -0
  691. package/src/client/embed-auth.ts +544 -0
  692. package/src/client/embed.ts +54 -0
  693. package/src/client/error-capture.ts +690 -0
  694. package/src/client/error-format.ts +211 -0
  695. package/src/client/error-reporting.ts +100 -0
  696. package/src/client/extensions/AgentNativeExtensionFrame.e2e-host.tsx +136 -0
  697. package/src/client/extensions/AgentNativeExtensionFrame.tsx +708 -0
  698. package/src/client/extensions/EmbeddedExtension.tsx +604 -0
  699. package/src/client/extensions/ExtensionEditor.tsx +450 -0
  700. package/src/client/extensions/ExtensionQueryErrorState.tsx +47 -0
  701. package/src/client/extensions/ExtensionSlot.tsx +345 -0
  702. package/src/client/extensions/ExtensionViewer.tsx +1502 -0
  703. package/src/client/extensions/ExtensionViewerPage.tsx +32 -0
  704. package/src/client/extensions/ExtensionsListPage.tsx +432 -0
  705. package/src/client/extensions/ExtensionsSidebarSection.tsx +1259 -0
  706. package/src/client/extensions/InlineExtensionFrame.tsx +660 -0
  707. package/src/client/extensions/agent-native-extension-runtime.ts +495 -0
  708. package/src/client/extensions/delete-extension.ts +76 -0
  709. package/src/client/extensions/extension-load-error.ts +26 -0
  710. package/src/client/extensions/extension-order.ts +49 -0
  711. package/src/client/extensions/extension-popularity.ts +61 -0
  712. package/src/client/extensions/iframe-bridge.ts +377 -0
  713. package/src/client/extensions/index.ts +84 -0
  714. package/src/client/extensions/portable-extension.ts +712 -0
  715. package/src/client/feature-flags/FeatureFlagsPanel.tsx +519 -0
  716. package/src/client/feature-flags/helpers.ts +77 -0
  717. package/src/client/feature-flags/index.ts +13 -0
  718. package/src/client/feature-flags/types.ts +29 -0
  719. package/src/client/feature-flags/use-feature-flag.ts +26 -0
  720. package/src/client/feedback-context.ts +90 -0
  721. package/src/client/frame-protocol.ts +168 -0
  722. package/src/client/frame.ts +329 -0
  723. package/src/client/guided-questions.tsx +1152 -0
  724. package/src/client/history/VersionHistoryPanel.tsx +175 -0
  725. package/src/client/history/index.ts +21 -0
  726. package/src/client/history/use-history.ts +114 -0
  727. package/src/client/hooks/index.ts +46 -0
  728. package/src/client/host/index.ts +170 -0
  729. package/src/client/host-bridge.ts +1272 -0
  730. package/src/client/host-tools.ts +190 -0
  731. package/src/client/i18n.tsx +798 -0
  732. package/src/client/index.ts +370 -0
  733. package/src/client/integrations/IntegrationCard.tsx +186 -0
  734. package/src/client/integrations/IntegrationsPanel.tsx +633 -0
  735. package/src/client/integrations/api.ts +295 -0
  736. package/src/client/integrations/index.ts +29 -0
  737. package/src/client/integrations/useIntegrationStatus.ts +52 -0
  738. package/src/client/mcp-app-host.ts +720 -0
  739. package/src/client/mcp-apps/McpAppRenderer.tsx +760 -0
  740. package/src/client/navigation/index.ts +54 -0
  741. package/src/client/notifications/NotificationsBell.tsx +383 -0
  742. package/src/client/notifications/index.ts +1 -0
  743. package/src/client/observability/ObservabilityDashboard.tsx +890 -0
  744. package/src/client/observability/ThumbsFeedback.tsx +160 -0
  745. package/src/client/observability/index.ts +20 -0
  746. package/src/client/observability/useObservability.ts +266 -0
  747. package/src/client/onboarding/OnboardingBanner.tsx +73 -0
  748. package/src/client/onboarding/OnboardingPanel.tsx +1036 -0
  749. package/src/client/onboarding/SetupButton.tsx +64 -0
  750. package/src/client/onboarding/index.ts +25 -0
  751. package/src/client/onboarding/use-onboarding.ts +164 -0
  752. package/src/client/onboarding/use-preview-mode.ts +40 -0
  753. package/src/client/org/InvitationBanner.tsx +148 -0
  754. package/src/client/org/OrgSwitcher.tsx +754 -0
  755. package/src/client/org/RequireActiveOrg.tsx +337 -0
  756. package/src/client/org/TeamPage.tsx +1432 -0
  757. package/src/client/org/hooks.ts +359 -0
  758. package/src/client/org/index.ts +70 -0
  759. package/src/client/org/workspace-app-links.ts +367 -0
  760. package/src/client/org-team/index.ts +1 -0
  761. package/src/client/progress/RunsTray.tsx +680 -0
  762. package/src/client/progress/index.ts +1 -0
  763. package/src/client/require-session.tsx +142 -0
  764. package/src/client/resources/BuiltinCapabilityDetail.tsx +258 -0
  765. package/src/client/resources/McpConnectionSuggestion.tsx +276 -0
  766. package/src/client/resources/McpIntegrationDialog.tsx +808 -0
  767. package/src/client/resources/McpServerDetail.tsx +230 -0
  768. package/src/client/resources/ResourceEditor.tsx +872 -0
  769. package/src/client/resources/ResourceTree.tsx +860 -0
  770. package/src/client/resources/ResourcesPanel.tsx +1960 -0
  771. package/src/client/resources/index.ts +25 -0
  772. package/src/client/resources/mcp-integration-catalog.ts +771 -0
  773. package/src/client/resources/mcp-integration-logos.ts +108 -0
  774. package/src/client/resources/runtime.ts +1 -0
  775. package/src/client/resources/use-builtin-capabilities.ts +113 -0
  776. package/src/client/resources/use-mcp-servers.ts +217 -0
  777. package/src/client/resources/use-resources.ts +402 -0
  778. package/src/client/review/ReviewCommentComposer.tsx +123 -0
  779. package/src/client/review/ReviewStatusBadge.tsx +39 -0
  780. package/src/client/review/ReviewThreadPanel.tsx +625 -0
  781. package/src/client/review/index.ts +38 -0
  782. package/src/client/review/use-review.ts +186 -0
  783. package/src/client/route-chunk-recovery/index.ts +1 -0
  784. package/src/client/route-chunk-recovery.ts +331 -0
  785. package/src/client/route-state.ts +455 -0
  786. package/src/client/route-warmup.tsx +543 -0
  787. package/src/client/session-replay-iframe.e2e-host.tsx +100 -0
  788. package/src/client/session-replay.ts +3417 -0
  789. package/src/client/settings/AgentsSection.tsx +441 -0
  790. package/src/client/settings/AutomationsSection.tsx +516 -0
  791. package/src/client/settings/BackgroundAgentSection.tsx +189 -0
  792. package/src/client/settings/BrowserSection.tsx +110 -0
  793. package/src/client/settings/DemoModeSection.tsx +48 -0
  794. package/src/client/settings/SecretsSection.tsx +875 -0
  795. package/src/client/settings/SettingsPanel.tsx +3162 -0
  796. package/src/client/settings/SettingsSection.tsx +283 -0
  797. package/src/client/settings/SettingsTabsPage.tsx +592 -0
  798. package/src/client/settings/UsageSection.tsx +401 -0
  799. package/src/client/settings/VoiceTranscriptionSection.tsx +960 -0
  800. package/src/client/settings/agent-settings-search.ts +220 -0
  801. package/src/client/settings/index.ts +27 -0
  802. package/src/client/settings/useBuilderStatus.ts +1055 -0
  803. package/src/client/setup-connections/BuilderConnectCard.tsx +89 -0
  804. package/src/client/setup-connections/ProviderReadinessBadge.tsx +73 -0
  805. package/src/client/setup-connections/SetupConnectionsPage.tsx +94 -0
  806. package/src/client/setup-connections/catalog.ts +6 -0
  807. package/src/client/setup-connections/index.ts +47 -0
  808. package/src/client/setup-connections/runtime.ts +1 -0
  809. package/src/client/sharing/ShareButton.tsx +1748 -0
  810. package/src/client/sharing/ShareDialog.tsx +846 -0
  811. package/src/client/sharing/VisibilityBadge.tsx +4 -0
  812. package/src/client/sharing/index.ts +2 -0
  813. package/src/client/sse-event-processor.ts +2002 -0
  814. package/src/client/terminal/AgentTerminal.tsx +488 -0
  815. package/src/client/terminal/index.ts +7 -0
  816. package/src/client/theme.ts +27 -0
  817. package/src/client/tombstone/agent-presence-chip.ts +17 -0
  818. package/src/client/tombstone/editor.ts +265 -0
  819. package/src/client/tombstone/live-cursor-overlay.ts +21 -0
  820. package/src/client/tombstone/presence-bar.ts +17 -0
  821. package/src/client/tombstone/recent-edit-highlights.ts +17 -0
  822. package/src/client/tombstone/remote-selection-rings.ts +21 -0
  823. package/src/client/tombstone/rich-markdown-editor.ts +265 -0
  824. package/src/client/tombstone/ui-dialog.ts +49 -0
  825. package/src/client/tombstone/ui-dropdown-menu.ts +69 -0
  826. package/src/client/tombstone/ui-hover-card.ts +21 -0
  827. package/src/client/tombstone/ui-popover.ts +25 -0
  828. package/src/client/tombstone/ui-sheet.ts +49 -0
  829. package/src/client/tombstone/ui-tooltip.ts +29 -0
  830. package/src/client/tombstone/visual-style-controls.ts +61 -0
  831. package/src/client/tool-cells/BashCell.tsx +164 -0
  832. package/src/client/tool-cells/EditCell.tsx +303 -0
  833. package/src/client/tool-cells/FilesChangedSummary.tsx +208 -0
  834. package/src/client/tool-cells/WriteCell.tsx +145 -0
  835. package/src/client/tool-cells/index.ts +7 -0
  836. package/src/client/tool-display.ts +41 -0
  837. package/src/client/track.ts +57 -0
  838. package/src/client/transcription/BuilderTranscriptionCta.tsx +120 -0
  839. package/src/client/transcription/use-live-transcription.ts +292 -0
  840. package/src/client/ui/index.ts +55 -0
  841. package/src/client/uploads/index.ts +6 -0
  842. package/src/client/uploads/upload-editor-image.ts +79 -0
  843. package/src/client/uploads/use-upload-resource.ts +24 -0
  844. package/src/client/url-scrub.ts +51 -0
  845. package/src/client/use-action.ts +766 -0
  846. package/src/client/use-agent-chat-context.ts +63 -0
  847. package/src/client/use-agent-chat-home-handoff.ts +207 -0
  848. package/src/client/use-agent-chat.ts +53 -0
  849. package/src/client/use-agent-engine-configured.ts +211 -0
  850. package/src/client/use-avatar.ts +127 -0
  851. package/src/client/use-change-version.ts +150 -0
  852. package/src/client/use-chat-models.ts +252 -0
  853. package/src/client/use-chat-threads.ts +1262 -0
  854. package/src/client/use-db-sync.ts +1112 -0
  855. package/src/client/use-demo-mode-status.ts +30 -0
  856. package/src/client/use-dev-mode.ts +177 -0
  857. package/src/client/use-external-value.ts +40 -0
  858. package/src/client/use-pausing-interval.ts +65 -0
  859. package/src/client/use-pinch-zoom.ts +202 -0
  860. package/src/client/use-run-stuck-detection.ts +427 -0
  861. package/src/client/use-send-to-agent-chat.ts +85 -0
  862. package/src/client/use-session.ts +114 -0
  863. package/src/client/utils.ts +7 -0
  864. package/src/client/visual-style-controls.tsx +1 -0
  865. package/src/client/vite-dev-recovery-script.ts +226 -0
  866. package/src/client/voice-provider-status.ts +44 -0
  867. package/src/client/widgets/index.ts +41 -0
  868. package/src/code-agents/background-controller.ts +398 -0
  869. package/src/code-agents/background-run.ts +156 -0
  870. package/src/code-agents/index.ts +95 -0
  871. package/src/code-agents/prompt-attachments.ts +39 -0
  872. package/src/code-agents/transcript-normalizer.ts +750 -0
  873. package/src/code-agents/transcript-order.ts +73 -0
  874. package/src/coding-tools/index.ts +742 -0
  875. package/src/coding-tools/run-code.ts +1662 -0
  876. package/src/coding-tools/sandbox/adapter.ts +82 -0
  877. package/src/coding-tools/sandbox/background.ts +406 -0
  878. package/src/coding-tools/sandbox/executions-store.ts +517 -0
  879. package/src/coding-tools/sandbox/index.ts +132 -0
  880. package/src/coding-tools/sandbox/local-child-process-adapter.ts +217 -0
  881. package/src/collab/agent-identity.ts +5 -0
  882. package/src/collab/agent-presence.ts +341 -0
  883. package/src/collab/awareness-store.ts +196 -0
  884. package/src/collab/awareness.ts +317 -0
  885. package/src/collab/client-struct.ts +366 -0
  886. package/src/collab/client.ts +1205 -0
  887. package/src/collab/emitter.ts +31 -0
  888. package/src/collab/follow-mode.ts +107 -0
  889. package/src/collab/index.ts +151 -0
  890. package/src/collab/json-to-yjs.ts +504 -0
  891. package/src/collab/presence.ts +207 -0
  892. package/src/collab/recent-edits.ts +215 -0
  893. package/src/collab/routes.ts +191 -0
  894. package/src/collab/storage.ts +228 -0
  895. package/src/collab/struct-routes.ts +133 -0
  896. package/src/collab/text-to-yjs.ts +79 -0
  897. package/src/collab/undo.ts +432 -0
  898. package/src/collab/xml-ops.ts +68 -0
  899. package/src/collab/ydoc-manager.ts +544 -0
  900. package/src/command-navigation/actions.ts +100 -0
  901. package/src/command-navigation/index.ts +12 -0
  902. package/src/comments-review/index.ts +1 -0
  903. package/src/connections/catalog.ts +451 -0
  904. package/src/connections/index.ts +48 -0
  905. package/src/connections/reader.ts +911 -0
  906. package/src/connections/runtime.ts +1 -0
  907. package/src/credentials/index.ts +187 -0
  908. package/src/data-programs/actions.ts +335 -0
  909. package/src/data-programs/contract.ts +284 -0
  910. package/src/data-programs/execute.ts +693 -0
  911. package/src/data-programs/index.ts +72 -0
  912. package/src/data-programs/schema.ts +148 -0
  913. package/src/data-programs/store.ts +755 -0
  914. package/src/data-widgets/index.ts +376 -0
  915. package/src/db/client.ts +1627 -0
  916. package/src/db/create-get-db.ts +579 -0
  917. package/src/db/ddl-guard.ts +302 -0
  918. package/src/db/drizzle-config.ts +190 -0
  919. package/src/db/ensure-additive-columns.ts +430 -0
  920. package/src/db/index.ts +57 -0
  921. package/src/db/migrations.ts +691 -0
  922. package/src/db/request-telemetry.ts +154 -0
  923. package/src/db/runtime-diagnostics.ts +331 -0
  924. package/src/db/schema.ts +121 -0
  925. package/src/db/widen-columns.ts +75 -0
  926. package/src/db-admin/agent-tools.ts +202 -0
  927. package/src/db-admin/index.ts +26 -0
  928. package/src/db-admin/operations.ts +803 -0
  929. package/src/db-admin/routes.ts +174 -0
  930. package/src/db-admin/types.ts +110 -0
  931. package/src/demo/browser-state.ts +47 -0
  932. package/src/demo/fetch-interceptor.ts +175 -0
  933. package/src/demo/redact.ts +575 -0
  934. package/src/deploy/build.ts +3935 -0
  935. package/src/deploy/immutable-assets.ts +65 -0
  936. package/src/deploy/route-discovery.ts +458 -0
  937. package/src/deploy/workspace-core.ts +282 -0
  938. package/src/deploy/workspace-deploy.ts +1488 -0
  939. package/src/eject/provider-api-definitions.ts +193 -0
  940. package/src/eject/remote-mcp-presets.ts +137 -0
  941. package/src/eject/setup-readiness-ui.tsx +29 -0
  942. package/src/eject/workspace-connections.ts +92 -0
  943. package/src/embedding/agent.ts +159 -0
  944. package/src/embedding/bridge.ts +297 -0
  945. package/src/embedding/index.ts +43 -0
  946. package/src/embedding/protocol.ts +185 -0
  947. package/src/embedding/react.tsx +319 -0
  948. package/src/embeddings/index.ts +233 -0
  949. package/src/eval/agent-runner.ts +210 -0
  950. package/src/eval/define-eval.ts +55 -0
  951. package/src/eval/index.ts +49 -0
  952. package/src/eval/report.ts +75 -0
  953. package/src/eval/runner.ts +369 -0
  954. package/src/eval/scorer.ts +244 -0
  955. package/src/eval/types.ts +188 -0
  956. package/src/event-bus/bus.ts +140 -0
  957. package/src/event-bus/index.ts +3 -0
  958. package/src/event-bus/registry.ts +79 -0
  959. package/src/event-bus/types.ts +29 -0
  960. package/src/extensions/actions.ts +1636 -0
  961. package/src/extensions/change-marker.ts +54 -0
  962. package/src/extensions/content-patch.ts +468 -0
  963. package/src/extensions/fetch-tool.ts +461 -0
  964. package/src/extensions/html-shell.ts +803 -0
  965. package/src/extensions/local.ts +462 -0
  966. package/src/extensions/path.ts +40 -0
  967. package/src/extensions/proxy-security.ts +171 -0
  968. package/src/extensions/routes.ts +1080 -0
  969. package/src/extensions/schema.ts +269 -0
  970. package/src/extensions/session-replay-iframe.ts +131 -0
  971. package/src/extensions/slots/routes.ts +126 -0
  972. package/src/extensions/slots/schema.ts +87 -0
  973. package/src/extensions/slots/store.ts +450 -0
  974. package/src/extensions/store.ts +1347 -0
  975. package/src/extensions/theme.ts +114 -0
  976. package/src/extensions/url-safety.ts +316 -0
  977. package/src/extensions/web-content.ts +663 -0
  978. package/src/extensions/web-search-tool.ts +437 -0
  979. package/src/feature-flags/a2a-action-route.ts +56 -0
  980. package/src/feature-flags/actions/get-feature-flags.ts +24 -0
  981. package/src/feature-flags/actions/list-feature-flags.ts +69 -0
  982. package/src/feature-flags/actions/set-feature-flag.ts +89 -0
  983. package/src/feature-flags/index.ts +21 -0
  984. package/src/feature-flags/permissions.ts +53 -0
  985. package/src/feature-flags/plugin.ts +44 -0
  986. package/src/feature-flags/registry.ts +96 -0
  987. package/src/feature-flags/store.ts +176 -0
  988. package/src/file-upload/actions/upload-image.ts +213 -0
  989. package/src/file-upload/builder.ts +431 -0
  990. package/src/file-upload/index.ts +24 -0
  991. package/src/file-upload/pre-upload-attachments.ts +305 -0
  992. package/src/file-upload/registry.ts +125 -0
  993. package/src/file-upload/types.ts +89 -0
  994. package/src/guards/db-tool-scoping.ts +129 -0
  995. package/src/guards/index.ts +23 -0
  996. package/src/guards/no-drizzle-push.ts +116 -0
  997. package/src/guards/no-env-credentials.ts +229 -0
  998. package/src/guards/no-env-mutation.ts +114 -0
  999. package/src/guards/no-localhost-fallback.ts +124 -0
  1000. package/src/guards/no-unscoped-credentials.ts +227 -0
  1001. package/src/guards/no-unscoped-queries.ts +834 -0
  1002. package/src/guards/scan-utils.ts +105 -0
  1003. package/src/guards/types.ts +30 -0
  1004. package/src/history/actions/create-resource-version.ts +92 -0
  1005. package/src/history/actions/get-resource-version.ts +60 -0
  1006. package/src/history/actions/list-resource-history.ts +53 -0
  1007. package/src/history/actions/list-resource-versions.ts +43 -0
  1008. package/src/history/actions/restore-resource-version.ts +96 -0
  1009. package/src/history/index.ts +26 -0
  1010. package/src/history/registry.ts +111 -0
  1011. package/src/history/store.ts +379 -0
  1012. package/src/history/types.ts +69 -0
  1013. package/src/index.browser.ts +155 -0
  1014. package/src/index.ts +408 -0
  1015. package/src/ingestion/docx.ts +158 -0
  1016. package/src/ingestion/figma-node-to-html.ts +1860 -0
  1017. package/src/ingestion/figma.ts +548 -0
  1018. package/src/ingestion/index.ts +107 -0
  1019. package/src/ingestion/media.ts +264 -0
  1020. package/src/ingestion/notion.ts +121 -0
  1021. package/src/ingestion/office.ts +213 -0
  1022. package/src/ingestion/orchestration.ts +160 -0
  1023. package/src/ingestion/pptx.ts +331 -0
  1024. package/src/ingestion/selection.ts +81 -0
  1025. package/src/ingestion/website.ts +151 -0
  1026. package/src/integrations/a2a-continuation-marker.ts +2 -0
  1027. package/src/integrations/a2a-continuation-processor.ts +888 -0
  1028. package/src/integrations/a2a-continuations-store.ts +643 -0
  1029. package/src/integrations/adapter-overrides.ts +12 -0
  1030. package/src/integrations/adapters/discord.ts +364 -0
  1031. package/src/integrations/adapters/email.ts +1164 -0
  1032. package/src/integrations/adapters/google-docs.ts +371 -0
  1033. package/src/integrations/adapters/index.ts +29 -0
  1034. package/src/integrations/adapters/microsoft-teams.ts +413 -0
  1035. package/src/integrations/adapters/slack.ts +1914 -0
  1036. package/src/integrations/adapters/telegram.ts +386 -0
  1037. package/src/integrations/adapters/whatsapp.ts +358 -0
  1038. package/src/integrations/awaiting-input-store.ts +130 -0
  1039. package/src/integrations/catalog.ts +571 -0
  1040. package/src/integrations/computer-supervision-store.ts +423 -0
  1041. package/src/integrations/computer-supervision.ts +213 -0
  1042. package/src/integrations/config-store.ts +131 -0
  1043. package/src/integrations/controls-store.ts +187 -0
  1044. package/src/integrations/eject/messaging-adapters.ts +85 -0
  1045. package/src/integrations/google-docs-poller.ts +671 -0
  1046. package/src/integrations/identity-links-store.ts +210 -0
  1047. package/src/integrations/identity.ts +196 -0
  1048. package/src/integrations/index.ts +220 -0
  1049. package/src/integrations/installations-store.ts +677 -0
  1050. package/src/integrations/integration-memory.ts +187 -0
  1051. package/src/integrations/internal-token.ts +106 -0
  1052. package/src/integrations/pending-tasks-retry-job.ts +286 -0
  1053. package/src/integrations/pending-tasks-store.ts +468 -0
  1054. package/src/integrations/plugin.ts +3048 -0
  1055. package/src/integrations/remote-commands-store.ts +690 -0
  1056. package/src/integrations/remote-devices-store.ts +492 -0
  1057. package/src/integrations/remote-json-safety.ts +127 -0
  1058. package/src/integrations/remote-push-delivery-job.ts +48 -0
  1059. package/src/integrations/remote-push-delivery.ts +370 -0
  1060. package/src/integrations/remote-push-store.ts +664 -0
  1061. package/src/integrations/remote-retry-job.ts +55 -0
  1062. package/src/integrations/remote-run-events-store.ts +222 -0
  1063. package/src/integrations/remote-types.ts +186 -0
  1064. package/src/integrations/runtime.ts +1 -0
  1065. package/src/integrations/scope-store.ts +498 -0
  1066. package/src/integrations/slack-manifest.ts +78 -0
  1067. package/src/integrations/slack-oauth.ts +344 -0
  1068. package/src/integrations/task-queue-stats.ts +144 -0
  1069. package/src/integrations/thread-mapping-store.ts +134 -0
  1070. package/src/integrations/types.ts +485 -0
  1071. package/src/integrations/usage-budget-store.ts +906 -0
  1072. package/src/integrations/webhook-delivery.ts +55 -0
  1073. package/src/integrations/webhook-handler.ts +1939 -0
  1074. package/src/jobs/actions/list-recurring-jobs.ts +105 -0
  1075. package/src/jobs/actions/manage-recurring-job.ts +85 -0
  1076. package/src/jobs/cron.ts +126 -0
  1077. package/src/jobs/index.ts +9 -0
  1078. package/src/jobs/scheduler.ts +703 -0
  1079. package/src/jobs/tools.ts +367 -0
  1080. package/src/local-artifacts/index.ts +1372 -0
  1081. package/src/localization/actions/get-localization-preference.ts +24 -0
  1082. package/src/localization/actions/set-localization-preference.ts +32 -0
  1083. package/src/localization/default-messages.ts +1009 -0
  1084. package/src/localization/index.ts +2 -0
  1085. package/src/localization/server.ts +131 -0
  1086. package/src/localization/shared.ts +208 -0
  1087. package/src/mcp/actions/call-mcp-tool.ts +19 -0
  1088. package/src/mcp/actions/create-org-service-token.ts +87 -0
  1089. package/src/mcp/actions/list-mcp-tools.ts +18 -0
  1090. package/src/mcp/actions/list-org-service-tokens.ts +44 -0
  1091. package/src/mcp/actions/revoke-org-service-token.ts +30 -0
  1092. package/src/mcp/actions/service-token-access.ts +121 -0
  1093. package/src/mcp/ask-app-inline-tasks.ts +125 -0
  1094. package/src/mcp/build-server.ts +2356 -0
  1095. package/src/mcp/builtin-tools.ts +1506 -0
  1096. package/src/mcp/connect-route.ts +1460 -0
  1097. package/src/mcp/connect-store.ts +680 -0
  1098. package/src/mcp/embed-app.ts +2051 -0
  1099. package/src/mcp/embed-route.ts +84 -0
  1100. package/src/mcp/external-agent-policy.ts +18 -0
  1101. package/src/mcp/index.ts +47 -0
  1102. package/src/mcp/oauth-route.ts +1016 -0
  1103. package/src/mcp/oauth-store.ts +581 -0
  1104. package/src/mcp/oauth-token.ts +227 -0
  1105. package/src/mcp/org-directory.ts +343 -0
  1106. package/src/mcp/route-paths.ts +34 -0
  1107. package/src/mcp/screen-memory-stdio.ts +290 -0
  1108. package/src/mcp/server.ts +507 -0
  1109. package/src/mcp/stdio.ts +328 -0
  1110. package/src/mcp/workspace-resolve.ts +261 -0
  1111. package/src/mcp-client/app-api.ts +136 -0
  1112. package/src/mcp-client/app-result.ts +64 -0
  1113. package/src/mcp-client/builtin-capabilities.ts +146 -0
  1114. package/src/mcp-client/builtin-store.ts +93 -0
  1115. package/src/mcp-client/config.ts +281 -0
  1116. package/src/mcp-client/errors.ts +54 -0
  1117. package/src/mcp-client/hub-client.ts +172 -0
  1118. package/src/mcp-client/hub-routes.ts +198 -0
  1119. package/src/mcp-client/index.ts +504 -0
  1120. package/src/mcp-client/manager.ts +968 -0
  1121. package/src/mcp-client/oauth-client.ts +462 -0
  1122. package/src/mcp-client/oauth-routes.ts +307 -0
  1123. package/src/mcp-client/remote-store.ts +674 -0
  1124. package/src/mcp-client/remote-url.ts +97 -0
  1125. package/src/mcp-client/routes.ts +1093 -0
  1126. package/src/mcp-client/screen-memory-local.ts +461 -0
  1127. package/src/mcp-client/tool-policy.ts +182 -0
  1128. package/src/mcp-client/visibility.ts +56 -0
  1129. package/src/mcp-client/workspace-servers.ts +379 -0
  1130. package/src/navigation/index.ts +170 -0
  1131. package/src/notifications/actions.ts +151 -0
  1132. package/src/notifications/channels.ts +410 -0
  1133. package/src/notifications/index.ts +22 -0
  1134. package/src/notifications/registry.ts +216 -0
  1135. package/src/notifications/routes.ts +106 -0
  1136. package/src/notifications/store.ts +236 -0
  1137. package/src/notifications/types.ts +52 -0
  1138. package/src/oauth-tokens/google-refresh.ts +175 -0
  1139. package/src/oauth-tokens/index.ts +15 -0
  1140. package/src/oauth-tokens/store.ts +384 -0
  1141. package/src/observability/cleanup-job.ts +124 -0
  1142. package/src/observability/evals.ts +507 -0
  1143. package/src/observability/experiments.ts +359 -0
  1144. package/src/observability/feedback.ts +332 -0
  1145. package/src/observability/hosted-model-experiment.ts +118 -0
  1146. package/src/observability/index.ts +62 -0
  1147. package/src/observability/plugin.ts +31 -0
  1148. package/src/observability/routes.ts +431 -0
  1149. package/src/observability/sentiment.ts +261 -0
  1150. package/src/observability/store.ts +1347 -0
  1151. package/src/observability/traces.ts +789 -0
  1152. package/src/observability/tracing.ts +157 -0
  1153. package/src/observability/tracking-identity.ts +55 -0
  1154. package/src/observability/types.ts +211 -0
  1155. package/src/onboarding/default-steps.ts +428 -0
  1156. package/src/onboarding/index.ts +22 -0
  1157. package/src/onboarding/plugin.ts +262 -0
  1158. package/src/onboarding/registry.ts +47 -0
  1159. package/src/onboarding/types.ts +96 -0
  1160. package/src/org/accept-pending.ts +98 -0
  1161. package/src/org/auto-join-domain.ts +113 -0
  1162. package/src/org/context.ts +614 -0
  1163. package/src/org/free-email-providers.ts +124 -0
  1164. package/src/org/handlers.ts +1153 -0
  1165. package/src/org/index.ts +63 -0
  1166. package/src/org/migrations.ts +105 -0
  1167. package/src/org/permissions.ts +30 -0
  1168. package/src/org/plugin.ts +255 -0
  1169. package/src/org/schema.ts +28 -0
  1170. package/src/org/types.ts +57 -0
  1171. package/src/org-team/index.ts +1 -0
  1172. package/src/package-lifecycle/deprecated-imports.ts +179 -0
  1173. package/src/package-lifecycle/eject-manifest.ts +345 -0
  1174. package/src/package-lifecycle/index.ts +7 -0
  1175. package/src/package-lifecycle/manifest.ts +120 -0
  1176. package/src/package-lifecycle/migration-manifest.ts +159 -0
  1177. package/src/package-lifecycle/migration-message.ts +6 -0
  1178. package/src/package-lifecycle/tombstone.ts +58 -0
  1179. package/src/package-lifecycle/upgrade-error.ts +37 -0
  1180. package/src/private-blob/index.ts +18 -0
  1181. package/src/private-blob/registry.ts +242 -0
  1182. package/src/private-blob/types.ts +55 -0
  1183. package/src/progress/actions.ts +179 -0
  1184. package/src/progress/index.ts +16 -0
  1185. package/src/progress/registry.ts +127 -0
  1186. package/src/progress/routes.ts +89 -0
  1187. package/src/progress/store.ts +353 -0
  1188. package/src/progress/types.ts +59 -0
  1189. package/src/provider-api/actions/custom-provider-registration.ts +197 -0
  1190. package/src/provider-api/actions/delete-staged-dataset.ts +5 -0
  1191. package/src/provider-api/actions/github-repo-files.ts +266 -0
  1192. package/src/provider-api/actions/list-staged-datasets.ts +5 -0
  1193. package/src/provider-api/actions/provider-api-audit.ts +88 -0
  1194. package/src/provider-api/actions/provider-api.ts +460 -0
  1195. package/src/provider-api/actions/query-staged-dataset.ts +5 -0
  1196. package/src/provider-api/actions/staged-datasets.ts +359 -0
  1197. package/src/provider-api/corpus-jobs-store.ts +522 -0
  1198. package/src/provider-api/corpus-jobs.ts +1817 -0
  1199. package/src/provider-api/custom-registry.ts +456 -0
  1200. package/src/provider-api/github-repo.ts +675 -0
  1201. package/src/provider-api/gong.ts +108 -0
  1202. package/src/provider-api/index.ts +5444 -0
  1203. package/src/provider-api/quota-governor.ts +562 -0
  1204. package/src/provider-api/runtime.ts +1 -0
  1205. package/src/provider-api/staged-datasets-aggregate.ts +304 -0
  1206. package/src/provider-api/staged-datasets-store.ts +441 -0
  1207. package/src/provider-api/staging.ts +483 -0
  1208. package/src/resources/agents.ts +65 -0
  1209. package/src/resources/emitter.ts +54 -0
  1210. package/src/resources/handlers.ts +728 -0
  1211. package/src/resources/index.ts +4 -0
  1212. package/src/resources/metadata.ts +252 -0
  1213. package/src/resources/script-helpers.ts +160 -0
  1214. package/src/resources/store.ts +1618 -0
  1215. package/src/review/actions/consume-review-feedback.ts +48 -0
  1216. package/src/review/actions/create-review-comment.ts +108 -0
  1217. package/src/review/actions/delete-review-comment.ts +67 -0
  1218. package/src/review/actions/get-review-feedback.ts +49 -0
  1219. package/src/review/actions/list-review-comments.ts +87 -0
  1220. package/src/review/actions/reply-review-comment.ts +118 -0
  1221. package/src/review/actions/resolve-review-thread.ts +94 -0
  1222. package/src/review/actions/send-review-thread-to-agent.ts +62 -0
  1223. package/src/review/actions/set-review-status.ts +58 -0
  1224. package/src/review/identity.ts +101 -0
  1225. package/src/review/index.ts +45 -0
  1226. package/src/review/mentions.ts +44 -0
  1227. package/src/review/registry.ts +111 -0
  1228. package/src/review/store.ts +997 -0
  1229. package/src/review/types.ts +101 -0
  1230. package/src/router/index.ts +24 -0
  1231. package/src/scripts/agent-engines/list-agent-engines.ts +130 -0
  1232. package/src/scripts/agent-engines/manage-agent-engine.ts +197 -0
  1233. package/src/scripts/agent-engines/set-agent-engine.ts +84 -0
  1234. package/src/scripts/agent-engines/test-agent-engine.ts +174 -0
  1235. package/src/scripts/call-agent.ts +792 -0
  1236. package/src/scripts/chat/index.ts +8 -0
  1237. package/src/scripts/chat/open-chat.ts +56 -0
  1238. package/src/scripts/chat/search-chats.ts +121 -0
  1239. package/src/scripts/core-scripts.ts +22 -0
  1240. package/src/scripts/db/check-scoping.ts +212 -0
  1241. package/src/scripts/db/exec.ts +791 -0
  1242. package/src/scripts/db/index.ts +19 -0
  1243. package/src/scripts/db/migrate-encrypt-credentials.ts +223 -0
  1244. package/src/scripts/db/migrate-encrypt-oauth-tokens.ts +213 -0
  1245. package/src/scripts/db/migrate-user-api-keys.ts +257 -0
  1246. package/src/scripts/db/patch.ts +820 -0
  1247. package/src/scripts/db/query.ts +299 -0
  1248. package/src/scripts/db/reset-dev-owner.ts +285 -0
  1249. package/src/scripts/db/safety.ts +286 -0
  1250. package/src/scripts/db/schema.ts +364 -0
  1251. package/src/scripts/db/scoping.ts +341 -0
  1252. package/src/scripts/db/sqlite-client.ts +78 -0
  1253. package/src/scripts/db/tool-mode.ts +23 -0
  1254. package/src/scripts/db/tool-schemas.ts +31 -0
  1255. package/src/scripts/db/wipe-leaked-builder-keys.ts +201 -0
  1256. package/src/scripts/dev/index.ts +296 -0
  1257. package/src/scripts/dev/list-files.ts +119 -0
  1258. package/src/scripts/dev/read-file.ts +77 -0
  1259. package/src/scripts/dev/search-files.ts +151 -0
  1260. package/src/scripts/dev/shell.ts +111 -0
  1261. package/src/scripts/dev/write-file.ts +56 -0
  1262. package/src/scripts/dev-session.ts +96 -0
  1263. package/src/scripts/docs/index.ts +8 -0
  1264. package/src/scripts/docs/search.ts +274 -0
  1265. package/src/scripts/docs/source-search.ts +363 -0
  1266. package/src/scripts/index.ts +15 -0
  1267. package/src/scripts/manage-agent-loop-settings.ts +84 -0
  1268. package/src/scripts/parse-args.ts +46 -0
  1269. package/src/scripts/resources/delete-memory.ts +67 -0
  1270. package/src/scripts/resources/delete.ts +69 -0
  1271. package/src/scripts/resources/effective.ts +71 -0
  1272. package/src/scripts/resources/index.ts +18 -0
  1273. package/src/scripts/resources/list.ts +103 -0
  1274. package/src/scripts/resources/migrate-learnings.ts +40 -0
  1275. package/src/scripts/resources/read.ts +107 -0
  1276. package/src/scripts/resources/save-memory.ts +99 -0
  1277. package/src/scripts/resources/write.ts +158 -0
  1278. package/src/scripts/runner.ts +339 -0
  1279. package/src/scripts/utils.ts +130 -0
  1280. package/src/search/index.ts +413 -0
  1281. package/src/search-utils/index.ts +112 -0
  1282. package/src/secrets/crypto.ts +228 -0
  1283. package/src/secrets/index.ts +65 -0
  1284. package/src/secrets/onboarding.ts +101 -0
  1285. package/src/secrets/register-framework-secrets.ts +228 -0
  1286. package/src/secrets/register.ts +129 -0
  1287. package/src/secrets/routes.ts +697 -0
  1288. package/src/secrets/schema.ts +52 -0
  1289. package/src/secrets/storage.ts +561 -0
  1290. package/src/secrets/substitution.ts +305 -0
  1291. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +150 -0
  1292. package/src/server/action-change.ts +66 -0
  1293. package/src/server/action-discovery.ts +774 -0
  1294. package/src/server/action-routes.ts +608 -0
  1295. package/src/server/agent-access.ts +72 -0
  1296. package/src/server/agent-chat/action-filters-a2a.ts +339 -0
  1297. package/src/server/agent-chat/browser-team-tools.ts +510 -0
  1298. package/src/server/agent-chat/context-tools.ts +599 -0
  1299. package/src/server/agent-chat/framework-prompts.ts +467 -0
  1300. package/src/server/agent-chat/lazy-fs.ts +11 -0
  1301. package/src/server/agent-chat/mcp-glue.ts +91 -0
  1302. package/src/server/agent-chat/plugin-options.ts +379 -0
  1303. package/src/server/agent-chat/process-run-failure.ts +62 -0
  1304. package/src/server/agent-chat/prompt-resources.ts +1004 -0
  1305. package/src/server/agent-chat/recurring-jobs-runtime.ts +80 -0
  1306. package/src/server/agent-chat/request-surface.ts +71 -0
  1307. package/src/server/agent-chat/run-code-tools.ts +67 -0
  1308. package/src/server/agent-chat/script-entries.ts +796 -0
  1309. package/src/server/agent-chat/shared-thread.ts +301 -0
  1310. package/src/server/agent-chat/skill-frontmatter.ts +41 -0
  1311. package/src/server/agent-chat-plugin.ts +5930 -0
  1312. package/src/server/agent-discovery.ts +706 -0
  1313. package/src/server/agent-engine-api-key-route.ts +236 -0
  1314. package/src/server/agent-run-context.ts +204 -0
  1315. package/src/server/agent-teams-run-queue.ts +344 -0
  1316. package/src/server/agent-teams.ts +2257 -0
  1317. package/src/server/agents-bundle.ts +464 -0
  1318. package/src/server/analytics.ts +105 -0
  1319. package/src/server/app-base-path.ts +79 -0
  1320. package/src/server/app-name.ts +53 -0
  1321. package/src/server/app-url.ts +184 -0
  1322. package/src/server/attachment-actions.ts +276 -0
  1323. package/src/server/attribution.ts +214 -0
  1324. package/src/server/auth-marketing.ts +260 -0
  1325. package/src/server/auth-plugin.ts +27 -0
  1326. package/src/server/auth.ts +3803 -0
  1327. package/src/server/better-auth-instance.ts +1197 -0
  1328. package/src/server/builder-browser.ts +1701 -0
  1329. package/src/server/builder-design-systems.ts +668 -0
  1330. package/src/server/builder-space.ts +176 -0
  1331. package/src/server/captcha.ts +63 -0
  1332. package/src/server/capture-error.ts +64 -0
  1333. package/src/server/cli-capture.ts +141 -0
  1334. package/src/server/collab-plugin.ts +391 -0
  1335. package/src/server/complete-text.ts +231 -0
  1336. package/src/server/cookie-namespace.ts +159 -0
  1337. package/src/server/core-routes-plugin.ts +4122 -0
  1338. package/src/server/cors-origins.ts +60 -0
  1339. package/src/server/create-server.ts +268 -0
  1340. package/src/server/credential-provider.ts +1202 -0
  1341. package/src/server/csrf.ts +229 -0
  1342. package/src/server/date-utils.ts +42 -0
  1343. package/src/server/deep-link.ts +119 -0
  1344. package/src/server/derived-secret.ts +32 -0
  1345. package/src/server/design-token-utils.ts +1032 -0
  1346. package/src/server/desktop-sso.ts +83 -0
  1347. package/src/server/edge.ts +69 -0
  1348. package/src/server/email-actions.ts +218 -0
  1349. package/src/server/email-template.ts +192 -0
  1350. package/src/server/email-templates.ts +148 -0
  1351. package/src/server/email.ts +219 -0
  1352. package/src/server/embed-route.ts +283 -0
  1353. package/src/server/embed-session.ts +805 -0
  1354. package/src/server/embedded.ts +252 -0
  1355. package/src/server/entry-server.tsx +154 -0
  1356. package/src/server/framework-request-handler.ts +848 -0
  1357. package/src/server/fusion-app.ts +447 -0
  1358. package/src/server/google-auth-mode.ts +34 -0
  1359. package/src/server/google-auth-plugin.ts +496 -0
  1360. package/src/server/google-oauth-credentials.ts +128 -0
  1361. package/src/server/google-oauth.ts +972 -0
  1362. package/src/server/google-realtime-session.ts +182 -0
  1363. package/src/server/h3-helpers.ts +174 -0
  1364. package/src/server/http-response-telemetry.ts +396 -0
  1365. package/src/server/identity-sso-store.ts +304 -0
  1366. package/src/server/identity-sso.ts +514 -0
  1367. package/src/server/index.ts +593 -0
  1368. package/src/server/missing-key.ts +36 -0
  1369. package/src/server/oauth-helpers.ts +44 -0
  1370. package/src/server/oauth-public-origin.ts +44 -0
  1371. package/src/server/oauth-return-url.ts +120 -0
  1372. package/src/server/og-fonts-data.ts +15 -0
  1373. package/src/server/og-fonts.ts +75 -0
  1374. package/src/server/onboarding-html.ts +4040 -0
  1375. package/src/server/open-route.ts +311 -0
  1376. package/src/server/org-admin.ts +28 -0
  1377. package/src/server/poll-events.ts +88 -0
  1378. package/src/server/poll.ts +1224 -0
  1379. package/src/server/prompts/framework-core-compact.ts +107 -0
  1380. package/src/server/prompts/framework-core.ts +143 -0
  1381. package/src/server/prompts/index.ts +16 -0
  1382. package/src/server/prompts/model-overlays.ts +54 -0
  1383. package/src/server/prompts/shared-rules.ts +104 -0
  1384. package/src/server/realtime-voice.ts +967 -0
  1385. package/src/server/recap-image-route.ts +242 -0
  1386. package/src/server/recap-image-store.ts +185 -0
  1387. package/src/server/request-context.ts +416 -0
  1388. package/src/server/request-origin.ts +67 -0
  1389. package/src/server/resources-plugin.ts +119 -0
  1390. package/src/server/schema-prompt.ts +429 -0
  1391. package/src/server/scoped-key-storage.ts +223 -0
  1392. package/src/server/security-headers.ts +170 -0
  1393. package/src/server/self-dispatch.ts +224 -0
  1394. package/src/server/sentry-config.ts +73 -0
  1395. package/src/server/sentry-plugin.ts +138 -0
  1396. package/src/server/sentry.ts +444 -0
  1397. package/src/server/short-lived-token.ts +170 -0
  1398. package/src/server/social-og-image.ts +454 -0
  1399. package/src/server/sse.ts +102 -0
  1400. package/src/server/ssr-handler.ts +466 -0
  1401. package/src/server/transcribe-voice.ts +1076 -0
  1402. package/src/server/voice-providers-status.ts +118 -0
  1403. package/src/server/workspace-oauth.ts +31 -0
  1404. package/src/server/workspace-provider-oauth.ts +970 -0
  1405. package/src/session-replay-iframe-protocol.ts +58 -0
  1406. package/src/settings/handlers.ts +44 -0
  1407. package/src/settings/index.ts +34 -0
  1408. package/src/settings/org-settings.ts +83 -0
  1409. package/src/settings/script-helpers.ts +24 -0
  1410. package/src/settings/store.ts +247 -0
  1411. package/src/settings/user-settings.ts +47 -0
  1412. package/src/setup-connections/index.ts +90 -0
  1413. package/src/setup-connections/onboarding.ts +47 -0
  1414. package/src/shared/agent-access.ts +112 -0
  1415. package/src/shared/agent-chat.ts +124 -0
  1416. package/src/shared/agent-env.ts +46 -0
  1417. package/src/shared/agent-readable-resource.ts +111 -0
  1418. package/src/shared/agent-sidebar-url.ts +39 -0
  1419. package/src/shared/cache-control.ts +25 -0
  1420. package/src/shared/cloudflare-globals.d.ts +34 -0
  1421. package/src/shared/context-xray.ts +172 -0
  1422. package/src/shared/embed-auth.ts +6 -0
  1423. package/src/shared/index.ts +83 -0
  1424. package/src/shared/llm-connection.ts +42 -0
  1425. package/src/shared/markdown-block-split.ts +129 -0
  1426. package/src/shared/mcp-connect-content.ts +130 -0
  1427. package/src/shared/mcp-embed-headers.ts +175 -0
  1428. package/src/shared/mcp-integration-config.ts +101 -0
  1429. package/src/shared/merge-by-id.ts +14 -0
  1430. package/src/shared/oauth-state.ts +39 -0
  1431. package/src/shared/reasoning-effort.ts +228 -0
  1432. package/src/shared/route-warmup-config.ts +128 -0
  1433. package/src/shared/runtime.ts +31 -0
  1434. package/src/shared/social-meta.ts +82 -0
  1435. package/src/shared/streaming-text-smoothing.ts +184 -0
  1436. package/src/shared/truncate.ts +13 -0
  1437. package/src/shared/workspace-app-audience.ts +177 -0
  1438. package/src/shared/workspace-app-id.ts +54 -0
  1439. package/src/sharing/access.ts +585 -0
  1440. package/src/sharing/actions/create-agent-resource-link.ts +91 -0
  1441. package/src/sharing/actions/extension-change.ts +22 -0
  1442. package/src/sharing/actions/list-resource-shares.ts +93 -0
  1443. package/src/sharing/actions/set-resource-visibility.ts +91 -0
  1444. package/src/sharing/actions/share-resource.ts +322 -0
  1445. package/src/sharing/actions/unshare-resource.ts +72 -0
  1446. package/src/sharing/index.ts +35 -0
  1447. package/src/sharing/registry.ts +201 -0
  1448. package/src/sharing/schema.ts +99 -0
  1449. package/src/styles/agent-conversation.css +766 -0
  1450. package/src/styles/agent-native.css +938 -0
  1451. package/src/styles/blocks.css +1717 -0
  1452. package/src/styles/chat-history-list.css +1 -0
  1453. package/src/styles/rich-markdown-editor.css +1 -0
  1454. package/src/tailwind.preset.ts +140 -0
  1455. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1456. package/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1457. package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +9 -6
  1458. package/src/templates/chat/AGENTS.md +3 -2
  1459. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1460. package/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1461. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +9 -6
  1462. package/src/templates/default/AGENTS.md +6 -5
  1463. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1464. package/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1465. package/src/templates/headless/AGENTS.md +5 -4
  1466. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +15 -13
  1467. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +3 -2
  1468. package/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +63 -20
  1469. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +9 -6
  1470. package/src/templates/workspace-core/AGENTS.md +4 -4
  1471. package/src/templates/workspace-root/AGENTS.md +4 -4
  1472. package/src/terminal/cli-registry.ts +57 -0
  1473. package/src/terminal/index.ts +22 -0
  1474. package/src/terminal/pty-server.ts +389 -0
  1475. package/src/terminal/terminal-plugin.ts +265 -0
  1476. package/src/testing.ts +23 -0
  1477. package/src/tracking/index.ts +10 -0
  1478. package/src/tracking/providers.ts +422 -0
  1479. package/src/tracking/registry.ts +102 -0
  1480. package/src/tracking/route.ts +108 -0
  1481. package/src/tracking/types.ts +16 -0
  1482. package/src/transcription/builder-transcription.ts +118 -0
  1483. package/src/triggers/actions/list-automations.ts +99 -0
  1484. package/src/triggers/actions/manage-automation.ts +78 -0
  1485. package/src/triggers/actions.ts +333 -0
  1486. package/src/triggers/condition-evaluator.ts +163 -0
  1487. package/src/triggers/dispatcher.ts +536 -0
  1488. package/src/triggers/index.ts +13 -0
  1489. package/src/triggers/routes.ts +322 -0
  1490. package/src/triggers/types.ts +42 -0
  1491. package/src/types/pglite.d.ts +26 -0
  1492. package/src/usage/store.ts +698 -0
  1493. package/src/vite/action-types-plugin.ts +481 -0
  1494. package/src/vite/agent-web-plugin.ts +78 -0
  1495. package/src/vite/agents-bundle-plugin.ts +185 -0
  1496. package/src/vite/client.ts +3039 -0
  1497. package/src/vite/index.ts +21 -0
  1498. package/src/voice/index.ts +18 -0
  1499. package/src/voice/voice-cleanup-prompt.ts +38 -0
  1500. package/src/voice/voice-context.ts +217 -0
  1501. package/src/voice/voice-replacements.ts +75 -0
  1502. package/src/workspace-connections/credentials.ts +603 -0
  1503. package/src/workspace-connections/index.ts +72 -0
  1504. package/src/workspace-connections/lifecycle.ts +43 -0
  1505. package/src/workspace-connections/store.ts +1943 -0
  1506. package/src/workspace-files/index.ts +18 -0
  1507. package/src/workspace-files/store.ts +339 -0
  1508. package/src/workspace-files/tool.ts +266 -0
@@ -0,0 +1,3162 @@
1
+ import * as SelectPrimitive from "@radix-ui/react-select";
2
+ import {
3
+ IconChevronDown,
4
+ IconChevronRight,
5
+ IconCheck,
6
+ IconExternalLink,
7
+ IconBrain,
8
+ IconHierarchy2,
9
+ IconBrowser,
10
+ IconGitBranch,
11
+ IconCloud,
12
+ IconDatabase,
13
+ IconShield,
14
+ IconPlugConnected,
15
+ IconTopologyRing2,
16
+ IconLoader2,
17
+ IconUpload,
18
+ IconCoin,
19
+ IconMail,
20
+ IconKey,
21
+ IconMicrophone,
22
+ IconEyeOff,
23
+ IconBolt,
24
+ IconGauge,
25
+ IconUserCircle,
26
+ IconApps,
27
+ IconUsersGroup,
28
+ } from "@tabler/icons-react";
29
+ import React, {
30
+ Suspense,
31
+ lazy,
32
+ useState,
33
+ useEffect,
34
+ useCallback,
35
+ useMemo,
36
+ useRef,
37
+ } from "react";
38
+
39
+ import { PROVIDER_ENV_PLACEHOLDERS } from "../../agent/engine/provider-env-vars.js";
40
+ import { saveAgentEngineProviderSettings } from "../agent-engine-key.js";
41
+ import { agentNativePath } from "../api-path.js";
42
+ import { BuilderBMark } from "../builder-mark.js";
43
+ import {
44
+ Tooltip,
45
+ TooltipContent,
46
+ TooltipTrigger,
47
+ } from "../components/ui/tooltip.js";
48
+ import { TeamPage } from "../org/TeamPage.js";
49
+ import { BuilderConnectCard } from "../setup-connections/BuilderConnectCard.js";
50
+ import { callAction } from "../use-action.js";
51
+ import { uploadAvatar, useAvatarUrl } from "../use-avatar.js";
52
+ import { useDevMode } from "../use-dev-mode.js";
53
+ import { useSession } from "../use-session.js";
54
+ import { cn } from "../utils.js";
55
+ import {
56
+ AGENT_SETTINGS_SECTIONS,
57
+ ALL_SETTINGS_SECTIONS,
58
+ CONNECTION_SETTINGS_SECTIONS,
59
+ SETTINGS_SECTION_IDS,
60
+ WORKSPACE_SETTINGS_SECTIONS,
61
+ getAgentSettingsSearchTabs,
62
+ type SettingsSectionId,
63
+ } from "./agent-settings-search.js";
64
+ import { AgentsSection } from "./AgentsSection.js";
65
+ import { AutomationsSection } from "./AutomationsSection.js";
66
+ import { DemoModeSection } from "./DemoModeSection.js";
67
+ import { SecretsSection } from "./SecretsSection.js";
68
+ import {
69
+ SettingsSection,
70
+ SettingsSurfaceProvider,
71
+ useSettingsSurface,
72
+ type SettingsSurface,
73
+ } from "./SettingsSection.js";
74
+ import type { SettingsTabItem } from "./SettingsTabsPage.js";
75
+ import { UsageSection } from "./UsageSection.js";
76
+ import {
77
+ type BuilderConnectFlow,
78
+ useBuilderConnectFlow,
79
+ useBuilderStatus,
80
+ } from "./useBuilderStatus.js";
81
+ import { VoiceTranscriptionSection } from "./VoiceTranscriptionSection.js";
82
+
83
+ const IntegrationsPanel = lazy(() =>
84
+ import("../integrations/IntegrationsPanel.js").then((m) => ({
85
+ default: m.IntegrationsPanel,
86
+ })),
87
+ );
88
+
89
+ // ─── Shared helpers ─────────────────────────────────────────────────────────
90
+
91
+ function SettingsSkeleton({ lines = 3 }: { lines?: number }) {
92
+ return (
93
+ <div className="space-y-3 animate-pulse">
94
+ {Array.from({ length: lines }, (_, i) => (
95
+ <div key={i} className="space-y-1.5">
96
+ <div
97
+ className="h-3 rounded bg-muted-foreground/10"
98
+ style={{ width: i === 0 ? "30%" : i === 1 ? "100%" : "60%" }}
99
+ />
100
+ {i < 2 && (
101
+ <div className="h-9 rounded-md border border-border bg-muted-foreground/5" />
102
+ )}
103
+ </div>
104
+ ))}
105
+ </div>
106
+ );
107
+ }
108
+
109
+ interface SettingsSelectOption {
110
+ value: string;
111
+ label: string;
112
+ description?: string;
113
+ }
114
+
115
+ const CONTROL_STYLE = {
116
+ fontSize: 12,
117
+ lineHeight: 1,
118
+ } satisfies React.CSSProperties;
119
+
120
+ const CONTROL_STYLE_PAGE = {
121
+ fontSize: 14,
122
+ lineHeight: 1.2,
123
+ } satisfies React.CSSProperties;
124
+
125
+ // Surface-aware class helpers so section bodies (shared with the compact
126
+ // sidebar) read as roomy, shadcn-style forms on the full settings page while
127
+ // staying dense in the sidebar.
128
+ function fieldLabelClass(isPage: boolean): string {
129
+ return cn("font-medium text-foreground", isPage ? "text-sm" : "text-[12px]");
130
+ }
131
+
132
+ // Secondary label / row-title size (e.g. "This app", provider names).
133
+ function subTextClass(isPage: boolean): string {
134
+ return isPage ? "text-sm" : "text-[11px]";
135
+ }
136
+
137
+ // Helper / hint / status note size.
138
+ function noteTextClass(isPage: boolean): string {
139
+ return isPage ? "text-xs" : "text-[10px]";
140
+ }
141
+
142
+ function textInputClass(isPage: boolean): string {
143
+ return cn(
144
+ "flex w-full rounded-md border border-border bg-background text-foreground outline-none transition-colors hover:bg-accent/40 focus:ring-1 focus:ring-accent placeholder:text-muted-foreground/50",
145
+ isPage ? "h-10 px-3 text-sm" : "h-9 px-3 text-[12px]",
146
+ );
147
+ }
148
+
149
+ function pillButtonClass(
150
+ isPage: boolean,
151
+ tone: "solid" | "outline" | "ghost" = "outline",
152
+ ): string {
153
+ const base = cn(
154
+ "inline-flex items-center justify-center gap-1 rounded-md font-medium transition-colors disabled:opacity-40",
155
+ isPage ? "px-3 py-1.5 text-sm" : "px-2.5 py-1 text-[10px]",
156
+ );
157
+ if (tone === "solid") {
158
+ return cn(base, "bg-accent text-foreground hover:bg-accent/80");
159
+ }
160
+ if (tone === "ghost") {
161
+ return cn(
162
+ base,
163
+ "text-muted-foreground hover:bg-accent/40 hover:text-foreground",
164
+ );
165
+ }
166
+ return cn(base, "border border-border text-foreground hover:bg-accent/40");
167
+ }
168
+
169
+ function SettingsSelect({
170
+ label,
171
+ labelAdornment,
172
+ value,
173
+ options,
174
+ onValueChange,
175
+ disabled = false,
176
+ }: {
177
+ label: string;
178
+ labelAdornment?: React.ReactNode;
179
+ value: string;
180
+ options: SettingsSelectOption[];
181
+ onValueChange: (value: string) => void;
182
+ disabled?: boolean;
183
+ }) {
184
+ const isPage = useSettingsSurface() === "page";
185
+ const controlStyle = isPage ? CONTROL_STYLE_PAGE : CONTROL_STYLE;
186
+ const selected = options.find((option) => option.value === value);
187
+
188
+ return (
189
+ <div className="space-y-1.5">
190
+ <div className="flex items-center justify-between">
191
+ <p className={fieldLabelClass(isPage)}>{label}</p>
192
+ {labelAdornment}
193
+ </div>
194
+ <SelectPrimitive.Root
195
+ value={value}
196
+ onValueChange={onValueChange}
197
+ disabled={disabled}
198
+ >
199
+ <SelectPrimitive.Trigger
200
+ className={cn(
201
+ "flex w-full items-center justify-between rounded-md border border-border bg-background px-3 text-start text-foreground outline-none transition-colors hover:bg-accent/40 data-[placeholder]:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-60",
202
+ isPage ? "h-10 text-sm" : "h-9 text-[12px]",
203
+ )}
204
+ aria-label={label}
205
+ style={controlStyle}
206
+ >
207
+ <SelectPrimitive.Value>
208
+ {selected?.label ?? value}
209
+ </SelectPrimitive.Value>
210
+ <SelectPrimitive.Icon asChild>
211
+ <IconChevronDown size={16} className="text-muted-foreground" />
212
+ </SelectPrimitive.Icon>
213
+ </SelectPrimitive.Trigger>
214
+ <SelectPrimitive.Portal>
215
+ <SelectPrimitive.Content
216
+ position="popper"
217
+ sideOffset={6}
218
+ className="z-[9999] w-[var(--radix-select-trigger-width)] overflow-hidden rounded-lg border border-border bg-popover shadow-lg"
219
+ >
220
+ <SelectPrimitive.Viewport className="p-1">
221
+ {options.map((option) => (
222
+ <SelectPrimitive.Item
223
+ key={option.value}
224
+ value={option.value}
225
+ className={cn(
226
+ "relative flex w-full cursor-pointer select-none items-start gap-2 rounded-md px-8 outline-none data-[highlighted]:bg-accent/60 data-[state=checked]:bg-accent/40",
227
+ isPage ? "py-2.5 text-sm" : "py-2.5 text-[12px]",
228
+ )}
229
+ style={controlStyle}
230
+ >
231
+ <span className="absolute start-2 top-2.5 flex h-4 w-4 items-center justify-center text-muted-foreground">
232
+ <SelectPrimitive.ItemIndicator>
233
+ <IconCheck size={14} />
234
+ </SelectPrimitive.ItemIndicator>
235
+ </span>
236
+ <div className="flex min-w-0 flex-col">
237
+ <SelectPrimitive.ItemText>
238
+ <span className="text-foreground">{option.label}</span>
239
+ </SelectPrimitive.ItemText>
240
+ {option.description ? (
241
+ <span
242
+ className={cn(
243
+ "mt-0.5 leading-relaxed text-muted-foreground",
244
+ isPage ? "text-xs" : "text-[11px]",
245
+ )}
246
+ >
247
+ {option.description}
248
+ </span>
249
+ ) : null}
250
+ </div>
251
+ </SelectPrimitive.Item>
252
+ ))}
253
+ </SelectPrimitive.Viewport>
254
+ </SelectPrimitive.Content>
255
+ </SelectPrimitive.Portal>
256
+ </SelectPrimitive.Root>
257
+ </div>
258
+ );
259
+ }
260
+
261
+ // ─── Disconnect button for the Builder card's connected state ───────────────
262
+ //
263
+ // Two-step confirmation: first click arms the button ("Confirm?"), second
264
+ // click actually disconnects. Arm auto-reverts after 4s of idle so a user
265
+ // who wandered off doesn't come back to a disconnect waiting for them.
266
+ //
267
+ // Hits /_agent-native/builder/disconnect which removes request-scoped
268
+ // Builder credentials from app_secrets. Deployment env credentials are left
269
+ // alone and remain as fallback. On success we dispatch
270
+ // `agent-engine:configured-changed` so dependent cards refresh inline.
271
+ function DisconnectBuilderButton() {
272
+ const { status } = useBuilderStatus();
273
+ const [phase, setPhase] = useState<"idle" | "armed" | "busy">("idle");
274
+ const [err, setErr] = useState<string | null>(null);
275
+ const armedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
276
+
277
+ const clearArmedTimer = useCallback(() => {
278
+ if (armedTimerRef.current) {
279
+ clearTimeout(armedTimerRef.current);
280
+ armedTimerRef.current = null;
281
+ }
282
+ }, []);
283
+
284
+ useEffect(() => {
285
+ return () => clearArmedTimer();
286
+ }, [clearArmedTimer]);
287
+
288
+ const performDisconnect = useCallback(async () => {
289
+ setPhase("busy");
290
+ setErr(null);
291
+ clearArmedTimer();
292
+ try {
293
+ const res = await fetch(
294
+ agentNativePath("/_agent-native/builder/disconnect"),
295
+ {
296
+ method: "POST",
297
+ headers: { "Content-Type": "application/json" },
298
+ },
299
+ );
300
+ // Parse defensively — a nitro 404 fallback returns HTML, not JSON,
301
+ // and res.json() on that would throw.
302
+ const text = await res.text();
303
+ let body: {
304
+ ok?: boolean;
305
+ error?: string;
306
+ warnings?: Record<string, string>;
307
+ } = {};
308
+ if (text) {
309
+ try {
310
+ body = JSON.parse(text);
311
+ } catch {
312
+ // Non-JSON response — likely a 404/HTML fallback.
313
+ }
314
+ }
315
+ if (!res.ok) {
316
+ throw new Error(
317
+ body.error ||
318
+ `Failed (${res.status}). Is your dev server up to date?`,
319
+ );
320
+ }
321
+ if (body.ok !== true) {
322
+ throw new Error(body.error || "Disconnect didn't confirm ok");
323
+ }
324
+ if (body.warnings && Object.keys(body.warnings).length > 0) {
325
+ // Disconnect flag persisted (we only reach here when ok:true), so
326
+ // the user IS disconnected — but some ancillary cleanup failed.
327
+ // Log so it's visible during dev; don't block the success path.
328
+ console.warn(
329
+ "[builder-disconnect] completed with warnings:",
330
+ body.warnings,
331
+ );
332
+ }
333
+ window.dispatchEvent(new CustomEvent("agent-engine:configured-changed"));
334
+ setPhase("idle");
335
+ } catch (e) {
336
+ setErr(e instanceof Error ? e.message : "Disconnect failed");
337
+ setPhase("idle");
338
+ }
339
+ }, [clearArmedTimer]);
340
+
341
+ const handleDisconnectClick = useCallback(() => {
342
+ if (phase === "busy") return;
343
+ if (phase === "idle") {
344
+ // First click — arm the button. Auto-revert after 4s to avoid a
345
+ // stale "confirm" state someone else could hit by accident.
346
+ setPhase("armed");
347
+ setErr(null);
348
+ clearArmedTimer();
349
+ armedTimerRef.current = setTimeout(() => {
350
+ setPhase("idle");
351
+ armedTimerRef.current = null;
352
+ }, 4000);
353
+ return;
354
+ }
355
+ // phase === "armed" — user confirmed, actually disconnect.
356
+ void performDisconnect();
357
+ }, [phase, performDisconnect, clearArmedTimer]);
358
+
359
+ const handleCancel = useCallback(() => {
360
+ clearArmedTimer();
361
+ setPhase("idle");
362
+ }, [clearArmedTimer]);
363
+
364
+ // When only the deploy fallback is active there is nothing request-scoped
365
+ // for this button to remove. The early return MUST come after every hook
366
+ // above to satisfy rules-of-hooks.
367
+ if (status?.credentialSource === "env") return null;
368
+
369
+ if (phase === "armed") {
370
+ return (
371
+ <>
372
+ <button
373
+ type="button"
374
+ onClick={handleDisconnectClick}
375
+ className="inline-flex items-center gap-1 rounded border border-destructive/40 bg-destructive/10 px-2 py-0.5 text-[10px] font-medium text-destructive hover:bg-destructive/20"
376
+ >
377
+ Confirm disconnect
378
+ </button>
379
+ <button
380
+ type="button"
381
+ onClick={handleCancel}
382
+ className="inline-flex items-center gap-1 rounded border border-border px-2 py-0.5 text-[10px] text-muted-foreground hover:text-foreground hover:bg-accent/40"
383
+ >
384
+ Cancel
385
+ </button>
386
+ </>
387
+ );
388
+ }
389
+
390
+ return (
391
+ <>
392
+ <button
393
+ type="button"
394
+ onClick={handleDisconnectClick}
395
+ disabled={phase === "busy"}
396
+ className="inline-flex items-center gap-1 rounded border border-border px-2 py-0.5 text-[10px] text-muted-foreground hover:text-foreground hover:bg-accent/40 disabled:opacity-60 disabled:cursor-wait"
397
+ aria-busy={phase === "busy"}
398
+ >
399
+ {phase === "busy" ? (
400
+ <>
401
+ <IconLoader2 size={10} className="animate-spin" />
402
+ Disconnecting…
403
+ </>
404
+ ) : (
405
+ "Disconnect"
406
+ )}
407
+ </button>
408
+ {err && <span className="text-[10px] text-destructive">{err}</span>}
409
+ </>
410
+ );
411
+ }
412
+
413
+ // ─── "Connect Builder.io" card (shared across all sections) ─────────────────
414
+
415
+ function UseBuilderCard({
416
+ builderFlow,
417
+ connectUrl,
418
+ connected,
419
+ orgName,
420
+ envManaged,
421
+ credentialSource,
422
+ trackingSource = "settings_panel_builder_card",
423
+ trackingFlow = "connect_llm",
424
+ label = "Connect Builder.io",
425
+ subtitle = "Free credits to start — no API key needed.",
426
+ dim,
427
+ }: {
428
+ builderFlow: BuilderConnectFlow;
429
+ connectUrl?: string;
430
+ connected: boolean;
431
+ orgName?: string;
432
+ envManaged?: boolean;
433
+ credentialSource?: "user" | "org" | "workspace" | "env";
434
+ trackingSource?: string;
435
+ trackingFlow?: string;
436
+ label?: string;
437
+ subtitle?: string;
438
+ dim?: boolean;
439
+ }) {
440
+ const isPage = useSettingsSurface() === "page";
441
+ const effectiveConnected = connected || builderFlow.configured;
442
+ const effectiveOrgName = builderFlow.orgName ?? orgName;
443
+ const bgClass = dim ? "" : "bg-accent/30";
444
+ const titleCls = isPage ? "text-sm" : "text-[11px]";
445
+ const bodyCls = isPage ? "text-xs" : "text-[10px]";
446
+
447
+ if (effectiveConnected) {
448
+ return (
449
+ <div
450
+ className={cn(
451
+ "rounded-md border border-border",
452
+ isPage ? "px-3.5 py-3" : "px-2.5 py-2",
453
+ bgClass,
454
+ )}
455
+ >
456
+ <div className="flex items-center justify-between">
457
+ <div className={cn("font-medium text-foreground", titleCls)}>
458
+ Builder.io
459
+ </div>
460
+ <span
461
+ className={cn("flex items-center gap-1 text-green-500", bodyCls)}
462
+ >
463
+ <IconCheck size={isPage ? 14 : 10} />
464
+ Connected
465
+ </span>
466
+ </div>
467
+ {effectiveOrgName && (
468
+ <p className={cn("text-muted-foreground mt-0.5", bodyCls)}>
469
+ {effectiveOrgName}
470
+ </p>
471
+ )}
472
+ {envManaged ? (
473
+ <p className={cn("text-muted-foreground mt-1", bodyCls)}>
474
+ {credentialSource === "env"
475
+ ? "Deployment fallback is available. Connect your own account to override it."
476
+ : "Using your connected Builder account. Deployment fallback is still available."}
477
+ </p>
478
+ ) : null}
479
+ {connectUrl || credentialSource !== "env" ? (
480
+ <div className="flex items-center gap-2 mt-2.5">
481
+ {connectUrl && (
482
+ <button
483
+ type="button"
484
+ onClick={() =>
485
+ builderFlow.start({ trackingSource, trackingFlow })
486
+ }
487
+ disabled={builderFlow.connecting}
488
+ className={cn(pillButtonClass(isPage, "ghost"), "no-underline")}
489
+ >
490
+ {builderFlow.connecting
491
+ ? "Connecting..."
492
+ : credentialSource === "env"
493
+ ? "Connect account"
494
+ : "Reconnect"}
495
+ <IconExternalLink size={isPage ? 14 : 10} />
496
+ </button>
497
+ )}
498
+ {credentialSource !== "env" ? <DisconnectBuilderButton /> : null}
499
+ </div>
500
+ ) : null}
501
+ </div>
502
+ );
503
+ }
504
+
505
+ if (!connectUrl) return null;
506
+
507
+ return (
508
+ <button
509
+ type="button"
510
+ onClick={() => builderFlow.start({ trackingSource, trackingFlow })}
511
+ disabled={builderFlow.connecting}
512
+ className={cn(
513
+ "block w-full rounded-md border border-border text-start no-underline bg-gradient-to-br from-teal-500/10 via-transparent to-transparent hover:border-foreground/30 transition-colors disabled:cursor-wait disabled:opacity-70",
514
+ isPage ? "px-4 py-3.5" : "px-3 py-3",
515
+ )}
516
+ >
517
+ <div className="flex items-start gap-2.5">
518
+ <div
519
+ className={cn(
520
+ "flex shrink-0 items-center justify-center rounded-md bg-foreground text-background",
521
+ isPage ? "h-8 w-8" : "h-7 w-7",
522
+ )}
523
+ >
524
+ <BuilderBMark className={isPage ? "h-4 w-4" : "h-3.5 w-3.5"} />
525
+ </div>
526
+ <div className="flex-1 min-w-0">
527
+ <div className="flex items-center gap-1.5 flex-wrap">
528
+ <span
529
+ className={cn(
530
+ "font-semibold text-foreground",
531
+ isPage ? "text-sm" : "text-[12px]",
532
+ )}
533
+ >
534
+ {builderFlow.connecting ? "Connecting Builder.io..." : label}
535
+ </span>
536
+ {builderFlow.connecting && (
537
+ <IconLoader2
538
+ size={isPage ? 14 : 12}
539
+ className="shrink-0 animate-spin text-muted-foreground"
540
+ />
541
+ )}
542
+ </div>
543
+ <p
544
+ className={cn(
545
+ "text-muted-foreground mt-0.5 leading-snug",
546
+ isPage ? "text-xs" : "text-[10.5px]",
547
+ )}
548
+ >
549
+ {subtitle}
550
+ </p>
551
+ {builderFlow.error && (
552
+ <p className={cn("mt-1 text-destructive", bodyCls)}>
553
+ {builderFlow.error}
554
+ </p>
555
+ )}
556
+ </div>
557
+ <IconExternalLink
558
+ size={isPage ? 14 : 12}
559
+ className="shrink-0 text-muted-foreground mt-0.5"
560
+ />
561
+ </div>
562
+ </button>
563
+ );
564
+ }
565
+
566
+ // ─── Manual setup card ──────────────────────────────────────────────────────
567
+
568
+ function ManualSetupCard({
569
+ hint,
570
+ docsUrl,
571
+ docsLabel = "Read the docs",
572
+ children,
573
+ dim,
574
+ sourceBadge,
575
+ }: {
576
+ hint?: string;
577
+ docsUrl?: string;
578
+ docsLabel?: string;
579
+ children?: React.ReactNode;
580
+ dim?: boolean;
581
+ /** Optional "Connected via X" badge shown in the header row. */
582
+ sourceBadge?: string;
583
+ }) {
584
+ const isPage = useSettingsSurface() === "page";
585
+ const titleCls = isPage ? "text-sm" : "text-[11px]";
586
+ const bodyCls = isPage ? "text-xs" : "text-[10px]";
587
+ return (
588
+ <div
589
+ className={cn(
590
+ "rounded-md border border-border",
591
+ isPage ? "px-3.5 py-3" : "px-2.5 py-2",
592
+ dim ? "" : "bg-accent/30",
593
+ )}
594
+ >
595
+ <div className="flex items-center justify-between mb-1">
596
+ <div className={cn("font-medium text-foreground", titleCls)}>
597
+ Set up manually
598
+ </div>
599
+ {sourceBadge ? (
600
+ <span
601
+ className={cn("flex items-center gap-1 text-green-500", bodyCls)}
602
+ >
603
+ <IconCheck size={isPage ? 14 : 10} />
604
+ {sourceBadge}
605
+ </span>
606
+ ) : null}
607
+ </div>
608
+ {hint && (
609
+ <p className={cn("text-muted-foreground mb-1.5", bodyCls)}>{hint}</p>
610
+ )}
611
+ {children}
612
+ {docsUrl && (
613
+ <a
614
+ href={docsUrl}
615
+ target="_blank"
616
+ rel="noopener noreferrer"
617
+ className={cn(
618
+ pillButtonClass(isPage, "outline"),
619
+ "mt-1.5 no-underline",
620
+ )}
621
+ >
622
+ {docsLabel}
623
+ <IconExternalLink size={isPage ? 14 : 10} />
624
+ </a>
625
+ )}
626
+ </div>
627
+ );
628
+ }
629
+
630
+ // ─── LLM helpers ────────────────────────────────────────────────────────────
631
+
632
+ function friendlyModelName(model: string): string {
633
+ if (model === "z-ai/glm-5.2") return "GLM 5.2";
634
+ const claude = model.match(
635
+ /^claude-(opus|sonnet|haiku)-(\d+)(?:-(\d+))?(?:-\d{8,})?$/,
636
+ );
637
+ if (claude) {
638
+ const tier = claude[1][0].toUpperCase() + claude[1].slice(1);
639
+ return `${tier} ${claude[2]}${claude[3] ? `.${claude[3]}` : ""}`;
640
+ }
641
+ if (model.startsWith("gpt-")) {
642
+ const rest = model.slice(4);
643
+ const gpt = rest.match(/^(\d+)[.-](\d+)(?:[.-](.+))?$/);
644
+ if (gpt) {
645
+ const suffix = gpt[3]
646
+ ? ` ${gpt[3]
647
+ .split("-")
648
+ .map((part) => part[0].toUpperCase() + part.slice(1))
649
+ .join(" ")}`
650
+ : "";
651
+ return `GPT-${gpt[1]}.${gpt[2]}${suffix}`;
652
+ }
653
+ return `GPT-${rest}`;
654
+ }
655
+ if (/^o\d/.test(model)) return model;
656
+ const geminiVersioned = model.match(
657
+ /^gemini-(\d+)-(\d+)-(.+?)(?:-preview)?$/,
658
+ );
659
+ if (geminiVersioned) {
660
+ const variant = geminiVersioned[3]
661
+ .split("-")
662
+ .map((part) => part[0].toUpperCase() + part.slice(1))
663
+ .join(" ");
664
+ return `Gemini ${geminiVersioned[1]}.${geminiVersioned[2]} ${variant}`;
665
+ }
666
+ const gemini = model.match(/^gemini-(.+?)(?:-preview)?$/);
667
+ if (gemini) {
668
+ const parts = gemini[1]
669
+ .split("-")
670
+ .map((s) => s[0].toUpperCase() + s.slice(1))
671
+ .join(" ");
672
+ return `Gemini ${parts}${model.endsWith("-preview") ? " (preview)" : ""}`;
673
+ }
674
+ return model;
675
+ }
676
+
677
+ type SettingsStatus = {
678
+ engine: string;
679
+ source: "env" | "settings";
680
+ envVar: string | null;
681
+ } | null;
682
+
683
+ function computeSourceBadge(args: {
684
+ settingsConfigured: boolean;
685
+ settingsStatus: SettingsStatus;
686
+ envConfigured: boolean;
687
+ envVar: string | undefined;
688
+ builderConnected: boolean;
689
+ }): string | undefined {
690
+ const { settingsConfigured, settingsStatus } = args;
691
+ if (args.builderConnected) return "Connected via Builder";
692
+ if (settingsConfigured) {
693
+ if (settingsStatus?.source === "env") {
694
+ return `Connected via ${settingsStatus.envVar ?? args.envVar ?? "env"}`;
695
+ }
696
+ return "Connected via template (server-side)";
697
+ }
698
+ if (args.envConfigured) return `Connected via ${args.envVar ?? "env"}`;
699
+ return undefined;
700
+ }
701
+
702
+ function latestModelsOnly(models: string[]): string[] {
703
+ const seen = new Set<string>();
704
+ return models.filter((m) => {
705
+ const claude = m.match(/^claude-(opus|sonnet|haiku)-/);
706
+ if (claude) {
707
+ if (seen.has(claude[1])) return false;
708
+ seen.add(claude[1]);
709
+ return true;
710
+ }
711
+ const gemini = m.match(/^gemini-(\d+(?:\.\d+)?)-(.+?)(?:-preview)?$/);
712
+ if (gemini) {
713
+ const family = gemini[2];
714
+ if (seen.has(`gemini-${family}`)) return false;
715
+ seen.add(`gemini-${family}`);
716
+ return true;
717
+ }
718
+ return true;
719
+ });
720
+ }
721
+
722
+ export function AppDefaultModelField({
723
+ engine,
724
+ models,
725
+ value,
726
+ defaultModel,
727
+ disabled,
728
+ onValueChange,
729
+ onEnter,
730
+ }: {
731
+ engine: string;
732
+ models: string[];
733
+ value: string;
734
+ defaultModel?: string;
735
+ disabled?: boolean;
736
+ onValueChange: (value: string) => void;
737
+ onEnter?: () => void;
738
+ }) {
739
+ const isPage = useSettingsSurface() === "page";
740
+ const modelOptions: SettingsSelectOption[] = latestModelsOnly(models).map(
741
+ (model) => ({ value: model, label: friendlyModelName(model) }),
742
+ );
743
+
744
+ // Builder models are a closed catalog (and are validated server-side), so a
745
+ // real select keeps every available model visible even when one is already
746
+ // selected. Native datalists filter against the current input value, which
747
+ // made this field appear to contain only the active model.
748
+ if (engine === "builder" && modelOptions.length > 0) {
749
+ return (
750
+ <SettingsSelect
751
+ label="Model"
752
+ value={value}
753
+ options={modelOptions}
754
+ onValueChange={onValueChange}
755
+ disabled={disabled}
756
+ />
757
+ );
758
+ }
759
+
760
+ return (
761
+ <div className="space-y-1.5">
762
+ <p className={fieldLabelClass(isPage)}>Model</p>
763
+ <input
764
+ type="text"
765
+ list={`app-model-suggestions-${engine}`}
766
+ value={value}
767
+ disabled={disabled}
768
+ onChange={(event) => onValueChange(event.target.value)}
769
+ onKeyDown={(event) => {
770
+ if (event.key === "Enter") onEnter?.();
771
+ }}
772
+ placeholder={defaultModel ?? "model-id"}
773
+ spellCheck={false}
774
+ autoComplete="off"
775
+ className={cn(textInputClass(isPage), "disabled:opacity-60")}
776
+ style={isPage ? CONTROL_STYLE_PAGE : CONTROL_STYLE}
777
+ />
778
+ {modelOptions.length > 0 && (
779
+ <datalist id={`app-model-suggestions-${engine}`}>
780
+ {modelOptions.map((option) => (
781
+ <option
782
+ key={option.value}
783
+ value={option.value}
784
+ label={option.label}
785
+ />
786
+ ))}
787
+ </datalist>
788
+ )}
789
+ </div>
790
+ );
791
+ }
792
+
793
+ // ─── LLM Section ────────────────────────────────────────────────────────────
794
+
795
+ interface EngineInfo {
796
+ name: string;
797
+ label: string;
798
+ description: string;
799
+ defaultModel: string;
800
+ supportedModels: string[];
801
+ requiredEnvVars: string[];
802
+ installPackage?: string;
803
+ packageInstalled?: boolean;
804
+ }
805
+
806
+ const PROVIDER_DOCS: Record<string, string> = {
807
+ anthropic: "https://console.anthropic.com/settings/keys",
808
+ "ai-sdk:anthropic": "https://console.anthropic.com/settings/keys",
809
+ "ai-sdk:openai": "https://platform.openai.com/api-keys",
810
+ "ai-sdk:google": "https://aistudio.google.com/apikey",
811
+ "ai-sdk:openrouter": "https://openrouter.ai/keys",
812
+ "ai-sdk:groq": "https://console.groq.com/keys",
813
+ "ai-sdk:mistral": "https://console.mistral.ai/api-keys/",
814
+ "ai-sdk:cohere": "https://dashboard.cohere.com/api-keys",
815
+ };
816
+
817
+ function LLMSectionInner({
818
+ builderFlow,
819
+ builderLoading,
820
+ connectUrl,
821
+ connected,
822
+ orgName,
823
+ envManaged,
824
+ credentialSource,
825
+ open,
826
+ onToggle,
827
+ }: {
828
+ builderFlow: BuilderConnectFlow;
829
+ builderLoading?: boolean;
830
+ connectUrl?: string;
831
+ connected: boolean;
832
+ orgName?: string;
833
+ envManaged?: boolean;
834
+ credentialSource?: "user" | "org" | "workspace" | "env";
835
+ open?: boolean;
836
+ onToggle?: () => void;
837
+ }) {
838
+ const isPage = useSettingsSurface() === "page";
839
+ const [envKeys, setEnvKeys] = useState<
840
+ Array<{ key: string; configured: boolean }>
841
+ >([]);
842
+ const [apiKey, setApiKey] = useState("");
843
+ const [saving, setSaving] = useState(false);
844
+ const [saved, setSaved] = useState(false);
845
+ const [engines, setEngines] = useState<EngineInfo[]>([]);
846
+ const [currentEngine, setCurrentEngine] = useState("anthropic");
847
+ const [currentModel, setCurrentModel] = useState("");
848
+ const [selectedEngine, setSelectedEngine] = useState("anthropic");
849
+ const [selectedModel, setSelectedModel] = useState("");
850
+ const [baseUrl, setBaseUrl] = useState("");
851
+ const [baseUrlConfigured, setBaseUrlConfigured] = useState(false);
852
+ const [clearBaseUrl, setClearBaseUrl] = useState(false);
853
+ const [advancedOpen, setAdvancedOpen] = useState(false);
854
+ const [applyNote, setApplyNote] = useState(false);
855
+ const [testing, setTesting] = useState(false);
856
+ const [testResult, setTestResult] = useState<
857
+ | { ok: true; latencyMs: number; model: string }
858
+ | { ok: false; error: string }
859
+ | null
860
+ >(null);
861
+ const [settingsStatus, setSettingsStatus] = useState<SettingsStatus>(null);
862
+ const [disconnectError, setDisconnectError] = useState<string | null>(null);
863
+ const [envLoaded, setEnvLoaded] = useState(false);
864
+ const [enginesLoaded, setEnginesLoaded] = useState(false);
865
+ const [statusLoaded, setStatusLoaded] = useState(false);
866
+
867
+ const initialLoading =
868
+ !envLoaded || !enginesLoaded || !statusLoaded || !!builderLoading;
869
+
870
+ useEffect(() => {
871
+ fetch(agentNativePath("/_agent-native/env-status"))
872
+ .then((r) => (r.ok ? r.json() : []))
873
+ .then(setEnvKeys)
874
+ .catch(() => {})
875
+ .finally(() => setEnvLoaded(true));
876
+ }, [saved]);
877
+
878
+ const notifyConfigChanged = useCallback(() => {
879
+ window.dispatchEvent(new CustomEvent("agent-engine:configured-changed"));
880
+ }, []);
881
+
882
+ const refreshSettingsStatus = useCallback(() => {
883
+ fetch(agentNativePath("/_agent-native/agent-engine/status"))
884
+ .then((r) => (r.ok ? r.json() : null))
885
+ .then((data) => {
886
+ setBaseUrlConfigured(Boolean(data?.openAiBaseUrlConfigured));
887
+ if (
888
+ data?.configured &&
889
+ typeof data.engine === "string" &&
890
+ (data.source === "env" || data.source === "settings")
891
+ ) {
892
+ setSettingsStatus({
893
+ engine: data.engine,
894
+ source: data.source,
895
+ envVar: typeof data.envVar === "string" ? data.envVar : null,
896
+ });
897
+ } else {
898
+ setSettingsStatus(null);
899
+ }
900
+ })
901
+ .catch(() => {})
902
+ .finally(() => setStatusLoaded(true));
903
+ }, []);
904
+
905
+ useEffect(() => {
906
+ refreshSettingsStatus();
907
+ }, [refreshSettingsStatus]);
908
+
909
+ useEffect(() => {
910
+ callAction("manage-agent-engine" as any, { action: "list" } as any)
911
+ .then((data) => {
912
+ if (!data) return;
913
+ const engineData = data as {
914
+ engines?: EngineInfo[];
915
+ current?: { engine?: string; model?: string };
916
+ };
917
+ setEngines(engineData.engines ?? []);
918
+ const cur = engineData.current ?? {};
919
+ setCurrentEngine(cur.engine ?? "anthropic");
920
+ setCurrentModel(cur.model ?? "");
921
+ setSelectedEngine(cur.engine ?? "anthropic");
922
+ setSelectedModel(cur.model ?? "");
923
+ })
924
+ .catch(() => {})
925
+ .finally(() => setEnginesLoaded(true));
926
+ }, []);
927
+
928
+ const selectedEngineInfo = engines.find((e) => e.name === selectedEngine);
929
+ const envVar = selectedEngineInfo?.requiredEnvVars?.[0];
930
+ const selectedEnginePackageInstalled =
931
+ selectedEngineInfo?.packageInstalled !== false;
932
+ const envConfigured = envVar
933
+ ? (envKeys.find((k) => k.key === envVar)?.configured ?? false)
934
+ : false;
935
+ const settingsConfigured =
936
+ settingsStatus != null && settingsStatus.engine === currentEngine;
937
+ const builderConnected = connected || builderFlow.configured;
938
+ const anyKeyConfigured =
939
+ builderConnected ||
940
+ (selectedEnginePackageInstalled && (envConfigured || settingsConfigured));
941
+ const sourceBadge = computeSourceBadge({
942
+ settingsConfigured,
943
+ settingsStatus,
944
+ envConfigured,
945
+ envVar,
946
+ builderConnected,
947
+ });
948
+ const manualSetupHint =
949
+ selectedEngine === "ai-sdk:openrouter"
950
+ ? "Provide an OpenRouter key to use OpenRouter models like GLM 5.2."
951
+ : "Choose your AI provider and model.";
952
+
953
+ const engineChanged =
954
+ selectedEngine !== currentEngine || selectedModel !== currentModel;
955
+ const isOpenAiEngine = selectedEngine === "ai-sdk:openai";
956
+ const endpointChanged = isOpenAiEngine && (!!baseUrl.trim() || clearBaseUrl);
957
+ const providerSettingsChanged = !!apiKey.trim() || endpointChanged;
958
+
959
+ // Hide the Anthropic-via-AI-SDK alias (redundant with the native entry)
960
+ // and Ollama (no API key to set here). The currently-selected engine is
961
+ // always kept so a stale setting doesn't vanish from the picker.
962
+ const providerOptions: SettingsSelectOption[] = engines
963
+ .filter(
964
+ (e) =>
965
+ e.name === selectedEngine ||
966
+ (e.name !== "ai-sdk:anthropic" && e.name !== "ai-sdk:ollama"),
967
+ )
968
+ .map((e) => ({ value: e.name, label: e.label }));
969
+
970
+ const modelOptions: SettingsSelectOption[] = latestModelsOnly(
971
+ selectedEngineInfo?.supportedModels ?? [],
972
+ ).map((m) => ({ value: m, label: friendlyModelName(m) }));
973
+
974
+ const handleSave = async () => {
975
+ if (!providerSettingsChanged || !envVar) return;
976
+ setSaving(true);
977
+ try {
978
+ const nextBaseUrl = isOpenAiEngine ? baseUrl.trim() : "";
979
+ await saveAgentEngineProviderSettings({
980
+ key: envVar,
981
+ ...(apiKey.trim() ? { apiKey } : {}),
982
+ ...(nextBaseUrl ? { baseUrl: nextBaseUrl } : {}),
983
+ ...(isOpenAiEngine && clearBaseUrl ? { clearBaseUrl: true } : {}),
984
+ });
985
+ setSaved(true);
986
+ setApiKey("");
987
+ setBaseUrl("");
988
+ setClearBaseUrl(false);
989
+ if (nextBaseUrl) setBaseUrlConfigured(true);
990
+ if (clearBaseUrl) setBaseUrlConfigured(false);
991
+ refreshSettingsStatus();
992
+ notifyConfigChanged();
993
+ setTimeout(() => setSaved(false), 2000);
994
+ } finally {
995
+ setSaving(false);
996
+ }
997
+ };
998
+
999
+ const handleDisconnect = async () => {
1000
+ setDisconnectError(null);
1001
+ try {
1002
+ const res = await fetch(
1003
+ agentNativePath("/_agent-native/agent-engine/disconnect"),
1004
+ {
1005
+ method: "POST",
1006
+ },
1007
+ );
1008
+ if (res.ok) {
1009
+ setTestResult(null);
1010
+ setApplyNote(false);
1011
+ refreshSettingsStatus();
1012
+ notifyConfigChanged();
1013
+ return;
1014
+ }
1015
+ const body = (await res.json().catch(() => null)) as {
1016
+ error?: string;
1017
+ } | null;
1018
+ setDisconnectError(
1019
+ body?.error ??
1020
+ (res.status === 401
1021
+ ? "You must be signed in to disconnect."
1022
+ : `Disconnect failed (HTTP ${res.status})`),
1023
+ );
1024
+ } catch (err) {
1025
+ setDisconnectError(err instanceof Error ? err.message : String(err));
1026
+ }
1027
+ };
1028
+
1029
+ const handleTest = async () => {
1030
+ setTesting(true);
1031
+ setTestResult(null);
1032
+ try {
1033
+ const data = await callAction(
1034
+ "manage-agent-engine" as any,
1035
+ {
1036
+ action: "test",
1037
+ engine: selectedEngine,
1038
+ model: selectedModel || selectedEngineInfo?.defaultModel,
1039
+ } as any,
1040
+ );
1041
+ // Older action paths wrapped tool output in { result }. Accept either
1042
+ // shape while the action route normalizes JSON-string script output.
1043
+ const parsed =
1044
+ typeof data === "string"
1045
+ ? JSON.parse(data)
1046
+ : typeof data?.result === "string"
1047
+ ? JSON.parse(data.result)
1048
+ : data;
1049
+ if (parsed?.ok) {
1050
+ setTestResult({
1051
+ ok: true,
1052
+ latencyMs: parsed.latencyMs ?? 0,
1053
+ model: parsed.model ?? selectedModel,
1054
+ });
1055
+ } else {
1056
+ setTestResult({
1057
+ ok: false,
1058
+ error: parsed?.error ?? "Test failed (no error message)",
1059
+ });
1060
+ }
1061
+ } catch (err) {
1062
+ setTestResult({
1063
+ ok: false,
1064
+ error: err instanceof Error ? err.message : String(err),
1065
+ });
1066
+ } finally {
1067
+ setTesting(false);
1068
+ }
1069
+ };
1070
+
1071
+ const handleApply = async () => {
1072
+ try {
1073
+ const res = await fetch(
1074
+ agentNativePath("/_agent-native/actions/manage-agent-engine"),
1075
+ {
1076
+ method: "POST",
1077
+ headers: { "Content-Type": "application/json" },
1078
+ body: JSON.stringify({
1079
+ action: "set",
1080
+ engine: selectedEngine,
1081
+ model: selectedModel,
1082
+ }),
1083
+ },
1084
+ );
1085
+ if (res.ok) {
1086
+ setCurrentEngine(selectedEngine);
1087
+ setCurrentModel(selectedModel);
1088
+ setApplyNote(true);
1089
+ refreshSettingsStatus();
1090
+ notifyConfigChanged();
1091
+ setTimeout(() => setApplyNote(false), 4000);
1092
+ }
1093
+ } catch {}
1094
+ };
1095
+
1096
+ return (
1097
+ <SettingsSection
1098
+ id={settingsSectionDomId("llm")}
1099
+ icon={<IconBrain size={14} />}
1100
+ title="LLM"
1101
+ subtitle="Connect any major LLM — Claude, GPT, Gemini, and more."
1102
+ required
1103
+ connected={initialLoading ? undefined : anyKeyConfigured}
1104
+ open={open}
1105
+ onToggle={onToggle}
1106
+ >
1107
+ {initialLoading ? (
1108
+ <SettingsSkeleton lines={3} />
1109
+ ) : (
1110
+ <div className="space-y-2">
1111
+ <UseBuilderCard
1112
+ builderFlow={builderFlow}
1113
+ connectUrl={connectUrl}
1114
+ connected={connected}
1115
+ orgName={orgName}
1116
+ envManaged={envManaged}
1117
+ credentialSource={credentialSource}
1118
+ trackingSource="llm_settings"
1119
+ trackingFlow="connect_llm"
1120
+ label="Connect Builder.io"
1121
+ />
1122
+ {!builderConnected && (
1123
+ <ManualSetupCard
1124
+ hint={manualSetupHint}
1125
+ docsUrl={PROVIDER_DOCS[selectedEngine]}
1126
+ sourceBadge={sourceBadge}
1127
+ docsLabel="Get an API key"
1128
+ >
1129
+ <div className="space-y-2 mb-1">
1130
+ <SettingsSelect
1131
+ label="Provider"
1132
+ value={selectedEngine}
1133
+ options={providerOptions}
1134
+ onValueChange={(val) => {
1135
+ setSelectedEngine(val);
1136
+ const info = engines.find((e) => e.name === val);
1137
+ setSelectedModel(info?.defaultModel ?? "");
1138
+ setApiKey("");
1139
+ setBaseUrl("");
1140
+ setClearBaseUrl(false);
1141
+ setAdvancedOpen(false);
1142
+ }}
1143
+ />
1144
+
1145
+ {/* Free-form input so OpenRouter/Ollama custom model IDs can
1146
+ be typed — the registry's supportedModels is only suggestions. */}
1147
+ <div className="space-y-1.5">
1148
+ <p className={fieldLabelClass(isPage)}>Model</p>
1149
+ <input
1150
+ type="text"
1151
+ list={`model-suggestions-${selectedEngine}`}
1152
+ value={selectedModel}
1153
+ onChange={(e) => setSelectedModel(e.target.value)}
1154
+ placeholder={
1155
+ selectedEngineInfo?.defaultModel ?? "e.g. model-id"
1156
+ }
1157
+ spellCheck={false}
1158
+ autoComplete="off"
1159
+ className={textInputClass(isPage)}
1160
+ style={isPage ? CONTROL_STYLE_PAGE : CONTROL_STYLE}
1161
+ />
1162
+ {modelOptions.length > 0 && (
1163
+ <datalist id={`model-suggestions-${selectedEngine}`}>
1164
+ {modelOptions.map((opt) => (
1165
+ <option
1166
+ key={opt.value}
1167
+ value={opt.value}
1168
+ label={opt.label}
1169
+ />
1170
+ ))}
1171
+ </datalist>
1172
+ )}
1173
+ </div>
1174
+
1175
+ {isOpenAiEngine && (
1176
+ <div className="border-t border-border/70 pt-2">
1177
+ <button
1178
+ type="button"
1179
+ onClick={() => setAdvancedOpen((v) => !v)}
1180
+ className="flex w-full cursor-pointer items-center justify-between gap-2 rounded px-0.5 py-1 text-left hover:text-foreground"
1181
+ >
1182
+ <span className="inline-flex min-w-0 items-center gap-1.5 text-[11px] font-medium text-foreground">
1183
+ {advancedOpen ? (
1184
+ <IconChevronDown size={12} />
1185
+ ) : (
1186
+ <IconChevronRight
1187
+ size={12}
1188
+ className="rtl:-scale-x-100"
1189
+ />
1190
+ )}
1191
+ Advanced
1192
+ </span>
1193
+ <span className="truncate text-[10px] text-muted-foreground">
1194
+ OpenAI-compatible endpoint
1195
+ </span>
1196
+ </button>
1197
+
1198
+ {advancedOpen && (
1199
+ <div className="mt-1.5 space-y-1.5">
1200
+ <div className="flex items-center justify-between gap-2">
1201
+ <p className="text-[12px] font-medium text-foreground">
1202
+ Endpoint URL
1203
+ </p>
1204
+ <span className="text-[10px] text-muted-foreground">
1205
+ {baseUrlConfigured ? "Configured" : "Optional"}
1206
+ </span>
1207
+ </div>
1208
+ <input
1209
+ type="url"
1210
+ value={baseUrl}
1211
+ onChange={(e) => {
1212
+ setBaseUrl(e.target.value);
1213
+ if (e.target.value.trim()) setClearBaseUrl(false);
1214
+ }}
1215
+ onKeyDown={(e) => {
1216
+ if (e.key === "Enter") handleSave();
1217
+ }}
1218
+ placeholder={
1219
+ baseUrlConfigured
1220
+ ? "Leave blank to keep current endpoint"
1221
+ : "https://gateway.example/v1"
1222
+ }
1223
+ disabled={clearBaseUrl}
1224
+ spellCheck={false}
1225
+ autoComplete="off"
1226
+ className="flex h-9 w-full rounded-md border border-border bg-background px-3 text-[12px] text-foreground outline-none transition-colors hover:bg-accent/40 focus:ring-1 focus:ring-accent disabled:opacity-50 placeholder:text-muted-foreground/50"
1227
+ style={CONTROL_STYLE}
1228
+ />
1229
+ <p className="text-[10px] leading-relaxed text-muted-foreground">
1230
+ Use for LiteLLM or another OpenAI-compatible chat
1231
+ gateway. Leave blank for OpenAI.
1232
+ </p>
1233
+ {baseUrlConfigured && (
1234
+ <label className="flex items-center gap-1.5 text-[10px] text-muted-foreground">
1235
+ <input
1236
+ type="checkbox"
1237
+ checked={clearBaseUrl}
1238
+ onChange={(e) => {
1239
+ setClearBaseUrl(e.target.checked);
1240
+ if (e.target.checked) setBaseUrl("");
1241
+ }}
1242
+ className="h-3 w-3 accent-current"
1243
+ />
1244
+ Clear saved endpoint override
1245
+ </label>
1246
+ )}
1247
+ {envVar && envConfigured && endpointChanged && (
1248
+ <button
1249
+ type="button"
1250
+ onClick={handleSave}
1251
+ disabled={saving}
1252
+ className="rounded bg-accent px-2.5 py-1 text-[10px] font-medium text-foreground hover:bg-accent/80 disabled:opacity-40"
1253
+ >
1254
+ {saving ? (
1255
+ <IconLoader2 size={10} className="animate-spin" />
1256
+ ) : saved ? (
1257
+ <IconCheck size={10} />
1258
+ ) : (
1259
+ "Save endpoint"
1260
+ )}
1261
+ </button>
1262
+ )}
1263
+ </div>
1264
+ )}
1265
+ </div>
1266
+ )}
1267
+
1268
+ {envVar && envConfigured ? (
1269
+ <div
1270
+ className={cn(
1271
+ "flex items-center gap-1.5 text-green-500",
1272
+ isPage ? "text-xs" : "text-[10px]",
1273
+ )}
1274
+ >
1275
+ <IconCheck size={isPage ? 14 : 10} />
1276
+ {envVar} configured
1277
+ </div>
1278
+ ) : envVar ? (
1279
+ <div className="flex gap-1.5">
1280
+ <input
1281
+ type="password"
1282
+ value={apiKey}
1283
+ onChange={(e) => setApiKey(e.target.value)}
1284
+ onKeyDown={(e) => {
1285
+ if (e.key === "Enter") handleSave();
1286
+ }}
1287
+ placeholder={PROVIDER_ENV_PLACEHOLDERS[envVar] ?? "..."}
1288
+ className={cn(textInputClass(isPage), "flex-1")}
1289
+ style={isPage ? CONTROL_STYLE_PAGE : undefined}
1290
+ />
1291
+ <button
1292
+ onClick={handleSave}
1293
+ disabled={!providerSettingsChanged || saving}
1294
+ className={pillButtonClass(isPage, "solid")}
1295
+ >
1296
+ {saving ? (
1297
+ <IconLoader2
1298
+ size={isPage ? 14 : 10}
1299
+ className="animate-spin"
1300
+ />
1301
+ ) : saved ? (
1302
+ <IconCheck size={isPage ? 14 : 10} />
1303
+ ) : (
1304
+ "Save"
1305
+ )}
1306
+ </button>
1307
+ </div>
1308
+ ) : null}
1309
+
1310
+ <div className="flex items-center gap-2">
1311
+ <button
1312
+ onClick={handleTest}
1313
+ disabled={testing}
1314
+ className={pillButtonClass(isPage, "outline")}
1315
+ >
1316
+ {testing ? (
1317
+ <span className="flex items-center gap-1">
1318
+ <IconLoader2
1319
+ size={isPage ? 14 : 10}
1320
+ className="animate-spin"
1321
+ />
1322
+ Testing…
1323
+ </span>
1324
+ ) : (
1325
+ "Test"
1326
+ )}
1327
+ </button>
1328
+ {engineChanged && (
1329
+ <button
1330
+ onClick={handleApply}
1331
+ className={pillButtonClass(isPage, "solid")}
1332
+ >
1333
+ Apply
1334
+ </button>
1335
+ )}
1336
+ {settingsStatus != null && (
1337
+ <Tooltip>
1338
+ <TooltipTrigger asChild>
1339
+ <button
1340
+ onClick={handleDisconnect}
1341
+ className={cn(
1342
+ pillButtonClass(isPage, "outline"),
1343
+ "ms-auto text-muted-foreground hover:bg-destructive/10 hover:text-destructive hover:border-destructive/40",
1344
+ )}
1345
+ >
1346
+ Disconnect
1347
+ </button>
1348
+ </TooltipTrigger>
1349
+ <TooltipContent>
1350
+ Clear the saved engine — the app will fall back to the
1351
+ default until you re-apply.
1352
+ </TooltipContent>
1353
+ </Tooltip>
1354
+ )}
1355
+ </div>
1356
+ {testResult && testResult.ok && (
1357
+ <p
1358
+ className={cn(
1359
+ "flex items-center gap-1 text-green-500",
1360
+ isPage ? "text-xs" : "text-[10px]",
1361
+ )}
1362
+ >
1363
+ <IconCheck size={isPage ? 14 : 10} />
1364
+ Test passed — {testResult.latencyMs}ms
1365
+ </p>
1366
+ )}
1367
+ {testResult && testResult.ok === false && (
1368
+ <p
1369
+ className={cn(
1370
+ "text-destructive",
1371
+ isPage ? "text-xs" : "text-[10px]",
1372
+ )}
1373
+ >
1374
+ Test failed: {testResult.error}
1375
+ </p>
1376
+ )}
1377
+ {disconnectError && (
1378
+ <p
1379
+ className={cn(
1380
+ "text-destructive",
1381
+ isPage ? "text-xs" : "text-[10px]",
1382
+ )}
1383
+ >
1384
+ Disconnect failed: {disconnectError}
1385
+ </p>
1386
+ )}
1387
+ {applyNote && (
1388
+ <p
1389
+ className={cn(
1390
+ "text-muted-foreground",
1391
+ isPage ? "text-xs" : "text-[10px]",
1392
+ )}
1393
+ >
1394
+ Changes take effect on next conversation
1395
+ </p>
1396
+ )}
1397
+ </div>
1398
+ </ManualSetupCard>
1399
+ )}
1400
+ </div>
1401
+ )}
1402
+ </SettingsSection>
1403
+ );
1404
+ }
1405
+
1406
+ // ─── App Default Model Section ──────────────────────────────────────────────
1407
+
1408
+ interface AppModelDefaultEngine extends EngineInfo {
1409
+ configured: boolean;
1410
+ }
1411
+
1412
+ interface AppModelDefaultsResponse {
1413
+ appId: string;
1414
+ engine: string | null;
1415
+ model: string | null;
1416
+ scope: "org" | "user" | "default";
1417
+ source: "org" | "user" | "default";
1418
+ canUpdate: boolean;
1419
+ orgId?: string | null;
1420
+ orgName?: string | null;
1421
+ role?: string | null;
1422
+ engines: AppModelDefaultEngine[];
1423
+ }
1424
+
1425
+ function friendlyAppName(appId: string): string {
1426
+ return appId
1427
+ .split("-")
1428
+ .filter(Boolean)
1429
+ .map((part) => part[0]?.toUpperCase() + part.slice(1))
1430
+ .join(" ");
1431
+ }
1432
+
1433
+ function AppModelDefaultsSectionInner({
1434
+ open,
1435
+ onToggle,
1436
+ }: {
1437
+ open?: boolean;
1438
+ onToggle?: () => void;
1439
+ }) {
1440
+ const isPage = useSettingsSurface() === "page";
1441
+ const [settings, setSettings] = useState<AppModelDefaultsResponse | null>(
1442
+ null,
1443
+ );
1444
+ const [selectedEngine, setSelectedEngine] = useState("");
1445
+ const [selectedModel, setSelectedModel] = useState("");
1446
+ const [loading, setLoading] = useState(true);
1447
+ const [saving, setSaving] = useState(false);
1448
+ const [saved, setSaved] = useState(false);
1449
+ const [error, setError] = useState<string | null>(null);
1450
+
1451
+ const load = useCallback(() => {
1452
+ let cancelled = false;
1453
+ setLoading(true);
1454
+ fetch(agentNativePath("/_agent-native/agent-model-defaults"))
1455
+ .then((r) => (r.ok ? r.json() : null))
1456
+ .then((data: AppModelDefaultsResponse | null) => {
1457
+ if (cancelled || !data) return;
1458
+ setSettings(data);
1459
+ const firstConfigured =
1460
+ data.engines.find((engine) => engine.configured) ?? data.engines[0];
1461
+ const nextEngine = data.engine ?? firstConfigured?.name ?? "";
1462
+ const nextEngineInfo =
1463
+ data.engines.find((engine) => engine.name === nextEngine) ??
1464
+ firstConfigured;
1465
+ setSelectedEngine(nextEngine);
1466
+ setSelectedModel(data.model ?? nextEngineInfo?.defaultModel ?? "");
1467
+ })
1468
+ .catch(() => {})
1469
+ .finally(() => {
1470
+ if (!cancelled) setLoading(false);
1471
+ });
1472
+ return () => {
1473
+ cancelled = true;
1474
+ };
1475
+ }, []);
1476
+
1477
+ useEffect(() => load(), [load]);
1478
+
1479
+ const selectedEngineInfo =
1480
+ settings?.engines.find((engine) => engine.name === selectedEngine) ?? null;
1481
+ const engineOptions: SettingsSelectOption[] = (settings?.engines ?? [])
1482
+ .filter(
1483
+ (engine) =>
1484
+ engine.name === selectedEngine ||
1485
+ (engine.name !== "ai-sdk:anthropic" && engine.name !== "ai-sdk:ollama"),
1486
+ )
1487
+ .map((engine) => ({
1488
+ value: engine.name,
1489
+ label:
1490
+ engine.name === "builder"
1491
+ ? "Builder.io Gateway"
1492
+ : engine.label || engine.name,
1493
+ description: engine.configured
1494
+ ? "Configured for this workspace"
1495
+ : engine.packageInstalled === false
1496
+ ? `Install ${engine.installPackage ?? "the provider packages"} to use this provider`
1497
+ : "Credentials not detected yet",
1498
+ }));
1499
+ const hasPendingChange =
1500
+ !!settings &&
1501
+ settings.canUpdate &&
1502
+ !!selectedEngine &&
1503
+ !!selectedModel.trim() &&
1504
+ (selectedEngine !== settings.engine ||
1505
+ selectedModel.trim() !== settings.model);
1506
+ const hasAppDefault = settings?.source !== "default";
1507
+ const scopeLabel =
1508
+ settings?.scope === "org"
1509
+ ? settings.orgName
1510
+ ? `${settings.orgName} organization`
1511
+ : "organization"
1512
+ : "your account";
1513
+
1514
+ const notifyChanged = () => {
1515
+ window.dispatchEvent(new CustomEvent("agent-engine:configured-changed"));
1516
+ };
1517
+
1518
+ const save = async () => {
1519
+ if (!hasPendingChange) return;
1520
+ setSaving(true);
1521
+ setSaved(false);
1522
+ setError(null);
1523
+ try {
1524
+ const res = await fetch(
1525
+ agentNativePath("/_agent-native/agent-model-defaults"),
1526
+ {
1527
+ method: "PUT",
1528
+ headers: { "Content-Type": "application/json" },
1529
+ body: JSON.stringify({
1530
+ engine: selectedEngine,
1531
+ model: selectedModel.trim(),
1532
+ }),
1533
+ },
1534
+ );
1535
+ const body = await res.json().catch(() => ({}));
1536
+ if (!res.ok)
1537
+ throw new Error(body?.error ?? `Save failed (${res.status})`);
1538
+ const next = body as AppModelDefaultsResponse;
1539
+ setSettings(next);
1540
+ setSelectedEngine(next.engine ?? selectedEngine);
1541
+ setSelectedModel(next.model ?? selectedModel.trim());
1542
+ setSaved(true);
1543
+ notifyChanged();
1544
+ setTimeout(() => setSaved(false), 2000);
1545
+ } catch (err) {
1546
+ setError(err instanceof Error ? err.message : "Save failed");
1547
+ } finally {
1548
+ setSaving(false);
1549
+ }
1550
+ };
1551
+
1552
+ const reset = async () => {
1553
+ if (!settings?.canUpdate || !hasAppDefault) return;
1554
+ setSaving(true);
1555
+ setSaved(false);
1556
+ setError(null);
1557
+ try {
1558
+ const res = await fetch(
1559
+ agentNativePath("/_agent-native/agent-model-defaults"),
1560
+ { method: "DELETE" },
1561
+ );
1562
+ const body = await res.json().catch(() => ({}));
1563
+ if (!res.ok)
1564
+ throw new Error(body?.error ?? `Reset failed (${res.status})`);
1565
+ const next = body as AppModelDefaultsResponse;
1566
+ setSettings(next);
1567
+ const fallback = next.engines.find((engine) => engine.configured);
1568
+ setSelectedEngine(next.engine ?? fallback?.name ?? selectedEngine);
1569
+ setSelectedModel(next.model ?? fallback?.defaultModel ?? selectedModel);
1570
+ notifyChanged();
1571
+ } catch (err) {
1572
+ setError(err instanceof Error ? err.message : "Reset failed");
1573
+ } finally {
1574
+ setSaving(false);
1575
+ }
1576
+ };
1577
+
1578
+ return (
1579
+ <SettingsSection
1580
+ id={settingsSectionDomId("app-models")}
1581
+ icon={<IconApps size={14} />}
1582
+ title="App Default Model"
1583
+ subtitle="Choose the default model for this app/template when no one-off composer model is selected."
1584
+ connected={loading ? undefined : hasAppDefault}
1585
+ open={open}
1586
+ onToggle={onToggle}
1587
+ >
1588
+ {loading ? (
1589
+ <SettingsSkeleton lines={2} />
1590
+ ) : settings ? (
1591
+ <div className="space-y-2">
1592
+ <div
1593
+ className={cn(
1594
+ "rounded-md border border-border bg-accent/20",
1595
+ isPage ? "px-3.5 py-3" : "px-2.5 py-2",
1596
+ )}
1597
+ >
1598
+ <div className="mb-2 flex items-center justify-between gap-2">
1599
+ <div className="min-w-0">
1600
+ <p
1601
+ className={cn(
1602
+ "truncate font-medium text-foreground",
1603
+ subTextClass(isPage),
1604
+ )}
1605
+ >
1606
+ {friendlyAppName(settings.appId) || "This app"}
1607
+ </p>
1608
+ <p
1609
+ className={cn(
1610
+ "mt-0.5 text-muted-foreground",
1611
+ noteTextClass(isPage),
1612
+ )}
1613
+ >
1614
+ {hasAppDefault
1615
+ ? `Applies to ${scopeLabel}.`
1616
+ : "Using the global LLM default."}
1617
+ </p>
1618
+ </div>
1619
+ <span
1620
+ className={cn(
1621
+ "shrink-0 rounded-full bg-background px-2 py-0.5 font-medium text-muted-foreground",
1622
+ noteTextClass(isPage),
1623
+ )}
1624
+ >
1625
+ {settings.source}
1626
+ </span>
1627
+ </div>
1628
+
1629
+ <div className="space-y-2">
1630
+ <SettingsSelect
1631
+ label="Provider"
1632
+ value={selectedEngine}
1633
+ options={engineOptions}
1634
+ onValueChange={(value) => {
1635
+ setSelectedEngine(value);
1636
+ const info = settings.engines.find(
1637
+ (engine) => engine.name === value,
1638
+ );
1639
+ setSelectedModel(info?.defaultModel ?? "");
1640
+ setError(null);
1641
+ }}
1642
+ />
1643
+
1644
+ <AppDefaultModelField
1645
+ engine={selectedEngine}
1646
+ models={selectedEngineInfo?.supportedModels ?? []}
1647
+ value={selectedModel}
1648
+ defaultModel={selectedEngineInfo?.defaultModel}
1649
+ disabled={!settings.canUpdate || saving}
1650
+ onValueChange={(value) => {
1651
+ setSelectedModel(value);
1652
+ setError(null);
1653
+ }}
1654
+ onEnter={() => {
1655
+ if (hasPendingChange) void save();
1656
+ }}
1657
+ />
1658
+
1659
+ <div className="flex items-center gap-1.5">
1660
+ <button
1661
+ type="button"
1662
+ onClick={save}
1663
+ disabled={!hasPendingChange || saving}
1664
+ className={pillButtonClass(isPage, "solid")}
1665
+ >
1666
+ {saving ? (
1667
+ <IconLoader2
1668
+ size={isPage ? 14 : 10}
1669
+ className="animate-spin"
1670
+ />
1671
+ ) : saved ? (
1672
+ <IconCheck size={isPage ? 14 : 10} />
1673
+ ) : (
1674
+ "Save"
1675
+ )}
1676
+ </button>
1677
+ <button
1678
+ type="button"
1679
+ onClick={reset}
1680
+ disabled={!settings.canUpdate || !hasAppDefault || saving}
1681
+ className={pillButtonClass(isPage, "outline")}
1682
+ >
1683
+ Reset
1684
+ </button>
1685
+ </div>
1686
+ </div>
1687
+
1688
+ {!settings.canUpdate && (
1689
+ <p
1690
+ className={cn(
1691
+ "mt-2 text-muted-foreground",
1692
+ noteTextClass(isPage),
1693
+ )}
1694
+ >
1695
+ Only organization owners and admins can change app model
1696
+ defaults.
1697
+ </p>
1698
+ )}
1699
+ {selectedEngineInfo?.packageInstalled === false ? (
1700
+ <p
1701
+ className={cn(
1702
+ "mt-2 text-muted-foreground",
1703
+ noteTextClass(isPage),
1704
+ )}
1705
+ >
1706
+ This app does not include the optional runtime packages for this
1707
+ provider.
1708
+ </p>
1709
+ ) : selectedEngineInfo && !selectedEngineInfo.configured ? (
1710
+ <p
1711
+ className={cn(
1712
+ "mt-2 text-muted-foreground",
1713
+ noteTextClass(isPage),
1714
+ )}
1715
+ >
1716
+ Credentials for this provider were not detected; runtime will
1717
+ fall back if the model cannot be used.
1718
+ </p>
1719
+ ) : null}
1720
+ {error && (
1721
+ <p className={cn("mt-2 text-destructive", noteTextClass(isPage))}>
1722
+ {error}
1723
+ </p>
1724
+ )}
1725
+ </div>
1726
+ </div>
1727
+ ) : (
1728
+ <p className={cn("text-muted-foreground", noteTextClass(isPage))}>
1729
+ App model defaults are unavailable.
1730
+ </p>
1731
+ )}
1732
+ </SettingsSection>
1733
+ );
1734
+ }
1735
+
1736
+ // ─── Email Section ──────────────────────────────────────────────────────────
1737
+
1738
+ function EmailSectionInner({
1739
+ open,
1740
+ onToggle,
1741
+ }: {
1742
+ open?: boolean;
1743
+ onToggle?: () => void;
1744
+ }) {
1745
+ const isPage = useSettingsSurface() === "page";
1746
+ const emailInputCls = cn(textInputClass(isPage), "flex-1");
1747
+ const emailBtnCls = pillButtonClass(isPage, "solid");
1748
+ const emailIconSize = isPage ? 14 : 10;
1749
+ const [envKeys, setEnvKeys] = useState<
1750
+ Array<{ key: string; configured: boolean }>
1751
+ >([]);
1752
+ const [resendKey, setResendKey] = useState("");
1753
+ const [sendgridKey, setSendgridKey] = useState("");
1754
+ const [fromAddr, setFromAddr] = useState("");
1755
+ const [saving, setSaving] = useState(false);
1756
+ const [saved, setSaved] = useState(false);
1757
+ const [emailProvider, setEmailProvider] = useState<"resend" | "sendgrid">(
1758
+ "resend",
1759
+ );
1760
+ const [envLoaded, setEnvLoaded] = useState(false);
1761
+
1762
+ useEffect(() => {
1763
+ fetch(agentNativePath("/_agent-native/env-status"))
1764
+ .then((r) => (r.ok ? r.json() : []))
1765
+ .then(setEnvKeys)
1766
+ .catch(() => {})
1767
+ .finally(() => setEnvLoaded(true));
1768
+ }, [saved]);
1769
+
1770
+ const resendConfigured =
1771
+ envKeys.find((k) => k.key === "RESEND_API_KEY")?.configured ?? false;
1772
+ const sendgridConfigured =
1773
+ envKeys.find((k) => k.key === "SENDGRID_API_KEY")?.configured ?? false;
1774
+ const fromConfigured =
1775
+ envKeys.find((k) => k.key === "EMAIL_FROM")?.configured ?? false;
1776
+ const anyConfigured = resendConfigured || sendgridConfigured;
1777
+
1778
+ useEffect(() => {
1779
+ if (sendgridConfigured && !resendConfigured) {
1780
+ setEmailProvider("sendgrid");
1781
+ }
1782
+ }, [resendConfigured, sendgridConfigured]);
1783
+
1784
+ const save = async (vars: Array<{ key: string; value: string }>) => {
1785
+ setSaving(true);
1786
+ try {
1787
+ const res = await fetch(agentNativePath("/_agent-native/env-vars"), {
1788
+ method: "POST",
1789
+ headers: { "Content-Type": "application/json" },
1790
+ body: JSON.stringify({ vars }),
1791
+ });
1792
+ if (res.ok) {
1793
+ setSaved(true);
1794
+ setResendKey("");
1795
+ setSendgridKey("");
1796
+ setFromAddr("");
1797
+ setTimeout(() => setSaved(false), 2000);
1798
+ }
1799
+ } finally {
1800
+ setSaving(false);
1801
+ }
1802
+ };
1803
+
1804
+ const saveResend = () => {
1805
+ const vars: Array<{ key: string; value: string }> = [];
1806
+ if (resendKey.trim())
1807
+ vars.push({ key: "RESEND_API_KEY", value: resendKey.trim() });
1808
+ if (fromAddr.trim())
1809
+ vars.push({ key: "EMAIL_FROM", value: fromAddr.trim() });
1810
+ if (vars.length) save(vars);
1811
+ };
1812
+
1813
+ const saveSendgrid = () => {
1814
+ const vars: Array<{ key: string; value: string }> = [];
1815
+ if (sendgridKey.trim())
1816
+ vars.push({ key: "SENDGRID_API_KEY", value: sendgridKey.trim() });
1817
+ if (fromAddr.trim())
1818
+ vars.push({ key: "EMAIL_FROM", value: fromAddr.trim() });
1819
+ if (vars.length) save(vars);
1820
+ };
1821
+
1822
+ return (
1823
+ <SettingsSection
1824
+ id={settingsSectionDomId("email")}
1825
+ icon={<IconMail size={14} />}
1826
+ title="Email"
1827
+ subtitle="Needed before deploy for password resets, team invitations, share notifications, and dashboard email reports. Local development can run without it."
1828
+ connected={!envLoaded ? undefined : anyConfigured}
1829
+ open={open}
1830
+ onToggle={onToggle}
1831
+ >
1832
+ {!envLoaded ? (
1833
+ <SettingsSkeleton lines={2} />
1834
+ ) : (
1835
+ <div className="space-y-2">
1836
+ <label className="block space-y-1">
1837
+ <span
1838
+ className={cn(
1839
+ "uppercase tracking-wide text-muted-foreground",
1840
+ noteTextClass(isPage),
1841
+ )}
1842
+ >
1843
+ Provider
1844
+ </span>
1845
+ <select
1846
+ value={emailProvider}
1847
+ onChange={(e) =>
1848
+ setEmailProvider(e.target.value as "resend" | "sendgrid")
1849
+ }
1850
+ className={cn(textInputClass(isPage), "w-full")}
1851
+ style={isPage ? CONTROL_STYLE_PAGE : undefined}
1852
+ >
1853
+ <option value="resend">Resend</option>
1854
+ <option value="sendgrid">SendGrid</option>
1855
+ </select>
1856
+ </label>
1857
+
1858
+ {emailProvider === "resend" ? (
1859
+ <ManualSetupCard
1860
+ hint="Use Resend for transactional email."
1861
+ docsUrl="https://resend.com/api-keys"
1862
+ docsLabel="Get a Resend key"
1863
+ >
1864
+ {resendConfigured ? (
1865
+ <div
1866
+ className={cn(
1867
+ "mb-1 flex items-center gap-1.5 text-green-500",
1868
+ noteTextClass(isPage),
1869
+ )}
1870
+ >
1871
+ <IconCheck size={emailIconSize} />
1872
+ RESEND_API_KEY configured
1873
+ </div>
1874
+ ) : (
1875
+ <div className="mb-1 flex gap-1.5">
1876
+ <input
1877
+ type="password"
1878
+ value={resendKey}
1879
+ onChange={(e) => setResendKey(e.target.value)}
1880
+ onKeyDown={(e) => {
1881
+ if (e.key === "Enter") saveResend();
1882
+ }}
1883
+ placeholder="re_..."
1884
+ className={emailInputCls}
1885
+ />
1886
+ <button
1887
+ onClick={saveResend}
1888
+ disabled={!resendKey.trim() || saving}
1889
+ className={emailBtnCls}
1890
+ >
1891
+ {saving ? (
1892
+ <IconLoader2 size={10} className="animate-spin" />
1893
+ ) : saved ? (
1894
+ <IconCheck size={10} />
1895
+ ) : (
1896
+ "Save"
1897
+ )}
1898
+ </button>
1899
+ </div>
1900
+ )}
1901
+ {fromConfigured ? (
1902
+ <div
1903
+ className={cn(
1904
+ "flex items-center gap-1.5 text-green-500",
1905
+ noteTextClass(isPage),
1906
+ )}
1907
+ >
1908
+ <IconCheck size={emailIconSize} />
1909
+ EMAIL_FROM configured
1910
+ </div>
1911
+ ) : (
1912
+ <div className="flex gap-1.5">
1913
+ <input
1914
+ type="text"
1915
+ value={fromAddr}
1916
+ onChange={(e) => setFromAddr(e.target.value)}
1917
+ onKeyDown={(e) => {
1918
+ if (e.key === "Enter") saveResend();
1919
+ }}
1920
+ placeholder="From address - e.g. Acme <hi@acme.com>"
1921
+ className={emailInputCls}
1922
+ />
1923
+ {!resendConfigured ? null : (
1924
+ <button
1925
+ onClick={saveResend}
1926
+ disabled={!fromAddr.trim() || saving}
1927
+ className={emailBtnCls}
1928
+ >
1929
+ {saving ? (
1930
+ <IconLoader2 size={10} className="animate-spin" />
1931
+ ) : saved ? (
1932
+ <IconCheck size={10} />
1933
+ ) : (
1934
+ "Save"
1935
+ )}
1936
+ </button>
1937
+ )}
1938
+ </div>
1939
+ )}
1940
+ </ManualSetupCard>
1941
+ ) : (
1942
+ <ManualSetupCard
1943
+ hint="Use SendGrid for transactional email. SendGrid requires a verified from address."
1944
+ docsUrl="https://app.sendgrid.com/settings/api_keys"
1945
+ docsLabel="Get a SendGrid key"
1946
+ >
1947
+ {sendgridConfigured ? (
1948
+ <div
1949
+ className={cn(
1950
+ "mb-1 flex items-center gap-1.5 text-green-500",
1951
+ noteTextClass(isPage),
1952
+ )}
1953
+ >
1954
+ <IconCheck size={emailIconSize} />
1955
+ SENDGRID_API_KEY configured
1956
+ </div>
1957
+ ) : (
1958
+ <div className="mb-1 flex gap-1.5">
1959
+ <input
1960
+ type="password"
1961
+ value={sendgridKey}
1962
+ onChange={(e) => setSendgridKey(e.target.value)}
1963
+ onKeyDown={(e) => {
1964
+ if (e.key === "Enter") saveSendgrid();
1965
+ }}
1966
+ placeholder="SG...."
1967
+ className={emailInputCls}
1968
+ />
1969
+ <button
1970
+ onClick={saveSendgrid}
1971
+ disabled={!sendgridKey.trim() || saving}
1972
+ className={emailBtnCls}
1973
+ >
1974
+ {saving ? (
1975
+ <IconLoader2 size={10} className="animate-spin" />
1976
+ ) : saved ? (
1977
+ <IconCheck size={10} />
1978
+ ) : (
1979
+ "Save"
1980
+ )}
1981
+ </button>
1982
+ </div>
1983
+ )}
1984
+ {fromConfigured ? (
1985
+ <div
1986
+ className={cn(
1987
+ "flex items-center gap-1.5 text-green-500",
1988
+ noteTextClass(isPage),
1989
+ )}
1990
+ >
1991
+ <IconCheck size={emailIconSize} />
1992
+ EMAIL_FROM configured
1993
+ </div>
1994
+ ) : (
1995
+ <div className="flex gap-1.5">
1996
+ <input
1997
+ type="text"
1998
+ value={fromAddr}
1999
+ onChange={(e) => setFromAddr(e.target.value)}
2000
+ onKeyDown={(e) => {
2001
+ if (e.key === "Enter") saveSendgrid();
2002
+ }}
2003
+ placeholder="From address - e.g. Acme <hi@acme.com>"
2004
+ className={emailInputCls}
2005
+ />
2006
+ {!sendgridConfigured ? null : (
2007
+ <button
2008
+ onClick={saveSendgrid}
2009
+ disabled={!fromAddr.trim() || saving}
2010
+ className={emailBtnCls}
2011
+ >
2012
+ {saving ? (
2013
+ <IconLoader2 size={10} className="animate-spin" />
2014
+ ) : saved ? (
2015
+ <IconCheck size={10} />
2016
+ ) : (
2017
+ "Save"
2018
+ )}
2019
+ </button>
2020
+ )}
2021
+ </div>
2022
+ )}
2023
+ </ManualSetupCard>
2024
+ )}
2025
+ </div>
2026
+ )}
2027
+ </SettingsSection>
2028
+ );
2029
+ }
2030
+
2031
+ // ─── Agent Limits Section ──────────────────────────────────────────────────
2032
+
2033
+ interface AgentLoopSettingsResponse {
2034
+ maxIterations: number;
2035
+ defaultMaxIterations: number;
2036
+ minMaxIterations: number;
2037
+ maxMaxIterations: number;
2038
+ scope: "org" | "user" | "default";
2039
+ source: "org" | "user" | "env" | "default";
2040
+ canUpdate: boolean;
2041
+ orgName?: string | null;
2042
+ role?: string | null;
2043
+ }
2044
+
2045
+ function AgentLimitsSectionInner({
2046
+ open,
2047
+ onToggle,
2048
+ }: {
2049
+ open?: boolean;
2050
+ onToggle?: () => void;
2051
+ }) {
2052
+ const isPage = useSettingsSurface() === "page";
2053
+ const [settings, setSettings] = useState<AgentLoopSettingsResponse | null>(
2054
+ null,
2055
+ );
2056
+ const [value, setValue] = useState("");
2057
+ const [loading, setLoading] = useState(true);
2058
+ const [saving, setSaving] = useState(false);
2059
+ const [saved, setSaved] = useState(false);
2060
+ const [error, setError] = useState<string | null>(null);
2061
+
2062
+ const load = useCallback(() => {
2063
+ let cancelled = false;
2064
+ setLoading(true);
2065
+ fetch(agentNativePath("/_agent-native/agent-loop-settings"))
2066
+ .then((r) => (r.ok ? r.json() : null))
2067
+ .then((data: AgentLoopSettingsResponse | null) => {
2068
+ if (cancelled || !data) return;
2069
+ setSettings(data);
2070
+ setValue(String(data.maxIterations));
2071
+ })
2072
+ .catch(() => {})
2073
+ .finally(() => {
2074
+ if (!cancelled) setLoading(false);
2075
+ });
2076
+ return () => {
2077
+ cancelled = true;
2078
+ };
2079
+ }, []);
2080
+
2081
+ useEffect(() => load(), [load]);
2082
+
2083
+ useEffect(() => {
2084
+ const handler = (event: Event) => {
2085
+ const detail = (event as CustomEvent).detail as
2086
+ | AgentLoopSettingsResponse
2087
+ | undefined;
2088
+ if (!detail?.maxIterations) return;
2089
+ setSettings(detail);
2090
+ setValue(String(detail.maxIterations));
2091
+ };
2092
+ window.addEventListener("agent-loop-settings:changed", handler);
2093
+ return () =>
2094
+ window.removeEventListener("agent-loop-settings:changed", handler);
2095
+ }, []);
2096
+
2097
+ const numericValue = Number(value);
2098
+ const hasPendingChange =
2099
+ !!settings &&
2100
+ settings.canUpdate &&
2101
+ Number.isInteger(numericValue) &&
2102
+ numericValue !== settings.maxIterations;
2103
+ const scopeLabel =
2104
+ settings?.scope === "org"
2105
+ ? settings.orgName
2106
+ ? `${settings.orgName} organization`
2107
+ : "organization"
2108
+ : "your account";
2109
+
2110
+ const save = async () => {
2111
+ if (!settings?.canUpdate) return;
2112
+ setSaving(true);
2113
+ setSaved(false);
2114
+ setError(null);
2115
+ try {
2116
+ const res = await fetch(
2117
+ agentNativePath("/_agent-native/agent-loop-settings"),
2118
+ {
2119
+ method: "PUT",
2120
+ headers: { "Content-Type": "application/json" },
2121
+ body: JSON.stringify({ maxIterations: numericValue }),
2122
+ },
2123
+ );
2124
+ const body = await res.json().catch(() => ({}));
2125
+ if (!res.ok) {
2126
+ throw new Error(body?.error ?? `Save failed (${res.status})`);
2127
+ }
2128
+ setSettings(body as AgentLoopSettingsResponse);
2129
+ setValue(String((body as AgentLoopSettingsResponse).maxIterations));
2130
+ setSaved(true);
2131
+ window.dispatchEvent(
2132
+ new CustomEvent("agent-loop-settings:changed", { detail: body }),
2133
+ );
2134
+ setTimeout(() => setSaved(false), 2000);
2135
+ } catch (err) {
2136
+ setError(err instanceof Error ? err.message : "Save failed");
2137
+ } finally {
2138
+ setSaving(false);
2139
+ }
2140
+ };
2141
+
2142
+ const reset = async () => {
2143
+ if (!settings?.canUpdate) return;
2144
+ setSaving(true);
2145
+ setSaved(false);
2146
+ setError(null);
2147
+ try {
2148
+ const res = await fetch(
2149
+ agentNativePath("/_agent-native/agent-loop-settings"),
2150
+ { method: "DELETE" },
2151
+ );
2152
+ const body = await res.json().catch(() => ({}));
2153
+ if (!res.ok) {
2154
+ throw new Error(body?.error ?? `Reset failed (${res.status})`);
2155
+ }
2156
+ setSettings(body as AgentLoopSettingsResponse);
2157
+ setValue(String((body as AgentLoopSettingsResponse).maxIterations));
2158
+ window.dispatchEvent(
2159
+ new CustomEvent("agent-loop-settings:changed", { detail: body }),
2160
+ );
2161
+ } catch (err) {
2162
+ setError(err instanceof Error ? err.message : "Reset failed");
2163
+ } finally {
2164
+ setSaving(false);
2165
+ }
2166
+ };
2167
+
2168
+ return (
2169
+ <SettingsSection
2170
+ id={settingsSectionDomId("limits")}
2171
+ icon={<IconGauge size={14} />}
2172
+ title="Agent Limits"
2173
+ subtitle="Control how long a single agent response can work before pausing."
2174
+ connected={
2175
+ loading
2176
+ ? undefined
2177
+ : settings
2178
+ ? settings.maxIterations !== settings.defaultMaxIterations
2179
+ : false
2180
+ }
2181
+ open={open}
2182
+ onToggle={onToggle}
2183
+ >
2184
+ {loading ? (
2185
+ <SettingsSkeleton lines={2} />
2186
+ ) : settings ? (
2187
+ <div className="space-y-2">
2188
+ <div
2189
+ className={cn(
2190
+ "rounded-md border border-border bg-accent/20",
2191
+ isPage ? "px-3.5 py-3" : "px-2.5 py-2",
2192
+ )}
2193
+ >
2194
+ <div className="flex items-center justify-between gap-2">
2195
+ <div>
2196
+ <p
2197
+ className={cn(
2198
+ "font-medium text-foreground",
2199
+ subTextClass(isPage),
2200
+ )}
2201
+ >
2202
+ Max iterations
2203
+ </p>
2204
+ <p
2205
+ className={cn(
2206
+ "mt-0.5 text-muted-foreground",
2207
+ noteTextClass(isPage),
2208
+ )}
2209
+ >
2210
+ Applies to {scopeLabel}. Default is{" "}
2211
+ {settings.defaultMaxIterations.toLocaleString()}.
2212
+ </p>
2213
+ </div>
2214
+ <span
2215
+ className={cn(
2216
+ "rounded-full bg-background px-2 py-0.5 font-medium text-muted-foreground",
2217
+ noteTextClass(isPage),
2218
+ )}
2219
+ >
2220
+ {settings.source}
2221
+ </span>
2222
+ </div>
2223
+ <div className="mt-2 flex items-center gap-1.5">
2224
+ <input
2225
+ type="number"
2226
+ min={settings.minMaxIterations}
2227
+ max={settings.maxMaxIterations}
2228
+ value={value}
2229
+ disabled={!settings.canUpdate || saving}
2230
+ onChange={(e) => {
2231
+ setValue(e.target.value);
2232
+ setError(null);
2233
+ }}
2234
+ onKeyDown={(e) => {
2235
+ if (e.key === "Enter" && hasPendingChange) void save();
2236
+ }}
2237
+ className={cn(
2238
+ textInputClass(isPage),
2239
+ "min-w-0 flex-1 disabled:opacity-60",
2240
+ )}
2241
+ style={isPage ? CONTROL_STYLE_PAGE : undefined}
2242
+ />
2243
+ <button
2244
+ type="button"
2245
+ onClick={save}
2246
+ disabled={!hasPendingChange || saving}
2247
+ className={pillButtonClass(isPage, "solid")}
2248
+ >
2249
+ {saving ? (
2250
+ <IconLoader2
2251
+ size={isPage ? 14 : 10}
2252
+ className="animate-spin"
2253
+ />
2254
+ ) : saved ? (
2255
+ <IconCheck size={isPage ? 14 : 10} />
2256
+ ) : (
2257
+ "Save"
2258
+ )}
2259
+ </button>
2260
+ <button
2261
+ type="button"
2262
+ onClick={reset}
2263
+ disabled={
2264
+ !settings.canUpdate ||
2265
+ saving ||
2266
+ settings.maxIterations === settings.defaultMaxIterations
2267
+ }
2268
+ className={pillButtonClass(isPage, "outline")}
2269
+ >
2270
+ Reset
2271
+ </button>
2272
+ </div>
2273
+ {!settings.canUpdate && (
2274
+ <p
2275
+ className={cn(
2276
+ "mt-2 text-muted-foreground",
2277
+ noteTextClass(isPage),
2278
+ )}
2279
+ >
2280
+ Only organization owners and admins can change this limit.
2281
+ </p>
2282
+ )}
2283
+ {error && (
2284
+ <p className={cn("mt-2 text-destructive", noteTextClass(isPage))}>
2285
+ {error}
2286
+ </p>
2287
+ )}
2288
+ </div>
2289
+ </div>
2290
+ ) : (
2291
+ <p className={cn("text-muted-foreground", noteTextClass(isPage))}>
2292
+ Agent limit settings are unavailable.
2293
+ </p>
2294
+ )}
2295
+ </SettingsSection>
2296
+ );
2297
+ }
2298
+
2299
+ // ─── Main SettingsPanel ─────────────────────────────────────────────────────
2300
+
2301
+ export interface SettingsPanelProps {
2302
+ isDevMode: boolean;
2303
+ onToggleDevMode: () => void;
2304
+ showDevToggle: boolean;
2305
+ devAppUrl?: string;
2306
+ initialSection?: string | null;
2307
+ sectionRequestKey?: number;
2308
+ }
2309
+
2310
+ function normalizeSettingsSection(
2311
+ value?: string | null,
2312
+ ): SettingsSectionId | null {
2313
+ const normalized = value?.replace(/^#/, "").toLowerCase() ?? "";
2314
+ if (!normalized) return null;
2315
+ if (normalized.startsWith("secrets")) return "secrets";
2316
+ if (
2317
+ normalized === "workspace" ||
2318
+ normalized === "workspace-settings" ||
2319
+ normalized === "organization" ||
2320
+ normalized === "org"
2321
+ ) {
2322
+ return "secrets";
2323
+ }
2324
+ if (normalized === "agent-engine") return "llm";
2325
+ if (
2326
+ normalized === "agent-model-defaults" ||
2327
+ normalized === "app-model-defaults" ||
2328
+ normalized === "models"
2329
+ ) {
2330
+ return "app-models";
2331
+ }
2332
+ if (normalized === "agent-limits" || normalized === "loop-settings") {
2333
+ return "limits";
2334
+ }
2335
+ return SETTINGS_SECTION_IDS.has(normalized as SettingsSectionId)
2336
+ ? (normalized as SettingsSectionId)
2337
+ : null;
2338
+ }
2339
+
2340
+ function settingsSectionDomId(section: SettingsSectionId): string {
2341
+ return `agent-settings-section-${section}`;
2342
+ }
2343
+
2344
+ function initialOpenSection(): SettingsSectionId {
2345
+ if (typeof window === "undefined") return "llm";
2346
+ return normalizeSettingsSection(window.location.hash) ?? "llm";
2347
+ }
2348
+
2349
+ function firstVisibleSection(
2350
+ sections: readonly SettingsSectionId[],
2351
+ ): SettingsSectionId {
2352
+ return sections[0] ?? "llm";
2353
+ }
2354
+
2355
+ // Agent capability modes. The internal values ("production"/"development") are
2356
+ // kept for back-compat with the AGENT_MODE wiring; only the visible labels
2357
+ // changed to "App mode" / "Code mode" so this control reads as the agent
2358
+ // capability it is — not the deployment environment (NODE_ENV).
2359
+ const agentModeOptions: SettingsSelectOption[] = [
2360
+ {
2361
+ value: "production",
2362
+ label: "App mode",
2363
+ description:
2364
+ "App tools only; code, bash, and files require Builder or a local clone.",
2365
+ },
2366
+ {
2367
+ value: "development",
2368
+ label: "Code mode",
2369
+ description: "Full access to code editing, bash, and files.",
2370
+ },
2371
+ ];
2372
+
2373
+ function CapabilityStatusRow({
2374
+ label,
2375
+ value,
2376
+ active,
2377
+ }: {
2378
+ label: string;
2379
+ value: React.ReactNode;
2380
+ active: boolean;
2381
+ }) {
2382
+ return (
2383
+ <div className="flex items-center justify-between gap-2 text-[10px]">
2384
+ <span className="flex items-center gap-1.5 text-muted-foreground">
2385
+ <span
2386
+ className={`h-1.5 w-1.5 rounded-full ${active ? "bg-green-500" : "bg-muted-foreground/30"}`}
2387
+ aria-hidden="true"
2388
+ />
2389
+ {label}
2390
+ </span>
2391
+ <span className="min-w-0 truncate text-end text-foreground">{value}</span>
2392
+ </div>
2393
+ );
2394
+ }
2395
+
2396
+ function CapabilityStatusStrip({
2397
+ isDevMode,
2398
+ builderConnected,
2399
+ builderLoading,
2400
+ builderBranchesAvailable,
2401
+ onOpenLlm,
2402
+ }: {
2403
+ isDevMode: boolean;
2404
+ builderConnected: boolean;
2405
+ builderLoading: boolean;
2406
+ builderBranchesAvailable: boolean;
2407
+ onOpenLlm: () => void;
2408
+ }) {
2409
+ const codeAvailable =
2410
+ isDevMode || (builderConnected && builderBranchesAvailable);
2411
+ const codeLabel = isDevMode
2412
+ ? "Local tools"
2413
+ : builderConnected && builderBranchesAvailable
2414
+ ? "Builder branches"
2415
+ : "Desktop/local";
2416
+
2417
+ return (
2418
+ <div className="rounded-md border border-border bg-muted/20 px-2.5 py-2">
2419
+ <div className="mb-1.5 text-[10px] font-medium text-muted-foreground">
2420
+ Available now
2421
+ </div>
2422
+ <div className="space-y-1.5">
2423
+ <CapabilityStatusRow label="App" value="Chat + actions" active />
2424
+ <CapabilityStatusRow
2425
+ label="Code"
2426
+ value={codeLabel}
2427
+ active={codeAvailable}
2428
+ />
2429
+ <CapabilityStatusRow
2430
+ label="Builder"
2431
+ active={builderConnected}
2432
+ value={
2433
+ builderLoading ? (
2434
+ "Checking..."
2435
+ ) : builderConnected ? (
2436
+ "Connected"
2437
+ ) : (
2438
+ <button
2439
+ type="button"
2440
+ onClick={onOpenLlm}
2441
+ className="rounded border border-border px-1.5 py-0.5 text-[10px] text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground"
2442
+ >
2443
+ Connect
2444
+ </button>
2445
+ )
2446
+ }
2447
+ />
2448
+ </div>
2449
+ </div>
2450
+ );
2451
+ }
2452
+
2453
+ function AccountSectionInner({
2454
+ open,
2455
+ onToggle,
2456
+ }: {
2457
+ open: boolean;
2458
+ onToggle: () => void;
2459
+ }) {
2460
+ const isPage = useSettingsSurface() === "page";
2461
+ const { session, isLoading } = useSession();
2462
+ const email = session?.email;
2463
+ const avatarUrl = useAvatarUrl(email);
2464
+ const fileInputRef = useRef<HTMLInputElement>(null);
2465
+ const [uploading, setUploading] = useState(false);
2466
+ const [status, setStatus] = useState<"idle" | "saved" | "error">("idle");
2467
+
2468
+ const displayName = session?.name || email || "Signed out";
2469
+ const initials = (session?.name || email || "?")
2470
+ .split(/[ @._-]+/)
2471
+ .filter(Boolean)
2472
+ .slice(0, 2)
2473
+ .map((part) => part[0]?.toUpperCase())
2474
+ .join("");
2475
+
2476
+ const handleAvatarChange = async (
2477
+ event: React.ChangeEvent<HTMLInputElement>,
2478
+ ) => {
2479
+ const file = event.target.files?.[0];
2480
+ event.target.value = "";
2481
+ if (!file || !email) return;
2482
+ setUploading(true);
2483
+ setStatus("idle");
2484
+ try {
2485
+ await uploadAvatar(file, email);
2486
+ setStatus("saved");
2487
+ } catch {
2488
+ setStatus("error");
2489
+ } finally {
2490
+ setUploading(false);
2491
+ }
2492
+ };
2493
+
2494
+ return (
2495
+ <SettingsSection
2496
+ id={settingsSectionDomId("account")}
2497
+ icon={<IconUserCircle size={14} />}
2498
+ title="Account"
2499
+ subtitle="Your profile photo and signed-in identity."
2500
+ open={open}
2501
+ onToggle={onToggle}
2502
+ >
2503
+ <div className="flex items-center gap-3">
2504
+ <div
2505
+ className={cn(
2506
+ "flex shrink-0 items-center justify-center overflow-hidden rounded-full border border-border bg-accent font-semibold text-muted-foreground",
2507
+ isPage ? "h-14 w-14 text-[15px]" : "h-12 w-12 text-[13px]",
2508
+ )}
2509
+ >
2510
+ {avatarUrl ? (
2511
+ <img
2512
+ src={avatarUrl}
2513
+ alt=""
2514
+ className="h-full w-full object-cover"
2515
+ />
2516
+ ) : (
2517
+ initials
2518
+ )}
2519
+ </div>
2520
+ <div className="min-w-0 flex-1">
2521
+ <p
2522
+ className={cn(
2523
+ "truncate font-medium text-foreground",
2524
+ isPage ? "text-sm" : "text-[12px]",
2525
+ )}
2526
+ >
2527
+ {isLoading ? "Loading..." : displayName}
2528
+ </p>
2529
+ {email && (
2530
+ <p
2531
+ className={cn(
2532
+ "truncate text-muted-foreground",
2533
+ subTextClass(isPage),
2534
+ )}
2535
+ >
2536
+ {email}
2537
+ </p>
2538
+ )}
2539
+ {status === "saved" && (
2540
+ <p
2541
+ className={cn(
2542
+ "mt-1 text-green-600 dark:text-green-400",
2543
+ subTextClass(isPage),
2544
+ )}
2545
+ >
2546
+ Photo updated
2547
+ </p>
2548
+ )}
2549
+ {status === "error" && (
2550
+ <p className={cn("mt-1 text-destructive", subTextClass(isPage))}>
2551
+ Could not update photo
2552
+ </p>
2553
+ )}
2554
+ </div>
2555
+ <input
2556
+ ref={fileInputRef}
2557
+ type="file"
2558
+ accept="image/*"
2559
+ className="hidden"
2560
+ onChange={handleAvatarChange}
2561
+ />
2562
+ <button
2563
+ type="button"
2564
+ disabled={!email || uploading}
2565
+ onClick={() => fileInputRef.current?.click()}
2566
+ className={cn(
2567
+ pillButtonClass(isPage, "outline"),
2568
+ "shrink-0 justify-center",
2569
+ )}
2570
+ >
2571
+ {uploading ? "Uploading..." : "Change photo"}
2572
+ </button>
2573
+ </div>
2574
+ </SettingsSection>
2575
+ );
2576
+ }
2577
+
2578
+ interface SettingsPanelContentProps extends SettingsPanelProps {
2579
+ sections?: readonly SettingsSectionId[];
2580
+ showCapabilityStrip?: boolean;
2581
+ className?: string;
2582
+ surface?: SettingsSurface;
2583
+ builderConnectionOwnedExternally?: boolean;
2584
+ }
2585
+
2586
+ function SettingsPanelContent({
2587
+ isDevMode,
2588
+ onToggleDevMode,
2589
+ showDevToggle,
2590
+ devAppUrl,
2591
+ initialSection,
2592
+ sectionRequestKey,
2593
+ sections = ALL_SETTINGS_SECTIONS,
2594
+ showCapabilityStrip = true,
2595
+ className,
2596
+ surface = "sidebar",
2597
+ builderConnectionOwnedExternally = false,
2598
+ }: SettingsPanelContentProps) {
2599
+ const { status: builder, loading: builderLoading } = useBuilderStatus({
2600
+ enabled: !builderConnectionOwnedExternally,
2601
+ });
2602
+ const connected = builder?.configured ?? false;
2603
+ const connectUrl = builder?.cliAuthUrl ?? builder?.connectUrl;
2604
+ const orgName = builder?.orgName;
2605
+ const envManaged = !!builder?.envManaged;
2606
+ const credentialSource = builder?.credentialSource;
2607
+ const builderBranchesAvailable = !!builder?.builderEnabled;
2608
+ const builderFlow = useBuilderConnectFlow({
2609
+ enabled: !builderConnectionOwnedExternally,
2610
+ popupUrl: connectUrl,
2611
+ trackingSource: "settings_panel_builder_card",
2612
+ });
2613
+
2614
+ // When opened via a `#secrets:<KEY>` hash, focus that specific secret input
2615
+ // inside the "API Keys & Connections" section.
2616
+ const [focusSecretKey, setFocusSecretKey] = useState<string | undefined>(
2617
+ undefined,
2618
+ );
2619
+ const visibleSections = useMemo(() => new Set(sections), [sections]);
2620
+ const shouldShowSection = useCallback(
2621
+ (section: SettingsSectionId) => visibleSections.has(section),
2622
+ [visibleSections],
2623
+ );
2624
+
2625
+ // Accordion: only one section open at a time (null = all closed)
2626
+ const [openSection, setOpenSection] = useState<string | null>(() => {
2627
+ const initial = initialOpenSection();
2628
+ return visibleSections.has(initial)
2629
+ ? initial
2630
+ : firstVisibleSection(sections);
2631
+ });
2632
+ const toggle = (id: string) =>
2633
+ setOpenSection((prev) => (prev === id ? null : id));
2634
+
2635
+ const scrollSectionIntoView = useCallback((section: SettingsSectionId) => {
2636
+ window.requestAnimationFrame(() => {
2637
+ document.getElementById(settingsSectionDomId(section))?.scrollIntoView({
2638
+ block: "start",
2639
+ behavior: "smooth",
2640
+ });
2641
+ });
2642
+ }, []);
2643
+
2644
+ const openSettingsSection = useCallback(
2645
+ (section: SettingsSectionId, scroll = false) => {
2646
+ setOpenSection(section);
2647
+ if (scroll) scrollSectionIntoView(section);
2648
+ },
2649
+ [scrollSectionIntoView],
2650
+ );
2651
+
2652
+ useEffect(() => {
2653
+ const section = normalizeSettingsSection(initialSection);
2654
+ if (!section || !shouldShowSection(section)) return;
2655
+ if (section !== "secrets") setFocusSecretKey(undefined);
2656
+ openSettingsSection(section, true);
2657
+ }, [
2658
+ initialSection,
2659
+ sectionRequestKey,
2660
+ openSettingsSection,
2661
+ shouldShowSection,
2662
+ ]);
2663
+
2664
+ // Support `#secrets:<KEY>` hash fragments from the onboarding CTA — opens
2665
+ // the section and focuses the matching input.
2666
+ useEffect(() => {
2667
+ if (typeof window === "undefined") return;
2668
+ const handleHash = () => {
2669
+ const hash = window.location.hash?.replace(/^#/, "") ?? "";
2670
+ const section = normalizeSettingsSection(hash);
2671
+ if (!section || !shouldShowSection(section)) return;
2672
+ if (hash.startsWith("secrets:") || hash === "secrets") {
2673
+ const key = hash.slice("secrets:".length);
2674
+ setFocusSecretKey(key || undefined);
2675
+ } else {
2676
+ setFocusSecretKey(undefined);
2677
+ }
2678
+ openSettingsSection(section, true);
2679
+ };
2680
+ handleHash();
2681
+ window.addEventListener("hashchange", handleHash);
2682
+ return () => window.removeEventListener("hashchange", handleHash);
2683
+ }, [openSettingsSection, shouldShowSection]);
2684
+
2685
+ const isPage = surface === "page";
2686
+
2687
+ return (
2688
+ <SettingsSurfaceProvider surface={surface}>
2689
+ <div
2690
+ className={cn(
2691
+ isPage ? "space-y-3" : "flex-1 min-h-0 overflow-y-auto p-3 space-y-2",
2692
+ className,
2693
+ )}
2694
+ style={isPage ? undefined : { overflowY: "auto" }}
2695
+ >
2696
+ {/* Agent capability mode (App vs Code) + app link */}
2697
+ {(showDevToggle || devAppUrl) && (
2698
+ <div className="space-y-2 pb-2 border-b border-border mb-2">
2699
+ {showDevToggle && (
2700
+ <SettingsSelect
2701
+ label="Agent mode"
2702
+ labelAdornment={
2703
+ devAppUrl ? (
2704
+ <Tooltip>
2705
+ <TooltipTrigger asChild>
2706
+ <a
2707
+ href={devAppUrl}
2708
+ target="_blank"
2709
+ rel="noopener noreferrer"
2710
+ aria-label="Open app in new tab"
2711
+ className="flex items-center text-muted-foreground hover:text-foreground"
2712
+ >
2713
+ <IconExternalLink size={14} />
2714
+ </a>
2715
+ </TooltipTrigger>
2716
+ <TooltipContent>Open app in new tab</TooltipContent>
2717
+ </Tooltip>
2718
+ ) : undefined
2719
+ }
2720
+ value={isDevMode ? "development" : "production"}
2721
+ options={agentModeOptions}
2722
+ onValueChange={(next) => {
2723
+ const nextIsDev = next === "development";
2724
+ if (nextIsDev !== isDevMode) onToggleDevMode();
2725
+ }}
2726
+ />
2727
+ )}
2728
+ </div>
2729
+ )}
2730
+
2731
+ {showCapabilityStrip && (
2732
+ <CapabilityStatusStrip
2733
+ isDevMode={isDevMode}
2734
+ builderConnected={connected}
2735
+ builderLoading={builderLoading}
2736
+ builderBranchesAvailable={builderBranchesAvailable}
2737
+ onOpenLlm={() => openSettingsSection("llm", true)}
2738
+ />
2739
+ )}
2740
+
2741
+ {/* Account */}
2742
+ {shouldShowSection("account") && (
2743
+ <AccountSectionInner
2744
+ open={openSection === "account"}
2745
+ onToggle={() => toggle("account")}
2746
+ />
2747
+ )}
2748
+
2749
+ {/* LLM */}
2750
+ {shouldShowSection("llm") && (
2751
+ <LLMSectionInner
2752
+ builderFlow={builderFlow}
2753
+ builderLoading={builderLoading}
2754
+ connectUrl={connectUrl}
2755
+ connected={connected}
2756
+ orgName={orgName}
2757
+ envManaged={envManaged}
2758
+ credentialSource={credentialSource}
2759
+ open={openSection === "llm"}
2760
+ onToggle={() => toggle("llm")}
2761
+ />
2762
+ )}
2763
+
2764
+ {/* App default model */}
2765
+ {shouldShowSection("app-models") && (
2766
+ <AppModelDefaultsSectionInner
2767
+ open={openSection === "app-models"}
2768
+ onToggle={() => toggle("app-models")}
2769
+ />
2770
+ )}
2771
+
2772
+ {/* Agent limits */}
2773
+ {shouldShowSection("limits") && (
2774
+ <AgentLimitsSectionInner
2775
+ open={openSection === "limits"}
2776
+ onToggle={() => toggle("limits")}
2777
+ />
2778
+ )}
2779
+
2780
+ {/* Voice transcription */}
2781
+ {shouldShowSection("voice") && (
2782
+ <SettingsSection
2783
+ id={settingsSectionDomId("voice")}
2784
+ icon={<IconMicrophone size={14} />}
2785
+ title="Voice Transcription"
2786
+ subtitle="How the composer microphone turns your voice into text."
2787
+ open={openSection === "voice"}
2788
+ onToggle={() => toggle("voice")}
2789
+ >
2790
+ <VoiceTranscriptionSection />
2791
+ </SettingsSection>
2792
+ )}
2793
+
2794
+ {/* Demo mode */}
2795
+ {shouldShowSection("demo-mode") && (
2796
+ <SettingsSection
2797
+ id={settingsSectionDomId("demo-mode")}
2798
+ icon={<IconEyeOff size={14} />}
2799
+ title="Demo mode"
2800
+ subtitle="Replace displayed emails with realistic fake data in this browser and reshape supported charts for presentations. Backend, MCP, and agent results stay real and access-scoped."
2801
+ open={openSection === "demo-mode"}
2802
+ onToggle={() => toggle("demo-mode")}
2803
+ >
2804
+ <DemoModeSection />
2805
+ </SettingsSection>
2806
+ )}
2807
+
2808
+ {/* Automations */}
2809
+ {shouldShowSection("automations") && (
2810
+ <SettingsSection
2811
+ id={settingsSectionDomId("automations")}
2812
+ icon={<IconBolt size={14} />}
2813
+ title="Automations"
2814
+ subtitle="Event-triggered and scheduled automations."
2815
+ open={openSection === "automations"}
2816
+ onToggle={() => toggle("automations")}
2817
+ >
2818
+ <AutomationsSection />
2819
+ </SettingsSection>
2820
+ )}
2821
+
2822
+ {/* API Keys & Connections */}
2823
+ {shouldShowSection("secrets") && (
2824
+ <SettingsSection
2825
+ id={settingsSectionDomId("secrets")}
2826
+ icon={<IconKey size={14} />}
2827
+ title="API Keys & Connections"
2828
+ subtitle="Service credentials and automation keys."
2829
+ open={openSection === "secrets"}
2830
+ onToggle={() => toggle("secrets")}
2831
+ >
2832
+ <SecretsSection focusKey={focusSecretKey} />
2833
+ </SettingsSection>
2834
+ )}
2835
+
2836
+ {/* Hosting */}
2837
+ {shouldShowSection("hosting") && (
2838
+ <SettingsSection
2839
+ id={settingsSectionDomId("hosting")}
2840
+ icon={<IconCloud size={14} />}
2841
+ title="Hosting"
2842
+ subtitle="Deploy your app to the cloud."
2843
+ connected={connected}
2844
+ open={openSection === "hosting"}
2845
+ onToggle={() => toggle("hosting")}
2846
+ >
2847
+ <div className="space-y-2">
2848
+ <UseBuilderCard
2849
+ builderFlow={builderFlow}
2850
+ connectUrl={connectUrl}
2851
+ connected={connected}
2852
+ orgName={orgName}
2853
+ envManaged={envManaged}
2854
+ credentialSource={credentialSource}
2855
+ trackingSource="hosting_settings"
2856
+ trackingFlow="hosting"
2857
+ />
2858
+ <ManualSetupCard
2859
+ hint="Deploy manually to Netlify, Vercel, Cloudflare, or any Nitro-supported target."
2860
+ docsUrl="https://www.builder.io/c/docs/agent-native-deployment"
2861
+ dim={connected}
2862
+ />
2863
+ </div>
2864
+ </SettingsSection>
2865
+ )}
2866
+
2867
+ {/* Database */}
2868
+ {shouldShowSection("database") && (
2869
+ <SettingsSection
2870
+ id={settingsSectionDomId("database")}
2871
+ icon={<IconDatabase size={14} />}
2872
+ title="Database"
2873
+ subtitle="Connect a cloud database for persistent storage."
2874
+ connected={connected}
2875
+ open={openSection === "database"}
2876
+ onToggle={() => toggle("database")}
2877
+ >
2878
+ <div className="space-y-2">
2879
+ <UseBuilderCard
2880
+ builderFlow={builderFlow}
2881
+ connectUrl={connectUrl}
2882
+ connected={connected}
2883
+ orgName={orgName}
2884
+ envManaged={envManaged}
2885
+ credentialSource={credentialSource}
2886
+ trackingSource="database_settings"
2887
+ trackingFlow="database"
2888
+ />
2889
+ <ManualSetupCard
2890
+ hint="Set DATABASE_URL in your .env to connect Neon, Supabase, Turso, any Postgres/SQLite database, or local PGlite with pglite:./data/pglite."
2891
+ docsUrl="https://www.builder.io/c/docs/agent-native-database"
2892
+ dim={connected}
2893
+ />
2894
+ </div>
2895
+ </SettingsSection>
2896
+ )}
2897
+
2898
+ {/* File uploads */}
2899
+ {shouldShowSection("uploads") && (
2900
+ <SettingsSection
2901
+ id={settingsSectionDomId("uploads")}
2902
+ icon={<IconUpload size={14} />}
2903
+ title="File uploads"
2904
+ subtitle="Where user-uploaded files (avatars, chat attachments) are stored."
2905
+ connected={connected}
2906
+ open={openSection === "uploads"}
2907
+ onToggle={() => toggle("uploads")}
2908
+ >
2909
+ <div className="space-y-2">
2910
+ <UseBuilderCard
2911
+ builderFlow={builderFlow}
2912
+ connectUrl={connectUrl}
2913
+ connected={connected}
2914
+ orgName={orgName}
2915
+ envManaged={envManaged}
2916
+ credentialSource={credentialSource}
2917
+ trackingSource="file_upload_settings"
2918
+ trackingFlow="file_upload"
2919
+ />
2920
+ <ManualSetupCard
2921
+ hint="Without a provider, files are stored as base64 in your database. Fine for dev, not recommended for production."
2922
+ docsUrl="https://www.builder.io/c/docs/agent-native-file-uploads"
2923
+ dim={connected}
2924
+ />
2925
+ </div>
2926
+ </SettingsSection>
2927
+ )}
2928
+
2929
+ {/* Authentication */}
2930
+ {shouldShowSection("auth") && (
2931
+ <SettingsSection
2932
+ id={settingsSectionDomId("auth")}
2933
+ icon={<IconShield size={14} />}
2934
+ title="Authentication"
2935
+ subtitle="Set up user authentication and access control."
2936
+ connected={connected}
2937
+ open={openSection === "auth"}
2938
+ onToggle={() => toggle("auth")}
2939
+ >
2940
+ <div className="space-y-2">
2941
+ <UseBuilderCard
2942
+ builderFlow={builderFlow}
2943
+ connectUrl={connectUrl}
2944
+ connected={connected}
2945
+ orgName={orgName}
2946
+ envManaged={envManaged}
2947
+ credentialSource={credentialSource}
2948
+ trackingSource="auth_settings"
2949
+ trackingFlow="auth"
2950
+ />
2951
+ <ManualSetupCard
2952
+ hint="Configure Better Auth with BETTER_AUTH_SECRET and optional Google/GitHub OAuth providers."
2953
+ docsUrl="https://www.builder.io/c/docs/agent-native-authentication"
2954
+ dim={connected}
2955
+ />
2956
+ </div>
2957
+ </SettingsSection>
2958
+ )}
2959
+
2960
+ {/* Email */}
2961
+ {shouldShowSection("email") && (
2962
+ <EmailSectionInner
2963
+ open={openSection === "email"}
2964
+ onToggle={() => toggle("email")}
2965
+ />
2966
+ )}
2967
+
2968
+ {/* Browser Automation */}
2969
+ {shouldShowSection("browser") && (
2970
+ <SettingsSection
2971
+ id={settingsSectionDomId("browser")}
2972
+ icon={<IconBrowser size={14} />}
2973
+ title="Browser Automation"
2974
+ subtitle="Let agents control a real browser for web tasks."
2975
+ connected={builderConnectionOwnedExternally ? undefined : connected}
2976
+ open={openSection === "browser"}
2977
+ onToggle={() => toggle("browser")}
2978
+ >
2979
+ {!builderConnectionOwnedExternally ? (
2980
+ <UseBuilderCard
2981
+ builderFlow={builderFlow}
2982
+ connectUrl={connectUrl}
2983
+ connected={connected}
2984
+ orgName={orgName}
2985
+ envManaged={envManaged}
2986
+ credentialSource={credentialSource}
2987
+ trackingSource="browser_settings"
2988
+ trackingFlow="browser_automation"
2989
+ />
2990
+ ) : null}
2991
+ </SettingsSection>
2992
+ )}
2993
+
2994
+ {builderBranchesAvailable && shouldShowSection("background") && (
2995
+ <SettingsSection
2996
+ id={settingsSectionDomId("background")}
2997
+ icon={<IconGitBranch size={14} />}
2998
+ title="Background Agent"
2999
+ subtitle="Make code changes from production mode via Builder."
3000
+ connected={connected}
3001
+ open={openSection === "background"}
3002
+ onToggle={() => toggle("background")}
3003
+ >
3004
+ <UseBuilderCard
3005
+ builderFlow={builderFlow}
3006
+ connectUrl={connectUrl}
3007
+ connected={connected}
3008
+ orgName={orgName}
3009
+ envManaged={envManaged}
3010
+ credentialSource={credentialSource}
3011
+ trackingSource="background_agent_settings"
3012
+ trackingFlow="background_agent"
3013
+ />
3014
+ </SettingsSection>
3015
+ )}
3016
+
3017
+ {/* Integrations */}
3018
+ {shouldShowSection("integrations") && (
3019
+ <SettingsSection
3020
+ id={settingsSectionDomId("integrations")}
3021
+ icon={<IconPlugConnected size={14} />}
3022
+ title="Integrations"
3023
+ subtitle="Connect messaging platforms and external services."
3024
+ open={openSection === "integrations"}
3025
+ onToggle={() => toggle("integrations")}
3026
+ >
3027
+ <Suspense fallback={null}>
3028
+ <IntegrationsPanel />
3029
+ </Suspense>
3030
+ </SettingsSection>
3031
+ )}
3032
+
3033
+ {/* Usage & spend */}
3034
+ {shouldShowSection("usage") && (
3035
+ <SettingsSection
3036
+ id={settingsSectionDomId("usage")}
3037
+ icon={<IconCoin size={14} />}
3038
+ title="Usage"
3039
+ subtitle="Track token consumption and estimated cost — broken down by chat, automations, and background jobs."
3040
+ open={openSection === "usage"}
3041
+ onToggle={() => toggle("usage")}
3042
+ >
3043
+ <UsageSection />
3044
+ </SettingsSection>
3045
+ )}
3046
+
3047
+ {/* A2A Agents */}
3048
+ {shouldShowSection("a2a") && (
3049
+ <SettingsSection
3050
+ id={settingsSectionDomId("a2a")}
3051
+ icon={<IconTopologyRing2 size={14} />}
3052
+ title="Connected Agents (A2A)"
3053
+ subtitle="Manage remote agents connected via the A2A protocol."
3054
+ open={openSection === "a2a"}
3055
+ onToggle={() => toggle("a2a")}
3056
+ >
3057
+ <AgentsSection />
3058
+ </SettingsSection>
3059
+ )}
3060
+ </div>
3061
+ </SettingsSurfaceProvider>
3062
+ );
3063
+ }
3064
+
3065
+ export function SettingsPanel(props: SettingsPanelProps) {
3066
+ return <SettingsPanelContent {...props} />;
3067
+ }
3068
+
3069
+ export function ConnectionsSettingsContent({
3070
+ settingsPanelProps,
3071
+ }: {
3072
+ settingsPanelProps: SettingsPanelProps;
3073
+ }) {
3074
+ return (
3075
+ <div className="mx-auto w-full max-w-2xl space-y-4">
3076
+ <BuilderConnectCard trackingSource="settings_connections" />
3077
+ <SettingsPanelContent
3078
+ {...settingsPanelProps}
3079
+ surface="page"
3080
+ sections={CONNECTION_SETTINGS_SECTIONS}
3081
+ showCapabilityStrip={false}
3082
+ className="w-full"
3083
+ builderConnectionOwnedExternally
3084
+ />
3085
+ </div>
3086
+ );
3087
+ }
3088
+
3089
+ export function useAgentSettingsTabs(): SettingsTabItem[] {
3090
+ const { isDevMode, canToggle, setDevMode } = useDevMode();
3091
+ const baseProps = useMemo<SettingsPanelProps>(
3092
+ () => ({
3093
+ isDevMode,
3094
+ onToggleDevMode: () => {
3095
+ void setDevMode(!isDevMode);
3096
+ },
3097
+ showDevToggle: canToggle,
3098
+ }),
3099
+ [canToggle, isDevMode, setDevMode],
3100
+ );
3101
+
3102
+ return useMemo<SettingsTabItem[]>(() => {
3103
+ const searchTabs = getAgentSettingsSearchTabs();
3104
+ const searchTab = (
3105
+ id: "agent" | "connections" | "organization" | "workspace",
3106
+ ) => {
3107
+ const tab = searchTabs.find((candidate) => candidate.id === id);
3108
+ if (!tab) throw new Error(`Missing agent workspace tab: ${id}`);
3109
+ return tab;
3110
+ };
3111
+ const agent = searchTab("agent");
3112
+ const connections = searchTab("connections");
3113
+ const organization = searchTab("organization");
3114
+ const workspace = searchTab("workspace");
3115
+ return [
3116
+ {
3117
+ ...agent,
3118
+ icon: IconHierarchy2,
3119
+ group: "agent",
3120
+ content: (
3121
+ <SettingsPanelContent
3122
+ {...baseProps}
3123
+ surface="page"
3124
+ sections={AGENT_SETTINGS_SECTIONS}
3125
+ showCapabilityStrip={false}
3126
+ className="mx-auto w-full max-w-2xl"
3127
+ />
3128
+ ),
3129
+ },
3130
+ {
3131
+ ...connections,
3132
+ icon: IconPlugConnected,
3133
+ group: "agent",
3134
+ content: <ConnectionsSettingsContent settingsPanelProps={baseProps} />,
3135
+ },
3136
+ {
3137
+ ...organization,
3138
+ icon: IconUsersGroup,
3139
+ group: "workspace",
3140
+ content: (
3141
+ <div className="mx-auto w-full max-w-2xl">
3142
+ <TeamPage showTitle={false} />
3143
+ </div>
3144
+ ),
3145
+ },
3146
+ {
3147
+ ...workspace,
3148
+ icon: IconCloud,
3149
+ group: "workspace",
3150
+ content: (
3151
+ <SettingsPanelContent
3152
+ {...baseProps}
3153
+ surface="page"
3154
+ sections={WORKSPACE_SETTINGS_SECTIONS}
3155
+ showCapabilityStrip={false}
3156
+ className="mx-auto w-full max-w-2xl"
3157
+ />
3158
+ ),
3159
+ },
3160
+ ];
3161
+ }, [baseProps]);
3162
+ }