@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.2

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 (430) hide show
  1. package/bun.lock +0 -20
  2. package/docs/workspace-tools.md +33 -42
  3. package/eslint-rules/cli-no-daemon-internals.js +0 -6
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
  5. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
  6. package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
  7. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
  8. package/node_modules/@vellumai/service-contracts/package.json +0 -1
  9. package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
  10. package/openapi.yaml +0 -155
  11. package/package.json +1 -4
  12. package/scripts/test.sh +15 -36
  13. package/src/__tests__/actor-token-service.test.ts +14 -36
  14. package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
  15. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
  16. package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
  17. package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
  18. package/src/__tests__/annotate-risk-options.test.ts +0 -2
  19. package/src/__tests__/approval-cascade.test.ts +0 -2
  20. package/src/__tests__/assistant-attachments.test.ts +0 -42
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  22. package/src/__tests__/btw-routes.test.ts +0 -2
  23. package/src/__tests__/build-persisted-content.test.ts +0 -2
  24. package/src/__tests__/call-controller.test.ts +0 -19
  25. package/src/__tests__/channel-guardian.test.ts +58 -94
  26. package/src/__tests__/channel-reply-delivery.test.ts +0 -2
  27. package/src/__tests__/compaction-events.test.ts +0 -2
  28. package/src/__tests__/compaction.benchmark.test.ts +0 -2
  29. package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
  30. package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
  31. package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
  32. package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
  33. package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
  34. package/src/__tests__/config-loader-backfill.test.ts +10 -123
  35. package/src/__tests__/config-schema.test.ts +0 -1
  36. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
  37. package/src/__tests__/contacts-relay-reads.test.ts +15 -13
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
  39. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  42. package/src/__tests__/conversation-agent-loop.test.ts +0 -134
  43. package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
  44. package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
  45. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
  46. package/src/__tests__/conversation-history-web-search.test.ts +0 -2
  47. package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
  48. package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
  49. package/src/__tests__/conversation-pairing.test.ts +0 -2
  50. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +0 -2
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
  53. package/src/__tests__/conversation-queue.test.ts +0 -91
  54. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
  56. package/src/__tests__/conversation-slash-queue.test.ts +0 -2
  57. package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
  58. package/src/__tests__/conversation-speed-override.test.ts +0 -2
  59. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
  60. package/src/__tests__/conversation-title-service.test.ts +0 -2
  61. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
  62. package/src/__tests__/conversation-usage.test.ts +0 -2
  63. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
  64. package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
  65. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
  66. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  67. package/src/__tests__/db-migration-rollback.test.ts +171 -205
  68. package/src/__tests__/db-test-helpers.ts +4 -5
  69. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
  70. package/src/__tests__/disk-pressure-guard.test.ts +0 -41
  71. package/src/__tests__/dm-persistence.test.ts +0 -2
  72. package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
  73. package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
  74. package/src/__tests__/exploration-drift-hook.test.ts +2 -3
  75. package/src/__tests__/filing-service.test.ts +0 -2
  76. package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
  77. package/src/__tests__/guardian-dispatch.test.ts +1 -95
  78. package/src/__tests__/guardian-outbound-http.test.ts +0 -13
  79. package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
  80. package/src/__tests__/heartbeat-service.test.ts +0 -2
  81. package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
  82. package/src/__tests__/host-app-control-routes.test.ts +30 -24
  83. package/src/__tests__/host-bash-routes.test.ts +41 -31
  84. package/src/__tests__/host-browser-routes.test.ts +32 -26
  85. package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
  86. package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
  87. package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
  88. package/src/__tests__/http-user-message-parity.test.ts +8 -290
  89. package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
  90. package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
  91. package/src/__tests__/invite-redemption-service.test.ts +0 -198
  92. package/src/__tests__/llm-context-normalization.test.ts +0 -105
  93. package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
  94. package/src/__tests__/llm-usage-store.test.ts +0 -25
  95. package/src/__tests__/mcp-health-check.test.ts +1 -2
  96. package/src/__tests__/media-stream-server-integration.test.ts +0 -127
  97. package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
  98. package/src/__tests__/messaging-send-tool.test.ts +0 -2
  99. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  100. package/src/__tests__/mtime-cache.test.ts +5 -146
  101. package/src/__tests__/native-web-search.test.ts +0 -2
  102. package/src/__tests__/non-member-access-request.test.ts +17 -189
  103. package/src/__tests__/notification-broadcaster.test.ts +0 -4
  104. package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
  105. package/src/__tests__/notification-deep-link.test.ts +0 -6
  106. package/src/__tests__/notification-guardian-path.test.ts +0 -19
  107. package/src/__tests__/openai-provider.test.ts +12 -22
  108. package/src/__tests__/openai-responses-provider.test.ts +2 -12
  109. package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
  110. package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
  111. package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
  112. package/src/__tests__/plugin-bootstrap.test.ts +73 -3
  113. package/src/__tests__/plugin-route-contribution.test.ts +17 -4
  114. package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
  115. package/src/__tests__/plugin-types.test.ts +2 -0
  116. package/src/__tests__/process-message-background-slack.test.ts +0 -2
  117. package/src/__tests__/process-message-display-content.test.ts +0 -2
  118. package/src/__tests__/provider-error-scenarios.test.ts +4 -5
  119. package/src/__tests__/provider-usage-tracking.test.ts +0 -39
  120. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
  121. package/src/__tests__/registry.test.ts +1 -4
  122. package/src/__tests__/relay-server.test.ts +25 -694
  123. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
  124. package/src/__tests__/secret-ingress-http.test.ts +0 -14
  125. package/src/__tests__/send-endpoint-busy.test.ts +8 -30
  126. package/src/__tests__/skills.test.ts +0 -44
  127. package/src/__tests__/slack-inbound-verification.test.ts +2 -47
  128. package/src/__tests__/stt-hints.test.ts +13 -44
  129. package/src/__tests__/subagent-detail.test.ts +0 -27
  130. package/src/__tests__/subagent-disposal.test.ts +0 -65
  131. package/src/__tests__/subagent-notify-parent.test.ts +0 -2
  132. package/src/__tests__/subagent-role-registry.test.ts +2 -7
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
  134. package/src/__tests__/subagent-tools.test.ts +0 -2
  135. package/src/__tests__/suggestion-routes.test.ts +0 -2
  136. package/src/__tests__/title-generate-hook.test.ts +0 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
  138. package/src/__tests__/tool-executor.test.ts +11 -16
  139. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
  140. package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
  141. package/src/__tests__/tool-start-timestamp.test.ts +0 -2
  142. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
  143. package/src/__tests__/twilio-routes.test.ts +0 -96
  144. package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
  145. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  146. package/src/__tests__/voice-invite-redemption.test.ts +0 -33
  147. package/src/__tests__/web-search-backend-failure.test.ts +0 -2
  148. package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
  149. package/src/__tests__/workspace-tool-loader.test.ts +2 -195
  150. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  151. package/src/agent/loop.ts +0 -56
  152. package/src/api/index.ts +1 -19
  153. package/src/api/responses/llm-request-log-entry.ts +0 -29
  154. package/src/api/responses/subagent-detail.ts +0 -17
  155. package/src/api/surfaces.ts +3 -39
  156. package/src/approvals/guardian-request-resolvers.ts +11 -1
  157. package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
  158. package/src/calls/call-domain.ts +3 -3
  159. package/src/calls/guardian-dispatch.ts +8 -10
  160. package/src/calls/inbound-trust-reader.ts +1 -17
  161. package/src/calls/media-stream-server.ts +0 -21
  162. package/src/calls/relay-server.ts +50 -167
  163. package/src/calls/relay-setup-router.ts +7 -37
  164. package/src/calls/relay-verification.ts +4 -4
  165. package/src/calls/stt-hints.ts +12 -9
  166. package/src/calls/twilio-routes.ts +4 -14
  167. package/src/channels/types.ts +20 -10
  168. package/src/cli/commands/__tests__/cache.test.ts +1 -8
  169. package/src/cli/commands/cache.ts +181 -194
  170. package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
  171. package/src/cli/commands/db/status.ts +1 -37
  172. package/src/cli/commands/mcp.ts +218 -252
  173. package/src/cli/commands/memory/index.ts +0 -2
  174. package/src/cli/commands/plugins.ts +3 -75
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
  177. package/src/cli/lib/list-installed-plugins.ts +1 -179
  178. package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
  179. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
  180. package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
  181. package/src/config/bundled-skills/subagent/SKILL.md +1 -1
  182. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  183. package/src/config/feature-flag-registry.json +13 -5
  184. package/src/config/loader.ts +5 -38
  185. package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
  186. package/src/config/schemas/memory-lifecycle.ts +0 -12
  187. package/src/config/schemas/memory-v3.ts +0 -7
  188. package/src/config/schemas/memory.ts +0 -4
  189. package/src/config/schemas/timeouts.ts +0 -8
  190. package/src/config/seed-inference-profiles.ts +11 -21
  191. package/src/config/skills.ts +5 -27
  192. package/src/config/sync-gated-profiles.ts +13 -12
  193. package/src/contacts/contacts-write.ts +0 -3
  194. package/src/daemon/assistant-attachments.ts +4 -27
  195. package/src/daemon/conversation-agent-loop.ts +0 -28
  196. package/src/daemon/conversation-process.ts +16 -35
  197. package/src/daemon/conversation-surfaces.ts +38 -111
  198. package/src/daemon/conversation-tool-setup.ts +16 -50
  199. package/src/daemon/conversation.ts +1 -13
  200. package/src/daemon/disk-pressure-guard.ts +2 -12
  201. package/src/daemon/event-loop-watchdog.ts +1 -28
  202. package/src/daemon/external-plugins-bootstrap.ts +34 -4
  203. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
  204. package/src/daemon/handlers/config-a2a.ts +14 -6
  205. package/src/daemon/handlers/config-channels.ts +22 -78
  206. package/src/daemon/handlers/conversations.ts +0 -77
  207. package/src/daemon/lifecycle.ts +0 -4
  208. package/src/daemon/mcp-reload-service.ts +0 -10
  209. package/src/daemon/memory-v2-startup.test.ts +0 -72
  210. package/src/daemon/memory-v2-startup.ts +19 -87
  211. package/src/daemon/message-types/conversations.ts +0 -2
  212. package/src/daemon/message-types/surfaces.ts +12 -12
  213. package/src/daemon/server.ts +4 -0
  214. package/src/daemon/shutdown-handlers.ts +0 -20
  215. package/src/daemon/tool-setup-types.ts +0 -9
  216. package/src/daemon/workspace-tools-watcher.ts +328 -0
  217. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  218. package/src/ipc/assistant-server.ts +2 -2
  219. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  220. package/src/mcp/client.ts +1 -15
  221. package/src/mcp/mcp-auth-orchestrator.ts +1 -6
  222. package/src/mcp/mcp-oauth-provider.ts +8 -19
  223. package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
  224. package/src/memory/conversation-crud.ts +0 -38
  225. package/src/memory/db-connection.ts +3 -22
  226. package/src/memory/db-init.ts +502 -36
  227. package/src/memory/db-singleton.ts +4 -6
  228. package/src/memory/jobs-worker.ts +0 -58
  229. package/src/memory/llm-request-log-store.ts +1 -26
  230. package/src/memory/llm-usage-store.ts +20 -48
  231. package/src/memory/memory-retrospective-job.ts +8 -9
  232. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
  233. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  234. package/src/memory/migrations/registry.ts +573 -0
  235. package/src/memory/migrations/run-migrations.ts +6 -90
  236. package/src/memory/migrations/validate-migration-state.ts +66 -101
  237. package/src/memory/schema/conversations.ts +0 -9
  238. package/src/memory/schema/infrastructure.ts +0 -20
  239. package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
  240. package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
  241. package/src/memory/v2/cli-command-store.ts +38 -75
  242. package/src/memory/v2/prompts/consolidation.ts +82 -13
  243. package/src/memory/v2/prompts/router.ts +93 -21
  244. package/src/memory/v2/skill-store.ts +31 -68
  245. package/src/notifications/__tests__/broadcaster.test.ts +8 -16
  246. package/src/notifications/__tests__/decision-engine.test.ts +9 -78
  247. package/src/notifications/broadcaster.ts +1 -8
  248. package/src/notifications/decision-engine.ts +7 -15
  249. package/src/notifications/destination-resolver.ts +24 -68
  250. package/src/notifications/emit-signal.ts +14 -39
  251. package/src/permissions/question-prompter.test.ts +1 -1
  252. package/src/permissions/question-prompter.ts +4 -7
  253. package/src/plugin-api/index.ts +6 -6
  254. package/src/plugin-api/types.ts +5 -3
  255. package/src/plugin-api/vision-support.test.ts +4 -28
  256. package/src/plugin-api/vision-support.ts +31 -66
  257. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
  258. package/src/plugins/defaults/advisor/consult.ts +6 -110
  259. package/src/plugins/defaults/advisor/steering.ts +2 -14
  260. package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
  261. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
  262. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
  263. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
  264. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
  265. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
  266. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
  267. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
  268. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
  269. package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
  270. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
  271. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
  272. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
  273. package/src/plugins/mtime-cache.ts +291 -76
  274. package/src/plugins/pipeline.ts +13 -111
  275. package/src/plugins/types.ts +2 -0
  276. package/src/providers/anthropic/client.ts +0 -5
  277. package/src/providers/call-site-routing.ts +0 -4
  278. package/src/providers/model-catalog.ts +0 -16
  279. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  280. package/src/providers/openai/chat-completions-provider.ts +83 -37
  281. package/src/providers/openai/responses-provider.ts +46 -50
  282. package/src/providers/openrouter/client.ts +0 -5
  283. package/src/providers/provider-send-message.ts +0 -4
  284. package/src/providers/ratelimit.ts +0 -4
  285. package/src/providers/retry.ts +0 -4
  286. package/src/providers/types.ts +0 -9
  287. package/src/providers/usage-tracking.ts +0 -4
  288. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
  289. package/src/runtime/access-request-helper.ts +39 -19
  290. package/src/runtime/actor-trust-resolver.ts +2 -2
  291. package/src/runtime/assistant-event-hub.ts +1 -1
  292. package/src/runtime/assistant-stream-state.ts +2 -9
  293. package/src/runtime/auth/require-bound-guardian.ts +11 -21
  294. package/src/runtime/channel-verification-service.ts +31 -56
  295. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  296. package/src/runtime/guardian-vellum-migration.ts +7 -66
  297. package/src/runtime/invite-redemption-service.ts +187 -198
  298. package/src/runtime/local-actor-identity.ts +11 -76
  299. package/src/runtime/pending-interactions.ts +1 -11
  300. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
  301. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  302. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
  303. package/src/runtime/routes/browser-routes.ts +1 -1
  304. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
  305. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  306. package/src/runtime/routes/contact-routes.ts +32 -8
  307. package/src/runtime/routes/conversation-cli-routes.ts +5 -4
  308. package/src/runtime/routes/conversation-list-routes.ts +7 -4
  309. package/src/runtime/routes/conversation-query-routes.ts +0 -72
  310. package/src/runtime/routes/conversation-routes.ts +85 -84
  311. package/src/runtime/routes/events-routes.ts +2 -2
  312. package/src/runtime/routes/global-search-routes.ts +1 -3
  313. package/src/runtime/routes/guardian-action-routes.ts +5 -4
  314. package/src/runtime/routes/host-app-control-routes.ts +4 -5
  315. package/src/runtime/routes/host-bash-routes.ts +4 -5
  316. package/src/runtime/routes/host-browser-routes.ts +11 -9
  317. package/src/runtime/routes/host-cu-routes.ts +4 -5
  318. package/src/runtime/routes/host-file-routes.ts +4 -5
  319. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  320. package/src/runtime/routes/http-adapter.ts +1 -1
  321. package/src/runtime/routes/identity-routes.ts +2 -3
  322. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  323. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
  324. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
  325. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
  326. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  327. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
  328. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
  329. package/src/runtime/routes/index.ts +0 -2
  330. package/src/runtime/routes/llm-context-normalization.ts +0 -83
  331. package/src/runtime/routes/mcp-auth-routes.ts +19 -171
  332. package/src/runtime/routes/migration-rollback-routes.ts +3 -4
  333. package/src/runtime/routes/migration-routes.ts +1 -4
  334. package/src/runtime/routes/subagents-routes.ts +0 -5
  335. package/src/runtime/routes/surface-action-routes.ts +56 -42
  336. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
  337. package/src/runtime/services/conversation-serializer.ts +9 -7
  338. package/src/runtime/tool-grant-request-helper.ts +3 -3
  339. package/src/runtime/trust-verdict-consumer.ts +9 -85
  340. package/src/runtime/verification-outbound-actions.ts +18 -18
  341. package/src/signals/user-message.ts +0 -16
  342. package/src/subagent/manager.ts +0 -9
  343. package/src/subagent/types.ts +3 -3
  344. package/src/telemetry/types.ts +1 -34
  345. package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
  346. package/src/telemetry/usage-telemetry-reporter.ts +3 -87
  347. package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
  348. package/src/tools/ask-question/ask-question-tool.ts +0 -13
  349. package/src/tools/executor.ts +4 -4
  350. package/src/tools/registry.ts +0 -18
  351. package/src/tools/shared/filesystem/path-policy.ts +5 -12
  352. package/src/tools/tool-approval-handler.ts +1 -1
  353. package/src/tools/tool-defaults.ts +2 -9
  354. package/src/tools/tool-manifest.ts +0 -3
  355. package/src/tools/types.ts +2 -17
  356. package/src/tools/workspace-tools/loader.ts +244 -348
  357. package/src/util/errors.ts +1 -26
  358. package/src/util/platform.ts +0 -5
  359. package/src/workflows/library.test.ts +0 -140
  360. package/src/workflows/library.ts +28 -82
  361. package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
  362. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
  363. package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
  364. package/src/workspace/migrations/registry.ts +0 -2
  365. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
  366. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
  367. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
  368. package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
  369. package/src/__tests__/code-search-tool.test.ts +0 -585
  370. package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
  371. package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
  372. package/src/__tests__/plugin-pipeline.test.ts +0 -96
  373. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
  374. package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
  375. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
  376. package/src/agent/loop-exclusive-tool.test.ts +0 -150
  377. package/src/api/constants/sse-replay.ts +0 -41
  378. package/src/api/events/conversation-notice.ts +0 -26
  379. package/src/approvals/guardian-channel-delivery.ts +0 -30
  380. package/src/approvals/guardian-expiry-notifier.ts +0 -148
  381. package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
  382. package/src/cli/commands/memory/worker.ts +0 -175
  383. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
  384. package/src/config/prune-seeded-callsite-defaults.ts +0 -110
  385. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
  386. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
  387. package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
  388. package/src/contacts/guardian-delivery-reader.ts +0 -223
  389. package/src/contacts/member-write-relay.ts +0 -189
  390. package/src/daemon/conversation-notices.ts +0 -60
  391. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
  392. package/src/hooks/hook-loader.ts +0 -341
  393. package/src/mcp/mcp-header-store.ts +0 -134
  394. package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
  395. package/src/memory/__tests__/prompt-override.test.ts +0 -192
  396. package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
  397. package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
  398. package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
  399. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
  400. package/src/memory/prompt-override.ts +0 -129
  401. package/src/memory/steps.ts +0 -573
  402. package/src/memory/watchdog-events-store.ts +0 -87
  403. package/src/memory/worker-control.ts +0 -118
  404. package/src/memory/worker-process.ts +0 -72
  405. package/src/notifications/__tests__/connected-channels.test.ts +0 -114
  406. package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
  407. package/src/onboarding/checkin-event.test.ts +0 -222
  408. package/src/onboarding/checkin-event.ts +0 -321
  409. package/src/onboarding/schedule-checkin.ts +0 -190
  410. package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
  411. package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
  412. package/src/plugins/defaults/advisor/context-pack.ts +0 -288
  413. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
  414. package/src/plugins/surface-import.ts +0 -121
  415. package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
  416. package/src/providers/openai/api-error-normalization.ts +0 -270
  417. package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
  418. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
  419. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
  420. package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
  421. package/src/runtime/anchored-guardian.test.ts +0 -156
  422. package/src/runtime/anchored-guardian.ts +0 -135
  423. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
  424. package/src/runtime/local-principal-trust.ts +0 -52
  425. package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
  426. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
  427. package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
  428. package/src/tools/filesystem/search.ts +0 -543
  429. package/src/util/telemetry-db-path.ts +0 -24
  430. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
@@ -3,17 +3,10 @@
3
3
  *
4
4
  * A plugin that gates image processing on vision capability (e.g. an
5
5
  * image-to-text fallback for text-only models) calls {@link doesSupportVision}
6
- * instead of hardcoding model names. One entry point serves both shapes a
7
- * caller might hold:
8
- * - a concrete model id (e.g. the provider-reported model that just ran), and
9
- * - a profile either a {@link ModelProfileInfo} or a bare profile key —
10
- * resolved through `llm.profiles` to an effective `(provider, model)`.
11
- *
12
- * A bare string is tried as a model id first and then as a profile key, so the
13
- * two callers share one function. Resolution returns `false` when nothing
14
- * resolves (rather than failing open): a consumer gating an image→text
15
- * fallback wants an unknown model treated as "can't show images" — caption it —
16
- * over silently shipping a raw image to a provider that may reject it.
6
+ * instead of hardcoding model names. The function resolves the effective
7
+ * (provider, model) for a profile — merging with `llm.default` to fill gaps,
8
+ * inferring the provider for model-only profiles via the catalog and then
9
+ * looks up `supportsVision` in the model catalog.
17
10
  */
18
11
 
19
12
  import { getConfig } from "../config/loader.js";
@@ -24,74 +17,46 @@ import {
24
17
  import type { ModelProfileInfo } from "./types.js";
25
18
 
26
19
  /**
27
- * Whether the given model or profile can process image input.
20
+ * Whether a profile's resolved model can process image input.
28
21
  *
29
- * `modelOrProfile` may be a concrete model id, a profile key, or a
30
- * {@link ModelProfileInfo}. A bare string is resolved as a model id first and,
31
- * failing that, as a profile key. Returns `false` when nothing resolves.
32
- */
33
- export function doesSupportVision(
34
- modelOrProfile: ModelProfileInfo | string,
35
- ): boolean {
36
- if (typeof modelOrProfile === "string") {
37
- // Concrete model id first, then fall back to treating it as a profile key.
38
- return (
39
- modelVision(modelOrProfile) ?? profileVision(modelOrProfile) ?? false
40
- );
41
- }
42
- return profileVision(modelOrProfile.key) ?? false;
43
- }
44
-
45
- /**
46
- * Catalog vision flag for a concrete model id, or `undefined` when the catalog
47
- * doesn't know the model. The same model id carries the same capability under
48
- * every provider that offers it, so the first catalog match wins.
22
+ * Resolution mirrors the host's call-site resolver:
23
+ * - The profile's `(provider, model)` fields are merged over `llm.default` so
24
+ * a profile that only sets `model` (or only `provider`) inherits the other
25
+ * from the workspace default.
26
+ * - When `provider` is still missing but `model` is a known catalog model,
27
+ * the provider is inferred via `getCatalogProviderForModel` (same logic as
28
+ * the resolver's `withImpliedProviderForKnownModel`).
29
+ * - For a mix profile, returns `true` if any constituent arm supports vision
30
+ * (the mix can route to it) and `false` only if every arm is text-only.
31
+ * - Unknown `(provider, model)` pairs default to `true` (fail-open), matching
32
+ * the config GET route's `enrichProfilesWithVisionFlag`.
49
33
  */
50
- function modelVision(model: string): boolean | undefined {
51
- for (const provider of PROVIDER_CATALOG) {
52
- const catalogModel = provider.models.find((m) => m.id === model);
53
- if (catalogModel != null) return catalogModel.supportsVision ?? false;
54
- }
55
- return undefined;
56
- }
57
-
58
- /**
59
- * Resolve a profile key through `llm.profiles` to its vision capability, or
60
- * `undefined` when the key is unknown or resolves to a model the catalog
61
- * doesn't know. A mix profile resolves to `true` if any arm supports vision
62
- * (the mix can route to it) and `false` only once every arm is a known
63
- * text-only model.
64
- */
65
- function profileVision(profileKey: string): boolean | undefined {
34
+ export function doesSupportVision(profile: ModelProfileInfo): boolean {
66
35
  const { llm } = getConfig();
67
- const entry = llm.profiles[profileKey];
68
- if (entry == null) return undefined;
36
+ const entry = llm.profiles[profile.key];
37
+ if (entry == null) return true;
69
38
 
39
+ // Mix: fail-open if any arm supports vision.
70
40
  if (entry.mix != null) {
71
- let sawUnknown = false;
72
- for (const arm of entry.mix) {
41
+ return entry.mix.some((arm) => {
73
42
  const armEntry = llm.profiles[arm.profile];
74
- const armVision =
75
- armEntry == null ? undefined : resolveEntryVision(armEntry, llm);
76
- if (armVision === true) return true;
77
- if (armVision == null) sawUnknown = true;
78
- }
79
- return sawUnknown ? undefined : false;
43
+ if (armEntry == null) return true;
44
+ return resolveEntrySupportsVision(armEntry, llm);
45
+ });
80
46
  }
81
47
 
82
- return resolveEntryVision(entry, llm);
48
+ return resolveEntrySupportsVision(entry, llm);
83
49
  }
84
50
 
85
51
  /**
86
52
  * Resolve whether a concrete (non-mix) profile entry supports vision by
87
- * merging its fields over `llm.default` and inferring the provider when only
88
- * the model is set. Returns `undefined` when the effective `(provider, model)`
89
- * can't be determined or isn't in the catalog.
53
+ * merging its fields over `llm.default` and inferring the provider when
54
+ * only the model is set.
90
55
  */
91
- function resolveEntryVision(
56
+ function resolveEntrySupportsVision(
92
57
  entry: { provider?: string; model?: string },
93
58
  llm: { default?: { provider?: string; model?: string } },
94
- ): boolean | undefined {
59
+ ): boolean {
95
60
  const provider = entry.provider ?? llm.default?.provider;
96
61
  const model = entry.model ?? llm.default?.model;
97
62
 
@@ -102,12 +67,12 @@ function resolveEntryVision(
102
67
  (typeof model === "string" ? getCatalogProviderForModel(model) : undefined);
103
68
 
104
69
  if (typeof effectiveProvider !== "string" || typeof model !== "string") {
105
- return undefined;
70
+ return true; // fail-open
106
71
  }
107
72
 
108
73
  const catalogProvider = PROVIDER_CATALOG.find(
109
74
  (p) => p.id === effectiveProvider,
110
75
  );
111
76
  const catalogModel = catalogProvider?.models.find((m) => m.id === model);
112
- return catalogModel?.supportsVision;
77
+ return catalogModel?.supportsVision ?? true;
113
78
  }
@@ -8,26 +8,12 @@ let sendMessageArgs: Record<string, unknown> | null = null;
8
8
  let responseText = "Use a channel-based worker pool; drain on shutdown.";
9
9
  let sendMessageError: Error | null = null;
10
10
  let providerResolves = true;
11
- let providerSupportsWeb = false;
12
- let streamDeltas: string[] = [];
13
- let streamEvents: Array<Record<string, unknown>> = [];
14
11
 
15
12
  const fakeProvider = {
16
13
  name: "mock-advisor-provider",
17
- get supportsNativeWebSearch() {
18
- return providerSupportsWeb;
19
- },
20
14
  async sendMessage(messages: unknown, options: unknown) {
21
15
  sendMessageArgs = { messages, options } as Record<string, unknown>;
22
16
  if (sendMessageError) throw sendMessageError;
23
- const onEvent = (
24
- options as { onEvent?: (e: Record<string, unknown>) => void }
25
- ).onEvent;
26
- if (onEvent) {
27
- // Activity (search/thinking) streams before the final advice text.
28
- for (const ev of streamEvents) onEvent(ev);
29
- for (const text of streamDeltas) onEvent({ type: "text_delta", text });
30
- }
31
17
  return {
32
18
  content: [{ type: "text", text: responseText }],
33
19
  model: "mock-model",
@@ -43,14 +29,6 @@ mock.module("../../../../providers/provider-send-message.js", () => ({
43
29
  getConfiguredProvider: async () => (providerResolves ? fakeProvider : null),
44
30
  }));
45
31
 
46
- // Keep the tool tests focused on the consult wiring: stub the context pack so
47
- // they don't reach into the registry / workspace / memory sources (those have
48
- // their own coverage). The consult itself never imports this module.
49
- mock.module("../context-pack.js", () => ({
50
- buildAdvisorContext: async () => null,
51
- deriveRecallQuery: () => null,
52
- }));
53
-
54
32
  const { consultAdvisor } = await import("../consult.js");
55
33
  const advisorTool = (await import("../tools/advisor.js")).default;
56
34
  const { recordSystemPrompt, recordMessages, resetAdvisorStateForTests } =
@@ -71,9 +49,6 @@ beforeEach(() => {
71
49
  responseText = "Use a channel-based worker pool; drain on shutdown.";
72
50
  sendMessageError = null;
73
51
  providerResolves = true;
74
- providerSupportsWeb = false;
75
- streamDeltas = [];
76
- streamEvents = [];
77
52
  resetAdvisorStateForTests();
78
53
  });
79
54
 
@@ -125,104 +100,6 @@ describe("consultAdvisor", () => {
125
100
  expect(options.systemPrompt).toContain("You are a coding agent.");
126
101
  });
127
102
 
128
- test("stays tool-less when the provider has no native web search", async () => {
129
- providerSupportsWeb = false;
130
- await consultAdvisor({ systemPrompt: null, messages: [userMsg("hi")] });
131
- const options = sendMessageArgs?.options as { tools?: unknown };
132
- expect(options.tools).toBeUndefined();
133
- expect(optionConfig().tool_choice).toEqual({ type: "none" });
134
- });
135
-
136
- test("enables native web search when the provider supports it", async () => {
137
- providerSupportsWeb = true;
138
- await consultAdvisor({ systemPrompt: null, messages: [userMsg("hi")] });
139
-
140
- const options = sendMessageArgs?.options as {
141
- tools?: Array<{ name: string }>;
142
- };
143
- expect(options.tools?.map((t) => t.name)).toEqual(["web_search"]);
144
- // tool_choice must not be `none`, or the provider suppresses its server tool.
145
- expect(optionConfig().tool_choice).toEqual({ type: "auto" });
146
- });
147
-
148
- test("streams web-search activity to onText, not just the final advice", async () => {
149
- providerSupportsWeb = true;
150
- streamEvents = [
151
- { type: "server_tool_start", name: "web_search", toolUseId: "s1", input: {} },
152
- {
153
- type: "server_tool_complete",
154
- toolUseId: "s1",
155
- isError: false,
156
- resolvedInput: { query: "vellum streaming" },
157
- },
158
- ];
159
- streamDeltas = ["Here is ", "the advice."];
160
- const chunks: string[] = [];
161
-
162
- await consultAdvisor({
163
- systemPrompt: null,
164
- messages: [userMsg("hi")],
165
- onText: (c) => chunks.push(c),
166
- });
167
-
168
- const joined = chunks.join("");
169
- // The drawer isn't silent during the search prefix...
170
- expect(joined).toContain("Searching the web");
171
- expect(joined).toContain("Searched: vellum streaming");
172
- // ...and the advice text still streams.
173
- expect(joined).toContain("Here is the advice.");
174
- });
175
-
176
- test("surfaces a failure note (not 'Searched') when a web search errors", async () => {
177
- providerSupportsWeb = true;
178
- streamEvents = [
179
- { type: "server_tool_start", name: "web_search", toolUseId: "s1", input: {} },
180
- {
181
- type: "server_tool_complete",
182
- toolUseId: "s1",
183
- isError: true,
184
- errorCode: "query_too_long",
185
- resolvedInput: { query: "an overly long query" },
186
- },
187
- ];
188
- streamDeltas = ["Proceeding without search."];
189
- const chunks: string[] = [];
190
-
191
- await consultAdvisor({
192
- systemPrompt: null,
193
- messages: [userMsg("hi")],
194
- onText: (c) => chunks.push(c),
195
- });
196
-
197
- const joined = chunks.join("");
198
- expect(joined).toContain("Web search failed");
199
- expect(joined).not.toContain("🔎 Searched:");
200
- // The consult still continues and streams its guidance.
201
- expect(joined).toContain("Proceeding without search.");
202
- });
203
-
204
- test("streams the model's reasoning summary to onText", async () => {
205
- streamEvents = [{ type: "thinking_delta", thinking: "weighing tradeoffs" }];
206
- const chunks: string[] = [];
207
- await consultAdvisor({
208
- systemPrompt: null,
209
- messages: [userMsg("hi")],
210
- onText: (c) => chunks.push(c),
211
- });
212
- expect(chunks.join("")).toContain("weighing tradeoffs");
213
- });
214
-
215
- test("embeds the runtime context in the advisor system prompt", async () => {
216
- await consultAdvisor({
217
- systemPrompt: "You are a coding agent.",
218
- messages: [userMsg("hi")],
219
- runtimeContext: "## Available tools\n- bash — run commands",
220
- });
221
- const options = sendMessageArgs?.options as { systemPrompt: string };
222
- expect(options.systemPrompt).toContain("<agent_runtime_context>");
223
- expect(options.systemPrompt).toContain("- bash — run commands");
224
- });
225
-
226
103
  test("soft-fails when no provider is configured", async () => {
227
104
  providerResolves = false;
228
105
  const advice = await consultAdvisor({
@@ -246,29 +123,6 @@ describe("consultAdvisor", () => {
246
123
  });
247
124
  expect(advice).toContain("no guidance");
248
125
  });
249
-
250
- test("streams the model's text deltas to `onText` as it generates", async () => {
251
- streamDeltas = ["Use a ", "channel-based ", "worker pool."];
252
- const chunks: string[] = [];
253
-
254
- const advice = await consultAdvisor({
255
- systemPrompt: null,
256
- messages: [userMsg("hi")],
257
- onText: (c) => chunks.push(c),
258
- });
259
-
260
- // Each visible delta is forwarded live...
261
- expect(chunks).toEqual(["Use a ", "channel-based ", "worker pool."]);
262
- // ...and the complete guidance is still returned.
263
- expect(advice).toBe(responseText);
264
- });
265
-
266
- test("registers no `onEvent` sink when `onText` is absent", async () => {
267
- streamDeltas = ["x"];
268
- await consultAdvisor({ systemPrompt: null, messages: [userMsg("hi")] });
269
- const options = sendMessageArgs?.options as { onEvent?: unknown };
270
- expect(options.onEvent).toBeUndefined();
271
- });
272
126
  });
273
127
 
274
128
  describe("advisor tool.execute", () => {
@@ -296,19 +150,4 @@ describe("advisor tool.execute", () => {
296
150
  expect(result?.content).toContain("advisor unavailable");
297
151
  expect(result?.content).toContain("kaboom");
298
152
  });
299
-
300
- test("streams the consult live via `ctx.onOutput`", async () => {
301
- recordMessages("c3", [userMsg("hi")]);
302
- streamDeltas = ["plan: ", "do X"];
303
- const out: string[] = [];
304
-
305
- const result = await advisorTool.execute?.({}, {
306
- conversationId: "c3",
307
- onOutput: (c: string) => out.push(c),
308
- } as never);
309
-
310
- expect(out).toEqual(["plan: ", "do X"]);
311
- expect(result?.isError).toBe(false);
312
- expect(result?.content).toBe(responseText);
313
- });
314
153
  });
@@ -16,11 +16,7 @@ import {
16
16
  getConfiguredProvider,
17
17
  userMessage,
18
18
  } from "../../../providers/provider-send-message.js";
19
- import type {
20
- Message,
21
- ProviderEvent,
22
- ToolDefinition,
23
- } from "../../../providers/types.js";
19
+ import type { Message } from "../../../providers/types.js";
24
20
  import { ADVISOR_CONFIG } from "./config.js";
25
21
  import { advisorRequestText, buildAdvisorSystem } from "./steering.js";
26
22
  import { toAdvisorMessages } from "./transcript.js";
@@ -30,26 +26,6 @@ import { toAdvisorMessages } from "./transcript.js";
30
26
  // on via `llm.advisorProfile`, which we float above the call-site layers.
31
27
  const ADVISOR_CALL_SITE: LLMCallSite = "advisor";
32
28
 
33
- /**
34
- * The single tool the consult may attach: a `web_search`-named tool that
35
- * provider-native search (Anthropic/OpenAI) substitutes for its server-side
36
- * web tool. Only passed when `provider.supportsNativeWebSearch` is true, so the
37
- * provider runs the search itself and returns results inline — no agent loop,
38
- * which keeps the consult a one-shot completion.
39
- */
40
- const ADVISOR_WEB_SEARCH_TOOL: ToolDefinition = {
41
- name: "web_search",
42
- description:
43
- "Search the web for current information to ground your guidance.",
44
- input_schema: {
45
- type: "object",
46
- properties: {
47
- query: { type: "string", description: "The search query." },
48
- },
49
- required: ["query"],
50
- },
51
- };
52
-
53
29
  /**
54
30
  * Resolve the routing override for the advisor consult. When the workspace has
55
31
  * set `llm.advisorProfile`, force it above the call-site layers so it is
@@ -69,22 +45,7 @@ function advisorOverride(): {
69
45
  export interface ConsultParams {
70
46
  systemPrompt: string | null;
71
47
  messages: ReadonlyArray<Message>;
72
- /**
73
- * The agent's runtime context (available tools and skills, workspace/project
74
- * context, recalled memory), gathered by the tool from its `ToolContext`.
75
- * Embedded in the advisor's system prompt so its advice is grounded in what
76
- * the agent can actually do. Omitted/null when nothing could be gathered.
77
- */
78
- runtimeContext?: string | null;
79
48
  signal?: AbortSignal;
80
- /**
81
- * Optional sink for the advisor's live activity as it generates: incremental
82
- * advice text, the reasoning summary (when surfaced), and a note per web
83
- * search. Wiring this to the tool's `onOutput` surfaces the consult live as
84
- * `tool_output_chunk` while the advisor is still working; the complete
85
- * guidance is still returned as the resolved string. See `advisorActivitySink`.
86
- */
87
- onText?: (chunk: string) => void;
88
49
  }
89
50
 
90
51
  /** Combine the caller's signal with a consult timeout. */
@@ -93,55 +54,6 @@ function withTimeout(signal: AbortSignal | undefined, ms: number): AbortSignal {
93
54
  return signal ? AbortSignal.any([signal, timeout]) : timeout;
94
55
  }
95
56
 
96
- /**
97
- * Build the streaming sink for a consult: forward the advisor's live activity
98
- * to `onText` so the tool-output drawer streams throughout the consult instead
99
- * of sitting silent until the final advice lands.
100
- *
101
- * The consult searches the web (up to 5×) and reasons over full context before
102
- * writing its guidance. Forwarding the visible advice text alone would leave
103
- * the drawer blank for that whole prefix, so the sink also surfaces the
104
- * reasoning summary (when the model emits one) and a one-line note per web
105
- * search — a success note with the query, or a failure note when the search
106
- * errors. The complete guidance is still returned by `consultAdvisor`; the
107
- * renderer swaps it in once the tool result arrives.
108
- */
109
- function advisorActivitySink(
110
- onText: (chunk: string) => void,
111
- ): (event: ProviderEvent) => void {
112
- return (event) => {
113
- switch (event.type) {
114
- case "text_delta":
115
- if (event.text) onText(event.text);
116
- break;
117
- case "thinking_delta":
118
- if (event.thinking) onText(event.thinking);
119
- break;
120
- case "server_tool_start":
121
- if (event.name === "web_search") onText("\n🔎 Searching the web…\n");
122
- break;
123
- case "server_tool_complete": {
124
- const rawQuery = event.resolvedInput?.["query"];
125
- const query = typeof rawQuery === "string" ? rawQuery.trim() : "";
126
- if (event.isError) {
127
- // A failed search (e.g. `query_too_long`, `max_uses_exceeded`) must
128
- // not be announced as a success — the advisor proceeds without it.
129
- onText(
130
- query
131
- ? `\n⚠️ Web search failed: ${query}\n`
132
- : "\n⚠️ Web search failed.\n",
133
- );
134
- } else if (query) {
135
- onText(`\n🔎 Searched: ${query}\n`);
136
- }
137
- break;
138
- }
139
- default:
140
- break;
141
- }
142
- };
143
- }
144
-
145
57
  /**
146
58
  * Returns the advisor's guidance text, or a short benign notice when the
147
59
  * advisor can't run. Callers should surface the string as a non-error tool
@@ -161,33 +73,17 @@ export async function consultAdvisor(params: ConsultParams): Promise<string> {
161
73
  }
162
74
 
163
75
  // Append the consult instruction as the final user turn, then run a
164
- // completion through the resolved provider. No `max_tokens` is set, so the
165
- // resolver applies the profile's normal output budget rather than an
166
- // advisor-specific cap.
76
+ // tool-less completion through the resolved provider. No `max_tokens` is
77
+ // set, so the resolver applies the profile's normal output budget rather
78
+ // than an advisor-specific cap.
167
79
  const messages: Message[] = [...history, userMessage(advisorRequestText())];
168
80
 
169
- // Give the advisor live web access when — and only when — the resolved
170
- // provider runs search server-side (provider-native). Passing a `web_search`
171
- // tool to a non-native provider would surface a client tool call this
172
- // one-shot consult cannot execute, so we gate strictly on the capability and
173
- // otherwise keep the consult tool-less.
174
- const webEnabled = provider.supportsNativeWebSearch === true;
175
-
176
- const { onText } = params;
177
81
  const response = await provider.sendMessage(messages, {
178
- systemPrompt: buildAdvisorSystem(
179
- params.systemPrompt,
180
- params.runtimeContext,
181
- ),
182
- ...(webEnabled ? { tools: [ADVISOR_WEB_SEARCH_TOOL] } : {}),
183
- // Stream the consult's activity live (advice text, reasoning summary, and a
184
- // note per web search) so the drawer isn't blank while the advisor searches
185
- // and reasons before writing its guidance. See `advisorActivitySink`.
186
- onEvent: onText ? advisorActivitySink(onText) : undefined,
82
+ systemPrompt: buildAdvisorSystem(params.systemPrompt),
187
83
  config: {
188
84
  callSite: ADVISOR_CALL_SITE,
189
85
  ...override,
190
- tool_choice: webEnabled ? { type: "auto" } : { type: "none" },
86
+ tool_choice: { type: "none" },
191
87
  },
192
88
  signal: withTimeout(params.signal, ADVISOR_CONFIG.timeoutMs),
193
89
  });
@@ -33,15 +33,9 @@ export function stripSteering(systemPrompt: string | null): string | null {
33
33
  * System prompt for the advisor sub-call. Frames the advisor's role and, for
34
34
  * context, quotes the executor's own system prompt (as the advisor tool does —
35
35
  * the advisor sees the system prompt as context about the executor's task).
36
- *
37
- * `runtimeContext`, when present, carries the agent's situational context that
38
- * lives outside its system prompt — available tools and skills, workspace /
39
- * project context, and recalled memory (see `buildAdvisorContext`) — so the
40
- * advisor can ground its recommendations in what the agent can actually do.
41
36
  */
42
37
  export function buildAdvisorSystem(
43
38
  originalSystemPrompt: string | null,
44
- runtimeContext?: string | null,
45
39
  ): string {
46
40
  const base = `You are a senior advisor consulted by another AI agent working on a task — most often at the planning stage, before it starts building, but sometimes partway through. The entire conversation above is the agent's working context: its task or goal, every tool call it has made, and every result it has seen. The agent has paused to consult you because you bring a second, independent perspective it cannot get from inside its own reasoning loop. Your job is to maximize its odds of completing the task correctly and efficiently.
47
41
 
@@ -60,14 +54,8 @@ How to advise:
60
54
  - Stay in your lane. Advise the agent; do not role-play as it, write its final deliverable, or take its next action for it. If the agent is already on the right track, confirm it and sharpen the plan rather than manufacturing objections.
61
55
 
62
56
  Write as much as the guidance genuinely needs, and no more.`;
63
- let prompt = base;
64
- if (originalSystemPrompt) {
65
- prompt += `\n\nFor context, the agent is operating under this system prompt:\n<agent_system_prompt>\n${originalSystemPrompt}\n</agent_system_prompt>`;
66
- }
67
- if (runtimeContext) {
68
- prompt += `\n\nThe agent's runtime context — the tools and skills available to it, the loaded workspace/project context, and relevant memory — follows. Ground your recommendations in what the agent can actually do and what is around it; reference specific tools, skills, files, or memory where relevant.\n<agent_runtime_context>\n${runtimeContext}\n</agent_runtime_context>`;
69
- }
70
- return prompt;
57
+ if (!originalSystemPrompt) return base;
58
+ return `${base}\n\nFor context, the agent is operating under this system prompt:\n<agent_system_prompt>\n${originalSystemPrompt}\n</agent_system_prompt>`;
71
59
  }
72
60
 
73
61
  /**
@@ -19,26 +19,19 @@ import { RiskLevel } from "@vellumai/plugin-api";
19
19
  import { advisorEnabledForProfile } from "../advisor-gate.js";
20
20
  import { getCapture } from "../advisor-state-store.js";
21
21
  import { consultAdvisor } from "../consult.js";
22
- import { buildAdvisorContext } from "../context-pack.js";
23
22
 
24
23
  const advisorTool: ToolDefinition = {
25
24
  name: "advisor",
26
25
  description:
27
26
  "Consult a stronger advisor model to shape your plan and get strategic guidance. " +
28
27
  "Takes NO parameters — your full conversation (the task, every tool call, and every " +
29
- "result) is forwarded automatically, along with your available tools and skills, the " +
30
- "workspace/project context, and relevant memory. Call it BEFORE you start building: it " +
31
- "can lay out a plan when you don't have one yet, or review and sharpen the plan you've " +
32
- "already drafted. Also call it when you're stuck, when weighing a change in approach, and " +
33
- "once before declaring a task complete. It runs on its own — if you call it alongside " +
34
- "other tools, those are held back until you've seen its guidance. Give its guidance " +
35
- "serious weight.",
28
+ "result) is forwarded automatically. Call it BEFORE you start building: it can lay out " +
29
+ "a plan when you don't have one yet, or review and sharpen the plan you've already " +
30
+ "drafted. Also call it when you're stuck, when weighing a change in approach, and once " +
31
+ "before declaring a task complete. Give its guidance serious weight.",
36
32
  input_schema: { type: "object", properties: {}, additionalProperties: false },
37
33
  // Read-only advice; low risk so the consult isn't gated behind a prompt.
38
34
  defaultRiskLevel: RiskLevel.Low,
39
- // Runs alone in its turn: the loop defers any sibling tool calls so the model
40
- // incorporates the advisor's guidance before acting on anything else.
41
- exclusive: true,
42
35
  async execute(
43
36
  _input: Record<string, unknown>,
44
37
  ctx: ToolContext,
@@ -55,30 +48,10 @@ const advisorTool: ToolDefinition = {
55
48
  }
56
49
  try {
57
50
  const capture = getCapture(ctx.conversationId);
58
- const messages = capture?.messages ?? [];
59
- // Gather the agent's situational context (tools, skills, workspace,
60
- // memory) so the advisor reasons with the same awareness the agent has.
61
- // Best-effort: a failure here must not block the consult.
62
- const runtimeContext = await buildAdvisorContext({
63
- conversationId: ctx.conversationId,
64
- workingDir: ctx.workingDir,
65
- allowedToolNames: ctx.allowedToolNames,
66
- // Per-turn trust snapshot — gates personal-memory surfaces off the same
67
- // values the executor captured for this invocation, not live state.
68
- trustClass: ctx.trustClass,
69
- sourceChannel: ctx.executionChannel,
70
- transcript: messages,
71
- signal: ctx.signal,
72
- }).catch(() => null);
73
51
  const advice = await consultAdvisor({
74
52
  systemPrompt: capture?.systemPrompt ?? null,
75
- messages,
76
- runtimeContext,
53
+ messages: capture?.messages ?? [],
77
54
  signal: ctx.signal,
78
- // Stream the advisor's guidance live as it generates: each delta is
79
- // surfaced as a `tool_output_chunk` for this tool call and rendered in
80
- // the tool-detail drawer. The complete text is still returned below.
81
- onText: (chunk) => ctx.onOutput?.(chunk),
82
55
  });
83
56
  return { content: advice, isError: false };
84
57
  } catch (err) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Default `post-tool-use` hook: when a turn's exploration tool calls (bash,
3
- * code_search, file_read, file_list) show drift — a long unbroken run with no text sent to
3
+ * file_read, file_list) show drift — a long unbroken run with no text sent to
4
4
  * the user, or the model re-issuing the exact same call — surface a notice
5
5
  * via `additionalContext` that coaches it to (a) give the user a brief
6
6
  * progress summary and (b) delegate the rest of the investigation to an
@@ -105,7 +105,6 @@ const LOOP_PRONE_MODEL_PATTERN = /kimi-k2[p.]6|minimax-m3/i;
105
105
  /** Read-only exploration tools whose unbroken runs indicate inline drift. */
106
106
  const EXPLORATION_TOOL_NAMES: ReadonlySet<string> = new Set([
107
107
  "bash",
108
- "code_search",
109
108
  "file_read",
110
109
  "file_list",
111
110
  ]);