@vellumai/assistant 0.9.0 → 0.10.0-staging.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 (572) hide show
  1. package/ARCHITECTURE.md +18 -34
  2. package/bun.lock +7 -8
  3. package/docs/activation-funnel-telemetry.md +28 -22
  4. package/docs/architecture/security.md +29 -28
  5. package/docs/stt-provider-onboarding.md +3 -5
  6. package/docs/workflows-testing.md +13 -44
  7. package/docs/workflows.md +3 -5
  8. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
  9. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
  10. package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
  11. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
  12. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  13. package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
  14. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
  15. package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
  16. package/openapi.yaml +976 -63
  17. package/package.json +2 -1
  18. package/scripts/sync-llm-catalog.ts +6 -15
  19. package/scripts/sync-web-search-catalog.ts +3 -11
  20. package/src/__tests__/access-request-card-view.test.ts +98 -0
  21. package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
  22. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
  23. package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
  24. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
  25. package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
  26. package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
  27. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
  28. package/src/__tests__/app-compiler.test.ts +15 -1
  29. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  30. package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
  31. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  32. package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
  33. package/src/__tests__/avatar-identity-sync.test.ts +2 -27
  34. package/src/__tests__/btw-routes.test.ts +6 -8
  35. package/src/__tests__/call-pointer-messages.test.ts +28 -0
  36. package/src/__tests__/cancel-clears-processing.test.ts +89 -0
  37. package/src/__tests__/channel-approval-routes.test.ts +0 -4
  38. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
  39. package/src/__tests__/checker.test.ts +0 -3
  40. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
  41. package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
  42. package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
  43. package/src/__tests__/config-loader-backfill.test.ts +268 -27
  44. package/src/__tests__/config-schema.test.ts +35 -0
  45. package/src/__tests__/config-watcher.test.ts +0 -18
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
  47. package/src/__tests__/contact-store-user-file.test.ts +0 -6
  48. package/src/__tests__/contacts-tools.test.ts +29 -0
  49. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
  50. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop.test.ts +58 -0
  52. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  53. package/src/__tests__/conversation-lifecycle.test.ts +7 -9
  54. package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
  55. package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
  56. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
  57. package/src/__tests__/conversation-title-service.test.ts +62 -0
  58. package/src/__tests__/credential-broker.test.ts +449 -1
  59. package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
  60. package/src/__tests__/credential-execution-tools.test.ts +0 -1
  61. package/src/__tests__/credential-prompt-route.test.ts +4 -4
  62. package/src/__tests__/credential-routes.test.ts +360 -0
  63. package/src/__tests__/credential-security-invariants.test.ts +4 -13
  64. package/src/__tests__/disk-pressure-policy.test.ts +12 -0
  65. package/src/__tests__/disk-usage.test.ts +65 -0
  66. package/src/__tests__/dynamic-page-surface.test.ts +152 -1
  67. package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
  68. package/src/__tests__/gateway-flag-listener.test.ts +110 -1
  69. package/src/__tests__/gateway-only-guard.test.ts +3 -7
  70. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  71. package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
  72. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
  73. package/src/__tests__/guardian-grant-minting.test.ts +3 -35
  74. package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
  75. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  76. package/src/__tests__/headless-browser-mode.test.ts +10 -0
  77. package/src/__tests__/headless-browser-navigate.test.ts +8 -3
  78. package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
  79. package/src/__tests__/host-browser-proxy.test.ts +87 -0
  80. package/src/__tests__/identity-routes.test.ts +0 -189
  81. package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
  82. package/src/__tests__/injector-v3-suppression.test.ts +27 -20
  83. package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
  84. package/src/__tests__/invite-redemption-service.test.ts +4 -7
  85. package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
  86. package/src/__tests__/llm-catalog-parity.test.ts +30 -23
  87. package/src/__tests__/llm-resolver.test.ts +70 -24
  88. package/src/__tests__/llm-schema.test.ts +1 -0
  89. package/src/__tests__/managed-profile-guard.test.ts +163 -4
  90. package/src/__tests__/mcp-health-check.test.ts +6 -7
  91. package/src/__tests__/media-stream-server-integration.test.ts +317 -13
  92. package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
  93. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  94. package/src/__tests__/path-policy.test.ts +34 -0
  95. package/src/__tests__/persona-resolver.test.ts +49 -14
  96. package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
  97. package/src/__tests__/plugin-api-provider.test.ts +24 -0
  98. package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
  99. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
  100. package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
  101. package/src/__tests__/reaction-persistence.test.ts +150 -29
  102. package/src/__tests__/registry.test.ts +2 -7
  103. package/src/__tests__/relay-server.test.ts +285 -0
  104. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  105. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
  106. package/src/__tests__/schedule-routes.test.ts +0 -30
  107. package/src/__tests__/schedule-tools.test.ts +2 -18
  108. package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
  109. package/src/__tests__/skill-execute-input.test.ts +51 -1
  110. package/src/__tests__/skill-runtime-path.test.ts +2 -3
  111. package/src/__tests__/skills.test.ts +51 -0
  112. package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
  113. package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
  114. package/src/__tests__/subagent-tools.test.ts +266 -0
  115. package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
  116. package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
  117. package/src/__tests__/title-generate-hook.test.ts +100 -3
  118. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
  119. package/src/__tests__/token-manager.test.ts +519 -0
  120. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
  121. package/src/__tests__/tool-audit-listener.test.ts +7 -7
  122. package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
  123. package/src/__tests__/tool-executor.test.ts +0 -79
  124. package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
  125. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
  126. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
  127. package/src/__tests__/trusted-contact-verification.test.ts +8 -10
  128. package/src/__tests__/twilio-routes.test.ts +81 -1
  129. package/src/__tests__/voice-invite-redemption.test.ts +2 -3
  130. package/src/__tests__/weak-open-model.test.ts +30 -0
  131. package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
  132. package/src/__tests__/workspace-greetings.test.ts +152 -0
  133. package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
  134. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
  135. package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
  136. package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
  137. package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
  138. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
  139. package/src/agent/loop.ts +49 -29
  140. package/src/api/README.md +6 -6
  141. package/src/api/events/tool-result.ts +6 -0
  142. package/src/api/events/workflow-completed.ts +53 -0
  143. package/src/api/events/workflow-leaf-finished.ts +38 -0
  144. package/src/api/events/workflow-leaf-started.ts +35 -0
  145. package/src/api/events/workflow-progress.ts +32 -0
  146. package/src/api/events/workflow-started.ts +31 -0
  147. package/src/api/index.ts +40 -0
  148. package/src/api/responses/conversation-message.ts +28 -4
  149. package/src/api/responses/home.ts +26 -4
  150. package/src/api/responses/workflow-journal.ts +53 -0
  151. package/src/approvals/guardian-card-withdrawal.ts +145 -0
  152. package/src/approvals/guardian-decision-primitive.ts +26 -3
  153. package/src/approvals/guardian-request-resolvers.ts +183 -80
  154. package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
  155. package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
  156. package/src/calls/call-pointer-messages.ts +10 -4
  157. package/src/calls/channel-admission-reader.ts +104 -0
  158. package/src/calls/guardian-dispatch.ts +17 -45
  159. package/src/calls/media-stream-server.ts +84 -2
  160. package/src/calls/relay-access-wait.ts +1 -1
  161. package/src/calls/relay-server.ts +66 -0
  162. package/src/calls/relay-setup-router.ts +82 -1
  163. package/src/calls/twilio-routes.ts +17 -8
  164. package/src/calls/voice-session-bridge.ts +2 -2
  165. package/src/cli/commands/clients.ts +3 -0
  166. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
  167. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
  168. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
  169. package/src/cli/commands/memory/index.ts +30 -0
  170. package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
  171. package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
  172. package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
  173. package/src/cli/commands/oauth/status.test.ts +36 -0
  174. package/src/cli/commands/oauth/status.ts +23 -3
  175. package/src/cli/commands/plugins.ts +197 -4
  176. package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
  177. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  178. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
  179. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
  180. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
  181. package/src/cli/lib/diff-plugin.ts +346 -0
  182. package/src/cli/lib/inspect-plugin.ts +12 -1
  183. package/src/cli/lib/install-from-github.ts +105 -17
  184. package/src/cli/lib/merge-plugin-tree.ts +328 -0
  185. package/src/cli/lib/plugin-fingerprint.ts +14 -0
  186. package/src/cli/lib/plugin-surfaces.ts +104 -0
  187. package/src/cli/lib/upgrade-plugin.ts +298 -10
  188. package/src/cli/program.ts +2 -6
  189. package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
  190. package/src/config/assistant-feature-flags.ts +22 -7
  191. package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
  192. package/src/config/bundled-skills/messaging/SKILL.md +6 -4
  193. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
  194. package/src/config/bundled-skills/subagent/SKILL.md +4 -0
  195. package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
  196. package/src/config/bundled-skills/workflows/SKILL.md +14 -8
  197. package/src/config/bundled-tool-registry.ts +2 -7
  198. package/src/config/call-site-defaults.ts +15 -2
  199. package/src/config/feature-flag-registry.json +46 -31
  200. package/src/config/inference-profile-validation.ts +26 -0
  201. package/src/config/llm-resolver.ts +3 -0
  202. package/src/config/loader.ts +4 -0
  203. package/src/config/memory-v3-gate.ts +11 -0
  204. package/src/config/profile-order.ts +28 -0
  205. package/src/config/schema.ts +8 -6
  206. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  207. package/src/config/schemas/call-site-catalog.ts +7 -0
  208. package/src/config/schemas/channels.ts +11 -0
  209. package/src/config/schemas/elevenlabs.ts +0 -1
  210. package/src/config/schemas/llm.ts +31 -0
  211. package/src/config/schemas/memory-lifecycle.ts +3 -7
  212. package/src/config/schemas/memory-v3.ts +6 -0
  213. package/src/config/schemas/platform.ts +0 -8
  214. package/src/config/schemas/services.ts +18 -0
  215. package/src/config/seed-inference-profiles.ts +109 -44
  216. package/src/config/skills.ts +21 -0
  217. package/src/config/sync-gated-profiles.ts +220 -0
  218. package/src/contacts/contact-store.ts +89 -106
  219. package/src/contacts/contacts-write.ts +5 -22
  220. package/src/contacts/types.ts +0 -1
  221. package/src/context/compactor.ts +88 -54
  222. package/src/context/strip-injections.ts +58 -10
  223. package/src/context/token-estimator.ts +1 -1
  224. package/src/credential-execution/process-manager.ts +55 -14
  225. package/src/credential-execution/prompted-credential.ts +2 -3
  226. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
  227. package/src/daemon/config-watcher.ts +0 -4
  228. package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
  229. package/src/daemon/conversation-agent-loop.ts +114 -22
  230. package/src/daemon/conversation-history.ts +1 -1
  231. package/src/daemon/conversation-lifecycle.ts +3 -5
  232. package/src/daemon/conversation-process.ts +13 -5
  233. package/src/daemon/conversation-runtime-assembly.ts +13 -15
  234. package/src/daemon/conversation-slash.ts +2 -23
  235. package/src/daemon/conversation-surfaces.ts +26 -0
  236. package/src/daemon/conversation-tool-setup.ts +27 -14
  237. package/src/daemon/conversation.ts +66 -14
  238. package/src/daemon/disk-pressure-policy.ts +5 -3
  239. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
  240. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
  241. package/src/daemon/handlers/config-a2a.ts +0 -2
  242. package/src/daemon/handlers/config-channels.ts +15 -16
  243. package/src/daemon/handlers/config-slack-channel.ts +22 -3
  244. package/src/daemon/handlers/conversations.ts +107 -0
  245. package/src/daemon/host-browser-proxy.ts +41 -0
  246. package/src/daemon/lifecycle.ts +55 -27
  247. package/src/daemon/message-provenance.ts +2 -0
  248. package/src/daemon/message-types/contacts.ts +0 -1
  249. package/src/daemon/message-types/conversations.ts +3 -3
  250. package/src/daemon/message-types/sync.ts +0 -1
  251. package/src/daemon/message-types/web-activity.ts +7 -1
  252. package/src/daemon/message-types/workflows.ts +83 -1
  253. package/src/daemon/orphan-reaper.test.ts +0 -19
  254. package/src/daemon/orphan-reaper.ts +2 -24
  255. package/src/daemon/server.ts +0 -10
  256. package/src/daemon/tool-setup-types.ts +4 -0
  257. package/src/daemon/trust-context.ts +1 -1
  258. package/src/events/tool-audit-listener.ts +2 -2
  259. package/src/home/feed-source-enrichment.test.ts +151 -0
  260. package/src/home/feed-source-enrichment.ts +176 -0
  261. package/src/home/relationship-state.ts +2 -4
  262. package/src/instrument.ts +18 -6
  263. package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
  264. package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
  265. package/src/ipc/assistant-server.ts +37 -4
  266. package/src/ipc/gateway-flag-listener.ts +18 -2
  267. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
  268. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
  269. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
  270. package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
  271. package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
  272. package/src/memory/auth-fallback-events-store.ts +2 -2
  273. package/src/memory/auto-analysis-enqueue.ts +3 -5
  274. package/src/memory/bookmark-crud.ts +1 -2
  275. package/src/memory/canonical-guardian-store.ts +39 -1
  276. package/src/memory/conversation-crud.ts +9 -4
  277. package/src/memory/conversation-key-store.ts +17 -2
  278. package/src/memory/conversation-title-service.ts +64 -7
  279. package/src/memory/db-init.ts +17 -17
  280. package/src/memory/embedding-backend.ts +38 -1
  281. package/src/memory/embedding-billing-breaker.ts +96 -0
  282. package/src/memory/jobs-store.ts +25 -13
  283. package/src/memory/jobs-worker.ts +54 -1
  284. package/src/memory/lifecycle-events-store.ts +2 -2
  285. package/src/memory/memory-retrospective-constants.ts +4 -4
  286. package/src/memory/memory-retrospective-enqueue.ts +31 -6
  287. package/src/memory/memory-retrospective-job.ts +28 -227
  288. package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
  289. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
  290. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
  291. package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
  292. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
  293. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
  294. package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
  295. package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
  296. package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
  297. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
  298. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
  299. package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
  300. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
  301. package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
  302. package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
  303. package/src/memory/migrations/index.ts +6 -0
  304. package/src/memory/migrations/run-migrations.ts +41 -0
  305. package/src/memory/migrations/validate-migration-state.ts +1 -1
  306. package/src/memory/onboarding-events-store.ts +3 -3
  307. package/src/memory/schema/contacts.ts +0 -5
  308. package/src/memory/skill-loaded-events-store.test.ts +7 -15
  309. package/src/memory/skill-loaded-events-store.ts +2 -2
  310. package/src/memory/tool-executed-events-store.test.ts +7 -7
  311. package/src/memory/turn-trace-store.test.ts +736 -0
  312. package/src/memory/turn-trace-store.ts +364 -0
  313. package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
  314. package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
  315. package/src/memory/v2/consolidation-job.ts +2 -2
  316. package/src/memory/v2/skill-content.ts +25 -7
  317. package/src/memory/v2/skill-store.ts +7 -1
  318. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
  319. package/src/memory/v3-eval/eval-packets.ts +546 -0
  320. package/src/messaging/providers/slack/adapter.ts +1 -1
  321. package/src/messaging/providers/slack/api.ts +31 -0
  322. package/src/messaging/providers/slack/send.test.ts +114 -2
  323. package/src/messaging/providers/slack/send.ts +30 -7
  324. package/src/messaging/providers/slack/withdraw.test.ts +200 -0
  325. package/src/messaging/providers/slack/withdraw.ts +161 -0
  326. package/src/notifications/AGENTS.md +2 -0
  327. package/src/notifications/access-request-copy.ts +72 -59
  328. package/src/notifications/adapters/shared.ts +29 -0
  329. package/src/notifications/adapters/slack.ts +58 -103
  330. package/src/notifications/adapters/telegram.ts +2 -20
  331. package/src/notifications/approval-card-data.ts +333 -0
  332. package/src/notifications/broadcaster.ts +16 -3
  333. package/src/notifications/canonical-delivery-recorder.ts +139 -0
  334. package/src/notifications/copy-composer.ts +3 -3
  335. package/src/notifications/decision-engine.ts +4 -2
  336. package/src/notifications/destination-resolver.ts +4 -6
  337. package/src/notifications/guardian-question-mode.ts +10 -0
  338. package/src/notifications/home-feed-side-effect.ts +7 -16
  339. package/src/notifications/notification-utils.ts +19 -20
  340. package/src/notifications/signal.ts +79 -43
  341. package/src/notifications/types.ts +98 -121
  342. package/src/oauth/AGENTS.md +5 -24
  343. package/src/permissions/checker.test.ts +51 -0
  344. package/src/permissions/checker.ts +185 -26
  345. package/src/permissions/ipc-risk-types.ts +24 -0
  346. package/src/permissions/question-prompter.test.ts +27 -0
  347. package/src/permissions/question-prompter.ts +4 -0
  348. package/src/platform/client.test.ts +119 -0
  349. package/src/platform/client.ts +66 -0
  350. package/src/platform/consent-cache.test.ts +267 -0
  351. package/src/platform/consent-cache.ts +174 -0
  352. package/src/plugin-api/constants.ts +1 -1
  353. package/src/plugin-api/index.ts +33 -1
  354. package/src/plugin-api/model-profiles.ts +33 -0
  355. package/src/plugin-api/types.ts +50 -2
  356. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
  357. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
  358. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
  359. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
  360. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
  361. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
  362. package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
  363. package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
  364. package/src/plugins/defaults/advisor/config.ts +21 -0
  365. package/src/plugins/defaults/advisor/consult.ts +93 -0
  366. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
  367. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
  368. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
  369. package/src/plugins/defaults/advisor/package.json +14 -0
  370. package/src/plugins/defaults/advisor/steering.ts +67 -0
  371. package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
  372. package/src/plugins/defaults/advisor/transcript.ts +76 -0
  373. package/src/plugins/defaults/index.ts +60 -0
  374. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
  375. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  376. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
  377. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
  378. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
  379. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  380. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
  381. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
  382. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
  383. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
  384. package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
  385. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
  386. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
  387. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
  388. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
  389. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
  390. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
  391. package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
  392. package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
  393. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
  394. package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
  395. package/src/prompts/persona-resolver.ts +14 -4
  396. package/src/prompts/templates/system-sections.ts +7 -2
  397. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  398. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  399. package/src/providers/__tests__/retry-callsite.test.ts +176 -0
  400. package/src/providers/atlascloud/client.ts +85 -0
  401. package/src/providers/fetch-provider-catalog.ts +85 -0
  402. package/src/providers/inference/adapter-factory.ts +3 -0
  403. package/src/providers/model-catalog.ts +58 -0
  404. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
  405. package/src/providers/openai/chat-completions-provider.ts +7 -0
  406. package/src/providers/openai/responses-provider.ts +10 -0
  407. package/src/providers/provider-send-message.ts +11 -3
  408. package/src/providers/retry.ts +53 -12
  409. package/src/providers/search-provider-catalog.ts +10 -0
  410. package/src/providers/weak-open-model.ts +22 -0
  411. package/src/runtime/AGENTS.md +0 -1
  412. package/src/runtime/__tests__/agent-wake.test.ts +181 -0
  413. package/src/runtime/__tests__/client-health.test.ts +44 -0
  414. package/src/runtime/access-request-helper.ts +21 -53
  415. package/src/runtime/actor-trust-resolver.ts +59 -63
  416. package/src/runtime/agent-wake.ts +52 -0
  417. package/src/runtime/assistant-event-hub.ts +18 -4
  418. package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
  419. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  420. package/src/runtime/btw-sidechain.ts +3 -6
  421. package/src/runtime/capabilities.test.ts +120 -0
  422. package/src/runtime/capabilities.ts +197 -0
  423. package/src/runtime/channel-approval-types.ts +22 -45
  424. package/src/runtime/channel-invite-transports/telegram.ts +4 -4
  425. package/src/runtime/channel-retry-sweep.ts +1 -0
  426. package/src/runtime/channel-verification-service.ts +3 -3
  427. package/src/runtime/client-health.ts +26 -0
  428. package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
  429. package/src/runtime/effective-capabilities.test.ts +128 -0
  430. package/src/runtime/effective-capabilities.ts +84 -0
  431. package/src/runtime/guardian-reply-router.ts +106 -21
  432. package/src/runtime/invite-redemption-service.ts +9 -25
  433. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
  434. package/src/runtime/migrations/vbundle-builder.ts +49 -20
  435. package/src/runtime/pending-interactions.ts +15 -0
  436. package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
  437. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
  438. package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
  439. package/src/runtime/routes/app-routes.ts +1 -1
  440. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
  441. package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
  442. package/src/runtime/routes/browser-tabs-routes.ts +9 -0
  443. package/src/runtime/routes/btw-routes.ts +1 -27
  444. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
  445. package/src/runtime/routes/client-routes.ts +10 -0
  446. package/src/runtime/routes/contact-routes.ts +31 -8
  447. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  448. package/src/runtime/routes/conversation-management-routes.ts +80 -1
  449. package/src/runtime/routes/conversation-query-routes.ts +68 -22
  450. package/src/runtime/routes/conversation-routes.ts +39 -14
  451. package/src/runtime/routes/credential-routes.ts +40 -16
  452. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
  453. package/src/runtime/routes/events-routes.ts +1 -3
  454. package/src/runtime/routes/guardian-approval-interception.ts +14 -73
  455. package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
  456. package/src/runtime/routes/home-feed-routes.ts +8 -3
  457. package/src/runtime/routes/identity-routes.ts +1 -296
  458. package/src/runtime/routes/inbound-message-handler.ts +214 -228
  459. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
  460. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
  461. package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
  462. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
  463. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
  464. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
  465. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
  466. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
  467. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
  468. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
  469. package/src/runtime/routes/index.ts +2 -0
  470. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
  471. package/src/runtime/routes/integrations/slack/channel.ts +36 -0
  472. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  473. package/src/runtime/routes/mcp-auth-routes.ts +233 -41
  474. package/src/runtime/routes/memory-eval-routes.ts +87 -0
  475. package/src/runtime/routes/notification-routes.ts +122 -133
  476. package/src/runtime/routes/platform-routes.ts +2 -2
  477. package/src/runtime/routes/plugins-routes.ts +202 -3
  478. package/src/runtime/routes/schedule-routes.ts +0 -22
  479. package/src/runtime/routes/secret-routes.ts +10 -0
  480. package/src/runtime/routes/surface-action-routes.ts +2 -1
  481. package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
  482. package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
  483. package/src/runtime/routes/workflow-routes.test.ts +229 -44
  484. package/src/runtime/routes/workflow-routes.ts +131 -29
  485. package/src/runtime/routes/workspace-greetings.ts +55 -0
  486. package/src/runtime/sync/resource-sync-events.ts +1 -11
  487. package/src/runtime/tool-grant-request-helper.ts +18 -16
  488. package/src/runtime/trust-context-resolver.ts +8 -5
  489. package/src/schedule/inference-profile.ts +2 -14
  490. package/src/schedule/schedule-store.ts +1 -1
  491. package/src/schedule/scheduler-types.ts +5 -1
  492. package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
  493. package/src/security/secret-patterns.ts +3 -0
  494. package/src/subagent/manager.ts +17 -4
  495. package/src/subagent/types.ts +6 -0
  496. package/src/telemetry/trace-collection-policy.test.ts +28 -0
  497. package/src/telemetry/trace-collection-policy.ts +30 -0
  498. package/src/telemetry/types.ts +89 -0
  499. package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
  500. package/src/telemetry/usage-telemetry-reporter.ts +148 -41
  501. package/src/tools/AGENTS.md +3 -3
  502. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
  503. package/src/tools/browser/browser-execution.ts +30 -19
  504. package/src/tools/document/document-tool.ts +2 -3
  505. package/src/tools/executor.ts +5 -3
  506. package/src/tools/host-terminal/host-shell.ts +5 -4
  507. package/src/tools/memory/register.ts +2 -2
  508. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
  509. package/src/tools/network/__tests__/web-search.test.ts +143 -0
  510. package/src/tools/network/web-fetch.ts +372 -1
  511. package/src/tools/network/web-search-error.ts +1 -1
  512. package/src/tools/network/web-search.ts +213 -10
  513. package/src/tools/permission-checker.ts +4 -3
  514. package/src/tools/registry.ts +20 -0
  515. package/src/tools/schedule/create.ts +7 -12
  516. package/src/tools/schedule/update.ts +4 -11
  517. package/src/tools/shared/filesystem/path-policy.ts +39 -13
  518. package/src/tools/side-effects.ts +2 -17
  519. package/src/tools/skills/execute.ts +33 -0
  520. package/src/tools/subagent/spawn.ts +61 -12
  521. package/src/tools/terminal/shell.ts +10 -4
  522. package/src/tools/tool-approval-handler.ts +18 -13
  523. package/src/tools/tool-manifest.ts +0 -2
  524. package/src/tools/types.ts +9 -0
  525. package/src/tools/ui-surface/definitions.ts +64 -3
  526. package/src/tools/verification-control-plane-policy.ts +3 -1
  527. package/src/tools/workflows/run-workflow.test.ts +8 -18
  528. package/src/tools/workflows/run-workflow.ts +1 -0
  529. package/src/util/disk-usage.ts +78 -23
  530. package/src/util/platform.ts +10 -3
  531. package/src/watcher/telemetry.ts +2 -2
  532. package/src/workflows/capabilities.ts +2 -3
  533. package/src/workflows/engine.test.ts +175 -1
  534. package/src/workflows/engine.ts +82 -0
  535. package/src/workflows/journal-store.test.ts +70 -0
  536. package/src/workflows/journal-store.ts +18 -3
  537. package/src/workflows/run-manager.test.ts +171 -28
  538. package/src/workflows/run-manager.ts +66 -24
  539. package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
  540. package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
  541. package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
  542. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
  543. package/src/workspace/migrations/registry.ts +8 -0
  544. package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
  545. package/src/__tests__/credential-security-e2e.test.ts +0 -362
  546. package/src/__tests__/credential-vault-unit.test.ts +0 -1528
  547. package/src/__tests__/credential-vault.test.ts +0 -1706
  548. package/src/__tests__/identity-intro-cache.test.ts +0 -315
  549. package/src/__tests__/secret-onetime-send.test.ts +0 -182
  550. package/src/cli/commands/__tests__/task.test.ts +0 -914
  551. package/src/cli/commands/task.ts +0 -771
  552. package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
  553. package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
  554. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
  555. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
  556. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
  557. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
  558. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
  559. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
  560. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
  561. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
  562. package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
  563. package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
  564. package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
  565. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
  566. package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
  567. package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
  568. package/src/memory/preloaded-apps.ts +0 -116
  569. package/src/notifications/tool-approval-copy.ts +0 -142
  570. package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
  571. package/src/runtime/routes/identity-intro-cache.ts +0 -172
  572. package/src/tools/credentials/vault.ts +0 -712
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Per-conversation capture store for the advisor plugin.
3
+ *
4
+ * A tool's `execute` does not receive the conversation transcript — only
5
+ * lifecycle hooks do. So the hooks snapshot what the executor saw (the system
6
+ * prompt from `pre-model-call`, the running transcript from `post-model-call`)
7
+ * into this module-level store, keyed by conversation id, and the `advisor`
8
+ * tool reads the latest snapshot when the model calls it. This reproduces the
9
+ * advisor-tool property that the model calls the tool with no arguments and the
10
+ * full context is supplied for it.
11
+ *
12
+ * Bounded by a small LRU so a long-lived daemon does not accumulate state for
13
+ * every conversation it has ever served.
14
+ */
15
+
16
+ import type { Message } from "../../../providers/types.js";
17
+
18
+ export interface AdvisorCapture {
19
+ /** The executor's system prompt (steering stripped), or null if unseen. */
20
+ systemPrompt: string | null;
21
+ /** The transcript the executor most recently saw on a `mainAgent` call. */
22
+ messages: Message[];
23
+ /** Last-write timestamp, used for LRU eviction. */
24
+ updatedAt: number;
25
+ }
26
+
27
+ const MAX_CONVERSATIONS = 200;
28
+ const store = new Map<string, AdvisorCapture>();
29
+
30
+ /** Move an entry to most-recently-used and evict the oldest past the cap. */
31
+ function bump(conversationId: string, entry: AdvisorCapture): void {
32
+ entry.updatedAt = Date.now();
33
+ store.delete(conversationId);
34
+ store.set(conversationId, entry);
35
+ while (store.size > MAX_CONVERSATIONS) {
36
+ const oldest = store.keys().next().value;
37
+ if (oldest === undefined) break;
38
+ store.delete(oldest);
39
+ }
40
+ }
41
+
42
+ function ensure(conversationId: string): AdvisorCapture {
43
+ return (
44
+ store.get(conversationId) ?? {
45
+ systemPrompt: null,
46
+ messages: [],
47
+ updatedAt: Date.now(),
48
+ }
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Seed the capture at the start of a user turn with the inbound history, so an
54
+ * advisor call on the very first model turn still has context even before
55
+ * `post-model-call` snapshots the running transcript.
56
+ */
57
+ export function seedCapture(
58
+ conversationId: string,
59
+ messages: ReadonlyArray<Message>,
60
+ ): void {
61
+ const entry = ensure(conversationId);
62
+ entry.messages = [...messages];
63
+ bump(conversationId, entry);
64
+ }
65
+
66
+ /** Record the executor's system prompt (steering already stripped). */
67
+ export function recordSystemPrompt(
68
+ conversationId: string,
69
+ systemPrompt: string | null,
70
+ ): void {
71
+ const entry = ensure(conversationId);
72
+ entry.systemPrompt = systemPrompt;
73
+ bump(conversationId, entry);
74
+ }
75
+
76
+ /** Snapshot the transcript the executor just saw (before tools run). */
77
+ export function recordMessages(
78
+ conversationId: string,
79
+ messages: ReadonlyArray<Message>,
80
+ ): void {
81
+ const entry = ensure(conversationId);
82
+ entry.messages = [...messages];
83
+ bump(conversationId, entry);
84
+ }
85
+
86
+ /** The latest capture for a conversation, or `undefined` if none recorded. */
87
+ export function getCapture(conversationId: string): AdvisorCapture | undefined {
88
+ return store.get(conversationId);
89
+ }
90
+
91
+ /** Test-only: clear all captured state. */
92
+ export function resetAdvisorStateForTests(): void {
93
+ store.clear();
94
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Static behavioral configuration for the advisor.
3
+ *
4
+ * The advisor *model* is no longer hardcoded here: it routes through the
5
+ * dedicated `advisor` call site, whose default profile (`quality-optimized`)
6
+ * lives in CALL_SITE_DEFAULTS and is overridden per workspace by
7
+ * `llm.advisorProfile`. Whether the advisor is active is decided per chat
8
+ * profile by `ProfileEntry.advisorEnabled` (default on).
9
+ */
10
+ export const ADVISOR_CONFIG = {
11
+ // No advisor-specific output cap: the consult omits `max_tokens` (so the
12
+ // resolver applies the profile's normal output budget) and the request text
13
+ // carries no word limit. The advisor decides its own length.
14
+ /** Abort the consult if the sub-call runs longer than this. */
15
+ timeoutMs: 60_000,
16
+ /**
17
+ * Global kill-switch for the steering injection. The per-chat-profile
18
+ * `advisorEnabled` toggle gates it further; this stays as a hard off switch.
19
+ */
20
+ steeringEnabled: true,
21
+ } as const;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Run one advisor consult.
3
+ *
4
+ * Routed entirely through the assistant's own inference: `getConfiguredProvider`
5
+ * resolves the general-purpose `inference` call site (with the advisor profile
6
+ * applied as an `overrideProfile`) to a provider/model/credentials from the
7
+ * configured profiles — managed-proxy or BYOK, no separate API key. The consult
8
+ * then runs a tool-less, capped one-shot completion through `provider.sendMessage`
9
+ * and returns the text.
10
+ */
11
+
12
+ import { getConfig } from "../../../config/loader.js";
13
+ import type { LLMCallSite } from "../../../config/schemas/llm.js";
14
+ import {
15
+ extractAllText,
16
+ getConfiguredProvider,
17
+ userMessage,
18
+ } from "../../../providers/provider-send-message.js";
19
+ import type { Message } from "../../../providers/types.js";
20
+ import { ADVISOR_CONFIG } from "./config.js";
21
+ import { advisorRequestText, buildAdvisorSystem } from "./steering.js";
22
+ import { toAdvisorMessages } from "./transcript.js";
23
+
24
+ // Dedicated advisor call site. Its default profile (`quality-optimized`) lives
25
+ // in CALL_SITE_DEFAULTS; a workspace overrides which profile the advisor runs
26
+ // on via `llm.advisorProfile`, which we float above the call-site layers.
27
+ const ADVISOR_CALL_SITE: LLMCallSite = "advisor";
28
+
29
+ /**
30
+ * Resolve the routing override for the advisor consult. When the workspace has
31
+ * set `llm.advisorProfile`, force it above the call-site layers so it is
32
+ * authoritative; otherwise return `{}` so the `advisor` call site resolves to
33
+ * its default profile.
34
+ */
35
+ function advisorOverride(): {
36
+ overrideProfile?: string;
37
+ forceOverrideProfile?: boolean;
38
+ } {
39
+ const advisorProfile = getConfig().llm.advisorProfile;
40
+ return advisorProfile
41
+ ? { overrideProfile: advisorProfile, forceOverrideProfile: true }
42
+ : {};
43
+ }
44
+
45
+ export interface ConsultParams {
46
+ systemPrompt: string | null;
47
+ messages: ReadonlyArray<Message>;
48
+ signal?: AbortSignal;
49
+ }
50
+
51
+ /** Combine the caller's signal with a consult timeout. */
52
+ function withTimeout(signal: AbortSignal | undefined, ms: number): AbortSignal {
53
+ const timeout = AbortSignal.timeout(ms);
54
+ return signal ? AbortSignal.any([signal, timeout]) : timeout;
55
+ }
56
+
57
+ /**
58
+ * Returns the advisor's guidance text, or a short benign notice when the
59
+ * advisor can't run. Callers should surface the string as a non-error tool
60
+ * result so the executor continues regardless.
61
+ */
62
+ export async function consultAdvisor(params: ConsultParams): Promise<string> {
63
+ const history = toAdvisorMessages(params.messages);
64
+ if (history.length === 0) {
65
+ return "(advisor: no conversation context is available yet)";
66
+ }
67
+
68
+ const override = advisorOverride();
69
+
70
+ const provider = await getConfiguredProvider(ADVISOR_CALL_SITE, override);
71
+ if (!provider) {
72
+ return "(advisor unavailable: no inference provider is configured)";
73
+ }
74
+
75
+ // Append the consult instruction as the final user turn, then run a
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.
79
+ const messages: Message[] = [...history, userMessage(advisorRequestText())];
80
+
81
+ const response = await provider.sendMessage(messages, {
82
+ systemPrompt: buildAdvisorSystem(params.systemPrompt),
83
+ config: {
84
+ callSite: ADVISOR_CALL_SITE,
85
+ ...override,
86
+ tool_choice: { type: "none" },
87
+ },
88
+ signal: withTimeout(params.signal, ADVISOR_CONFIG.timeoutMs),
89
+ });
90
+
91
+ const advice = extractAllText(response).trim();
92
+ return advice.length > 0 ? advice : "(advisor returned no guidance)";
93
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `post-model-call` hook: snapshot the transcript the executor just saw. Fires
3
+ * after the model returns its message (which may carry the `advisor` tool_use)
4
+ * but before tools run, so when `advisor.execute()` runs an instant later it
5
+ * reads exactly this snapshot.
6
+ *
7
+ * Pure observer: never mutates `content` or the continue/stop `decision`. Gated
8
+ * to the user-facing reply, so background/subagent/compaction calls — and the
9
+ * advisor's own `inference`-call-site sub-call — are ignored.
10
+ */
11
+
12
+ import type { PluginHookFn, PostModelCallContext } from "@vellumai/plugin-api";
13
+
14
+ import { recordMessages } from "../advisor-state-store.js";
15
+
16
+ const postModelCall: PluginHookFn<PostModelCallContext> = async (ctx) => {
17
+ if (ctx.callSite !== "mainAgent") return;
18
+ if (ctx.error) return;
19
+ // `ctx.messages` is the pre-reply history; the turn the model just produced —
20
+ // including any text/plan it wrote before the `advisor` tool_use — lives in
21
+ // `ctx.content` and is not yet in `messages`. Append it (cloned) so the
22
+ // advisor reviews the full current transcript, not just the prior history.
23
+ // `transcript.ts` strips the pending tool_use from this final assistant turn.
24
+ const messages =
25
+ ctx.content.length > 0
26
+ ? [
27
+ ...ctx.messages,
28
+ { role: "assistant" as const, content: [...ctx.content] },
29
+ ]
30
+ : ctx.messages;
31
+ recordMessages(ctx.conversationId, messages);
32
+ };
33
+
34
+ export default postModelCall;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * `pre-model-call` hook: for the user-facing reply (`mainAgent`), capture the
3
+ * executor's system prompt (steering stripped) so the advisor can be given it
4
+ * as context, and inject the advisor steering so the model reaches for the
5
+ * tool. Idempotent via the steering marker.
6
+ */
7
+
8
+ import type { PluginHookFn, PreModelCallContext } from "@vellumai/plugin-api";
9
+
10
+ import { advisorEnabledForProfile } from "../advisor-gate.js";
11
+ import { recordSystemPrompt } from "../advisor-state-store.js";
12
+ import { ADVISOR_CONFIG } from "../config.js";
13
+ import { appendSteering, stripSteering } from "../steering.js";
14
+
15
+ const preModelCall: PluginHookFn<PreModelCallContext> = async (ctx) => {
16
+ if (ctx.callSite !== "mainAgent") return;
17
+
18
+ recordSystemPrompt(ctx.conversationId, stripSteering(ctx.systemPrompt));
19
+
20
+ // Steer the model to consult only when the steering is globally on AND the
21
+ // chat profile this turn routes to has the advisor enabled (default on).
22
+ if (
23
+ ADVISOR_CONFIG.steeringEnabled &&
24
+ advisorEnabledForProfile(ctx.modelProfile)
25
+ ) {
26
+ ctx.systemPrompt = appendSteering(ctx.systemPrompt);
27
+ }
28
+ };
29
+
30
+ export default preModelCall;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `user-prompt-submit` hook: seed the per-conversation capture at the start of a
3
+ * user turn with the inbound history, so an advisor call on the very first model
4
+ * turn still has context even before `post-model-call` snapshots the running
5
+ * transcript.
6
+ */
7
+
8
+ import type {
9
+ PluginHookFn,
10
+ UserPromptSubmitContext,
11
+ } from "@vellumai/plugin-api";
12
+
13
+ import { seedCapture } from "../advisor-state-store.js";
14
+
15
+ const userPromptSubmit: PluginHookFn<UserPromptSubmitContext> = async (ctx) => {
16
+ seedCapture(ctx.conversationId, ctx.latestMessages);
17
+ };
18
+
19
+ export default userPromptSubmit;
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "default-advisor",
3
+ "version": "1.0.0",
4
+ "description": "First-party default plugin that adds an `advisor` tool: a no-argument tool the model calls mid-task to consult a stronger inference profile on the full conversation transcript for strategic guidance, routed through the assistant's own inference.",
5
+ "private": true,
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "engines": {
9
+ "node": ">=20.12.0"
10
+ },
11
+ "peerDependencies": {
12
+ "@vellumai/plugin-api": "^0.8.0"
13
+ }
14
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Prompt fragments for the advisor plugin:
3
+ * - `appendSteering` / `stripSteering` — the executor-facing steering block the
4
+ * `pre-model-call` hook injects so the model reaches for the advisor tool at
5
+ * the right times.
6
+ * - `buildAdvisorSystem` / `advisorRequestText` — the advisor-facing framing for
7
+ * the consult itself.
8
+ */
9
+
10
+ /** Idempotency marker; the steering block is appended at the end of the prompt. */
11
+ export const STEERING_MARKER = "<!-- advisor:steering -->";
12
+
13
+ const STEERING_BODY = `You have an \`advisor\` tool backed by a stronger reviewer model. It takes NO parameters — calling it forwards your entire conversation automatically (the task, every tool call, every result). Call advisor BEFORE you start building or implementing: once you understand what's being asked, consult it to shape the plan — it can lay out the plan when you don't have one yet, or pressure-test and sharpen a plan you've already drafted. Orient yourself first (read the relevant files, understand the task), then call advisor before you commit to an approach and start producing work. Also call it when you get stuck, when you're weighing a change in direction, and once before you declare the task done. Give its guidance serious weight; only override it when primary-source evidence contradicts a specific claim, and say so when you do.`;
14
+
15
+ const ADVISOR_STEERING = `${STEERING_MARKER}\n${STEERING_BODY}`;
16
+
17
+ /** Append the steering block to the executor's system prompt (idempotent). */
18
+ export function appendSteering(systemPrompt: string | null): string | null {
19
+ if (systemPrompt === null) return null;
20
+ if (systemPrompt.includes(STEERING_MARKER)) return systemPrompt;
21
+ return `${systemPrompt}\n\n${ADVISOR_STEERING}`;
22
+ }
23
+
24
+ /** Remove a previously-appended steering block, recovering the original prompt. */
25
+ export function stripSteering(systemPrompt: string | null): string | null {
26
+ if (systemPrompt === null) return null;
27
+ const idx = systemPrompt.indexOf(STEERING_MARKER);
28
+ if (idx === -1) return systemPrompt;
29
+ return systemPrompt.slice(0, idx).trimEnd();
30
+ }
31
+
32
+ /**
33
+ * System prompt for the advisor sub-call. Frames the advisor's role and, for
34
+ * context, quotes the executor's own system prompt (as the advisor tool does —
35
+ * the advisor sees the system prompt as context about the executor's task).
36
+ */
37
+ export function buildAdvisorSystem(
38
+ originalSystemPrompt: string | null,
39
+ ): string {
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.
41
+
42
+ Evaluate the work along these dimensions, and lead with whatever matters most right now:
43
+
44
+ - Approach & plan: If the agent has already drafted a plan or chosen an approach, pressure-test it — is it the right one, or is there a materially better path? If it hasn't committed to one yet, lay out a concrete plan for how to proceed. Either way, be specific about the path you would take and why.
45
+ - Assumptions & requirements: Surface any wrong, unstated, or unverified assumption the agent is building on, and any part of the task it has misread, silently narrowed, or skipped. These are the failures it is least able to see itself.
46
+ - Critical risk: Identify the single failure mode most likely to derail the task — or that already has — and how to avoid or recover from it.
47
+ - Next step: Give one concrete action the agent can take immediately. Name the specific file, function, command, interface, or decision involved — not a generic direction.
48
+ - Verification: If the agent has no clear way to confirm its work is correct, tell it how it will know.
49
+
50
+ How to advise:
51
+ - Be specific and grounded. Cite what you actually see in the transcript — a particular result, a line of reasoning, a command that failed. Never invent details that aren't there; if a decisive fact is missing, say what the agent should go find out.
52
+ - Be decisive. Give a clear recommendation, not a menu of equally weighted options. When genuinely uncertain, say so and state what would resolve it.
53
+ - Prioritize ruthlessly. Lead with the highest-leverage point. Don't restate at length what the agent already did well, and don't pad the response with minor nitpicks — a focused, well-reasoned critique beats an exhaustive one.
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.
55
+
56
+ Write as much as the guidance genuinely needs, and no more.`;
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>`;
59
+ }
60
+
61
+ /**
62
+ * The final user turn appended to the transcript for the advisor sub-call. Asks
63
+ * for guidance; imposes no length limit — the advisor decides how much to say.
64
+ */
65
+ export function advisorRequestText(): string {
66
+ return `Review the conversation above — the task, the tool calls, and their results — and give focused strategic guidance on how to proceed.`;
67
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The `advisor` tool — a no-argument tool the model calls to consult a stronger
3
+ * model for strategic guidance. The model supplies no input; the plugin reads
4
+ * the transcript captured by the lifecycle hooks and runs the consult, routed
5
+ * through the assistant's own inference.
6
+ *
7
+ * Default export = the tool definition. `defaults/index.ts` finalizes it and
8
+ * attaches it to the advisor plugin's `tools` array, which `bootstrapPlugins`
9
+ * registers into the model-visible tool catalog.
10
+ */
11
+
12
+ import type {
13
+ ToolContext,
14
+ ToolDefinition,
15
+ ToolExecutionResult,
16
+ } from "@vellumai/plugin-api";
17
+ import { RiskLevel } from "@vellumai/plugin-api";
18
+
19
+ import { advisorEnabledForProfile } from "../advisor-gate.js";
20
+ import { getCapture } from "../advisor-state-store.js";
21
+ import { consultAdvisor } from "../consult.js";
22
+
23
+ const advisorTool: ToolDefinition = {
24
+ name: "advisor",
25
+ description:
26
+ "Consult a stronger advisor model to shape your plan and get strategic guidance. " +
27
+ "Takes NO parameters — your full conversation (the task, every tool call, and every " +
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.",
32
+ input_schema: { type: "object", properties: {}, additionalProperties: false },
33
+ // Read-only advice; low risk so the consult isn't gated behind a prompt.
34
+ defaultRiskLevel: RiskLevel.Low,
35
+ async execute(
36
+ _input: Record<string, unknown>,
37
+ ctx: ToolContext,
38
+ ): Promise<ToolExecutionResult> {
39
+ // Defense-in-depth: the steering is already gated per profile, but a model
40
+ // could still call the tool. Honor the chat profile this turn runs under —
41
+ // the per-turn override (per-conversation / profile-session) when present,
42
+ // else the workspace active profile.
43
+ if (!advisorEnabledForProfile(ctx.overrideProfile ?? null)) {
44
+ return {
45
+ content: "(advisor is disabled for the active profile)",
46
+ isError: false,
47
+ };
48
+ }
49
+ try {
50
+ const capture = getCapture(ctx.conversationId);
51
+ const advice = await consultAdvisor({
52
+ systemPrompt: capture?.systemPrompt ?? null,
53
+ messages: capture?.messages ?? [],
54
+ signal: ctx.signal,
55
+ });
56
+ return { content: advice, isError: false };
57
+ } catch (err) {
58
+ // Degrade like the advisor tool: never fail the turn over a consult.
59
+ const reason = err instanceof Error ? err.message : String(err);
60
+ return { content: `(advisor unavailable: ${reason})`, isError: false };
61
+ }
62
+ },
63
+ };
64
+
65
+ export default advisorTool;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Convert a captured executor transcript into the message list sent to the
3
+ * advisor sub-call.
4
+ *
5
+ * Strips blocks the advisor shouldn't (or can't) replay:
6
+ * - thinking / redacted-thinking (the advisor tool drops thinking),
7
+ * - files,
8
+ * - `server_tool_use` AND `web_search_tool_result` — provider-side tool calls
9
+ * (e.g. web search) and their results are dropped *together*. Dropping the
10
+ * result without its paired `server_tool_use` would leave an orphaned call
11
+ * block the provider rejects, so any consult after prior web-search history
12
+ * would fail; dropping both keeps the sequence valid.
13
+ *
14
+ * Images are preserved — top-level and nested inside `tool_result.contentBlocks`
15
+ * (which are recursively sanitized) — so the advisor sees what the executor saw.
16
+ * Visual tasks depend on it; the advisor profile is expected to be vision-capable.
17
+ *
18
+ * It also strips the *pending* client tool calls from the final assistant turn:
19
+ * at capture time (a `post-model-call` before tools run) the last assistant
20
+ * message carries the `advisor` tool_use with no matching `tool_result` yet, so
21
+ * sending it would be a dangling call. Earlier, completed `tool_use` /
22
+ * `tool_result` pairs are preserved intact.
23
+ */
24
+
25
+ import type { ContentBlock, Message } from "../../../providers/types.js";
26
+
27
+ /** Drop disallowed blocks; recursively sanitize tool_result content. `null` = drop. */
28
+ function sanitize(block: ContentBlock): ContentBlock | null {
29
+ switch (block.type) {
30
+ case "thinking":
31
+ case "redacted_thinking":
32
+ case "file":
33
+ case "server_tool_use":
34
+ case "web_search_tool_result":
35
+ return null;
36
+ case "tool_result": {
37
+ if (!block.contentBlocks) return block;
38
+ // Keep images (and other allowed blocks) nested in the tool result; drop
39
+ // the disallowed ones.
40
+ const contentBlocks = block.contentBlocks
41
+ .map(sanitize)
42
+ .filter((b): b is ContentBlock => b !== null);
43
+ return {
44
+ ...block,
45
+ contentBlocks: contentBlocks.length > 0 ? contentBlocks : undefined,
46
+ };
47
+ }
48
+ default:
49
+ // text, image, tool_use — kept.
50
+ return block;
51
+ }
52
+ }
53
+
54
+ export function toAdvisorMessages(messages: ReadonlyArray<Message>): Message[] {
55
+ const out: Message[] = [];
56
+ const lastIndex = messages.length - 1;
57
+
58
+ messages.forEach((message, index) => {
59
+ let content = message.content
60
+ .map(sanitize)
61
+ .filter((b): b is ContentBlock => b !== null);
62
+
63
+ // The final assistant turn's client tool calls have no results yet — drop
64
+ // them so we never send a dangling tool_use. (server_tool_use is already
65
+ // dropped above.)
66
+ if (index === lastIndex && message.role === "assistant") {
67
+ content = content.filter(
68
+ (b) => b.type !== "tool_use" && b.type !== "server_tool_use",
69
+ );
70
+ }
71
+
72
+ if (content.length > 0) out.push({ role: message.role, content });
73
+ });
74
+
75
+ return out;
76
+ }
@@ -24,8 +24,15 @@
24
24
  * {@link registerDefaultPlugins} at call time.
25
25
  */
26
26
 
27
+ import { finalizeTool } from "../../tools/tool-defaults.js";
27
28
  import { registerPlugin, resetPluginRegistryForTests } from "../registry.js";
28
29
  import { type Plugin, PluginExecutionError } from "../types.js";
30
+ import { resetAdvisorStateForTests } from "./advisor/advisor-state-store.js";
31
+ import advisorPostModelCall from "./advisor/hooks/post-model-call.js";
32
+ import advisorPreModelCall from "./advisor/hooks/pre-model-call.js";
33
+ import advisorUserPromptSubmit from "./advisor/hooks/user-prompt-submit.js";
34
+ import advisorPkg from "./advisor/package.json" with { type: "json" };
35
+ import advisorTool from "./advisor/tools/advisor.js";
29
36
  import compactionPkg from "./compaction/package.json" with { type: "json" };
30
37
  import emptyResponsePostModelCall from "./empty-response/hooks/post-model-call.js";
31
38
  import emptyResponseStop from "./empty-response/hooks/stop.js";
@@ -54,6 +61,10 @@ import memoryRetrievalPkg from "./memory-retrieval/package.json" with { type: "j
54
61
  import memoryV3PostCompact from "./memory-v3-shadow/hooks/post-compact.js";
55
62
  import memoryV3UserPromptSubmit from "./memory-v3-shadow/hooks/user-prompt-submit.js";
56
63
  import memoryV3Pkg from "./memory-v3-shadow/package.json" with { type: "json" };
64
+ import surfaceCompletionNudgePostModelCall from "./surface-completion-nudge/hooks/post-model-call.js";
65
+ import surfaceCompletionNudgeStop from "./surface-completion-nudge/hooks/stop.js";
66
+ import { resetSurfaceCompletionNudgeStoreForTests } from "./surface-completion-nudge/nudge-state-store.js";
67
+ import surfaceCompletionNudgePkg from "./surface-completion-nudge/package.json" with { type: "json" };
57
68
  import taskProgressNudgePostToolUse, {
58
69
  resetTaskProgressNudgeStateForTests,
59
70
  } from "./task-progress-nudge/hooks/post-tool-use.js";
@@ -259,6 +270,25 @@ export const defaultTaskProgressNudgePlugin: Plugin = {
259
270
  },
260
271
  };
261
272
 
273
+ /**
274
+ * `surface-completion-nudge` — a `post-model-call` hook that, when a user-facing
275
+ * turn is about to end with a progress surface (a `task_progress` card or
276
+ * `work_result`) the model showed but never advanced to a terminal status or
277
+ * dismissed, nudges the model once to close it and re-queries so it can act; the
278
+ * `stop` hook clears the one-shot bound on a terminal stop so the next run
279
+ * nudges afresh.
280
+ */
281
+ export const defaultSurfaceCompletionNudgePlugin: Plugin = {
282
+ manifest: {
283
+ name: surfaceCompletionNudgePkg.name,
284
+ version: surfaceCompletionNudgePkg.version,
285
+ },
286
+ hooks: {
287
+ "post-model-call": surfaceCompletionNudgePostModelCall,
288
+ stop: surfaceCompletionNudgeStop,
289
+ },
290
+ };
291
+
262
292
  /**
263
293
  * `tool-result-truncate` — a `post-tool-use` hook that tail-drops an oversized
264
294
  * tool result down to a character budget derived from the model's context
@@ -274,6 +304,30 @@ export const defaultToolResultTruncatePlugin: Plugin = {
274
304
  },
275
305
  };
276
306
 
307
+ /**
308
+ * `advisor` — adds the model-visible `advisor` tool: a no-argument tool the
309
+ * model calls to consult a stronger inference profile (the `inference` call
310
+ * site with a `quality-optimized` override) on the full transcript, routed
311
+ * through the assistant's own inference. Three hooks feed it: `user-prompt-submit`
312
+ * seeds the capture, `pre-model-call` records the executor's system prompt and
313
+ * injects the steering that nudges the model to consult, and `post-model-call`
314
+ * snapshots the transcript the tool reads. `finalizeTool` fills the tool's
315
+ * defaults so it satisfies `Tool`, and `bootstrapPlugins` registers it into the
316
+ * catalog.
317
+ */
318
+ export const defaultAdvisorPlugin: Plugin = {
319
+ manifest: {
320
+ name: advisorPkg.name,
321
+ version: advisorPkg.version,
322
+ },
323
+ hooks: {
324
+ "user-prompt-submit": advisorUserPromptSubmit,
325
+ "pre-model-call": advisorPreModelCall,
326
+ "post-model-call": advisorPostModelCall,
327
+ },
328
+ tools: [finalizeTool(advisorTool, "advisor")],
329
+ };
330
+
277
331
  /**
278
332
  * Full set of first-party default plugins. Used by
279
333
  * {@link registerDefaultPlugins} to drive the registration loop; the array
@@ -289,11 +343,15 @@ function getAllDefaultPlugins(): readonly Plugin[] {
289
343
  defaultToolErrorPlugin,
290
344
  defaultExplorationDriftPlugin,
291
345
  defaultTaskProgressNudgePlugin,
346
+ defaultSurfaceCompletionNudgePlugin,
292
347
  defaultHistoryRepairPlugin,
293
348
  defaultImageRecoveryPlugin,
294
349
  defaultCompactionPlugin,
295
350
  defaultTitleGeneratePlugin,
296
351
  memoryV3ShadowPlugin,
352
+ // Registered last so its capture hooks observe the fully-processed turn
353
+ // (memory injections, history repair) that the executor actually sees.
354
+ defaultAdvisorPlugin,
297
355
  ];
298
356
  }
299
357
 
@@ -339,5 +397,7 @@ export function resetPluginRegistryAndRegisterDefaults(): void {
339
397
  resetImageRecoveryStoreForTests();
340
398
  resetExplorationDriftStateForTests();
341
399
  resetTaskProgressNudgeStateForTests();
400
+ resetSurfaceCompletionNudgeStoreForTests();
401
+ resetAdvisorStateForTests();
342
402
  registerDefaultPlugins();
343
403
  }