@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
@@ -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
- }