@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
@@ -1,12 +1,17 @@
1
1
  /**
2
2
  * Tests for `assistant/src/memory/v2/skill-store.ts`.
3
3
  *
4
- * Coverage matrix from PR 5 acceptance criteria:
4
+ * Coverage matrix:
5
5
  * - `seedV2SkillEntries` enumerates the catalog and calls
6
- * `upsertSkillEmbedding` for each enabled skill.
6
+ * `upsertConceptPageEmbedding` with `slug: "skills/<id>"` for each
7
+ * enabled skill in the unified `memory_v2_concept_pages` collection.
7
8
  * - It skips skills whose declared feature flag is disabled.
8
- * - It calls `pruneSkillsExcept` with the active id list.
9
- * - It populates the `entries` cache so `getSkillCapability` returns each entry.
9
+ * - It calls `pruneSlugsWithPrefixExcept("skills/", ...)` with the active
10
+ * id list as suffixes, so stale skill slugs in the unified collection
11
+ * get pruned without touching concept-page slugs.
12
+ * - It populates the `entries` cache so `getSkillCapability` returns each
13
+ * entry — accepting both bare ids (`"example-skill"`) and unified-collection
14
+ * slugs (`"skills/example-skill"`).
10
15
  * - It swallows errors from the embedding backend — the function resolves
11
16
  * and the cache is unchanged from prior state.
12
17
  *
@@ -29,6 +34,18 @@ mock.module("../../../util/logger.js", () => ({
29
34
  // Programmable test state — drives every mocked dependency below.
30
35
  // ---------------------------------------------------------------------------
31
36
 
37
+ interface UpsertCall {
38
+ slug: string;
39
+ dense: number[];
40
+ sparse: { indices: number[]; values: number[] };
41
+ updatedAt: number;
42
+ }
43
+
44
+ interface PruneCall {
45
+ prefix: string;
46
+ activeSuffixes: readonly string[];
47
+ }
48
+
32
49
  interface TestState {
33
50
  catalog: SkillSummary[];
34
51
  resolved: ResolvedSkill[];
@@ -38,14 +55,8 @@ interface TestState {
38
55
  embedThrows: Error | null;
39
56
  embedReturn: number[][];
40
57
  sparseReturn: { indices: number[]; values: number[] };
41
- upsertCalls: Array<{
42
- id: string;
43
- content: string;
44
- dense: number[];
45
- sparse: { indices: number[]; values: number[] };
46
- updatedAt: number;
47
- }>;
48
- pruneCalls: Array<readonly string[]>;
58
+ upsertCalls: UpsertCall[];
59
+ pruneCalls: PruneCall[];
49
60
  upsertThrows: Error | null;
50
61
  }
51
62
 
@@ -99,13 +110,16 @@ mock.module("../../embedding-backend.js", () => ({
99
110
  generateSparseEmbedding: () => state.sparseReturn,
100
111
  }));
101
112
 
102
- mock.module("../skill-qdrant.js", () => ({
103
- upsertSkillEmbedding: async (params: TestState["upsertCalls"][number]) => {
113
+ mock.module("../qdrant.js", () => ({
114
+ upsertConceptPageEmbedding: async (params: UpsertCall) => {
104
115
  if (state.upsertThrows) throw state.upsertThrows;
105
116
  state.upsertCalls.push(params);
106
117
  },
107
- pruneSkillsExcept: async (ids: readonly string[]) => {
108
- state.pruneCalls.push(ids);
118
+ pruneSlugsWithPrefixExcept: async (
119
+ prefix: string,
120
+ activeSuffixes: readonly string[],
121
+ ) => {
122
+ state.pruneCalls.push({ prefix, activeSuffixes });
109
123
  },
110
124
  }));
111
125
 
@@ -160,7 +174,7 @@ afterEach(resetState);
160
174
  // ---------------------------------------------------------------------------
161
175
 
162
176
  describe("seedV2SkillEntries", () => {
163
- test("enumerates the catalog and upserts one point per enabled skill", async () => {
177
+ test("upserts each enabled skill into the unified collection under skills/<id>", async () => {
164
178
  const skillA = makeSummary({
165
179
  id: "example-skill-a",
166
180
  displayName: "Skill A",
@@ -182,15 +196,16 @@ describe("seedV2SkillEntries", () => {
182
196
  await seedV2SkillEntries();
183
197
 
184
198
  expect(state.upsertCalls).toHaveLength(2);
185
- const ids = state.upsertCalls.map((c) => c.id).sort();
186
- expect(ids).toEqual(["example-skill-a", "example-skill-b"]);
187
-
188
- // Each upsert carries the per-skill dense + sparse + content payload.
189
- const callA = state.upsertCalls.find((c) => c.id === "example-skill-a")!;
199
+ const slugs = state.upsertCalls.map((c) => c.slug).sort();
200
+ expect(slugs).toEqual(["skills/example-skill-a", "skills/example-skill-b"]);
201
+
202
+ // Each upsert carries the per-skill dense + sparse + updatedAt payload,
203
+ // keyed under the unified `skills/<id>` slug.
204
+ const callA = state.upsertCalls.find(
205
+ (c) => c.slug === "skills/example-skill-a",
206
+ )!;
190
207
  expect(callA.dense).toEqual([0.1, 0.2, 0.3]);
191
208
  expect(callA.sparse).toEqual(state.sparseReturn);
192
- expect(callA.content).toContain("Skill A");
193
- expect(callA.content).toContain("(example-skill-a)");
194
209
  expect(callA.updatedAt).toBeGreaterThan(0);
195
210
  });
196
211
 
@@ -207,12 +222,11 @@ describe("seedV2SkillEntries", () => {
207
222
  await seedV2SkillEntries();
208
223
 
209
224
  expect(state.upsertCalls).toHaveLength(1);
210
- expect(state.upsertCalls[0].id).toBe("example-skill-a");
225
+ expect(state.upsertCalls[0].slug).toBe("skills/example-skill-a");
211
226
  });
212
227
 
213
228
  test("does not re-seed an installed-but-disabled skill from the remote catalog", async () => {
214
- // Regression for https://github.com/vellum-ai/vellum-assistant/pull/28635
215
- // (Codex P1): if `seenIds` is built only from enabled skills, a locally
229
+ // Regression: if `seenIds` is built only from enabled skills, a locally
216
230
  // installed-but-disabled skill falls through to the catalog loop and gets
217
231
  // embedded as if it were a discoverable uninstalled skill — contradicting
218
232
  // the user's explicit disablement.
@@ -223,8 +237,6 @@ describe("seedV2SkillEntries", () => {
223
237
  { summary: enabledSkill, state: "enabled" },
224
238
  { summary: disabledSkill, state: "disabled" },
225
239
  ];
226
- // The remote catalog also contains the disabled skill (same id) — the
227
- // seed function must NOT pull it back in via `getCatalog()`.
228
240
  state.fullCatalog = [
229
241
  {
230
242
  id: "example-skill-b",
@@ -237,7 +249,7 @@ describe("seedV2SkillEntries", () => {
237
249
  await seedV2SkillEntries();
238
250
 
239
251
  expect(state.upsertCalls).toHaveLength(1);
240
- expect(state.upsertCalls[0].id).toBe("example-skill-a");
252
+ expect(state.upsertCalls[0].slug).toBe("skills/example-skill-a");
241
253
  });
242
254
 
243
255
  test("seeds genuinely uninstalled catalog skills alongside enabled installed skills", async () => {
@@ -263,8 +275,11 @@ describe("seedV2SkillEntries", () => {
263
275
 
264
276
  await seedV2SkillEntries();
265
277
 
266
- const ids = state.upsertCalls.map((c) => c.id).sort();
267
- expect(ids).toEqual(["example-skill-a", "uninstalled-skill"]);
278
+ const slugs = state.upsertCalls.map((c) => c.slug).sort();
279
+ expect(slugs).toEqual([
280
+ "skills/example-skill-a",
281
+ "skills/uninstalled-skill",
282
+ ]);
268
283
  });
269
284
 
270
285
  test("skips skills whose declared feature flag is disabled", async () => {
@@ -284,10 +299,10 @@ describe("seedV2SkillEntries", () => {
284
299
  await seedV2SkillEntries();
285
300
 
286
301
  expect(state.upsertCalls).toHaveLength(1);
287
- expect(state.upsertCalls[0].id).toBe("example-skill-b");
302
+ expect(state.upsertCalls[0].slug).toBe("skills/example-skill-b");
288
303
  });
289
304
 
290
- test("calls pruneSkillsExcept with the active id list", async () => {
305
+ test("calls pruneSlugsWithPrefixExcept with the active id list and the skills/ prefix", async () => {
291
306
  const skillA = makeSummary({ id: "example-skill-a" });
292
307
  const skillB = makeSummary({ id: "example-skill-b" });
293
308
  state.catalog = [skillA, skillB];
@@ -309,13 +324,14 @@ describe("seedV2SkillEntries", () => {
309
324
  await seedV2SkillEntries();
310
325
 
311
326
  expect(state.pruneCalls).toHaveLength(1);
312
- expect([...state.pruneCalls[0]].sort()).toEqual([
327
+ expect(state.pruneCalls[0].prefix).toBe("skills/");
328
+ expect([...state.pruneCalls[0].activeSuffixes].sort()).toEqual([
313
329
  "example-skill-a",
314
330
  "example-skill-b",
315
331
  ]);
316
332
  });
317
333
 
318
- test("passes only the active (post-flag-filter) ids to pruneSkillsExcept", async () => {
334
+ test("passes only the active (post-flag-filter) ids to pruneSlugsWithPrefixExcept", async () => {
319
335
  const flagged = makeSummary({
320
336
  id: "example-skill-a",
321
337
  featureFlag: "off-flag",
@@ -327,8 +343,6 @@ describe("seedV2SkillEntries", () => {
327
343
  { summary: unflagged, state: "enabled" },
328
344
  ];
329
345
  state.flagsEnabled = { "off-flag": false };
330
- // Remote catalog must be non-empty so catalogAvailable is true and
331
- // pruning is not skipped.
332
346
  state.fullCatalog = [
333
347
  { id: "example-skill-a", name: "example-skill-a", description: "A" },
334
348
  { id: "example-skill-b", name: "example-skill-b", description: "B" },
@@ -338,44 +352,35 @@ describe("seedV2SkillEntries", () => {
338
352
  await seedV2SkillEntries();
339
353
 
340
354
  expect(state.pruneCalls).toHaveLength(1);
341
- expect([...state.pruneCalls[0]]).toEqual(["example-skill-b"]);
355
+ expect(state.pruneCalls[0].prefix).toBe("skills/");
356
+ expect([...state.pruneCalls[0].activeSuffixes]).toEqual([
357
+ "example-skill-b",
358
+ ]);
342
359
  });
343
360
 
344
- test("populates the entries cache so getSkillCapability returns each entry", async () => {
361
+ test("populates the entries cache so getSkillCapability resolves both bare id and unified slug", async () => {
345
362
  const skillA = makeSummary({
346
363
  id: "example-skill-a",
347
364
  displayName: "Skill A",
348
365
  });
349
- const skillB = makeSummary({
350
- id: "example-skill-b",
351
- displayName: "Skill B",
352
- });
353
- state.catalog = [skillA, skillB];
354
- state.resolved = [
355
- { summary: skillA, state: "enabled" },
356
- { summary: skillB, state: "enabled" },
357
- ];
358
- state.embedReturn = [
359
- [0.1, 0.2, 0.3],
360
- [0.4, 0.5, 0.6],
361
- ];
366
+ state.catalog = [skillA];
367
+ state.resolved = [{ summary: skillA, state: "enabled" }];
368
+ state.embedReturn = [[0.1, 0.2, 0.3]];
362
369
 
363
370
  expect(getSkillCapability("example-skill-a")).toBeNull();
364
371
 
365
372
  await seedV2SkillEntries();
366
373
 
367
- const entryA = getSkillCapability("example-skill-a");
368
- const entryB = getSkillCapability("example-skill-b");
369
- expect(entryA).not.toBeNull();
370
- expect(entryA?.id).toBe("example-skill-a");
371
- expect(entryA?.content).toContain("Skill A");
372
-
373
- expect(entryB).not.toBeNull();
374
- expect(entryB?.id).toBe("example-skill-b");
375
- expect(entryB?.content).toContain("Skill B");
374
+ // Bare id and unified-slug forms both resolve to the same entry.
375
+ const byId = getSkillCapability("example-skill-a");
376
+ const bySlug = getSkillCapability("skills/example-skill-a");
377
+ expect(byId).not.toBeNull();
378
+ expect(byId?.id).toBe("example-skill-a");
379
+ expect(byId?.content).toContain("Skill A");
380
+ expect(bySlug).toEqual(byId);
376
381
 
377
- // Unknown ids return null even when the cache is populated.
378
382
  expect(getSkillCapability("unknown-skill")).toBeNull();
383
+ expect(getSkillCapability("skills/unknown-skill")).toBeNull();
379
384
  });
380
385
 
381
386
  test("swallows errors from embedWithBackend and leaves prior cache intact", async () => {
@@ -426,9 +431,10 @@ describe("seedV2SkillEntries", () => {
426
431
  await seedV2SkillEntries();
427
432
 
428
433
  expect(state.upsertCalls).toHaveLength(1);
429
- expect(state.upsertCalls[0].id).toBe("remote-only");
434
+ expect(state.upsertCalls[0].slug).toBe("skills/remote-only");
430
435
  expect(state.pruneCalls).toHaveLength(1);
431
- expect([...state.pruneCalls[0]]).toEqual(["remote-only"]);
436
+ expect(state.pruneCalls[0].prefix).toBe("skills/");
437
+ expect([...state.pruneCalls[0].activeSuffixes]).toEqual(["remote-only"]);
432
438
  });
433
439
 
434
440
  test("skips pruning when catalog fetch returns empty (network failure guard)", async () => {
@@ -49,7 +49,8 @@ mock.module("../../../config/loader.js", () => ({
49
49
 
50
50
  const { _setOverridesForTesting } =
51
51
  await import("../../../config/assistant-feature-flags.js");
52
- const { readMemoryV2StaticContent } = await import("../static-context.js");
52
+ const { readMemoryV2StaticContent, shouldLoadMemoryV2Static } =
53
+ await import("../static-context.js");
53
54
 
54
55
  const MEMORY_FILES = [
55
56
  "essentials.md",
@@ -150,3 +151,77 @@ describe("readMemoryV2StaticContent", () => {
150
151
  expect(readMemoryV2StaticContent()).toBeNull();
151
152
  });
152
153
  });
154
+
155
+ describe("shouldLoadMemoryV2Static", () => {
156
+ test("blocks all turns until the cadence gate fires", () => {
157
+ expect(
158
+ shouldLoadMemoryV2Static({
159
+ shouldInjectNowAndPkb: false,
160
+ sourceChannel: "vellum",
161
+ isTrustedActor: true,
162
+ }),
163
+ ).toBe(false);
164
+ });
165
+
166
+ test("allows guardian-trusted local conversations", () => {
167
+ expect(
168
+ shouldLoadMemoryV2Static({
169
+ shouldInjectNowAndPkb: true,
170
+ sourceChannel: "vellum",
171
+ isTrustedActor: true,
172
+ }),
173
+ ).toBe(true);
174
+ });
175
+
176
+ test("allows local-channel conversations even when trust class is unknown (analyze runs, dev)", () => {
177
+ expect(
178
+ shouldLoadMemoryV2Static({
179
+ shouldInjectNowAndPkb: true,
180
+ sourceChannel: "vellum",
181
+ isTrustedActor: false,
182
+ }),
183
+ ).toBe(true);
184
+ });
185
+
186
+ test("allows turns with no trust context (work-item task runs, internal background)", () => {
187
+ expect(
188
+ shouldLoadMemoryV2Static({
189
+ shouldInjectNowAndPkb: true,
190
+ sourceChannel: undefined,
191
+ isTrustedActor: false,
192
+ }),
193
+ ).toBe(true);
194
+ });
195
+
196
+ const REMOTE_CHANNELS = [
197
+ "phone",
198
+ "slack",
199
+ "telegram",
200
+ "whatsapp",
201
+ "email",
202
+ ] as const;
203
+
204
+ test("allows guardian-trusted remote channels (user's own phone/Slack)", () => {
205
+ for (const channel of REMOTE_CHANNELS) {
206
+ expect(
207
+ shouldLoadMemoryV2Static({
208
+ shouldInjectNowAndPkb: true,
209
+ sourceChannel: channel,
210
+ isTrustedActor: true,
211
+ }),
212
+ ).toBe(true);
213
+ }
214
+ });
215
+
216
+ test("blocks non-guardian remote-channel actors (the leak this gate exists to prevent)", () => {
217
+ for (const channel of REMOTE_CHANNELS) {
218
+ expect(
219
+ shouldLoadMemoryV2Static({
220
+ shouldInjectNowAndPkb: true,
221
+ sourceChannel: channel,
222
+ isTrustedActor: false,
223
+ }),
224
+ ).toBe(false);
225
+ }
226
+ });
227
+ });