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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) hide show
  1. package/bun.lock +0 -20
  2. package/docs/workspace-tools.md +33 -42
  3. package/eslint-rules/cli-no-daemon-internals.js +0 -6
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
  5. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
  6. package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
  7. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
  8. package/node_modules/@vellumai/service-contracts/package.json +0 -1
  9. package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
  10. package/openapi.yaml +0 -155
  11. package/package.json +1 -4
  12. package/scripts/test.sh +15 -36
  13. package/src/__tests__/actor-token-service.test.ts +14 -36
  14. package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
  15. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
  16. package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
  17. package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
  18. package/src/__tests__/annotate-risk-options.test.ts +0 -2
  19. package/src/__tests__/approval-cascade.test.ts +0 -2
  20. package/src/__tests__/assistant-attachments.test.ts +0 -42
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  22. package/src/__tests__/btw-routes.test.ts +0 -2
  23. package/src/__tests__/build-persisted-content.test.ts +0 -2
  24. package/src/__tests__/call-controller.test.ts +0 -19
  25. package/src/__tests__/channel-guardian.test.ts +58 -94
  26. package/src/__tests__/channel-reply-delivery.test.ts +0 -2
  27. package/src/__tests__/compaction-events.test.ts +0 -2
  28. package/src/__tests__/compaction.benchmark.test.ts +0 -2
  29. package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
  30. package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
  31. package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
  32. package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
  33. package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
  34. package/src/__tests__/config-loader-backfill.test.ts +10 -123
  35. package/src/__tests__/config-schema.test.ts +0 -1
  36. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
  37. package/src/__tests__/contacts-relay-reads.test.ts +15 -13
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
  39. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  42. package/src/__tests__/conversation-agent-loop.test.ts +0 -134
  43. package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
  44. package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
  45. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
  46. package/src/__tests__/conversation-history-web-search.test.ts +0 -2
  47. package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
  48. package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
  49. package/src/__tests__/conversation-pairing.test.ts +0 -2
  50. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +0 -2
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
  53. package/src/__tests__/conversation-queue.test.ts +0 -91
  54. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
  56. package/src/__tests__/conversation-slash-queue.test.ts +0 -2
  57. package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
  58. package/src/__tests__/conversation-speed-override.test.ts +0 -2
  59. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
  60. package/src/__tests__/conversation-title-service.test.ts +0 -2
  61. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
  62. package/src/__tests__/conversation-usage.test.ts +0 -2
  63. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
  64. package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
  65. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
  66. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  67. package/src/__tests__/db-migration-rollback.test.ts +171 -205
  68. package/src/__tests__/db-test-helpers.ts +4 -5
  69. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
  70. package/src/__tests__/disk-pressure-guard.test.ts +0 -41
  71. package/src/__tests__/dm-persistence.test.ts +0 -2
  72. package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
  73. package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
  74. package/src/__tests__/exploration-drift-hook.test.ts +2 -3
  75. package/src/__tests__/filing-service.test.ts +0 -2
  76. package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
  77. package/src/__tests__/guardian-dispatch.test.ts +1 -95
  78. package/src/__tests__/guardian-outbound-http.test.ts +0 -13
  79. package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
  80. package/src/__tests__/heartbeat-service.test.ts +0 -2
  81. package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
  82. package/src/__tests__/host-app-control-routes.test.ts +30 -24
  83. package/src/__tests__/host-bash-routes.test.ts +41 -31
  84. package/src/__tests__/host-browser-routes.test.ts +32 -26
  85. package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
  86. package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
  87. package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
  88. package/src/__tests__/http-user-message-parity.test.ts +8 -290
  89. package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
  90. package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
  91. package/src/__tests__/invite-redemption-service.test.ts +0 -198
  92. package/src/__tests__/llm-context-normalization.test.ts +0 -105
  93. package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
  94. package/src/__tests__/llm-usage-store.test.ts +0 -25
  95. package/src/__tests__/mcp-health-check.test.ts +1 -2
  96. package/src/__tests__/media-stream-server-integration.test.ts +0 -127
  97. package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
  98. package/src/__tests__/messaging-send-tool.test.ts +0 -2
  99. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  100. package/src/__tests__/mtime-cache.test.ts +5 -146
  101. package/src/__tests__/native-web-search.test.ts +0 -2
  102. package/src/__tests__/non-member-access-request.test.ts +17 -189
  103. package/src/__tests__/notification-broadcaster.test.ts +0 -4
  104. package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
  105. package/src/__tests__/notification-deep-link.test.ts +0 -6
  106. package/src/__tests__/notification-guardian-path.test.ts +0 -19
  107. package/src/__tests__/openai-provider.test.ts +12 -22
  108. package/src/__tests__/openai-responses-provider.test.ts +2 -12
  109. package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
  110. package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
  111. package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
  112. package/src/__tests__/plugin-bootstrap.test.ts +73 -3
  113. package/src/__tests__/plugin-route-contribution.test.ts +17 -4
  114. package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
  115. package/src/__tests__/plugin-types.test.ts +2 -0
  116. package/src/__tests__/process-message-background-slack.test.ts +0 -2
  117. package/src/__tests__/process-message-display-content.test.ts +0 -2
  118. package/src/__tests__/provider-error-scenarios.test.ts +4 -5
  119. package/src/__tests__/provider-usage-tracking.test.ts +0 -39
  120. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
  121. package/src/__tests__/registry.test.ts +1 -4
  122. package/src/__tests__/relay-server.test.ts +25 -694
  123. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
  124. package/src/__tests__/secret-ingress-http.test.ts +0 -14
  125. package/src/__tests__/send-endpoint-busy.test.ts +8 -30
  126. package/src/__tests__/skills.test.ts +0 -44
  127. package/src/__tests__/slack-inbound-verification.test.ts +2 -47
  128. package/src/__tests__/stt-hints.test.ts +13 -44
  129. package/src/__tests__/subagent-detail.test.ts +0 -27
  130. package/src/__tests__/subagent-disposal.test.ts +0 -65
  131. package/src/__tests__/subagent-notify-parent.test.ts +0 -2
  132. package/src/__tests__/subagent-role-registry.test.ts +2 -7
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
  134. package/src/__tests__/subagent-tools.test.ts +0 -2
  135. package/src/__tests__/suggestion-routes.test.ts +0 -2
  136. package/src/__tests__/title-generate-hook.test.ts +0 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
  138. package/src/__tests__/tool-executor.test.ts +11 -16
  139. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
  140. package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
  141. package/src/__tests__/tool-start-timestamp.test.ts +0 -2
  142. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
  143. package/src/__tests__/twilio-routes.test.ts +0 -96
  144. package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
  145. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  146. package/src/__tests__/voice-invite-redemption.test.ts +0 -33
  147. package/src/__tests__/web-search-backend-failure.test.ts +0 -2
  148. package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
  149. package/src/__tests__/workspace-tool-loader.test.ts +2 -195
  150. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  151. package/src/agent/loop.ts +0 -56
  152. package/src/api/index.ts +1 -19
  153. package/src/api/responses/llm-request-log-entry.ts +0 -29
  154. package/src/api/responses/subagent-detail.ts +0 -17
  155. package/src/api/surfaces.ts +3 -39
  156. package/src/approvals/guardian-request-resolvers.ts +11 -1
  157. package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
  158. package/src/calls/call-domain.ts +3 -3
  159. package/src/calls/guardian-dispatch.ts +8 -10
  160. package/src/calls/inbound-trust-reader.ts +1 -17
  161. package/src/calls/media-stream-server.ts +0 -21
  162. package/src/calls/relay-server.ts +50 -167
  163. package/src/calls/relay-setup-router.ts +7 -37
  164. package/src/calls/relay-verification.ts +4 -4
  165. package/src/calls/stt-hints.ts +12 -9
  166. package/src/calls/twilio-routes.ts +4 -14
  167. package/src/channels/types.ts +20 -10
  168. package/src/cli/commands/__tests__/cache.test.ts +1 -8
  169. package/src/cli/commands/cache.ts +181 -194
  170. package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
  171. package/src/cli/commands/db/status.ts +1 -37
  172. package/src/cli/commands/mcp.ts +218 -252
  173. package/src/cli/commands/memory/index.ts +0 -2
  174. package/src/cli/commands/plugins.ts +3 -75
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
  177. package/src/cli/lib/list-installed-plugins.ts +1 -179
  178. package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
  179. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
  180. package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
  181. package/src/config/bundled-skills/subagent/SKILL.md +1 -1
  182. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  183. package/src/config/feature-flag-registry.json +13 -5
  184. package/src/config/loader.ts +5 -38
  185. package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
  186. package/src/config/schemas/memory-lifecycle.ts +0 -12
  187. package/src/config/schemas/memory-v3.ts +0 -7
  188. package/src/config/schemas/memory.ts +0 -4
  189. package/src/config/schemas/timeouts.ts +0 -8
  190. package/src/config/seed-inference-profiles.ts +11 -21
  191. package/src/config/skills.ts +5 -27
  192. package/src/config/sync-gated-profiles.ts +13 -12
  193. package/src/contacts/contacts-write.ts +0 -3
  194. package/src/daemon/assistant-attachments.ts +4 -27
  195. package/src/daemon/conversation-agent-loop.ts +0 -28
  196. package/src/daemon/conversation-process.ts +16 -35
  197. package/src/daemon/conversation-surfaces.ts +38 -111
  198. package/src/daemon/conversation-tool-setup.ts +16 -50
  199. package/src/daemon/conversation.ts +1 -13
  200. package/src/daemon/disk-pressure-guard.ts +2 -12
  201. package/src/daemon/event-loop-watchdog.ts +1 -28
  202. package/src/daemon/external-plugins-bootstrap.ts +34 -4
  203. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
  204. package/src/daemon/handlers/config-a2a.ts +14 -6
  205. package/src/daemon/handlers/config-channels.ts +22 -78
  206. package/src/daemon/handlers/conversations.ts +0 -77
  207. package/src/daemon/lifecycle.ts +0 -4
  208. package/src/daemon/mcp-reload-service.ts +0 -10
  209. package/src/daemon/memory-v2-startup.test.ts +0 -72
  210. package/src/daemon/memory-v2-startup.ts +19 -87
  211. package/src/daemon/message-types/conversations.ts +0 -2
  212. package/src/daemon/message-types/surfaces.ts +12 -12
  213. package/src/daemon/server.ts +4 -0
  214. package/src/daemon/shutdown-handlers.ts +0 -20
  215. package/src/daemon/tool-setup-types.ts +0 -9
  216. package/src/daemon/workspace-tools-watcher.ts +328 -0
  217. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  218. package/src/ipc/assistant-server.ts +2 -2
  219. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  220. package/src/mcp/client.ts +1 -15
  221. package/src/mcp/mcp-auth-orchestrator.ts +1 -6
  222. package/src/mcp/mcp-oauth-provider.ts +8 -19
  223. package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
  224. package/src/memory/conversation-crud.ts +0 -38
  225. package/src/memory/db-connection.ts +3 -22
  226. package/src/memory/db-init.ts +502 -36
  227. package/src/memory/db-singleton.ts +4 -6
  228. package/src/memory/jobs-worker.ts +0 -58
  229. package/src/memory/llm-request-log-store.ts +1 -26
  230. package/src/memory/llm-usage-store.ts +20 -48
  231. package/src/memory/memory-retrospective-job.ts +8 -9
  232. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
  233. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  234. package/src/memory/migrations/registry.ts +573 -0
  235. package/src/memory/migrations/run-migrations.ts +6 -90
  236. package/src/memory/migrations/validate-migration-state.ts +66 -101
  237. package/src/memory/schema/conversations.ts +0 -9
  238. package/src/memory/schema/infrastructure.ts +0 -20
  239. package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
  240. package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
  241. package/src/memory/v2/cli-command-store.ts +38 -75
  242. package/src/memory/v2/prompts/consolidation.ts +82 -13
  243. package/src/memory/v2/prompts/router.ts +93 -21
  244. package/src/memory/v2/skill-store.ts +31 -68
  245. package/src/notifications/__tests__/broadcaster.test.ts +8 -16
  246. package/src/notifications/__tests__/decision-engine.test.ts +9 -78
  247. package/src/notifications/broadcaster.ts +1 -8
  248. package/src/notifications/decision-engine.ts +7 -15
  249. package/src/notifications/destination-resolver.ts +24 -68
  250. package/src/notifications/emit-signal.ts +14 -39
  251. package/src/permissions/question-prompter.test.ts +1 -1
  252. package/src/permissions/question-prompter.ts +4 -7
  253. package/src/plugin-api/index.ts +6 -6
  254. package/src/plugin-api/types.ts +5 -3
  255. package/src/plugin-api/vision-support.test.ts +4 -28
  256. package/src/plugin-api/vision-support.ts +31 -66
  257. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
  258. package/src/plugins/defaults/advisor/consult.ts +6 -110
  259. package/src/plugins/defaults/advisor/steering.ts +2 -14
  260. package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
  261. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
  262. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
  263. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
  264. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
  265. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
  266. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
  267. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
  268. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
  269. package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
  270. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
  271. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
  272. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
  273. package/src/plugins/mtime-cache.ts +291 -76
  274. package/src/plugins/pipeline.ts +13 -111
  275. package/src/plugins/types.ts +2 -0
  276. package/src/providers/anthropic/client.ts +0 -5
  277. package/src/providers/call-site-routing.ts +0 -4
  278. package/src/providers/model-catalog.ts +0 -16
  279. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  280. package/src/providers/openai/chat-completions-provider.ts +83 -37
  281. package/src/providers/openai/responses-provider.ts +46 -50
  282. package/src/providers/openrouter/client.ts +0 -5
  283. package/src/providers/provider-send-message.ts +0 -4
  284. package/src/providers/ratelimit.ts +0 -4
  285. package/src/providers/retry.ts +0 -4
  286. package/src/providers/types.ts +0 -9
  287. package/src/providers/usage-tracking.ts +0 -4
  288. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
  289. package/src/runtime/access-request-helper.ts +39 -19
  290. package/src/runtime/actor-trust-resolver.ts +2 -2
  291. package/src/runtime/assistant-event-hub.ts +1 -1
  292. package/src/runtime/assistant-stream-state.ts +2 -9
  293. package/src/runtime/auth/require-bound-guardian.ts +11 -21
  294. package/src/runtime/channel-verification-service.ts +31 -56
  295. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  296. package/src/runtime/guardian-vellum-migration.ts +7 -66
  297. package/src/runtime/invite-redemption-service.ts +187 -198
  298. package/src/runtime/local-actor-identity.ts +11 -76
  299. package/src/runtime/pending-interactions.ts +1 -11
  300. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
  301. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  302. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
  303. package/src/runtime/routes/browser-routes.ts +1 -1
  304. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
  305. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  306. package/src/runtime/routes/contact-routes.ts +32 -8
  307. package/src/runtime/routes/conversation-cli-routes.ts +5 -4
  308. package/src/runtime/routes/conversation-list-routes.ts +7 -4
  309. package/src/runtime/routes/conversation-query-routes.ts +0 -72
  310. package/src/runtime/routes/conversation-routes.ts +85 -84
  311. package/src/runtime/routes/events-routes.ts +2 -2
  312. package/src/runtime/routes/global-search-routes.ts +1 -3
  313. package/src/runtime/routes/guardian-action-routes.ts +5 -4
  314. package/src/runtime/routes/host-app-control-routes.ts +4 -5
  315. package/src/runtime/routes/host-bash-routes.ts +4 -5
  316. package/src/runtime/routes/host-browser-routes.ts +11 -9
  317. package/src/runtime/routes/host-cu-routes.ts +4 -5
  318. package/src/runtime/routes/host-file-routes.ts +4 -5
  319. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  320. package/src/runtime/routes/http-adapter.ts +1 -1
  321. package/src/runtime/routes/identity-routes.ts +2 -3
  322. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  323. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
  324. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
  325. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
  326. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  327. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
  328. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
  329. package/src/runtime/routes/index.ts +0 -2
  330. package/src/runtime/routes/llm-context-normalization.ts +0 -83
  331. package/src/runtime/routes/mcp-auth-routes.ts +19 -171
  332. package/src/runtime/routes/migration-rollback-routes.ts +3 -4
  333. package/src/runtime/routes/migration-routes.ts +1 -4
  334. package/src/runtime/routes/subagents-routes.ts +0 -5
  335. package/src/runtime/routes/surface-action-routes.ts +56 -42
  336. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
  337. package/src/runtime/services/conversation-serializer.ts +9 -7
  338. package/src/runtime/tool-grant-request-helper.ts +3 -3
  339. package/src/runtime/trust-verdict-consumer.ts +9 -85
  340. package/src/runtime/verification-outbound-actions.ts +18 -18
  341. package/src/signals/user-message.ts +0 -16
  342. package/src/subagent/manager.ts +0 -9
  343. package/src/subagent/types.ts +3 -3
  344. package/src/telemetry/types.ts +1 -34
  345. package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
  346. package/src/telemetry/usage-telemetry-reporter.ts +3 -87
  347. package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
  348. package/src/tools/ask-question/ask-question-tool.ts +0 -13
  349. package/src/tools/executor.ts +4 -4
  350. package/src/tools/registry.ts +0 -18
  351. package/src/tools/shared/filesystem/path-policy.ts +5 -12
  352. package/src/tools/tool-approval-handler.ts +1 -1
  353. package/src/tools/tool-defaults.ts +2 -9
  354. package/src/tools/tool-manifest.ts +0 -3
  355. package/src/tools/types.ts +2 -17
  356. package/src/tools/workspace-tools/loader.ts +244 -348
  357. package/src/util/errors.ts +1 -26
  358. package/src/util/platform.ts +0 -5
  359. package/src/workflows/library.test.ts +0 -140
  360. package/src/workflows/library.ts +28 -82
  361. package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
  362. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
  363. package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
  364. package/src/workspace/migrations/registry.ts +0 -2
  365. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
  366. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
  367. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
  368. package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
  369. package/src/__tests__/code-search-tool.test.ts +0 -585
  370. package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
  371. package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
  372. package/src/__tests__/plugin-pipeline.test.ts +0 -96
  373. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
  374. package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
  375. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
  376. package/src/agent/loop-exclusive-tool.test.ts +0 -150
  377. package/src/api/constants/sse-replay.ts +0 -41
  378. package/src/api/events/conversation-notice.ts +0 -26
  379. package/src/approvals/guardian-channel-delivery.ts +0 -30
  380. package/src/approvals/guardian-expiry-notifier.ts +0 -148
  381. package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
  382. package/src/cli/commands/memory/worker.ts +0 -175
  383. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
  384. package/src/config/prune-seeded-callsite-defaults.ts +0 -110
  385. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
  386. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
  387. package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
  388. package/src/contacts/guardian-delivery-reader.ts +0 -223
  389. package/src/contacts/member-write-relay.ts +0 -189
  390. package/src/daemon/conversation-notices.ts +0 -60
  391. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
  392. package/src/hooks/hook-loader.ts +0 -341
  393. package/src/mcp/mcp-header-store.ts +0 -134
  394. package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
  395. package/src/memory/__tests__/prompt-override.test.ts +0 -192
  396. package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
  397. package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
  398. package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
  399. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
  400. package/src/memory/prompt-override.ts +0 -129
  401. package/src/memory/steps.ts +0 -573
  402. package/src/memory/watchdog-events-store.ts +0 -87
  403. package/src/memory/worker-control.ts +0 -118
  404. package/src/memory/worker-process.ts +0 -72
  405. package/src/notifications/__tests__/connected-channels.test.ts +0 -114
  406. package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
  407. package/src/onboarding/checkin-event.test.ts +0 -222
  408. package/src/onboarding/checkin-event.ts +0 -321
  409. package/src/onboarding/schedule-checkin.ts +0 -190
  410. package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
  411. package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
  412. package/src/plugins/defaults/advisor/context-pack.ts +0 -288
  413. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
  414. package/src/plugins/surface-import.ts +0 -121
  415. package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
  416. package/src/providers/openai/api-error-normalization.ts +0 -270
  417. package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
  418. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
  419. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
  420. package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
  421. package/src/runtime/anchored-guardian.test.ts +0 -156
  422. package/src/runtime/anchored-guardian.ts +0 -135
  423. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
  424. package/src/runtime/local-principal-trust.ts +0 -52
  425. package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
  426. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
  427. package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
  428. package/src/tools/filesystem/search.ts +0 -543
  429. package/src/util/telemetry-db-path.ts +0 -24
  430. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
@@ -3,10 +3,7 @@ import { v4 as uuid } from "uuid";
3
3
  import { z } from "zod";
4
4
 
5
5
  import { SurfaceActionSchema } from "../api/events/ui-surface-show.js";
6
- import {
7
- CardSurfaceDataSchema,
8
- FileUploadSurfaceDataSchema,
9
- } from "../api/surfaces.js";
6
+ import { CardSurfaceDataSchema } from "../api/surfaces.js";
10
7
  import { isActivationSession } from "../memory/activation-session-store.js";
11
8
  import {
12
9
  addAppConversationId,
@@ -59,7 +56,6 @@ import type {
59
56
  ConfirmationSurfaceData,
60
57
  CopyBlockSurfaceData,
61
58
  DynamicPageSurfaceData,
62
- FileUploadSurfaceData,
63
59
  FormSurfaceData,
64
60
  ListSurfaceData,
65
61
  OAuthConnectSurfaceData,
@@ -587,20 +583,12 @@ function normalizeCardShowData(
587
583
  (typeof input[k] === "string" &&
588
584
  (input[k] as string).trim().length > 0),
589
585
  );
590
- try {
591
- Sentry.withScope((scope) => {
592
- scope.setLevel("info");
593
- scope.setTag("card_normalization", "alias_recovery");
594
- scope.setTag("target_field", "body");
595
- scope.setContext("card_normalization", {
596
- used_aliases: usedAliases,
597
- candidate_count: candidates.length,
598
- });
599
- Sentry.captureMessage("card_normalization:alias_recovery:body");
600
- });
601
- } catch {
602
- // Never let telemetry break card rendering.
603
- }
586
+ Sentry.addBreadcrumb({
587
+ category: "card-normalization",
588
+ message: `alias recovery: ${usedAliases.join(", ")} → body`,
589
+ level: "info",
590
+ data: { usedAliases, candidateCount: candidates.length },
591
+ });
604
592
  }
605
593
  }
606
594
  for (const key of bodyAliasKeys) {
@@ -617,16 +605,11 @@ function normalizeCardShowData(
617
605
  ]);
618
606
  if (aliased !== undefined) {
619
607
  normalized.title = aliased;
620
- try {
621
- Sentry.withScope((scope) => {
622
- scope.setLevel("info");
623
- scope.setTag("card_normalization", "alias_recovery");
624
- scope.setTag("target_field", "title");
625
- Sentry.captureMessage("card_normalization:alias_recovery:title");
626
- });
627
- } catch {
628
- // Never let telemetry break card rendering.
629
- }
608
+ Sentry.addBreadcrumb({
609
+ category: "card-normalization",
610
+ message: `alias recovery: title`,
611
+ level: "info",
612
+ });
630
613
  }
631
614
  }
632
615
  for (const key of titleAliasKeys) {
@@ -651,16 +634,11 @@ function normalizeCardShowData(
651
634
  ]);
652
635
  if (aliased !== undefined) {
653
636
  normalized.subtitle = aliased;
654
- try {
655
- Sentry.withScope((scope) => {
656
- scope.setLevel("info");
657
- scope.setTag("card_normalization", "alias_recovery");
658
- scope.setTag("target_field", "subtitle");
659
- Sentry.captureMessage("card_normalization:alias_recovery:subtitle");
660
- });
661
- } catch {
662
- // Never let telemetry break card rendering.
663
- }
637
+ Sentry.addBreadcrumb({
638
+ category: "card-normalization",
639
+ message: `alias recovery: subtitle`,
640
+ level: "info",
641
+ });
664
642
  }
665
643
  }
666
644
  for (const key of subtitleAliasKeys) {
@@ -710,21 +688,12 @@ function normalizeCardShowData(
710
688
  { droppedKeys },
711
689
  "ui_show card data carried keys the card contract does not model; their content will not render",
712
690
  );
713
- try {
714
- Sentry.withScope((scope) => {
715
- scope.setLevel("warning");
716
- scope.setTag("card_normalization", "dropped_keys");
717
- scope.setContext("card_normalization", {
718
- dropped_count: droppedKeys.length,
719
- });
720
- // Key names are model-controlled, so they ride in `extra`, which
721
- // beforeSend redacts (it does not scrub `contexts`) — see instrument.ts.
722
- scope.setExtra("dropped_keys", droppedKeys);
723
- Sentry.captureMessage("card_normalization:dropped_keys");
724
- });
725
- } catch {
726
- // Never let telemetry break card rendering.
727
- }
691
+ Sentry.addBreadcrumb({
692
+ category: "card-normalization",
693
+ message: `dropped keys: ${droppedKeys.join(", ")}`,
694
+ level: "warning",
695
+ data: { droppedKeys },
696
+ });
728
697
  }
729
698
  const parsed = CardSurfaceDataSchema.safeParse(normalized);
730
699
  if (parsed.success) {
@@ -860,24 +829,6 @@ function normalizeOAuthConnectShowData(
860
829
  };
861
830
  }
862
831
 
863
- function normalizeFileUploadShowData(
864
- rawData: Record<string, unknown>,
865
- ): FileUploadSurfaceData {
866
- // Parse against the canonical schema so the surface carries the shape the
867
- // renderer expects. The schema is tolerant (every field optional and coerced)
868
- // and recovers the common malformed `acceptedTypes` shapes — a comma-joined or
869
- // bare string — into the `string[]` the renderer requires.
870
- const parsed = FileUploadSurfaceDataSchema.safeParse(rawData);
871
- if (parsed.success) {
872
- return parsed.data;
873
- }
874
- log.warn(
875
- { issues: parsed.error.issues },
876
- "ui_show file_upload data failed FileUploadSurfaceDataSchema; rendering an empty file_upload surface",
877
- );
878
- return {};
879
- }
880
-
881
832
  function buildChoiceActions(data: ChoiceSurfaceData): Array<{
882
833
  id: string;
883
834
  label: string;
@@ -2944,9 +2895,7 @@ export async function surfaceProxyResolver(
2944
2895
  ? normalizeOAuthConnectShowData(rawData)
2945
2896
  : surfaceType === "dynamic_page"
2946
2897
  ? normalizeDynamicPageShowData(input, rawData)
2947
- : surfaceType === "file_upload"
2948
- ? normalizeFileUploadShowData(rawData)
2949
- : (rawData as SurfaceData);
2898
+ : (rawData as SurfaceData);
2950
2899
  // Parse actions through the schema instead of typecasting raw model output.
2951
2900
  // The model may place actions inside `data` instead of the top-level
2952
2901
  // `actions` param — recover them so they aren't silently dropped.
@@ -2963,27 +2912,18 @@ export async function surfaceProxyResolver(
2963
2912
  if (result.success) {
2964
2913
  valid.push(result.data);
2965
2914
  } else {
2966
- try {
2967
- Sentry.withScope((scope) => {
2968
- scope.setLevel("warning");
2969
- scope.setTag("card_normalization", "action_parse_failure");
2970
- scope.setContext("card_normalization", {
2971
- issue_paths: result.error.issues.map((i) => i.path.join(".")),
2972
- });
2973
- // raw object keys are model-controlled, so they ride in `extra`,
2974
- // which beforeSend redacts (it does not scrub `contexts`) — see
2975
- // instrument.ts.
2976
- scope.setExtra(
2977
- "raw_keys",
2915
+ Sentry.addBreadcrumb({
2916
+ category: "card-normalization",
2917
+ message: "action parse failure (individual)",
2918
+ level: "warning",
2919
+ data: {
2920
+ issuePaths: result.error.issues.map((i) => i.path.join(".")),
2921
+ keys:
2978
2922
  typeof raw === "object" && raw !== null
2979
2923
  ? Object.keys(raw)
2980
2924
  : [typeof raw],
2981
- );
2982
- Sentry.captureMessage("card_normalization:action_parse_failure");
2983
- });
2984
- } catch {
2985
- // Never let telemetry break card rendering.
2986
- }
2925
+ },
2926
+ });
2987
2927
  }
2988
2928
  }
2989
2929
  inputActions = valid.length > 0 ? valid : undefined;
@@ -3021,24 +2961,11 @@ export async function surfaceProxyResolver(
3021
2961
  !hasTemplate &&
3022
2962
  !hasActions
3023
2963
  ) {
3024
- try {
3025
- Sentry.withScope((scope) => {
3026
- scope.setLevel("warning");
3027
- scope.setTag("card_normalization", "empty_card_rejected");
3028
- scope.setContext("card_normalization", {
3029
- surface_type: surfaceType,
3030
- has_title: hasTitle,
3031
- has_body: hasBody,
3032
- has_subtitle: hasSubtitle,
3033
- has_metadata: hasMetadata,
3034
- has_template: hasTemplate,
3035
- has_actions: hasActions,
3036
- });
3037
- Sentry.captureMessage("card_normalization:empty_card_rejected");
3038
- });
3039
- } catch {
3040
- // Never let telemetry break card rendering.
3041
- }
2964
+ Sentry.addBreadcrumb({
2965
+ category: "card-normalization",
2966
+ message: "empty card rejected",
2967
+ level: "warning",
2968
+ });
3042
2969
  return {
3043
2970
  content:
3044
2971
  "Error: ui_show card requires content — provide `data.body`, a `template` (e.g. task_progress with steps), `data.metadata`, `data.subtitle`, a `title`, or `actions`. The surface was not displayed because it carried no renderable content. Resend ui_show with populated card content.",
@@ -22,12 +22,7 @@ import type { Message, ToolDefinition } from "../providers/types.js";
22
22
  import { assistantEventHub } from "../runtime/assistant-event-hub.js";
23
23
  import { registerConversationSender } from "../tools/browser/browser-screencast.js";
24
24
  import type { ToolExecutor } from "../tools/executor.js";
25
- import {
26
- getMcpToolDefinitions,
27
- getTool,
28
- getWorkspaceToolDefinitions,
29
- getWorkspaceToolNames,
30
- } from "../tools/registry.js";
25
+ import { getMcpToolDefinitions, getTool } from "../tools/registry.js";
31
26
  import {
32
27
  ACTIVITY_SKIP_SET,
33
28
  injectActivityField,
@@ -46,7 +41,6 @@ import {
46
41
  type ToolExecutionResult,
47
42
  type ToolLifecycleEventHandler,
48
43
  } from "../tools/types.js";
49
- import { loadWorkspaceTools } from "../tools/workspace-tools/loader.js";
50
44
  import {
51
45
  resolveUsageAttribution,
52
46
  type UsageAttributionSnapshot,
@@ -244,10 +238,7 @@ export function createToolExecutor(
244
238
  });
245
239
  }
246
240
  },
247
- isInteractive:
248
- ctx.currentTurnIsNonInteractive !== undefined
249
- ? !ctx.currentTurnIsNonInteractive
250
- : !ctx.hasNoClient && !ctx.headlessLock,
241
+ isInteractive: !ctx.hasNoClient && !ctx.headlessLock,
251
242
  proxyToolResolver: (
252
243
  toolName: string,
253
244
  proxyInput: Record<string, unknown>,
@@ -515,7 +506,6 @@ const PLATFORM_TOOL_NAMES = new Set(["request_system_permission"]);
515
506
  */
516
507
  export const SUBAGENT_ONLY_TOOL_NAMES = new Set<string>([
517
508
  "file_list",
518
- "code_search",
519
509
  "notify_parent",
520
510
  ]);
521
511
 
@@ -660,13 +650,11 @@ export function isToolActiveForContext(
660
650
  * allowedToolNames so newly-activated skill tools aren't blocked by
661
651
  * the executor's stale gate.
662
652
  *
663
- * Core (non-MCP, non-workspace) tool definitions are captured at conversation
664
- * creation and reused on each turn. MCP and workspace tool definitions are
665
- * re-read from the global registry on each turn so that tools registered or
666
- * changed after conversation creation are automatically picked up without
667
- * requiring conversation disposal or app restart — MCP via `vellum mcp
668
- * reload`, workspace tools via edits under `<workspaceDir>/tools/` that the
669
- * per-turn reconcile (kicked below) folds into the registry.
653
+ * Core (non-MCP) tool definitions are captured at conversation creation and
654
+ * reused on each turn. MCP tool definitions are re-read from the global
655
+ * registry on each turn so that tools registered after conversation creation
656
+ * (e.g. via `vellum mcp reload`) are automatically picked up without
657
+ * requiring conversation disposal or app restart.
670
658
  */
671
659
  export function createResolveToolsCallback(
672
660
  toolDefs: ToolDefinition[],
@@ -674,21 +662,16 @@ export function createResolveToolsCallback(
674
662
  ): ((history: Message[]) => ToolDefinition[]) | undefined {
675
663
  if (toolDefs.length === 0) return undefined;
676
664
 
677
- // Separate the initial tool defs into core (stable) and the two dynamic
678
- // categories (MCP, workspace). We keep core tools from the snapshot and
679
- // re-read MCP + workspace tools from the registry each turn.
665
+ // Separate the initial tool defs into core (stable) and MCP (dynamic).
666
+ // We keep core tools from the snapshot and re-read MCP tools each turn.
680
667
  const initialMcpDefs = getMcpToolDefinitions();
681
668
  const initialMcpNames = new Set(initialMcpDefs.map((d) => d.name));
682
- const initialWorkspaceNames = new Set(getWorkspaceToolNames());
683
- const coreToolDefs = toolDefs.filter(
684
- (d) => !initialMcpNames.has(d.name) && !initialWorkspaceNames.has(d.name),
685
- );
669
+ const coreToolDefs = toolDefs.filter((d) => !initialMcpNames.has(d.name));
686
670
  log.debug(
687
671
  {
688
672
  coreCount: coreToolDefs.length,
689
673
  mcpCount: initialMcpDefs.length,
690
674
  mcpTools: initialMcpDefs.map((d) => d.name),
691
- workspaceCount: initialWorkspaceNames.size,
692
675
  },
693
676
  "Conversation tool resolver initialized",
694
677
  );
@@ -702,13 +685,6 @@ export function createResolveToolsCallback(
702
685
  return [];
703
686
  }
704
687
 
705
- // Reconcile workspace tool overrides under `<workspaceDir>/tools/` into
706
- // the registry, then re-read them below — the on-read replacement for a
707
- // filesystem watcher. Fire-and-forget: the reconcile is idempotent,
708
- // mtime-cached (a no-op costs one readdir + a stat per file) and
709
- // serialized, so the registry settles for a subsequent turn to read.
710
- void loadWorkspaceTools();
711
-
712
688
  // Filter core tools based on current conversation context so that tools
713
689
  // irrelevant to this turn (e.g. UI tools when no client is connected)
714
690
  // are omitted from the definitions sent to the provider.
@@ -729,34 +705,24 @@ export function createResolveToolsCallback(
729
705
  ? filteredCoreDefs.filter((d) => wireAllowlist.has(d.name))
730
706
  : filteredCoreDefs;
731
707
 
732
- // Re-read MCP and workspace tool definitions from the registry each turn
733
- // so conversations automatically pick up tools added/removed by `vellum
734
- // mcp reload` and workspace-tool edits reconciled from disk, without
735
- // recreating the conversation.
708
+ // Re-read MCP tool definitions from the registry each turn so conversations
709
+ // automatically pick up tools added/removed by `vellum mcp reload`.
736
710
  const currentMcpDefs = getMcpToolDefinitions();
737
- const currentWorkspaceDefs = getWorkspaceToolDefinitions();
738
711
  log.debug(
739
712
  {
740
713
  coreCount: scopedCoreDefs.length,
741
714
  mcpCount: currentMcpDefs.length,
742
715
  mcpTools: currentMcpDefs.map((d) => d.name),
743
- workspaceCount: currentWorkspaceDefs.length,
744
- workspaceTools: currentWorkspaceDefs.map((d) => d.name),
745
716
  },
746
- "MCP and workspace tools resolved for turn",
717
+ "MCP tools resolved for turn",
747
718
  );
748
719
  const scopedMcpDefs = wireAllowlist
749
720
  ? currentMcpDefs.filter((d) => wireAllowlist.has(d.name))
750
721
  : currentMcpDefs;
751
- const scopedWorkspaceDefs = wireAllowlist
752
- ? currentWorkspaceDefs.filter((d) => wireAllowlist.has(d.name))
753
- : currentWorkspaceDefs;
754
722
  const excluded = new Set(getConfig().tools.exclude);
755
- const allBaseDefs = [
756
- ...scopedCoreDefs,
757
- ...scopedWorkspaceDefs,
758
- ...scopedMcpDefs,
759
- ].filter((d) => !excluded.has(d.name));
723
+ const allBaseDefs = [...scopedCoreDefs, ...scopedMcpDefs].filter(
724
+ (d) => !excluded.has(d.name),
725
+ );
760
726
 
761
727
  const effectivePreactivated = [
762
728
  ...DEFAULT_PREACTIVATED_SKILL_IDS,
@@ -50,7 +50,6 @@ import {
50
50
  getMessages,
51
51
  resolveOverrideProfile,
52
52
  setConversationHistoryStrippedAt,
53
- setConversationProcessingStartedAt,
54
53
  } from "../memory/conversation-crud.js";
55
54
  import { getResolvedConversationDirPath } from "../memory/conversation-directories.js";
56
55
  import { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
@@ -92,7 +91,7 @@ import {
92
91
  isActivationMomentParam,
93
92
  } from "../telemetry/activation-funnel.js";
94
93
  import { ToolExecutor } from "../tools/executor.js";
95
- import { getAllToolDefinitions, getTool } from "../tools/registry.js";
94
+ import { getAllToolDefinitions } from "../tools/registry.js";
96
95
  import type { ToolLifecycleEvent } from "../tools/types.js";
97
96
  import type { OnboardingContext } from "../types/onboarding-context.js";
98
97
  import type { AbortReason } from "../util/abort-reasons.js";
@@ -377,7 +376,6 @@ export class Conversation {
377
376
  */
378
377
  wakePersonaOverride?: SystemPromptPersonaOverride;
379
378
  /** @internal */ currentTurnOverrideProfile?: string;
380
- /** @internal */ currentTurnIsNonInteractive?: boolean;
381
379
  /** @internal */ authContext?: AuthContext;
382
380
  /** @internal */ currentTurnAuthContext?: AuthContext;
383
381
  /** @internal */ currentTurnSourceActorPrincipalId?: string;
@@ -703,9 +701,6 @@ export class Conversation {
703
701
  tools: toolDefs.length > 0 ? toolDefs : undefined,
704
702
  toolExecutor: toolDefs.length > 0 ? toolExecutor : undefined,
705
703
  resolveTools,
706
- // A tool the registry marks exclusive (e.g. `advisor`) runs alone in its
707
- // turn; the loop defers any sibling calls until the next turn.
708
- isExclusiveTool: (name) => getTool(name)?.exclusive === true,
709
704
  resolveConversationDir: () => {
710
705
  const conv = getConversation(this.conversationId);
711
706
  if (!conv) return null;
@@ -1340,13 +1335,6 @@ export class Conversation {
1340
1335
  setProcessing(value: boolean): void {
1341
1336
  const wasProcessing = this._processing;
1342
1337
  this._processing = value;
1343
- // Persist the cross-process source of truth so out-of-process callers
1344
- // (retrospective CLI, future detached workers) can detect mid-turn state
1345
- // by reading the conversations row directly.
1346
- setConversationProcessingStartedAt(
1347
- this.conversationId,
1348
- value ? Date.now() : null,
1349
- );
1350
1338
  if (wasProcessing && !value) {
1351
1339
  void publishSyncInvalidation([
1352
1340
  conversationMetadataSyncTag(this.conversationId),
@@ -24,12 +24,6 @@ export const DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT = 90;
24
24
  // clears the warning state, which discards the banner's (state-scoped) dismissal
25
25
  // so it re-appears the moment usage ticks back up.
26
26
  export const DISK_PRESSURE_WARNING_CLEAR_THRESHOLD_PERCENT = 77;
27
- // Absolute free-space floor (MiB). Regardless of usage percentage, never enter
28
- // the warning or critical state while at least this much space remains free. A
29
- // high usage percentage on a large disk can still leave many gigabytes
30
- // available, where locking is pointless. Small volumes (where a high percentage
31
- // genuinely means near-full) drop below the floor and remain protected.
32
- export const DISK_PRESSURE_MIN_FREE_FLOOR_MB = 2048;
33
27
  export const DISK_PRESSURE_CHECK_INTERVAL_MS = 60_000;
34
28
  export const DISK_PRESSURE_OVERRIDE_CONFIRMATION = "I understand the risks";
35
29
  export const DISK_PRESSURE_BLOCKED_CAPABILITIES = [
@@ -225,10 +219,7 @@ export function evaluateDiskPressureNow(): DiskPressureStatus {
225
219
  const criticalThreshold = state.status.locked
226
220
  ? DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT
227
221
  : DISK_PRESSURE_THRESHOLD_PERCENT;
228
- // Absolute free-space floor overrides the percentage thresholds: while ample
229
- // space remains free, report "ok" no matter how full the volume is by percent.
230
- const hasAmpleFreeSpace = usageInfo.freeMb >= DISK_PRESSURE_MIN_FREE_FLOOR_MB;
231
- const isCritical = !hasAmpleFreeSpace && usagePercent >= criticalThreshold;
222
+ const isCritical = usagePercent >= criticalThreshold;
232
223
  // Mirror the critical deadband for the warning band: once in an active
233
224
  // pressure state (warning or critical), hold warning until usage clears the
234
225
  // lower warning-clear threshold. Treating "critical" as active here matters
@@ -244,8 +235,7 @@ export function evaluateDiskPressureNow(): DiskPressureStatus {
244
235
  const warningThreshold = inActivePressureState
245
236
  ? DISK_PRESSURE_WARNING_CLEAR_THRESHOLD_PERCENT
246
237
  : DISK_PRESSURE_WARNING_THRESHOLD_PERCENT;
247
- const isWarning =
248
- !hasAmpleFreeSpace && !isCritical && usagePercent >= warningThreshold;
238
+ const isWarning = !isCritical && usagePercent >= warningThreshold;
249
239
  const lastCheckedAt = new Date().toISOString();
250
240
 
251
241
  if (!isCritical && !isWarning) {
@@ -33,7 +33,6 @@
33
33
 
34
34
  import * as Sentry from "@sentry/node";
35
35
 
36
- import { recordWatchdogEvent } from "../memory/watchdog-events-store.js";
37
36
  import { getLogger } from "../util/logger.js";
38
37
 
39
38
  const log = getLogger("event-loop-watchdog");
@@ -75,37 +74,11 @@ export function evaluateTick(
75
74
  return { blockedMs, exceeded: blockedMs >= thresholdMs };
76
75
  }
77
76
 
78
- /**
79
- * Check name emitted for event-loop block events. The platform's
80
- * `watchdog__event_loop_blocking_daily` admin query filters `check_name` to
81
- * this exact string, so it is the primary group-by dimension downstream —
82
- * keep it stable.
83
- */
84
- export const EVENT_LOOP_BLOCKED_CHECK_NAME = "event_loop_blocked";
85
-
86
77
  function reportBlock(blockedMs: number, thresholdMs: number): void {
87
78
  log.warn(
88
79
  { blockedMs, thresholdMs, tickIntervalMs: TICK_INTERVAL_MS },
89
80
  "event loop blocked",
90
81
  );
91
- // Persist a `watchdog` telemetry event so the platform can surface
92
- // event-loop blocking in the infrastructure admin chart. `recordWatchdogEvent`
93
- // no-ops when usage-data collection is disabled (the event is dropped to
94
- // honor the opt-out), so the watchdog runs unconditionally without leaking
95
- // health data for opted-out owners. Never let a telemetry failure escape
96
- // the timer callback — wrap it alongside the Sentry capture below.
97
- try {
98
- recordWatchdogEvent({
99
- checkName: EVENT_LOOP_BLOCKED_CHECK_NAME,
100
- value: blockedMs,
101
- detail: {
102
- threshold_ms: thresholdMs,
103
- tick_interval_ms: TICK_INTERVAL_MS,
104
- },
105
- });
106
- } catch {
107
- // Never let a telemetry failure escape the timer callback.
108
- }
109
82
  try {
110
83
  Sentry.withScope((scope) => {
111
84
  scope.setLevel("warning");
@@ -115,7 +88,7 @@ function reportBlock(blockedMs: number, thresholdMs: number): void {
115
88
  threshold_ms: thresholdMs,
116
89
  tick_interval_ms: TICK_INTERVAL_MS,
117
90
  });
118
- Sentry.captureMessage(EVENT_LOOP_BLOCKED_CHECK_NAME);
91
+ Sentry.captureMessage("event_loop_blocked");
119
92
  });
120
93
  } catch {
121
94
  // Never let a telemetry failure escape the timer callback.
@@ -19,20 +19,24 @@
19
19
  * dropped from the registry via {@link unregisterPlugin} so none of its
20
20
  * hooks participate in the turn lifecycle. This is the primary mechanism for
21
21
  * shipping experimental plugins behind a feature flag.
22
- * 4. Validates the config block under `plugins.<name>` against
22
+ * 4. Resolves the plugin's `manifest.requiresCredential` entries via the
23
+ * credential store helper ({@link getSecureKeyAsync}). In Docker mode
24
+ * that helper goes through the CES HTTP API transparently; in local mode
25
+ * it hits the encrypted file store / CES RPC backend.
26
+ * 5. Validates the config block under `plugins.<name>` against
23
27
  * `manifest.config` if the manifest supplies a parser-like validator
24
28
  * (Zod schemas with `.parse()` are supported; anything else is passed
25
29
  * through untouched).
26
- * 5. Creates `<workspaceDir>/plugins-data/<plugin>/` on demand for per-plugin
30
+ * 6. Creates `<workspaceDir>/plugins-data/<plugin>/` on demand for per-plugin
27
31
  * writable state and exposes it via {@link PluginInitContext.pluginStorageDir}.
28
- * 6. For each surviving plugin, registers its contributed tools and routes
32
+ * 7. For each surviving plugin, registers its contributed tools and routes
29
33
  * into their global registries via {@link registerPluginTools} and
30
34
  * {@link registerSkillRoute}. Contributions land BEFORE `init()` so
31
35
  * the plugin's hook can observe a registry where its own model-visible
32
36
  * surface is already wired — useful for plugins that want to attach
33
37
  * metadata, warm caches, or otherwise interact with their own
34
38
  * contributions during initialization.
35
- * 7. Awaits `plugin.init(ctx)` sequentially. An init failure is contained to
39
+ * 8. Awaits `plugin.init(ctx)` sequentially. An init failure is contained to
36
40
  * the offending plugin: its already-registered tools and routes are rolled
37
41
  * back, it is dropped from the registry, the failure is logged, and
38
42
  * bootstrap continues with the remaining plugins. A single plugin's failure
@@ -72,6 +76,7 @@ import {
72
76
  type SkillRouteHandle,
73
77
  unregisterSkillRoute,
74
78
  } from "../runtime/skill-route-registry.js";
79
+ import { getSecureKeyAsync } from "../security/secure-keys.js";
75
80
  import {
76
81
  registerPluginTools,
77
82
  unregisterPluginTools,
@@ -83,6 +88,25 @@ import { registerShutdownHook } from "./shutdown-registry.js";
83
88
 
84
89
  const log = getLogger("plugins-bootstrap");
85
90
 
91
+ /**
92
+ * Resolve one credential value. Returns the raw secret string or throws a
93
+ * {@link PluginExecutionError} tagged with the plugin name so the caller can
94
+ * fail startup with clear attribution.
95
+ */
96
+ async function resolveCredentialOrThrow(
97
+ pluginName: string,
98
+ credentialKey: string,
99
+ ): Promise<string> {
100
+ const value = await getSecureKeyAsync(credentialKey);
101
+ if (value === undefined || value === "") {
102
+ throw new PluginExecutionError(
103
+ `plugin ${pluginName} requires credential "${credentialKey}" but the credential store returned no value`,
104
+ pluginName,
105
+ );
106
+ }
107
+ return value;
108
+ }
109
+
86
110
  /**
87
111
  * Validate a plugin config block. If the manifest supplies a parser-like
88
112
  * validator (Zod schemas expose `.parse()`), use it. Otherwise pass the
@@ -322,6 +346,11 @@ async function initializePlugin(
322
346
  let initCompleted = false;
323
347
 
324
348
  try {
349
+ const credentials: Record<string, string> = {};
350
+ for (const key of plugin.manifest.requiresCredential ?? []) {
351
+ credentials[key] = await resolveCredentialOrThrow(name, key);
352
+ }
353
+
325
354
  const config = validatePluginConfig(
326
355
  name,
327
356
  plugin.manifest.config,
@@ -330,6 +359,7 @@ async function initializePlugin(
330
359
 
331
360
  const initContext = {
332
361
  config,
362
+ credentials,
333
363
  logger: log.child({ plugin: name }),
334
364
  pluginStorageDir: ensurePluginStorageDir(name),
335
365
  assistantVersion: APP_VERSION,
@@ -129,29 +129,4 @@ describe("redeemA2AInvite", () => {
129
129
  const result = redeemA2AInvite({ sender: SENDER });
130
130
  expect(result.success).toBe(true);
131
131
  });
132
-
133
- test("activeConnections counts a2a channel existence, not status", () => {
134
- const result = redeemA2AInvite({ sender: SENDER });
135
- expect(result.success).toBe(true);
136
-
137
- expect(getA2AConfig().activeConnections).toBe(1);
138
-
139
- // Readiness is existence-based: a non-active stored status still counts.
140
- const sqlite = getSqlite();
141
- sqlite.run("UPDATE contact_channels SET status = 'unverified'");
142
- invalidateConfigCache();
143
- expect(getA2AConfig().activeConnections).toBe(1);
144
- });
145
-
146
- test("already-connected guard fires regardless of stored channel status", () => {
147
- const first = redeemA2AInvite({ sender: SENDER });
148
- expect(first.success).toBe(true);
149
-
150
- const sqlite = getSqlite();
151
- sqlite.run("UPDATE contact_channels SET status = 'revoked'");
152
-
153
- const second = redeemA2AInvite({ sender: SENDER });
154
- expect(second.alreadyConnected).toBe(true);
155
- expect(second.contactId).toBe(first.contactId);
156
- });
157
132
  });
@@ -96,11 +96,13 @@ export function getA2AConfig(): A2AConfigResult {
96
96
  const config = getConfig();
97
97
  const enabled = config.a2a?.enabled ?? false;
98
98
 
99
- // a2a is peer binding outside the human-trust ACL model — the gateway has no
100
- // canonical a2a channel status, so channel existence is the readiness signal.
101
99
  const contacts = searchContacts({ channelType: "a2a" });
102
100
  const activeConnections = contacts.reduce((count, c) => {
103
- return count + c.channels.filter((ch) => ch.type === "a2a").length;
101
+ return (
102
+ count +
103
+ c.channels.filter((ch) => ch.type === "a2a" && ch.status === "active")
104
+ .length
105
+ );
104
106
  }, 0);
105
107
 
106
108
  return { success: true, enabled, activeConnections };
@@ -268,9 +270,12 @@ export function redeemA2AInvite(params: {
268
270
  setA2AConfig();
269
271
  }
270
272
 
271
- // 2. Check for existing contact with this sender (a2a binding existence)
273
+ // 2. Check for existing active contact with this sender
272
274
  const existing = findContactByAddress("a2a", params.sender.assistantId);
273
- if (existing && existing.channels.some((ch) => ch.type === "a2a")) {
275
+ if (
276
+ existing &&
277
+ existing.channels.some((ch) => ch.type === "a2a" && ch.status === "active")
278
+ ) {
274
279
  return { success: true, alreadyConnected: true, contactId: existing.id };
275
280
  }
276
281
 
@@ -368,7 +373,10 @@ export async function acceptA2AInvite(params: {
368
373
  // 2. Short-circuit if already connected — avoids a network round-trip
369
374
  // and consuming a token on the sender side.
370
375
  const existing = findContactByAddress("a2a", params.senderAssistantId);
371
- if (existing && existing.channels.some((ch) => ch.type === "a2a")) {
376
+ if (
377
+ existing &&
378
+ existing.channels.some((ch) => ch.type === "a2a" && ch.status === "active")
379
+ ) {
372
380
  return { success: true, alreadyConnected: true, contactId: existing.id };
373
381
  }
374
382