@vellumai/assistant 0.7.1 → 0.7.3

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 (739) hide show
  1. package/ARCHITECTURE.md +48 -50
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/memory.md +5 -2
  7. package/docs/architecture/security.md +20 -0
  8. package/docs/plugins.md +7 -9
  9. package/knip.json +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  11. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
  12. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  13. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  15. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  16. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  17. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  18. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  19. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  20. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  21. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  22. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  23. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  24. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  25. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  26. package/openapi.yaml +1020 -40
  27. package/package.json +6 -3
  28. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  29. package/src/__tests__/app-bundler.test.ts +170 -1
  30. package/src/__tests__/app-control-flow.test.ts +384 -0
  31. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  32. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  33. package/src/__tests__/app-executors.test.ts +30 -43
  34. package/src/__tests__/approval-routes-http.test.ts +23 -6
  35. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  37. package/src/__tests__/assistant-event-hub.test.ts +157 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
  39. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  40. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  41. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  42. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  43. package/src/__tests__/btw-routes.test.ts +13 -4
  44. package/src/__tests__/call-controller.test.ts +49 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  46. package/src/__tests__/call-domain.test.ts +0 -2
  47. package/src/__tests__/call-routes-http.test.ts +0 -2
  48. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  49. package/src/__tests__/channel-readiness-service.test.ts +62 -2
  50. package/src/__tests__/checker.test.ts +3 -4
  51. package/src/__tests__/config-loader-backfill.test.ts +461 -147
  52. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  53. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  54. package/src/__tests__/config-schema.test.ts +1 -0
  55. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  56. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
  57. package/src/__tests__/config-watcher.test.ts +142 -71
  58. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  59. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  60. package/src/__tests__/context-search-fanout.test.ts +0 -1
  61. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  62. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  63. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  64. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  65. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  66. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  67. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  68. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  69. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  70. package/src/__tests__/conversation-error.test.ts +150 -3
  71. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  72. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  74. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  80. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  81. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  82. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  83. package/src/__tests__/conversation-store.test.ts +0 -18
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  85. package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
  86. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  87. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  88. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  89. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  90. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  91. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  92. package/src/__tests__/credentials-cli.test.ts +12 -12
  93. package/src/__tests__/cu-unified-flow.test.ts +351 -23
  94. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  95. package/src/__tests__/date-context.test.ts +164 -2
  96. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  97. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  98. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  99. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  100. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  101. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  102. package/src/__tests__/disk-usage.test.ts +150 -0
  103. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  104. package/src/__tests__/events-client-registration.test.ts +52 -0
  105. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  106. package/src/__tests__/file-write-tool.test.ts +4 -10
  107. package/src/__tests__/filing-service.test.ts +3 -4
  108. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  109. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  110. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  111. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  112. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  113. package/src/__tests__/heartbeat-service.test.ts +968 -2
  114. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  115. package/src/__tests__/host-app-control-proxy.test.ts +772 -0
  116. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  117. package/src/__tests__/host-bash-proxy.test.ts +439 -47
  118. package/src/__tests__/host-bash-routes.test.ts +459 -0
  119. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  120. package/src/__tests__/host-browser-routes.test.ts +39 -13
  121. package/src/__tests__/host-cu-proxy.test.ts +248 -52
  122. package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
  123. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  124. package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
  125. package/src/__tests__/host-file-proxy.test.ts +301 -45
  126. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  127. package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
  128. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  129. package/src/__tests__/host-proxy-base.test.ts +312 -0
  130. package/src/__tests__/host-shell-tool.test.ts +22 -4
  131. package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
  132. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  133. package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
  134. package/src/__tests__/http-user-message-parity.test.ts +108 -1
  135. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  136. package/src/__tests__/identity-routes.test.ts +103 -1
  137. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  138. package/src/__tests__/injector-chain.test.ts +18 -6
  139. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  140. package/src/__tests__/inline-command-runner.test.ts +0 -1
  141. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  142. package/src/__tests__/integration-status.test.ts +85 -5
  143. package/src/__tests__/intent-routing.test.ts +0 -1
  144. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  145. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  146. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  147. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  148. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  149. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  150. package/src/__tests__/mcp-cli.test.ts +338 -2
  151. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  153. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  155. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  156. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  157. package/src/__tests__/oauth-cli.test.ts +0 -2
  158. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  159. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  160. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  161. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  162. package/src/__tests__/openai-provider.test.ts +45 -8
  163. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  164. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  165. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  166. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  167. package/src/__tests__/platform.test.ts +2 -1
  168. package/src/__tests__/playbook-execution.test.ts +0 -43
  169. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  170. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
  171. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  172. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  173. package/src/__tests__/provider-tool-name.test.ts +23 -0
  174. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  175. package/src/__tests__/relay-server.test.ts +15 -4
  176. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  177. package/src/__tests__/retry-backoff.test.ts +87 -0
  178. package/src/__tests__/runtime-events-sse.test.ts +2 -2
  179. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  180. package/src/__tests__/schedule-retry.test.ts +715 -0
  181. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  182. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  183. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  184. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  185. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  186. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  187. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  188. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  189. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  190. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  191. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  192. package/src/__tests__/slack-channel-config.test.ts +9 -14
  193. package/src/__tests__/suggestion-routes.test.ts +46 -0
  194. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  195. package/src/__tests__/system-prompt.test.ts +0 -1
  196. package/src/__tests__/telegram-config.test.ts +0 -1
  197. package/src/__tests__/test-preload.ts +8 -0
  198. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  199. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  200. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  201. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  202. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  203. package/src/__tests__/tool-executor.test.ts +0 -1
  204. package/src/__tests__/twilio-config.test.ts +3 -16
  205. package/src/__tests__/twilio-routes.test.ts +3 -5
  206. package/src/__tests__/twilio-validation.test.ts +93 -0
  207. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  208. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  209. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  210. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  211. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  212. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  213. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  214. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  215. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  216. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  217. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  218. package/src/approvals/guardian-decision-primitive.ts +13 -0
  219. package/src/approvals/guardian-request-resolvers.ts +16 -17
  220. package/src/backup/__tests__/paths.test.ts +0 -22
  221. package/src/backup/__tests__/restore.test.ts +51 -151
  222. package/src/backup/paths.ts +2 -18
  223. package/src/backup/restore.ts +107 -231
  224. package/src/backup/snapshot-lock.ts +2 -27
  225. package/src/bundler/app-bundler.ts +51 -3
  226. package/src/bundler/compiler-tools.ts +3 -2
  227. package/src/calls/call-conversation-messages.ts +46 -10
  228. package/src/calls/relay-server.ts +4 -44
  229. package/src/calls/twilio-config.ts +2 -17
  230. package/src/calls/twilio-rest.ts +33 -105
  231. package/src/calls/twilio-routes.ts +11 -12
  232. package/src/channels/types.ts +8 -7
  233. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  234. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  235. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  236. package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
  237. package/src/cli/commands/backup.ts +6 -331
  238. package/src/cli/commands/bash.ts +35 -108
  239. package/src/cli/commands/clients.ts +36 -37
  240. package/src/cli/commands/contacts.ts +137 -25
  241. package/src/cli/commands/conversations.ts +2 -5
  242. package/src/cli/commands/credentials.ts +71 -7
  243. package/src/cli/commands/domain.ts +66 -15
  244. package/src/cli/commands/gateway.ts +183 -0
  245. package/src/cli/commands/keys.ts +9 -6
  246. package/src/cli/commands/mcp.ts +116 -156
  247. package/src/cli/commands/memory-v2.ts +303 -7
  248. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  249. package/src/cli/commands/oauth/connect.ts +127 -1
  250. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
  251. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
  252. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
  253. package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
  254. package/src/cli/commands/platform/disconnect.ts +5 -4
  255. package/src/cli/commands/platform/index.ts +16 -25
  256. package/src/cli/commands/status.ts +57 -0
  257. package/src/cli/lib/daemon-credential-client.ts +110 -28
  258. package/src/cli/program.ts +6 -2
  259. package/src/config/assistant-feature-flags.ts +79 -12
  260. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  261. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  262. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  263. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  264. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  265. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  266. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  267. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  268. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  269. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  270. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  271. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  272. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  273. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  274. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  275. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  276. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  277. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  278. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  279. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  280. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  281. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  282. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  283. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  284. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  285. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  286. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  287. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
  288. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  289. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  290. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  291. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  292. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  293. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  294. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  295. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  296. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  297. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  298. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  299. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  300. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  301. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  302. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  303. package/src/config/bundled-tool-registry.ts +21 -0
  304. package/src/config/env-registry.ts +0 -2
  305. package/src/config/env.ts +19 -20
  306. package/src/config/feature-flag-registry.json +47 -135
  307. package/src/config/loader.ts +197 -104
  308. package/src/config/sanitize-for-transfer.ts +2 -0
  309. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  310. package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
  311. package/src/config/schemas/call-site-catalog.ts +14 -0
  312. package/src/config/schemas/calls.ts +0 -9
  313. package/src/config/schemas/channels.ts +0 -5
  314. package/src/config/schemas/heartbeat.ts +64 -1
  315. package/src/config/schemas/ingress.ts +10 -6
  316. package/src/config/schemas/llm.ts +7 -10
  317. package/src/config/schemas/memory-lifecycle.ts +90 -24
  318. package/src/config/schemas/memory-v2.ts +121 -13
  319. package/src/config/schemas/platform.ts +49 -3
  320. package/src/config/schemas/services.ts +29 -15
  321. package/src/config/schemas/skills.ts +0 -6
  322. package/src/config/seed-inference-profiles.ts +230 -33
  323. package/src/contacts/contact-store.ts +0 -55
  324. package/src/contacts/contacts-write.ts +0 -27
  325. package/src/context/window-manager.ts +1 -2
  326. package/src/credential-execution/feature-gates.ts +10 -10
  327. package/src/credential-execution/process-manager.ts +12 -41
  328. package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
  329. package/src/daemon/assistant-attachments.ts +4 -4
  330. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  331. package/src/daemon/config-watcher.ts +89 -60
  332. package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
  333. package/src/daemon/conversation-agent-loop.ts +202 -61
  334. package/src/daemon/conversation-error.ts +87 -15
  335. package/src/daemon/conversation-lifecycle.ts +9 -4
  336. package/src/daemon/conversation-process.ts +24 -11
  337. package/src/daemon/conversation-runtime-assembly.ts +28 -2
  338. package/src/daemon/conversation-store.ts +2 -2
  339. package/src/daemon/conversation-surfaces.ts +305 -4
  340. package/src/daemon/conversation-tool-setup.ts +66 -62
  341. package/src/daemon/conversation.ts +38 -24
  342. package/src/daemon/date-context.ts +71 -22
  343. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  344. package/src/daemon/disk-pressure-guard.ts +343 -0
  345. package/src/daemon/disk-pressure-policy.ts +163 -0
  346. package/src/daemon/doordash-steps.ts +1 -1
  347. package/src/daemon/handlers/shared.ts +4 -2
  348. package/src/daemon/handlers/skills.ts +3 -4
  349. package/src/daemon/host-app-control-proxy.ts +389 -0
  350. package/src/daemon/host-bash-proxy.ts +117 -82
  351. package/src/daemon/host-browser-proxy.ts +67 -82
  352. package/src/daemon/host-cu-proxy.ts +127 -86
  353. package/src/daemon/host-file-proxy.ts +129 -69
  354. package/src/daemon/host-proxy-base.ts +294 -0
  355. package/src/daemon/host-proxy-preactivation.ts +82 -0
  356. package/src/daemon/host-transfer-proxy.ts +338 -129
  357. package/src/daemon/lifecycle.ts +194 -145
  358. package/src/daemon/meet-host-supervisor.ts +4 -4
  359. package/src/daemon/meet-manifest-loader.ts +0 -1
  360. package/src/daemon/memory-v2-startup.ts +14 -4
  361. package/src/daemon/message-protocol.ts +6 -8
  362. package/src/daemon/message-types/contacts.ts +23 -1
  363. package/src/daemon/message-types/conversations.ts +15 -8
  364. package/src/daemon/message-types/disk-pressure.ts +9 -0
  365. package/src/daemon/message-types/host-app-control.ts +150 -0
  366. package/src/daemon/message-types/host-bash.ts +4 -0
  367. package/src/daemon/message-types/host-cu.ts +2 -0
  368. package/src/daemon/message-types/host-file.ts +4 -0
  369. package/src/daemon/message-types/host-transfer.ts +3 -0
  370. package/src/daemon/message-types/messages.ts +3 -0
  371. package/src/daemon/message-types/schedules.ts +8 -3
  372. package/src/daemon/message-types/skills.ts +2 -2
  373. package/src/daemon/process-message.ts +18 -1
  374. package/src/daemon/profiler-run-store.ts +5 -5
  375. package/src/daemon/shutdown-handlers.ts +0 -3
  376. package/src/daemon/tool-setup-types.ts +51 -0
  377. package/src/daemon/tool-side-effects.ts +1 -1
  378. package/src/documents/document-store.ts +85 -0
  379. package/src/events/tool-audit-listener.ts +2 -1
  380. package/src/filing/filing-service.ts +30 -5
  381. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
  382. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
  383. package/src/heartbeat/heartbeat-run-store.ts +249 -0
  384. package/src/heartbeat/heartbeat-service.ts +459 -54
  385. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  386. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  387. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  388. package/src/home/feed-scheduler.ts +18 -0
  389. package/src/home/post-connect-feed.ts +68 -0
  390. package/src/home/relationship-state-writer.ts +17 -92
  391. package/src/home/suggested-prompts.ts +46 -10
  392. package/src/inbound/platform-callback-registration.ts +8 -15
  393. package/src/inbound/public-ingress-urls.ts +32 -34
  394. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  395. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  396. package/src/ipc/assistant-server.ts +70 -3
  397. package/src/ipc/cli-client.ts +32 -1
  398. package/src/ipc/gateway-client.ts +37 -3
  399. package/src/live-voice/live-voice-archive.ts +4 -4
  400. package/src/live-voice/live-voice-metrics.ts +10 -10
  401. package/src/live-voice/protocol.ts +5 -7
  402. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  403. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  404. package/src/mcp/mcp-auth-state.ts +133 -0
  405. package/src/mcp/mcp-oauth-provider.ts +19 -0
  406. package/src/media/image-service.ts +1 -7
  407. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  408. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  409. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  412. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  413. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  414. package/src/memory/admin.ts +5 -9
  415. package/src/memory/anisotropy.test.ts +247 -0
  416. package/src/memory/anisotropy.ts +443 -0
  417. package/src/memory/auto-analysis-constants.ts +17 -0
  418. package/src/memory/auto-analysis-guard.ts +5 -15
  419. package/src/memory/canonical-guardian-store.ts +7 -7
  420. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  421. package/src/memory/context-search/agent-protocol.ts +6 -6
  422. package/src/memory/context-search/agent-runner.ts +51 -9
  423. package/src/memory/context-search/sources/conversations.ts +2 -11
  424. package/src/memory/context-search/sources/memory-v2.ts +22 -9
  425. package/src/memory/context-search/sources/memory.ts +0 -1
  426. package/src/memory/context-search/types.ts +0 -1
  427. package/src/memory/conversation-crud.ts +5 -13
  428. package/src/memory/conversation-key-store.ts +2 -15
  429. package/src/memory/db-init.ts +6 -0
  430. package/src/memory/embedding-backend.ts +9 -21
  431. package/src/memory/embedding-runtime-manager.ts +119 -5
  432. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
  433. package/src/memory/graph/conversation-graph-memory.ts +43 -78
  434. package/src/memory/graph/extraction.ts +1 -3
  435. package/src/memory/graph/graph-search.test.ts +10 -67
  436. package/src/memory/graph/graph-search.ts +9 -20
  437. package/src/memory/graph/retriever.test.ts +6 -0
  438. package/src/memory/graph/retriever.ts +34 -10
  439. package/src/memory/graph/tools.ts +1 -1
  440. package/src/memory/indexer.ts +54 -45
  441. package/src/memory/job-handlers/backfill.ts +2 -11
  442. package/src/memory/job-handlers/cleanup.ts +43 -0
  443. package/src/memory/job-handlers/embedding.ts +6 -8
  444. package/src/memory/job-handlers/summarization.ts +2 -7
  445. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  446. package/src/memory/jobs/embed-concept-page.ts +28 -2
  447. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  448. package/src/memory/jobs-store.ts +114 -22
  449. package/src/memory/jobs-worker.ts +193 -106
  450. package/src/memory/memory-v2-activation-log-store.ts +33 -15
  451. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  452. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  453. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  454. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  455. package/src/memory/migrations/index.ts +6 -0
  456. package/src/memory/migrations/registry.ts +8 -0
  457. package/src/memory/pkb/pkb-search.test.ts +6 -0
  458. package/src/memory/pkb/pkb-search.ts +7 -0
  459. package/src/memory/qdrant-client.ts +49 -32
  460. package/src/memory/rerank-local.ts +374 -0
  461. package/src/memory/schema/infrastructure.ts +15 -0
  462. package/src/memory/search/semantic.ts +13 -67
  463. package/src/memory/sparse-tokenize.ts +49 -0
  464. package/src/memory/trace-event-store.ts +1 -17
  465. package/src/memory/v2/__tests__/activation.test.ts +387 -344
  466. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  467. package/src/memory/v2/__tests__/injection.test.ts +181 -169
  468. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  469. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  470. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  471. package/src/memory/v2/__tests__/sim.test.ts +154 -188
  472. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  473. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  474. package/src/memory/v2/__tests__/static-context.test.ts +76 -2
  475. package/src/memory/v2/activation.ts +213 -239
  476. package/src/memory/v2/consolidation-job.ts +65 -17
  477. package/src/memory/v2/constants.ts +7 -0
  478. package/src/memory/v2/injection.ts +123 -103
  479. package/src/memory/v2/prompts/consolidation.ts +348 -92
  480. package/src/memory/v2/qdrant.ts +198 -1
  481. package/src/memory/v2/reranker.ts +177 -0
  482. package/src/memory/v2/sim.ts +113 -77
  483. package/src/memory/v2/skill-content.ts +4 -3
  484. package/src/memory/v2/skill-store.ts +91 -53
  485. package/src/memory/v2/sparse-bm25.ts +245 -0
  486. package/src/memory/v2/static-context.ts +28 -5
  487. package/src/memory/v2/types.ts +10 -10
  488. package/src/messaging/providers/gmail/types.ts +0 -49
  489. package/src/messaging/providers/slack/adapter.ts +1 -31
  490. package/src/messaging/providers/slack/types.ts +0 -32
  491. package/src/notifications/README.md +10 -10
  492. package/src/notifications/broadcaster.ts +1 -1
  493. package/src/notifications/copy-composer.ts +13 -0
  494. package/src/notifications/guardian-question-mode.ts +5 -5
  495. package/src/notifications/signal.ts +4 -0
  496. package/src/oauth/AGENTS.md +3 -1
  497. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  498. package/src/oauth/connect-orchestrator.ts +6 -0
  499. package/src/oauth/connection-resolver.test.ts +66 -1
  500. package/src/oauth/connection-resolver.ts +55 -1
  501. package/src/oauth/credential-token-resolver.ts +1 -3
  502. package/src/oauth/manual-token-connection.ts +0 -4
  503. package/src/oauth/oauth-connect-state.ts +77 -0
  504. package/src/oauth/seed-providers.ts +58 -1
  505. package/src/outbound-proxy/index.ts +1 -37
  506. package/src/outbound-proxy/logging.ts +1 -1
  507. package/src/outbound-proxy/policy.ts +6 -5
  508. package/src/outbound-proxy/router.ts +2 -1
  509. package/src/permissions/approval-policy.test.ts +6 -275
  510. package/src/permissions/approval-policy.ts +0 -51
  511. package/src/permissions/checker.test.ts +0 -1
  512. package/src/permissions/checker.ts +3 -17
  513. package/src/permissions/gateway-threshold-reader.ts +2 -0
  514. package/src/permissions/prompter.ts +34 -1
  515. package/src/permissions/secret-prompter.ts +6 -2
  516. package/src/plugins/defaults/injectors.ts +35 -2
  517. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  518. package/src/plugins/types.ts +7 -0
  519. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  520. package/src/proactive-artifact/decision.test.ts +226 -0
  521. package/src/proactive-artifact/decision.ts +165 -0
  522. package/src/proactive-artifact/index.ts +7 -0
  523. package/src/proactive-artifact/job.test.ts +867 -0
  524. package/src/proactive-artifact/job.ts +352 -0
  525. package/src/proactive-artifact/message-copy.ts +41 -0
  526. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  527. package/src/proactive-artifact/trigger-state.ts +119 -0
  528. package/src/prompts/bootstrap-cleanup.ts +27 -0
  529. package/src/prompts/normalize-onboarding.ts +80 -0
  530. package/src/prompts/persona-resolver.ts +101 -9
  531. package/src/prompts/system-prompt.ts +23 -24
  532. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  533. package/src/prompts/templates/SOUL.md +13 -1
  534. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  535. package/src/providers/model-intents.ts +7 -0
  536. package/src/providers/openrouter/client.ts +8 -0
  537. package/src/providers/retry.ts +50 -0
  538. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  539. package/src/providers/types.ts +1 -0
  540. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  541. package/src/runtime/agent-wake.ts +238 -100
  542. package/src/runtime/assistant-event-hub.ts +151 -99
  543. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  544. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  545. package/src/runtime/auth/middleware.ts +0 -96
  546. package/src/runtime/auth/route-policy.ts +32 -0
  547. package/src/runtime/auth/same-actor.ts +216 -0
  548. package/src/runtime/btw-sidechain.ts +2 -3
  549. package/src/runtime/channel-invite-transport.ts +2 -48
  550. package/src/runtime/channel-invite-transports/email.ts +1 -1
  551. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  552. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  553. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  554. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  555. package/src/runtime/channel-invite-types.ts +54 -0
  556. package/src/runtime/channel-readiness-service.ts +32 -13
  557. package/src/runtime/channel-retry-sweep.ts +65 -1
  558. package/src/runtime/guardian-reply-router.ts +10 -0
  559. package/src/runtime/http-server.ts +3 -329
  560. package/src/runtime/http-types.ts +0 -5
  561. package/src/runtime/local-actor-identity.ts +52 -11
  562. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  563. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  564. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  565. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  566. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  567. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  568. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  569. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  570. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  571. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  572. package/src/runtime/migrations/migration-transport.ts +7 -7
  573. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  574. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  575. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  576. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  577. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  578. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  579. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  580. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  581. package/src/runtime/pending-interactions.ts +43 -9
  582. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  583. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  584. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
  585. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  586. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  587. package/src/runtime/routes/approval-interception-types.ts +13 -0
  588. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  589. package/src/runtime/routes/backup-routes.ts +15 -38
  590. package/src/runtime/routes/btw-routes.ts +14 -37
  591. package/src/runtime/routes/client-routes.ts +21 -2
  592. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  593. package/src/runtime/routes/contact-routes.ts +0 -25
  594. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  595. package/src/runtime/routes/conversation-routes.ts +65 -39
  596. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  597. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  598. package/src/runtime/routes/document-pdf-renderer.ts +169 -0
  599. package/src/runtime/routes/documents-routes.ts +32 -75
  600. package/src/runtime/routes/errors.ts +19 -4
  601. package/src/runtime/routes/events-routes.ts +38 -0
  602. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  603. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  604. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  605. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  606. package/src/runtime/routes/host-bash-routes.ts +56 -6
  607. package/src/runtime/routes/host-browser-routes.ts +108 -13
  608. package/src/runtime/routes/host-cu-routes.ts +66 -9
  609. package/src/runtime/routes/host-file-routes.ts +54 -5
  610. package/src/runtime/routes/host-transfer-routes.ts +122 -19
  611. package/src/runtime/routes/http-adapter.ts +1 -0
  612. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  613. package/src/runtime/routes/identity-routes.ts +21 -180
  614. package/src/runtime/routes/inbound-message-handler.ts +78 -21
  615. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  616. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  617. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  618. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  619. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  620. package/src/runtime/routes/index.ts +14 -0
  621. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  622. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  623. package/src/runtime/routes/memory-item-routes.ts +10 -12
  624. package/src/runtime/routes/memory-v2-routes.ts +474 -1
  625. package/src/runtime/routes/migration-routes.ts +96 -0
  626. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  627. package/src/runtime/routes/schedule-routes.ts +7 -0
  628. package/src/runtime/verification-outbound-actions.ts +4 -4
  629. package/src/runtime/verification-templates.ts +4 -7
  630. package/src/schedule/integration-status.ts +66 -2
  631. package/src/schedule/recurrence-engine.ts +4 -1
  632. package/src/schedule/retry-backoff.ts +18 -0
  633. package/src/schedule/retry-policy.ts +82 -0
  634. package/src/schedule/run-script.ts +37 -5
  635. package/src/schedule/schedule-recovery.ts +64 -0
  636. package/src/schedule/schedule-store.ts +106 -2
  637. package/src/schedule/scheduler-types.ts +25 -0
  638. package/src/schedule/scheduler.ts +83 -39
  639. package/src/security/encrypted-store.ts +2 -0
  640. package/src/security/oauth-callback-registry.ts +8 -0
  641. package/src/security/secure-keys.ts +55 -0
  642. package/src/sequence/analytics.ts +5 -5
  643. package/src/sequence/engine.ts +1 -1
  644. package/src/skills/catalog-files.ts +2 -8
  645. package/src/skills/include-graph.ts +5 -5
  646. package/src/skills/remote-skill-policy.ts +10 -16
  647. package/src/skills/skill-file-provider.ts +1 -1
  648. package/src/skills/skill-file-types.ts +13 -0
  649. package/src/skills/skillssh-audit-types.ts +28 -0
  650. package/src/skills/skillssh-registry.ts +8 -21
  651. package/src/subagent/index.ts +1 -7
  652. package/src/subagent/manager.ts +1 -15
  653. package/src/tasks/task-runner.ts +0 -1
  654. package/src/tasks/task-store.ts +0 -3
  655. package/src/telemetry/types.ts +2 -0
  656. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  657. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  658. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  659. package/src/tools/apps/executors.ts +56 -69
  660. package/src/tools/background-tool-registry.ts +17 -3
  661. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  662. package/src/tools/browser/browser-execution.ts +2 -2
  663. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  664. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  665. package/src/tools/browser/cdp-client/factory.ts +23 -24
  666. package/src/tools/browser/cdp-client/index.ts +1 -14
  667. package/src/tools/computer-use/definitions.ts +42 -20
  668. package/src/tools/executor.ts +2 -0
  669. package/src/tools/host-filesystem/edit.test.ts +151 -0
  670. package/src/tools/host-filesystem/edit.ts +68 -0
  671. package/src/tools/host-filesystem/read.test.ts +129 -0
  672. package/src/tools/host-filesystem/read.ts +68 -0
  673. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  674. package/src/tools/host-filesystem/transfer.ts +78 -3
  675. package/src/tools/host-filesystem/write.test.ts +134 -0
  676. package/src/tools/host-filesystem/write.ts +68 -0
  677. package/src/tools/host-terminal/host-shell.ts +66 -1
  678. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  679. package/src/tools/memory/register.test.ts +12 -9
  680. package/src/tools/memory/register.ts +1 -2
  681. package/src/tools/provider-tool-name.ts +28 -0
  682. package/src/tools/registry.ts +30 -9
  683. package/src/tools/schedule/create.ts +6 -0
  684. package/src/tools/schedule/list.ts +2 -0
  685. package/src/tools/schedule/update.ts +10 -0
  686. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  687. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  688. package/src/tools/skills/load.ts +0 -32
  689. package/src/tools/terminal/shell.ts +9 -1
  690. package/src/tools/tool-approval-handler.ts +32 -11
  691. package/src/tools/types.ts +28 -2
  692. package/src/tts/provider-catalog.ts +3 -5
  693. package/src/usage/pricing.ts +1 -1
  694. package/src/util/disk-usage.ts +138 -0
  695. package/src/util/platform.ts +21 -11
  696. package/src/util/process-liveness.ts +26 -0
  697. package/src/workspace/hatched-date.ts +86 -0
  698. package/src/workspace/heartbeat-service.ts +19 -0
  699. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  700. package/src/workspace/migrations/006-services-config.ts +8 -5
  701. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  702. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  703. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  704. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  705. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  706. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  707. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  708. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  709. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  710. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  711. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  712. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  713. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  714. package/src/workspace/migrations/AGENTS.md +1 -1
  715. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  716. package/src/workspace/migrations/registry.ts +8 -0
  717. package/src/workspace/migrations/utils.ts +21 -0
  718. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  719. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  720. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  721. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  722. package/src/__tests__/twilio-rest.test.ts +0 -34
  723. package/src/backup/__tests__/backup-key.test.ts +0 -152
  724. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  725. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  726. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  727. package/src/backup/backup-key.ts +0 -137
  728. package/src/backup/backup-worker.ts +0 -472
  729. package/src/backup/offsite-writer.ts +0 -222
  730. package/src/backup/stream-crypt.ts +0 -263
  731. package/src/daemon/message-types/pairing.ts +0 -58
  732. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  733. package/src/memory/v2/skill-qdrant.ts +0 -395
  734. package/src/outbound-proxy/config.ts +0 -20
  735. package/src/outbound-proxy/health.ts +0 -18
  736. package/src/outbound-proxy/types.ts +0 -150
  737. package/src/runtime/capability-tokens.ts +0 -190
  738. package/src/signals/bash.ts +0 -198
  739. package/src/signals/mcp-reload.ts +0 -18
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  existsSync,
3
3
  mkdirSync,
4
+ readdirSync,
4
5
  readFileSync,
5
6
  rmSync,
6
7
  writeFileSync,
@@ -63,12 +64,15 @@ afterAll(() => {
63
64
  mock.restore();
64
65
  });
65
66
 
67
+ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
66
68
  import {
67
- deepMergeMissing,
68
69
  deepMergeOverwrite,
70
+ getConfig,
69
71
  invalidateConfigCache,
70
72
  loadConfig,
73
+ mergeDefaultWorkspaceConfig,
71
74
  } from "../config/loader.js";
75
+ import { seedInferenceProfiles } from "../config/seed-inference-profiles.js";
72
76
  import { _setStorePath } from "../security/encrypted-store.js";
73
77
 
74
78
  // ---------------------------------------------------------------------------
@@ -79,73 +83,19 @@ function writeConfig(obj: unknown): void {
79
83
  writeFileSync(CONFIG_PATH, JSON.stringify(obj, null, 2) + "\n");
80
84
  }
81
85
 
82
- function readConfig(): Record<string, unknown> {
83
- return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
84
- }
85
-
86
- // ---------------------------------------------------------------------------
87
- // Tests: deepMergeMissing (unit)
88
- // ---------------------------------------------------------------------------
89
-
90
- describe("deepMergeMissing", () => {
91
- test("adds missing top-level keys", () => {
92
- const target: Record<string, unknown> = { a: 1 };
93
- const defaults: Record<string, unknown> = { a: 99, b: 2 };
94
- const changed = deepMergeMissing(target, defaults);
95
- expect(changed).toBe(true);
96
- expect(target).toEqual({ a: 1, b: 2 });
97
- });
98
-
99
- test("does not overwrite existing values", () => {
100
- const target: Record<string, unknown> = { a: 1, b: "user" };
101
- const defaults: Record<string, unknown> = { a: 99, b: "default" };
102
- const changed = deepMergeMissing(target, defaults);
103
- expect(changed).toBe(false);
104
- expect(target).toEqual({ a: 1, b: "user" });
86
+ function mergeDefaultConfigAndSeedInferenceProfiles(): void {
87
+ const defaultConfigMerge = mergeDefaultWorkspaceConfig();
88
+ seedInferenceProfiles({
89
+ preserveProfileNames: defaultConfigMerge.providedLlmProfileNames,
90
+ preserveActiveProfile: defaultConfigMerge.providedLlmActiveProfile,
105
91
  });
106
-
107
- test("recursively fills nested objects", () => {
108
- const target: Record<string, unknown> = {
109
- nested: { existingKey: "keep" },
110
- };
111
- const defaults: Record<string, unknown> = {
112
- nested: { existingKey: "default", newKey: 42 },
113
- };
114
- const changed = deepMergeMissing(target, defaults);
115
- expect(changed).toBe(true);
116
- expect(target).toEqual({
117
- nested: { existingKey: "keep", newKey: 42 },
118
- });
119
- });
120
-
121
- test("returns false when no changes needed", () => {
122
- const target: Record<string, unknown> = { a: 1, b: { c: 3 } };
123
- const defaults: Record<string, unknown> = { a: 99, b: { c: 100 } };
124
- const changed = deepMergeMissing(target, defaults);
125
- expect(changed).toBe(false);
126
- });
127
-
128
- test("does not merge arrays", () => {
129
- const target: Record<string, unknown> = { items: [1, 2] };
130
- const defaults: Record<string, unknown> = { items: [3, 4, 5] };
131
- const changed = deepMergeMissing(target, defaults);
132
- expect(changed).toBe(false);
133
- expect(target).toEqual({ items: [1, 2] });
134
- });
135
-
136
- test("adds entire missing nested section", () => {
137
- const target: Record<string, unknown> = {};
138
- const defaults: Record<string, unknown> = {
139
- slack: { deliverAuthBypass: false },
140
- };
141
- const changed = deepMergeMissing(target, defaults);
142
- expect(changed).toBe(true);
143
- expect(target).toEqual({ slack: { deliverAuthBypass: false } });
144
- });
145
- });
92
+ }
146
93
 
147
94
  // ---------------------------------------------------------------------------
148
95
  // Tests: deepMergeOverwrite (unit) — JSON-null-as-deletion semantics
96
+ //
97
+ // `deepMergeOverwrite` is used by `mergeDefaultWorkspaceConfig` and platform
98
+ // override paths.
149
99
  // ---------------------------------------------------------------------------
150
100
 
151
101
  describe("deepMergeOverwrite", () => {
@@ -275,7 +225,11 @@ describe("deepMergeOverwrite", () => {
275
225
  heartbeat: { activeHoursStart: null, activeHoursEnd: null },
276
226
  });
277
227
  expect(target).toEqual({
278
- heartbeat: { intervalMs: 6000, activeHoursStart: null, activeHoursEnd: null },
228
+ heartbeat: {
229
+ intervalMs: 6000,
230
+ activeHoursStart: null,
231
+ activeHoursEnd: null,
232
+ },
279
233
  });
280
234
  });
281
235
 
@@ -318,14 +272,21 @@ describe("deepMergeOverwrite", () => {
318
272
  });
319
273
 
320
274
  // ---------------------------------------------------------------------------
321
- // Tests: startup backfill integration
275
+ // Tests: loadConfig() startup behavior
276
+ //
277
+ // Contract: disk = user intent, in-memory cache = effective values. loadConfig
278
+ // must NOT silently materialize schema defaults into config.json on load.
279
+ // The legitimate self-healing paths that DO rewrite the file (deprecated-key
280
+ // strip, fresh-config seed, corrupt-JSON quarantine) are protected below.
322
281
  // ---------------------------------------------------------------------------
323
282
 
324
- describe("config loader backfill", () => {
283
+ describe("loadConfig startup behavior", () => {
325
284
  beforeEach(() => {
326
285
  ensureTestDir();
327
286
  const resetPaths = [
328
287
  CONFIG_PATH,
288
+ join(WORKSPACE_DIR, "default-config.json"),
289
+ join(WORKSPACE_DIR, "hatch-overlay.json"),
329
290
  join(WORKSPACE_DIR, "keys.enc"),
330
291
  join(WORKSPACE_DIR, "data"),
331
292
  join(WORKSPACE_DIR, "data", "memory"),
@@ -335,129 +296,482 @@ describe("config loader backfill", () => {
335
296
  rmSync(path, { recursive: true, force: true });
336
297
  }
337
298
  }
299
+ // Also clear any leftover quarantine files from previous test runs.
300
+ if (existsSync(WORKSPACE_DIR)) {
301
+ for (const entry of readdirSync(WORKSPACE_DIR)) {
302
+ if (entry.startsWith("config.json.corrupt-")) {
303
+ rmSync(join(WORKSPACE_DIR, entry), { force: true });
304
+ }
305
+ }
306
+ }
307
+ const updatesPath = join(WORKSPACE_DIR, "UPDATES.md");
308
+ if (existsSync(updatesPath)) rmSync(updatesPath, { force: true });
338
309
  ensureTestDir();
339
310
  _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
311
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
340
312
  invalidateConfigCache();
341
313
  });
342
314
 
343
315
  afterEach(() => {
344
316
  _setStorePath(null);
317
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
345
318
  invalidateConfigCache();
346
319
  });
347
320
 
348
- test("backfills missing schema keys into existing config.json", () => {
349
- // Write a minimal config that is missing many sections
350
- writeConfig({ provider: "anthropic", model: "claude-opus-4-6" });
321
+ test("does not modify existing config.json on load", () => {
322
+ // Write a partial config and confirm the file's bytes are unchanged
323
+ // after loadConfig(). Schema defaults must apply in-memory only; disk
324
+ // is the user's source of truth.
325
+ writeConfig({ provider: "anthropic" });
326
+ const before = readFileSync(CONFIG_PATH);
351
327
 
352
328
  loadConfig();
353
329
 
354
- // Re-read the file from disk — it should have been backfilled
355
- const raw = readConfig();
356
- // New fields from this PR should be present
357
- expect(raw.telegram).toBeDefined();
358
- expect((raw.telegram as Record<string, unknown>).apiBaseUrl).toBe(
359
- "https://api.telegram.org",
360
- );
361
- expect((raw.telegram as Record<string, unknown>).deliverAuthBypass).toBe(
362
- false,
363
- );
364
- expect((raw.telegram as Record<string, unknown>).timeoutMs).toBe(15_000);
365
- expect((raw.telegram as Record<string, unknown>).maxRetries).toBe(3);
366
- expect((raw.telegram as Record<string, unknown>).initialBackoffMs).toBe(
367
- 1_000,
368
- );
330
+ const after = readFileSync(CONFIG_PATH);
331
+ expect(after.equals(before)).toBe(true);
332
+ });
369
333
 
370
- expect(raw.whatsapp).toBeDefined();
371
- expect((raw.whatsapp as Record<string, unknown>).deliverAuthBypass).toBe(
372
- false,
373
- );
374
- expect((raw.whatsapp as Record<string, unknown>).timeoutMs).toBe(15_000);
375
- expect((raw.whatsapp as Record<string, unknown>).maxRetries).toBe(3);
376
- expect((raw.whatsapp as Record<string, unknown>).initialBackoffMs).toBe(
377
- 1_000,
378
- );
334
+ test("getConfig().memory.v2.bm25_b returns schema default when absent on disk", () => {
335
+ // Consumer-side correctness: even though loadConfig no longer writes
336
+ // schema defaults back to disk, accessors still see them via the
337
+ // in-memory `cached: AssistantConfig` populated by `applyNestedDefaults`.
338
+ writeConfig({ provider: "anthropic" });
339
+
340
+ const config = getConfig();
341
+
342
+ expect(config.memory.v2.bm25_b).toBe(0.4);
343
+ });
344
+
345
+ test("reloads cached config when config.json is updated externally", () => {
346
+ // Models a CLI subprocess writing twilio.accountSid while the assistant
347
+ // process already has an effective config cached in memory.
348
+ writeConfig({ twilio: { accountSid: "AC_cached_before" } });
349
+ expect(loadConfig().twilio.accountSid).toBe("AC_cached_before");
379
350
 
380
- expect(raw.slack).toBeDefined();
381
- expect((raw.slack as Record<string, unknown>).deliverAuthBypass).toBe(
382
- false,
351
+ writeConfig({
352
+ twilio: { accountSid: "AC_fresh_after_external_write" },
353
+ });
354
+
355
+ expect(loadConfig().twilio.accountSid).toBe(
356
+ "AC_fresh_after_external_write",
383
357
  );
384
358
  });
385
359
 
386
- test("preserves existing user-defined values during backfill", () => {
360
+ test("still strips deprecated fields and rewrites", () => {
361
+ // `warnAndStripDeprecatedFields` is a legitimate self-healing path:
362
+ // it removes fields the schema no longer recognizes and persists the
363
+ // cleaned config so the deprecation warning fires only once.
387
364
  writeConfig({
388
- services: {
389
- inference: { provider: "openai", model: "gpt-4" },
390
- },
391
- telegram: { botUsername: "mybot", timeoutMs: 30_000 },
392
- whatsapp: { phoneNumber: "+1234567890" },
365
+ provider: "anthropic",
366
+ rateLimit: { maxTokensPerSession: 100_000 },
393
367
  });
394
368
 
395
369
  loadConfig();
396
370
 
397
- const raw = readConfig();
398
- // User values preserved
399
- const services = raw.services as Record<string, Record<string, unknown>>;
400
- expect(services.inference.provider).toBe("openai");
401
- expect(services.inference.model).toBe("gpt-4");
402
- expect((raw.telegram as Record<string, unknown>).botUsername).toBe("mybot");
403
- expect((raw.telegram as Record<string, unknown>).timeoutMs).toBe(30_000);
404
- expect((raw.whatsapp as Record<string, unknown>).phoneNumber).toBe(
405
- "+1234567890",
371
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
372
+ expect(raw.rateLimit?.maxTokensPerSession).toBeUndefined();
373
+ // Other rateLimit keys are not affected — only the deprecated entry is stripped
374
+ expect(raw.provider).toBe("anthropic");
375
+ });
376
+
377
+ test("strips memory.jobs.batchSize from existing user configs", () => {
378
+ // Pre-PR-#29364, the memory job worker read `memory.jobs.batchSize` to
379
+ // size its single claim batch. The per-lane scheduler no longer reads
380
+ // it, so the field is deprecated. Existing configs that have it
381
+ // written to disk should load cleanly with the field silently stripped.
382
+ writeConfig({
383
+ provider: "anthropic",
384
+ memory: { jobs: { batchSize: 25, workerConcurrency: 4 } },
385
+ });
386
+
387
+ loadConfig();
388
+
389
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
390
+ expect(raw.memory?.jobs?.batchSize).toBeUndefined();
391
+ // Sibling fields under memory.jobs are preserved
392
+ expect(raw.memory?.jobs?.workerConcurrency).toBe(4);
393
+ });
394
+
395
+ test("still writes a default config on first launch when file is absent", () => {
396
+ // Discoverability: when no config.json exists, write one populated with
397
+ // all schema defaults so users can see and edit available options.
398
+ expect(existsSync(CONFIG_PATH)).toBe(false);
399
+
400
+ loadConfig();
401
+
402
+ expect(existsSync(CONFIG_PATH)).toBe(true);
403
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
404
+ // Sanity: schema-defaulted nested fields are materialized
405
+ expect(raw.memory?.v2?.bm25_b).toBe(0.4);
406
+ expect(raw.dataDir).toBeUndefined();
407
+ });
408
+
409
+ test("hatch default overlay does not suppress first-load inference profiles", () => {
410
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
411
+ writeFileSync(
412
+ overlayPath,
413
+ JSON.stringify(
414
+ {
415
+ llm: {
416
+ default: {
417
+ provider: "anthropic",
418
+ model: "claude-opus-4-7",
419
+ },
420
+ },
421
+ },
422
+ null,
423
+ 2,
424
+ ) + "\n",
406
425
  );
426
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
407
427
 
408
- // Missing fields backfilled
409
- expect((raw.telegram as Record<string, unknown>).apiBaseUrl).toBe(
410
- "https://api.telegram.org",
428
+ mergeDefaultConfigAndSeedInferenceProfiles();
429
+ const config = loadConfig();
430
+
431
+ expect(config.llm.default.provider).toBe("anthropic");
432
+ expect(config.llm.default.model).toBe("claude-opus-4-7");
433
+ expect(config.llm.activeProfile).toBe("balanced");
434
+ expect(config.llm.profiles.balanced?.model).toBe("claude-sonnet-4-6");
435
+
436
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
437
+ expect(raw.llm.default).toEqual({
438
+ provider: "anthropic",
439
+ model: "claude-opus-4-7",
440
+ });
441
+ expect(raw.llm.activeProfile).toBe("balanced");
442
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
443
+ });
444
+
445
+ test("non-Anthropic hatch overlay seeds custom-* profiles and activates custom-balanced", () => {
446
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
447
+ writeFileSync(
448
+ overlayPath,
449
+ JSON.stringify(
450
+ {
451
+ llm: {
452
+ default: {
453
+ provider: "openai",
454
+ },
455
+ },
456
+ },
457
+ null,
458
+ 2,
459
+ ) + "\n",
460
+ );
461
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
462
+
463
+ mergeDefaultConfigAndSeedInferenceProfiles();
464
+ const config = loadConfig();
465
+ const mainAgentConfig = resolveCallSiteConfig("mainAgent", config.llm);
466
+
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",
411
472
  );
412
- expect((raw.telegram as Record<string, unknown>).deliverAuthBypass).toBe(
413
- false,
473
+ expect(config.llm.profiles["custom-cost-optimized"]?.provider).toBe(
474
+ "openai",
414
475
  );
415
- expect((raw.whatsapp as Record<string, unknown>).deliverAuthBypass).toBe(
416
- false,
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,
417
490
  );
418
491
  });
419
492
 
420
- test("does not rewrite config.json when no effective change exists", () => {
421
- // First load: creates config from scratch with all defaults
422
- loadConfig();
423
- invalidateConfigCache();
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.
496
+ writeConfig({
497
+ llm: {
498
+ default: { provider: "openai", model: "gpt-5.4-mini" },
499
+ profiles: {
500
+ "custom-balanced": {
501
+ source: "managed",
502
+ provider: "openai",
503
+ model: "gpt-5.4-mini",
504
+ },
505
+ },
506
+ activeProfile: "custom-balanced",
507
+ },
508
+ });
424
509
 
425
- // Read file and record its content
426
- const contentBefore = readFileSync(CONFIG_PATH, "utf-8");
510
+ const overlayPath = join(WORKSPACE_DIR, "rehatch-anthropic.json");
511
+ writeFileSync(
512
+ overlayPath,
513
+ JSON.stringify({ llm: { default: { provider: "anthropic" } } }, null, 2) +
514
+ "\n",
515
+ );
516
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
427
517
 
428
- // Second load: file already has all keys — no write expected
429
- loadConfig();
518
+ mergeDefaultConfigAndSeedInferenceProfiles();
430
519
 
431
- const contentAfter = readFileSync(CONFIG_PATH, "utf-8");
432
- expect(contentAfter).toBe(contentBefore);
520
+ 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");
433
524
  });
434
525
 
435
- test("does not write dataDir during backfill", () => {
436
- writeConfig({ provider: "anthropic" });
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
+ },
536
+ },
537
+ },
538
+ null,
539
+ 2,
540
+ ) + "\n",
541
+ );
542
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
543
+
544
+ mergeDefaultConfigAndSeedInferenceProfiles();
545
+
546
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
547
+ expect(raw.llm.activeProfile).toBe("balanced");
548
+ 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");
556
+ });
437
557
 
438
- loadConfig();
558
+ test("preserves user-supplied non-catalog model on every restart (ollama custom model)", () => {
559
+ // Models the ollama case: catalog lists only `llama3.2` but the user has
560
+ // pulled `codellama`. The seeder must NOT silently overwrite their pick.
561
+ writeConfig({
562
+ llm: { default: { provider: "ollama", model: "codellama" } },
563
+ });
439
564
 
440
- const raw = readConfig();
441
- expect(raw.dataDir).toBeUndefined();
565
+ mergeDefaultConfigAndSeedInferenceProfiles();
566
+ let raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
567
+ expect(raw.llm.default.model).toBe("codellama");
568
+
569
+ // Re-run to confirm idempotency — the user's model survives every restart.
570
+ mergeDefaultConfigAndSeedInferenceProfiles();
571
+ raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
572
+ expect(raw.llm.default.model).toBe("codellama");
442
573
  });
443
574
 
444
- test("backfills new nested fields into existing sections", () => {
445
- // Config with only the old telegram.botUsername field
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");
578
+ writeFileSync(
579
+ overlayMissing,
580
+ JSON.stringify({ llm: { default: { provider: "openai" } } }, null, 2) +
581
+ "\n",
582
+ );
583
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayMissing;
584
+ 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,
588
+ );
589
+
590
+ // 2. Inconsistent (previous default model belongs to a different provider)
591
+ // is overwritten on the next seed run.
592
+ rmSync(CONFIG_PATH);
446
593
  writeConfig({
447
- telegram: { botUsername: "oldbot" },
594
+ llm: {
595
+ default: { provider: "openai", model: "claude-opus-4-7" },
596
+ },
448
597
  });
598
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayMissing;
599
+ mergeDefaultConfigAndSeedInferenceProfiles();
600
+ raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
601
+ expect(raw.llm.default.model).toBe(
602
+ raw.llm.profiles["custom-balanced"].model,
603
+ );
604
+
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",
624
+ },
625
+ },
626
+ null,
627
+ 2,
628
+ ) + "\n",
629
+ );
630
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = explicit;
631
+ 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");
635
+ });
636
+
637
+ test("platform-provided profile fragments are not polluted by managed seeds", () => {
638
+ writeConfig({
639
+ llm: {
640
+ default: {
641
+ provider: "anthropic",
642
+ model: "claude-opus-4-7",
643
+ },
644
+ profiles: {
645
+ balanced: {
646
+ source: "managed",
647
+ provider: "anthropic",
648
+ model: "claude-sonnet-4-6",
649
+ maxTokens: 16000,
650
+ effort: "high",
651
+ thinking: { enabled: true, streamThinking: true },
652
+ },
653
+ },
654
+ activeProfile: "balanced",
655
+ },
656
+ });
657
+
658
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
659
+ writeFileSync(
660
+ overlayPath,
661
+ JSON.stringify(
662
+ {
663
+ llm: {
664
+ default: {
665
+ provider: "openai",
666
+ model: "gpt-5.4",
667
+ },
668
+ profiles: {
669
+ balanced: {
670
+ source: "managed",
671
+ provider: "openai",
672
+ model: "gpt-5.4",
673
+ label: "Platform Balanced",
674
+ },
675
+ },
676
+ activeProfile: "balanced",
677
+ },
678
+ },
679
+ null,
680
+ 2,
681
+ ) + "\n",
682
+ );
683
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
684
+
685
+ mergeDefaultConfigAndSeedInferenceProfiles();
686
+ const config = loadConfig();
687
+ const mainAgentConfig = resolveCallSiteConfig("mainAgent", config.llm);
688
+
689
+ expect(config.llm.activeProfile).toBe("balanced");
690
+ expect(config.llm.profiles.balanced).toEqual({
691
+ source: "managed",
692
+ provider: "openai",
693
+ model: "gpt-5.4",
694
+ label: "Platform Balanced",
695
+ });
696
+ expect(mainAgentConfig.provider).toBe("openai");
697
+ expect(mainAgentConfig.model).toBe("gpt-5.4");
698
+
699
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
700
+ expect(raw.llm.profiles.balanced).toEqual({
701
+ source: "managed",
702
+ provider: "openai",
703
+ model: "gpt-5.4",
704
+ label: "Platform Balanced",
705
+ });
706
+ expect(raw.llm.profiles.balanced.maxTokens).toBeUndefined();
707
+ expect(raw.llm.profiles.balanced.thinking).toBeUndefined();
708
+
709
+ mergeDefaultConfigAndSeedInferenceProfiles();
710
+
711
+ const afterRestart = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
712
+ expect(afterRestart.llm.activeProfile).toBe("balanced");
713
+ expect(afterRestart.llm.profiles.balanced).toEqual({
714
+ source: "managed",
715
+ provider: "openai",
716
+ model: "gpt-5.4",
717
+ label: "Platform Balanced",
718
+ });
719
+ });
720
+
721
+ test("quarantines corrupt config before merging hatch overlay", () => {
722
+ writeFileSync(CONFIG_PATH, "{not valid json");
723
+
724
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
725
+ writeFileSync(
726
+ overlayPath,
727
+ JSON.stringify(
728
+ {
729
+ llm: {
730
+ default: {
731
+ provider: "anthropic",
732
+ model: "claude-opus-4-7",
733
+ },
734
+ },
735
+ },
736
+ null,
737
+ 2,
738
+ ) + "\n",
739
+ );
740
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
741
+
742
+ mergeDefaultConfigAndSeedInferenceProfiles();
743
+
744
+ const quarantined = readdirSync(WORKSPACE_DIR).filter((n) =>
745
+ n.startsWith("config.json.corrupt-"),
746
+ );
747
+ expect(quarantined.length).toBeGreaterThan(0);
748
+
749
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
750
+ expect(raw.llm.default).toEqual({
751
+ provider: "anthropic",
752
+ model: "claude-opus-4-7",
753
+ });
754
+ expect(raw.llm.activeProfile).toBe("balanced");
755
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
756
+ });
757
+
758
+ test("still quarantines corrupt JSON", () => {
759
+ // Corrupt-config quarantine is a recovery path: the broken file is
760
+ // renamed to `config.json.corrupt-<ts>.json` and the daemon proceeds
761
+ // with defaults. This must keep working.
762
+ writeFileSync(CONFIG_PATH, "{not valid json");
449
763
 
450
764
  loadConfig();
451
765
 
452
- const raw = readConfig();
453
- const telegram = raw.telegram as Record<string, unknown>;
454
- // Old field preserved
455
- expect(telegram.botUsername).toBe("oldbot");
456
- // New fields backfilled
457
- expect(telegram.apiBaseUrl).toBe("https://api.telegram.org");
458
- expect(telegram.deliverAuthBypass).toBe(false);
459
- expect(telegram.timeoutMs).toBe(15_000);
460
- expect(telegram.maxRetries).toBe(3);
461
- expect(telegram.initialBackoffMs).toBe(1_000);
766
+ // A new defaults-populated config.json is written in place
767
+ expect(existsSync(CONFIG_PATH)).toBe(true);
768
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
769
+ expect(raw.memory?.v2?.bm25_b).toBe(0.4);
770
+
771
+ // The corrupt original is preserved as a `*.corrupt-*.json` sibling
772
+ const quarantined = readdirSync(WORKSPACE_DIR).filter((n) =>
773
+ n.startsWith("config.json.corrupt-"),
774
+ );
775
+ expect(quarantined.length).toBeGreaterThan(0);
462
776
  });
463
777
  });