@vellumai/assistant 0.8.5 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/AGENTS.md +33 -1
  2. package/ARCHITECTURE.md +1 -1
  3. package/bunfig.toml +6 -1
  4. package/docs/credential-execution-service.md +6 -6
  5. package/docs/plugins.md +4 -3
  6. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
  7. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
  8. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
  9. package/openapi.yaml +1900 -166
  10. package/package.json +1 -1
  11. package/src/__tests__/actor-token-service.test.ts +3 -2
  12. package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
  13. package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
  14. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  15. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  16. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  17. package/src/__tests__/annotate-risk-options.test.ts +1 -0
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/approval-routes-http.test.ts +9 -13
  20. package/src/__tests__/assert-not-live-db.ts +79 -0
  21. package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
  22. package/src/__tests__/audit-log-rotation.test.ts +2 -2
  23. package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
  24. package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
  25. package/src/__tests__/browser-skill-endstate.test.ts +3 -3
  26. package/src/__tests__/btw-routes.test.ts +3 -2
  27. package/src/__tests__/call-controller.test.ts +3 -2
  28. package/src/__tests__/channel-approval-routes.test.ts +3 -2
  29. package/src/__tests__/channel-guardian.test.ts +3 -2
  30. package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
  31. package/src/__tests__/channel-reply-delivery.test.ts +35 -0
  32. package/src/__tests__/channel-retry-sweep.test.ts +320 -3
  33. package/src/__tests__/checker.test.ts +12 -12
  34. package/src/__tests__/compaction-events.test.ts +1 -0
  35. package/src/__tests__/compaction-trail-store.test.ts +264 -0
  36. package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
  37. package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
  38. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
  39. package/src/__tests__/computer-use-tools.test.ts +12 -14
  40. package/src/__tests__/config-loader-backfill.test.ts +13 -28
  41. package/src/__tests__/config-loader-corrupt.test.ts +5 -5
  42. package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
  43. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
  44. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
  45. package/src/__tests__/config-schema.test.ts +10 -10
  46. package/src/__tests__/connection-model-compat.test.ts +83 -0
  47. package/src/__tests__/contacts-tools.test.ts +3 -2
  48. package/src/__tests__/context-token-estimator.test.ts +22 -0
  49. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
  50. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
  52. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  53. package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
  54. package/src/__tests__/conversation-agent-loop.test.ts +488 -2
  55. package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
  56. package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
  57. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
  58. package/src/__tests__/conversation-attention-store.test.ts +101 -0
  59. package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  61. package/src/__tests__/conversation-error.test.ts +30 -0
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -8
  63. package/src/__tests__/conversation-fork-route.test.ts +3 -2
  64. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  65. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
  66. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
  67. package/src/__tests__/conversation-lifecycle.test.ts +1 -0
  68. package/src/__tests__/conversation-list-source.test.ts +3 -2
  69. package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
  70. package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
  71. package/src/__tests__/conversation-pairing.test.ts +53 -0
  72. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
  73. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  74. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
  75. package/src/__tests__/conversation-queue.test.ts +333 -291
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
  80. package/src/__tests__/conversation-skill-tools.test.ts +38 -142
  81. package/src/__tests__/conversation-slash-queue.test.ts +84 -32
  82. package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
  83. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
  85. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
  90. package/src/__tests__/conversation-sync-tags.test.ts +128 -12
  91. package/src/__tests__/conversation-title-service.test.ts +1 -0
  92. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
  93. package/src/__tests__/conversation-usage.test.ts +1 -0
  94. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  95. package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
  96. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
  97. package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
  98. package/src/__tests__/credential-broker-server-use.test.ts +5 -5
  99. package/src/__tests__/credential-execution-client.test.ts +72 -1
  100. package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
  101. package/src/__tests__/credential-health-service.test.ts +252 -3
  102. package/src/__tests__/credential-security-invariants.test.ts +5 -5
  103. package/src/__tests__/credential-vault-unit.test.ts +19 -19
  104. package/src/__tests__/credential-vault.test.ts +5 -5
  105. package/src/__tests__/cross-provider-web-search.test.ts +56 -2
  106. package/src/__tests__/db-connection-isolation.test.ts +7 -6
  107. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
  108. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
  109. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
  110. package/src/__tests__/db-test-helpers.ts +58 -0
  111. package/src/__tests__/disk-pressure-guard.test.ts +58 -41
  112. package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
  113. package/src/__tests__/disk-pressure-routes.test.ts +0 -33
  114. package/src/__tests__/disk-pressure-tools.test.ts +0 -4
  115. package/src/__tests__/dm-persistence.test.ts +26 -40
  116. package/src/__tests__/document-create-dedupe.test.ts +189 -0
  117. package/src/__tests__/document-find-replace.test.ts +3 -2
  118. package/src/__tests__/document-tool-security.test.ts +81 -2
  119. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
  120. package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
  121. package/src/__tests__/encrypted-store.test.ts +11 -9
  122. package/src/__tests__/feature-flag-test-helpers.ts +53 -0
  123. package/src/__tests__/filing-service.test.ts +1 -0
  124. package/src/__tests__/first-greeting.test.ts +62 -12
  125. package/src/__tests__/gateway-flag-listener.test.ts +0 -1
  126. package/src/__tests__/gemini-provider.test.ts +26 -0
  127. package/src/__tests__/guardian-action-sweep.test.ts +3 -2
  128. package/src/__tests__/guardian-outbound-http.test.ts +3 -2
  129. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
  130. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
  131. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  132. package/src/__tests__/heartbeat-service.test.ts +1 -0
  133. package/src/__tests__/helpers/mock-logger.ts +26 -0
  134. package/src/__tests__/host-bash-routes.test.ts +1 -0
  135. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
  136. package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
  137. package/src/__tests__/host-shell-tool.test.ts +5 -4
  138. package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
  139. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  140. package/src/__tests__/http-user-message-parity.test.ts +29 -7
  141. package/src/__tests__/identity-intro-cache.test.ts +133 -22
  142. package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
  143. package/src/__tests__/inference-profile-reaper.test.ts +3 -2
  144. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
  145. package/src/__tests__/injector-disk-pressure.test.ts +3 -17
  146. package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
  147. package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
  148. package/src/__tests__/llm-context-normalization.test.ts +42 -0
  149. package/src/__tests__/llm-resolver.test.ts +331 -0
  150. package/src/__tests__/llm-schema.test.ts +1 -1
  151. package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
  152. package/src/__tests__/mcp-abort-signal.test.ts +14 -0
  153. package/src/__tests__/mcp-client-auth.test.ts +14 -0
  154. package/src/__tests__/messaging-send-tool.test.ts +1 -0
  155. package/src/__tests__/migration-import-from-url.test.ts +3 -3
  156. package/src/__tests__/mock-gateway-ipc.ts +18 -2
  157. package/src/__tests__/model-intents.test.ts +3 -3
  158. package/src/__tests__/native-web-search.test.ts +30 -2
  159. package/src/__tests__/notification-deep-link.test.ts +62 -0
  160. package/src/__tests__/oauth-commands-routes.test.ts +37 -0
  161. package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
  162. package/src/__tests__/oauth-store.test.ts +3 -2
  163. package/src/__tests__/onboarding-template-contract.test.ts +3 -2
  164. package/src/__tests__/openai-provider.test.ts +8 -9
  165. package/src/__tests__/openai-responses-provider.test.ts +70 -10
  166. package/src/__tests__/openrouter-provider-only.test.ts +27 -5
  167. package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
  168. package/src/__tests__/persistence-pipeline.test.ts +139 -1
  169. package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
  170. package/src/__tests__/plugin-bootstrap.test.ts +9 -11
  171. package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
  172. package/src/__tests__/process-message-background-slack.test.ts +21 -16
  173. package/src/__tests__/process-message-display-content.test.ts +19 -22
  174. package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
  175. package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
  176. package/src/__tests__/provider-registry-ollama.test.ts +45 -22
  177. package/src/__tests__/recording-handler.test.ts +1 -0
  178. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  179. package/src/__tests__/registry.test.ts +82 -76
  180. package/src/__tests__/relay-server.test.ts +10 -10
  181. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
  182. package/src/__tests__/schedule-store.test.ts +16 -1
  183. package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
  184. package/src/__tests__/secret-ingress-http.test.ts +5 -1
  185. package/src/__tests__/secure-keys.test.ts +3 -3
  186. package/src/__tests__/send-endpoint-busy.test.ts +81 -42
  187. package/src/__tests__/server-history-render.test.ts +4 -1
  188. package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
  189. package/src/__tests__/skill-feature-flags.test.ts +14 -16
  190. package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
  191. package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
  192. package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
  193. package/src/__tests__/skill-tool-factory.test.ts +96 -95
  194. package/src/__tests__/slack-channel-config.test.ts +3 -3
  195. package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
  196. package/src/__tests__/subagent-disposal.test.ts +27 -8
  197. package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
  198. package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
  199. package/src/__tests__/subagent-manager-notify.test.ts +20 -8
  200. package/src/__tests__/subagent-notify-parent.test.ts +5 -4
  201. package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
  202. package/src/__tests__/subagent-tools.test.ts +2 -1
  203. package/src/__tests__/suggestion-routes.test.ts +1 -0
  204. package/src/__tests__/system-prompt.test.ts +38 -0
  205. package/src/__tests__/test-preload-verifier.ts +68 -0
  206. package/src/__tests__/test-preload.ts +32 -39
  207. package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
  208. package/src/__tests__/tool-executor.test.ts +55 -10
  209. package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
  210. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  211. package/src/__tests__/twilio-routes.test.ts +3 -2
  212. package/src/__tests__/validate-input.test.ts +381 -0
  213. package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
  214. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
  215. package/src/__tests__/voice-session-bridge.test.ts +37 -28
  216. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
  217. package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
  218. package/src/acp/session-manager.ts +5 -6
  219. package/src/agent/loop.ts +80 -0
  220. package/src/api/README.md +124 -2
  221. package/src/api/constants/call-sites.ts +27 -0
  222. package/src/api/events/assistant-outbound-attachment.ts +51 -0
  223. package/src/api/events/assistant-text-delta.ts +32 -0
  224. package/src/api/events/assistant-turn-start.ts +33 -0
  225. package/src/api/events/document-comment-created.ts +48 -0
  226. package/src/api/events/document-comment-deleted.ts +24 -0
  227. package/src/api/events/document-comment-reopened.ts +25 -0
  228. package/src/api/events/document-comment-resolved.ts +27 -0
  229. package/src/api/events/generation-cancelled.ts +24 -0
  230. package/src/api/events/generation-handoff.ts +41 -0
  231. package/src/api/events/message-complete.ts +42 -0
  232. package/src/api/events/open-url.ts +30 -0
  233. package/src/{events → api/events}/relationship-state-updated.ts +3 -3
  234. package/src/api/events/tool-use-start.ts +32 -0
  235. package/src/api/index.ts +128 -3
  236. package/src/api/responses/llm-context-response.ts +39 -0
  237. package/src/api/responses/llm-request-log-entry.ts +93 -0
  238. package/src/api/responses/memory-recall-log.ts +65 -0
  239. package/src/api/responses/memory-v2-activation-log.ts +78 -0
  240. package/src/background-wake/background-wake-routes.test.ts +687 -52
  241. package/src/background-wake/platform-client.test.ts +308 -0
  242. package/src/background-wake/platform-client.ts +167 -0
  243. package/src/background-wake/publisher.ts +91 -0
  244. package/src/background-wake/runtime-registry.ts +2 -2
  245. package/src/background-wake/wake-intent-hooks.test.ts +282 -0
  246. package/src/calls/guardian-dispatch.ts +1 -0
  247. package/src/calls/voice-session-bridge.ts +4 -4
  248. package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
  249. package/src/cli/commands/__tests__/notifications.test.ts +184 -40
  250. package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
  251. package/src/cli/commands/channels/index.ts +229 -0
  252. package/src/cli/commands/memory-v3-render.ts +147 -0
  253. package/src/cli/commands/memory-v3.ts +255 -4
  254. package/src/cli/commands/notifications.ts +365 -55
  255. package/src/cli/lib/open-browser.ts +7 -2
  256. package/src/cli/program.ts +2 -0
  257. package/src/config/assistant-feature-flags.ts +23 -42
  258. package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
  259. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  260. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  261. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
  262. package/src/config/call-site-defaults.ts +1 -1
  263. package/src/config/feature-flag-cache.ts +86 -0
  264. package/src/config/feature-flag-registry.json +17 -17
  265. package/src/config/llm-context-resolution.ts +10 -1
  266. package/src/config/llm-resolver.ts +121 -15
  267. package/src/config/loader.ts +4 -5
  268. package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
  269. package/src/config/schemas/heartbeat.ts +1 -1
  270. package/src/config/schemas/llm.ts +90 -1
  271. package/src/config/schemas/memory-v2.ts +26 -0
  272. package/src/config/schemas/services.ts +6 -2
  273. package/src/config/seed-inference-profiles.ts +36 -16
  274. package/src/context/token-estimator.ts +10 -5
  275. package/src/credential-execution/executable-discovery.ts +40 -0
  276. package/src/credential-execution/process-manager.ts +6 -2
  277. package/src/credential-health/credential-health-service.ts +125 -40
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
  279. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
  280. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
  281. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
  282. package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
  283. package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
  284. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
  285. package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
  286. package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
  287. package/src/daemon/conversation-agent-loop.ts +132 -28
  288. package/src/daemon/conversation-error.ts +33 -5
  289. package/src/daemon/conversation-messaging.ts +84 -43
  290. package/src/daemon/conversation-process.ts +74 -37
  291. package/src/daemon/conversation-runtime-assembly.ts +29 -9
  292. package/src/daemon/conversation-skill-tools.ts +14 -30
  293. package/src/daemon/conversation-surfaces.ts +69 -34
  294. package/src/daemon/conversation-tool-setup.ts +33 -48
  295. package/src/daemon/conversation.ts +26 -46
  296. package/src/daemon/daemon-control.ts +1 -1
  297. package/src/daemon/daemon-skill-host.ts +9 -2
  298. package/src/daemon/disk-pressure-guard.ts +27 -29
  299. package/src/daemon/first-greeting.ts +31 -13
  300. package/src/daemon/handlers/shared.ts +6 -1
  301. package/src/daemon/lifecycle.ts +12 -12
  302. package/src/daemon/mcp-reload-service.ts +1 -1
  303. package/src/daemon/meet-manifest-loader.ts +10 -17
  304. package/src/daemon/message-types/conversations.ts +20 -22
  305. package/src/daemon/message-types/document-comments.ts +8 -44
  306. package/src/daemon/message-types/home.ts +2 -2
  307. package/src/daemon/message-types/integrations.ts +2 -7
  308. package/src/daemon/message-types/messages.ts +23 -38
  309. package/src/daemon/message-types/subagents.ts +6 -0
  310. package/src/daemon/process-message.ts +9 -9
  311. package/src/daemon/providers-setup.ts +1 -1
  312. package/src/daemon/server.ts +16 -0
  313. package/src/daemon/switch-inference-profile-tool.ts +13 -3
  314. package/src/daemon/tool-setup-types.ts +0 -6
  315. package/src/daemon/wake-target-adapter.ts +10 -0
  316. package/src/documents/document-store.ts +38 -0
  317. package/src/export/__tests__/transcript-formatter.test.ts +1 -0
  318. package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
  319. package/src/heartbeat/heartbeat-service.ts +63 -0
  320. package/src/home/__tests__/feed-writer.test.ts +161 -0
  321. package/src/home/__tests__/post-connect-feed.test.ts +1 -0
  322. package/src/home/__tests__/suggested-prompts.test.ts +55 -59
  323. package/src/home/feed-writer.ts +146 -7
  324. package/src/home/suggested-prompts.ts +27 -145
  325. package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
  326. package/src/ipc/gateway-client.test.ts +4 -1
  327. package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
  328. package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
  329. package/src/ipc/skill-routes/memory.ts +4 -3
  330. package/src/ipc/skill-routes/registries.ts +28 -29
  331. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
  332. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
  333. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
  334. package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
  335. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
  336. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
  337. package/src/memory/conversation-attention-store.ts +17 -3
  338. package/src/memory/conversation-crud.ts +352 -112
  339. package/src/memory/db-connection.ts +29 -19
  340. package/src/memory/db-init.ts +4 -0
  341. package/src/memory/db-singleton.ts +77 -0
  342. package/src/memory/delivery-channels.ts +82 -0
  343. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
  344. package/src/memory/graph/retriever.test.ts +3 -3
  345. package/src/memory/job-handlers/embedding.test.ts +3 -2
  346. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
  347. package/src/memory/jobs-worker.ts +12 -1
  348. package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
  349. package/src/memory/llm-request-log-source-local.ts +24 -0
  350. package/src/memory/llm-request-log-source.ts +31 -0
  351. package/src/memory/llm-request-log-store.ts +188 -3
  352. package/src/memory/memory-v2-activation-log-store.ts +95 -1
  353. package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
  354. package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
  355. package/src/memory/migrations/index.ts +2 -0
  356. package/src/memory/schema/conversations.ts +9 -1
  357. package/src/memory/schema/inference.ts +0 -1
  358. package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
  359. package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
  362. package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
  363. package/src/memory/v2/harness/metrics.ts +5 -1
  364. package/src/memory/v2/harness/replay-input.ts +19 -3
  365. package/src/memory/v2/harness/runner.ts +6 -0
  366. package/src/memory/v2/harness/trace.ts +6 -0
  367. package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
  368. package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
  369. package/src/memory/v3/__tests__/edges.test.ts +144 -1
  370. package/src/memory/v3/__tests__/filter.test.ts +48 -0
  371. package/src/memory/v3/__tests__/gate.test.ts +96 -33
  372. package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
  373. package/src/memory/v3/__tests__/loop.test.ts +250 -5
  374. package/src/memory/v3/__tests__/scouts.test.ts +49 -0
  375. package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
  376. package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
  377. package/src/memory/v3/__tests__/traversal.test.ts +39 -0
  378. package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
  379. package/src/memory/v3/__tests__/validate.test.ts +32 -0
  380. package/src/memory/v3/coretrieval-seed.ts +240 -0
  381. package/src/memory/v3/edges.ts +58 -21
  382. package/src/memory/v3/filter.ts +27 -22
  383. package/src/memory/v3/gate.ts +51 -36
  384. package/src/memory/v3/index-composition.ts +18 -5
  385. package/src/memory/v3/loop.ts +65 -17
  386. package/src/memory/v3/scouts.ts +15 -4
  387. package/src/memory/v3/shadow-diff.ts +287 -0
  388. package/src/memory/v3/shadow-middleware.ts +44 -2
  389. package/src/memory/v3/traversal.ts +6 -1
  390. package/src/memory/v3/tree-walk.ts +6 -1
  391. package/src/memory/v3/validate.ts +56 -33
  392. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  393. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
  394. package/src/notifications/adapters/slack.ts +45 -11
  395. package/src/notifications/broadcaster.ts +114 -63
  396. package/src/notifications/conversation-pairing.ts +23 -3
  397. package/src/notifications/decisions-store.ts +32 -1
  398. package/src/notifications/deliveries-store.ts +45 -0
  399. package/src/notifications/edit-notification.ts +201 -0
  400. package/src/notifications/emit-signal.ts +11 -1
  401. package/src/notifications/signal.ts +10 -0
  402. package/src/notifications/types.ts +37 -0
  403. package/src/oauth/byo-connection.test.ts +67 -3
  404. package/src/oauth/byo-connection.ts +32 -5
  405. package/src/oauth/connect-orchestrator.ts +9 -0
  406. package/src/oauth/connection-resolver.test.ts +76 -0
  407. package/src/oauth/connection-resolver.ts +49 -10
  408. package/src/oauth/manual-token-connection.ts +51 -3
  409. package/src/oauth/seed-providers.ts +3 -0
  410. package/src/permissions/approval-policy.test.ts +19 -5
  411. package/src/permissions/approval-policy.ts +14 -3
  412. package/src/permissions/checker.ts +21 -8
  413. package/src/platform/client.test.ts +24 -1
  414. package/src/platform/client.ts +8 -0
  415. package/src/platform/feature-gate.ts +15 -0
  416. package/src/plugins/defaults/injectors.ts +2 -8
  417. package/src/plugins/defaults/persistence.ts +25 -6
  418. package/src/plugins/types.ts +57 -13
  419. package/src/proactive-artifact/job.test.ts +1 -0
  420. package/src/prompts/__tests__/system-prompt.test.ts +4 -4
  421. package/src/prompts/system-prompt.ts +38 -40
  422. package/src/prompts/template-detection.ts +10 -4
  423. package/src/prompts/templates/BOOTSTRAP.md +7 -11
  424. package/src/prompts/templates/IDENTITY.md +0 -2
  425. package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
  426. package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
  427. package/src/providers/call-site-routing.ts +33 -9
  428. package/src/providers/connection-model-compat.ts +23 -0
  429. package/src/providers/connection-resolution.ts +39 -20
  430. package/src/providers/fireworks/client.ts +1 -0
  431. package/src/providers/gemini/client.ts +24 -3
  432. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
  433. package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
  434. package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
  435. package/src/providers/inference/auth.ts +0 -8
  436. package/src/providers/inference/connections.ts +3 -66
  437. package/src/providers/inference/resolve-auth.ts +2 -3
  438. package/src/providers/model-catalog.ts +35 -1
  439. package/src/providers/model-intents.ts +3 -3
  440. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  441. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
  442. package/src/providers/openai/chat-completions-provider.ts +110 -12
  443. package/src/providers/openai/codex-models.ts +2 -0
  444. package/src/providers/openai/responses-provider.ts +53 -53
  445. package/src/providers/openrouter/client.ts +13 -8
  446. package/src/providers/provider-send-message.ts +18 -9
  447. package/src/providers/registry.ts +48 -8
  448. package/src/providers/retry.ts +16 -4
  449. package/src/providers/search-provider-catalog.ts +17 -9
  450. package/src/providers/types.ts +9 -0
  451. package/src/runtime/__tests__/agent-wake.test.ts +1 -0
  452. package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
  453. package/src/runtime/access-request-helper.ts +1 -0
  454. package/src/runtime/auth/route-policy.ts +10 -0
  455. package/src/runtime/channel-readiness-service.ts +68 -0
  456. package/src/runtime/channel-reply-delivery.ts +23 -0
  457. package/src/runtime/channel-retry-sweep.ts +47 -14
  458. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  459. package/src/runtime/migrations/vbundle-builder.ts +3 -2
  460. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
  461. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
  462. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  463. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  464. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
  465. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
  466. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
  467. package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
  468. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
  469. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
  470. package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
  471. package/src/runtime/routes/acp-routes-list.test.ts +3 -0
  472. package/src/runtime/routes/app-management-routes.ts +111 -4
  473. package/src/runtime/routes/background-wake-routes.ts +188 -20
  474. package/src/runtime/routes/btw-routes.ts +4 -4
  475. package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
  476. package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
  477. package/src/runtime/routes/conversation-list-routes.ts +147 -0
  478. package/src/runtime/routes/conversation-management-routes.ts +39 -14
  479. package/src/runtime/routes/conversation-query-routes.ts +60 -10
  480. package/src/runtime/routes/conversation-routes.ts +186 -140
  481. package/src/runtime/routes/conversations-import-routes.ts +19 -6
  482. package/src/runtime/routes/documents-routes.ts +10 -1
  483. package/src/runtime/routes/group-routes.ts +11 -0
  484. package/src/runtime/routes/home-feed-routes.ts +129 -0
  485. package/src/runtime/routes/identity-intro-cache.ts +61 -16
  486. package/src/runtime/routes/identity-routes.ts +30 -9
  487. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
  488. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
  489. package/src/runtime/routes/index.ts +2 -0
  490. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
  491. package/src/runtime/routes/integrations/vercel.ts +15 -0
  492. package/src/runtime/routes/llm-context-normalization.ts +7 -2
  493. package/src/runtime/routes/memory-v3-routes.ts +160 -2
  494. package/src/runtime/routes/migration-routes.ts +20 -13
  495. package/src/runtime/routes/notification-routes.ts +63 -1
  496. package/src/runtime/routes/oauth-commands-routes.ts +6 -1
  497. package/src/runtime/routes/surface-action-routes.ts +1 -38
  498. package/src/runtime/routes/surface-content-routes.ts +12 -5
  499. package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
  500. package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
  501. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
  502. package/src/runtime/slack-dm-text-delivery.ts +177 -0
  503. package/src/runtime/sync/resource-sync-events.ts +1 -1
  504. package/src/runtime/tool-grant-request-helper.ts +1 -0
  505. package/src/schedule/schedule-store.ts +8 -1
  506. package/src/schedule/scheduler.ts +111 -15
  507. package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
  508. package/src/security/encrypted-store.ts +7 -16
  509. package/src/security/store-path-override.ts +61 -0
  510. package/src/signals/user-message.ts +5 -8
  511. package/src/skills/validate-input.ts +177 -0
  512. package/src/subagent/manager.ts +13 -13
  513. package/src/subagent/types.ts +6 -0
  514. package/src/tasks/tool-sanitizer.ts +2 -2
  515. package/src/tools/apps/definitions.ts +35 -21
  516. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
  517. package/src/tools/computer-use/definitions.ts +268 -266
  518. package/src/tools/document/document-tool.ts +131 -8
  519. package/src/tools/execution-target.ts +2 -5
  520. package/src/tools/executor.ts +18 -55
  521. package/src/tools/host-filesystem/edit.test.ts +1 -0
  522. package/src/tools/host-filesystem/read.test.ts +1 -0
  523. package/src/tools/host-filesystem/transfer.test.ts +31 -6
  524. package/src/tools/host-filesystem/write.test.ts +1 -0
  525. package/src/tools/mcp/mcp-tool-factory.ts +0 -2
  526. package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
  527. package/src/tools/network/__tests__/web-search.test.ts +211 -3
  528. package/src/tools/network/managed-search-proxy.ts +183 -0
  529. package/src/tools/network/web-search.ts +199 -44
  530. package/src/tools/policy-context.ts +3 -1
  531. package/src/tools/registry.ts +146 -103
  532. package/src/tools/schedule/create.ts +1 -1
  533. package/src/tools/skills/skill-tool-factory.ts +17 -36
  534. package/src/tools/subagent/spawn.ts +3 -0
  535. package/src/tools/tool-approval-handler.ts +10 -4
  536. package/src/tools/tool-name-aliases.ts +72 -14
  537. package/src/tools/types.ts +17 -15
  538. package/src/tools/ui-surface/definitions.ts +98 -86
  539. package/src/types/onboarding-context.ts +6 -0
  540. package/src/usage/attribution.ts +32 -1
  541. package/src/util/browser.ts +7 -2
  542. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
  543. package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
  544. package/src/workspace/migrations/registry.ts +4 -0
@@ -0,0 +1,183 @@
1
+ import { VellumPlatformClient } from "../../platform/client.js";
2
+
3
+ export type ManagedSearchProxyProvider = "brave";
4
+
5
+ export interface ManagedSearchProxyRequest {
6
+ method: string;
7
+ path: string;
8
+ query?: Record<string, string>;
9
+ headers?: Record<string, string>;
10
+ body?: unknown;
11
+ }
12
+
13
+ export interface ManagedSearchProxyResponse {
14
+ status: number;
15
+ headers: Record<string, string>;
16
+ body: unknown;
17
+ }
18
+
19
+ export type ManagedSearchProxyResult =
20
+ | ({ ok: true } & ManagedSearchProxyResponse)
21
+ | {
22
+ ok: false;
23
+ kind: "unavailable";
24
+ message: string;
25
+ }
26
+ | {
27
+ ok: false;
28
+ kind: "platform-error";
29
+ status: number;
30
+ headers: Record<string, string>;
31
+ body: unknown;
32
+ message: string;
33
+ }
34
+ | {
35
+ ok: false;
36
+ kind: "invalid-response";
37
+ body: unknown;
38
+ message: string;
39
+ };
40
+
41
+ interface ManagedSearchProxyEnvelope {
42
+ request: {
43
+ method: string;
44
+ path: string;
45
+ query: Record<string, string>;
46
+ headers: Record<string, string>;
47
+ body: unknown;
48
+ };
49
+ }
50
+
51
+ export async function callManagedSearchProxy(
52
+ provider: ManagedSearchProxyProvider,
53
+ request: ManagedSearchProxyRequest,
54
+ signal?: AbortSignal,
55
+ ): Promise<ManagedSearchProxyResult> {
56
+ const client = await VellumPlatformClient.create();
57
+ if (!client) {
58
+ return {
59
+ ok: false,
60
+ kind: "unavailable",
61
+ message: "Managed search proxy is unavailable in this environment.",
62
+ };
63
+ }
64
+
65
+ if (!client.platformAssistantId) {
66
+ return {
67
+ ok: false,
68
+ kind: "unavailable",
69
+ message:
70
+ "Managed search proxy is unavailable: platform assistant ID is missing.",
71
+ };
72
+ }
73
+
74
+ const path = `/v1/assistants/${encodeURIComponent(
75
+ client.platformAssistantId,
76
+ )}/managed-search-proxy/${encodeURIComponent(provider)}/`;
77
+
78
+ const envelope: ManagedSearchProxyEnvelope = {
79
+ request: {
80
+ method: request.method,
81
+ path: request.path,
82
+ query: request.query ?? {},
83
+ headers: request.headers ?? {},
84
+ body: request.body ?? null,
85
+ },
86
+ };
87
+
88
+ const response = await client.fetch(path, {
89
+ method: "POST",
90
+ headers: {
91
+ "Content-Type": "application/json",
92
+ },
93
+ body: JSON.stringify(envelope),
94
+ signal,
95
+ });
96
+
97
+ if (!response.ok) {
98
+ const body = await readResponseBody(response);
99
+ return {
100
+ ok: false,
101
+ kind: "platform-error",
102
+ status: response.status,
103
+ headers: responseHeadersToRecord(response.headers),
104
+ body,
105
+ message: platformErrorMessage(response.status, body),
106
+ };
107
+ }
108
+
109
+ const body = await readResponseBody(response);
110
+ if (!isManagedSearchProxyResponse(body)) {
111
+ return {
112
+ ok: false,
113
+ kind: "invalid-response",
114
+ body,
115
+ message: "Managed search proxy returned an invalid response envelope.",
116
+ };
117
+ }
118
+
119
+ return {
120
+ ok: true,
121
+ status: body.status,
122
+ headers: body.headers,
123
+ body: body.body,
124
+ };
125
+ }
126
+
127
+ function isManagedSearchProxyResponse(
128
+ value: unknown,
129
+ ): value is ManagedSearchProxyResponse {
130
+ if (!isRecord(value)) return false;
131
+ if (typeof value.status !== "number") return false;
132
+ if (!isStringRecord(value.headers)) return false;
133
+ return "body" in value;
134
+ }
135
+
136
+ async function readResponseBody(response: Response): Promise<unknown> {
137
+ const text = await response.text().catch(() => "");
138
+ if (!text) return null;
139
+
140
+ const contentType = response.headers.get("content-type") ?? "";
141
+ if (contentType.includes("application/json")) {
142
+ try {
143
+ return JSON.parse(text);
144
+ } catch {
145
+ return text;
146
+ }
147
+ }
148
+
149
+ return text;
150
+ }
151
+
152
+ function responseHeadersToRecord(headers: Headers): Record<string, string> {
153
+ return Object.fromEntries(headers.entries());
154
+ }
155
+
156
+ function platformErrorMessage(status: number, body: unknown): string {
157
+ const detail = extractErrorDetail(body);
158
+ if (detail) {
159
+ return `Managed search proxy returned status ${status}: ${detail}`;
160
+ }
161
+ return `Managed search proxy returned status ${status}.`;
162
+ }
163
+
164
+ function extractErrorDetail(body: unknown): string | undefined {
165
+ if (typeof body === "string") return body || undefined;
166
+ if (!isRecord(body)) return undefined;
167
+
168
+ for (const key of ["detail", "error", "message"]) {
169
+ const value = body[key];
170
+ if (typeof value === "string" && value) return value;
171
+ }
172
+
173
+ return undefined;
174
+ }
175
+
176
+ function isRecord(value: unknown): value is Record<string, unknown> {
177
+ return typeof value === "object" && value !== null && !Array.isArray(value);
178
+ }
179
+
180
+ function isStringRecord(value: unknown): value is Record<string, string> {
181
+ if (!isRecord(value)) return false;
182
+ return Object.values(value).every((entry) => typeof entry === "string");
183
+ }
@@ -17,14 +17,17 @@ import {
17
17
  import { registerTool } from "../registry.js";
18
18
  import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
19
19
  import { extractDomain } from "./domain-normalize.js";
20
+ import type { ManagedSearchProxyResult } from "./managed-search-proxy.js";
20
21
 
21
22
  const log = getLogger("web-search");
22
23
 
23
- const BRAVE_API_URL = "https://api.search.brave.com/res/v1/web/search";
24
+ const BRAVE_SEARCH_PATH = "/res/v1/web/search";
25
+ const BRAVE_API_URL = `https://api.search.brave.com${BRAVE_SEARCH_PATH}`;
24
26
  const PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions";
25
27
  const TAVILY_API_URL = "https://api.tavily.com/search";
26
28
 
27
29
  type WebSearchProvider = "perplexity" | "brave" | "tavily";
30
+ type WebSearchMode = "managed" | "your-own";
28
31
 
29
32
  /**
30
33
  * Arguments passed to every {@link WebSearchAdapter}. The full superset is
@@ -49,7 +52,7 @@ interface WebSearchAdapter {
49
52
  /** Stable provider identifier (matches config + secret-catalog values). */
50
53
  readonly id: WebSearchProvider;
51
54
  /** Secret-catalog key used to look up the API key via `getProviderKeyAsync`. */
52
- readonly secretKey: string;
55
+ readonly providerKeyName: string;
53
56
  /**
54
57
  * Position in the fallback chain (lower = earlier). Used when the
55
58
  * configured provider has no key and we try other BYOK providers.
@@ -98,17 +101,27 @@ interface TavilySearchResponse {
98
101
  function getWebSearchProvider(): WebSearchProvider {
99
102
  const config = getConfig();
100
103
  const configured = config.services["web-search"].provider ?? "perplexity";
101
- // 'inference-provider-native' is handled by the inference provider client
102
- // directly; fall back to perplexity for other providers.
104
+ // In Your Own mode, `inference-provider-native` is only executable when the
105
+ // inference provider swaps this tool for a native hosted-search definition.
106
+ // If this app-executed tool is still invoked, fall back to the existing BYOK
107
+ // provider chain. Managed mode short-circuits before this function and uses
108
+ // the platform search proxy instead.
103
109
  if (configured === "inference-provider-native") return "perplexity";
104
110
  return configured as WebSearchProvider;
105
111
  }
106
112
 
113
+ function getWebSearchMode(): WebSearchMode {
114
+ const config = getConfig();
115
+ return config.services["web-search"].mode === "managed"
116
+ ? "managed"
117
+ : "your-own";
118
+ }
119
+
107
120
  async function getApiKey(
108
121
  provider: WebSearchProvider,
109
122
  ): Promise<string | undefined> {
110
123
  const adapter = WEB_SEARCH_ADAPTERS[provider];
111
- return (await getProviderKeyAsync(adapter.secretKey)) ?? undefined;
124
+ return (await getProviderKeyAsync(adapter.providerKeyName)) ?? undefined;
112
125
  }
113
126
 
114
127
  function fallbackProvidersFor(
@@ -232,6 +245,46 @@ function buildBraveMetadata(
232
245
  };
233
246
  }
234
247
 
248
+ function braveQueryParams(
249
+ query: string,
250
+ count: number,
251
+ offset: number,
252
+ freshness: string | undefined,
253
+ ): Record<string, string> {
254
+ const params: Record<string, string> = {
255
+ q: query,
256
+ count: String(count),
257
+ offset: String(offset),
258
+ };
259
+
260
+ const validFreshness = ["pd", "pw", "pm", "py"];
261
+ if (freshness && validFreshness.includes(freshness)) {
262
+ params.freshness = freshness;
263
+ }
264
+
265
+ return params;
266
+ }
267
+
268
+ function successfulBraveResult(
269
+ data: BraveSearchResponse,
270
+ query: string,
271
+ startedAt: number,
272
+ ): ToolExecutionResult {
273
+ const results = data.web?.results ?? [];
274
+ const durationMs = Date.now() - startedAt;
275
+ return {
276
+ content:
277
+ wrapUntrustedContent(formatBraveResults(results, query), {
278
+ source: "search",
279
+ sourceDetail: "brave",
280
+ }) + CITATION_INSTRUCTION,
281
+ isError: false,
282
+ activityMetadata: {
283
+ webSearch: buildBraveMetadata(results, query, durationMs),
284
+ },
285
+ };
286
+ }
287
+
235
288
  function buildPerplexityMetadata(
236
289
  data: PerplexityResponse,
237
290
  query: string,
@@ -332,17 +385,9 @@ async function executeBraveSearch(
332
385
  apiKey: string,
333
386
  signal?: AbortSignal,
334
387
  ): Promise<ToolExecutionResult> {
335
- const params = new URLSearchParams({
336
- q: query,
337
- count: String(count),
338
- offset: String(offset),
339
- });
340
-
341
- const validFreshness = ["pd", "pw", "pm", "py"];
342
- if (freshness && validFreshness.includes(freshness)) {
343
- params.set("freshness", freshness);
344
- }
345
-
388
+ const params = new URLSearchParams(
389
+ braveQueryParams(query, count, offset, freshness),
390
+ );
346
391
  const url = `${BRAVE_API_URL}?${params.toString()}`;
347
392
  const startedAt = Date.now();
348
393
 
@@ -358,19 +403,7 @@ async function executeBraveSearch(
358
403
 
359
404
  if (response.ok) {
360
405
  const data = (await response.json()) as BraveSearchResponse;
361
- const results = data.web?.results ?? [];
362
- const durationMs = Date.now() - startedAt;
363
- return {
364
- content:
365
- wrapUntrustedContent(formatBraveResults(results, query), {
366
- source: "search",
367
- sourceDetail: "brave",
368
- }) + CITATION_INSTRUCTION,
369
- isError: false,
370
- activityMetadata: {
371
- webSearch: buildBraveMetadata(results, query, durationMs),
372
- },
373
- };
406
+ return successfulBraveResult(data, query, startedAt);
374
407
  }
375
408
 
376
409
  await response.text();
@@ -417,6 +450,90 @@ async function executeBraveSearch(
417
450
  );
418
451
  }
419
452
 
453
+ async function executeManagedBraveSearch(
454
+ query: string,
455
+ count: number,
456
+ offset: number,
457
+ freshness: string | undefined,
458
+ signal?: AbortSignal,
459
+ ): Promise<ToolExecutionResult> {
460
+ const { callManagedSearchProxy } = await import("./managed-search-proxy.js");
461
+ const startedAt = Date.now();
462
+ const proxyResult = await callManagedSearchProxy(
463
+ "brave",
464
+ {
465
+ method: "GET",
466
+ path: BRAVE_SEARCH_PATH,
467
+ query: braveQueryParams(query, count, offset, freshness),
468
+ headers: {
469
+ Accept: "application/json",
470
+ },
471
+ body: null,
472
+ },
473
+ signal,
474
+ );
475
+
476
+ if (!proxyResult.ok) {
477
+ return errorResult(
478
+ query,
479
+ "brave",
480
+ startedAt,
481
+ managedSearchProxyErrorMessage(proxyResult),
482
+ );
483
+ }
484
+
485
+ if (proxyResult.status >= 200 && proxyResult.status < 300) {
486
+ return successfulBraveResult(
487
+ proxyResult.body as BraveSearchResponse,
488
+ query,
489
+ startedAt,
490
+ );
491
+ }
492
+
493
+ if (proxyResult.status === 401 || proxyResult.status === 403) {
494
+ return errorResult(
495
+ query,
496
+ "brave",
497
+ startedAt,
498
+ "Managed Brave Search is not authenticated correctly. This is a Vellum platform configuration issue.",
499
+ );
500
+ }
501
+
502
+ if (proxyResult.status === 429) {
503
+ return errorResult(
504
+ query,
505
+ "brave",
506
+ startedAt,
507
+ "Managed Brave Search rate limit exceeded. Try again shortly.",
508
+ );
509
+ }
510
+
511
+ return errorResult(
512
+ query,
513
+ "brave",
514
+ startedAt,
515
+ `Managed Brave Search provider returned status ${proxyResult.status}`,
516
+ );
517
+ }
518
+
519
+ function managedSearchProxyErrorMessage(
520
+ result: Exclude<ManagedSearchProxyResult, { ok: true }>,
521
+ ): string {
522
+ if (result.kind === "unavailable") {
523
+ return `${result.message} Log in to Vellum or switch web search to Your Own mode.`;
524
+ }
525
+
526
+ if (result.kind === "platform-error" && result.status === 402) {
527
+ return "Managed web search is unavailable because your Vellum account balance is too low. Add funds or switch web search to Your Own mode.";
528
+ }
529
+
530
+ if (result.kind === "platform-error") {
531
+ return `Managed web search platform request failed: ${result.message}`;
532
+ }
533
+
534
+ return result.message;
535
+ }
536
+
420
537
  async function executePerplexitySearch(
421
538
  query: string,
422
539
  apiKey: string,
@@ -599,7 +716,7 @@ async function executeTavilySearch(
599
716
 
600
717
  const perplexitySearchAdapter: WebSearchAdapter = {
601
718
  id: "perplexity",
602
- secretKey: "perplexity",
719
+ providerKeyName: "perplexity",
603
720
  fallbackOrder: 1,
604
721
  execute: ({ query, apiKey, signal }) =>
605
722
  executePerplexitySearch(query, apiKey, signal),
@@ -607,15 +724,23 @@ const perplexitySearchAdapter: WebSearchAdapter = {
607
724
 
608
725
  const braveSearchAdapter: WebSearchAdapter = {
609
726
  id: "brave",
610
- secretKey: "brave",
727
+ providerKeyName: "brave",
611
728
  fallbackOrder: 2,
612
729
  execute: ({ query, count, offset, freshness, apiKey, signal }) =>
613
730
  executeBraveSearch(query, count, offset, freshness, apiKey, signal),
614
731
  };
615
732
 
733
+ const managedBraveSearchAdapter: WebSearchAdapter = {
734
+ id: "brave",
735
+ providerKeyName: "brave",
736
+ fallbackOrder: 2,
737
+ execute: ({ query, count, offset, freshness, signal }) =>
738
+ executeManagedBraveSearch(query, count, offset, freshness, signal),
739
+ };
740
+
616
741
  const tavilySearchAdapter: WebSearchAdapter = {
617
742
  id: "tavily",
618
- secretKey: "tavily",
743
+ providerKeyName: "tavily",
619
744
  fallbackOrder: 3,
620
745
  execute: ({ query, count, freshness, apiKey, signal }) =>
621
746
  executeTavilySearch(query, count, freshness, apiKey, signal),
@@ -690,6 +815,42 @@ class WebSearchTool implements Tool {
690
815
  }
691
816
 
692
817
  const startedAt = Date.now();
818
+ const mode = getWebSearchMode();
819
+
820
+ const count =
821
+ typeof input.count === "number"
822
+ ? Math.min(20, Math.max(1, Math.round(input.count)))
823
+ : 10;
824
+ const offset =
825
+ typeof input.offset === "number"
826
+ ? Math.min(9, Math.max(0, Math.round(input.offset)))
827
+ : 0;
828
+ const freshness =
829
+ typeof input.freshness === "string" ? input.freshness : undefined;
830
+
831
+ if (mode === "managed") {
832
+ try {
833
+ log.debug({ query, provider: "brave" }, "Executing managed web search");
834
+ return await managedBraveSearchAdapter.execute({
835
+ query,
836
+ count,
837
+ offset,
838
+ freshness,
839
+ apiKey: "",
840
+ signal: context.signal,
841
+ });
842
+ } catch (err) {
843
+ const msg = err instanceof Error ? err.message : String(err);
844
+ log.error({ err }, "Managed web search failed");
845
+ return errorResult(
846
+ query,
847
+ "brave",
848
+ startedAt,
849
+ `Managed web search failed: ${msg}`,
850
+ );
851
+ }
852
+ }
853
+
693
854
  let provider = getWebSearchProvider();
694
855
  let apiKey = await getApiKey(provider);
695
856
 
@@ -723,17 +884,6 @@ class WebSearchTool implements Tool {
723
884
  try {
724
885
  log.debug({ query, provider }, "Executing web search");
725
886
 
726
- const count =
727
- typeof input.count === "number"
728
- ? Math.min(20, Math.max(1, Math.round(input.count)))
729
- : 10;
730
- const offset =
731
- typeof input.offset === "number"
732
- ? Math.min(9, Math.max(0, Math.round(input.offset)))
733
- : 0;
734
- const freshness =
735
- typeof input.freshness === "string" ? input.freshness : undefined;
736
-
737
887
  return await WEB_SEARCH_ADAPTERS[provider].execute({
738
888
  query,
739
889
  count,
@@ -745,7 +895,12 @@ class WebSearchTool implements Tool {
745
895
  } catch (err) {
746
896
  const msg = err instanceof Error ? err.message : String(err);
747
897
  log.error({ err }, "Web search failed");
748
- return errorResult(query, provider, startedAt, `Web search failed: ${msg}`);
898
+ return errorResult(
899
+ query,
900
+ provider,
901
+ startedAt,
902
+ `Web search failed: ${msg}`,
903
+ );
749
904
  }
750
905
  }
751
906
  }
@@ -1,5 +1,6 @@
1
1
  import type { ExecutionContext } from "../permissions/approval-policy.js";
2
2
  import type { PolicyContext } from "../permissions/types.js";
3
+ import { getToolOwner } from "./registry.js";
3
4
  import type { Tool, ToolContext } from "./types.js";
4
5
 
5
6
  /**
@@ -31,7 +32,8 @@ export function buildPolicyContext(
31
32
 
32
33
  const conversationId = context?.conversationId;
33
34
 
34
- if (tool.origin === "skill" || tool.origin === "plugin") {
35
+ const ownerKind = getToolOwner(tool.name)?.kind;
36
+ if (ownerKind === "skill" || ownerKind === "plugin") {
35
37
  return {
36
38
  executionTarget: tool.executionTarget,
37
39
  executionContext,