@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,229 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
-
3
- import {
4
- createFrontDoorLegCoordinator,
5
- type EscalatedLeg,
6
- escalatedLegFor,
7
- type FrontDoorLegHost,
8
- type SpokenEscalationBridge,
9
- } from "../voice-leg-coordinator.js";
10
- import {
11
- ESCALATION_CONTINUATION_CONTENT,
12
- FALLBACK_ESCALATION_BRIDGE,
13
- FALLBACK_ESCALATION_BRIDGE_BY_LANGUAGE,
14
- } from "../voice-triage-escalate.js";
15
-
16
- interface Recorded {
17
- events: string[];
18
- answers: string[];
19
- bridges: SpokenEscalationBridge[];
20
- escalated: EscalatedLeg[];
21
- holds: number;
22
- commits: number;
23
- }
24
-
25
- function harness(opts?: {
26
- holdEnabled?: boolean;
27
- live?: () => boolean;
28
- language?: string;
29
- commit?: () => boolean;
30
- withProgress?: boolean;
31
- withHold?: boolean;
32
- }) {
33
- const recorded: Recorded = {
34
- events: [],
35
- answers: [],
36
- bridges: [],
37
- escalated: [],
38
- holds: 0,
39
- commits: 0,
40
- };
41
- const host: FrontDoorLegHost = {
42
- isLive: opts?.live ?? (() => true),
43
- language: () => opts?.language,
44
- ...(opts?.withProgress === false
45
- ? {}
46
- : {
47
- progress: {
48
- clear: () => recorded.events.push("progress.clear"),
49
- noteFloorHolder: () => recorded.events.push("progress.floor"),
50
- arm: () => recorded.events.push("progress.arm"),
51
- },
52
- }),
53
- ...(opts?.withHold
54
- ? {
55
- onHold: () => {
56
- recorded.holds += 1;
57
- recorded.events.push("hold");
58
- },
59
- }
60
- : {}),
61
- ...(opts?.commit
62
- ? {
63
- commit: () => {
64
- recorded.commits += 1;
65
- recorded.events.push("commit");
66
- return opts.commit!();
67
- },
68
- }
69
- : {}),
70
- onAnswerText: (text) => {
71
- recorded.answers.push(text);
72
- recorded.events.push(`answer:${text}`);
73
- },
74
- abortLeg: () => recorded.events.push("abort"),
75
- speakBridge: (bridge) => {
76
- recorded.bridges.push(bridge);
77
- recorded.events.push(`speak:${bridge.spokenBridge}`);
78
- },
79
- startEscalatedLeg: (leg) => {
80
- recorded.escalated.push(leg);
81
- recorded.events.push("start-escalated");
82
- },
83
- };
84
- const coordinator = createFrontDoorLegCoordinator({
85
- holdEnabled: opts?.holdEnabled ?? false,
86
- host,
87
- });
88
- return { coordinator, recorded };
89
- }
90
-
91
- describe("escalatedLegFor", () => {
92
- test("continues on the escalated leg with the spoken bridge quoted", () => {
93
- expect(escalatedLegFor("One moment.")).toEqual({
94
- content: ESCALATION_CONTINUATION_CONTENT,
95
- routingLeg: "escalated",
96
- spokenEscalationBridge: "One moment.",
97
- });
98
- });
99
- });
100
-
101
- describe("createFrontDoorLegCoordinator", () => {
102
- test("an answer releases the held leading text, then streams", () => {
103
- const { coordinator, recorded } = harness();
104
- coordinator.push("[");
105
- expect(recorded.answers).toEqual([]);
106
- coordinator.push("END_CALL] Bye");
107
- coordinator.push(" now.");
108
-
109
- expect(recorded.answers).toEqual(["[END_CALL] Bye", " now."]);
110
- expect(coordinator.complete()).toBe(false);
111
- expect(coordinator.handedOff).toBe(false);
112
- expect(recorded.escalated).toEqual([]);
113
- });
114
-
115
- test("an escalate verdict hands off in order: pause, abort, speak, floor, start, re-arm", () => {
116
- const { coordinator, recorded } = harness();
117
- coordinator.push("[1] Let me check");
118
- expect(coordinator.handedOff).toBe(false);
119
- coordinator.push(" that.");
120
-
121
- expect(coordinator.handedOff).toBe(true);
122
- expect(recorded.events).toEqual([
123
- "progress.clear",
124
- "abort",
125
- "speak:Let me check that.",
126
- "progress.floor",
127
- "start-escalated",
128
- "progress.arm",
129
- ]);
130
- expect(recorded.bridges[0]).toEqual({
131
- spokenBridge: "Let me check that.",
132
- usesFallback: false,
133
- });
134
- expect(recorded.escalated).toEqual([escalatedLegFor("Let me check that.")]);
135
- });
136
-
137
- test("after the hand-off the leg's stream and completion are ignored", () => {
138
- const { coordinator, recorded } = harness();
139
- coordinator.push("[1] One moment.");
140
- coordinator.push(" Ignored past the cap.");
141
- expect(coordinator.complete()).toBe(true);
142
-
143
- expect(recorded.answers).toEqual([]);
144
- expect(recorded.escalated.length).toBe(1);
145
- });
146
-
147
- test("a leg that stops mid-bridge hands off on completion with the canned bridge", () => {
148
- const { coordinator, recorded } = harness({ language: "es" });
149
- coordinator.push("[1]");
150
- expect(coordinator.handedOff).toBe(false);
151
-
152
- expect(coordinator.complete()).toBe(true);
153
- expect(recorded.bridges[0]).toEqual({
154
- spokenBridge: FALLBACK_ESCALATION_BRIDGE_BY_LANGUAGE.es,
155
- usesFallback: true,
156
- });
157
- expect(recorded.escalated[0].spokenEscalationBridge).toBe(
158
- FALLBACK_ESCALATION_BRIDGE_BY_LANGUAGE.es,
159
- );
160
- });
161
-
162
- test("the canned bridge for a language the table lacks is English and says so", () => {
163
- const { coordinator, recorded } = harness({ language: "ko" });
164
- coordinator.push("[1]");
165
- coordinator.complete();
166
-
167
- expect(recorded.bridges[0]).toEqual({
168
- spokenBridge: FALLBACK_ESCALATION_BRIDGE,
169
- usesFallback: true,
170
- language: "en",
171
- });
172
- });
173
-
174
- test("a dead turn never hands off", () => {
175
- let live = true;
176
- const { coordinator, recorded } = harness({ live: () => live });
177
- coordinator.push("[1] One");
178
- live = false;
179
- coordinator.push(" moment.");
180
- expect(coordinator.handedOff).toBe(false);
181
- expect(coordinator.complete()).toBe(false);
182
-
183
- expect(recorded.escalated).toEqual([]);
184
- expect(recorded.events).toEqual([]);
185
- });
186
-
187
- test("a hold verdict on a speculative leg discards the leg", () => {
188
- const { coordinator, recorded } = harness({
189
- holdEnabled: true,
190
- withHold: true,
191
- });
192
- coordinator.push("[0]");
193
-
194
- expect(recorded.holds).toBe(1);
195
- expect(recorded.answers).toEqual([]);
196
- expect(coordinator.handedOff).toBe(false);
197
- });
198
-
199
- test("a leg that does not teach the hold token reads [0] as an answer", () => {
200
- const { coordinator, recorded } = harness({ withHold: true });
201
- coordinator.push("[0] Sure.");
202
-
203
- expect(recorded.holds).toBe(0);
204
- expect(recorded.answers).toEqual(["[0] Sure."]);
205
- });
206
-
207
- test("answer and escalate verdicts commit a speculative turn first; a failed commit stops the verdict", () => {
208
- const committed = harness({ commit: () => true });
209
- committed.coordinator.push("Hello.");
210
- expect(committed.recorded.events).toEqual(["commit", "answer:Hello."]);
211
-
212
- const gone = harness({ commit: () => false });
213
- gone.coordinator.push("[1] One moment.");
214
- expect(gone.recorded.commits).toBe(1);
215
- expect(gone.coordinator.handedOff).toBe(false);
216
- expect(gone.recorded.escalated).toEqual([]);
217
- });
218
-
219
- test("works without a progress cadence", () => {
220
- const { coordinator, recorded } = harness({ withProgress: false });
221
- coordinator.push("[1] One moment.");
222
-
223
- expect(recorded.events).toEqual([
224
- "abort",
225
- "speak:One moment.",
226
- "start-escalated",
227
- ]);
228
- });
229
- });
@@ -1,274 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
-
3
- import { VoiceProgressConfigSchema } from "../../config/schemas/voice.js";
4
- import type { VoiceProgressNarrator } from "../progress-narration.js";
5
- import {
6
- PROGRESS_FALLBACK_PHRASES,
7
- PROGRESS_FALLBACK_PHRASES_BY_LANGUAGE,
8
- } from "../progress-phrases.js";
9
- import {
10
- createProgressCadence,
11
- type ProgressCadence,
12
- type ProgressCadenceHost,
13
- } from "../voice-progress-cadence.js";
14
-
15
- const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
16
-
17
- async function waitFor(predicate: () => boolean, attempts = 60): Promise<void> {
18
- for (let i = 0; i < attempts; i += 1) {
19
- if (predicate()) {
20
- return;
21
- }
22
- await sleep(5);
23
- }
24
- throw new Error("waitFor timed out");
25
- }
26
-
27
- interface Harness {
28
- cadence: ProgressCadence;
29
- spoken: Array<{ phrase: string; language: string | undefined }>;
30
- host: {
31
- live: boolean;
32
- audioIdle: boolean;
33
- tailUntilMs: number;
34
- language: string | undefined;
35
- deltaEpoch: number;
36
- narrationsSpoken: number;
37
- };
38
- }
39
-
40
- function harness(opts: {
41
- config?: Partial<ReturnType<typeof VoiceProgressConfigSchema.parse>>;
42
- narrator?: VoiceProgressNarrator | null;
43
- language?: string;
44
- }): Harness {
45
- const state = {
46
- live: true,
47
- audioIdle: true,
48
- tailUntilMs: 0,
49
- language: opts.language,
50
- deltaEpoch: 0,
51
- narrationsSpoken: 0,
52
- };
53
- const spoken: Harness["spoken"] = [];
54
- const host: ProgressCadenceHost = {
55
- turnId: "turn-1",
56
- launchedAtMs: Date.now(),
57
- signal: new AbortController().signal,
58
- canNarrate: () => state.live,
59
- isAudioIdle: () => state.audioIdle,
60
- playbackTailUntilMs: () => state.tailUntilMs,
61
- transcriptSoFar: () => "what is on my calendar",
62
- language: () => state.language,
63
- deltaEpoch: () => state.deltaEpoch,
64
- speak: (phrase, language) => {
65
- spoken.push({ phrase, language });
66
- return true;
67
- },
68
- onNarrationSpoken: () => {
69
- state.narrationsSpoken += 1;
70
- },
71
- };
72
- let counter = 0;
73
- const cadence = createProgressCadence({
74
- config: VoiceProgressConfigSchema.parse({
75
- opsThreshold: 3,
76
- idleIntervalMs: 60_000,
77
- maxSilenceMs: 60_000,
78
- longOpMs: 15_000,
79
- minGapMs: 10,
80
- generationTimeoutMs: 1_500,
81
- ...opts.config,
82
- }),
83
- narrator:
84
- opts.narrator === undefined
85
- ? { generateProgressText: async () => "Checking your calendar now." }
86
- : opts.narrator,
87
- host,
88
- nextFallbackPhraseIndex: () => counter++,
89
- });
90
- return { cadence, spoken, host: state };
91
- }
92
-
93
- describe("createProgressCadence", () => {
94
- test("the ops trigger narrates once the threshold of started tools is reached", async () => {
95
- const h = harness({});
96
- h.cadence.toolStarted("web_search", "t1");
97
- h.cadence.toolStarted("web_fetch", "t2");
98
- await sleep(15);
99
- expect(h.spoken).toEqual([]);
100
-
101
- h.cadence.toolStarted("file_read", "t3");
102
- await waitFor(() => h.spoken.length === 1);
103
-
104
- expect(h.spoken[0]).toEqual({
105
- phrase: "Checking your calendar now.",
106
- language: undefined,
107
- });
108
- expect(h.cadence.updatesSpoken).toBe(1);
109
- expect(h.host.narrationsSpoken).toBe(1);
110
- h.cadence.clear();
111
- });
112
-
113
- test("a long operation completing narrates on its own beat", async () => {
114
- const h = harness({ config: { longOpMs: 20 } });
115
- h.cadence.toolStarted("web_search", "t1");
116
- await sleep(30);
117
- h.cadence.toolFinished({
118
- toolName: "web_search",
119
- toolUseId: "t1",
120
- resultPreview: "three results",
121
- });
122
- await waitFor(() => h.spoken.length === 1);
123
-
124
- expect(h.cadence.ops[0].completedAtMs).toBeDefined();
125
- expect(h.cadence.ops[0].resultPreview).toBe("three results");
126
- h.cadence.clear();
127
- });
128
-
129
- test("a quick operation completing is only news, not a narration", async () => {
130
- const h = harness({});
131
- h.cadence.toolStarted("web_search", "t1");
132
- h.cadence.toolFinished({ toolName: "web_search", toolUseId: "t1" });
133
- await sleep(20);
134
-
135
- expect(h.spoken).toEqual([]);
136
- h.cadence.clear();
137
- });
138
-
139
- test("a tool_result with no id matches the newest incomplete op of that name", () => {
140
- const h = harness({});
141
- h.cadence.toolStarted("web_search", "t1");
142
- h.cadence.toolStarted("web_search", "t2");
143
- h.cadence.toolFinished({ toolName: "web_search", isError: true });
144
-
145
- expect(h.cadence.ops[1].completedAtMs).toBeDefined();
146
- expect(h.cadence.ops[1].isError).toBe(true);
147
- expect(h.cadence.ops[0].completedAtMs).toBeUndefined();
148
- h.cadence.clear();
149
- });
150
-
151
- test("the idle tick narrates news since the last update, and the static fallback covers a null generation", async () => {
152
- const h = harness({
153
- config: { idleIntervalMs: 30, maxSilenceMs: 60_000 },
154
- narrator: { generateProgressText: async () => null },
155
- language: "es",
156
- });
157
- h.cadence.arm();
158
- await sleep(60);
159
- // Nothing observable happened: the tick stays quiet.
160
- expect(h.spoken).toEqual([]);
161
-
162
- h.cadence.toolStarted("web_search", "t1");
163
- await waitFor(() => h.spoken.length === 1);
164
-
165
- expect(
166
- PROGRESS_FALLBACK_PHRASES_BY_LANGUAGE.es.map((p) => p.trim()),
167
- ).toContain(h.spoken[0].phrase.trim());
168
- // The Spanish table has an entry: the phrase rides the turn's language.
169
- expect(h.spoken[0].language).toBeUndefined();
170
- h.cadence.clear();
171
- });
172
-
173
- test("a static fallback the table lacks in the turn's language is pinned to English", async () => {
174
- const h = harness({
175
- config: { idleIntervalMs: 30 },
176
- narrator: { generateProgressText: async () => null },
177
- language: "ko",
178
- });
179
- h.cadence.arm();
180
- h.cadence.toolStarted("web_search", "t1");
181
- await waitFor(() => h.spoken.length === 1);
182
-
183
- expect(PROGRESS_FALLBACK_PHRASES).toContain(h.spoken[0].phrase);
184
- expect(h.spoken[0].language).toBe("en");
185
- h.cadence.clear();
186
- });
187
-
188
- test("the heartbeat speaks after maxSilenceMs even with nothing new", async () => {
189
- const h = harness({
190
- config: { idleIntervalMs: 30, maxSilenceMs: 30 },
191
- });
192
- h.cadence.arm();
193
- await waitFor(() => h.spoken.length === 1);
194
- h.cadence.clear();
195
- });
196
-
197
- test("nothing speaks while audio is still playing; the countdown restarts once it drains", async () => {
198
- const h = harness({ config: { idleIntervalMs: 30, maxSilenceMs: 30 } });
199
- h.host.audioIdle = false;
200
- h.cadence.arm();
201
- await sleep(80);
202
- expect(h.spoken).toEqual([]);
203
-
204
- h.host.audioIdle = true;
205
- h.cadence.noteAudioSettled();
206
- await waitFor(() => h.spoken.length === 1);
207
- h.cadence.clear();
208
- });
209
-
210
- test("a narration generated while the model resumed speaking is dropped", async () => {
211
- let release: () => void = () => {};
212
- const h = harness({
213
- config: { opsThreshold: 1 },
214
- narrator: {
215
- generateProgressText: () =>
216
- new Promise<string | null>((resolve) => {
217
- release = () => resolve("Still on it.");
218
- }),
219
- },
220
- });
221
- h.cadence.toolStarted("web_search", "t1");
222
- await sleep(10);
223
- h.host.deltaEpoch += 1;
224
- release();
225
- await sleep(20);
226
-
227
- expect(h.spoken).toEqual([]);
228
- h.cadence.clear();
229
- });
230
-
231
- test("minGapMs spaces narration from another floor holder", async () => {
232
- const h = harness({ config: { opsThreshold: 1, minGapMs: 200 } });
233
- h.cadence.noteFloorHolder();
234
- h.cadence.toolStarted("web_search", "t1");
235
- await sleep(30);
236
-
237
- expect(h.spoken).toEqual([]);
238
- h.cadence.clear();
239
- });
240
-
241
- test("a null narrator or a disabled config never speaks or arms", async () => {
242
- const off = harness({ narrator: null, config: { idleIntervalMs: 20 } });
243
- off.cadence.arm();
244
- off.cadence.toolStarted("a", "1");
245
- off.cadence.toolStarted("b", "2");
246
- off.cadence.toolStarted("c", "3");
247
- const disabled = harness({
248
- config: { enabled: false, idleIntervalMs: 20 },
249
- });
250
- disabled.cadence.arm();
251
- disabled.cadence.toolStarted("a", "1");
252
- disabled.cadence.toolStarted("b", "2");
253
- disabled.cadence.toolStarted("c", "3");
254
- await sleep(60);
255
-
256
- expect(off.spoken).toEqual([]);
257
- expect(disabled.spoken).toEqual([]);
258
- });
259
-
260
- test("clear stops the dead-air timer and a dead turn is never narrated", async () => {
261
- const h = harness({ config: { idleIntervalMs: 20, maxSilenceMs: 20 } });
262
- h.cadence.arm();
263
- h.cadence.clear();
264
- await sleep(60);
265
- expect(h.spoken).toEqual([]);
266
-
267
- h.host.live = false;
268
- h.cadence.toolStarted("a", "1");
269
- h.cadence.toolStarted("b", "2");
270
- h.cadence.toolStarted("c", "3");
271
- await sleep(20);
272
- expect(h.spoken).toEqual([]);
273
- });
274
- });
@@ -1,118 +0,0 @@
1
- /**
2
- * The sustained-speech barge-in guard, shared by the live-voice session and
3
- * the phone media-stream path.
4
- *
5
- * A single above-gate audio chunk is not an interruption: brief TTS bleed
6
- * through imperfect echo cancellation, a cough, a line click. Speech has to
7
- * accumulate to `minSpeechMs` before the assistant is cut off. Short gaps
8
- * inside a run are tolerated (a browser's half-duplex echo canceller ducks
9
- * the near-end voice into intermittent above-gate chunks; a phone line
10
- * drops frames), but a longer continuous silence, or a run that is mostly
11
- * silence, resets it, so sparse periodic blips can never sum into a
12
- * barge-in.
13
- *
14
- * The guard is pure accounting over classified chunks. What arms it, what
15
- * classifies a chunk, and what happens when it fires belong to the driver.
16
- */
17
-
18
- /** Sustained speech required before a barge-in fires. */
19
- export const DEFAULT_BARGE_IN_MIN_SPEECH_MS = 250;
20
-
21
- /**
22
- * Longest continuous sub-threshold gap tolerated inside a run. A gap of
23
- * exactly this length still counts as inside the run: the web client
24
- * batches PCM into 50 ms frames, so a run of ducked frames lands on the
25
- * boundary exactly (four frames = 200 ms).
26
- */
27
- export const BARGE_IN_GAP_TOLERANCE_MS = 200;
28
-
29
- /**
30
- * Ceiling on cumulative sub-threshold time across a whole run, as a
31
- * multiple of `minSpeechMs`. Per-gap tolerance alone lets sparse isolated
32
- * blips (a 10 ms echo spike every 200 ms) each clear the consecutive-gap
33
- * timer while retaining prior speech, so they would sum to the guard over
34
- * several seconds. Capping total tolerated silence imposes a minimum
35
- * above-gate duty cycle (1 / (1 + ratio), about 20%): once the run is mostly
36
- * silence it resets, so genuine choppy speech still lands but periodic noise
37
- * cannot accumulate into one.
38
- */
39
- export const BARGE_IN_MAX_TOLERATED_SILENCE_RATIO = 4;
40
-
41
- /**
42
- * How a chunk reads to the guard. `echo` is the assistant's own playback
43
- * heard back through the microphone, which live voice classifies; a phone
44
- * line carries only the caller's track and never produces it.
45
- */
46
- export type BargeInChunkClassification = "speech" | "silence" | "echo";
47
-
48
- /**
49
- * What one chunk did to the run: `pending` (still accumulating, or a
50
- * tolerated gap), `reset` (echo, or a gap past the limits, dropped the run),
51
- * `fired` (sustained speech reached the threshold; the guard is spent).
52
- */
53
- export type BargeInGuardStep = "pending" | "reset" | "fired";
54
-
55
- export interface BargeInGuard {
56
- /** Speech accumulated in the current run. */
57
- readonly speechMs: number;
58
- /** Feed one classified chunk of `chunkMs` audio. */
59
- track(
60
- classification: BargeInChunkClassification,
61
- chunkMs: number,
62
- ): BargeInGuardStep;
63
- }
64
-
65
- /**
66
- * Build a guard that fires after `minSpeechMs` of sustained speech. A zero
67
- * threshold fires on the first speech chunk (instant barge-in).
68
- */
69
- export function createBargeInGuard(minSpeechMs: number): BargeInGuard {
70
- let speechMs = 0;
71
- // Consecutive sub-threshold time since the last speech chunk.
72
- let silenceMs = 0;
73
- // Cumulative sub-threshold time over the whole run, never reset by speech.
74
- let toleratedSilenceMs = 0;
75
- let fired = false;
76
-
77
- const reset = (): BargeInGuardStep => {
78
- speechMs = 0;
79
- silenceMs = 0;
80
- toleratedSilenceMs = 0;
81
- return "reset";
82
- };
83
-
84
- return {
85
- get speechMs() {
86
- return speechMs;
87
- },
88
- track(classification, chunkMs) {
89
- if (fired) {
90
- return "fired";
91
- }
92
- if (classification === "echo") {
93
- return reset();
94
- }
95
- if (classification === "silence") {
96
- silenceMs += chunkMs;
97
- toleratedSilenceMs += chunkMs;
98
- // Strictly greater on the per-gap check: a gap of exactly the
99
- // tolerance is still inside the run.
100
- if (
101
- silenceMs > BARGE_IN_GAP_TOLERANCE_MS ||
102
- toleratedSilenceMs >
103
- minSpeechMs * BARGE_IN_MAX_TOLERATED_SILENCE_RATIO
104
- ) {
105
- return reset();
106
- }
107
- return "pending";
108
- }
109
- silenceMs = 0;
110
- speechMs += chunkMs;
111
- if (speechMs < minSpeechMs) {
112
- return "pending";
113
- }
114
- fired = true;
115
- return "fired";
116
- },
117
- };
118
- }