@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
@@ -34,38 +34,19 @@ mock.module("../../prompts/system-prompt.js", () => ({
34
34
  buildCoreIdentityContext: () => null,
35
35
  }));
36
36
 
37
- // Guardian binding (ACL) is resolved via the gateway pull; notes (INFO) are
38
- // joined locally by contactId. Tests drive both via mutable slots.
39
- let guardianDeliveryFixture: Array<{ contactId: string }> = [];
40
- let contactInfoFixture: Record<string, { notes: string | null } | null> = {};
41
-
42
- mock.module("../../contacts/guardian-delivery-reader.js", () => ({
43
- getGuardianDelivery: async () => guardianDeliveryFixture,
44
- anyGuardian: (list: Array<{ contactId: string }>) => list[0],
45
- }));
46
-
47
37
  mock.module("../../contacts/contact-store.js", () => ({
48
- findContactInfoById: (contactId: string) =>
49
- contactInfoFixture[contactId] ?? null,
38
+ listGuardianChannels: () => null,
50
39
  }));
51
40
 
52
- // Provider mock. By default `sendMessage` throws so the assistant_tool
53
- // pass-through path (which must skip the LLM) fails loudly if it reaches the
54
- // provider. LLM-path tests override `providerSendMessage` to capture inputs.
55
- let providerSendMessage: (
56
- messages: unknown[],
57
- opts: { systemPrompt?: string },
58
- ) => Promise<unknown> = () => {
59
- throw new Error(
60
- "provider.sendMessage should NOT be invoked for assistant_tool pass-through",
61
- );
62
- };
63
-
41
+ // Provider mock if `getConfiguredProvider` is ever called by the
42
+ // assistant_tool pass-through path, this throw makes the test fail
43
+ // loudly instead of silently exercising the LLM path.
64
44
  mock.module("../../providers/provider-send-message.js", () => ({
65
- getConfiguredProvider: async () => ({
66
- sendMessage: (messages: unknown[], opts: { systemPrompt?: string }) =>
67
- providerSendMessage(messages, opts),
68
- }),
45
+ getConfiguredProvider: async () => {
46
+ throw new Error(
47
+ "getConfiguredProvider should NOT be invoked for assistant_tool pass-through",
48
+ );
49
+ },
69
50
  createTimeout: () => ({
70
51
  signal: new AbortController().signal,
71
52
  cleanup: () => {},
@@ -300,53 +281,3 @@ describe("assistant_tool pass-through in notification decision engine", () => {
300
281
  expect(decision.renderedCopy.vellum?.body).toBe("fyi");
301
282
  });
302
283
  });
303
-
304
- describe("recipient notes injection (ACL from gateway, notes joined locally)", () => {
305
- function makeLlmSignal(): NotificationSignal {
306
- return {
307
- signalId: "sig-llm-notes-1",
308
- createdAt: Date.now(),
309
- sourceChannel: "scheduler",
310
- sourceContextId: "schedule-1",
311
- sourceEventName: "schedule.notify",
312
- contextPayload: {},
313
- attentionHints: {
314
- requiresAction: false,
315
- urgency: "low",
316
- isAsyncBackground: false,
317
- visibleInSourceNow: false,
318
- },
319
- };
320
- }
321
-
322
- test("injects the guardian's local notes, resolved via the gateway contactId", async () => {
323
- guardianDeliveryFixture = [{ contactId: "contact-42" }];
324
- contactInfoFixture = { "contact-42": { notes: "Prefers terse updates." } };
325
-
326
- let capturedSystemPrompt: string | undefined;
327
- providerSendMessage = async (_messages, opts) => {
328
- capturedSystemPrompt = opts.systemPrompt;
329
- return {};
330
- };
331
-
332
- await evaluateSignal(makeLlmSignal(), ["vellum"] as NotificationChannel[]);
333
-
334
- expect(capturedSystemPrompt).toContain("<recipient-context>");
335
- expect(capturedSystemPrompt).toContain("Prefers terse updates.");
336
- });
337
-
338
- test("omits recipient context when no guardian is bound", async () => {
339
- guardianDeliveryFixture = [];
340
- contactInfoFixture = {};
341
-
342
- let capturedSystemPrompt: string | undefined;
343
- providerSendMessage = async (_messages, opts) => {
344
- capturedSystemPrompt = opts.systemPrompt;
345
- return {};
346
- };
347
-
348
- await evaluateSignal(makeLlmSignal(), ["vellum"] as NotificationChannel[]);
349
-
350
- expect(capturedSystemPrompt).not.toContain("<recipient-context>");
351
- });
352
- });
@@ -11,7 +11,6 @@
11
11
 
12
12
  import { v4 as uuid } from "uuid";
13
13
 
14
- import { getGuardianDelivery } from "../contacts/guardian-delivery-reader.js";
15
14
  import { getConversation } from "../memory/conversation-crud.js";
16
15
  import type { ApprovalUIMetadata } from "../runtime/channel-approval-types.js";
17
16
  import { getLogger } from "../util/logger.js";
@@ -172,13 +171,7 @@ export class NotificationBroadcaster {
172
171
  decision: NotificationDecision,
173
172
  options?: BroadcastDecisionOptions,
174
173
  ): Promise<NotificationDeliveryResult[]> {
175
- // Pull the guardian list once so the resolver stays pure. A null list
176
- // (gateway unreachable) falls back to the local contacts read.
177
- const guardians = await getGuardianDelivery();
178
- const destinations = resolveDestinations(
179
- decision.selectedChannels,
180
- guardians,
181
- );
174
+ const destinations = resolveDestinations(decision.selectedChannels);
182
175
 
183
176
  // Ensure vellum is processed first so the notification_conversation_created
184
177
  // event fires immediately, before slower channel sends (e.g. Telegram 30s
@@ -12,11 +12,7 @@
12
12
  import { v4 as uuid } from "uuid";
13
13
 
14
14
  import { getDeliverableChannels } from "../channels/config.js";
15
- import { findContactInfoById } from "../contacts/contact-store.js";
16
- import {
17
- anyGuardian,
18
- getGuardianDelivery,
19
- } from "../contacts/guardian-delivery-reader.js";
15
+ import { listGuardianChannels } from "../contacts/contact-store.js";
20
16
  import { buildCoreIdentityContext } from "../prompts/system-prompt.js";
21
17
  import {
22
18
  createTimeout,
@@ -967,19 +963,15 @@ async function classifyWithLLM(
967
963
  ? truncate(rawIdentityContext, MAX_IDENTITY_CONTEXT_CHARS, "\n…[truncated]")
968
964
  : undefined;
969
965
 
970
- // Resolve guardian contact notes for recipient context. The guardian's
971
- // identity (ACL) comes from the gateway pull, channel-agnostic so notes are
972
- // available even when the only deliverable channel is "vellum". Notes (INFO)
973
- // stay local and are joined by contactId.
966
+ // Resolve guardian contact notes for recipient context. Use the channel-
967
+ // agnostic guardian lookup so notes are available even when the only
968
+ // deliverable channel is "vellum" (which has no contact channel type).
974
969
  let recipientNotes: string | undefined;
975
970
  try {
976
- const guardian = anyGuardian((await getGuardianDelivery()) ?? []);
977
- const notes = guardian
978
- ? findContactInfoById(guardian.contactId)?.notes
979
- : undefined;
980
- if (notes) {
971
+ const guardianResult = listGuardianChannels();
972
+ if (guardianResult?.contact.notes) {
981
973
  recipientNotes = truncate(
982
- notes,
974
+ guardianResult.contact.notes,
983
975
  MAX_IDENTITY_CONTEXT_CHARS,
984
976
  "\n…[truncated]",
985
977
  );
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Resolves per-channel destination endpoints for notification delivery.
3
3
  *
4
- * Reads guardian delivery info from the gateway-backed guardian list.
4
+ * Reads guardian delivery info from the contacts table.
5
5
  *
6
6
  * - Vellum: no external endpoint needed — delivery goes through the event
7
7
  * broadcast mechanism to connected desktop/mobile clients. The
@@ -11,54 +11,14 @@
11
11
  * sourced from the guardian contact's channel record.
12
12
  */
13
13
 
14
- import type { GuardianDelivery } from "@vellumai/gateway-client";
15
-
16
14
  import { isNotificationDeliverable } from "../channels/config.js";
17
15
  import type { ChannelId } from "../channels/types.js";
18
16
  import { findGuardianForChannel } from "../contacts/contact-store.js";
19
- import { guardianForChannel } from "../contacts/guardian-delivery-reader.js";
20
17
  import { getLogger } from "../util/logger.js";
21
18
  import type { ChannelDestination, NotificationChannel } from "./types.js";
22
19
 
23
20
  const log = getLogger("destination-resolver");
24
21
 
25
- /** Guardian delivery endpoint for a channel, flattened from either source. */
26
- interface ResolvedGuardian {
27
- principalId?: string;
28
- address: string;
29
- externalChatId?: string;
30
- }
31
-
32
- /**
33
- * Resolve the guardian delivery endpoint for a channel: gateway list first,
34
- * else the local contacts read. The local read is the transitional
35
- * dual-written mirror and covers a transient gateway failure (null list) or a
36
- * gateway list missing this channel, so a soft-failed gateway read does not
37
- * drop a binding the local store still holds. Removed in Combo 11.
38
- */
39
- function resolveGuardian(
40
- guardians: GuardianDelivery[] | null,
41
- channelType: string,
42
- ): ResolvedGuardian | undefined {
43
- const g = guardians
44
- ? guardianForChannel(guardians, channelType)
45
- : undefined;
46
- if (g) {
47
- return {
48
- principalId: g.principalId ?? undefined,
49
- address: g.address,
50
- externalChatId: g.externalChatId ?? undefined,
51
- };
52
- }
53
- const local = findGuardianForChannel(channelType);
54
- if (!local) return undefined;
55
- return {
56
- principalId: local.contact.principalId ?? undefined,
57
- address: local.channel.address,
58
- externalChatId: local.channel.externalChatId ?? undefined,
59
- };
60
- }
61
-
62
22
  /**
63
23
  * Resolve destination information for each requested channel.
64
24
  *
@@ -66,14 +26,9 @@ function resolveGuardian(
66
26
  * the function skips non-deliverable channels via `isNotificationDeliverable`.
67
27
  * Returns a map keyed by `NotificationChannel`. Channels that cannot be
68
28
  * resolved (e.g. no Telegram binding configured) are omitted from the result.
69
- *
70
- * `guardians` is the gateway-resolved guardian list; per channel, a missing
71
- * match (null list or no entry for the channel) falls back to the local
72
- * contacts read for this release.
73
29
  */
74
30
  export function resolveDestinations(
75
31
  channels: readonly (ChannelId | NotificationChannel)[],
76
- guardians: GuardianDelivery[] | null,
77
32
  ): Map<NotificationChannel, ChannelDestination> {
78
33
  const result = new Map<NotificationChannel, ChannelDestination>();
79
34
 
@@ -88,10 +43,10 @@ export function resolveDestinations(
88
43
  // Vellum delivery is local — no external endpoint required.
89
44
  // Include the guardianPrincipalId so the adapter can annotate
90
45
  // guardian-sensitive notifications for scoped delivery.
91
- const guardian = resolveGuardian(guardians, "vellum");
46
+ const guardianResult = findGuardianForChannel("vellum");
92
47
  const metadata: Record<string, unknown> = {};
93
- if (guardian?.principalId) {
94
- metadata.guardianPrincipalId = guardian.principalId;
48
+ if (guardianResult) {
49
+ metadata.guardianPrincipalId = guardianResult.contact.principalId;
95
50
  }
96
51
  result.set("vellum", {
97
52
  channel: "vellum",
@@ -100,7 +55,7 @@ export function resolveDestinations(
100
55
  log.debug(
101
56
  {
102
57
  channel: "vellum",
103
- source: "guardian-delivery",
58
+ source: "contacts",
104
59
  hasEndpoint: false,
105
60
  },
106
61
  "destination resolved",
@@ -108,52 +63,52 @@ export function resolveDestinations(
108
63
  break;
109
64
  }
110
65
  case "telegram": {
111
- const guardian = resolveGuardian(guardians, channel);
112
- if (guardian?.externalChatId) {
113
- const externalChatId = guardian.externalChatId;
66
+ const guardianResult = findGuardianForChannel(channel);
67
+ if (guardianResult && guardianResult.channel.externalChatId) {
68
+ const externalChatId = guardianResult.channel.externalChatId;
114
69
  result.set(channel as NotificationChannel, {
115
70
  channel: channel as NotificationChannel,
116
71
  endpoint: externalChatId,
117
72
  metadata: {
118
- externalUserId: guardian.address,
73
+ externalUserId: guardianResult.channel.address,
119
74
  },
120
75
  bindingContext: {
121
76
  sourceChannel: channel as NotificationChannel,
122
77
  externalChatId,
123
- externalUserId: guardian.address,
78
+ externalUserId: guardianResult.channel.address,
124
79
  },
125
80
  });
126
81
  }
127
82
  log.debug(
128
83
  {
129
84
  channel,
130
- source: "guardian-delivery",
131
- hasEndpoint: !!guardian?.externalChatId,
85
+ source: "contacts",
86
+ hasEndpoint: !!guardianResult?.channel.externalChatId,
132
87
  },
133
88
  "destination resolved",
134
89
  );
135
90
  break;
136
91
  }
137
92
  case "slack": {
138
- const guardian = resolveGuardian(guardians, "slack");
139
- const chatId = guardian?.externalChatId;
93
+ const guardianResult = findGuardianForChannel("slack");
94
+ const chatId = guardianResult?.channel.externalChatId;
140
95
  // Slack bindings can originate from app_mention in shared channels.
141
96
  // Only route notifications to DM channels (IDs starting with "D")
142
97
  // to prevent leaking notifications into shared workspaces.
143
- if (guardian && chatId && isSlackDmChannel(chatId)) {
98
+ if (guardianResult && chatId && isSlackDmChannel(chatId)) {
144
99
  result.set("slack", {
145
100
  channel: "slack",
146
101
  endpoint: chatId,
147
102
  metadata: {
148
- externalUserId: guardian.address,
103
+ externalUserId: guardianResult.channel.address,
149
104
  },
150
105
  bindingContext: {
151
106
  sourceChannel: "slack",
152
107
  externalChatId: chatId,
153
- externalUserId: guardian.address,
108
+ externalUserId: guardianResult.channel.address,
154
109
  },
155
110
  });
156
- } else if (guardian && chatId) {
111
+ } else if (guardianResult && chatId) {
157
112
  log.warn(
158
113
  { channel: "slack", chatId },
159
114
  "skipping non-DM Slack channel for notification delivery",
@@ -162,7 +117,7 @@ export function resolveDestinations(
162
117
  log.debug(
163
118
  {
164
119
  channel: "slack",
165
- source: "guardian-delivery",
120
+ source: "contacts",
166
121
  hasEndpoint: !!(chatId && isSlackDmChannel(chatId)),
167
122
  },
168
123
  "destination resolved",
@@ -173,10 +128,11 @@ export function resolveDestinations(
173
128
  // Platform delivery goes through the daemon's VellumPlatformClient —
174
129
  // no external binding needed. Include guardianPrincipalId so the
175
130
  // adapter can scope guardian-sensitive notifications.
176
- const platformGuardian = resolveGuardian(guardians, "vellum");
131
+ const platformGuardian = findGuardianForChannel("vellum");
177
132
  const platformMeta: Record<string, unknown> = {};
178
- if (platformGuardian?.principalId) {
179
- platformMeta.guardianPrincipalId = platformGuardian.principalId;
133
+ if (platformGuardian) {
134
+ platformMeta.guardianPrincipalId =
135
+ platformGuardian.contact.principalId;
180
136
  }
181
137
  result.set("platform", {
182
138
  channel: "platform",
@@ -184,7 +140,7 @@ export function resolveDestinations(
184
140
  Object.keys(platformMeta).length > 0 ? platformMeta : undefined,
185
141
  });
186
142
  log.debug(
187
- { channel: "platform", source: "guardian-delivery", hasEndpoint: false },
143
+ { channel: "platform", source: "contacts", hasEndpoint: false },
188
144
  "destination resolved",
189
145
  );
190
146
  break;
@@ -9,15 +9,10 @@
9
9
  * propagated unless `throwOnError` is enabled.
10
10
  */
11
11
 
12
- import type { GuardianDelivery } from "@vellumai/gateway-client";
13
12
  import { v4 as uuid } from "uuid";
14
13
 
15
14
  import { getDeliverableChannels } from "../channels/config.js";
16
15
  import { findGuardianForChannel } from "../contacts/contact-store.js";
17
- import {
18
- getGuardianDelivery,
19
- guardianForChannel,
20
- } from "../contacts/guardian-delivery-reader.js";
21
16
  import type { ConversationCreateType } from "../memory/conversation-crud.js";
22
17
  import { broadcastMessage } from "../runtime/assistant-event-hub.js";
23
18
  import { getLogger } from "../util/logger.js";
@@ -94,33 +89,9 @@ export function getBroadcaster(): NotificationBroadcaster {
94
89
 
95
90
  // ── Connected channels resolution ──────────────────────────────────────
96
91
 
97
- /**
98
- * Resolve a binding-based channel's delivery endpoint (externalChatId) the
99
- * SAME way destination-resolver's `resolveGuardian` does: gateway match first,
100
- * falling back to the LOCAL contacts read on ANY per-channel no-match — gateway
101
- * list null (unreachable) OR no active gateway entry for this channel. The
102
- * local read is the transitional dual-written mirror, removed in Combo 11.
103
- * Keeping connectivity aligned with delivery prevents a channel being marked
104
- * connected but then skipped with no destination (or vice-versa).
105
- */
106
- function resolveChannelChatId(
107
- guardians: GuardianDelivery[] | null,
108
- channelType: string,
109
- ): string | undefined {
110
- const g = guardians ? guardianForChannel(guardians, channelType) : undefined;
111
- if (g) {
112
- return g.externalChatId ?? undefined;
113
- }
114
- return findGuardianForChannel(channelType)?.channel.externalChatId ?? undefined;
115
- }
116
-
117
- export async function getConnectedChannels(): Promise<NotificationChannel[]> {
92
+ function getConnectedChannels(): NotificationChannel[] {
118
93
  const channels: NotificationChannel[] = [];
119
94
 
120
- // Guardian bindings (ACL) come from the gateway pull; null ⇒ gateway
121
- // unreachable, so binding-based connectivity falls back to the local read.
122
- const guardians = await getGuardianDelivery();
123
-
124
95
  // getDeliverableChannels() returns ChannelId[] but every returned channel
125
96
  // has deliveryEnabled: true, making it a valid NotificationChannel at
126
97
  // runtime. We iterate over the broad type and narrow via the switch.
@@ -139,20 +110,24 @@ export async function getConnectedChannels(): Promise<NotificationChannel[]> {
139
110
  channels.push(channel);
140
111
  break;
141
112
  case "telegram": {
142
- // Connected when the resolved guardian has a delivery endpoint —
143
- // mirroring destination-resolver so we never mark connected what
144
- // can't be delivered.
145
- if (resolveChannelChatId(guardians, channel)) {
113
+ // A binding-based channel is connected when the guardian has an
114
+ // active channel entry with a valid delivery endpoint. The
115
+ // externalChatId check ensures we don't report a channel as
116
+ // connected when the contacts record exists but lacks the
117
+ // delivery address the destination-resolver needs.
118
+ const guardian = findGuardianForChannel(channel);
119
+ if (guardian && guardian.channel.externalChatId) {
146
120
  channels.push(channel);
147
121
  }
148
122
  break;
149
123
  }
150
124
  case "slack": {
151
125
  // Slack bindings can originate from shared channels (app_mention).
152
- // Only consider Slack connected when the resolved chat ID is a DM
153
- // channel (D-prefixed), matching destination-resolver's DM gate.
154
- const chatId = resolveChannelChatId(guardians, "slack");
155
- if (chatId && chatId.startsWith("D")) {
126
+ // Only consider Slack connected when the stored chat ID is a DM
127
+ // channel (D-prefixed) to prevent leaking notifications.
128
+ const slackGuardian = findGuardianForChannel("slack");
129
+ const chatId = slackGuardian?.channel.externalChatId;
130
+ if (slackGuardian && chatId && chatId.startsWith("D")) {
156
131
  channels.push(channel);
157
132
  }
158
133
  break;
@@ -315,7 +290,7 @@ export async function emitNotificationSignal<TEventName extends string>(
315
290
  }
316
291
 
317
292
  // Step 2: Evaluate the signal through the decision engine
318
- const connectedChannels = await getConnectedChannels();
293
+ const connectedChannels = getConnectedChannels();
319
294
 
320
295
  log.debug(
321
296
  {
@@ -9,7 +9,7 @@ import type {
9
9
 
10
10
  // Use a tiny timeout so the setTimeout branch fires quickly in tests
11
11
  const mockConfig = {
12
- timeouts: { questionResponseTimeoutSec: 0.05 },
12
+ timeouts: { permissionTimeoutSec: 0.05 },
13
13
  };
14
14
  // Preserve every other export from the real config/loader so other
15
15
  // tests in the same `bun test` run (which share module-level mocks)
@@ -156,12 +156,9 @@ export interface QuestionBatchMetadata {
156
156
  * the whole batch to `/v1/question-response` when the user is done — no
157
157
  * per-question accumulator, no partial state machine.
158
158
  *
159
- * The idle timeout is a backstop (`getConfig().timeouts.questionResponseTimeoutSec`,
160
- * default 30 min), not the primary way a prompt is dismissed. An interactive
161
- * user who moves on instead of answering enqueues another message, which
162
- * supersedes the open prompt at the enqueue handler (see conversation-routes.ts);
163
- * a non-interactive turn resolves immediately at the tool. The backstop only
164
- * fires when a prompt is left open with no response and no follow-up message.
159
+ * Timeout reuses `getConfig().timeouts.permissionTimeoutSec` (default 5 min) —
160
+ * questions are user-prompts in the same UX family as permission prompts and
161
+ * secret prompts, so they share the same idle-timeout knob.
165
162
  */
166
163
  export class QuestionPrompter {
167
164
  async prompt(params: QuestionPromptParams): Promise<QuestionPromptResult> {
@@ -202,7 +199,7 @@ export class QuestionPrompter {
202
199
  const requestId = uuid();
203
200
 
204
201
  return new Promise<QuestionPromptResult>((resolve, reject) => {
205
- const timeoutMs = getConfig().timeouts.questionResponseTimeoutSec * 1000;
202
+ const timeoutMs = getConfig().timeouts.permissionTimeoutSec * 1000;
206
203
 
207
204
  // Closure-scoped idempotency guard. Every resolution path (timeout,
208
205
  // abort, route resolution via `rpcResolve`/`rpcReject`) routes through
@@ -130,12 +130,12 @@ export type {
130
130
  } from "../runtime/assistant-event-hub.js";
131
131
  export { assistantEventHub } from "../runtime/assistant-event-hub.js";
132
132
  export { getModelProfiles } from "./model-profiles.js";
133
- // Check whether a model or profile can process image input. Accepts a concrete
134
- // model id, a profile key, or a `ModelProfileInfo`; a bare string is resolved
135
- // as a model id first and then as a profile key. Profile resolution merges over
136
- // the workspace default and infers the provider for model-only profiles, then
137
- // looks up the model catalog's `supportsVision` flag (mix profiles are
138
- // vision-capable if any arm is). Returns false when nothing resolves.
133
+ // Check whether a profile's resolved model can process image input. Resolves
134
+ // the effective (provider, model) by merging over the workspace default and
135
+ // inferring the provider for model-only profiles, then looks up the model
136
+ // catalog's `supportsVision` flag. Handles mix profiles (true if any arm
137
+ // supports vision). Fail-open for unknown models. Pair with
138
+ // `getModelProfiles()` to inspect the active or candidate profiles.
139
139
  export { doesSupportVision } from "./vision-support.js";
140
140
  // Resolve a provider for a call site (optionally overriding the profile) so a
141
141
  // plugin can run inference through the workspace's configured profiles and
@@ -72,13 +72,15 @@ export type PluginHookFn<TCtx = unknown> = (
72
72
  // ─── Init context ────────────────────────────────────────────────────────────
73
73
 
74
74
  /**
75
- * Context passed to `Plugin.init()` during bootstrap. Carries the resolved
76
- * config, a pino-compatible logger scoped to the plugin, a per-plugin
77
- * writable data directory, and the assistant's version metadata.
75
+ * Context passed to `Plugin.init()` during bootstrap. Carries resolved
76
+ * config/credentials, a pino-compatible logger scoped to the plugin, a
77
+ * per-plugin writable data directory, and the assistant's version metadata.
78
78
  */
79
79
  export interface PluginInitContext {
80
80
  /** Parsed config for this plugin (may be `unknown` until the manifest validates). */
81
81
  config: unknown;
82
+ /** Resolved credential values keyed by the entries of `manifest.requiresCredential`. */
83
+ credentials: Record<string, string>;
82
84
  /** Pino-compatible child logger bound to `{ plugin: <name> }`. */
83
85
  logger: PluginLogger;
84
86
  /** Absolute path to `<workspaceDir>/plugins-data/<plugin>/` (created by bootstrap). */
@@ -84,16 +84,16 @@ describe("doesSupportVision", () => {
84
84
  expect(doesSupportVision(profile("text-profile"))).toBe(false);
85
85
  });
86
86
 
87
- test("returns false for an unknown profile key not in config", () => {
87
+ test("fails open (true) for an unknown profile key not in config", () => {
88
88
  setMockConfig({});
89
- expect(doesSupportVision(profile("nonexistent"))).toBe(false);
89
+ expect(doesSupportVision(profile("nonexistent"))).toBe(true);
90
90
  });
91
91
 
92
- test("returns false for an unknown provider/model pair", () => {
92
+ test("fails open (true) for an unknown provider/model pair", () => {
93
93
  setMockConfig({
94
94
  "unknown-model": { provider: "unknown-provider", model: "unknown-model" },
95
95
  });
96
- expect(doesSupportVision(profile("unknown-model"))).toBe(false);
96
+ expect(doesSupportVision(profile("unknown-model"))).toBe(true);
97
97
  });
98
98
 
99
99
  test("inherits provider from llm.default when profile only sets model", () => {
@@ -147,27 +147,3 @@ describe("doesSupportVision", () => {
147
147
  expect(doesSupportVision(profile("mix-profile"))).toBe(false);
148
148
  });
149
149
  });
150
-
151
- describe("doesSupportVision with a bare string", () => {
152
- test("returns true for a known vision-capable model id", () => {
153
- expect(doesSupportVision("claude-opus-4-6")).toBe(true);
154
- });
155
-
156
- test("returns false for a known text-only model id", () => {
157
- expect(doesSupportVision("accounts/fireworks/models/glm-5p2")).toBe(false);
158
- });
159
-
160
- test("falls back to resolving the string as a profile key", () => {
161
- // "vision-profile" is not a catalog model id, so it resolves as a profile
162
- // key → anthropic/claude-opus-4-6 (vision-capable).
163
- setMockConfig({
164
- "vision-profile": { provider: "anthropic", model: "claude-opus-4-6" },
165
- });
166
- expect(doesSupportVision("vision-profile")).toBe(true);
167
- });
168
-
169
- test("returns false for a string that is neither a model nor a profile", () => {
170
- setMockConfig({});
171
- expect(doesSupportVision("some-unknown-string")).toBe(false);
172
- });
173
- });