@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
@@ -49,6 +49,7 @@ describe("isConnectionCompatibleWithModel", () => {
49
49
  expect(isConnectionCompatibleWithModel(conn, "gpt-5")).toBe(false);
50
50
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-nano")).toBe(false);
51
51
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.5-pro")).toBe(false);
52
+ expect(isConnectionCompatibleWithModel(conn, "gpt-5.3-codex")).toBe(false);
52
53
  });
53
54
 
54
55
  test("oauth_subscription connection is compatible with a Codex model", () => {
@@ -59,7 +60,6 @@ describe("isConnectionCompatibleWithModel", () => {
59
60
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.5")).toBe(true);
60
61
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.4")).toBe(true);
61
62
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-mini")).toBe(true);
62
- expect(isConnectionCompatibleWithModel(conn, "gpt-5.3-codex")).toBe(true);
63
63
  });
64
64
 
65
65
  test("undefined model applies no gating (compatible)", () => {
@@ -239,6 +239,30 @@ describe("detectOpenAICompatibleContextOverflow", () => {
239
239
  expect(detectOpenAICompatibleContextOverflow(err)).toBeNull();
240
240
  });
241
241
 
242
+ test("matches OpenAI's per-part 10MiB string_above_max_length 400", () => {
243
+ const err = buildOpenAIApiError(400, {
244
+ message:
245
+ "Invalid 'input[191].content[1].text': string too long. Expected a string with maximum length 10485760, but got a string with length 11436754 instead.",
246
+ type: "invalid_request_error",
247
+ code: "string_above_max_length",
248
+ });
249
+ const out = detectOpenAICompatibleContextOverflow(err);
250
+ expect(out).not.toBeNull();
251
+ // Byte lengths in this message must not be misread as token counts.
252
+ expect(out?.actualTokens).toBeUndefined();
253
+ expect(out?.maxTokens).toBeUndefined();
254
+ });
255
+
256
+ test("returns null for string_above_max_length on a non-content field", () => {
257
+ const err = buildOpenAIApiError(400, {
258
+ message:
259
+ "Invalid 'tools[0].function.description': string too long. Expected a string with maximum length 1048576, but got a string with length 2000000 instead.",
260
+ type: "invalid_request_error",
261
+ code: "string_above_max_length",
262
+ });
263
+ expect(detectOpenAICompatibleContextOverflow(err)).toBeNull();
264
+ });
265
+
242
266
  test("matches 'too many input tokens' variant emitted by some OpenAI-compatible providers", () => {
243
267
  const err = buildOpenAIApiError(400, {
244
268
  message: "too many input tokens: 250000",
@@ -65,6 +65,10 @@ const fakeConnections = new Map<string, Connection>();
65
65
  mock.module("../inference/connections.js", () => ({
66
66
  getConnection: (_db: unknown, name: string) =>
67
67
  fakeConnections.get(name) ?? null,
68
+ listConnections: (_db: unknown, filter?: { provider?: string }) =>
69
+ Array.from(fakeConnections.values()).filter(
70
+ (c) => !filter?.provider || c.provider === filter.provider,
71
+ ),
68
72
  }));
69
73
 
70
74
  mock.module("../registry.js", () => ({
@@ -449,11 +453,43 @@ describe("routing identities", () => {
449
453
  },
450
454
  } as never);
451
455
  expect(resolveProviderCalls[0]?.name).toBe("chatgpt-subscription");
452
- // No override needed: the subscription row itself carries provider
453
- // "openai", so the adapter resolves from the row.
456
+ // A pre-migration row carries provider "openai": no override needed, the
457
+ // adapter resolves from the row.
454
458
  expect(resolveProviderCalls[0]?.provider).toBe("openai");
455
459
  });
456
460
 
461
+ test("a chatgpt-identity subscription row dispatches with an openai override", async () => {
462
+ // Migration 366 stamps the row with the "chatgpt" identity; the identity
463
+ // must never reach adapter construction, so dispatch threads the openai
464
+ // upstream as providerOverride, mirroring the vellum sentinel.
465
+ fakeConnections.set("chatgpt-subscription", {
466
+ name: "chatgpt-subscription",
467
+ provider: "chatgpt",
468
+ auth: {
469
+ type: "oauth_subscription",
470
+ credential: "credential/chatgpt/access_token",
471
+ },
472
+ });
473
+ fakeProviders.set("conn:chatgpt-subscription", {
474
+ name: "openai",
475
+ tag: "subscription",
476
+ });
477
+
478
+ const provider = await tryResolveProviderForConnectionName(
479
+ "ignored",
480
+ { llm: {} } as never,
481
+ "chatgpt",
482
+ "gpt-5.5",
483
+ );
484
+
485
+ expect(provider?.routeAttribution).toEqual({
486
+ connectionName: "chatgpt-subscription",
487
+ isManagedRoute: false,
488
+ });
489
+ expect(resolveProviderCalls[0]?.name).toBe("chatgpt-subscription");
490
+ expect(resolveProviderOpts[0]?.providerOverride).toBe("openai");
491
+ });
492
+
457
493
  // A second managed row is creatable under any non-reserved name: only the
458
494
  // canonical name is refused at the create route, and `provider: "vellum"`
459
495
  // derives platform auth. Managed-ness is the row, never its name.
@@ -492,3 +528,179 @@ describe("routing identities", () => {
492
528
  ).rejects.toMatchObject({ reason: "not_found" });
493
529
  });
494
530
  });
531
+
532
+ // ---------------------------------------------------------------------------
533
+ // Entry-name providers — a profile provider naming a connection row directly.
534
+ // Write surfaces reject these until the entries model enables them; dispatch
535
+ // translates them so hand-edited configs (and the collapse migration later)
536
+ // route through the named row.
537
+ // ---------------------------------------------------------------------------
538
+
539
+ describe("entry-name providers", () => {
540
+ beforeEach(() => {
541
+ resolveProviderCalls.length = 0;
542
+ resolveProviderOpts.length = 0;
543
+ fakeConnections.clear();
544
+ fakeProviders.clear();
545
+ setConfig("llm", {});
546
+ });
547
+
548
+ test("a profile naming an entry dispatches through that row", async () => {
549
+ registerConnection(
550
+ {
551
+ name: "anthropic-work",
552
+ provider: "anthropic",
553
+ auth: {
554
+ type: "api_key",
555
+ credential: "credential/anthropic-work/api_key",
556
+ },
557
+ },
558
+ { name: "anthropic", tag: "work-key" },
559
+ );
560
+ setLlmConfig({
561
+ profiles: {
562
+ work: { provider: "anthropic-work", model: "claude-opus-4-8" },
563
+ },
564
+ });
565
+
566
+ const result = await getConfiguredProvider("mainAgent", {
567
+ overrideProfile: "work",
568
+ });
569
+
570
+ expect(result).not.toBeNull();
571
+ expect(resolveProviderCalls.length).toBe(1);
572
+ expect(resolveProviderCalls[0]?.name).toBe("anthropic-work");
573
+ // The label is not a vendor: the row's own provider drives dispatch,
574
+ // so no override is threaded.
575
+ expect(resolveProviderOpts[0]?.providerOverride).toBeUndefined();
576
+ });
577
+
578
+ test("a vellum-kind entry derives its upstream from the model", async () => {
579
+ registerConnection(
580
+ { name: "work-managed", provider: "vellum", auth: { type: "platform" } },
581
+ { name: "anthropic", tag: "managed-stub" },
582
+ );
583
+ setLlmConfig({
584
+ profiles: {
585
+ managed: { provider: "work-managed", model: "claude-opus-4-8" },
586
+ },
587
+ });
588
+
589
+ const result = await getConfiguredProvider("mainAgent", {
590
+ overrideProfile: "managed",
591
+ });
592
+
593
+ expect(result).not.toBeNull();
594
+ expect(resolveProviderCalls[0]?.name).toBe("work-managed");
595
+ expect(resolveProviderOpts[0]?.providerOverride).toBe("anthropic");
596
+ });
597
+
598
+ test("an entry label alongside an explicit provider_connection still dispatches", async () => {
599
+ // The step-3 collapse migration rewrites provider to an entry name; a
600
+ // stale provider_connection left beside it must not fail the vendor
601
+ // equality against a label that is not a vendor.
602
+ registerConnection(
603
+ {
604
+ name: "anthropic-work",
605
+ provider: "anthropic",
606
+ auth: {
607
+ type: "api_key",
608
+ credential: "credential/anthropic-work/api_key",
609
+ },
610
+ },
611
+ { name: "anthropic", tag: "work-key" },
612
+ );
613
+ setLlmConfig({
614
+ profiles: {
615
+ work: {
616
+ provider: "anthropic-work",
617
+ provider_connection: "anthropic-work",
618
+ model: "claude-opus-4-8",
619
+ },
620
+ },
621
+ });
622
+
623
+ const result = await getConfiguredProvider("mainAgent", {
624
+ overrideProfile: "work",
625
+ });
626
+
627
+ expect(result).not.toBeNull();
628
+ expect(resolveProviderCalls[0]?.name).toBe("anthropic-work");
629
+ expect(resolveProviderOpts[0]?.providerOverride).toBeUndefined();
630
+ });
631
+
632
+ test("a label with a conflicting provider_connection is held to the label's kind", async () => {
633
+ // The label's row kind threads as the expected vendor, so a stale or
634
+ // conflicting connection cannot silently dispatch a different vendor:
635
+ // the equality mismatch auto-recovers to a row matching the kind.
636
+ registerConnection(
637
+ {
638
+ name: "anthropic-work",
639
+ provider: "anthropic",
640
+ auth: {
641
+ type: "api_key",
642
+ credential: "credential/anthropic-work/api_key",
643
+ },
644
+ },
645
+ { name: "anthropic", tag: "work-key" },
646
+ );
647
+ registerConnection(
648
+ { name: "ollama-local", provider: "ollama", auth: { type: "none" } },
649
+ { name: "ollama", tag: "local" },
650
+ );
651
+ setLlmConfig({
652
+ profiles: {
653
+ conflicted: {
654
+ provider: "anthropic-work",
655
+ provider_connection: "ollama-local",
656
+ model: "claude-opus-4-8",
657
+ },
658
+ },
659
+ });
660
+
661
+ const result = await getConfiguredProvider("mainAgent", {
662
+ overrideProfile: "conflicted",
663
+ });
664
+
665
+ expect(result).not.toBeNull();
666
+ expect(resolveProviderCalls[0]?.name).toBe("anthropic-work");
667
+ });
668
+
669
+ test("a profile naming no row is healed away at selection", async () => {
670
+ // Selection treats an unresolvable provider like an incomplete profile:
671
+ // the broken winner loses and the next rung's model AND transport apply
672
+ // together, restoring the pre-open-schema self-healing. The anchor is
673
+ // the managed default, so the heal lands on the vellum route.
674
+ registerConnection(
675
+ { name: "vellum", provider: "vellum", auth: { type: "platform" } },
676
+ { name: "anthropic", tag: "managed-anchor" },
677
+ );
678
+ setLlmConfig({
679
+ profiles: {
680
+ ghost: { provider: "no-such-entry", model: "claude-opus-4-8" },
681
+ },
682
+ });
683
+
684
+ const result = await getConfiguredProvider("mainAgent", {
685
+ overrideProfile: "ghost",
686
+ });
687
+
688
+ expect(result).not.toBeNull();
689
+ expect(resolveProviderCalls[0]?.name).toBe("vellum");
690
+ });
691
+
692
+ test("healing hands off to the anchor, whose own failures stay loud", async () => {
693
+ // With the broken profile healed away, resolution rests on the managed
694
+ // anchor; its canonical row missing is a boot-seeding violation and
695
+ // throws explainably rather than masquerading as the ghost profile.
696
+ setLlmConfig({
697
+ profiles: {
698
+ ghost: { provider: "no-such-entry", model: "claude-opus-4-8" },
699
+ },
700
+ });
701
+
702
+ await expect(
703
+ getConfiguredProvider("mainAgent", { overrideProfile: "ghost" }),
704
+ ).rejects.toMatchObject({ reason: "not_found", connectionName: "vellum" });
705
+ });
706
+ });
@@ -220,6 +220,63 @@ describe("preflightResolvedConfig", () => {
220
220
  ).resolves.toBeUndefined();
221
221
  });
222
222
 
223
+ test("an explicit connection outranks an entry-name provider, matching dispatch", async () => {
224
+ // A healthy entry row must not mask the row the request actually uses.
225
+ connectionsByName["anthropic-work"] = {
226
+ name: "anthropic-work",
227
+ provider: "anthropic",
228
+ auth: {
229
+ type: "api_key",
230
+ credential: "credential/anthropic-work/api_key",
231
+ },
232
+ };
233
+ secureKeys["credential/anthropic-work/api_key"] = "healthy";
234
+
235
+ const err = await preflightError(
236
+ resolved({
237
+ provider: "anthropic-work",
238
+ provider_connection: "deleted-row",
239
+ model: "claude-opus-4-8",
240
+ }),
241
+ );
242
+ expect(err?.reason).toBe("not_found");
243
+ expect(err?.connectionName).toBe("deleted-row");
244
+ });
245
+
246
+ test("a chatgpt-identity subscription row preflights the same way", async () => {
247
+ // Migration 366 stamps the row with provider "chatgpt"; preflight judges
248
+ // its subscription credential, not a provider equality with the openai
249
+ // upstream.
250
+ connectionsByName["chatgpt-subscription"] = {
251
+ name: "chatgpt-subscription",
252
+ provider: "chatgpt",
253
+ auth: {
254
+ type: "oauth_subscription",
255
+ credential: "credential/chatgpt/access_token",
256
+ },
257
+ };
258
+ const missing = await preflightError(
259
+ resolved({
260
+ provider: "chatgpt",
261
+ provider_connection: "",
262
+ model: "gpt-5.5",
263
+ }),
264
+ );
265
+ expect(missing?.reason).toBe("missing_credential");
266
+
267
+ secureKeys["credential/chatgpt/access_token"] = "tok";
268
+ await expect(
269
+ preflightResolvedConfig(
270
+ resolved({
271
+ provider: "chatgpt",
272
+ provider_connection: "",
273
+ model: "gpt-5.5",
274
+ }),
275
+ {},
276
+ ),
277
+ ).resolves.toBeUndefined();
278
+ });
279
+
223
280
  test("a chatgpt identity with no subscription row throws not_found", async () => {
224
281
  const err = await preflightError(
225
282
  resolved({
@@ -337,7 +337,7 @@ describe("RetryProvider — callSite resolution", () => {
337
337
  expect(config.max_tokens).toBe(expected.maxTokens as number);
338
338
  });
339
339
 
340
- test("live-voice front-door call sites reach OpenAI with reasoning off", async () => {
340
+ test("latency-sensitive live-voice call sites reach OpenAI with reasoning off", async () => {
341
341
  // The `latency-optimized` pin's whole value is time-to-first-token, and on
342
342
  // an OpenAI upstream that depends entirely on disabled thinking being
343
343
  // encoded as `effort: "none"`. OpenAI-compatible APIs reason by default
@@ -351,7 +351,10 @@ describe("RetryProvider — callSite resolution", () => {
351
351
  setLlmConfig({});
352
352
 
353
353
  const expected = CODE_DEFAULT_PROFILE_ENTRIES["latency-optimized"];
354
- for (const callSite of ["voiceFrontDoor", "voiceFrontDecision"] as const) {
354
+ for (const callSite of [
355
+ "voiceFrontDoor",
356
+ "voiceProgressNarration",
357
+ ] as const) {
355
358
  let seen: SendMessageOptions | undefined;
356
359
  const wrapped = new RetryProvider(
357
360
  makeProvider("openai", (options) => {
@@ -367,6 +370,26 @@ describe("RetryProvider — callSite resolution", () => {
367
370
  }
368
371
  });
369
372
 
373
+ test("memory-v3 selection does not inherit high effort", async () => {
374
+ setLlmConfig({ defaultProvider: { provider: "anthropic" } });
375
+
376
+ let seen: SendMessageOptions | undefined;
377
+ const wrapped = new RetryProvider(
378
+ makeProvider("anthropic", (options) => {
379
+ seen = options;
380
+ }),
381
+ );
382
+
383
+ await wrapped.sendMessage(DUMMY_MESSAGES, {
384
+ config: { callSite: "memoryV3SelectL2" },
385
+ });
386
+
387
+ const config = seen?.config as Record<string, unknown>;
388
+ expect(config.effort).toBe("low");
389
+ expect(config.thinking).toEqual({ type: "disabled" });
390
+ expect(config.temperature).toBe(0);
391
+ });
392
+
370
393
  test("propagates resolved effort/speed/temperature; omits server-side fields", async () => {
371
394
  setLlmConfig({
372
395
  callSites: {
@@ -0,0 +1,170 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import type Anthropic from "@anthropic-ai/sdk";
4
+
5
+ import { AnthropicProvider, MAX_PAUSE_TURN_CONTINUATIONS } from "../client.js";
6
+
7
+ function makeMessage(overrides: {
8
+ stop_reason: Anthropic.Message["stop_reason"];
9
+ content: Anthropic.ContentBlock[];
10
+ usage?: Partial<Anthropic.Usage>;
11
+ }): Anthropic.Message {
12
+ return {
13
+ id: "msg_test",
14
+ type: "message",
15
+ role: "assistant",
16
+ model: "claude-opus-4-6",
17
+ stop_sequence: null,
18
+ content: overrides.content,
19
+ stop_reason: overrides.stop_reason,
20
+ usage: {
21
+ input_tokens: 0,
22
+ output_tokens: 0,
23
+ cache_creation_input_tokens: null,
24
+ cache_read_input_tokens: null,
25
+ ...overrides.usage,
26
+ } as Anthropic.Usage,
27
+ } as Anthropic.Message;
28
+ }
29
+
30
+ function textBlock(text: string): Anthropic.ContentBlock {
31
+ return { type: "text", text, citations: null } as Anthropic.ContentBlock;
32
+ }
33
+
34
+ function serverToolUseBlock(id: string): Anthropic.ContentBlock {
35
+ return {
36
+ type: "server_tool_use",
37
+ id,
38
+ name: "web_search",
39
+ input: { query: "test" },
40
+ } as Anthropic.ContentBlock;
41
+ }
42
+
43
+ /**
44
+ * Stub the SDK client on a provider instance. Every stream call records its
45
+ * params and resolves to the next response in `responses` (repeating the last
46
+ * one once exhausted). Both the plain and beta endpoints share the recorder —
47
+ * which endpoint fires depends on the model's beta set.
48
+ */
49
+ function stubProvider(responses: Anthropic.Message[]): {
50
+ provider: AnthropicProvider;
51
+ calls: Anthropic.MessageStreamParams[];
52
+ } {
53
+ const provider = new AnthropicProvider("test-key", "claude-opus-4-6");
54
+ const calls: Anthropic.MessageStreamParams[] = [];
55
+ const stream = (params: Anthropic.MessageStreamParams) => {
56
+ calls.push(params);
57
+ const response =
58
+ responses[Math.min(calls.length - 1, responses.length - 1)];
59
+ return {
60
+ on() {
61
+ return this;
62
+ },
63
+ async finalMessage() {
64
+ return response;
65
+ },
66
+ };
67
+ };
68
+ (provider as unknown as { client: unknown }).client = {
69
+ baseURL: "https://api.anthropic.com",
70
+ messages: { stream },
71
+ beta: { messages: { stream } },
72
+ };
73
+ return { provider, calls };
74
+ }
75
+
76
+ describe("pause_turn continuation", () => {
77
+ test("resends the paused assistant content as-is and merges the segments", async () => {
78
+ const pausedContent = [
79
+ textBlock("Searching..."),
80
+ serverToolUseBlock("srvtoolu_1"),
81
+ ];
82
+ const { provider, calls } = stubProvider([
83
+ makeMessage({
84
+ stop_reason: "pause_turn",
85
+ content: pausedContent,
86
+ usage: { input_tokens: 10, output_tokens: 5 },
87
+ }),
88
+ makeMessage({
89
+ stop_reason: "end_turn",
90
+ content: [textBlock("Done")],
91
+ usage: {
92
+ input_tokens: 20,
93
+ output_tokens: 7,
94
+ cache_creation_input_tokens: 3,
95
+ cache_read_input_tokens: 4,
96
+ },
97
+ }),
98
+ ]);
99
+
100
+ const result = await provider.sendMessage([
101
+ { role: "user", content: [{ type: "text", text: "search something" }] },
102
+ ]);
103
+
104
+ expect(calls.length).toBe(2);
105
+ // The continuation appends the paused assistant message unchanged.
106
+ expect(calls[1].messages.length).toBe(calls[0].messages.length + 1);
107
+ const appended = calls[1].messages[calls[1].messages.length - 1];
108
+ expect(appended.role).toBe("assistant");
109
+ expect(appended.content).toBe(pausedContent);
110
+
111
+ // Content is the concatenation of the paused segment and the final one.
112
+ expect(result.content).toEqual([
113
+ { type: "text", text: "Searching..." },
114
+ {
115
+ type: "server_tool_use",
116
+ id: "srvtoolu_1",
117
+ name: "web_search",
118
+ input: { query: "test" },
119
+ },
120
+ { type: "text", text: "Done" },
121
+ ]);
122
+ expect(result.stopReason).toBe("end_turn");
123
+
124
+ // Usage sums across both billed requests (input includes cache tokens).
125
+ expect(result.usage.inputTokens).toBe(10 + 20 + 3 + 4);
126
+ expect(result.usage.outputTokens).toBe(12);
127
+ expect(result.usage.cacheCreationInputTokens).toBe(3);
128
+ expect(result.usage.cacheReadInputTokens).toBe(4);
129
+ });
130
+
131
+ test("a turn that never pauses issues a single request", async () => {
132
+ const { provider, calls } = stubProvider([
133
+ makeMessage({
134
+ stop_reason: "end_turn",
135
+ content: [textBlock("Hi")],
136
+ usage: { input_tokens: 8, output_tokens: 2 },
137
+ }),
138
+ ]);
139
+
140
+ const result = await provider.sendMessage([
141
+ { role: "user", content: [{ type: "text", text: "hello" }] },
142
+ ]);
143
+
144
+ expect(calls.length).toBe(1);
145
+ expect(result.content).toEqual([{ type: "text", text: "Hi" }]);
146
+ expect(result.stopReason).toBe("end_turn");
147
+ expect(result.usage.inputTokens).toBe(8);
148
+ expect(result.usage.cacheCreationInputTokens).toBeUndefined();
149
+ expect(result.usage.cacheReadInputTokens).toBeUndefined();
150
+ });
151
+
152
+ test("stops resending at the continuation cap and returns the paused response", async () => {
153
+ const { provider, calls } = stubProvider([
154
+ makeMessage({
155
+ stop_reason: "pause_turn",
156
+ content: [serverToolUseBlock("srvtoolu_stuck")],
157
+ usage: { input_tokens: 1, output_tokens: 1 },
158
+ }),
159
+ ]);
160
+
161
+ const result = await provider.sendMessage([
162
+ { role: "user", content: [{ type: "text", text: "search forever" }] },
163
+ ]);
164
+
165
+ expect(calls.length).toBe(1 + MAX_PAUSE_TURN_CONTINUATIONS);
166
+ expect(result.stopReason).toBe("pause_turn");
167
+ // Every billed request's usage is accounted for.
168
+ expect(result.usage.inputTokens).toBe(1 + MAX_PAUSE_TURN_CONTINUATIONS);
169
+ });
170
+ });