@vellumai/assistant 0.6.5 → 0.6.6

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 (443) hide show
  1. package/AGENTS.md +9 -1
  2. package/ARCHITECTURE.md +15 -17
  3. package/Dockerfile +6 -4
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
  5. package/docs/architecture/integrations.md +32 -39
  6. package/docs/architecture/memory.md +25 -30
  7. package/docs/architecture/security.md +7 -6
  8. package/docs/browser-use-architecture-phase2.md +63 -20
  9. package/docs/plugins.md +761 -0
  10. package/examples/plugins/echo/README.md +132 -0
  11. package/examples/plugins/echo/package.json +17 -0
  12. package/examples/plugins/echo/register.ts +187 -0
  13. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  14. package/openapi.yaml +212 -68
  15. package/package.json +1 -1
  16. package/src/__tests__/app-compiler.test.ts +57 -0
  17. package/src/__tests__/approval-cascade.test.ts +7 -2
  18. package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
  19. package/src/__tests__/avatar-generator.test.ts +4 -2
  20. package/src/__tests__/bundled-asset.test.ts +6 -6
  21. package/src/__tests__/catalog-cache.test.ts +69 -0
  22. package/src/__tests__/checker.test.ts +459 -171
  23. package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
  24. package/src/__tests__/compaction-events.test.ts +501 -0
  25. package/src/__tests__/compaction-pipeline.test.ts +210 -0
  26. package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
  27. package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
  28. package/src/__tests__/config-model-image-provider.test.ts +110 -0
  29. package/src/__tests__/config-schema.test.ts +22 -9
  30. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
  31. package/src/__tests__/contacts-tools.test.ts +26 -0
  32. package/src/__tests__/context-overflow-policy.test.ts +7 -7
  33. package/src/__tests__/context-window-manager.test.ts +355 -4
  34. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  35. package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
  36. package/src/__tests__/conversation-agent-loop.test.ts +30 -141
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
  38. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
  40. package/src/__tests__/conversation-pairing.test.ts +174 -10
  41. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
  42. package/src/__tests__/conversation-process-callsite.test.ts +3 -0
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
  44. package/src/__tests__/conversation-queue.test.ts +29 -14
  45. package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
  47. package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
  48. package/src/__tests__/conversation-seed-composer.test.ts +2 -2
  49. package/src/__tests__/conversation-slash-queue.test.ts +7 -2
  50. package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
  51. package/src/__tests__/conversation-speed-override.test.ts +6 -1
  52. package/src/__tests__/conversation-title-service.test.ts +116 -0
  53. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
  54. package/src/__tests__/conversation-usage.test.ts +1 -1
  55. package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
  56. package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
  57. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
  58. package/src/__tests__/credential-health-service.test.ts +78 -9
  59. package/src/__tests__/credential-security-invariants.test.ts +2 -2
  60. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  61. package/src/__tests__/empty-response-pipeline.test.ts +305 -0
  62. package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
  63. package/src/__tests__/first-greeting.test.ts +247 -5
  64. package/src/__tests__/headless-browser-mode.test.ts +57 -0
  65. package/src/__tests__/history-repair-pipeline.test.ts +399 -0
  66. package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
  67. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
  68. package/src/__tests__/host-proxy-interface.test.ts +36 -2
  69. package/src/__tests__/image-credentials.test.ts +137 -0
  70. package/src/__tests__/image-service-dispatcher.test.ts +186 -0
  71. package/src/__tests__/injector-chain.test.ts +526 -0
  72. package/src/__tests__/intent-routing.test.ts +0 -26
  73. package/src/__tests__/llm-call-pipeline.test.ts +285 -0
  74. package/src/__tests__/llm-schema.test.ts +1 -1
  75. package/src/__tests__/media-generate-image.test.ts +119 -13
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
  77. package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
  78. package/src/__tests__/migration-import-from-url.test.ts +5 -68
  79. package/src/__tests__/model-intents.test.ts +4 -2
  80. package/src/__tests__/notification-broadcaster.test.ts +3 -3
  81. package/src/__tests__/notification-decision-strategy.test.ts +0 -11
  82. package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
  83. package/src/__tests__/oauth-apps-routes.test.ts +1 -1
  84. package/src/__tests__/oauth-cli.test.ts +14 -12
  85. package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
  86. package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
  87. package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
  88. package/src/__tests__/oauth-providers-routes.test.ts +3 -2
  89. package/src/__tests__/oauth-store.test.ts +41 -76
  90. package/src/__tests__/onboarding-template-contract.test.ts +16 -64
  91. package/src/__tests__/openai-image-service.test.ts +368 -0
  92. package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
  93. package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
  94. package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
  95. package/src/__tests__/persistence-pipeline.test.ts +377 -0
  96. package/src/__tests__/pipeline-runner.test.ts +565 -0
  97. package/src/__tests__/platform.test.ts +5 -2
  98. package/src/__tests__/plugin-bootstrap.test.ts +483 -0
  99. package/src/__tests__/plugin-registry.test.ts +273 -0
  100. package/src/__tests__/plugin-route-contribution.test.ts +288 -0
  101. package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
  102. package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
  103. package/src/__tests__/plugin-types.test.ts +320 -0
  104. package/src/__tests__/pricing.test.ts +44 -12
  105. package/src/__tests__/proxy-approval-callback.test.ts +69 -8
  106. package/src/__tests__/reaction-persistence.test.ts +1 -0
  107. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  108. package/src/__tests__/registry.test.ts +0 -2
  109. package/src/__tests__/schedule-routes.test.ts +131 -1
  110. package/src/__tests__/scheduler-recurrence.test.ts +14 -70
  111. package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
  112. package/src/__tests__/secret-detection-handler.test.ts +0 -10
  113. package/src/__tests__/shell-identity.test.ts +0 -134
  114. package/src/__tests__/suggestion-routes.test.ts +103 -4
  115. package/src/__tests__/task-memory-cleanup.test.ts +1 -0
  116. package/src/__tests__/task-scheduler.test.ts +3 -15
  117. package/src/__tests__/test-preload.ts +11 -0
  118. package/src/__tests__/title-generate-pipeline.test.ts +224 -0
  119. package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
  120. package/src/__tests__/tool-error-pipeline.test.ts +244 -0
  121. package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
  122. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
  123. package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
  124. package/src/__tests__/tool-executor.test.ts +141 -0
  125. package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
  126. package/src/__tests__/tool-result-truncation.test.ts +0 -110
  127. package/src/__tests__/user-plugin-loader.test.ts +191 -0
  128. package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
  129. package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
  130. package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
  131. package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
  132. package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
  133. package/src/__tests__/workspace-policy.test.ts +21 -3
  134. package/src/agent/loop.ts +340 -102
  135. package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
  136. package/src/approvals/guardian-request-resolvers.ts +80 -0
  137. package/src/backup/__tests__/backup-worker.test.ts +2 -13
  138. package/src/backup/backup-worker.ts +3 -15
  139. package/src/bundler/app-compiler.ts +84 -1
  140. package/src/calls/call-state.ts +2 -2
  141. package/src/channels/__tests__/types.test.ts +3 -3
  142. package/src/channels/types.ts +6 -4
  143. package/src/cli/__tests__/notifications.test.ts +87 -211
  144. package/src/cli/commands/__tests__/backup.test.ts +1 -1
  145. package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
  146. package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
  147. package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
  148. package/src/cli/commands/backup.ts +2 -2
  149. package/src/cli/commands/clients.ts +138 -0
  150. package/src/cli/commands/completions.ts +2 -9
  151. package/src/cli/commands/conversations.ts +55 -7
  152. package/src/cli/commands/image-generation.ts +33 -34
  153. package/src/cli/commands/notifications.ts +68 -103
  154. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
  155. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  156. package/src/cli/commands/oauth/connect.ts +2 -2
  157. package/src/cli/commands/oauth/providers.ts +176 -8
  158. package/src/cli/commands/oauth/status.ts +46 -36
  159. package/src/cli/commands/skills.ts +3 -4
  160. package/src/cli/program.ts +25 -29
  161. package/src/config/__tests__/backup-schema.test.ts +7 -2
  162. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  163. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
  164. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
  165. package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
  166. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
  167. package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
  168. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
  169. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
  170. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  171. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
  172. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
  174. package/src/config/bundled-skills/schedule/SKILL.md +8 -3
  175. package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
  176. package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
  177. package/src/config/bundled-tool-registry.ts +0 -15
  178. package/src/config/feature-flag-registry.json +17 -1
  179. package/src/config/schema.ts +19 -0
  180. package/src/config/schemas/backup.ts +1 -1
  181. package/src/config/schemas/conversations.ts +16 -0
  182. package/src/config/schemas/llm.ts +2 -3
  183. package/src/config/schemas/security.ts +6 -6
  184. package/src/config/schemas/tts.ts +11 -0
  185. package/src/config/skill-state.ts +6 -2
  186. package/src/config/skills.ts +94 -5
  187. package/src/context/__tests__/compact-prompt.test.ts +27 -9
  188. package/src/context/prompts/compact.md +26 -12
  189. package/src/context/tool-result-truncation.ts +3 -63
  190. package/src/context/window-manager.ts +190 -16
  191. package/src/credential-health/credential-health-service.ts +19 -6
  192. package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
  193. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
  194. package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
  195. package/src/daemon/config-watcher.ts +0 -2
  196. package/src/daemon/context-overflow-policy.ts +4 -13
  197. package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
  198. package/src/daemon/conversation-agent-loop.ts +984 -683
  199. package/src/daemon/conversation-history.ts +10 -19
  200. package/src/daemon/conversation-lifecycle.ts +37 -19
  201. package/src/daemon/conversation-notifiers.ts +2 -110
  202. package/src/daemon/conversation-process.ts +14 -7
  203. package/src/daemon/conversation-runtime-assembly.ts +532 -411
  204. package/src/daemon/conversation-tool-setup.ts +41 -4
  205. package/src/daemon/conversation.ts +80 -35
  206. package/src/daemon/external-plugins-bootstrap.ts +478 -0
  207. package/src/daemon/first-greeting.ts +191 -14
  208. package/src/daemon/handlers/config-model.ts +11 -0
  209. package/src/daemon/handlers/skills.ts +5 -1
  210. package/src/daemon/lifecycle.ts +33 -68
  211. package/src/daemon/message-types/computer-use.ts +2 -34
  212. package/src/daemon/message-types/conversations.ts +49 -0
  213. package/src/daemon/message-types/messages.ts +12 -0
  214. package/src/daemon/server.ts +5 -3
  215. package/src/daemon/shutdown-handlers.ts +2 -12
  216. package/src/daemon/tool-side-effects.ts +14 -56
  217. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
  218. package/src/heartbeat/heartbeat-service.ts +24 -1
  219. package/src/home/__tests__/feed-population-integration.test.ts +312 -0
  220. package/src/home/emit-feed-event.ts +7 -0
  221. package/src/home/feed-types.ts +41 -2
  222. package/src/home/rewrite-command-preview.ts +66 -0
  223. package/src/ipc/__tests__/socket-path.test.ts +11 -50
  224. package/src/ipc/cli-client.ts +1 -1
  225. package/src/ipc/cli-server.ts +3 -3
  226. package/src/ipc/gateway-client.ts +4 -1
  227. package/src/ipc/routes/browser-context.ts +2 -0
  228. package/src/ipc/routes/browser.ts +1 -0
  229. package/src/ipc/routes/get-contact.ts +16 -0
  230. package/src/ipc/routes/index.ts +14 -0
  231. package/src/ipc/routes/list-clients.ts +31 -0
  232. package/src/ipc/routes/merge-contacts.ts +17 -0
  233. package/src/ipc/routes/notification.ts +133 -0
  234. package/src/ipc/routes/rename-conversation.ts +59 -0
  235. package/src/ipc/routes/search-contacts.ts +19 -0
  236. package/src/ipc/routes/upsert-contact.ts +25 -0
  237. package/src/ipc/socket-path.ts +14 -38
  238. package/src/media/app-icon-generator.ts +23 -46
  239. package/src/media/avatar-router.ts +26 -41
  240. package/src/media/gemini-image-service.ts +8 -41
  241. package/src/media/image-credentials.ts +73 -0
  242. package/src/media/image-service.ts +85 -0
  243. package/src/media/openai-image-service.ts +131 -0
  244. package/src/media/types.ts +46 -0
  245. package/src/memory/conversation-crud.ts +48 -18
  246. package/src/memory/conversation-queries.ts +57 -4
  247. package/src/memory/conversation-title-service.ts +25 -0
  248. package/src/memory/db-init.ts +8 -0
  249. package/src/memory/embedding-gemini.test.ts +41 -2
  250. package/src/memory/embedding-gemini.ts +6 -1
  251. package/src/memory/graph/bootstrap.test.ts +282 -0
  252. package/src/memory/graph/bootstrap.ts +8 -5
  253. package/src/memory/graph/extraction.ts +10 -2
  254. package/src/memory/graph/graph-search.test.ts +1 -0
  255. package/src/memory/graph/inspect.ts +2 -2
  256. package/src/memory/graph/retriever.ts +10 -3
  257. package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
  258. package/src/memory/migrations/149-oauth-tables.ts +1 -0
  259. package/src/memory/migrations/223-schedule-script-column.ts +11 -0
  260. package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
  261. package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
  262. package/src/memory/migrations/index.ts +4 -0
  263. package/src/memory/pkb/pkb-index.test.ts +1 -0
  264. package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
  265. package/src/memory/pkb/pkb-search.test.ts +65 -4
  266. package/src/memory/pkb/pkb-search.ts +40 -18
  267. package/src/memory/qdrant-client.test.ts +60 -0
  268. package/src/memory/qdrant-client.ts +25 -0
  269. package/src/memory/schema/infrastructure.ts +1 -0
  270. package/src/memory/schema/oauth.ts +4 -1
  271. package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
  272. package/src/messaging/providers/slack/render-transcript.ts +58 -0
  273. package/src/notifications/conversation-pairing.ts +78 -19
  274. package/src/notifications/copy-composer.ts +0 -5
  275. package/src/notifications/emit-signal.ts +1 -1
  276. package/src/notifications/signal.ts +1 -2
  277. package/src/oauth/AGENTS.md +1 -1
  278. package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
  279. package/src/oauth/connect-orchestrator.ts +8 -34
  280. package/src/oauth/connect-types.ts +6 -10
  281. package/src/oauth/manual-token-connection.ts +23 -0
  282. package/src/oauth/oauth-store.ts +30 -14
  283. package/src/oauth/provider-serializer.ts +6 -1
  284. package/src/oauth/seed-providers.ts +56 -108
  285. package/src/outbound-proxy/http-forwarder.ts +9 -0
  286. package/src/permissions/approval-policy.test.ts +293 -18
  287. package/src/permissions/approval-policy.ts +110 -58
  288. package/src/permissions/arg-parser.test.ts +161 -0
  289. package/src/permissions/arg-parser.ts +141 -0
  290. package/src/permissions/bash-risk-classifier.test.ts +414 -2
  291. package/src/permissions/bash-risk-classifier.ts +303 -60
  292. package/src/permissions/checker.ts +157 -29
  293. package/src/permissions/command-registry.test.ts +239 -0
  294. package/src/permissions/command-registry.ts +234 -54
  295. package/src/permissions/defaults.ts +5 -4
  296. package/src/permissions/gateway-threshold-reader.ts +196 -0
  297. package/src/permissions/prompter.ts +4 -0
  298. package/src/permissions/risk-types.ts +61 -4
  299. package/src/permissions/schedule-risk-classifier.test.ts +129 -0
  300. package/src/permissions/schedule-risk-classifier.ts +85 -0
  301. package/src/permissions/shell-identity.ts +2 -42
  302. package/src/permissions/types.ts +2 -0
  303. package/src/permissions/workspace-policy.ts +8 -3
  304. package/src/plugins/defaults/circuit-breaker.ts +146 -0
  305. package/src/plugins/defaults/compaction.ts +145 -0
  306. package/src/plugins/defaults/empty-response.ts +126 -0
  307. package/src/plugins/defaults/history-repair.ts +85 -0
  308. package/src/plugins/defaults/index.ts +116 -0
  309. package/src/plugins/defaults/injectors.ts +491 -0
  310. package/src/plugins/defaults/llm-call.ts +82 -0
  311. package/src/plugins/defaults/memory-retrieval.ts +226 -0
  312. package/src/plugins/defaults/overflow-reduce.ts +181 -0
  313. package/src/plugins/defaults/persistence.ts +129 -0
  314. package/src/plugins/defaults/title-generate.ts +95 -0
  315. package/src/plugins/defaults/token-estimate.ts +104 -0
  316. package/src/plugins/defaults/tool-error.ts +126 -0
  317. package/src/plugins/defaults/tool-execute.ts +89 -0
  318. package/src/plugins/defaults/tool-result-truncate.ts +88 -0
  319. package/src/plugins/pipeline.ts +316 -0
  320. package/src/plugins/plugin-skill-contributions.ts +292 -0
  321. package/src/plugins/registry.ts +241 -0
  322. package/src/plugins/types.ts +1134 -0
  323. package/src/plugins/user-loader.ts +177 -0
  324. package/src/prompts/templates/BOOTSTRAP.md +27 -77
  325. package/src/providers/model-catalog.ts +52 -29
  326. package/src/providers/model-intents.ts +1 -1
  327. package/src/providers/openrouter/client.ts +5 -1
  328. package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
  329. package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
  330. package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
  331. package/src/providers/speech-to-text/xai-realtime.ts +39 -14
  332. package/src/runtime/AGENTS.md +25 -16
  333. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
  334. package/src/runtime/__tests__/client-registry.test.ts +293 -0
  335. package/src/runtime/client-registry.ts +261 -0
  336. package/src/runtime/http-server.ts +77 -8
  337. package/src/runtime/http-types.ts +0 -2
  338. package/src/runtime/migrations/vbundle-builder.ts +1 -22
  339. package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
  340. package/src/runtime/routes/approval-routes.ts +17 -0
  341. package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
  342. package/src/runtime/routes/conversation-routes.ts +223 -116
  343. package/src/runtime/routes/inbound-message-handler.ts +88 -13
  344. package/src/runtime/routes/memory-item-routes.test.ts +1 -0
  345. package/src/runtime/routes/migration-routes.ts +0 -3
  346. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
  347. package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
  348. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
  349. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
  350. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
  351. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
  352. package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
  353. package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
  354. package/src/runtime/routes/playground/deps.ts +56 -0
  355. package/src/runtime/routes/playground/force-compact.ts +73 -0
  356. package/src/runtime/routes/playground/guard.ts +37 -0
  357. package/src/runtime/routes/playground/index.ts +28 -0
  358. package/src/runtime/routes/playground/inject-failures.ts +159 -0
  359. package/src/runtime/routes/playground/reset-circuit.ts +115 -0
  360. package/src/runtime/routes/playground/seed-conversation.ts +139 -0
  361. package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
  362. package/src/runtime/routes/playground/state.ts +78 -0
  363. package/src/runtime/routes/schedule-routes.ts +89 -8
  364. package/src/runtime/skill-route-registry.ts +75 -15
  365. package/src/schedule/run-script.ts +68 -0
  366. package/src/schedule/schedule-store.ts +7 -1
  367. package/src/schedule/scheduler.ts +48 -8
  368. package/src/skills/catalog-cache.ts +12 -5
  369. package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
  370. package/src/tools/browser/browser-execution.ts +88 -19
  371. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
  372. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
  373. package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
  374. package/src/tools/browser/cdp-client/factory.ts +15 -4
  375. package/src/tools/executor.ts +126 -74
  376. package/src/tools/network/script-proxy/session-manager.ts +37 -1
  377. package/src/tools/permission-checker.ts +98 -49
  378. package/src/tools/policy-context.ts +4 -0
  379. package/src/tools/registry.ts +140 -3
  380. package/src/tools/schedule/create.ts +23 -8
  381. package/src/tools/schedule/update.ts +3 -1
  382. package/src/tools/secret-detection-handler.ts +0 -51
  383. package/src/tools/system/avatar-generator.ts +6 -2
  384. package/src/tools/types.ts +28 -2
  385. package/src/util/platform.ts +7 -2
  386. package/src/util/pricing.ts +26 -3
  387. package/src/workspace/migrations/006-services-config.ts +2 -4
  388. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
  389. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
  390. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
  391. package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
  392. package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
  393. package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
  394. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
  395. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
  396. package/src/workspace/migrations/registry.ts +12 -0
  397. package/tsconfig.json +1 -1
  398. package/hook-templates/debug-prompt-logger/hook.json +0 -7
  399. package/hook-templates/debug-prompt-logger/run.sh +0 -66
  400. package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
  401. package/src/__tests__/context-overflow-approval.test.ts +0 -156
  402. package/src/__tests__/hooks-blocking.test.ts +0 -178
  403. package/src/__tests__/hooks-cli.test.ts +0 -182
  404. package/src/__tests__/hooks-config.test.ts +0 -108
  405. package/src/__tests__/hooks-discovery.test.ts +0 -211
  406. package/src/__tests__/hooks-integration.test.ts +0 -196
  407. package/src/__tests__/hooks-manager.test.ts +0 -226
  408. package/src/__tests__/hooks-runner.test.ts +0 -175
  409. package/src/__tests__/hooks-settings.test.ts +0 -160
  410. package/src/__tests__/hooks-templates.test.ts +0 -169
  411. package/src/__tests__/hooks-ts-runner.test.ts +0 -170
  412. package/src/__tests__/hooks-watch.test.ts +0 -112
  413. package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
  414. package/src/__tests__/oauth-scope-policy.test.ts +0 -180
  415. package/src/__tests__/send-notification-tool.test.ts +0 -83
  416. package/src/cli/commands/shotgun.ts +0 -266
  417. package/src/config/bundled-skills/conversations/SKILL.md +0 -20
  418. package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
  419. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
  420. package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
  421. package/src/config/bundled-skills/notifications/SKILL.md +0 -40
  422. package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
  423. package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
  424. package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
  425. package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
  426. package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
  427. package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
  428. package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
  429. package/src/daemon/context-overflow-approval.ts +0 -52
  430. package/src/daemon/watch-handler.ts +0 -399
  431. package/src/hooks/cli.ts +0 -253
  432. package/src/hooks/config.ts +0 -100
  433. package/src/hooks/discovery.ts +0 -135
  434. package/src/hooks/manager.ts +0 -179
  435. package/src/hooks/runner.ts +0 -117
  436. package/src/hooks/templates.ts +0 -77
  437. package/src/hooks/types.ts +0 -75
  438. package/src/oauth/scope-policy.ts +0 -89
  439. package/src/runtime/gateway-internal-client.ts +0 -94
  440. package/src/runtime/routes/watch-routes.ts +0 -156
  441. package/src/signals/shotgun.ts +0 -203
  442. package/src/tools/watch/screen-watch.ts +0 -144
  443. package/src/tools/watch/watch-state.ts +0 -142
@@ -410,7 +410,7 @@ describe("GET /v1/suggestion", () => {
410
410
  expect(body.suggestion).toBe("sounds good");
411
411
  });
412
412
 
413
- test("passes prefill message, stop_sequences, and max_tokens", async () => {
413
+ test("passes stop_sequences, max_tokens, and XML-framed user prompt", async () => {
414
414
  const provider = makeMockProvider("on my way");
415
415
  mockGetConfiguredProvider.mockImplementation(async () => provider);
416
416
  mockGetConversationByKey.mockImplementation(() => ({
@@ -454,9 +454,8 @@ describe("GET /v1/suggestion", () => {
454
454
  };
455
455
  };
456
456
 
457
- expect(messages.length).toBe(2);
458
- expect(messages[1].role).toBe("assistant");
459
- expect(messages[1].content[0].text).toBe("<reply>");
457
+ expect(messages.length).toBe(1);
458
+ expect(messages[0].role).toBe("user");
460
459
  expect(options.config?.stop_sequences).toEqual(["</reply>"]);
461
460
  expect(options.config?.max_tokens).toBe(60);
462
461
  expect(messages[0].content[0].text).toContain("<assistant_message>");
@@ -568,4 +567,104 @@ describe("GET /v1/suggestion", () => {
568
567
  | undefined;
569
568
  expect(options?.config?.callSite).toBe("conversationStarters");
570
569
  });
570
+
571
+ test("does not send an assistant-role prefill message", async () => {
572
+ // Regression guard: Anthropic rejects assistant-message prefill
573
+ // whenever the request triggers extended thinking (e.g. Opus 4.x at
574
+ // `effort: "xhigh"`). The suggestion generator must only send a
575
+ // single user-role message so it stays compatible with every
576
+ // possible `conversationStarters` call-site config.
577
+ const provider = makeMockProvider("<reply>Sure, works for me</reply>");
578
+ mockGetConfiguredProvider.mockImplementation(async () => provider);
579
+ mockGetConversationByKey.mockImplementation(() => ({
580
+ conversationId: "conv-test",
581
+ }));
582
+ mockGetMessages.mockImplementation(() => [
583
+ {
584
+ id: "msg-asst-1",
585
+ conversationId: "conv-test",
586
+ role: "assistant",
587
+ content: JSON.stringify([
588
+ { type: "text", text: "Want to meet tomorrow?" },
589
+ ]),
590
+ createdAt: Date.now(),
591
+ metadata: null,
592
+ },
593
+ ]);
594
+
595
+ const url = makeUrl({ conversationKey: "test-key" });
596
+ const deps = makeDeps();
597
+ const response = await handleGetSuggestion(url, deps);
598
+
599
+ expect(provider.sendMessage).toHaveBeenCalledTimes(1);
600
+ const callArgs = provider.sendMessage.mock.calls[0] as unknown[];
601
+ const messages = callArgs[0] as Array<{ role: string }>;
602
+ expect(messages).toHaveLength(1);
603
+ expect(messages[0].role).toBe("user");
604
+ expect(messages.every((m) => m.role === "user")).toBe(true);
605
+
606
+ // Tag-wrapped response is extracted back to just the reply text.
607
+ const body = (await response.json()) as { suggestion: string | null };
608
+ expect(body.suggestion).toBe("Sure, works for me");
609
+ });
610
+
611
+ test("handles untagged model response by falling back to raw text", async () => {
612
+ // Some non-Anthropic models and some Anthropic configs drop the
613
+ // `<reply>…</reply>` wrapper entirely. The parser must still
614
+ // produce a usable suggestion from the raw text.
615
+ const provider = makeMockProvider("Sounds good to me");
616
+ mockGetConfiguredProvider.mockImplementation(async () => provider);
617
+ mockGetConversationByKey.mockImplementation(() => ({
618
+ conversationId: "conv-test",
619
+ }));
620
+ mockGetMessages.mockImplementation(() => [
621
+ {
622
+ id: "msg-asst-untagged",
623
+ conversationId: "conv-test",
624
+ role: "assistant",
625
+ content: JSON.stringify([
626
+ { type: "text", text: "Want to meet tomorrow?" },
627
+ ]),
628
+ createdAt: Date.now(),
629
+ metadata: null,
630
+ },
631
+ ]);
632
+
633
+ const url = makeUrl({ conversationKey: "test-key" });
634
+ const deps = makeDeps();
635
+ const response = await handleGetSuggestion(url, deps);
636
+
637
+ const body = (await response.json()) as { suggestion: string | null };
638
+ expect(body.suggestion).toBe("Sounds good to me");
639
+ });
640
+
641
+ test("extracts reply content when model adds preamble before tag", async () => {
642
+ // Without assistant-role prefill, nothing stops a chatty model from
643
+ // adding a preamble. The parser's tag-extraction step must take the
644
+ // `<reply>…</reply>` span and ignore surrounding commentary.
645
+ const provider = makeMockProvider(
646
+ "Here's a good option:\n\n<reply>Let's do it</reply>",
647
+ );
648
+ mockGetConfiguredProvider.mockImplementation(async () => provider);
649
+ mockGetConversationByKey.mockImplementation(() => ({
650
+ conversationId: "conv-test",
651
+ }));
652
+ mockGetMessages.mockImplementation(() => [
653
+ {
654
+ id: "msg-asst-preamble",
655
+ conversationId: "conv-test",
656
+ role: "assistant",
657
+ content: JSON.stringify([{ type: "text", text: "Ready to ship it?" }]),
658
+ createdAt: Date.now(),
659
+ metadata: null,
660
+ },
661
+ ]);
662
+
663
+ const url = makeUrl({ conversationKey: "test-key" });
664
+ const deps = makeDeps();
665
+ const response = await handleGetSuggestion(url, deps);
666
+
667
+ const body = (await response.json()) as { suggestion: string | null };
668
+ expect(body.suggestion).toBe("Let's do it");
669
+ });
571
670
  });
@@ -18,6 +18,7 @@ mock.module("../memory/qdrant-client.js", () => ({
18
18
  deletePoints: async () => {},
19
19
  }),
20
20
  initQdrantClient: () => {},
21
+ resolveQdrantUrl: () => "http://127.0.0.1:6333",
21
22
  }));
22
23
 
23
24
  const TEST_CONFIG = {
@@ -141,11 +141,7 @@ describe("scheduler run_task detection", () => {
141
141
  directCalls.push({ conversationId, message, options });
142
142
  };
143
143
 
144
- const scheduler = startScheduler(
145
- processMessage,
146
- () => {},
147
- () => {},
148
- );
144
+ const scheduler = startScheduler(processMessage, () => {});
149
145
 
150
146
  // Wait for the initial tick to complete
151
147
  await new Promise((resolve) => setTimeout(resolve, 500));
@@ -190,11 +186,7 @@ describe("scheduler run_task detection", () => {
190
186
  processedMessages.push({ conversationId, message, options });
191
187
  };
192
188
 
193
- const scheduler = startScheduler(
194
- processMessage,
195
- () => {},
196
- () => {},
197
- );
189
+ const scheduler = startScheduler(processMessage, () => {});
198
190
 
199
191
  await new Promise((resolve) => setTimeout(resolve, 500));
200
192
  scheduler.stop();
@@ -229,11 +221,7 @@ describe("scheduler run_task detection", () => {
229
221
  _message: string,
230
222
  ) => {};
231
223
 
232
- const scheduler = startScheduler(
233
- processMessage,
234
- () => {},
235
- () => {},
236
- );
224
+ const scheduler = startScheduler(processMessage, () => {});
237
225
 
238
226
  await new Promise((resolve) => setTimeout(resolve, 500));
239
227
  scheduler.stop();
@@ -20,10 +20,16 @@ import { installGatewayIpcMock } from "../__tests__/mock-gateway-ipc.js";
20
20
  import { resetDb } from "../memory/db-connection.js";
21
21
  import { _setStorePath } from "../security/encrypted-store.js";
22
22
 
23
+ const savedBaseDataDir = process.env.BASE_DATA_DIR;
24
+
23
25
  const testDir = realpathSync(
24
26
  mkdtempSync(join(tmpdir(), "vellum-test-workspace-")),
25
27
  );
26
28
  process.env.VELLUM_WORKSPACE_DIR = testDir;
29
+ // Also set BASE_DATA_DIR so that vellumRoot() (and all derived paths like
30
+ // getProtectedDir()) resolve under the temp dir. This gives each test file
31
+ // its own IPC socket path, preventing socket races between parallel files.
32
+ process.env.BASE_DATA_DIR = testDir;
27
33
  process.env.VELLUM_PLATFORM_URL = "https://test-platform.vellum.ai";
28
34
  process.exitCode = 0;
29
35
 
@@ -56,6 +62,11 @@ afterAll(() => {
56
62
  process.exitCode = 0;
57
63
  delete process.env.VELLUM_WORKSPACE_DIR;
58
64
  delete process.env.VELLUM_PLATFORM_URL;
65
+ if (savedBaseDataDir !== undefined) {
66
+ process.env.BASE_DATA_DIR = savedBaseDataDir;
67
+ } else {
68
+ delete process.env.BASE_DATA_DIR;
69
+ }
59
70
  if (savedIsContainerized !== undefined) {
60
71
  process.env.IS_CONTAINERIZED = savedIsContainerized;
61
72
  }
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Tests for the `titleGenerate` pipeline (PR 28).
3
+ *
4
+ * The title-generation side effect used to be a direct call to
5
+ * `queueGenerateConversationTitle` inside `conversation-agent-loop.ts`.
6
+ * After PR 28 the assistant routes that call through the plugin pipeline
7
+ * runner, giving plugins an opportunity to observe/replace the default
8
+ * implementation.
9
+ *
10
+ * Covers:
11
+ * - The default plugin's terminal delegates to
12
+ * `queueGenerateConversationTitle` with the same arguments the agent
13
+ * loop constructs.
14
+ * - A custom plugin can install a short-circuit middleware that replaces
15
+ * the terminal with a deterministic generator. The default terminal is
16
+ * NOT invoked in that case.
17
+ *
18
+ * Mocks `memory/conversation-title-service.js` so the tests don't touch
19
+ * the real provider stack, and resets the plugin registry between cases.
20
+ */
21
+
22
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
23
+
24
+ // Stub the title-generation service before importing anything that binds
25
+ // to it, so both the default plugin and the agent loop capture the
26
+ // stubbed binding.
27
+ const queueGenerateConversationTitleMock = mock(
28
+ (_params: {
29
+ conversationId: string;
30
+ provider?: unknown;
31
+ userMessage?: string;
32
+ onTitleUpdated?: (title: string) => void;
33
+ }): void => undefined,
34
+ );
35
+ mock.module("../memory/conversation-title-service.js", () => ({
36
+ queueGenerateConversationTitle: queueGenerateConversationTitleMock,
37
+ }));
38
+
39
+ import { defaultTitleGenerateTerminal } from "../plugins/defaults/title-generate.js";
40
+ import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
41
+ import {
42
+ getMiddlewaresFor,
43
+ registerPlugin,
44
+ resetPluginRegistryForTests,
45
+ } from "../plugins/registry.js";
46
+ import type {
47
+ Middleware,
48
+ Plugin,
49
+ TitleArgs,
50
+ TitleResult,
51
+ TurnContext,
52
+ } from "../plugins/types.js";
53
+
54
+ function makeCtx(overrides: Partial<TurnContext> = {}): TurnContext {
55
+ return {
56
+ requestId: "req-1",
57
+ conversationId: "conv-1",
58
+ turnIndex: 0,
59
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
60
+ ...overrides,
61
+ };
62
+ }
63
+
64
+ function makeArgs(overrides: Partial<TitleArgs> = {}): TitleArgs {
65
+ return {
66
+ conversationId: "conv-1",
67
+ userMessage: "hello world",
68
+ ...overrides,
69
+ };
70
+ }
71
+
72
+ describe("titleGenerate pipeline", () => {
73
+ beforeEach(() => {
74
+ resetPluginRegistryForTests();
75
+ queueGenerateConversationTitleMock.mockReset();
76
+ queueGenerateConversationTitleMock.mockImplementation(() => undefined);
77
+ // Re-register the default plugin after the registry reset so tests see
78
+ // the same shape the daemon sees at runtime.
79
+ registerPlugin({
80
+ manifest: {
81
+ name: "default-title-generate",
82
+ version: "1.0.0",
83
+ provides: { titleGenerate: "v1" },
84
+ requires: {
85
+ pluginRuntime: "v1",
86
+ titleGenerateApi: "v1",
87
+ },
88
+ },
89
+ });
90
+ });
91
+
92
+ test("default: pipeline terminal queues a title-generation job", async () => {
93
+ const ctx = makeCtx();
94
+ const onTitleUpdated = mock((_title: string) => undefined);
95
+ const args = makeArgs({
96
+ conversationId: "conv-1",
97
+ userMessage: "first message",
98
+ onTitleUpdated,
99
+ });
100
+
101
+ await runPipeline(
102
+ "titleGenerate",
103
+ getMiddlewaresFor("titleGenerate"),
104
+ defaultTitleGenerateTerminal,
105
+ args,
106
+ ctx,
107
+ DEFAULT_TIMEOUTS.titleGenerate,
108
+ );
109
+
110
+ // The default terminal must have delegated to queueGenerateConversationTitle
111
+ // with every argument the caller supplied, including the callback.
112
+ expect(queueGenerateConversationTitleMock).toHaveBeenCalledTimes(1);
113
+ const call = queueGenerateConversationTitleMock.mock.calls[0]?.[0];
114
+ expect(call?.conversationId).toBe("conv-1");
115
+ expect(call?.userMessage).toBe("first message");
116
+ expect(call?.onTitleUpdated).toBe(onTitleUpdated);
117
+ });
118
+
119
+ test("default: pipeline result is the empty object from the terminal", async () => {
120
+ const ctx = makeCtx();
121
+ const result = await runPipeline(
122
+ "titleGenerate",
123
+ getMiddlewaresFor("titleGenerate"),
124
+ defaultTitleGenerateTerminal,
125
+ makeArgs(),
126
+ ctx,
127
+ DEFAULT_TIMEOUTS.titleGenerate,
128
+ );
129
+ expect(result).toEqual({});
130
+ });
131
+
132
+ test("custom plugin: short-circuit middleware replaces the default with a deterministic generator", async () => {
133
+ // A custom plugin installs middleware that fabricates a title
134
+ // deterministically and never calls `next`, so the default terminal
135
+ // (which would delegate to queueGenerateConversationTitle) is
136
+ // skipped entirely.
137
+ const observedTitles: string[] = [];
138
+
139
+ const deterministicMw: Middleware<TitleArgs, TitleResult> = async (
140
+ args,
141
+ ) => {
142
+ const fabricated = `[deterministic] ${args.userMessage}`;
143
+ args.onTitleUpdated?.(fabricated);
144
+ observedTitles.push(fabricated);
145
+ return {};
146
+ };
147
+
148
+ const customPlugin: Plugin = {
149
+ manifest: {
150
+ name: "custom-deterministic-title",
151
+ version: "0.0.1",
152
+ requires: {
153
+ pluginRuntime: "v1",
154
+ titleGenerateApi: "v1",
155
+ },
156
+ },
157
+ middleware: { titleGenerate: deterministicMw },
158
+ };
159
+ registerPlugin(customPlugin);
160
+
161
+ const receivedTitle: string[] = [];
162
+ const args = makeArgs({
163
+ userMessage: "what is the weather",
164
+ onTitleUpdated: (title) => {
165
+ receivedTitle.push(title);
166
+ },
167
+ });
168
+
169
+ await runPipeline(
170
+ "titleGenerate",
171
+ getMiddlewaresFor("titleGenerate"),
172
+ defaultTitleGenerateTerminal,
173
+ args,
174
+ makeCtx(),
175
+ DEFAULT_TIMEOUTS.titleGenerate,
176
+ );
177
+
178
+ // Deterministic middleware produced the expected title and invoked
179
+ // the caller's callback.
180
+ expect(observedTitles).toEqual(["[deterministic] what is the weather"]);
181
+ expect(receivedTitle).toEqual(["[deterministic] what is the weather"]);
182
+ // The default terminal must NOT have been reached — it would have
183
+ // called the real title-service stub.
184
+ expect(queueGenerateConversationTitleMock).not.toHaveBeenCalled();
185
+ });
186
+
187
+ test("custom plugin: passthrough middleware leaves the default in charge", async () => {
188
+ // A plugin that always calls `next` just observes — the default
189
+ // terminal still runs and queues the title-generation job.
190
+ let middlewareSawArgs = false;
191
+
192
+ const passthroughMw: Middleware<TitleArgs, TitleResult> = async (
193
+ args,
194
+ next,
195
+ ) => {
196
+ middlewareSawArgs = true;
197
+ return next(args);
198
+ };
199
+
200
+ registerPlugin({
201
+ manifest: {
202
+ name: "observer",
203
+ version: "0.0.1",
204
+ requires: {
205
+ pluginRuntime: "v1",
206
+ titleGenerateApi: "v1",
207
+ },
208
+ },
209
+ middleware: { titleGenerate: passthroughMw },
210
+ });
211
+
212
+ await runPipeline(
213
+ "titleGenerate",
214
+ getMiddlewaresFor("titleGenerate"),
215
+ defaultTitleGenerateTerminal,
216
+ makeArgs(),
217
+ makeCtx(),
218
+ DEFAULT_TIMEOUTS.titleGenerate,
219
+ );
220
+
221
+ expect(middlewareSawArgs).toBe(true);
222
+ expect(queueGenerateConversationTitleMock).toHaveBeenCalledTimes(1);
223
+ });
224
+ });