@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-staging.2

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 (439) 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/docs/guardian-request-flow.md +0 -16
  5. package/openapi.yaml +49 -291
  6. package/package.json +1 -1
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  8. package/src/__tests__/app-compiler.test.ts +0 -6
  9. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  10. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  11. package/src/__tests__/app-source-watcher.test.ts +218 -0
  12. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  13. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  14. package/src/__tests__/computer-use-tools.test.ts +5 -17
  15. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  16. package/src/__tests__/config-schema.test.ts +29 -28
  17. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  18. package/src/__tests__/config-watcher.test.ts +8 -23
  19. package/src/__tests__/connection-model-compat.test.ts +2 -2
  20. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  21. package/src/__tests__/conversation-pairing.test.ts +0 -26
  22. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  23. package/src/__tests__/conversation-queue.test.ts +207 -48
  24. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  25. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  26. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  27. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  28. package/src/__tests__/conversation-title-service.test.ts +10 -14
  29. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  30. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  31. package/src/__tests__/credential-record-retire.test.ts +1 -171
  32. package/src/__tests__/credential-routes.test.ts +3 -212
  33. package/src/__tests__/credential-security-invariants.test.ts +2 -4
  34. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  35. package/src/__tests__/document-sync-tags.test.ts +0 -25
  36. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  37. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  38. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  39. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  40. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  41. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  42. package/src/__tests__/host-file-proxy.test.ts +23 -11
  43. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  44. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  45. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  46. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  47. package/src/__tests__/mcp-health-check.test.ts +11 -8
  48. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  49. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  51. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  52. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  53. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  54. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  55. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  56. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  57. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  58. package/src/__tests__/model-intents.test.ts +0 -3
  59. package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
  60. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  61. package/src/__tests__/platform-callback-registration.test.ts +16 -8
  62. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  63. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  64. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  66. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  67. package/src/__tests__/speaker-identification.test.ts +56 -0
  68. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  69. package/src/__tests__/subagent-tools.test.ts +2 -3
  70. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  71. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  72. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  73. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  74. package/src/__tests__/workspace-git-service.test.ts +0 -26
  75. package/src/acp/__tests__/agent-process.test.ts +4 -258
  76. package/src/acp/__tests__/auth-required.test.ts +0 -96
  77. package/src/acp/__tests__/client-handler.test.ts +2 -90
  78. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  79. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  80. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  81. package/src/acp/__tests__/session-manager.test.ts +4 -895
  82. package/src/acp/agent-process.test.ts +1 -4
  83. package/src/acp/agent-process.ts +9 -94
  84. package/src/acp/auth-required.ts +1 -50
  85. package/src/acp/auto-install.test.ts +7 -9
  86. package/src/acp/client-handler.ts +3 -16
  87. package/src/acp/resolve-agent.test.ts +6 -220
  88. package/src/acp/resolve-agent.ts +23 -88
  89. package/src/acp/session-manager.test.ts +3 -196
  90. package/src/acp/session-manager.ts +18 -441
  91. package/src/acp/types.ts +5 -50
  92. package/src/api/events/app-files-changed.ts +3 -4
  93. package/src/api/events/notification-intent.ts +0 -2
  94. package/src/api/index.ts +0 -6
  95. package/src/apps/app-store.ts +1 -1
  96. package/src/bundler/app-compiler.ts +0 -15
  97. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  98. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  99. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  100. package/src/calls/call-constants.ts +4 -24
  101. package/src/calls/call-controller.ts +199 -499
  102. package/src/calls/call-transport.ts +0 -16
  103. package/src/calls/media-stream-output.ts +0 -32
  104. package/src/calls/media-stream-server.ts +30 -82
  105. package/src/calls/media-stream-stt-session.ts +0 -15
  106. package/src/calls/resolve-call-tts-provider.ts +2 -33
  107. package/src/calls/speaker-identification.ts +233 -0
  108. package/src/calls/tts-call-strategy.ts +5 -9
  109. package/src/calls/types.ts +0 -2
  110. package/src/calls/voice-control-protocol.ts +21 -53
  111. package/src/calls/voice-session-bridge.ts +46 -59
  112. package/src/calls/voice-triage-escalate.ts +56 -175
  113. package/src/cli/commands/apps.help.ts +13 -67
  114. package/src/cli/commands/apps.ts +0 -183
  115. package/src/cli/commands/bash.help.ts +13 -8
  116. package/src/cli/commands/bash.ts +25 -7
  117. package/src/cli/commands/channels/index.help.ts +2 -70
  118. package/src/cli/commands/channels/index.ts +3 -16
  119. package/src/cli/commands/credentials.help.ts +2 -6
  120. package/src/cli/commands/credentials.ts +2 -2
  121. package/src/cli/commands/mcp.help.ts +8 -8
  122. package/src/cli/commands/mcp.ts +1 -1
  123. package/src/cli/commands/roadmap.help.ts +1 -5
  124. package/src/cli/commands/roadmap.ts +1 -1
  125. package/src/cli/lib/bundled-marketplace.json +90 -103
  126. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  127. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  128. package/src/config/__tests__/platform-rehydration.test.ts +9 -99
  129. package/src/config/acp-defaults.test.ts +3 -13
  130. package/src/config/acp-defaults.ts +6 -23
  131. package/src/config/acp-schema.ts +2 -30
  132. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  133. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  134. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  135. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  136. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  137. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  138. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  139. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  140. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  141. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  142. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  143. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  144. package/src/config/default-profile-catalog.ts +1 -1
  145. package/src/config/env.ts +2 -2
  146. package/src/config/feature-flag-registry.json +12 -24
  147. package/src/config/loader.ts +0 -1
  148. package/src/config/memory-v3-gate.test.ts +0 -31
  149. package/src/config/memory-v3-gate.ts +16 -20
  150. package/src/config/platform-rehydration.ts +27 -11
  151. package/src/config/schema.ts +2 -2
  152. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  153. package/src/config/schemas/calls.ts +28 -1
  154. package/src/config/schemas/live-voice.ts +173 -1
  155. package/src/config/schemas/mcp.ts +1 -1
  156. package/src/config/schemas/memory-retrospective.ts +0 -10
  157. package/src/config/schemas/services.ts +0 -8
  158. package/src/config/schemas/skills.ts +14 -0
  159. package/src/credential-execution/process-manager.test.ts +19 -18
  160. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  161. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  162. package/src/daemon/app-source-watcher.ts +218 -0
  163. package/src/daemon/config-watcher.ts +194 -13
  164. package/src/daemon/conversation-process.ts +64 -35
  165. package/src/daemon/conversation-skill-tools.ts +31 -13
  166. package/src/daemon/conversation-store.ts +1 -1
  167. package/src/daemon/conversation-surfaces.ts +8 -10
  168. package/src/daemon/conversation-tool-setup.ts +43 -37
  169. package/src/daemon/conversation.ts +3 -0
  170. package/src/daemon/host-bash-proxy.ts +12 -8
  171. package/src/daemon/host-browser-proxy.ts +1 -15
  172. package/src/daemon/host-file-proxy.ts +10 -8
  173. package/src/daemon/host-transfer-proxy.ts +18 -14
  174. package/src/daemon/lifecycle.ts +5 -0
  175. package/src/daemon/mcp-reload-service.ts +5 -5
  176. package/src/daemon/message-types/sync.ts +0 -1
  177. package/src/daemon/orphan-reaper.ts +1 -1
  178. package/src/daemon/providers-setup.ts +1 -1
  179. package/src/daemon/shutdown-handlers.ts +9 -1
  180. package/src/daemon/skill-memory-refresh.ts +0 -64
  181. package/src/daemon/tool-side-effects.ts +18 -7
  182. package/src/home/__tests__/feed-writer.test.ts +0 -22
  183. package/src/home/feed-writer.ts +2 -11
  184. package/src/hooks/types.ts +0 -33
  185. package/src/inbound/platform-callback-registration.ts +5 -4
  186. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  187. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  188. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  189. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  190. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  191. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  192. package/src/live-voice/live-voice-session.ts +693 -213
  193. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  194. package/src/live-voice/protocol.ts +2 -0
  195. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  196. package/src/mcp/effective-config.ts +3 -3
  197. package/src/mcp/mcp-header-store.ts +45 -29
  198. package/src/mcp/startup.ts +4 -8
  199. package/src/messaging/provider.ts +3 -10
  200. package/src/messaging/providers/callback-routing.ts +0 -18
  201. package/src/messaging/providers/channel-transport.ts +0 -56
  202. package/src/messaging/providers/discord/transport.ts +0 -17
  203. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  204. package/src/messaging/providers/slack/adapter.ts +44 -7
  205. package/src/messaging/providers/slack/transport.ts +0 -16
  206. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  207. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  208. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  209. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  210. package/src/messaging/providers/whatsapp/client.ts +29 -0
  211. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  212. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  213. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  214. package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
  215. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  216. package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
  217. package/src/notifications/adapters/macos.ts +0 -3
  218. package/src/notifications/assistant-reply-producer.ts +3 -8
  219. package/src/notifications/conversation-pairing.ts +16 -36
  220. package/src/notifications/delivered-post-record.ts +1 -11
  221. package/src/notifications/guardian-feed-projection.ts +5 -125
  222. package/src/notifications/home-feed-side-effect.ts +7 -55
  223. package/src/notifications/schedule-result-producer.ts +22 -66
  224. package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
  225. package/src/oauth/byo-connection.test.ts +0 -45
  226. package/src/oauth/byo-connection.ts +6 -36
  227. package/src/oauth/connection-resolver.test.ts +0 -73
  228. package/src/oauth/connection-resolver.ts +2 -95
  229. package/src/oauth/seed-providers.ts +0 -165
  230. package/src/outbound-proxy/certs.ts +5 -3
  231. package/src/permissions/checker.test.ts +6 -11
  232. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  233. package/src/persistence/conversation-crud.ts +63 -71
  234. package/src/persistence/conversation-lineage.ts +4 -12
  235. package/src/persistence/conversation-title-service.ts +26 -9
  236. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  237. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  238. package/src/persistence/message-reads.ts +0 -30
  239. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  240. package/src/persistence/schema/memory-core.ts +0 -5
  241. package/src/platform/client.test.ts +2 -4
  242. package/src/platform/client.ts +10 -2
  243. package/src/plugin-api/constants.ts +0 -2
  244. package/src/plugin-api/index.ts +0 -1
  245. package/src/plugin-api/types.ts +0 -2
  246. package/src/plugins/defaults/index.ts +0 -2
  247. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  248. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  249. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  250. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  251. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  252. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  253. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  254. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  255. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  256. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  257. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  258. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  259. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  260. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  261. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  262. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  263. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  264. package/src/plugins/defaults/memory/startup.ts +1 -6
  265. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  266. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  267. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  268. package/src/plugins/defaults/memory/worker.ts +0 -6
  269. package/src/plugins/mcp-servers.ts +75 -15
  270. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  271. package/src/providers/gemini/client.ts +23 -9
  272. package/src/providers/inference/auth.ts +3 -2
  273. package/src/providers/inference/connection-availability.ts +8 -27
  274. package/src/providers/inference/resolve-auth.ts +4 -22
  275. package/src/providers/model-catalog.ts +0 -34
  276. package/src/providers/model-intents.ts +5 -10
  277. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  278. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  279. package/src/providers/openai/chat-completions-provider.ts +78 -192
  280. package/src/providers/openai/codex-models.ts +4 -0
  281. package/src/runtime/AGENTS.md +0 -2
  282. package/src/runtime/auth/same-actor.ts +3 -38
  283. package/src/runtime/http-server.ts +151 -160
  284. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  286. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  287. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  288. package/src/runtime/routes/acp-routes.test.ts +0 -15
  289. package/src/runtime/routes/acp-routes.ts +9 -72
  290. package/src/runtime/routes/app-management-routes.ts +0 -73
  291. package/src/runtime/routes/app-routes.ts +1 -1
  292. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  293. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  294. package/src/runtime/routes/credential-routes.ts +10 -19
  295. package/src/runtime/routes/debug-bash-routes.ts +173 -0
  296. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  297. package/src/runtime/routes/index.ts +2 -4
  298. package/src/runtime/routes/log-export-routes.ts +0 -2
  299. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  300. package/src/runtime/routes/migration-routes.ts +20 -6
  301. package/src/runtime/routes/platform-routes.ts +15 -18
  302. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  303. package/src/runtime/services/conversation-serializer.ts +3 -16
  304. package/src/runtime/sync/resource-sync-events.ts +1 -2
  305. package/src/schedule/worker.ts +1 -1
  306. package/src/security/ces-rpc-record-backend.ts +0 -7
  307. package/src/subagent/consult-context.ts +25 -12
  308. package/src/tools/acp/list-agents.test.ts +1 -3
  309. package/src/tools/acp/spawn.test.ts +11 -146
  310. package/src/tools/acp/spawn.ts +3 -21
  311. package/src/tools/acp/status.ts +3 -40
  312. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  313. package/src/tools/capability-offer.test.ts +2 -22
  314. package/src/tools/capability-offer.ts +1 -16
  315. package/src/tools/computer-use/definitions.ts +2 -4
  316. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  317. package/src/tools/credentials/metadata-store.ts +0 -100
  318. package/src/tools/host-filesystem/edit.test.ts +1 -2
  319. package/src/tools/host-filesystem/edit.ts +2 -2
  320. package/src/tools/host-filesystem/read.test.ts +1 -2
  321. package/src/tools/host-filesystem/read.ts +2 -2
  322. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  323. package/src/tools/host-filesystem/transfer.ts +2 -2
  324. package/src/tools/host-filesystem/write.test.ts +1 -2
  325. package/src/tools/host-filesystem/write.ts +2 -2
  326. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  327. package/src/tools/host-terminal/host-shell.ts +20 -4
  328. package/src/tools/policy-context.ts +7 -6
  329. package/src/tools/subagent/spawn.ts +8 -5
  330. package/src/tools/watch/watch-retro-report.ts +8 -0
  331. package/src/util/__tests__/language-subtag.test.ts +1 -23
  332. package/src/util/fs-watcher-error.ts +36 -0
  333. package/src/util/language-subtag.ts +0 -16
  334. package/src/util/platform.ts +0 -8
  335. package/src/workspace/git-service.ts +54 -5
  336. package/src/workspace/migrations/registry.ts +0 -6
  337. package/scripts/smoke-desktop-window-theme.ts +0 -186
  338. package/src/__tests__/git-porcelain.test.ts +0 -47
  339. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  340. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  341. package/src/__tests__/resolve-app.test.ts +0 -135
  342. package/src/__tests__/service-account-token.test.ts +0 -247
  343. package/src/__tests__/source-fingerprint.test.ts +0 -184
  344. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  345. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  346. package/src/acp/model-config.test.ts +0 -166
  347. package/src/acp/model-config.ts +0 -138
  348. package/src/api/events/acp-session-model-update.test.ts +0 -88
  349. package/src/api/events/acp-session-model-update.ts +0 -46
  350. package/src/apps/resolve-app.ts +0 -81
  351. package/src/apps/source-fingerprint.ts +0 -266
  352. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  353. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  354. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  355. package/src/calls/barge-in-guard.ts +0 -118
  356. package/src/calls/voice-leg-coordinator.ts +0 -189
  357. package/src/calls/voice-progress-cadence.ts +0 -423
  358. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  359. package/src/cli/commands/__tests__/bash.test.ts +0 -53
  360. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  361. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  362. package/src/cli/commands/channels/send.ts +0 -128
  363. package/src/config/__tests__/platform-identity.test.ts +0 -255
  364. package/src/config/acp-agent-write.ts +0 -43
  365. package/src/config/acp-schema.test.ts +0 -81
  366. package/src/config/platform-identity.ts +0 -201
  367. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  368. package/src/config/schemas/voice.ts +0 -150
  369. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  370. package/src/daemon/app-change-notify.ts +0 -45
  371. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  372. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  373. package/src/desktop/desktop-chrome-policy.ts +0 -42
  374. package/src/desktop/desktop-dependencies.test.ts +0 -102
  375. package/src/desktop/desktop-dependencies.ts +0 -306
  376. package/src/desktop/desktop-feature.test.ts +0 -18
  377. package/src/desktop/desktop-feature.ts +0 -19
  378. package/src/desktop/desktop-panel-config.test.ts +0 -135
  379. package/src/desktop/desktop-panel-config.ts +0 -149
  380. package/src/desktop/desktop-session-manager.test.ts +0 -627
  381. package/src/desktop/desktop-session-manager.ts +0 -814
  382. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  383. package/src/desktop/desktop-stream-bridge.ts +0 -214
  384. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  385. package/src/desktop/desktop-wallpaper.ts +0 -113
  386. package/src/desktop/desktop-window-theme.ts +0 -170
  387. package/src/i18n/AGENTS.md +0 -22
  388. package/src/i18n/__tests__/i18n.test.ts +0 -108
  389. package/src/i18n/index.ts +0 -16
  390. package/src/i18n/locales.ts +0 -93
  391. package/src/i18n/messages.ts +0 -61
  392. package/src/i18n/title.ts +0 -25
  393. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  394. package/src/mcp/spec-schema.ts +0 -111
  395. package/src/mcp/workspace-mcp-config.ts +0 -188
  396. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  397. package/src/persistence/conversation-title-placeholders.ts +0 -23
  398. package/src/persistence/message-cursor.ts +0 -78
  399. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  400. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  401. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  402. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  403. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  404. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  405. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  406. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  407. package/src/providers/gemini-thought-signature.test.ts +0 -63
  408. package/src/providers/gemini-thought-signature.ts +0 -44
  409. package/src/providers/inference/service-account-token.ts +0 -248
  410. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  411. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  412. package/src/providers/openai/google-thought-signature.ts +0 -320
  413. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  414. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  415. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  416. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  417. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  418. package/src/runtime/channel-send.ts +0 -316
  419. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  420. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  421. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  422. package/src/runtime/routes/channel-send-routes.ts +0 -85
  423. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  424. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  425. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  426. package/src/security/ces-http-record-backend.ts +0 -120
  427. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  428. package/src/skills/workspace-skill-md-signature.ts +0 -50
  429. package/src/tools/acp/status.test.ts +0 -94
  430. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
  431. package/src/tools/terminal/sanitized-bash.ts +0 -105
  432. package/src/util/ca-bundle.ts +0 -13
  433. package/src/workspace/git-porcelain.ts +0 -66
  434. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  435. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  436. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  437. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  438. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  439. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -1,443 +0,0 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- import type {
4
- ChannelTransport,
5
- ProactiveTarget,
6
- } from "../../messaging/providers/channel-transport.js";
7
-
8
- // The seam under test is the send function: it must ask the transport for
9
- // the address, deliver through it, and record only what the channel
10
- // acknowledged. The transport is a fake registered by channel id; the
11
- // recording dependencies are stubbed so the tests read what was recorded.
12
-
13
- const deliverCalls: Array<{
14
- ctx: { callbackUrl: string; params: Record<string, string> };
15
- payload: Record<string, unknown>;
16
- }> = [];
17
- let deliverResult: Record<string, unknown> = {
18
- ok: true,
19
- ts: "1700000000.000100",
20
- messageIds: ["1700000000.000100"],
21
- };
22
-
23
- function fakeTransport(
24
- channel: "slack" | "telegram",
25
- opts: { binds?: boolean; addressable?: boolean; refuses?: boolean } = {},
26
- ): ChannelTransport {
27
- const transport: ChannelTransport = {
28
- channel,
29
- async deliver(ctx, payload) {
30
- deliverCalls.push({
31
- ctx: { callbackUrl: ctx.callbackUrl, params: { ...ctx.params } },
32
- payload: payload as unknown as Record<string, unknown>,
33
- });
34
- return deliverResult as unknown as Awaited<
35
- ReturnType<ChannelTransport["deliver"]>
36
- >;
37
- },
38
- };
39
- if (opts.addressable !== false) {
40
- transport.addressFor = (target: ProactiveTarget) => {
41
- if (opts.refuses) {
42
- return undefined;
43
- }
44
- const threadId = target.threadId?.trim();
45
- const params: Record<string, string> = threadId ? { threadId } : {};
46
- return {
47
- ctx: { callbackUrl: `/deliver/${channel}`, params },
48
- chatId: target.chatId,
49
- ...(threadId ? { threadId } : {}),
50
- };
51
- };
52
- }
53
- if (opts.binds) {
54
- (
55
- transport as { bindsChatOnProactiveSend?: boolean }
56
- ).bindsChatOnProactiveSend = true;
57
- }
58
- return transport;
59
- }
60
-
61
- let transports: Record<string, ChannelTransport> = {};
62
- mock.module("../../messaging/providers/index.js", () => ({
63
- getTransportForChannel: (channel: string | undefined) =>
64
- channel ? transports[channel] : undefined,
65
- }));
66
-
67
- const resolveHomeMock = mock(async (_params: Record<string, unknown>) => ({
68
- conversationId: "home-1",
69
- createdNewConversation: false,
70
- }));
71
- const recordMock = mock(async (_post: Record<string, unknown>) => ({
72
- messageId: "row-1",
73
- }));
74
- const bindCalls: Array<Record<string, unknown>> = [];
75
- const getOrCreateCalls: string[] = [];
76
-
77
- mock.module("../../notifications/conversation-pairing.js", () => ({
78
- resolveProactiveHomeConversation: resolveHomeMock,
79
- }));
80
- mock.module("../../notifications/delivered-post-record.js", () => ({
81
- recordDeliveredChannelPost: recordMock,
82
- }));
83
- mock.module("../../persistence/conversation-crud.js", () => ({
84
- getConversation: (id: string) => ({ id, createdAt: 1700000000000 }),
85
- }));
86
- mock.module("../../persistence/conversation-disk-view.js", () => ({
87
- syncMessageToDisk: () => {},
88
- }));
89
- let bindCreates = true;
90
- let bindThrows = false;
91
- mock.module("../../persistence/conversation-key-store.js", () => ({
92
- getOrCreateConversation: (key: string) => {
93
- getOrCreateCalls.push(key);
94
- return { conversationId: `conv-for-${key}`, created: bindCreates };
95
- },
96
- }));
97
- const listChangedMock = mock((_reason: string) => {});
98
- const actualSync = await import("../sync/resource-sync-events.js");
99
- mock.module("../sync/resource-sync-events.js", () => ({
100
- ...actualSync,
101
- publishConversationListChanged: listChangedMock,
102
- }));
103
- mock.module("../../persistence/delivery-crud.js", () => ({
104
- buildScopedConversationKey: (
105
- channel: string,
106
- chatId: string,
107
- threadId?: string | null,
108
- ) =>
109
- threadId
110
- ? `asst:self:${channel}:${chatId}:thread:${threadId}`
111
- : `asst:self:${channel}:${chatId}`,
112
- }));
113
- mock.module("../../persistence/external-conversation-store.js", () => ({
114
- normalizeExternalThreadId: (value: string | null | undefined) => {
115
- const trimmed = value?.trim();
116
- return trimmed ? trimmed : null;
117
- },
118
- upsertOutboundBinding: (input: Record<string, unknown>) => {
119
- if (bindThrows) {
120
- throw new Error("binding store unavailable");
121
- }
122
- bindCalls.push(input);
123
- },
124
- }));
125
-
126
- const {
127
- ChannelNotAddressableError,
128
- ChannelSendFailedError,
129
- isProactivelyAddressable,
130
- sendChannelText,
131
- } = await import("../channel-send.js");
132
-
133
- beforeEach(() => {
134
- deliverCalls.length = 0;
135
- bindCalls.length = 0;
136
- getOrCreateCalls.length = 0;
137
- bindCreates = true;
138
- bindThrows = false;
139
- listChangedMock.mockClear();
140
- resolveHomeMock.mockClear();
141
- recordMock.mockClear();
142
- deliverResult = {
143
- ok: true,
144
- ts: "1700000000.000100",
145
- messageIds: ["1700000000.000100"],
146
- };
147
- transports = {
148
- slack: fakeTransport("slack"),
149
- telegram: fakeTransport("telegram", { binds: true }),
150
- };
151
- });
152
-
153
- const sender = {
154
- conversationId: "conv-A",
155
- executionChannel: "slack",
156
- requesterChatId: "C123",
157
- sourceThreadId: "1690000000.000001",
158
- };
159
-
160
- describe("addressability", () => {
161
- test("a channel is addressable exactly when its transport declares it", () => {
162
- transports.a2a = fakeTransport("slack", { addressable: false });
163
- expect(isProactivelyAddressable("slack")).toBe(true);
164
- expect(isProactivelyAddressable("a2a")).toBe(false);
165
- expect(isProactivelyAddressable("email")).toBe(false);
166
- expect(isProactivelyAddressable("not-a-channel")).toBe(false);
167
- });
168
-
169
- test("refuses before delivery when the channel has no addressing, or refuses the chat", async () => {
170
- await expect(
171
- sendChannelText({
172
- channel: "email",
173
- target: { kind: "chat", chatId: "x" },
174
- text: "hi",
175
- }),
176
- ).rejects.toBeInstanceOf(ChannelNotAddressableError);
177
-
178
- transports.slack = fakeTransport("slack", { refuses: true });
179
- await expect(
180
- sendChannelText({
181
- channel: "slack",
182
- target: { kind: "chat", chatId: "C-unreachable" },
183
- text: "hi",
184
- }),
185
- ).rejects.toBeInstanceOf(ChannelNotAddressableError);
186
- expect(deliverCalls).toEqual([]);
187
- });
188
- });
189
-
190
- describe("delivery through the transport", () => {
191
- test("delivers to the address the transport resolves, with the rich render asked for", async () => {
192
- const result = await sendChannelText({
193
- channel: "slack",
194
- target: { kind: "chat", chatId: "C123", threadId: "1690000000.000001" },
195
- text: "hello",
196
- renderRichly: true,
197
- assistantId: "self",
198
- });
199
-
200
- expect(deliverCalls).toEqual([
201
- {
202
- ctx: {
203
- callbackUrl: "/deliver/slack",
204
- params: { threadId: "1690000000.000001" },
205
- },
206
- payload: {
207
- chatId: "C123",
208
- text: "hello",
209
- renderRichly: true,
210
- assistantId: "self",
211
- },
212
- },
213
- ]);
214
- expect(result).toMatchObject({
215
- channel: "slack",
216
- chatId: "C123",
217
- threadId: "1690000000.000001",
218
- messageIds: ["1700000000.000100"],
219
- lastMessageId: "1700000000.000100",
220
- });
221
- });
222
-
223
- test("a send the channel does not acknowledge fails and records nothing", async () => {
224
- deliverResult = { ok: false };
225
- await expect(
226
- sendChannelText({
227
- channel: "slack",
228
- target: { kind: "chat", chatId: "C123" },
229
- text: "hello",
230
- }),
231
- ).rejects.toBeInstanceOf(ChannelSendFailedError);
232
- expect(recordMock).not.toHaveBeenCalled();
233
- });
234
-
235
- test("binds the chat's inbound conversation after acknowledgement, only where the transport declares it", async () => {
236
- await sendChannelText({
237
- channel: "telegram",
238
- target: { kind: "chat", chatId: "123456789" },
239
- text: "hello",
240
- });
241
- expect(getOrCreateCalls).toEqual(["asst:self:telegram:123456789"]);
242
- expect(bindCalls).toEqual([
243
- {
244
- conversationId: "conv-for-asst:self:telegram:123456789",
245
- sourceChannel: "telegram",
246
- externalChatId: "123456789",
247
- externalThreadId: null,
248
- },
249
- ]);
250
-
251
- bindCalls.length = 0;
252
- await sendChannelText({
253
- channel: "slack",
254
- target: { kind: "chat", chatId: "C123" },
255
- text: "hello",
256
- });
257
- expect(bindCalls).toEqual([]);
258
- });
259
-
260
- test("a topic send binds the topic's own conversation, the one its replies resolve to", async () => {
261
- await sendChannelText({
262
- channel: "telegram",
263
- target: { kind: "chat", chatId: "123456789", threadId: "42" },
264
- text: "hello",
265
- });
266
- expect(getOrCreateCalls).toEqual([
267
- "asst:self:telegram:123456789:thread:42",
268
- ]);
269
- expect(bindCalls).toEqual([
270
- {
271
- conversationId: "conv-for-asst:self:telegram:123456789:thread:42",
272
- sourceChannel: "telegram",
273
- externalChatId: "123456789",
274
- externalThreadId: "42",
275
- },
276
- ]);
277
- });
278
-
279
- test("a conversation the binding mints reaches the list; one it finds does not", async () => {
280
- await sendChannelText({
281
- channel: "telegram",
282
- target: { kind: "chat", chatId: "123456789", threadId: "42" },
283
- text: "hello",
284
- });
285
- expect(listChangedMock).toHaveBeenCalledTimes(1);
286
- expect(listChangedMock).toHaveBeenCalledWith("created");
287
-
288
- listChangedMock.mockClear();
289
- bindCreates = false;
290
- await sendChannelText({
291
- channel: "telegram",
292
- target: { kind: "chat", chatId: "123456789", threadId: "42" },
293
- text: "again",
294
- });
295
- expect(listChangedMock).not.toHaveBeenCalled();
296
- });
297
-
298
- test("a binding that throws still leaves its minted conversation in the list", async () => {
299
- bindThrows = true;
300
- const result = await sendChannelText({
301
- channel: "telegram",
302
- target: { kind: "chat", chatId: "123456789", threadId: "42" },
303
- text: "hello",
304
- });
305
- expect(bindCalls).toEqual([]);
306
- expect(listChangedMock).toHaveBeenCalledWith("created");
307
- expect(result.messageIds).toEqual(["1700000000.000100"]);
308
- });
309
-
310
- test("a failed send binds nothing, so it does not move where the next inbound lands", async () => {
311
- deliverResult = { ok: false };
312
- await expect(
313
- sendChannelText({
314
- channel: "telegram",
315
- target: { kind: "chat", chatId: "123456789" },
316
- text: "hello",
317
- }),
318
- ).rejects.toBeInstanceOf(ChannelSendFailedError);
319
- expect(getOrCreateCalls).toEqual([]);
320
- expect(bindCalls).toEqual([]);
321
- });
322
-
323
- test("does not bind a chat when acting for another assistant", async () => {
324
- await sendChannelText({
325
- channel: "telegram",
326
- target: { kind: "chat", chatId: "123456789" },
327
- text: "hello",
328
- assistantId: "asst-other",
329
- });
330
- expect(bindCalls).toEqual([]);
331
- });
332
- });
333
-
334
- describe("recording after acknowledgement", () => {
335
- test("records every acknowledged id in the chat's home, cross-posted from the sender", async () => {
336
- deliverResult = { ok: true, messageIds: ["10", "11", "12"] };
337
- const result = await sendChannelText({
338
- channel: "telegram",
339
- target: { kind: "chat", chatId: "123456789" },
340
- text: "a long message",
341
- sender: { conversationId: "conv-A" },
342
- });
343
-
344
- expect(resolveHomeMock.mock.calls[0]![0]).toMatchObject({
345
- sourceChannel: "telegram",
346
- externalChatId: "123456789",
347
- });
348
- expect(recordMock).toHaveBeenCalledTimes(1);
349
- expect(recordMock.mock.calls[0]![0]).toEqual({
350
- conversationId: "home-1",
351
- channel: "telegram",
352
- externalChatId: "123456789",
353
- text: "a long message",
354
- providerMessageId: "10",
355
- additionalProviderMessageIds: ["11", "12"],
356
- crossPostedFrom: "conv-A",
357
- });
358
- expect(result).toMatchObject({
359
- messageIds: ["10", "11", "12"],
360
- lastMessageId: "12",
361
- recordedIn: "home-1",
362
- });
363
- });
364
-
365
- test("a success that names no message id is not an acknowledgement", async () => {
366
- deliverResult = { ok: true, messageIds: [] };
367
- await expect(
368
- sendChannelText({
369
- channel: "slack",
370
- target: { kind: "chat", chatId: "C123" },
371
- text: "hello",
372
- }),
373
- ).rejects.toThrow("acknowledged no message id");
374
- expect(recordMock).not.toHaveBeenCalled();
375
- });
376
-
377
- test("records nothing when the post landed in the turn's own chat and thread", async () => {
378
- await sendChannelText({
379
- channel: "slack",
380
- target: { kind: "chat", chatId: "C123", threadId: "1690000000.000001" },
381
- text: "hello",
382
- sender,
383
- });
384
- expect(resolveHomeMock).not.toHaveBeenCalled();
385
- expect(recordMock).not.toHaveBeenCalled();
386
- });
387
-
388
- test("a send into the turn's chat but a different thread is a cross-post, recorded in that thread", async () => {
389
- await sendChannelText({
390
- channel: "slack",
391
- target: { kind: "chat", chatId: "C123", threadId: "1690000000.000009" },
392
- text: "hello",
393
- sender,
394
- });
395
- expect(resolveHomeMock.mock.calls[0]![0]).toMatchObject({
396
- sourceChannel: "slack",
397
- externalChatId: "C123",
398
- threadId: "1690000000.000009",
399
- });
400
- expect(recordMock).toHaveBeenCalledTimes(1);
401
- expect(recordMock.mock.calls[0]![0]).toMatchObject({
402
- externalChatId: "C123",
403
- threadId: "1690000000.000009",
404
- });
405
- });
406
-
407
- test("a thread-less delivery never matches a turn that arrived in a thread", async () => {
408
- await sendChannelText({
409
- channel: "slack",
410
- target: { kind: "chat", chatId: "C123" },
411
- text: "hello",
412
- sender,
413
- });
414
- expect(recordMock).toHaveBeenCalledTimes(1);
415
- });
416
-
417
- test("a sender that arrived through no channel falls back to the home comparison", async () => {
418
- resolveHomeMock.mockImplementationOnce(async () => ({
419
- conversationId: "conv-A",
420
- createdNewConversation: false,
421
- }));
422
- await sendChannelText({
423
- channel: "slack",
424
- target: { kind: "chat", chatId: "C123" },
425
- text: "hello",
426
- sender: { conversationId: "conv-A" },
427
- });
428
- expect(recordMock).not.toHaveBeenCalled();
429
- });
430
-
431
- test("a recording failure does not fail the send", async () => {
432
- recordMock.mockImplementationOnce(async () => {
433
- throw new Error("db unavailable");
434
- });
435
- const result = await sendChannelText({
436
- channel: "slack",
437
- target: { kind: "chat", chatId: "C123" },
438
- text: "hello",
439
- });
440
- expect(result.messageIds).toEqual(["1700000000.000100"]);
441
- expect(result.recordedIn).toBeUndefined();
442
- });
443
- });
@@ -1,89 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
-
3
- import { setOverridesForTesting } from "../../__tests__/feature-flag-test-helpers.js";
4
- import { RuntimeHttpServer } from "../http-server.js";
5
- import {
6
- mintActorToken,
7
- mintGatewayToken,
8
- requireHttpAuth,
9
- upgradeHeaders,
10
- waitForClose,
11
- } from "./runtime-ws-test-utils.js";
12
-
13
- describe("RuntimeHttpServer /v1/desktop/stream upgrade", () => {
14
- let server: RuntimeHttpServer;
15
- let baseUrl: string;
16
- let restoreAuthEnv: () => void;
17
- const originalContainerized = process.env.IS_CONTAINERIZED;
18
-
19
- beforeEach(async () => {
20
- restoreAuthEnv = requireHttpAuth();
21
- const port = 21400 + Math.floor(Math.random() * 300);
22
- server = new RuntimeHttpServer({ port, hostname: "127.0.0.1" });
23
- await server.start();
24
- baseUrl = `127.0.0.1:${server.actualPort}`;
25
- });
26
-
27
- afterEach(async () => {
28
- await server.stop();
29
- restoreAuthEnv();
30
- if (originalContainerized === undefined) {
31
- delete process.env.IS_CONTAINERIZED;
32
- } else {
33
- process.env.IS_CONTAINERIZED = originalContainerized;
34
- }
35
- setOverridesForTesting({});
36
- });
37
-
38
- test("refuses a non-private origin with 403", async () => {
39
- const res = await fetch(
40
- `http://${baseUrl}/v1/desktop/stream?token=${mintGatewayToken()}`,
41
- {
42
- headers: { ...upgradeHeaders, Origin: "https://external.example.com" },
43
- },
44
- );
45
- expect(res.status).toBe(403);
46
- const body = (await res.json()) as { error: { message: string } };
47
- expect(body.error.message).toContain(
48
- "Direct desktop stream access disabled",
49
- );
50
- });
51
-
52
- test("refuses a missing or non-gateway token with 401", async () => {
53
- const missing = await fetch(`http://${baseUrl}/v1/desktop/stream`, {
54
- headers: upgradeHeaders,
55
- });
56
- expect(missing.status).toBe(401);
57
-
58
- const actor = await fetch(
59
- `http://${baseUrl}/v1/desktop/stream?token=${mintActorToken()}`,
60
- { headers: upgradeHeaders },
61
- );
62
- expect(actor.status).toBe(401);
63
- });
64
-
65
- test("upgrades a gateway request and reports the feature gate as close code 4008", async () => {
66
- // The test daemon is not containerized, so the socket opens and is then
67
- // closed by the desktop-stream open handler rather than refused pre-upgrade.
68
- const ws = new WebSocket(
69
- `ws://${baseUrl}/v1/desktop/stream?token=${encodeURIComponent(mintGatewayToken())}`,
70
- );
71
- const closed = await waitForClose(ws);
72
- expect(closed.code).toBe(4008);
73
- expect(closed.reason).toBe("Desktop is not available on this assistant");
74
- });
75
- for (const flag of [false, undefined]) {
76
- test(`refuses a containerized stream with a disabled or missing flag (${flag})`, async () => {
77
- process.env.IS_CONTAINERIZED = "true";
78
- setOverridesForTesting(
79
- flag === undefined ? {} : { "assistant-desktop": flag },
80
- );
81
- const ws = new WebSocket(
82
- `ws://${baseUrl}/v1/desktop/stream?token=${encodeURIComponent(mintGatewayToken())}`,
83
- );
84
- const closed = await waitForClose(ws);
85
- expect(closed.code).toBe(4008);
86
- expect(closed.reason).toBe("Desktop is not available on this assistant");
87
- });
88
- }
89
- });
@@ -1,58 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- import { RuntimeHttpServer } from "../http-server.js";
4
- import {
5
- mintActorToken,
6
- mintGatewayToken,
7
- requireHttpAuth,
8
- upgradeHeaders,
9
- } from "./runtime-ws-test-utils.js";
10
-
11
- describe("Live voice through the shared runtime upgrade", () => {
12
- let restoreAuth: () => void;
13
- beforeEach(() => {
14
- restoreAuth = requireHttpAuth();
15
- });
16
- afterEach(() => restoreAuth());
17
-
18
- function upgrade(token: string, guardianPrincipalId?: string) {
19
- const runtime = new RuntimeHttpServer();
20
- const server = {
21
- requestIP: () => ({ address: "127.0.0.1" }),
22
- upgrade: mock(() => true),
23
- };
24
- const query = new URLSearchParams({ token });
25
- if (guardianPrincipalId !== undefined) {
26
- query.set("guardianPrincipalId", guardianPrincipalId);
27
- }
28
- const response = runtime["handleLiveVoiceUpgrade"](
29
- new Request(`http://127.0.0.1/v1/live-voice?${query}`, {
30
- headers: upgradeHeaders,
31
- }),
32
- server as unknown as ReturnType<typeof Bun.serve>,
33
- );
34
- return { response, server };
35
- }
36
-
37
- test("forwards the gateway-admitted guardian identity to the session", () => {
38
- const { response, server } = upgrade(mintGatewayToken(), "user-123");
39
- expect(response).toBeUndefined();
40
- expect(server.upgrade).toHaveBeenCalledWith(expect.any(Request), {
41
- data: { wsType: "live-voice", guardianPrincipalId: "user-123" },
42
- });
43
- });
44
-
45
- test("accepts gateway clients without a guardian identity", () => {
46
- const { response, server } = upgrade(mintGatewayToken());
47
- expect(response).toBeUndefined();
48
- expect(server.upgrade).toHaveBeenCalledWith(expect.any(Request), {
49
- data: { wsType: "live-voice" },
50
- });
51
- });
52
-
53
- test("rejects actor tokens even when they supply a guardian identity", () => {
54
- const { response, server } = upgrade(mintActorToken(), "user-123");
55
- expect(response?.status).toBe(401);
56
- expect(server.upgrade).not.toHaveBeenCalled();
57
- });
58
- });
@@ -1,72 +0,0 @@
1
- /** Shared pieces for suites that open WebSockets against `RuntimeHttpServer`. */
2
-
3
- import { CURRENT_POLICY_EPOCH } from "../auth/policy.js";
4
- import { mintToken } from "../auth/token-service.js";
5
-
6
- export function mintGatewayToken(): string {
7
- return mintToken({
8
- aud: "vellum-daemon",
9
- sub: "svc:gateway:self",
10
- scope_profile: "gateway_ingress_v1",
11
- policy_epoch: CURRENT_POLICY_EPOCH,
12
- ttlSeconds: 3600,
13
- });
14
- }
15
-
16
- export function mintActorToken(): string {
17
- return mintToken({
18
- aud: "vellum-daemon",
19
- sub: "actor:self:user-123",
20
- scope_profile: "actor_client_v1",
21
- policy_epoch: CURRENT_POLICY_EPOCH,
22
- ttlSeconds: 3600,
23
- });
24
- }
25
-
26
- /** Headers of a WebSocket upgrade sent through plain `fetch`. */
27
- export const upgradeHeaders = {
28
- Upgrade: "websocket",
29
- Connection: "Upgrade",
30
- "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==",
31
- "Sec-WebSocket-Version": "13",
32
- };
33
-
34
- export function waitForClose(
35
- ws: WebSocket,
36
- timeoutMs = 2000,
37
- ): Promise<CloseEvent> {
38
- return new Promise((resolve, reject) => {
39
- const timer = setTimeout(() => {
40
- cleanup();
41
- reject(new Error("Timed out waiting for WebSocket close"));
42
- }, timeoutMs);
43
- const cleanup = () => {
44
- clearTimeout(timer);
45
- ws.removeEventListener("close", onClose);
46
- ws.removeEventListener("error", onError);
47
- };
48
- const onClose = (event: CloseEvent) => {
49
- cleanup();
50
- resolve(event);
51
- };
52
- const onError = () => {
53
- cleanup();
54
- reject(new Error("WebSocket close failed"));
55
- };
56
- ws.addEventListener("close", onClose);
57
- ws.addEventListener("error", onError);
58
- });
59
- }
60
-
61
- /** Turn real HTTP auth on for a test; the returned function restores the env. */
62
- export function requireHttpAuth(): () => void {
63
- const saved = process.env.DISABLE_HTTP_AUTH;
64
- delete process.env.DISABLE_HTTP_AUTH;
65
- return () => {
66
- if (saved === undefined) {
67
- delete process.env.DISABLE_HTTP_AUTH;
68
- } else {
69
- process.env.DISABLE_HTTP_AUTH = saved;
70
- }
71
- };
72
- }