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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. package/AGENTS.md +0 -4
  2. package/ARCHITECTURE.md +12 -11
  3. package/docs/architecture/turn-actor.md +8 -15
  4. package/docs/guardian-request-flow.md +0 -16
  5. package/openapi.yaml +49 -291
  6. package/package.json +1 -1
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  8. package/src/__tests__/app-compiler.test.ts +0 -6
  9. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  10. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  11. package/src/__tests__/app-source-watcher.test.ts +218 -0
  12. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  13. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  14. package/src/__tests__/computer-use-tools.test.ts +5 -17
  15. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  16. package/src/__tests__/config-schema.test.ts +29 -28
  17. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  18. package/src/__tests__/config-watcher.test.ts +8 -23
  19. package/src/__tests__/connection-model-compat.test.ts +2 -2
  20. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  21. package/src/__tests__/conversation-pairing.test.ts +0 -26
  22. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  23. package/src/__tests__/conversation-queue.test.ts +207 -48
  24. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  25. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  26. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  27. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  28. package/src/__tests__/conversation-title-service.test.ts +10 -14
  29. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  30. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  31. package/src/__tests__/credential-record-retire.test.ts +1 -171
  32. package/src/__tests__/credential-routes.test.ts +3 -212
  33. package/src/__tests__/credential-security-invariants.test.ts +2 -4
  34. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  35. package/src/__tests__/document-sync-tags.test.ts +0 -25
  36. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  37. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  38. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  39. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  40. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  41. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  42. package/src/__tests__/host-file-proxy.test.ts +23 -11
  43. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  44. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  45. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  46. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  47. package/src/__tests__/mcp-health-check.test.ts +11 -8
  48. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  49. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  51. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  52. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  53. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  54. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  55. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  56. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  57. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  58. package/src/__tests__/model-intents.test.ts +0 -3
  59. package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
  60. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  61. package/src/__tests__/platform-callback-registration.test.ts +16 -8
  62. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  63. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  64. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  66. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  67. package/src/__tests__/speaker-identification.test.ts +56 -0
  68. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  69. package/src/__tests__/subagent-tools.test.ts +2 -3
  70. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  71. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  72. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  73. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  74. package/src/__tests__/workspace-git-service.test.ts +0 -26
  75. package/src/acp/__tests__/agent-process.test.ts +4 -258
  76. package/src/acp/__tests__/auth-required.test.ts +0 -96
  77. package/src/acp/__tests__/client-handler.test.ts +2 -90
  78. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  79. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  80. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  81. package/src/acp/__tests__/session-manager.test.ts +4 -895
  82. package/src/acp/agent-process.test.ts +1 -4
  83. package/src/acp/agent-process.ts +9 -94
  84. package/src/acp/auth-required.ts +1 -50
  85. package/src/acp/auto-install.test.ts +7 -9
  86. package/src/acp/client-handler.ts +3 -16
  87. package/src/acp/resolve-agent.test.ts +6 -220
  88. package/src/acp/resolve-agent.ts +23 -88
  89. package/src/acp/session-manager.test.ts +3 -196
  90. package/src/acp/session-manager.ts +18 -441
  91. package/src/acp/types.ts +5 -50
  92. package/src/api/events/app-files-changed.ts +3 -4
  93. package/src/api/events/notification-intent.ts +0 -2
  94. package/src/api/index.ts +0 -6
  95. package/src/apps/app-store.ts +1 -1
  96. package/src/bundler/app-compiler.ts +0 -15
  97. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  98. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  99. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  100. package/src/calls/call-constants.ts +4 -24
  101. package/src/calls/call-controller.ts +199 -499
  102. package/src/calls/call-transport.ts +0 -16
  103. package/src/calls/media-stream-output.ts +0 -32
  104. package/src/calls/media-stream-server.ts +30 -82
  105. package/src/calls/media-stream-stt-session.ts +0 -15
  106. package/src/calls/resolve-call-tts-provider.ts +2 -33
  107. package/src/calls/speaker-identification.ts +233 -0
  108. package/src/calls/tts-call-strategy.ts +5 -9
  109. package/src/calls/types.ts +0 -2
  110. package/src/calls/voice-control-protocol.ts +21 -53
  111. package/src/calls/voice-session-bridge.ts +46 -59
  112. package/src/calls/voice-triage-escalate.ts +56 -175
  113. package/src/cli/commands/apps.help.ts +13 -67
  114. package/src/cli/commands/apps.ts +0 -183
  115. package/src/cli/commands/bash.help.ts +13 -8
  116. package/src/cli/commands/bash.ts +25 -7
  117. package/src/cli/commands/channels/index.help.ts +2 -70
  118. package/src/cli/commands/channels/index.ts +3 -16
  119. package/src/cli/commands/credentials.help.ts +2 -6
  120. package/src/cli/commands/credentials.ts +2 -2
  121. package/src/cli/commands/mcp.help.ts +8 -8
  122. package/src/cli/commands/mcp.ts +1 -1
  123. package/src/cli/commands/roadmap.help.ts +1 -5
  124. package/src/cli/commands/roadmap.ts +1 -1
  125. package/src/cli/lib/bundled-marketplace.json +90 -103
  126. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  127. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  128. package/src/config/__tests__/platform-rehydration.test.ts +9 -99
  129. package/src/config/acp-defaults.test.ts +3 -13
  130. package/src/config/acp-defaults.ts +6 -23
  131. package/src/config/acp-schema.ts +2 -30
  132. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  133. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  134. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  135. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  136. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  137. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  138. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  139. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  140. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  141. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  142. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  143. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  144. package/src/config/default-profile-catalog.ts +1 -1
  145. package/src/config/env.ts +2 -2
  146. package/src/config/feature-flag-registry.json +12 -24
  147. package/src/config/loader.ts +0 -1
  148. package/src/config/memory-v3-gate.test.ts +0 -31
  149. package/src/config/memory-v3-gate.ts +16 -20
  150. package/src/config/platform-rehydration.ts +27 -11
  151. package/src/config/schema.ts +2 -2
  152. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  153. package/src/config/schemas/calls.ts +28 -1
  154. package/src/config/schemas/live-voice.ts +173 -1
  155. package/src/config/schemas/mcp.ts +1 -1
  156. package/src/config/schemas/memory-retrospective.ts +0 -10
  157. package/src/config/schemas/services.ts +0 -8
  158. package/src/config/schemas/skills.ts +14 -0
  159. package/src/credential-execution/process-manager.test.ts +19 -18
  160. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  161. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  162. package/src/daemon/app-source-watcher.ts +218 -0
  163. package/src/daemon/config-watcher.ts +194 -13
  164. package/src/daemon/conversation-process.ts +64 -35
  165. package/src/daemon/conversation-skill-tools.ts +31 -13
  166. package/src/daemon/conversation-store.ts +1 -1
  167. package/src/daemon/conversation-surfaces.ts +8 -10
  168. package/src/daemon/conversation-tool-setup.ts +43 -37
  169. package/src/daemon/conversation.ts +3 -0
  170. package/src/daemon/host-bash-proxy.ts +12 -8
  171. package/src/daemon/host-browser-proxy.ts +1 -15
  172. package/src/daemon/host-file-proxy.ts +10 -8
  173. package/src/daemon/host-transfer-proxy.ts +18 -14
  174. package/src/daemon/lifecycle.ts +5 -0
  175. package/src/daemon/mcp-reload-service.ts +5 -5
  176. package/src/daemon/message-types/sync.ts +0 -1
  177. package/src/daemon/orphan-reaper.ts +1 -1
  178. package/src/daemon/providers-setup.ts +1 -1
  179. package/src/daemon/shutdown-handlers.ts +9 -1
  180. package/src/daemon/skill-memory-refresh.ts +0 -64
  181. package/src/daemon/tool-side-effects.ts +18 -7
  182. package/src/home/__tests__/feed-writer.test.ts +0 -22
  183. package/src/home/feed-writer.ts +2 -11
  184. package/src/hooks/types.ts +0 -33
  185. package/src/inbound/platform-callback-registration.ts +5 -4
  186. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  187. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  188. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  189. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  190. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  191. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  192. package/src/live-voice/live-voice-session.ts +693 -213
  193. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  194. package/src/live-voice/protocol.ts +2 -0
  195. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  196. package/src/mcp/effective-config.ts +3 -3
  197. package/src/mcp/mcp-header-store.ts +45 -29
  198. package/src/mcp/startup.ts +4 -8
  199. package/src/messaging/provider.ts +3 -10
  200. package/src/messaging/providers/callback-routing.ts +0 -18
  201. package/src/messaging/providers/channel-transport.ts +0 -56
  202. package/src/messaging/providers/discord/transport.ts +0 -17
  203. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  204. package/src/messaging/providers/slack/adapter.ts +44 -7
  205. package/src/messaging/providers/slack/transport.ts +0 -16
  206. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  207. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  208. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  209. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  210. package/src/messaging/providers/whatsapp/client.ts +29 -0
  211. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  212. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  213. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  214. package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
  215. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  216. package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
  217. package/src/notifications/adapters/macos.ts +0 -3
  218. package/src/notifications/assistant-reply-producer.ts +3 -8
  219. package/src/notifications/conversation-pairing.ts +16 -36
  220. package/src/notifications/delivered-post-record.ts +1 -11
  221. package/src/notifications/guardian-feed-projection.ts +5 -125
  222. package/src/notifications/home-feed-side-effect.ts +7 -55
  223. package/src/notifications/schedule-result-producer.ts +22 -66
  224. package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
  225. package/src/oauth/byo-connection.test.ts +0 -45
  226. package/src/oauth/byo-connection.ts +6 -36
  227. package/src/oauth/connection-resolver.test.ts +0 -73
  228. package/src/oauth/connection-resolver.ts +2 -95
  229. package/src/oauth/seed-providers.ts +0 -165
  230. package/src/outbound-proxy/certs.ts +5 -3
  231. package/src/permissions/checker.test.ts +6 -11
  232. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  233. package/src/persistence/conversation-crud.ts +63 -71
  234. package/src/persistence/conversation-lineage.ts +4 -12
  235. package/src/persistence/conversation-title-service.ts +26 -9
  236. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  237. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  238. package/src/persistence/message-reads.ts +0 -30
  239. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  240. package/src/persistence/schema/memory-core.ts +0 -5
  241. package/src/platform/client.test.ts +2 -4
  242. package/src/platform/client.ts +10 -2
  243. package/src/plugin-api/constants.ts +0 -2
  244. package/src/plugin-api/index.ts +0 -1
  245. package/src/plugin-api/types.ts +0 -2
  246. package/src/plugins/defaults/index.ts +0 -2
  247. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  248. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  249. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  250. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  251. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  252. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  253. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  254. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  255. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  256. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  257. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  258. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  259. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  260. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  261. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  262. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  263. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  264. package/src/plugins/defaults/memory/startup.ts +1 -6
  265. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  266. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  267. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  268. package/src/plugins/defaults/memory/worker.ts +0 -6
  269. package/src/plugins/mcp-servers.ts +75 -15
  270. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  271. package/src/providers/gemini/client.ts +23 -9
  272. package/src/providers/inference/auth.ts +3 -2
  273. package/src/providers/inference/connection-availability.ts +8 -27
  274. package/src/providers/inference/resolve-auth.ts +4 -22
  275. package/src/providers/model-catalog.ts +0 -34
  276. package/src/providers/model-intents.ts +5 -10
  277. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  278. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  279. package/src/providers/openai/chat-completions-provider.ts +78 -192
  280. package/src/providers/openai/codex-models.ts +4 -0
  281. package/src/runtime/AGENTS.md +0 -2
  282. package/src/runtime/auth/same-actor.ts +3 -38
  283. package/src/runtime/http-server.ts +151 -160
  284. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  286. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  287. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  288. package/src/runtime/routes/acp-routes.test.ts +0 -15
  289. package/src/runtime/routes/acp-routes.ts +9 -72
  290. package/src/runtime/routes/app-management-routes.ts +0 -73
  291. package/src/runtime/routes/app-routes.ts +1 -1
  292. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  293. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  294. package/src/runtime/routes/credential-routes.ts +10 -19
  295. package/src/runtime/routes/debug-bash-routes.ts +173 -0
  296. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  297. package/src/runtime/routes/index.ts +2 -4
  298. package/src/runtime/routes/log-export-routes.ts +0 -2
  299. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  300. package/src/runtime/routes/migration-routes.ts +20 -6
  301. package/src/runtime/routes/platform-routes.ts +15 -18
  302. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  303. package/src/runtime/services/conversation-serializer.ts +3 -16
  304. package/src/runtime/sync/resource-sync-events.ts +1 -2
  305. package/src/schedule/worker.ts +1 -1
  306. package/src/security/ces-rpc-record-backend.ts +0 -7
  307. package/src/subagent/consult-context.ts +25 -12
  308. package/src/tools/acp/list-agents.test.ts +1 -3
  309. package/src/tools/acp/spawn.test.ts +11 -146
  310. package/src/tools/acp/spawn.ts +3 -21
  311. package/src/tools/acp/status.ts +3 -40
  312. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  313. package/src/tools/capability-offer.test.ts +2 -22
  314. package/src/tools/capability-offer.ts +1 -16
  315. package/src/tools/computer-use/definitions.ts +2 -4
  316. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  317. package/src/tools/credentials/metadata-store.ts +0 -100
  318. package/src/tools/host-filesystem/edit.test.ts +1 -2
  319. package/src/tools/host-filesystem/edit.ts +2 -2
  320. package/src/tools/host-filesystem/read.test.ts +1 -2
  321. package/src/tools/host-filesystem/read.ts +2 -2
  322. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  323. package/src/tools/host-filesystem/transfer.ts +2 -2
  324. package/src/tools/host-filesystem/write.test.ts +1 -2
  325. package/src/tools/host-filesystem/write.ts +2 -2
  326. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  327. package/src/tools/host-terminal/host-shell.ts +20 -4
  328. package/src/tools/policy-context.ts +7 -6
  329. package/src/tools/subagent/spawn.ts +8 -5
  330. package/src/tools/watch/watch-retro-report.ts +8 -0
  331. package/src/util/__tests__/language-subtag.test.ts +1 -23
  332. package/src/util/fs-watcher-error.ts +36 -0
  333. package/src/util/language-subtag.ts +0 -16
  334. package/src/util/platform.ts +0 -8
  335. package/src/workspace/git-service.ts +54 -5
  336. package/src/workspace/migrations/registry.ts +0 -6
  337. package/scripts/smoke-desktop-window-theme.ts +0 -186
  338. package/src/__tests__/git-porcelain.test.ts +0 -47
  339. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  340. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  341. package/src/__tests__/resolve-app.test.ts +0 -135
  342. package/src/__tests__/service-account-token.test.ts +0 -247
  343. package/src/__tests__/source-fingerprint.test.ts +0 -184
  344. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  345. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  346. package/src/acp/model-config.test.ts +0 -166
  347. package/src/acp/model-config.ts +0 -138
  348. package/src/api/events/acp-session-model-update.test.ts +0 -88
  349. package/src/api/events/acp-session-model-update.ts +0 -46
  350. package/src/apps/resolve-app.ts +0 -81
  351. package/src/apps/source-fingerprint.ts +0 -266
  352. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  353. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  354. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  355. package/src/calls/barge-in-guard.ts +0 -118
  356. package/src/calls/voice-leg-coordinator.ts +0 -189
  357. package/src/calls/voice-progress-cadence.ts +0 -423
  358. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  359. package/src/cli/commands/__tests__/bash.test.ts +0 -53
  360. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  361. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  362. package/src/cli/commands/channels/send.ts +0 -128
  363. package/src/config/__tests__/platform-identity.test.ts +0 -255
  364. package/src/config/acp-agent-write.ts +0 -43
  365. package/src/config/acp-schema.test.ts +0 -81
  366. package/src/config/platform-identity.ts +0 -201
  367. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  368. package/src/config/schemas/voice.ts +0 -150
  369. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  370. package/src/daemon/app-change-notify.ts +0 -45
  371. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  372. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  373. package/src/desktop/desktop-chrome-policy.ts +0 -42
  374. package/src/desktop/desktop-dependencies.test.ts +0 -102
  375. package/src/desktop/desktop-dependencies.ts +0 -306
  376. package/src/desktop/desktop-feature.test.ts +0 -18
  377. package/src/desktop/desktop-feature.ts +0 -19
  378. package/src/desktop/desktop-panel-config.test.ts +0 -135
  379. package/src/desktop/desktop-panel-config.ts +0 -149
  380. package/src/desktop/desktop-session-manager.test.ts +0 -627
  381. package/src/desktop/desktop-session-manager.ts +0 -814
  382. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  383. package/src/desktop/desktop-stream-bridge.ts +0 -214
  384. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  385. package/src/desktop/desktop-wallpaper.ts +0 -113
  386. package/src/desktop/desktop-window-theme.ts +0 -170
  387. package/src/i18n/AGENTS.md +0 -22
  388. package/src/i18n/__tests__/i18n.test.ts +0 -108
  389. package/src/i18n/index.ts +0 -16
  390. package/src/i18n/locales.ts +0 -93
  391. package/src/i18n/messages.ts +0 -61
  392. package/src/i18n/title.ts +0 -25
  393. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  394. package/src/mcp/spec-schema.ts +0 -111
  395. package/src/mcp/workspace-mcp-config.ts +0 -188
  396. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  397. package/src/persistence/conversation-title-placeholders.ts +0 -23
  398. package/src/persistence/message-cursor.ts +0 -78
  399. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  400. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  401. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  402. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  403. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  404. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  405. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  406. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  407. package/src/providers/gemini-thought-signature.test.ts +0 -63
  408. package/src/providers/gemini-thought-signature.ts +0 -44
  409. package/src/providers/inference/service-account-token.ts +0 -248
  410. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  411. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  412. package/src/providers/openai/google-thought-signature.ts +0 -320
  413. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  414. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  415. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  416. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  417. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  418. package/src/runtime/channel-send.ts +0 -316
  419. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  420. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  421. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  422. package/src/runtime/routes/channel-send-routes.ts +0 -85
  423. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  424. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  425. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  426. package/src/security/ces-http-record-backend.ts +0 -120
  427. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  428. package/src/skills/workspace-skill-md-signature.ts +0 -50
  429. package/src/tools/acp/status.test.ts +0 -94
  430. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
  431. package/src/tools/terminal/sanitized-bash.ts +0 -105
  432. package/src/util/ca-bundle.ts +0 -13
  433. package/src/workspace/git-porcelain.ts +0 -66
  434. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  435. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  436. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  437. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  438. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  439. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -3,9 +3,28 @@ import { describe, expect, test } from "bun:test";
3
3
  import {
4
4
  LiveVoiceConfigSchema,
5
5
  LiveVoiceFluxConfigSchema,
6
+ LiveVoiceFrontModelConfigSchema,
6
7
  LiveVoiceVadConfigSchema,
8
+ VALID_LIVE_VOICE_MODES,
7
9
  } from "../live-voice.js";
8
10
 
11
+ const PROGRESS_DEFAULTS = {
12
+ enabled: true,
13
+ opsThreshold: 3,
14
+ idleIntervalMs: 5_000,
15
+ maxSilenceMs: 35_000,
16
+ longOpMs: 15_000,
17
+ minGapMs: 6_000,
18
+ generationTimeoutMs: 1_500,
19
+ };
20
+
21
+ const FRONT_MODEL_DEFAULTS = {
22
+ endpointDecisionTimeoutMs: 1200,
23
+ endpointExtensionMs: 1500,
24
+ endpointMaxExtensions: 2,
25
+ progress: PROGRESS_DEFAULTS,
26
+ };
27
+
9
28
  // `eagerEotThreshold` is deliberately absent: it has no default, and leaving it
10
29
  // unset is what keeps Deepgram from emitting speculative turn events. `model`
11
30
  // is absent for a related reason: unset means the spoken language selects the
@@ -111,6 +130,117 @@ describe("LiveVoiceVadConfigSchema", () => {
111
130
  });
112
131
  });
113
132
 
133
+ describe("LiveVoiceFrontModelConfigSchema", () => {
134
+ test("empty object parses to defaults", () => {
135
+ const parsed = LiveVoiceFrontModelConfigSchema.parse({});
136
+ expect(parsed).toEqual(FRONT_MODEL_DEFAULTS);
137
+ });
138
+
139
+ test("accepts overrides", () => {
140
+ const parsed = LiveVoiceFrontModelConfigSchema.parse({
141
+ endpointDecisionTimeoutMs: 400,
142
+ endpointMaxExtensions: 0,
143
+ });
144
+ expect(parsed.endpointDecisionTimeoutMs).toBe(400);
145
+ expect(parsed.endpointMaxExtensions).toBe(0);
146
+ // Unspecified fields still get defaults
147
+ expect(parsed.endpointExtensionMs).toBe(1500);
148
+ });
149
+
150
+ test("strips retired generated-ack settings", () => {
151
+ const parsed = LiveVoiceFrontModelConfigSchema.parse({
152
+ ackFirstDeltaTimeoutMs: 2500,
153
+ ackGenerationTimeoutMs: 600,
154
+ });
155
+ expect(parsed).not.toHaveProperty("ackFirstDeltaTimeoutMs");
156
+ expect(parsed).not.toHaveProperty("ackGenerationTimeoutMs");
157
+ });
158
+
159
+ test("rejects non-positive endpointDecisionTimeoutMs", () => {
160
+ const result = LiveVoiceFrontModelConfigSchema.safeParse({
161
+ endpointDecisionTimeoutMs: 0,
162
+ });
163
+ expect(result.success).toBe(false);
164
+ });
165
+
166
+ test("rejects negative endpointMaxExtensions", () => {
167
+ const result = LiveVoiceFrontModelConfigSchema.safeParse({
168
+ endpointMaxExtensions: -1,
169
+ });
170
+ expect(result.success).toBe(false);
171
+ });
172
+
173
+ test("absent progress namespace parses to full progress defaults", () => {
174
+ const parsed = LiveVoiceFrontModelConfigSchema.parse({});
175
+ expect(parsed.progress).toEqual(PROGRESS_DEFAULTS);
176
+ });
177
+
178
+ test("partial progress overrides merge with defaults", () => {
179
+ const parsed = LiveVoiceFrontModelConfigSchema.parse({
180
+ progress: { enabled: false, opsThreshold: 5 },
181
+ });
182
+ expect(parsed.progress.enabled).toBe(false);
183
+ expect(parsed.progress.opsThreshold).toBe(5);
184
+ // Unspecified progress fields still get defaults
185
+ expect(parsed.progress.idleIntervalMs).toBe(5_000);
186
+ expect(parsed.progress.maxSilenceMs).toBe(35_000);
187
+ expect(parsed.progress.longOpMs).toBe(15_000);
188
+ expect(parsed.progress.minGapMs).toBe(6_000);
189
+ expect(parsed.progress.generationTimeoutMs).toBe(1_500);
190
+ });
191
+
192
+ test("a stale maxPerTurn key is stripped, not rejected", () => {
193
+ // The cap was removed; configs written while it existed must still parse.
194
+ const parsed = LiveVoiceFrontModelConfigSchema.parse({
195
+ progress: { maxPerTurn: 3 },
196
+ });
197
+ expect("maxPerTurn" in parsed.progress).toBe(false);
198
+ });
199
+
200
+ test("rejects non-positive progress.opsThreshold", () => {
201
+ const result = LiveVoiceFrontModelConfigSchema.safeParse({
202
+ progress: { opsThreshold: 0 },
203
+ });
204
+ expect(result.success).toBe(false);
205
+ });
206
+
207
+ test("rejects a heartbeat ceiling shorter than the idle tick interval", () => {
208
+ // The heartbeat is only checked on the idle tick, so a shorter ceiling
209
+ // could be overshot by a full interval.
210
+ const result = LiveVoiceFrontModelConfigSchema.safeParse({
211
+ progress: { idleIntervalMs: 60_000, maxSilenceMs: 10_000 },
212
+ });
213
+ expect(result.success).toBe(false);
214
+ if (!result.success) {
215
+ const msgs = result.error.issues.map((issue) => issue.message);
216
+ expect(
217
+ msgs.some((msg) =>
218
+ msg.includes("liveVoice.frontModel.progress.maxSilenceMs"),
219
+ ),
220
+ ).toBe(true);
221
+ }
222
+ // The floor itself is allowed: the tick is exactly on the ceiling.
223
+ expect(
224
+ LiveVoiceFrontModelConfigSchema.safeParse({
225
+ progress: { idleIntervalMs: 60_000, maxSilenceMs: 60_000 },
226
+ }).success,
227
+ ).toBe(true);
228
+ });
229
+
230
+ test("rejects a non-boolean progress.enabled", () => {
231
+ const result = LiveVoiceFrontModelConfigSchema.safeParse({
232
+ progress: { enabled: "yes" },
233
+ });
234
+ expect(result.success).toBe(false);
235
+ if (!result.success) {
236
+ const msgs = result.error.issues.map((i) => i.message);
237
+ expect(
238
+ msgs.some((m) => m.includes("liveVoice.frontModel.progress.enabled")),
239
+ ).toBe(true);
240
+ }
241
+ });
242
+ });
243
+
114
244
  describe("LiveVoiceFluxConfigSchema", () => {
115
245
  test("empty object parses to defaults, with turn-end on", () => {
116
246
  expect(LiveVoiceFluxConfigSchema.parse({})).toEqual(FLUX_DEFAULTS);
@@ -196,6 +326,7 @@ describe("LiveVoiceConfigSchema", () => {
196
326
  test("empty object parses to defaults", () => {
197
327
  const parsed = LiveVoiceConfigSchema.parse({});
198
328
  expect(parsed).toEqual({
329
+ mode: "open-mic",
199
330
  vad: {
200
331
  speechEnergyThreshold: 800,
201
332
  noiseFloorMargin: 3,
@@ -206,9 +337,11 @@ describe("LiveVoiceConfigSchema", () => {
206
337
  echoEmaHalfLifeMs: 400,
207
338
  echoDrainSlackMs: 300,
208
339
  },
340
+ frontModel: FRONT_MODEL_DEFAULTS,
209
341
  // Off by default: Flux turn detection is opt-in, so the front-door hold
210
342
  // verdict keeps committing turns until it is enabled.
211
343
  flux: FLUX_DEFAULTS,
344
+ maxSessionDurationSeconds: 1800,
212
345
  // Off by default: voice turns carry only their transcript, no audio
213
346
  // artifacts on the conversation messages (JARVIS-1283).
214
347
  archiveAudio: false,
@@ -232,26 +365,43 @@ describe("LiveVoiceConfigSchema", () => {
232
365
 
233
366
  test("accepts overrides", () => {
234
367
  const parsed = LiveVoiceConfigSchema.parse({
368
+ mode: "ptt",
235
369
  vad: { silenceThresholdMs: 900 },
370
+ frontModel: { endpointDecisionTimeoutMs: 300 },
236
371
  flux: { turnEnd: { enabled: true } },
372
+ maxSessionDurationSeconds: 600,
237
373
  });
374
+ expect(parsed.mode).toBe("ptt");
238
375
  expect(parsed.vad.silenceThresholdMs).toBe(900);
239
376
  // Unspecified vad fields still get defaults
240
377
  expect(parsed.vad.speechEnergyThreshold).toBe(800);
241
378
  expect(parsed.vad.maxTurnDurationMs).toBe(30_000);
379
+ // Partial frontModel overrides merge with defaults
380
+ expect(parsed.frontModel.endpointDecisionTimeoutMs).toBe(300);
381
+ expect(parsed.frontModel.endpointExtensionMs).toBe(1500);
242
382
  // Partial flux overrides merge with defaults
243
383
  expect(parsed.flux.turnEnd.enabled).toBe(true);
244
384
  expect(parsed.flux.eotThreshold).toBe(0.7);
385
+ expect(parsed.maxSessionDurationSeconds).toBe(600);
245
386
  });
246
387
 
247
- test("persisted configs carrying retired keys keep parsing", () => {
248
- // Zod strips unrecognized keys, so a persisted config that still carries
249
- // `mode` or `maxSessionDurationSeconds` parses.
250
- const parsed = LiveVoiceConfigSchema.parse({
251
- mode: "ptt",
252
- maxSessionDurationSeconds: 600,
388
+ test("rejects invalid mode", () => {
389
+ const result = LiveVoiceConfigSchema.safeParse({ mode: "always-on" });
390
+ expect(result.success).toBe(false);
391
+ if (!result.success) {
392
+ const msgs = result.error.issues.map((i) => i.message);
393
+ expect(msgs.some((m) => m.includes("liveVoice.mode"))).toBe(true);
394
+ }
395
+ });
396
+
397
+ test("rejects non-positive maxSessionDurationSeconds", () => {
398
+ const result = LiveVoiceConfigSchema.safeParse({
399
+ maxSessionDurationSeconds: -1,
253
400
  });
254
- expect(parsed).not.toHaveProperty("mode");
255
- expect(parsed).not.toHaveProperty("maxSessionDurationSeconds");
401
+ expect(result.success).toBe(false);
402
+ });
403
+
404
+ test("VALID_LIVE_VOICE_MODES lists ptt and open-mic", () => {
405
+ expect(VALID_LIVE_VOICE_MODES).toEqual(["ptt", "open-mic"]);
256
406
  });
257
407
  });
@@ -26,8 +26,32 @@ const CallsDisclosureConfigSchema = z
26
26
  "Controls whether and how the assistant discloses its nature at the start of a phone call",
27
27
  );
28
28
 
29
+ const CallsSafetyConfigSchema = z
30
+ .object({
31
+ denyCategories: z
32
+ .array(
33
+ z.string({
34
+ error: "calls.safety.denyCategories values must be strings",
35
+ }),
36
+ )
37
+ .default([])
38
+ .describe(
39
+ "Categories of calls that should be denied (e.g. for safety or compliance reasons)",
40
+ ),
41
+ })
42
+ .describe("Safety guardrails for phone calls");
43
+
29
44
  const CallsVoiceConfigSchema = z
30
45
  .object({
46
+ interruptSensitivity: z
47
+ .enum(["low", "medium", "high"], {
48
+ error:
49
+ "calls.voice.interruptSensitivity must be one of: low, medium, high",
50
+ })
51
+ .default("low")
52
+ .describe(
53
+ "How aggressively the STT provider detects the start of caller speech — low reduces false interrupts from background noise",
54
+ ),
31
55
  telephonyStreaming: z
32
56
  .boolean({
33
57
  error: "calls.voice.telephonyStreaming must be a boolean",
@@ -203,6 +227,7 @@ export const CallsConfigSchema = z
203
227
  disclosure: CallsDisclosureConfigSchema.default(
204
228
  CallsDisclosureConfigSchema.parse({}),
205
229
  ),
230
+ safety: CallsSafetyConfigSchema.default(CallsSafetyConfigSchema.parse({})),
206
231
  voice: CallsVoiceConfigSchema.default(CallsVoiceConfigSchema.parse({})),
207
232
  callerIdentity: CallerIdentityConfigSchema.default(
208
233
  CallerIdentityConfigSchema.parse({}),
@@ -211,4 +236,6 @@ export const CallsConfigSchema = z
211
236
  CallsVerificationConfigSchema.parse({}),
212
237
  ),
213
238
  })
214
- .describe("Phone call configuration: telephony, voice, and call behavior");
239
+ .describe(
240
+ "Phone call configuration — controls telephony, voice, safety, and call behavior",
241
+ );
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
 
3
+ export const VALID_LIVE_VOICE_MODES = ["ptt", "open-mic"] as const;
4
+
3
5
  export const LiveVoiceVadConfigSchema = z
4
6
  .object({
5
7
  speechEnergyThreshold: z
@@ -77,6 +79,149 @@ export const LiveVoiceVadConfigSchema = z
77
79
  "Voice-activity-detection tuning for live voice sessions (open-mic turn segmentation)",
78
80
  );
79
81
 
82
+ export const LiveVoiceProgressConfigSchema = z
83
+ .object({
84
+ enabled: z
85
+ .boolean({
86
+ error: "liveVoice.frontModel.progress.enabled must be a boolean",
87
+ })
88
+ .default(true)
89
+ .describe(
90
+ "Speak short progress updates during long-running tool-heavy turns; the opt-out for progress narration",
91
+ ),
92
+ opsThreshold: z
93
+ .number({
94
+ error: "liveVoice.frontModel.progress.opsThreshold must be a number",
95
+ })
96
+ .int("liveVoice.frontModel.progress.opsThreshold must be an integer")
97
+ .positive(
98
+ "liveVoice.frontModel.progress.opsThreshold must be a positive integer",
99
+ )
100
+ .default(3)
101
+ .describe(
102
+ "Narrate after this many tool operations since the last narration",
103
+ ),
104
+ idleIntervalMs: z
105
+ .number({
106
+ error: "liveVoice.frontModel.progress.idleIntervalMs must be a number",
107
+ })
108
+ .int("liveVoice.frontModel.progress.idleIntervalMs must be an integer")
109
+ .positive(
110
+ "liveVoice.frontModel.progress.idleIntervalMs must be a positive integer",
111
+ )
112
+ .default(5_000)
113
+ .describe(
114
+ "How often (ms) a running turn's silence is checked, and so the soonest new tool activity is narrated",
115
+ ),
116
+ maxSilenceMs: z
117
+ .number({
118
+ error: "liveVoice.frontModel.progress.maxSilenceMs must be a number",
119
+ })
120
+ .int("liveVoice.frontModel.progress.maxSilenceMs must be an integer")
121
+ .positive(
122
+ "liveVoice.frontModel.progress.maxSilenceMs must be a positive integer",
123
+ )
124
+ .default(35_000)
125
+ .describe(
126
+ "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",
127
+ ),
128
+ longOpMs: z
129
+ .number({
130
+ error: "liveVoice.frontModel.progress.longOpMs must be a number",
131
+ })
132
+ .int("liveVoice.frontModel.progress.longOpMs must be an integer")
133
+ .positive(
134
+ "liveVoice.frontModel.progress.longOpMs must be a positive integer",
135
+ )
136
+ .default(15_000)
137
+ .describe(
138
+ "A tool operation that ran at least this long (ms) narrates the moment it completes, without waiting for opsThreshold",
139
+ ),
140
+ minGapMs: z
141
+ .number({
142
+ error: "liveVoice.frontModel.progress.minGapMs must be a number",
143
+ })
144
+ .int("liveVoice.frontModel.progress.minGapMs must be an integer")
145
+ .positive(
146
+ "liveVoice.frontModel.progress.minGapMs must be a positive integer",
147
+ )
148
+ .default(6_000)
149
+ .describe(
150
+ "Minimum spacing (ms) from any spoken floor-holder — ack or narration",
151
+ ),
152
+ generationTimeoutMs: z
153
+ .number({
154
+ error:
155
+ "liveVoice.frontModel.progress.generationTimeoutMs must be a number",
156
+ })
157
+ .int(
158
+ "liveVoice.frontModel.progress.generationTimeoutMs must be an integer",
159
+ )
160
+ .positive(
161
+ "liveVoice.frontModel.progress.generationTimeoutMs must be a positive integer",
162
+ )
163
+ .default(1_500)
164
+ .describe(
165
+ "Budget (ms) for LLM-generated progress text — not latency-critical: it speaks into dead air",
166
+ ),
167
+ })
168
+ // The heartbeat is checked when the idle tick finds the turn silent, so a
169
+ // ceiling shorter than the tick interval would be missed by up to a full
170
+ // interval — a promise the cadence cannot keep. Rejecting the combination
171
+ // beats silently overshooting it.
172
+ .refine((progress) => progress.maxSilenceMs >= progress.idleIntervalMs, {
173
+ error:
174
+ "liveVoice.frontModel.progress.maxSilenceMs must be at least idleIntervalMs — the heartbeat is evaluated on the idle tick",
175
+ })
176
+ .describe(
177
+ "Progress-narration tuning for live voice sessions (spoken updates during long-running turns)",
178
+ );
179
+
180
+ export const LiveVoiceFrontModelConfigSchema = z
181
+ .object({
182
+ endpointDecisionTimeoutMs: z
183
+ .number({
184
+ error:
185
+ "liveVoice.frontModel.endpointDecisionTimeoutMs must be a number",
186
+ })
187
+ .int("liveVoice.frontModel.endpointDecisionTimeoutMs must be an integer")
188
+ .positive(
189
+ "liveVoice.frontModel.endpointDecisionTimeoutMs must be a positive integer",
190
+ )
191
+ .default(1200)
192
+ .describe(
193
+ "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.",
194
+ ),
195
+ endpointExtensionMs: z
196
+ .number({
197
+ error: "liveVoice.frontModel.endpointExtensionMs must be a number",
198
+ })
199
+ .int("liveVoice.frontModel.endpointExtensionMs must be an integer")
200
+ .positive(
201
+ "liveVoice.frontModel.endpointExtensionMs must be a positive integer",
202
+ )
203
+ .default(1500)
204
+ .describe(
205
+ "How long (ms) a 'hold' decision keeps the turn open before turn-end replays",
206
+ ),
207
+ endpointMaxExtensions: z
208
+ .number({
209
+ error: "liveVoice.frontModel.endpointMaxExtensions must be a number",
210
+ })
211
+ .int("liveVoice.frontModel.endpointMaxExtensions must be an integer")
212
+ .nonnegative(
213
+ "liveVoice.frontModel.endpointMaxExtensions must be a nonnegative integer",
214
+ )
215
+ .default(2)
216
+ .describe("Cap on consecutive 'hold' extensions per utterance"),
217
+ progress: LiveVoiceProgressConfigSchema.default(
218
+ LiveVoiceProgressConfigSchema.parse({}),
219
+ ),
220
+ })
221
+ .describe(
222
+ "Voice front-door endpointing and long-turn progress narration tuning",
223
+ );
224
+
80
225
  const LiveVoiceFluxTurnEndConfigSchema = z
81
226
  .object({
82
227
  enabled: z
@@ -140,10 +285,31 @@ export const LiveVoiceFluxConfigSchema = z
140
285
 
141
286
  export const LiveVoiceConfigSchema = z
142
287
  .object({
288
+ mode: z
289
+ .enum(VALID_LIVE_VOICE_MODES, {
290
+ error: `liveVoice.mode must be one of: ${VALID_LIVE_VOICE_MODES.join(", ")}`,
291
+ })
292
+ .default("open-mic")
293
+ .describe(
294
+ "Default microphone mode for live voice sessions — hands-free (open-mic) or push-to-talk (ptt)",
295
+ ),
143
296
  vad: LiveVoiceVadConfigSchema.default(LiveVoiceVadConfigSchema.parse({})),
297
+ frontModel: LiveVoiceFrontModelConfigSchema.default(
298
+ LiveVoiceFrontModelConfigSchema.parse({}),
299
+ ),
144
300
  flux: LiveVoiceFluxConfigSchema.default(
145
301
  LiveVoiceFluxConfigSchema.parse({}),
146
302
  ),
303
+ maxSessionDurationSeconds: z
304
+ .number({
305
+ error: "liveVoice.maxSessionDurationSeconds must be a number",
306
+ })
307
+ .int("liveVoice.maxSessionDurationSeconds must be an integer")
308
+ .positive(
309
+ "liveVoice.maxSessionDurationSeconds must be a positive integer",
310
+ )
311
+ .default(1800)
312
+ .describe("Maximum duration of a single live voice session in seconds"),
147
313
  archiveAudio: z
148
314
  .boolean({ error: "liveVoice.archiveAudio must be a boolean" })
149
315
  .default(false)
@@ -152,9 +318,15 @@ export const LiveVoiceConfigSchema = z
152
318
  ),
153
319
  })
154
320
  .describe(
155
- "Live voice (in-app duplex audio) configuration: VAD tuning, Flux turn detection, and audio archiving",
321
+ "Live voice (in-app duplex audio) configuration — mic mode, VAD tuning, and session limits",
156
322
  );
157
323
 
158
324
  export type LiveVoiceConfig = z.infer<typeof LiveVoiceConfigSchema>;
159
325
  export type LiveVoiceVadConfig = z.infer<typeof LiveVoiceVadConfigSchema>;
326
+ export type LiveVoiceFrontModelConfig = z.infer<
327
+ typeof LiveVoiceFrontModelConfigSchema
328
+ >;
329
+ export type LiveVoiceProgressConfig = z.infer<
330
+ typeof LiveVoiceProgressConfigSchema
331
+ >;
160
332
  export type LiveVoiceFluxConfig = z.infer<typeof LiveVoiceFluxConfigSchema>;
@@ -102,7 +102,7 @@ export type McpServerConfig = z.infer<typeof McpServerConfigSchema>;
102
102
  export type McpConfig = z.infer<typeof McpConfigSchema>;
103
103
 
104
104
  /**
105
- * Who declared a server: the workspace `mcp.json`, which the user owns,
105
+ * Who declared a server: the workspace `config.json`, which the user owns,
106
106
  * or a plugin's `mcp.json`, which its author owns.
107
107
  *
108
108
  * Deliberately not a schema field. It is resolved from where the entry was
@@ -9,16 +9,6 @@ export const MemoryRetrospectiveConfigSchema = z
9
9
  "Whether the memory-retrospective background pass runs. When false, no retrospective is enqueued by any trigger (interval, message count, pre-compaction, scheduled sweep), the scheduled sweep job stops being queued, and any row already queued completes as a no-op. The rest of the memory system (extraction, retrieval, embeddings, `<memory>` injection) is unaffected. Use `memory.enabled` to disable memory as a whole.",
10
10
  ),
11
11
 
12
- skillImprovement: z
13
- .boolean({
14
- error:
15
- "memory.retrospective.skillImprovement must be a boolean",
16
- })
17
- .default(true)
18
- .describe(
19
- "Whether retrospectives may discover, refine, and create managed skills from observed procedures. When false, retrospectives still capture ordinary memories through `remember`, but cannot load skill management, search for similar skills, or scaffold managed skills.",
20
- ),
21
-
22
12
  timeThresholdMs: z
23
13
  .number({
24
14
  error: "memory.retrospective.timeThresholdMs must be a number",
@@ -140,11 +140,6 @@ const MondayOAuthServiceSchema = BaseServiceSchema.extend({
140
140
  mode: ServiceModeSchema.default("your-own"),
141
141
  });
142
142
 
143
- export const ShopifyOAuthServiceSchema = BaseServiceSchema.extend({
144
- mode: ServiceModeSchema.default("your-own"),
145
- });
146
- export type ShopifyOAuthService = z.infer<typeof ShopifyOAuthServiceSchema>;
147
-
148
143
  export const StripeLinkOAuthServiceSchema = BaseServiceSchema.extend({
149
144
  mode: ServiceModeSchema.default("your-own"),
150
145
  });
@@ -219,9 +214,6 @@ export const ServicesSchema = z.object({
219
214
  "monday-oauth": MondayOAuthServiceSchema.default(
220
215
  MondayOAuthServiceSchema.parse({}),
221
216
  ),
222
- "shopify-oauth": ShopifyOAuthServiceSchema.default(
223
- ShopifyOAuthServiceSchema.parse({}),
224
- ),
225
217
  "stripe-link-oauth": StripeLinkOAuthServiceSchema.default(
226
218
  StripeLinkOAuthServiceSchema.parse({}),
227
219
  ),
@@ -32,6 +32,20 @@ const SkillsLoadConfigSchema = z
32
32
  )
33
33
  .default([])
34
34
  .describe("Additional directories to search for skill definitions"),
35
+ watch: z
36
+ .boolean({ error: "skills.load.watch must be a boolean" })
37
+ .default(true)
38
+ .describe(
39
+ "Whether to watch skill directories for changes and auto-reload",
40
+ ),
41
+ watchDebounceMs: z
42
+ .number({ error: "skills.load.watchDebounceMs must be a number" })
43
+ .int()
44
+ .positive()
45
+ .default(250)
46
+ .describe(
47
+ "Debounce delay in milliseconds for skill file change detection",
48
+ ),
35
49
  })
36
50
  .describe("Controls how skills are discovered and loaded");
37
51
 
@@ -12,15 +12,8 @@ import {
12
12
  test,
13
13
  } from "bun:test";
14
14
 
15
- import { waitFor } from "../__tests__/helpers/wait-for.js";
16
15
  import { createCesProcessManager } from "./process-manager.js";
17
16
 
18
- const untilClosed = (predicate: () => boolean) =>
19
- waitFor(predicate, {
20
- timeoutMs: 2000,
21
- message: "socket close never propagated to the transport",
22
- });
23
-
24
17
  // ---------------------------------------------------------------------------
25
18
  // onTransportClose tests
26
19
  // ---------------------------------------------------------------------------
@@ -86,7 +79,10 @@ describe("CesProcessManager.onTransportClose", () => {
86
79
  sock.destroy();
87
80
  }
88
81
 
89
- await untilClosed(() => closeFired);
82
+ // Give the close event a tick to propagate.
83
+ await new Promise((resolve) => setTimeout(resolve, 50));
84
+
85
+ expect(closeFired).toBe(true);
90
86
  expect(transport.isAlive()).toBe(false);
91
87
 
92
88
  await pm.stop();
@@ -116,7 +112,8 @@ describe("CesProcessManager.onTransportClose", () => {
116
112
  for (const sock of connections) {
117
113
  sock.destroy();
118
114
  }
119
- await untilClosed(() => !transport.isAlive());
115
+ await new Promise((resolve) => setTimeout(resolve, 50));
116
+ expect(transport.isAlive()).toBe(false);
120
117
 
121
118
  // Register handler AFTER transport is already dead.
122
119
  let closeFired = false;
@@ -193,12 +190,14 @@ describe("CesProcessManager transport-death logging", () => {
193
190
  for (const sock of connections) {
194
191
  sock.destroy();
195
192
  }
196
- await untilClosed(() =>
193
+ await new Promise((resolve) => setTimeout(resolve, 50));
194
+ expect(transport.isAlive()).toBe(false);
195
+
196
+ expect(
197
197
  calls.some(
198
198
  (c) => c.level === "warn" && c.msg.includes("died unexpectedly"),
199
199
  ),
200
- );
201
- expect(transport.isAlive()).toBe(false);
200
+ ).toBe(true);
202
201
 
203
202
  await pm.stop();
204
203
  });
@@ -209,17 +208,19 @@ describe("CesProcessManager transport-death logging", () => {
209
208
  await pm.start();
210
209
 
211
210
  await pm.stop();
212
- await untilClosed(() =>
213
- calls.some(
214
- (c) =>
215
- c.level === "debug" && c.msg.includes("CES socket transport closed"),
216
- ),
217
- );
211
+ // Let the socket close event propagate after destroy().
212
+ await new Promise((resolve) => setTimeout(resolve, 50));
218
213
 
219
214
  expect(
220
215
  calls.some(
221
216
  (c) => c.level === "warn" && c.msg.includes("died unexpectedly"),
222
217
  ),
223
218
  ).toBe(false);
219
+ expect(
220
+ calls.some(
221
+ (c) =>
222
+ c.level === "debug" && c.msg.includes("CES socket transport closed"),
223
+ ),
224
+ ).toBe(true);
224
225
  });
225
226
  });