@vellumai/assistant 0.7.2 → 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 (347) hide show
  1. package/ARCHITECTURE.md +16 -1
  2. package/docs/architecture/memory.md +5 -2
  3. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
  4. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
  5. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  6. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  7. package/openapi.yaml +449 -22
  8. package/package.json +1 -1
  9. package/src/__tests__/app-control-flow.test.ts +21 -11
  10. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  11. package/src/__tests__/assistant-event.test.ts +0 -10
  12. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
  13. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
  14. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  15. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  16. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  17. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  18. package/src/__tests__/channel-readiness-service.test.ts +4 -2
  19. package/src/__tests__/config-loader-backfill.test.ts +379 -0
  20. package/src/__tests__/config-schema.test.ts +1 -0
  21. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
  22. package/src/__tests__/config-watcher.test.ts +140 -69
  23. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  24. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  25. package/src/__tests__/context-search-fanout.test.ts +0 -1
  26. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  27. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  28. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  29. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  30. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  31. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  32. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  33. package/src/__tests__/conversation-error.test.ts +150 -3
  34. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  35. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  36. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  37. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  38. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  39. package/src/__tests__/conversation-store.test.ts +0 -18
  40. package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
  41. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  42. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  43. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  44. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  45. package/src/__tests__/credentials-cli.test.ts +7 -0
  46. package/src/__tests__/cu-unified-flow.test.ts +176 -10
  47. package/src/__tests__/date-context.test.ts +164 -2
  48. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  49. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  50. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  51. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  52. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  53. package/src/__tests__/disk-usage.test.ts +150 -0
  54. package/src/__tests__/events-client-registration.test.ts +52 -0
  55. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  56. package/src/__tests__/file-write-tool.test.ts +4 -10
  57. package/src/__tests__/filing-service.test.ts +3 -4
  58. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  59. package/src/__tests__/heartbeat-service.test.ts +260 -11
  60. package/src/__tests__/host-app-control-proxy.test.ts +195 -25
  61. package/src/__tests__/host-bash-proxy.test.ts +227 -34
  62. package/src/__tests__/host-bash-routes.test.ts +178 -13
  63. package/src/__tests__/host-cu-proxy.test.ts +210 -3
  64. package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
  65. package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
  66. package/src/__tests__/host-file-proxy.test.ts +268 -6
  67. package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
  68. package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
  69. package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
  70. package/src/__tests__/http-user-message-parity.test.ts +107 -1
  71. package/src/__tests__/injector-chain.test.ts +18 -6
  72. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  73. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  74. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  75. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  77. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  78. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  79. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  80. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  81. package/src/__tests__/openai-provider.test.ts +45 -8
  82. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  83. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  84. package/src/__tests__/platform.test.ts +2 -1
  85. package/src/__tests__/playbook-execution.test.ts +0 -43
  86. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  87. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
  88. package/src/__tests__/provider-tool-name.test.ts +23 -0
  89. package/src/__tests__/relay-server.test.ts +15 -4
  90. package/src/__tests__/runtime-events-sse.test.ts +4 -8
  91. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  92. package/src/__tests__/secret-ingress-http.test.ts +0 -1
  93. package/src/__tests__/suggestion-routes.test.ts +46 -0
  94. package/src/__tests__/twilio-validation.test.ts +2 -2
  95. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  96. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  97. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  98. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  99. package/src/approvals/guardian-decision-primitive.ts +13 -0
  100. package/src/approvals/guardian-request-resolvers.ts +16 -17
  101. package/src/backup/snapshot-lock.ts +2 -27
  102. package/src/bundler/compiler-tools.ts +3 -2
  103. package/src/calls/call-conversation-messages.ts +46 -10
  104. package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
  105. package/src/cli/commands/bash.ts +35 -108
  106. package/src/cli/commands/contacts.ts +64 -25
  107. package/src/cli/commands/credentials.ts +56 -0
  108. package/src/cli/commands/memory-v2.ts +7 -6
  109. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  110. package/src/cli/commands/oauth/connect.ts +127 -1
  111. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
  112. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
  113. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  114. package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
  115. package/src/cli/commands/platform/index.ts +16 -7
  116. package/src/cli/commands/status.ts +57 -0
  117. package/src/cli/program.ts +4 -2
  118. package/src/config/assistant-feature-flags.ts +13 -3
  119. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  120. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
  121. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  122. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  123. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  124. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  125. package/src/config/env.ts +0 -8
  126. package/src/config/feature-flag-registry.json +27 -3
  127. package/src/config/loader.ts +127 -8
  128. package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
  129. package/src/config/schemas/call-site-catalog.ts +14 -0
  130. package/src/config/schemas/channels.ts +0 -5
  131. package/src/config/schemas/heartbeat.ts +1 -1
  132. package/src/config/schemas/llm.ts +2 -0
  133. package/src/config/schemas/memory-lifecycle.ts +13 -0
  134. package/src/config/schemas/memory-v2.ts +75 -11
  135. package/src/config/schemas/platform.ts +43 -3
  136. package/src/config/schemas/services.ts +28 -0
  137. package/src/config/seed-inference-profiles.ts +230 -33
  138. package/src/contacts/contact-store.ts +0 -25
  139. package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
  140. package/src/daemon/assistant-attachments.ts +4 -4
  141. package/src/daemon/config-watcher.ts +85 -57
  142. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  143. package/src/daemon/conversation-agent-loop.ts +170 -33
  144. package/src/daemon/conversation-error.ts +87 -15
  145. package/src/daemon/conversation-lifecycle.ts +1 -3
  146. package/src/daemon/conversation-process.ts +8 -0
  147. package/src/daemon/conversation-runtime-assembly.ts +26 -0
  148. package/src/daemon/conversation-store.ts +2 -2
  149. package/src/daemon/conversation-surfaces.ts +195 -15
  150. package/src/daemon/conversation-tool-setup.ts +57 -14
  151. package/src/daemon/conversation.ts +17 -22
  152. package/src/daemon/date-context.ts +71 -22
  153. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  154. package/src/daemon/disk-pressure-guard.ts +343 -0
  155. package/src/daemon/disk-pressure-policy.ts +163 -0
  156. package/src/daemon/handlers/shared.ts +0 -1
  157. package/src/daemon/handlers/skills.ts +3 -4
  158. package/src/daemon/host-app-control-proxy.ts +137 -41
  159. package/src/daemon/host-bash-proxy.ts +46 -21
  160. package/src/daemon/host-cu-proxy.ts +49 -3
  161. package/src/daemon/host-file-proxy.ts +43 -7
  162. package/src/daemon/host-transfer-proxy.ts +95 -4
  163. package/src/daemon/lifecycle.ts +79 -28
  164. package/src/daemon/meet-host-supervisor.ts +4 -4
  165. package/src/daemon/meet-manifest-loader.ts +0 -1
  166. package/src/daemon/memory-v2-startup.ts +14 -4
  167. package/src/daemon/message-protocol.ts +3 -0
  168. package/src/daemon/message-types/conversations.ts +4 -0
  169. package/src/daemon/message-types/disk-pressure.ts +9 -0
  170. package/src/daemon/message-types/messages.ts +3 -0
  171. package/src/daemon/profiler-run-store.ts +5 -5
  172. package/src/daemon/tool-setup-types.ts +2 -2
  173. package/src/documents/document-store.ts +85 -0
  174. package/src/filing/filing-service.ts +30 -5
  175. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
  176. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
  177. package/src/heartbeat/heartbeat-run-store.ts +13 -0
  178. package/src/heartbeat/heartbeat-service.ts +205 -31
  179. package/src/home/feed-scheduler.ts +18 -0
  180. package/src/inbound/platform-callback-registration.ts +8 -15
  181. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  182. package/src/ipc/assistant-server.ts +56 -2
  183. package/src/ipc/gateway-client.ts +37 -3
  184. package/src/live-voice/live-voice-archive.ts +4 -4
  185. package/src/live-voice/protocol.ts +5 -7
  186. package/src/media/image-service.ts +1 -7
  187. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  188. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  189. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  190. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  191. package/src/memory/admin.ts +5 -9
  192. package/src/memory/context-search/agent-runner.ts +19 -2
  193. package/src/memory/context-search/sources/conversations.ts +2 -11
  194. package/src/memory/context-search/sources/memory-v2.ts +5 -4
  195. package/src/memory/context-search/sources/memory.ts +0 -1
  196. package/src/memory/context-search/types.ts +0 -1
  197. package/src/memory/conversation-crud.ts +4 -12
  198. package/src/memory/db-init.ts +2 -0
  199. package/src/memory/embedding-runtime-manager.ts +119 -5
  200. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
  201. package/src/memory/graph/conversation-graph-memory.ts +42 -54
  202. package/src/memory/graph/extraction.ts +1 -3
  203. package/src/memory/graph/graph-search.test.ts +10 -67
  204. package/src/memory/graph/graph-search.ts +1 -20
  205. package/src/memory/graph/retriever.test.ts +6 -0
  206. package/src/memory/graph/retriever.ts +6 -10
  207. package/src/memory/indexer.ts +54 -45
  208. package/src/memory/job-handlers/backfill.ts +2 -11
  209. package/src/memory/job-handlers/cleanup.ts +43 -0
  210. package/src/memory/job-handlers/embedding.ts +6 -8
  211. package/src/memory/job-handlers/summarization.ts +2 -7
  212. package/src/memory/jobs-store.ts +48 -0
  213. package/src/memory/jobs-worker.ts +81 -43
  214. package/src/memory/memory-v2-activation-log-store.ts +32 -14
  215. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  216. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  217. package/src/memory/migrations/index.ts +1 -0
  218. package/src/memory/pkb/pkb-search.test.ts +6 -0
  219. package/src/memory/qdrant-client.ts +0 -13
  220. package/src/memory/rerank-local.ts +374 -0
  221. package/src/memory/search/semantic.ts +6 -67
  222. package/src/memory/trace-event-store.ts +1 -17
  223. package/src/memory/v2/__tests__/activation.test.ts +311 -250
  224. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  225. package/src/memory/v2/__tests__/injection.test.ts +157 -167
  226. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  227. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  228. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  229. package/src/memory/v2/__tests__/sim.test.ts +5 -199
  230. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  231. package/src/memory/v2/__tests__/static-context.test.ts +76 -1
  232. package/src/memory/v2/activation.ts +149 -156
  233. package/src/memory/v2/consolidation-job.ts +62 -12
  234. package/src/memory/v2/injection.ts +47 -60
  235. package/src/memory/v2/prompts/consolidation.ts +36 -1
  236. package/src/memory/v2/qdrant.ts +99 -0
  237. package/src/memory/v2/reranker.ts +177 -0
  238. package/src/memory/v2/sim.ts +10 -84
  239. package/src/memory/v2/skill-content.ts +4 -3
  240. package/src/memory/v2/skill-store.ts +82 -59
  241. package/src/memory/v2/static-context.ts +22 -0
  242. package/src/memory/v2/types.ts +10 -10
  243. package/src/notifications/copy-composer.ts +13 -0
  244. package/src/notifications/signal.ts +4 -0
  245. package/src/oauth/AGENTS.md +3 -1
  246. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  247. package/src/oauth/connect-orchestrator.ts +2 -0
  248. package/src/oauth/connection-resolver.test.ts +66 -1
  249. package/src/oauth/connection-resolver.ts +55 -1
  250. package/src/oauth/oauth-connect-state.ts +77 -0
  251. package/src/oauth/seed-providers.ts +58 -1
  252. package/src/plugins/defaults/injectors.ts +35 -2
  253. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  254. package/src/plugins/types.ts +7 -0
  255. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  256. package/src/proactive-artifact/decision.test.ts +226 -0
  257. package/src/proactive-artifact/decision.ts +165 -0
  258. package/src/proactive-artifact/index.ts +7 -0
  259. package/src/proactive-artifact/job.test.ts +867 -0
  260. package/src/proactive-artifact/job.ts +352 -0
  261. package/src/proactive-artifact/message-copy.ts +41 -0
  262. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  263. package/src/proactive-artifact/trigger-state.ts +119 -0
  264. package/src/prompts/normalize-onboarding.ts +80 -0
  265. package/src/prompts/persona-resolver.ts +101 -9
  266. package/src/prompts/system-prompt.ts +21 -7
  267. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  268. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  269. package/src/providers/model-intents.ts +7 -0
  270. package/src/providers/openrouter/client.ts +8 -0
  271. package/src/providers/retry.ts +50 -0
  272. package/src/providers/types.ts +1 -0
  273. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  274. package/src/runtime/agent-wake.ts +238 -100
  275. package/src/runtime/assistant-event-hub.ts +36 -6
  276. package/src/runtime/assistant-event.ts +0 -1
  277. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  278. package/src/runtime/auth/route-policy.ts +14 -1
  279. package/src/runtime/auth/same-actor.ts +216 -0
  280. package/src/runtime/channel-retry-sweep.ts +65 -1
  281. package/src/runtime/guardian-reply-router.ts +10 -0
  282. package/src/runtime/local-actor-identity.ts +52 -11
  283. package/src/runtime/pending-interactions.ts +8 -0
  284. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
  286. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  287. package/src/runtime/routes/client-routes.ts +20 -2
  288. package/src/runtime/routes/contact-routes.ts +0 -25
  289. package/src/runtime/routes/conversation-routes.ts +35 -26
  290. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  291. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  292. package/src/runtime/routes/document-pdf-renderer.ts +6 -2
  293. package/src/runtime/routes/documents-routes.ts +2 -75
  294. package/src/runtime/routes/events-routes.ts +41 -9
  295. package/src/runtime/routes/host-bash-routes.ts +23 -3
  296. package/src/runtime/routes/host-cu-routes.ts +33 -6
  297. package/src/runtime/routes/host-file-routes.ts +32 -6
  298. package/src/runtime/routes/host-transfer-routes.ts +79 -16
  299. package/src/runtime/routes/identity-routes.ts +7 -138
  300. package/src/runtime/routes/inbound-message-handler.ts +77 -12
  301. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  302. package/src/runtime/routes/index.ts +6 -0
  303. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  304. package/src/runtime/routes/memory-v2-routes.ts +33 -0
  305. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  306. package/src/runtime/verification-outbound-actions.ts +4 -4
  307. package/src/schedule/run-script.ts +37 -5
  308. package/src/schedule/scheduler.ts +20 -1
  309. package/src/security/encrypted-store.ts +2 -0
  310. package/src/security/secure-keys.ts +55 -0
  311. package/src/skills/remote-skill-policy.ts +4 -10
  312. package/src/subagent/index.ts +1 -7
  313. package/src/subagent/manager.ts +1 -15
  314. package/src/tasks/task-runner.ts +0 -1
  315. package/src/tasks/task-store.ts +0 -3
  316. package/src/tools/background-tool-registry.ts +17 -3
  317. package/src/tools/host-filesystem/edit.test.ts +151 -0
  318. package/src/tools/host-filesystem/edit.ts +43 -1
  319. package/src/tools/host-filesystem/read.test.ts +129 -0
  320. package/src/tools/host-filesystem/read.ts +43 -1
  321. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  322. package/src/tools/host-filesystem/transfer.ts +56 -11
  323. package/src/tools/host-filesystem/write.test.ts +134 -0
  324. package/src/tools/host-filesystem/write.ts +43 -1
  325. package/src/tools/host-terminal/host-shell.ts +13 -6
  326. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  327. package/src/tools/memory/register.test.ts +12 -9
  328. package/src/tools/memory/register.ts +1 -2
  329. package/src/tools/provider-tool-name.ts +28 -0
  330. package/src/tools/registry.ts +30 -9
  331. package/src/tools/terminal/shell.ts +9 -1
  332. package/src/tools/tool-approval-handler.ts +31 -6
  333. package/src/tools/types.ts +24 -2
  334. package/src/tts/provider-catalog.ts +3 -5
  335. package/src/util/disk-usage.ts +138 -0
  336. package/src/util/platform.ts +21 -11
  337. package/src/util/process-liveness.ts +26 -0
  338. package/src/workspace/heartbeat-service.ts +19 -0
  339. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  340. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  341. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  342. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  343. package/src/workspace/migrations/registry.ts +8 -0
  344. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  345. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  346. package/src/memory/v2/skill-qdrant.ts +0 -404
  347. package/src/signals/bash.ts +0 -198
@@ -64,12 +64,15 @@ afterAll(() => {
64
64
  mock.restore();
65
65
  });
66
66
 
67
+ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
67
68
  import {
68
69
  deepMergeOverwrite,
69
70
  getConfig,
70
71
  invalidateConfigCache,
71
72
  loadConfig,
73
+ mergeDefaultWorkspaceConfig,
72
74
  } from "../config/loader.js";
75
+ import { seedInferenceProfiles } from "../config/seed-inference-profiles.js";
73
76
  import { _setStorePath } from "../security/encrypted-store.js";
74
77
 
75
78
  // ---------------------------------------------------------------------------
@@ -80,6 +83,14 @@ function writeConfig(obj: unknown): void {
80
83
  writeFileSync(CONFIG_PATH, JSON.stringify(obj, null, 2) + "\n");
81
84
  }
82
85
 
86
+ function mergeDefaultConfigAndSeedInferenceProfiles(): void {
87
+ const defaultConfigMerge = mergeDefaultWorkspaceConfig();
88
+ seedInferenceProfiles({
89
+ preserveProfileNames: defaultConfigMerge.providedLlmProfileNames,
90
+ preserveActiveProfile: defaultConfigMerge.providedLlmActiveProfile,
91
+ });
92
+ }
93
+
83
94
  // ---------------------------------------------------------------------------
84
95
  // Tests: deepMergeOverwrite (unit) — JSON-null-as-deletion semantics
85
96
  //
@@ -274,6 +285,8 @@ describe("loadConfig startup behavior", () => {
274
285
  ensureTestDir();
275
286
  const resetPaths = [
276
287
  CONFIG_PATH,
288
+ join(WORKSPACE_DIR, "default-config.json"),
289
+ join(WORKSPACE_DIR, "hatch-overlay.json"),
277
290
  join(WORKSPACE_DIR, "keys.enc"),
278
291
  join(WORKSPACE_DIR, "data"),
279
292
  join(WORKSPACE_DIR, "data", "memory"),
@@ -295,11 +308,13 @@ describe("loadConfig startup behavior", () => {
295
308
  if (existsSync(updatesPath)) rmSync(updatesPath, { force: true });
296
309
  ensureTestDir();
297
310
  _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
311
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
298
312
  invalidateConfigCache();
299
313
  });
300
314
 
301
315
  afterEach(() => {
302
316
  _setStorePath(null);
317
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
303
318
  invalidateConfigCache();
304
319
  });
305
320
 
@@ -327,6 +342,21 @@ describe("loadConfig startup behavior", () => {
327
342
  expect(config.memory.v2.bm25_b).toBe(0.4);
328
343
  });
329
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");
350
+
351
+ writeConfig({
352
+ twilio: { accountSid: "AC_fresh_after_external_write" },
353
+ });
354
+
355
+ expect(loadConfig().twilio.accountSid).toBe(
356
+ "AC_fresh_after_external_write",
357
+ );
358
+ });
359
+
330
360
  test("still strips deprecated fields and rewrites", () => {
331
361
  // `warnAndStripDeprecatedFields` is a legitimate self-healing path:
332
362
  // it removes fields the schema no longer recognizes and persists the
@@ -376,6 +406,355 @@ describe("loadConfig startup behavior", () => {
376
406
  expect(raw.dataDir).toBeUndefined();
377
407
  });
378
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",
425
+ );
426
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
427
+
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",
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,
490
+ );
491
+ });
492
+
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
+ });
509
+
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;
517
+
518
+ mergeDefaultConfigAndSeedInferenceProfiles();
519
+
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");
524
+ });
525
+
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
+ });
557
+
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
+ });
564
+
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");
573
+ });
574
+
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);
593
+ writeConfig({
594
+ llm: {
595
+ default: { provider: "openai", model: "claude-opus-4-7" },
596
+ },
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
+
379
758
  test("still quarantines corrupt JSON", () => {
380
759
  // Corrupt-config quarantine is a recovery path: the broken file is
381
760
  // renamed to `config.json.corrupt-<ts>.json` and the daemon proceeds
@@ -358,6 +358,7 @@ describe("AssistantConfigSchema", () => {
358
358
  supersededItemRetentionMs: 30 * 24 * 60 * 60 * 1000,
359
359
  conversationRetentionDays: 0,
360
360
  llmRequestLogRetentionMs: 1 * 60 * 60 * 1000,
361
+ traceEventRetentionDays: 3,
361
362
  });
362
363
  });
363
364
 
@@ -37,6 +37,7 @@ describe("cleanupSettingsChanged", () => {
37
37
  supersededItemRetentionMs: 30 * 24 * 60 * 60 * 1000,
38
38
  conversationRetentionDays: 0,
39
39
  llmRequestLogRetentionMs: 1 * 24 * 60 * 60 * 1000,
40
+ traceEventRetentionDays: 3,
40
41
  };
41
42
 
42
43
  test("returns false when either side is undefined", () => {
@@ -128,11 +129,9 @@ mock.module("../util/logger.js", () => ({
128
129
  truncateForLog: (v: string) => v,
129
130
  }));
130
131
 
131
- // Simulate a config-cache layer: `diskConfig` is the on-disk value,
132
- // `cachedConfig` is what getConfig() returns until invalidateConfigCache()
133
- // is called. This matches the production behavior where getConfig() returns
134
- // a memoized value that only refreshes after explicit invalidation. Tests
135
- // mutate `diskConfig` to simulate a user writing a new config.json.
132
+ // Simulate a config-cache layer: `diskConfig` is the on-disk value and
133
+ // `cachedConfig` is the in-memory value returned by getConfig() when present.
134
+ // Tests mutate `diskConfig` to simulate a user writing a new config.json.
136
135
  interface TestConfig {
137
136
  memory: {
138
137
  enabled: boolean;
@@ -199,10 +198,6 @@ mock.module("../providers/registry.js", () => ({
199
198
  initializeProviders: async () => {},
200
199
  }));
201
200
 
202
- mock.module("../signals/bash.js", () => ({
203
- handleBashSignal: () => {},
204
- }));
205
-
206
201
  mock.module("../signals/cancel.js", () => ({
207
202
  handleCancelSignal: () => {},
208
203
  }));
@@ -252,6 +247,20 @@ describe("ConfigWatcher.refreshConfigFromSources cleanup throttle reset", () =>
252
247
  expect(resetCleanupScheduleThrottleCalls).toBe(1);
253
248
  });
254
249
 
250
+ test("resets throttle when the loader cache has already observed the disk change", async () => {
251
+ const watcher = new ConfigWatcher();
252
+ watcher.initFingerprint(diskConfig as never);
253
+
254
+ diskConfig = makeConfig({
255
+ llmRequestLogRetentionMs: 7 * 24 * 60 * 60 * 1000,
256
+ });
257
+ cachedConfig = null;
258
+
259
+ const changed = await watcher.refreshConfigFromSources();
260
+ expect(changed).toBe(true);
261
+ expect(resetCleanupScheduleThrottleCalls).toBe(1);
262
+ });
263
+
255
264
  test("does NOT reset throttle when config is identical (no fingerprint change)", async () => {
256
265
  const watcher = new ConfigWatcher();
257
266
  watcher.initFingerprint(diskConfig as never);