@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
@@ -98,20 +98,4 @@ export interface CallTransport {
98
98
  * this — the controller then treats playback as already drained.
99
99
  */
100
100
  awaitPlaybackDrained?(): Promise<void>;
101
-
102
- /**
103
- * Whether no assistant speech is buffered, queued, in flight, or
104
- * (estimatedly) still playing to the caller. Progress narration speaks
105
- * only into audible silence, so it asks before every update. Transports
106
- * that play speech synchronously may omit this; the controller then
107
- * treats the transport as idle.
108
- */
109
- isPlaybackIdle?(): boolean;
110
-
111
- /**
112
- * Wall-clock estimate of when audio already sent finishes playing to the
113
- * caller, 0 when nothing is playing. Anchors the dead-air countdown for
114
- * progress narration to when the caller last heard something.
115
- */
116
- playbackTailUntilMs?(): number;
117
101
  }
@@ -327,14 +327,6 @@ export class MediaStreamOutput implements CallTransport {
327
327
  /** True when the queue drain loop is actively running. */
328
328
  private draining = false;
329
329
 
330
- /**
331
- * Estimated wall-clock instant the audio already sent to Twilio finishes
332
- * playing to the caller. Frames leave faster than real time and Twilio
333
- * buffers them, so the only local view of "still audible" is this running
334
- * sum of sent frame durations; a `clear` drops the buffer and resets it.
335
- */
336
- private playbackTailAtMs = 0;
337
-
338
330
  /** Abort controller for the currently in-flight synthesis/fetch. */
339
331
  private activePlaybackAbort: AbortController | null = null;
340
332
 
@@ -667,7 +659,6 @@ export class MediaStreamOutput implements CallTransport {
667
659
  return;
668
660
  }
669
661
  this.sendClearCommand();
670
- this.playbackTailAtMs = 0;
671
662
  // Twilio drops its buffered audio (and the marks within it) on `clear`, so
672
663
  // any end-of-turn mark already sent will never echo. Treat those as drained
673
664
  // so a pending end-call drain wait resolves instead of stalling on the cap.
@@ -725,24 +716,6 @@ export class MediaStreamOutput implements CallTransport {
725
716
  return this.playbackQueue.length;
726
717
  }
727
718
 
728
- /**
729
- * Whether no speech is buffered toward a sentence, queued, being
730
- * synthesized or fetched, or (estimatedly) still playing at Twilio.
731
- */
732
- isPlaybackIdle(): boolean {
733
- return (
734
- this.textBuffer.length === 0 &&
735
- this.playbackQueue.length === 0 &&
736
- !this.draining &&
737
- Date.now() >= this.playbackTailAtMs
738
- );
739
- }
740
-
741
- /** See {@link CallTransport.playbackTailUntilMs}. */
742
- playbackTailUntilMs(): number {
743
- return this.playbackTailAtMs;
744
- }
745
-
746
719
  /**
747
720
  * Runtime check for closed state. Used instead of direct property access
748
721
  * in async methods because TypeScript's control flow analysis cannot
@@ -799,7 +772,6 @@ export class MediaStreamOutput implements CallTransport {
799
772
  this.playbackQueue.length = 0;
800
773
  this.playbackVersion++;
801
774
  this.audioStartCallback = null;
802
- this.playbackTailAtMs = 0;
803
775
  if (this.activePlaybackAbort) {
804
776
  this.activePlaybackAbort.abort();
805
777
  this.activePlaybackAbort = null;
@@ -882,10 +854,6 @@ export class MediaStreamOutput implements CallTransport {
882
854
  for (const frame of frames) {
883
855
  this.sendAudioPayload(frame);
884
856
  }
885
- const durationMs =
886
- (frames.length * MULAW_FRAME_SIZE * 1000) / TELEPHONY_SAMPLE_RATE_HZ;
887
- this.playbackTailAtMs =
888
- Math.max(Date.now(), this.playbackTailAtMs) + durationMs;
889
857
  }
890
858
 
891
859
  /**
@@ -47,11 +47,6 @@ import { addMessage } from "../persistence/conversation-crud.js";
47
47
  import { resolveGuardianName } from "../prompts/user-reference.js";
48
48
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
49
49
  import { getLogger } from "../util/logger.js";
50
- import {
51
- type BargeInGuard,
52
- createBargeInGuard,
53
- DEFAULT_BARGE_IN_MIN_SPEECH_MS,
54
- } from "./barge-in-guard.js";
55
50
  import { CallController } from "./call-controller.js";
56
51
  import {
57
52
  formatDuration,
@@ -193,8 +188,6 @@ export class MediaStreamCallSession {
193
188
  private bargeInAccepted = 0;
194
189
  /** Number of barge-in attempts that were ignored (assistant not speaking). */
195
190
  private bargeInIgnored = 0;
196
- /** Armed by caller speech while a turn or its tail is interruptible. */
197
- private bargeInGuard: BargeInGuard | null = null;
198
191
  /** Number of turn-start transitions detected by the STT session. */
199
192
  private turnStarts = 0;
200
193
  /** Number of transcript finals produced (non-empty). */
@@ -222,9 +215,6 @@ export class MediaStreamCallSession {
222
215
  // Create STT session with callbacks wired to the controller.
223
216
  const callbacks: MediaStreamSttSessionCallbacks = {
224
217
  onSpeechStart: () => this.handleSpeechStart(),
225
- onMediaFrame: (hasSpeech, durationMs) =>
226
- this.handleMediaFrame(hasSpeech, durationMs),
227
- onSpeechEnd: () => this.handleSpeechEnd(),
228
218
  onTranscriptFinal: (text, durationMs) =>
229
219
  this.handleTranscriptFinal(text, durationMs),
230
220
  onDtmf: (digit) => this.handleDtmf(digit),
@@ -778,80 +768,38 @@ export class MediaStreamCallSession {
778
768
 
779
769
  private handleSpeechStart(): void {
780
770
  this.turnStarts++;
781
- }
782
771
 
783
- // Sustained-speech barge-in guard, fed by every inbound frame. Speech only
784
- // counts while there is something to interrupt: an assistant turn in
785
- // flight (thinking or speaking) or a completed turn's tail still playing
786
- // from Twilio's buffer. Outside that window the guard is dropped, so
787
- // speech from the caller's own utterance never carries into a turn that
788
- // starts before the local VAD has ended the utterance (a streaming final
789
- // can start the turn first). A speech frame inside the window arms the
790
- // guard; a fired guard reaches the controller. A line click, a cough, or
791
- // TTS bleed never gets that far.
792
- private handleMediaFrame(hasSpeech: boolean, durationMs: number): void {
793
- if (!this.output || !this.controller) {
794
- return;
795
- }
796
- const bargeable =
797
- this.controller.getState() !== "idle" || !this.output.isPlaybackIdle();
798
- if (!bargeable) {
799
- this.bargeInGuard = null;
800
- return;
801
- }
802
- if (this.bargeInGuard === null) {
803
- if (!hasSpeech) {
804
- return;
772
+ // Barge-in: clear queued outbound audio and abort the in-flight LLM
773
+ // turn only when the assistant is actively speaking. Uses the gated
774
+ // handleBargeIn path so initial inbound audio frames do not cancel a
775
+ // still-starting initial turn.
776
+ //
777
+ // clearAudio runs via the onAccepted hook so it only fires when the
778
+ // barge-in passes the speaking gate — an ignored barge-in (controller
779
+ // idle/processing) must not flush queued/in-flight TTS such as a
780
+ // buffered greeting. The hook runs before handleInterrupt so the
781
+ // end-of-turn mark it enqueues survives the queue flush.
782
+ if (this.output && this.controller) {
783
+ const output = this.output;
784
+ const accepted = this.controller.handleBargeIn(() => output.clearAudio());
785
+ if (accepted) {
786
+ this.bargeInAccepted++;
787
+ log.info(
788
+ { callSessionId: this.callSessionId },
789
+ "Media-stream barge-in accepted — cleared outbound audio",
790
+ );
791
+ } else {
792
+ // No turn to abort, but a completed turn's tail can still be
793
+ // playing from Twilio's buffer — flush only that buffer so the
794
+ // caller isn't talked over. Queued speech that hasn't reached
795
+ // Twilio yet (greeting, handoff prompt) is preserved.
796
+ output.clearBufferedAudio();
797
+ this.bargeInIgnored++;
798
+ log.debug(
799
+ { callSessionId: this.callSessionId },
800
+ "Media-stream barge-in ignored — assistant not speaking",
801
+ );
805
802
  }
806
- this.bargeInGuard = createBargeInGuard(DEFAULT_BARGE_IN_MIN_SPEECH_MS);
807
- }
808
- const step = this.bargeInGuard.track(
809
- hasSpeech ? "speech" : "silence",
810
- durationMs,
811
- );
812
- if (step === "fired") {
813
- this.bargeInGuard = null;
814
- this.fireBargeIn();
815
- }
816
- }
817
-
818
- private handleSpeechEnd(): void {
819
- // An untripped guard was noise or a fragment: the run never reached the
820
- // threshold before the caller's turn ended.
821
- this.bargeInGuard = null;
822
- }
823
-
824
- // Sustained caller speech landed: clear queued outbound audio and abort
825
- // the in-flight LLM turn when one is in flight (thinking or speaking).
826
- //
827
- // clearAudio runs via the onAccepted hook so it only fires when the
828
- // barge-in passes the controller's gate; an ignored barge-in (controller
829
- // idle) must not flush queued/in-flight TTS such as a buffered greeting.
830
- // The hook runs before handleInterrupt so the end-of-turn mark it
831
- // enqueues survives the queue flush.
832
- private fireBargeIn(): void {
833
- if (!this.output || !this.controller) {
834
- return;
835
- }
836
- const output = this.output;
837
- const accepted = this.controller.handleBargeIn(() => output.clearAudio());
838
- if (accepted) {
839
- this.bargeInAccepted++;
840
- log.info(
841
- { callSessionId: this.callSessionId },
842
- "Media-stream barge-in accepted: cleared outbound audio",
843
- );
844
- } else {
845
- // No turn to abort, but a completed turn's tail can still be
846
- // playing from Twilio's buffer, so flush only that buffer so the
847
- // caller isn't talked over. Queued speech that hasn't reached
848
- // Twilio yet (greeting, handoff prompt) is preserved.
849
- output.clearBufferedAudio();
850
- this.bargeInIgnored++;
851
- log.debug(
852
- { callSessionId: this.callSessionId },
853
- "Media-stream barge-in ignored: no turn in flight",
854
- );
855
803
  }
856
804
  }
857
805
 
@@ -120,16 +120,6 @@ export interface MediaStreamSttSessionCallbacks {
120
120
  /** Called when the turn detector transitions to active (first speech-bearing chunk). */
121
121
  onSpeechStart?: () => void;
122
122
 
123
- /**
124
- * Called for every inbound frame with the local VAD's verdict on it and
125
- * the frame's duration. Drives the sustained-speech barge-in guard, which
126
- * needs the silence frames inside a detector turn as well as the speech.
127
- */
128
- onMediaFrame?: (hasSpeech: boolean, durationMs: number) => void;
129
-
130
- /** Called when the turn detector ends the caller's turn (silence or cap). */
131
- onSpeechEnd?: () => void;
132
-
133
123
  /**
134
124
  * Called when a completed caller utterance has been transcribed.
135
125
  *
@@ -265,7 +255,6 @@ export class MediaStreamSttSession {
265
255
  this.callbacks.onSpeechStart?.();
266
256
  },
267
257
  onTurnEnd: (reason, durationMs) => {
268
- this.callbacks.onSpeechEnd?.();
269
258
  void this.handleTurnEnd(reason, durationMs);
270
259
  },
271
260
  });
@@ -388,10 +377,6 @@ export class MediaStreamSttSession {
388
377
  const raw = Buffer.from(event.media.payload, "base64");
389
378
  const hasSpeech = detectSpeechActivity(raw);
390
379
  this.turnDetector.onMediaChunk(hasSpeech);
391
- this.callbacks.onMediaFrame?.(
392
- hasSpeech,
393
- raw.length / (TELEPHONY_SOURCE_SAMPLE_RATE / 1000),
394
- );
395
380
 
396
381
  if (this.mode === "batch") {
397
382
  this.currentTurnChunks.push(event.media.payload);
@@ -8,7 +8,6 @@
8
8
  */
9
9
 
10
10
  import { loadConfig } from "../config/loader.js";
11
- import { resolveEffectiveSpeechProviders } from "../config/managed-speech-defaults.js";
12
11
  import {
13
12
  getCatalogProvider,
14
13
  getTtsProvider,
@@ -74,13 +73,6 @@ export interface ResolveCallTtsOptions {
74
73
  /**
75
74
  * Resolve the active TTS provider via the global provider abstraction.
76
75
  *
77
- * The provider is the effective one after managed-speech defaulting
78
- * ({@link resolveEffectiveSpeechProviders}): a configured BYOK provider
79
- * whose credential does not resolve is stood in for by managed speech
80
- * while the platform connection is usable, the same substitution live
81
- * voice makes, so a fresh Vellum connection speaks on the phone with zero
82
- * TTS configuration.
83
- *
84
76
  * The native-vs-synthesized decision is driven by the catalog's
85
77
  * `callMode` field via {@link resolveCallStrategy}. Providers with
86
78
  * `callMode: "synthesized-play"` have their audio streamed through the
@@ -102,11 +94,10 @@ export async function resolveCallTtsProvider(
102
94
  ): Promise<ResolvedCallTts> {
103
95
  try {
104
96
  const config = loadConfig();
105
- const effectiveProviderId = await effectiveTtsProviderId(config);
106
- const resolved = resolveTtsConfig(config, effectiveProviderId);
97
+ const resolved = resolveTtsConfig(config);
107
98
 
108
99
  // Use the catalog's callMode to decide the call path.
109
- const strategy = resolveCallStrategy(config, effectiveProviderId);
100
+ const strategy = resolveCallStrategy(config);
110
101
 
111
102
  let providerId = resolved.provider;
112
103
  let useSynthesizedPath = strategy.callMode === "synthesized-play";
@@ -184,28 +175,6 @@ export async function resolveCallTtsProvider(
184
175
  }
185
176
  }
186
177
 
187
- /**
188
- * The TTS provider the call actually uses after managed-speech defaulting.
189
- * A failure inside the managed lookup (platform client, credential store)
190
- * keeps the configured provider: a managed-speech hiccup must not demote a
191
- * working BYOK provider, and the outer resolver's own fallback is the
192
- * silent native path.
193
- */
194
- async function effectiveTtsProviderId(
195
- config: ReturnType<typeof loadConfig>,
196
- ): Promise<TtsProviderId | undefined> {
197
- try {
198
- const { tts } = await resolveEffectiveSpeechProviders(config);
199
- return tts;
200
- } catch (err) {
201
- log.warn(
202
- { err },
203
- "Managed-speech defaulting failed for call TTS; keeping the configured provider",
204
- );
205
- return undefined;
206
- }
207
- }
208
-
209
178
  /**
210
179
  * Decode a resolved call audio format into the provider request format
211
180
  * and the audio-store format.
@@ -0,0 +1,233 @@
1
+ export interface PromptSpeakerContext {
2
+ speakerId: string;
3
+ speakerLabel: string;
4
+ speakerConfidence: number | null;
5
+ source: "provider" | "inferred";
6
+ }
7
+
8
+ export interface PromptSpeakerMetadata {
9
+ speakerId?: string;
10
+ speakerLabel?: string;
11
+ speakerName?: string;
12
+ speakerConfidence?: number;
13
+ participantId?: string;
14
+ }
15
+
16
+ interface SpeakerProfile {
17
+ speakerId: string;
18
+ speakerLabel: string;
19
+ speakerConfidence: number | null;
20
+ source: "provider" | "inferred";
21
+ utteranceCount: number;
22
+ firstSeenAt: number;
23
+ lastSeenAt: number;
24
+ }
25
+
26
+ function toCleanString(value: unknown): string | null {
27
+ if (typeof value !== "string") {
28
+ return null;
29
+ }
30
+ const trimmed = value.trim();
31
+ return trimmed.length > 0 ? trimmed : null;
32
+ }
33
+
34
+ function toNumber(value: unknown): number | null {
35
+ if (typeof value === "number" && Number.isFinite(value)) {
36
+ return value;
37
+ }
38
+ if (typeof value === "string") {
39
+ const parsed = Number(value);
40
+ if (Number.isFinite(parsed)) {
41
+ return parsed;
42
+ }
43
+ }
44
+ return null;
45
+ }
46
+
47
+ function getObject(value: unknown): Record<string, unknown> | null {
48
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
49
+ return null;
50
+ }
51
+ return value as Record<string, unknown>;
52
+ }
53
+
54
+ function normalizeSpeakerLabel(
55
+ metadata: PromptSpeakerMetadata,
56
+ fallbackIndex: number,
57
+ ): string {
58
+ const preferredLabel =
59
+ toCleanString(metadata.speakerName) ?? toCleanString(metadata.speakerLabel);
60
+ if (preferredLabel) {
61
+ return preferredLabel;
62
+ }
63
+ return `Speaker ${fallbackIndex}`;
64
+ }
65
+
66
+ export function extractPromptSpeakerMetadata(
67
+ message: Record<string, unknown>,
68
+ ): PromptSpeakerMetadata {
69
+ const providerMetadata = getObject(message.providerMetadata);
70
+ const metadata = getObject(message.metadata);
71
+ const participant = getObject(message.participant);
72
+ const speaker = getObject(message.speaker);
73
+
74
+ const pick = (...values: unknown[]): string | undefined => {
75
+ for (const value of values) {
76
+ const cleaned = toCleanString(value);
77
+ if (cleaned) {
78
+ return cleaned;
79
+ }
80
+ }
81
+ return undefined;
82
+ };
83
+
84
+ const pickNumber = (...values: unknown[]): number | undefined => {
85
+ for (const value of values) {
86
+ const parsed = toNumber(value);
87
+ if (parsed != null) {
88
+ return parsed;
89
+ }
90
+ }
91
+ return undefined;
92
+ };
93
+
94
+ return {
95
+ speakerId: pick(
96
+ message.speakerId,
97
+ message.speaker_id,
98
+ speaker?.id,
99
+ speaker?.speakerId,
100
+ metadata?.speakerId,
101
+ providerMetadata?.speakerId,
102
+ metadata?.speaker_id,
103
+ providerMetadata?.speaker_id,
104
+ ),
105
+ speakerLabel: pick(
106
+ message.speakerLabel,
107
+ message.speaker_label,
108
+ message.speaker,
109
+ speaker?.label,
110
+ speaker?.name,
111
+ metadata?.speakerLabel,
112
+ providerMetadata?.speakerLabel,
113
+ metadata?.speaker_label,
114
+ providerMetadata?.speaker_label,
115
+ ),
116
+ speakerName: pick(
117
+ message.speakerName,
118
+ message.speaker_name,
119
+ participant?.name,
120
+ metadata?.speakerName,
121
+ providerMetadata?.speakerName,
122
+ metadata?.speaker_name,
123
+ providerMetadata?.speaker_name,
124
+ ),
125
+ speakerConfidence: pickNumber(
126
+ message.speakerConfidence,
127
+ message.speaker_confidence,
128
+ message.confidence,
129
+ speaker?.confidence,
130
+ metadata?.speakerConfidence,
131
+ providerMetadata?.speakerConfidence,
132
+ metadata?.speaker_confidence,
133
+ providerMetadata?.speaker_confidence,
134
+ ),
135
+ participantId: pick(
136
+ message.participantId,
137
+ message.participant_id,
138
+ participant?.id,
139
+ metadata?.participantId,
140
+ providerMetadata?.participantId,
141
+ metadata?.participant_id,
142
+ providerMetadata?.participant_id,
143
+ ),
144
+ };
145
+ }
146
+
147
+ export class SpeakerIdentityTracker {
148
+ private profiles = new Map<string, SpeakerProfile>();
149
+ private nextInferredIndex = 1;
150
+
151
+ identifySpeaker(metadata: PromptSpeakerMetadata): PromptSpeakerContext {
152
+ const providerSpeakerId =
153
+ toCleanString(metadata.speakerId) ??
154
+ toCleanString(metadata.participantId) ??
155
+ null;
156
+
157
+ if (providerSpeakerId) {
158
+ const existing = this.profiles.get(providerSpeakerId);
159
+ if (existing) {
160
+ existing.lastSeenAt = Date.now();
161
+ existing.utteranceCount += 1;
162
+ if (metadata.speakerConfidence !== undefined) {
163
+ existing.speakerConfidence = metadata.speakerConfidence;
164
+ }
165
+ return {
166
+ speakerId: existing.speakerId,
167
+ speakerLabel: existing.speakerLabel,
168
+ speakerConfidence: existing.speakerConfidence,
169
+ source: existing.source,
170
+ };
171
+ }
172
+
173
+ const profile: SpeakerProfile = {
174
+ speakerId: providerSpeakerId,
175
+ speakerLabel: normalizeSpeakerLabel(metadata, this.nextInferredIndex),
176
+ speakerConfidence: metadata.speakerConfidence ?? null,
177
+ source: "provider",
178
+ utteranceCount: 1,
179
+ firstSeenAt: Date.now(),
180
+ lastSeenAt: Date.now(),
181
+ };
182
+ this.profiles.set(providerSpeakerId, profile);
183
+ this.nextInferredIndex += 1;
184
+ return {
185
+ speakerId: profile.speakerId,
186
+ speakerLabel: profile.speakerLabel,
187
+ speakerConfidence: profile.speakerConfidence,
188
+ source: profile.source,
189
+ };
190
+ }
191
+
192
+ const inferredSpeakerId = "primary-speaker";
193
+ const existingPrimary = this.profiles.get(inferredSpeakerId);
194
+ if (existingPrimary) {
195
+ existingPrimary.lastSeenAt = Date.now();
196
+ existingPrimary.utteranceCount += 1;
197
+ return {
198
+ speakerId: existingPrimary.speakerId,
199
+ speakerLabel: existingPrimary.speakerLabel,
200
+ speakerConfidence: existingPrimary.speakerConfidence,
201
+ source: existingPrimary.source,
202
+ };
203
+ }
204
+
205
+ const inferredProfile: SpeakerProfile = {
206
+ speakerId: inferredSpeakerId,
207
+ speakerLabel: normalizeSpeakerLabel(metadata, this.nextInferredIndex),
208
+ speakerConfidence: metadata.speakerConfidence ?? null,
209
+ source: "inferred",
210
+ utteranceCount: 1,
211
+ firstSeenAt: Date.now(),
212
+ lastSeenAt: Date.now(),
213
+ };
214
+ this.profiles.set(inferredSpeakerId, inferredProfile);
215
+ this.nextInferredIndex += 1;
216
+
217
+ return {
218
+ speakerId: inferredProfile.speakerId,
219
+ speakerLabel: inferredProfile.speakerLabel,
220
+ speakerConfidence: inferredProfile.speakerConfidence,
221
+ source: inferredProfile.source,
222
+ };
223
+ }
224
+
225
+ listProfiles(): PromptSpeakerContext[] {
226
+ return [...this.profiles.values()].map((profile) => ({
227
+ speakerId: profile.speakerId,
228
+ speakerLabel: profile.speakerLabel,
229
+ speakerConfidence: profile.speakerConfidence,
230
+ source: profile.source,
231
+ }));
232
+ }
233
+ }
@@ -40,21 +40,17 @@ export interface TtsCallStrategy {
40
40
  }
41
41
 
42
42
  /**
43
- * Resolve the call strategy for the active TTS provider.
43
+ * Resolve the call strategy for the currently configured TTS provider.
44
44
  *
45
- * Reads the provider from config via {@link resolveTtsConfig} (or takes
46
- * `providerOverride`, the provider a caller already resolved after
47
- * managed-speech defaulting), then looks up its `callMode` in the catalog.
45
+ * Reads the active provider from config via {@link resolveTtsConfig},
46
+ * then looks up the provider's `callMode` in the catalog.
48
47
  *
49
48
  * Falls back to `native-twilio` with `"elevenlabs"` when the config
50
49
  * or catalog is unavailable (e.g. test mocks, pre-migration configs).
51
50
  */
52
- export function resolveCallStrategy(
53
- config: AssistantConfig,
54
- providerOverride?: TtsProviderId,
55
- ): TtsCallStrategy {
51
+ export function resolveCallStrategy(config: AssistantConfig): TtsCallStrategy {
56
52
  try {
57
- const resolved = resolveTtsConfig(config, providerOverride);
53
+ const resolved = resolveTtsConfig(config);
58
54
  const catalogEntry = getCatalogProvider(resolved.provider);
59
55
  return {
60
56
  providerId: catalogEntry.id,
@@ -11,8 +11,6 @@ export type CallEventType =
11
11
  | "call_connected"
12
12
  | "caller_spoke"
13
13
  | "assistant_spoke"
14
- | "tool_use_started"
15
- | "tool_use_completed"
16
14
  | "user_question_asked"
17
15
  | "user_answered"
18
16
  | "user_instruction_relayed"