@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
@@ -32,12 +32,6 @@ import {
32
32
  } from "../daemon/daemon-readiness.js";
33
33
  import { processMessage } from "../daemon/process-message.js";
34
34
  import { makeAddrInUseError } from "../daemon/startup-error.js";
35
- import { isAssistantDesktopEnabled } from "../desktop/desktop-feature.js";
36
- import {
37
- DESKTOP_CLOSE,
38
- destroyDesktopSessionManager,
39
- } from "../desktop/desktop-session-manager.js";
40
- import { DesktopStreamBridge } from "../desktop/desktop-stream-bridge.js";
41
35
  import {
42
36
  createLiveVoiceConnection,
43
37
  type LiveVoiceConnection,
@@ -235,32 +229,6 @@ interface WatchStreamWebSocketData {
235
229
  session?: WatchStreamSession;
236
230
  }
237
231
 
238
- /**
239
- * WebSocket data for `/v1/desktop/stream`: raw RFB bytes to the assistant
240
- * desktop.
241
- */
242
- interface DesktopStreamWebSocketData {
243
- wsType: "desktop-stream";
244
- /** Bound at open time so message/close handlers reach this socket's pump. */
245
- bridge?: DesktopStreamBridge;
246
- }
247
-
248
- type AllWebSocketData =
249
- | MediaStreamWebSocketData
250
- | SttStreamWebSocketData
251
- | LiveVoiceWebSocketData
252
- | WatchStreamWebSocketData
253
- | DesktopStreamWebSocketData;
254
-
255
- function assistantDesktopEnabled(): boolean {
256
- try {
257
- return isAssistantDesktopEnabled(getConfig());
258
- } catch (err) {
259
- log.warn({ err }, "Failed to read config for desktop stream gate");
260
- return false;
261
- }
262
- }
263
-
264
232
  export class RuntimeHttpServer {
265
233
  private server: ReturnType<typeof Bun.serve> | null = null;
266
234
  private port: number;
@@ -296,6 +264,11 @@ export class RuntimeHttpServer {
296
264
  }
297
265
 
298
266
  async start(): Promise<void> {
267
+ type AllWebSocketData =
268
+ | MediaStreamWebSocketData
269
+ | SttStreamWebSocketData
270
+ | LiveVoiceWebSocketData
271
+ | WatchStreamWebSocketData;
299
272
  this.server = Bun.serve<AllWebSocketData>({
300
273
  port: this.port,
301
274
  hostname: this.hostname,
@@ -451,22 +424,6 @@ export class RuntimeHttpServer {
451
424
  void session.start();
452
425
  return;
453
426
  }
454
- if (data.wsType === "desktop-stream") {
455
- log.info("Desktop stream WebSocket opened");
456
- if (!assistantDesktopEnabled()) {
457
- ws.close(
458
- DESKTOP_CLOSE.unavailable,
459
- "Desktop is not available on this assistant",
460
- );
461
- return;
462
- }
463
- const bridge = new DesktopStreamBridge(ws, {
464
- isEnabled: assistantDesktopEnabled,
465
- });
466
- data.bridge = bridge;
467
- void bridge.start();
468
- return;
469
- }
470
427
  log.warn("WebSocket opened with unknown data type — closing");
471
428
  ws.close(1008, "Unknown WebSocket type");
472
429
  },
@@ -517,10 +474,6 @@ export class RuntimeHttpServer {
517
474
  }
518
475
  return;
519
476
  }
520
- if (data.wsType === "desktop-stream") {
521
- data.bridge?.handleClientFrame(message);
522
- return;
523
- }
524
477
  log.warn("WebSocket message on unknown data type — closing");
525
478
  ws.close(1008, "Unknown WebSocket type");
526
479
  },
@@ -614,14 +567,6 @@ export class RuntimeHttpServer {
614
567
  }
615
568
  return;
616
569
  }
617
- if (data.wsType === "desktop-stream") {
618
- log.info(
619
- { code, reason: reason?.toString() },
620
- "Desktop stream WebSocket closed",
621
- );
622
- data.bridge?.handleClose();
623
- return;
624
- }
625
570
  log.warn(
626
571
  { code, reason: reason?.toString() },
627
572
  "WebSocket with unknown data type closed",
@@ -762,9 +707,6 @@ export class RuntimeHttpServer {
762
707
  // that a socket closing just before shutdown had already under way.
763
708
  await drainWatchRetros();
764
709
 
765
- // Bounded by the manager's kill grace, so shutdown never hangs on X.
766
- await destroyDesktopSessionManager();
767
-
768
710
  const liveVoiceManager = getLiveVoiceSessionManager();
769
711
  const liveVoiceSessionId = liveVoiceManager.activeSessionId;
770
712
  if (liveVoiceSessionId) {
@@ -868,15 +810,6 @@ export class RuntimeHttpServer {
868
810
  return this.handleWatchStreamUpgrade(req, server);
869
811
  }
870
812
 
871
- // WebSocket upgrade for the assistant desktop RFB stream, under the same
872
- // private-network restrictions and gateway-service token verification.
873
- if (
874
- path === "/v1/desktop/stream" &&
875
- req.headers.get("upgrade")?.toLowerCase() === "websocket"
876
- ) {
877
- return this.handleDesktopStreamUpgrade(req, server);
878
- }
879
-
880
813
  // Twilio webhook endpoints — before auth check because Twilio
881
814
  // webhook POSTs don't include bearer tokens.
882
815
  const twilioResponse = await this.handleTwilioWebhook(req, path);
@@ -1016,141 +949,199 @@ export class RuntimeHttpServer {
1016
949
  return null;
1017
950
  }
1018
951
 
1019
- /**
1020
- * Shared path for gateway-proxied WebSocket upgrades: private network peers
1021
- * and origins only, then a gateway service token, then `parse` builds the
1022
- * socket data (or a 4xx Response) and the upgrade happens. The gateway owns
1023
- * downstream client auth and dials these upstreams on the client's behalf.
1024
- * Returns a Response on failure. On success Bun has consumed the request and
1025
- * nothing is returned; the type is `Response` only to fit the router.
1026
- */
1027
- private upgradeRuntimeStream(
952
+ private handleMediaStreamUpgrade(
1028
953
  req: Request,
1029
954
  server: ReturnType<typeof Bun.serve>,
1030
- label: string,
1031
- parse: (query: URLSearchParams) => AllWebSocketData | Response,
1032
955
  ): Response {
1033
956
  if (!isPrivateNetworkPeer(server, req) || !isPrivateNetworkOrigin(req)) {
1034
957
  return httpError(
1035
958
  "FORBIDDEN",
1036
- `Direct ${label} access disabled: only private network peers allowed`,
959
+ "Direct media-stream access disabled — only private network peers allowed",
1037
960
  403,
1038
961
  );
1039
962
  }
963
+
964
+ // Verify the gateway service token before accepting the upgrade.
1040
965
  const tokenError = this.verifyGatewayServiceToken(req);
1041
966
  if (tokenError) {
1042
967
  return tokenError;
1043
968
  }
1044
- const data = parse(new URL(req.url).searchParams);
1045
- if (data instanceof Response) {
1046
- return data;
1047
- }
1048
- if (!server.upgrade(req, { data })) {
1049
- return new Response("WebSocket upgrade failed", { status: 500 });
1050
- }
1051
- return undefined!;
1052
- }
1053
969
 
1054
- private handleMediaStreamUpgrade(
1055
- req: Request,
1056
- server: ReturnType<typeof Bun.serve>,
1057
- ): Response {
1058
- return this.upgradeRuntimeStream(req, server, "media-stream", (query) => {
1059
- const callSessionId = query.get("callSessionId");
1060
- if (!callSessionId) {
1061
- return new Response("Missing callSessionId", { status: 400 });
1062
- }
1063
- // A distinct wsType routes these to MediaStreamCallSession.
1064
- return {
970
+ const wsUrl = new URL(req.url);
971
+ const callSessionId = wsUrl.searchParams.get("callSessionId");
972
+ if (!callSessionId) {
973
+ return new Response("Missing callSessionId", { status: 400 });
974
+ }
975
+ // Media-stream connections use a distinct wsType so the open/message/close
976
+ // handlers route them to MediaStreamCallSession.
977
+ const upgraded = server.upgrade(req, {
978
+ data: {
1065
979
  wsType: "media-stream",
1066
980
  callSessionId,
1067
- } satisfies MediaStreamWebSocketData;
981
+ } satisfies MediaStreamWebSocketData,
1068
982
  });
983
+ if (!upgraded) {
984
+ return new Response("WebSocket upgrade failed", { status: 500 });
985
+ }
986
+ // Bun's WebSocket upgrade consumes the request — no Response is sent.
987
+ return undefined!;
1069
988
  }
1070
989
 
1071
- /** Handle WebSocket upgrade for `/v1/stt/stream`. */
990
+ /**
991
+ * Handle WebSocket upgrade for `/v1/stt/stream`.
992
+ *
993
+ * Private-network restrictions apply (same as media-stream) so the
994
+ * runtime remains unreachable from the public internet. The gateway
995
+ * authenticates the downstream client and proxies the upgrade with a
996
+ * short-lived gateway service token.
997
+ */
1072
998
  private handleSttStreamUpgrade(
1073
999
  req: Request,
1074
1000
  server: ReturnType<typeof Bun.serve>,
1075
1001
  ): Response {
1076
- return this.upgradeRuntimeStream(req, server, "STT stream", (query) => {
1077
- // provider is optional compatibility metadata; the runtime resolves
1078
- // the streaming transcriber from config (`services.stt.provider`).
1079
- const provider = query.get("provider") ?? undefined;
1080
- const mimeType = query.get("mimeType");
1081
- if (!mimeType) {
1082
- return new Response("Missing required query parameter: mimeType", {
1083
- status: 400,
1084
- });
1085
- }
1086
- const sampleRateRaw = query.get("sampleRate");
1087
- return {
1002
+ if (!isPrivateNetworkPeer(server, req) || !isPrivateNetworkOrigin(req)) {
1003
+ return httpError(
1004
+ "FORBIDDEN",
1005
+ "Direct STT stream access disabled — only private network peers allowed",
1006
+ 403,
1007
+ );
1008
+ }
1009
+
1010
+ // Verify the gateway service token before accepting the upgrade.
1011
+ const tokenError = this.verifyGatewayServiceToken(req);
1012
+ if (tokenError) {
1013
+ return tokenError;
1014
+ }
1015
+
1016
+ const wsUrl = new URL(req.url);
1017
+ // provider is optional compatibility metadata — the runtime resolves
1018
+ // the streaming transcriber from config (`services.stt.provider`).
1019
+ const provider = wsUrl.searchParams.get("provider") ?? undefined;
1020
+ const mimeType = wsUrl.searchParams.get("mimeType");
1021
+ if (!mimeType) {
1022
+ return new Response("Missing required query parameter: mimeType", {
1023
+ status: 400,
1024
+ });
1025
+ }
1026
+
1027
+ const sampleRateRaw = wsUrl.searchParams.get("sampleRate");
1028
+ const sampleRate = sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined;
1029
+
1030
+ const sessionId = crypto.randomUUID();
1031
+ const upgraded = server.upgrade(req, {
1032
+ data: {
1088
1033
  wsType: "stt-stream",
1089
1034
  provider,
1090
1035
  mimeType,
1091
- sampleRate: sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined,
1092
- sessionId: crypto.randomUUID(),
1093
- } satisfies SttStreamWebSocketData;
1036
+ sampleRate,
1037
+ sessionId,
1038
+ } satisfies SttStreamWebSocketData,
1094
1039
  });
1040
+ if (!upgraded) {
1041
+ return new Response("WebSocket upgrade failed", { status: 500 });
1042
+ }
1043
+ // Bun's WebSocket upgrade consumes the request — no Response is sent.
1044
+ return undefined!;
1095
1045
  }
1096
1046
 
1097
- /** Handle WebSocket upgrade for `/v1/live-voice`. */
1047
+ /**
1048
+ * Handle WebSocket upgrade for `/v1/live-voice`.
1049
+ *
1050
+ * The gateway owns downstream client auth and forwards this upstream with
1051
+ * a short-lived gateway service token. The runtime accepts only private
1052
+ * network peers/origins so the shell is not publicly reachable.
1053
+ */
1098
1054
  private handleLiveVoiceUpgrade(
1099
1055
  req: Request,
1100
1056
  server: ReturnType<typeof Bun.serve>,
1101
1057
  ): Response {
1102
- return this.upgradeRuntimeStream(req, server, "live voice", (query) => {
1103
- const guardianPrincipalId = query.get("guardianPrincipalId")?.trim();
1104
- return {
1058
+ if (!isPrivateNetworkPeer(server, req) || !isPrivateNetworkOrigin(req)) {
1059
+ return httpError(
1060
+ "FORBIDDEN",
1061
+ "Direct live voice access disabled — only private network peers allowed",
1062
+ 403,
1063
+ );
1064
+ }
1065
+
1066
+ const tokenError = this.verifyGatewayServiceToken(req);
1067
+ if (tokenError) {
1068
+ return tokenError;
1069
+ }
1070
+
1071
+ const guardianPrincipalId =
1072
+ new URL(req.url).searchParams.get("guardianPrincipalId")?.trim() ||
1073
+ undefined;
1074
+
1075
+ const upgraded = server.upgrade(req, {
1076
+ data: {
1105
1077
  wsType: "live-voice",
1106
1078
  ...(guardianPrincipalId ? { guardianPrincipalId } : {}),
1107
- } satisfies LiveVoiceWebSocketData;
1079
+ } satisfies LiveVoiceWebSocketData,
1108
1080
  });
1081
+ if (!upgraded) {
1082
+ return new Response("WebSocket upgrade failed", { status: 500 });
1083
+ }
1084
+ return undefined!;
1109
1085
  }
1110
1086
 
1111
- /** Handle WebSocket upgrade for `/v1/watch/stream`. */
1087
+ /**
1088
+ * Handle WebSocket upgrade for `/v1/watch/stream`.
1089
+ *
1090
+ * Gated exactly as `/v1/stt/stream` is: private network peers and origins
1091
+ * only, then a gateway service token. The gateway owns downstream client
1092
+ * auth and dials this upstream on the client's behalf.
1093
+ */
1112
1094
  private handleWatchStreamUpgrade(
1113
1095
  req: Request,
1114
1096
  server: ReturnType<typeof Bun.serve>,
1115
1097
  ): Response {
1116
- return this.upgradeRuntimeStream(req, server, "watch stream", (query) => {
1117
- const mimeType = query.get("mimeType");
1118
- if (!mimeType) {
1119
- return new Response("Missing required query parameter: mimeType", {
1120
- status: 400,
1121
- });
1122
- }
1123
- const sampleRateRaw = query.get("sampleRate");
1124
- const parsedTarget = parseWatchCaptureTarget(query);
1125
- if ("error" in parsedTarget) {
1126
- return new Response(parsedTarget.error, { status: 400 });
1127
- }
1128
- return {
1098
+ if (!isPrivateNetworkPeer(server, req) || !isPrivateNetworkOrigin(req)) {
1099
+ return httpError(
1100
+ "FORBIDDEN",
1101
+ "Direct watch stream access disabled: only private network peers allowed",
1102
+ 403,
1103
+ );
1104
+ }
1105
+
1106
+ const tokenError = this.verifyGatewayServiceToken(req);
1107
+ if (tokenError) {
1108
+ return tokenError;
1109
+ }
1110
+
1111
+ const wsUrl = new URL(req.url);
1112
+ const mimeType = wsUrl.searchParams.get("mimeType");
1113
+ if (!mimeType) {
1114
+ return new Response("Missing required query parameter: mimeType", {
1115
+ status: 400,
1116
+ });
1117
+ }
1118
+
1119
+ const sampleRateRaw = wsUrl.searchParams.get("sampleRate");
1120
+ const sampleRate = sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined;
1121
+ const conversationId =
1122
+ wsUrl.searchParams.get("conversationId")?.trim() || undefined;
1123
+ const clientId = wsUrl.searchParams.get("clientId")?.trim() || undefined;
1124
+ const parsedTarget = parseWatchCaptureTarget(wsUrl.searchParams);
1125
+ if ("error" in parsedTarget) {
1126
+ return new Response(parsedTarget.error, { status: 400 });
1127
+ }
1128
+
1129
+ const upgraded = server.upgrade(req, {
1130
+ data: {
1129
1131
  wsType: "watch-stream",
1130
1132
  mimeType,
1131
- sampleRate: sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined,
1132
- conversationId: query.get("conversationId")?.trim() || undefined,
1133
- clientId: query.get("clientId")?.trim() || undefined,
1133
+ sampleRate,
1134
+ conversationId,
1135
+ clientId,
1134
1136
  captureTarget: parsedTarget.captureTarget,
1135
1137
  sessionId: crypto.randomUUID(),
1136
- } satisfies WatchStreamWebSocketData;
1138
+ } satisfies WatchStreamWebSocketData,
1137
1139
  });
1138
- }
1139
-
1140
- /**
1141
- * Handle WebSocket upgrade for `/v1/desktop/stream`. The feature gate runs
1142
- * in the open handler, as close code 4008.
1143
- */
1144
- private handleDesktopStreamUpgrade(
1145
- req: Request,
1146
- server: ReturnType<typeof Bun.serve>,
1147
- ): Response {
1148
- return this.upgradeRuntimeStream(
1149
- req,
1150
- server,
1151
- "desktop stream",
1152
- () => ({ wsType: "desktop-stream" }) satisfies DesktopStreamWebSocketData,
1153
- );
1140
+ if (!upgraded) {
1141
+ return new Response("WebSocket upgrade failed", { status: 500 });
1142
+ }
1143
+ // Bun's WebSocket upgrade consumes the request, so no Response is sent.
1144
+ return undefined!;
1154
1145
  }
1155
1146
 
1156
1147
  private async handleTwilioWebhook(
@@ -11,8 +11,7 @@
11
11
  * silently auto-installs allowlisted adapter packages via a sandboxed `bun`
12
12
  * global install before failing with the install hint. `execFile` is stubbed
13
13
  * via the shared `installExecFileStub` helper so tests can script
14
- * `bun add --global` outcomes. It also threads the optional `model` through to
15
- * the session manager and relays the warning a refused model comes back with.
14
+ * `bun add --global` outcomes.
16
15
  */
17
16
 
18
17
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
@@ -44,10 +43,6 @@ interface FakeSessionState {
44
43
  completedAt?: number;
45
44
  error?: string;
46
45
  stopReason?: string;
47
- model?: string;
48
- availableModels?: Array<{ value: string; label: string }>;
49
- modelRevisionEpoch?: string;
50
- modelRevision?: number;
51
46
  latestUsage?: {
52
47
  usedTokens: number;
53
48
  contextSize: number;
@@ -60,27 +55,10 @@ interface FakeSessionState {
60
55
 
61
56
  let fakeInMemorySessions: FakeSessionState[] = [];
62
57
 
63
- interface SpawnResult {
64
- acpSessionId: string;
65
- protocolSessionId: string;
66
- requestedModel?: string;
67
- effectiveModel?: string;
68
- modelWarning?: string;
69
- }
70
-
71
- const DEFAULT_SPAWN_RESULT: SpawnResult = {
58
+ const spawnMock = mock(async () => ({
72
59
  acpSessionId: "acp-route-session",
73
60
  protocolSessionId: "proto-route-session",
74
- effectiveModel: "opus",
75
- };
76
- let spawnResult: SpawnResult = DEFAULT_SPAWN_RESULT;
77
- const spawnMock = mock(async (...args: unknown[]) => {
78
- const options = args[6] as { model?: string } | undefined;
79
- return {
80
- ...spawnResult,
81
- requestedModel: options?.model?.trim() || undefined,
82
- };
83
- });
61
+ }));
84
62
 
85
63
  const defaultSteerOrResumeImpl = async (
86
64
  _id: string,
@@ -204,10 +182,6 @@ interface ResponseShape {
204
182
  outputTokens?: number;
205
183
  eventLog?: unknown[];
206
184
  authErrorCode?: string;
207
- model?: string;
208
- availableModels?: Array<{ value: string; label: string }>;
209
- modelRevisionEpoch?: string;
210
- modelRevision?: number;
211
185
  }>;
212
186
  }
213
187
 
@@ -216,7 +190,6 @@ beforeEach(() => {
216
190
  clearHistory();
217
191
  resetExecFileStub();
218
192
  spawnMock.mockClear();
219
- spawnResult = DEFAULT_SPAWN_RESULT;
220
193
  steerOrResumeMock.mockClear();
221
194
  steerOrResumeImpl = defaultSteerOrResumeImpl;
222
195
  _resetAdapterInstallCacheForTests();
@@ -355,60 +328,6 @@ describe("GET /v1/acp/sessions — merged in-memory + history", () => {
355
328
  expect(s!.outputTokens).toBeUndefined();
356
329
  });
357
330
 
358
- test("carries the model for both layers and the picker for live ones only", async () => {
359
- fakeInMemorySessions = [
360
- {
361
- id: "live-model",
362
- agentId: "agent-live",
363
- acpSessionId: "proto-live",
364
- parentConversationId: "conv-model",
365
- status: "running",
366
- startedAt: 9000,
367
- model: "opus",
368
- modelRevisionEpoch: "01900000-0000-7000-8000-000000000001",
369
- modelRevision: 17,
370
- availableModels: [
371
- { value: "sonnet", label: "Sonnet" },
372
- { value: "opus", label: "Opus" },
373
- ],
374
- },
375
- ];
376
- insertHistoryRow({
377
- id: "hist-model",
378
- agentId: "agent-hist",
379
- acpSessionId: "proto-hist",
380
- parentConversationId: "conv-model",
381
- startedAt: 1000,
382
- status: "completed",
383
- });
384
-
385
- const handler = getSessionsHandler();
386
- const body = (await handler({})) as ResponseShape;
387
- const live = body.sessions.find((s) => s.id === "live-model");
388
- const hist = body.sessions.find((s) => s.id === "hist-model");
389
- expect(live).toMatchObject({
390
- model: "opus",
391
- modelRevisionEpoch: "01900000-0000-7000-8000-000000000001",
392
- modelRevision: 17,
393
- availableModels: [
394
- { value: "sonnet", label: "Sonnet" },
395
- { value: "opus", label: "Opus" },
396
- ],
397
- });
398
- // A finished run has no live process to ask, so it reports neither.
399
- expect(hist?.model).toBeUndefined();
400
- expect(hist?.availableModels).toBeUndefined();
401
- });
402
-
403
- test("omits the model for history rows written without one", async () => {
404
- insertHistoryRow({ id: "hist-no-model", status: "completed" });
405
-
406
- const handler = getSessionsHandler();
407
- const body = (await handler({})) as ResponseShape;
408
- const s = body.sessions.find((row) => row.id === "hist-no-model");
409
- expect(s?.model).toBeUndefined();
410
- });
411
-
412
331
  test("dedupes by id with in-memory winning on collision", async () => {
413
332
  // Same id in both layers — in-memory entry should win and its eventLog
414
333
  // comes from the live ring buffer (empty here), not the stale history row.
@@ -660,8 +579,6 @@ describe("POST /v1/acp/spawn: sandboxed bun auto-install on missing binary", ()
660
579
  acpSessionId: "acp-route-session",
661
580
  protocolSessionId: "proto-route-session",
662
581
  agent: "claude",
663
- requestedModel: null,
664
- effectiveModel: "opus",
665
582
  });
666
583
  expect(spawnMock).toHaveBeenCalledTimes(1);
667
584
  // The real adapter binary is spawned, not a `bun x` wrapper.
@@ -676,7 +593,7 @@ describe("POST /v1/acp/spawn: sandboxed bun auto-install on missing binary", ()
676
593
  expect(args).toEqual([
677
594
  "add",
678
595
  "--global",
679
- "@agentclientprotocol/claude-agent-acp@0.75.1",
596
+ "@agentclientprotocol/claude-agent-acp",
680
597
  ]);
681
598
  });
682
599
 
@@ -763,78 +680,6 @@ describe("POST /v1/acp/spawn: sandboxed bun auto-install on missing binary", ()
763
680
  });
764
681
  });
765
682
 
766
- describe("POST /v1/acp/spawn: model selection", () => {
767
- test("threads the requested model to the session manager", async () => {
768
- const handler = getSpawnHandler();
769
- const body = (await handler({
770
- body: { ...SPAWN_BODY, model: "opus" },
771
- })) as Record<string, unknown>;
772
-
773
- expect(confirmationRequests).toHaveLength(1);
774
- expect(confirmationRequests[0]?.input).toEqual({
775
- agent: "claude",
776
- task: "do something",
777
- cwd: process.cwd(),
778
- model: "opus",
779
- });
780
- expect(spawnMock).toHaveBeenCalledTimes(1);
781
- expect((spawnMock.mock.calls[0] as unknown[])[6]).toEqual({
782
- model: "opus",
783
- });
784
-
785
- expect(body.requestedModel).toBe("opus");
786
- expect(body.effectiveModel).toBe("opus");
787
- });
788
-
789
- test("reports the manager-normalized requested model", async () => {
790
- const handler = getSpawnHandler();
791
- const body = (await handler({
792
- body: { ...SPAWN_BODY, model: " opus " },
793
- })) as Record<string, unknown>;
794
-
795
- expect((spawnMock.mock.calls[0] as unknown[])[6]).toEqual({
796
- model: " opus ",
797
- });
798
- expect(body.requestedModel).toBe("opus");
799
- });
800
-
801
- test("a spawn that names no model asks the manager for none", async () => {
802
- const handler = getSpawnHandler();
803
- await handler({ body: SPAWN_BODY });
804
-
805
- const options = (spawnMock.mock.calls[0] as unknown[])[6] as {
806
- model?: string;
807
- };
808
- const approvalInput = confirmationRequests[0]?.input as Record<
809
- string,
810
- unknown
811
- >;
812
- expect(approvalInput).not.toHaveProperty("model");
813
- expect(options.model).toBeUndefined();
814
- });
815
-
816
- test("a refused model is a warning on an otherwise successful spawn", async () => {
817
- spawnResult = {
818
- ...DEFAULT_SPAWN_RESULT,
819
- modelWarning: "Invalid value for config option model: nope",
820
- };
821
-
822
- const handler = getSpawnHandler();
823
- const body = (await handler({
824
- body: { ...SPAWN_BODY, model: "nope" },
825
- })) as Record<string, unknown>;
826
-
827
- expect(body).toEqual({
828
- acpSessionId: "acp-route-session",
829
- protocolSessionId: "proto-route-session",
830
- agent: "claude",
831
- requestedModel: "nope",
832
- effectiveModel: "opus",
833
- modelWarning: "Invalid value for config option model: nope",
834
- });
835
- });
836
- });
837
-
838
683
  // ---------------------------------------------------------------------------
839
684
  // POST /v1/acp/:id/steer: transparent resume of sessions not in memory
840
685
  // ---------------------------------------------------------------------------