@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
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Tests for the shared OAuth callback URL resolver.
3
+ *
4
+ * The property that matters is stability: every caller and every attempt
5
+ * must get the same redirect URI. Dynamic client registration and Client
6
+ * ID Metadata Documents both pin `redirect_uris` when the client is
7
+ * registered, and the authorization server matches the value exactly on
8
+ * each authorization request, so a URI that varies per attempt makes both
9
+ * mechanisms unusable.
10
+ */
11
+
12
+ import { afterEach, describe, expect, mock, test } from "bun:test";
13
+
14
+ const resolveCallbackUrl = mock(
15
+ async () => "https://ingress.example/webhooks/oauth/callback",
16
+ );
17
+
18
+ mock.module("../platform-callback-registration.js", () => ({
19
+ resolveCallbackUrl,
20
+ }));
21
+
22
+ mock.module("../public-ingress-urls.js", () => ({
23
+ getOAuthCallbackUrl: () => "https://direct.example/webhooks/oauth/callback",
24
+ }));
25
+
26
+ mock.module("../../config/loader.js", () => ({
27
+ loadConfig: () => ({}),
28
+ }));
29
+
30
+ const { OAUTH_CALLBACK_PATH, resolveOauthCallbackUrl } =
31
+ await import("../oauth-callback-url.js");
32
+
33
+ afterEach(() => {
34
+ resolveCallbackUrl.mockClear();
35
+ });
36
+
37
+ describe("resolveOauthCallbackUrl", () => {
38
+ test("returns whatever the shared resolver decides", async () => {
39
+ await expect(resolveOauthCallbackUrl()).resolves.toEqual(
40
+ "https://ingress.example/webhooks/oauth/callback",
41
+ );
42
+ });
43
+
44
+ test("registers the shared callback path, not a per-caller one", async () => {
45
+ await resolveOauthCallbackUrl();
46
+ const [, callbackPath] = resolveCallbackUrl.mock.calls[0] as unknown[];
47
+ expect(callbackPath).toEqual(OAUTH_CALLBACK_PATH);
48
+ expect(OAUTH_CALLBACK_PATH).toEqual("webhooks/oauth/callback");
49
+ });
50
+
51
+ test("every call resolves to the same URL, path, and registration type", async () => {
52
+ // The URI a client registers and the URI it later authorizes with are
53
+ // the same string, which is what an exact-match redirect_uri check
54
+ // needs. Nothing about the caller can vary it: the function takes no
55
+ // arguments.
56
+ const first = await resolveOauthCallbackUrl();
57
+ const second = await resolveOauthCallbackUrl();
58
+ expect(first).toEqual(second);
59
+
60
+ const [, pathA, typeA] = resolveCallbackUrl.mock.calls[0] as unknown[];
61
+ const [, pathB, typeB] = resolveCallbackUrl.mock.calls[1] as unknown[];
62
+ expect(pathA).toEqual(pathB);
63
+ expect(typeA).toEqual(typeB);
64
+ });
65
+
66
+ test("registers one route type so the platform holds a single admin row", async () => {
67
+ await resolveOauthCallbackUrl();
68
+ const [, , type] = resolveCallbackUrl.mock.calls[0] as unknown[];
69
+ expect(type).toEqual("oauth");
70
+ });
71
+
72
+ test("propagates the resolver's failure rather than inventing a URL", async () => {
73
+ // No ingress and no platform connection means there is no URL that
74
+ // would work. Returning a plausible one produces an authorization
75
+ // request whose callback silently never arrives.
76
+ resolveCallbackUrl.mockImplementationOnce(async () => {
77
+ throw new Error("No public base URL configured.");
78
+ });
79
+ await expect(resolveOauthCallbackUrl()).rejects.toThrow(
80
+ /No public base URL/,
81
+ );
82
+ });
83
+ });
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Public URL resolution for the assistant's shared OAuth callback route.
3
+ *
4
+ * Every browser-based OAuth flow in the daemon redirects back to one path,
5
+ * `webhooks/oauth/callback`, which the gateway serves and forwards to
6
+ * `POST /v1/internal/oauth/callback`. The runtime matches the arriving
7
+ * `state` against `security/oauth-callback-registry.ts` and resolves the
8
+ * waiting flow, so one route multiplexes every concurrent handshake and no
9
+ * caller needs a listener of its own.
10
+ *
11
+ * Which base URL is correct depends on how the assistant is reachable: a
12
+ * platform pod and a platform-connected assistant are served through a
13
+ * managed callback route, a self-hosted deployment through its configured
14
+ * public ingress. `resolveCallbackUrl` owns that decision, and this is the
15
+ * OAuth-shaped entry point to it, mirroring `plugin-api/webhook-url.ts`
16
+ * for plugin ingress.
17
+ */
18
+
19
+ import { loadConfig } from "../config/loader.js";
20
+ import { resolveCallbackUrl } from "./platform-callback-registration.js";
21
+ import { getOAuthCallbackUrl } from "./public-ingress-urls.js";
22
+
23
+ /**
24
+ * Path the gateway serves the shared OAuth callback on.
25
+ *
26
+ * Fixed rather than caller-supplied. Every flow is demultiplexed by OAuth
27
+ * `state`, so a per-caller path would buy nothing and would need its own
28
+ * gateway route and its own platform registration.
29
+ */
30
+ export const OAUTH_CALLBACK_PATH = "webhooks/oauth/callback";
31
+
32
+ /**
33
+ * Registration type recorded with the platform.
34
+ *
35
+ * The platform keys a callback route by `(path, type)`, and there is one
36
+ * OAuth route, so one type describes it. Registering the same path under
37
+ * several types would produce duplicate admin rows pointing at the same
38
+ * URL.
39
+ */
40
+ const OAUTH_REGISTRATION_TYPE = "oauth";
41
+
42
+ /**
43
+ * Resolve the redirect URI an authorization server should send the user
44
+ * back to.
45
+ *
46
+ * Takes no arguments on purpose: every caller shares one route, so there
47
+ * is nothing to vary. That is what makes the URI stable across callers and
48
+ * across attempts, which is what an exact-match `redirect_uri` check needs.
49
+ *
50
+ * @throws when no public ingress is configured and the assistant is not
51
+ * connected to the platform. There is no URL that would work in that
52
+ * case, and returning a plausible one produces an authorization request
53
+ * whose callback silently never arrives.
54
+ */
55
+ export async function resolveOauthCallbackUrl(): Promise<string> {
56
+ return resolveCallbackUrl(
57
+ () => getOAuthCallbackUrl(loadConfig()),
58
+ OAUTH_CALLBACK_PATH,
59
+ OAUTH_REGISTRATION_TYPE,
60
+ );
61
+ }
@@ -143,7 +143,7 @@ describe("ipcClassifyRisk retry", () => {
143
143
  const CLASSIFY_OK = {
144
144
  risk: "low",
145
145
  reason: "safe",
146
- matchType: "none",
146
+ matchType: "registry",
147
147
  scopeOptions: [],
148
148
  };
149
149
  const emptyParams = {} as unknown as Parameters<typeof ipcClassifyRisk>[0];
@@ -10,16 +10,17 @@
10
10
  * deterministic fallback for long AF_UNIX paths.
11
11
  */
12
12
 
13
+ import {
14
+ type ClassifyRiskIpcParams,
15
+ type ClassifyRiskIpcResponse,
16
+ ClassifyRiskIpcResponseSchema,
17
+ } from "@vellumai/gateway-client";
13
18
  import {
14
19
  ipcCall as packageIpcCall,
15
20
  IpcCallError,
16
21
  PersistentIpcClient as PackagePersistentIpcClient,
17
22
  } from "@vellumai/gateway-client/ipc-client";
18
23
 
19
- import type {
20
- ClassificationResult,
21
- ClassifyRiskParams,
22
- } from "../permissions/ipc-risk-types.js";
23
24
  import { getLogger } from "../util/logger.js";
24
25
  import { abortableSleep, computeRetryDelay } from "../util/retry.js";
25
26
  import { resolveIpcSocketPath } from "./socket-path.js";
@@ -173,37 +174,29 @@ const CLASSIFY_RISK_ATTEMPT_TIMEOUT_MS = 1_500; // per-attempt cap (< 5s default
173
174
  * When a `signal` is supplied, retries stop as soon as it aborts.
174
175
  */
175
176
  export async function ipcClassifyRisk(
176
- params: ClassifyRiskParams,
177
+ params: ClassifyRiskIpcParams,
177
178
  signal?: AbortSignal,
178
- ): Promise<ClassificationResult | undefined> {
179
+ ): Promise<ClassifyRiskIpcResponse | undefined> {
179
180
  for (let attempt = 0; ; attempt++) {
180
181
  try {
181
182
  const result = await ipcCallPersistent(
182
183
  "classify_risk",
183
- params as unknown as Record<string, unknown>,
184
+ params,
184
185
  CLASSIFY_RISK_ATTEMPT_TIMEOUT_MS,
185
186
  );
186
187
 
187
- // Returned-but-malformed responses are deterministic, not transient:
188
+ // A returned-but-malformed response is deterministic, not transient:
188
189
  // fail closed immediately (no retry).
189
- if (!result || typeof result !== "object" || Array.isArray(result)) {
190
- log.warn(
191
- { result },
192
- "ipcClassifyRisk: gateway returned non-object response",
193
- );
194
- return undefined;
195
- }
196
-
197
- const obj = result as Record<string, unknown>;
198
- if (typeof obj.risk !== "string") {
190
+ const parsed = ClassifyRiskIpcResponseSchema.safeParse(result);
191
+ if (!parsed.success) {
199
192
  log.warn(
200
- { result },
201
- "ipcClassifyRisk: gateway response missing 'risk' field",
193
+ { result, issues: parsed.error.issues },
194
+ "ipcClassifyRisk: gateway response does not match the classify_risk contract",
202
195
  );
203
196
  return undefined;
204
197
  }
205
198
 
206
- return result as ClassificationResult;
199
+ return parsed.data;
207
200
  } catch (err) {
208
201
  // A structured gateway error means the gateway was reachable and
209
202
  // deterministically rejected the request — not a transient blip.
@@ -1,6 +1,7 @@
1
1
  import { connect, type Socket } from "node:net";
2
2
 
3
3
  import { refreshOverridesFromGateway } from "../config/assistant-feature-flags.js";
4
+ import { getBalancedModelExperimentArm } from "../config/balanced-model-experiment.js";
4
5
  import { reconcileFlagGatedProfiles } from "../config/sync-gated-profiles.js";
5
6
  import { SYNC_TAGS } from "../daemon/message-types/sync.js";
6
7
  import { publishConfigChanged } from "../runtime/sync/resource-sync-events.js";
@@ -19,13 +20,26 @@ const log = getLogger("gateway-flag-listener");
19
20
  * when the refresh confirmed flags loaded from the gateway — a transient IPC
20
21
  * failure leaves the cache unset and resolves `os-beta` to its registry default
21
22
  * `false`, which would remove the user's profile and reset their selection.
23
+ *
24
+ * A new balanced-model experiment arm gets the same broadcast. It repoints what
25
+ * the managed Balanced profile resolves to without moving anything on disk, so
26
+ * the reconcile reports no change and clients would otherwise keep rendering
27
+ * the previous model beside a profile already running the new one.
22
28
  */
23
29
  function refreshFlagsAndReconcileProfiles(context: string): void {
30
+ const balancedArmBefore = getBalancedModelExperimentArm();
24
31
  refreshOverridesFromGateway()
25
32
  .then((loaded) => {
26
- if (loaded && reconcileFlagGatedProfiles()) {
27
- // Reuse the config-changed broadcast clients already consume so the
28
- // profile picker reflects the added/removed managed profile.
33
+ if (!loaded) {
34
+ return;
35
+ }
36
+ const profilesChanged = reconcileFlagGatedProfiles();
37
+ const balancedArmChanged =
38
+ getBalancedModelExperimentArm() !== balancedArmBefore;
39
+ if (profilesChanged || balancedArmChanged) {
40
+ // Reuse the config-changed broadcast clients already consume: web
41
+ // routes the `assistant:self:config` sync tag to the effective profile
42
+ // catalog and the call-site catalog, both derived from config.
29
43
  publishConfigChanged();
30
44
  }
31
45
  })
@@ -1,16 +1,13 @@
1
1
  import { describe, expect, mock, test } from "bun:test";
2
2
 
3
- import { sanitizeForTts } from "../../calls/tts-text-sanitizer.js";
4
3
  import type {
5
4
  VoiceTurnCallbacks,
6
5
  VoiceTurnOptions,
7
6
  } from "../../calls/voice-session-bridge.js";
8
- import type { LiveVoiceFrontModelConfig } from "../../config/schemas/live-voice.js";
9
7
  import type {
10
8
  StreamingTranscriber,
11
9
  SttStreamServerEvent,
12
10
  } from "../../stt/types.js";
13
- import type { VoiceFrontDecider } from "../front-decision.js";
14
11
  import {
15
12
  LiveVoiceSession,
16
13
  type LiveVoiceTtsStreamer,
@@ -96,8 +93,6 @@ function createSessionHarness(
96
93
  createTurnId?: () => string;
97
94
  emitMetrics?: boolean;
98
95
  streamTtsAudio?: LiveVoiceTtsStreamer;
99
- frontModelConfig?: Partial<LiveVoiceFrontModelConfig>;
100
- frontDecider?: VoiceFrontDecider;
101
96
  } = {},
102
97
  ) {
103
98
  const transcriber =
@@ -119,10 +114,6 @@ function createSessionHarness(
119
114
  ...(options.streamTtsAudio
120
115
  ? { streamTtsAudio: options.streamTtsAudio }
121
116
  : {}),
122
- ...(options.frontModelConfig
123
- ? { frontModelConfig: options.frontModelConfig }
124
- : {}),
125
- ...(options.frontDecider ? { frontDecider: options.frontDecider } : {}),
126
117
  });
127
118
 
128
119
  return { frames, session, startVoiceTurn, transcriber };
@@ -468,7 +459,7 @@ describe("LiveVoiceSession assistant turn", () => {
468
459
  });
469
460
  });
470
461
 
471
- test("records tool_use_start on the active turn and publishes what it is doing", async () => {
462
+ test("publishes tool activity while the turn is running", async () => {
472
463
  let callbacks: VoiceTurnCallbacks | undefined;
473
464
  const startVoiceTurn = mock(async (options: VoiceTurnOptions) => {
474
465
  callbacks = options.callbacks;
@@ -488,12 +479,6 @@ describe("LiveVoiceSession assistant turn", () => {
488
479
  callbacks?.tool_use_start?.("some_tool");
489
480
  await waitForFrameCount(frames, 4);
490
481
 
491
- const activeTurn = (
492
- session as unknown as {
493
- activeAssistantTurn: { toolUseStarted: boolean } | null;
494
- }
495
- ).activeAssistantTurn;
496
- expect(activeTurn?.toolUseStarted).toBe(true);
497
482
  // One activity frame, so a silent stretch of tool work is visible on the
498
483
  // surfaces that show the session. An unrecognized tool still gets a line.
499
484
  expect(frames.at(-1)).toMatchObject({
@@ -560,90 +545,6 @@ describe("LiveVoiceSession assistant turn", () => {
560
545
  });
561
546
  });
562
547
 
563
- describe("LiveVoiceSession tool-use spoken ack", () => {
564
- const ACK_TIMEOUT_MS = 40;
565
- // Every ack is front-model-phrased; the generated text passes through the
566
- // same TTS sanitizer as regular segments. The stub varies its phrasing by
567
- // trigger so the two ack kinds stay distinguishable in assertions.
568
- const TOOL_ACK = "Let me look that up.";
569
- const FIRST_DELTA_ACK = "Sure — one moment.";
570
- const EXPECTED_TOOL_ACK = sanitizeForTts(TOOL_ACK).trim();
571
- const EXPECTED_FIRST_DELTA_ACK = sanitizeForTts(FIRST_DELTA_ACK).trim();
572
-
573
- const ackDecider: VoiceFrontDecider = {
574
- generateAckText: async (input) =>
575
- input.toolName ? TOOL_ACK : FIRST_DELTA_ACK,
576
- generateProgressText: async () => null,
577
- };
578
-
579
- function createAckHarness() {
580
- const { startVoiceTurn, getCallbacks } = createCapturingTurnStarter();
581
- const { streamTtsAudio, ttsTexts } = createRecordingTtsStreamer();
582
- const harness = createSessionHarness({
583
- startVoiceTurn,
584
- streamTtsAudio,
585
- frontModelConfig: { ackFirstDeltaTimeoutMs: ACK_TIMEOUT_MS },
586
- frontDecider: ackDecider,
587
- });
588
- return { ...harness, getCallbacks, ttsTexts };
589
- }
590
-
591
- test("tool_use_start before any delta speaks an immediate tool ack and cancels the timer", async () => {
592
- const { frames, session, getCallbacks, ttsTexts } = createAckHarness();
593
-
594
- await startReleasedTurn(session, getCallbacks);
595
- getCallbacks()?.tool_use_start?.("web_search");
596
- await waitFor(() => ttsTexts.length === 1);
597
- expect(ttsTexts).toEqual([EXPECTED_TOOL_ACK]);
598
-
599
- // The pending first-delta timer was cancelled: letting its budget elapse
600
- // speaks no second ack.
601
- await new Promise((resolve) => setTimeout(resolve, ACK_TIMEOUT_MS + 40));
602
- expect(ttsTexts).toEqual([EXPECTED_TOOL_ACK]);
603
-
604
- // The ack is audio-only — no caption frame carries it.
605
- expect(frames.some((frame) => frame.type === "assistant_text_delta")).toBe(
606
- false,
607
- );
608
-
609
- emitTextDelta(getCallbacks, "Hello there.");
610
- emitMessageComplete(getCallbacks);
611
- await waitFor(() => frames.some((frame) => frame.type === "tts_done"));
612
- expect(ttsTexts).toEqual([EXPECTED_TOOL_ACK, "Hello there."]);
613
- });
614
-
615
- test("tool_use_start after the first delta speaks no ack", async () => {
616
- const { frames, session, getCallbacks, ttsTexts } = createAckHarness();
617
-
618
- await startReleasedTurn(session, getCallbacks);
619
- emitTextDelta(getCallbacks, "Hello there.");
620
- getCallbacks()?.tool_use_start?.("web_search");
621
- emitMessageComplete(getCallbacks);
622
- await waitFor(() => frames.some((frame) => frame.type === "tts_done"));
623
- await new Promise((resolve) => setTimeout(resolve, ACK_TIMEOUT_MS + 40));
624
-
625
- expect(ttsTexts).toEqual(["Hello there."]);
626
- });
627
-
628
- test("tool_use_start after a first-delta ack already spoke adds no second ack", async () => {
629
- const { frames, session, getCallbacks, ttsTexts } = createAckHarness();
630
-
631
- await startReleasedTurn(session, getCallbacks);
632
- // Let the slow-first-delta timer speak the turn's one ack first.
633
- await waitFor(() => ttsTexts.length === 1);
634
- expect(ttsTexts).toEqual([EXPECTED_FIRST_DELTA_ACK]);
635
-
636
- getCallbacks()?.tool_use_start?.("web_search");
637
- await flushAsyncCallbacks();
638
- expect(ttsTexts).toEqual([EXPECTED_FIRST_DELTA_ACK]);
639
-
640
- emitTextDelta(getCallbacks, "Hello there.");
641
- emitMessageComplete(getCallbacks);
642
- await waitFor(() => frames.some((frame) => frame.type === "tts_done"));
643
- expect(ttsTexts).toEqual([EXPECTED_FIRST_DELTA_ACK, "Hello there."]);
644
- });
645
- });
646
-
647
548
  describe("LiveVoiceSession room reveal", () => {
648
549
  function createMarkerHarness() {
649
550
  const { startVoiceTurn, getCallbacks } = createCapturingTurnStarter();
@@ -651,9 +552,6 @@ describe("LiveVoiceSession room reveal", () => {
651
552
  const harness = createSessionHarness({
652
553
  startVoiceTurn,
653
554
  streamTtsAudio,
654
- // Deltas are emitted immediately in these runs; a long ack budget keeps
655
- // filler phrases out of the recorded TTS text.
656
- frontModelConfig: { ackFirstDeltaTimeoutMs: 10_000 },
657
555
  });
658
556
  return { ...harness, getCallbacks, ttsTexts };
659
557
  }
@@ -689,7 +587,6 @@ describe("LiveVoiceSession room reveal", () => {
689
587
  const harness = createSessionHarness({
690
588
  startVoiceTurn,
691
589
  streamTtsAudio,
692
- frontModelConfig: { ackFirstDeltaTimeoutMs: 10_000 },
693
590
  });
694
591
  return {
695
592
  ...harness,
@@ -4,7 +4,6 @@ import type {
4
4
  VoiceTurnCallbacks,
5
5
  VoiceTurnOptions,
6
6
  } from "../../calls/voice-session-bridge.js";
7
- import { VOICE_NO_SETUP_FLOWS_RULE } from "../../calls/voice-session-bridge.js";
8
7
  import type {
9
8
  StreamingTranscriber,
10
9
  SttStreamServerEvent,
@@ -254,14 +253,14 @@ describe("LiveVoiceSession archive and metrics events", () => {
254
253
  userMessageInterface: "macos",
255
254
  assistantMessageInterface: "macos",
256
255
  // Pins the full production control prompt for the FRONT-DOOR leg (the
257
- // first leg of every routed turn): the speech-first rule (which now
258
- // permits a surface, since the room reveals one by itself) and the
259
- // shared no-setup-flows rule (no OAuth/browser flows mid-call). The [-1]
260
- // room-minimize teaching is deliberately absent — only the escalated
261
- // leg learns it (see live-voice-triage-escalate.test.ts).
256
+ // first leg of every routed turn): the speech-first rule, and nothing
257
+ // else. This leg is toolless, so both the screen-reveal and setup-flow
258
+ // teachings are deliberately absent. It has nothing to show and no
259
+ // connection to run, and its capability digest already routes anything
260
+ // needing a tool to the escalated leg (see
261
+ // live-voice-triage-escalate.test.ts).
262
262
  voiceControlPrompt:
263
- "You are speaking in a local live voice session. Keep replies brief and conversational. Speech is the main channel: say the answer, and do not narrate a surface instead of answering. You can also put something on screen when it genuinely helps (a form, a list to pick from, a progress card for long work); the call overlay minimizes by itself once you finish speaking, so the user sees it without doing anything. Never tell the user you cannot show them something. Reply in the language the caller is speaking; if they switch languages, switch with them. " +
264
- VOICE_NO_SETUP_FLOWS_RULE,
263
+ "You are speaking in a local live voice session. Keep replies brief and conversational. Speech is the main channel: say the answer, and do not narrate a surface instead of answering. You can also put something on screen when it genuinely helps (a form, a list to pick from, a progress card for long work); the call overlay minimizes by itself once you finish speaking, so the user sees it without doing anything. Never tell the user you cannot show them something. Reply in the language the caller is speaking; if they switch languages, switch with them. ",
265
264
  });
266
265
  callbacks?.assistant_text_delta?.(makeTextDelta("Hello there."));
267
266
  callbacks?.message_complete?.(makeMessageComplete());