@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,278 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { afterEach, describe, expect, test } from "bun:test";
4
+
5
+ import type { z } from "zod";
6
+
7
+ import { setOverridesForTesting } from "../../__tests__/feature-flag-test-helpers.js";
8
+ import {
9
+ catalogMaxOutputTokens,
10
+ isModelInCatalog,
11
+ } from "../../providers/model-catalog.js";
12
+ import { getManagedUpstream } from "../../providers/vellum-model-routing.js";
13
+ import { BALANCED_MODEL_EXPERIMENT_FLAG_KEY } from "../balanced-model-experiment.js";
14
+ import {
15
+ CODE_DEFAULT_PROFILE_ENTRIES,
16
+ getEffectiveProfilesForProvider,
17
+ resolveDefaultProfileForProvider,
18
+ } from "../default-profile-catalog.js";
19
+ import { clearCachedOverrides } from "../feature-flag-cache.js";
20
+ import { resolveCallSiteConfig } from "../llm-resolver.js";
21
+ import {
22
+ type DefaultProviderConfig,
23
+ LLMSchema,
24
+ type ProfileEntry,
25
+ } from "../schemas/llm.js";
26
+
27
+ // The `experiment-balanced-model-2026-08-06` arm repoints the model the managed
28
+ // Balanced profile resolves to. Both the runtime resolver and the client-facing
29
+ // profile listing go through `defaultProfileBodyForProvider`, so both are
30
+ // exercised here: a disagreement between them shows the user one model beside a
31
+ // profile that runs another.
32
+
33
+ const FLAG = BALANCED_MODEL_EXPERIMENT_FLAG_KEY;
34
+ const SHIPPED_MODEL = "gpt-5.6-luna";
35
+ const GLM_MODEL = "accounts/fireworks/models/glm-5p2";
36
+
37
+ function setArm(value: boolean | string): void {
38
+ setOverridesForTesting({ [FLAG]: value });
39
+ }
40
+
41
+ const managed: DefaultProviderConfig = { provider: "vellum" };
42
+
43
+ function llmWithActiveBalanced(
44
+ overrides: Record<string, unknown> = {},
45
+ ): z.infer<typeof LLMSchema> {
46
+ return LLMSchema.parse({
47
+ profiles: {},
48
+ profileOrder: [],
49
+ activeProfile: "balanced",
50
+ defaultProvider: managed,
51
+ ...overrides,
52
+ });
53
+ }
54
+
55
+ afterEach(() => {
56
+ clearCachedOverrides();
57
+ });
58
+
59
+ describe("balanced-model experiment arms", () => {
60
+ test("terra repoints mainAgent at gpt-5.6-terra on the managed connection", () => {
61
+ setArm("terra");
62
+ const resolved = resolveCallSiteConfig(
63
+ "mainAgent",
64
+ llmWithActiveBalanced(),
65
+ );
66
+ expect(resolved.model).toBe("gpt-5.6-terra");
67
+ expect(resolved.provider).toBe("vellum");
68
+ expect(getManagedUpstream("gpt-5.6-terra")).toBe("openai");
69
+
70
+ const entry = resolveDefaultProfileForProvider(
71
+ undefined,
72
+ "balanced",
73
+ managed,
74
+ );
75
+ expect(entry?.model).toBe("gpt-5.6-terra");
76
+ expect(entry?.provider).toBe("vellum");
77
+ // Routing-identity providers derive their connection per request.
78
+ expect(entry?.provider_connection).toBeUndefined();
79
+ expect(entry?.source).toBe("managed");
80
+ });
81
+
82
+ test("glm-5p2 repoints mainAgent at GLM 5.2 within the model's output cap", () => {
83
+ setArm("glm-5p2");
84
+ const resolved = resolveCallSiteConfig(
85
+ "mainAgent",
86
+ llmWithActiveBalanced(),
87
+ );
88
+ expect(resolved.model).toBe(GLM_MODEL);
89
+ expect(resolved.provider).toBe("vellum");
90
+
91
+ const upstream = getManagedUpstream(GLM_MODEL);
92
+ expect(upstream).toBe("fireworks");
93
+ const cap = catalogMaxOutputTokens(upstream as string, GLM_MODEL);
94
+ expect(cap).toBeDefined();
95
+ expect(resolved.maxTokens).toBeLessThanOrEqual(cap as number);
96
+ // Only the model moves: the shipped token budget stands.
97
+ expect(resolved.maxTokens).toBe(
98
+ CODE_DEFAULT_PROFILE_ENTRIES.balanced.maxTokens as number,
99
+ );
100
+ });
101
+
102
+ test("an arm changes only the model of the managed balanced body", () => {
103
+ setArm("terra");
104
+ const entry = resolveDefaultProfileForProvider(
105
+ undefined,
106
+ "balanced",
107
+ managed,
108
+ );
109
+ const shipped = CODE_DEFAULT_PROFILE_ENTRIES.balanced;
110
+ expect(entry).toEqual({ ...shipped, model: "gpt-5.6-terra" });
111
+ });
112
+
113
+ test("the other default profiles are untouched by an arm", () => {
114
+ setArm("glm-5p2");
115
+ for (const key of [
116
+ "quality-optimized",
117
+ "cost-optimized",
118
+ "latency-optimized",
119
+ ]) {
120
+ expect(
121
+ resolveDefaultProfileForProvider(undefined, key, managed)?.model,
122
+ ).toBe(CODE_DEFAULT_PROFILE_ENTRIES[key].model);
123
+ }
124
+ });
125
+
126
+ test("every pinned arm model is managed-routable and in its upstream catalog", () => {
127
+ for (const model of ["gpt-5.6-terra", GLM_MODEL]) {
128
+ const upstream = getManagedUpstream(model);
129
+ expect(upstream).not.toBeNull();
130
+ expect(isModelInCatalog(upstream as string, model)).toBe(true);
131
+ }
132
+ });
133
+ });
134
+
135
+ describe("balanced-model experiment fallbacks", () => {
136
+ const shippedCases: [string, () => void][] = [
137
+ ["the flag is unset", () => clearCachedOverrides()],
138
+ ["no override is present", () => setOverridesForTesting({})],
139
+ ["the arm is control", () => setArm("control")],
140
+ ["the arm is an unknown string", () => setArm("gpt-9-does-not-exist")],
141
+ ["the arm is the empty string", () => setArm("")],
142
+ ["the value is boolean true", () => setArm(true)],
143
+ ["the value is boolean false", () => setArm(false)],
144
+ // The arm is remote input, so it can name an Object.prototype member. The
145
+ // pin table is a Map, which has no such members to inherit.
146
+ ["the arm is constructor", () => setArm("constructor")],
147
+ ["the arm is toString", () => setArm("toString")],
148
+ ["the arm is valueOf", () => setArm("valueOf")],
149
+ ["the arm is __proto__", () => setArm("__proto__")],
150
+ ["the arm is hasOwnProperty", () => setArm("hasOwnProperty")],
151
+ ];
152
+
153
+ for (const [label, seed] of shippedCases) {
154
+ test(`balanced stays on the shipped model when ${label}`, () => {
155
+ seed();
156
+ expect(
157
+ resolveDefaultProfileForProvider(undefined, "balanced", managed)?.model,
158
+ ).toBe(SHIPPED_MODEL);
159
+ expect(
160
+ resolveCallSiteConfig("mainAgent", llmWithActiveBalanced()).model,
161
+ ).toBe(SHIPPED_MODEL);
162
+ });
163
+ }
164
+
165
+ test("the shipped catalog body is the control arm", () => {
166
+ expect(CODE_DEFAULT_PROFILE_ENTRIES.balanced.model).toBe(SHIPPED_MODEL);
167
+ });
168
+
169
+ test("the registry default is control, which the override-only flag read assumes", () => {
170
+ const registryPath = join(
171
+ import.meta.dirname,
172
+ "..",
173
+ "..",
174
+ "..",
175
+ "..",
176
+ "meta",
177
+ "feature-flags",
178
+ "feature-flag-registry.json",
179
+ );
180
+ const registry = JSON.parse(readFileSync(registryPath, "utf-8")) as {
181
+ flags: {
182
+ key: string;
183
+ scope: string;
184
+ defaultEnabled: boolean | string;
185
+ values?: string[];
186
+ }[];
187
+ };
188
+ const flag = registry.flags.find((entry) => entry.key === FLAG);
189
+ expect(flag).toBeDefined();
190
+ expect(flag?.scope).toBe("assistant");
191
+ expect(flag?.defaultEnabled).toBe("control");
192
+ expect(flag?.values).toEqual(["control", "terra", "glm-5p2"]);
193
+ });
194
+ });
195
+
196
+ describe("balanced-model experiment boundaries", () => {
197
+ test("a user-owned balanced shadow wins over the arm", () => {
198
+ setArm("terra");
199
+ const profiles: Record<string, ProfileEntry> = {
200
+ balanced: { source: "user", provider: "openai", model: "gpt-5.5" },
201
+ };
202
+ expect(
203
+ resolveDefaultProfileForProvider(profiles, "balanced", managed),
204
+ ).toEqual(profiles.balanced);
205
+ expect(
206
+ resolveCallSiteConfig("mainAgent", llmWithActiveBalanced({ profiles }))
207
+ .model,
208
+ ).toBe("gpt-5.5");
209
+ });
210
+
211
+ test("a managed-source stub still resolves to the arm's body", () => {
212
+ setArm("terra");
213
+ const profiles: Record<string, ProfileEntry> = {
214
+ balanced: { source: "managed", label: "My Balanced" },
215
+ };
216
+ const entry = resolveDefaultProfileForProvider(
217
+ profiles,
218
+ "balanced",
219
+ managed,
220
+ );
221
+ expect(entry?.model).toBe("gpt-5.6-terra");
222
+ expect(entry?.label).toBe("My Balanced");
223
+ });
224
+
225
+ test("the chatgpt and BYOK columns stay out of the experiment", () => {
226
+ setArm("terra");
227
+ for (const provider of ["anthropic", "openai", "chatgpt"] as const) {
228
+ const armed = resolveDefaultProfileForProvider(undefined, "balanced", {
229
+ provider,
230
+ });
231
+ clearCachedOverrides();
232
+ const shipped = resolveDefaultProfileForProvider(undefined, "balanced", {
233
+ provider,
234
+ });
235
+ expect(armed).toEqual(shipped as ProfileEntry);
236
+ expect(armed?.provider).toBe(provider);
237
+ setArm("terra");
238
+ }
239
+ });
240
+
241
+ test("an install with no defaultProvider still picks up the arm", () => {
242
+ setArm("glm-5p2");
243
+ expect(
244
+ resolveDefaultProfileForProvider(undefined, "balanced", null)?.model,
245
+ ).toBe(GLM_MODEL);
246
+ });
247
+ });
248
+
249
+ describe("client-facing profile listing", () => {
250
+ test("reports the arm's model so the UI matches what runs", () => {
251
+ setArm("terra");
252
+ const profiles = getEffectiveProfilesForProvider(undefined, managed);
253
+ expect(profiles.balanced?.model).toBe("gpt-5.6-terra");
254
+ expect(profiles["quality-optimized"]?.model).toBe(
255
+ CODE_DEFAULT_PROFILE_ENTRIES["quality-optimized"].model,
256
+ );
257
+ });
258
+
259
+ test("reports the shipped model on the control arm", () => {
260
+ setArm("control");
261
+ expect(
262
+ getEffectiveProfilesForProvider(undefined, managed).balanced?.model,
263
+ ).toBe(SHIPPED_MODEL);
264
+ });
265
+
266
+ test("agrees with the runtime resolver on every arm", () => {
267
+ for (const arm of ["control", "terra", "glm-5p2", "nonsense"]) {
268
+ setArm(arm);
269
+ const listed = getEffectiveProfilesForProvider(undefined, managed)
270
+ .balanced?.model;
271
+ const resolved = resolveCallSiteConfig(
272
+ "mainAgent",
273
+ llmWithActiveBalanced(),
274
+ ).model;
275
+ expect(listed).toBe(resolved as string);
276
+ }
277
+ });
278
+ });
@@ -7,6 +7,7 @@ import {
7
7
  CODE_DEFAULT_PROFILE_ENTRIES,
8
8
  getEffectiveProfile,
9
9
  getEffectiveProfiles,
10
+ getEffectiveProfilesForProvider,
10
11
  PROFILE_IMPLS,
11
12
  resolveDefaultProfileForProvider,
12
13
  } from "../default-profile-catalog.js";
@@ -22,6 +23,7 @@ import {
22
23
  import {
23
24
  type DefaultProviderConfig,
24
25
  type LLMCallSite,
26
+ LLMCallSiteEnum,
25
27
  LLMSchema,
26
28
  type ProfileEntry,
27
29
  } from "../schemas/llm.js";
@@ -245,7 +247,10 @@ describe("resolver integration", () => {
245
247
  },
246
248
  });
247
249
  const body = CODE_DEFAULT_PROFILE_ENTRIES["latency-optimized"]!;
248
- for (const callSite of ["voiceFrontDoor", "voiceFrontDecision"] as const) {
250
+ for (const callSite of [
251
+ "voiceFrontDoor",
252
+ "voiceProgressNarration",
253
+ ] as const) {
249
254
  const resolved = resolveCallSiteConfig(callSite, llm);
250
255
  expect(resolved.model).toBe(body.model as string);
251
256
  expect(resolved.model).not.toBe("claude-opus-4-6");
@@ -265,6 +270,12 @@ describe("resolver integration", () => {
265
270
  });
266
271
 
267
272
  describe("schema validation", () => {
273
+ test("voiceFrontDoor is the only front callsite", () => {
274
+ expect(
275
+ LLMCallSiteEnum.options.filter((callSite) => callSite.includes("Front")),
276
+ ).toEqual(["voiceFrontDoor"]);
277
+ });
278
+
268
279
  test("always-available default names are valid references; os-beta only when materialized", () => {
269
280
  expect(() => LLMSchema.parse({ activeProfile: "balanced" })).not.toThrow();
270
281
  expect(() =>
@@ -323,7 +334,7 @@ describe("resolveDefaultProfileForProvider", () => {
323
334
  expect(typeof entry?.model).toBe("string");
324
335
  expect(entry?.provider).toBeDefined();
325
336
  // Identity columns stamp no connection; BYOK columns always do.
326
- if (entry?.provider === "vellum") {
337
+ if (entry?.provider === "vellum" || entry?.provider === "chatgpt") {
327
338
  expect(entry?.provider_connection).toBeUndefined();
328
339
  } else {
329
340
  expect(entry?.provider_connection).toBeDefined();
@@ -333,6 +344,27 @@ describe("resolveDefaultProfileForProvider", () => {
333
344
  }
334
345
  });
335
346
 
347
+ test("the chatgpt column resolves Codex-pinned models with no connection stamp", () => {
348
+ const byKey: Record<string, string> = {
349
+ balanced: "gpt-5.6-luna",
350
+ "quality-optimized": "gpt-5.6-sol",
351
+ "cost-optimized": "gpt-5.6-luna",
352
+ "latency-optimized": "gpt-5.6-luna",
353
+ };
354
+ const effective = getEffectiveProfilesForProvider(undefined, dp("chatgpt"));
355
+ for (const [key, model] of Object.entries(byKey)) {
356
+ const entry = effective[key];
357
+ expect(entry?.provider).toBe("chatgpt");
358
+ expect(entry?.model).toBe(model);
359
+ expect(entry?.provider_connection).toBeUndefined();
360
+ expect(entry?.source).toBe("managed");
361
+ }
362
+ // Cost and Speed both opt fully out of reasoning.
363
+ expect(effective["cost-optimized"]?.effort).toBe("none");
364
+ expect(effective["latency-optimized"]?.effort).toBe("none");
365
+ expect(effective.balanced?.thinking?.enabled).toBe(true);
366
+ });
367
+
336
368
  test("a provider without a named matrix column materializes from the shared BYOK templates", () => {
337
369
  const entry = resolveDefaultProfileForProvider(
338
370
  undefined,
@@ -157,6 +157,12 @@ describe("resolveDefaultConnectionName", () => {
157
157
  );
158
158
  });
159
159
 
160
+ test("chatgpt resolves to the canonical subscription connection name", () => {
161
+ expect(resolveDefaultConnectionName({ provider: "chatgpt" })).toBe(
162
+ "chatgpt-subscription",
163
+ );
164
+ });
165
+
160
166
  test("every other provider resolves to its personal connection", () => {
161
167
  expect(resolveDefaultConnectionName({ provider: "anthropic" })).toBe(
162
168
  "anthropic-personal",
@@ -221,7 +227,6 @@ describe("getDefaultProvider / setDefaultProvider", () => {
221
227
  test("setDefaultProvider validates the provider before writing", () => {
222
228
  expect(() =>
223
229
  setDefaultProvider({
224
- // @ts-expect-error deliberately invalid for the test
225
230
  provider: "not-a-provider",
226
231
  }),
227
232
  ).toThrow();
@@ -1,4 +1,17 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, mock, test } from "bun:test";
2
+
3
+ // Entry-name folds are gated on the named row existing with an agreeing
4
+ // kind, so the tests control the row store directly.
5
+ const connectionRows = new Map<string, { name: string; provider: string }>([
6
+ ["anthropic-personal", { name: "anthropic-personal", provider: "anthropic" }],
7
+ ]);
8
+ mock.module("../../persistence/db-connection.js", () => ({
9
+ getDb: () => ({}),
10
+ }));
11
+ mock.module("../../providers/inference/connections.js", () => ({
12
+ getConnection: (_db: unknown, name: string) =>
13
+ connectionRows.get(name) ?? null,
14
+ }));
2
15
 
3
16
  import { VELLUM_MANAGED_CONNECTION_NAME } from "../../providers/vellum-model-routing.js";
4
17
  import { completeCustomProfile } from "../profile-materialization.js";
@@ -28,8 +41,10 @@ describe("completeCustomProfile", () => {
28
41
  model: "claude-fable-5",
29
42
  });
30
43
  expect(completed.model).toBe("claude-fable-5");
31
- expect(completed.provider).toBe("anthropic");
32
- expect(completed.provider_connection).toBe("anthropic-personal");
44
+ // The default's explicit binding is inherited IN the provider value
45
+ // (the entries-model representation), never as a stamped binding.
46
+ expect(completed.provider).toBe("anthropic-personal");
47
+ expect(completed.provider_connection).toBeUndefined();
33
48
  expect(completed.maxTokens).toBe(64000);
34
49
  expect(completed.effort).toBe("max");
35
50
  expect(completed.speed).toBe("standard");
@@ -78,12 +93,12 @@ describe("completeCustomProfile", () => {
78
93
  expect(completed.contextWindow?.overflowRecovery?.enabled).toBe(true);
79
94
  });
80
95
 
81
- test("keeps the inherited provider when it serves the profile's model", () => {
96
+ test("inherits the default's binding as the entry name when the provider serves the model", () => {
82
97
  const completed = completeCustomProfile(fullDefault, {
83
98
  model: "claude-fable-5",
84
99
  });
85
- expect(completed.provider).toBe("anthropic");
86
- expect(completed.provider_connection).toBe("anthropic-personal");
100
+ expect(completed.provider).toBe("anthropic-personal");
101
+ expect(completed.provider_connection).toBeUndefined();
87
102
  });
88
103
 
89
104
  test("stamps the catalog owner for a model the default provider does not serve, and drops the default's connection", () => {
@@ -123,36 +138,77 @@ describe("completeCustomProfile", () => {
123
138
  expect(completed.provider_connection).toBeUndefined();
124
139
  });
125
140
 
126
- test("inherits the vellum managed connection across a provider change, but only onto managed-routable providers", () => {
141
+ test("a managed default's binding becomes the routing identity, never a stamped field", () => {
127
142
  const managedDefault = LLMConfigBase.parse({
128
143
  ...fullDefault,
129
144
  provider_connection: VELLUM_MANAGED_CONNECTION_NAME,
130
145
  });
131
146
  const implied = completeCustomProfile(managedDefault, { model: "gpt-5.5" });
132
- expect(implied.provider).toBe("openai");
133
- expect(implied.provider_connection).toBe(VELLUM_MANAGED_CONNECTION_NAME);
147
+ expect(implied.provider).toBe("vellum");
148
+ expect(implied.provider_connection).toBeUndefined();
134
149
 
135
150
  const explicit = completeCustomProfile(managedDefault, {
136
151
  provider: "openai",
137
152
  model: "gpt-5.4",
138
153
  });
139
- expect(explicit.provider_connection).toBe(VELLUM_MANAGED_CONNECTION_NAME);
154
+ expect(explicit.provider).toBe("vellum");
155
+ expect(explicit.provider_connection).toBeUndefined();
156
+ });
140
157
 
141
- // The vellum connection can't route a non-managed provider; baking it in
142
- // would fail dispatch's mismatch path instead of auto-resolving.
143
- const nonRoutable = completeCustomProfile(managedDefault, {
144
- provider: "openrouter",
145
- model: "minimax/minimax-m3",
158
+ test("inherits the binding as the entry name even for a model unknown to the catalog", () => {
159
+ const completed = completeCustomProfile(fullDefault, {
160
+ model: "totally-custom-model",
146
161
  });
147
- expect(nonRoutable.provider_connection).toBeUndefined();
162
+ expect(completed.provider).toBe("anthropic-personal");
163
+ expect(completed.provider_connection).toBeUndefined();
148
164
  });
149
165
 
150
- test("keeps the inherited provider for a model unknown to the catalog", () => {
151
- const completed = completeCustomProfile(fullDefault, {
166
+ test("a dangling default binding passes through as the legacy field", () => {
167
+ const dangling = LLMConfigBase.parse({
168
+ ...fullDefault,
169
+ provider_connection: "deleted-row",
170
+ });
171
+ const completed = completeCustomProfile(dangling, {
172
+ model: "claude-fable-5",
173
+ });
174
+ // Folding an unverifiable binding would hide it from the collapse
175
+ // migration's dangling recovery; the legacy field keeps it visible.
176
+ expect(completed.provider).toBe("anthropic");
177
+ expect(completed.provider_connection).toBe("deleted-row");
178
+ });
179
+
180
+ test("a kind-disagreeing default binding passes through as the legacy field", () => {
181
+ connectionRows.set("mislabeled", {
182
+ name: "mislabeled",
183
+ provider: "openai",
184
+ });
185
+ try {
186
+ const mismatched = LLMConfigBase.parse({
187
+ ...fullDefault,
188
+ provider_connection: "mislabeled",
189
+ });
190
+ const completed = completeCustomProfile(mismatched, {
191
+ model: "claude-fable-5",
192
+ });
193
+ expect(completed.provider).toBe("anthropic");
194
+ expect(completed.provider_connection).toBe("mislabeled");
195
+ } finally {
196
+ connectionRows.delete("mislabeled");
197
+ }
198
+ });
199
+
200
+ test("a managed default binding is not inherited when the identity cannot serve the model", () => {
201
+ const managedDefault = LLMConfigBase.parse({
202
+ ...fullDefault,
203
+ provider_connection: VELLUM_MANAGED_CONNECTION_NAME,
204
+ });
205
+ const completed = completeCustomProfile(managedDefault, {
152
206
  model: "totally-custom-model",
153
207
  });
208
+ // Dispatch auto-resolves by vendor instead of pinning an unservable
209
+ // managed route.
154
210
  expect(completed.provider).toBe("anthropic");
155
- expect(completed.provider_connection).toBe("anthropic-personal");
211
+ expect(completed.provider_connection).toBeUndefined();
156
212
  });
157
213
 
158
214
  test("passes mix profiles through untouched", () => {
@@ -59,6 +59,12 @@ function loadDefaultsRegistry(): FeatureFlagDefaultsRegistry {
59
59
  // Works in Docker / packaged builds where the repo-root `meta/` dir
60
60
  // is not available.
61
61
  join(thisDir, REGISTRY_FILENAME),
62
+ ...(process.platform === "win32"
63
+ ? [
64
+ // Packaged Windows CLI runtime: assets live beside the executable.
65
+ join(dirname(process.execPath), REGISTRY_FILENAME),
66
+ ]
67
+ : []),
62
68
  // Packaged macOS app layout: the daemon binary lives at
63
69
  // <App>.app/Contents/MacOS/vellum-daemon and the registry is copied
64
70
  // to <App>.app/Contents/Resources/ by build.sh. In bun --compile
@@ -190,11 +196,11 @@ const DEFAULT_INIT_RETRY_BACKOFFS_MS: readonly number[] = [
190
196
  * intentionally simulate an unreachable gateway and want immediate
191
197
  * fallback without waiting through the production schedule).
192
198
  *
193
- * No-ops when the cache is already populated — callers that want to
194
- * refresh must call `clearFeatureFlagOverridesCache()` first. This lets
195
- * tests preseed flag state via `setOverridesForTesting()` (in
196
- * `__tests__/feature-flag-test-helpers.ts`) without the gateway IPC call
197
- * clobbering their setup.
199
+ * No-ops when the cache is already populated — this is the load-time
200
+ * populate, and `refreshOverridesFromGateway()` is what re-reads a cache that
201
+ * already holds values. The no-op also lets tests preseed flag state via
202
+ * `setOverridesForTesting()` (in `__tests__/feature-flag-test-helpers.ts`)
203
+ * without the gateway IPC call clobbering their setup.
198
204
  *
199
205
  * Resolves `true` when the override cache is populated from the gateway and
200
206
  * `false` when the cache is left unset (exhausted retries / unreachable
@@ -274,10 +280,13 @@ function loadOverrides(): Record<string, boolean | string> {
274
280
  * Invalidate the cached overrides so the next call to
275
281
  * `isAssistantFeatureFlagEnabled` re-reads from the gateway.
276
282
  *
277
- * Called by `refreshOverridesFromGateway()` when the gateway pushes a
278
- * `feature_flags_changed` event, and by tests between cases to reset
279
- * module state. (Tests typically call `setOverridesForTesting()` from
280
- * `__tests__/feature-flag-test-helpers.ts`, which combines clear + seed.)
283
+ * Used by tests between cases to reset module state. (Tests typically call
284
+ * `setOverridesForTesting()` from `__tests__/feature-flag-test-helpers.ts`,
285
+ * which combines clear + seed.)
286
+ *
287
+ * Not a step in refreshing from the gateway: `refreshOverridesFromGateway()`
288
+ * swaps the cache atomically so flag values never read as unset while a
289
+ * refresh is in flight.
281
290
  */
282
291
  export function clearFeatureFlagOverridesCache(): void {
283
292
  clearCachedOverrides();
@@ -286,18 +295,30 @@ export function clearFeatureFlagOverridesCache(): void {
286
295
  /**
287
296
  * Re-fetch feature flag overrides from the gateway.
288
297
  *
289
- * Clears the cached overrides and re-runs the gateway IPC fetch without
290
- * retries (the gateway is known to be up because it just pushed an event).
291
- * Called by the gateway flag listener when a `feature_flags_changed` event
292
- * arrives.
298
+ * Runs the gateway IPC fetch without retries (the gateway is known to be up
299
+ * because it just pushed an event) and replaces the cache only once that fetch
300
+ * succeeds. Called by the gateway flag listener when a `feature_flags_changed`
301
+ * event arrives and on reconnect.
302
+ *
303
+ * The swap is atomic on purpose. The previously fetched values stay readable
304
+ * for the whole call, so a sync flag read that lands mid-refresh sees the last
305
+ * known values rather than an empty cache, and a failed fetch leaves them in
306
+ * place rather than dropping every flag to its registry default until the next
307
+ * event. A flag that selects behavior rather than gating it (an experiment
308
+ * arm, a kill switch) therefore cannot flip to its default because one IPC
309
+ * call timed out.
293
310
  *
294
311
  * Resolves `true` when the cache was repopulated from the gateway, `false`
295
312
  * when the fetch came back empty/failed — callers gate persisted-state
296
313
  * reconciliation on a `true` result.
297
314
  */
298
315
  export async function refreshOverridesFromGateway(): Promise<boolean> {
299
- clearFeatureFlagOverridesCache();
300
- return initFeatureFlagOverrides({ retryBackoffsMs: [] });
316
+ const gatewayOverrides = await fetchOverridesFromGateway();
317
+ if (Object.keys(gatewayOverrides).length === 0) {
318
+ return false;
319
+ }
320
+ setCachedOverrides(gatewayOverrides, { fromGateway: true });
321
+ return true;
301
322
  }
302
323
 
303
324
  // ---------------------------------------------------------------------------
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Flag read for the managed Balanced profile's model A/B test.
3
+ *
4
+ * `experiment-balanced-model-2026-08-06` is a multivariate LaunchDarkly flag
5
+ * whose arm repoints the model the managed (`vellum`) implementation of the
6
+ * `balanced` default profile resolves to. The arm to model pins live beside
7
+ * the profile bodies in `default-profile-catalog.ts`, which validates their
8
+ * managed routability at load time; this module owns only the flag read.
9
+ *
10
+ * The read goes straight to the override cache rather than through
11
+ * `assistant-feature-flags.ts`. `feature-flag-cache.ts` is a stdlib-only leaf,
12
+ * so the profile catalog stays free of the pino logger and the gateway IPC
13
+ * client that resolver would pull into its import graph, and the registry
14
+ * declares `defaultEnabled: "control"` for this flag, which is the same
15
+ * shipped body an absent override already resolves to. That equivalence is
16
+ * pinned by `__tests__/balanced-model-experiment.test.ts` so it cannot drift.
17
+ */
18
+
19
+ import { getCachedOverrides } from "./feature-flag-cache.js";
20
+
21
+ export const BALANCED_MODEL_EXPERIMENT_FLAG_KEY =
22
+ "experiment-balanced-model-2026-08-06";
23
+
24
+ /**
25
+ * The experiment arm in force, or `undefined` when the flag resolves to
26
+ * anything that is not an arm name: unset, a boolean, or the empty string.
27
+ * `control` and any arm this build does not know are returned as-is and miss
28
+ * the pin table, which is what keeps a stale or malformed LaunchDarkly value
29
+ * on the shipped model rather than stranding an install on one that does not
30
+ * exist.
31
+ */
32
+ export function getBalancedModelExperimentArm(): string | undefined {
33
+ const value = getCachedOverrides()?.[BALANCED_MODEL_EXPERIMENT_FLAG_KEY];
34
+ return typeof value === "string" && value.length > 0 ? value : undefined;
35
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: acp
3
- description: Spawn external coding agents via the Agent Client Protocol (ACP)
3
+ description: Set up, authenticate, and run external coding agents (Claude Code, Codex) via the Agent Client Protocol
4
4
  compatibility: "Designed for Vellum personal assistants"
5
5
  metadata:
6
6
  emoji: "🔗"
@@ -8,13 +8,12 @@ metadata:
8
8
  display-name: "ACP"
9
9
  category: "development"
10
10
  activation-hints:
11
- - "User asks to use Claude Code or Codex to do something"
12
- - "User wants to delegate a coding task to Claude Code, Codex, or another ACP agent"
13
- - "User wants to hand a coding task to another agent and check on it later"
14
- - "User wants to spawn an external coding agent that runs autonomously and streams results back"
15
- - "User mentions ACP, claude-agent-acp, codex-acp, or running multiple coding agents in parallel"
11
+ - "User wants to set up, install, configure, authenticate, or connect Claude Code or Codex"
12
+ - "User asks to use Claude Code or Codex, or delegate a coding task to an ACP agent"
13
+ - "User wants an agent to work autonomously and report back later"
14
+ - "User mentions ACP, claude-agent-acp, or codex-acp"
16
15
  avoid-when:
17
- - "Task is small enough to do inline with the assistant's own tools - no need for an external agent"
16
+ - "The task is small enough to do inline"
18
17
  ---
19
18
 
20
19
  ACP agent orchestration - spawn external coding agents (Claude Code, Codex) to work on tasks via the Agent Client Protocol. Each agent runs as its own subprocess speaking ACP over stdio and streams results back into the conversation.