@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea

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 (570) hide show
  1. package/Dockerfile +20 -4
  2. package/bun.lock +2 -2
  3. package/docker-entrypoint.sh +4 -2
  4. package/docker-init-apt-root.sh +3 -1
  5. package/docker-kata-apt-env.sh +3 -1
  6. package/docker-kata-runtime-family.sh +12 -0
  7. package/docs/architecture/memory.md +1 -1
  8. package/examples/plugins/echo/README.md +61 -66
  9. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  10. package/examples/plugins/echo/hooks/stop.ts +16 -0
  11. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  12. package/examples/plugins/echo/package.json +1 -2
  13. package/examples/plugins/echo/src/emit.ts +19 -0
  14. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
  15. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  16. package/openapi.yaml +3378 -335
  17. package/package.json +2 -2
  18. package/scripts/generate-openapi.ts +68 -41
  19. package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
  21. package/src/__tests__/agent-loop.test.ts +37 -87
  22. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  23. package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
  24. package/src/__tests__/annotate-risk-options.test.ts +2 -3
  25. package/src/__tests__/anthropic-provider.test.ts +95 -2
  26. package/src/__tests__/app-control-flow.test.ts +1 -1
  27. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  28. package/src/__tests__/approval-routes-http.test.ts +4 -1
  29. package/src/__tests__/assistant-event-hub.test.ts +25 -0
  30. package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
  31. package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
  32. package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
  33. package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
  34. package/src/__tests__/btw-routes.test.ts +62 -3
  35. package/src/__tests__/build-persisted-content.test.ts +184 -0
  36. package/src/__tests__/catalog-files.test.ts +1 -1
  37. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  38. package/src/__tests__/channel-approvals.test.ts +1 -1
  39. package/src/__tests__/clawhub-files.test.ts +1 -1
  40. package/src/__tests__/compaction-circuit.test.ts +258 -0
  41. package/src/__tests__/compaction-direct.test.ts +132 -0
  42. package/src/__tests__/compaction.benchmark.test.ts +0 -30
  43. package/src/__tests__/config-watcher.test.ts +1 -1
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
  48. package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
  49. package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
  50. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  51. package/src/__tests__/conversation-history-web-search.test.ts +11 -1
  52. package/src/__tests__/conversation-pairing.test.ts +4 -31
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
  54. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
  55. package/src/__tests__/conversation-queue.test.ts +2 -0
  56. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
  57. package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
  58. package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
  59. package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
  60. package/src/__tests__/conversation-slash-commands.test.ts +8 -42
  61. package/src/__tests__/conversation-slash-queue.test.ts +6 -1
  62. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  63. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
  64. package/src/__tests__/conversation-sync-tags.test.ts +27 -15
  65. package/src/__tests__/conversation-title-service.test.ts +135 -2
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
  67. package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
  69. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  70. package/src/__tests__/cross-provider-web-search.test.ts +214 -1
  71. package/src/__tests__/db-acp-history.test.ts +101 -0
  72. package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
  73. package/src/__tests__/dm-persistence.test.ts +5 -1
  74. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  75. package/src/__tests__/empty-response-hook.test.ts +304 -0
  76. package/src/__tests__/feature-flag-test-helpers.ts +2 -2
  77. package/src/__tests__/file-write-tool.test.ts +63 -0
  78. package/src/__tests__/gateway-only-guard.test.ts +12 -2
  79. package/src/__tests__/gemini-image-service.test.ts +13 -0
  80. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  81. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  82. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  83. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  84. package/src/__tests__/heartbeat-service.test.ts +1 -0
  85. package/src/__tests__/helpers/mock-provider.ts +110 -0
  86. package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
  87. package/src/__tests__/history-repair-hook.test.ts +1 -0
  88. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  89. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  90. package/src/__tests__/identity-intro-cache.test.ts +12 -100
  91. package/src/__tests__/identity-routes.test.ts +248 -7
  92. package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
  93. package/src/__tests__/injector-background-turn.test.ts +3 -9
  94. package/src/__tests__/injector-chain.test.ts +139 -275
  95. package/src/__tests__/injector-disk-pressure.test.ts +75 -41
  96. package/src/__tests__/injector-document-comments.test.ts +3 -3
  97. package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
  98. package/src/__tests__/injector-v3-suppression.test.ts +31 -37
  99. package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
  100. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  101. package/src/__tests__/list-messages-page-latest.test.ts +60 -0
  102. package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
  103. package/src/__tests__/llm-usage-store.test.ts +223 -1
  104. package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
  105. package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
  106. package/src/__tests__/native-web-search.test.ts +191 -0
  107. package/src/__tests__/onboarding-template-contract.test.ts +2 -0
  108. package/src/__tests__/openai-image-service.test.ts +17 -0
  109. package/src/__tests__/openai-provider.test.ts +31 -1
  110. package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
  111. package/src/__tests__/persist-unsendable-image.test.ts +215 -0
  112. package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
  113. package/src/__tests__/pkb-autoinject.test.ts +2 -5
  114. package/src/__tests__/plugin-api-shim.test.ts +3 -6
  115. package/src/__tests__/plugin-bootstrap.test.ts +14 -40
  116. package/src/__tests__/plugin-registry.test.ts +3 -76
  117. package/src/__tests__/plugin-types.test.ts +0 -193
  118. package/src/__tests__/process-message-display-content.test.ts +6 -2
  119. package/src/__tests__/reaction-persistence.test.ts +1 -1
  120. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
  121. package/src/__tests__/resolve-trust-class.test.ts +4 -4
  122. package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
  123. package/src/__tests__/schedule-routes.test.ts +603 -2
  124. package/src/__tests__/schedule-store.test.ts +41 -0
  125. package/src/__tests__/schedule-tools.test.ts +35 -0
  126. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  127. package/src/__tests__/server-history-render.test.ts +314 -1
  128. package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
  129. package/src/__tests__/skillssh-files.test.ts +1 -1
  130. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  131. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  132. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  133. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  134. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  135. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  136. package/src/__tests__/system-prompt.test.ts +20 -0
  137. package/src/__tests__/task-scheduler.test.ts +162 -1
  138. package/src/__tests__/terminal-tools.test.ts +6 -1
  139. package/src/__tests__/title-generate-hook.test.ts +319 -0
  140. package/src/__tests__/tool-error-hook.test.ts +278 -0
  141. package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
  142. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  143. package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
  144. package/src/__tests__/tool-result-truncation.test.ts +0 -2
  145. package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
  146. package/src/__tests__/ui-work-result-surface.test.ts +159 -0
  147. package/src/__tests__/usage-routes.test.ts +285 -1
  148. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  149. package/src/__tests__/voice-session-bridge.test.ts +6 -3
  150. package/src/__tests__/web-search-backend-failure.test.ts +166 -0
  151. package/src/acp/__tests__/agent-process.test.ts +161 -0
  152. package/src/acp/__tests__/client-handler.test.ts +40 -0
  153. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  154. package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
  155. package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
  156. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  157. package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
  158. package/src/acp/agent-process.ts +61 -1
  159. package/src/acp/auto-install.test.ts +196 -0
  160. package/src/acp/auto-install.ts +177 -0
  161. package/src/acp/client-handler.ts +31 -0
  162. package/src/acp/feature-gate.test.ts +48 -0
  163. package/src/acp/feature-gate.ts +34 -0
  164. package/src/acp/prepare-agent-env.ts +83 -29
  165. package/src/acp/resolve-agent.test.ts +320 -7
  166. package/src/acp/resolve-agent.ts +182 -18
  167. package/src/acp/resume-hint.ts +25 -0
  168. package/src/acp/session-manager.ts +495 -73
  169. package/src/acp/types.ts +8 -0
  170. package/src/agent/compaction-circuit.ts +60 -102
  171. package/src/agent/loop.ts +362 -485
  172. package/src/api/events/assistant-thinking-delta.ts +33 -0
  173. package/src/api/events/tool-output-chunk.ts +45 -0
  174. package/src/api/events/tool-use-preview-start.ts +32 -0
  175. package/src/api/events/trace-event.ts +69 -0
  176. package/src/api/index.ts +48 -13
  177. package/src/api/responses/conversation-message.ts +374 -0
  178. package/src/approvals/guardian-request-resolvers.ts +1 -1
  179. package/src/avatar/__tests__/avatar-store.test.ts +34 -29
  180. package/src/background-wake/next-wake.ts +1 -0
  181. package/src/cli/commands/__tests__/notifications.test.ts +58 -14
  182. package/src/cli/commands/notifications.ts +112 -60
  183. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  184. package/src/config/acp-defaults.test.ts +10 -0
  185. package/src/config/acp-defaults.ts +6 -0
  186. package/src/config/assistant-feature-flags.ts +22 -11
  187. package/src/config/bundled-skills/acp/SKILL.md +83 -31
  188. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  189. package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
  190. package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
  191. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  192. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  193. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  194. package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
  195. package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
  196. package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
  197. package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
  198. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  199. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  200. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  201. package/src/config/bundled-skills/messaging/SKILL.md +0 -7
  202. package/src/config/bundled-tool-registry.ts +2 -0
  203. package/src/config/feature-flag-cache.ts +3 -3
  204. package/src/config/feature-flag-registry.json +48 -7
  205. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  206. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
  207. package/src/config/schemas/heartbeat.ts +9 -0
  208. package/src/config/schemas/llm.ts +1 -0
  209. package/src/config/schemas/memory-v2.ts +8 -0
  210. package/src/config/schemas/memory-v3.ts +8 -0
  211. package/src/config/schemas/platform.ts +8 -0
  212. package/src/config/seed-inference-profiles.ts +2 -2
  213. package/src/config/skills.ts +13 -0
  214. package/src/context/compactor.ts +1 -1
  215. package/src/context/strip-injections.ts +128 -0
  216. package/src/context/token-estimator.ts +23 -0
  217. package/src/context/tool-result-truncation.ts +0 -23
  218. package/src/context/window-manager.ts +5 -7
  219. package/src/credential-execution/executable-discovery.ts +16 -0
  220. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
  221. package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
  222. package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
  223. package/src/daemon/assistant-attachments.ts +1 -1
  224. package/src/daemon/config-watcher.ts +2 -2
  225. package/src/daemon/context-overflow-reducer.ts +0 -1
  226. package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
  227. package/src/daemon/conversation-agent-loop.ts +301 -997
  228. package/src/daemon/conversation-history.ts +5 -4
  229. package/src/daemon/conversation-lifecycle.ts +3 -4
  230. package/src/daemon/conversation-messaging.ts +7 -6
  231. package/src/daemon/conversation-process.ts +11 -16
  232. package/src/daemon/conversation-registry.ts +159 -0
  233. package/src/daemon/conversation-runtime-assembly.ts +218 -398
  234. package/src/daemon/conversation-slash.ts +6 -25
  235. package/src/daemon/conversation-store.ts +9 -90
  236. package/src/daemon/conversation-surfaces.ts +222 -4
  237. package/src/daemon/conversation-tool-setup.ts +2 -29
  238. package/src/daemon/conversation-workspace.ts +17 -0
  239. package/src/daemon/conversation.ts +32 -20
  240. package/src/daemon/external-plugins-bootstrap.ts +17 -18
  241. package/src/daemon/handlers/config-a2a.ts +51 -36
  242. package/src/daemon/handlers/config-slack-channel.ts +20 -14
  243. package/src/daemon/handlers/config-telegram.ts +16 -2
  244. package/src/daemon/handlers/conversations.ts +3 -1
  245. package/src/daemon/handlers/shared.ts +156 -84
  246. package/src/daemon/handlers/skills.ts +42 -10
  247. package/src/daemon/lifecycle.ts +25 -0
  248. package/src/daemon/message-types/apps.ts +1 -29
  249. package/src/daemon/message-types/messages.ts +9 -57
  250. package/src/daemon/message-types/skills.ts +2 -0
  251. package/src/daemon/message-types/surfaces.ts +136 -3
  252. package/src/daemon/now-scratchpad.ts +21 -0
  253. package/src/daemon/orphan-reaper.test.ts +210 -0
  254. package/src/daemon/orphan-reaper.ts +240 -0
  255. package/src/daemon/overflow-reduction-loop.ts +230 -0
  256. package/src/daemon/persist-unsendable-image.ts +117 -0
  257. package/src/daemon/process-message.ts +1 -3
  258. package/src/daemon/server.ts +2 -0
  259. package/src/daemon/trace-emitter.ts +6 -4
  260. package/src/daemon/trust-context.ts +19 -0
  261. package/src/daemon/wake-target-adapter.ts +3 -1
  262. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  263. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  264. package/src/heartbeat/heartbeat-service.ts +26 -0
  265. package/src/home/home-greeting-cache.ts +24 -1
  266. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  267. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  268. package/src/ipc/gateway-client.test.ts +2 -2
  269. package/src/ipc/gateway-client.ts +3 -3
  270. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  271. package/src/ipc/skill-routes/memory.ts +4 -2
  272. package/src/media/gemini-image-service.ts +15 -0
  273. package/src/media/openai-image-service.ts +14 -0
  274. package/src/media/types.ts +34 -0
  275. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
  276. package/src/memory/auth-fallback-events-store.ts +94 -0
  277. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  278. package/src/memory/conversation-title-service.ts +65 -41
  279. package/src/memory/db-init.ts +6 -0
  280. package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
  281. package/src/memory/graph/conversation-graph-memory.ts +65 -0
  282. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  283. package/src/memory/jobs-store.ts +33 -0
  284. package/src/memory/jobs-worker.ts +32 -5
  285. package/src/memory/llm-usage-store.ts +224 -50
  286. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
  287. package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
  288. package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
  289. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  290. package/src/memory/migrations/index.ts +3 -0
  291. package/src/memory/pkb/autoinject.ts +61 -0
  292. package/src/memory/pkb/context.ts +50 -0
  293. package/src/memory/pkb/types.ts +14 -0
  294. package/src/memory/schedule-attribution-sql.ts +104 -0
  295. package/src/memory/schema/acp.ts +4 -0
  296. package/src/memory/schema/infrastructure.ts +16 -0
  297. package/src/memory/usage-grouped-buckets.ts +6 -1
  298. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
  299. package/src/memory/v2/consolidation-job.ts +14 -5
  300. package/src/notifications/conversation-pairing.ts +8 -15
  301. package/src/notifications/decision-engine.ts +6 -3
  302. package/src/notifications/home-feed-side-effect.ts +12 -1
  303. package/src/permissions/prompter.ts +4 -0
  304. package/src/plugin-api/constants.ts +4 -0
  305. package/src/plugin-api/index.ts +7 -5
  306. package/src/plugin-api/types.ts +151 -1
  307. package/src/plugins/defaults/compaction/compact.ts +59 -0
  308. package/src/plugins/defaults/compaction/package.json +1 -1
  309. package/src/plugins/defaults/compaction/register.ts +8 -19
  310. package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
  311. package/src/plugins/defaults/empty-response/register.ts +8 -13
  312. package/src/plugins/defaults/index.ts +2 -18
  313. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
  314. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
  315. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
  316. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
  317. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
  318. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
  319. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
  321. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
  322. package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
  323. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
  324. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
  325. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
  326. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
  328. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
  329. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
  330. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
  331. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
  332. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  333. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  334. package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
  335. package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
  336. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
  337. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
  338. package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
  339. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
  340. package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
  341. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
  342. package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
  343. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
  344. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
  345. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
  346. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
  347. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
  348. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
  349. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
  350. package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
  351. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
  352. package/src/plugins/defaults/title-generate/package.json +1 -1
  353. package/src/plugins/defaults/title-generate/register.ts +18 -18
  354. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
  355. package/src/plugins/defaults/tool-error/package.json +1 -1
  356. package/src/plugins/defaults/tool-error/register.ts +9 -21
  357. package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
  358. package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
  359. package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
  360. package/src/plugins/external-api.ts +2 -2
  361. package/src/plugins/pipeline.ts +6 -305
  362. package/src/plugins/registry.ts +10 -55
  363. package/src/plugins/types.ts +62 -797
  364. package/src/plugins/user-loader.ts +30 -127
  365. package/src/proactive-artifact/aux-message-injector.ts +4 -4
  366. package/src/proactive-artifact/job.test.ts +8 -13
  367. package/src/prompts/__tests__/system-prompt.test.ts +42 -0
  368. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
  369. package/src/prompts/templates/BOOTSTRAP.md +2 -2
  370. package/src/prompts/templates/system-sections.ts +15 -0
  371. package/src/providers/anthropic/client.ts +37 -29
  372. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
  373. package/src/providers/openai/chat-completions-provider.ts +44 -0
  374. package/src/providers/openrouter/client.ts +1 -0
  375. package/src/providers/placeholder-sentinels.ts +35 -0
  376. package/src/runtime/__tests__/agent-wake.test.ts +10 -6
  377. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  378. package/src/runtime/agent-wake.ts +2 -5
  379. package/src/runtime/assistant-event-hub.ts +37 -7
  380. package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
  381. package/src/runtime/channel-approvals.ts +1 -1
  382. package/src/runtime/http-router.ts +16 -21
  383. package/src/runtime/http-types.ts +16 -70
  384. package/src/runtime/interactive-ui.ts +1 -1
  385. package/src/runtime/pending-interactions.ts +1 -0
  386. package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
  387. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
  388. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  389. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
  390. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
  391. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  392. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  393. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  394. package/src/runtime/routes/acp-routes.test.ts +89 -25
  395. package/src/runtime/routes/acp-routes.ts +81 -29
  396. package/src/runtime/routes/app-management-routes.ts +6 -117
  397. package/src/runtime/routes/app-routes.ts +13 -15
  398. package/src/runtime/routes/approval-routes.ts +1 -1
  399. package/src/runtime/routes/attachment-routes.ts +26 -15
  400. package/src/runtime/routes/avatar-routes.ts +26 -0
  401. package/src/runtime/routes/browser-routes.ts +1 -1
  402. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  403. package/src/runtime/routes/btw-routes.ts +29 -23
  404. package/src/runtime/routes/consolidation-routes.ts +120 -20
  405. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  406. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  407. package/src/runtime/routes/conversation-query-routes.ts +3 -1
  408. package/src/runtime/routes/conversation-routes.ts +372 -185
  409. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  410. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  411. package/src/runtime/routes/documents-routes.ts +4 -0
  412. package/src/runtime/routes/domain-routes.ts +51 -37
  413. package/src/runtime/routes/epoch-millis-range.ts +34 -0
  414. package/src/runtime/routes/events-routes.ts +28 -34
  415. package/src/runtime/routes/gateway-log-routes.ts +26 -4
  416. package/src/runtime/routes/heartbeat-routes.ts +32 -12
  417. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  418. package/src/runtime/routes/host-cu-routes.ts +1 -1
  419. package/src/runtime/routes/identity-intro-cache.ts +11 -34
  420. package/src/runtime/routes/identity-routes.ts +224 -18
  421. package/src/runtime/routes/image-generation-routes.ts +40 -2
  422. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  423. package/src/runtime/routes/index.ts +2 -0
  424. package/src/runtime/routes/integrations/a2a.ts +12 -10
  425. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
  426. package/src/runtime/routes/integrations/slack/channel.ts +4 -0
  427. package/src/runtime/routes/integrations/slack/share.ts +27 -6
  428. package/src/runtime/routes/integrations/telegram.ts +6 -0
  429. package/src/runtime/routes/integrations/twilio.ts +42 -0
  430. package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
  431. package/src/runtime/routes/log-export-routes.ts +8 -0
  432. package/src/runtime/routes/memory-v2-routes.ts +15 -8
  433. package/src/runtime/routes/memory-v3-routes.ts +66 -34
  434. package/src/runtime/routes/oauth-apps.ts +66 -12
  435. package/src/runtime/routes/oauth-providers.ts +44 -5
  436. package/src/runtime/routes/platform-routes.ts +81 -5
  437. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
  438. package/src/runtime/routes/playground/force-compact.ts +1 -1
  439. package/src/runtime/routes/playground/helpers.ts +1 -1
  440. package/src/runtime/routes/rename-conversation-routes.ts +5 -0
  441. package/src/runtime/routes/schedule-routes.ts +152 -42
  442. package/src/runtime/routes/secret-routes.ts +14 -2
  443. package/src/runtime/routes/skills-routes.ts +43 -14
  444. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  445. package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
  446. package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
  447. package/src/runtime/routes/trust-rules-routes.ts +26 -2
  448. package/src/runtime/routes/tts-routes.ts +35 -0
  449. package/src/runtime/routes/types.ts +66 -8
  450. package/src/runtime/routes/usage-routes.ts +47 -39
  451. package/src/runtime/routes/webhook-routes.ts +41 -2
  452. package/src/runtime/routes/work-items-routes.ts +2 -4
  453. package/src/runtime/routes/workspace-routes.ts +4 -0
  454. package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
  455. package/src/runtime/services/analyze-conversation.ts +2 -2
  456. package/src/runtime/services/conversation-serializer.ts +1 -1
  457. package/src/schedule/schedule-store.ts +20 -1
  458. package/src/schedule/schedule-usage-store.ts +83 -0
  459. package/src/schedule/scheduler.ts +12 -5
  460. package/src/signals/cancel.ts +2 -4
  461. package/src/skills/catalog-files.ts +2 -2
  462. package/src/skills/catalog-install.ts +3 -0
  463. package/src/skills/categories-cache.ts +118 -0
  464. package/src/skills/clawhub-files.ts +1 -2
  465. package/src/skills/skillssh-files.ts +1 -2
  466. package/src/subagent/manager.ts +17 -5
  467. package/src/telemetry/types.ts +29 -1
  468. package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
  469. package/src/telemetry/usage-telemetry-reporter.ts +57 -2
  470. package/src/tools/acp/context.ts +20 -0
  471. package/src/tools/acp/list-agents.test.ts +7 -1
  472. package/src/tools/acp/spawn.test.ts +158 -55
  473. package/src/tools/acp/spawn.ts +47 -72
  474. package/src/tools/acp/steer.test.ts +105 -8
  475. package/src/tools/acp/steer.ts +48 -17
  476. package/src/tools/apps/executors.ts +13 -8
  477. package/src/tools/executor.ts +1 -53
  478. package/src/tools/filesystem/write.ts +34 -0
  479. package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
  480. package/src/tools/network/__tests__/web-search.test.ts +11 -3
  481. package/src/tools/network/web-search-error.test.ts +248 -0
  482. package/src/tools/network/web-search-error.ts +267 -0
  483. package/src/tools/network/web-search.ts +207 -48
  484. package/src/tools/schedule/create.ts +2 -0
  485. package/src/tools/subagent/spawn.ts +2 -4
  486. package/src/tools/terminal/safe-env.ts +10 -1
  487. package/src/tools/ui-surface/definitions.ts +34 -5
  488. package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
  489. package/src/tts/provider-catalog.ts +76 -1
  490. package/src/util/mutex.ts +47 -0
  491. package/src/workspace/git-service.ts +1 -42
  492. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  493. package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
  494. package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
  495. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
  496. package/src/workspace/migrations/registry.ts +6 -0
  497. package/docs/plugins.md +0 -836
  498. package/examples/plugins/echo/register.ts +0 -184
  499. package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
  500. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  501. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  502. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  503. package/src/__tests__/empty-response-pipeline.test.ts +0 -423
  504. package/src/__tests__/llm-call-pipeline.test.ts +0 -287
  505. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
  506. package/src/__tests__/persistence-pipeline.test.ts +0 -503
  507. package/src/__tests__/pipeline-runner.test.ts +0 -564
  508. package/src/__tests__/title-generate-pipeline.test.ts +0 -211
  509. package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
  510. package/src/__tests__/tool-error-pipeline.test.ts +0 -241
  511. package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
  512. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
  513. package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
  514. package/src/gallery/default-gallery.ts +0 -1359
  515. package/src/gallery/gallery-manifest.ts +0 -28
  516. package/src/home/feature-gate.ts +0 -22
  517. package/src/memory/v3/provider-blocks.ts +0 -16
  518. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  519. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  520. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  521. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  522. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  523. package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
  524. package/src/plugins/defaults/empty-response/terminal.ts +0 -106
  525. package/src/plugins/defaults/injectors/package.json +0 -15
  526. package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
  527. package/src/plugins/defaults/llm-call/register.ts +0 -45
  528. package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
  529. package/src/plugins/defaults/memory-retrieval/package.json +0 -15
  530. package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
  531. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  532. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  533. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  534. package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
  535. package/src/plugins/defaults/persistence/package.json +0 -15
  536. package/src/plugins/defaults/persistence/register.ts +0 -38
  537. package/src/plugins/defaults/persistence/terminal.ts +0 -83
  538. package/src/plugins/defaults/title-generate/terminal.ts +0 -31
  539. package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
  540. package/src/plugins/defaults/token-estimate/package.json +0 -15
  541. package/src/plugins/defaults/token-estimate/register.ts +0 -34
  542. package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
  543. package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
  544. package/src/plugins/defaults/tool-error/terminal.ts +0 -47
  545. package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
  546. package/src/plugins/defaults/tool-execute/package.json +0 -15
  547. package/src/plugins/defaults/tool-execute/register.ts +0 -49
  548. package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
  549. package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
  550. package/src/skills/category-inference.ts +0 -111
  551. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
  552. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
  553. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  554. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  555. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
  556. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
  557. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
  558. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +0 -0
  559. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  560. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  561. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
  562. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  563. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  564. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  565. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  566. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  567. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  568. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
  569. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
  570. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
package/docs/plugins.md DELETED
@@ -1,836 +0,0 @@
1
- # Plugins
2
-
3
- > **Note:** This guide documents the **legacy** plugin architecture — the
4
- > in-tree `register.ts` + middleware-pipeline system. We are converging on
5
- > the schema at
6
- > [`experimental/plugins/README.md`](../../experimental/plugins/README.md)
7
- > (file-based discovery, a `package.json` manifest, the
8
- > `@vellumai/plugin-api` public contract). The plan is to reshape this guide
9
- > section by section until it matches that one; wherever the two still
10
- > differ is the next piece of consolidation work. New plugins should target
11
- > the modern schema.
12
-
13
- Plugins extend the assistant's default capabilities using hooks, tools,
14
- skills, and more.
15
-
16
- If you're authoring a plugin against the current convention, this file is
17
- your map. Read [`examples/plugins/echo/`](../examples/plugins/echo/README.md)
18
- alongside, it's the canonical reference implementation and exercises every
19
- wired surface.
20
-
21
- ## Table of contents
22
-
23
- - [TL;DR](#tldr)
24
- - [What a plugin can contribute today](#what-a-plugin-can-contribute-today)
25
- - [Anatomy of a plugin](#anatomy-of-a-plugin)
26
- - [Where plugins live](#where-plugins-live)
27
- - [Manifest](#manifest)
28
- - [Registration](#registration)
29
- - [Middleware patterns](#middleware-patterns)
30
- - [Pipeline reference](#pipeline-reference)
31
- - [Timeouts](#timeouts)
32
- - [Strict-fail semantics](#strict-fail-semantics)
33
- - [Credentials and config](#credentials-and-config)
34
- - [Tool, route, and skill contributions](#tool-route-and-skill-contributions)
35
- - [Cross-plugin communication](#cross-plugin-communication)
36
- - [Hot reload](#hot-reload)
37
- - [Troubleshooting](#troubleshooting)
38
-
39
- ---
40
-
41
- ## TL;DR
42
-
43
- 1. Create a directory `<workspaceDir>/plugins/my-plugin/`.
44
- 2. Drop a `package.json` with a `name` and a `peerDependencies["@vellumai/plugin-api"]` semver range.
45
- 3. Add `middlewares/<name>.ts` files (default export = middleware function).
46
- 4. Add `tools/<name>.ts` files (default export = tool definition).
47
- 5. Restart the assistant — the loader scans `<workspaceDir>/plugins/*` and
48
- registers the plugin on startup.
49
-
50
- ## What a plugin can contribute today
51
-
52
- | Surface | Where | Discovery |
53
- | ----------------------- | ------------------------- | ------------------------------------------------- |
54
- | Pipeline middleware | `plugin.middleware` | keyed by pipeline name in `PipelineMiddlewareMap` |
55
- | Model-visible tools | `plugin.tools` | each `PluginToolRegistration` |
56
- | HTTP routes | `plugin.routes` | each `PluginRouteRegistration` |
57
- | Skills | `plugin.skills` | each `PluginSkillRegistration` |
58
- | System-prompt injectors | `plugin.injectors` | each `Injector` |
59
- | Lifecycle | `init()` / `onShutdown()` | methods on the `Plugin` object |
60
-
61
- The modern schema wires only **hooks** and **tools**; the middleware
62
- pipelines, routes, skills, and injectors above are the surfaces that still
63
- have no modern equivalent.
64
-
65
- ---
66
-
67
- ## Anatomy of a plugin
68
-
69
- A plugin is a directory that exports a single `register.ts` (or compiled
70
- `register.js`) entry point. That file builds a `Plugin` object and passes
71
- it to `registerPlugin()` as an import-time side effect. Everything else —
72
- pipeline middleware, lifecycle hooks, model-visible capabilities — hangs
73
- off that one `Plugin` object.
74
-
75
- ```
76
- my-plugin/
77
- ├── package.json # Node/Bun package metadata
78
- ├── README.md # optional — human docs
79
- └── register.ts # the entry point the assistant imports
80
- ```
81
-
82
- The `Plugin` shape is declared in
83
- [`assistant/src/plugins/types.ts`](../src/plugins/types.ts):
84
-
85
- ```typescript
86
- export interface Plugin {
87
- manifest: PluginManifest;
88
- init?(ctx: PluginInitContext): Promise<void>;
89
- onShutdown?(): Promise<void>;
90
- tools?: PluginToolRegistration[];
91
- routes?: PluginRouteRegistration[];
92
- skills?: PluginSkillRegistration[];
93
- injectors?: Injector[];
94
- middleware?: Partial<PipelineMiddlewareMap>;
95
- }
96
- ```
97
-
98
- Every field except `manifest` is optional. A plugin that only contributes
99
- middleware doesn't need tools or routes; a plugin that only contributes a
100
- skill can omit middleware entirely.
101
-
102
- ## Where plugins live
103
-
104
- The assistant scans `<workspaceDir>/plugins/*` at startup. Any subdirectory
105
- containing `register.js` or `register.ts` is dynamic-imported once. The
106
- loader lives in
107
- [`assistant/src/plugins/user-loader.ts`](../src/plugins/user-loader.ts) and
108
- has three key properties:
109
-
110
- - **Compiled wins.** If both `register.js` and `register.ts` are present,
111
- the compiled `.js` file is loaded. This matches how the compiled
112
- assistant binary resolves modules in production.
113
- - **Per-plugin isolation.** If one plugin throws at import time, the error
114
- is logged with the plugin directory and the loader moves on. Other
115
- plugins still load. One broken plugin cannot brick the assistant.
116
- - **Per-instance.** The scan runs under `vellumRoot()`. Each assistant
117
- instance loads its own plugin set.
118
-
119
- The loader runs after first-party plugin registrations and before
120
- `bootstrapPlugins()` invokes every plugin's `init()`.
121
-
122
- ## Manifest
123
-
124
- The manifest is static metadata validated by the registry at registration
125
- time. Its shape (see
126
- [`types.ts`](../src/plugins/types.ts)):
127
-
128
- ```typescript
129
- export interface PluginManifest {
130
- name: string; // kebab-case, unique
131
- version: string; // semver, informational
132
- requiresCredential?: string[]; // credential keys resolved before init()
133
- requiresFlag?: string[]; // feature flag keys that must all be enabled
134
- config?: unknown; // Zod-like parser for plugins.<name>
135
- }
136
- ```
137
-
138
- | Field | Required | Purpose |
139
- | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
140
- | `name` | yes | Unique plugin identifier. Duplicate names fail registration. Used as the directory under `<workspaceDir>/plugins-data/<name>/` and the attribution tag in logs. |
141
- | `version` | yes | Plugin's own semver. Informational — the registry does not compare it. |
142
- | `requiresCredential` | no | Credential keys the plugin needs. The bootstrap resolves them via the credential store before `init()` runs and hands the values to the plugin in `ctx.credentials`. A missing credential fails startup with a clear error. |
143
- | `requiresFlag` | no | Assistant feature-flag keys that must all be ON for the plugin to activate. If any listed flag is disabled at bootstrap, the plugin is skipped entirely: `init()` is not invoked and no tools, routes, skills, or shutdown hooks are registered for it. See [Feature-flag gating](#feature-flag-gating) below. |
144
- | `config` | no | A parser-like validator (Zod schema, or any object with a `.parse(input)` method). If supplied, the bootstrap validates `config.plugins.<name>` through it before passing the result into `init()`. |
145
-
146
- ### Host-compat: `peerDependencies["@vellumai/plugin-api"]`
147
-
148
- Plugins declare which assistant versions they support via standard
149
- `peerDependencies` in their `package.json`:
150
-
151
- ```json
152
- {
153
- "name": "@me/my-logger",
154
- "version": "1.2.3",
155
- "peerDependencies": {
156
- "@vellumai/plugin-api": "^0.8.0"
157
- }
158
- }
159
- ```
160
-
161
- At load time, the external-plugin loader resolves the assistant's running
162
- version and runs `semver.satisfies(assistantVersion, range)` against the
163
- declared range. The contract is currently soft while the plugin-installation
164
- flow is in flux:
165
-
166
- - **Range satisfied** — plugin loads.
167
- - **Range not satisfied** — loader logs an error (`log.error`) and loads
168
- the plugin anyway.
169
- - **Range unparseable** — loader logs an error and loads the plugin anyway.
170
- - **`@vellumai/plugin-api` peerDep absent** — loader logs a warning and
171
- loads the plugin without a host-compat claim.
172
-
173
- Once the install flow settles, the two error-logging branches above will
174
- harden into hard rejections (with per-plugin isolation catching the
175
- throw so one bad plugin can't brick the rest of the registry).
176
-
177
- In-tree default plugins do not declare a peerDep — they ship with the
178
- assistant binary and are version-locked by construction.
179
-
180
- ### Example manifest
181
-
182
- ```typescript
183
- const manifest: PluginManifest = {
184
- name: "my-logger",
185
- version: "1.2.3",
186
- requiresCredential: ["LOGGER_API_KEY"],
187
- requiresFlag: ["my-logger-enabled"],
188
- config: z.object({
189
- endpoint: z.string().url(),
190
- sampleRate: z.number().min(0).max(1).default(0.1),
191
- }),
192
- };
193
- ```
194
-
195
- ### Feature-flag gating
196
-
197
- `manifest.requiresFlag` lists one or more **assistant-scope** feature-flag
198
- keys (the same keys declared in
199
- `meta/feature-flags/feature-flag-registry.json`). The bootstrap checks each
200
- key against `isAssistantFeatureFlagEnabled` before touching the plugin. If
201
- **any** listed flag is disabled, the plugin is skipped entirely for the
202
- duration of this assistant boot:
203
-
204
- - `init()` is **not** invoked.
205
- - `tools`, `routes`, and `skills` are **not** registered.
206
- - No shutdown hook entry is installed, so a plugin skipped at boot has
207
- nothing to tear down on shutdown.
208
-
209
- Flag state is resolved once at bootstrap time. Flipping a `requiresFlag`
210
- key at runtime does not hot-reload the plugin — restart the assistant
211
- after changing the flag to pick up the new state. An empty `requiresFlag` (or
212
- the field being absent) means the plugin activates unconditionally.
213
-
214
- The skip path emits a single `info`-level log line naming both the plugin
215
- and the disabled flag, so operators can diagnose "why isn't my plugin
216
- loading?" at a glance:
217
-
218
- ```
219
- plugins-bootstrap skipping plugin my-logger: feature flag my-logger-enabled is disabled
220
- ```
221
-
222
- **Cross-repo note:** new flag keys used here must be declared in the
223
- assistant-scope section of
224
- `meta/feature-flags/feature-flag-registry.json` (and provisioned in the
225
- platform's Terraform configuration). See the root `CLAUDE.md`'s "Assistant
226
- Feature Flags" section for the full procedure.
227
-
228
- ## Registration
229
-
230
- A plugin's `register.ts` calls `registerPlugin()` at module load time. The
231
- function is exposed via the `globalThis.__vellumPluginRuntime` bridge so the
232
- plugin file does not need to import from the daemon's source tree:
233
-
234
- ```typescript
235
- import type { Plugin } from "<path-to-assistant>/src/plugins/types.js";
236
-
237
- interface VellumPluginRuntime {
238
- readonly version: 1;
239
- readonly registerPlugin: (plugin: Plugin) => void;
240
- readonly assistantEventHub: import("<path-to-assistant>/src/runtime/assistant-event-hub.js").AssistantEventHub;
241
- readonly getSecureKeyAsync: (account: string) => Promise<string | undefined>;
242
- }
243
-
244
- const runtime = (globalThis as { __vellumPluginRuntime?: VellumPluginRuntime })
245
- .__vellumPluginRuntime;
246
- if (!runtime || runtime.version !== 1) {
247
- throw new Error(
248
- "vellum plugin runtime not available — install a recent assistant build",
249
- );
250
- }
251
- const { registerPlugin } = runtime;
252
-
253
- const myPlugin: Plugin = {
254
- manifest: {
255
- name: "my-plugin",
256
- version: "0.1.0",
257
- },
258
- middleware: {
259
- /* ... */
260
- },
261
- };
262
-
263
- registerPlugin(myPlugin);
264
- ```
265
-
266
- **Why the bridge?** When the daemon is a `bun --compile` binary, its modules
267
- are bundled into the executable. Plugins that import the daemon's modules by
268
- absolute path (`/abs/path/to/assistant/src/plugins/registry.js`) reload fresh
269
- disk copies into a separate module graph, and any `registerPlugin()` call in
270
- the plugin lands in a registry the daemon never reads. The
271
- `globalThis.__vellumPluginRuntime` handle is the same instance the daemon's
272
- bundled code holds onto, so plugin registrations always reach the right
273
- place — whether the daemon was built with `bun --compile` or is running from
274
- source.
275
-
276
- Type-only imports (`import type { Plugin } from "..."`) remain free to use
277
- absolute paths to the assistant source — the TypeScript compiler erases them
278
- and they have no module-identity effect at runtime.
279
-
280
- **Rules:**
281
-
282
- - Exactly one `registerPlugin()` call per plugin. The registry rejects
283
- duplicate names.
284
- - `register.ts` must not export named symbols consumed from outside. The
285
- loader treats the import as side-effect-only.
286
- - Throwing inside `register.ts` is caught by the loader and logged, then
287
- the loader moves on. Do not rely on throws to signal "please don't load
288
- this plugin" — use `requiresFlag` or a guard inside `init()` instead.
289
- - The file runs before any lifecycle hooks. Keep it fast — heavy work
290
- belongs in `init()`.
291
- - The bridge is installed by the daemon before `loadUserPlugins()` runs, so
292
- the global is always present when a plugin's module body executes.
293
-
294
- ## Middleware patterns
295
-
296
- Middleware is the heart of the plugin system. Every pipeline slot uses the
297
- same onion-style signature:
298
-
299
- ```typescript
300
- export type Middleware<A, R> = (
301
- args: A,
302
- next: (args: A) => Promise<R>,
303
- ctx: TurnContext,
304
- ) => Promise<R>;
305
- ```
306
-
307
- The runner composes an array of middleware around a terminal handler. The
308
- first middleware sees the request first and the response last; the
309
- terminal runs at the innermost layer. See
310
- [`assistant/src/plugins/pipeline.ts`](../src/plugins/pipeline.ts) for the
311
- composition algorithm.
312
-
313
- Four common patterns emerge from that signature:
314
-
315
- ### Observe-only
316
-
317
- Record something without changing the call. Call `next(args)` unchanged,
318
- return the result unchanged. Wrap the call in `try`/`finally` so your
319
- observer runs on both success and failure paths.
320
-
321
- ```typescript
322
- const observer: Middleware<ToolExecuteArgs, ToolExecuteResult> =
323
- async function observeToolExecute(args, next, ctx) {
324
- const start = performance.now();
325
- let outcome: "success" | "error" = "success";
326
- try {
327
- return await next(args);
328
- } catch (err) {
329
- outcome = "error";
330
- throw err;
331
- } finally {
332
- const ms = Math.round(performance.now() - start);
333
- console.error(JSON.stringify({ tool: args.name, ms, outcome }));
334
- }
335
- };
336
- ```
337
-
338
- ### Transform input
339
-
340
- Rewrite `args` before calling downstream. Useful for request shimming
341
- (adding headers, redacting inputs, picking a different provider).
342
-
343
- ```typescript
344
- const addHeader: Middleware<LLMCallArgs, LLMCallResult> =
345
- async function addHeader(args, next, ctx) {
346
- const tagged = {
347
- ...args,
348
- options: {
349
- ...args.options,
350
- config: { ...args.options?.config, requestId: ctx.requestId },
351
- },
352
- };
353
- return next(tagged);
354
- };
355
- ```
356
-
357
- ### Transform output
358
-
359
- Call `next(args)` first, then modify the result before returning.
360
-
361
- ```typescript
362
- const redactPII: Middleware<LLMCallArgs, LLMCallResult> =
363
- async function redactPII(args, next, ctx) {
364
- const response = await next(args);
365
- return {
366
- ...response,
367
- content: response.content.map(redactBlock),
368
- };
369
- };
370
- ```
371
-
372
- ### Short-circuit
373
-
374
- Do not call `next(args)` — return a synthetic result directly. The
375
- terminal and any inner middleware are skipped. Use this to stub, cache,
376
- or mock a pipeline.
377
-
378
- ```typescript
379
- const cacheHit: Middleware<LLMCallArgs, LLMCallResult> =
380
- async function cacheHit(args, next, ctx) {
381
- const cached = await lookupCache(args);
382
- if (cached) return cached;
383
- return next(args);
384
- };
385
- ```
386
-
387
- ### Veto (throw)
388
-
389
- Throwing from middleware aborts the pipeline. The error propagates out
390
- through any outer middleware unchanged — there is no internal
391
- `try`/`catch` around user middleware.
392
-
393
- ```typescript
394
- const denyIfUnauthorized: Middleware<ToolExecuteArgs, ToolExecuteResult> =
395
- async function denyIfUnauthorized(args, next, ctx) {
396
- if (!isAuthorizedFor(args.name, ctx.trust)) {
397
- throw new Error(`tool ${args.name} denied by policy`);
398
- }
399
- return next(args);
400
- };
401
- ```
402
-
403
- ### Naming middleware
404
-
405
- Give middleware a stable `name` (via `async function <name>(…)`). The
406
- pipeline runner pulls `Function.name` into its `chain` log field so
407
- operators can see the registered chain at a glance:
408
-
409
- ```
410
- plugin.pipeline pipeline=llmCall chain=["observeLlm","addHeader","defaultLlmCall"] durationMs=1840 outcome=success
411
- ```
412
-
413
- ## Pipeline reference
414
-
415
- Every pipeline slot and its purpose. Type details live in
416
- [`types.ts`](../src/plugins/types.ts).
417
-
418
- | Pipeline | Purpose |
419
- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
420
- | `turn` | The outermost wrapper around a single assistant turn. Middleware here sees everything a turn does end-to-end. |
421
- | `llmCall` | Every call to `Provider.sendMessage`. Input carries `messages` and `options` (with `tools`, `systemPrompt`, `config`, `onEvent`, `signal` inside). |
422
- | `toolExecute` | Every `ToolExecutor.execute` call. Input carries `name`, `input`, and the full `ToolContext`. |
423
- | `memoryRetrieval` | PKB, NOW.md, and memory-graph retrieval for a turn. Output is a merged `MemoryResult`. |
424
- | `historyRepair` | The pre-run repair pass on the message history. Wraps `repairHistory`. |
425
- | `tokenEstimate` | The token-count estimate used for budgeting. Wraps `estimatePromptTokensRaw`. |
426
- | `compaction` | The conversation-compaction step. Wraps `ContextWindowManager.maybeCompact`. |
427
- | `overflowReduce` | The reducer tier loop invoked when a turn blows the context budget. |
428
- | `persistence` | Every message CRUD op (`add` / `update` / `delete`). Discriminated by `args.op`. |
429
- | `titleGenerate` | Conversation title generation. Fire-and-forget by default. |
430
- | `toolResultTruncate` | The per-tool-result truncation step that fits a tool's output into the context window. |
431
- | `emptyResponse` | The decision about what to do when the model returns an empty turn (nudge / accept / error). |
432
- | `toolError` | The decision about what to do when one or more tool calls errored on a turn. |
433
- | `circuitBreaker` | The compaction circuit breaker. Tracks consecutive-failure state, decides whether to open the circuit. |
434
-
435
- ## Timeouts
436
-
437
- Each pipeline has a default timeout budget in milliseconds. When the
438
- budget is exceeded the runner throws `PluginTimeoutError` carrying the
439
- pipeline name, the offending plugin's name (if known), and the elapsed
440
- duration. See
441
- [`assistant/src/plugins/pipeline.ts`](../src/plugins/pipeline.ts) for the
442
- current values.
443
-
444
- | Pipeline | Timeout | Rationale |
445
- | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
446
- | `turn` | none | Turn duration is bounded by the downstream `llmCall` / `toolExecute` timeouts, not a pipeline-level timer. |
447
- | `llmCall` | none | Deferred to the provider's HTTP timeout so network hiccups surface as provider errors, not pipeline timeouts. |
448
- | `toolExecute` | none | Deferred to the per-tool timeout already enforced by `ToolExecutor`. |
449
- | `memoryRetrieval` | 5000 ms | Memory reads may hit Qdrant and disk; 5 s leaves slack for cold caches without blocking the turn indefinitely. |
450
- | `historyRepair` | 1000 ms | CPU-bound list walk — should finish in a few ms. |
451
- | `tokenEstimate` | 1000 ms | Same — CPU-bound, should return instantly. |
452
- | `compaction` | 30000 ms | Summarization involves a provider call; mirrors the pipeline-level budget for LLM-backed operations. |
453
- | `overflowReduce` | 30000 ms | Iterative compaction; matches the `compaction` budget since each tier step may invoke it. |
454
- | `persistence` | 10000 ms | SQLite writes, Qdrant deletes, and disk syncs. 10 s is generous for the slowest op (batched segment inserts). |
455
- | `titleGenerate` | 30000 ms | Provider-backed. Fire-and-forget, but the budget exists so a stuck call doesn't leak forever. |
456
- | `toolResultTruncate` | 1000 ms | Pure string op. |
457
- | `emptyResponse` | 500 ms | Decision logic only — must be near-instant. |
458
- | `toolError` | 500 ms | Decision logic only — must be near-instant. |
459
- | `circuitBreaker` | 500 ms | Numeric state update — must be near-instant. |
460
-
461
- `null` timeouts skip the timer entirely. Finite timeouts arm a
462
- `setTimeout` that races the pipeline via `Promise.race`.
463
-
464
- ## Strict-fail semantics
465
-
466
- **Plugin errors and timeouts fail the turn loudly. There is no silent
467
- fallback to the default behavior.**
468
-
469
- This is a deliberate design decision. The old inline behavior silently
470
- absorbed many edge cases (a memory retrieval failure became an empty
471
- memory block, a compaction error became no compaction, etc.). That made
472
- debugging production issues miserable because failures disappeared into
473
- logs nobody checked.
474
-
475
- With strict-fail:
476
-
477
- - Any error thrown from middleware propagates up to the caller. The
478
- pipeline runner does not catch it.
479
- - Any `PluginTimeoutError` from a budget breach propagates identically.
480
- - The caller (agent loop, memory subsystem, whoever) decides how to
481
- degrade. The pipeline itself does not paper over the failure.
482
- - Exactly one structured log line is emitted per pipeline invocation, in
483
- a `finally` block, regardless of outcome. It carries `outcome`
484
- (`"success" | "error" | "timeout"`), `durationMs`, `chain`, plugin
485
- attribution, and error details when applicable.
486
-
487
- If you're writing middleware that wants to "try, fall back to default on
488
- failure," express that at the call site instead — wrap the pipeline
489
- invocation in your own try/catch. Do not swallow the error inside your
490
- middleware's `try`/`catch` and silently return a degraded result.
491
-
492
- ## Credentials and config
493
-
494
- ### Credentials
495
-
496
- Declare required credential keys in `manifest.requiresCredential`:
497
-
498
- ```typescript
499
- const manifest: PluginManifest = {
500
- name: "my-plugin",
501
- version: "1.0.0",
502
- requiresCredential: ["MY_PLUGIN_API_KEY"],
503
- };
504
- ```
505
-
506
- During bootstrap, the assistant resolves each key through the credential
507
- store (via `getSecureKeyAsync`). In Docker mode that call goes through
508
- the CES HTTP API; in local mode it hits the encrypted file store / CES
509
- RPC backend. The resolved values are handed to your `init()`:
510
-
511
- ```typescript
512
- async init(ctx: PluginInitContext) {
513
- const apiKey = ctx.credentials["MY_PLUGIN_API_KEY"];
514
- // use it
515
- }
516
- ```
517
-
518
- **Rules:**
519
-
520
- - Never import the credential store directly. Always go through the
521
- manifest.
522
- - Missing credentials fail startup with a clear error naming the plugin
523
- and the key. There is no silent fallback.
524
- - Credentials are resolved once at bootstrap. Long-running plugins that
525
- need rotation must re-resolve through their own mechanism.
526
-
527
- ### Config
528
-
529
- Declare a parser-like validator in `manifest.config`:
530
-
531
- ```typescript
532
- const configSchema = z.object({
533
- endpoint: z.string().url(),
534
- sampleRate: z.number().min(0).max(1).default(0.1),
535
- });
536
-
537
- const manifest: PluginManifest = {
538
- name: "my-plugin",
539
- version: "1.0.0",
540
- config: configSchema,
541
- };
542
- ```
543
-
544
- The bootstrap reads `config.plugins.<name>` from the assistant's config
545
- and calls `manifest.config.parse(raw)`. The parsed result is handed to
546
- your `init()`:
547
-
548
- ```typescript
549
- async init(ctx: PluginInitContext) {
550
- const cfg = ctx.config as z.infer<typeof configSchema>;
551
- // use cfg
552
- }
553
- ```
554
-
555
- If you don't supply a validator, the raw config is passed through
556
- untouched as `unknown` and your plugin must narrow it itself.
557
-
558
- ### Other init context fields
559
-
560
- The full `PluginInitContext`:
561
-
562
- ```typescript
563
- export interface PluginInitContext {
564
- config: unknown; // parsed config (or raw if no validator)
565
- credentials: Record<string, string>; // resolved credentials from requiresCredential
566
- logger: unknown; // pino child logger, tagged { plugin: <name> }
567
- pluginStorageDir: string; // <workspaceDir>/plugins-data/<name>/ (created by bootstrap)
568
- assistantVersion: string; // assistant semver — same value used by the loader
569
- // against your peerDependencies range
570
- }
571
- ```
572
-
573
- `pluginStorageDir` is a per-plugin writable directory. Use it for
574
- persistent state — cache files, counters, anything that must survive an
575
- assistant restart. The bootstrap creates it on demand.
576
-
577
- ## Tool, route, and skill contributions
578
-
579
- Plugins can contribute model-visible capabilities alongside their
580
- middleware. Each is optional.
581
-
582
- ### Tools (`plugin.tools`)
583
-
584
- An array of `Tool` objects. The bootstrap registers them with the global
585
- tool registry after `init()` succeeds, stamping `origin: "plugin"` and
586
- `owner: { kind: "plugin", id: <plugin.name> }` so they live in a ref-count
587
- namespace disjoint from real skills (a plugin whose `manifest.name`
588
- happens to match a skill id cannot collide with that skill's
589
- registrations).
590
-
591
- ```typescript
592
- const myPlugin: Plugin = {
593
- manifest: {
594
- /* ... */
595
- },
596
- tools: [
597
- {
598
- name: "my_tool",
599
- description: "Does the thing.",
600
- category: "plugin",
601
- defaultRiskLevel: "low",
602
- getDefinition: () => ({
603
- name: "my_tool",
604
- description: "Does the thing.",
605
- input_schema: { type: "object", properties: {}, required: [] },
606
- }),
607
- execute: async (input, ctx) => ({ content: "result", isError: false }),
608
- },
609
- ],
610
- };
611
- ```
612
-
613
- Tools are unregistered automatically on shutdown. See
614
- [`assistant/src/tools/types.ts`](../src/tools/types.ts) for the full
615
- `Tool` interface including optional fields like `executionMode` and
616
- `executionTarget`.
617
-
618
- ### Routes (`plugin.routes`)
619
-
620
- An array of `SkillRoute` objects — the same shape the skill-route
621
- registry consumes. Registered via `registerSkillRoute` after `init()`
622
- succeeds; the runtime retains the opaque handle returned by each call
623
- and uses those handles to unregister the plugin's routes on shutdown.
624
- Handle-keyed unregistration is deliberate: two owners (plugin vs.
625
- skill, or plugin vs. plugin) can legitimately declare the same regex,
626
- and identity matching ensures one owner's teardown cannot evict
627
- another owner's live routes.
628
-
629
- ```typescript
630
- const myPlugin: Plugin = {
631
- manifest: {
632
- /* ... */
633
- },
634
- routes: [
635
- {
636
- pattern: /^\/_plugin\/my-plugin\/status$/,
637
- methods: ["GET"],
638
- handler: async (req, match) => new Response("ok"),
639
- },
640
- ],
641
- };
642
- ```
643
-
644
- ### Skills (`plugin.skills`)
645
-
646
- An array of `PluginSkillRegistration` objects. Each becomes a discoverable
647
- skill under `source: "plugin"` in the model's `skill_load` /
648
- `skill_execute` flow.
649
-
650
- ```typescript
651
- const myPlugin: Plugin = {
652
- manifest: {
653
- /* ... */
654
- },
655
- skills: [
656
- {
657
- id: "my-plugin/do-thing",
658
- name: "do-thing",
659
- description: "Does the thing via plugin-contributed skill.",
660
- body: "# SKILL.md body returned when loaded\n...",
661
- },
662
- ],
663
- };
664
- ```
665
-
666
- See
667
- [`plugin-skill-contributions.ts`](../src/plugins/plugin-skill-contributions.ts)
668
- for the in-memory registry details and ref-counted lifecycle.
669
-
670
- ### Injectors (`plugin.injectors`)
671
-
672
- An array of `Injector` objects that emit system-prompt-time content.
673
- Each has a stable `name`, an ascending `order` used to position it in the
674
- injection chain, and a `produce(ctx)` method that returns an
675
- `InjectionBlock` or `null`.
676
-
677
- The default injectors use `order` 10 through 70 with gaps of 10, so
678
- plugin-contributed injectors can slot at `25`, `35`, etc. without
679
- renumbering.
680
-
681
- ```typescript
682
- const myPlugin: Plugin = {
683
- manifest: {
684
- /* ... */
685
- },
686
- injectors: [
687
- {
688
- name: "my-plugin/status",
689
- order: 25,
690
- async produce(ctx) {
691
- return {
692
- id: "my-plugin/status",
693
- text: `<my_plugin_status>ok</my_plugin_status>`,
694
- };
695
- },
696
- },
697
- ],
698
- };
699
- ```
700
-
701
- ## Cross-plugin communication
702
-
703
- Plugins should not call each other directly. There is no cross-plugin
704
- import API — a plugin's export surface is intentionally limited to the
705
- `Plugin` object it registers.
706
-
707
- For cross-cutting concerns (broadcasting events, reacting to
708
- system-level changes), use the `assistantEventHub` pub/sub in
709
- [`runtime/assistant-event-hub.ts`](../src/runtime/assistant-event-hub.ts).
710
- The hub is the canonical place to publish events from inside the
711
- assistant process and to subscribe from anywhere that has access to the
712
- assistant's module graph.
713
-
714
- Do not add new HTTP endpoints to implement plugin-to-plugin messaging
715
- inside a single assistant process.
716
-
717
- ## Hot reload
718
-
719
- **Not supported in v1.** Registering a plugin takes effect at assistant
720
- startup only. To pick up a new or modified plugin:
721
-
722
- ```bash
723
- vellum restart
724
- ```
725
-
726
- The registry's internal state is not mutable at runtime. `init()` and
727
- `onShutdown()` hooks are fired exactly once per assistant boot.
728
-
729
- If you need hot reload for development, symlink your plugin directory
730
- into `<workspaceDir>/plugins/` so edits propagate, and automate the restart
731
- loop externally.
732
-
733
- ## Troubleshooting
734
-
735
- ### `external plugin X: peerDependencies["@vellumai/plugin-api"] requires "<range>" but assistant is <version> — loading anyway`
736
-
737
- Logged at `error` level. Your plugin's declared
738
- `peerDependencies["@vellumai/plugin-api"]` range does not include the
739
- running assistant's version. The plugin still loads while the install
740
- flow is being shaped, but a future release will turn this into a hard
741
- rejection. Either widen the range in your `package.json` (typically by
742
- bumping the major in `^X.Y.Z`) or upgrade the assistant.
743
-
744
- ### `external plugin X: peerDependencies["@vellumai/plugin-api"] is not a valid semver range — loading anyway`
745
-
746
- Logged at `error` level, same lenient policy as above. The value declared
747
- under `peerDependencies["@vellumai/plugin-api"]` is not parseable as a
748
- semver range. Use a standard range expression such as `^0.8.0`,
749
- `>=0.8.0 <0.10`, or an exact version.
750
-
751
- ### `external plugin X missing plugin-api peerDependency — loading without host-compat claim`
752
-
753
- Warning, not an error. Your plugin's `package.json` does not declare a
754
- `peerDependencies["@vellumai/plugin-api"]` entry, so the loader has no
755
- host-compat range to check and loads the plugin without that guard. Add
756
- the peerDep so future assistant upgrades surface incompatibility before
757
- the plugin runs.
758
-
759
- ### "plugin X is already registered"
760
-
761
- Two plugins tried to register under the same `manifest.name`. Names must
762
- be globally unique. Rename one, or if this is a dev-reload issue,
763
- restart the assistant.
764
-
765
- ### "plugin X requires credential Y but the credential store returned no value"
766
-
767
- The credential named in `requiresCredential` is not set. Run:
768
-
769
- ```bash
770
- vellum credentials set Y
771
- ```
772
-
773
- …and restart the assistant.
774
-
775
- ### "plugin X config validation failed: …"
776
-
777
- The config block under `config.plugins.<name>` failed the manifest's
778
- parser. Check your config against the plugin's schema — the error
779
- message carries the validator's diagnostic.
780
-
781
- ### `PluginTimeoutError: Plugin pipeline '<name>' timed out after N ms`
782
-
783
- A plugin's middleware exceeded the pipeline's budget. The offending
784
- plugin is named in `ctx.pluginName` when available. Tighten the
785
- middleware (it's probably blocking on I/O it shouldn't) or, if the
786
- work is genuinely heavy, move it out of the critical path into a
787
- background job that publishes results through `assistantEventHub`.
788
-
789
- ### Reading pipeline log records
790
-
791
- Every pipeline invocation emits one structured line tagged
792
- `event=plugin.pipeline`. The fields:
793
-
794
- | Field | Meaning |
795
- | ------------------------------------------ | ----------------------------------------------------------------------- |
796
- | `pipeline` | Pipeline name (`llmCall`, `toolExecute`, …). |
797
- | `chain` | Ordered list of middleware function names, outermost first. |
798
- | `durationMs` | Total time spent in the composed chain. |
799
- | `outcome` | `"success"`, `"error"`, or `"timeout"`. |
800
- | `pluginName` | The specific plugin's name when the runner could attribute the frame. |
801
- | `timeoutMs` | The configured budget (only when one was set). |
802
- | `errorName`, `errorMessage`, `errorStack` | Present on failure outcomes. |
803
- | `requestId`, `conversationId`, `turnIndex` | Per-turn context for correlating with the rest of the assistant's logs. |
804
-
805
- Pipe the assistant's stderr through `jq` to filter and inspect:
806
-
807
- ```bash
808
- tail -f ~/.vellum/daemon.log | jq 'select(.event == "plugin.pipeline")'
809
- ```
810
-
811
- To isolate slow pipelines:
812
-
813
- ```bash
814
- tail -f ~/.vellum/daemon.log \
815
- | jq 'select(.event == "plugin.pipeline" and .durationMs > 1000)'
816
- ```
817
-
818
- To isolate errors and timeouts:
819
-
820
- ```bash
821
- tail -f ~/.vellum/daemon.log \
822
- | jq 'select(.event == "plugin.pipeline" and .outcome != "success")'
823
- ```
824
-
825
- ### Plugin not loading at all
826
-
827
- - Confirm the directory is under `<workspaceDir>/plugins/`.
828
- - Confirm it has a `register.ts` or `register.js` at the top level.
829
- - Check the assistant's stderr for a line like
830
- `loaded user plugin (side-effect import completed)` or
831
- `Failed to load user plugin <dir>: <err>`. Import-time throws are
832
- logged but do not crash the assistant — the plugin is silently skipped
833
- otherwise.
834
- - Verify `register.ts` calls `registerPlugin()` exactly once at module
835
- level. If the call is inside an unrelated conditional or wrapped in
836
- an async function that is never awaited, the registry won't see it.