@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
@@ -537,50 +537,47 @@ describe("OpenAIChatCompletionsProvider reasoning parsing", () => {
537
537
  });
538
538
  });
539
539
 
540
- describe("reasoning opt-out rejection fallback", () => {
541
- function stubProviderWithErrors(
542
- errors: unknown[],
543
- chunks: MockChunk[],
544
- ): { provider: OpenAIChatCompletionsProvider; requests: unknown[] } {
545
- const provider = new OpenAIChatCompletionsProvider(
546
- "test-key",
547
- "test-model",
548
- );
549
- const requests: unknown[] = [];
550
- const pending = [...errors];
551
- (provider as unknown as { client: unknown }).client = {
552
- chat: {
553
- completions: {
554
- create: async (params: unknown) => {
555
- // Snapshot: the fallback mutates `params` between attempts.
556
- requests.push(JSON.parse(JSON.stringify(params)));
557
- const error = pending.shift();
558
- if (error !== undefined) {
559
- throw error;
560
- }
561
- return makeStream(chunks);
562
- },
540
+ function stubProviderWithErrors(
541
+ errors: unknown[],
542
+ chunks: MockChunk[],
543
+ ): { provider: OpenAIChatCompletionsProvider; requests: unknown[] } {
544
+ const provider = new OpenAIChatCompletionsProvider("test-key", "test-model");
545
+ const requests: unknown[] = [];
546
+ const pending = [...errors];
547
+ (provider as unknown as { client: unknown }).client = {
548
+ chat: {
549
+ completions: {
550
+ create: async (params: unknown) => {
551
+ // Snapshot: the fallback mutates `params` between attempts.
552
+ requests.push(JSON.parse(JSON.stringify(params)));
553
+ const error = pending.shift();
554
+ if (error !== undefined) {
555
+ throw error;
556
+ }
557
+ return makeStream(chunks);
563
558
  },
564
559
  },
565
- };
566
- return { provider, requests };
567
- }
568
-
569
- const okChunks: MockChunk[] = [
570
- {
571
- choices: [{ delta: { content: "ok" }, finish_reason: "stop" }],
572
- usage: { prompt_tokens: 1, completion_tokens: 1 },
573
560
  },
574
- ];
561
+ };
562
+ return { provider, requests };
563
+ }
564
+
565
+ const OK_CHUNKS: MockChunk[] = [
566
+ {
567
+ choices: [{ delta: { content: "ok" }, finish_reason: "stop" }],
568
+ usage: { prompt_tokens: 1, completion_tokens: 1 },
569
+ },
570
+ ];
575
571
 
576
- function rejection(message: string, status = 400): Error {
577
- return Object.assign(new Error(message), { status });
578
- }
572
+ function rejection(message: string, status = 400): Error {
573
+ return Object.assign(new Error(message), { status });
574
+ }
579
575
 
576
+ describe("reasoning opt-out rejection fallback", () => {
580
577
  test("retries once without reasoning params when a model rejects the explicit opt-out", async () => {
581
578
  const { provider, requests } = stubProviderWithErrors(
582
579
  [rejection("reasoning_effort 'none' is not supported for this model")],
583
- okChunks,
580
+ OK_CHUNKS,
584
581
  );
585
582
 
586
583
  const response = await provider.sendMessage(
@@ -626,7 +623,7 @@ describe("reasoning opt-out rejection fallback", () => {
626
623
  // can only fire off the normalized upstream detail.
627
624
  expect(/reasoning/i.test(wrapped.message)).toBe(false);
628
625
 
629
- const { provider, requests } = stubProviderWithErrors([wrapped], okChunks);
626
+ const { provider, requests } = stubProviderWithErrors([wrapped], OK_CHUNKS);
630
627
 
631
628
  const response = await provider.sendMessage(
632
629
  [{ role: "user", content: [{ type: "text", text: "hi" }] }],
@@ -651,7 +648,7 @@ describe("reasoning opt-out rejection fallback", () => {
651
648
  test("does not retry when the request did not opt out of reasoning", async () => {
652
649
  const { provider, requests } = stubProviderWithErrors(
653
650
  [rejection("reasoning_effort is invalid")],
654
- okChunks,
651
+ OK_CHUNKS,
655
652
  );
656
653
 
657
654
  await expect(
@@ -666,7 +663,7 @@ describe("reasoning opt-out rejection fallback", () => {
666
663
  test("does not retry a 4xx that does not name reasoning", async () => {
667
664
  const { provider, requests } = stubProviderWithErrors(
668
665
  [rejection("invalid api key")],
669
- okChunks,
666
+ OK_CHUNKS,
670
667
  );
671
668
 
672
669
  await expect(
@@ -681,7 +678,7 @@ describe("reasoning opt-out rejection fallback", () => {
681
678
  test("does not retry server errors", async () => {
682
679
  const { provider, requests } = stubProviderWithErrors(
683
680
  [rejection("reasoning backend unavailable", 500)],
684
- okChunks,
681
+ OK_CHUNKS,
685
682
  );
686
683
 
687
684
  await expect(
@@ -694,6 +691,132 @@ describe("reasoning opt-out rejection fallback", () => {
694
691
  });
695
692
  });
696
693
 
694
+ describe("thinking-mode tool_choice rejection fallback", () => {
695
+ test("retries once without tool_choice when thinking mode rejects it", async () => {
696
+ const { provider, requests } = stubProviderWithErrors(
697
+ [rejection("Thinking mode does not support this tool_choice")],
698
+ OK_CHUNKS,
699
+ );
700
+
701
+ const response = await provider.sendMessage(
702
+ [{ role: "user", content: [{ type: "text", text: "hi" }] }],
703
+ {
704
+ tools: [
705
+ {
706
+ name: "bash",
707
+ description: "Run a shell command",
708
+ input_schema: { type: "object", properties: {} },
709
+ },
710
+ ],
711
+ config: { tool_choice: { type: "none" }, effort: "high" },
712
+ },
713
+ );
714
+
715
+ expect(requests).toHaveLength(2);
716
+ const first = requests[0] as {
717
+ tool_choice?: string;
718
+ reasoning_effort?: string;
719
+ };
720
+ const second = requests[1] as {
721
+ tool_choice?: string;
722
+ reasoning_effort?: string;
723
+ };
724
+ expect(first.tool_choice).toBe("none");
725
+ expect(first.reasoning_effort).toBe("high");
726
+ expect(second.tool_choice).toBeUndefined();
727
+ expect(second.reasoning_effort).toBe("high");
728
+ const text = response.content.find((b) => b.type === "text") as
729
+ | { type: "text"; text: string }
730
+ | undefined;
731
+ expect(text?.text).toBe("ok");
732
+ });
733
+
734
+ test("retries once for an OpenRouter-wrapped thinking-mode tool_choice rejection", async () => {
735
+ const wrapped = new OpenAI.APIError(
736
+ 400,
737
+ {
738
+ code: 400,
739
+ message: "Provider returned error",
740
+ metadata: {
741
+ raw: "[invalid_request_error] Thinking mode does not support this tool_choice",
742
+ provider_name: "deepseek",
743
+ },
744
+ },
745
+ undefined,
746
+ new Headers(),
747
+ );
748
+ expect(/tool_choice/i.test(wrapped.message)).toBe(false);
749
+
750
+ const { provider, requests } = stubProviderWithErrors([wrapped], OK_CHUNKS);
751
+
752
+ await provider.sendMessage(
753
+ [{ role: "user", content: [{ type: "text", text: "hi" }] }],
754
+ {
755
+ tools: [
756
+ {
757
+ name: "bash",
758
+ description: "Run a shell command",
759
+ input_schema: { type: "object", properties: {} },
760
+ },
761
+ ],
762
+ config: { tool_choice: { type: "none" }, effort: "high" },
763
+ },
764
+ );
765
+
766
+ expect(requests).toHaveLength(2);
767
+ expect((requests[0] as { tool_choice?: string }).tool_choice).toBe("none");
768
+ expect((requests[1] as { tool_choice?: string }).tool_choice).toBeUndefined();
769
+ });
770
+
771
+ test("does not retry a 4xx that does not name tool_choice", async () => {
772
+ const { provider, requests } = stubProviderWithErrors(
773
+ [rejection("invalid api key")],
774
+ OK_CHUNKS,
775
+ );
776
+
777
+ await expect(
778
+ provider.sendMessage(
779
+ [{ role: "user", content: [{ type: "text", text: "hi" }] }],
780
+ {
781
+ tools: [
782
+ {
783
+ name: "bash",
784
+ description: "Run a shell command",
785
+ input_schema: { type: "object", properties: {} },
786
+ },
787
+ ],
788
+ config: { tool_choice: { type: "none" }, effort: "high" },
789
+ },
790
+ ),
791
+ ).rejects.toThrow();
792
+ expect(requests).toHaveLength(1);
793
+ });
794
+
795
+ test("does not retry thinking-mode tool_choice 500s", async () => {
796
+ const { provider, requests } = stubProviderWithErrors(
797
+ [rejection("Thinking mode does not support this tool_choice", 500)],
798
+ OK_CHUNKS,
799
+ );
800
+
801
+ await expect(
802
+ provider.sendMessage(
803
+ [{ role: "user", content: [{ type: "text", text: "hi" }] }],
804
+ {
805
+ tools: [
806
+ {
807
+ name: "bash",
808
+ description: "Run a shell command",
809
+ input_schema: { type: "object", properties: {} },
810
+ },
811
+ ],
812
+ config: { tool_choice: { type: "none" }, effort: "high" },
813
+ },
814
+ ),
815
+ ).rejects.toThrow();
816
+ expect(requests).toHaveLength(1);
817
+ });
818
+ });
819
+
697
820
  describe("OpenAIChatCompletionsProvider cache usage parsing", () => {
698
821
  test("maps prompt_tokens_details cache fields into usage", async () => {
699
822
  // prompt_tokens is the inclusive total; the cached subset surfaces as
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import type { Message, ToolDefinition } from "../../types.js";
4
4
  import {
5
+ isThinkingEnabledOnWire,
5
6
  mapNeutralToolChoice,
6
7
  OpenAIChatCompletionsProvider,
7
8
  } from "../chat-completions-provider.js";
@@ -23,11 +24,17 @@ const USER_MESSAGE: Message[] = [
23
24
  * Stub the SDK client so we can capture the outgoing chat.completions.create
24
25
  * params without hitting the network.
25
26
  */
26
- function stubChatProvider(): {
27
+ function stubChatProvider(
28
+ options?: ConstructorParameters<typeof OpenAIChatCompletionsProvider>[2],
29
+ ): {
27
30
  provider: OpenAIChatCompletionsProvider;
28
31
  requests: Array<Record<string, unknown>>;
29
32
  } {
30
- const provider = new OpenAIChatCompletionsProvider("test-key", "test-model");
33
+ const provider = new OpenAIChatCompletionsProvider(
34
+ "test-key",
35
+ "test-model",
36
+ options,
37
+ );
31
38
  const requests: Array<Record<string, unknown>> = [];
32
39
  (provider as unknown as { client: unknown }).client = {
33
40
  chat: {
@@ -49,6 +56,23 @@ function stubChatProvider(): {
49
56
  return { provider, requests };
50
57
  }
51
58
 
59
+ describe("isThinkingEnabledOnWire", () => {
60
+ test("detects flat reasoning_effort and nested reasoning flags", () => {
61
+ expect(isThinkingEnabledOnWire({})).toBe(false);
62
+ expect(isThinkingEnabledOnWire({ reasoning_effort: "none" })).toBe(false);
63
+ expect(isThinkingEnabledOnWire({ reasoning_effort: "high" })).toBe(true);
64
+ expect(isThinkingEnabledOnWire({ reasoning: { effort: "none" } })).toBe(
65
+ false,
66
+ );
67
+ expect(isThinkingEnabledOnWire({ reasoning: { effort: "medium" } })).toBe(
68
+ true,
69
+ );
70
+ expect(isThinkingEnabledOnWire({ reasoning: { enabled: true } })).toBe(
71
+ true,
72
+ );
73
+ });
74
+ });
75
+
52
76
  describe("mapNeutralToolChoice (chat-completions wire format)", () => {
53
77
  // Each neutral tool_choice variant maps to its OpenAI-compatible form.
54
78
  test("maps the Anthropic-shaped union to OpenAI's tool_choice values", () => {
@@ -144,4 +168,103 @@ describe("OpenAIChatCompletionsProvider tool_choice wiring", () => {
144
168
  expect(requests[0].tools).toBeUndefined();
145
169
  expect(requests[0].tool_choice).toBeUndefined();
146
170
  });
171
+
172
+ // `"auto"` is the chat-completions default when tools are present. Sending it
173
+ // alongside reasoning_effort 400s DeepSeek thinking mode, so it is omitted.
174
+ test("omits redundant tool_choice auto when thinking is on the wire", async () => {
175
+ const { provider, requests } = stubChatProvider();
176
+
177
+ await provider.sendMessage(USER_MESSAGE, {
178
+ tools: TOOLS,
179
+ config: { tool_choice: { type: "auto" }, effort: "high" },
180
+ });
181
+
182
+ expect(requests[0].reasoning_effort).toBe("high");
183
+ expect(requests[0].tool_choice).toBeUndefined();
184
+ expect(requests[0].tools).toBeDefined();
185
+ });
186
+
187
+ test("omits redundant tool_choice auto when nested reasoning.enabled is set", async () => {
188
+ const { provider, requests } = stubChatProvider({
189
+ extraCreateParams: { reasoning: { enabled: true } },
190
+ });
191
+
192
+ await provider.sendMessage(USER_MESSAGE, {
193
+ tools: TOOLS,
194
+ config: { tool_choice: { type: "auto" } },
195
+ });
196
+
197
+ expect(requests[0].tool_choice).toBeUndefined();
198
+ });
199
+
200
+ test("forwards tool_choice auto when thinking is off", async () => {
201
+ const { provider, requests } = stubChatProvider();
202
+
203
+ await provider.sendMessage(USER_MESSAGE, {
204
+ tools: TOOLS,
205
+ config: { tool_choice: { type: "auto" } },
206
+ });
207
+
208
+ expect(requests[0].tool_choice).toBe("auto");
209
+ });
210
+
211
+ // Catalog providers (Fireworks, Together) honor `none` with thinking.
212
+ test("forwards tool_choice none with thinking when omitToolChoiceWhenReasoning is off", async () => {
213
+ const { provider, requests } = stubChatProvider();
214
+
215
+ await provider.sendMessage(USER_MESSAGE, {
216
+ tools: TOOLS,
217
+ config: { tool_choice: { type: "none" }, effort: "high" },
218
+ });
219
+
220
+ expect(requests[0].reasoning_effort).toBe("high");
221
+ expect(requests[0].tool_choice).toBe("none");
222
+ });
223
+
224
+ test("forwards a forced tool_choice with thinking when omitToolChoiceWhenReasoning is off", async () => {
225
+ const { provider, requests } = stubChatProvider();
226
+
227
+ await provider.sendMessage(USER_MESSAGE, {
228
+ tools: TOOLS,
229
+ config: { tool_choice: { type: "tool", name: "bash" }, effort: "high" },
230
+ });
231
+
232
+ expect(requests[0].tool_choice).toEqual({
233
+ type: "function",
234
+ function: { name: "bash" },
235
+ });
236
+ });
237
+
238
+ test("omits every tool_choice in thinking mode when omitToolChoiceWhenReasoning is on", async () => {
239
+ const { provider, requests } = stubChatProvider({
240
+ omitToolChoiceWhenReasoning: true,
241
+ });
242
+
243
+ await provider.sendMessage(USER_MESSAGE, {
244
+ tools: TOOLS,
245
+ config: { tool_choice: { type: "none" }, effort: "high" },
246
+ });
247
+ await provider.sendMessage(USER_MESSAGE, {
248
+ tools: TOOLS,
249
+ config: { tool_choice: { type: "tool", name: "bash" }, effort: "high" },
250
+ });
251
+
252
+ expect(requests[0].reasoning_effort).toBe("high");
253
+ expect(requests[0].tool_choice).toBeUndefined();
254
+ expect(requests[1].tool_choice).toBeUndefined();
255
+ });
256
+
257
+ test("still forwards tool_choice when omitToolChoiceWhenReasoning is on but thinking is off", async () => {
258
+ const { provider, requests } = stubChatProvider({
259
+ omitToolChoiceWhenReasoning: true,
260
+ });
261
+
262
+ await provider.sendMessage(USER_MESSAGE, {
263
+ tools: TOOLS,
264
+ config: { tool_choice: { type: "none" } },
265
+ });
266
+
267
+ expect(requests[0].reasoning_effort).toBeUndefined();
268
+ expect(requests[0].tool_choice).toBe("none");
269
+ });
147
270
  });
@@ -5,6 +5,7 @@ import { isAbortReason } from "../../util/abort-reasons.js";
5
5
  import { ProviderError, type ProviderErrorReason } from "../../util/errors.js";
6
6
  import { getLogger } from "../../util/logger.js";
7
7
  import { extractRetryAfterMs } from "../../util/retry.js";
8
+ import { partialTagSuffix as sharedPartialTagSuffix } from "../../util/think-tag-stream.js";
8
9
  import { escapeXmlAttr } from "../../util/xml.js";
9
10
  import {
10
11
  base64Source,
@@ -84,7 +85,17 @@ export function detectOpenAICompatibleContextOverflow(
84
85
  /context.?length.?exceeded|context.?window.?exceeded|prompt.?is.?too.?long|prompt_too_long|input.?too.?long|too.?many.?(?:input.?)?tokens|maximum.?context/i.test(
85
86
  message,
86
87
  );
87
- if (!codeMatches && !messageMatches) {
88
+ // string_above_max_length is OpenAI's generic oversized-string validation
89
+ // code, so only treat it as overflow when the error points at a message
90
+ // content part (e.g. "Invalid 'input[191].content[1].text': string too
91
+ // long" — OpenAI's per-part 10 MiB cap). The overflow ladder can shrink
92
+ // message content (media stubbing collapses a file's extracted_text to a
93
+ // preview) but cannot fix other oversized fields like tool definitions.
94
+ const oversizedContentPart =
95
+ /string.?too.?long|string_above_max_length/i.test(
96
+ `${code ?? ""} ${message}`,
97
+ ) && /\b(?:input|messages)\[\d+\]\.content/i.test(message);
98
+ if (!codeMatches && !messageMatches && !oversizedContentPart) {
88
99
  return null;
89
100
  }
90
101
  // OpenAI-compatible providers rarely report usable token counts; best-effort extract.
@@ -166,6 +177,13 @@ export interface OpenAIChatCompletionsProviderOptions {
166
177
  * with minimax-m3 on Fireworks). Off by default; scalars/arrays unaffected.
167
178
  * See {@link coerceObjectParamsToJsonString}. */
168
179
  coerceObjectArgsToJsonString?: boolean;
180
+ /** Drop `tool_choice` when thinking/reasoning is on the wire. Strict
181
+ * OpenAI-compatible reasoning upstreams (DeepSeek thinking mode) reject any
182
+ * explicit `tool_choice` with `Thinking mode does not support this
183
+ * tool_choice`. Off by default so catalog providers that honor the combo
184
+ * (Fireworks, Together) keep sending `none` / forced choices. Enabled for
185
+ * the generic `openai-compatible` adapter, whose upstream is unknown. */
186
+ omitToolChoiceWhenReasoning?: boolean;
169
187
  }
170
188
 
171
189
  const log = getLogger("chat-completions");
@@ -208,12 +226,29 @@ export function clampReasoningEffort(
208
226
  : value;
209
227
  }
210
228
 
229
+ /** Human-readable text from an OpenAI-compatible error, including wrapped
230
+ * upstream detail (OpenRouter `metadata.raw`). Used by the one-shot
231
+ * compatibility retries so a generic SDK wrapper message cannot hide the
232
+ * real reason. */
233
+ function openaiCompatErrorHaystack(error: unknown): string {
234
+ return error instanceof OpenAI.APIError
235
+ ? normalizedErrorText(normalizeOpenAIAPIError(error))
236
+ : error instanceof Error
237
+ ? error.message
238
+ : String(error);
239
+ }
240
+
241
+ function isClientErrorStatus(error: unknown): boolean {
242
+ const status = (error as { status?: unknown }).status;
243
+ return typeof status === "number" && status >= 400 && status < 500;
244
+ }
245
+
211
246
  /**
212
247
  * True when the request carried an explicit reasoning opt-out (`"none"` sent
213
248
  * as flat `reasoning_effort` or nested `reasoning.effort`) and the provider
214
249
  * rejected it with a 4xx that names the reasoning field. Reasoning-only
215
250
  * models (e.g. DeepSeek R1) reject the opt-out rather than ignore it; that
216
- * one case is worth a single retry with the reasoning params stripped —
251
+ * one case is worth a single retry with the reasoning params stripped:
217
252
  * model-default reasoning beats a hard failure.
218
253
  */
219
254
  function isReasoningOptOutRejection(error: unknown, params: unknown): boolean {
@@ -229,22 +264,58 @@ function isReasoningOptOutRejection(error: unknown, params: unknown): boolean {
229
264
  if (!optedOut) {
230
265
  return false;
231
266
  }
232
- const status = (error as { status?: unknown }).status;
233
- if (typeof status !== "number" || status < 400 || status >= 500) {
267
+ if (!isClientErrorStatus(error)) {
268
+ return false;
269
+ }
270
+ return /reasoning/i.test(openaiCompatErrorHaystack(error));
271
+ }
272
+
273
+ /**
274
+ * True when thinking/reasoning is active on the outbound chat-completions
275
+ * body: a non-`"none"` `reasoning_effort`, a nested `reasoning.effort`, or
276
+ * `reasoning.enabled: true` (OpenRouter / Vercel AI Gateway).
277
+ */
278
+ export function isThinkingEnabledOnWire(params: unknown): boolean {
279
+ const p = params as {
280
+ reasoning_effort?: unknown;
281
+ reasoning?: { effort?: unknown; enabled?: unknown } | null;
282
+ };
283
+ const nested = p.reasoning;
284
+ if (nested && typeof nested === "object") {
285
+ if (nested.enabled === true) {
286
+ return true;
287
+ }
288
+ if (typeof nested.effort === "string" && nested.effort !== "none") {
289
+ return true;
290
+ }
291
+ }
292
+ return (
293
+ typeof p.reasoning_effort === "string" && p.reasoning_effort !== "none"
294
+ );
295
+ }
296
+
297
+ /**
298
+ * True when the request sent an explicit `tool_choice` and the provider
299
+ * rejected it because thinking/reasoning mode forbids that parameter.
300
+ * DeepSeek thinking mode 400s with `Thinking mode does not support this
301
+ * tool_choice` for any explicit value, including `"auto"` and `"none"`.
302
+ * One retry without `tool_choice` lets the same provider succeed instead of
303
+ * failing over to a different backend.
304
+ */
305
+ function isThinkingModeToolChoiceRejection(
306
+ error: unknown,
307
+ params: unknown,
308
+ ): boolean {
309
+ const p = params as { tool_choice?: unknown };
310
+ if (p.tool_choice === undefined) {
311
+ return false;
312
+ }
313
+ if (!isClientErrorStatus(error)) {
234
314
  return false;
235
315
  }
236
- // OpenRouter wraps upstream 4xxs in a generic "Provider returned error" and
237
- // stashes the real reason under `metadata.raw`, which `normalizeOpenAIAPIError`
238
- // promotes into the normalized fields. Scan those, not just `error.message` —
239
- // otherwise the wrapped reasoning rejection is missed and this one-shot
240
- // fallback never fires.
241
- const haystack =
242
- error instanceof OpenAI.APIError
243
- ? normalizedErrorText(normalizeOpenAIAPIError(error))
244
- : error instanceof Error
245
- ? error.message
246
- : String(error);
247
- return /reasoning/i.test(haystack);
316
+ return /does not support this tool_choice/i.test(
317
+ openaiCompatErrorHaystack(error),
318
+ );
248
319
  }
249
320
 
250
321
  /**
@@ -293,13 +364,11 @@ const OPENAI_SUPPORTED_IMAGE_TYPES = new Set([
293
364
  "image/webp",
294
365
  ]);
295
366
 
367
+ // Think-tag scanning primitives are shared with the TTS reasoning filter
368
+ // (util/think-tag-stream.ts) so the two stream parsers cannot drift. This
369
+ // provider keeps its exact historical behavior: case-sensitive, <think> only.
296
370
  function partialTagSuffix(text: string, tag: string): number {
297
- for (let len = Math.min(text.length, tag.length - 1); len > 0; len--) {
298
- if (text.endsWith(tag.substring(0, len))) {
299
- return len;
300
- }
301
- }
302
- return 0;
371
+ return sharedPartialTagSuffix(text, [tag], false);
303
372
  }
304
373
 
305
374
  /**
@@ -325,6 +394,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
325
394
  | undefined;
326
395
  private backfillEmptyAssistantContent: boolean;
327
396
  private coerceObjectArgsToJsonString: boolean;
397
+ private omitToolChoiceWhenReasoning: boolean;
328
398
 
329
399
  constructor(
330
400
  apiKey: string,
@@ -354,6 +424,8 @@ export class OpenAIChatCompletionsProvider implements Provider {
354
424
  options.backfillEmptyAssistantContent ?? false;
355
425
  this.coerceObjectArgsToJsonString =
356
426
  options.coerceObjectArgsToJsonString ?? false;
427
+ this.omitToolChoiceWhenReasoning =
428
+ options.omitToolChoiceWhenReasoning ?? false;
357
429
  }
358
430
 
359
431
  get defaultModel(): string {
@@ -460,11 +532,24 @@ export class OpenAIChatCompletionsProvider implements Provider {
460
532
 
461
533
  // Honor a caller-supplied tool_choice (e.g. `{ type: "none" }` to force
462
534
  // a text-only answer, or `{ type: "tool", name }` for a forced call).
463
- // Only meaningful when tools are present — OpenAI rejects a named or
535
+ // Only meaningful when tools are present: OpenAI rejects a named or
464
536
  // "required" choice with no tools.
537
+ //
538
+ // Strict reasoning upstreams (DeepSeek thinking mode) reject any
539
+ // explicit tool_choice, including `"auto"` (the API default when tools
540
+ // are present) and `"none"`. Omit `"auto"` whenever thinking is on the
541
+ // wire. Catalog providers that honor `none` / forced choices still
542
+ // receive them; the generic openai-compatible adapter drops every
543
+ // explicit value in thinking mode via `omitToolChoiceWhenReasoning`.
465
544
  const toolChoice = mapNeutralToolChoice(configObj?.tool_choice);
466
545
  if (toolChoice !== undefined) {
467
- params.tool_choice = toolChoice;
546
+ const thinkingOn = isThinkingEnabledOnWire(params);
547
+ const skipAutoDefault = thinkingOn && toolChoice === "auto";
548
+ const skipAllChoices =
549
+ thinkingOn && this.omitToolChoiceWhenReasoning;
550
+ if (!skipAutoDefault && !skipAllChoices) {
551
+ params.tool_choice = toolChoice;
552
+ }
468
553
  }
469
554
  }
470
555
 
@@ -564,20 +649,32 @@ export class OpenAIChatCompletionsProvider implements Provider {
564
649
  try {
565
650
  stream = await createStream();
566
651
  } catch (error) {
567
- if (!isReasoningOptOutRejection(error, params)) {
652
+ if (isReasoningOptOutRejection(error, params)) {
653
+ log.warn(
654
+ {
655
+ provider: this.name,
656
+ model: modelOverride ?? this.model,
657
+ error: error instanceof Error ? error.message : String(error),
658
+ },
659
+ "Model rejected the explicit reasoning opt-out; retrying without reasoning params",
660
+ );
661
+ delete params.reasoning_effort;
662
+ delete (params as unknown as Record<string, unknown>).reasoning;
663
+ stream = await createStream();
664
+ } else if (isThinkingModeToolChoiceRejection(error, params)) {
665
+ log.warn(
666
+ {
667
+ provider: this.name,
668
+ model: modelOverride ?? this.model,
669
+ error: error instanceof Error ? error.message : String(error),
670
+ },
671
+ "Upstream rejected tool_choice in thinking mode; retrying without tool_choice",
672
+ );
673
+ delete params.tool_choice;
674
+ stream = await createStream();
675
+ } else {
568
676
  throw error;
569
677
  }
570
- log.warn(
571
- {
572
- provider: this.name,
573
- model: modelOverride ?? this.model,
574
- error: error instanceof Error ? error.message : String(error),
575
- },
576
- "Model rejected the explicit reasoning opt-out; retrying without reasoning params",
577
- );
578
- delete params.reasoning_effort;
579
- delete (params as unknown as Record<string, unknown>).reasoning;
580
- stream = await createStream();
581
678
  }
582
679
 
583
680
  for await (const chunk of stream) {
@@ -13,9 +13,10 @@ export const CODEX_SUBSCRIPTION_MODEL_IDS: ReadonlySet<string> = new Set([
13
13
  "gpt-5.6-terra",
14
14
  "gpt-5.6-luna",
15
15
  "gpt-5.5",
16
+ // OpenAI retires these two from ChatGPT sign-in on 2026-08-31; API-key
17
+ // auth is unaffected.
16
18
  "gpt-5.4",
17
19
  "gpt-5.4-mini",
18
- "gpt-5.3-codex",
19
20
  ]);
20
21
 
21
22
  /** True when `model` is allowlisted for Codex subscription routing. */