@vellumai/assistant 0.10.9 → 0.10.10-dev.202607162206.d08e98e

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 (456) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/Dockerfile +8 -0
  3. package/docs/activation-funnel-telemetry.md +13 -7
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  7. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  9. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  12. package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  13. package/openapi.yaml +530 -107
  14. package/package.json +1 -1
  15. package/scripts/generate-openapi.ts +8 -0
  16. package/src/__tests__/activation-early-marking.test.ts +6 -5
  17. package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
  18. package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
  19. package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
  20. package/src/__tests__/app-bundler.test.ts +4 -12
  21. package/src/__tests__/app-executors.test.ts +2 -49
  22. package/src/__tests__/app-routes-csp.test.ts +114 -146
  23. package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
  24. package/src/__tests__/build-persisted-content.test.ts +96 -0
  25. package/src/__tests__/bundle-scanner.test.ts +27 -1
  26. package/src/__tests__/call-controller.test.ts +291 -0
  27. package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
  28. package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
  29. package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
  30. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  31. package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
  32. package/src/__tests__/config-loader-backfill.test.ts +9 -4
  33. package/src/__tests__/config-schema-cmd.test.ts +10 -11
  34. package/src/__tests__/config-schema.test.ts +190 -257
  35. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
  37. package/src/__tests__/conversation-agent-loop.test.ts +22 -9
  38. package/src/__tests__/conversation-error.test.ts +31 -0
  39. package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
  40. package/src/__tests__/conversation-process-callsite.test.ts +12 -19
  41. package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
  42. package/src/__tests__/conversation-summarize-route.test.ts +36 -44
  43. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  44. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
  45. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
  46. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
  47. package/src/__tests__/conversation-usage.test.ts +4 -12
  48. package/src/__tests__/credential-routes.test.ts +250 -0
  49. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  50. package/src/__tests__/db-migration-rollback.test.ts +22 -0
  51. package/src/__tests__/empty-response-hook.test.ts +186 -1
  52. package/src/__tests__/external-plugin-loader.test.ts +11 -5
  53. package/src/__tests__/heartbeat-service.test.ts +0 -28
  54. package/src/__tests__/host-shell-tool.test.ts +2 -0
  55. package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
  56. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
  57. package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
  58. package/src/__tests__/invite-routes-http.test.ts +12 -16
  59. package/src/__tests__/list-all-apps.test.ts +0 -4
  60. package/src/__tests__/llm-context-resolution.test.ts +32 -56
  61. package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
  62. package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
  63. package/src/__tests__/llm-resolver.test.ts +342 -602
  64. package/src/__tests__/llm-schema.test.ts +79 -37
  65. package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
  66. package/src/__tests__/media-stream-output.test.ts +259 -3
  67. package/src/__tests__/media-stream-server-integration.test.ts +22 -1
  68. package/src/__tests__/media-stream-stt-session.test.ts +47 -0
  69. package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
  70. package/src/__tests__/memory-recall-log-store.test.ts +47 -13
  71. package/src/__tests__/mock-gateway-ipc.ts +46 -1
  72. package/src/__tests__/mtime-cache.test.ts +61 -0
  73. package/src/__tests__/navigate-settings-tab.test.ts +2 -0
  74. package/src/__tests__/normalize-onboarding.test.ts +33 -0
  75. package/src/__tests__/onboarding-persona-write.test.ts +26 -0
  76. package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
  77. package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
  78. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
  79. package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
  80. package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
  81. package/src/__tests__/provider-connections-backfill.test.ts +138 -0
  82. package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
  83. package/src/__tests__/provider-registry-ollama.test.ts +8 -18
  84. package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
  85. package/src/__tests__/provider-usage-tracking.test.ts +9 -19
  86. package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
  87. package/src/__tests__/published-app-updater.test.ts +22 -16
  88. package/src/__tests__/registry.test.ts +5 -16
  89. package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
  90. package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
  91. package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
  92. package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
  93. package/src/__tests__/reveal-success-registry.test.ts +123 -0
  94. package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
  95. package/src/__tests__/secret-fixtures.ts +9 -0
  96. package/src/__tests__/server-history-render.test.ts +28 -0
  97. package/src/__tests__/skills.test.ts +9 -4
  98. package/src/__tests__/slack-share-routes.test.ts +0 -1
  99. package/src/__tests__/stt-stream-session.test.ts +6 -5
  100. package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
  101. package/src/__tests__/subagent-disposal.test.ts +2 -0
  102. package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
  103. package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
  104. package/src/__tests__/subagent-manager-notify.test.ts +2 -0
  105. package/src/__tests__/subagent-role-registry.test.ts +37 -0
  106. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  107. package/src/__tests__/subagent-terminal-message.test.ts +50 -0
  108. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
  109. package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
  110. package/src/__tests__/telemetry-routes.test.ts +99 -19
  111. package/src/__tests__/tool-audit.test.ts +34 -4
  112. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  113. package/src/__tests__/tool-profiler.test.ts +72 -1
  114. package/src/__tests__/tool-result-spool.test.ts +49 -4
  115. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
  116. package/src/__tests__/ui-channel-variants.test.ts +108 -0
  117. package/src/__tests__/ui-shape-teaching.test.ts +255 -0
  118. package/src/__tests__/usage-attribution.test.ts +18 -41
  119. package/src/__tests__/user-plugin-loader.test.ts +4 -4
  120. package/src/__tests__/voice-config-update.test.ts +46 -0
  121. package/src/__tests__/voice-session-bridge.test.ts +216 -84
  122. package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
  123. package/src/agent/loop.ts +4 -3
  124. package/src/api/events/open-conversation.test.ts +64 -0
  125. package/src/api/events/open-conversation.ts +33 -0
  126. package/src/api/index.ts +6 -0
  127. package/src/api/responses/conversation-message.ts +5 -0
  128. package/src/apps/app-store.ts +25 -35
  129. package/src/bundler/app-bundler.ts +34 -48
  130. package/src/bundler/app-compiler.ts +39 -4
  131. package/src/bundler/bundle-scanner.ts +13 -0
  132. package/src/bundler/manifest.ts +1 -1
  133. package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
  134. package/src/calls/call-constants.ts +5 -0
  135. package/src/calls/call-controller.ts +100 -32
  136. package/src/calls/call-transport.ts +9 -0
  137. package/src/calls/media-stream-output.ts +107 -4
  138. package/src/calls/media-stream-server.ts +29 -9
  139. package/src/calls/media-stream-stt-session.ts +7 -1
  140. package/src/calls/media-turn-detector.ts +11 -1
  141. package/src/calls/voice-session-bridge.ts +84 -63
  142. package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
  143. package/src/cli/commands/__tests__/notifications.test.ts +24 -3
  144. package/src/cli/commands/config.help.ts +6 -6
  145. package/src/cli/commands/credentials.help.ts +13 -0
  146. package/src/cli/commands/credentials.ts +6 -1
  147. package/src/cli/commands/email.help.ts +7 -0
  148. package/src/cli/commands/email.ts +35 -1
  149. package/src/cli/commands/inference-providers.ts +168 -107
  150. package/src/cli/commands/inference.help.ts +118 -46
  151. package/src/cli/commands/memory/index.help.ts +23 -0
  152. package/src/cli/commands/memory/nodes.ts +146 -0
  153. package/src/cli/commands/notifications.help.ts +10 -10
  154. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
  155. package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
  156. package/src/cli/commands/oauth/connect.test.ts +126 -0
  157. package/src/cli/commands/oauth/connect.ts +29 -6
  158. package/src/cli/commands/oauth/index.help.ts +7 -1
  159. package/src/cli/commands/oauth/status.test.ts +69 -3
  160. package/src/cli/commands/oauth/status.ts +50 -12
  161. package/src/cli/commands/plugins.help.ts +13 -2
  162. package/src/cli/commands/plugins.ts +61 -7
  163. package/src/cli/commands/telemetry.help.ts +13 -0
  164. package/src/cli/commands/telemetry.ts +45 -5
  165. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
  166. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
  167. package/src/cli/lib/bundled-marketplace.json +93 -36
  168. package/src/cli/lib/inspect-plugin.ts +5 -1
  169. package/src/cli/lib/install-from-github.ts +68 -4
  170. package/src/cli/lib/plugin-catalog-local.ts +6 -2
  171. package/src/cli/lib/plugin-fingerprint.ts +3 -3
  172. package/src/cli/lib/upgrade-plugin.ts +236 -35
  173. package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
  174. package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
  175. package/src/config/__tests__/profile-materialization.test.ts +1 -88
  176. package/src/config/bundled-skills/AGENTS.md +3 -30
  177. package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
  178. package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
  179. package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
  180. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  181. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
  182. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  183. package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
  184. package/src/config/bundled-skills/settings/TOOLS.json +3 -1
  185. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
  186. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
  187. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  188. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  189. package/src/config/call-site-defaults.ts +3 -3
  190. package/src/config/feature-flag-registry.json +24 -39
  191. package/src/config/llm-resolver.ts +88 -475
  192. package/src/config/profile-materialization.ts +11 -11
  193. package/src/config/schema.ts +93 -127
  194. package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
  195. package/src/config/schemas/__tests__/stt.test.ts +31 -3
  196. package/src/config/schemas/live-voice.ts +10 -4
  197. package/src/config/schemas/llm.ts +52 -15
  198. package/src/config/schemas/memory-lifecycle.ts +1 -1
  199. package/src/config/schemas/memory-retrospective.ts +8 -0
  200. package/src/config/schemas/memory-v2.ts +2 -2
  201. package/src/config/schemas/memory-v3.ts +1 -1
  202. package/src/config/schemas/services.ts +6 -3
  203. package/src/config/schemas/stt.ts +38 -21
  204. package/src/config/schemas/tts.ts +13 -18
  205. package/src/config/skills.ts +31 -21
  206. package/src/context/compactor.ts +44 -7
  207. package/src/context/post-turn-tool-result-truncation.ts +4 -2
  208. package/src/context/tool-result-spool.ts +26 -5
  209. package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
  210. package/src/conversations/message-consolidation.ts +22 -2
  211. package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
  212. package/src/daemon/app-source-watcher.ts +17 -23
  213. package/src/daemon/chat-credential-redaction.ts +1365 -0
  214. package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
  215. package/src/daemon/conversation-agent-loop.ts +71 -31
  216. package/src/daemon/conversation-error.ts +36 -14
  217. package/src/daemon/conversation-process.ts +22 -0
  218. package/src/daemon/conversation-store.ts +35 -0
  219. package/src/daemon/conversation-surfaces.ts +25 -25
  220. package/src/daemon/conversation-tool-setup.ts +33 -7
  221. package/src/daemon/conversation.ts +55 -5
  222. package/src/daemon/handlers/shared.ts +33 -2
  223. package/src/daemon/lifecycle.ts +4 -4
  224. package/src/daemon/message-types/conversations.ts +6 -17
  225. package/src/daemon/providers-setup.ts +8 -0
  226. package/src/daemon/tool-setup-types.ts +7 -1
  227. package/src/daemon/wake-conversation-ops.ts +10 -1
  228. package/src/hooks/types.ts +9 -0
  229. package/src/ipc/__tests__/email-ipc.test.ts +90 -0
  230. package/src/ipc/gateway-client.test.ts +59 -0
  231. package/src/ipc/gateway-client.ts +70 -27
  232. package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
  233. package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
  234. package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
  235. package/src/live-voice/__tests__/protocol.test.ts +122 -0
  236. package/src/live-voice/live-voice-session.ts +443 -40
  237. package/src/live-voice/protocol.ts +143 -1
  238. package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
  239. package/src/monitoring/plugin-source-watch.ts +3 -62
  240. package/src/notifications/README.md +1 -1
  241. package/src/permissions/checker.ts +8 -4
  242. package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
  243. package/src/persistence/conversation-crud.ts +104 -2
  244. package/src/persistence/db-init.ts +14 -3
  245. package/src/persistence/job-handlers/cleanup.ts +15 -7
  246. package/src/persistence/llm-request-log-store.ts +88 -52
  247. package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
  248. package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
  249. package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
  250. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
  251. package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
  252. package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
  253. package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
  254. package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
  255. package/src/persistence/migrations/helpers/relocation.ts +44 -1
  256. package/src/persistence/migrations/run-migrations.ts +25 -1
  257. package/src/persistence/schema/infrastructure.ts +9 -0
  258. package/src/persistence/schema/memory-core.ts +3 -0
  259. package/src/persistence/schema/memory-injection.ts +2 -0
  260. package/src/persistence/steps.ts +36 -0
  261. package/src/platform/client.test.ts +1 -44
  262. package/src/platform/client.ts +10 -20
  263. package/src/platform/consent-cache.test.ts +89 -23
  264. package/src/platform/consent-cache.ts +71 -33
  265. package/src/plugin-api/constants.ts +12 -0
  266. package/src/plugin-api/conversation-turn.ts +37 -14
  267. package/src/plugin-api/index.ts +11 -1
  268. package/src/plugin-api/resolve-credential.ts +75 -0
  269. package/src/plugin-api/vision-support.test.ts +8 -19
  270. package/src/plugin-api/vision-support.ts +26 -17
  271. package/src/plugins/collect-source-versions.ts +77 -0
  272. package/src/plugins/defaults/compaction/compact.ts +6 -0
  273. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
  275. package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
  276. package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
  277. package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
  278. package/src/plugins/defaults/index.ts +8 -1
  279. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
  280. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
  281. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
  282. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
  283. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
  284. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
  285. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
  286. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
  287. package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
  288. package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
  289. package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
  290. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
  291. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
  292. package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
  293. package/src/plugins/defaults/memory/graph/store.ts +114 -0
  294. package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
  295. package/src/plugins/defaults/memory/graph/tools.ts +47 -13
  296. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
  297. package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
  298. package/src/plugins/defaults/memory/memory-db.ts +3 -2
  299. package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
  300. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
  301. package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
  302. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
  303. package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
  304. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
  305. package/src/plugins/defaults/memory/path-containment.ts +21 -0
  306. package/src/plugins/defaults/memory/prompt-override.ts +51 -13
  307. package/src/plugins/defaults/memory/tools.test.ts +34 -0
  308. package/src/plugins/defaults/memory/tools.ts +12 -2
  309. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
  310. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
  311. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
  312. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
  313. package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
  314. package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
  315. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
  316. package/src/plugins/defaults/memory/v2/migration.ts +46 -16
  317. package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
  318. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
  319. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
  320. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
  321. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
  322. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
  323. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
  324. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
  325. package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
  326. package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
  327. package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
  328. package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
  329. package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
  330. package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
  331. package/src/plugins/defaults/memory/v3/prune.ts +17 -11
  332. package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
  333. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
  334. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
  335. package/src/plugins/external-plugin-loader.ts +15 -15
  336. package/src/plugins/mtime-cache.ts +47 -0
  337. package/src/plugins/pipeline.ts +9 -1
  338. package/src/plugins/plugin-execution-context.ts +44 -0
  339. package/src/plugins/plugin-tree-walk.ts +31 -24
  340. package/src/plugins/source-fingerprint.ts +3 -4
  341. package/src/prompts/normalize-onboarding.ts +12 -0
  342. package/src/prompts/persona-resolver.ts +8 -0
  343. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
  344. package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
  345. package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
  346. package/src/providers/__tests__/retry-callsite.test.ts +235 -215
  347. package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
  348. package/src/providers/atlascloud/client.ts +10 -49
  349. package/src/providers/baseten/client.ts +43 -0
  350. package/src/providers/call-site-routing.ts +26 -13
  351. package/src/providers/connection-resolution.ts +9 -11
  352. package/src/providers/fetch-provider-catalog.ts +4 -2
  353. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
  354. package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
  355. package/src/providers/inference/adapter-factory.ts +27 -6
  356. package/src/providers/inference/auth.ts +29 -1
  357. package/src/providers/inference/backfill.ts +61 -10
  358. package/src/providers/inference/connection-availability.ts +3 -2
  359. package/src/providers/inference/resolve-auth.ts +9 -1
  360. package/src/providers/model-catalog.ts +37 -0
  361. package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
  362. package/src/providers/openai/api-key-validation.ts +70 -0
  363. package/src/providers/retry.ts +2 -0
  364. package/src/providers/types.ts +11 -4
  365. package/src/providers/vellum-model-routing.test.ts +26 -0
  366. package/src/providers/vellum-model-routing.ts +30 -0
  367. package/src/providers/voice-error-copy.ts +47 -0
  368. package/src/runtime/agent-wake.ts +40 -24
  369. package/src/runtime/for-chat-mint-registry.ts +118 -0
  370. package/src/runtime/reveal-nonce.ts +49 -0
  371. package/src/runtime/reveal-success-registry.ts +306 -0
  372. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
  373. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
  374. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
  375. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
  376. package/src/runtime/routes/app-management-routes.ts +152 -45
  377. package/src/runtime/routes/app-routes.ts +16 -77
  378. package/src/runtime/routes/canned-message-complete.ts +16 -16
  379. package/src/runtime/routes/conversation-management-routes.ts +17 -14
  380. package/src/runtime/routes/conversation-query-routes.ts +54 -6
  381. package/src/runtime/routes/conversation-routes.ts +48 -2
  382. package/src/runtime/routes/credential-routes.ts +116 -3
  383. package/src/runtime/routes/email-routes.ts +17 -1
  384. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
  385. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
  386. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
  387. package/src/runtime/routes/inference-send-routes.ts +1 -1
  388. package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
  389. package/src/runtime/routes/plugins-routes.ts +37 -6
  390. package/src/runtime/routes/publish-routes.ts +15 -18
  391. package/src/runtime/routes/schedule-worker-routes.ts +9 -0
  392. package/src/runtime/routes/secret-routes.ts +10 -0
  393. package/src/runtime/routes/telemetry-routes.ts +149 -45
  394. package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
  395. package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
  396. package/src/schedule/schedule-store.ts +12 -1
  397. package/src/schedule/schedule-timezone.ts +63 -0
  398. package/src/schedule/scheduler.ts +100 -6
  399. package/src/schedule/worker-control.ts +19 -0
  400. package/src/security/auth-fallback-events-store.ts +7 -6
  401. package/src/security/secret-scanner.ts +26 -1
  402. package/src/services/published-app-updater.ts +6 -11
  403. package/src/stt/stt-stream-session.ts +36 -16
  404. package/src/subagent/manager.ts +34 -8
  405. package/src/telemetry/AGENTS.md +30 -1
  406. package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
  407. package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
  408. package/src/telemetry/config-setting-snapshot.ts +44 -10
  409. package/src/telemetry/telemetry-event-sources.test.ts +124 -30
  410. package/src/telemetry/telemetry-event-sources.ts +137 -83
  411. package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
  412. package/src/telemetry/telemetry-events-outbox.ts +60 -9
  413. package/src/telemetry/telemetry-wire-source.json +1 -1
  414. package/src/telemetry/telemetry-wire-validation.ts +39 -2
  415. package/src/telemetry/telemetry-wire.generated.ts +8 -0
  416. package/src/telemetry/tool-audit.ts +15 -9
  417. package/src/telemetry/tool-executed-events-store.test.ts +1 -1
  418. package/src/telemetry/turn-events-store.ts +20 -0
  419. package/src/telemetry/types.ts +45 -12
  420. package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
  421. package/src/telemetry/usage-telemetry-reporter.ts +117 -18
  422. package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
  423. package/src/telemetry/watchdog-direct-emit.ts +11 -6
  424. package/src/tools/apps/executors.ts +11 -36
  425. package/src/tools/executor.ts +14 -1
  426. package/src/tools/host-terminal/host-shell.ts +6 -2
  427. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
  428. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
  429. package/src/tools/network/web-fetch.ts +6 -2
  430. package/src/tools/skills/sandbox-runner.ts +5 -2
  431. package/src/tools/subagent/spawn.ts +7 -11
  432. package/src/tools/terminal/shell.ts +5 -2
  433. package/src/tools/tool-manifest.ts +0 -2
  434. package/src/tools/tool-profiler.ts +37 -6
  435. package/src/tools/ui-surface/channel-variants.ts +101 -0
  436. package/src/tools/ui-surface/definitions.ts +23 -67
  437. package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
  438. package/src/tts/__tests__/provider-adapters.test.ts +18 -0
  439. package/src/tts/provider-catalog.ts +2 -4
  440. package/src/tts/providers/deepgram-provider.ts +10 -1
  441. package/src/types/onboarding-context.ts +8 -0
  442. package/src/usage/attribution.ts +18 -112
  443. package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
  444. package/src/util/provider-error-patterns.ts +7 -1
  445. package/src/util/worker-process.ts +105 -0
  446. package/src/watcher/__tests__/telemetry.test.ts +17 -4
  447. package/src/watcher/telemetry.ts +5 -5
  448. package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
  449. package/src/workspace/migrations/registry.ts +2 -0
  450. package/src/workspace/provider-commit-message-generator.ts +6 -4
  451. package/src/__tests__/app-open-proxy.test.ts +0 -67
  452. package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
  453. package/src/onboarding/onboarding-research-events-store.ts +0 -104
  454. package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
  455. package/src/tools/apps/definitions.ts +0 -73
  456. package/src/tools/apps/open-proxy.ts +0 -43
@@ -1,24 +1,26 @@
1
- import { beforeAll, describe, expect, test } from "bun:test";
2
-
3
- import { setOverridesForTesting } from "./feature-flag-test-helpers.js";
4
-
5
- // This suite pins the LEGACY merge-cascade semantics — the kill-switch
6
- // (flag-off) path. The override-or-default (flag-on, shipped default)
7
- // semantics are pinned by llm-resolver-override-or-default.test.ts.
8
- beforeAll(() => {
9
- setOverridesForTesting({ "override-or-default-resolution": false });
10
- });
1
+ import { describe, expect, test } from "bun:test";
11
2
 
12
3
  import { z } from "zod";
13
4
 
5
+ import { CODE_DEFAULT_PROFILE_ENTRIES } from "../config/default-profile-catalog.js";
14
6
  import {
7
+ type ResolutionFallbackReason,
15
8
  resolveCallSiteConfig,
16
9
  resolveDefaultProfileKey,
17
10
  resolveEffectiveProfileKey,
18
11
  } from "../config/llm-resolver.js";
19
12
  import { type LLMCallSite, LLMSchema } from "../config/schemas/llm.js";
13
+ import { resolveModelIntent } from "../providers/model-intents.js";
20
14
 
21
- const fullDefault = {
15
+ // Pins the single-winner call-site resolution semantics. The core selection
16
+ // chain (override → active → call-site profile → default intent → anchor) is
17
+ // also pinned by llm-resolver-override-or-default.test.ts; this suite covers
18
+ // composition, fixtures with user profile shadows, mixes, and provenance.
19
+
20
+ // Fully-specified call-site fragment. The call-site tweak is applied last in
21
+ // the base + winner + tweak composition, so this fragment pins every knob of
22
+ // the resolved config regardless of the winning profile.
23
+ const fullTweak = {
22
24
  provider: "anthropic" as const,
23
25
  model: "claude-opus-4-7",
24
26
  maxTokens: 64000,
@@ -45,44 +47,51 @@ const fullDefault = {
45
47
  openrouter: { only: [] as string[] },
46
48
  };
47
49
 
50
+ type Fallback = {
51
+ callSite: string;
52
+ requested: string;
53
+ reason: ResolutionFallbackReason;
54
+ };
55
+
56
+ const collect = () => {
57
+ const fallbacks: Fallback[] = [];
58
+ return {
59
+ fallbacks,
60
+ opts: {
61
+ onResolutionFallback: (info: Fallback) => fallbacks.push(info),
62
+ },
63
+ };
64
+ };
65
+
48
66
  describe("resolveCallSiteConfig", () => {
49
- test("returns default when the call-site default profile is disabled and no custom fallback exists", () => {
50
- // mainAgent's catalog default (`balanced`) always resolves from the code
51
- // catalog, so the pure fall-through-to-default path requires a disabled
52
- // stub (the BYOK hatch state) with no `custom-balanced` present.
67
+ test("a full call-site tweak determines every field of the resolved config", () => {
53
68
  const llm = LLMSchema.parse({
54
- default: fullDefault,
55
- profiles: { balanced: { source: "managed", status: "disabled" } },
69
+ callSites: { mainAgent: fullTweak },
56
70
  });
57
71
  const resolved = resolveCallSiteConfig("mainAgent", llm);
58
- expect(resolved).toEqual(fullDefault);
72
+ // The tweak is the last composition layer, so it wins every field it sets
73
+ // over the winning profile's fragment.
74
+ expect(resolved).toMatchObject(fullTweak);
59
75
  });
60
76
 
61
- test("site-level field overrides default", () => {
77
+ test("a single call-site tweak field overrides the winner while siblings survive", () => {
62
78
  const llm = LLMSchema.parse({
63
- default: fullDefault,
64
79
  callSites: {
65
- mainAgent: { model: "claude-sonnet-4-7" },
80
+ mainAgent: { ...fullTweak, model: "claude-sonnet-4-7" },
66
81
  },
67
82
  });
68
83
  const resolved = resolveCallSiteConfig("mainAgent", llm);
69
84
  expect(resolved.model).toBe("claude-sonnet-4-7");
70
- // Sibling fields are preserved.
85
+ // Sibling tweak fields are preserved.
71
86
  expect(resolved.provider).toBe("anthropic");
72
87
  expect(resolved.maxTokens).toBe(64000);
73
88
  });
74
89
 
75
90
  test("model-only call-site override infers provider from known model owner", () => {
91
+ // The winner resolves through the openai default provider; the tweak's
92
+ // model belongs to anthropic's catalog, so the catalog owner is implied.
76
93
  const llm = LLMSchema.parse({
77
- default: {
78
- ...fullDefault,
79
- provider: "openai",
80
- model: "gpt-5.5",
81
- },
82
- profiles: {
83
- active: { provider: "openai", model: "gpt-5.5" },
84
- },
85
- activeProfile: "active",
94
+ defaultProvider: { provider: "openai" },
86
95
  callSites: {
87
96
  conversationStarters: {
88
97
  model: "claude-haiku-4-5-20251001",
@@ -98,18 +107,19 @@ describe("resolveCallSiteConfig", () => {
98
107
  expect(resolved.effort).toBe("low");
99
108
  });
100
109
 
101
- test("model-only override of a shared gateway model keeps a vercel-ai-gateway default provider", () => {
110
+ test("model-only override of a shared gateway model keeps a vercel-ai-gateway winner", () => {
102
111
  // `anthropic/claude-opus-4.8` is listed by both openrouter and
103
- // vercel-ai-gateway; the applicable default provider serves it, so no
104
- // provider is implied and the default wins.
112
+ // vercel-ai-gateway; the winner's provider serves it, so no provider is
113
+ // implied and the winner's provider stands.
105
114
  const llm = LLMSchema.parse({
106
- default: {
107
- ...fullDefault,
108
- provider: "vercel-ai-gateway",
109
- model: "anthropic/claude-sonnet-4.6",
115
+ profiles: {
116
+ gw: {
117
+ provider: "vercel-ai-gateway",
118
+ model: "anthropic/claude-sonnet-4.6",
119
+ },
110
120
  },
111
121
  callSites: {
112
- memoryExtraction: { model: "anthropic/claude-opus-4.8" },
122
+ memoryExtraction: { profile: "gw", model: "anthropic/claude-opus-4.8" },
113
123
  },
114
124
  });
115
125
 
@@ -119,15 +129,13 @@ describe("resolveCallSiteConfig", () => {
119
129
  expect(resolved.model).toBe("anthropic/claude-opus-4.8");
120
130
  });
121
131
 
122
- test("model-only override of a shared gateway model keeps an openrouter default provider", () => {
132
+ test("model-only override of a shared gateway model keeps an openrouter winner", () => {
123
133
  const llm = LLMSchema.parse({
124
- default: {
125
- ...fullDefault,
126
- provider: "openrouter",
127
- model: "anthropic/claude-sonnet-4.6",
134
+ profiles: {
135
+ gw: { provider: "openrouter", model: "anthropic/claude-sonnet-4.6" },
128
136
  },
129
137
  callSites: {
130
- memoryExtraction: { model: "anthropic/claude-opus-4.8" },
138
+ memoryExtraction: { profile: "gw", model: "anthropic/claude-opus-4.8" },
131
139
  },
132
140
  });
133
141
 
@@ -137,12 +145,12 @@ describe("resolveCallSiteConfig", () => {
137
145
  expect(resolved.model).toBe("anthropic/claude-opus-4.8");
138
146
  });
139
147
 
140
- test("model-only override of a gateway model with a non-serving default implies the catalog owner", () => {
148
+ test("model-only override of a gateway model with a non-serving winner implies the catalog owner", () => {
141
149
  // Anthropic's own catalog uses bare slugs, so it does not serve
142
150
  // `anthropic/claude-sonnet-4.6` — the catalog owner (openrouter, the
143
151
  // earliest entry listing it) is implied.
144
152
  const llm = LLMSchema.parse({
145
- default: fullDefault,
153
+ defaultProvider: { provider: "anthropic" },
146
154
  callSites: {
147
155
  memoryExtraction: { model: "anthropic/claude-sonnet-4.6" },
148
156
  },
@@ -156,7 +164,7 @@ describe("resolveCallSiteConfig", () => {
156
164
 
157
165
  test("model unique to vercel-ai-gateway implies vercel-ai-gateway", () => {
158
166
  const llm = LLMSchema.parse({
159
- default: fullDefault,
167
+ defaultProvider: { provider: "anthropic" },
160
168
  callSites: {
161
169
  memoryExtraction: { model: "openai/gpt-5.5-pro" },
162
170
  },
@@ -168,13 +176,9 @@ describe("resolveCallSiteConfig", () => {
168
176
  expect(resolved.model).toBe("openai/gpt-5.5-pro");
169
177
  });
170
178
 
171
- test("unknown model-only override preserves inherited provider", () => {
179
+ test("unknown model-only override preserves the winner's provider", () => {
172
180
  const llm = LLMSchema.parse({
173
- default: {
174
- ...fullDefault,
175
- provider: "openai",
176
- model: "gpt-5.5",
177
- },
181
+ defaultProvider: { provider: "openai" },
178
182
  callSites: {
179
183
  memoryExtraction: { model: "local-custom-model" },
180
184
  },
@@ -186,11 +190,15 @@ describe("resolveCallSiteConfig", () => {
186
190
  expect(resolved.model).toBe("local-custom-model");
187
191
  });
188
192
 
189
- test("profile field overrides default when call site references it", () => {
193
+ test("a call-site profile supplies the config; untouched fields fall to schema defaults", () => {
190
194
  const llm = LLMSchema.parse({
191
- default: fullDefault,
192
195
  profiles: {
193
- fast: { speed: "fast", effort: "low" },
196
+ fast: {
197
+ provider: "anthropic",
198
+ model: "claude-opus-4-7",
199
+ speed: "fast",
200
+ effort: "low",
201
+ },
194
202
  },
195
203
  callSites: {
196
204
  memoryExtraction: { profile: "fast" },
@@ -199,16 +207,22 @@ describe("resolveCallSiteConfig", () => {
199
207
  const resolved = resolveCallSiteConfig("memoryExtraction", llm);
200
208
  expect(resolved.speed).toBe("fast");
201
209
  expect(resolved.effort).toBe("low");
202
- // Untouched defaults persist.
203
210
  expect(resolved.provider).toBe("anthropic");
204
211
  expect(resolved.model).toBe("claude-opus-4-7");
212
+ // Fields nobody set fall to the code-owned schema defaults.
213
+ expect(resolved.maxTokens).toBe(64000);
214
+ expect(resolved.verbosity).toBe("medium");
205
215
  });
206
216
 
207
- test("site field beats both profile and default (precedence test)", () => {
217
+ test("site field beats the winning profile (precedence test)", () => {
208
218
  const llm = LLMSchema.parse({
209
- default: fullDefault,
210
219
  profiles: {
211
- fast: { speed: "fast", effort: "low", model: "profile-model" },
220
+ fast: {
221
+ provider: "anthropic",
222
+ model: "profile-model",
223
+ speed: "fast",
224
+ effort: "low",
225
+ },
212
226
  },
213
227
  callSites: {
214
228
  memoryExtraction: {
@@ -222,15 +236,13 @@ describe("resolveCallSiteConfig", () => {
222
236
  // Site-level wins where it sets a value.
223
237
  expect(resolved.model).toBe("site-model");
224
238
  expect(resolved.effort).toBe("high");
225
- // Profile wins where site is silent.
239
+ // The winning profile wins where the site is silent.
226
240
  expect(resolved.speed).toBe("fast");
227
- // Default wins where neither overrides.
228
241
  expect(resolved.provider).toBe("anthropic");
229
242
  });
230
243
 
231
244
  test("thinking.enabled override does not nuke thinking.streamThinking (deep merge)", () => {
232
245
  const llm = LLMSchema.parse({
233
- default: fullDefault,
234
246
  callSites: {
235
247
  mainAgent: { thinking: { enabled: false } },
236
248
  },
@@ -242,7 +254,6 @@ describe("resolveCallSiteConfig", () => {
242
254
 
243
255
  test("contextWindow.overflowRecovery.maxAttempts override preserves siblings (depth 2 deep merge)", () => {
244
256
  const llm = LLMSchema.parse({
245
- default: fullDefault,
246
257
  callSites: {
247
258
  mainAgent: {
248
259
  contextWindow: {
@@ -254,7 +265,7 @@ describe("resolveCallSiteConfig", () => {
254
265
  const resolved = resolveCallSiteConfig("mainAgent", llm);
255
266
  // Overridden leaf at depth 2.
256
267
  expect(resolved.contextWindow.overflowRecovery.maxAttempts).toBe(7);
257
- // Sibling leaves of overflowRecovery survive.
268
+ // Sibling leaves of overflowRecovery survive from the schema-default base.
258
269
  expect(resolved.contextWindow.overflowRecovery.enabled).toBe(true);
259
270
  expect(resolved.contextWindow.overflowRecovery.safetyMarginRatio).toBe(
260
271
  0.05,
@@ -272,9 +283,9 @@ describe("resolveCallSiteConfig", () => {
272
283
  expect(resolved.contextWindow.targetBudgetRatio).toBe(0.3);
273
284
  });
274
285
 
275
- test("site without profile uses only default + site overrides", () => {
286
+ test("a defined-but-unreferenced profile never leaks into the resolved config", () => {
276
287
  const llm = LLMSchema.parse({
277
- default: fullDefault,
288
+ defaultProvider: { provider: "anthropic" },
278
289
  profiles: {
279
290
  // Defined but unused — must not leak into the resolved config.
280
291
  fast: { speed: "fast", effort: "low" },
@@ -285,22 +296,22 @@ describe("resolveCallSiteConfig", () => {
285
296
  });
286
297
  const resolved = resolveCallSiteConfig("mainAgent", llm);
287
298
  expect(resolved.temperature).toBe(0.5);
288
- // Profile fields must not appear because mainAgent didn't reference them.
299
+ // The unused profile's fields must not appear: `speed` falls to the base
300
+ // and `effort` comes from the winning balanced-intent profile.
289
301
  expect(resolved.speed).toBe("standard");
290
- expect(resolved.effort).toBe("max");
302
+ expect(resolved.effort).toBe("high");
291
303
  });
292
304
 
293
305
  test("topP defaults to null when no profile or override sets it", () => {
294
- const llm = LLMSchema.parse({ default: fullDefault });
306
+ const llm = LLMSchema.parse({});
295
307
  const resolved = resolveCallSiteConfig("mainAgent", llm);
296
308
  expect(resolved.topP).toBeNull();
297
309
  });
298
310
 
299
- test("profile-level topP resolves onto the merged config", () => {
311
+ test("winning-profile topP resolves onto the merged config", () => {
300
312
  const llm = LLMSchema.parse({
301
- default: fullDefault,
302
313
  profiles: {
303
- nucleus: { topP: 0.9 },
314
+ nucleus: { provider: "anthropic", model: "claude-opus-4-7", topP: 0.9 },
304
315
  },
305
316
  callSites: {
306
317
  memoryExtraction: { profile: "nucleus" },
@@ -310,30 +321,42 @@ describe("resolveCallSiteConfig", () => {
310
321
  expect(resolved.topP).toBe(0.9);
311
322
  });
312
323
 
313
- test("returns isolated nested objects (not aliased to llm.default)", () => {
314
- // Resolve a call site that has no override touching `thinking` or
315
- // `contextWindow` the bug being guarded against would have those
316
- // nested objects aliased directly to `llm.default`. We resolve once,
317
- // mutate the returned config's nested objects, then resolve again and
318
- // verify the second call sees the original `llm.default` values
319
- // (i.e. the source was never corrupted).
320
- const llm = LLMSchema.parse({ default: fullDefault });
324
+ test("returns isolated nested objects (not aliased to the winning profile)", () => {
325
+ // Resolve a call site whose winner supplies nested `thinking` and
326
+ // `contextWindow` fragments. The bug being guarded against would have
327
+ // those nested objects aliased to the profile entry in `llm.profiles`.
328
+ // We resolve once, mutate the returned config's nested objects, then
329
+ // resolve again and verify the second call sees the original values
330
+ // (i.e. the source config was never corrupted).
331
+ const llm = LLMSchema.parse({
332
+ profiles: {
333
+ mine: {
334
+ provider: "anthropic",
335
+ model: "claude-opus-4-7",
336
+ thinking: { enabled: true, streamThinking: true },
337
+ contextWindow: { overflowRecovery: { maxAttempts: 3 } },
338
+ },
339
+ },
340
+ activeProfile: "mine",
341
+ });
321
342
 
322
343
  const first = resolveCallSiteConfig("mainAgent", llm);
323
344
  expect(first.thinking.enabled).toBe(true);
324
345
  expect(first.contextWindow.overflowRecovery.maxAttempts).toBe(3);
325
346
 
326
- // Mutate the result. If nested objects were aliased into `llm.default`,
347
+ // Mutate the result. If nested objects were aliased into the profile,
327
348
  // these writes would silently corrupt the source config.
328
349
  first.thinking.enabled = false;
329
350
  first.contextWindow.overflowRecovery.maxAttempts = 999;
330
351
 
331
- // Defensive: the source `fullDefault` literal should be untouched.
332
- expect(fullDefault.thinking.enabled).toBe(true);
333
- expect(fullDefault.contextWindow.overflowRecovery.maxAttempts).toBe(3);
352
+ // Defensive: the source profile entry should be untouched.
353
+ expect(llm.profiles["mine"]?.thinking?.enabled).toBe(true);
354
+ expect(
355
+ llm.profiles["mine"]?.contextWindow?.overflowRecovery?.maxAttempts,
356
+ ).toBe(3);
334
357
 
335
358
  // The real test: resolving the same call site again must see the
336
- // original `llm.default` values, not the mutations applied to `first`.
359
+ // original profile values, not the mutations applied to `first`.
337
360
  const second = resolveCallSiteConfig("mainAgent", llm);
338
361
  expect(second.thinking.enabled).toBe(true);
339
362
  expect(second.contextWindow.overflowRecovery.maxAttempts).toBe(3);
@@ -349,13 +372,13 @@ describe("resolveCallSiteConfig", () => {
349
372
  );
350
373
  });
351
374
 
352
- test("defensive throw on unknown profile reference (bypassing superRefine)", () => {
375
+ test("an unknown call-site profile reference falls through with a report (bypassing superRefine)", () => {
353
376
  // Hand-craft an `LLMSchema`-typed object that bypasses validation by
354
377
  // referencing a profile that doesn't exist in `profiles`. The schema's
355
378
  // `superRefine` would reject this at parse time, so we construct it
356
- // manually to exercise the defensive throw in the resolver.
379
+ // manually to exercise the resolver's silent fall-through: the missing
380
+ // rung is reported and resolution lands on the code-owned anchor.
357
381
  const llm: z.infer<typeof LLMSchema> = {
358
- default: fullDefault,
359
382
  profiles: {},
360
383
  profileOrder: [],
361
384
  callSites: {
@@ -364,73 +387,53 @@ describe("resolveCallSiteConfig", () => {
364
387
  profileSession: { defaultTtlSeconds: 1800, maxTtlSeconds: 43200 },
365
388
  pricingOverrides: [],
366
389
  };
367
- expect(() => resolveCallSiteConfig("mainAgent", llm)).toThrow(
368
- /references undefined profile "nonexistent"/,
390
+ const { fallbacks, opts } = collect();
391
+ const resolved = resolveCallSiteConfig("mainAgent", llm, opts);
392
+ expect(resolved.model).toBe(
393
+ CODE_DEFAULT_PROFILE_ENTRIES.balanced.model as string,
369
394
  );
370
- });
371
-
372
- test("5-layer precedence: each layer overrides the prior for non-main call sites", () => {
373
- // Set up a config where every layer touches `model` and `effort` so we
374
- // can verify each layer's contribution and that higher layers win.
375
- //
376
- // Layer order (low → high):
377
- // 1. default → model=claude-opus-4-7, effort=max
378
- // 2. activeProfile → effort=medium (everything else falls through)
379
- // 3. overrideProfile → effort=low, speed=fast
380
- // 4. callSite.profile → effort=high, verbosity=high
381
- // 5. callSite frag → effort=none (top dog)
382
- const llm = LLMSchema.parse({
383
- default: fullDefault,
384
- profiles: {
385
- active: { effort: "medium" },
386
- override: { effort: "low", speed: "fast" },
387
- siteProfile: { effort: "high", verbosity: "high" },
388
- },
389
- callSites: {
390
- memoryExtraction: { profile: "siteProfile", effort: "none" },
391
- },
392
- activeProfile: "active",
393
- });
394
-
395
- const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
396
- overrideProfile: "override",
395
+ expect(fallbacks).toContainEqual({
396
+ callSite: "mainAgent",
397
+ requested: "nonexistent",
398
+ reason: "missing",
397
399
  });
398
-
399
- // Top layer (callSite fragment) wins for `effort` over every other
400
- // layer's contribution (max → medium → low → high → none).
401
- expect(resolved.effort).toBe("none");
402
- // siteProfile contributes verbosity (no higher layer touches it).
403
- expect(resolved.verbosity).toBe("high");
404
- // overrideProfile contributes speed (no higher layer touches it).
405
- expect(resolved.speed).toBe("fast");
406
- // default wins for everything no higher layer touches.
407
- expect(resolved.provider).toBe("anthropic");
408
- expect(resolved.model).toBe("claude-opus-4-7");
409
- expect(resolved.maxTokens).toBe(64000);
410
400
  });
411
401
 
412
- test("activeProfile applies when set with no overrideProfile and no callsite", () => {
402
+ test("activeProfile applies for mainAgent when set with no overrideProfile and no callsite", () => {
413
403
  const llm = LLMSchema.parse({
414
- default: fullDefault,
415
404
  profiles: {
416
- balanced: { effort: "medium", verbosity: "low" },
405
+ mine: {
406
+ provider: "anthropic",
407
+ model: "claude-sonnet-4-7",
408
+ effort: "medium",
409
+ verbosity: "low",
410
+ },
417
411
  },
418
- activeProfile: "balanced",
412
+ activeProfile: "mine",
419
413
  });
420
414
  const resolved = resolveCallSiteConfig("mainAgent", llm);
421
415
  expect(resolved.effort).toBe("medium");
422
416
  expect(resolved.verbosity).toBe("low");
423
- // Default still shines through where the profile is silent.
424
- expect(resolved.model).toBe("claude-opus-4-7");
417
+ expect(resolved.model).toBe("claude-sonnet-4-7");
418
+ // The base still shines through where the winner is silent.
425
419
  expect(resolved.speed).toBe("standard");
426
420
  });
427
421
 
428
- test("overrideProfile beats activeProfile but loses to non-main callsite-level fields", () => {
422
+ test("call-site tweak fields apply over the override winner; shadowed profiles contribute nothing", () => {
429
423
  const llm = LLMSchema.parse({
430
- default: fullDefault,
431
424
  profiles: {
432
- active: { effort: "low", verbosity: "low" },
433
- override: { effort: "high", speed: "fast" },
425
+ active: {
426
+ provider: "anthropic",
427
+ model: "active-model",
428
+ effort: "low",
429
+ verbosity: "low",
430
+ },
431
+ override: {
432
+ provider: "anthropic",
433
+ model: "override-model",
434
+ effort: "high",
435
+ speed: "fast",
436
+ },
434
437
  },
435
438
  callSites: {
436
439
  memoryExtraction: { effort: "none" },
@@ -440,68 +443,50 @@ describe("resolveCallSiteConfig", () => {
440
443
  const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
441
444
  overrideProfile: "override",
442
445
  });
443
- // Callsite fragment wins for effort.
446
+ // The call-site tweak is the last composition layer.
444
447
  expect(resolved.effort).toBe("none");
445
- // Override profile wins where callsite is silent.
448
+ // The override profile is the single winner.
449
+ expect(resolved.model).toBe("override-model");
446
450
  expect(resolved.speed).toBe("fast");
447
- // Active profile wins where neither override nor callsite touches.
448
- expect(resolved.verbosity).toBe("low");
451
+ // The active profile is not the winner, so its fields never contribute —
452
+ // verbosity falls to the schema default.
453
+ expect(resolved.verbosity).toBe("medium");
449
454
  });
450
455
 
451
- test("forceOverrideProfile floats the override profile above site profile and callsite fields for non-main call sites", () => {
456
+ test("call-site tweak fields apply on top of the override winner regardless of forceOverrideProfile", () => {
452
457
  const llm = LLMSchema.parse({
453
- default: fullDefault,
454
458
  profiles: {
455
- active: { verbosity: "low" },
456
- sitep: { effort: "none", speed: "fast" },
457
459
  forced: {
458
- model: "claude-haiku-4-5",
460
+ provider: "anthropic",
461
+ model: "claude-opus-4-7",
459
462
  effort: "high",
460
- thinking: { enabled: false },
461
463
  },
462
464
  },
463
465
  callSites: {
464
- memoryExtraction: { profile: "sitep", maxTokens: 1000 },
466
+ memoryExtraction: { effort: "none" },
465
467
  },
466
- activeProfile: "active",
467
468
  });
468
- const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
469
+ const plain = resolveCallSiteConfig("memoryExtraction", llm, {
469
470
  overrideProfile: "forced",
470
- forceOverrideProfile: true,
471
471
  });
472
- // Forced override wins over both the site profile and the call-site
473
- // override fields it touches.
474
- expect(resolved.model).toBe("claude-haiku-4-5");
475
- expect(resolved.effort).toBe("high");
476
- expect(resolved.thinking.enabled).toBe(false);
477
- // Call-site layers still win where the forced profile is silent.
478
- expect(resolved.maxTokens).toBe(1000);
479
- expect(resolved.speed).toBe("fast");
480
- // Active profile still applies under everything.
481
- expect(resolved.verbosity).toBe("low");
482
- });
483
-
484
- test("forceOverrideProfile absent leaves the override below callsite fields (unchanged precedence)", () => {
485
- const llm = LLMSchema.parse({
486
- default: fullDefault,
487
- profiles: {
488
- forced: { effort: "high" },
489
- },
490
- callSites: {
491
- memoryExtraction: { effort: "none" },
492
- },
493
- });
494
- const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
472
+ const forced = resolveCallSiteConfig("memoryExtraction", llm, {
495
473
  overrideProfile: "forced",
474
+ forceOverrideProfile: true,
496
475
  });
497
- expect(resolved.effort).toBe("none");
476
+ // The tweak is the last layer in both cases; force is a no-op.
477
+ expect(plain.effort).toBe("none");
478
+ expect(plain.model).toBe("claude-opus-4-7");
479
+ expect(forced).toEqual(plain);
498
480
  });
499
481
 
500
- test("forceOverrideProfile with a missing profile reference falls through to unchanged precedence", () => {
482
+ test("forceOverrideProfile with a missing profile reference falls through to the call-site profile", () => {
501
483
  const llm = LLMSchema.parse({
502
- default: fullDefault,
503
484
  profiles: {
504
- sitep: { effort: "low", model: "claude-haiku-4-5" },
485
+ sitep: {
486
+ provider: "anthropic",
487
+ effort: "low",
488
+ model: "claude-haiku-4-5",
489
+ },
505
490
  },
506
491
  callSites: {
507
492
  memoryExtraction: { profile: "sitep" },
@@ -511,20 +496,24 @@ describe("resolveCallSiteConfig", () => {
511
496
  overrideProfile: "nonexistent",
512
497
  forceOverrideProfile: true,
513
498
  });
514
- // The missing reference is inert: site profile still wins.
499
+ // The missing reference is inert: the site profile still wins.
515
500
  expect(resolved.effort).toBe("low");
516
501
  expect(resolved.model).toBe("claude-haiku-4-5");
517
502
  });
518
503
 
519
504
  test("forceOverrideProfile is a no-op for mainAgent (override already resolves on top)", () => {
520
505
  const llm = LLMSchema.parse({
521
- default: fullDefault,
522
506
  profiles: {
523
- active: { effort: "low" },
524
- override: { effort: "high" },
525
- },
526
- callSites: {
527
- mainAgent: { effort: "none" },
507
+ active: {
508
+ provider: "anthropic",
509
+ model: "claude-sonnet-4-7",
510
+ effort: "low",
511
+ },
512
+ override: {
513
+ provider: "anthropic",
514
+ model: "claude-opus-4-7",
515
+ effort: "high",
516
+ },
528
517
  },
529
518
  activeProfile: "active",
530
519
  });
@@ -539,13 +528,16 @@ describe("resolveCallSiteConfig", () => {
539
528
  expect(withForce.effort).toBe("high");
540
529
  });
541
530
 
542
- test("overrideProfile absent leaves prior behavior intact", () => {
543
- // No `opts` argument at all — the resolver must behave exactly as it did
544
- // before this PR for configs without activeProfile/overrideProfile.
531
+ test("overrideProfile absent leaves the call-site profile as the winner", () => {
532
+ // No `opts` argument at all — the call-site profile wins the chain.
545
533
  const llm = LLMSchema.parse({
546
- default: fullDefault,
547
534
  profiles: {
548
- fast: { speed: "fast", effort: "low" },
535
+ fast: {
536
+ provider: "anthropic",
537
+ model: "claude-opus-4-7",
538
+ speed: "fast",
539
+ effort: "low",
540
+ },
549
541
  },
550
542
  callSites: {
551
543
  memoryExtraction: { profile: "fast" },
@@ -558,33 +550,13 @@ describe("resolveCallSiteConfig", () => {
558
550
  expect(resolved.model).toBe("claude-opus-4-7");
559
551
  });
560
552
 
561
- test("overrideProfile referencing a missing key falls through silently", () => {
562
- const llm = LLMSchema.parse({
563
- default: fullDefault,
564
- profiles: {
565
- balanced: { effort: "medium" },
566
- },
567
- });
568
- // The schema's superRefine doesn't validate `overrideProfile` (it's a
569
- // runtime parameter), so a missing key must silently fall through.
570
- const resolved = resolveCallSiteConfig("mainAgent", llm, {
571
- overrideProfile: "nonexistent",
572
- });
573
- // overrideProfile is set so the shipped default's profile is stripped.
574
- // The nonexistent overrideProfile also adds nothing. Falls through to default.
575
- expect(resolved.effort).toBe("max");
576
- expect(resolved.model).toBe("claude-opus-4-7");
577
- });
578
-
579
553
  test("activeProfile referencing a missing key falls through silently", () => {
580
554
  // Hand-craft an `LLMSchema`-typed object that bypasses superRefine —
581
555
  // schema validation rejects an unknown `activeProfile` at parse, but the
582
- // resolver itself must not throw (parity with `overrideProfile`).
556
+ // resolver itself must not throw (parity with `overrideProfile`): the
557
+ // missing rung is skipped and resolution lands on the balanced anchor.
583
558
  const llm: z.infer<typeof LLMSchema> = {
584
- default: fullDefault,
585
- // Disable the catalog default so the missing activeProfile's silent
586
- // fall-through lands on `llm.default` rather than catalog `balanced`.
587
- profiles: { balanced: { source: "managed", status: "disabled" } },
559
+ profiles: {},
588
560
  profileOrder: [],
589
561
  callSites: {},
590
562
  activeProfile: "nonexistent",
@@ -592,113 +564,22 @@ describe("resolveCallSiteConfig", () => {
592
564
  pricingOverrides: [],
593
565
  };
594
566
  const resolved = resolveCallSiteConfig("mainAgent", llm);
595
- // Falls through to default.
596
- expect(resolved.effort).toBe("max");
597
- expect(resolved.model).toBe("claude-opus-4-7");
598
- });
599
-
600
- test("thinking and contextWindow deep-merge across the contributing layers for non-main call sites", () => {
601
- // Each layer touches a different leaf inside `thinking` and
602
- // `contextWindow.overflowRecovery` so we can verify deep merge composes
603
- // every contribution rather than wholesale-replacing the nested objects.
604
- // The call site pins `siteProfile`, so the active profile is excluded — its
605
- // leaves fall through to default while override, site profile, and the
606
- // call-site fragment still compose.
607
- const llm = LLMSchema.parse({
608
- default: fullDefault,
609
- profiles: {
610
- active: {
611
- thinking: { enabled: false },
612
- contextWindow: { overflowRecovery: { maxAttempts: 7 } },
613
- },
614
- override: {
615
- thinking: { streamThinking: false },
616
- contextWindow: { overflowRecovery: { safetyMarginRatio: 0.1 } },
617
- },
618
- siteProfile: {
619
- contextWindow: { targetBudgetRatio: 0.5 },
620
- },
621
- },
622
- callSites: {
623
- memoryExtraction: {
624
- profile: "siteProfile",
625
- contextWindow: { compactThreshold: 0.9 },
626
- },
627
- },
628
- activeProfile: "active",
629
- });
630
- const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
631
- overrideProfile: "override",
632
- });
633
- // Override, site profile, and the call-site fragment each contribute a leaf.
634
- expect(resolved.thinking.streamThinking).toBe(false); // override
635
- expect(resolved.contextWindow.overflowRecovery.safetyMarginRatio).toBe(0.1); // override
636
- expect(resolved.contextWindow.targetBudgetRatio).toBe(0.5); // siteProfile
637
- expect(resolved.contextWindow.compactThreshold).toBe(0.9); // callsite
638
- // The active profile is excluded (the call site pins its own profile), so
639
- // its leaves fall through to default instead of contributing.
640
- expect(resolved.thinking.enabled).toBe(true); // default, NOT active's false
641
- expect(resolved.contextWindow.overflowRecovery.maxAttempts).toBe(3); // default, NOT active's 7
642
- // Untouched leaves at depth 2 fall through to default.
643
- expect(resolved.contextWindow.overflowRecovery.enabled).toBe(true);
644
- expect(
645
- resolved.contextWindow.overflowRecovery.interactiveLatestTurnCompression,
646
- ).toBe("summarize");
647
- // Untouched leaves at depth 1 fall through to default.
648
- expect(resolved.contextWindow.maxInputTokens).toBe(200000);
649
- expect(resolved.contextWindow.summaryBudgetRatio).toBe(0.05);
650
- });
651
-
652
- test("callSite fragment fields still win at the top for non-main call sites", () => {
653
- const llm = LLMSchema.parse({
654
- default: fullDefault,
655
- profiles: {
656
- active: { model: "active-model", effort: "low" },
657
- override: { model: "override-model", speed: "fast" },
658
- siteProfile: { model: "siteProfile-model", verbosity: "high" },
659
- },
660
- callSites: {
661
- memoryExtraction: {
662
- profile: "siteProfile",
663
- model: "site-model",
664
- maxTokens: 12345,
665
- },
666
- },
667
- activeProfile: "active",
668
- });
669
- const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
670
- overrideProfile: "override",
671
- });
672
- // Site fragment wins for fields it sets.
673
- expect(resolved.model).toBe("site-model");
674
- expect(resolved.maxTokens).toBe(12345);
675
- // Lower layers contribute fields the site fragment does not touch.
676
- expect(resolved.verbosity).toBe("high"); // from siteProfile
677
- expect(resolved.speed).toBe("fast"); // from override
678
- // The active profile is excluded when the call site pins its own profile,
679
- // so `effort` falls through to default rather than active's "low".
680
- expect(resolved.effort).toBe("max"); // default, NOT active's "low"
567
+ expect(resolved.model).toBe(
568
+ CODE_DEFAULT_PROFILE_ENTRIES.balanced.model as string,
569
+ );
681
570
  });
682
571
 
683
- test("mainAgent activeProfile overrides static call-site defaults", () => {
572
+ test("mainAgent activeProfile determines identity when no explicit call-site tweak exists", () => {
684
573
  const llm = LLMSchema.parse({
685
- default: fullDefault,
686
574
  profiles: {
687
575
  balanced: {
576
+ source: "user",
688
577
  provider: "openai",
689
578
  model: "gpt-5.4",
690
579
  maxTokens: 16000,
691
580
  contextWindow: { maxInputTokens: 400000 },
692
581
  },
693
582
  },
694
- callSites: {
695
- mainAgent: {
696
- provider: "anthropic",
697
- model: "claude-opus-4-7",
698
- maxTokens: 32000,
699
- contextWindow: { maxInputTokens: 200000 },
700
- },
701
- },
702
583
  activeProfile: "balanced",
703
584
  });
704
585
 
@@ -710,9 +591,8 @@ describe("resolveCallSiteConfig", () => {
710
591
  expect(resolved.contextWindow.maxInputTokens).toBe(400000);
711
592
  });
712
593
 
713
- test("mainAgent overrideProfile beats activeProfile and static call-site defaults", () => {
594
+ test("mainAgent overrideProfile beats activeProfile", () => {
714
595
  const llm = LLMSchema.parse({
715
- default: fullDefault,
716
596
  profiles: {
717
597
  active: {
718
598
  provider: "openai",
@@ -727,14 +607,6 @@ describe("resolveCallSiteConfig", () => {
727
607
  contextWindow: { maxInputTokens: 1048576 },
728
608
  },
729
609
  },
730
- callSites: {
731
- mainAgent: {
732
- provider: "anthropic",
733
- model: "claude-opus-4-7",
734
- maxTokens: 32000,
735
- contextWindow: { maxInputTokens: 200000 },
736
- },
737
- },
738
610
  activeProfile: "active",
739
611
  });
740
612
 
@@ -750,9 +622,10 @@ describe("resolveCallSiteConfig", () => {
750
622
 
751
623
  test("call site with no explicit config falls back to CALL_SITE_DEFAULTS", () => {
752
624
  const llm = LLMSchema.parse({
753
- default: fullDefault,
754
625
  profiles: {
755
626
  "cost-optimized": {
627
+ source: "user",
628
+ provider: "anthropic",
756
629
  model: "claude-haiku-4-5-20251001",
757
630
  effort: "low",
758
631
  },
@@ -765,13 +638,16 @@ describe("resolveCallSiteConfig", () => {
765
638
 
766
639
  test("empty-state greeting defaults to the balanced profile", () => {
767
640
  const llm = LLMSchema.parse({
768
- default: fullDefault,
769
641
  profiles: {
770
642
  balanced: {
643
+ source: "user",
644
+ provider: "anthropic",
771
645
  model: "claude-sonnet-4-7",
772
646
  effort: "medium",
773
647
  },
774
648
  "cost-optimized": {
649
+ source: "user",
650
+ provider: "anthropic",
775
651
  model: "claude-haiku-4-5-20251001",
776
652
  effort: "low",
777
653
  },
@@ -788,13 +664,19 @@ describe("resolveCallSiteConfig", () => {
788
664
 
789
665
  test("explicit callSites config overrides CALL_SITE_DEFAULTS", () => {
790
666
  const llm = LLMSchema.parse({
791
- default: fullDefault,
792
667
  profiles: {
793
668
  "cost-optimized": {
669
+ source: "user",
670
+ provider: "anthropic",
794
671
  model: "claude-haiku-4-5-20251001",
795
672
  effort: "low",
796
673
  },
797
- "quality-optimized": { model: "claude-opus-4-7", effort: "max" },
674
+ "quality-optimized": {
675
+ source: "user",
676
+ provider: "anthropic",
677
+ model: "claude-opus-4-7",
678
+ effort: "max",
679
+ },
798
680
  },
799
681
  callSites: {
800
682
  memoryExtraction: { profile: "quality-optimized" },
@@ -805,121 +687,36 @@ describe("resolveCallSiteConfig", () => {
805
687
  expect(resolved.effort).toBe("max");
806
688
  });
807
689
 
808
- test("BYOK: disabled managed profile falls back to custom-* user profile", () => {
690
+ test("BYOK: a disabled managed stub does not block resolution the default-provider intent wins", () => {
809
691
  const llm = LLMSchema.parse({
810
- default: {
811
- ...fullDefault,
812
- provider: "openai",
813
- model: "gpt-5.5",
814
- provider_connection: "openai-personal",
815
- },
816
692
  profiles: {
817
- "cost-optimized": {
818
- status: "disabled",
819
- model: "claude-haiku-4-5-20251001",
820
- provider: "anthropic",
821
- provider_connection: "anthropic-managed",
822
- },
823
- "custom-cost-optimized": {
824
- source: "user",
825
- model: "gpt-5.4-nano",
826
- provider: "openai",
827
- provider_connection: "openai-personal",
828
- },
829
- "custom-balanced": {
830
- source: "user",
831
- model: "gpt-5.5",
832
- provider: "openai",
833
- provider_connection: "openai-personal",
834
- },
835
- },
836
- activeProfile: "custom-balanced",
837
- });
838
- const resolved = resolveCallSiteConfig("memoryExtraction", llm);
839
- expect(resolved.provider).toBe("openai");
840
- expect(resolved.model).toBe("gpt-5.4-nano");
841
- expect(resolved.provider_connection).toBe("openai-personal");
842
- });
843
-
844
- test("BYOK: strips profile when neither managed nor custom-* is available", () => {
845
- const llm = LLMSchema.parse({
846
- default: {
847
- ...fullDefault,
848
- provider: "openai",
849
- model: "gpt-5.5",
850
- provider_connection: "openai-personal",
851
- },
852
- profiles: {
853
- "cost-optimized": {
854
- status: "disabled",
855
- model: "claude-haiku-4-5-20251001",
856
- provider: "anthropic",
857
- provider_connection: "anthropic-managed",
858
- },
859
- "custom-balanced": {
860
- model: "gpt-5.5",
861
- provider: "openai",
862
- provider_connection: "openai-personal",
863
- },
693
+ "cost-optimized": { source: "managed", status: "disabled" },
864
694
  },
865
- activeProfile: "custom-balanced",
695
+ defaultProvider: { provider: "openai" },
866
696
  });
867
697
  const resolved = resolveCallSiteConfig("memoryExtraction", llm);
868
698
  expect(resolved.provider).toBe("openai");
869
- expect(resolved.model).toBe("gpt-5.5");
870
699
  expect(resolved.provider_connection).toBe("openai-personal");
700
+ expect(resolved.model).toBe(
701
+ resolveModelIntent("openai", "latency-optimized"),
702
+ );
871
703
  });
872
704
 
873
- test("BYOK full-workspace: cost-optimized call sites use custom-cost-optimized, balanced use custom-balanced", () => {
705
+ test("BYOK full-workspace: every call site resolves through the default provider, never the managed connection", () => {
874
706
  const byokConfig = LLMSchema.parse({
875
- default: {
876
- ...fullDefault,
877
- provider: "openai",
878
- model: "gpt-5.5",
879
- provider_connection: "openai-personal",
880
- },
881
707
  profiles: {
882
- balanced: {
883
- status: "disabled",
884
- source: "managed",
885
- provider: "anthropic",
886
- model: "claude-sonnet-4-6",
887
- provider_connection: "anthropic-managed",
888
- },
889
- "cost-optimized": {
890
- status: "disabled",
891
- source: "managed",
892
- provider: "anthropic",
893
- model: "claude-haiku-4-5-20251001",
894
- provider_connection: "anthropic-managed",
895
- },
896
- "quality-optimized": {
897
- status: "disabled",
898
- source: "managed",
899
- provider: "anthropic",
900
- model: "claude-opus-4-7",
901
- provider_connection: "anthropic-managed",
902
- },
708
+ balanced: { source: "managed", status: "disabled" },
709
+ "cost-optimized": { source: "managed", status: "disabled" },
710
+ "quality-optimized": { source: "managed", status: "disabled" },
903
711
  "custom-balanced": {
904
712
  source: "user",
905
713
  provider: "openai",
906
714
  model: "gpt-5.5",
907
715
  provider_connection: "openai-personal",
908
716
  },
909
- "custom-cost-optimized": {
910
- source: "user",
911
- provider: "openai",
912
- model: "gpt-5.4-nano",
913
- provider_connection: "openai-personal",
914
- },
915
- "custom-quality-optimized": {
916
- source: "user",
917
- provider: "openai",
918
- model: "gpt-5.5-pro",
919
- provider_connection: "openai-personal",
920
- },
921
717
  },
922
718
  activeProfile: "custom-balanced",
719
+ defaultProvider: { provider: "openai" },
923
720
  });
924
721
 
925
722
  const callSites: LLMCallSite[] = [
@@ -952,48 +749,30 @@ describe("resolveCallSiteConfig", () => {
952
749
  expect(resolved.provider).toBe("openai");
953
750
  }
954
751
 
955
- // Cost-optimized call sites should use the user's nano model
752
+ // Cost-optimized call sites resolve the intent through the BYOK provider.
956
753
  const costSite = resolveCallSiteConfig("heartbeatAgent", byokConfig);
957
- expect(costSite.model).toBe("gpt-5.4-nano");
754
+ expect(costSite.model).toBe(
755
+ resolveModelIntent("openai", "latency-optimized"),
756
+ );
958
757
 
959
- // Balanced call sites should use the user's balanced model
758
+ // mainAgent uses the user's active profile.
960
759
  const balancedSite = resolveCallSiteConfig("mainAgent", byokConfig);
961
760
  expect(balancedSite.model).toBe("gpt-5.5");
962
761
  });
963
762
 
964
- test("BYOK: tuning overrides from defaults apply on top of custom-* fallback profile", () => {
763
+ test("BYOK: tuning overrides from CALL_SITE_DEFAULTS apply on top of the default-provider winner", () => {
965
764
  const byokConfig = LLMSchema.parse({
966
- default: {
967
- ...fullDefault,
968
- provider: "openai",
969
- model: "gpt-5.5",
970
- provider_connection: "openai-personal",
971
- },
972
765
  profiles: {
973
- "cost-optimized": {
974
- status: "disabled",
975
- provider: "anthropic",
976
- model: "claude-haiku-4-5-20251001",
977
- provider_connection: "anthropic-managed",
978
- },
979
- "custom-cost-optimized": {
980
- source: "user",
981
- provider: "openai",
982
- model: "gpt-5.4-nano",
983
- provider_connection: "openai-personal",
984
- },
985
- "custom-balanced": {
986
- provider: "openai",
987
- model: "gpt-5.5",
988
- provider_connection: "openai-personal",
989
- },
766
+ "cost-optimized": { source: "managed", status: "disabled" },
990
767
  },
991
- activeProfile: "custom-balanced",
768
+ defaultProvider: { provider: "openai" },
992
769
  });
993
770
 
994
771
  const resolved = resolveCallSiteConfig("commitMessage", byokConfig);
995
772
  expect(resolved.provider).toBe("openai");
996
- expect(resolved.model).toBe("gpt-5.4-nano");
773
+ expect(resolved.model).toBe(
774
+ resolveModelIntent("openai", "latency-optimized"),
775
+ );
997
776
  expect(resolved.maxTokens).toBe(120);
998
777
  expect(resolved.effort).toBe("low");
999
778
  expect(resolved.thinking.enabled).toBe(false);
@@ -1001,10 +780,19 @@ describe("resolveCallSiteConfig", () => {
1001
780
 
1002
781
  test("overrideProfile wins over CALL_SITE_DEFAULTS profile for non-main call sites", () => {
1003
782
  const llm = LLMSchema.parse({
1004
- default: fullDefault,
1005
783
  profiles: {
1006
- "cost-optimized": { model: "claude-haiku-4-5-20251001", effort: "low" },
1007
- "quality-optimized": { model: "claude-opus-4-7", effort: "max" },
784
+ "cost-optimized": {
785
+ source: "user",
786
+ provider: "anthropic",
787
+ model: "claude-haiku-4-5-20251001",
788
+ effort: "low",
789
+ },
790
+ "quality-optimized": {
791
+ source: "user",
792
+ provider: "anthropic",
793
+ model: "claude-opus-4-7",
794
+ effort: "max",
795
+ },
1008
796
  },
1009
797
  });
1010
798
  const resolved = resolveCallSiteConfig("inference", llm, {
@@ -1014,20 +802,12 @@ describe("resolveCallSiteConfig", () => {
1014
802
  expect(resolved.effort).toBe("max");
1015
803
  });
1016
804
 
1017
- test("profile with provider but no provider_connection inherits stale default connection (JARVIS-861)", () => {
1018
- // This test documents the merge behavior that causes JARVIS-861: a profile
1019
- // overrides `provider` but not `provider_connection`, so the deep merge
1020
- // inherits a stale connection from the default layer. The fix is in the
1021
- // dispatch layer (connection-resolution auto-resolves the mismatch).
805
+ test("a winning profile without provider_connection resolves without one (no stale connection inheritance)", () => {
806
+ // Single-winner selection means nothing outside the winner can supply a
807
+ // provider connection: a profile that omits it resolves without one, and
808
+ // dispatch auto-resolves the connection by provider (JARVIS-861).
1022
809
  const llm = LLMSchema.parse({
1023
- default: {
1024
- ...fullDefault,
1025
- provider_connection: "anthropic-managed",
1026
- },
1027
810
  profiles: {
1028
- // Disable the catalog default so the stale connection under test
1029
- // comes from `llm.default`, not the catalog `balanced` layer.
1030
- balanced: { source: "managed", status: "disabled" },
1031
811
  fireworks: {
1032
812
  provider: "fireworks",
1033
813
  model: "accounts/fireworks/models/kimi-k2p5",
@@ -1039,18 +819,16 @@ describe("resolveCallSiteConfig", () => {
1039
819
  const resolved = resolveCallSiteConfig("mainAgent", llm);
1040
820
 
1041
821
  expect(resolved.provider).toBe("fireworks");
1042
- // The merge inherits the stale connection — the dispatch layer handles this.
1043
- expect(resolved.provider_connection).toBe("anthropic-managed");
822
+ expect(resolved.provider_connection).toBeUndefined();
1044
823
  });
1045
824
  });
1046
825
 
1047
826
  describe("mix profiles", () => {
1048
827
  // A mix that routes 80% to `a` (model-a) and 20% to `b` (model-b).
1049
828
  const mixLlm = LLMSchema.parse({
1050
- default: fullDefault,
1051
829
  profiles: {
1052
- a: { model: "model-a", effort: "low" },
1053
- b: { model: "model-b", effort: "high" },
830
+ a: { provider: "anthropic", model: "model-a", effort: "low" },
831
+ b: { provider: "anthropic", model: "model-b", effort: "high" },
1054
832
  ab: {
1055
833
  mix: [
1056
834
  { profile: "a", weight: 80 },
@@ -1074,15 +852,18 @@ describe("mix profiles", () => {
1074
852
  expect(first.model).toBe(second.model);
1075
853
  expect(["model-a", "model-b"]).toContain(first.model);
1076
854
  // The chosen arm's other fields flow through; the other arm's don't.
1077
- if (first.model === "model-a") expect(first.effort).toBe("low");
1078
- else expect(first.effort).toBe("high");
855
+ if (first.model === "model-a") {
856
+ expect(first.effort).toBe("low");
857
+ } else {
858
+ expect(first.effort).toBe("high");
859
+ }
1079
860
  });
1080
861
 
1081
862
  test("all dereference spots in a turn agree for the same seed", () => {
1082
- // mainAgent (mix layered as activeProfile) and a non-main call site
1083
- // resolving the same mix as activeProfile must pick the same arm when
1084
- // given the same conversation seed — guards the invariant that every
1085
- // resolver call within a conversation lands on one arm.
863
+ // mainAgent (mix as activeProfile) and a non-main call site resolving the
864
+ // same mix as its call-site profile must pick the same arm when given the
865
+ // same conversation seed — guards the invariant that every resolver call
866
+ // within a conversation lands on one arm.
1086
867
  const main = resolveCallSiteConfig("mainAgent", mixLlm, {
1087
868
  selectionSeed: "conv-xyz",
1088
869
  });
@@ -1099,8 +880,11 @@ describe("mix profiles", () => {
1099
880
  const resolved = resolveCallSiteConfig("mainAgent", mixLlm, {
1100
881
  selectionSeed: `conv-${i}`,
1101
882
  });
1102
- if (resolved.model === "model-a") aCount++;
1103
- else if (resolved.model === "model-b") bCount++;
883
+ if (resolved.model === "model-a") {
884
+ aCount++;
885
+ } else if (resolved.model === "model-b") {
886
+ bCount++;
887
+ }
1104
888
  }
1105
889
  // Both arms must be reachable, and the 80/20 weighting must skew toward
1106
890
  // `a`. Wide band so the assertion locks weighting without coupling to the
@@ -1113,10 +897,9 @@ describe("mix profiles", () => {
1113
897
 
1114
898
  test("relative weights are normalized by their sum ([80,20] ≡ [4,1])", () => {
1115
899
  const llm2 = LLMSchema.parse({
1116
- default: fullDefault,
1117
900
  profiles: {
1118
- a: { model: "model-a" },
1119
- b: { model: "model-b" },
901
+ a: { provider: "anthropic", model: "model-a" },
902
+ b: { provider: "anthropic", model: "model-b" },
1120
903
  ab: {
1121
904
  mix: [
1122
905
  { profile: "a", weight: 4 },
@@ -1139,10 +922,9 @@ describe("mix profiles", () => {
1139
922
 
1140
923
  test("mix works as overrideProfile", () => {
1141
924
  const llm = LLMSchema.parse({
1142
- default: fullDefault,
1143
925
  profiles: {
1144
- a: { model: "model-a" },
1145
- b: { model: "model-b" },
926
+ a: { provider: "anthropic", model: "model-a" },
927
+ b: { provider: "anthropic", model: "model-b" },
1146
928
  ab: {
1147
929
  mix: [
1148
930
  { profile: "a", weight: 50 },
@@ -1160,10 +942,9 @@ describe("mix profiles", () => {
1160
942
 
1161
943
  test("mix works as a call-site profile (non-mainAgent and mainAgent)", () => {
1162
944
  const llm = LLMSchema.parse({
1163
- default: fullDefault,
1164
945
  profiles: {
1165
- a: { model: "model-a" },
1166
- b: { model: "model-b" },
946
+ a: { provider: "anthropic", model: "model-a" },
947
+ b: { provider: "anthropic", model: "model-b" },
1167
948
  ab: {
1168
949
  mix: [
1169
950
  { profile: "a", weight: 50 },
@@ -1211,7 +992,6 @@ describe("mix profiles", () => {
1211
992
 
1212
993
  describe("mix validation (LLMSchema.superRefine)", () => {
1213
994
  const base = {
1214
- default: fullDefault,
1215
995
  profiles: {
1216
996
  a: { model: "model-a" },
1217
997
  b: { model: "model-b" },
@@ -1343,7 +1123,6 @@ describe("mix validation (LLMSchema.superRefine)", () => {
1343
1123
  describe("resolveDefaultProfileKey", () => {
1344
1124
  test("mainAgent returns activeProfile when set and enabled", () => {
1345
1125
  const llm = LLMSchema.parse({
1346
- default: fullDefault,
1347
1126
  profiles: {
1348
1127
  balanced: { provider: "anthropic", model: "claude-sonnet-4-7" },
1349
1128
  gemini: { provider: "gemini", model: "gemini-2.5-pro" },
@@ -1353,9 +1132,8 @@ describe("resolveDefaultProfileKey", () => {
1353
1132
  expect(resolveDefaultProfileKey("mainAgent", llm)).toBe("gemini");
1354
1133
  });
1355
1134
 
1356
- test("mainAgent falls back to catalog default when activeProfile is unset", () => {
1135
+ test("mainAgent falls back to the call-site intent when activeProfile is unset", () => {
1357
1136
  const llm = LLMSchema.parse({
1358
- default: fullDefault,
1359
1137
  profiles: {
1360
1138
  balanced: { provider: "anthropic", model: "claude-sonnet-4-7" },
1361
1139
  },
@@ -1364,9 +1142,8 @@ describe("resolveDefaultProfileKey", () => {
1364
1142
  expect(resolveDefaultProfileKey("mainAgent", llm)).toBe("balanced");
1365
1143
  });
1366
1144
 
1367
- test("mainAgent falls back to catalog default when activeProfile points to a missing profile", () => {
1145
+ test("mainAgent falls back to the call-site intent when activeProfile points to a missing profile", () => {
1368
1146
  const llm = LLMSchema.parse({
1369
- default: fullDefault,
1370
1147
  profiles: {
1371
1148
  balanced: { provider: "anthropic", model: "claude-sonnet-4-7" },
1372
1149
  },
@@ -1378,9 +1155,8 @@ describe("resolveDefaultProfileKey", () => {
1378
1155
  expect(resolveDefaultProfileKey("mainAgent", mutated)).toBe("balanced");
1379
1156
  });
1380
1157
 
1381
- test("mainAgent falls back to catalog default when activeProfile is disabled", () => {
1158
+ test("mainAgent falls back to the call-site intent when activeProfile is disabled", () => {
1382
1159
  const llm = LLMSchema.parse({
1383
- default: fullDefault,
1384
1160
  profiles: {
1385
1161
  balanced: { provider: "anthropic", model: "claude-sonnet-4-7" },
1386
1162
  gemini: {
@@ -1394,9 +1170,8 @@ describe("resolveDefaultProfileKey", () => {
1394
1170
  expect(resolveDefaultProfileKey("mainAgent", llm)).toBe("balanced");
1395
1171
  });
1396
1172
 
1397
- test("non-mainAgent ignores activeProfile and returns catalog default", () => {
1173
+ test("non-mainAgent ignores activeProfile and returns the call-site intent", () => {
1398
1174
  const llm = LLMSchema.parse({
1399
- default: fullDefault,
1400
1175
  profiles: {
1401
1176
  balanced: { provider: "anthropic", model: "claude-sonnet-4-7" },
1402
1177
  "cost-optimized": { provider: "openai", model: "gpt-5-mini" },
@@ -1408,9 +1183,11 @@ describe("resolveDefaultProfileKey", () => {
1408
1183
  expect(resolveDefaultProfileKey("filingAgent", llm)).toBe("cost-optimized");
1409
1184
  });
1410
1185
 
1411
- test("non-mainAgent falls back to custom-* when the catalog profile is disabled", () => {
1186
+ test("a disabled managed default stub does not divert the key to custom-*", () => {
1187
+ // The default intent is code-owned: a legacy disabled stub is overridden
1188
+ // by the catalog body, and the user-mutable custom-* clone never captures
1189
+ // the call site.
1412
1190
  const llm = LLMSchema.parse({
1413
- default: fullDefault,
1414
1191
  profiles: {
1415
1192
  "cost-optimized": { source: "managed", status: "disabled" },
1416
1193
  "custom-cost-optimized": {
@@ -1419,17 +1196,14 @@ describe("resolveDefaultProfileKey", () => {
1419
1196
  },
1420
1197
  },
1421
1198
  });
1422
- expect(resolveDefaultProfileKey("filingAgent", llm)).toBe(
1423
- "custom-cost-optimized",
1424
- );
1199
+ expect(resolveDefaultProfileKey("filingAgent", llm)).toBe("cost-optimized");
1425
1200
  });
1426
1201
 
1427
1202
  test("mainAgent returns the mix key (not an arm) when activeProfile is a mix", () => {
1428
1203
  const llm = LLMSchema.parse({
1429
- default: fullDefault,
1430
1204
  profiles: {
1431
- a: { model: "model-a" },
1432
- b: { model: "model-b" },
1205
+ a: { provider: "anthropic", model: "model-a" },
1206
+ b: { provider: "anthropic", model: "model-b" },
1433
1207
  ab: {
1434
1208
  mix: [
1435
1209
  { profile: "a", weight: 1 },
@@ -1442,13 +1216,12 @@ describe("resolveDefaultProfileKey", () => {
1442
1216
  expect(resolveDefaultProfileKey("mainAgent", llm)).toBe("ab");
1443
1217
  });
1444
1218
 
1445
- test("mainAgent falls back to catalog default when the mix activeProfile is disabled", () => {
1219
+ test("mainAgent falls back to the call-site intent when the mix activeProfile is disabled", () => {
1446
1220
  const llm = LLMSchema.parse({
1447
- default: fullDefault,
1448
1221
  profiles: {
1449
1222
  balanced: { provider: "anthropic", model: "claude-sonnet-4-7" },
1450
- a: { model: "model-a" },
1451
- b: { model: "model-b" },
1223
+ a: { provider: "anthropic", model: "model-a" },
1224
+ b: { provider: "anthropic", model: "model-b" },
1452
1225
  ab: {
1453
1226
  status: "disabled",
1454
1227
  mix: [
@@ -1465,7 +1238,6 @@ describe("resolveDefaultProfileKey", () => {
1465
1238
 
1466
1239
  describe("resolveEffectiveProfileKey", () => {
1467
1240
  const llm = LLMSchema.parse({
1468
- default: fullDefault,
1469
1241
  profiles: {
1470
1242
  balanced: { provider: "anthropic", model: "claude-sonnet-4-7" },
1471
1243
  "cost-optimized": { provider: "openai", model: "gpt-5-mini" },
@@ -1486,10 +1258,7 @@ describe("resolveEffectiveProfileKey", () => {
1486
1258
  expect(resolveEffectiveProfileKey("mainAgent", llm)).toBe("balanced");
1487
1259
  });
1488
1260
 
1489
- // Codex P2: a pinned override on a bare non-mainAgent site must attribute to
1490
- // the override — `effectiveDefault` strips the catalog default when an
1491
- // override is present, so the override is the profile that supplies the config.
1492
- test("non-mainAgent: pinned override wins over stripped catalog default", () => {
1261
+ test("non-mainAgent: pinned override wins over the call-site intent", () => {
1493
1262
  expect(
1494
1263
  resolveEffectiveProfileKey("filingAgent", llm, {
1495
1264
  overrideProfile: "pinned",
@@ -1497,14 +1266,16 @@ describe("resolveEffectiveProfileKey", () => {
1497
1266
  ).toBe("pinned");
1498
1267
  });
1499
1268
 
1500
- test("non-mainAgent: catalog default when no override", () => {
1269
+ test("non-mainAgent: call-site intent when no override", () => {
1501
1270
  // filingAgent's CALL_SITE_DEFAULTS profile is `cost-optimized`.
1502
1271
  expect(resolveEffectiveProfileKey("filingAgent", llm)).toBe(
1503
1272
  "cost-optimized",
1504
1273
  );
1505
1274
  });
1506
1275
 
1507
- test("non-mainAgent: explicit call-site profile is authoritative over override", () => {
1276
+ test("non-mainAgent: the override outranks an explicit call-site profile (forced or not)", () => {
1277
+ // The override is the first rung of the selection chain on every call
1278
+ // site; `forceOverrideProfile` is a no-op.
1508
1279
  const withSite = LLMSchema.parse({
1509
1280
  ...llm,
1510
1281
  callSites: { filingAgent: { profile: "cost-optimized" } },
@@ -1513,14 +1284,7 @@ describe("resolveEffectiveProfileKey", () => {
1513
1284
  resolveEffectiveProfileKey("filingAgent", withSite, {
1514
1285
  overrideProfile: "pinned",
1515
1286
  }),
1516
- ).toBe("cost-optimized");
1517
- });
1518
-
1519
- test("non-mainAgent: forced override floats above the call-site profile", () => {
1520
- const withSite = LLMSchema.parse({
1521
- ...llm,
1522
- callSites: { filingAgent: { profile: "cost-optimized" } },
1523
- });
1287
+ ).toBe("pinned");
1524
1288
  expect(
1525
1289
  resolveEffectiveProfileKey("filingAgent", withSite, {
1526
1290
  overrideProfile: "pinned",
@@ -1535,7 +1299,6 @@ describe("resolveCallSiteConfig logitBias provenance", () => {
1535
1299
 
1536
1300
  test("forwards logitBias from the active profile that opted in", () => {
1537
1301
  const llm = LLMSchema.parse({
1538
- default: fullDefault,
1539
1302
  profiles: {
1540
1303
  "balanced-economy": {
1541
1304
  provider: "fireworks",
@@ -1550,12 +1313,11 @@ describe("resolveCallSiteConfig logitBias provenance", () => {
1550
1313
  );
1551
1314
  });
1552
1315
 
1553
- test("a higher-precedence override profile that omits logitBias clears it", () => {
1316
+ test("an override profile that omits logitBias clears it", () => {
1554
1317
  // Active profile opts in, but a pinned (override) Kimi profile did not —
1555
1318
  // the override must not inherit suppress-cjk just because it resolves to
1556
1319
  // Fireworks.
1557
1320
  const llm = LLMSchema.parse({
1558
- default: fullDefault,
1559
1321
  profiles: {
1560
1322
  "balanced-economy": {
1561
1323
  provider: "fireworks",
@@ -1576,7 +1338,6 @@ describe("resolveCallSiteConfig logitBias provenance", () => {
1576
1338
  // For non-main call sites the call-site profile wins; since it didn't opt
1577
1339
  // in, the active profile's preset must not bleed through.
1578
1340
  const llm = LLMSchema.parse({
1579
- default: fullDefault,
1580
1341
  profiles: {
1581
1342
  "balanced-economy": {
1582
1343
  provider: "fireworks",
@@ -1592,24 +1353,14 @@ describe("resolveCallSiteConfig logitBias provenance", () => {
1592
1353
  resolveCallSiteConfig("memoryExtraction", llm).logitBias,
1593
1354
  ).toBeUndefined();
1594
1355
  });
1595
-
1596
- test("a logitBias on a non-profile layer (llm.default) does not apply when the winning profile omits it", () => {
1597
- const llm = LLMSchema.parse({
1598
- default: { ...fullDefault, logitBias: "suppress-cjk" },
1599
- profiles: { plain: { provider: "anthropic", model: "claude-opus-4-7" } },
1600
- activeProfile: "plain",
1601
- });
1602
- expect(resolveCallSiteConfig("mainAgent", llm).logitBias).toBeUndefined();
1603
- });
1604
1356
  });
1605
1357
 
1606
1358
  describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)", () => {
1607
- // Mirrors production: the active `balanced` profile carries `topP: 0.95` (a
1359
+ // Mirrors production: the user's `balanced` profile carries `topP: 0.95` (a
1608
1360
  // MiniMax tuning), while background call sites resolve to the Anthropic
1609
- // `cost-optimized` profile. A field-by-field deep-merge would leak the active
1361
+ // `cost-optimized` profile. A cross-profile leak would put the balanced
1610
1362
  // profile's `top_p` onto those Anthropic requests.
1611
1363
  const balancedActive = LLMSchema.parse({
1612
- default: fullDefault,
1613
1364
  profiles: {
1614
1365
  balanced: {
1615
1366
  provider: "together",
@@ -1626,9 +1377,8 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1626
1377
  activeProfile: "balanced",
1627
1378
  });
1628
1379
 
1629
- test("active profile's top_p does not leak into a profile-pinned call site (Option 1 + 2)", () => {
1380
+ test("active profile's top_p does not leak into a profile-pinned call site", () => {
1630
1381
  const llm = LLMSchema.parse({
1631
- default: fullDefault,
1632
1382
  profiles: {
1633
1383
  balanced: {
1634
1384
  provider: "together",
@@ -1646,8 +1396,8 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1646
1396
  const resolved = resolveCallSiteConfig("memoryExtraction", llm);
1647
1397
  expect(resolved.provider).toBe("anthropic");
1648
1398
  expect(resolved.model).toBe("claude-haiku-4-5-20251001");
1649
- // balanced (active) is shadowed by the pinned cost-optimized profile, so
1650
- // its top_p must not ride along onto the Anthropic request.
1399
+ // balanced is not the winner here, so its top_p must not ride along onto
1400
+ // the Anthropic request.
1651
1401
  expect(resolved.topP).toBeNull();
1652
1402
  });
1653
1403
 
@@ -1656,7 +1406,7 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1656
1406
  expect(greeting.model).toBe("claude-haiku-4-5-20251001");
1657
1407
  // Per-call-site temperature from CALL_SITE_DEFAULTS survives.
1658
1408
  expect(greeting.temperature).toBe(0.7);
1659
- // The active profile's top_p does NOT — both together would trip
1409
+ // The balanced profile's top_p does NOT — both together would trip
1660
1410
  // Anthropic's "temperature and top_p cannot both be specified".
1661
1411
  expect(greeting.topP).toBeNull();
1662
1412
 
@@ -1665,10 +1415,10 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1665
1415
  expect(commit.topP).toBeNull();
1666
1416
  });
1667
1417
 
1668
- test("profile-less call site still inherits the active profile's provider AND sampling", () => {
1669
- // `workflowLeaf` pins no profile, so the active profile is the legitimate
1670
- // fallback (Option 1 keeps it): it supplies provider/model and its own
1671
- // (coherent, same-provider) sampling.
1418
+ test("a profile-less call site anchors on the balanced intent, which the user's shadow implements (provider AND sampling)", () => {
1419
+ // `workflowLeaf` pins no profile, so it anchors on the balanced intent —
1420
+ // here implemented by the user's own `balanced` shadow, which supplies
1421
+ // provider/model and its own (coherent, same-provider) sampling.
1672
1422
  const resolved = resolveCallSiteConfig("workflowLeaf", balancedActive);
1673
1423
  expect(resolved.provider).toBe("together");
1674
1424
  expect(resolved.model).toBe("MiniMaxAI/MiniMax-M3");
@@ -1683,8 +1433,14 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1683
1433
 
1684
1434
  test("an explicit call-site temperature override still wins over the winning profile", () => {
1685
1435
  const llm = LLMSchema.parse({
1686
- default: fullDefault,
1687
- profiles: { nucleus: { topP: 0.9, temperature: 0.1 } },
1436
+ profiles: {
1437
+ nucleus: {
1438
+ provider: "anthropic",
1439
+ model: "claude-opus-4-7",
1440
+ topP: 0.9,
1441
+ temperature: 0.1,
1442
+ },
1443
+ },
1688
1444
  callSites: { memoryExtraction: { profile: "nucleus", temperature: 0.5 } },
1689
1445
  });
1690
1446
  const resolved = resolveCallSiteConfig("memoryExtraction", llm);
@@ -1694,12 +1450,10 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1694
1450
  expect(resolved.topP).toBe(0.9);
1695
1451
  });
1696
1452
 
1697
- test("a higher-precedence profile that omits top_p clears a lower profile's top_p (Option 2)", () => {
1698
- // No site profile is involved here, so the active profile IS folded in —
1699
- // this isolates Option 2: the override profile wins and omits top_p, so
1700
- // balanced's 0.95 must be cleared rather than surviving the merge.
1453
+ test("an override winner that omits top_p clears a shadowed profile's top_p", () => {
1454
+ // The override profile wins and omits top_p, so balanced's 0.95 must not
1455
+ // survive only the single winner contributes sampling.
1701
1456
  const llm = LLMSchema.parse({
1702
- default: fullDefault,
1703
1457
  profiles: {
1704
1458
  balanced: {
1705
1459
  provider: "together",
@@ -1717,13 +1471,15 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1717
1471
  expect(resolved.topP).toBeNull();
1718
1472
  });
1719
1473
 
1720
- test("forceOverrideProfile: an explicit call-site temperature survives a forced profile silent on sampling", () => {
1474
+ test("an explicit call-site temperature survives an override winner silent on sampling", () => {
1721
1475
  const llm = LLMSchema.parse({
1722
- default: fullDefault,
1723
1476
  profiles: {
1724
- active: { verbosity: "low" },
1725
1477
  sitep: { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
1726
- forced: { model: "claude-opus-4-7", effort: "high" },
1478
+ forced: {
1479
+ provider: "anthropic",
1480
+ model: "claude-opus-4-7",
1481
+ effort: "high",
1482
+ },
1727
1483
  },
1728
1484
  callSites: {
1729
1485
  memoryExtraction: {
@@ -1732,85 +1488,71 @@ describe("resolveCallSiteConfig sampling-param provenance (temperature / top_p)"
1732
1488
  maxTokens: 1000,
1733
1489
  },
1734
1490
  },
1735
- activeProfile: "active",
1736
1491
  });
1737
1492
  const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
1738
1493
  overrideProfile: "forced",
1739
1494
  forceOverrideProfile: true,
1740
1495
  });
1741
- // The forced profile floats to the top for fields it sets.
1496
+ // The override profile is the winner for the fields it sets.
1742
1497
  expect(resolved.model).toBe("claude-opus-4-7");
1743
1498
  expect(resolved.effort).toBe("high");
1744
1499
  // It is silent on temperature, so the deliberate call-site value survives —
1745
- // consistent with sibling call-site fields like maxTokens (which flow
1746
- // through the deep-merge).
1500
+ // consistent with sibling call-site fields like maxTokens.
1747
1501
  expect(resolved.temperature).toBe(0.7);
1748
1502
  expect(resolved.maxTokens).toBe(1000);
1749
1503
  });
1750
1504
 
1751
- test("forceOverrideProfile: a forced profile that sets temperature wins over the call-site override", () => {
1505
+ test("mainAgent: an explicit call-site temperature survives an active profile silent on sampling", () => {
1752
1506
  const llm = LLMSchema.parse({
1753
- default: fullDefault,
1754
1507
  profiles: {
1755
- sitep: { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
1756
- forced: { model: "claude-opus-4-7", temperature: 0.1 },
1757
- },
1758
- callSites: {
1759
- memoryExtraction: { profile: "sitep", temperature: 0.7 },
1508
+ active: { provider: "anthropic", model: "claude-sonnet-4-7" },
1760
1509
  },
1761
- });
1762
- const resolved = resolveCallSiteConfig("memoryExtraction", llm, {
1763
- overrideProfile: "forced",
1764
- forceOverrideProfile: true,
1765
- });
1766
- // The forced profile explicitly sets temperature, so it floats above the
1767
- // call-site override.
1768
- expect(resolved.temperature).toBe(0.1);
1769
- });
1770
-
1771
- test("mainAgent: an explicit call-site temperature survives an active profile silent on sampling", () => {
1772
- const llm = LLMSchema.parse({
1773
- default: fullDefault,
1774
- profiles: { active: { model: "claude-sonnet-4-7" } },
1775
1510
  callSites: { mainAgent: { temperature: 0.5 } },
1776
1511
  activeProfile: "active",
1777
1512
  });
1778
1513
  const resolved = resolveCallSiteConfig("mainAgent", llm);
1779
- // The active profile floats above the call-site for mainAgent but is silent
1780
- // on temperature, so the deliberate call-site value survives.
1514
+ // The active profile wins the chain but is silent on temperature, so the
1515
+ // deliberate call-site value survives.
1781
1516
  expect(resolved.model).toBe("claude-sonnet-4-7");
1782
1517
  expect(resolved.temperature).toBe(0.5);
1783
1518
  });
1784
1519
 
1785
- test("mainAgent: the active profile's explicit temperature wins over a call-site temperature", () => {
1520
+ test("mainAgent: an explicit call-site temperature tweak applies over the active profile's", () => {
1786
1521
  const llm = LLMSchema.parse({
1787
- default: fullDefault,
1788
- profiles: { active: { model: "claude-sonnet-4-7", temperature: 0.2 } },
1522
+ profiles: {
1523
+ active: {
1524
+ provider: "anthropic",
1525
+ model: "claude-sonnet-4-7",
1526
+ temperature: 0.2,
1527
+ },
1528
+ },
1789
1529
  callSites: { mainAgent: { temperature: 0.5 } },
1790
1530
  activeProfile: "active",
1791
1531
  });
1792
1532
  const resolved = resolveCallSiteConfig("mainAgent", llm);
1793
- // For mainAgent the active profile floats above the call-site override, so
1794
- // its explicit temperature wins.
1795
- expect(resolved.temperature).toBe(0.2);
1533
+ // The call-site tweak is the last composition layer on every call site,
1534
+ // so its explicit temperature wins over the winner's.
1535
+ expect(resolved.temperature).toBe(0.5);
1796
1536
  });
1797
1537
  });
1798
1538
 
1799
1539
  describe("resolveCallSiteConfig — workflowLeaf default", () => {
1800
- test("inherits the workspace default config rather than pinning cost-optimized", () => {
1540
+ test("anchors on the balanced intent through the default provider rather than pinning cost-optimized", () => {
1801
1541
  const llm = LLMSchema.parse({
1802
- default: fullDefault,
1803
1542
  profiles: {
1804
1543
  "cost-optimized": {
1544
+ source: "user",
1805
1545
  provider: "anthropic",
1806
1546
  model: "claude-haiku-4-5-20251001",
1807
1547
  },
1808
1548
  },
1549
+ defaultProvider: { provider: "anthropic" },
1809
1550
  });
1810
1551
  const resolved = resolveCallSiteConfig("workflowLeaf", llm);
1811
- // No pinned profile → the model comes from llm.default, NOT the
1812
- // `cost-optimized` profile (which is uncredentialed on a BYOK install).
1813
- expect(resolved.model).toBe("claude-opus-4-7");
1552
+ // No pinned profile → the model comes from the balanced-intent anchor
1553
+ // through the default provider, NOT the `cost-optimized` profile.
1554
+ expect(resolved.model).toBe(resolveModelIntent("anthropic", "balanced"));
1555
+ expect(resolved.model).not.toBe("claude-haiku-4-5-20251001");
1814
1556
  // Call-site tuning still applies.
1815
1557
  expect(resolved.effort).toBe("low");
1816
1558
  expect(resolved.thinking?.enabled).toBe(false);
@@ -1820,7 +1562,6 @@ describe("resolveCallSiteConfig — workflowLeaf default", () => {
1820
1562
 
1821
1563
  test("honors an explicit workflowLeaf call-site override", () => {
1822
1564
  const llm = LLMSchema.parse({
1823
- default: fullDefault,
1824
1565
  profiles: {
1825
1566
  cheap: { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
1826
1567
  },
@@ -1833,7 +1574,6 @@ describe("resolveCallSiteConfig — workflowLeaf default", () => {
1833
1574
 
1834
1575
  test("honors a per-call override profile (an explicit per-leaf profile)", () => {
1835
1576
  const llm = LLMSchema.parse({
1836
- default: fullDefault,
1837
1577
  profiles: {
1838
1578
  fancy: { provider: "anthropic", model: "claude-sonnet-4-7" },
1839
1579
  },