@vellumai/assistant 0.12.1-staging.1 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. package/AGENTS.md +0 -4
  2. package/ARCHITECTURE.md +12 -11
  3. package/docs/architecture/turn-actor.md +8 -15
  4. package/openapi.yaml +1 -291
  5. package/package.json +1 -1
  6. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  7. package/src/__tests__/app-compiler.test.ts +0 -6
  8. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  9. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  10. package/src/__tests__/app-source-watcher.test.ts +218 -0
  11. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  12. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  13. package/src/__tests__/computer-use-tools.test.ts +5 -17
  14. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  15. package/src/__tests__/config-schema.test.ts +29 -28
  16. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  17. package/src/__tests__/config-watcher.test.ts +8 -23
  18. package/src/__tests__/connection-model-compat.test.ts +2 -2
  19. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  20. package/src/__tests__/conversation-pairing.test.ts +0 -26
  21. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  22. package/src/__tests__/conversation-queue.test.ts +207 -48
  23. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  24. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  25. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  26. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  27. package/src/__tests__/conversation-title-service.test.ts +10 -14
  28. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  29. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  30. package/src/__tests__/credential-record-retire.test.ts +1 -171
  31. package/src/__tests__/credential-routes.test.ts +3 -212
  32. package/src/__tests__/credential-security-invariants.test.ts +1 -2
  33. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  34. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  35. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  36. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  37. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  38. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  39. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  40. package/src/__tests__/host-file-proxy.test.ts +23 -11
  41. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  42. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  43. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  44. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  45. package/src/__tests__/mcp-health-check.test.ts +11 -8
  46. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  47. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  48. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  49. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  51. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  52. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  53. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  54. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  55. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  56. package/src/__tests__/model-intents.test.ts +0 -3
  57. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  58. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  59. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  60. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  61. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  62. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  63. package/src/__tests__/speaker-identification.test.ts +56 -0
  64. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  65. package/src/__tests__/subagent-tools.test.ts +2 -3
  66. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  67. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  68. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  69. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  70. package/src/__tests__/workspace-git-service.test.ts +0 -26
  71. package/src/acp/__tests__/agent-process.test.ts +4 -258
  72. package/src/acp/__tests__/auth-required.test.ts +0 -96
  73. package/src/acp/__tests__/client-handler.test.ts +2 -90
  74. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  75. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  76. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  77. package/src/acp/__tests__/session-manager.test.ts +4 -895
  78. package/src/acp/agent-process.test.ts +1 -4
  79. package/src/acp/agent-process.ts +9 -94
  80. package/src/acp/auth-required.ts +1 -50
  81. package/src/acp/auto-install.test.ts +7 -9
  82. package/src/acp/client-handler.ts +3 -16
  83. package/src/acp/resolve-agent.test.ts +6 -220
  84. package/src/acp/resolve-agent.ts +23 -88
  85. package/src/acp/session-manager.test.ts +3 -196
  86. package/src/acp/session-manager.ts +18 -441
  87. package/src/acp/types.ts +5 -50
  88. package/src/api/events/app-files-changed.ts +3 -4
  89. package/src/api/index.ts +0 -6
  90. package/src/apps/app-store.ts +1 -1
  91. package/src/bundler/app-compiler.ts +0 -15
  92. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  93. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  94. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  95. package/src/calls/call-constants.ts +4 -24
  96. package/src/calls/call-controller.ts +199 -499
  97. package/src/calls/call-transport.ts +0 -16
  98. package/src/calls/media-stream-output.ts +0 -32
  99. package/src/calls/media-stream-server.ts +30 -82
  100. package/src/calls/media-stream-stt-session.ts +0 -15
  101. package/src/calls/resolve-call-tts-provider.ts +2 -33
  102. package/src/calls/speaker-identification.ts +233 -0
  103. package/src/calls/tts-call-strategy.ts +5 -9
  104. package/src/calls/types.ts +0 -2
  105. package/src/calls/voice-control-protocol.ts +21 -53
  106. package/src/calls/voice-session-bridge.ts +46 -59
  107. package/src/calls/voice-triage-escalate.ts +56 -175
  108. package/src/cli/commands/apps.help.ts +13 -67
  109. package/src/cli/commands/apps.ts +0 -183
  110. package/src/cli/commands/channels/index.help.ts +2 -70
  111. package/src/cli/commands/channels/index.ts +3 -16
  112. package/src/cli/commands/credentials.help.ts +2 -6
  113. package/src/cli/commands/credentials.ts +2 -2
  114. package/src/cli/commands/mcp.help.ts +8 -8
  115. package/src/cli/commands/mcp.ts +1 -1
  116. package/src/cli/commands/roadmap.help.ts +1 -5
  117. package/src/cli/commands/roadmap.ts +1 -1
  118. package/src/cli/lib/bundled-marketplace.json +90 -103
  119. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  120. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  121. package/src/config/__tests__/platform-rehydration.test.ts +0 -93
  122. package/src/config/acp-defaults.test.ts +3 -13
  123. package/src/config/acp-defaults.ts +6 -23
  124. package/src/config/acp-schema.ts +2 -30
  125. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  126. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  127. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  128. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  129. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  130. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  131. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  132. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  133. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  134. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  135. package/src/config/default-profile-catalog.ts +1 -1
  136. package/src/config/env.ts +2 -2
  137. package/src/config/feature-flag-registry.json +12 -8
  138. package/src/config/memory-v3-gate.test.ts +0 -31
  139. package/src/config/memory-v3-gate.ts +16 -20
  140. package/src/config/platform-rehydration.ts +21 -75
  141. package/src/config/schema.ts +2 -2
  142. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  143. package/src/config/schemas/calls.ts +28 -1
  144. package/src/config/schemas/live-voice.ts +173 -1
  145. package/src/config/schemas/mcp.ts +1 -1
  146. package/src/config/schemas/memory-retrospective.ts +0 -10
  147. package/src/config/schemas/skills.ts +14 -0
  148. package/src/credential-execution/process-manager.test.ts +19 -18
  149. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  150. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  151. package/src/daemon/app-source-watcher.ts +218 -0
  152. package/src/daemon/config-watcher.ts +194 -13
  153. package/src/daemon/conversation-process.ts +64 -35
  154. package/src/daemon/conversation-skill-tools.ts +31 -13
  155. package/src/daemon/conversation-store.ts +1 -1
  156. package/src/daemon/conversation-surfaces.ts +8 -10
  157. package/src/daemon/conversation-tool-setup.ts +43 -37
  158. package/src/daemon/conversation.ts +3 -0
  159. package/src/daemon/host-bash-proxy.ts +12 -8
  160. package/src/daemon/host-browser-proxy.ts +1 -15
  161. package/src/daemon/host-file-proxy.ts +10 -8
  162. package/src/daemon/host-transfer-proxy.ts +18 -14
  163. package/src/daemon/lifecycle.ts +5 -0
  164. package/src/daemon/mcp-reload-service.ts +5 -5
  165. package/src/daemon/message-types/sync.ts +0 -1
  166. package/src/daemon/providers-setup.ts +1 -1
  167. package/src/daemon/shutdown-handlers.ts +9 -1
  168. package/src/daemon/skill-memory-refresh.ts +0 -64
  169. package/src/daemon/tool-side-effects.ts +18 -7
  170. package/src/hooks/types.ts +0 -33
  171. package/src/inbound/platform-callback-registration.ts +5 -4
  172. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  173. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  174. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  175. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  176. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  177. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  178. package/src/live-voice/live-voice-session.ts +693 -213
  179. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  180. package/src/live-voice/protocol.ts +2 -0
  181. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  182. package/src/mcp/effective-config.ts +3 -3
  183. package/src/mcp/mcp-header-store.ts +45 -29
  184. package/src/mcp/startup.ts +4 -8
  185. package/src/messaging/provider.ts +3 -10
  186. package/src/messaging/providers/callback-routing.ts +0 -18
  187. package/src/messaging/providers/channel-transport.ts +0 -56
  188. package/src/messaging/providers/discord/transport.ts +0 -17
  189. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  190. package/src/messaging/providers/slack/adapter.ts +44 -7
  191. package/src/messaging/providers/slack/transport.ts +0 -16
  192. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  193. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  194. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  195. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  196. package/src/messaging/providers/whatsapp/client.ts +29 -0
  197. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  198. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  199. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  200. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  201. package/src/notifications/assistant-reply-producer.ts +3 -8
  202. package/src/notifications/conversation-pairing.ts +16 -36
  203. package/src/notifications/delivered-post-record.ts +1 -11
  204. package/src/notifications/home-feed-side-effect.ts +7 -55
  205. package/src/outbound-proxy/certs.ts +5 -3
  206. package/src/permissions/checker.test.ts +6 -11
  207. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  208. package/src/persistence/conversation-crud.ts +63 -71
  209. package/src/persistence/conversation-lineage.ts +4 -12
  210. package/src/persistence/conversation-title-service.ts +26 -9
  211. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  212. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  213. package/src/persistence/message-reads.ts +0 -30
  214. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  215. package/src/persistence/schema/memory-core.ts +0 -5
  216. package/src/platform/client.test.ts +0 -2
  217. package/src/platform/client.ts +10 -2
  218. package/src/plugin-api/constants.ts +0 -2
  219. package/src/plugin-api/index.ts +0 -1
  220. package/src/plugin-api/types.ts +0 -2
  221. package/src/plugins/defaults/index.ts +0 -2
  222. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  223. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  224. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  225. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  226. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  227. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  228. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  229. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  230. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  231. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  232. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  233. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  234. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  235. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  236. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  237. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  238. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  239. package/src/plugins/defaults/memory/startup.ts +1 -6
  240. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  241. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  242. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  243. package/src/plugins/defaults/memory/worker.ts +0 -6
  244. package/src/plugins/mcp-servers.ts +75 -15
  245. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  246. package/src/providers/gemini/client.ts +23 -9
  247. package/src/providers/model-catalog.ts +0 -34
  248. package/src/providers/model-intents.ts +5 -10
  249. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  250. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  251. package/src/providers/openai/chat-completions-provider.ts +78 -192
  252. package/src/providers/openai/codex-models.ts +4 -0
  253. package/src/runtime/AGENTS.md +0 -2
  254. package/src/runtime/auth/same-actor.ts +3 -38
  255. package/src/runtime/http-server.ts +151 -160
  256. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  257. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  258. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  259. package/src/runtime/routes/acp-routes.test.ts +0 -15
  260. package/src/runtime/routes/acp-routes.ts +9 -72
  261. package/src/runtime/routes/app-management-routes.ts +0 -73
  262. package/src/runtime/routes/app-routes.ts +1 -1
  263. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  264. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  265. package/src/runtime/routes/credential-routes.ts +10 -19
  266. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  267. package/src/runtime/routes/index.ts +0 -4
  268. package/src/runtime/routes/log-export-routes.ts +0 -2
  269. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  270. package/src/runtime/routes/migration-routes.ts +21 -8
  271. package/src/runtime/routes/platform-routes.ts +15 -18
  272. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  273. package/src/runtime/services/conversation-serializer.ts +3 -16
  274. package/src/runtime/sync/resource-sync-events.ts +1 -2
  275. package/src/schedule/worker.ts +1 -1
  276. package/src/security/ces-rpc-record-backend.ts +0 -7
  277. package/src/subagent/consult-context.ts +25 -12
  278. package/src/tools/acp/list-agents.test.ts +1 -3
  279. package/src/tools/acp/spawn.test.ts +11 -146
  280. package/src/tools/acp/spawn.ts +3 -21
  281. package/src/tools/acp/status.ts +3 -40
  282. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  283. package/src/tools/capability-offer.test.ts +2 -22
  284. package/src/tools/capability-offer.ts +1 -16
  285. package/src/tools/computer-use/definitions.ts +2 -4
  286. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  287. package/src/tools/credentials/metadata-store.ts +0 -100
  288. package/src/tools/host-filesystem/edit.test.ts +1 -2
  289. package/src/tools/host-filesystem/edit.ts +2 -2
  290. package/src/tools/host-filesystem/read.test.ts +1 -2
  291. package/src/tools/host-filesystem/read.ts +2 -2
  292. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  293. package/src/tools/host-filesystem/transfer.ts +2 -2
  294. package/src/tools/host-filesystem/write.test.ts +1 -2
  295. package/src/tools/host-filesystem/write.ts +2 -2
  296. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  297. package/src/tools/host-terminal/host-shell.ts +20 -4
  298. package/src/tools/policy-context.ts +7 -6
  299. package/src/tools/subagent/spawn.ts +8 -5
  300. package/src/tools/watch/watch-retro-report.ts +8 -0
  301. package/src/util/__tests__/language-subtag.test.ts +1 -23
  302. package/src/util/fs-watcher-error.ts +36 -0
  303. package/src/util/language-subtag.ts +0 -16
  304. package/src/util/platform.ts +0 -8
  305. package/src/workspace/git-service.ts +54 -5
  306. package/src/workspace/migrations/registry.ts +0 -6
  307. package/scripts/smoke-desktop-window-theme.ts +0 -186
  308. package/src/__tests__/git-porcelain.test.ts +0 -47
  309. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  310. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  311. package/src/__tests__/resolve-app.test.ts +0 -135
  312. package/src/__tests__/source-fingerprint.test.ts +0 -184
  313. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  314. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  315. package/src/acp/model-config.test.ts +0 -166
  316. package/src/acp/model-config.ts +0 -138
  317. package/src/api/events/acp-session-model-update.test.ts +0 -88
  318. package/src/api/events/acp-session-model-update.ts +0 -46
  319. package/src/apps/resolve-app.ts +0 -81
  320. package/src/apps/source-fingerprint.ts +0 -266
  321. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  322. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  323. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  324. package/src/calls/barge-in-guard.ts +0 -118
  325. package/src/calls/voice-leg-coordinator.ts +0 -189
  326. package/src/calls/voice-progress-cadence.ts +0 -423
  327. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  328. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  329. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  330. package/src/cli/commands/channels/send.ts +0 -128
  331. package/src/config/__tests__/platform-identity.test.ts +0 -117
  332. package/src/config/acp-agent-write.ts +0 -43
  333. package/src/config/acp-schema.test.ts +0 -81
  334. package/src/config/platform-identity.ts +0 -144
  335. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  336. package/src/config/schemas/voice.ts +0 -150
  337. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  338. package/src/daemon/app-change-notify.ts +0 -45
  339. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  340. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  341. package/src/desktop/desktop-chrome-policy.ts +0 -42
  342. package/src/desktop/desktop-dependencies.test.ts +0 -102
  343. package/src/desktop/desktop-dependencies.ts +0 -306
  344. package/src/desktop/desktop-feature.test.ts +0 -18
  345. package/src/desktop/desktop-feature.ts +0 -19
  346. package/src/desktop/desktop-panel-config.test.ts +0 -135
  347. package/src/desktop/desktop-panel-config.ts +0 -149
  348. package/src/desktop/desktop-session-manager.test.ts +0 -627
  349. package/src/desktop/desktop-session-manager.ts +0 -814
  350. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  351. package/src/desktop/desktop-stream-bridge.ts +0 -214
  352. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  353. package/src/desktop/desktop-wallpaper.ts +0 -113
  354. package/src/desktop/desktop-window-theme.ts +0 -170
  355. package/src/i18n/AGENTS.md +0 -22
  356. package/src/i18n/__tests__/i18n.test.ts +0 -108
  357. package/src/i18n/index.ts +0 -16
  358. package/src/i18n/locales.ts +0 -93
  359. package/src/i18n/messages.ts +0 -61
  360. package/src/i18n/title.ts +0 -25
  361. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  362. package/src/mcp/spec-schema.ts +0 -111
  363. package/src/mcp/workspace-mcp-config.ts +0 -188
  364. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  365. package/src/persistence/conversation-title-placeholders.ts +0 -23
  366. package/src/persistence/message-cursor.ts +0 -78
  367. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  368. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  369. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  370. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  371. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  372. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  373. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  374. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  375. package/src/providers/gemini-thought-signature.test.ts +0 -63
  376. package/src/providers/gemini-thought-signature.ts +0 -44
  377. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  378. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  379. package/src/providers/openai/google-thought-signature.ts +0 -320
  380. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  381. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  382. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  383. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  384. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  385. package/src/runtime/channel-send.ts +0 -316
  386. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  387. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  388. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  389. package/src/runtime/routes/channel-send-routes.ts +0 -85
  390. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  391. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  392. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  393. package/src/security/ces-http-record-backend.ts +0 -120
  394. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  395. package/src/skills/workspace-skill-md-signature.ts +0 -50
  396. package/src/tools/acp/status.test.ts +0 -94
  397. package/src/util/ca-bundle.ts +0 -13
  398. package/src/workspace/git-porcelain.ts +0 -66
  399. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  400. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  401. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  402. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  403. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  404. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -1,117 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
-
3
- import {
4
- setPlatformAssistantId,
5
- setPlatformOrganizationId,
6
- setPlatformUserId,
7
- } from "../env.js";
8
- import {
9
- fetchPlatformIdentityIds,
10
- PLATFORM_IDENTITY_VALIDATE_PATH,
11
- resolvePlatformAssistantId,
12
- } from "../platform-identity.js";
13
-
14
- const BASE_URL = "https://platform.vellum.ai";
15
- const ASSISTANT_ID = "11111111-2222-4333-8444-555555555555";
16
- const ORG_ID = "22222222-3333-4444-8555-666666666666";
17
- const USER_ID = "33333333-4444-4555-8666-777777777777";
18
-
19
- describe("fetchPlatformIdentityIds", () => {
20
- const originalFetch = globalThis.fetch;
21
- const fetchCalls: Array<{ url: string; init?: RequestInit }> = [];
22
- let fetchImpl: (
23
- input: RequestInfo | URL,
24
- init?: RequestInit,
25
- ) => Promise<Response> = async () =>
26
- new Response("not found", { status: 404 });
27
-
28
- beforeEach(() => {
29
- fetchCalls.length = 0;
30
- fetchImpl = async () => new Response("not found", { status: 404 });
31
- globalThis.fetch = (async (
32
- input: RequestInfo | URL,
33
- init?: RequestInit,
34
- ) => {
35
- const url = typeof input === "string" ? input : input.toString();
36
- fetchCalls.push({ url, init });
37
- return fetchImpl(input, init);
38
- }) as unknown as typeof fetch;
39
- });
40
-
41
- afterEach(() => {
42
- globalThis.fetch = originalFetch;
43
- });
44
-
45
- test("returns the three ids from a successful validate response", async () => {
46
- fetchImpl = async () =>
47
- new Response(
48
- JSON.stringify({
49
- assistant_id: ASSISTANT_ID,
50
- organization_id: ORG_ID,
51
- user_id: USER_ID,
52
- name: "Example Assistant",
53
- }),
54
- { status: 200 },
55
- );
56
-
57
- await expect(
58
- fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
59
- ).resolves.toEqual({
60
- assistantId: ASSISTANT_ID,
61
- organizationId: ORG_ID,
62
- userId: USER_ID,
63
- });
64
- expect(fetchCalls[0]?.url).toBe(
65
- `${BASE_URL}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
66
- );
67
- expect(fetchCalls[0]?.init?.method).toBe("POST");
68
- const headers = new Headers(fetchCalls[0]?.init?.headers);
69
- expect(headers.get("Authorization")).toBe("Api-Key assistant-key");
70
- });
71
-
72
- test("strips a trailing slash from the base URL", async () => {
73
- fetchImpl = async () =>
74
- new Response(
75
- JSON.stringify({
76
- assistant_id: ASSISTANT_ID,
77
- organization_id: ORG_ID,
78
- user_id: USER_ID,
79
- }),
80
- { status: 200 },
81
- );
82
-
83
- await fetchPlatformIdentityIds(`${BASE_URL}/`, "assistant-key");
84
- expect(fetchCalls[0]?.url).toBe(
85
- `${BASE_URL}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
86
- );
87
- });
88
-
89
- test("returns null on 401 without throwing", async () => {
90
- fetchImpl = async () => new Response("no", { status: 401 });
91
- await expect(
92
- fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
93
- ).resolves.toBeNull();
94
- });
95
-
96
- test("returns null on a network error without throwing", async () => {
97
- fetchImpl = async () => {
98
- throw new Error("network down");
99
- };
100
- await expect(
101
- fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
102
- ).resolves.toBeNull();
103
- });
104
- });
105
-
106
- describe("resolvePlatformAssistantId", () => {
107
- afterEach(() => {
108
- setPlatformAssistantId(undefined);
109
- setPlatformOrganizationId(undefined);
110
- setPlatformUserId(undefined);
111
- });
112
-
113
- test("returns the in-memory override", async () => {
114
- setPlatformAssistantId(ASSISTANT_ID);
115
- await expect(resolvePlatformAssistantId()).resolves.toBe(ASSISTANT_ID);
116
- });
117
- });
@@ -1,43 +0,0 @@
1
- /**
2
- * Raw-config helper shared by the config PATCH and SET routes, the paths that
3
- * write a coding agent's entry.
4
- */
5
-
6
- import { isPlainObject } from "../util/object.js";
7
-
8
- /**
9
- * Clearing a leaf of a coding agent's entry is a write of `null` - a PATCH of
10
- * `{ acp: { agents: { <id>: { model: null } } } }` or a
11
- * `config set acp.agents.<id>.model null`. The deep-merge assigns that literal
12
- * `null` because the stored value is a scalar, and a SET writes it verbatim by
13
- * design. Both `command` and `model` are optional strings in `AcpConfigSchema`,
14
- * so a persisted `null` makes every later `loadConfig()` warn and take its
15
- * salvage path, dropping the whole `acp` section with the agents defined in it.
16
- * Clearing means removing the key, so drop it here on every write path.
17
- *
18
- * A cleared `command` then reads as an omitted one: a bundled id inherits the
19
- * profile's command, and an id that has no profile fails the agents refinement
20
- * with a message naming the id, which tells the user more than zod's "expected
21
- * string, received null".
22
- */
23
- export function scrubNulledAcpAgentLeaves(raw: Record<string, unknown>): void {
24
- const acp = raw.acp;
25
- if (!isPlainObject(acp)) {
26
- return;
27
- }
28
- const agents = acp.agents;
29
- if (!isPlainObject(agents)) {
30
- return;
31
- }
32
- for (const entry of Object.values(agents)) {
33
- if (!isPlainObject(entry)) {
34
- continue;
35
- }
36
- if (entry.command === null) {
37
- delete entry.command;
38
- }
39
- if (entry.model === null) {
40
- delete entry.model;
41
- }
42
- }
43
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * Covers the ACP config leaf that carries model selection, the per-agent
3
- * `model`. It is optional with no `.default()`, so an absent value must stay
4
- * absent after parsing: the bundled profile supplies the model a session
5
- * starts on, and a key materialized as `undefined` would shadow it.
6
- *
7
- * `command` is optional in the same shape, so an entry for a bundled id can
8
- * carry a model and nothing else; the record's own check keeps a command
9
- * required for every id that has no bundled profile to inherit one from.
10
- */
11
-
12
- import { describe, expect, test } from "bun:test";
13
-
14
- import { AcpAgentConfigSchema, AcpConfigSchema } from "./acp-schema.js";
15
-
16
- describe("AcpConfigSchema", () => {
17
- test("populates defaults for an empty config", () => {
18
- expect(AcpConfigSchema.parse({})).toEqual({
19
- maxConcurrentSessions: 4,
20
- agents: {},
21
- });
22
- });
23
- });
24
-
25
- describe("AcpConfigSchema agents", () => {
26
- test("a bundled id's entry may omit command and name only a model", () => {
27
- const parsed = AcpConfigSchema.parse({
28
- agents: { claude: { model: "sonnet" } },
29
- });
30
-
31
- expect(parsed.agents).toEqual({ claude: { args: [], model: "sonnet" } });
32
- expect("command" in parsed.agents.claude!).toBe(false);
33
- });
34
-
35
- test("an id with no bundled profile needs a command", () => {
36
- const result = AcpConfigSchema.safeParse({
37
- agents: { mine: { model: "sonnet" } },
38
- });
39
-
40
- expect(result.success).toBe(false);
41
- if (result.success) {
42
- return;
43
- }
44
- expect(result.error.issues.map((issue) => issue.path)).toEqual([
45
- ["agents", "mine", "command"],
46
- ]);
47
- expect(result.error.issues[0]?.message).toContain("acp.agents.mine");
48
- });
49
-
50
- test("an id naming an Object.prototype member inherits no command", () => {
51
- expect(
52
- AcpConfigSchema.safeParse({ agents: { constructor: { model: "x" } } })
53
- .success,
54
- ).toBe(false);
55
- });
56
- });
57
-
58
- describe("AcpAgentConfigSchema", () => {
59
- test("round-trips a per-agent model override", () => {
60
- expect(
61
- AcpAgentConfigSchema.parse({
62
- command: "claude-agent-acp",
63
- model: "opus",
64
- }),
65
- ).toEqual({ command: "claude-agent-acp", args: [], model: "opus" });
66
- });
67
-
68
- test("leaves model unset when omitted, so a bundled profile's shows through", () => {
69
- const parsed = AcpAgentConfigSchema.parse({ command: "claude-agent-acp" });
70
-
71
- expect(parsed.model).toBeUndefined();
72
- expect("model" in parsed).toBe(false);
73
- });
74
-
75
- test("rejects a non-string model", () => {
76
- expect(
77
- AcpAgentConfigSchema.safeParse({ command: "claude-agent-acp", model: 3 })
78
- .success,
79
- ).toBe(false);
80
- });
81
- });
@@ -1,144 +0,0 @@
1
- /**
2
- * Bound platform identity (assistant, organization, user).
3
- *
4
- * Django maps an assistant API key to these ids via
5
- * `POST /v1/internal/assistants/validate/`. Process startup rehydrates from
6
- * that endpoint. Resolution prefers the in-memory ids, then the vault
7
- * copies of `vellum:platform_*`.
8
- */
9
-
10
- import { credentialKey } from "../security/credential-key.js";
11
- import { getSecureKeyAsync } from "../security/secure-keys.js";
12
- import { getLogger } from "../util/logger.js";
13
- import {
14
- getPlatformAssistantId,
15
- getPlatformOrganizationId,
16
- getPlatformUserId,
17
- setPlatformAssistantId,
18
- setPlatformOrganizationId,
19
- setPlatformUserId,
20
- } from "./env.js";
21
-
22
- const log = getLogger("platform-identity");
23
-
24
- export const PLATFORM_IDENTITY_VALIDATE_PATH =
25
- "/v1/internal/assistants/validate/";
26
-
27
- const VALIDATE_TIMEOUT_MS = 5_000;
28
-
29
- export type PlatformIdentityIds = {
30
- assistantId: string;
31
- organizationId: string;
32
- userId: string;
33
- };
34
-
35
- function asNonEmptyString(value: unknown): string | undefined {
36
- if (typeof value !== "string") {
37
- return undefined;
38
- }
39
- const trimmed = value.trim();
40
- return trimmed.length > 0 ? trimmed : undefined;
41
- }
42
-
43
- export function applyPlatformIdentityIds(ids: PlatformIdentityIds): void {
44
- if (ids.assistantId) {
45
- setPlatformAssistantId(ids.assistantId);
46
- }
47
- if (ids.organizationId) {
48
- setPlatformOrganizationId(ids.organizationId);
49
- }
50
- if (ids.userId) {
51
- setPlatformUserId(ids.userId);
52
- }
53
- }
54
-
55
- /**
56
- * Trade an assistant API key for the bound platform ids.
57
- *
58
- * Returns null when the platform is unreachable, refuses the key, or the
59
- * body has no ids. Never throws.
60
- */
61
- export async function fetchPlatformIdentityIds(
62
- baseUrl: string,
63
- apiKey: string,
64
- ): Promise<PlatformIdentityIds | null> {
65
- const url = `${baseUrl.replace(/\/+$/, "")}${PLATFORM_IDENTITY_VALIDATE_PATH}`;
66
- try {
67
- const res = await fetch(url, {
68
- method: "POST",
69
- headers: {
70
- Authorization: `Api-Key ${apiKey}`,
71
- "Content-Type": "application/json",
72
- },
73
- body: "{}",
74
- signal: AbortSignal.timeout(VALIDATE_TIMEOUT_MS),
75
- });
76
- if (!res.ok) {
77
- log.warn(
78
- { status: res.status },
79
- "platform identity validate returned non-2xx",
80
- );
81
- return null;
82
- }
83
- const body: unknown = await res.json();
84
- if (!body || typeof body !== "object") {
85
- return null;
86
- }
87
- const obj = body as Record<string, unknown>;
88
- const assistantId = asNonEmptyString(obj.assistant_id);
89
- const organizationId = asNonEmptyString(obj.organization_id);
90
- const userId = asNonEmptyString(obj.user_id);
91
- if (!assistantId && !organizationId && !userId) {
92
- return null;
93
- }
94
- return {
95
- assistantId: assistantId ?? "",
96
- organizationId: organizationId ?? "",
97
- userId: userId ?? "",
98
- };
99
- } catch (err) {
100
- log.warn({ err }, "platform identity validate failed");
101
- return null;
102
- }
103
- }
104
-
105
- async function readVaultField(field: string): Promise<string> {
106
- try {
107
- return (
108
- (await getSecureKeyAsync(credentialKey("vellum", field)))?.trim() ?? ""
109
- );
110
- } catch (err) {
111
- log.warn(
112
- { err, field },
113
- "failed to read platform identity from credential store",
114
- );
115
- return "";
116
- }
117
- }
118
-
119
- export async function resolvePlatformAssistantId(): Promise<string> {
120
- return (
121
- getPlatformAssistantId().trim() ||
122
- (await readVaultField("platform_assistant_id"))
123
- );
124
- }
125
-
126
- export async function resolvePlatformAssistantIdOrNull(): Promise<
127
- string | null
128
- > {
129
- const id = await resolvePlatformAssistantId();
130
- return id || null;
131
- }
132
-
133
- export async function resolvePlatformOrganizationId(): Promise<string> {
134
- return (
135
- getPlatformOrganizationId().trim() ||
136
- (await readVaultField("platform_organization_id"))
137
- );
138
- }
139
-
140
- export async function resolvePlatformUserId(): Promise<string> {
141
- return (
142
- getPlatformUserId().trim() || (await readVaultField("platform_user_id"))
143
- );
144
- }
@@ -1,148 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
-
3
- import { VoiceConfigSchema, VoiceFrontModelConfigSchema } from "../voice.js";
4
-
5
- const PROGRESS_DEFAULTS = {
6
- enabled: true,
7
- opsThreshold: 3,
8
- idleIntervalMs: 5_000,
9
- maxSilenceMs: 35_000,
10
- longOpMs: 15_000,
11
- minGapMs: 6_000,
12
- generationTimeoutMs: 1_500,
13
- };
14
-
15
- const FRONT_MODEL_DEFAULTS = {
16
- endpointDecisionTimeoutMs: 1200,
17
- endpointExtensionMs: 1500,
18
- endpointMaxExtensions: 2,
19
- progress: PROGRESS_DEFAULTS,
20
- };
21
-
22
- describe("VoiceFrontModelConfigSchema", () => {
23
- test("empty object parses to defaults", () => {
24
- const parsed = VoiceFrontModelConfigSchema.parse({});
25
- expect(parsed).toEqual(FRONT_MODEL_DEFAULTS);
26
- });
27
-
28
- test("accepts overrides", () => {
29
- const parsed = VoiceFrontModelConfigSchema.parse({
30
- endpointDecisionTimeoutMs: 400,
31
- endpointMaxExtensions: 0,
32
- });
33
- expect(parsed.endpointDecisionTimeoutMs).toBe(400);
34
- expect(parsed.endpointMaxExtensions).toBe(0);
35
- // Unspecified fields still get defaults
36
- expect(parsed.endpointExtensionMs).toBe(1500);
37
- });
38
-
39
- test("strips retired generated-ack settings", () => {
40
- const parsed = VoiceFrontModelConfigSchema.parse({
41
- ackFirstDeltaTimeoutMs: 2500,
42
- ackGenerationTimeoutMs: 600,
43
- });
44
- expect(parsed).not.toHaveProperty("ackFirstDeltaTimeoutMs");
45
- expect(parsed).not.toHaveProperty("ackGenerationTimeoutMs");
46
- });
47
-
48
- test("rejects non-positive endpointDecisionTimeoutMs", () => {
49
- const result = VoiceFrontModelConfigSchema.safeParse({
50
- endpointDecisionTimeoutMs: 0,
51
- });
52
- expect(result.success).toBe(false);
53
- });
54
-
55
- test("rejects negative endpointMaxExtensions", () => {
56
- const result = VoiceFrontModelConfigSchema.safeParse({
57
- endpointMaxExtensions: -1,
58
- });
59
- expect(result.success).toBe(false);
60
- });
61
-
62
- test("absent progress namespace parses to full progress defaults", () => {
63
- const parsed = VoiceFrontModelConfigSchema.parse({});
64
- expect(parsed.progress).toEqual(PROGRESS_DEFAULTS);
65
- });
66
-
67
- test("partial progress overrides merge with defaults", () => {
68
- const parsed = VoiceFrontModelConfigSchema.parse({
69
- progress: { enabled: false, opsThreshold: 5 },
70
- });
71
- expect(parsed.progress.enabled).toBe(false);
72
- expect(parsed.progress.opsThreshold).toBe(5);
73
- // Unspecified progress fields still get defaults
74
- expect(parsed.progress.idleIntervalMs).toBe(5_000);
75
- expect(parsed.progress.maxSilenceMs).toBe(35_000);
76
- expect(parsed.progress.longOpMs).toBe(15_000);
77
- expect(parsed.progress.minGapMs).toBe(6_000);
78
- expect(parsed.progress.generationTimeoutMs).toBe(1_500);
79
- });
80
-
81
- test("a stale maxPerTurn key is stripped, not rejected", () => {
82
- // The cap was removed; configs written while it existed must still parse.
83
- const parsed = VoiceFrontModelConfigSchema.parse({
84
- progress: { maxPerTurn: 3 },
85
- });
86
- expect("maxPerTurn" in parsed.progress).toBe(false);
87
- });
88
-
89
- test("rejects non-positive progress.opsThreshold", () => {
90
- const result = VoiceFrontModelConfigSchema.safeParse({
91
- progress: { opsThreshold: 0 },
92
- });
93
- expect(result.success).toBe(false);
94
- });
95
-
96
- test("rejects a heartbeat ceiling shorter than the idle tick interval", () => {
97
- // The heartbeat is only checked on the idle tick, so a shorter ceiling
98
- // could be overshot by a full interval.
99
- const result = VoiceFrontModelConfigSchema.safeParse({
100
- progress: { idleIntervalMs: 60_000, maxSilenceMs: 10_000 },
101
- });
102
- expect(result.success).toBe(false);
103
- if (!result.success) {
104
- const msgs = result.error.issues.map((issue) => issue.message);
105
- expect(
106
- msgs.some((msg) =>
107
- msg.includes("voice.frontModel.progress.maxSilenceMs"),
108
- ),
109
- ).toBe(true);
110
- }
111
- // The floor itself is allowed: the tick is exactly on the ceiling.
112
- expect(
113
- VoiceFrontModelConfigSchema.safeParse({
114
- progress: { idleIntervalMs: 60_000, maxSilenceMs: 60_000 },
115
- }).success,
116
- ).toBe(true);
117
- });
118
-
119
- test("rejects a non-boolean progress.enabled", () => {
120
- const result = VoiceFrontModelConfigSchema.safeParse({
121
- progress: { enabled: "yes" },
122
- });
123
- expect(result.success).toBe(false);
124
- if (!result.success) {
125
- const msgs = result.error.issues.map((i) => i.message);
126
- expect(
127
- msgs.some((m) => m.includes("voice.frontModel.progress.enabled")),
128
- ).toBe(true);
129
- }
130
- });
131
- });
132
-
133
- describe("VoiceConfigSchema", () => {
134
- test("empty object parses to front-model defaults", () => {
135
- expect(VoiceConfigSchema.parse({})).toEqual({
136
- frontModel: FRONT_MODEL_DEFAULTS,
137
- });
138
- });
139
-
140
- test("partial frontModel overrides merge with defaults", () => {
141
- const parsed = VoiceConfigSchema.parse({
142
- frontModel: { endpointDecisionTimeoutMs: 300 },
143
- });
144
- expect(parsed.frontModel.endpointDecisionTimeoutMs).toBe(300);
145
- expect(parsed.frontModel.endpointExtensionMs).toBe(1500);
146
- expect(parsed.frontModel.progress).toEqual(PROGRESS_DEFAULTS);
147
- });
148
- });
@@ -1,150 +0,0 @@
1
- import { z } from "zod";
2
-
3
- export const VoiceProgressConfigSchema = z
4
- .object({
5
- enabled: z
6
- .boolean({
7
- error: "voice.frontModel.progress.enabled must be a boolean",
8
- })
9
- .default(true)
10
- .describe(
11
- "Speak short progress updates during long-running tool-heavy turns; the opt-out for progress narration",
12
- ),
13
- opsThreshold: z
14
- .number({
15
- error: "voice.frontModel.progress.opsThreshold must be a number",
16
- })
17
- .int("voice.frontModel.progress.opsThreshold must be an integer")
18
- .positive(
19
- "voice.frontModel.progress.opsThreshold must be a positive integer",
20
- )
21
- .default(3)
22
- .describe(
23
- "Narrate after this many tool operations since the last narration",
24
- ),
25
- idleIntervalMs: z
26
- .number({
27
- error: "voice.frontModel.progress.idleIntervalMs must be a number",
28
- })
29
- .int("voice.frontModel.progress.idleIntervalMs must be an integer")
30
- .positive(
31
- "voice.frontModel.progress.idleIntervalMs must be a positive integer",
32
- )
33
- .default(5_000)
34
- .describe(
35
- "How often (ms) a running turn's silence is checked, and so the soonest new tool activity is narrated",
36
- ),
37
- maxSilenceMs: z
38
- .number({
39
- error: "voice.frontModel.progress.maxSilenceMs must be a number",
40
- })
41
- .int("voice.frontModel.progress.maxSilenceMs must be an integer")
42
- .positive(
43
- "voice.frontModel.progress.maxSilenceMs must be a positive integer",
44
- )
45
- .default(35_000)
46
- .describe(
47
- "Heartbeat ceiling (ms): narrate after this much unbroken silence even when nothing new has happened. Evaluated on the idle tick, so its resolution is idleIntervalMs and it must be at least that long",
48
- ),
49
- longOpMs: z
50
- .number({
51
- error: "voice.frontModel.progress.longOpMs must be a number",
52
- })
53
- .int("voice.frontModel.progress.longOpMs must be an integer")
54
- .positive("voice.frontModel.progress.longOpMs must be a positive integer")
55
- .default(15_000)
56
- .describe(
57
- "A tool operation that ran at least this long (ms) narrates the moment it completes, without waiting for opsThreshold",
58
- ),
59
- minGapMs: z
60
- .number({
61
- error: "voice.frontModel.progress.minGapMs must be a number",
62
- })
63
- .int("voice.frontModel.progress.minGapMs must be an integer")
64
- .positive("voice.frontModel.progress.minGapMs must be a positive integer")
65
- .default(6_000)
66
- .describe(
67
- "Minimum spacing (ms) from any spoken floor-holder (ack or narration)",
68
- ),
69
- generationTimeoutMs: z
70
- .number({
71
- error: "voice.frontModel.progress.generationTimeoutMs must be a number",
72
- })
73
- .int("voice.frontModel.progress.generationTimeoutMs must be an integer")
74
- .positive(
75
- "voice.frontModel.progress.generationTimeoutMs must be a positive integer",
76
- )
77
- .default(1_500)
78
- .describe(
79
- "Budget (ms) for LLM-generated progress text. Not latency-critical: it speaks into dead air",
80
- ),
81
- })
82
- // The heartbeat is checked when the idle tick finds the turn silent, so a
83
- // ceiling shorter than the tick interval would be missed by up to a full
84
- // interval, a promise the cadence cannot keep. Rejecting the combination
85
- // beats silently overshooting it.
86
- .refine((progress) => progress.maxSilenceMs >= progress.idleIntervalMs, {
87
- error:
88
- "voice.frontModel.progress.maxSilenceMs must be at least idleIntervalMs: the heartbeat is evaluated on the idle tick",
89
- })
90
- .describe(
91
- "Progress-narration tuning for live voice sessions (spoken updates during long-running turns)",
92
- );
93
-
94
- export const VoiceFrontModelConfigSchema = z
95
- .object({
96
- endpointDecisionTimeoutMs: z
97
- .number({
98
- error: "voice.frontModel.endpointDecisionTimeoutMs must be a number",
99
- })
100
- .int("voice.frontModel.endpointDecisionTimeoutMs must be an integer")
101
- .positive(
102
- "voice.frontModel.endpointDecisionTimeoutMs must be a positive integer",
103
- )
104
- .default(1200)
105
- .describe(
106
- "Hard budget (ms) for the endpoint decision LLM call. This adds to end-of-turn latency when semantic endpointing is on, so keep it as tight as the decider model's real roundtrip allows. Measured Haiku roundtrips through the managed proxy run ~670-1130ms (dev), so tighter budgets turn the feature into a fail-open no-op.",
107
- ),
108
- endpointExtensionMs: z
109
- .number({
110
- error: "voice.frontModel.endpointExtensionMs must be a number",
111
- })
112
- .int("voice.frontModel.endpointExtensionMs must be an integer")
113
- .positive(
114
- "voice.frontModel.endpointExtensionMs must be a positive integer",
115
- )
116
- .default(1500)
117
- .describe(
118
- "How long (ms) a 'hold' decision keeps the turn open before turn-end replays",
119
- ),
120
- endpointMaxExtensions: z
121
- .number({
122
- error: "voice.frontModel.endpointMaxExtensions must be a number",
123
- })
124
- .int("voice.frontModel.endpointMaxExtensions must be an integer")
125
- .nonnegative(
126
- "voice.frontModel.endpointMaxExtensions must be a nonnegative integer",
127
- )
128
- .default(2)
129
- .describe("Cap on consecutive 'hold' extensions per utterance"),
130
- progress: VoiceProgressConfigSchema.default(
131
- VoiceProgressConfigSchema.parse({}),
132
- ),
133
- })
134
- .describe(
135
- "Voice front-door endpointing and long-turn progress narration tuning, shared by live voice and phone calls",
136
- );
137
-
138
- export const VoiceConfigSchema = z
139
- .object({
140
- frontModel: VoiceFrontModelConfigSchema.default(
141
- VoiceFrontModelConfigSchema.parse({}),
142
- ),
143
- })
144
- .describe(
145
- "Transport-agnostic voice configuration shared by live voice and phone calls: front-door routing and progress narration tuning",
146
- );
147
-
148
- export type VoiceConfig = z.infer<typeof VoiceConfigSchema>;
149
- export type VoiceFrontModelConfig = z.infer<typeof VoiceFrontModelConfigSchema>;
150
- export type VoiceProgressConfig = z.infer<typeof VoiceProgressConfigSchema>;