@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
@@ -26,14 +26,13 @@ const USER_MESSAGE: Message[] = [
26
26
  */
27
27
  function stubChatProvider(
28
28
  options?: ConstructorParameters<typeof OpenAIChatCompletionsProvider>[2],
29
- model = "test-model",
30
29
  ): {
31
30
  provider: OpenAIChatCompletionsProvider;
32
31
  requests: Array<Record<string, unknown>>;
33
32
  } {
34
33
  const provider = new OpenAIChatCompletionsProvider(
35
34
  "test-key",
36
- model,
35
+ "test-model",
37
36
  options,
38
37
  );
39
38
  const requests: Array<Record<string, unknown>> = [];
@@ -236,87 +235,6 @@ describe("OpenAIChatCompletionsProvider tool_choice wiring", () => {
236
235
  });
237
236
  });
238
237
 
239
- test("omits a forced tool choice for OpenRouter Kimi K2.6 with thinking", async () => {
240
- const { provider, requests } = stubChatProvider(
241
- { providerName: "openrouter" },
242
- "moonshotai/kimi-k2.6-20260420",
243
- );
244
-
245
- await provider.sendMessage(USER_MESSAGE, {
246
- tools: TOOLS,
247
- config: { tool_choice: { type: "tool", name: "bash" }, effort: "high" },
248
- });
249
-
250
- expect(requests).toHaveLength(1);
251
- expect(requests[0].reasoning_effort).toBe("high");
252
- expect(requests[0].tool_choice).toBeUndefined();
253
- });
254
-
255
- test("omits required for OpenRouter Kimi K2.6 with thinking", async () => {
256
- const { provider, requests } = stubChatProvider(
257
- { providerName: "openrouter" },
258
- "moonshotai/kimi-k2.6-20260420",
259
- );
260
-
261
- await provider.sendMessage(USER_MESSAGE, {
262
- tools: TOOLS,
263
- config: { tool_choice: { type: "any" }, effort: "high" },
264
- });
265
-
266
- expect(requests).toHaveLength(1);
267
- expect(requests[0].reasoning_effort).toBe("high");
268
- expect(requests[0].tool_choice).toBeUndefined();
269
- });
270
-
271
- test("keeps tool_choice none for OpenRouter Kimi K2.6 with thinking", async () => {
272
- const { provider, requests } = stubChatProvider(
273
- { providerName: "openrouter" },
274
- "moonshotai/kimi-k2.6-20260420",
275
- );
276
-
277
- await provider.sendMessage(USER_MESSAGE, {
278
- tools: TOOLS,
279
- config: { tool_choice: { type: "none" }, effort: "high" },
280
- });
281
-
282
- expect(requests[0].reasoning_effort).toBe("high");
283
- expect(requests[0].tool_choice).toBe("none");
284
- });
285
-
286
- test("keeps a forced tool choice for OpenRouter Kimi K2.6 when thinking is off", async () => {
287
- const { provider, requests } = stubChatProvider(
288
- { providerName: "openrouter" },
289
- "moonshotai/kimi-k2.6-20260420",
290
- );
291
-
292
- await provider.sendMessage(USER_MESSAGE, {
293
- tools: TOOLS,
294
- config: { tool_choice: { type: "tool", name: "bash" } },
295
- });
296
-
297
- expect(requests[0].tool_choice).toEqual({
298
- type: "function",
299
- function: { name: "bash" },
300
- });
301
- });
302
-
303
- test("keeps a forced tool choice for Vercel Kimi K2.6 with thinking", async () => {
304
- const { provider, requests } = stubChatProvider(
305
- { providerName: "vercel-ai-gateway" },
306
- "moonshotai/kimi-k2.6",
307
- );
308
-
309
- await provider.sendMessage(USER_MESSAGE, {
310
- tools: TOOLS,
311
- config: { tool_choice: { type: "tool", name: "bash" }, effort: "high" },
312
- });
313
-
314
- expect(requests[0].tool_choice).toEqual({
315
- type: "function",
316
- function: { name: "bash" },
317
- });
318
- });
319
-
320
238
  test("omits every tool_choice in thinking mode when omitToolChoiceWhenReasoning is on", async () => {
321
239
  const { provider, requests } = stubChatProvider({
322
240
  omitToolChoiceWhenReasoning: true,
@@ -17,7 +17,6 @@ import {
17
17
  mediaSourceByteLength,
18
18
  resolveMediaReferences,
19
19
  } from "../media-resolve.js";
20
- import { supportsForcedToolChoiceWithThinking } from "../model-catalog.js";
21
20
  import { PLACEHOLDER_EMPTY_TURN } from "../placeholder-sentinels.js";
22
21
  import { recordProviderRequestDiagnostics } from "../request-diagnostics.js";
23
22
  import { createStreamTimeout } from "../stream-timeout.js";
@@ -28,7 +27,6 @@ import type {
28
27
  Provider,
29
28
  ProviderResponse,
30
29
  SendMessageOptions,
31
- ToolUseContent,
32
30
  } from "../types.js";
33
31
  import {
34
32
  ContextOverflowError,
@@ -53,15 +51,6 @@ import {
53
51
  coerceObjectParamsToJsonString,
54
52
  decodeCoercedObjectArgs,
55
53
  } from "./coerce-object-args.js";
56
- import {
57
- applyGemini3UnsignedToolCallFallback,
58
- attachGoogleThoughtSignatureIfNeeded,
59
- classifyGoogleThoughtSignatureRetry,
60
- geminiThoughtSignaturesByToolCallId,
61
- type GoogleToolCallExtraContent,
62
- thoughtSignatureFromToolUseMetadata,
63
- toolUseMetadataFromChatCompletionsDelta,
64
- } from "./google-thought-signature.js";
65
54
  import {
66
55
  isOpenAICompatInlineAudio,
67
56
  OPENAI_COMPAT_MAX_INLINE_AUDIO_BYTES,
@@ -215,13 +204,7 @@ const log = getLogger("chat-completions");
215
204
  /** Wire-level reasoning_effort values. The OpenAI SDK type doesn't include
216
205
  * `"max"`, but Fireworks accepts it for DeepSeek V4; the assignment to
217
206
  * `params.reasoning_effort` casts through this union. */
218
- export type ReasoningEffortWire =
219
- | "none"
220
- | "low"
221
- | "medium"
222
- | "high"
223
- | "xhigh"
224
- | "max";
207
+ export type ReasoningEffortWire = "none" | "low" | "medium" | "high" | "xhigh" | "max";
225
208
 
226
209
  const REASONING_EFFORT_RANK: Record<ReasoningEffortWire, number> = {
227
210
  none: 0,
@@ -405,15 +388,9 @@ export function isThinkingEnabledOnWire(params: unknown): boolean {
405
388
  * rejected it because thinking/reasoning mode forbids that parameter.
406
389
  * DeepSeek thinking mode 400s with `Thinking mode does not support this
407
390
  * tool_choice` for any explicit value, including `"auto"` and `"none"`.
408
- * Kimi 400s with `tool_choice 'specified' is incompatible with thinking
409
- * enabled`. One retry without `tool_choice` lets the same provider succeed
410
- * instead of failing over to a different backend.
391
+ * One retry without `tool_choice` lets the same provider succeed instead of
392
+ * failing over to a different backend.
411
393
  */
412
- const THINKING_MODE_TOOL_CHOICE_REJECTION_PATTERNS: RegExp[] = [
413
- /does not support this tool_choice/i,
414
- /tool_choice\s+'specified'\s+is incompatible with thinking/i,
415
- ];
416
-
417
394
  function isThinkingModeToolChoiceRejection(
418
395
  error: unknown,
419
396
  params: unknown,
@@ -425,9 +402,8 @@ function isThinkingModeToolChoiceRejection(
425
402
  if (!isClientErrorStatus(error)) {
426
403
  return false;
427
404
  }
428
- const haystack = openaiCompatErrorHaystack(error);
429
- return THINKING_MODE_TOOL_CHOICE_REJECTION_PATTERNS.some((pattern) =>
430
- pattern.test(haystack),
405
+ return /does not support this tool_choice/i.test(
406
+ openaiCompatErrorHaystack(error),
431
407
  );
432
408
  }
433
409
 
@@ -565,10 +541,8 @@ function isMissingReasoningContentRejection(
565
541
 
566
542
  /**
567
543
  * True when the request included an assistant `reasoning` / `reasoning_content`
568
- * extra and the provider rejected it as an unknown or unsupported message
569
- * property. One retry without those extras lets a strict Chat Completions
570
- * schema succeed. Groq phrases this as
571
- * `property 'reasoning_content' is unsupported`.
544
+ * extra and the provider rejected it as an unknown message property. One retry
545
+ * without those extras lets a strict Chat Completions schema succeed.
572
546
  */
573
547
  function isUnknownAssistantReasoningFieldRejection(
574
548
  error: unknown,
@@ -587,7 +561,7 @@ function isUnknownAssistantReasoningFieldRejection(
587
561
  if (!haystackNamesAssistantReasoningField(haystack)) {
588
562
  return false;
589
563
  }
590
- return /unknown|unexpected|unrecognized|unsupported|not supported|additional propert|extra (?:field|property)|not (?:a )?valid|invalid (?:argument|parameter|field|property)/i.test(
564
+ return /unknown|unexpected|unrecognized|additional propert|extra (?:field|property)|not (?:a )?valid|invalid (?:argument|parameter|field|property)/i.test(
591
565
  haystack,
592
566
  );
593
567
  }
@@ -660,82 +634,6 @@ function flattenContentPartsToStrings(params: unknown): boolean {
660
634
  return flattened;
661
635
  }
662
636
 
663
- type OpenAICompatRetryKind =
664
- | "reasoning-opt-out"
665
- | "thinking-tool-choice"
666
- | "missing-reasoning-content"
667
- | "unknown-reasoning-field"
668
- | "missing-thought-signature"
669
- | "unknown-extra-content"
670
- | "chat-template";
671
-
672
- function classifyOpenAICompatRetry(
673
- error: unknown,
674
- params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming,
675
- thoughtSignaturesByCallId: ReadonlyMap<string, string>,
676
- ): { kind: OpenAICompatRetryKind; message: string; apply: () => void } | null {
677
- if (isReasoningOptOutRejection(error, params)) {
678
- return {
679
- kind: "reasoning-opt-out",
680
- message:
681
- "Model rejected the explicit reasoning opt-out; retrying without reasoning params",
682
- apply: () => {
683
- delete params.reasoning_effort;
684
- delete (params as unknown as Record<string, unknown>).reasoning;
685
- },
686
- };
687
- }
688
- if (isThinkingModeToolChoiceRejection(error, params)) {
689
- return {
690
- kind: "thinking-tool-choice",
691
- message:
692
- "Upstream rejected tool_choice in thinking mode; retrying without tool_choice",
693
- apply: () => {
694
- delete params.tool_choice;
695
- },
696
- };
697
- }
698
- if (isMissingReasoningContentRejection(error, params)) {
699
- return {
700
- kind: "missing-reasoning-content",
701
- message:
702
- "Upstream requires reasoning_content round-trip; retrying with empty field on assistant messages",
703
- apply: () => {
704
- backfillEmptyReasoningContent(params);
705
- },
706
- };
707
- }
708
- if (isUnknownAssistantReasoningFieldRejection(error, params)) {
709
- return {
710
- kind: "unknown-reasoning-field",
711
- message:
712
- "Upstream rejected assistant reasoning field; retrying without it",
713
- apply: () => {
714
- stripAssistantReasoningFields(params);
715
- },
716
- };
717
- }
718
- const thoughtSignatureRetry = classifyGoogleThoughtSignatureRetry(params, {
719
- isClientError: isClientErrorStatus(error),
720
- haystack: openaiCompatErrorHaystack(error),
721
- capturedByCallId: thoughtSignaturesByCallId,
722
- });
723
- if (thoughtSignatureRetry) {
724
- return thoughtSignatureRetry;
725
- }
726
- if (isChatTemplateRejection(error, params)) {
727
- return {
728
- kind: "chat-template",
729
- message:
730
- "Upstream chat template rejected structured message content; retrying with flattened plain-text content",
731
- apply: () => {
732
- flattenContentPartsToStrings(params);
733
- },
734
- };
735
- }
736
- return null;
737
- }
738
-
739
637
  /**
740
638
  * Translate the neutral (Anthropic-shaped) `tool_choice` carried on the call
741
639
  * config into the OpenAI chat-completions wire format. Callers express
@@ -876,13 +774,10 @@ export class OpenAIChatCompletionsProvider implements Provider {
876
774
  const coercedObjectKeys = new Map<string, string[]>();
877
775
 
878
776
  try {
879
- const thoughtSignaturesByCallId =
880
- geminiThoughtSignaturesByToolCallId(messages);
881
777
  const openaiMessages = await this.toOpenAIMessages(
882
778
  messages,
883
779
  systemPrompt,
884
780
  requestSupportsInlineAudio(modelOverride ?? this.model),
885
- modelOverride ?? this.model,
886
781
  );
887
782
 
888
783
  recordProviderRequestDiagnostics({
@@ -979,18 +874,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
979
874
  const thinkingOn = isThinkingEnabledOnWire(params);
980
875
  const skipAutoDefault = thinkingOn && toolChoice === "auto";
981
876
  const skipAllChoices = thinkingOn && this.omitToolChoiceWhenReasoning;
982
- const skipIncompatibleForcedChoice =
983
- thinkingOn &&
984
- !supportsForcedToolChoiceWithThinking(
985
- this.name,
986
- modelOverride ?? this.model,
987
- ) &&
988
- (toolChoice === "required" || typeof toolChoice === "object");
989
- if (
990
- !skipAutoDefault &&
991
- !skipAllChoices &&
992
- !skipIncompatibleForcedChoice
993
- ) {
877
+ if (!skipAutoDefault && !skipAllChoices) {
994
878
  params.tool_choice = toolChoice;
995
879
  }
996
880
  }
@@ -1089,12 +973,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
1089
973
 
1090
974
  const toolCallMap = new Map<
1091
975
  number,
1092
- {
1093
- id: string;
1094
- name: string;
1095
- args: string;
1096
- providerMetadata?: ToolUseContent["providerMetadata"];
1097
- }
976
+ { id: string; name: string; args: string }
1098
977
  >();
1099
978
  const toolProgress = createToolProgressEmitter(onEvent);
1100
979
  let finishReason = "unknown";
@@ -1122,31 +1001,68 @@ export class OpenAIChatCompletionsProvider implements Provider {
1122
1001
  ? { headers: requestHeaders }
1123
1002
  : {}),
1124
1003
  });
1125
- const attemptedCompatRetries = new Set<OpenAICompatRetryKind>();
1126
1004
  let stream: Awaited<ReturnType<typeof createStream>>;
1127
- for (;;) {
1128
- try {
1005
+ try {
1006
+ stream = await createStream();
1007
+ } catch (error) {
1008
+ if (isReasoningOptOutRejection(error, params)) {
1009
+ log.warn(
1010
+ {
1011
+ provider: this.name,
1012
+ model: modelOverride ?? this.model,
1013
+ error: error instanceof Error ? error.message : String(error),
1014
+ },
1015
+ "Model rejected the explicit reasoning opt-out; retrying without reasoning params",
1016
+ );
1017
+ delete params.reasoning_effort;
1018
+ delete (params as unknown as Record<string, unknown>).reasoning;
1129
1019
  stream = await createStream();
1130
- break;
1131
- } catch (error) {
1132
- const retry = classifyOpenAICompatRetry(
1133
- error,
1134
- params,
1135
- thoughtSignaturesByCallId,
1020
+ } else if (isThinkingModeToolChoiceRejection(error, params)) {
1021
+ log.warn(
1022
+ {
1023
+ provider: this.name,
1024
+ model: modelOverride ?? this.model,
1025
+ error: error instanceof Error ? error.message : String(error),
1026
+ },
1027
+ "Upstream rejected tool_choice in thinking mode; retrying without tool_choice",
1136
1028
  );
1137
- if (!retry || attemptedCompatRetries.has(retry.kind)) {
1138
- throw error;
1139
- }
1140
- attemptedCompatRetries.add(retry.kind);
1029
+ delete params.tool_choice;
1030
+ stream = await createStream();
1031
+ } else if (isMissingReasoningContentRejection(error, params)) {
1032
+ log.warn(
1033
+ {
1034
+ provider: this.name,
1035
+ model: modelOverride ?? this.model,
1036
+ error: error instanceof Error ? error.message : String(error),
1037
+ },
1038
+ "Upstream requires reasoning_content round-trip; retrying with empty field on assistant messages",
1039
+ );
1040
+ backfillEmptyReasoningContent(params);
1041
+ stream = await createStream();
1042
+ } else if (isUnknownAssistantReasoningFieldRejection(error, params)) {
1141
1043
  log.warn(
1142
1044
  {
1143
1045
  provider: this.name,
1144
1046
  model: modelOverride ?? this.model,
1145
1047
  error: error instanceof Error ? error.message : String(error),
1146
1048
  },
1147
- retry.message,
1049
+ "Upstream rejected assistant reasoning field; retrying without it",
1148
1050
  );
1149
- retry.apply();
1051
+ stripAssistantReasoningFields(params);
1052
+ stream = await createStream();
1053
+ } else if (isChatTemplateRejection(error, params)) {
1054
+ log.warn(
1055
+ {
1056
+ provider: this.name,
1057
+ model: modelOverride ?? this.model,
1058
+ error: error instanceof Error ? error.message : String(error),
1059
+ },
1060
+ "Upstream chat template rejected structured message content; retrying with flattened plain-text content",
1061
+ );
1062
+ flattenContentPartsToStrings(params);
1063
+ stream = await createStream();
1064
+ } else {
1065
+ throw error;
1150
1066
  }
1151
1067
  }
1152
1068
 
@@ -1234,14 +1150,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
1234
1150
  entry.args,
1235
1151
  );
1236
1152
  }
1237
- const providerMetadata =
1238
- toolUseMetadataFromChatCompletionsDelta(tc);
1239
- if (
1240
- providerMetadata &&
1241
- !thoughtSignatureFromToolUseMetadata(entry.providerMetadata)
1242
- ) {
1243
- entry.providerMetadata = providerMetadata;
1244
- }
1245
1153
  }
1246
1154
  }
1247
1155
 
@@ -1363,9 +1271,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
1363
1271
  id: tc.id,
1364
1272
  name: tc.name,
1365
1273
  input,
1366
- ...(tc.providerMetadata
1367
- ? { providerMetadata: tc.providerMetadata }
1368
- : {}),
1369
1274
  });
1370
1275
  }
1371
1276
 
@@ -1379,19 +1284,11 @@ export class OpenAIChatCompletionsProvider implements Provider {
1379
1284
  content: contentText || null,
1380
1285
  tool_calls:
1381
1286
  toolCallMap.size > 0
1382
- ? Array.from(toolCallMap.values()).map((tc) =>
1383
- attachGoogleThoughtSignatureIfNeeded(
1384
- {
1385
- id: tc.id,
1386
- type: "function",
1387
- function: { name: tc.name, arguments: tc.args },
1388
- },
1389
- thoughtSignatureFromToolUseMetadata(
1390
- tc.providerMetadata,
1391
- ),
1392
- modelOverride ?? this.model,
1393
- ),
1394
- )
1287
+ ? Array.from(toolCallMap.values()).map((tc) => ({
1288
+ id: tc.id,
1289
+ type: "function",
1290
+ function: { name: tc.name, arguments: tc.args },
1291
+ }))
1395
1292
  : undefined,
1396
1293
  },
1397
1294
  finish_reason: finishReason,
@@ -1595,7 +1492,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
1595
1492
  messages: Message[],
1596
1493
  systemPrompt?: string,
1597
1494
  audioInputEnabled = false,
1598
- model = this.model,
1599
1495
  ): Promise<OpenAI.Chat.Completions.ChatCompletionMessageParam[]> {
1600
1496
  // Swap any persisted attachment references back to inline base64 before
1601
1497
  // serializing, so the block transforms below can read `source.data`.
@@ -1617,7 +1513,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
1617
1513
  const emittedToolCallIds = new Set<string>();
1618
1514
  for (const msg of messages) {
1619
1515
  if (msg.role === "assistant") {
1620
- const assistantMessage = this.toOpenAIAssistantMessage(msg, model);
1516
+ const assistantMessage = this.toOpenAIAssistantMessage(msg);
1621
1517
  for (const toolCall of assistantMessage.tool_calls ?? []) {
1622
1518
  emittedToolCallIds.add(toolCall.id);
1623
1519
  }
@@ -1695,14 +1591,11 @@ export class OpenAIChatCompletionsProvider implements Provider {
1695
1591
  /** Convert an assistant message with text + tool_use blocks to OpenAI format. */
1696
1592
  private toOpenAIAssistantMessage(
1697
1593
  msg: Message,
1698
- model: string,
1699
1594
  ): OpenAI.Chat.Completions.ChatCompletionAssistantMessageParam {
1700
1595
  const textParts: string[] = [];
1701
1596
  const reasoningParts: string[] = [];
1702
- const toolCalls: Array<
1703
- OpenAI.Chat.Completions.ChatCompletionMessageToolCall &
1704
- GoogleToolCallExtraContent
1705
- > = [];
1597
+ const toolCalls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[] =
1598
+ [];
1706
1599
 
1707
1600
  for (const block of msg.content) {
1708
1601
  switch (block.type) {
@@ -1716,20 +1609,14 @@ export class OpenAIChatCompletionsProvider implements Provider {
1716
1609
  }
1717
1610
  break;
1718
1611
  case "tool_use":
1719
- toolCalls.push(
1720
- attachGoogleThoughtSignatureIfNeeded(
1721
- {
1722
- id: block.id,
1723
- type: "function",
1724
- function: {
1725
- name: block.name,
1726
- arguments: JSON.stringify(block.input),
1727
- },
1728
- },
1729
- thoughtSignatureFromToolUseMetadata(block.providerMetadata),
1730
- model,
1731
- ),
1732
- );
1612
+ toolCalls.push({
1613
+ id: block.id,
1614
+ type: "function",
1615
+ function: {
1616
+ name: block.name,
1617
+ arguments: JSON.stringify(block.input),
1618
+ },
1619
+ });
1733
1620
  break;
1734
1621
  case "server_tool_use":
1735
1622
  textParts.push(`[Web search: ${block.name}]`);
@@ -1748,7 +1635,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
1748
1635
  };
1749
1636
 
1750
1637
  if (toolCalls.length > 0) {
1751
- applyGemini3UnsignedToolCallFallback(toolCalls, model);
1752
1638
  result.tool_calls = toolCalls;
1753
1639
  }
1754
1640
 
@@ -14,6 +14,10 @@ export const CODEX_SUBSCRIPTION_MODEL_IDS: ReadonlySet<string> = new Set([
14
14
  "gpt-5.6-terra",
15
15
  "gpt-5.6-luna",
16
16
  "gpt-5.5",
17
+ // OpenAI retires these two from ChatGPT sign-in on 2026-08-31; API-key
18
+ // auth is unaffected.
19
+ "gpt-5.4",
20
+ "gpt-5.4-mini",
17
21
  ]);
18
22
 
19
23
  /** True when `model` is allowlisted for Codex subscription routing. */
@@ -12,8 +12,6 @@ The single HTTP send endpoint is `POST /v1/messages`. Key behaviors:
12
12
 
13
13
  Do NOT add new send endpoints. All message ingress should go through `POST /v1/messages` (HTTP).
14
14
 
15
- `POST /v1/channels/send` is not ingress: it is outbound delivery, the assistant posting text to a channel chat. It runs `sendChannelText` (`runtime/channel-send.ts`), the one send implementation for every channel whose transport declares proactive addressing (`ChannelTransport.addressFor`), and the messaging tool's channel branch runs the same function in-process, as the CLI's channel send door does over the route. A model-directed channel send goes through that function or it is not recorded; do not add a provider-side send for a channel that has a transport. The route names no sending turn: only the in-process tool call can claim a send landed in the turn's own chat, so everything sent through the route is recorded.
16
-
17
15
  **`interrupt-on-send`: a send may stop the running turn instead of queueing behind it.** With the flag on, a busy conversation is handed to `interruptRunningTurn` (`daemon/conversation-interrupt.ts`), which aborts the turn with `preempted_by_new_message`, waits for it to release the processing lock AND for its turn-boundary commit to finish, repairs the abandoned `tool_use` blocks with a persisted synthetic `tool_result`, and answers `released`. The route then falls through to the code an idle conversation already uses, so there is one turn dispatch rather than a second one for interrupts. The queue is not discarded: it may hold another actor's messages.
18
16
 
19
17
  **The handover runs off the response, not on it.** Fire-and-forget is not suspended for an interrupt. The eligibility decision is synchronous (`classifyInterruptEligibility`), so the route answers `202 { accepted, requestId }` the moment it accepts the message, then runs the abort, the release wait, the commit wait, the repair, the persist and the dispatch in a detached task. Holding the request would cost the abort budget (`ABORT_RELEASE_WAIT_MS`) plus the turn-boundary commit wait, long enough for a client to time out and retry a message the daemon is still placing. That 202 carries `messageId` as well as `requestId`, and they are the same value: a user turn persists its row under its `requestId` (`persistUserMessage` passes `id: requestId`), which is what lets the id be answered before the row exists. Both are required, not decorative: `postChatMessage` rejects an accepted, non-queued response without a string `messageId` and the client drops the optimistic row. Clients reconcile that row on `user_message_echo`. Two rules for anything added to that task: it must not be able to drop the message (every failure path falls back to `queueSend`, which never takes the enqueue's idle fast path, and a queue that refuses the fallback is reported to the sender as a `QUEUE_FULL` error keyed on the `requestId` the 202 carried, since the 429 itself reaches nobody), and a duplicate `clientMessageId` is answered from the existing row BEFORE the abort, since the insert's own dedup settles too late to un-abort a turn.
@@ -142,7 +142,9 @@ function detectRejection(
142
142
  ? args.hub.getActorPrincipalIdForClient(args.targetClientId)
143
143
  : (args.targetActorPrincipalId ??
144
144
  (isHttpAuthDisabled() && targetClientId
145
- ? args.hubForMissingTarget?.getActorPrincipalIdForClient(targetClientId)
145
+ ? args.hubForMissingTarget?.getActorPrincipalIdForClient(
146
+ targetClientId,
147
+ )
146
148
  : undefined));
147
149
 
148
150
  let reason: RejectionReason | undefined;
@@ -262,43 +264,6 @@ export function pickSameUserAutoResolve(args: {
262
264
  return { kind: "ambiguous" };
263
265
  }
264
266
 
265
- /**
266
- * Pick the most recently active capable client owned by the turn actor.
267
- * `listClientsByCapability` is ordered by recent activity, so the first
268
- * same-user match provides deterministic routing without broadcasting a host
269
- * request across multiple devices.
270
- */
271
- export function pickMostRecentSameUserClient(args: {
272
- hub: Pick<AssistantEventHub, "listClientsByCapability">;
273
- capability: HostProxyCapability;
274
- sourceActorPrincipalId: string | undefined;
275
- }): string | undefined {
276
- const { hub, capability, sourceActorPrincipalId } = args;
277
- if (sourceActorPrincipalId == null) {
278
- return undefined;
279
- }
280
- return hub
281
- .listClientsByCapability(capability)
282
- .find((client) => client.actorPrincipalId === sourceActorPrincipalId)
283
- ?.clientId;
284
- }
285
-
286
- /**
287
- * Error result for an automatic host route with no capable client owned by the
288
- * actor that initiated the turn.
289
- */
290
- export function unavailableSameUserClientError(
291
- capability: HostProxyCapability,
292
- ): {
293
- content: string;
294
- isError: true;
295
- } {
296
- return {
297
- content: `No connected ${capability} client belongs to this user. Connect a capable client signed in as the same user, then retry.`,
298
- isError: true,
299
- };
300
- }
301
-
302
267
  /**
303
268
  * Actor principal persisted on a host-proxy pending interaction.
304
269
  *