@vellumai/assistant 0.8.0 → 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 (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /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
+ });