@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
@@ -3,14 +3,21 @@ import { v4 as uuid } from "uuid";
3
3
  import { clearAll, getConversation } from "../../memory/conversation-crud.js";
4
4
  import { resolveConversationId } from "../../memory/conversation-key-store.js";
5
5
  import { broadcastMessage } from "../../runtime/assistant-event-hub.js";
6
+ import { resolveCapabilities } from "../../runtime/capabilities.js";
6
7
  import { getSubagentManager } from "../../subagent/index.js";
7
8
  import { createAbortReason } from "../../util/abort-reasons.js";
9
+ import { UserError } from "../../util/errors.js";
8
10
  import { truncate } from "../../util/truncate.js";
9
11
  import { regenerate } from "../conversation-history.js";
12
+ import {
13
+ buildSlashContext,
14
+ formatCleanResult,
15
+ } from "../conversation-process.js";
10
16
  import {
11
17
  conversationEntries,
12
18
  findConversation,
13
19
  } from "../conversation-registry.js";
20
+ import { resolveSlash } from "../conversation-slash.js";
14
21
  import {
15
22
  clearAllActiveConversations,
16
23
  getOrCreateConversation,
@@ -18,6 +25,7 @@ import {
18
25
  } from "../conversation-store.js";
19
26
  import type { ConfirmationResponse } from "../message-protocol.js";
20
27
  import { normalizeConversationType } from "../message-protocol.js";
28
+ import { INTERNAL_GUARDIAN_TRUST_CONTEXT } from "../trust-context.js";
21
29
  import { log } from "./shared.js";
22
30
 
23
31
  export function handleConfirmationResponse(msg: ConfirmationResponse): void {
@@ -98,6 +106,12 @@ export function cancelGeneration(conversationId: string): boolean {
98
106
  // being cancelled, so enqueuing synthetic messages would trigger
99
107
  // unwanted model activity after the user pressed stop.
100
108
  getSubagentManager().abortAllForParent(conversationId);
109
+ // The processing flag is cleared by the in-flight turn's `finally`, not here.
110
+ // Abort propagates into the provider call and tool execution (and is backed
111
+ // by the agent loop's abort watchdog), so the turn reaches its `finally`
112
+ // within a bounded time and tears down its own state there — which publishes
113
+ // the metadata sync invalidation that drives clients to the authoritative
114
+ // idle state.
101
115
  return true;
102
116
  }
103
117
 
@@ -118,6 +132,99 @@ export async function undoLastMessage(
118
132
  const removedCount = conversation.undo();
119
133
  return { removedCount };
120
134
  }
135
+
136
+ export interface MetaSlashCommandResult {
137
+ kind: "clean" | "info";
138
+ /** User-facing text to render (clean stats card or info listing). */
139
+ text: string;
140
+ /** Present for `/clean`: the post-strip context-window usage. */
141
+ contextUsage?: {
142
+ tokens: number;
143
+ maxTokens: number | null;
144
+ fillRatio: number | null;
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Resolve a local meta slash command (`/clean`, `/status`, `/commands`,
150
+ * `/models`) for a conversation without running a turn: no user/assistant
151
+ * messages are persisted and no streaming/turn events are emitted. `/clean`
152
+ * additionally strips runtime injections via `forceClean`.
153
+ *
154
+ * Returns null if the conversation cannot be resolved. Throws `UserError` for
155
+ * commands that are not local meta commands (`/compact`, passthrough) — those
156
+ * must be sent as a normal message so they run a real turn.
157
+ */
158
+ export async function resolveMetaSlashCommand(
159
+ conversationId: string,
160
+ command: string,
161
+ ): Promise<MetaSlashCommandResult | null> {
162
+ const resolvedId = resolveConversationId(conversationId);
163
+ if (!resolvedId) {
164
+ return null;
165
+ }
166
+ const conversation = await getOrCreateConversation(resolvedId);
167
+ touchConversation(resolvedId);
168
+
169
+ // Meta commands reload (and, for `/clean`, strip) the in-memory history
170
+ // array. Running that against an in-flight turn would corrupt the messages
171
+ // the active agent loop is iterating over, and mutating trustContext would
172
+ // elevate that turn's actor trust to guardian for subsequent tool calls.
173
+ if (conversation.isProcessing()) {
174
+ throw new UserError(
175
+ `\`${command.trim()}\` cannot run while the assistant is responding.`,
176
+ );
177
+ }
178
+
179
+ // Owner self-maintenance operates on the full (guardian) history. Without a
180
+ // trusted context, `loadFromDb` filters to non-guardian provenance — so a
181
+ // guardian-authored conversation would report 0 preserved / 0 messages.
182
+ // Temporarily apply the guardian context for hydration and restore it
183
+ // afterward so the elevated class never leaks into a later turn's snapshot.
184
+ const priorTrustContext = conversation.trustContext;
185
+ if (!resolveCapabilities(priorTrustContext?.trustClass).canAccessMemory) {
186
+ conversation.setTrustContext(INTERNAL_GUARDIAN_TRUST_CONTEXT);
187
+ }
188
+ try {
189
+ await conversation.ensureActorScopedHistory();
190
+
191
+ const slashResult = await resolveSlash(
192
+ command,
193
+ buildSlashContext(command, conversation),
194
+ );
195
+
196
+ if (slashResult.kind === "clean") {
197
+ const result = await conversation.forceClean();
198
+ return {
199
+ kind: "clean",
200
+ text: formatCleanResult(result),
201
+ contextUsage: {
202
+ tokens: result.estimatedInputTokens,
203
+ maxTokens: result.maxInputTokens,
204
+ fillRatio:
205
+ result.maxInputTokens > 0
206
+ ? result.estimatedInputTokens / result.maxInputTokens
207
+ : null,
208
+ },
209
+ };
210
+ }
211
+
212
+ if (slashResult.kind === "unknown") {
213
+ return { kind: "info", text: slashResult.message };
214
+ }
215
+
216
+ // `compact` / `passthrough` are real turns, not local meta commands.
217
+ throw new UserError(`\`${command.trim()}\` is not a local meta command.`);
218
+ } finally {
219
+ // Only undo the temporary guardian context this handler installed. If a
220
+ // new turn started at an `await` boundary and legitimately updated
221
+ // trustContext, the reference will differ and we leave it alone.
222
+ if (conversation.trustContext === INTERNAL_GUARDIAN_TRUST_CONTEXT) {
223
+ conversation.setTrustContext(priorTrustContext ?? null);
224
+ }
225
+ }
226
+ }
227
+
121
228
  /**
122
229
  * Regenerate the last assistant response for a conversation. The caller provides
123
230
  * a `sendEvent` callback for delivering streaming events via HTTP/SSE.
@@ -9,6 +9,7 @@ import * as pendingInteractions from "../runtime/pending-interactions.js";
9
9
  import type { ToolExecutionResult } from "../tools/types.js";
10
10
  import { AssistantError, ErrorCode } from "../util/errors.js";
11
11
  import { getLogger } from "../util/logger.js";
12
+ import { sleep } from "../util/retry.js";
12
13
  import type { HostBrowserRequest } from "./message-types/host-browser.js";
13
14
 
14
15
  /** Distributive omit that preserves union variant fields. */
@@ -24,6 +25,16 @@ export type HostBrowserInput = DistributiveOmit<
24
25
 
25
26
  const log = getLogger("host-browser-proxy");
26
27
 
28
+ /**
29
+ * Grace window for a flapping extension SSE connection. The Chrome
30
+ * extension's stream can briefly drop and reconnect (MV3 service-worker
31
+ * churn); without a short wait, a dispatch landing in a "down" blip
32
+ * hard-fails even though the extension is effectively connected. Well
33
+ * under the request-layer timeout (default 30s).
34
+ */
35
+ const EXTENSION_RECONNECT_GRACE_MS = 3_000;
36
+ const EXTENSION_RECONNECT_POLL_MS = 250;
37
+
27
38
  /**
28
39
  * Extension-only pseudo-CDP methods (Vellum.listTabs, Vellum.selectTab,
29
40
  * Vellum.closeTab, Vellum.createTab, Vellum.findTab, Vellum.attach,
@@ -196,6 +207,36 @@ export class HostBrowserProxy {
196
207
  );
197
208
  }
198
209
 
210
+ /**
211
+ * Poll until the extension client that dispatch will route to is
212
+ * connected, or `timeoutMs` elapses. Absorbs brief SSE reconnect blips
213
+ * so extension-pinned dispatch doesn't hard-fail on a momentary gap.
214
+ *
215
+ * When `targetClientId` is supplied, waits for that *exact* client —
216
+ * `request()` resolves the target by id, so waiting for any sibling
217
+ * extension (multi-install setups) would return early and still fail.
218
+ * Otherwise waits for any extension owned by the actor, matching the
219
+ * auto-resolution preference. Returns the final availability; callers
220
+ * proceed to dispatch regardless (which still surfaces the typed "no
221
+ * Chrome Extension connected" error if absent).
222
+ */
223
+ async waitForExtensionClient(
224
+ sourceActorPrincipalId?: string,
225
+ targetClientId?: string,
226
+ timeoutMs = EXTENSION_RECONNECT_GRACE_MS,
227
+ ): Promise<boolean> {
228
+ const connected = () =>
229
+ targetClientId != null
230
+ ? assistantEventHub.getClientById(targetClientId) !== undefined
231
+ : this.hasExtensionClient(sourceActorPrincipalId);
232
+ const deadline = Date.now() + timeoutMs;
233
+ for (;;) {
234
+ if (connected()) return true;
235
+ if (Date.now() >= deadline) return false;
236
+ await sleep(EXTENSION_RECONNECT_POLL_MS);
237
+ }
238
+ }
239
+
199
240
  /**
200
241
  * Send a host_browser request to the connected extension/macOS bridge.
201
242
  *
@@ -20,6 +20,7 @@ import {
20
20
  import { loadConfig, mergeDefaultWorkspaceConfig } from "../config/loader.js";
21
21
  import type { AssistantConfig } from "../config/schema.js";
22
22
  import { seedInferenceProfiles } from "../config/seed-inference-profiles.js";
23
+ import { reconcileFlagGatedProfiles } from "../config/sync-gated-profiles.js";
23
24
  import type { CesClient } from "../credential-execution/client.js";
24
25
  import { createCesClient } from "../credential-execution/client.js";
25
26
  import { refreshManagedConnectionCache } from "../credential-execution/managed-catalog.js";
@@ -60,6 +61,10 @@ import { sweepConceptPageFrontmatter } from "../memory/v2/frontmatter-sweep.js";
60
61
  import { emitNotificationSignal } from "../notifications/emit-signal.js";
61
62
  import { backfillManualTokenConnections } from "../oauth/manual-token-connection.js";
62
63
  import { seedOAuthProviders } from "../oauth/seed-providers.js";
64
+ import {
65
+ startConsentRefresh,
66
+ stopConsentRefresh,
67
+ } from "../platform/consent-cache.js";
63
68
  import { ensurePromptFiles } from "../prompts/system-prompt.js";
64
69
  import { runProviderConnectionsBackfill } from "../providers/inference/backfill.js";
65
70
  import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js";
@@ -71,7 +76,10 @@ import {
71
76
  import { RuntimeHttpServer } from "../runtime/http-server.js";
72
77
  import { recoverInterruptedImport } from "../runtime/migrations/vbundle-streaming-importer.js";
73
78
  import { registerSecretsDeps } from "../runtime/routes/secrets-deps.js";
74
- import { publishConversationListChanged } from "../runtime/sync/resource-sync-events.js";
79
+ import {
80
+ publishConfigChanged,
81
+ publishConversationListChanged,
82
+ } from "../runtime/sync/resource-sync-events.js";
75
83
  import { recoverStaleSchedules } from "../schedule/schedule-recovery.js";
76
84
  import { startScheduler } from "../schedule/scheduler.js";
77
85
  import {
@@ -130,6 +138,7 @@ import {
130
138
  } from "./providers-setup.js";
131
139
  import { DaemonServer } from "./server.js";
132
140
  import { installShutdownHandlers } from "./shutdown-handlers.js";
141
+ import { registerShutdownHook } from "./shutdown-registry.js";
133
142
  import { refreshSkillCapabilityMemories } from "./skill-memory-refresh.js";
134
143
 
135
144
  const log = getLogger("lifecycle");
@@ -284,9 +293,10 @@ export async function runDaemon(): Promise<void> {
284
293
  log.info({ version: APP_VERSION }, "Daemon starting");
285
294
 
286
295
  try {
287
- // Initialize crash reporting eagerly so early startup failures are
288
- // captured. After config loads we check the opt-out flag and call
289
- // closeSentry() if the user has disabled it.
296
+ // Initialize crash reporting eagerly so the Sentry client is ready before
297
+ // early startup failures occur. Events are dropped (beforeSend) until the
298
+ // consent gate below confirms share_diagnostics opt-in; dev mode and the
299
+ // legacy local opt-out hard-disable via closeSentry().
290
300
  initSentry();
291
301
 
292
302
  ensureDataDir();
@@ -365,8 +375,23 @@ export async function runDaemon(): Promise<void> {
365
375
  // this fetch completes, so without this follow-up sync a flag-enabled
366
376
  // assistant would not expose the gated tools until a restart (which can lose
367
377
  // the same race). Enable-direction only; chained so it sees the fresh cache.
378
+ // Then reconcile flag-gated managed profiles (OS Beta): `seedInferenceProfiles()`
379
+ // runs synchronously earlier in boot before flags are available, so this lands
380
+ // the profile on the same boot once the flag cache is populated. When this
381
+ // reconcile is the call that mutates config (it raced ahead of the gateway
382
+ // flag listener), publish the config invalidation so any client that already
383
+ // fetched `GET /v1/config` refreshes its profile picker.
384
+ // Profiles are reconciled only when flags actually loaded from the gateway:
385
+ // a failed fetch leaves the cache unset and resolves `os-beta` to its
386
+ // registry default `false`, which would remove the user's profile and reset
387
+ // their selection. Tool sync tolerates the default and stays unconditional.
368
388
  void initFeatureFlagOverrides()
369
- .then(() => syncFlagGatedTools())
389
+ .then(async (loaded) => {
390
+ await syncFlagGatedTools();
391
+ if (loaded && reconcileFlagGatedProfiles()) {
392
+ publishConfigChanged();
393
+ }
394
+ })
370
395
  .catch((err) => log.warn({ err }, "Background feature flag init failed"));
371
396
 
372
397
  startGatewayFlagListener();
@@ -636,22 +661,27 @@ export async function runDaemon(): Promise<void> {
636
661
  });
637
662
  }
638
663
 
639
- // Privacy gating: Sentry crash/error reporting is gated by sendDiagnostics,
640
- // while the usage telemetry reporter re-checks collectUsageData on every
641
- // flush. Both are disabled in dev mode. Early-startup crashes before this
642
- // point are still captured.
664
+ // Privacy gating: Sentry crash/error reporting follows the platform owner's
665
+ // share_diagnostics consent; the usage telemetry reporter re-checks
666
+ // share_analytics on every flush. Both are disabled in dev mode. Sentry was
667
+ // initialized early, but beforeSend re-reads getCachedShareDiagnostics() on
668
+ // every event, so it drops events until consent confirms opt-in and honors a
669
+ // later revocation within one refresh cycle (the cache is refreshed by
670
+ // startConsentRefresh() below, mirroring the share_analytics posture).
643
671
  const isDevMode = process.env.VELLUM_DEV === "1";
644
- const sendDiagnostics = !isDevMode && config.sendDiagnostics;
645
- if (!sendDiagnostics) {
672
+ if (isDevMode || config.legacyDiagnosticsOptOut === true) {
673
+ // Dev mode and a preserved legacy local opt-out both disable Sentry
674
+ // unconditionally, without waiting on platform consent.
646
675
  await closeSentry();
647
676
  }
648
677
 
649
678
  // Construct and start the reporter even when usage collection is disabled:
650
- // flush() re-checks collectUsageData each cycle and, when opted out, sends
651
- // nothing but advances all watermarks (including the final flush in
652
- // stop()). New opted-out tool_invocations rows are already unreportable by
653
- // construction — the audit listener persists NULL telemetry columns for
654
- // them, which the tool_executed projection filters out — so the opted-out
679
+ // flush() re-checks the platform share_analytics consent each cycle and,
680
+ // when opted out, sends nothing but advances all watermarks (including the
681
+ // final flush in stop()). New opted-out tool_invocations rows are already
682
+ // unreportable by construction — the audit listener persists NULL telemetry
683
+ // columns for them, which the tool_executed projection filters out — so the
684
+ // opted-out
655
685
  // flushes are defense in depth there (covering rows recorded under builds
656
686
  // that predate that write-time gate) and remain the primary guard for the
657
687
  // always-on tables without a write-time gate (llm_usage, turn events).
@@ -665,12 +695,17 @@ export async function runDaemon(): Promise<void> {
665
695
  telemetryReporter = new UsageTelemetryReporter();
666
696
  setUsageTelemetryReporter(telemetryReporter);
667
697
  telemetryReporter.start();
668
- log.info(
669
- { collectUsageData: config.collectUsageData },
670
- "Usage telemetry reporter started",
671
- );
698
+ log.info("Usage telemetry reporter started");
672
699
  }
673
700
 
701
+ // Refresh the consent cache regardless of dev mode so record-time telemetry
702
+ // writes (gated on getCachedShareAnalytics()) work in dev too. The reporter
703
+ // flush stays dev-gated above, so dev still never sends telemetry to the
704
+ // platform. Fire-and-forget: startConsentRefresh() runs an immediate
705
+ // non-blocking refresh, so the startup hot path is never blocked.
706
+ startConsentRefresh();
707
+ registerShutdownHook("consent-cache", () => stopConsentRefresh());
708
+
674
709
  // CES lifecycle — kick off early so CES handshake runs concurrently with
675
710
  // provider/tool initialization. The CES sidecar accepts exactly one
676
711
  // bootstrap connection, so startup must happen at the process level.
@@ -1281,13 +1316,6 @@ export async function runDaemon(): Promise<void> {
1281
1316
  log.warn({ err }, "Assistant symlink installation failed — continuing");
1282
1317
  }
1283
1318
 
1284
- // Seed preloaded apps (personal landing page) in background (non-blocking).
1285
- void import("../memory/preloaded-apps.js")
1286
- .then(({ seedPreloadedApps }) => seedPreloadedApps(config))
1287
- .catch((err) =>
1288
- log.warn({ err }, "Preloaded app seeding failed — continuing"),
1289
- );
1290
-
1291
1319
  // Download embedding runtime in background (non-blocking).
1292
1320
  // If download fails, local embeddings gracefully fall back to cloud backends.
1293
1321
  void (async () => {
@@ -26,6 +26,7 @@ export function parseProvenanceTrustClass(
26
26
  if (
27
27
  trustClass === "guardian" ||
28
28
  trustClass === "trusted_contact" ||
29
+ trustClass === "unverified_contact" ||
29
30
  trustClass === "unknown"
30
31
  ) {
31
32
  return trustClass;
@@ -43,6 +44,7 @@ export function filterMessagesForUntrustedActor(
43
44
  const provenanceTrustClass = parseProvenanceTrustClass(m.metadata);
44
45
  return (
45
46
  provenanceTrustClass === "trusted_contact" ||
47
+ provenanceTrustClass === "unverified_contact" ||
46
48
  provenanceTrustClass === "unknown"
47
49
  );
48
50
  });
@@ -54,7 +54,6 @@ export interface ContactChannelPayload {
54
54
  type: string;
55
55
  address: string;
56
56
  isPrimary: boolean;
57
- externalUserId?: string;
58
57
  status: string;
59
58
  policy: string;
60
59
  verifiedAt?: number;
@@ -462,9 +462,9 @@ export interface ContextCompacted {
462
462
  * - `summaryCharCount`: length of the produced summary text.
463
463
  * - `summaryHeaderCount`: number of `## ` section headers in the summary.
464
464
  * - `summaryHadMemoryEcho`: `true` if the summary contains any runtime
465
- * injection tag (e.g. `<memory`, `<turn_context>`, `<workspace>`).
466
- * Should always be `false` `true` indicates the compaction strip
467
- * logic failed to remove an injected block from the summarizer input.
465
+ * injection tag (e.g. `<memory`, `<turn_context>`, `<workspace>`). The
466
+ * durable summary should be clean prose, so `true` flags an echoed or
467
+ * invented tag worth investigating.
468
468
  */
469
469
  summaryCharCount?: number;
470
470
  summaryHeaderCount?: number;
@@ -10,7 +10,6 @@ export { type SyncChangedEvent, SyncChangedEventSchema };
10
10
  export const SYNC_TAGS = {
11
11
  assistantAvatar: "assistant:self:avatar",
12
12
  assistantIdentity: "assistant:self:identity",
13
- assistantIdentityIntro: "assistant:self:identity-intro",
14
13
  assistantConfig: "assistant:self:config",
15
14
  assistantSounds: "assistant:self:sounds",
16
15
  assistantSchedules: "assistant:self:schedules",
@@ -9,7 +9,11 @@ export type WebSearchProviderId =
9
9
  | "anthropic-native"
10
10
  | "brave"
11
11
  | "perplexity"
12
- | "tavily";
12
+ | "tavily"
13
+ | "firecrawl";
14
+
15
+ /** Provider that backed a `web_fetch` call. `default` is the built-in fetcher. */
16
+ export type WebFetchProviderId = "default" | "firecrawl";
13
17
 
14
18
  export interface WebSearchResultItem {
15
19
  rank: number; // 1-indexed
@@ -35,6 +39,8 @@ export interface WebSearchMetadata {
35
39
  export interface WebFetchMetadata {
36
40
  url: string;
37
41
  finalUrl: string;
42
+ /** Provider that served the fetch. Defaults to the built-in fetcher. */
43
+ provider?: WebFetchProviderId;
38
44
  status: number;
39
45
  contentType?: string;
40
46
  byteCount: number;
@@ -18,6 +18,13 @@ import type { WorkflowRunStatus } from "../../workflows/journal-store.js";
18
18
  export interface WorkflowProgress {
19
19
  type: "workflow_progress";
20
20
  runId: string;
21
+ /**
22
+ * Originating conversation id, when launched from one; lets `broadcastMessage`
23
+ * auto-scope + seq-stamp the event to that conversation's SSE stream. Omitted
24
+ * for a conversationless run (e.g. a scheduled workflow), which broadcasts
25
+ * unscoped for raw SSE listeners and the DB record.
26
+ */
27
+ conversationId?: string;
21
28
  /** Latest phase title, when this emission came from a `phase(...)` call. */
22
29
  phase?: string;
23
30
  /** Run label (the workflow's `meta.name`), for client display. */
@@ -36,6 +43,13 @@ export interface WorkflowProgress {
36
43
  export interface WorkflowCompleted {
37
44
  type: "workflow_completed";
38
45
  runId: string;
46
+ /**
47
+ * Originating conversation id, when launched from one; lets `broadcastMessage`
48
+ * auto-scope + seq-stamp the event to that conversation's SSE stream. Omitted
49
+ * for a conversationless run (e.g. a scheduled workflow), which broadcasts
50
+ * unscoped for raw SSE listeners and the DB record.
51
+ */
52
+ conversationId?: string;
39
53
  status: WorkflowRunStatus;
40
54
  agentsSpawned: number;
41
55
  inputTokens: number;
@@ -44,6 +58,74 @@ export interface WorkflowCompleted {
44
58
  summary?: string;
45
59
  }
46
60
 
61
+ /**
62
+ * A workflow run has started. Emitted once at launch, before any leaf events.
63
+ */
64
+ export interface WorkflowStarted {
65
+ type: "workflow_started";
66
+ runId: string;
67
+ /**
68
+ * Originating conversation id; lets `broadcastMessage` auto-scope +
69
+ * seq-stamp the event to the conversation's SSE stream.
70
+ */
71
+ conversationId: string;
72
+ /**
73
+ * Tool-use id of the `skill_execute` block that launched this run, for
74
+ * anchoring the inline workflow card to the exact spawn tool call.
75
+ */
76
+ toolUseId?: string;
77
+ /** Run label (the workflow's `meta.name`), for client display. */
78
+ label?: string;
79
+ }
80
+
81
+ /**
82
+ * A leaf agent within a workflow run has started. `seq` orders leaves within
83
+ * the run for stable client-side tree placement.
84
+ */
85
+ export interface WorkflowLeafStarted {
86
+ type: "workflow_leaf_started";
87
+ runId: string;
88
+ /**
89
+ * Originating conversation id; lets `broadcastMessage` auto-scope +
90
+ * seq-stamp the event to the conversation's SSE stream.
91
+ */
92
+ conversationId: string;
93
+ seq: number;
94
+ /** Leaf label, for client display. */
95
+ label?: string;
96
+ /** Phase the leaf belongs to, when the workflow declares phases. */
97
+ phase?: string;
98
+ /** Short summary of the leaf's prompt, for client display. */
99
+ promptSummary?: string;
100
+ }
101
+
102
+ /**
103
+ * A leaf agent within a workflow run has finished. `seq` matches the
104
+ * corresponding `workflow_leaf_started` event.
105
+ */
106
+ export interface WorkflowLeafFinished {
107
+ type: "workflow_leaf_finished";
108
+ runId: string;
109
+ /**
110
+ * Originating conversation id; lets `broadcastMessage` auto-scope +
111
+ * seq-stamp the event to the conversation's SSE stream.
112
+ */
113
+ conversationId: string;
114
+ seq: number;
115
+ status: "completed" | "failed";
116
+ /** Leaf label, for client display. */
117
+ label?: string;
118
+ inputTokens?: number;
119
+ outputTokens?: number;
120
+ /** Short summary of the leaf's result, for client display. */
121
+ resultSummary?: string;
122
+ }
123
+
47
124
  // --- Domain-level union aliases (consumed by the barrel file) ---
48
125
 
49
- export type _WorkflowsServerMessages = WorkflowProgress | WorkflowCompleted;
126
+ export type _WorkflowsServerMessages =
127
+ | WorkflowProgress
128
+ | WorkflowCompleted
129
+ | WorkflowStarted
130
+ | WorkflowLeafStarted
131
+ | WorkflowLeafFinished;
@@ -21,7 +21,6 @@ mock.module("../util/logger.js", () => ({
21
21
  }));
22
22
 
23
23
  const { parseProcStat, selectReapable } = await import("./orphan-reaper.js");
24
- const { DaemonConfigSchema } = await import("../config/schemas/platform.js");
25
24
 
26
25
  describe("parseProcStat", () => {
27
26
  test("parses a normal stat line", () => {
@@ -89,24 +88,6 @@ describe("selectReapable", () => {
89
88
  });
90
89
  });
91
90
 
92
- describe("daemon.reapOrphanedSubprocesses gate", () => {
93
- test("defaults to off so the reaper is opt-in", () => {
94
- // GIVEN a daemon config with the reaper flag unspecified
95
- // WHEN it is parsed with schema defaults
96
- const parsed = DaemonConfigSchema.parse({});
97
- // THEN the reaper is disabled unless explicitly turned on
98
- expect(parsed.reapOrphanedSubprocesses).toBe(false);
99
- });
100
-
101
- test("honors an explicit opt-in", () => {
102
- // GIVEN a daemon config that explicitly enables the reaper
103
- // WHEN it is parsed
104
- const parsed = DaemonConfigSchema.parse({ reapOrphanedSubprocesses: true });
105
- // THEN the flag is respected
106
- expect(parsed.reapOrphanedSubprocesses).toBe(true);
107
- });
108
- });
109
-
110
91
  // ── Integration: real reparented orphan on Linux ────────────────────────────
111
92
  const itLinux = process.platform === "linux" ? test : test.skip;
112
93
 
@@ -26,9 +26,7 @@
26
26
  * macOS dev, or if an init such as tini is ever placed above the daemon),
27
27
  * orphans reparent to that init and are reaped there, so there is nothing for
28
28
  * this to do. Because the daemon is PID 1, orphans already reparent to it and
29
- * `PR_SET_CHILD_SUBREAPER` is unnecessary. It is additionally gated behind the
30
- * `daemon.reapOrphanedSubprocesses` config flag (default off) so the behavior
31
- * can be enabled per workspace for validation before becoming the default.
29
+ * `PR_SET_CHILD_SUBREAPER` is unnecessary.
32
30
  *
33
31
  * References:
34
32
  * - libuv reaps its own children by pid on SIGCHLD (`uv__wait_children`):
@@ -42,7 +40,6 @@
42
40
  import { readdirSync, readFileSync } from "node:fs";
43
41
  import { dlopen, FFIType, ptr } from "bun:ffi";
44
42
 
45
- import { getConfigReadOnly } from "../config/loader.js";
46
43
  import { getLogger } from "../util/logger.js";
47
44
 
48
45
  const log = getLogger("orphan-reaper");
@@ -192,22 +189,9 @@ function reapScan(): void {
192
189
  }
193
190
  }
194
191
 
195
- /**
196
- * Read the opt-in gate from workspace config (`daemon.reapOrphanedSubprocesses`),
197
- * tolerating a missing or malformed config so startup never fails on it.
198
- */
199
- function isReaperEnabled(): boolean {
200
- try {
201
- return getConfigReadOnly().daemon.reapOrphanedSubprocesses;
202
- } catch {
203
- return false;
204
- }
205
- }
206
-
207
192
  /**
208
193
  * Start the periodic orphan reaper. No-op unless the daemon is PID 1 on Linux
209
- * (otherwise reparented orphans are reaped by the real init) and the
210
- * `daemon.reapOrphanedSubprocesses` config gate is enabled.
194
+ * (otherwise reparented orphans are reaped by the real init).
211
195
  */
212
196
  export function startOrphanReaper(): void {
213
197
  if (scanTimer) return;
@@ -218,12 +202,6 @@ export function startOrphanReaper(): void {
218
202
  );
219
203
  return;
220
204
  }
221
- if (!isReaperEnabled()) {
222
- log.info(
223
- "Orphan reaper not started: daemon.reapOrphanedSubprocesses is disabled",
224
- );
225
- return;
226
- }
227
205
  if (!initWaitpid()) return;
228
206
  seenLastScan = new Set();
229
207
  scanTimer = setInterval(reapScan, SCAN_INTERVAL_MS);
@@ -19,7 +19,6 @@ import {
19
19
  publishAvatarChanged,
20
20
  publishConfigChanged,
21
21
  publishIdentityChanged,
22
- publishIdentityIntroChanged,
23
22
  publishSoundsConfigUpdated,
24
23
  } from "../runtime/sync/resource-sync-events.js";
25
24
  import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
@@ -193,14 +192,6 @@ export class DaemonServer {
193
192
  }
194
193
  }
195
194
 
196
- private broadcastIdentityIntroChanged(): void {
197
- try {
198
- publishIdentityIntroChanged();
199
- } catch (err) {
200
- log.error({ err }, "Failed to broadcast identity intro change");
201
- }
202
- }
203
-
204
195
  /** Best-effort sync of the IDENTITY.md name to the platform record. */
205
196
  private syncIdentityToPlatform(): void {
206
197
  try {
@@ -313,7 +304,6 @@ export class DaemonServer {
313
304
  () => this.broadcastAvatarUpdated(),
314
305
  () => this.broadcastConfigChanged(),
315
306
  () => refreshSkillCapabilityMemories(getConfig()),
316
- () => this.broadcastIdentityIntroChanged(),
317
307
  );
318
308
 
319
309
  this.syncIdentityToPlatform();
@@ -88,6 +88,10 @@ export interface ToolSetupContext extends SurfaceConversationContext {
88
88
  taskRunId?: string;
89
89
  /** Guardian runtime context for the conversation — trustClass is propagated into ToolContext for control-plane policy enforcement. */
90
90
  trustContext?: TrustContext;
91
+ /** Per-turn trust snapshot, captured at turn start. Preferred over the live
92
+ * `trustContext` for mid-turn trust decisions (tool approval, control-plane
93
+ * policy) so a concurrent mutation cannot elevate the in-flight turn. */
94
+ currentTurnTrustContext?: TrustContext;
91
95
  /** Voice/call session ID, if the conversation originates from a call. Propagated into ToolContext for scoped grant consumption. */
92
96
  callSessionId?: string;
93
97
  /** The interface ID of the connected client driving the current turn (e.g. "macos", "chrome-extension"). Propagated into ToolContext for browser backend selection. */