@vellumai/assistant 0.7.0 → 0.7.1

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 (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -1,5 +1,9 @@
1
1
  import { resolveCallSiteConfig } from "../config/llm-resolver.js";
2
2
  import { getConfig } from "../config/loader.js";
3
+ import {
4
+ resolveUsageAttribution,
5
+ sanitizeUsageMetadataValue,
6
+ } from "../usage/attribution.js";
3
7
  import { ProviderError } from "../util/errors.js";
4
8
  import { getLogger } from "../util/logger.js";
5
9
  import {
@@ -24,6 +28,14 @@ import {
24
28
 
25
29
  const log = getLogger("retry");
26
30
 
31
+ const USAGE_ATTRIBUTION_HEADER_NAMES = {
32
+ callSite: "X-Vellum-LLM-Call-Site",
33
+ inferenceProfile: "X-Vellum-Inference-Profile",
34
+ inferenceProfileSource: "X-Vellum-Inference-Profile-Source",
35
+ resolvedProvider: "X-Vellum-Resolved-Provider",
36
+ resolvedModel: "X-Vellum-Resolved-Model",
37
+ } as const;
38
+
27
39
  /** Providers that support the `effort` config (extended thinking / reasoning). */
28
40
  const EFFORT_SUPPORTED_PROVIDERS = new Set([
29
41
  "anthropic",
@@ -118,12 +130,18 @@ function isRetryableError(error: unknown): boolean {
118
130
  function normalizeSendMessageOptions(
119
131
  providerName: string,
120
132
  options?: SendMessageOptions,
133
+ normalizeOptions: { forwardUsageAttributionHeaders?: boolean } = {},
121
134
  ): SendMessageOptions | undefined {
122
135
  const config = options?.config;
123
136
  if (!config) return options;
124
137
 
125
138
  const nextConfig: Record<string, unknown> = { ...config };
126
139
 
140
+ // Internal metadata must be derived here, not accepted from callers, and it
141
+ // must never leak into provider JSON request bodies.
142
+ delete nextConfig.usageAttributionHeaders;
143
+ delete nextConfig.usageTracking;
144
+
127
145
  // `overrideProfile` is a routing/resolution-time concern (consumed by the
128
146
  // resolver below and `CallSiteRoutingProvider`'s provider selection); it is
129
147
  // not a wire-format field. Strip unconditionally so it never leaks into
@@ -134,6 +152,10 @@ function normalizeSendMessageOptions(
134
152
  const resolved = resolveCallSiteConfig(config.callSite, getConfig().llm, {
135
153
  overrideProfile: config.overrideProfile,
136
154
  });
155
+ const attribution = resolveUsageAttribution({
156
+ callSite: config.callSite,
157
+ overrideProfile: config.overrideProfile,
158
+ });
137
159
 
138
160
  const explicitModel =
139
161
  typeof config.model === "string" && config.model.trim().length > 0
@@ -143,6 +165,18 @@ function normalizeSendMessageOptions(
143
165
  // Routing key is consumed by the resolver above and must not leak
144
166
  // downstream as a wire-format field.
145
167
  delete nextConfig.callSite;
168
+ if (normalizeOptions.forwardUsageAttributionHeaders === true) {
169
+ const usageAttributionHeaders = buildUsageAttributionHeaders({
170
+ callSite: attribution.callSite,
171
+ appliedProfile: attribution.appliedProfile,
172
+ profileSource: attribution.profileSource,
173
+ resolvedProvider: attribution.resolvedProvider,
174
+ resolvedModel: attribution.resolvedModel,
175
+ });
176
+ if (Object.keys(usageAttributionHeaders).length > 0) {
177
+ nextConfig.usageAttributionHeaders = usageAttributionHeaders;
178
+ }
179
+ }
146
180
 
147
181
  // Apply resolved values, letting per-call explicit fields win where set.
148
182
  nextConfig.model = explicitModel ?? resolved.model;
@@ -194,12 +228,11 @@ function normalizeSendMessageOptions(
194
228
  nextConfig.openrouter = { only: resolved.openrouter.only };
195
229
  }
196
230
  // `contextWindow` and `provider` are server-side concerns, not provider
197
- // request parameters: `contextWindow` is consumed by the agent loop's
198
- // overflow recovery and the conversation manager directly from
199
- // `config.llm.default.contextWindow.*`; `provider` selection is handled
200
- // by `CallSiteRoutingProvider` upstream. Forwarding them as per-call
201
- // config leaks unknown fields into provider request bodies — Anthropic
202
- // (and other strict-schema clients) reject the request with
231
+ // request parameters: effective context is resolved per call site/profile
232
+ // by the agent/conversation path, while `provider` selection is handled by
233
+ // `CallSiteRoutingProvider` upstream. Forwarding them as per-call config
234
+ // leaks unknown fields into provider request bodies — Anthropic (and other
235
+ // strict-schema clients) reject the request with
203
236
  // "Extra inputs are not permitted".
204
237
  }
205
238
 
@@ -274,6 +307,55 @@ function normalizeSendMessageOptions(
274
307
  };
275
308
  }
276
309
 
310
+ function buildUsageAttributionHeaders(input: {
311
+ callSite: string | null;
312
+ appliedProfile: string | null;
313
+ profileSource: string;
314
+ resolvedProvider: string;
315
+ resolvedModel: string;
316
+ }): Record<string, string> {
317
+ const headers: Record<string, string> = {};
318
+ addSanitizedHeader(
319
+ headers,
320
+ USAGE_ATTRIBUTION_HEADER_NAMES.callSite,
321
+ input.callSite,
322
+ );
323
+ addSanitizedHeader(
324
+ headers,
325
+ USAGE_ATTRIBUTION_HEADER_NAMES.inferenceProfile,
326
+ input.appliedProfile,
327
+ );
328
+ if (input.appliedProfile) {
329
+ addSanitizedHeader(
330
+ headers,
331
+ USAGE_ATTRIBUTION_HEADER_NAMES.inferenceProfileSource,
332
+ input.profileSource,
333
+ );
334
+ }
335
+ addSanitizedHeader(
336
+ headers,
337
+ USAGE_ATTRIBUTION_HEADER_NAMES.resolvedProvider,
338
+ input.resolvedProvider,
339
+ );
340
+ addSanitizedHeader(
341
+ headers,
342
+ USAGE_ATTRIBUTION_HEADER_NAMES.resolvedModel,
343
+ input.resolvedModel,
344
+ );
345
+ return headers;
346
+ }
347
+
348
+ function addSanitizedHeader(
349
+ headers: Record<string, string>,
350
+ name: string,
351
+ value: unknown,
352
+ ): void {
353
+ const sanitized = sanitizeUsageMetadataValue(value);
354
+ if (sanitized != null) {
355
+ headers[name] = sanitized;
356
+ }
357
+ }
358
+
277
359
  /**
278
360
  * `RetryProvider` sets `retriesExhausted = true` on the final thrown error
279
361
  * when the retry loop burned through all attempts against a retryable error
@@ -289,7 +371,10 @@ export class RetryProvider implements Provider {
289
371
  return this.inner.tokenEstimationProvider;
290
372
  }
291
373
 
292
- constructor(private readonly inner: Provider) {
374
+ constructor(
375
+ private readonly inner: Provider,
376
+ private readonly options: { forwardUsageAttributionHeaders?: boolean } = {},
377
+ ) {
293
378
  this.name = inner.name;
294
379
  }
295
380
 
@@ -302,7 +387,10 @@ export class RetryProvider implements Provider {
302
387
  let lastError: unknown;
303
388
  let didRetry = false;
304
389
 
305
- const normalizedOptions = normalizeSendMessageOptions(this.name, options);
390
+ const normalizedOptions = normalizeSendMessageOptions(this.name, options, {
391
+ forwardUsageAttributionHeaders:
392
+ this.options.forwardUsageAttributionHeaders === true,
393
+ });
306
394
 
307
395
  for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
308
396
  try {
@@ -156,6 +156,19 @@ export interface SendMessageConfig {
156
156
  * silently fall through.
157
157
  */
158
158
  overrideProfile?: string;
159
+ /**
160
+ * Internal per-request HTTP headers for managed-proxy usage attribution.
161
+ * Provider clients may pass these through SDK request options only when the
162
+ * transport is Vellum-managed, and must never include this object in provider
163
+ * JSON request bodies.
164
+ */
165
+ usageAttributionHeaders?: Record<string, string>;
166
+ /**
167
+ * Controls local usage-ledger writes for attributed provider calls.
168
+ * Defaults to `auto`; conversation paths that aggregate usage separately
169
+ * set `manual` to avoid double-counting.
170
+ */
171
+ usageTracking?: "auto" | "manual";
159
172
  effort?: "none" | "low" | "medium" | "high" | "xhigh" | "max";
160
173
  speed?: "standard" | "fast";
161
174
  verbosity?: "low" | "medium" | "high";
@@ -0,0 +1,96 @@
1
+ import { recordUsageEvent } from "../memory/llm-usage-store.js";
2
+ import { resolveUsageAttribution } from "../usage/attribution.js";
3
+ import {
4
+ buildPricingUsageFromResponse,
5
+ resolveStructuredPricing,
6
+ } from "../usage/pricing.js";
7
+ import { getLogger } from "../util/logger.js";
8
+ import type {
9
+ Message,
10
+ Provider,
11
+ ProviderResponse,
12
+ SendMessageOptions,
13
+ ToolDefinition,
14
+ } from "./types.js";
15
+
16
+ const log = getLogger("provider-usage-tracking");
17
+
18
+ export class UsageTrackingProvider implements Provider {
19
+ public readonly name: string;
20
+ public readonly tokenEstimationProvider?: string;
21
+
22
+ constructor(private readonly inner: Provider) {
23
+ this.name = inner.name;
24
+ this.tokenEstimationProvider = inner.tokenEstimationProvider;
25
+ }
26
+
27
+ async sendMessage(
28
+ messages: Message[],
29
+ tools?: ToolDefinition[],
30
+ systemPrompt?: string,
31
+ options?: SendMessageOptions,
32
+ ): Promise<ProviderResponse> {
33
+ const response = await this.inner.sendMessage(
34
+ messages,
35
+ tools,
36
+ systemPrompt,
37
+ options,
38
+ );
39
+ this.recordUsage(response, options);
40
+ return response;
41
+ }
42
+
43
+ private recordUsage(
44
+ response: ProviderResponse,
45
+ options?: SendMessageOptions,
46
+ ): void {
47
+ const config = options?.config;
48
+ if (!config?.callSite) return;
49
+ if (config.usageTracking === "manual") return;
50
+ if (response.usage.inputTokens <= 0 && response.usage.outputTokens <= 0) {
51
+ return;
52
+ }
53
+
54
+ try {
55
+ const attribution = resolveUsageAttribution({
56
+ callSite: config.callSite,
57
+ overrideProfile: config.overrideProfile,
58
+ });
59
+ const providerName = response.actualProvider ?? this.inner.name;
60
+ const pricingUsage = buildPricingUsageFromResponse(
61
+ providerName,
62
+ response,
63
+ );
64
+ const pricing = resolveStructuredPricing(
65
+ providerName,
66
+ response.model,
67
+ pricingUsage,
68
+ );
69
+
70
+ recordUsageEvent(
71
+ {
72
+ actor: "llm_call_site",
73
+ provider: providerName,
74
+ model: response.model,
75
+ inputTokens: pricingUsage.directInputTokens,
76
+ outputTokens: pricingUsage.outputTokens,
77
+ cacheCreationInputTokens: pricingUsage.cacheCreationInputTokens,
78
+ cacheReadInputTokens: pricingUsage.cacheReadInputTokens,
79
+ conversationId: null,
80
+ runId: null,
81
+ requestId: null,
82
+ callSite: attribution.callSite,
83
+ inferenceProfile: attribution.appliedProfile,
84
+ inferenceProfileSource: attribution.profileSource,
85
+ llmCallCount: 1,
86
+ },
87
+ pricing,
88
+ );
89
+ } catch (err) {
90
+ log.warn(
91
+ { err, callSite: config.callSite },
92
+ "Failed to auto-record provider usage event (non-fatal)",
93
+ );
94
+ }
95
+ }
96
+ }
@@ -12,6 +12,10 @@ The single HTTP send endpoint is `POST /v1/messages`. Key behaviors:
12
12
 
13
13
  Do NOT add new send endpoints. All message ingress should go through `POST /v1/messages` (HTTP).
14
14
 
15
+ ### GET handler idempotency
16
+
17
+ GET handlers must be safe and side-effect-free — they must not enqueue background jobs, mutate database state, or trigger writes. If a feature needs server-initiated work in response to a client request, use an explicit POST endpoint or a push-based flow (SSE event → client refetch). See [RFC 9110 §9.2.1 — Safe Methods](https://httpwg.org/specs/rfc9110.html#safe.methods).
18
+
15
19
  ### Approvals (confirmations, secrets, trust rules)
16
20
 
17
21
  Approvals are **orthogonal to message sending**. The assistant asks for approval whenever it needs one — this is a separate concern from how a message enters the system.
@@ -65,11 +69,11 @@ Host browser allows the assistant to proxy CDP (Chrome DevTools Protocol) JSON-R
65
69
 
66
70
  The `chrome-extension` interface in `INTERFACE_IDS` is a non-interactive transport that supports only the `host_browser` capability — it does NOT support `host_bash`, `host_file`, or `host_cu`. This is encoded in `supportsHostProxy(id, capability)`: passing a capability argument returns `true` for `chrome-extension` only when the capability is `host_browser`; the no-arg form returns `false` for `chrome-extension` (so legacy desktop-only call sites that assume full-desktop proxy availability continue to gate correctly).
67
71
 
68
- For **self-hosted** deployments, `host_browser_request` frames are routed through the `ChromeExtensionRegistry` singleton (`runtime/chrome-extension-registry.ts`), which tracks active chrome-extension WebSocket connections keyed by `(guardianId, clientInstanceId)`. The registry is populated on WebSocket `open` and drained on `close` inside `http-server.ts`'s `/v1/browser-relay` handlers — see the `wsType === "browser-relay"` branches. For **cloud/platform-hosted** deployments, the chrome extension connects via SSE (`GET /v1/events` with `X-Vellum-Interface-Id: chrome-extension`) and `host_browser_request` frames travel through `assistantEventHub` to the SSE stream. The extension POSTs results back to `POST /v1/host-browser-result`. Transport selection is handled by `resolveHostBrowserSender()` which checks the `ChromeExtensionRegistry` first (WS), then the `ClientRegistry` for an SSE-connected chrome-extension client. For macOS, `host_browser_request` frames travel through `assistantEventHub` (SSE) by default; when the guardian also has an active extension connection, the registry-routed WebSocket sender takes precedence.
72
+ For **self-hosted** deployments, `host_browser_request` frames are routed through the `ChromeExtensionRegistry` singleton (`runtime/chrome-extension-registry.ts`), which tracks active chrome-extension WebSocket connections keyed by `(guardianId, clientInstanceId)`. The registry is populated on WebSocket `open` and drained on `close` inside `http-server.ts`'s `/v1/browser-relay` handlers — see the `wsType === "browser-relay"` branches. For **cloud/platform-hosted** deployments, the chrome extension connects via SSE (`GET /v1/events` with `X-Vellum-Interface-Id: chrome-extension`) and `host_browser_request` frames travel through `assistantEventHub` to the SSE stream. The extension POSTs results back to `POST /v1/host-browser-result`. Transport selection is handled by `HostBrowserProxy`, which publishes events to the `assistantEventHub` with `targetCapability: "host_browser"` the hub delivers to whichever subscriber (chrome-extension or macOS client) has the `host_browser` capability. For macOS, `host_browser_request` frames travel through `assistantEventHub` (SSE) by default; when the guardian also has an active extension connection, the registry-routed WebSocket sender takes precedence.
69
73
 
70
74
  A single guardian may have multiple parallel extension installs connected at once (two Chrome profiles, two desktops sharing a sync identity). Each install generates a stable `clientInstanceId` on first run, persists it in `chrome.storage.local`, and sends it on every WebSocket handshake as a query param (`clientInstanceId=...`) or header (`x-client-instance-id`). The registry keys inner entries by that id so sibling installs don't evict each other on register/unregister. The default `send(guardianId, msg)` path routes to whichever instance has the most recent activity (`lastActiveAt`); `sendToInstance(guardianId, clientInstanceId, msg)` pins a specific install. Older extension builds that omit the id get a connection-scoped `legacy:<connectionId>` fallback key so they degrade gracefully to single-instance semantics.
71
75
 
72
- `Conversation.hostBrowserSenderOverride` is the integration point between the turn layer and the registry. When any turn enters the routes layer and the guardian has an active extension connection in the `ChromeExtensionRegistry`, `conversation-routes.ts` resolves the registry entry and sets the override to a sender that writes to that WebSocket. This applies to chrome-extension turns (where the registry is the only transport) and macOS turns (where the extension connection lets browser tools route through the user's real Chrome session instead of cdp-inspect/local). `Conversation.restoreBrowserProxyAvailability()` re-threads the override on queue drain — without this, the drain path would clobber the registry-routed sender with the default `sendToClient` (pointed at the SSE hub) and `host_browser_request` frames would stop reaching the extension mid-queue.
76
+ `Conversation.hostBrowserSenderOverride` is the integration point between the turn layer and the proxy. When any turn enters the routes layer and the guardian has an active extension connection in the `ChromeExtensionRegistry`, `conversation-routes.ts` resolves the registry entry and sets the override to a sender that writes to that WebSocket. This applies to chrome-extension turns (where the registry is the only transport) and macOS turns (where the extension connection lets browser tools route through the user's real Chrome session instead of cdp-inspect/local). `Conversation.restoreBrowserProxyAvailability()` re-threads the override on queue drain — without this, the drain path would clobber the registry-routed sender with the default `sendToClient` (pointed at the SSE hub) and `host_browser_request` frames would stop reaching the extension mid-queue.
73
77
 
74
78
  Capability token bootstrap for self-hosted deployments is handled by the gateway (`gateway/src/http/routes/browser-extension-pair.ts`) which mints a guardian-bound HMAC capability token. The daemon delegates token verification to the gateway via IPC (`verify_capability_token`) — it must never read secrets from `GATEWAY_SECURITY_DIR` or any other gateway-owned directory. Cloud deployments issue guardian-bound JWTs via the gateway's WorkOS-backed flow.
75
79
 
@@ -81,7 +85,7 @@ On macOS-originated turns, the CDP factory (`tools/browser/cdp-client/factory.ts
81
85
 
82
86
  | Priority | Backend | Condition | Transport |
83
87
  | -------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
84
- | 1 | **Extension / host proxy** | `hostBrowserProxy` present AND `isAvailable()` returns `true`. On macOS, the proxy is always provisioned. On other interfaces, requires an active transport (WS registry or SSE chrome-extension client) | WS via `ChromeExtensionRegistry` (self-hosted), SSE via `assistantEventHub` (cloud extension or macOS) |
88
+ | 1 | **Extension / host proxy** | `hostBrowserProxy` present AND `isAvailable()` returns `true`. On macOS, the proxy is always provisioned. On other interfaces, requires an active hub subscriber with `host_browser` capability | WS via `ChromeExtensionRegistry` (self-hosted), SSE via `assistantEventHub` with `targetCapability: "host_browser"` (cloud extension or macOS) |
85
89
  | 2 | **cdp-inspect** | (a) `hostBrowser.cdpInspect.enabled` is `true` in config, OR (b) `transportInterface === "macos"` AND `desktopAuto.enabled` is `true` (default) AND the cooldown from a prior failure is not active | Direct CDP WebSocket to `localhost:9222` |
86
90
  | 3 | **Local** | Always present as the final fallback | In-process Playwright CDP via `browserManager` |
87
91
 
@@ -89,9 +93,9 @@ On macOS-originated turns, the CDP factory (`tools/browser/cdp-client/factory.ts
89
93
 
90
94
  The "extension" backend label is a misnomer inherited from the original Phase 2 design where only the Chrome Extension provided host-browser access. In the current architecture, two transports can power this backend:
91
95
 
92
- - **Extension WebSocket** (self-hosted): When the `ChromeExtensionRegistry` has an active entry for the guardian, `resolveHostBrowserSender()` returns a registry-routed sender. `host_browser_request` frames travel over the `/v1/browser-relay` WebSocket to the Chrome extension, which executes CDP commands via `chrome.debugger`.
93
- - **Extension SSE** (cloud/platform): When no WebSocket entry exists but a `chrome-extension` client is registered in the `ClientRegistry` (connected via `GET /v1/events`), `resolveHostBrowserSender()` returns the `onEvent` SSE hub sender and sets `hasSseExtension = true`. `host_browser_request` frames travel through `assistantEventHub` to the extension's SSE stream. The extension POSTs results back to `/v1/host-browser-result`. This path is used for any `canServiceSseBrowser()` interface (`web`, `chrome-extension`, `macos`).
94
- - **macOS SSE bridge**: When the macOS desktop client is connected but no extension is present, `resolveHostBrowserSender()` returns the `onEvent` SSE hub sender. `host_browser_request` frames travel through `assistantEventHub` to the desktop client's SSE connection. The desktop client executes CDP commands against the local Chrome and POSTs results back to `/v1/host-browser-result`.
96
+ - **Extension WebSocket** (self-hosted): When the `ChromeExtensionRegistry` has an active entry for the guardian, the registry-routed sender delivers frames over the `/v1/browser-relay` WebSocket to the Chrome extension, which executes CDP commands via `chrome.debugger`.
97
+ - **Extension SSE** (cloud/platform): When no WebSocket entry exists, `HostBrowserProxy.send()` publishes to `assistantEventHub` with `targetCapability: "host_browser"`. The hub delivers the event to the chrome-extension subscriber (which registered with that capability via SSE). The extension POSTs results back to `/v1/host-browser-result`. This path is used for any `canServiceSseBrowser()` interface (`web`, `chrome-extension`, `macos`).
98
+ - **macOS SSE bridge**: When the macOS desktop client is connected but no extension is present, the same hub publish with `targetCapability: "host_browser"` delivers to the macOS subscriber (which has all host-proxy capabilities). The desktop client executes CDP commands against the local Chrome and POSTs results back to `/v1/host-browser-result`.
95
99
 
96
100
  All three transports use the same `HostBrowserProxy` → `ExtensionCdpClient` pipeline. The `browser_status` output distinguishes the transport via the `details.transport` field: `"extension-ws"` or `"macos-sse"`.
97
101
 
@@ -402,6 +402,95 @@ describe("wakeAgentForOpportunity", () => {
402
402
  expect(processing).toBe(false);
403
403
  });
404
404
 
405
+ test("applies caller-supplied trustContext to the target before the agent loop runs", async () => {
406
+ // Background system jobs (memory consolidation, update-bulletin) need
407
+ // guardian trust to clear the side-effect approval gate. The wake must
408
+ // call setTrustContext BEFORE agentLoop.run so the per-turn snapshot
409
+ // captures the elevated trust.
410
+ const trustCalls: Array<{ ctx: unknown; before: number }> = [];
411
+ const runCalls: number[] = [];
412
+ let callOrder = 0;
413
+
414
+ const history: Message[] = [];
415
+ let processing = false;
416
+ const target: WakeTarget = {
417
+ conversationId: "conv-trust",
418
+ agentLoop: {
419
+ run: async (input) => {
420
+ runCalls.push(callOrder++);
421
+ return [...input];
422
+ },
423
+ },
424
+ getMessages: () => history,
425
+ pushMessage: () => {},
426
+ emitAgentEvent: () => {},
427
+ isProcessing: () => processing,
428
+ markProcessing: (on) => {
429
+ processing = on;
430
+ },
431
+ persistTailMessage: async () => {},
432
+ setTrustContext: (ctx) => {
433
+ trustCalls.push({ ctx, before: callOrder++ });
434
+ },
435
+ };
436
+
437
+ await wakeAgentForOpportunity(
438
+ {
439
+ conversationId: "conv-trust",
440
+ hint: "consolidate memory",
441
+ source: "memory_v2_consolidation",
442
+ trustContext: { sourceChannel: "vellum", trustClass: "guardian" },
443
+ },
444
+ { resolveTarget: async () => target },
445
+ );
446
+
447
+ expect(trustCalls).toHaveLength(1);
448
+ expect(trustCalls[0]!.ctx).toEqual({
449
+ sourceChannel: "vellum",
450
+ trustClass: "guardian",
451
+ });
452
+ // setTrustContext fired strictly before agentLoop.run.
453
+ expect(runCalls).toHaveLength(1);
454
+ expect(trustCalls[0]!.before).toBeLessThan(runCalls[0]!);
455
+ });
456
+
457
+ test("does not call setTrustContext when no trustContext is supplied", async () => {
458
+ const trustCalls: unknown[] = [];
459
+ const history: Message[] = [];
460
+ let processing = false;
461
+ const target: WakeTarget = {
462
+ conversationId: "conv-no-trust",
463
+ agentLoop: {
464
+ run: async (input) => [...input],
465
+ },
466
+ getMessages: () => history,
467
+ pushMessage: () => {},
468
+ emitAgentEvent: () => {},
469
+ isProcessing: () => processing,
470
+ markProcessing: (on) => {
471
+ processing = on;
472
+ },
473
+ persistTailMessage: async () => {},
474
+ setTrustContext: (ctx) => {
475
+ trustCalls.push(ctx);
476
+ },
477
+ };
478
+
479
+ await wakeAgentForOpportunity(
480
+ {
481
+ conversationId: "conv-no-trust",
482
+ hint: "x",
483
+ source: "t",
484
+ },
485
+ { resolveTarget: async () => target },
486
+ );
487
+
488
+ // Inbound-message conversations populate trust via processMessage().
489
+ // Without an explicit opt-in from the caller, the wake must not
490
+ // overwrite whatever the conversation already holds.
491
+ expect(trustCalls).toHaveLength(0);
492
+ });
493
+
405
494
  test("two concurrent wakes on the same conversation are serialized", async () => {
406
495
  // Build a target whose agentLoop.run resolves only when we signal.
407
496
  const gate1 = Promise.withResolvers<void>();
@@ -41,6 +41,9 @@
41
41
  */
42
42
 
43
43
  import type { AgentEvent, AgentLoop } from "../agent/loop.js";
44
+ import { resolveEffectiveContextWindow } from "../config/llm-context-resolution.js";
45
+ import { getConfig } from "../config/loader.js";
46
+ import type { TrustContext } from "../daemon/trust-context.js";
44
47
  import { getConversationOverrideProfile } from "../memory/conversation-crud.js";
45
48
  import type { Message } from "../providers/types.js";
46
49
  import { getLogger } from "../util/logger.js";
@@ -137,12 +140,30 @@ export interface WakeTarget {
137
140
  * typically omit it.
138
141
  */
139
142
  onWakeProducedOutput?(source: string, hint: string, surfaceId: string): void;
143
+ /**
144
+ * Apply a trust context to the underlying conversation before the agent
145
+ * loop runs. Internal background jobs (memory consolidation, update
146
+ * bulletin) use this to declare guardian trust so side-effect tools
147
+ * (file_edit, file_write, bash) clear the approval gate. Inbound message
148
+ * conversations populate trust via `processMessage()` and don't pass
149
+ * `trustContext` through the wake.
150
+ */
151
+ setTrustContext?(ctx: TrustContext): void;
140
152
  }
141
153
 
142
154
  export interface WakeOptions {
143
155
  conversationId: string;
144
156
  hint: string;
145
157
  source: string;
158
+ /**
159
+ * Optional trust context to apply to the conversation before the agent
160
+ * loop runs. Required for internal background jobs that need elevated
161
+ * trust to invoke side-effect tools — without it the loop falls back to
162
+ * `trustClass: "unknown"` and side-effect tools are blocked. Caller
163
+ * should pass `{ sourceChannel: "vellum", trustClass: "guardian" }` for
164
+ * assistant-self-maintenance jobs.
165
+ */
166
+ trustContext?: TrustContext;
146
167
  }
147
168
 
148
169
  /**
@@ -370,6 +391,13 @@ export async function wakeAgentForOpportunity(
370
391
  return { invoked: false, producedToolCalls: false, reason: "timeout" };
371
392
  }
372
393
 
394
+ // Apply caller-supplied trust before the agent loop reads its per-turn
395
+ // snapshot. Background jobs without an inbound message use this to
396
+ // declare guardian trust so side-effect tools clear the approval gate.
397
+ if (opts.trustContext && target.setTrustContext) {
398
+ target.setTrustContext(opts.trustContext);
399
+ }
400
+
373
401
  const baseline = target.getMessages();
374
402
  const hintContent = `[opportunity:${source}] ${hint}`;
375
403
  // Sandwich the hint as an assistant message between two hardcoded
@@ -409,10 +437,18 @@ export async function wakeAgentForOpportunity(
409
437
  // Honor the conversation's pinned inference-profile override (if any).
410
438
  // Without this, scheduled-task wakes and other opportunity wakes bypass
411
439
  // `runAgentLoopImpl` entirely and execute under workspace defaults,
412
- // silently violating the user's pinned preference. Read before
413
- // `markProcessing(true)` so a thrown DB read can't strand the
440
+ // silently violating the user's pinned preference. Resolve the effective
441
+ // context budget here as well because wakes bypass the normal user-turn
442
+ // path that computes it for tool-result truncation. Read before
443
+ // `markProcessing(true)` so a thrown DB/config read can't strand the
414
444
  // processing flag.
415
445
  const overrideProfile = getConversationOverrideProfile(conversationId);
446
+ const config = getConfig();
447
+ const effectiveContextWindow = resolveEffectiveContextWindow({
448
+ llm: config.llm,
449
+ callSite: "mainAgent",
450
+ overrideProfile,
451
+ });
416
452
 
417
453
  // Mark processing for the duration of the run so a concurrent user
418
454
  // send is queued by `enqueueMessage()` rather than spawning a second
@@ -442,6 +478,7 @@ export async function wakeAgentForOpportunity(
442
478
  "mainAgent",
443
479
  undefined, // turnContext
444
480
  overrideProfile,
481
+ effectiveContextWindow.maxInputTokens,
445
482
  );
446
483
  } catch (err) {
447
484
  // Capture the error for post-finally logging, then short-circuit