@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2

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 (596) hide show
  1. package/AGENTS.md +9 -3
  2. package/ARCHITECTURE.md +32 -10
  3. package/docs/architecture/memory.md +43 -5
  4. package/docs/architecture/security.md +96 -152
  5. package/docs/architecture/turn-actor.md +70 -0
  6. package/docs/browser-use-architecture-phase2.md +128 -56
  7. package/docs/flux-turn-detection-spike.md +248 -0
  8. package/docs/guardian-request-flow.md +35 -0
  9. package/docs/stt-provider-onboarding.md +3 -1
  10. package/knip.json +3 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  19. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
  24. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  25. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  26. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  27. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  28. package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  29. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  30. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  31. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  32. package/openapi.yaml +289 -113
  33. package/package.json +1 -1
  34. package/scripts/voice-ttft-spike.ts +3 -3
  35. package/scripts/write-plugin-api-shim.ts +10 -0
  36. package/src/__tests__/app-compiler.test.ts +38 -3
  37. package/src/__tests__/app-control-flow.test.ts +1 -0
  38. package/src/__tests__/approval-routes-http.test.ts +2 -2
  39. package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
  40. package/src/__tests__/attachments-store.test.ts +21 -12
  41. package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
  42. package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
  43. package/src/__tests__/call-site-routing-provider.test.ts +1 -1
  44. package/src/__tests__/channel-availability-routes.test.ts +14 -1
  45. package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
  46. package/src/__tests__/channel-delivery-store.test.ts +14 -14
  47. package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
  48. package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
  49. package/src/__tests__/checker.test.ts +20 -314
  50. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  51. package/src/__tests__/compaction-events.test.ts +8 -10
  52. package/src/__tests__/config-loader-backfill.test.ts +3 -3
  53. package/src/__tests__/config-schema.test.ts +25 -10
  54. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  55. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
  56. package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
  57. package/src/__tests__/conversation-agent-loop.test.ts +32 -21
  58. package/src/__tests__/conversation-attachments.test.ts +0 -1
  59. package/src/__tests__/conversation-attention-store.test.ts +63 -0
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
  61. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -0
  63. package/src/__tests__/conversation-fork-referential.test.ts +67 -0
  64. package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
  65. package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
  66. package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
  67. package/src/__tests__/conversation-queue.test.ts +154 -4
  68. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  69. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
  71. package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
  75. package/src/__tests__/conversation-slash-queue.test.ts +3 -0
  76. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  77. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
  78. package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
  79. package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
  80. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
  81. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
  82. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
  83. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
  85. package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
  86. package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
  87. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
  88. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  89. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  90. package/src/__tests__/credential-prompt-route.test.ts +7 -10
  91. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  92. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  93. package/src/__tests__/custom-profile-ensure.test.ts +5 -1
  94. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  95. package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
  96. package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
  97. package/src/__tests__/document-append-idempotency.test.ts +233 -0
  98. package/src/__tests__/document-sync-tags.test.ts +0 -75
  99. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  100. package/src/__tests__/edit-propagation.test.ts +107 -11
  101. package/src/__tests__/file-ops-service.test.ts +163 -30
  102. package/src/__tests__/filesystem-tools.test.ts +23 -24
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -5
  104. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  105. package/src/__tests__/helpers/mock-actor-context.ts +49 -0
  106. package/src/__tests__/helpers/mock-conversation.ts +13 -1
  107. package/src/__tests__/host-file-read-tool.test.ts +16 -19
  108. package/src/__tests__/http-user-message-parity.test.ts +1 -1
  109. package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
  110. package/src/__tests__/injector-chain.test.ts +63 -41
  111. package/src/__tests__/injector-disk-pressure.test.ts +11 -23
  112. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  113. package/src/__tests__/llm-context-resolution.test.ts +73 -1
  114. package/src/__tests__/llm-schema.test.ts +5 -2
  115. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
  116. package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
  117. package/src/__tests__/media-generate-image.test.ts +131 -21
  118. package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
  119. package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
  120. package/src/__tests__/mtime-cache.test.ts +3 -1
  121. package/src/__tests__/non-member-access-request.test.ts +0 -20
  122. package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
  123. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  124. package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
  125. package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
  126. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  127. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  128. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  129. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  130. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
  131. package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
  132. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
  133. package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
  134. package/src/__tests__/proxy-approval-callback.test.ts +1 -0
  135. package/src/__tests__/qdrant-manager.test.ts +14 -1
  136. package/src/__tests__/reaction-persistence.test.ts +200 -7
  137. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  138. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  139. package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
  140. package/src/__tests__/run-due-schedules.test.ts +21 -0
  141. package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
  142. package/src/__tests__/schedule-routes.test.ts +23 -0
  143. package/src/__tests__/schedule-store.test.ts +17 -0
  144. package/src/__tests__/scoped-approval-grants.test.ts +11 -6
  145. package/src/__tests__/secret-ingress-channel.test.ts +0 -1
  146. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  147. package/src/__tests__/send-endpoint-busy.test.ts +3 -3
  148. package/src/__tests__/skills.test.ts +32 -0
  149. package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
  150. package/src/__tests__/starter-task-flow.test.ts +5 -4
  151. package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
  152. package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
  153. package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
  154. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  155. package/src/__tests__/subagent-tools.test.ts +81 -101
  156. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
  157. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  158. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  159. package/src/__tests__/tool-executor.test.ts +68 -39
  160. package/src/__tests__/turn-events-store.test.ts +43 -0
  161. package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
  162. package/src/__tests__/ui-shape-teaching.test.ts +33 -0
  163. package/src/__tests__/ui-visual-surface.test.ts +1 -1
  164. package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
  165. package/src/__tests__/ui-work-result-surface.test.ts +1 -1
  166. package/src/__tests__/user-plugin-loader.test.ts +3 -1
  167. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  168. package/src/__tests__/visible-app-context.test.ts +16 -9
  169. package/src/__tests__/voice-config-update.test.ts +40 -0
  170. package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
  171. package/src/__tests__/voice-session-bridge.test.ts +85 -29
  172. package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
  173. package/src/__tests__/worker-plugin-surface.test.ts +77 -0
  174. package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
  175. package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
  176. package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
  177. package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
  178. package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
  179. package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
  180. package/src/acp/__tests__/auth-required.test.ts +161 -0
  181. package/src/acp/acp-claude-oauth.ts +19 -2
  182. package/src/acp/agent-process.test.ts +100 -0
  183. package/src/acp/agent-process.ts +29 -26
  184. package/src/acp/auth-required.ts +102 -0
  185. package/src/acp/session-manager.test.ts +119 -0
  186. package/src/acp/session-manager.ts +76 -3
  187. package/src/api/events/acp-auth-required.ts +55 -0
  188. package/src/api/events/host-file.ts +2 -2
  189. package/src/api/index.ts +7 -0
  190. package/src/api/surfaces.ts +12 -3
  191. package/src/apps/app-store.ts +3 -0
  192. package/src/bundler/package-resolver.ts +2 -30
  193. package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
  194. package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
  195. package/src/calls/call-controller.ts +19 -3
  196. package/src/calls/call-setup-flow.ts +0 -1
  197. package/src/calls/media-stream-stt-session.ts +15 -0
  198. package/src/calls/voice-session-bridge.ts +115 -41
  199. package/src/calls/voice-triage-escalate.ts +105 -2
  200. package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
  201. package/src/channels/config.ts +13 -0
  202. package/src/channels/plugin-channel-declarations.ts +108 -0
  203. package/src/channels/types.ts +30 -0
  204. package/src/cli/AGENTS.md +5 -2
  205. package/src/cli/bundled-modules.ts +29 -0
  206. package/src/cli/commands/credentials.help.ts +2 -2
  207. package/src/cli/commands/db/repair.ts +4 -8
  208. package/src/cli/commands/domain.ts +6 -3
  209. package/src/cli/commands/email.ts +6 -3
  210. package/src/cli/commands/inference-providers.ts +1 -1
  211. package/src/cli/commands/keys.ts +8 -3
  212. package/src/cli/commands/mcp.help.ts +13 -4
  213. package/src/cli/commands/mcp.ts +9 -0
  214. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  215. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
  216. package/src/cli/commands/memory/index.help.ts +84 -28
  217. package/src/cli/commands/memory/index.ts +2 -0
  218. package/src/cli/commands/memory/memory-v2.ts +58 -54
  219. package/src/cli/commands/memory/memory-v3.ts +64 -0
  220. package/src/cli/commands/memory/memory-validate.ts +18 -0
  221. package/src/cli/commands/plugins.ts +85 -36
  222. package/src/cli/commands/schedules.ts +35 -1
  223. package/src/cli/commands/stt.help.ts +27 -2
  224. package/src/cli/commands/trust.ts +3 -14
  225. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
  226. package/src/cli/lib/bundled-marketplace.json +14 -1
  227. package/src/cli/lib/upgrade-plugin.ts +42 -0
  228. package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
  229. package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
  230. package/src/config/__tests__/default-provider.test.ts +6 -1
  231. package/src/config/__tests__/profile-materialization.test.ts +75 -19
  232. package/src/config/assistant-feature-flags.ts +36 -15
  233. package/src/config/balanced-model-experiment.ts +35 -0
  234. package/src/config/bundled-skills/acp/SKILL.md +6 -7
  235. package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
  236. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  237. package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
  238. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
  240. package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
  241. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  242. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
  243. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
  244. package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
  245. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
  246. package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
  247. package/src/config/bundled-skills/subagent/SKILL.md +17 -12
  248. package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
  249. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
  250. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
  251. package/src/config/call-site-defaults.ts +11 -5
  252. package/src/config/default-profile-catalog.ts +179 -16
  253. package/src/config/default-profile-names.ts +4 -1
  254. package/src/config/default-provider-resolution.ts +4 -0
  255. package/src/config/feature-flag-registry.json +12 -12
  256. package/src/config/llm-context-resolution.ts +11 -3
  257. package/src/config/llm-resolver.ts +28 -1
  258. package/src/config/profile-materialization.ts +70 -22
  259. package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
  260. package/src/config/schemas/call-site-catalog.ts +4 -4
  261. package/src/config/schemas/live-voice.ts +57 -23
  262. package/src/config/schemas/llm.ts +59 -32
  263. package/src/config/schemas/mcp.ts +23 -0
  264. package/src/config/schemas/plugin-updates.ts +6 -2
  265. package/src/config/schemas/stt.ts +1 -0
  266. package/src/config/skills.ts +9 -2
  267. package/src/context/outbound-sanitize.ts +96 -1
  268. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
  269. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
  270. package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
  271. package/src/daemon/conversation-agent-loop.ts +31 -19
  272. package/src/daemon/conversation-messaging.ts +5 -1
  273. package/src/daemon/conversation-notifiers.ts +20 -10
  274. package/src/daemon/conversation-process.ts +20 -6
  275. package/src/daemon/conversation-runtime-assembly.ts +12 -6
  276. package/src/daemon/conversation-store.ts +14 -4
  277. package/src/daemon/conversation-surfaces.ts +75 -26
  278. package/src/daemon/conversation-tool-setup.ts +3 -6
  279. package/src/daemon/conversation.ts +154 -51
  280. package/src/daemon/doordash-steps.ts +2 -2
  281. package/src/daemon/lifecycle.ts +14 -1
  282. package/src/daemon/mcp-reload-service.ts +36 -6
  283. package/src/daemon/process-message.ts +13 -26
  284. package/src/daemon/providers-setup.ts +6 -3
  285. package/src/daemon/trust-context-types.ts +29 -0
  286. package/src/daemon/trust-context.ts +12 -7
  287. package/src/daemon/wake-conversation-ops.ts +3 -2
  288. package/src/daemon/windows-compiled-entry.ts +4 -0
  289. package/src/documents/document-store.ts +143 -240
  290. package/src/hooks/hook-loader.ts +3 -3
  291. package/src/hooks/registry.ts +103 -45
  292. package/src/hooks/types.ts +5 -0
  293. package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
  294. package/src/inbound/oauth-callback-url.ts +61 -0
  295. package/src/ipc/gateway-client.test.ts +1 -1
  296. package/src/ipc/gateway-client.ts +14 -21
  297. package/src/ipc/gateway-flag-listener.ts +17 -3
  298. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
  299. package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
  300. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
  301. package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
  302. package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
  303. package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
  304. package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
  305. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
  306. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
  307. package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
  308. package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
  309. package/src/live-voice/live-voice-archive.ts +2 -0
  310. package/src/live-voice/live-voice-manager.ts +16 -3
  311. package/src/live-voice/live-voice-metrics.ts +57 -32
  312. package/src/live-voice/live-voice-photo.ts +1 -2
  313. package/src/live-voice/live-voice-session.ts +598 -323
  314. package/src/live-voice/progress-narration.ts +277 -0
  315. package/src/live-voice/protocol.ts +21 -1
  316. package/src/live-voice/windows-compiled-live-voice.ts +4 -0
  317. package/src/mcp/__tests__/effective-config.test.ts +238 -0
  318. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  319. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
  320. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
  321. package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
  322. package/src/mcp/client.ts +16 -11
  323. package/src/mcp/effective-config.ts +113 -0
  324. package/src/mcp/manager.ts +11 -6
  325. package/src/mcp/mcp-auth-orchestrator.ts +13 -22
  326. package/src/mcp/mcp-oauth-provider.ts +205 -240
  327. package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
  328. package/src/monitoring/control.ts +1 -0
  329. package/src/monitoring/db-integrity-sample.ts +4 -5
  330. package/src/monitoring/plugin-auto-update.ts +128 -24
  331. package/src/notifications/AGENTS.md +2 -0
  332. package/src/notifications/approval-card-data.ts +33 -0
  333. package/src/notifications/signal.ts +1 -0
  334. package/src/permissions/AGENTS.md +16 -0
  335. package/src/permissions/checker.test.ts +75 -122
  336. package/src/permissions/checker.ts +44 -560
  337. package/src/permissions/confirmation-guardian-request.test.ts +15 -11
  338. package/src/permissions/confirmation-guardian-request.ts +2 -2
  339. package/src/permissions/prompter.ts +1 -5
  340. package/src/permissions/question-guardian-request.test.ts +14 -6
  341. package/src/permissions/question-guardian-request.ts +1 -2
  342. package/src/persistence/attachments-store.ts +8 -1
  343. package/src/persistence/bookmark-crud.ts +3 -7
  344. package/src/persistence/conversation-attention-store.ts +16 -45
  345. package/src/persistence/conversation-crud.ts +33 -4
  346. package/src/persistence/conversation-lineage.ts +9 -0
  347. package/src/persistence/conversation-queries.ts +182 -52
  348. package/src/persistence/delivery-crud.ts +150 -36
  349. package/src/persistence/embeddings/qdrant-manager.ts +84 -49
  350. package/src/persistence/external-conversation-store.ts +32 -4
  351. package/src/persistence/llm-request-log-store.ts +4 -10
  352. package/src/persistence/llm-usage-store.ts +8 -3
  353. package/src/persistence/message-reads.test.ts +197 -0
  354. package/src/persistence/message-reads.ts +211 -0
  355. package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
  356. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
  357. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
  358. package/src/persistence/real-user-turn-filter.ts +27 -3
  359. package/src/persistence/schema/documents.ts +4 -4
  360. package/src/persistence/steps.ts +9 -0
  361. package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
  362. package/src/plugin-api/constants.ts +8 -0
  363. package/src/plugin-api/conversation-turn.ts +195 -5
  364. package/src/plugin-api/index.ts +38 -6
  365. package/src/plugin-api/resolve-credential.ts +3 -2
  366. package/src/plugin-api/store-credential.ts +146 -0
  367. package/src/plugin-api/vision-support.test.ts +1 -1
  368. package/src/plugin-api/webhook-url.ts +13 -11
  369. package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
  370. package/src/plugins/defaults/main.ts +21 -7
  371. package/src/plugins/defaults/memory/AGENTS.md +15 -3
  372. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
  373. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
  374. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
  375. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
  376. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  377. package/src/plugins/defaults/memory/buffer-format.ts +165 -0
  378. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
  379. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
  380. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
  381. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
  382. package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
  383. package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
  384. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
  385. package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
  386. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
  387. package/src/plugins/defaults/memory/indexer.ts +3 -1
  388. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
  389. package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
  390. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
  391. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  392. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
  393. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
  394. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  395. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  396. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  397. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  398. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  399. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  400. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
  401. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
  402. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  403. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  404. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  405. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  406. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  407. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  408. package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
  409. package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
  410. package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
  411. package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
  412. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
  413. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
  414. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  415. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  416. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  417. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  418. package/src/plugins/defaults/memory/v3/injector.ts +8 -0
  419. package/src/plugins/defaults/memory/v3/prune.ts +2 -0
  420. package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
  421. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
  422. package/src/plugins/defaults/memory/worker-control.ts +1 -0
  423. package/src/plugins/defaults/memory/worker.ts +6 -3
  424. package/src/plugins/defaults/worker-entrypoints.ts +3 -0
  425. package/src/plugins/external-plugin-loader.ts +47 -0
  426. package/src/plugins/mcp-servers.ts +361 -0
  427. package/src/plugins/mtime-cache.ts +37 -46
  428. package/src/plugins/pipeline.ts +14 -7
  429. package/src/plugins/plugin-execution-context.ts +35 -11
  430. package/src/plugins/worker-plugin-surface.ts +33 -0
  431. package/src/prompts/templates/system-sections.ts +0 -7
  432. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  433. package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
  434. package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
  435. package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
  436. package/src/providers/__tests__/retry-callsite.test.ts +25 -2
  437. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  438. package/src/providers/anthropic/client.ts +332 -241
  439. package/src/providers/call-site-routing.ts +30 -3
  440. package/src/providers/connection-resolution.ts +194 -11
  441. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
  442. package/src/providers/inference/adapter-factory.ts +3 -0
  443. package/src/providers/inference/auth.ts +6 -0
  444. package/src/providers/inference/connection-availability.ts +24 -2
  445. package/src/providers/inference/connections.ts +2 -0
  446. package/src/providers/model-catalog.ts +3 -3
  447. package/src/providers/model-intents.ts +28 -8
  448. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
  449. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  450. package/src/providers/openai/chat-completions-provider.ts +133 -36
  451. package/src/providers/openai/codex-models.ts +2 -1
  452. package/src/providers/provider-send-message.ts +32 -3
  453. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
  454. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
  455. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
  456. package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
  457. package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
  458. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
  459. package/src/providers/speech-to-text/provider-catalog.ts +99 -8
  460. package/src/providers/speech-to-text/resolve.ts +25 -2
  461. package/src/routes/control.ts +1 -0
  462. package/src/routes/route-host-client.ts +1 -0
  463. package/src/routes/route-host-protocol.ts +7 -0
  464. package/src/routes/worker.ts +48 -15
  465. package/src/runtime/AGENTS.md +16 -17
  466. package/src/runtime/access-request-helper.ts +9 -12
  467. package/src/runtime/agent-wake.ts +18 -15
  468. package/src/runtime/effective-capabilities.test.ts +43 -0
  469. package/src/runtime/effective-capabilities.ts +27 -0
  470. package/src/runtime/guardian-reply-router.ts +6 -2
  471. package/src/runtime/pre-first-message-gate.ts +4 -0
  472. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
  473. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
  474. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
  475. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
  476. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
  477. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
  478. package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
  479. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
  480. package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
  481. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  482. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  483. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
  484. package/src/runtime/routes/channel-availability-routes.ts +32 -14
  485. package/src/runtime/routes/channel-route-shared.ts +0 -6
  486. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
  487. package/src/runtime/routes/conversation-list-routes.ts +181 -23
  488. package/src/runtime/routes/conversation-management-routes.ts +17 -12
  489. package/src/runtime/routes/conversation-query-routes.ts +40 -27
  490. package/src/runtime/routes/conversation-routes.ts +43 -29
  491. package/src/runtime/routes/credential-prompt-routes.ts +4 -7
  492. package/src/runtime/routes/credential-routes.ts +26 -82
  493. package/src/runtime/routes/default-provider-routes.ts +15 -0
  494. package/src/runtime/routes/documents-routes.ts +3 -222
  495. package/src/runtime/routes/inbound-message-handler.ts +21 -45
  496. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
  497. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
  498. package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
  499. package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
  500. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
  501. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
  502. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
  503. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
  504. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
  505. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
  506. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
  507. package/src/runtime/routes/inference-profiles-routes.ts +20 -11
  508. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
  509. package/src/runtime/routes/log-export-routes.ts +3 -0
  510. package/src/runtime/routes/mcp-auth-routes.ts +148 -57
  511. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
  512. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
  513. package/src/runtime/routes/playground/inject-failures.ts +2 -2
  514. package/src/runtime/routes/playground/reset-circuit.ts +1 -1
  515. package/src/runtime/routes/plugins-routes.ts +38 -8
  516. package/src/runtime/routes/schedule-routes.ts +94 -7
  517. package/src/runtime/routes/settings-routes.ts +6 -6
  518. package/src/runtime/routes/stt-routes.ts +31 -25
  519. package/src/runtime/routes/surface-action-routes.ts +20 -19
  520. package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
  521. package/src/runtime/routes/user-route-dispatcher.ts +69 -15
  522. package/src/runtime/routes/user-route-import.ts +108 -0
  523. package/src/runtime/routes/user-route-resolution.ts +18 -1
  524. package/src/runtime/routes/workspace-routes.ts +0 -9
  525. package/src/runtime/routes/workspace-utils.ts +3 -13
  526. package/src/runtime/services/conversation-serializer.ts +7 -2
  527. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
  528. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
  529. package/src/schedule/plugin-schedule-availability.ts +58 -0
  530. package/src/schedule/plugin-schedule-declarations.ts +23 -27
  531. package/src/schedule/plugin-schedule-reconciler.ts +12 -3
  532. package/src/schedule/schedule-store.ts +5 -1
  533. package/src/schedule/scheduler.ts +9 -4
  534. package/src/schedule/worker-control.ts +1 -0
  535. package/src/schedule/worker.ts +6 -0
  536. package/src/security/oauth2.ts +6 -22
  537. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
  538. package/src/stt/__tests__/types.test.ts +94 -0
  539. package/src/stt/daemon-batch-transcriber.ts +10 -0
  540. package/src/stt/stt-stream-session.ts +8 -4
  541. package/src/stt/types.ts +103 -0
  542. package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
  543. package/src/subagent/consult-context.ts +11 -11
  544. package/src/subagent/consult-prompt.ts +26 -35
  545. package/src/subagent/manager.ts +21 -40
  546. package/src/subagent/notify.ts +7 -1
  547. package/src/subagent/types.ts +15 -12
  548. package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
  549. package/src/tools/acp/spawn.test.ts +97 -0
  550. package/src/tools/acp/spawn.ts +38 -4
  551. package/src/tools/credentials/ref-parse.ts +35 -0
  552. package/src/tools/credentials/resolve.ts +4 -10
  553. package/src/tools/credentials/store.ts +168 -0
  554. package/src/tools/document/document-tool.ts +12 -3
  555. package/src/tools/executor.ts +53 -15
  556. package/src/tools/filesystem/read.ts +27 -10
  557. package/src/tools/host-filesystem/read.ts +27 -15
  558. package/src/tools/network/url-safety.ts +9 -16
  559. package/src/tools/permission-checker.ts +43 -52
  560. package/src/tools/registry.ts +2 -1
  561. package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
  562. package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
  563. package/src/tools/shared/filesystem/types.ts +5 -5
  564. package/src/tools/skills/scaffold-managed.ts +25 -7
  565. package/src/tools/subagent/spawn.ts +28 -88
  566. package/src/tools/tool-types.ts +26 -13
  567. package/src/tools/types.ts +6 -6
  568. package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
  569. package/src/tools/workflows/run-workflow.ts +1 -2
  570. package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
  571. package/src/tts/reasoning-tag-filter.ts +89 -0
  572. package/src/util/__tests__/worker-process-command.test.ts +37 -0
  573. package/src/util/logger.ts +16 -0
  574. package/src/util/think-tag-stream.ts +95 -0
  575. package/src/util/worker-process.ts +37 -4
  576. package/src/windows-compiled-cli.ts +32 -0
  577. package/src/windows-compiled-entry.ts +4 -0
  578. package/src/windows-compiled-logger.ts +6 -0
  579. package/src/windows-compiled-worker-entry.ts +29 -0
  580. package/src/workspace/byok-default-profile-ensure.ts +76 -24
  581. package/src/workspace/custom-profile-ensure.ts +4 -24
  582. package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
  583. package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
  584. package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
  585. package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
  586. package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
  587. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
  588. package/src/workspace/migrations/registry.ts +10 -0
  589. package/src/workspace/provider-commit-message-generator.ts +7 -5
  590. package/src/__tests__/document-workspace-file.test.ts +0 -467
  591. package/src/live-voice/__tests__/front-decision.test.ts +0 -645
  592. package/src/live-voice/front-decision.ts +0 -476
  593. package/src/permissions/ipc-risk-types.ts +0 -143
  594. package/src/permissions/risk-types.ts +0 -76
  595. package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
  596. package/src/subagent/consult-transcript.ts +0 -90
@@ -150,6 +150,50 @@ describe("POST inference/profiles (create) validation", () => {
150
150
  ).rejects.toBeInstanceOf(BadRequestError);
151
151
  });
152
152
 
153
+ test("creates an entry-backed profile, validating the model by the row's kind", async () => {
154
+ seedConnection("anthropic-work", "anthropic", {
155
+ type: "api_key",
156
+ credential: "credential/anthropic-work/api_key",
157
+ });
158
+ const result = (await call("inference_profiles_create", {
159
+ body: {
160
+ name: "work-profile",
161
+ provider: "anthropic-work",
162
+ model: "claude-opus-4-8",
163
+ },
164
+ })) as { entry: Record<string, unknown> };
165
+ expect(result.entry.provider).toBe("anthropic-work");
166
+ expect(result.entry.model).toBe("claude-opus-4-8");
167
+ });
168
+
169
+ test("rejects an entry-backed profile whose model the row's kind cannot serve", async () => {
170
+ seedConnection("anthropic-work", "anthropic", {
171
+ type: "api_key",
172
+ credential: "credential/anthropic-work/api_key",
173
+ });
174
+ await expect(
175
+ call("inference_profiles_create", {
176
+ body: {
177
+ name: "work-profile",
178
+ provider: "anthropic-work",
179
+ model: "gpt-5.5",
180
+ },
181
+ }),
182
+ ).rejects.toBeInstanceOf(BadRequestError);
183
+ });
184
+
185
+ test("rejects a provider naming no known vendor or entry", async () => {
186
+ await expect(
187
+ call("inference_profiles_create", {
188
+ body: {
189
+ name: "ghost-profile",
190
+ provider: "no-such-entry",
191
+ model: "claude-opus-4-8",
192
+ },
193
+ }),
194
+ ).rejects.toBeInstanceOf(BadRequestError);
195
+ });
196
+
153
197
  test("creates a vellum profile for a managed-routable model", async () => {
154
198
  seedVellumConnection();
155
199
  const result = (await call("inference_profiles_create", {
@@ -232,6 +232,61 @@ describe("POST inference/provider-connections (create)", () => {
232
232
  expect((err as BadRequestError).message).toContain("vellum");
233
233
  });
234
234
 
235
+ test("rejects a chatgpt identity row under a non-canonical name", async () => {
236
+ const err = await call(
237
+ findHandler("inference_provider_connections_create"),
238
+ {
239
+ body: {
240
+ name: "my-chatgpt",
241
+ provider: "chatgpt",
242
+ auth: { type: "oauth_subscription", credential: "credential/x" },
243
+ },
244
+ },
245
+ ).catch((e: unknown) => e);
246
+
247
+ expect(err).toBeInstanceOf(BadRequestError);
248
+ expect((err as BadRequestError).message).toContain("chatgpt-subscription");
249
+ });
250
+
251
+ test("rejects key auth on the chatgpt provider, derived or explicit", async () => {
252
+ for (const body of [
253
+ {
254
+ name: "chatgpt-subscription",
255
+ provider: "chatgpt",
256
+ auth: { type: "api_key", credential: "vault/x" },
257
+ },
258
+ // No explicit auth: derivation would fall through to api_key.
259
+ {
260
+ name: "chatgpt-subscription",
261
+ provider: "chatgpt",
262
+ credential: "vault/x",
263
+ },
264
+ ]) {
265
+ const err = await call(
266
+ findHandler("inference_provider_connections_create"),
267
+ { body },
268
+ ).catch((e: unknown) => e);
269
+ expect(err).toBeInstanceOf(BadRequestError);
270
+ expect((err as BadRequestError).message).toContain("sign-in");
271
+ }
272
+ });
273
+
274
+ test("rejects subscription auth on a non-chatgpt provider", async () => {
275
+ const err = await call(
276
+ findHandler("inference_provider_connections_create"),
277
+ {
278
+ body: {
279
+ name: "keyed-oauth",
280
+ provider: "openai",
281
+ auth: { type: "oauth_subscription", credential: "credential/x" },
282
+ },
283
+ },
284
+ ).catch((e: unknown) => e);
285
+
286
+ expect(err).toBeInstanceOf(BadRequestError);
287
+ expect((err as BadRequestError).message).toContain("chatgpt");
288
+ });
289
+
235
290
  test("rejects key auth on the vellum provider", async () => {
236
291
  const err = await call(
237
292
  findHandler("inference_provider_connections_create"),
@@ -396,7 +451,7 @@ describe("POST inference/provider-connections (create)", () => {
396
451
  models: [{ id: "my-model" }],
397
452
  },
398
453
  }),
399
- ).rejects.toThrow(/belongs to a built-in provider/);
454
+ ).rejects.toThrow(/reserved as a provider id/);
400
455
 
401
456
  await call(findHandler("inference_provider_connections_create"), {
402
457
  body: {
@@ -677,6 +732,52 @@ describe("PATCH inference/provider-connections/:name (update)", () => {
677
732
 
678
733
  // The guard must not trap a legacy row in its mismatched state: an auth
679
734
  // change that repairs the pairing is exactly what should be allowed.
735
+ // The canonical subscription row owns the "chatgpt" identity: writing
736
+ // subscription auth to it stamps the provider (the CLI login-chatgpt path
737
+ // PATCHes auth through this route on a row the identity migration
738
+ // deliberately skipped).
739
+ test("stamps the chatgpt identity when subscription auth lands on the canonical row", async () => {
740
+ seedConnection({
741
+ name: "chatgpt-subscription",
742
+ provider: "openai",
743
+ auth: { type: "api_key", credential: "vault/openai/key" },
744
+ });
745
+
746
+ const result = (await call(
747
+ findHandler("inference_provider_connections_update"),
748
+ {
749
+ pathParams: { name: "chatgpt-subscription" },
750
+ body: {
751
+ auth: {
752
+ type: "oauth_subscription",
753
+ credential: "credential/chatgpt/access_token",
754
+ },
755
+ },
756
+ },
757
+ )) as { provider: string; auth: { type: string } };
758
+ expect(result.provider).toBe("chatgpt");
759
+ expect(result.auth.type).toBe("oauth_subscription");
760
+ });
761
+
762
+ test("does not stamp the identity for non-subscription auth on that name", async () => {
763
+ seedConnection({
764
+ name: "chatgpt-subscription",
765
+ provider: "openai",
766
+ auth: { type: "api_key", credential: "vault/openai/key" },
767
+ });
768
+
769
+ const result = (await call(
770
+ findHandler("inference_provider_connections_update"),
771
+ {
772
+ pathParams: { name: "chatgpt-subscription" },
773
+ body: {
774
+ auth: { type: "api_key", credential: "vault/openai/other-key" },
775
+ },
776
+ },
777
+ )) as { provider: string };
778
+ expect(result.provider).toBe("openai");
779
+ });
780
+
680
781
  test("allows repairing a legacy mismatched row with a valid auth change", async () => {
681
782
  seedConnection({
682
783
  name: "legacy-managed-anthropic",
@@ -38,9 +38,12 @@
38
38
  * `plugins:list` tag via the canonical resource-sync publisher (enable and
39
39
  * disable emit the SAME invalidation)
40
40
  * - Threads `x-vellum-client-id` into the published event's `originClientId`
41
- * - Pokes the plugin-declared schedule reconcile on a successful toggle (and
42
- * not on a failed one), so the plugin's rows disarm / re-arm immediately
43
- * instead of at the reconciler's next backstop sweep
41
+ * - Enable pokes the imperative plugin source reconcile, which activates a
42
+ * plugin the boot scan skipped for its sentinel and converges its
43
+ * schedules and MCP servers
44
+ * - Disable pokes the plugin-declared schedule reconcile on a successful
45
+ * toggle (and not on a failed one), so the plugin's rows disarm
46
+ * immediately instead of at the reconciler's next backstop sweep
44
47
  * - A broadcast failure does not fail a successful toggle (the publisher
45
48
  * swallows hub errors)
46
49
  * - Maps `InvalidPluginNameError` → BadRequestError (400)
@@ -109,6 +112,7 @@ import {
109
112
  } from "../../../cli/lib/uninstall-plugin.js";
110
113
  import {
111
114
  PluginMergeBaselineError,
115
+ PluginNotCuratedError,
112
116
  PluginNotUpgradableError,
113
117
  type PluginUpgradeResult,
114
118
  type UpgradePluginDeps,
@@ -252,6 +256,7 @@ const upgradeSpy = mock(
252
256
 
253
257
  mock.module("../../../cli/lib/upgrade-plugin.js", () => ({
254
258
  PluginMergeBaselineError,
259
+ PluginNotCuratedError,
255
260
  PluginNotUpgradableError,
256
261
  upgradePlugin: upgradeSpy,
257
262
  }));
@@ -314,8 +319,8 @@ mock.module("../../../cli/lib/toggle-plugin.js", () => ({
314
319
  enablePlugin: enablePluginSpy,
315
320
  }));
316
321
 
317
- // Spy on the plugin-schedule reconcile the toggle handlers poke. The handlers
318
- // import it lazily at call time, so this mock intercepts the dynamic import
322
+ // Spy on the plugin-schedule reconcile the disable handler pokes. The handler
323
+ // imports it lazily at call time, so this mock intercepts the dynamic import
319
324
  // and keeps the reconciler's persistence graph out of the test.
320
325
  const reconcilePluginSchedulesSpy = mock(() => Promise.resolve());
321
326
 
@@ -323,6 +328,21 @@ mock.module("../../../schedule/plugin-schedule-reconciler.js", () => ({
323
328
  reconcilePluginSchedules: reconcilePluginSchedulesSpy,
324
329
  }));
325
330
 
331
+ // Spy on the imperative plugin source reconcile so the enable route's
332
+ // activation poke is assertable without scanning a real plugins tree. Only
333
+ // that one export is swapped; the rest of the module passes through real,
334
+ // because other modules in this route's graph import their own bindings from
335
+ // it.
336
+ const reconcilePluginSourcesNowSpy = mock(() => Promise.resolve());
337
+
338
+ const actualMtimeCache: typeof import("../../../plugins/mtime-cache.js") =
339
+ await import("../../../plugins/mtime-cache.js");
340
+
341
+ mock.module("../../../plugins/mtime-cache.js", () => ({
342
+ ...actualMtimeCache,
343
+ reconcilePluginSourcesNow: reconcilePluginSourcesNowSpy,
344
+ }));
345
+
326
346
  // Spy on broadcastMessage so we can assert the sync_changed invalidation the
327
347
  // enable/disable handlers emit. The handlers publish through the canonical
328
348
  // `publishPluginsChanged` → `publishSyncInvalidation` path (both left real), so
@@ -2127,6 +2147,7 @@ describe("POST /v1/plugins/:name/upgrade", () => {
2127
2147
  name: "level-up",
2128
2148
  dryRun: false,
2129
2149
  strategy: undefined,
2150
+ marketplaceOnly: false,
2130
2151
  });
2131
2152
  });
2132
2153
 
@@ -2148,6 +2169,7 @@ describe("POST /v1/plugins/:name/upgrade", () => {
2148
2169
  name: "level-up",
2149
2170
  dryRun: undefined,
2150
2171
  strategy: "ours",
2172
+ marketplaceOnly: false,
2151
2173
  });
2152
2174
  });
2153
2175
 
@@ -2175,6 +2197,7 @@ describe("POST /v1/plugins/:name/upgrade", () => {
2175
2197
  name: "level-up",
2176
2198
  dryRun: undefined,
2177
2199
  strategy: "assistant",
2200
+ marketplaceOnly: false,
2178
2201
  });
2179
2202
  });
2180
2203
 
@@ -2300,6 +2323,10 @@ describe("POST /v1/plugins/:name/upgrade", () => {
2300
2323
  expect(upgradeSpy.mock.calls[0]?.[0]).toEqual({
2301
2324
  name: "level-up",
2302
2325
  dryRun: undefined,
2326
+ strategy: undefined,
2327
+ // Unlike dryRun, an absent flag here is a definite "no": the untrusted
2328
+ // direct path stays available unless a caller opts out of it.
2329
+ marketplaceOnly: false,
2303
2330
  });
2304
2331
  });
2305
2332
 
@@ -2343,6 +2370,41 @@ describe("POST /v1/plugins/:name/upgrade", () => {
2343
2370
  ).rejects.toBeInstanceOf(ConflictError);
2344
2371
  });
2345
2372
 
2373
+ test("marketplaceOnly is forwarded so the lib enforces it, not the caller", async () => {
2374
+ // The lib re-inspects the catalog inside the call, so the flag has to
2375
+ // travel with the request: a caller's own pre-check cannot bind a decision
2376
+ // the lib makes afterwards.
2377
+ upgradeSpy.mockImplementation(async () => upgradeResult());
2378
+
2379
+ await invokeUpgrade({
2380
+ pathParams: { name: "level-up" },
2381
+ body: { marketplaceOnly: true },
2382
+ });
2383
+
2384
+ expect(upgradeSpy.mock.calls[0]?.[0]).toEqual({
2385
+ name: "level-up",
2386
+ dryRun: undefined,
2387
+ strategy: undefined,
2388
+ marketplaceOnly: true,
2389
+ });
2390
+ });
2391
+
2392
+ test("PluginNotCuratedError → ConflictError (409)", async () => {
2393
+ // A marketplaceOnly caller asked about an install the catalog does not
2394
+ // claim. Retrying changes nothing: only a human upgrading it without the
2395
+ // flag can move it.
2396
+ upgradeSpy.mockImplementation(async () => {
2397
+ throw new PluginNotCuratedError("level-up");
2398
+ });
2399
+
2400
+ await expect(
2401
+ invokeUpgrade({
2402
+ pathParams: { name: "level-up" },
2403
+ body: { marketplaceOnly: true },
2404
+ }),
2405
+ ).rejects.toBeInstanceOf(ConflictError);
2406
+ });
2407
+
2346
2408
  test("PluginNotFoundError → NotFoundError (404)", async () => {
2347
2409
  upgradeSpy.mockImplementation(async () => {
2348
2410
  throw new PluginNotFoundError("level-up", "main", "vellum-ai/level-up");
@@ -2529,8 +2591,10 @@ function toggleResult(
2529
2591
  };
2530
2592
  }
2531
2593
 
2532
- function invokeEnable(args: RouteHandlerArgs = {}): { ok: boolean } {
2533
- return enableHandler(args) as { ok: boolean };
2594
+ async function invokeEnable(
2595
+ args: RouteHandlerArgs = {},
2596
+ ): Promise<{ ok: boolean }> {
2597
+ return (await enableHandler(args)) as { ok: boolean };
2534
2598
  }
2535
2599
 
2536
2600
  function invokeDisable(args: RouteHandlerArgs = {}): { ok: boolean } {
@@ -2538,18 +2602,22 @@ function invokeDisable(args: RouteHandlerArgs = {}): { ok: boolean } {
2538
2602
  }
2539
2603
 
2540
2604
  /**
2541
- * Wait for the toggle handlers' fire-and-forget reconcile poke to land. The
2542
- * lazy `import()` resolves off the microtask queue, so the assertion cannot
2543
- * run on the handler's synchronous return.
2605
+ * Wait for a toggle handler's fire-and-forget reconcile poke to land. The poke
2606
+ * runs off the microtask queue (the disable path also resolves a lazy
2607
+ * `import()` first), so the assertion cannot run on the handler's synchronous
2608
+ * return.
2544
2609
  */
2545
- async function waitForScheduleReconcile(): Promise<void> {
2610
+ async function waitForReconcile(
2611
+ spy: { mock: { calls: unknown[] } },
2612
+ label: string,
2613
+ ): Promise<void> {
2546
2614
  for (let i = 0; i < 50; i++) {
2547
- if (reconcilePluginSchedulesSpy.mock.calls.length > 0) {
2615
+ if (spy.mock.calls.length > 0) {
2548
2616
  return;
2549
2617
  }
2550
2618
  await new Promise((resolve) => setTimeout(resolve, 2));
2551
2619
  }
2552
- throw new Error("plugin schedule reconcile was never triggered");
2620
+ throw new Error(`${label} was never triggered`);
2553
2621
  }
2554
2622
 
2555
2623
  /** Assert the spy received exactly one sync_changed carrying `plugins:list`. */
@@ -2565,30 +2633,50 @@ describe("POST /v1/plugins/:name/enable", () => {
2565
2633
  enablePluginSpy.mockReset();
2566
2634
  broadcastMessageSpy.mockReset();
2567
2635
  reconcilePluginSchedulesSpy.mockClear();
2636
+ reconcilePluginSourcesNowSpy.mockClear();
2568
2637
  });
2569
2638
 
2570
- test("reconciles plugin-declared schedules so the plugin's rows re-arm now", async () => {
2639
+ test("awaits the source reconcile so a boot-disabled plugin activates before the route returns", async () => {
2571
2640
  enablePluginSpy.mockImplementation((name) => toggleResult(name, "enable"));
2572
2641
 
2573
- invokeEnable({ pathParams: { name: "simple-memory" } });
2642
+ await invokeEnable({ pathParams: { name: "simple-memory" } });
2643
+
2644
+ // The boot scan skipped this plugin for its sentinel, so clearing the
2645
+ // sentinel only brings its hooks, tools, MCP servers and schedules up if
2646
+ // the source reconcile runs. The route awaits it, so by the time the
2647
+ // response lands the reconcile has completed; it converges the schedules
2648
+ // itself, so the route does not poke them separately.
2649
+ expect(reconcilePluginSourcesNowSpy).toHaveBeenCalledTimes(1);
2650
+ expect(reconcilePluginSchedulesSpy).not.toHaveBeenCalled();
2651
+ });
2652
+
2653
+ test("a failed toggle does not run the source reconcile", async () => {
2654
+ enablePluginSpy.mockImplementation((name) => {
2655
+ throw new PluginDirectoryNotFoundError(name);
2656
+ });
2574
2657
 
2575
- await waitForScheduleReconcile();
2658
+ await expect(
2659
+ invokeEnable({ pathParams: { name: "ghost" } }),
2660
+ ).rejects.toThrow(NotFoundError);
2661
+ expect(reconcilePluginSourcesNowSpy).not.toHaveBeenCalled();
2576
2662
  });
2577
2663
 
2578
- test("enables the plugin and broadcasts sync_changed(plugins:list)", () => {
2664
+ test("enables the plugin and broadcasts sync_changed(plugins:list)", async () => {
2579
2665
  enablePluginSpy.mockImplementation((name) => toggleResult(name, "enable"));
2580
2666
 
2581
- const result = invokeEnable({ pathParams: { name: "simple-memory" } });
2667
+ const result = await invokeEnable({
2668
+ pathParams: { name: "simple-memory" },
2669
+ });
2582
2670
 
2583
2671
  expect(result).toEqual({ ok: true });
2584
2672
  expect(enablePluginSpy.mock.calls[0]?.[0]).toBe("simple-memory");
2585
2673
  expectPluginsListBroadcast();
2586
2674
  });
2587
2675
 
2588
- test("threads x-vellum-client-id into the published event's originClientId", () => {
2676
+ test("threads x-vellum-client-id into the published event's originClientId", async () => {
2589
2677
  enablePluginSpy.mockImplementation((name) => toggleResult(name, "enable"));
2590
2678
 
2591
- invokeEnable({
2679
+ await invokeEnable({
2592
2680
  pathParams: { name: "simple-memory" },
2593
2681
  headers: { "x-vellum-client-id": "client-abc" },
2594
2682
  });
@@ -2602,7 +2690,7 @@ describe("POST /v1/plugins/:name/enable", () => {
2602
2690
  });
2603
2691
  });
2604
2692
 
2605
- test("a broadcast failure does not fail a successful toggle", () => {
2693
+ test("a broadcast failure does not fail a successful toggle", async () => {
2606
2694
  enablePluginSpy.mockImplementation((name) => toggleResult(name, "enable"));
2607
2695
  // The sentinel was already flipped; a hub throw AFTER that must not surface
2608
2696
  // as a 500 — the canonical publisher swallows broadcast errors.
@@ -2610,40 +2698,42 @@ describe("POST /v1/plugins/:name/enable", () => {
2610
2698
  throw new Error("hub unavailable");
2611
2699
  });
2612
2700
 
2613
- const result = invokeEnable({ pathParams: { name: "simple-memory" } });
2701
+ const result = await invokeEnable({
2702
+ pathParams: { name: "simple-memory" },
2703
+ });
2614
2704
  expect(result).toEqual({ ok: true });
2615
2705
  });
2616
2706
 
2617
- test("PluginAlreadyInStateException → ConflictError (409), no broadcast", () => {
2707
+ test("PluginAlreadyInStateException → ConflictError (409), no broadcast", async () => {
2618
2708
  enablePluginSpy.mockImplementation((name) => {
2619
2709
  throw new PluginAlreadyInStateException(name, "enable");
2620
2710
  });
2621
2711
 
2622
- expect(() =>
2712
+ await expect(
2623
2713
  invokeEnable({ pathParams: { name: "simple-memory" } }),
2624
- ).toThrow(ConflictError);
2714
+ ).rejects.toThrow(ConflictError);
2625
2715
  // A no-op toggle must not fan out a spurious invalidation.
2626
2716
  expect(broadcastMessageSpy).not.toHaveBeenCalled();
2627
2717
  });
2628
2718
 
2629
- test("PluginDirectoryNotFoundError → NotFoundError (404)", () => {
2719
+ test("PluginDirectoryNotFoundError → NotFoundError (404)", async () => {
2630
2720
  enablePluginSpy.mockImplementation((name) => {
2631
2721
  throw new PluginDirectoryNotFoundError(name);
2632
2722
  });
2633
2723
 
2634
- expect(() => invokeEnable({ pathParams: { name: "ghost" } })).toThrow(
2635
- NotFoundError,
2636
- );
2724
+ await expect(
2725
+ invokeEnable({ pathParams: { name: "ghost" } }),
2726
+ ).rejects.toThrow(NotFoundError);
2637
2727
  });
2638
2728
 
2639
- test("InvalidPluginNameError → BadRequestError (400)", () => {
2729
+ test("InvalidPluginNameError → BadRequestError (400)", async () => {
2640
2730
  enablePluginSpy.mockImplementation(() => {
2641
2731
  throw new ToggleInvalidPluginNameError("../escape");
2642
2732
  });
2643
2733
 
2644
- expect(() => invokeEnable({ pathParams: { name: "../escape" } })).toThrow(
2645
- BadRequestError,
2646
- );
2734
+ await expect(
2735
+ invokeEnable({ pathParams: { name: "../escape" } }),
2736
+ ).rejects.toThrow(BadRequestError);
2647
2737
  });
2648
2738
  });
2649
2739
 
@@ -2652,6 +2742,7 @@ describe("POST /v1/plugins/:name/disable", () => {
2652
2742
  disablePluginSpy.mockReset();
2653
2743
  broadcastMessageSpy.mockReset();
2654
2744
  reconcilePluginSchedulesSpy.mockClear();
2745
+ reconcilePluginSourcesNowSpy.mockClear();
2655
2746
  });
2656
2747
 
2657
2748
  test("reconciles plugin-declared schedules so the plugin's rows disarm now", async () => {
@@ -2662,8 +2753,14 @@ describe("POST /v1/plugins/:name/disable", () => {
2662
2753
  invokeDisable({ pathParams: { name: "simple-memory" } });
2663
2754
 
2664
2755
  // Without this poke the rows stay armed until the reconciler's next
2665
- // backstop sweep.
2666
- await waitForScheduleReconcile();
2756
+ // backstop sweep. Disable stays on the schedule poke: the sentinel filters
2757
+ // the plugin out at read time, and a source reconcile here would run its
2758
+ // shutdown hooks.
2759
+ await waitForReconcile(
2760
+ reconcilePluginSchedulesSpy,
2761
+ "plugin schedule reconcile",
2762
+ );
2763
+ expect(reconcilePluginSourcesNowSpy).not.toHaveBeenCalled();
2667
2764
  });
2668
2765
 
2669
2766
  test("a failed toggle does not poke the schedule reconcile", async () => {