@vellumai/assistant 0.12.2 → 0.12.3-staging.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. package/.env.example +2 -0
  2. package/AGENTS.md +1 -1
  3. package/ARCHITECTURE.md +43 -29
  4. package/Dockerfile +63 -0
  5. package/docs/architecture/integrations.md +7 -0
  6. package/docs/architecture/memory.md +17 -2
  7. package/docs/architecture/security.md +10 -5
  8. package/docs/architecture/turn-actor.md +2 -0
  9. package/docs/credential-execution-service.md +1 -1
  10. package/docs/desktop-browser-cli.md +50 -5
  11. package/docs/live-voice-task-outcomes.md +100 -0
  12. package/docs/mode-sessions.md +183 -0
  13. package/docs/voice-input-diagnostics.md +58 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  19. package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
  20. package/node_modules/@vellumai/environments/src/shell.ts +24 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  25. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  26. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
  28. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  29. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  30. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  31. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  32. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  33. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  34. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  35. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  36. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  37. package/openapi.yaml +716 -16
  38. package/package.json +1 -1
  39. package/scripts/smoke-desktop-browser-cli.ts +11 -26
  40. package/scripts/smoke-desktop-window-theme.ts +2 -3
  41. package/scripts/sync-llm-catalog.ts +3 -0
  42. package/scripts/voice-ttft-spike.ts +2 -2
  43. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  44. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  45. package/src/__tests__/agent-loop.test.ts +259 -0
  46. package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
  47. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  48. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  49. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  50. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  51. package/src/__tests__/anthropic-provider.test.ts +55 -0
  52. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  53. package/src/__tests__/approval-message-composer.test.ts +1 -118
  54. package/src/__tests__/approval-routes-http.test.ts +3 -0
  55. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  56. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  57. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  58. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  59. package/src/__tests__/attachments-store.test.ts +22 -3
  60. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  61. package/src/__tests__/btw-routes.test.ts +4 -1
  62. package/src/__tests__/build-persisted-content.test.ts +1 -1
  63. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  64. package/src/__tests__/call-recovery.test.ts +7 -2
  65. package/src/__tests__/call-routes-http.test.ts +12 -0
  66. package/src/__tests__/call-store.test.ts +7 -2
  67. package/src/__tests__/channel-approval.test.ts +9 -14
  68. package/src/__tests__/channel-reply-delivery.test.ts +56 -0
  69. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  70. package/src/__tests__/chat-credential-redaction.test.ts +23 -0
  71. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  72. package/src/__tests__/checker.test.ts +11 -3
  73. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  74. package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
  75. package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
  76. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  77. package/src/__tests__/computer-use-tools.test.ts +1 -233
  78. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  79. package/src/__tests__/config-schema.test.ts +16 -0
  80. package/src/__tests__/config-watcher.test.ts +24 -0
  81. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  82. package/src/__tests__/context-search-fanout.test.ts +1 -1
  83. package/src/__tests__/context-search-types.test.ts +7 -7
  84. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  85. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  86. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  87. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  88. package/src/__tests__/conversation-agent-loop.test.ts +797 -16
  89. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  90. package/src/__tests__/conversation-attachments.test.ts +106 -0
  91. package/src/__tests__/conversation-evictor.test.ts +62 -37
  92. package/src/__tests__/conversation-fork-crud.test.ts +191 -0
  93. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  94. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  95. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  96. package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
  97. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  98. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  99. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  100. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  101. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  102. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  103. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  104. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  105. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  106. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  107. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  108. package/src/__tests__/conversation-undo.test.ts +61 -0
  109. package/src/__tests__/credential-execution-client.test.ts +72 -55
  110. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  111. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  112. package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
  113. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  114. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  115. package/src/__tests__/dm-backfill.test.ts +91 -1
  116. package/src/__tests__/document-create-route.test.ts +88 -0
  117. package/src/__tests__/document-sync-tags.test.ts +27 -0
  118. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  119. package/src/__tests__/events-tail-route.test.ts +58 -0
  120. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  121. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  122. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  123. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  124. package/src/__tests__/heartbeat-service.test.ts +2 -59
  125. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  126. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  127. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  128. package/src/__tests__/history-repair.test.ts +53 -0
  129. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  130. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  131. package/src/__tests__/image-credentials.test.ts +49 -0
  132. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  133. package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
  134. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  135. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  136. package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
  137. package/src/__tests__/llm-catalog-parity.test.ts +27 -4
  138. package/src/__tests__/media-generate-image.test.ts +49 -1
  139. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  140. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  141. package/src/__tests__/mode-session-history.test.ts +245 -0
  142. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  143. package/src/__tests__/mode-session-wire.test.ts +141 -0
  144. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  145. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  146. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  147. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  148. package/src/__tests__/oauth-commands-routes.test.ts +114 -101
  149. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  150. package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
  151. package/src/__tests__/oauth-providers-routes.test.ts +3 -0
  152. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  153. package/src/__tests__/persist-media-references.test.ts +50 -0
  154. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  155. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  156. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  157. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -1
  158. package/src/__tests__/process-message-display-content.test.ts +56 -0
  159. package/src/__tests__/reaction-persistence.test.ts +5 -0
  160. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  161. package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
  162. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  163. package/src/__tests__/schedule-routes.test.ts +20 -0
  164. package/src/__tests__/scheduler-result-notification.test.ts +23 -4
  165. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  166. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  167. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  168. package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
  169. package/src/__tests__/secret-routes-scrub.test.ts +22 -27
  170. package/src/__tests__/secret-scanner.test.ts +20 -0
  171. package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
  172. package/src/__tests__/secure-keys.test.ts +50 -4
  173. package/src/__tests__/send-endpoint-busy.test.ts +163 -1
  174. package/src/__tests__/server-history-render.test.ts +91 -1
  175. package/src/__tests__/server-tool-pairing.test.ts +107 -0
  176. package/src/__tests__/settings-routes.test.ts +50 -1
  177. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  178. package/src/__tests__/skills.test.ts +5 -4
  179. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  180. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  181. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  182. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
  184. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  185. package/src/__tests__/terminal-tools.test.ts +8 -0
  186. package/src/__tests__/thread-backfill.test.ts +53 -0
  187. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  188. package/src/__tests__/tool-result-follow-up.test.ts +99 -0
  189. package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
  190. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  191. package/src/__tests__/twilio-routes.test.ts +1 -0
  192. package/src/__tests__/unicode.test.ts +36 -0
  193. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  194. package/src/activation/progress-store.test.ts +12 -7
  195. package/src/agent/loop.ts +136 -53
  196. package/src/agent/tool-result-follow-up.ts +70 -0
  197. package/src/api/attachment-provenance.test.ts +68 -0
  198. package/src/api/computer-use-tool.test.ts +55 -0
  199. package/src/api/computer-use-tool.ts +27 -0
  200. package/src/api/events/assistant-outbound-attachment.ts +3 -0
  201. package/src/api/events/assistant-turn-start.ts +3 -0
  202. package/src/api/events/desktop-activity-changed.ts +10 -0
  203. package/src/api/events/generation-handoff.ts +2 -0
  204. package/src/api/events/message-complete.ts +2 -0
  205. package/src/api/events/notification-conversation-created.ts +14 -16
  206. package/src/api/events/notification-intent.ts +4 -2
  207. package/src/api/events/question-request.ts +1 -0
  208. package/src/api/events/tool-result.ts +85 -0
  209. package/src/api/events/tool-use-start.ts +3 -0
  210. package/src/api/events/user-message-echo.ts +3 -0
  211. package/src/api/index.ts +42 -6
  212. package/src/api/mode-session.test.ts +131 -0
  213. package/src/api/mode-session.ts +148 -0
  214. package/src/api/remember-tool.ts +15 -0
  215. package/src/api/responses/conversation-message.ts +9 -0
  216. package/src/approvals/AGENTS.md +4 -2
  217. package/src/approvals/approval-primitive.ts +5 -2
  218. package/src/approvals/scoped-approval-grants.ts +6 -2
  219. package/src/browser/__tests__/operations.test.ts +29 -0
  220. package/src/browser/operation-meta.ts +2 -1
  221. package/src/browser/operations.ts +29 -0
  222. package/src/browser/virtual-desktop-target.ts +2 -9
  223. package/src/bundler/bundle-signer.ts +1 -3
  224. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  225. package/src/calls/__tests__/call-controller.test.ts +94 -0
  226. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  227. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  228. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  229. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  230. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  231. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  232. package/src/calls/barge-in-guard.ts +5 -0
  233. package/src/calls/call-controller.ts +196 -1
  234. package/src/calls/call-domain.ts +4 -0
  235. package/src/calls/call-store.ts +87 -2
  236. package/src/calls/guardian-action-sweep.ts +22 -8
  237. package/src/calls/media-stream-audio-transcode.ts +1 -3
  238. package/src/calls/typesafe-noul.ts +156 -0
  239. package/src/calls/voice-control-protocol.ts +6 -0
  240. package/src/calls/voice-escalation-judge.ts +145 -0
  241. package/src/calls/voice-escalation-target.ts +10 -0
  242. package/src/calls/voice-leg-coordinator.ts +121 -3
  243. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  244. package/src/calls/voice-session-bridge.ts +256 -112
  245. package/src/calls/voice-triage-escalate.ts +7 -0
  246. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  247. package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
  248. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  249. package/src/cli/commands/__tests__/plugins.test.ts +20 -1
  250. package/src/cli/commands/__tests__/schedules.test.ts +14 -0
  251. package/src/cli/commands/bash.help.ts +4 -3
  252. package/src/cli/commands/browser.help.ts +9 -6
  253. package/src/cli/commands/browser.ts +0 -1
  254. package/src/cli/commands/clients.help.ts +46 -0
  255. package/src/cli/commands/clients.ts +116 -0
  256. package/src/cli/commands/credentials.help.ts +9 -4
  257. package/src/cli/commands/notifications.help.ts +16 -2
  258. package/src/cli/commands/notifications.ts +30 -8
  259. package/src/cli/commands/oauth/index.help.ts +10 -0
  260. package/src/cli/commands/oauth/providers.ts +12 -0
  261. package/src/cli/commands/oauth/request.test.ts +179 -2
  262. package/src/cli/commands/oauth/request.ts +41 -10
  263. package/src/cli/commands/plugins.ts +12 -5
  264. package/src/cli/commands/roadmap.help.ts +18 -21
  265. package/src/cli/commands/roadmap.ts +4 -21
  266. package/src/cli/commands/schedules.ts +2 -0
  267. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  268. package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
  269. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  270. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
  271. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
  272. package/src/cli/lib/bundled-marketplace.json +906 -1
  273. package/src/cli/lib/bundled-plugin-packages.json +783 -1
  274. package/src/cli/lib/inspect-plugin.ts +11 -4
  275. package/src/cli/lib/plugin-marketplace.ts +8 -0
  276. package/src/cli/lib/publish-plugin.ts +1 -2
  277. package/src/cli/lib/upgrade-plugin.ts +19 -11
  278. package/src/cli/output.ts +18 -4
  279. package/src/config/__tests__/default-provider.test.ts +6 -0
  280. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  281. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  282. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  283. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  284. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  285. package/src/config/bundled-skills/schedule/SKILL.md +6 -6
  286. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  287. package/src/config/call-site-defaults.ts +9 -0
  288. package/src/config/feature-flag-registry.json +16 -0
  289. package/src/config/loader.ts +9 -17
  290. package/src/config/platform-identity.ts +8 -8
  291. package/src/config/profile-text-generation.test.ts +51 -0
  292. package/src/config/profile-text-generation.ts +51 -0
  293. package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
  294. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  295. package/src/config/schemas/call-site-catalog.ts +14 -0
  296. package/src/config/schemas/channels.ts +0 -18
  297. package/src/config/schemas/llm.ts +9 -2
  298. package/src/config/schemas/mcp.ts +6 -1
  299. package/src/config/schemas/memory-retrospective.ts +11 -2
  300. package/src/config/schemas/memory-v3.ts +12 -0
  301. package/src/config/schemas/services.ts +15 -6
  302. package/src/config/schemas/tools.ts +10 -0
  303. package/src/config/session-groups-gate.ts +21 -0
  304. package/src/config/skills.ts +2 -6
  305. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  306. package/src/conversations/message-consolidation.ts +102 -5
  307. package/src/credential-execution/ces-connect.test.ts +69 -0
  308. package/src/credential-execution/ces-connect.ts +115 -0
  309. package/src/credential-execution/ces-runtime.ts +55 -93
  310. package/src/credential-execution/executable-discovery.ts +34 -142
  311. package/src/credential-execution/process-manager.test.ts +20 -24
  312. package/src/credential-execution/process-manager.ts +24 -19
  313. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  314. package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
  315. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  316. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
  317. package/src/daemon/assistant-attachments.ts +20 -12
  318. package/src/daemon/browser-mode-session.test.ts +402 -0
  319. package/src/daemon/browser-mode-session.ts +186 -0
  320. package/src/daemon/chat-credential-redaction.ts +16 -1
  321. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  322. package/src/daemon/computer-use-mode-session.ts +105 -0
  323. package/src/daemon/config-watcher.ts +10 -0
  324. package/src/daemon/conversation-agent-loop-handlers.ts +132 -13
  325. package/src/daemon/conversation-agent-loop.ts +231 -25
  326. package/src/daemon/conversation-attachments.ts +93 -12
  327. package/src/daemon/conversation-evictor.ts +5 -24
  328. package/src/daemon/conversation-history.ts +10 -0
  329. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  330. package/src/daemon/conversation-interrupt.ts +7 -11
  331. package/src/daemon/conversation-messaging.ts +58 -5
  332. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  333. package/src/daemon/conversation-mode-session.ts +1008 -0
  334. package/src/daemon/conversation-process.ts +5 -0
  335. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  336. package/src/daemon/conversation-skill-tools.ts +1 -0
  337. package/src/daemon/conversation-store.ts +4 -4
  338. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  339. package/src/daemon/conversation-surfaces.ts +113 -5
  340. package/src/daemon/conversation-tool-setup.ts +79 -6
  341. package/src/daemon/conversation-turn-finalize.ts +26 -13
  342. package/src/daemon/conversation.ts +215 -58
  343. package/src/daemon/daemon-control.ts +3 -7
  344. package/src/daemon/handlers/config-model.ts +7 -5
  345. package/src/daemon/handlers/shared.ts +55 -16
  346. package/src/daemon/host-cu-proxy.ts +51 -22
  347. package/src/daemon/lifecycle.ts +30 -13
  348. package/src/daemon/mcp-reload-service.ts +1 -1
  349. package/src/daemon/message-protocol.ts +0 -1
  350. package/src/daemon/message-provenance.ts +28 -4
  351. package/src/daemon/message-types/shared.ts +1 -0
  352. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  353. package/src/daemon/mode-session-tracking.ts +54 -0
  354. package/src/daemon/orphan-reaper.ts +4 -3
  355. package/src/daemon/persist-media-references.ts +20 -3
  356. package/src/daemon/process-message.ts +13 -4
  357. package/src/daemon/tool-setup-types.ts +6 -0
  358. package/src/daemon/virtual-desktop-context.ts +21 -0
  359. package/src/daemon/wake-conversation-ops.ts +50 -15
  360. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  361. package/src/desktop/desktop-accessibility-script.ts +88 -0
  362. package/src/desktop/desktop-accessibility.test.ts +160 -0
  363. package/src/desktop/desktop-accessibility.ts +169 -0
  364. package/src/desktop/desktop-automation-lease.test.ts +302 -64
  365. package/src/desktop/desktop-automation-lease.ts +129 -54
  366. package/src/desktop/desktop-browser-endpoint.ts +4 -0
  367. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  368. package/src/desktop/desktop-computer-use.test.ts +449 -0
  369. package/src/desktop/desktop-computer-use.ts +502 -0
  370. package/src/desktop/desktop-dependencies.ts +47 -293
  371. package/src/desktop/desktop-display.ts +2 -2
  372. package/src/desktop/desktop-help.ts +15 -0
  373. package/src/desktop/desktop-panel-config.test.ts +13 -3
  374. package/src/desktop/desktop-panel-config.ts +109 -15
  375. package/src/desktop/desktop-session-manager.test.ts +69 -21
  376. package/src/desktop/desktop-session-manager.ts +76 -22
  377. package/src/desktop/desktop-stream-bridge.test.ts +76 -132
  378. package/src/desktop/desktop-stream-bridge.ts +9 -11
  379. package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
  380. package/src/desktop/desktop-wallpaper-worker.ts +17 -0
  381. package/src/desktop/desktop-wallpaper.test.ts +48 -7
  382. package/src/desktop/desktop-wallpaper.ts +34 -102
  383. package/src/desktop/desktop-window-theme.ts +5 -25
  384. package/src/desktop/virtual-desktop-feature.ts +53 -3
  385. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  386. package/src/documents/document-store.ts +23 -0
  387. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  388. package/src/heartbeat/heartbeat-service.ts +5 -33
  389. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  390. package/src/ipc/assistant-server.ts +2 -0
  391. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  392. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  393. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  394. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  395. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  396. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  397. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  398. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  399. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  400. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  401. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  402. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  403. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  404. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  405. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  406. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  407. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  408. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  409. package/src/live-voice/camera-mode-session.test.ts +265 -0
  410. package/src/live-voice/camera-mode-session.ts +277 -0
  411. package/src/live-voice/continuation-judge.ts +123 -0
  412. package/src/live-voice/live-activity-reporter.ts +115 -6
  413. package/src/live-voice/live-voice-manager.ts +36 -1
  414. package/src/live-voice/live-voice-photo.ts +88 -7
  415. package/src/live-voice/live-voice-session-manager.ts +15 -0
  416. package/src/live-voice/live-voice-session.ts +1443 -747
  417. package/src/live-voice/live-voice-tts.ts +22 -4
  418. package/src/live-voice/microphone-idle-gate.ts +56 -0
  419. package/src/live-voice/protocol.ts +171 -4
  420. package/src/live-voice/session-controls.ts +11 -3
  421. package/src/live-voice/task-outcomes.ts +131 -0
  422. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  423. package/src/mcp/__tests__/manager-tool-caps.test.ts +156 -0
  424. package/src/mcp/__tests__/startup.test.ts +30 -7
  425. package/src/mcp/__tests__/tool-caps.test.ts +134 -0
  426. package/src/mcp/manager.ts +171 -101
  427. package/src/mcp/startup.ts +33 -13
  428. package/src/mcp/tool-caps.ts +184 -0
  429. package/src/media/__tests__/image-models.test.ts +58 -0
  430. package/src/media/image-credentials.ts +5 -0
  431. package/src/media/image-models.ts +52 -0
  432. package/src/media/image-service.ts +8 -0
  433. package/src/media/openrouter-image-service.test.ts +133 -0
  434. package/src/media/openrouter-image-service.ts +153 -0
  435. package/src/media/types.ts +1 -1
  436. package/src/messaging/provider-message-metadata.ts +3 -3
  437. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  438. package/src/messaging/providers/discord/send.ts +4 -17
  439. package/src/messaging/providers/discord/transport.ts +2 -2
  440. package/src/messaging/providers/outlook/client.ts +16 -22
  441. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  442. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  443. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  444. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  445. package/src/monitoring/__tests__/control.test.ts +17 -5
  446. package/src/monitoring/control.ts +15 -5
  447. package/src/notifications/AGENTS.md +1 -1
  448. package/src/notifications/README.md +83 -99
  449. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  450. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  451. package/src/notifications/__tests__/copy-composer.test.ts +71 -1
  452. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  453. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  454. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  455. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  456. package/src/notifications/adapters/macos.ts +37 -46
  457. package/src/notifications/broadcaster.ts +5 -6
  458. package/src/notifications/channel-allowlist.ts +44 -0
  459. package/src/notifications/copy-composer.ts +11 -26
  460. package/src/notifications/decision-engine.ts +24 -14
  461. package/src/notifications/deterministic-checks.ts +1 -1
  462. package/src/notifications/emit-signal.ts +123 -37
  463. package/src/notifications/home-feed-side-effect.ts +9 -7
  464. package/src/notifications/notification-utils.ts +19 -0
  465. package/src/notifications/schedule-result-producer.ts +4 -6
  466. package/src/notifications/signal.ts +4 -19
  467. package/src/notifications/types.ts +15 -0
  468. package/src/oauth/AGENTS.md +2 -0
  469. package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
  470. package/src/oauth/connection-resolver.ts +1 -2
  471. package/src/oauth/identity-verifier.ts +24 -0
  472. package/src/oauth/oauth-store.ts +12 -4
  473. package/src/oauth/provider-serializer.ts +8 -0
  474. package/src/oauth/seed-providers.ts +42 -0
  475. package/src/onboarding/onboarding-events-store.ts +99 -12
  476. package/src/permissions/confirmation-guardian-request.test.ts +16 -0
  477. package/src/permissions/confirmation-guardian-request.ts +2 -3
  478. package/src/permissions/question-prompter.test.ts +31 -0
  479. package/src/permissions/question-prompter.ts +2 -0
  480. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  481. package/src/persistence/attachments-store.ts +84 -44
  482. package/src/persistence/client-connection-events-store.ts +377 -0
  483. package/src/persistence/conversation-crud.ts +166 -26
  484. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  485. package/src/persistence/conversation-mode-sessions.ts +460 -0
  486. package/src/persistence/conversation-plugin-facade.ts +30 -0
  487. package/src/persistence/conversation-queries.ts +6 -19
  488. package/src/persistence/conversation-tool-surface.ts +135 -0
  489. package/src/persistence/conversation-types.test.ts +32 -0
  490. package/src/persistence/conversation-types.ts +26 -4
  491. package/src/persistence/llm-usage-store.ts +3 -9
  492. package/src/persistence/message-metadata.ts +25 -0
  493. package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
  494. package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
  495. package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
  496. package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
  497. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
  498. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
  499. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  500. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  501. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  502. package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
  503. package/src/persistence/schema/conversations.ts +67 -0
  504. package/src/persistence/schema/index.ts +1 -0
  505. package/src/persistence/schema/infrastructure.ts +29 -0
  506. package/src/persistence/schema/oauth.ts +1 -0
  507. package/src/persistence/steps.ts +41 -3
  508. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  509. package/src/plugin-api/conversation-turn.ts +31 -7
  510. package/src/plugin-api/effective-context-window.ts +33 -0
  511. package/src/plugin-api/index.ts +35 -6
  512. package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
  513. package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
  514. package/src/plugin-api/plugin-name-env.ts +125 -0
  515. package/src/plugin-api/resolve-credential.ts +79 -20
  516. package/src/plugin-api/vision-support.test.ts +22 -0
  517. package/src/plugin-api/vision-support.ts +17 -5
  518. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  519. package/src/plugins/active-plugin-env.ts +51 -0
  520. package/src/plugins/defaults/index.ts +24 -0
  521. package/src/plugins/defaults/memory/AGENTS.md +39 -5
  522. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  523. package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
  524. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
  525. package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
  526. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
  527. package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
  528. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
  530. package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
  531. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  532. package/src/plugins/defaults/memory/buffer-file.ts +354 -0
  533. package/src/plugins/defaults/memory/buffer-format.ts +40 -0
  534. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  535. package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
  536. package/src/plugins/defaults/memory/context-search/format.ts +53 -8
  537. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  538. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  539. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  540. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  541. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
  542. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
  543. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  544. package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
  545. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  546. package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
  547. package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
  548. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  549. package/src/plugins/defaults/memory/host-utils.ts +0 -10
  550. package/src/plugins/defaults/memory/injectors.ts +4 -3
  551. package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
  552. package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
  553. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  554. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
  555. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  556. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
  557. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
  558. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
  559. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
  560. package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
  561. package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
  562. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
  563. package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
  564. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  565. package/src/plugins/defaults/memory/tools.ts +38 -11
  566. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
  567. package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
  568. package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
  570. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
  571. package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
  572. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
  573. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
  574. package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
  575. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
  576. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  577. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
  578. package/src/plugins/defaults/memory/v3/card.ts +2 -1
  579. package/src/plugins/defaults/memory/v3/injector.ts +212 -178
  580. package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
  581. package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
  582. package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
  583. package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
  584. package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
  585. package/src/plugins/defaults/memory/v3/sections.ts +2 -1
  586. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
  587. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  588. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  589. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  590. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  591. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  592. package/src/plugins/defaults/task-progress/package.json +14 -0
  593. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  594. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  595. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
  596. package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
  597. package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
  598. package/src/prompts/delegation-gate.ts +57 -0
  599. package/src/prompts/system-prompt.ts +14 -32
  600. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  601. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  602. package/src/providers/anthropic/client.ts +10 -1
  603. package/src/providers/anthropic-gateway-shared.ts +6 -0
  604. package/src/providers/fetch-provider-catalog.ts +11 -0
  605. package/src/providers/gemini/client.ts +25 -8
  606. package/src/providers/inference/adapter-factory.ts +6 -0
  607. package/src/providers/jev/client.test.ts +270 -0
  608. package/src/providers/jev/client.ts +534 -0
  609. package/src/providers/model-catalog.ts +59 -3
  610. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  611. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  612. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  613. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  614. package/src/providers/openai/chat-completions-provider.ts +100 -29
  615. package/src/providers/openai/google-thought-signature.ts +0 -6
  616. package/src/providers/openai/responses-provider.ts +23 -1
  617. package/src/providers/ratelimit.ts +1 -3
  618. package/src/providers/search-provider-catalog.ts +24 -0
  619. package/src/providers/server-tool-pairing.ts +16 -7
  620. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  621. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  622. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  623. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  624. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  625. package/src/providers/types.ts +5 -0
  626. package/src/routes/control.ts +7 -5
  627. package/src/runtime/AGENTS.md +6 -4
  628. package/src/runtime/__tests__/agent-wake.test.ts +94 -1
  629. package/src/runtime/actor-trust-resolver.ts +3 -3
  630. package/src/runtime/agent-wake.ts +32 -5
  631. package/src/runtime/approval-message-composer.ts +3 -69
  632. package/src/runtime/assistant-event-hub.ts +73 -75
  633. package/src/runtime/assistant-event-publish-options.ts +7 -0
  634. package/src/runtime/assistant-event-targeting.ts +79 -0
  635. package/src/runtime/assistant-stream-state.ts +13 -100
  636. package/src/runtime/background-job-runner.ts +5 -5
  637. package/src/runtime/channel-retry-sweep.ts +1 -0
  638. package/src/runtime/guardian-action-message-composer.ts +8 -161
  639. package/src/runtime/guardian-action-service.ts +2 -17
  640. package/src/runtime/guardian-reply-router.ts +29 -40
  641. package/src/runtime/http-server.ts +2 -2
  642. package/src/runtime/http-types.ts +6 -0
  643. package/src/runtime/message-composer-types.ts +3 -61
  644. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  645. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
  646. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  647. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  648. package/src/runtime/migrations/vbundle-import-policy.ts +43 -11
  649. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  650. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  651. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  652. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  653. package/src/runtime/pending-interactions.ts +29 -0
  654. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  655. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  656. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
  657. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  658. package/src/runtime/routes/browser-context.ts +31 -11
  659. package/src/runtime/routes/browser-routes.ts +43 -4
  660. package/src/runtime/routes/btw-routes.ts +9 -4
  661. package/src/runtime/routes/channel-route-shared.ts +1 -9
  662. package/src/runtime/routes/client-routes.ts +108 -0
  663. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  664. package/src/runtime/routes/conversation-routes.ts +125 -14
  665. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  666. package/src/runtime/routes/credential-routes.ts +1 -2
  667. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  668. package/src/runtime/routes/desktop-setup-routes.ts +8 -7
  669. package/src/runtime/routes/documents-routes.ts +51 -0
  670. package/src/runtime/routes/email-routes.ts +3 -7
  671. package/src/runtime/routes/events-routes.ts +75 -54
  672. package/src/runtime/routes/guardian-approval-interception.ts +24 -0
  673. package/src/runtime/routes/identity-routes.ts +1 -5
  674. package/src/runtime/routes/image-generation-routes.ts +8 -14
  675. package/src/runtime/routes/inbound-message-handler.ts +37 -41
  676. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  677. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  678. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +39 -10
  679. package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
  680. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  681. package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
  682. package/src/runtime/routes/inference-profiles-routes.ts +9 -0
  683. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  684. package/src/runtime/routes/migration-routes.ts +73 -2
  685. package/src/runtime/routes/notification-routes.ts +10 -0
  686. package/src/runtime/routes/oauth-commands-routes.ts +57 -54
  687. package/src/runtime/routes/oauth-providers.ts +11 -0
  688. package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
  689. package/src/runtime/routes/oauth-request-hints.ts +149 -0
  690. package/src/runtime/routes/plugins-routes.ts +6 -0
  691. package/src/runtime/routes/roadmap-routes.ts +47 -8
  692. package/src/runtime/routes/schedule-routes.ts +2 -0
  693. package/src/runtime/routes/secret-routes.ts +99 -119
  694. package/src/runtime/routes/settings-routes.ts +10 -4
  695. package/src/runtime/routes/watcher-routes.ts +1 -3
  696. package/src/runtime/trust-class.test.ts +7 -6
  697. package/src/runtime/trust-class.ts +9 -17
  698. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  699. package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
  700. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
  701. package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
  702. package/src/schedule/run-script.ts +2 -2
  703. package/src/schedule/scheduler.ts +47 -11
  704. package/src/schedule/tool-surface-readiness.ts +65 -0
  705. package/src/schedule/worker-control.ts +15 -5
  706. package/src/schedule/worker-mcp.ts +85 -0
  707. package/src/schedule/worker.ts +9 -31
  708. package/src/security/secure-keys.ts +74 -112
  709. package/src/skills/clawhub.ts +3 -8
  710. package/src/skills/managed-store.ts +1 -5
  711. package/src/stt/types.ts +4 -0
  712. package/src/subagent/notify.ts +54 -34
  713. package/src/subagent/parent-notification.ts +6 -0
  714. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  715. package/src/telemetry/phone-call-funnel.ts +144 -0
  716. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  717. package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
  718. package/src/tools/ask-question/ask-question-tool.ts +120 -22
  719. package/src/tools/browser/browser-execution.ts +29 -60
  720. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  721. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  722. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  723. package/src/tools/client-os.ts +15 -0
  724. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  725. package/src/tools/computer-use/target.ts +42 -0
  726. package/src/tools/document/document-tool.ts +13 -18
  727. package/src/tools/execution-target.ts +14 -16
  728. package/src/tools/host-terminal/host-shell.ts +16 -7
  729. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  730. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  731. package/src/tools/network/web-fetch.ts +274 -7
  732. package/src/tools/network/web-search.ts +468 -6
  733. package/src/tools/permission-checker.ts +3 -3
  734. package/src/tools/policy-context.ts +3 -1
  735. package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
  736. package/src/tools/shared/shell-output.test.ts +10 -0
  737. package/src/tools/shared/shell-output.ts +14 -2
  738. package/src/tools/skills/load.ts +2 -1
  739. package/src/tools/skills/sandbox-runner.ts +24 -4
  740. package/src/tools/skills/scaffold-managed.ts +2 -1
  741. package/src/tools/skills/skill-script-runner.ts +7 -0
  742. package/src/tools/skills/skill-tool-factory.ts +15 -1
  743. package/src/tools/terminal/__tests__/safe-env.test.ts +44 -4
  744. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
  745. package/src/tools/terminal/safe-env.ts +39 -24
  746. package/src/tools/terminal/sanitized-bash.ts +15 -2
  747. package/src/tools/terminal/shell-launch.test.ts +162 -0
  748. package/src/tools/terminal/shell.test.ts +29 -0
  749. package/src/tools/terminal/shell.ts +15 -7
  750. package/src/tools/tool-approval-handler.ts +5 -1
  751. package/src/tools/tool-types.ts +3 -3
  752. package/src/tools/types.ts +8 -2
  753. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  754. package/src/util/abort-reasons.ts +18 -26
  755. package/src/util/browser-human-verification.ts +14 -0
  756. package/src/util/canonicalize-identity.test.ts +21 -0
  757. package/src/util/canonicalize-identity.ts +16 -0
  758. package/src/util/errors.ts +13 -3
  759. package/src/util/host-process.test.ts +17 -1
  760. package/src/util/host-process.ts +24 -0
  761. package/src/util/provider-error-patterns.ts +3 -0
  762. package/src/util/unicode.ts +29 -0
  763. package/src/util/worker-process.ts +77 -35
  764. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  765. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  766. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  767. package/src/workspace/migrations/registry.ts +2 -0
  768. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  769. package/src/api/events/heartbeat-alert.ts +0 -20
  770. package/src/daemon/message-types/web-activity.ts +0 -65
  771. package/src/desktop/desktop-dependencies.test.ts +0 -131
  772. package/src/tools/computer-use/definitions.ts +0 -607
@@ -33,9 +33,11 @@
33
33
  * - {@link assistantEventHub} — the assistant's pub/sub hub for runtime events
34
34
  * - {@link getModelProfiles} — list the workspace inference profiles a plugin
35
35
  * can route to (e.g. a model router building its category → profile map)
36
- * - {@link getConfiguredProvider} — resolve a {@link Provider} for a call site
36
+ * - {@link getConfiguredProvider}: resolve a {@link Provider} for a call site
37
37
  * (optionally overriding the profile) and run inference through the
38
- * workspace's configured profiles and credentials — no plugin-supplied API key
38
+ * workspace's configured profiles and credentials, with no plugin-supplied API key
39
+ * - {@link getEffectiveContextWindow}: resolve that call site's provider,
40
+ * model, and effective maximum input size
39
41
  *
40
42
  * - {@link InitContext} — passed to `init` hook at bootstrap
41
43
  * - {@link ShutdownContext} — passed to `shutdown` hook at teardown
@@ -169,10 +171,12 @@ export { publishEvent } from "./publish-event.js";
169
171
  // `inputModalities.image` override winning when set (mix profiles are
170
172
  // vision-capable if any arm is). Returns false when nothing resolves.
171
173
  export { doesSupportVision } from "./vision-support.js";
172
- // Resolve a stored credential to its plaintext value — the same value
173
- // `assistant credentials reveal` prints — from a UUID or a "service/field"
174
+ // Resolve a stored credential to its plaintext value (the same value
175
+ // `assistant credentials reveal` prints) from a UUID or a "service/field"
174
176
  // reference. When a plugin is in context, resolution is scoped to credentials
175
- // whose service matches the plugin's manifest name; outside any plugin it is
177
+ // whose service matches the plugin's runtime name. A plugin-resident skill
178
+ // script or skill-tool child presents a daemon-issued invocation grant and is
179
+ // scoped the same way. Outside any plugin context or grant the resolver is
176
180
  // unscoped. Throws CredentialResolutionError when the ref does not resolve, the
177
181
  // store is unreachable, or the credential is out of the plugin's scope.
178
182
  export {
@@ -218,6 +222,11 @@ export { resolveOauthCallbackUrl } from "../inbound/oauth-callback-url.js";
218
222
  // float the chosen profile above the call-site layers when the plugin must
219
223
  // run on a specific profile regardless of workspace tuning.
220
224
  export { getConfiguredProvider } from "../providers/provider-send-message.js";
225
+ export type {
226
+ EffectiveContextWindowInfo,
227
+ EffectiveContextWindowOptions,
228
+ } from "./effective-context-window.js";
229
+ export { getEffectiveContextWindow } from "./effective-context-window.js";
221
230
  // Resolve an image/file block's media `source` to its bytes as inline base64,
222
231
  // whether the source is inline base64 or a persisted workspace reference
223
232
  // (attachment-store row or a file on disk). Returns null when a reference can no
@@ -286,6 +295,11 @@ export {
286
295
  // writes files under the workspace (e.g. its own `plugins/<name>/data/`
287
296
  // directory) resolves them against this instead of hardcoding a base path.
288
297
  export { getWorkspaceDir } from "../util/platform.js";
298
+ // `String.prototype.slice` that never cuts a UTF-16 surrogate pair in half.
299
+ // Any text a plugin truncates by character budget and hands to a model must
300
+ // go through this: an orphaned half is invalid UTF-16 that strict provider
301
+ // parsers reject.
302
+ export { safeStringSlice } from "../util/unicode.js";
289
303
  // Declarative help for the top-level `assistant` CLI commands that have adopted
290
304
  // the static-help split. Plugins (e.g. the memory capability indexer) read this
291
305
  // to embed CLI command capabilities without importing the CLI action graph.
@@ -359,7 +373,8 @@ export {
359
373
  stringifyMessageContent,
360
374
  } from "../persistence/message-content.js";
361
375
  // Conversation history — reads and writes on the host conversation store
362
- // (rows, message history, processing state, disk-view paths) plus the lexical
376
+ // (rows, message history, processing state, the recorded wire tool surface,
377
+ // disk-view paths) plus the lexical
363
378
  // message-search surface. Every operation takes explicit parameters; nothing
364
379
  // is resolved from config. Async because the facade loads the DB store graph
365
380
  // lazily on first call.
@@ -371,7 +386,9 @@ export {
371
386
  getConversation,
372
387
  getConversationDirPath,
373
388
  getConversationProcessingStartedAt,
389
+ getConversationToolSurface,
374
390
  getMessages,
391
+ getRecordedConversationToolSurface,
375
392
  hasLexicalTokens,
376
393
  isConversationProcessing,
377
394
  listConversations,
@@ -380,6 +397,7 @@ export {
380
397
  syncMessageToDisk,
381
398
  updateMessageMetadata,
382
399
  } from "../persistence/conversation-plugin-facade.js";
400
+ export type { ConversationToolSurface } from "../persistence/conversation-tool-surface.js";
383
401
  // System cards: a transcript notice authored by the daemon rather than the
384
402
  // assistant persona, for telling the user something a turn did to their input
385
403
  // that the model's reply cannot explain (e.g. an attachment that could not be
@@ -392,6 +410,16 @@ export { persistSystemCard } from "./system-card.js";
392
410
  // what makes that true. Host tools and plugin tools share this one guard.
393
411
  export type { CancellableToolContext } from "./tool-cancellation.js";
394
412
  export { throwIfCancelled } from "./tool-cancellation.js";
413
+ // Tool input from a Zod schema: derive the advertised `input_schema` from the
414
+ // schema the tool parses its input with, so what the model is told and what
415
+ // the tool accepts share one source. The host validates built-in tools'
416
+ // input centrally; a plugin tool parses its own, and answers a failed parse
417
+ // with `invalidToolInputResult` so its message reads the same as the host's.
418
+ export {
419
+ invalidToolInputResult,
420
+ nullAsOmitted,
421
+ toToolInputSchema,
422
+ } from "../tools/shared/zod-tool-schema.js";
395
423
  // Synthesize text to speech through the assistant's globally configured TTS
396
424
  // provider (ElevenLabs, Fish Audio, etc.). Plugins that need voice output —
397
425
  // e.g. a meeting bot speaking into a live call — use this instead of managing
@@ -438,6 +466,7 @@ export type {
438
466
  RunConversationTurnResult,
439
467
  } from "./conversation-turn.js";
440
468
  export { runConversationTurn } from "./conversation-turn.js";
469
+ export { PluginTurnNotAdmittedError } from "./plugin-channel-turn-trust.js";
441
470
  // Live voice — drive a single client's real-time voice session (STT → agent
442
471
  // turn → TTS, with server-VAD turn-taking, pauses, and barge-in) over a
443
472
  // transport the plugin owns. The plugin brings only a `send` callback (e.g.
@@ -0,0 +1,133 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ type InboundTrustReadResult =
4
+ | {
5
+ ok: true;
6
+ verdict: {
7
+ trustClass: string;
8
+ canonicalSenderId: string | null;
9
+ contactId?: string;
10
+ status?: string;
11
+ resolutionFailed?: boolean;
12
+ };
13
+ admissionPolicy: string | null;
14
+ }
15
+ | { ok: false };
16
+
17
+ let nextRead: InboundTrustReadResult = { ok: false };
18
+
19
+ mock.module("../calls/inbound-trust-reader.js", () => ({
20
+ readInboundTrust: async () => nextRead,
21
+ }));
22
+
23
+ import {
24
+ PluginTurnNotAdmittedError,
25
+ resolvePluginChannelTurnTrust,
26
+ } from "./plugin-channel-turn-trust.js";
27
+
28
+ const CHANNEL = {
29
+ sourceChannel: "plugin" as const,
30
+ externalChatId: "imessage:+12025550142",
31
+ externalUserId: "imessage:+12025550142",
32
+ displayName: "Ada",
33
+ };
34
+
35
+ beforeEach(() => {
36
+ nextRead = { ok: false };
37
+ });
38
+
39
+ describe("resolvePluginChannelTurnTrust", () => {
40
+ test("returns the gateway verdict as the turn trust context", async () => {
41
+ nextRead = {
42
+ ok: true,
43
+ verdict: {
44
+ trustClass: "trusted_contact",
45
+ canonicalSenderId: "imessage:+12025550142",
46
+ contactId: "c-ada",
47
+ status: "active",
48
+ },
49
+ admissionPolicy: "trusted_contacts",
50
+ };
51
+
52
+ const trust = await resolvePluginChannelTurnTrust(CHANNEL);
53
+ expect(trust.trustClass).toBe("trusted_contact");
54
+ expect(trust.sourceChannel).toBe("plugin");
55
+ expect(trust.requesterChatId).toBe(CHANNEL.externalChatId);
56
+ });
57
+
58
+ test("fails closed when the gateway could not vouch for the sender", async () => {
59
+ nextRead = {
60
+ ok: true,
61
+ verdict: {
62
+ trustClass: "unknown",
63
+ canonicalSenderId: null,
64
+ resolutionFailed: true,
65
+ },
66
+ admissionPolicy: "strangers",
67
+ };
68
+
69
+ await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toMatchObject({
70
+ name: "PluginTurnNotAdmittedError",
71
+ reason: "trust_resolution_failed",
72
+ });
73
+ });
74
+
75
+ test("fails closed when the gateway trust read fails", async () => {
76
+ nextRead = { ok: false };
77
+ await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toMatchObject({
78
+ name: "PluginTurnNotAdmittedError",
79
+ reason: "trust_resolution_failed",
80
+ });
81
+ });
82
+
83
+ test("rejects a sender below the channel admission floor", async () => {
84
+ nextRead = {
85
+ ok: true,
86
+ verdict: { trustClass: "unknown", canonicalSenderId: null },
87
+ admissionPolicy: "guardian_only",
88
+ };
89
+
90
+ await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toEqual(
91
+ expect.objectContaining({
92
+ name: "PluginTurnNotAdmittedError",
93
+ reason: "admission_policy_guardian_only",
94
+ }),
95
+ );
96
+ });
97
+
98
+ test("rejects a blocked member regardless of floor", async () => {
99
+ nextRead = {
100
+ ok: true,
101
+ verdict: {
102
+ trustClass: "trusted_contact",
103
+ canonicalSenderId: "imessage:+12025550142",
104
+ contactId: "c-ada",
105
+ status: "blocked",
106
+ },
107
+ admissionPolicy: "strangers",
108
+ };
109
+
110
+ await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toMatchObject({
111
+ name: "PluginTurnNotAdmittedError",
112
+ reason: "member_blocked",
113
+ });
114
+ });
115
+
116
+ test("admits when the gateway reports no admission policy", async () => {
117
+ nextRead = {
118
+ ok: true,
119
+ verdict: { trustClass: "unknown", canonicalSenderId: null },
120
+ admissionPolicy: null,
121
+ };
122
+
123
+ const trust = await resolvePluginChannelTurnTrust(CHANNEL);
124
+ expect(trust.trustClass).toBe("unknown");
125
+ });
126
+
127
+ test("PluginTurnNotAdmittedError names the deny reason", () => {
128
+ const err = new PluginTurnNotAdmittedError("admission_policy_no_one");
129
+ expect(err).toBeInstanceOf(Error);
130
+ expect(err.reason).toBe("admission_policy_no_one");
131
+ expect(err.message).toContain("admission_policy_no_one");
132
+ });
133
+ });
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Gateway admission and trust for plugin turns addressed by a channel chat.
3
+ *
4
+ * A channel address means an inbound sender, not an internal plugin job.
5
+ * Trust comes from the gateway verdict (`resolve_inbound_trust`); the turn
6
+ * runs only when that sender clears the channel admission floor.
7
+ */
8
+
9
+ import { meetsAdmissionFloor } from "@vellumai/gateway-client";
10
+
11
+ import { readInboundTrust } from "../calls/inbound-trust-reader.js";
12
+ import type { ChannelId } from "../channels/types.js";
13
+ import type { TrustContext } from "../daemon/trust-context-types.js";
14
+ import { trustContextFromVerdict } from "../runtime/trust-verdict-consumer.js";
15
+
16
+ interface PluginChannelTurnAddress {
17
+ sourceChannel: ChannelId;
18
+ externalChatId: string;
19
+ externalUserId?: string | null;
20
+ displayName?: string | null;
21
+ username?: string | null;
22
+ }
23
+
24
+ export class PluginTurnNotAdmittedError extends Error {
25
+ readonly reason: string;
26
+
27
+ constructor(reason: string) {
28
+ super(`This inbound plugin turn was not admitted (${reason}).`);
29
+ this.name = "PluginTurnNotAdmittedError";
30
+ this.reason = reason;
31
+ }
32
+ }
33
+
34
+ export async function resolvePluginChannelTurnTrust(
35
+ channel: PluginChannelTurnAddress,
36
+ ): Promise<TrustContext> {
37
+ const actorExternalId = channel.externalUserId?.trim() || undefined;
38
+ const read = await readInboundTrust({
39
+ channelType: channel.sourceChannel,
40
+ actorExternalId,
41
+ });
42
+ if (!read.ok) {
43
+ throw new PluginTurnNotAdmittedError("trust_resolution_failed");
44
+ }
45
+
46
+ if (read.verdict.resolutionFailed) {
47
+ throw new PluginTurnNotAdmittedError("trust_resolution_failed");
48
+ }
49
+
50
+ const memberStatus = read.verdict.status;
51
+ if (memberStatus === "blocked" || memberStatus === "revoked") {
52
+ throw new PluginTurnNotAdmittedError(`member_${memberStatus}`);
53
+ }
54
+
55
+ const trustClass = read.verdict.trustClass;
56
+ if (
57
+ read.admissionPolicy != null &&
58
+ !meetsAdmissionFloor(read.admissionPolicy, trustClass)
59
+ ) {
60
+ throw new PluginTurnNotAdmittedError(
61
+ `admission_policy_${read.admissionPolicy}`,
62
+ );
63
+ }
64
+
65
+ return trustContextFromVerdict(read.verdict, {
66
+ sourceChannel: channel.sourceChannel,
67
+ conversationExternalId: channel.externalChatId,
68
+ actorDisplayName: channel.displayName ?? undefined,
69
+ actorUsername: channel.username ?? undefined,
70
+ });
71
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * How a child process learns which plugin it is running as.
3
+ *
4
+ * In-process plugin hooks, tools, and routes use AsyncLocalStorage
5
+ * ({@link getCurrentPluginName}). A bash or skill-sandbox child does not
6
+ * inherit that store. Those children recover the install-directory basename
7
+ * from `VELLUM_PLUGIN_NAME` (injected after env sanitization) or from the
8
+ * entry script path under `plugins/<service>/skills/<skill>/{scripts,tools}/`.
9
+ */
10
+
11
+ import { isAbsolute, relative, resolve, sep } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ import { getCurrentPluginName } from "../plugins/plugin-execution-context.js";
15
+ import { getWorkspacePluginsDir } from "../util/platform.js";
16
+
17
+ export const PLUGIN_NAME_ENV = "VELLUM_PLUGIN_NAME";
18
+
19
+ const SKILL_SCRIPT_ROOTS = new Set(["scripts", "tools"]);
20
+
21
+ /**
22
+ * Read a plugin install-directory name from the process environment.
23
+ * Empty or whitespace-only values are ignored.
24
+ */
25
+ export function readPluginNameFromEnv(
26
+ env: NodeJS.ProcessEnv = process.env,
27
+ ): string | undefined {
28
+ const raw = env[PLUGIN_NAME_ENV];
29
+ if (typeof raw !== "string") {
30
+ return undefined;
31
+ }
32
+ const trimmed = raw.trim();
33
+ return trimmed.length > 0 ? trimmed : undefined;
34
+ }
35
+
36
+ /**
37
+ * If `filePath` is a skill script or tool under an installed plugin, return
38
+ * that plugin's install-directory basename (the runtime service name).
39
+ *
40
+ * Expected layout:
41
+ * `plugins/<service>/skills/<skill-id>/scripts|tools/<file>`.
42
+ */
43
+ export function derivePluginNameFromSkillScriptPath(
44
+ filePath: string,
45
+ pluginsDir: string = getWorkspacePluginsDir(),
46
+ ): string | undefined {
47
+ if (filePath.length === 0) {
48
+ return undefined;
49
+ }
50
+ let resolved = filePath;
51
+ if (filePath.startsWith("file:")) {
52
+ try {
53
+ resolved = fileURLToPath(filePath);
54
+ } catch {
55
+ return undefined;
56
+ }
57
+ }
58
+ if (!isAbsolute(resolved)) {
59
+ resolved = resolve(process.cwd(), resolved);
60
+ }
61
+ const pluginsRoot = resolve(pluginsDir);
62
+ const rel = relative(pluginsRoot, resolved);
63
+ if (rel.length === 0 || rel.startsWith("..") || isAbsolute(rel)) {
64
+ return undefined;
65
+ }
66
+ const parts = rel.split(sep).filter((part) => part.length > 0);
67
+ if (parts.length < 5) {
68
+ return undefined;
69
+ }
70
+ const [service, skillsSeg, skillId, root] = parts;
71
+ if (
72
+ service === undefined ||
73
+ skillsSeg !== "skills" ||
74
+ skillId === undefined ||
75
+ root === undefined ||
76
+ !SKILL_SCRIPT_ROOTS.has(root)
77
+ ) {
78
+ return undefined;
79
+ }
80
+ return service;
81
+ }
82
+
83
+ /**
84
+ * Scan argv for a plugin-resident skill script path, resolving relative
85
+ * entries against `cwd`.
86
+ */
87
+ export function derivePluginNameFromProcess(
88
+ argv: readonly string[] = process.argv,
89
+ cwd: string = process.cwd(),
90
+ pluginsDir: string = getWorkspacePluginsDir(),
91
+ ): string | undefined {
92
+ for (const candidate of argv.slice(1)) {
93
+ if (typeof candidate !== "string" || candidate.length === 0) {
94
+ continue;
95
+ }
96
+ if (candidate.startsWith("-")) {
97
+ continue;
98
+ }
99
+ const absolute = isAbsolute(candidate)
100
+ ? candidate
101
+ : resolve(cwd, candidate);
102
+ const name = derivePluginNameFromSkillScriptPath(absolute, pluginsDir);
103
+ if (name !== undefined) {
104
+ return name;
105
+ }
106
+ }
107
+ return undefined;
108
+ }
109
+
110
+ /**
111
+ * Plugin identity for credential scoping: in-process AsyncLocalStorage,
112
+ * then the injected env var, then the process entry script path.
113
+ */
114
+ export function resolveCallingPluginName(
115
+ env: NodeJS.ProcessEnv = process.env,
116
+ argv: readonly string[] = process.argv,
117
+ cwd: string = process.cwd(),
118
+ pluginsDir: string = getWorkspacePluginsDir(),
119
+ ): string | undefined {
120
+ return (
121
+ getCurrentPluginName() ??
122
+ readPluginNameFromEnv(env) ??
123
+ derivePluginNameFromProcess(argv, cwd, pluginsDir)
124
+ );
125
+ }
@@ -1,28 +1,42 @@
1
1
  /**
2
2
  * Plugin-facing credential resolution.
3
3
  *
4
- * {@link resolveCredential} returns a stored credential's plaintext value — the
5
- * same value `assistant credentials reveal` prints — resolving a reference that
6
- * is either a credential UUID or a `"service/field"` string, exactly as the
7
- * reveal path does (see {@link ../tools/credentials/resolve.resolveCredentialRef}
8
- * and the `credentials/reveal` route).
4
+ * {@link resolveCredential} returns a stored credential's plaintext value
5
+ * (the same value `assistant credentials reveal` prints), resolving a
6
+ * reference that is either a credential UUID or a `"service/field"` string,
7
+ * exactly as the reveal path does (see
8
+ * {@link ../tools/credentials/resolve.resolveCredentialRef} and the
9
+ * `credentials/reveal` route).
9
10
  *
10
11
  * ## Plugin scoping
11
12
  *
12
- * When a plugin is in context (its hook, tool, or one of its own
13
- * `/x/plugins/<name>/` routes is executing, tracked by
14
- * {@link ../plugins/plugin-execution-context.getCurrentPluginName}), resolution
15
- * is restricted: the plugin may only resolve credentials whose `service`
16
- * equals its manifest name (`imessage/api_key` for plugin `imessage`). It
17
- * cannot read another service (`openai/api_key`, `openai/imessage`). Outside
18
- * any plugin context (host-internal callers, CLI, tests) the resolver is
19
- * unscoped and behaves like a direct reveal.
13
+ * When a plugin is in context, resolution is restricted to credentials
14
+ * whose `service` equals the plugin's runtime install-directory name
15
+ * (`sms/account_sid` for plugin `sms`). Context is:
16
+ *
17
+ * 1. In-process AsyncLocalStorage from `runInPluginContext` (hooks, plugin
18
+ * tools, plugin routes).
19
+ * 2. `VELLUM_PLUGIN_NAME` on a bash or skill-sandbox child.
20
+ * 3. The process entry path, when it sits under
21
+ * `plugins/<service>/skills/<skill>/{scripts,tools}/`.
22
+ *
23
+ * Outside any plugin context the resolver is unscoped and behaves like a
24
+ * direct reveal. A standalone child has an empty in-process metadata
25
+ * cache; when plugin context is set, a cache miss consults the live
26
+ * credential catalog so an empty cache is not reported as "not found".
20
27
  */
21
28
 
22
- import { getCurrentPluginName } from "../plugins/plugin-execution-context.js";
29
+ import { credentialKey } from "@vellumai/credential-storage";
30
+
23
31
  import { getSecureKeyResultAsync } from "../security/secure-keys.js";
32
+ import {
33
+ type CredentialMetadata,
34
+ listCredentialRecordsLive,
35
+ } from "../tools/credentials/metadata-store.js";
36
+ import { parseServiceFieldRef } from "../tools/credentials/ref-parse.js";
24
37
  import { resolveCredentialRef } from "../tools/credentials/resolve.js";
25
38
  import { credentialInPluginScope } from "./credential-scope.js";
39
+ import { resolveCallingPluginName } from "./plugin-name-env.js";
26
40
 
27
41
  /**
28
42
  * Raised when a credential cannot be resolved: the reference does not match a
@@ -36,6 +50,50 @@ export class CredentialResolutionError extends Error {
36
50
  }
37
51
  }
38
52
 
53
+ interface ResolvedRef {
54
+ service: string;
55
+ field: string;
56
+ storageKey: string;
57
+ }
58
+
59
+ function findLiveRecord(
60
+ records: CredentialMetadata[],
61
+ ref: string,
62
+ ): CredentialMetadata | undefined {
63
+ const byId = records.find((record) => record.credentialId === ref);
64
+ if (byId) {
65
+ return byId;
66
+ }
67
+ const parsed = parseServiceFieldRef(ref);
68
+ if (!parsed) {
69
+ return undefined;
70
+ }
71
+ return records.find(
72
+ (record) =>
73
+ record.service === parsed.service && record.field === parsed.field,
74
+ );
75
+ }
76
+
77
+ async function resolveCredentialRefLive(
78
+ ref: string,
79
+ ): Promise<ResolvedRef | undefined> {
80
+ const live = await listCredentialRecordsLive();
81
+ if (live.unreachable) {
82
+ throw new CredentialResolutionError(
83
+ "Credential store is unreachable.",
84
+ );
85
+ }
86
+ const record = findLiveRecord(live.records, ref);
87
+ if (!record) {
88
+ return undefined;
89
+ }
90
+ return {
91
+ service: record.service,
92
+ field: record.field,
93
+ storageKey: credentialKey(record.service, record.field),
94
+ };
95
+ }
96
+
39
97
  /**
40
98
  * Resolve a credential reference to its plaintext value.
41
99
  *
@@ -45,15 +103,16 @@ export class CredentialResolutionError extends Error {
45
103
  * store is unreachable, or a plugin in context is not scoped to the credential.
46
104
  */
47
105
  export async function resolveCredential(ref: string): Promise<string> {
48
- const resolved = resolveCredentialRef(ref);
106
+ const pluginName = resolveCallingPluginName();
107
+
108
+ let resolved: ResolvedRef | undefined = resolveCredentialRef(ref);
109
+ if (!resolved && pluginName !== undefined) {
110
+ resolved = await resolveCredentialRefLive(ref);
111
+ }
49
112
  if (!resolved) {
50
113
  throw new CredentialResolutionError(`Credential not found: ${ref}`);
51
114
  }
52
115
 
53
- // Scope the resolution to the plugin in context, if any. The ownership gate
54
- // is enforced before the plaintext is read so an out-of-scope plugin never
55
- // touches the secure backend.
56
- const pluginName = getCurrentPluginName();
57
116
  if (
58
117
  pluginName !== undefined &&
59
118
  !credentialInPluginScope(pluginName, resolved.service)
@@ -70,7 +129,7 @@ export async function resolveCredential(ref: string): Promise<string> {
70
129
  if (value == null || value.length === 0) {
71
130
  if (unreachable) {
72
131
  throw new CredentialResolutionError(
73
- "Credential store is unreachable — ensure the assistant is running",
132
+ "Credential store is unreachable.",
74
133
  );
75
134
  }
76
135
  throw new CredentialResolutionError(`Credential not found: ${ref}`);
@@ -397,3 +397,25 @@ describe("doesSupportVision with a bare string", () => {
397
397
  expect(doesSupportVision("qwen2.5-vl")).toBe(true);
398
398
  });
399
399
  });
400
+
401
+ describe("doesSupportVision with a resolved target", () => {
402
+ test("profile policy can enable images for a catalog text model", () => {
403
+ expect(
404
+ doesSupportVision({
405
+ provider: "fireworks",
406
+ model: "accounts/fireworks/models/glm-5p2",
407
+ inputModalities: { image: { enabled: true, supported: true } },
408
+ }),
409
+ ).toBe(true);
410
+ });
411
+
412
+ test("profile policy can disable images for a catalog vision model", () => {
413
+ expect(
414
+ doesSupportVision({
415
+ provider: "anthropic",
416
+ model: "claude-opus-4-6",
417
+ inputModalities: { image: { enabled: false } },
418
+ }),
419
+ ).toBe(false);
420
+ });
421
+ });
@@ -37,15 +37,24 @@ import {
37
37
  } from "../providers/model-catalog.js";
38
38
  import type { ModelProfileInfo } from "./types.js";
39
39
 
40
+ /** A fully resolved provider target plus the winning profile's policy. */
41
+ export interface ResolvedVisionTarget {
42
+ readonly provider?: string;
43
+ readonly model: string;
44
+ readonly inputModalities?: InputModalities | null;
45
+ }
46
+
40
47
  /**
41
48
  * Whether the given model or profile can process image input.
42
49
  *
43
- * `modelOrProfile` may be a concrete model id, a profile key, or a
44
- * {@link ModelProfileInfo}. A bare string is resolved as a model id first and,
45
- * failing that, as a profile key. Returns `false` when nothing resolves.
50
+ * `modelOrProfile` may be a concrete model id, a profile key, a
51
+ * {@link ModelProfileInfo}, or a fully resolved target. A resolved target
52
+ * combines the final provider/model with the winning profile's modality
53
+ * policy. A bare string is resolved as a model id first and, failing that, as
54
+ * a profile key. Returns `false` when nothing resolves.
46
55
  */
47
56
  export function doesSupportVision(
48
- modelOrProfile: ModelProfileInfo | string,
57
+ modelOrProfile: ModelProfileInfo | ResolvedVisionTarget | string,
49
58
  ): boolean {
50
59
  if (typeof modelOrProfile === "string") {
51
60
  // Concrete catalog model id first, then a profile key, then any profile
@@ -58,7 +67,10 @@ export function doesSupportVision(
58
67
  false
59
68
  );
60
69
  }
61
- return profileVision(modelOrProfile.key) ?? false;
70
+ if ("key" in modelOrProfile) {
71
+ return profileVision(modelOrProfile.key) ?? false;
72
+ }
73
+ return resolveEntryVision(modelOrProfile) ?? false;
62
74
  }
63
75
 
64
76
  /**