@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2

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 (596) hide show
  1. package/AGENTS.md +9 -3
  2. package/ARCHITECTURE.md +32 -10
  3. package/docs/architecture/memory.md +43 -5
  4. package/docs/architecture/security.md +96 -152
  5. package/docs/architecture/turn-actor.md +70 -0
  6. package/docs/browser-use-architecture-phase2.md +128 -56
  7. package/docs/flux-turn-detection-spike.md +248 -0
  8. package/docs/guardian-request-flow.md +35 -0
  9. package/docs/stt-provider-onboarding.md +3 -1
  10. package/knip.json +3 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  19. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
  24. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  25. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  26. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  27. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  28. package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  29. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  30. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  31. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  32. package/openapi.yaml +289 -113
  33. package/package.json +1 -1
  34. package/scripts/voice-ttft-spike.ts +3 -3
  35. package/scripts/write-plugin-api-shim.ts +10 -0
  36. package/src/__tests__/app-compiler.test.ts +38 -3
  37. package/src/__tests__/app-control-flow.test.ts +1 -0
  38. package/src/__tests__/approval-routes-http.test.ts +2 -2
  39. package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
  40. package/src/__tests__/attachments-store.test.ts +21 -12
  41. package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
  42. package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
  43. package/src/__tests__/call-site-routing-provider.test.ts +1 -1
  44. package/src/__tests__/channel-availability-routes.test.ts +14 -1
  45. package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
  46. package/src/__tests__/channel-delivery-store.test.ts +14 -14
  47. package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
  48. package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
  49. package/src/__tests__/checker.test.ts +20 -314
  50. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  51. package/src/__tests__/compaction-events.test.ts +8 -10
  52. package/src/__tests__/config-loader-backfill.test.ts +3 -3
  53. package/src/__tests__/config-schema.test.ts +25 -10
  54. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  55. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
  56. package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
  57. package/src/__tests__/conversation-agent-loop.test.ts +32 -21
  58. package/src/__tests__/conversation-attachments.test.ts +0 -1
  59. package/src/__tests__/conversation-attention-store.test.ts +63 -0
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
  61. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -0
  63. package/src/__tests__/conversation-fork-referential.test.ts +67 -0
  64. package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
  65. package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
  66. package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
  67. package/src/__tests__/conversation-queue.test.ts +154 -4
  68. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  69. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
  71. package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
  75. package/src/__tests__/conversation-slash-queue.test.ts +3 -0
  76. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  77. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
  78. package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
  79. package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
  80. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
  81. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
  82. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
  83. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
  85. package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
  86. package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
  87. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
  88. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  89. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  90. package/src/__tests__/credential-prompt-route.test.ts +7 -10
  91. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  92. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  93. package/src/__tests__/custom-profile-ensure.test.ts +5 -1
  94. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  95. package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
  96. package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
  97. package/src/__tests__/document-append-idempotency.test.ts +233 -0
  98. package/src/__tests__/document-sync-tags.test.ts +0 -75
  99. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  100. package/src/__tests__/edit-propagation.test.ts +107 -11
  101. package/src/__tests__/file-ops-service.test.ts +163 -30
  102. package/src/__tests__/filesystem-tools.test.ts +23 -24
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -5
  104. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  105. package/src/__tests__/helpers/mock-actor-context.ts +49 -0
  106. package/src/__tests__/helpers/mock-conversation.ts +13 -1
  107. package/src/__tests__/host-file-read-tool.test.ts +16 -19
  108. package/src/__tests__/http-user-message-parity.test.ts +1 -1
  109. package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
  110. package/src/__tests__/injector-chain.test.ts +63 -41
  111. package/src/__tests__/injector-disk-pressure.test.ts +11 -23
  112. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  113. package/src/__tests__/llm-context-resolution.test.ts +73 -1
  114. package/src/__tests__/llm-schema.test.ts +5 -2
  115. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
  116. package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
  117. package/src/__tests__/media-generate-image.test.ts +131 -21
  118. package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
  119. package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
  120. package/src/__tests__/mtime-cache.test.ts +3 -1
  121. package/src/__tests__/non-member-access-request.test.ts +0 -20
  122. package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
  123. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  124. package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
  125. package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
  126. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  127. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  128. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  129. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  130. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
  131. package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
  132. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
  133. package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
  134. package/src/__tests__/proxy-approval-callback.test.ts +1 -0
  135. package/src/__tests__/qdrant-manager.test.ts +14 -1
  136. package/src/__tests__/reaction-persistence.test.ts +200 -7
  137. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  138. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  139. package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
  140. package/src/__tests__/run-due-schedules.test.ts +21 -0
  141. package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
  142. package/src/__tests__/schedule-routes.test.ts +23 -0
  143. package/src/__tests__/schedule-store.test.ts +17 -0
  144. package/src/__tests__/scoped-approval-grants.test.ts +11 -6
  145. package/src/__tests__/secret-ingress-channel.test.ts +0 -1
  146. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  147. package/src/__tests__/send-endpoint-busy.test.ts +3 -3
  148. package/src/__tests__/skills.test.ts +32 -0
  149. package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
  150. package/src/__tests__/starter-task-flow.test.ts +5 -4
  151. package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
  152. package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
  153. package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
  154. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  155. package/src/__tests__/subagent-tools.test.ts +81 -101
  156. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
  157. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  158. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  159. package/src/__tests__/tool-executor.test.ts +68 -39
  160. package/src/__tests__/turn-events-store.test.ts +43 -0
  161. package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
  162. package/src/__tests__/ui-shape-teaching.test.ts +33 -0
  163. package/src/__tests__/ui-visual-surface.test.ts +1 -1
  164. package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
  165. package/src/__tests__/ui-work-result-surface.test.ts +1 -1
  166. package/src/__tests__/user-plugin-loader.test.ts +3 -1
  167. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  168. package/src/__tests__/visible-app-context.test.ts +16 -9
  169. package/src/__tests__/voice-config-update.test.ts +40 -0
  170. package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
  171. package/src/__tests__/voice-session-bridge.test.ts +85 -29
  172. package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
  173. package/src/__tests__/worker-plugin-surface.test.ts +77 -0
  174. package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
  175. package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
  176. package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
  177. package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
  178. package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
  179. package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
  180. package/src/acp/__tests__/auth-required.test.ts +161 -0
  181. package/src/acp/acp-claude-oauth.ts +19 -2
  182. package/src/acp/agent-process.test.ts +100 -0
  183. package/src/acp/agent-process.ts +29 -26
  184. package/src/acp/auth-required.ts +102 -0
  185. package/src/acp/session-manager.test.ts +119 -0
  186. package/src/acp/session-manager.ts +76 -3
  187. package/src/api/events/acp-auth-required.ts +55 -0
  188. package/src/api/events/host-file.ts +2 -2
  189. package/src/api/index.ts +7 -0
  190. package/src/api/surfaces.ts +12 -3
  191. package/src/apps/app-store.ts +3 -0
  192. package/src/bundler/package-resolver.ts +2 -30
  193. package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
  194. package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
  195. package/src/calls/call-controller.ts +19 -3
  196. package/src/calls/call-setup-flow.ts +0 -1
  197. package/src/calls/media-stream-stt-session.ts +15 -0
  198. package/src/calls/voice-session-bridge.ts +115 -41
  199. package/src/calls/voice-triage-escalate.ts +105 -2
  200. package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
  201. package/src/channels/config.ts +13 -0
  202. package/src/channels/plugin-channel-declarations.ts +108 -0
  203. package/src/channels/types.ts +30 -0
  204. package/src/cli/AGENTS.md +5 -2
  205. package/src/cli/bundled-modules.ts +29 -0
  206. package/src/cli/commands/credentials.help.ts +2 -2
  207. package/src/cli/commands/db/repair.ts +4 -8
  208. package/src/cli/commands/domain.ts +6 -3
  209. package/src/cli/commands/email.ts +6 -3
  210. package/src/cli/commands/inference-providers.ts +1 -1
  211. package/src/cli/commands/keys.ts +8 -3
  212. package/src/cli/commands/mcp.help.ts +13 -4
  213. package/src/cli/commands/mcp.ts +9 -0
  214. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  215. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
  216. package/src/cli/commands/memory/index.help.ts +84 -28
  217. package/src/cli/commands/memory/index.ts +2 -0
  218. package/src/cli/commands/memory/memory-v2.ts +58 -54
  219. package/src/cli/commands/memory/memory-v3.ts +64 -0
  220. package/src/cli/commands/memory/memory-validate.ts +18 -0
  221. package/src/cli/commands/plugins.ts +85 -36
  222. package/src/cli/commands/schedules.ts +35 -1
  223. package/src/cli/commands/stt.help.ts +27 -2
  224. package/src/cli/commands/trust.ts +3 -14
  225. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
  226. package/src/cli/lib/bundled-marketplace.json +14 -1
  227. package/src/cli/lib/upgrade-plugin.ts +42 -0
  228. package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
  229. package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
  230. package/src/config/__tests__/default-provider.test.ts +6 -1
  231. package/src/config/__tests__/profile-materialization.test.ts +75 -19
  232. package/src/config/assistant-feature-flags.ts +36 -15
  233. package/src/config/balanced-model-experiment.ts +35 -0
  234. package/src/config/bundled-skills/acp/SKILL.md +6 -7
  235. package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
  236. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  237. package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
  238. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
  240. package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
  241. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  242. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
  243. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
  244. package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
  245. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
  246. package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
  247. package/src/config/bundled-skills/subagent/SKILL.md +17 -12
  248. package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
  249. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
  250. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
  251. package/src/config/call-site-defaults.ts +11 -5
  252. package/src/config/default-profile-catalog.ts +179 -16
  253. package/src/config/default-profile-names.ts +4 -1
  254. package/src/config/default-provider-resolution.ts +4 -0
  255. package/src/config/feature-flag-registry.json +12 -12
  256. package/src/config/llm-context-resolution.ts +11 -3
  257. package/src/config/llm-resolver.ts +28 -1
  258. package/src/config/profile-materialization.ts +70 -22
  259. package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
  260. package/src/config/schemas/call-site-catalog.ts +4 -4
  261. package/src/config/schemas/live-voice.ts +57 -23
  262. package/src/config/schemas/llm.ts +59 -32
  263. package/src/config/schemas/mcp.ts +23 -0
  264. package/src/config/schemas/plugin-updates.ts +6 -2
  265. package/src/config/schemas/stt.ts +1 -0
  266. package/src/config/skills.ts +9 -2
  267. package/src/context/outbound-sanitize.ts +96 -1
  268. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
  269. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
  270. package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
  271. package/src/daemon/conversation-agent-loop.ts +31 -19
  272. package/src/daemon/conversation-messaging.ts +5 -1
  273. package/src/daemon/conversation-notifiers.ts +20 -10
  274. package/src/daemon/conversation-process.ts +20 -6
  275. package/src/daemon/conversation-runtime-assembly.ts +12 -6
  276. package/src/daemon/conversation-store.ts +14 -4
  277. package/src/daemon/conversation-surfaces.ts +75 -26
  278. package/src/daemon/conversation-tool-setup.ts +3 -6
  279. package/src/daemon/conversation.ts +154 -51
  280. package/src/daemon/doordash-steps.ts +2 -2
  281. package/src/daemon/lifecycle.ts +14 -1
  282. package/src/daemon/mcp-reload-service.ts +36 -6
  283. package/src/daemon/process-message.ts +13 -26
  284. package/src/daemon/providers-setup.ts +6 -3
  285. package/src/daemon/trust-context-types.ts +29 -0
  286. package/src/daemon/trust-context.ts +12 -7
  287. package/src/daemon/wake-conversation-ops.ts +3 -2
  288. package/src/daemon/windows-compiled-entry.ts +4 -0
  289. package/src/documents/document-store.ts +143 -240
  290. package/src/hooks/hook-loader.ts +3 -3
  291. package/src/hooks/registry.ts +103 -45
  292. package/src/hooks/types.ts +5 -0
  293. package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
  294. package/src/inbound/oauth-callback-url.ts +61 -0
  295. package/src/ipc/gateway-client.test.ts +1 -1
  296. package/src/ipc/gateway-client.ts +14 -21
  297. package/src/ipc/gateway-flag-listener.ts +17 -3
  298. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
  299. package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
  300. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
  301. package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
  302. package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
  303. package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
  304. package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
  305. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
  306. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
  307. package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
  308. package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
  309. package/src/live-voice/live-voice-archive.ts +2 -0
  310. package/src/live-voice/live-voice-manager.ts +16 -3
  311. package/src/live-voice/live-voice-metrics.ts +57 -32
  312. package/src/live-voice/live-voice-photo.ts +1 -2
  313. package/src/live-voice/live-voice-session.ts +598 -323
  314. package/src/live-voice/progress-narration.ts +277 -0
  315. package/src/live-voice/protocol.ts +21 -1
  316. package/src/live-voice/windows-compiled-live-voice.ts +4 -0
  317. package/src/mcp/__tests__/effective-config.test.ts +238 -0
  318. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  319. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
  320. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
  321. package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
  322. package/src/mcp/client.ts +16 -11
  323. package/src/mcp/effective-config.ts +113 -0
  324. package/src/mcp/manager.ts +11 -6
  325. package/src/mcp/mcp-auth-orchestrator.ts +13 -22
  326. package/src/mcp/mcp-oauth-provider.ts +205 -240
  327. package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
  328. package/src/monitoring/control.ts +1 -0
  329. package/src/monitoring/db-integrity-sample.ts +4 -5
  330. package/src/monitoring/plugin-auto-update.ts +128 -24
  331. package/src/notifications/AGENTS.md +2 -0
  332. package/src/notifications/approval-card-data.ts +33 -0
  333. package/src/notifications/signal.ts +1 -0
  334. package/src/permissions/AGENTS.md +16 -0
  335. package/src/permissions/checker.test.ts +75 -122
  336. package/src/permissions/checker.ts +44 -560
  337. package/src/permissions/confirmation-guardian-request.test.ts +15 -11
  338. package/src/permissions/confirmation-guardian-request.ts +2 -2
  339. package/src/permissions/prompter.ts +1 -5
  340. package/src/permissions/question-guardian-request.test.ts +14 -6
  341. package/src/permissions/question-guardian-request.ts +1 -2
  342. package/src/persistence/attachments-store.ts +8 -1
  343. package/src/persistence/bookmark-crud.ts +3 -7
  344. package/src/persistence/conversation-attention-store.ts +16 -45
  345. package/src/persistence/conversation-crud.ts +33 -4
  346. package/src/persistence/conversation-lineage.ts +9 -0
  347. package/src/persistence/conversation-queries.ts +182 -52
  348. package/src/persistence/delivery-crud.ts +150 -36
  349. package/src/persistence/embeddings/qdrant-manager.ts +84 -49
  350. package/src/persistence/external-conversation-store.ts +32 -4
  351. package/src/persistence/llm-request-log-store.ts +4 -10
  352. package/src/persistence/llm-usage-store.ts +8 -3
  353. package/src/persistence/message-reads.test.ts +197 -0
  354. package/src/persistence/message-reads.ts +211 -0
  355. package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
  356. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
  357. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
  358. package/src/persistence/real-user-turn-filter.ts +27 -3
  359. package/src/persistence/schema/documents.ts +4 -4
  360. package/src/persistence/steps.ts +9 -0
  361. package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
  362. package/src/plugin-api/constants.ts +8 -0
  363. package/src/plugin-api/conversation-turn.ts +195 -5
  364. package/src/plugin-api/index.ts +38 -6
  365. package/src/plugin-api/resolve-credential.ts +3 -2
  366. package/src/plugin-api/store-credential.ts +146 -0
  367. package/src/plugin-api/vision-support.test.ts +1 -1
  368. package/src/plugin-api/webhook-url.ts +13 -11
  369. package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
  370. package/src/plugins/defaults/main.ts +21 -7
  371. package/src/plugins/defaults/memory/AGENTS.md +15 -3
  372. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
  373. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
  374. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
  375. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
  376. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  377. package/src/plugins/defaults/memory/buffer-format.ts +165 -0
  378. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
  379. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
  380. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
  381. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
  382. package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
  383. package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
  384. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
  385. package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
  386. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
  387. package/src/plugins/defaults/memory/indexer.ts +3 -1
  388. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
  389. package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
  390. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
  391. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  392. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
  393. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
  394. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  395. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  396. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  397. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  398. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  399. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  400. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
  401. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
  402. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  403. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  404. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  405. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  406. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  407. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  408. package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
  409. package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
  410. package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
  411. package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
  412. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
  413. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
  414. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  415. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  416. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  417. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  418. package/src/plugins/defaults/memory/v3/injector.ts +8 -0
  419. package/src/plugins/defaults/memory/v3/prune.ts +2 -0
  420. package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
  421. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
  422. package/src/plugins/defaults/memory/worker-control.ts +1 -0
  423. package/src/plugins/defaults/memory/worker.ts +6 -3
  424. package/src/plugins/defaults/worker-entrypoints.ts +3 -0
  425. package/src/plugins/external-plugin-loader.ts +47 -0
  426. package/src/plugins/mcp-servers.ts +361 -0
  427. package/src/plugins/mtime-cache.ts +37 -46
  428. package/src/plugins/pipeline.ts +14 -7
  429. package/src/plugins/plugin-execution-context.ts +35 -11
  430. package/src/plugins/worker-plugin-surface.ts +33 -0
  431. package/src/prompts/templates/system-sections.ts +0 -7
  432. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  433. package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
  434. package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
  435. package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
  436. package/src/providers/__tests__/retry-callsite.test.ts +25 -2
  437. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  438. package/src/providers/anthropic/client.ts +332 -241
  439. package/src/providers/call-site-routing.ts +30 -3
  440. package/src/providers/connection-resolution.ts +194 -11
  441. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
  442. package/src/providers/inference/adapter-factory.ts +3 -0
  443. package/src/providers/inference/auth.ts +6 -0
  444. package/src/providers/inference/connection-availability.ts +24 -2
  445. package/src/providers/inference/connections.ts +2 -0
  446. package/src/providers/model-catalog.ts +3 -3
  447. package/src/providers/model-intents.ts +28 -8
  448. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
  449. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  450. package/src/providers/openai/chat-completions-provider.ts +133 -36
  451. package/src/providers/openai/codex-models.ts +2 -1
  452. package/src/providers/provider-send-message.ts +32 -3
  453. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
  454. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
  455. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
  456. package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
  457. package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
  458. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
  459. package/src/providers/speech-to-text/provider-catalog.ts +99 -8
  460. package/src/providers/speech-to-text/resolve.ts +25 -2
  461. package/src/routes/control.ts +1 -0
  462. package/src/routes/route-host-client.ts +1 -0
  463. package/src/routes/route-host-protocol.ts +7 -0
  464. package/src/routes/worker.ts +48 -15
  465. package/src/runtime/AGENTS.md +16 -17
  466. package/src/runtime/access-request-helper.ts +9 -12
  467. package/src/runtime/agent-wake.ts +18 -15
  468. package/src/runtime/effective-capabilities.test.ts +43 -0
  469. package/src/runtime/effective-capabilities.ts +27 -0
  470. package/src/runtime/guardian-reply-router.ts +6 -2
  471. package/src/runtime/pre-first-message-gate.ts +4 -0
  472. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
  473. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
  474. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
  475. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
  476. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
  477. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
  478. package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
  479. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
  480. package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
  481. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  482. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  483. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
  484. package/src/runtime/routes/channel-availability-routes.ts +32 -14
  485. package/src/runtime/routes/channel-route-shared.ts +0 -6
  486. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
  487. package/src/runtime/routes/conversation-list-routes.ts +181 -23
  488. package/src/runtime/routes/conversation-management-routes.ts +17 -12
  489. package/src/runtime/routes/conversation-query-routes.ts +40 -27
  490. package/src/runtime/routes/conversation-routes.ts +43 -29
  491. package/src/runtime/routes/credential-prompt-routes.ts +4 -7
  492. package/src/runtime/routes/credential-routes.ts +26 -82
  493. package/src/runtime/routes/default-provider-routes.ts +15 -0
  494. package/src/runtime/routes/documents-routes.ts +3 -222
  495. package/src/runtime/routes/inbound-message-handler.ts +21 -45
  496. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
  497. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
  498. package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
  499. package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
  500. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
  501. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
  502. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
  503. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
  504. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
  505. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
  506. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
  507. package/src/runtime/routes/inference-profiles-routes.ts +20 -11
  508. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
  509. package/src/runtime/routes/log-export-routes.ts +3 -0
  510. package/src/runtime/routes/mcp-auth-routes.ts +148 -57
  511. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
  512. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
  513. package/src/runtime/routes/playground/inject-failures.ts +2 -2
  514. package/src/runtime/routes/playground/reset-circuit.ts +1 -1
  515. package/src/runtime/routes/plugins-routes.ts +38 -8
  516. package/src/runtime/routes/schedule-routes.ts +94 -7
  517. package/src/runtime/routes/settings-routes.ts +6 -6
  518. package/src/runtime/routes/stt-routes.ts +31 -25
  519. package/src/runtime/routes/surface-action-routes.ts +20 -19
  520. package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
  521. package/src/runtime/routes/user-route-dispatcher.ts +69 -15
  522. package/src/runtime/routes/user-route-import.ts +108 -0
  523. package/src/runtime/routes/user-route-resolution.ts +18 -1
  524. package/src/runtime/routes/workspace-routes.ts +0 -9
  525. package/src/runtime/routes/workspace-utils.ts +3 -13
  526. package/src/runtime/services/conversation-serializer.ts +7 -2
  527. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
  528. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
  529. package/src/schedule/plugin-schedule-availability.ts +58 -0
  530. package/src/schedule/plugin-schedule-declarations.ts +23 -27
  531. package/src/schedule/plugin-schedule-reconciler.ts +12 -3
  532. package/src/schedule/schedule-store.ts +5 -1
  533. package/src/schedule/scheduler.ts +9 -4
  534. package/src/schedule/worker-control.ts +1 -0
  535. package/src/schedule/worker.ts +6 -0
  536. package/src/security/oauth2.ts +6 -22
  537. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
  538. package/src/stt/__tests__/types.test.ts +94 -0
  539. package/src/stt/daemon-batch-transcriber.ts +10 -0
  540. package/src/stt/stt-stream-session.ts +8 -4
  541. package/src/stt/types.ts +103 -0
  542. package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
  543. package/src/subagent/consult-context.ts +11 -11
  544. package/src/subagent/consult-prompt.ts +26 -35
  545. package/src/subagent/manager.ts +21 -40
  546. package/src/subagent/notify.ts +7 -1
  547. package/src/subagent/types.ts +15 -12
  548. package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
  549. package/src/tools/acp/spawn.test.ts +97 -0
  550. package/src/tools/acp/spawn.ts +38 -4
  551. package/src/tools/credentials/ref-parse.ts +35 -0
  552. package/src/tools/credentials/resolve.ts +4 -10
  553. package/src/tools/credentials/store.ts +168 -0
  554. package/src/tools/document/document-tool.ts +12 -3
  555. package/src/tools/executor.ts +53 -15
  556. package/src/tools/filesystem/read.ts +27 -10
  557. package/src/tools/host-filesystem/read.ts +27 -15
  558. package/src/tools/network/url-safety.ts +9 -16
  559. package/src/tools/permission-checker.ts +43 -52
  560. package/src/tools/registry.ts +2 -1
  561. package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
  562. package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
  563. package/src/tools/shared/filesystem/types.ts +5 -5
  564. package/src/tools/skills/scaffold-managed.ts +25 -7
  565. package/src/tools/subagent/spawn.ts +28 -88
  566. package/src/tools/tool-types.ts +26 -13
  567. package/src/tools/types.ts +6 -6
  568. package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
  569. package/src/tools/workflows/run-workflow.ts +1 -2
  570. package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
  571. package/src/tts/reasoning-tag-filter.ts +89 -0
  572. package/src/util/__tests__/worker-process-command.test.ts +37 -0
  573. package/src/util/logger.ts +16 -0
  574. package/src/util/think-tag-stream.ts +95 -0
  575. package/src/util/worker-process.ts +37 -4
  576. package/src/windows-compiled-cli.ts +32 -0
  577. package/src/windows-compiled-entry.ts +4 -0
  578. package/src/windows-compiled-logger.ts +6 -0
  579. package/src/windows-compiled-worker-entry.ts +29 -0
  580. package/src/workspace/byok-default-profile-ensure.ts +76 -24
  581. package/src/workspace/custom-profile-ensure.ts +4 -24
  582. package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
  583. package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
  584. package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
  585. package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
  586. package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
  587. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
  588. package/src/workspace/migrations/registry.ts +10 -0
  589. package/src/workspace/provider-commit-message-generator.ts +7 -5
  590. package/src/__tests__/document-workspace-file.test.ts +0 -467
  591. package/src/live-voice/__tests__/front-decision.test.ts +0 -645
  592. package/src/live-voice/front-decision.ts +0 -476
  593. package/src/permissions/ipc-risk-types.ts +0 -143
  594. package/src/permissions/risk-types.ts +0 -76
  595. package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
  596. package/src/subagent/consult-transcript.ts +0 -90
@@ -45,9 +45,29 @@ mock.module("../../notifications/emit-signal.js", () => ({
45
45
  },
46
46
  }));
47
47
 
48
+ /**
49
+ * Plugin directories the daemon has not activated. The reconciler arms only
50
+ * plugins this process brought up, and no test here runs the plugin loader, so
51
+ * the double answers "activated" unless a case says otherwise.
52
+ */
53
+ const notActivatedDirs = new Set<string>();
54
+
55
+ /** Every directory the reconciler put through the activation predicate. */
56
+ const activationProbes: string[] = [];
57
+
58
+ const realMtimeCache = await import("../../plugins/mtime-cache.js");
59
+ mock.module("../../plugins/mtime-cache.js", () => ({
60
+ ...realMtimeCache,
61
+ isPluginDirActivated: (dir: string) => {
62
+ activationProbes.push(dir);
63
+ return !notActivatedDirs.has(dir);
64
+ },
65
+ }));
66
+
48
67
  import { setOverridesForTesting } from "../../__tests__/feature-flag-test-helpers.js";
49
68
  import { getDb } from "../../persistence/db-connection.js";
50
69
  import { initializeDb } from "../../persistence/db-init.js";
70
+ import { listInstalledPluginDirs } from "../../plugins/installed-plugin-dirs.js";
51
71
  import { getWorkspacePluginsDir } from "../../util/platform.js";
52
72
  import {
53
73
  reconcilePluginSchedules,
@@ -175,6 +195,8 @@ function resetReconcilerFixtures(): void {
175
195
  emittedSignals.length = 0;
176
196
  emitResultOverride = null;
177
197
  emitGate = null;
198
+ notActivatedDirs.clear();
199
+ activationProbes.length = 0;
178
200
  resetDefinitionErrorEmitGuardForTests();
179
201
  }
180
202
 
@@ -970,6 +992,65 @@ describe("reconcilePluginSchedules", () => {
970
992
  expect(payload.reason).toContain("no upcoming occurrences");
971
993
  });
972
994
 
995
+ test("a plugin the daemon never activated arms nothing", async () => {
996
+ // Everything the parser needs is on disk; only the activation is missing,
997
+ // which is what a directory dropped into the plugins root looks like.
998
+ const dir = writePlugin("news", digest());
999
+ notActivatedDirs.add(dir);
1000
+
1001
+ await reconcilePluginSchedules();
1002
+
1003
+ expect(listDeclaredSchedules()).toHaveLength(0);
1004
+ expect(emittedSignals).toHaveLength(0);
1005
+ });
1006
+
1007
+ test("a row disarms once its plugin is no longer activated", async () => {
1008
+ const dir = writePlugin("news", digest());
1009
+ await reconcilePluginSchedules();
1010
+ const created = listDeclaredSchedules()[0]!;
1011
+ expect(created.enabled).toBe(true);
1012
+
1013
+ notActivatedDirs.add(dir);
1014
+ await reconcilePluginSchedules();
1015
+
1016
+ const row = listDeclaredSchedules()[0]!;
1017
+ expect(row.id).toBe(created.id);
1018
+ expect(row.enabled).toBe(false);
1019
+ });
1020
+
1021
+ test("a plugin activated between passes arms on the second one", async () => {
1022
+ const dir = writePlugin("news", digest());
1023
+ notActivatedDirs.add(dir);
1024
+ await reconcilePluginSchedules();
1025
+ expect(listDeclaredSchedules()).toHaveLength(0);
1026
+
1027
+ notActivatedDirs.delete(dir);
1028
+ await reconcilePluginSchedules();
1029
+
1030
+ const rows = listDeclaredSchedules();
1031
+ expect(rows).toHaveLength(1);
1032
+ expect(rows[0]!.sourceKey).toBe(DIGEST_KEY);
1033
+ expect(rows[0]!.enabled).toBe(true);
1034
+ // The row arms for the first time here, so it announces its arrival.
1035
+ const declared = emittedSignals.filter(
1036
+ (s) => s.sourceEventName === "schedule.declared",
1037
+ );
1038
+ expect(declared).toHaveLength(1);
1039
+ expect(declared[0]!.sourceContextId).toBe(DIGEST_KEY);
1040
+ });
1041
+
1042
+ test("the activation probe sees the directory string the walk yields", async () => {
1043
+ // The predicate is keyed by directory path, so the enumeration the
1044
+ // reconciler walks and the map the daemon activates into have to agree on
1045
+ // the exact string. Both come from `listInstalledPluginDirs`.
1046
+ const dir = writePlugin("news", digest());
1047
+
1048
+ await reconcilePluginSchedules();
1049
+
1050
+ expect(listInstalledPluginDirs().map((p) => p.dir)).toEqual([dir]);
1051
+ expect(activationProbes).toEqual([dir]);
1052
+ });
1053
+
973
1054
  test("a suppressed error emit still latches the day guard", async () => {
974
1055
  writePlugin("news", brokenDigest());
975
1056
  emitResultOverride = {
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Availability probe for a plugin-declared schedule's source.
3
+ *
4
+ * Composes the daemon's activation state with the on-disk declaration probe:
5
+ * did this process bring the plugin up, and is its declaration still
6
+ * sourceable.
7
+ *
8
+ * **This probe is only meaningful in the main daemon process.** Activation is
9
+ * tracked in an in-memory map that `bringUpPlugin` writes, so only the process
10
+ * that ran the plugin loader can answer for it. HTTP routes and the plugin
11
+ * schedule reconciler run there, so they may use this. Worker processes (the
12
+ * schedule worker in `schedule/worker.ts`, sidecar turn workers) activate no
13
+ * plugins, so their ledger is empty and every plugin would read as
14
+ * unactivated. Those paths call {@link declarationExistsOnDisk} directly.
15
+ *
16
+ * That split is safe because the reconciler owns arming and runs in the
17
+ * daemon: a plugin it has not activated never arms, and its sweep disarms the
18
+ * rows of a plugin that stops being activated within one pass. The window
19
+ * between those passes is the whole exposure of the worker-side disk-only
20
+ * probes.
21
+ *
22
+ * The composition lives here rather than in `./plugin-schedule-declarations.ts`
23
+ * because that parser is reachable from the plugin loader's own static graph
24
+ * and must stay free of daemon runtime state. `plugins/mtime-cache.ts` reaches
25
+ * the schedule side only through a dynamic import, so importing it here does
26
+ * not close a static cycle.
27
+ */
28
+
29
+ import { join } from "node:path";
30
+
31
+ import { isPluginDirActivated } from "../plugins/mtime-cache.js";
32
+ import { getWorkspacePluginsDir } from "../util/platform.js";
33
+ import { declarationExistsOnDisk } from "./plugin-schedule-declarations.js";
34
+
35
+ /**
36
+ * True when the schedule behind `sourceKey`
37
+ * (`plugin:<pluginName>/<scheduleName>`) may run: the daemon activated the
38
+ * plugin, and {@link declarationExistsOnDisk} still finds the declaration.
39
+ *
40
+ * The activation half is what keeps a plugin directory dropped into the
41
+ * plugins root out of the scheduler. Such a directory has files the disk probe
42
+ * accepts, but no `init` has run for it, so its hooks and tools are not live
43
+ * and its schedules must not be either.
44
+ */
45
+ export async function pluginScheduleSourceAvailable(
46
+ sourceKey: string,
47
+ ): Promise<boolean> {
48
+ const match = /^plugin:([^/]+)\/(.+)$/.exec(sourceKey);
49
+ if (!match) {
50
+ return false;
51
+ }
52
+ const [, pluginName] = match;
53
+ const pluginDir = join(getWorkspacePluginsDir(), pluginName!);
54
+ return (
55
+ isPluginDirActivated(pluginDir) &&
56
+ (await declarationExistsOnDisk(sourceKey))
57
+ );
58
+ }
@@ -30,7 +30,6 @@ import { z } from "zod";
30
30
  import { isPluginDisabled } from "../plugins/disabled-state.js";
31
31
  import { parsePluginManifest } from "../plugins/external-plugin-loader.js";
32
32
  import { isInsidePluginRoot } from "../plugins/installed-plugin-dirs.js";
33
- import { walkPluginTree } from "../plugins/plugin-tree-walk.js";
34
33
  import { FRONTMATTER_REGEX } from "../skills/frontmatter.js";
35
34
  import { getWorkspacePluginsDir } from "../util/platform.js";
36
35
  import {
@@ -77,9 +76,13 @@ export interface ScheduleDeclaration {
77
76
  scriptInvocation: string | null;
78
77
  config: PluginScheduleConfig;
79
78
  /**
80
- * Stable sha256 over the declaration's file contents and their paths
81
- * relative to `schedules/`. Any edit, addition, removal, or rename of a
82
- * declaration file changes the hash.
79
+ * Stable sha256 over the declaration's `config.json` and its entrypoint,
80
+ * each hashed together with its path relative to `schedules/`. Nothing else
81
+ * under the declaration directory takes part. Helper scripts, and any state
82
+ * a script writes beside itself, do not change the stored row definition, so
83
+ * hashing them would report a definition change every time a stateful
84
+ * schedule runs. Scripts execute by path, so an edit to a helper takes
85
+ * effect without a definition change.
83
86
  */
84
87
  definitionHash: string;
85
88
  }
@@ -292,21 +295,6 @@ function hashDeclarationFiles(files: DeclarationFile[]): string {
292
295
  return hash.digest("hex");
293
296
  }
294
297
 
295
- /**
296
- * Collect every regular file under `dir` (recursively, dot entries and
297
- * symlinks skipped) with paths relative to the schedules/ root.
298
- */
299
- function collectDeclarationFiles(
300
- dir: string,
301
- relPrefix: string,
302
- ): DeclarationFile[] {
303
- const files: DeclarationFile[] = [];
304
- walkPluginTree(dir, { excludeDotEntries: true }, (rel, abs) => {
305
- files.push({ relPath: `${relPrefix}${rel}`, content: readFileSync(abs) });
306
- });
307
- return files;
308
- }
309
-
310
298
  function shellQuote(value: string): string {
311
299
  return `'${value.replace(/'/g, `'\\''`)}'`;
312
300
  }
@@ -395,25 +383,24 @@ function parseDirectoryDeclaration(
395
383
  let message: string | null = null;
396
384
  let scriptInvocation: string | null = null;
397
385
  let mode: PluginScheduleMode;
386
+ let entrypointText: string;
398
387
  if (entrypoint === "index.md") {
399
- const content = readFileSync(join(dirPath, "index.md"), "utf8");
400
- if (FRONTMATTER_REGEX.test(content)) {
388
+ entrypointText = readFileSync(join(dirPath, "index.md"), "utf8");
389
+ if (FRONTMATTER_REGEX.test(entrypointText)) {
401
390
  return {
402
391
  error:
403
392
  "index.md must not contain frontmatter: directory-form config belongs in config.json",
404
393
  };
405
394
  }
406
- message = content.trim();
395
+ message = entrypointText.trim();
407
396
  if (!message) {
408
397
  return { error: "prompt body is empty" };
409
398
  }
410
399
  mode = "execute";
411
400
  } else {
412
401
  const scriptPath = join(dirPath, "index.sh");
413
- scriptInvocation = buildScriptInvocation(
414
- scriptPath,
415
- readFileSync(scriptPath, "utf8"),
416
- );
402
+ entrypointText = readFileSync(scriptPath, "utf8");
403
+ scriptInvocation = buildScriptInvocation(scriptPath, entrypointText);
417
404
  mode = "script";
418
405
  }
419
406
 
@@ -422,7 +409,16 @@ function parseDirectoryDeclaration(
422
409
  message,
423
410
  scriptInvocation,
424
411
  config: configResult.config,
425
- files: collectDeclarationFiles(dirPath, `${dirName}/`),
412
+ files: [
413
+ {
414
+ relPath: `${dirName}/config.json`,
415
+ content: Buffer.from(rawConfigText),
416
+ },
417
+ {
418
+ relPath: `${dirName}/${entrypoint}`,
419
+ content: Buffer.from(entrypointText),
420
+ },
421
+ ],
426
422
  };
427
423
  }
428
424
 
@@ -33,6 +33,7 @@ import type { AttentionHints } from "../notifications/signal.js";
33
33
  import { isPluginDisabled } from "../plugins/disabled-state.js";
34
34
  import { parsePluginManifest } from "../plugins/external-plugin-loader.js";
35
35
  import { listInstalledPluginDirs } from "../plugins/installed-plugin-dirs.js";
36
+ import { isPluginDirActivated } from "../plugins/mtime-cache.js";
36
37
  import { getLogger } from "../util/logger.js";
37
38
  import {
38
39
  type DeclarationError,
@@ -264,9 +265,14 @@ function isCompletedRecurrence(
264
265
  * as the plugin source collector) and gather their schedule declarations.
265
266
  * Identity = the directory basename, mirroring `parsePluginManifest`.
266
267
  *
267
- * Disabled plugins and plugins without a `schedules/` directory are skipped
268
- * entirely; in particular, only schedule-declaring plugins pay the manifest
269
- * parse each pass. A schedule-declaring plugin whose manifest fails
268
+ * Disabled plugins, plugins this daemon has not activated
269
+ * ({@link isPluginDirActivated}), and plugins without a `schedules/` directory
270
+ * are skipped entirely; in particular, only schedule-declaring plugins pay the
271
+ * manifest parse each pass. The activation gate is what keeps a directory
272
+ * dropped into the plugins root out of the desired set: nothing has run its
273
+ * `init`, so its hooks and tools are not live and its schedules must not arm
274
+ * either. It joins the set on the pass after the boot scan or an imperative
275
+ * reconcile brings it up. A schedule-declaring plugin whose manifest fails
270
276
  * `parsePluginManifest` (unreadable or schema-invalid `package.json`) also
271
277
  * contributes nothing to the desired set: the runtime loader refuses to
272
278
  * bring such a plugin up, so its schedules must not stay armed either. Each
@@ -282,6 +288,9 @@ async function collectDesiredDeclarations(): Promise<CollectedDeclarations> {
282
288
  if (isPluginDisabled(name)) {
283
289
  continue;
284
290
  }
291
+ if (!isPluginDirActivated(dir)) {
292
+ continue;
293
+ }
285
294
  if (!existsSync(join(dir, "schedules"))) {
286
295
  continue;
287
296
  }
@@ -840,7 +840,7 @@ export function listDeclaredSchedules(): ScheduleJob[] {
840
840
  * a null `lastRunAt` is a declared schedule inserted disabled, not an engine
841
841
  * latch, and stays re-armable.
842
842
  */
843
- function isEngineLatched(row: {
843
+ export function isEngineLatched(row: {
844
844
  status: string;
845
845
  nextRunAt: number;
846
846
  lastRunAt: number | null;
@@ -1051,6 +1051,10 @@ export async function setUserEnabled(
1051
1051
  // again. The reconciler is the authority on the declaration set; this
1052
1052
  // probe only closes that fire-before-next-sweep window. The override
1053
1053
  // itself is still recorded, so it applies if the declaration returns.
1054
+ // The probe is deliberately disk-only. A schedule tool calls this from a
1055
+ // conversation turn, which can run in a sidecar worker process where the
1056
+ // daemon's activation ledger is empty, so consulting activation here would
1057
+ // refuse to re-arm anything. Activation stays the reconciler's call.
1054
1058
  if (value && !(await declarationExistsOnDisk(existing.sourceKey))) {
1055
1059
  logger.info(
1056
1060
  { scheduleId: id, sourceKey: existing.sourceKey },
@@ -529,10 +529,15 @@ export async function runDueSchedulesOnce(
529
529
 
530
530
  // Fire-time gate for plugin-sourced rows, covering every way the source
531
531
  // can go away under an armed row. `declarationExistsOnDisk` is the probe
532
- // the run-now route and the enable path use, and it answers for all of
533
- // them: a `.disabled` sentinel, a plugin directory a local uninstall
534
- // removed, a manifest that no longer parses, and a declaration that is
535
- // simply gone. Turning the feature flag off retires the whole surface.
532
+ // the enable path uses, and it answers for all of them: a `.disabled`
533
+ // sentinel, a plugin directory a local uninstall removed, a manifest that
534
+ // no longer parses, and a declaration that is simply gone. Turning the
535
+ // feature flag off retires the whole surface.
536
+ // The probe is deliberately disk-only. Schedule execution runs in the
537
+ // schedule worker process, which activates no plugins, so the daemon's
538
+ // in-memory activation ledger is empty here and reading it would skip
539
+ // every plugin schedule. Activation is gated where the daemon owns it: the
540
+ // reconciler decides what arms, and the run-now route refuses by hand.
536
541
  // The reconciler is what disarms the rows any of these own, and it runs
537
542
  // on its own schedule, so re-reading here is what makes the change take
538
543
  // effect immediately: a row still armed (or already claimed) at that
@@ -96,6 +96,7 @@ async function spawnScheduleWorkerProcessUncoalesced(
96
96
  return await spawnWorkerProcess({
97
97
  pidPath: getScheduleWorkerPidPath(),
98
98
  entry: new URL("./worker.ts", import.meta.url),
99
+ packagedEntry: "schedule",
99
100
  workerLabel: "Schedule worker",
100
101
  options: opts,
101
102
  });
@@ -16,6 +16,7 @@ import { writeFileSync } from "node:fs";
16
16
  import { getConfig } from "../config/loader.js";
17
17
  import { rehydratePlatformCredentials } from "../config/platform-rehydration.js";
18
18
  import { resetDb } from "../persistence/db-connection.js";
19
+ import { registerWorkerPluginSurface } from "../plugins/worker-plugin-surface.js";
19
20
  import { disableStreamSeqStamping } from "../runtime/assistant-stream-state.js";
20
21
  import { initializeTools } from "../tools/registry.js";
21
22
  import { getLogger } from "../util/logger.js";
@@ -51,6 +52,11 @@ async function main(): Promise<void> {
51
52
  // rejected for both inference and background-wake requests.
52
53
  await rehydratePlatformCredentials();
53
54
 
55
+ // This process is the sole runner of schedule execution and hosts real agent
56
+ // conversations (wake, execute, and workflow modes), so it needs the default
57
+ // plugins' hooks and injectors just like the daemon.
58
+ registerWorkerPluginSurface();
59
+
54
60
  // Populate the tool registry (core built-ins + workspace tools). The daemon
55
61
  // does this at startup; this standalone process has to do it itself so
56
62
  // workflow schedules pass the core-tools readiness gate and agent-executed
@@ -273,20 +273,12 @@ async function runGatewayFlow(
273
273
  ): Promise<OAuth2FlowResult> {
274
274
  // Dynamic imports required here to avoid circular dependencies with
275
275
  // config/loader → security → oauth2 module chains.
276
- const { loadConfig } = await import("../config/loader.js");
277
- const { getOAuthCallbackUrl } =
278
- await import("../inbound/public-ingress-urls.js");
279
- const { resolveCallbackUrl } =
280
- await import("../inbound/platform-callback-registration.js");
276
+ const { resolveOauthCallbackUrl } =
277
+ await import("../inbound/oauth-callback-url.js");
281
278
  const { registerPendingCallback } =
282
279
  await import("./oauth-callback-registry.js");
283
280
 
284
- const appConfig = loadConfig();
285
- const redirectUri = await resolveCallbackUrl(
286
- () => getOAuthCallbackUrl(appConfig),
287
- "webhooks/oauth/callback",
288
- "oauth",
289
- );
281
+ const redirectUri = await resolveOauthCallbackUrl();
290
282
 
291
283
  const codePromise = new Promise<string>((resolve, reject) => {
292
284
  registerPendingCallback(state, resolve, reject);
@@ -556,20 +548,12 @@ export async function prepareOAuth2Flow(
556
548
 
557
549
  // Dynamic imports required here to avoid circular dependencies with
558
550
  // config/loader → security → oauth2 module chains.
559
- const { loadConfig } = await import("../config/loader.js");
560
- const { getOAuthCallbackUrl } =
561
- await import("../inbound/public-ingress-urls.js");
562
- const { resolveCallbackUrl } =
563
- await import("../inbound/platform-callback-registration.js");
551
+ const { resolveOauthCallbackUrl } =
552
+ await import("../inbound/oauth-callback-url.js");
564
553
  const { registerPendingCallback } =
565
554
  await import("./oauth-callback-registry.js");
566
555
 
567
- const appConfig = loadConfig();
568
- const redirectUri = await resolveCallbackUrl(
569
- () => getOAuthCallbackUrl(appConfig),
570
- "webhooks/oauth/callback",
571
- "oauth",
572
- );
556
+ const redirectUri = await resolveOauthCallbackUrl();
573
557
 
574
558
  const codeVerifier = generateCodeVerifier();
575
559
  const codeChallenge = generateCodeChallenge(codeVerifier);
@@ -1,5 +1,6 @@
1
1
  import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
+ import { batchBoundaryGapReason } from "../../providers/speech-to-text/provider-catalog.js";
3
4
  import { SttError } from "../types.js";
4
5
 
5
6
  // ---------------------------------------------------------------------------
@@ -620,3 +621,24 @@ describe("vellum factory case", () => {
620
621
  expect(createDaemonBatchTranscriber(null, "deepgram")).toBeNull();
621
622
  });
622
623
  });
624
+
625
+ describe("deepgram-flux factory case", () => {
626
+ // The copy itself is pinned in provider-catalog.test.ts; what matters here
627
+ // is that the factory speaks with the catalog's voice rather than its own.
628
+ test("throws the catalog's streaming-only reason", () => {
629
+ expect(() =>
630
+ createDaemonBatchTranscriber("dg-test-key", "deepgram-flux"),
631
+ ).toThrow(batchBoundaryGapReason("deepgram-flux"));
632
+ });
633
+
634
+ test("marks the error user-facing so friendly copy does not overwrite it", () => {
635
+ try {
636
+ createDaemonBatchTranscriber("dg-test-key", "deepgram-flux");
637
+ throw new Error("expected the factory to throw");
638
+ } catch (err) {
639
+ expect(err).toBeInstanceOf(SttError);
640
+ expect((err as SttError).category).toBe("provider-error");
641
+ expect((err as SttError).userFacing).toBe(true);
642
+ }
643
+ });
644
+ });
@@ -2,10 +2,14 @@ import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import type {
4
4
  SttStreamServerClosedEvent,
5
+ SttStreamServerEagerTurnEndEvent,
5
6
  SttStreamServerErrorEvent,
6
7
  SttStreamServerEvent,
7
8
  SttStreamServerFinalEvent,
8
9
  SttStreamServerPartialEvent,
10
+ SttStreamServerTurnEndEvent,
11
+ SttStreamServerTurnResumedEvent,
12
+ SttStreamServerTurnStartEvent,
9
13
  } from "../types.js";
10
14
 
11
15
  // ---------------------------------------------------------------------------
@@ -87,3 +91,93 @@ describe("SttStreamServerEvent types", () => {
87
91
  expect(_label).toBeUndefined();
88
92
  });
89
93
  });
94
+
95
+ describe("turn-detection server events", () => {
96
+ test("turn-start event compiles and round-trips", () => {
97
+ const event: SttStreamServerTurnStartEvent = { type: "turn-start" };
98
+ const asUnion: SttStreamServerEvent = event;
99
+ expect(asUnion.type).toBe("turn-start");
100
+ });
101
+
102
+ test("eager-turn-end event carries the speculated transcript", () => {
103
+ const event: SttStreamServerEagerTurnEndEvent = {
104
+ type: "eager-turn-end",
105
+ text: "is this the end",
106
+ };
107
+ const asUnion: SttStreamServerEvent = event;
108
+ expect(asUnion.type).toBe("eager-turn-end");
109
+ expect(event.text).toBe("is this the end");
110
+ });
111
+
112
+ test("turn-resumed event compiles and round-trips", () => {
113
+ const event: SttStreamServerTurnResumedEvent = { type: "turn-resumed" };
114
+ const asUnion: SttStreamServerEvent = event;
115
+ expect(asUnion.type).toBe("turn-resumed");
116
+ });
117
+
118
+ test("turn-end event carries the committed transcript and optional confidence", () => {
119
+ const withoutConfidence: SttStreamServerTurnEndEvent = {
120
+ type: "turn-end",
121
+ text: "done speaking",
122
+ };
123
+ expect(withoutConfidence.confidence).toBeUndefined();
124
+
125
+ const event: SttStreamServerTurnEndEvent = {
126
+ type: "turn-end",
127
+ text: "done speaking",
128
+ confidence: 0.82,
129
+ };
130
+ const asUnion: SttStreamServerEvent = event;
131
+ expect(asUnion.type).toBe("turn-end");
132
+ expect(event.text).toBe("done speaking");
133
+ expect(event.confidence).toBe(0.82);
134
+ });
135
+
136
+ test("a consumer switch over every variant is exhaustive", () => {
137
+ // Fails to compile if a variant is added to SttStreamServerEvent
138
+ // without a case here, which is what forces consumers to be revisited.
139
+ const label = (event: SttStreamServerEvent): string => {
140
+ switch (event.type) {
141
+ case "partial":
142
+ case "final":
143
+ case "finalized":
144
+ case "error":
145
+ case "closed":
146
+ return "transcript";
147
+ case "turn-start":
148
+ case "eager-turn-end":
149
+ case "turn-resumed":
150
+ case "turn-end":
151
+ return "turn";
152
+ default: {
153
+ const _exhaustive: never = event;
154
+ return _exhaustive;
155
+ }
156
+ }
157
+ };
158
+
159
+ const events: SttStreamServerEvent[] = [
160
+ { type: "partial", text: "a" },
161
+ { type: "final", text: "a" },
162
+ { type: "finalized" },
163
+ { type: "error", category: "provider-error", message: "boom" },
164
+ { type: "closed" },
165
+ { type: "turn-start" },
166
+ { type: "eager-turn-end", text: "a" },
167
+ { type: "turn-resumed" },
168
+ { type: "turn-end", text: "a" },
169
+ ];
170
+
171
+ expect(events.map(label)).toEqual([
172
+ "transcript",
173
+ "transcript",
174
+ "transcript",
175
+ "transcript",
176
+ "transcript",
177
+ "turn",
178
+ "turn",
179
+ "turn",
180
+ "turn",
181
+ ]);
182
+ });
183
+ });
@@ -13,6 +13,7 @@
13
13
  * - xAI (`xai`)
14
14
  */
15
15
 
16
+ import { batchBoundaryGapReason } from "../providers/speech-to-text/provider-catalog.js";
16
17
  import type {
17
18
  BatchTranscriber,
18
19
  SttProviderId,
@@ -245,6 +246,9 @@ class VellumManagedBatchTranscriber implements BatchTranscriber {
245
246
  * language code), and the vellum managed path, whose platform proxy passes
246
247
  * it to Deepgram server-side. Whisper and Gemini auto-detect natively and
247
248
  * take no language parameter, so it is silently ignored for them.
249
+ *
250
+ * Throws an {@link SttError} for a provider with no batch endpoint at all,
251
+ * which no key can fix and `null` would understate.
248
252
  */
249
253
  export function createDaemonBatchTranscriber(
250
254
  apiKey: string | null | undefined,
@@ -268,6 +272,12 @@ export function createDaemonBatchTranscriber(
268
272
  return new GoogleGeminiBatchTranscriber(apiKey);
269
273
  case "xai":
270
274
  return new XAIBatchTranscriber(apiKey, language);
275
+ case "deepgram-flux":
276
+ // Same copy the resolver raises, so a direct factory caller and a
277
+ // config-driven one report the mismatch identically.
278
+ throw new SttError("provider-error", batchBoundaryGapReason(providerId), {
279
+ userFacing: true,
280
+ });
271
281
  default: {
272
282
  // Exhaustive check — compile error if a new SttProviderId is added
273
283
  // without a corresponding case here.
@@ -5,8 +5,11 @@
5
5
  * a client WebSocket connection and a provider-specific streaming adapter.
6
6
  * The orchestrator accepts client events (`audio`, `stop`), routes audio
7
7
  * frames to the resolved {@link StreamingTranscriber}, and emits normalized
8
- * server events (`partial`, `final`, `error`, `closed`) back over the same
9
- * WebSocket connection with per-session ordering guarantees.
8
+ * server events back over the same WebSocket connection with per-session
9
+ * ordering guarantees: transcripts (`partial`, `final`, `finalized`),
10
+ * turn boundaries from providers that detect them (`turn-start`,
11
+ * `eager-turn-end`, `turn-resumed`, `turn-end`), and termination
12
+ * (`error`, `closed`).
10
13
  *
11
14
  * Session lifecycle:
12
15
  * 1. Client opens a WebSocket to `/v1/stt/stream` with required `mimeType`
@@ -17,8 +20,9 @@
17
20
  * `resolveStreamingTranscriber()` and starts the provider session.
18
21
  * 3. The client sends `audio` frames (binary or base64-encoded JSON) and
19
22
  * a `stop` event when recording is complete.
20
- * 4. The provider emits `partial` and `final` transcript events which the
21
- * orchestrator forwards to the client as JSON frames.
23
+ * 4. The provider emits transcript events, plus turn-boundary events when it
24
+ * detects turns, and the orchestrator forwards each to the client as a
25
+ * JSON frame.
22
26
  * 5. The session closes deterministically on client disconnect, `stop`
23
27
  * event, idle timeout, or runtime shutdown.
24
28
  *