@vellumai/assistant 0.7.3 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -88,6 +88,7 @@ function mergeDefaultConfigAndSeedInferenceProfiles(): void {
88
88
  seedInferenceProfiles({
89
89
  preserveProfileNames: defaultConfigMerge.providedLlmProfileNames,
90
90
  preserveActiveProfile: defaultConfigMerge.providedLlmActiveProfile,
91
+ isHatch: defaultConfigMerge.hadOverlay,
91
92
  });
92
93
  }
93
94
 
@@ -309,12 +310,14 @@ describe("loadConfig startup behavior", () => {
309
310
  ensureTestDir();
310
311
  _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
311
312
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
313
+ delete process.env.IS_PLATFORM;
312
314
  invalidateConfigCache();
313
315
  });
314
316
 
315
317
  afterEach(() => {
316
318
  _setStorePath(null);
317
319
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
320
+ delete process.env.IS_PLATFORM;
318
321
  invalidateConfigCache();
319
322
  });
320
323
 
@@ -406,7 +409,7 @@ describe("loadConfig startup behavior", () => {
406
409
  expect(raw.dataDir).toBeUndefined();
407
410
  });
408
411
 
409
- test("hatch default overlay does not suppress first-load inference profiles", () => {
412
+ test("off-platform hatch seeds both managed and user anthropic profiles", () => {
410
413
  const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
411
414
  writeFileSync(
412
415
  overlayPath,
@@ -430,19 +433,30 @@ describe("loadConfig startup behavior", () => {
430
433
 
431
434
  expect(config.llm.default.provider).toBe("anthropic");
432
435
  expect(config.llm.default.model).toBe("claude-opus-4-7");
433
- expect(config.llm.activeProfile).toBe("balanced");
436
+ // Off-platform: user profiles are active, backed by the user's API key.
437
+ expect(config.llm.activeProfile).toBe("custom-balanced");
438
+ expect(config.llm.profiles["custom-balanced"]?.provider).toBe("anthropic");
439
+ expect(config.llm.profiles["custom-balanced"]?.provider_connection).toBe(
440
+ "anthropic-personal",
441
+ );
442
+ // Managed profiles exist as well.
434
443
  expect(config.llm.profiles.balanced?.model).toBe("claude-sonnet-4-6");
444
+ expect(config.llm.profiles.balanced?.provider_connection).toBe(
445
+ "anthropic-managed",
446
+ );
435
447
 
436
448
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
437
449
  expect(raw.llm.default).toEqual({
438
450
  provider: "anthropic",
439
451
  model: "claude-opus-4-7",
440
452
  });
441
- expect(raw.llm.activeProfile).toBe("balanced");
453
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
442
454
  expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
443
455
  });
444
456
 
445
- test("non-Anthropic hatch overlay seeds custom-* profiles and activates custom-balanced", () => {
457
+ test("on-platform hatch seeds only managed profiles", () => {
458
+ process.env.IS_PLATFORM = "true";
459
+
446
460
  const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
447
461
  writeFileSync(
448
462
  overlayPath,
@@ -450,7 +464,8 @@ describe("loadConfig startup behavior", () => {
450
464
  {
451
465
  llm: {
452
466
  default: {
453
- provider: "openai",
467
+ provider: "anthropic",
468
+ model: "claude-opus-4-7",
454
469
  },
455
470
  },
456
471
  },
@@ -462,43 +477,26 @@ describe("loadConfig startup behavior", () => {
462
477
 
463
478
  mergeDefaultConfigAndSeedInferenceProfiles();
464
479
  const config = loadConfig();
465
- const mainAgentConfig = resolveCallSiteConfig("mainAgent", config.llm);
466
480
 
467
- expect(config.llm.activeProfile).toBe("custom-balanced");
468
- expect(config.llm.profiles["custom-balanced"]?.provider).toBe("openai");
469
- expect(config.llm.profiles["custom-balanced"]?.model).toBe("gpt-5.4-mini");
470
- expect(config.llm.profiles["custom-quality-optimized"]?.provider).toBe(
471
- "openai",
472
- );
473
- expect(config.llm.profiles["custom-cost-optimized"]?.provider).toBe(
474
- "openai",
475
- );
476
- expect(config.llm.profiles.balanced?.provider).toBe("anthropic");
477
- expect(config.llm.profiles["quality-optimized"]?.provider).toBe(
478
- "anthropic",
479
- );
480
- expect(config.llm.profiles["cost-optimized"]?.provider).toBe("anthropic");
481
- expect(config.llm.default.provider).toBe("openai");
482
- expect(config.llm.default.model).toBe("gpt-5.4-mini");
483
- expect(mainAgentConfig.provider).toBe("openai");
484
- expect(mainAgentConfig.model).toBe("gpt-5.4-mini");
485
-
486
- const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
487
- expect(raw.llm.activeProfile).toBe("custom-balanced");
488
- expect(raw.llm.default.model).toBe(
489
- raw.llm.profiles["custom-balanced"].model,
481
+ expect(config.llm.activeProfile).toBe("balanced");
482
+ expect(config.llm.profiles.balanced?.model).toBe("claude-sonnet-4-6");
483
+ expect(config.llm.profiles.balanced?.provider_connection).toBe(
484
+ "anthropic-managed",
490
485
  );
486
+ // No user profiles created on platform.
487
+ expect(config.llm.profiles["custom-balanced"]).toBeUndefined();
491
488
  });
492
489
 
493
- test("re-hatch from openai to anthropic resets stale custom-balanced active profile", () => {
494
- // Pre-seed an OpenAI-style workspace: custom-balanced is active, default is
495
- // openai. Simulates a workspace that previously hatched against OpenAI.
490
+ test("re-hatch from openai to anthropic creates user anthropic profiles off-platform", () => {
491
+ // Pre-seed an OpenAI-style workspace: user-defined custom-balanced profile
492
+ // is active, default is openai. Simulates a workspace that hatched against
493
+ // OpenAI under the pre-1.2 model.
496
494
  writeConfig({
497
495
  llm: {
498
496
  default: { provider: "openai", model: "gpt-5.4-mini" },
499
497
  profiles: {
500
498
  "custom-balanced": {
501
- source: "managed",
499
+ source: "user",
502
500
  provider: "openai",
503
501
  model: "gpt-5.4-mini",
504
502
  },
@@ -518,41 +516,56 @@ describe("loadConfig startup behavior", () => {
518
516
  mergeDefaultConfigAndSeedInferenceProfiles();
519
517
 
520
518
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
521
- expect(raw.llm.activeProfile).toBe("balanced");
522
- expect(raw.llm.default.provider).toBe("anthropic");
523
- expect(raw.llm.default.model).toBe("claude-sonnet-4-6");
519
+ // Off-platform re-hatch: user profiles are overwritten for the new
520
+ // provider and custom-balanced becomes active.
521
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
522
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("anthropic");
523
+ expect(raw.llm.profiles["custom-balanced"].provider_connection).toBe(
524
+ "anthropic-personal",
525
+ );
526
+ // Managed profiles are also seeded for anthropic-managed.
527
+ expect(raw.llm.profiles.balanced.provider).toBe("anthropic");
528
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
529
+ "anthropic-managed",
530
+ );
524
531
  });
525
532
 
526
- test("unknown overlay provider falls back to Anthropic seeding", () => {
527
- const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
528
- writeFileSync(
529
- overlayPath,
530
- JSON.stringify(
531
- {
532
- llm: {
533
- default: {
534
- provider: "unknownprov",
535
- },
533
+ test("on-platform re-hatch resets active profile to balanced", () => {
534
+ process.env.IS_PLATFORM = "true";
535
+
536
+ writeConfig({
537
+ llm: {
538
+ default: { provider: "openai", model: "gpt-5.4-mini" },
539
+ profiles: {
540
+ "custom-balanced": {
541
+ source: "user",
542
+ provider: "openai",
543
+ model: "gpt-5.4-mini",
536
544
  },
537
545
  },
538
- null,
539
- 2,
540
- ) + "\n",
546
+ activeProfile: "custom-balanced",
547
+ },
548
+ });
549
+
550
+ const overlayPath = join(WORKSPACE_DIR, "rehatch-anthropic.json");
551
+ writeFileSync(
552
+ overlayPath,
553
+ JSON.stringify({ llm: { default: { provider: "anthropic" } } }, null, 2) +
554
+ "\n",
541
555
  );
542
556
  process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
543
557
 
544
558
  mergeDefaultConfigAndSeedInferenceProfiles();
545
559
 
546
560
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
561
+ // On-platform: no user profiles created, active resets to managed balanced.
547
562
  expect(raw.llm.activeProfile).toBe("balanced");
548
563
  expect(raw.llm.profiles.balanced.provider).toBe("anthropic");
549
- expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
550
- expect(raw.llm.profiles["custom-balanced"]).toBeUndefined();
551
- expect(raw.llm.profiles["custom-quality-optimized"]).toBeUndefined();
552
- expect(raw.llm.profiles["custom-cost-optimized"]).toBeUndefined();
553
- // The unrecognized provider should be rewritten on disk so subsequent
554
- // loads don't trip Zod's enum validation warning.
555
- expect(raw.llm.default.provider).toBe("anthropic");
564
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
565
+ "anthropic-managed",
566
+ );
567
+ // The old custom-balanced is preserved on disk but no longer active.
568
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("openai");
556
569
  });
557
570
 
558
571
  test("preserves user-supplied non-catalog model on every restart (ollama custom model)", () => {
@@ -572,69 +585,175 @@ describe("loadConfig startup behavior", () => {
572
585
  expect(raw.llm.default.model).toBe("codellama");
573
586
  });
574
587
 
575
- test("syncs llm.default.model to active profile when missing or inconsistent, respects explicit user values", () => {
576
- // 1. Missing on disk → write to active profile's model.
577
- const overlayMissing = join(WORKSPACE_DIR, "overlay-missing.json");
588
+ test("off-platform hatch with openai seeds user profiles and managed anthropic profiles", () => {
589
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
578
590
  writeFileSync(
579
- overlayMissing,
580
- JSON.stringify({ llm: { default: { provider: "openai" } } }, null, 2) +
581
- "\n",
591
+ overlayPath,
592
+ JSON.stringify(
593
+ { llm: { default: { provider: "openai" } } },
594
+ null,
595
+ 2,
596
+ ) + "\n",
582
597
  );
583
- process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayMissing;
598
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
599
+
584
600
  mergeDefaultConfigAndSeedInferenceProfiles();
585
- let raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
586
- expect(raw.llm.default.model).toBe(
587
- raw.llm.profiles["custom-balanced"].model,
601
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
602
+
603
+ // User profiles for the hatch provider (openai).
604
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
605
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("openai");
606
+ expect(raw.llm.profiles["custom-balanced"].model).toBe("gpt-5.4-mini");
607
+ expect(raw.llm.profiles["custom-balanced"].provider_connection).toBe(
608
+ "openai-personal",
609
+ );
610
+ expect(raw.llm.profiles["custom-balanced"].source).toBe("user");
611
+ expect(raw.llm.profiles["custom-quality-optimized"].provider).toBe(
612
+ "openai",
613
+ );
614
+ expect(raw.llm.profiles["custom-quality-optimized"].model).toBe("gpt-5.4");
615
+ expect(raw.llm.profiles["custom-cost-optimized"].provider).toBe("openai");
616
+ expect(raw.llm.profiles["custom-cost-optimized"].model).toBe(
617
+ "gpt-5.4-nano",
618
+ );
619
+
620
+ // Managed anthropic profiles are also seeded.
621
+ expect(raw.llm.profiles.balanced.provider).toBe("anthropic");
622
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
623
+ "anthropic-managed",
588
624
  );
625
+ expect(raw.llm.profiles.balanced.source).toBe("managed");
626
+ expect(raw.llm.profiles["quality-optimized"].provider).toBe("anthropic");
627
+ expect(raw.llm.profiles["cost-optimized"].provider).toBe("anthropic");
628
+ });
589
629
 
590
- // 2. Inconsistent (previous default model belongs to a different provider)
591
- // is overwritten on the next seed run.
592
- rmSync(CONFIG_PATH);
630
+ test("off-platform managed profiles are overwritten on every boot", () => {
631
+ // Simulate a previous boot that left managed profiles on disk.
593
632
  writeConfig({
594
633
  llm: {
595
- default: { provider: "openai", model: "claude-opus-4-7" },
634
+ profiles: {
635
+ balanced: {
636
+ source: "managed",
637
+ provider: "anthropic",
638
+ model: "old-model-from-previous-release",
639
+ provider_connection: "anthropic-managed",
640
+ },
641
+ },
642
+ activeProfile: "balanced",
596
643
  },
597
644
  });
598
- process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayMissing;
645
+
646
+ // Non-hatch boot (no overlay). Managed profiles should be overwritten
647
+ // with the latest templates.
599
648
  mergeDefaultConfigAndSeedInferenceProfiles();
600
- raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
601
- expect(raw.llm.default.model).toBe(
602
- raw.llm.profiles["custom-balanced"].model,
649
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
650
+
651
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
652
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
653
+ "anthropic-managed",
603
654
  );
655
+ expect(raw.llm.activeProfile).toBe("balanced");
656
+ });
604
657
 
605
- // 3. Platform overlay supplies an explicit, internally-coherent
606
- // profile/active/default the user's explicit choice is preserved.
607
- rmSync(CONFIG_PATH);
608
- const explicit = join(WORKSPACE_DIR, "overlay-explicit.json");
609
- writeFileSync(
610
- explicit,
611
- JSON.stringify(
612
- {
613
- llm: {
614
- default: { provider: "openai", model: "gpt-5.4" },
615
- profiles: {
616
- balanced: {
617
- source: "managed",
618
- provider: "openai",
619
- model: "gpt-5.4",
620
- label: "Platform Balanced",
621
- },
622
- },
623
- activeProfile: "balanced",
658
+ test("off-platform reseed preserves user-edited label on managed profiles (Codex P1 on PR #30362)", () => {
659
+ // Simulate a user who renamed the managed "balanced" profile via
660
+ // PUT /v1/config/llm/profiles/balanced { label: "My Default" }.
661
+ writeConfig({
662
+ llm: {
663
+ profiles: {
664
+ balanced: {
665
+ source: "managed",
666
+ provider: "anthropic",
667
+ model: "old-model-from-previous-release",
668
+ provider_connection: "anthropic-managed",
669
+ label: "My Default",
624
670
  },
625
671
  },
626
- null,
627
- 2,
628
- ) + "\n",
629
- );
630
- process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = explicit;
672
+ activeProfile: "balanced",
673
+ },
674
+ });
675
+
631
676
  mergeDefaultConfigAndSeedInferenceProfiles();
632
- raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
633
- expect(raw.llm.activeProfile).toBe("balanced");
634
- expect(raw.llm.default.model).toBe("gpt-5.4");
677
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
678
+
679
+ // Model still gets the new template value (provider-controlled).
680
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
681
+ // But the user's label override is preserved across the reseed.
682
+ expect(raw.llm.profiles.balanced.label).toBe("My Default");
683
+ });
684
+
685
+ test("off-platform reseed preserves user-toggled status on managed profiles", () => {
686
+ // Simulate a user who disabled the managed "balanced" profile via
687
+ // PUT /v1/config/llm/profiles/balanced { status: "disabled" }.
688
+ writeConfig({
689
+ llm: {
690
+ profiles: {
691
+ balanced: {
692
+ source: "managed",
693
+ provider: "anthropic",
694
+ model: "old-model-from-previous-release",
695
+ provider_connection: "anthropic-managed",
696
+ status: "disabled",
697
+ },
698
+ },
699
+ activeProfile: "balanced",
700
+ },
701
+ });
702
+
703
+ mergeDefaultConfigAndSeedInferenceProfiles();
704
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
705
+
706
+ expect(raw.llm.profiles.balanced.status).toBe("disabled");
707
+ // Model still refreshes — only label/status are user-owned.
708
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
709
+ });
710
+
711
+ test("off-platform reseed preserves an explicit null label (user cleared it)", () => {
712
+ // Setting label to null is the "clear" intent — must survive too,
713
+ // otherwise the next boot would re-stamp the template's default
714
+ // label and ignore the user's clear action.
715
+ writeConfig({
716
+ llm: {
717
+ profiles: {
718
+ balanced: {
719
+ source: "managed",
720
+ provider: "anthropic",
721
+ model: "old-model",
722
+ provider_connection: "anthropic-managed",
723
+ label: null,
724
+ },
725
+ },
726
+ activeProfile: "balanced",
727
+ },
728
+ });
729
+
730
+ mergeDefaultConfigAndSeedInferenceProfiles();
731
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
732
+
733
+ expect(raw.llm.profiles.balanced.label).toBeNull();
734
+ });
735
+
736
+ test("off-platform reseed materializes template defaults with the BYOK label suffix when no user overrides exist", () => {
737
+ // First boot, no prior config — template defaults must materialize
738
+ // exactly. Off-platform installs get the " (Managed)" suffix so the
739
+ // managed profile is distinguishable from the personal "custom-*"
740
+ // sibling that shares the base label. Guards against accidentally
741
+ // clobbering template values with `undefined` from a `"label" in
742
+ // previous` check when previous is an empty shell.
743
+ writeConfig({});
744
+
745
+ mergeDefaultConfigAndSeedInferenceProfiles();
746
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
747
+
748
+ expect(raw.llm.profiles.balanced.label).toBe("Balanced (Managed)");
749
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
750
+ // Status is unset by default — must not appear as `undefined`.
751
+ expect("status" in raw.llm.profiles.balanced).toBe(false);
635
752
  });
636
753
 
637
754
  test("platform-provided profile fragments are not polluted by managed seeds", () => {
755
+ process.env.IS_PLATFORM = "true";
756
+
638
757
  writeConfig({
639
758
  llm: {
640
759
  default: {
@@ -751,7 +870,9 @@ describe("loadConfig startup behavior", () => {
751
870
  provider: "anthropic",
752
871
  model: "claude-opus-4-7",
753
872
  });
754
- expect(raw.llm.activeProfile).toBe("balanced");
873
+ // Off-platform hatch: user profiles are active.
874
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
875
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("anthropic");
755
876
  expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
756
877
  });
757
878
 
@@ -775,3 +896,306 @@ describe("loadConfig startup behavior", () => {
775
896
  expect(quarantined.length).toBeGreaterThan(0);
776
897
  });
777
898
  });
899
+
900
+ // ---------------------------------------------------------------------------
901
+ // Tests: BYOK-mode seed behavior (issues #2/#3/#4 of the May 12 provider UX
902
+ // queue). Off-platform managed profiles share base labels with the personal
903
+ // "custom-*" profiles (Balanced / Quality / Speed), so the seed function
904
+ // suffixes managed labels with " (Managed)" to disambiguate. Status is
905
+ // initialized to "disabled" ONLY at hatch on first materialization — a fresh
906
+ // BYOK user has no platform auth, so we don't want managed entries surfacing
907
+ // as enabled in the picker on day one. Post-hatch user toggles persist
908
+ // through every subsequent boot — the "never auto-disable BYOK connections"
909
+ // rule applies to RESTART, not to hatch. On-platform behavior is unchanged.
910
+ // ---------------------------------------------------------------------------
911
+
912
+ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
913
+ beforeEach(() => {
914
+ ensureTestDir();
915
+ const resetPaths = [
916
+ CONFIG_PATH,
917
+ join(WORKSPACE_DIR, "default-config.json"),
918
+ join(WORKSPACE_DIR, "hatch-overlay.json"),
919
+ join(WORKSPACE_DIR, "keys.enc"),
920
+ join(WORKSPACE_DIR, "data"),
921
+ join(WORKSPACE_DIR, "data", "memory"),
922
+ ];
923
+ for (const path of resetPaths) {
924
+ if (existsSync(path)) {
925
+ rmSync(path, { recursive: true, force: true });
926
+ }
927
+ }
928
+ ensureTestDir();
929
+ _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
930
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
931
+ delete process.env.IS_PLATFORM;
932
+ invalidateConfigCache();
933
+ });
934
+
935
+ afterEach(() => {
936
+ _setStorePath(null);
937
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
938
+ delete process.env.IS_PLATFORM;
939
+ invalidateConfigCache();
940
+ });
941
+
942
+ test("off-platform hatch suffixes managed profile labels with ' (Managed)'", () => {
943
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
944
+ writeFileSync(
945
+ overlayPath,
946
+ JSON.stringify(
947
+ {
948
+ llm: {
949
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
950
+ },
951
+ },
952
+ null,
953
+ 2,
954
+ ) + "\n",
955
+ );
956
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
957
+
958
+ mergeDefaultConfigAndSeedInferenceProfiles();
959
+ const config = loadConfig();
960
+
961
+ // Managed profile labels carry the suffix so they're visibly distinct
962
+ // from the personal "custom-*" profiles (which retain bare labels).
963
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced (Managed)");
964
+ expect(config.llm.profiles["quality-optimized"]?.label).toBe(
965
+ "Quality (Managed)",
966
+ );
967
+ expect(config.llm.profiles["cost-optimized"]?.label).toBe(
968
+ "Speed (Managed)",
969
+ );
970
+
971
+ // Personal profiles keep their bare labels — they're the daily driver.
972
+ expect(config.llm.profiles["custom-balanced"]?.label).toBe("Balanced");
973
+ });
974
+
975
+ test("off-platform hatch initializes managed profile status to 'disabled'", () => {
976
+ // On a fresh BYOK hatch the user has no platform auth, so managed
977
+ // profiles must not surface as enabled in the picker on day one. We
978
+ // flip the three canonical managed profiles to status="disabled"
979
+ // ONCE at hatch time. (The complementary "user re-enable persists
980
+ // across restarts" guarantee is covered by the test further down.)
981
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
982
+ writeFileSync(
983
+ overlayPath,
984
+ JSON.stringify(
985
+ { llm: { default: { provider: "anthropic" } } },
986
+ null,
987
+ 2,
988
+ ) + "\n",
989
+ );
990
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
991
+
992
+ mergeDefaultConfigAndSeedInferenceProfiles();
993
+ const config = loadConfig();
994
+
995
+ expect(config.llm.profiles.balanced?.status).toBe("disabled");
996
+ expect(config.llm.profiles["quality-optimized"]?.status).toBe("disabled");
997
+ expect(config.llm.profiles["cost-optimized"]?.status).toBe("disabled");
998
+ });
999
+
1000
+ test("non-hatch off-platform boot does NOT auto-disable freshly-materialized managed profiles", () => {
1001
+ // Existing installs that upgrade to a version where the managed
1002
+ // profile didn't previously exist (e.g. a new template added later)
1003
+ // must not be auto-disabled on a normal boot. The hatch-time disable
1004
+ // is gated on `isHatch && !previous`; without an overlay there's no
1005
+ // hatch signal, so the seeder leaves status unset (schema default
1006
+ // = "active"). This is the "we never want to auto-disable BYOK
1007
+ // connections on restart" guarantee.
1008
+ writeConfig({
1009
+ llm: {
1010
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1011
+ // Note: no `profiles` key — the managed profiles will be freshly
1012
+ // materialized by seedInferenceProfiles. !previous is true for all
1013
+ // three, but isHatch is false, so disable does NOT fire.
1014
+ },
1015
+ });
1016
+
1017
+ // No overlay → not a hatch.
1018
+ mergeDefaultConfigAndSeedInferenceProfiles();
1019
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1020
+
1021
+ expect("status" in raw.llm.profiles.balanced).toBe(false);
1022
+ expect("status" in raw.llm.profiles["quality-optimized"]).toBe(false);
1023
+ expect("status" in raw.llm.profiles["cost-optimized"]).toBe(false);
1024
+ });
1025
+
1026
+ test("on-platform hatch leaves managed labels untouched", () => {
1027
+ process.env.IS_PLATFORM = "true";
1028
+
1029
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
1030
+ writeFileSync(
1031
+ overlayPath,
1032
+ JSON.stringify(
1033
+ { llm: { default: { provider: "anthropic" } } },
1034
+ null,
1035
+ 2,
1036
+ ) + "\n",
1037
+ );
1038
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
1039
+
1040
+ mergeDefaultConfigAndSeedInferenceProfiles();
1041
+ const config = loadConfig();
1042
+
1043
+ // No "(Managed)" suffix on platform — the personal profiles don't exist
1044
+ // here so there's nothing to disambiguate from.
1045
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced");
1046
+ expect(config.llm.profiles["quality-optimized"]?.label).toBe("Quality");
1047
+ expect(config.llm.profiles["cost-optimized"]?.label).toBe("Speed");
1048
+ });
1049
+
1050
+ test("upgrade boot rewrites legacy bare labels to suffixed form on off-platform", () => {
1051
+ // Existing off-platform install (pre-suffix-PR) has `label: "Balanced"`
1052
+ // on disk. The "label" in previous preservation would normally keep
1053
+ // the bare label and the picker would stay ambiguous forever — so the
1054
+ // seeder runs a one-shot upgrade migration when previous.label exactly
1055
+ // equals the bare template default. User-customized labels and
1056
+ // explicit nulls are NOT rewritten.
1057
+ writeConfig({
1058
+ llm: {
1059
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1060
+ profiles: {
1061
+ balanced: {
1062
+ source: "managed",
1063
+ provider: "anthropic",
1064
+ provider_connection: "anthropic-managed",
1065
+ model: "claude-sonnet-4-6",
1066
+ label: "Balanced",
1067
+ },
1068
+ "quality-optimized": {
1069
+ source: "managed",
1070
+ provider: "anthropic",
1071
+ provider_connection: "anthropic-managed",
1072
+ label: "Quality",
1073
+ },
1074
+ "cost-optimized": {
1075
+ source: "managed",
1076
+ provider: "anthropic",
1077
+ provider_connection: "anthropic-managed",
1078
+ label: "Speed",
1079
+ },
1080
+ },
1081
+ activeProfile: "balanced",
1082
+ },
1083
+ });
1084
+
1085
+ // No overlay → not a hatch. Still upgrades labels.
1086
+ mergeDefaultConfigAndSeedInferenceProfiles();
1087
+ const config = loadConfig();
1088
+
1089
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced (Managed)");
1090
+ expect(config.llm.profiles["quality-optimized"]?.label).toBe(
1091
+ "Quality (Managed)",
1092
+ );
1093
+ expect(config.llm.profiles["cost-optimized"]?.label).toBe(
1094
+ "Speed (Managed)",
1095
+ );
1096
+ });
1097
+
1098
+ test("upgrade boot preserves user-customized labels and explicit null on off-platform", () => {
1099
+ // A user-set string that differs from the bare default must survive;
1100
+ // an explicit null (user cleared the label) must also survive. Only
1101
+ // exact matches against the bare template label trigger the upgrade.
1102
+ writeConfig({
1103
+ llm: {
1104
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1105
+ profiles: {
1106
+ balanced: {
1107
+ source: "managed",
1108
+ provider: "anthropic",
1109
+ provider_connection: "anthropic-managed",
1110
+ model: "claude-sonnet-4-6",
1111
+ label: "My Balanced",
1112
+ },
1113
+ "quality-optimized": {
1114
+ source: "managed",
1115
+ provider: "anthropic",
1116
+ provider_connection: "anthropic-managed",
1117
+ label: null,
1118
+ },
1119
+ // Already-suffixed labels are also preserved (idempotency).
1120
+ "cost-optimized": {
1121
+ source: "managed",
1122
+ provider: "anthropic",
1123
+ provider_connection: "anthropic-managed",
1124
+ label: "Speed (Managed)",
1125
+ },
1126
+ },
1127
+ activeProfile: "balanced",
1128
+ },
1129
+ });
1130
+
1131
+ mergeDefaultConfigAndSeedInferenceProfiles();
1132
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1133
+
1134
+ expect(raw.llm.profiles.balanced.label).toBe("My Balanced");
1135
+ expect(raw.llm.profiles["quality-optimized"].label).toBeNull();
1136
+ expect(raw.llm.profiles["cost-optimized"].label).toBe("Speed (Managed)");
1137
+ });
1138
+
1139
+ test("upgrade boot does NOT rewrite bare labels on platform", () => {
1140
+ // The migration is gated on isByokMode, so an on-platform install with
1141
+ // a bare "Balanced" label preserves it (no suffix on platform).
1142
+ process.env.IS_PLATFORM = "true";
1143
+ writeConfig({
1144
+ llm: {
1145
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1146
+ profiles: {
1147
+ balanced: {
1148
+ source: "managed",
1149
+ provider: "anthropic",
1150
+ provider_connection: "anthropic-managed",
1151
+ model: "claude-sonnet-4-6",
1152
+ label: "Balanced",
1153
+ },
1154
+ },
1155
+ activeProfile: "balanced",
1156
+ },
1157
+ });
1158
+
1159
+ mergeDefaultConfigAndSeedInferenceProfiles();
1160
+ const config = loadConfig();
1161
+
1162
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced");
1163
+ });
1164
+
1165
+ test("subsequent off-platform boot preserves user-set status on managed profiles", () => {
1166
+ // Simulate a user who hatched yesterday, then re-enabled the managed
1167
+ // Balanced profile (they have platform auth via a separate route).
1168
+ writeConfig({
1169
+ llm: {
1170
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1171
+ profiles: {
1172
+ balanced: {
1173
+ source: "managed",
1174
+ provider: "anthropic",
1175
+ provider_connection: "anthropic-managed",
1176
+ model: "claude-sonnet-4-6",
1177
+ label: "Balanced (Managed)",
1178
+ status: "active",
1179
+ },
1180
+ "custom-balanced": {
1181
+ source: "user",
1182
+ provider: "anthropic",
1183
+ provider_connection: "anthropic-personal",
1184
+ model: "claude-sonnet-4-6",
1185
+ label: "Balanced",
1186
+ },
1187
+ },
1188
+ activeProfile: "balanced",
1189
+ },
1190
+ });
1191
+
1192
+ // No overlay → this is a normal boot, not a hatch.
1193
+ mergeDefaultConfigAndSeedInferenceProfiles();
1194
+ const config = loadConfig();
1195
+
1196
+ // User's "active" decision survives the boot upsert.
1197
+ expect(config.llm.profiles.balanced?.status).toBe("active");
1198
+ // Label is still suffixed (Vellum can push label updates).
1199
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced (Managed)");
1200
+ });
1201
+ });