@vellumai/assistant 0.12.1-staging.1 → 0.12.1

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 (404) hide show
  1. package/AGENTS.md +0 -4
  2. package/ARCHITECTURE.md +12 -11
  3. package/docs/architecture/turn-actor.md +8 -15
  4. package/openapi.yaml +1 -291
  5. package/package.json +1 -1
  6. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  7. package/src/__tests__/app-compiler.test.ts +0 -6
  8. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  9. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  10. package/src/__tests__/app-source-watcher.test.ts +218 -0
  11. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  12. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  13. package/src/__tests__/computer-use-tools.test.ts +5 -17
  14. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  15. package/src/__tests__/config-schema.test.ts +29 -28
  16. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  17. package/src/__tests__/config-watcher.test.ts +8 -23
  18. package/src/__tests__/connection-model-compat.test.ts +2 -2
  19. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  20. package/src/__tests__/conversation-pairing.test.ts +0 -26
  21. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  22. package/src/__tests__/conversation-queue.test.ts +207 -48
  23. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  24. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  25. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  26. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  27. package/src/__tests__/conversation-title-service.test.ts +10 -14
  28. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  29. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  30. package/src/__tests__/credential-record-retire.test.ts +1 -171
  31. package/src/__tests__/credential-routes.test.ts +3 -212
  32. package/src/__tests__/credential-security-invariants.test.ts +1 -2
  33. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  34. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  35. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  36. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  37. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  38. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  39. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  40. package/src/__tests__/host-file-proxy.test.ts +23 -11
  41. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  42. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  43. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  44. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  45. package/src/__tests__/mcp-health-check.test.ts +11 -8
  46. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  47. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  48. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  49. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  51. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  52. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  53. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  54. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  55. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  56. package/src/__tests__/model-intents.test.ts +0 -3
  57. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  58. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  59. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  60. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  61. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  62. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  63. package/src/__tests__/speaker-identification.test.ts +56 -0
  64. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  65. package/src/__tests__/subagent-tools.test.ts +2 -3
  66. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  67. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  68. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  69. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  70. package/src/__tests__/workspace-git-service.test.ts +0 -26
  71. package/src/acp/__tests__/agent-process.test.ts +4 -258
  72. package/src/acp/__tests__/auth-required.test.ts +0 -96
  73. package/src/acp/__tests__/client-handler.test.ts +2 -90
  74. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  75. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  76. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  77. package/src/acp/__tests__/session-manager.test.ts +4 -895
  78. package/src/acp/agent-process.test.ts +1 -4
  79. package/src/acp/agent-process.ts +9 -94
  80. package/src/acp/auth-required.ts +1 -50
  81. package/src/acp/auto-install.test.ts +7 -9
  82. package/src/acp/client-handler.ts +3 -16
  83. package/src/acp/resolve-agent.test.ts +6 -220
  84. package/src/acp/resolve-agent.ts +23 -88
  85. package/src/acp/session-manager.test.ts +3 -196
  86. package/src/acp/session-manager.ts +18 -441
  87. package/src/acp/types.ts +5 -50
  88. package/src/api/events/app-files-changed.ts +3 -4
  89. package/src/api/index.ts +0 -6
  90. package/src/apps/app-store.ts +1 -1
  91. package/src/bundler/app-compiler.ts +0 -15
  92. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  93. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  94. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  95. package/src/calls/call-constants.ts +4 -24
  96. package/src/calls/call-controller.ts +199 -499
  97. package/src/calls/call-transport.ts +0 -16
  98. package/src/calls/media-stream-output.ts +0 -32
  99. package/src/calls/media-stream-server.ts +30 -82
  100. package/src/calls/media-stream-stt-session.ts +0 -15
  101. package/src/calls/resolve-call-tts-provider.ts +2 -33
  102. package/src/calls/speaker-identification.ts +233 -0
  103. package/src/calls/tts-call-strategy.ts +5 -9
  104. package/src/calls/types.ts +0 -2
  105. package/src/calls/voice-control-protocol.ts +21 -53
  106. package/src/calls/voice-session-bridge.ts +46 -59
  107. package/src/calls/voice-triage-escalate.ts +56 -175
  108. package/src/cli/commands/apps.help.ts +13 -67
  109. package/src/cli/commands/apps.ts +0 -183
  110. package/src/cli/commands/channels/index.help.ts +2 -70
  111. package/src/cli/commands/channels/index.ts +3 -16
  112. package/src/cli/commands/credentials.help.ts +2 -6
  113. package/src/cli/commands/credentials.ts +2 -2
  114. package/src/cli/commands/mcp.help.ts +8 -8
  115. package/src/cli/commands/mcp.ts +1 -1
  116. package/src/cli/commands/roadmap.help.ts +1 -5
  117. package/src/cli/commands/roadmap.ts +1 -1
  118. package/src/cli/lib/bundled-marketplace.json +90 -103
  119. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  120. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  121. package/src/config/__tests__/platform-rehydration.test.ts +0 -93
  122. package/src/config/acp-defaults.test.ts +3 -13
  123. package/src/config/acp-defaults.ts +6 -23
  124. package/src/config/acp-schema.ts +2 -30
  125. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  126. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  127. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  128. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  129. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  130. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  131. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  132. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  133. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  134. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  135. package/src/config/default-profile-catalog.ts +1 -1
  136. package/src/config/env.ts +2 -2
  137. package/src/config/feature-flag-registry.json +12 -8
  138. package/src/config/memory-v3-gate.test.ts +0 -31
  139. package/src/config/memory-v3-gate.ts +16 -20
  140. package/src/config/platform-rehydration.ts +21 -75
  141. package/src/config/schema.ts +2 -2
  142. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  143. package/src/config/schemas/calls.ts +28 -1
  144. package/src/config/schemas/live-voice.ts +173 -1
  145. package/src/config/schemas/mcp.ts +1 -1
  146. package/src/config/schemas/memory-retrospective.ts +0 -10
  147. package/src/config/schemas/skills.ts +14 -0
  148. package/src/credential-execution/process-manager.test.ts +19 -18
  149. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  150. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  151. package/src/daemon/app-source-watcher.ts +218 -0
  152. package/src/daemon/config-watcher.ts +194 -13
  153. package/src/daemon/conversation-process.ts +64 -35
  154. package/src/daemon/conversation-skill-tools.ts +31 -13
  155. package/src/daemon/conversation-store.ts +1 -1
  156. package/src/daemon/conversation-surfaces.ts +8 -10
  157. package/src/daemon/conversation-tool-setup.ts +43 -37
  158. package/src/daemon/conversation.ts +3 -0
  159. package/src/daemon/host-bash-proxy.ts +12 -8
  160. package/src/daemon/host-browser-proxy.ts +1 -15
  161. package/src/daemon/host-file-proxy.ts +10 -8
  162. package/src/daemon/host-transfer-proxy.ts +18 -14
  163. package/src/daemon/lifecycle.ts +5 -0
  164. package/src/daemon/mcp-reload-service.ts +5 -5
  165. package/src/daemon/message-types/sync.ts +0 -1
  166. package/src/daemon/providers-setup.ts +1 -1
  167. package/src/daemon/shutdown-handlers.ts +9 -1
  168. package/src/daemon/skill-memory-refresh.ts +0 -64
  169. package/src/daemon/tool-side-effects.ts +18 -7
  170. package/src/hooks/types.ts +0 -33
  171. package/src/inbound/platform-callback-registration.ts +5 -4
  172. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  173. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  174. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  175. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  176. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  177. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  178. package/src/live-voice/live-voice-session.ts +693 -213
  179. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  180. package/src/live-voice/protocol.ts +2 -0
  181. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  182. package/src/mcp/effective-config.ts +3 -3
  183. package/src/mcp/mcp-header-store.ts +45 -29
  184. package/src/mcp/startup.ts +4 -8
  185. package/src/messaging/provider.ts +3 -10
  186. package/src/messaging/providers/callback-routing.ts +0 -18
  187. package/src/messaging/providers/channel-transport.ts +0 -56
  188. package/src/messaging/providers/discord/transport.ts +0 -17
  189. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  190. package/src/messaging/providers/slack/adapter.ts +44 -7
  191. package/src/messaging/providers/slack/transport.ts +0 -16
  192. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  193. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  194. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  195. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  196. package/src/messaging/providers/whatsapp/client.ts +29 -0
  197. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  198. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  199. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  200. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  201. package/src/notifications/assistant-reply-producer.ts +3 -8
  202. package/src/notifications/conversation-pairing.ts +16 -36
  203. package/src/notifications/delivered-post-record.ts +1 -11
  204. package/src/notifications/home-feed-side-effect.ts +7 -55
  205. package/src/outbound-proxy/certs.ts +5 -3
  206. package/src/permissions/checker.test.ts +6 -11
  207. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  208. package/src/persistence/conversation-crud.ts +63 -71
  209. package/src/persistence/conversation-lineage.ts +4 -12
  210. package/src/persistence/conversation-title-service.ts +26 -9
  211. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  212. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  213. package/src/persistence/message-reads.ts +0 -30
  214. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  215. package/src/persistence/schema/memory-core.ts +0 -5
  216. package/src/platform/client.test.ts +0 -2
  217. package/src/platform/client.ts +10 -2
  218. package/src/plugin-api/constants.ts +0 -2
  219. package/src/plugin-api/index.ts +0 -1
  220. package/src/plugin-api/types.ts +0 -2
  221. package/src/plugins/defaults/index.ts +0 -2
  222. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  223. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  224. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  225. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  226. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  227. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  228. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  229. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  230. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  231. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  232. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  233. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  234. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  235. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  236. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  237. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  238. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  239. package/src/plugins/defaults/memory/startup.ts +1 -6
  240. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  241. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  242. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  243. package/src/plugins/defaults/memory/worker.ts +0 -6
  244. package/src/plugins/mcp-servers.ts +75 -15
  245. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  246. package/src/providers/gemini/client.ts +23 -9
  247. package/src/providers/model-catalog.ts +0 -34
  248. package/src/providers/model-intents.ts +5 -10
  249. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  250. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  251. package/src/providers/openai/chat-completions-provider.ts +78 -192
  252. package/src/providers/openai/codex-models.ts +4 -0
  253. package/src/runtime/AGENTS.md +0 -2
  254. package/src/runtime/auth/same-actor.ts +3 -38
  255. package/src/runtime/http-server.ts +151 -160
  256. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  257. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  258. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  259. package/src/runtime/routes/acp-routes.test.ts +0 -15
  260. package/src/runtime/routes/acp-routes.ts +9 -72
  261. package/src/runtime/routes/app-management-routes.ts +0 -73
  262. package/src/runtime/routes/app-routes.ts +1 -1
  263. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  264. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  265. package/src/runtime/routes/credential-routes.ts +10 -19
  266. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  267. package/src/runtime/routes/index.ts +0 -4
  268. package/src/runtime/routes/log-export-routes.ts +0 -2
  269. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  270. package/src/runtime/routes/migration-routes.ts +21 -8
  271. package/src/runtime/routes/platform-routes.ts +15 -18
  272. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  273. package/src/runtime/services/conversation-serializer.ts +3 -16
  274. package/src/runtime/sync/resource-sync-events.ts +1 -2
  275. package/src/schedule/worker.ts +1 -1
  276. package/src/security/ces-rpc-record-backend.ts +0 -7
  277. package/src/subagent/consult-context.ts +25 -12
  278. package/src/tools/acp/list-agents.test.ts +1 -3
  279. package/src/tools/acp/spawn.test.ts +11 -146
  280. package/src/tools/acp/spawn.ts +3 -21
  281. package/src/tools/acp/status.ts +3 -40
  282. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  283. package/src/tools/capability-offer.test.ts +2 -22
  284. package/src/tools/capability-offer.ts +1 -16
  285. package/src/tools/computer-use/definitions.ts +2 -4
  286. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  287. package/src/tools/credentials/metadata-store.ts +0 -100
  288. package/src/tools/host-filesystem/edit.test.ts +1 -2
  289. package/src/tools/host-filesystem/edit.ts +2 -2
  290. package/src/tools/host-filesystem/read.test.ts +1 -2
  291. package/src/tools/host-filesystem/read.ts +2 -2
  292. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  293. package/src/tools/host-filesystem/transfer.ts +2 -2
  294. package/src/tools/host-filesystem/write.test.ts +1 -2
  295. package/src/tools/host-filesystem/write.ts +2 -2
  296. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  297. package/src/tools/host-terminal/host-shell.ts +20 -4
  298. package/src/tools/policy-context.ts +7 -6
  299. package/src/tools/subagent/spawn.ts +8 -5
  300. package/src/tools/watch/watch-retro-report.ts +8 -0
  301. package/src/util/__tests__/language-subtag.test.ts +1 -23
  302. package/src/util/fs-watcher-error.ts +36 -0
  303. package/src/util/language-subtag.ts +0 -16
  304. package/src/util/platform.ts +0 -8
  305. package/src/workspace/git-service.ts +54 -5
  306. package/src/workspace/migrations/registry.ts +0 -6
  307. package/scripts/smoke-desktop-window-theme.ts +0 -186
  308. package/src/__tests__/git-porcelain.test.ts +0 -47
  309. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  310. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  311. package/src/__tests__/resolve-app.test.ts +0 -135
  312. package/src/__tests__/source-fingerprint.test.ts +0 -184
  313. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  314. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  315. package/src/acp/model-config.test.ts +0 -166
  316. package/src/acp/model-config.ts +0 -138
  317. package/src/api/events/acp-session-model-update.test.ts +0 -88
  318. package/src/api/events/acp-session-model-update.ts +0 -46
  319. package/src/apps/resolve-app.ts +0 -81
  320. package/src/apps/source-fingerprint.ts +0 -266
  321. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  322. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  323. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  324. package/src/calls/barge-in-guard.ts +0 -118
  325. package/src/calls/voice-leg-coordinator.ts +0 -189
  326. package/src/calls/voice-progress-cadence.ts +0 -423
  327. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  328. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  329. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  330. package/src/cli/commands/channels/send.ts +0 -128
  331. package/src/config/__tests__/platform-identity.test.ts +0 -117
  332. package/src/config/acp-agent-write.ts +0 -43
  333. package/src/config/acp-schema.test.ts +0 -81
  334. package/src/config/platform-identity.ts +0 -144
  335. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  336. package/src/config/schemas/voice.ts +0 -150
  337. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  338. package/src/daemon/app-change-notify.ts +0 -45
  339. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  340. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  341. package/src/desktop/desktop-chrome-policy.ts +0 -42
  342. package/src/desktop/desktop-dependencies.test.ts +0 -102
  343. package/src/desktop/desktop-dependencies.ts +0 -306
  344. package/src/desktop/desktop-feature.test.ts +0 -18
  345. package/src/desktop/desktop-feature.ts +0 -19
  346. package/src/desktop/desktop-panel-config.test.ts +0 -135
  347. package/src/desktop/desktop-panel-config.ts +0 -149
  348. package/src/desktop/desktop-session-manager.test.ts +0 -627
  349. package/src/desktop/desktop-session-manager.ts +0 -814
  350. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  351. package/src/desktop/desktop-stream-bridge.ts +0 -214
  352. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  353. package/src/desktop/desktop-wallpaper.ts +0 -113
  354. package/src/desktop/desktop-window-theme.ts +0 -170
  355. package/src/i18n/AGENTS.md +0 -22
  356. package/src/i18n/__tests__/i18n.test.ts +0 -108
  357. package/src/i18n/index.ts +0 -16
  358. package/src/i18n/locales.ts +0 -93
  359. package/src/i18n/messages.ts +0 -61
  360. package/src/i18n/title.ts +0 -25
  361. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  362. package/src/mcp/spec-schema.ts +0 -111
  363. package/src/mcp/workspace-mcp-config.ts +0 -188
  364. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  365. package/src/persistence/conversation-title-placeholders.ts +0 -23
  366. package/src/persistence/message-cursor.ts +0 -78
  367. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  368. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  369. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  370. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  371. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  372. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  373. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  374. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  375. package/src/providers/gemini-thought-signature.test.ts +0 -63
  376. package/src/providers/gemini-thought-signature.ts +0 -44
  377. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  378. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  379. package/src/providers/openai/google-thought-signature.ts +0 -320
  380. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  381. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  382. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  383. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  384. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  385. package/src/runtime/channel-send.ts +0 -316
  386. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  387. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  388. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  389. package/src/runtime/routes/channel-send-routes.ts +0 -85
  390. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  391. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  392. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  393. package/src/security/ces-http-record-backend.ts +0 -120
  394. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  395. package/src/skills/workspace-skill-md-signature.ts +0 -50
  396. package/src/tools/acp/status.test.ts +0 -94
  397. package/src/util/ca-bundle.ts +0 -13
  398. package/src/workspace/git-porcelain.ts +0 -66
  399. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  400. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  401. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  402. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  403. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  404. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -39,7 +39,6 @@ import type {
39
39
  SendMessageOptions,
40
40
  } from "@vellumai/plugin-api";
41
41
 
42
- import { OpenRouterProvider } from "../../../../../providers/openrouter/client.js";
43
42
  import { ProviderError } from "../../../../../util/errors.js";
44
43
  import { sectionHeadLine } from "../sections.js";
45
44
  import type { MemoryRoutingTurn, Section } from "../types.js";
@@ -844,91 +843,3 @@ describe("selectPool: sections and keyword-in-context snippets", () => {
844
843
  );
845
844
  });
846
845
  });
847
-
848
- // ---------------------------------------------------------------------------
849
- // selectPool: cataloged thinking and forced-tool compatibility.
850
- // ---------------------------------------------------------------------------
851
-
852
- describe("selectPool: cataloged thinking and forced-tool compatibility", () => {
853
- test("OpenRouter Kimi K2.6 omits the forced choice and yields a structured selection", async () => {
854
- // A real OpenAI chat-completions provider stands in for the cataloged
855
- // OpenRouter Kimi profile. The request succeeds without a reactive retry
856
- // because the forced select_pages choice is omitted before dispatch.
857
- const wireRequests: unknown[] = [];
858
- const kimi = new OpenRouterProvider(
859
- "test-key",
860
- "moonshotai/kimi-k2.6-20260420",
861
- );
862
- (kimi as unknown as { client: unknown }).client = {
863
- chat: {
864
- completions: {
865
- create: async (params: unknown) => {
866
- wireRequests.push(JSON.parse(JSON.stringify(params)));
867
- return {
868
- async *[Symbol.asyncIterator]() {
869
- yield {
870
- choices: [
871
- {
872
- delta: {
873
- tool_calls: [
874
- {
875
- index: 0,
876
- id: "call-1",
877
- function: {
878
- name: "select_pages",
879
- arguments: '{"ids":[3]}',
880
- },
881
- },
882
- ],
883
- },
884
- finish_reason: "tool_calls",
885
- },
886
- ],
887
- usage: { prompt_tokens: 10, completion_tokens: 2 },
888
- };
889
- },
890
- };
891
- },
892
- },
893
- },
894
- };
895
-
896
- // The profile layer injects the thinking effort onto the call config in
897
- // production; emulate that here so the forced tool_choice rides alongside
898
- // reasoning on the wire.
899
- providerStub = {
900
- name: "kimi-openai-compat",
901
- sendMessage: (messages: Message[], options?: SendMessageOptions) =>
902
- kimi.sendMessage(messages, {
903
- ...options,
904
- config: {
905
- ...options?.config,
906
- effort: "high",
907
- thinking: { enabled: true },
908
- },
909
- }),
910
- };
911
-
912
- const selection = await selectPool(makePool(), makeTurn("rollout?"));
913
-
914
- // The preflight path avoids an incompatible first request, and the
915
- // pool-level re-prompt loop never engages.
916
- expect(wireRequests).toHaveLength(1);
917
- const first = wireRequests[0] as {
918
- tool_choice?: unknown;
919
- reasoning?: { effort?: string; summary?: string };
920
- };
921
- expect(first.tool_choice).toBeUndefined();
922
- expect(first.reasoning).toMatchObject({
923
- effort: "high",
924
- summary: "detailed",
925
- });
926
- expect(
927
- warnPayloads().filter((p) => p.reason === "provider_error"),
928
- ).toEqual([]);
929
-
930
- // Structured selection survived: ids [3] is the topic-x finder line.
931
- expect(selection.keptAll).toBe(false);
932
- expect(selection.pages).toEqual([{ slug: "topic-x", sections: [] }]);
933
- });
934
- });
@@ -16,10 +16,6 @@ import { getConfig } from "../../../config/loader.js";
16
16
  import { isMemoryEnabled } from "../../../config/memory-v3-gate.js";
17
17
  import { rehydratePlatformCredentials } from "../../../config/platform-rehydration.js";
18
18
  import { startConversationEvictor } from "../../../daemon/conversation-evictor.js";
19
- import {
20
- startWorkspaceSkillMdMtimePoll,
21
- stopWorkspaceSkillMdMtimePoll,
22
- } from "../../../daemon/skill-memory-refresh.js";
23
19
  import { resetDb } from "../../../persistence/db-connection.js";
24
20
  import {
25
21
  EMBEDDING_SHUTDOWN_BUDGET_MS,
@@ -112,7 +108,6 @@ async function main(): Promise<void> {
112
108
  shuttingDown = true;
113
109
  log.info({ signal }, "Memory worker process shutting down");
114
110
  worker?.stop();
115
- stopWorkspaceSkillMdMtimePoll();
116
111
  if (keepAlive != null) {
117
112
  clearInterval(keepAlive);
118
113
  }
@@ -166,7 +161,6 @@ async function main(): Promise<void> {
166
161
  }
167
162
 
168
163
  worker = startMemoryJobsWorkerLoop();
169
- startWorkspaceSkillMdMtimePoll();
170
164
 
171
165
  // Keep-alive: the worker's setTimeout timers are unref'd, so without
172
166
  // this interval the process would exit immediately.
@@ -14,7 +14,7 @@
14
14
  * This module reads those files and projects each entry onto the
15
15
  * assistant's own `McpServerConfig` shape, so a plugin-declared server can
16
16
  * flow through the same surfaces as one configured in the workspace
17
- * `mcp.json`.
17
+ * `config.json`.
18
18
  *
19
19
  * Failure isolation follows the spec: an invalid top-level `mcp.json`
20
20
  * disables MCP for that plugin only, and an invalid individual server
@@ -39,17 +39,17 @@
39
39
  import { existsSync, readFileSync } from "node:fs";
40
40
  import { join } from "node:path";
41
41
 
42
+ import { z } from "zod";
43
+
42
44
  import {
43
45
  type AllPluginInfo,
44
46
  listAllPlugins,
45
47
  type ListInstalledPluginsOptions,
46
48
  } from "../cli/lib/list-installed-plugins.js";
47
- import type { ResolvedMcpServerConfig } from "../config/schemas/mcp.js";
48
- import {
49
- projectSpecServerToTransport,
50
- SpecMcpDocumentSchema,
51
- SpecMcpServerSchema,
52
- } from "../mcp/spec-schema.js";
49
+ import type {
50
+ McpTransport,
51
+ ResolvedMcpServerConfig,
52
+ } from "../config/schemas/mcp.js";
53
53
  import { getLogger } from "../util/logger.js";
54
54
 
55
55
  const log = getLogger("plugin-mcp-servers");
@@ -77,6 +77,45 @@ export const PLUGIN_MCP_MANIFEST = "mcp.json";
77
77
  * origin risk.
78
78
  */
79
79
 
80
+ // ---------------------------------------------------------------------------
81
+ // Wire schema (Agent Plugins 1.0.0)
82
+ // ---------------------------------------------------------------------------
83
+
84
+ const PluginStdioServerSchema = z.object({
85
+ type: z.literal("stdio"),
86
+ command: z.string().min(1),
87
+ args: z.array(z.string()).optional(),
88
+ env: z.record(z.string(), z.string()).optional(),
89
+ cwd: z.string().optional(),
90
+ });
91
+
92
+ /**
93
+ * Remote MCP entry. Agent Plugins 1.0.0 requires `type` and names no
94
+ * default. MCP's current remote transport is Streamable HTTP, so this
95
+ * host fills omitted `type` and the Claude-style `http` alias as
96
+ * `streamable-http`. `sse` stays explicit.
97
+ */
98
+ const PluginHttpServerSchema = z.object({
99
+ type: z
100
+ .union([
101
+ z.literal("streamable-http"),
102
+ z.literal("sse"),
103
+ z.literal("http").transform(() => "streamable-http" as const),
104
+ ])
105
+ .default("streamable-http"),
106
+ url: z.string().min(1),
107
+ headers: z.record(z.string(), z.string()).optional(),
108
+ });
109
+
110
+ const PluginMcpServerSchema = z.union([
111
+ PluginStdioServerSchema,
112
+ PluginHttpServerSchema,
113
+ ]);
114
+
115
+ const PluginMcpManifestSchema = z.object({
116
+ mcpServers: z.record(z.string(), z.unknown()),
117
+ });
118
+
80
119
  // ---------------------------------------------------------------------------
81
120
  // Public shape
82
121
  // ---------------------------------------------------------------------------
@@ -212,7 +251,7 @@ export function readPluginMcpServers(
212
251
  continue;
213
252
  }
214
253
 
215
- const entry = SpecMcpServerSchema.safeParse(raw);
254
+ const entry = PluginMcpServerSchema.safeParse(raw);
216
255
  if (!entry.success) {
217
256
  issues.push({
218
257
  pluginName: plugin.name,
@@ -286,7 +325,7 @@ function parseManifest(
286
325
  };
287
326
  }
288
327
 
289
- const manifest = SpecMcpDocumentSchema.safeParse(json);
328
+ const manifest = PluginMcpManifestSchema.safeParse(json);
290
329
  if (!manifest.success) {
291
330
  return {
292
331
  error: `${PLUGIN_MCP_MANIFEST} is missing a valid "mcpServers" object`,
@@ -295,12 +334,33 @@ function parseManifest(
295
334
  return { mcpServers: manifest.data.mcpServers };
296
335
  }
297
336
 
337
+ /**
338
+ * Project one spec-shaped entry onto the assistant's transport union. The
339
+ * two vocabularies already agree on type names and required fields, so this
340
+ * is a field copy plus path interpolation for the stdio case.
341
+ */
298
342
  function projectTransport(
299
- entry: Parameters<typeof projectSpecServerToTransport>[0],
343
+ entry: z.infer<typeof PluginMcpServerSchema>,
300
344
  pluginRoot: string,
301
- ) {
302
- const pluginData = join(pluginRoot, "data");
303
- return projectSpecServerToTransport(entry, (value) =>
304
- interpolatePluginPaths(value, pluginRoot, pluginData),
305
- );
345
+ ): McpTransport {
346
+ if (entry.type === "stdio") {
347
+ const pluginData = join(pluginRoot, "data");
348
+ const expand = (v: string): string =>
349
+ interpolatePluginPaths(v, pluginRoot, pluginData);
350
+ return {
351
+ type: "stdio",
352
+ command: entry.command,
353
+ args: (entry.args ?? []).map(expand),
354
+ ...(entry.env && {
355
+ env: Object.fromEntries(
356
+ Object.entries(entry.env).map(([k, v]) => [k, expand(v)]),
357
+ ),
358
+ }),
359
+ };
360
+ }
361
+ return {
362
+ type: entry.type,
363
+ url: entry.url,
364
+ ...(entry.headers && { headers: entry.headers }),
365
+ };
306
366
  }
@@ -50,8 +50,6 @@ describe("isConnectionCompatibleWithModel", () => {
50
50
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-nano")).toBe(false);
51
51
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.5-pro")).toBe(false);
52
52
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.3-codex")).toBe(false);
53
- expect(isConnectionCompatibleWithModel(conn, "gpt-5.4")).toBe(false);
54
- expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-mini")).toBe(false);
55
53
  });
56
54
 
57
55
  test("oauth_subscription connection is compatible with a Codex model", () => {
@@ -61,6 +59,8 @@ describe("isConnectionCompatibleWithModel", () => {
61
59
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.6-terra")).toBe(true);
62
60
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.6-luna")).toBe(true);
63
61
  expect(isConnectionCompatibleWithModel(conn, "gpt-5.5")).toBe(true);
62
+ expect(isConnectionCompatibleWithModel(conn, "gpt-5.4")).toBe(true);
63
+ expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-mini")).toBe(true);
64
64
  });
65
65
 
66
66
  test("undefined model applies no gating (compatible)", () => {
@@ -165,7 +165,7 @@ describe("auto-resolution skips oauth_subscription connections for non-Codex mod
165
165
 
166
166
  test("Codex model can select the oauth_subscription connection", async () => {
167
167
  registerConnections([OPENAI_CODEX, OPENAI_KEY]);
168
- setOpenAiProfile("gpt-5.5");
168
+ setOpenAiProfile("gpt-5.4");
169
169
 
170
170
  const result = await getConfiguredProvider("mainAgent", {
171
171
  overrideProfile: "openai-any",
@@ -15,7 +15,6 @@ import {
15
15
  keepFileAsWorkspaceRef,
16
16
  } from "../content-block-size.js";
17
17
  import { fileBlockToProviderText } from "../file-block-text.js";
18
- import { unsignedThoughtSignatureFallback } from "../gemini-thought-signature.js";
19
18
  import { base64Source, resolveMediaReferences } from "../media-resolve.js";
20
19
  import { PROVIDER_CATALOG } from "../model-catalog.js";
21
20
  import { recordProviderRequestDiagnostics } from "../request-diagnostics.js";
@@ -46,6 +45,13 @@ import {
46
45
  const GEMINI_CONTEXT_OVERFLOW_TOKEN_PATTERNS =
47
46
  /token.?count.*exceeds|exceeds.*maximum.*tokens|prompt.?is.?too.?long|too.?many.?(?:input.?)?tokens|input.?too.?long|context.?length.?exceeded/i;
48
47
 
48
+ const GEMINI_3_UNSIGNED_TOOL_CALL_THOUGHT_SIGNATURE =
49
+ "context_engineering_is_the_way_to_go";
50
+
51
+ function isGemini3Model(model: string): boolean {
52
+ return model.startsWith("gemini-3") || model.startsWith("models/gemini-3");
53
+ }
54
+
49
55
  const THINKING_LEVEL_BY_NAME: Record<ThinkingLevelName, ThinkingLevel> = {
50
56
  minimal: ThinkingLevel.MINIMAL,
51
57
  low: ThinkingLevel.LOW,
@@ -429,8 +435,7 @@ export class GeminiProvider implements Provider {
429
435
  const maxTokens = configObj?.max_tokens as number | undefined;
430
436
  const modelOverride = configObj?.model as string | undefined;
431
437
  const usageAttributionHeaders = configObj?.usageAttributionHeaders as
432
- | Record<string, string>
433
- | undefined;
438
+ Record<string, string> | undefined;
434
439
  const activeModel = modelOverride ?? this.model;
435
440
  const thinkingConfig = geminiModelSupportsThinking(activeModel)
436
441
  ? buildThinkingConfig(
@@ -897,19 +902,28 @@ export class GeminiProvider implements Provider {
897
902
  parts: genai.Part[],
898
903
  model: string,
899
904
  ): void {
905
+ if (!isGemini3Model(model)) {
906
+ return;
907
+ }
908
+
900
909
  const functionCallParts = parts.filter((part) => part.functionCall);
901
- const fallback = unsignedThoughtSignatureFallback(
902
- functionCallParts.map((part) => part.thoughtSignature),
903
- { model },
910
+ if (functionCallParts.length === 0) {
911
+ return;
912
+ }
913
+
914
+ const hasRealThoughtSignature = functionCallParts.some((part) =>
915
+ Boolean(part.thoughtSignature),
904
916
  );
905
- if (!fallback) {
917
+ if (hasRealThoughtSignature) {
906
918
  return;
907
919
  }
908
- const firstFunctionCallPart = functionCallParts[fallback.index];
920
+
921
+ const firstFunctionCallPart = functionCallParts[0];
909
922
  if (!firstFunctionCallPart) {
910
923
  return;
911
924
  }
912
- firstFunctionCallPart.thoughtSignature = fallback.signature;
925
+ firstFunctionCallPart.thoughtSignature =
926
+ GEMINI_3_UNSIGNED_TOOL_CALL_THOUGHT_SIGNATURE;
913
927
  }
914
928
 
915
929
  private supportsGeminiInlineFile(mimeType: string): boolean {
@@ -76,13 +76,6 @@ export interface CatalogModel {
76
76
  supportsAudioInput?: boolean;
77
77
  supportsToolUse?: boolean;
78
78
  supportsEffort?: boolean;
79
- /**
80
- * Whether this provider/model serving surface accepts a forced OpenAI
81
- * chat-completions tool choice while thinking is enabled. Omit unless the
82
- * combination is known incompatible. Daemon-only: not projected into the
83
- * client catalog (see scripts/sync-llm-catalog.ts).
84
- */
85
- supportsForcedToolChoiceWithThinking?: boolean;
86
79
  pricing?: CatalogModelPricing;
87
80
  /**
88
81
  * Upper bound for `reasoning_effort` accepted by this model's upstream API.
@@ -863,9 +856,6 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
863
856
  cacheReadPer1mTokens: 0.03,
864
857
  },
865
858
  },
866
- // Limited to grandfathered accounts: other API keys get HTTP 404 "no
867
- // longer available to new users", so this model is user-selectable
868
- // only and no intent column may resolve to it.
869
859
  {
870
860
  id: "gemini-2.5-flash-lite",
871
861
  displayName: "Gemini 2.5 Flash Lite",
@@ -1826,7 +1816,6 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
1826
1816
  supportsCaching: true,
1827
1817
  supportsVision: true,
1828
1818
  supportsToolUse: true,
1829
- supportsForcedToolChoiceWithThinking: false,
1830
1819
  pricing: {
1831
1820
  inputPer1mTokens: 0.95,
1832
1821
  outputPer1mTokens: 4.0,
@@ -2639,29 +2628,6 @@ export function modelSupportedEfforts(
2639
2628
  );
2640
2629
  }
2641
2630
 
2642
- /**
2643
- * Whether a provider/model serving surface accepts a forced OpenAI
2644
- * chat-completions tool choice while thinking is enabled. Unknown providers
2645
- * and models fail open so custom routes retain their existing request shape
2646
- * and can rely on the bounded provider-error retry if needed.
2647
- */
2648
- export function supportsForcedToolChoiceWithThinking(
2649
- providerId: string,
2650
- modelId: string,
2651
- ): boolean {
2652
- const provider = PROVIDER_CATALOG.find((entry) => entry.id === providerId);
2653
- if (!provider) {
2654
- return true;
2655
- }
2656
- const stripDateSuffix = (id: string): string => id.replace(/-\d{8}$/, "");
2657
- const normalizedModelId = stripDateSuffix(modelId);
2658
- return !provider.models.some(
2659
- (model) =>
2660
- model.supportsForcedToolChoiceWithThinking === false &&
2661
- (model.id === modelId || stripDateSuffix(model.id) === normalizedModelId),
2662
- );
2663
- }
2664
-
2665
2631
  /**
2666
2632
  * Return the catalog provider that owns a model ID, if known. When multiple
2667
2633
  * providers list the same ID (e.g. OpenRouter and the Vercel AI Gateway share
@@ -11,15 +11,10 @@ const PROVIDER_DEFAULT_MODELS: Record<string, string> = Object.fromEntries(
11
11
  );
12
12
 
13
13
  // `cost-optimized` is the cheapest model a provider serves, `latency-optimized`
14
- // the fastest to first token. On anthropic, ollama, fireworks, openai and
15
- // gemini the same model is both, so those columns repeat by construction
16
- // rather than by oversight (openai's balanced repeats it too: the
17
- // default-profile templates split those tiers by reasoning effort, not model).
18
- //
19
- // "Serves" means serves to every API key: Google's `gemini-2.5-flash-lite`
20
- // undercuts every 3.x Flash-Lite but is limited to grandfathered accounts
21
- // (other keys get HTTP 404 "no longer available to new users"), so the
22
- // gemini column skips it.
14
+ // the fastest to first token. On anthropic, ollama, fireworks and openai the
15
+ // same model is both, so those columns repeat by construction rather than by
16
+ // oversight (openai's balanced repeats it too: the default-profile templates
17
+ // split those tiers by reasoning effort, not model).
23
18
  const PROVIDER_MODEL_INTENTS: Record<string, Record<ModelIntent, string>> = {
24
19
  anthropic: {
25
20
  balanced: "claude-sonnet-4-6",
@@ -37,7 +32,7 @@ const PROVIDER_MODEL_INTENTS: Record<string, Record<ModelIntent, string>> = {
37
32
  },
38
33
  gemini: {
39
34
  balanced: "gemini-3-flash-preview",
40
- "cost-optimized": "gemini-3.1-flash-lite",
35
+ "cost-optimized": "gemini-2.5-flash-lite",
41
36
  "latency-optimized": "gemini-3.1-flash-lite",
42
37
  "quality-optimized": "gemini-3.1-pro-preview",
43
38
  "vision-optimized": "gemini-3-flash-preview",
@@ -934,55 +934,6 @@ describe("thinking-mode tool_choice rejection fallback", () => {
934
934
  expect(text?.text).toBe("ok");
935
935
  });
936
936
 
937
- test("retries once when Kimi rejects a specified tool_choice in thinking mode", async () => {
938
- const { provider, requests } = stubProviderWithErrors(
939
- [
940
- rejection(
941
- "tool_choice 'specified' is incompatible with thinking enabled",
942
- ),
943
- ],
944
- OK_CHUNKS,
945
- );
946
-
947
- const response = await provider.sendMessage(
948
- [{ role: "user", content: [{ type: "text", text: "hi" }] }],
949
- {
950
- tools: [
951
- {
952
- name: "select_pages",
953
- description: "Pick relevant memory pages",
954
- input_schema: { type: "object", properties: {} },
955
- },
956
- ],
957
- config: {
958
- tool_choice: { type: "tool", name: "select_pages" },
959
- effort: "high",
960
- },
961
- },
962
- );
963
-
964
- expect(requests).toHaveLength(2);
965
- const first = requests[0] as {
966
- tool_choice?: { type: string; function: { name: string } };
967
- reasoning_effort?: string;
968
- };
969
- const second = requests[1] as {
970
- tool_choice?: unknown;
971
- reasoning_effort?: string;
972
- };
973
- expect(first.tool_choice).toEqual({
974
- type: "function",
975
- function: { name: "select_pages" },
976
- });
977
- expect(first.reasoning_effort).toBe("high");
978
- expect(second.tool_choice).toBeUndefined();
979
- expect(second.reasoning_effort).toBe("high");
980
- const text = response.content.find((b) => b.type === "text") as
981
- | { type: "text"; text: string }
982
- | undefined;
983
- expect(text?.text).toBe("ok");
984
- });
985
-
986
937
  test("retries once for an OpenRouter-wrapped thinking-mode tool_choice rejection", async () => {
987
938
  const wrapped = new OpenAI.APIError(
988
939
  400,
@@ -1190,80 +1141,33 @@ describe("unknown assistant reasoning field rejection fallback", () => {
1190
1141
  },
1191
1142
  ];
1192
1143
 
1193
- test.each([
1194
- [
1195
- "a strict schema",
1196
- "Additional properties are not allowed ('reasoning_content' was unexpected)",
1197
- ],
1198
- ["Groq", "property 'reasoning_content' is unsupported"],
1199
- ])(
1200
- "retries once without reasoning_content when %s rejects it",
1201
- async (_upstream, message) => {
1202
- const { provider, requests } = stubProviderWithErrors(
1203
- [rejection(message)],
1204
- OK_CHUNKS,
1205
- { assistantReasoningField: "reasoning_content" },
1206
- );
1207
-
1208
- const response = await provider.sendMessage(thinkingHistory);
1209
-
1210
- expect(requests).toHaveLength(2);
1211
- const first = requests[0] as {
1212
- messages: Array<{ reasoning_content?: string; content: string | null }>;
1213
- };
1214
- const second = requests[1] as {
1215
- messages: Array<{ reasoning_content?: string; content: string | null }>;
1216
- };
1217
- expect(first.messages[0].reasoning_content).toBe("hidden chain");
1218
- expect(second.messages[0].reasoning_content).toBeUndefined();
1219
- expect(second.messages[0].content).toBe("answer");
1220
- const text = response.content.find((b) => b.type === "text") as
1221
- | { type: "text"; text: string }
1222
- | undefined;
1223
- expect(text?.text).toBe("ok");
1224
- },
1225
- );
1226
-
1227
- test("preserves assistant tool calls when stripping an unsupported reasoning_content", async () => {
1144
+ test("retries once without reasoning_content when a strict schema rejects it", async () => {
1228
1145
  const { provider, requests } = stubProviderWithErrors(
1229
- [rejection("property 'reasoning_content' is unsupported")],
1146
+ [
1147
+ rejection(
1148
+ "Additional properties are not allowed ('reasoning_content' was unexpected)",
1149
+ ),
1150
+ ],
1230
1151
  OK_CHUNKS,
1231
1152
  { assistantReasoningField: "reasoning_content" },
1232
1153
  );
1233
1154
 
1234
- await provider.sendMessage([
1235
- {
1236
- role: "assistant",
1237
- content: [
1238
- { type: "thinking", thinking: "hidden chain", signature: "" },
1239
- {
1240
- type: "tool_use",
1241
- id: "call_1",
1242
- name: "lookup",
1243
- input: { q: "x" },
1244
- },
1245
- ],
1246
- },
1247
- {
1248
- role: "user",
1249
- content: [
1250
- { type: "tool_result", tool_use_id: "call_1", content: "found" },
1251
- ],
1252
- },
1253
- ]);
1155
+ const response = await provider.sendMessage(thinkingHistory);
1254
1156
 
1255
1157
  expect(requests).toHaveLength(2);
1158
+ const first = requests[0] as {
1159
+ messages: Array<{ reasoning_content?: string; content: string | null }>;
1160
+ };
1256
1161
  const second = requests[1] as {
1257
- messages: Array<{
1258
- role: string;
1259
- reasoning_content?: string;
1260
- tool_calls?: Array<{ id: string; function: { name: string } }>;
1261
- }>;
1162
+ messages: Array<{ reasoning_content?: string; content: string | null }>;
1262
1163
  };
1263
- const assistant = second.messages.find((m) => m.role === "assistant");
1264
- expect(assistant?.reasoning_content).toBeUndefined();
1265
- expect(assistant?.tool_calls?.[0]?.id).toBe("call_1");
1266
- expect(assistant?.tool_calls?.[0]?.function.name).toBe("lookup");
1164
+ expect(first.messages[0].reasoning_content).toBe("hidden chain");
1165
+ expect(second.messages[0].reasoning_content).toBeUndefined();
1166
+ expect(second.messages[0].content).toBe("answer");
1167
+ const text = response.content.find((b) => b.type === "text") as
1168
+ | { type: "text"; text: string }
1169
+ | undefined;
1170
+ expect(text?.text).toBe("ok");
1267
1171
  });
1268
1172
 
1269
1173
  test("does not strip reasoning_content on a must-be-passed-back error", async () => {
@@ -1285,38 +1189,6 @@ describe("unknown assistant reasoning field rejection fallback", () => {
1285
1189
  ).toBe("hidden chain");
1286
1190
  });
1287
1191
 
1288
- test("does not strip reasoning_content on a 429 output-token limit", async () => {
1289
- const { provider, requests } = stubProviderWithErrors(
1290
- [
1291
- rejection(
1292
- "Rate limit reached for model `qwen/qwen3-32b` in organization `org_x` on tokens per minute (TPM): Limit 1000, Requested 4000.",
1293
- 429,
1294
- ),
1295
- ],
1296
- OK_CHUNKS,
1297
- { assistantReasoningField: "reasoning_content" },
1298
- );
1299
-
1300
- await expect(provider.sendMessage(thinkingHistory)).rejects.toThrow();
1301
- expect(requests).toHaveLength(1);
1302
- });
1303
-
1304
- test("does not strip reasoning_content on a 413 input-token limit", async () => {
1305
- const { provider, requests } = stubProviderWithErrors(
1306
- [
1307
- rejection(
1308
- "Request too large for model `qwen/qwen3-32b` in organization `org_x` on tokens per minute (TPM): Limit 7000, Requested 24936.",
1309
- 413,
1310
- ),
1311
- ],
1312
- OK_CHUNKS,
1313
- { assistantReasoningField: "reasoning_content" },
1314
- );
1315
-
1316
- await expect(provider.sendMessage(thinkingHistory)).rejects.toThrow();
1317
- expect(requests).toHaveLength(1);
1318
- });
1319
-
1320
1192
  test("does not retry unknown-field 500s", async () => {
1321
1193
  const { provider, requests } = stubProviderWithErrors(
1322
1194
  [