@vellumai/assistant 0.10.9 → 0.10.10-dev.202607170046.8482d40
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.
- package/ARCHITECTURE.md +1 -1
- package/Dockerfile +8 -0
- package/docs/activation-funnel-telemetry.md +13 -7
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +26 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +16 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +26 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +16 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +26 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +16 -0
- package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/openapi.yaml +678 -107
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +8 -0
- package/src/__tests__/activation-early-marking.test.ts +6 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
- package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
- package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
- package/src/__tests__/app-bundler.test.ts +4 -12
- package/src/__tests__/app-executors.test.ts +2 -49
- package/src/__tests__/app-routes-csp.test.ts +114 -146
- package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
- package/src/__tests__/build-persisted-content.test.ts +96 -0
- package/src/__tests__/bundle-scanner.test.ts +27 -1
- package/src/__tests__/call-controller.test.ts +291 -0
- package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
- package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
- package/src/__tests__/config-loader-backfill.test.ts +9 -4
- package/src/__tests__/config-schema-cmd.test.ts +10 -11
- package/src/__tests__/config-schema.test.ts +190 -257
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
- package/src/__tests__/conversation-agent-loop.test.ts +22 -9
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
- package/src/__tests__/conversation-process-callsite.test.ts +12 -19
- package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
- package/src/__tests__/conversation-summarize-route.test.ts +36 -44
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
- package/src/__tests__/conversation-usage.test.ts +4 -12
- package/src/__tests__/credential-prompt-route.test.ts +137 -0
- package/src/__tests__/credential-routes.test.ts +355 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -0
- package/src/__tests__/db-migration-rollback.test.ts +22 -0
- package/src/__tests__/empty-response-hook.test.ts +186 -1
- package/src/__tests__/external-plugin-loader.test.ts +11 -5
- package/src/__tests__/heartbeat-service.test.ts +0 -28
- package/src/__tests__/host-shell-tool.test.ts +2 -0
- package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
- package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
- package/src/__tests__/invite-routes-http.test.ts +12 -16
- package/src/__tests__/list-all-apps.test.ts +0 -4
- package/src/__tests__/llm-context-resolution.test.ts +32 -56
- package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
- package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
- package/src/__tests__/llm-resolver.test.ts +342 -602
- package/src/__tests__/llm-schema.test.ts +79 -37
- package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
- package/src/__tests__/media-stream-output.test.ts +259 -3
- package/src/__tests__/media-stream-server-integration.test.ts +22 -1
- package/src/__tests__/media-stream-stt-session.test.ts +47 -0
- package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
- package/src/__tests__/memory-recall-log-store.test.ts +47 -13
- package/src/__tests__/mock-gateway-ipc.ts +46 -1
- package/src/__tests__/mtime-cache.test.ts +61 -0
- package/src/__tests__/navigate-settings-tab.test.ts +2 -0
- package/src/__tests__/normalize-onboarding.test.ts +33 -0
- package/src/__tests__/onboarding-persona-write.test.ts +26 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
- package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
- package/src/__tests__/provider-connections-backfill.test.ts +138 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
- package/src/__tests__/provider-registry-ollama.test.ts +8 -18
- package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
- package/src/__tests__/provider-usage-tracking.test.ts +9 -19
- package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
- package/src/__tests__/published-app-updater.test.ts +22 -16
- package/src/__tests__/registry.test.ts +5 -16
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
- package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
- package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
- package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
- package/src/__tests__/reveal-success-registry.test.ts +123 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
- package/src/__tests__/secret-fixtures.ts +9 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +77 -0
- package/src/__tests__/server-history-render.test.ts +48 -0
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/slack-share-routes.test.ts +0 -1
- package/src/__tests__/stt-stream-session.test.ts +6 -5
- package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
- package/src/__tests__/subagent-disposal.test.ts +2 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
- package/src/__tests__/subagent-manager-notify.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +37 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
- package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/telemetry-routes.test.ts +99 -19
- package/src/__tests__/tool-audit.test.ts +34 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-profiler.test.ts +72 -1
- package/src/__tests__/tool-result-spool.test.ts +49 -4
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
- package/src/__tests__/ui-channel-variants.test.ts +108 -0
- package/src/__tests__/ui-shape-teaching.test.ts +255 -0
- package/src/__tests__/usage-attribution.test.ts +18 -41
- package/src/__tests__/user-plugin-loader.test.ts +4 -4
- package/src/__tests__/voice-config-update.test.ts +46 -0
- package/src/__tests__/voice-session-bridge.test.ts +216 -84
- package/src/__tests__/weak-open-model.test.ts +8 -1
- package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +206 -0
- package/src/acp/__tests__/acp-connect-card-state.test.ts +23 -0
- package/src/acp/__tests__/acp-credentials.test.ts +87 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +161 -1
- package/src/acp/acp-claude-oauth.ts +144 -0
- package/src/acp/acp-connect-card-state.ts +39 -0
- package/src/acp/acp-credentials.ts +67 -0
- package/src/acp/prepare-agent-env.ts +103 -6
- package/src/agent/loop.ts +8 -3
- package/src/api/events/open-conversation.test.ts +64 -0
- package/src/api/events/open-conversation.ts +33 -0
- package/src/api/events/tool-result.ts +8 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +14 -0
- package/src/apps/app-store.ts +25 -35
- package/src/bundler/app-bundler.ts +34 -48
- package/src/bundler/app-compiler.ts +39 -4
- package/src/bundler/bundle-scanner.ts +13 -0
- package/src/bundler/manifest.ts +1 -1
- package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
- package/src/calls/call-constants.ts +5 -0
- package/src/calls/call-controller.ts +100 -32
- package/src/calls/call-transport.ts +9 -0
- package/src/calls/media-stream-output.ts +107 -4
- package/src/calls/media-stream-server.ts +29 -9
- package/src/calls/media-stream-stt-session.ts +7 -1
- package/src/calls/media-turn-detector.ts +11 -1
- package/src/calls/voice-session-bridge.ts +84 -63
- package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +50 -0
- package/src/cli/commands/__tests__/notifications.test.ts +24 -3
- package/src/cli/commands/config.help.ts +6 -6
- package/src/cli/commands/credentials.help.ts +13 -0
- package/src/cli/commands/credentials.ts +23 -1
- package/src/cli/commands/email.help.ts +7 -0
- package/src/cli/commands/email.ts +35 -1
- package/src/cli/commands/inference-providers.ts +168 -107
- package/src/cli/commands/inference.help.ts +118 -46
- package/src/cli/commands/inference.ts +6 -0
- package/src/cli/commands/memory/index.help.ts +23 -0
- package/src/cli/commands/memory/nodes.ts +146 -0
- package/src/cli/commands/notifications.help.ts +10 -10
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
- package/src/cli/commands/oauth/connect.test.ts +126 -0
- package/src/cli/commands/oauth/connect.ts +29 -6
- package/src/cli/commands/oauth/index.help.ts +7 -1
- package/src/cli/commands/oauth/status.test.ts +69 -3
- package/src/cli/commands/oauth/status.ts +50 -12
- package/src/cli/commands/plugins.help.ts +13 -2
- package/src/cli/commands/plugins.ts +61 -7
- package/src/cli/commands/telemetry.help.ts +13 -0
- package/src/cli/commands/telemetry.ts +45 -5
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
- package/src/cli/lib/bundled-marketplace.json +93 -36
- package/src/cli/lib/inspect-plugin.ts +5 -1
- package/src/cli/lib/install-from-github.ts +68 -4
- package/src/cli/lib/plugin-catalog-local.ts +6 -2
- package/src/cli/lib/plugin-fingerprint.ts +3 -3
- package/src/cli/lib/upgrade-plugin.ts +236 -35
- package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
- package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
- package/src/config/__tests__/profile-materialization.test.ts +1 -88
- package/src/config/bundled-skills/AGENTS.md +3 -30
- package/src/config/bundled-skills/acp/SKILL.md +11 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
- package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
- package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -1
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/call-site-defaults.ts +3 -3
- package/src/config/feature-flag-registry.json +24 -39
- package/src/config/llm-resolver.ts +88 -475
- package/src/config/profile-materialization.ts +11 -11
- package/src/config/schema.ts +93 -127
- package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
- package/src/config/schemas/__tests__/stt.test.ts +31 -3
- package/src/config/schemas/live-voice.ts +10 -4
- package/src/config/schemas/llm.ts +52 -15
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +8 -0
- package/src/config/schemas/memory-v2.ts +2 -2
- package/src/config/schemas/memory-v3.ts +1 -1
- package/src/config/schemas/services.ts +6 -3
- package/src/config/schemas/stt.ts +38 -21
- package/src/config/schemas/tts.ts +13 -18
- package/src/config/skills.ts +31 -21
- package/src/context/compactor.ts +44 -7
- package/src/context/post-turn-tool-result-truncation.ts +4 -2
- package/src/context/tool-result-spool.ts +26 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
- package/src/conversations/message-consolidation.ts +22 -2
- package/src/credential-execution/prompted-credential.ts +18 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
- package/src/daemon/app-source-watcher.ts +17 -23
- package/src/daemon/chat-credential-redaction.ts +1365 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +640 -34
- package/src/daemon/conversation-agent-loop.ts +71 -31
- package/src/daemon/conversation-error.ts +36 -14
- package/src/daemon/conversation-process.ts +22 -0
- package/src/daemon/conversation-store.ts +35 -0
- package/src/daemon/conversation-surfaces.ts +25 -25
- package/src/daemon/conversation-tool-setup.ts +33 -7
- package/src/daemon/conversation.ts +55 -5
- package/src/daemon/handlers/shared.ts +40 -2
- package/src/daemon/lifecycle.ts +4 -4
- package/src/daemon/message-types/conversations.ts +6 -17
- package/src/daemon/providers-setup.ts +8 -0
- package/src/daemon/tool-setup-types.ts +7 -1
- package/src/daemon/wake-conversation-ops.ts +10 -1
- package/src/hooks/types.ts +9 -0
- package/src/ipc/__tests__/email-ipc.test.ts +90 -0
- package/src/ipc/gateway-client.test.ts +59 -0
- package/src/ipc/gateway-client.ts +70 -27
- package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
- package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
- package/src/live-voice/__tests__/protocol.test.ts +122 -0
- package/src/live-voice/live-voice-session.ts +443 -40
- package/src/live-voice/protocol.ts +143 -1
- package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
- package/src/monitoring/plugin-source-watch.ts +3 -62
- package/src/notifications/README.md +1 -1
- package/src/permissions/checker.ts +8 -4
- package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
- package/src/persistence/conversation-crud.ts +104 -2
- package/src/persistence/db-init.ts +14 -3
- package/src/persistence/job-handlers/cleanup.ts +15 -7
- package/src/persistence/llm-request-log-store.ts +88 -52
- package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
- package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
- package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
- package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
- package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
- package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
- package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
- package/src/persistence/migrations/helpers/relocation.ts +44 -1
- package/src/persistence/migrations/run-migrations.ts +25 -1
- package/src/persistence/schema/infrastructure.ts +9 -0
- package/src/persistence/schema/memory-core.ts +3 -0
- package/src/persistence/schema/memory-injection.ts +2 -0
- package/src/persistence/steps.ts +36 -0
- package/src/platform/client.test.ts +1 -44
- package/src/platform/client.ts +10 -20
- package/src/platform/consent-cache.test.ts +89 -23
- package/src/platform/consent-cache.ts +71 -33
- package/src/plugin-api/constants.ts +12 -0
- package/src/plugin-api/conversation-turn.ts +37 -14
- package/src/plugin-api/index.ts +11 -1
- package/src/plugin-api/resolve-credential.ts +75 -0
- package/src/plugin-api/vision-support.test.ts +8 -19
- package/src/plugin-api/vision-support.ts +26 -17
- package/src/plugins/collect-source-versions.ts +77 -0
- package/src/plugins/defaults/compaction/compact.ts +6 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
- package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
- package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
- package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
- package/src/plugins/defaults/index.ts +8 -1
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
- package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
- package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
- package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
- package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
- package/src/plugins/defaults/memory/graph/store.ts +114 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
- package/src/plugins/defaults/memory/graph/tools.ts +47 -13
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
- package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
- package/src/plugins/defaults/memory/memory-db.ts +3 -2
- package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
- package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
- package/src/plugins/defaults/memory/path-containment.ts +21 -0
- package/src/plugins/defaults/memory/prompt-override.ts +51 -13
- package/src/plugins/defaults/memory/tools.test.ts +34 -0
- package/src/plugins/defaults/memory/tools.ts +12 -2
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
- package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
- package/src/plugins/defaults/memory/v2/migration.ts +46 -16
- package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
- package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
- package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
- package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
- package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
- package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
- package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
- package/src/plugins/defaults/memory/v3/prune.ts +17 -11
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +8 -6
- package/src/plugins/external-plugin-loader.ts +15 -15
- package/src/plugins/mtime-cache.ts +47 -0
- package/src/plugins/pipeline.ts +9 -1
- package/src/plugins/plugin-execution-context.ts +44 -0
- package/src/plugins/plugin-tree-walk.ts +31 -24
- package/src/plugins/source-fingerprint.ts +3 -4
- package/src/prompts/normalize-onboarding.ts +12 -0
- package/src/prompts/persona-resolver.ts +8 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
- package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
- package/src/providers/__tests__/retry-callsite.test.ts +235 -215
- package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
- package/src/providers/anthropic/client.ts +1 -0
- package/src/providers/atlascloud/client.ts +10 -49
- package/src/providers/baseten/client.ts +43 -0
- package/src/providers/call-site-routing.ts +26 -13
- package/src/providers/connection-resolution.ts +9 -11
- package/src/providers/fetch-provider-catalog.ts +4 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
- package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
- package/src/providers/inference/adapter-factory.ts +27 -6
- package/src/providers/inference/auth.ts +29 -1
- package/src/providers/inference/backfill.ts +61 -10
- package/src/providers/inference/connection-availability.ts +3 -2
- package/src/providers/inference/resolve-auth.ts +9 -1
- package/src/providers/model-catalog.ts +49 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
- package/src/providers/openai/__tests__/chat-completions-provider-endpoint.test.ts +159 -0
- package/src/providers/openai/api-key-validation.ts +70 -0
- package/src/providers/openai/chat-completions-provider.ts +1 -0
- package/src/providers/openai/responses-provider.ts +1 -0
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +18 -4
- package/src/providers/vellum-model-routing.test.ts +26 -0
- package/src/providers/vellum-model-routing.ts +30 -0
- package/src/providers/voice-error-copy.ts +47 -0
- package/src/providers/weak-open-model.ts +14 -11
- package/src/runtime/agent-wake.ts +40 -24
- package/src/runtime/for-chat-mint-registry.ts +118 -0
- package/src/runtime/reveal-nonce.ts +49 -0
- package/src/runtime/reveal-success-registry.ts +306 -0
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +408 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
- package/src/runtime/routes/__tests__/inference-send-routes.test.ts +97 -0
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
- package/src/runtime/routes/acp-claude-auth-routes.ts +389 -0
- package/src/runtime/routes/app-management-routes.ts +152 -45
- package/src/runtime/routes/app-routes.ts +16 -77
- package/src/runtime/routes/canned-message-complete.ts +16 -16
- package/src/runtime/routes/conversation-management-routes.ts +17 -14
- package/src/runtime/routes/conversation-query-routes.ts +54 -6
- package/src/runtime/routes/conversation-routes.ts +48 -2
- package/src/runtime/routes/credential-prompt-routes.ts +45 -0
- package/src/runtime/routes/credential-routes.ts +134 -3
- package/src/runtime/routes/email-routes.ts +17 -1
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
- package/src/runtime/routes/inference-send-routes.ts +17 -1
- package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
- package/src/runtime/routes/plugins-routes.ts +37 -6
- package/src/runtime/routes/publish-routes.ts +15 -18
- package/src/runtime/routes/schedule-worker-routes.ts +9 -0
- package/src/runtime/routes/secret-routes.ts +29 -0
- package/src/runtime/routes/telemetry-routes.ts +149 -45
- package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
- package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
- package/src/schedule/schedule-store.ts +12 -1
- package/src/schedule/schedule-timezone.ts +63 -0
- package/src/schedule/scheduler.ts +100 -6
- package/src/schedule/worker-control.ts +19 -0
- package/src/security/__tests__/oauth2-exchange-body.test.ts +123 -0
- package/src/security/auth-fallback-events-store.ts +7 -6
- package/src/security/oauth2.ts +37 -9
- package/src/security/secret-scanner.ts +26 -1
- package/src/services/published-app-updater.ts +6 -11
- package/src/stt/stt-stream-session.ts +36 -16
- package/src/subagent/manager.ts +34 -8
- package/src/telemetry/AGENTS.md +30 -1
- package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
- package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
- package/src/telemetry/config-setting-snapshot.ts +44 -10
- package/src/telemetry/telemetry-event-sources.test.ts +124 -30
- package/src/telemetry/telemetry-event-sources.ts +137 -83
- package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
- package/src/telemetry/telemetry-events-outbox.ts +60 -9
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire-validation.ts +39 -2
- package/src/telemetry/telemetry-wire.generated.ts +8 -0
- package/src/telemetry/tool-audit.ts +15 -9
- package/src/telemetry/tool-executed-events-store.test.ts +1 -1
- package/src/telemetry/turn-events-store.ts +20 -0
- package/src/telemetry/types.ts +45 -12
- package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
- package/src/telemetry/usage-telemetry-reporter.ts +117 -18
- package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
- package/src/telemetry/watchdog-direct-emit.ts +11 -6
- package/src/tools/acp/spawn.test.ts +17 -0
- package/src/tools/acp/spawn.ts +31 -2
- package/src/tools/apps/executors.ts +11 -36
- package/src/tools/executor.ts +14 -1
- package/src/tools/host-terminal/host-shell.ts +6 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
- package/src/tools/network/web-fetch.ts +6 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/subagent/spawn.ts +7 -11
- package/src/tools/terminal/shell.ts +5 -2
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/tool-profiler.ts +37 -6
- package/src/tools/types.ts +8 -0
- package/src/tools/ui-surface/channel-variants.ts +101 -0
- package/src/tools/ui-surface/definitions.ts +23 -67
- package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
- package/src/tts/__tests__/provider-adapters.test.ts +18 -0
- package/src/tts/provider-catalog.ts +2 -4
- package/src/tts/providers/deepgram-provider.ts +10 -1
- package/src/types/onboarding-context.ts +8 -0
- package/src/usage/attribution.ts +18 -112
- package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
- package/src/util/provider-error-patterns.ts +7 -1
- package/src/util/worker-process.ts +105 -0
- package/src/watcher/__tests__/telemetry.test.ts +17 -4
- package/src/watcher/telemetry.ts +5 -5
- package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/workspace/provider-commit-message-generator.ts +6 -4
- package/src/__tests__/app-open-proxy.test.ts +0 -67
- package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
- package/src/onboarding/onboarding-research-events-store.ts +0 -104
- package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
- package/src/tools/apps/definitions.ts +0 -73
- package/src/tools/apps/open-proxy.ts +0 -43
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
MANAGED_ROUTABLE_PROVIDERS,
|
|
9
9
|
VELLUM_MANAGED_CONNECTION_NAME,
|
|
10
10
|
} from "../providers/vellum-model-routing.js";
|
|
11
|
-
import { isAssistantFeatureFlagEnabled } from "./assistant-feature-flags.js";
|
|
12
11
|
import { CALL_SITE_DEFAULTS } from "./call-site-defaults.js";
|
|
13
12
|
import {
|
|
14
13
|
getEffectiveProfile,
|
|
@@ -23,73 +22,50 @@ import {
|
|
|
23
22
|
} from "./schemas/llm.js";
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
|
-
* Resolves a fully-specified `LLMConfigBase` for a given call site
|
|
27
|
-
* call-site overrides, optional per-call profile, an optional ad-hoc override
|
|
28
|
-
* profile, the workspace's active profile, and the required `llm.default`.
|
|
25
|
+
* Resolves a fully-specified `LLMConfigBase` for a given call site.
|
|
29
26
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* profile, that profile is the authoritative provider config and the
|
|
38
|
-
* active profile does not contribute — otherwise a deep-merge would let
|
|
39
|
-
* its orphan fields bleed onto a different provider.
|
|
40
|
-
* 3. `llm.profiles[opts.overrideProfile]` (per-call ad-hoc override)
|
|
41
|
-
* 4. `llm.profiles[site.profile]` fields (call-site's named profile)
|
|
42
|
-
* 5. `llm.callSites[callSite]` fields (call-site override)
|
|
27
|
+
* Selection is a single-winner chain (see `selectWinningProfile`): the
|
|
28
|
+
* highest-precedence rung that names a usable, complete profile wins, and the
|
|
29
|
+
* resolved config is composed as code-owned schema defaults + the winning
|
|
30
|
+
* profile's fragment + the call site's own tuning tweak. No profile ever
|
|
31
|
+
* contributes a field to another profile — `deepMerge` here only lets nested
|
|
32
|
+
* tweaks (e.g. `thinking.enabled`) combine leaf-wise with the winner rather
|
|
33
|
+
* than wholesale-replacing sibling fields.
|
|
43
34
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
35
|
+
* Precedence of the selection chain (high → low):
|
|
36
|
+
* 1. `opts.overrideProfile` (per-turn / per-conversation pin)
|
|
37
|
+
* 2. `llm.activeProfile` — `mainAgent` only, since it IS that call site's
|
|
38
|
+
* user-facing chat-model selection
|
|
39
|
+
* 3. `llm.callSites[callSite].profile` (the call site's named profile)
|
|
40
|
+
* 4. `CALL_SITE_DEFAULTS[callSite].profile` intent resolved through
|
|
41
|
+
* `llm.defaultProvider`
|
|
42
|
+
* 5. balanced intent through `llm.defaultProvider` — the code-owned anchor
|
|
43
|
+
* for profileless call sites, or when nothing above is usable
|
|
53
44
|
*
|
|
54
|
-
* `
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* call-site override → overrideProfile. This mirrors how `mainAgent` treats
|
|
59
|
-
* the user's chat-model selection as authoritative, and exists for callers
|
|
60
|
-
* that must run a background call site under a specific conversation's
|
|
61
|
-
* inference profile (e.g. fork-based memory retrospectives matching the
|
|
62
|
-
* source conversation for provider prompt-cache reuse). When the referenced
|
|
63
|
-
* profile is missing, the flag is inert and the normal precedence applies
|
|
64
|
-
* (same silent fall-through as any `overrideProfile` reference); for
|
|
65
|
-
* `mainAgent` the flag is a no-op because the override already sits on top.
|
|
45
|
+
* A winner must carry its own `provider` AND `model`: the base layer's schema
|
|
46
|
+
* default identity never stands in for a selected profile. The anchor is
|
|
47
|
+
* code-owned and resolved through `llm.defaultProvider`, never through
|
|
48
|
+
* user-mutable state.
|
|
66
49
|
*
|
|
67
|
-
*
|
|
68
|
-
* `
|
|
69
|
-
*
|
|
70
|
-
* base value.
|
|
50
|
+
* `temperature`/`top_p` come only from the winner (or an explicit call-site
|
|
51
|
+
* tweak); `logitBias` only ever from the winner. These are provider-coupled, so
|
|
52
|
+
* a shadowed profile can never leak its sampling onto a different provider.
|
|
71
53
|
*
|
|
72
|
-
* `
|
|
73
|
-
*
|
|
74
|
-
* highest-precedence profile that determines provider/model) contributes them,
|
|
75
|
-
* and an explicit `llm.callSites[callSite]` override still wins. A lower-
|
|
76
|
-
* precedence profile whose model is shadowed never leaks its sampling onto a
|
|
77
|
-
* different provider (which would trip e.g. Anthropic's "temperature and top_p
|
|
78
|
-
* cannot both be specified" constraint). `logitBias` is winning-profile-scoped
|
|
79
|
-
* the same way.
|
|
54
|
+
* `opts.forceOverrideProfile` is a no-op here: the override profile already
|
|
55
|
+
* sits at the top of the chain for every call site.
|
|
80
56
|
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* unknown
|
|
57
|
+
* Profile names are resolved against the effective profile catalog
|
|
58
|
+
* (code-defined defaults + workspace `llm.profiles`; see `getEffectiveProfile`).
|
|
59
|
+
* A "mix" profile is expanded to one of its arms by a seeded weighted pick (see
|
|
60
|
+
* `resolveProfileFragment` and `opts.selectionSeed`), uniformly wherever a name
|
|
61
|
+
* is dereferenced. Missing references silently fall through (no throw) so the
|
|
62
|
+
* resolver stays pure; schema validation catches unknown static references at
|
|
63
|
+
* config-load time.
|
|
87
64
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* `profile`.
|
|
65
|
+
* Nested objects (`thinking`, `contextWindow`, and
|
|
66
|
+
* `contextWindow.overflowRecovery`) are deep-merged so partial tweaks at any
|
|
67
|
+
* nesting level merge into — rather than replace — the corresponding base
|
|
68
|
+
* value.
|
|
93
69
|
*
|
|
94
70
|
* Pure & synchronous: no I/O, no async work. (Random selection only occurs for
|
|
95
71
|
* mix profiles when no `selectionSeed` is supplied; with a seed the pick is
|
|
@@ -98,11 +74,11 @@ import {
|
|
|
98
74
|
export interface ResolveCallSiteOpts {
|
|
99
75
|
overrideProfile?: string;
|
|
100
76
|
/**
|
|
101
|
-
* Float `overrideProfile` above the call-site layers
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* profile
|
|
77
|
+
* Float `overrideProfile` above the call-site layers for non-main-agent call
|
|
78
|
+
* sites. Retained for API compatibility; under single-winner selection the
|
|
79
|
+
* override already sits at the top of the chain, so this is effectively a
|
|
80
|
+
* no-op. Inert when `overrideProfile` is absent or references a missing
|
|
81
|
+
* profile.
|
|
106
82
|
*/
|
|
107
83
|
forceOverrideProfile?: boolean;
|
|
108
84
|
/**
|
|
@@ -121,167 +97,29 @@ export interface ResolveCallSiteOpts {
|
|
|
121
97
|
*/
|
|
122
98
|
onMixSelected?: (info: { mixProfile: string; chosenProfile: string }) => void;
|
|
123
99
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
100
|
+
* Invoked once per chain rung that named a profile the resolver could not
|
|
101
|
+
* use, before resolution continues to the next rung. Fallback is silent to
|
|
102
|
+
* the call but must be visible in logs — callers on user-facing paths should
|
|
103
|
+
* log at warn.
|
|
128
104
|
*/
|
|
129
105
|
onResolutionFallback?: (info: {
|
|
130
106
|
callSite: LLMCallSite;
|
|
131
107
|
requested: string;
|
|
132
108
|
reason: ResolutionFallbackReason;
|
|
133
109
|
}) => void;
|
|
134
|
-
/**
|
|
135
|
-
* Test/caller override for the resolution semantics. When absent, the
|
|
136
|
-
* `override-or-default-resolution` feature flag decides (ships enabled;
|
|
137
|
-
* disabling it is the kill switch back to the legacy merge cascade).
|
|
138
|
-
*/
|
|
139
|
-
resolutionSemantics?: "override-or-default" | "legacy-merge";
|
|
140
110
|
}
|
|
141
111
|
|
|
142
112
|
export type ResolutionFallbackReason = "missing" | "disabled" | "incomplete";
|
|
143
113
|
|
|
144
|
-
export const OVERRIDE_OR_DEFAULT_RESOLUTION_FLAG =
|
|
145
|
-
"override-or-default-resolution";
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* The flag read ignores its config argument (the override cache and registry
|
|
149
|
-
* are module state), so the resolver stays call-site-compatible without
|
|
150
|
-
* threading `AssistantConfig` through every consumer.
|
|
151
|
-
*/
|
|
152
|
-
export function isOverrideOrDefaultResolutionEnabled(): boolean {
|
|
153
|
-
return isAssistantFeatureFlagEnabled(
|
|
154
|
-
OVERRIDE_OR_DEFAULT_RESOLUTION_FLAG,
|
|
155
|
-
undefined as never,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function useOverrideOrDefaultSemantics(opts: ResolveCallSiteOpts): boolean {
|
|
160
|
-
if (opts.resolutionSemantics != null) {
|
|
161
|
-
return opts.resolutionSemantics === "override-or-default";
|
|
162
|
-
}
|
|
163
|
-
return isOverrideOrDefaultResolutionEnabled();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
114
|
export function resolveCallSiteConfig(
|
|
167
115
|
callSite: LLMCallSite,
|
|
168
116
|
llm: z.infer<typeof LLMSchema>,
|
|
169
117
|
opts: ResolveCallSiteOpts = {},
|
|
170
118
|
): z.infer<typeof LLMConfigBase> {
|
|
171
|
-
|
|
172
|
-
return resolveOverrideOrDefault(callSite, llm, opts);
|
|
173
|
-
}
|
|
174
|
-
const layers: Mergeable[] = [llm.default as Mergeable];
|
|
175
|
-
|
|
176
|
-
// Effective logit-bias preset, tracked outside the deep-merge so it ties to
|
|
177
|
-
// the single highest-precedence *profile* that wins resolution rather than
|
|
178
|
-
// inheriting from a lower one. Profile layers are appended low→high, and each
|
|
179
|
-
// one fully determines the preset (a profile that omits `logitBias` clears
|
|
180
|
-
// any value a lower-precedence profile set), so the last profile appended
|
|
181
|
-
// wins — matching the merge's own precedence and including the implicit
|
|
182
|
-
// call-site default selected by `effectiveDefault`.
|
|
183
|
-
const biasRef: LogitBiasRef = { preset: undefined };
|
|
184
|
-
|
|
185
|
-
// Effective sampling params, tracked outside the deep-merge for the same
|
|
186
|
-
// reason as `logitBias`: `temperature`/`top_p` are provider-coupled, so only
|
|
187
|
-
// the winning profile may contribute them. A profile clears what a lower
|
|
188
|
-
// PROFILE set where it is silent (so a shadowed profile's sampling can't
|
|
189
|
-
// leak), while an explicit call-site override is sticky and survives a later
|
|
190
|
-
// silent profile (see `applyProfileSampling` / `appendCallSiteLayers`).
|
|
191
|
-
const samplingRef: SamplingRef = {
|
|
192
|
-
temperature: undefined,
|
|
193
|
-
topP: undefined,
|
|
194
|
-
temperatureFromCallSite: false,
|
|
195
|
-
topPFromCallSite: false,
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const activeFragment = resolveProfileFragment(llm.activeProfile, llm, opts);
|
|
199
|
-
const overrideFragment = resolveProfileFragment(
|
|
200
|
-
opts.overrideProfile,
|
|
201
|
-
llm,
|
|
202
|
-
opts,
|
|
203
|
-
);
|
|
204
|
-
const site =
|
|
205
|
-
llm.callSites?.[callSite] ??
|
|
206
|
-
effectiveDefault(callSite, llm, opts.overrideProfile != null);
|
|
207
|
-
|
|
208
|
-
if (callSite === "mainAgent") {
|
|
209
|
-
appendCallSiteLayers(
|
|
210
|
-
layers,
|
|
211
|
-
callSite,
|
|
212
|
-
llm,
|
|
213
|
-
site,
|
|
214
|
-
opts,
|
|
215
|
-
biasRef,
|
|
216
|
-
samplingRef,
|
|
217
|
-
);
|
|
218
|
-
appendProfileLayer(layers, activeFragment, biasRef, samplingRef);
|
|
219
|
-
appendProfileLayer(layers, overrideFragment, biasRef, samplingRef);
|
|
220
|
-
} else if (opts.forceOverrideProfile === true && overrideFragment != null) {
|
|
221
|
-
// Escape hatch: float the override profile above the call-site layers,
|
|
222
|
-
// mirroring mainAgent's treatment of the user's chat-model selection.
|
|
223
|
-
// Guarded on a resolved fragment so a missing profile reference degrades
|
|
224
|
-
// to the normal precedence below instead of silently dropping the
|
|
225
|
-
// call-site layers' standing. The active profile stays the bottom fallback
|
|
226
|
-
// (its sampling can't leak — a higher profile's REPLACE clears it).
|
|
227
|
-
appendProfileLayer(layers, activeFragment, biasRef, samplingRef);
|
|
228
|
-
appendCallSiteLayers(
|
|
229
|
-
layers,
|
|
230
|
-
callSite,
|
|
231
|
-
llm,
|
|
232
|
-
site,
|
|
233
|
-
opts,
|
|
234
|
-
biasRef,
|
|
235
|
-
samplingRef,
|
|
236
|
-
);
|
|
237
|
-
appendProfileLayer(layers, overrideFragment, biasRef, samplingRef);
|
|
238
|
-
} else {
|
|
239
|
-
// The active profile is a low-precedence FALLBACK for call sites that
|
|
240
|
-
// resolve no profile of their own — profile-less leaves (`vision`,
|
|
241
|
-
// `workflowLeaf`) and BYOK installs where the pinned managed profile was
|
|
242
|
-
// stripped. When the call site DOES resolve its own profile, that profile
|
|
243
|
-
// is the authoritative provider config, so the active profile must not
|
|
244
|
-
// contribute its orphan fields to a different provider.
|
|
245
|
-
if (site?.profile == null) {
|
|
246
|
-
appendProfileLayer(layers, activeFragment, biasRef, samplingRef);
|
|
247
|
-
}
|
|
248
|
-
appendProfileLayer(layers, overrideFragment, biasRef, samplingRef);
|
|
249
|
-
appendCallSiteLayers(
|
|
250
|
-
layers,
|
|
251
|
-
callSite,
|
|
252
|
-
llm,
|
|
253
|
-
site,
|
|
254
|
-
opts,
|
|
255
|
-
biasRef,
|
|
256
|
-
samplingRef,
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const resolved = finalize(deepMerge(...withImpliedProviders(layers)));
|
|
261
|
-
// `logitBias` is profile-scoped: the winning profile is its only source.
|
|
262
|
-
// Overwrite — or clear — whatever the deep-merge may have copied from a
|
|
263
|
-
// non-profile layer (`llm.default` or a call-site fragment), so a preset set
|
|
264
|
-
// outside a profile can't apply to a profile that didn't opt in.
|
|
265
|
-
if (biasRef.preset !== undefined) {
|
|
266
|
-
resolved.logitBias = biasRef.preset;
|
|
267
|
-
} else {
|
|
268
|
-
delete (resolved as { logitBias?: unknown }).logitBias;
|
|
269
|
-
}
|
|
270
|
-
// `temperature`/`top_p` are winning-profile-scoped like `logitBias`, but an
|
|
271
|
-
// explicit call-site override may also set them. Apply the tracked value,
|
|
272
|
-
// overriding whatever a shadowed profile may have left in the merge. An
|
|
273
|
-
// `undefined` ref means no profile or override opted in, so the `llm.default`
|
|
274
|
-
// base already in `resolved` stands.
|
|
275
|
-
if (samplingRef.temperature !== undefined) {
|
|
276
|
-
resolved.temperature = samplingRef.temperature;
|
|
277
|
-
}
|
|
278
|
-
if (samplingRef.topP !== undefined) {
|
|
279
|
-
resolved.topP = samplingRef.topP;
|
|
280
|
-
}
|
|
281
|
-
return resolved;
|
|
119
|
+
return resolveOverrideOrDefault(callSite, llm, opts);
|
|
282
120
|
}
|
|
283
121
|
|
|
284
|
-
// ───
|
|
122
|
+
// ─── Single-winner profile resolution ───────────────────────────────────────
|
|
285
123
|
//
|
|
286
124
|
// Selection is a single-winner chain — each rung is either a complete
|
|
287
125
|
// explicit choice or skipped with a reported reason — bottoming out on the
|
|
@@ -294,9 +132,8 @@ export function resolveCallSiteConfig(
|
|
|
294
132
|
// above usable)
|
|
295
133
|
// A winner must carry its own `provider` AND `model`: the base layer's
|
|
296
134
|
// schema-default identity must never stand in for a selected profile (that
|
|
297
|
-
// would be merge inheritance by the back door).
|
|
298
|
-
//
|
|
299
|
-
// user-mutable state.
|
|
135
|
+
// would be merge inheritance by the back door). A fallback anchor must be
|
|
136
|
+
// code-owned, never user-mutable state.
|
|
300
137
|
//
|
|
301
138
|
// The request config is the base + winner + site-tweak composition:
|
|
302
139
|
// code-owned schema defaults, then the single winning profile, then the call
|
|
@@ -508,8 +345,8 @@ function usableDefaultIntent(
|
|
|
508
345
|
|
|
509
346
|
/**
|
|
510
347
|
* Schema-default base for composition. Non-identity fields a winner omits
|
|
511
|
-
* fall to these code-owned defaults
|
|
512
|
-
*
|
|
348
|
+
* fall to these code-owned defaults; the winner's identity fields are
|
|
349
|
+
* guaranteed present by `selectWinningProfile`.
|
|
513
350
|
*/
|
|
514
351
|
const CODE_DEFAULT_BASE: z.infer<typeof LLMConfigBase> = LLMConfigBase.parse(
|
|
515
352
|
{},
|
|
@@ -525,8 +362,7 @@ function resolveOverrideOrDefault(
|
|
|
525
362
|
selection.entry == null ? {} : winnerConfigFragment(selection.entry);
|
|
526
363
|
|
|
527
364
|
// The call site's own tweak fragment: the workspace override replaces the
|
|
528
|
-
// code default wholesale
|
|
529
|
-
// CALL_SITE_DEFAULTS[site]`). `profile` is the selection discriminator and
|
|
365
|
+
// code default wholesale. `profile` is the selection discriminator and
|
|
530
366
|
// `logitBias` is winner-owned, so neither enters the merge.
|
|
531
367
|
const site = llm.callSites?.[callSite] ?? CALL_SITE_DEFAULTS[callSite];
|
|
532
368
|
const {
|
|
@@ -585,20 +421,6 @@ function winnerConfigFragment(entry: ProfileEntry): Mergeable {
|
|
|
585
421
|
return config as Mergeable;
|
|
586
422
|
}
|
|
587
423
|
|
|
588
|
-
type LogitBiasRef = { preset: ProfileEntry["logitBias"] };
|
|
589
|
-
|
|
590
|
-
type SamplingRef = {
|
|
591
|
-
temperature: ProfileEntry["temperature"];
|
|
592
|
-
topP: ProfileEntry["topP"];
|
|
593
|
-
// Provenance of the current pair: `true` when a field came from an explicit
|
|
594
|
-
// call-site override (deliberate, sticky), `false` when it came from a profile
|
|
595
|
-
// (clearable by a higher-precedence profile that determines the model). Lets a
|
|
596
|
-
// silent higher profile clear a lower profile's sampling without discarding a
|
|
597
|
-
// deliberate call-site override.
|
|
598
|
-
temperatureFromCallSite: boolean;
|
|
599
|
-
topPFromCallSite: boolean;
|
|
600
|
-
};
|
|
601
|
-
|
|
602
424
|
// ---------------------------------------------------------------------------
|
|
603
425
|
// Internal helpers
|
|
604
426
|
// ---------------------------------------------------------------------------
|
|
@@ -634,11 +456,15 @@ function weightedPick<T extends { weight: number }>(
|
|
|
634
456
|
): T {
|
|
635
457
|
const total = entries.reduce((sum, e) => sum + e.weight, 0);
|
|
636
458
|
// Defensive: a degenerate total (unreachable post-schema) → first arm.
|
|
637
|
-
if (!(total > 0))
|
|
459
|
+
if (!(total > 0)) {
|
|
460
|
+
return entries[0];
|
|
461
|
+
}
|
|
638
462
|
let threshold = unit * total;
|
|
639
463
|
for (const entry of entries) {
|
|
640
464
|
threshold -= entry.weight;
|
|
641
|
-
if (threshold < 0)
|
|
465
|
+
if (threshold < 0) {
|
|
466
|
+
return entry;
|
|
467
|
+
}
|
|
642
468
|
}
|
|
643
469
|
// Floating-point fall-through (unit ≈ 1): return the last arm.
|
|
644
470
|
return entries[entries.length - 1];
|
|
@@ -664,9 +490,13 @@ function resolveProfileFragment(
|
|
|
664
490
|
lookupEntry: (name: string) => ProfileEntry | undefined = (n) =>
|
|
665
491
|
getEffectiveProfile(llm.profiles, n),
|
|
666
492
|
): ProfileEntry | undefined {
|
|
667
|
-
if (name == null)
|
|
493
|
+
if (name == null) {
|
|
494
|
+
return undefined;
|
|
495
|
+
}
|
|
668
496
|
const entry = lookupEntry(name);
|
|
669
|
-
if (entry?.mix == null)
|
|
497
|
+
if (entry?.mix == null) {
|
|
498
|
+
return entry;
|
|
499
|
+
}
|
|
670
500
|
|
|
671
501
|
// Mix: pick one constituent. Seed by per-conversation seed + the mix's own
|
|
672
502
|
// name so two different mixes in the same conversation pick independently,
|
|
@@ -683,71 +513,33 @@ function resolveProfileFragment(
|
|
|
683
513
|
}
|
|
684
514
|
|
|
685
515
|
/**
|
|
686
|
-
* Returns the
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
*
|
|
690
|
-
* -
|
|
691
|
-
* call-site catalog default (and above any static `llm.callSites.mainAgent`
|
|
692
|
-
* override), so a non-disabled `activeProfile` wins.
|
|
693
|
-
* - For other call sites, the catalog default sits ABOVE `activeProfile`,
|
|
694
|
-
* so the catalog default (with `custom-*` fallback) wins.
|
|
516
|
+
* Returns the profile key `resolveCallSiteConfig` selects as the winner for a
|
|
517
|
+
* call site when no per-turn `overrideProfile` is supplied — the highest-
|
|
518
|
+
* precedence rung that resolves to a usable, complete profile (see
|
|
519
|
+
* `selectWinningProfile`). Returns `undefined` when the winner is the
|
|
520
|
+
* code-owned anchor rather than a named profile.
|
|
695
521
|
*/
|
|
696
522
|
export function resolveDefaultProfileKey(
|
|
697
523
|
callSite: LLMCallSite,
|
|
698
524
|
llm: z.infer<typeof LLMSchema>,
|
|
699
525
|
): string | undefined {
|
|
700
|
-
|
|
701
|
-
return selectWinningProfile(callSite, llm, {}).profileName ?? undefined;
|
|
702
|
-
}
|
|
703
|
-
if (callSite === "mainAgent" && llm.activeProfile != null) {
|
|
704
|
-
const active = getEffectiveProfile(llm.profiles, llm.activeProfile);
|
|
705
|
-
if (active != null && active.status !== "disabled") {
|
|
706
|
-
return llm.activeProfile;
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
const dflt = CALL_SITE_DEFAULTS[callSite];
|
|
711
|
-
if (dflt?.profile == null) return undefined;
|
|
712
|
-
const target = getEffectiveProfile(llm.profiles, dflt.profile);
|
|
713
|
-
if (target != null && target.status !== "disabled") return dflt.profile;
|
|
714
|
-
const customKey = `custom-${dflt.profile}`;
|
|
715
|
-
const customTarget = getEffectiveProfile(llm.profiles, customKey);
|
|
716
|
-
if (customTarget != null && customTarget.status !== "disabled")
|
|
717
|
-
return customKey;
|
|
718
|
-
return undefined;
|
|
526
|
+
return selectWinningProfile(callSite, llm, {}).profileName ?? undefined;
|
|
719
527
|
}
|
|
720
528
|
|
|
721
529
|
/**
|
|
722
|
-
* Returns the profile key that `resolveCallSiteConfig`
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
*
|
|
728
|
-
* - `mainAgent`: override → active → catalog default.
|
|
729
|
-
* - forced override: the override.
|
|
730
|
-
* - other sites: the call-site's own profile (explicit or catalog default) when
|
|
731
|
-
* one survives; otherwise override → active. A pinned override on a bare call
|
|
732
|
-
* site therefore attributes to the override, not the stripped catalog default.
|
|
530
|
+
* Returns the profile key that `resolveCallSiteConfig` treats as the winning
|
|
531
|
+
* (highest-precedence) profile for a turn — the profile whose fragment supplies
|
|
532
|
+
* the resolved provider/model. Accounts for the per-turn `overrideProfile`, so
|
|
533
|
+
* error attribution names the slot the resolver really used. Returns
|
|
534
|
+
* `undefined` when the winner is the code-owned anchor rather than a named
|
|
535
|
+
* profile.
|
|
733
536
|
*/
|
|
734
537
|
export function resolveEffectiveProfileKey(
|
|
735
538
|
callSite: LLMCallSite,
|
|
736
539
|
llm: z.infer<typeof LLMSchema>,
|
|
737
540
|
opts: ResolveCallSiteOpts = {},
|
|
738
541
|
): string | undefined {
|
|
739
|
-
|
|
740
|
-
if (callSite === "mainAgent") {
|
|
741
|
-
return override ?? resolveDefaultProfileKey(callSite, llm);
|
|
742
|
-
}
|
|
743
|
-
if (opts.forceOverrideProfile === true && override != null) {
|
|
744
|
-
return override;
|
|
745
|
-
}
|
|
746
|
-
const site =
|
|
747
|
-
llm.callSites?.[callSite] ??
|
|
748
|
-
effectiveDefault(callSite, llm, override != null);
|
|
749
|
-
if (site?.profile != null) return site.profile;
|
|
750
|
-
return override ?? llm.activeProfile ?? undefined;
|
|
542
|
+
return selectWinningProfile(callSite, llm, opts).profileName ?? undefined;
|
|
751
543
|
}
|
|
752
544
|
|
|
753
545
|
/**
|
|
@@ -763,191 +555,10 @@ export function resolveProfilelessModelKey(
|
|
|
763
555
|
try {
|
|
764
556
|
return resolveCallSiteConfig(callSite, llm, opts).model;
|
|
765
557
|
} catch {
|
|
766
|
-
return
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
function effectiveDefault(
|
|
771
|
-
callSite: LLMCallSite,
|
|
772
|
-
llm: z.infer<typeof LLMSchema>,
|
|
773
|
-
hasOverrideProfile = false,
|
|
774
|
-
): z.infer<typeof LLMSchema>["callSites"][LLMCallSite] | undefined {
|
|
775
|
-
const dflt = CALL_SITE_DEFAULTS[callSite];
|
|
776
|
-
if (dflt == null) return undefined;
|
|
777
|
-
const targetProfile =
|
|
778
|
-
dflt.profile != null
|
|
779
|
-
? getEffectiveProfile(llm.profiles, dflt.profile)
|
|
780
|
-
: undefined;
|
|
781
|
-
const profileUnavailable =
|
|
782
|
-
dflt.profile != null &&
|
|
783
|
-
(targetProfile == null || targetProfile.status === "disabled");
|
|
784
|
-
|
|
785
|
-
if (profileUnavailable && !hasOverrideProfile) {
|
|
786
|
-
const customKey = `custom-${dflt.profile}`;
|
|
787
|
-
const customProfile = getEffectiveProfile(llm.profiles, customKey);
|
|
788
|
-
if (customProfile != null && customProfile.status !== "disabled") {
|
|
789
|
-
return { ...dflt, profile: customKey };
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
const stripProfile = hasOverrideProfile || profileUnavailable;
|
|
794
|
-
if (stripProfile) {
|
|
795
|
-
const { profile: _profile, ...rest } = dflt;
|
|
796
|
-
return Object.keys(rest).length > 0 ? rest : undefined;
|
|
797
|
-
}
|
|
798
|
-
return dflt;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
/**
|
|
802
|
-
* Stamp a catalog-implied provider onto model-only layers whose model the
|
|
803
|
-
* provider applicable at that point in the merge does not serve. Layers are
|
|
804
|
-
* scanned in merge order (low → high precedence), tracking the provider the
|
|
805
|
-
* merged config would carry at each layer: when that provider already lists
|
|
806
|
-
* the layer's model in its own catalog, no implication is needed and the
|
|
807
|
-
* layer stays provider-less so the lower-precedence provider wins. Models
|
|
808
|
-
* unknown to the catalog never imply a provider.
|
|
809
|
-
*/
|
|
810
|
-
function withImpliedProviders(layers: Mergeable[]): Mergeable[] {
|
|
811
|
-
let applicableProvider: string | undefined;
|
|
812
|
-
return layers.map((layer) => {
|
|
813
|
-
if (layer.provider !== undefined) {
|
|
814
|
-
if (typeof layer.provider === "string") {
|
|
815
|
-
applicableProvider = layer.provider;
|
|
816
|
-
}
|
|
817
|
-
return layer;
|
|
818
|
-
}
|
|
819
|
-
const model = layer.model;
|
|
820
|
-
if (typeof model !== "string" || model.length === 0) {
|
|
821
|
-
return layer;
|
|
822
|
-
}
|
|
823
|
-
if (
|
|
824
|
-
applicableProvider !== undefined &&
|
|
825
|
-
isModelInCatalog(applicableProvider, model)
|
|
826
|
-
) {
|
|
827
|
-
return layer;
|
|
828
|
-
}
|
|
829
|
-
const provider = getCatalogProviderForModel(model);
|
|
830
|
-
if (provider === undefined) {
|
|
831
|
-
return layer;
|
|
832
|
-
}
|
|
833
|
-
applicableProvider = provider;
|
|
834
|
-
return { ...layer, provider };
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
/**
|
|
839
|
-
* Fold a profile's sampling into `samplingRef`. A profile determines
|
|
840
|
-
* provider/model, so its pair supersedes any LOWER PROFILE's: set each field the
|
|
841
|
-
* profile specifies, and clear a lower profile's value where the profile is
|
|
842
|
-
* silent. A deliberate call-site override is NOT a profile and outranks a silent
|
|
843
|
-
* profile — it survives until a profile EXPLICITLY sets the field. (The mirror
|
|
844
|
-
* COALESCE for call-site overrides lives in `appendCallSiteLayers`.)
|
|
845
|
-
*/
|
|
846
|
-
function applyProfileSampling(
|
|
847
|
-
samplingRef: SamplingRef,
|
|
848
|
-
profile: ProfileEntry,
|
|
849
|
-
): void {
|
|
850
|
-
if (profile.temperature !== undefined) {
|
|
851
|
-
samplingRef.temperature = profile.temperature;
|
|
852
|
-
samplingRef.temperatureFromCallSite = false;
|
|
853
|
-
} else if (!samplingRef.temperatureFromCallSite) {
|
|
854
|
-
samplingRef.temperature = undefined;
|
|
855
|
-
}
|
|
856
|
-
if (profile.topP !== undefined) {
|
|
857
|
-
samplingRef.topP = profile.topP;
|
|
858
|
-
samplingRef.topPFromCallSite = false;
|
|
859
|
-
} else if (!samplingRef.topPFromCallSite) {
|
|
860
|
-
samplingRef.topP = undefined;
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
function appendProfileLayer(
|
|
865
|
-
layers: Mergeable[],
|
|
866
|
-
profile: ProfileEntry | undefined,
|
|
867
|
-
biasRef: LogitBiasRef,
|
|
868
|
-
samplingRef: SamplingRef,
|
|
869
|
-
): void {
|
|
870
|
-
if (profile != null) {
|
|
871
|
-
biasRef.preset = profile.logitBias;
|
|
872
|
-
applyProfileSampling(samplingRef, profile);
|
|
873
|
-
layers.push(profileConfigFragment(profile));
|
|
558
|
+
return "default";
|
|
874
559
|
}
|
|
875
560
|
}
|
|
876
561
|
|
|
877
|
-
function appendCallSiteLayers(
|
|
878
|
-
layers: Mergeable[],
|
|
879
|
-
callSite: LLMCallSite,
|
|
880
|
-
llm: z.infer<typeof LLMSchema>,
|
|
881
|
-
site: z.infer<typeof LLMSchema>["callSites"][LLMCallSite] | undefined,
|
|
882
|
-
opts: ResolveCallSiteOpts,
|
|
883
|
-
biasRef: LogitBiasRef,
|
|
884
|
-
samplingRef: SamplingRef,
|
|
885
|
-
): void {
|
|
886
|
-
if (site != null) {
|
|
887
|
-
if (site.profile != null) {
|
|
888
|
-
const profileFragment = resolveProfileFragment(site.profile, llm, opts);
|
|
889
|
-
if (profileFragment == null) {
|
|
890
|
-
// Defensive: `LLMSchema.superRefine` already rejects unknown profile
|
|
891
|
-
// references (and unknown mix arms) at config load, so this branch is
|
|
892
|
-
// unreachable for any config that survived schema validation. Throw a
|
|
893
|
-
// clear error in case a hand-crafted (un-parsed) config slips through.
|
|
894
|
-
throw new Error(
|
|
895
|
-
`LLM call site "${callSite}" references undefined profile "${site.profile}"`,
|
|
896
|
-
);
|
|
897
|
-
}
|
|
898
|
-
biasRef.preset = profileFragment.logitBias;
|
|
899
|
-
applyProfileSampling(samplingRef, profileFragment);
|
|
900
|
-
layers.push(profileConfigFragment(profileFragment));
|
|
901
|
-
}
|
|
902
|
-
// Strip the `profile` discriminator (not a `LLMConfigBase` field) and the
|
|
903
|
-
// sampling params before merging. An explicit call-site `temperature` /
|
|
904
|
-
// `topP` is a deliberate per-site choice, so it COALESCES over the winning
|
|
905
|
-
// profile's pair (only overriding the fields it sets) and is marked sticky
|
|
906
|
-
// so a later silent profile can't clear it — routed through `samplingRef` so
|
|
907
|
-
// it never inherits a shadowed profile's value via merge.
|
|
908
|
-
const {
|
|
909
|
-
profile: _profile,
|
|
910
|
-
temperature: siteTemperature,
|
|
911
|
-
topP: siteTopP,
|
|
912
|
-
...siteFragment
|
|
913
|
-
} = site;
|
|
914
|
-
if (siteTemperature !== undefined) {
|
|
915
|
-
samplingRef.temperature = siteTemperature;
|
|
916
|
-
samplingRef.temperatureFromCallSite = true;
|
|
917
|
-
}
|
|
918
|
-
if (siteTopP !== undefined) {
|
|
919
|
-
samplingRef.topP = siteTopP;
|
|
920
|
-
samplingRef.topPFromCallSite = true;
|
|
921
|
-
}
|
|
922
|
-
layers.push(siteFragment as Mergeable);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
function profileConfigFragment(profile: ProfileEntry): Mergeable {
|
|
927
|
-
const {
|
|
928
|
-
source: _source,
|
|
929
|
-
label: _label,
|
|
930
|
-
description: _description,
|
|
931
|
-
// `mix` never reaches here in practice (a mix expands to a standard
|
|
932
|
-
// profile before this point), but strip it defensively so it can never
|
|
933
|
-
// leak into the merged `LLMConfigBase`.
|
|
934
|
-
mix: _mix,
|
|
935
|
-
// `logitBias` is profile-identity metadata, not inheritable config: a
|
|
936
|
-
// preset must apply only to the profile that opted in, never bleed from a
|
|
937
|
-
// lower-precedence (e.g. active) profile into one that merely inherited it.
|
|
938
|
-
// `RetryProvider` resolves it from the applied profile, not the merge.
|
|
939
|
-
logitBias: _logitBias,
|
|
940
|
-
// `temperature`/`top_p` are provider-coupled: only the winning profile
|
|
941
|
-
// contributes them (tracked via `samplingRef`, applied post-merge), so a
|
|
942
|
-
// shadowed profile's sampling can never reach a different provider through
|
|
943
|
-
// the deep-merge. Strip here so no profile's sampling enters the merge.
|
|
944
|
-
temperature: _temperature,
|
|
945
|
-
topP: _topP,
|
|
946
|
-
...config
|
|
947
|
-
} = profile;
|
|
948
|
-
return config as Mergeable;
|
|
949
|
-
}
|
|
950
|
-
|
|
951
562
|
/**
|
|
952
563
|
* Returns true for objects we should recurse into during deep merge. We
|
|
953
564
|
* deliberately exclude arrays so that array-valued fields (e.g.
|
|
@@ -972,15 +583,17 @@ function isPlainObject(value: unknown): value is Mergeable {
|
|
|
972
583
|
*
|
|
973
584
|
* Plain-object values are always cloned (via recursion) rather than aliased,
|
|
974
585
|
* so the returned config is an isolated snapshot — mutating any nested object
|
|
975
|
-
* on the result cannot affect
|
|
976
|
-
*
|
|
977
|
-
*
|
|
586
|
+
* on the result cannot affect named profiles or other call sites' resolutions.
|
|
587
|
+
* Arrays and primitives are copied by reference; the resolver does not return
|
|
588
|
+
* arrays, and primitives are immutable.
|
|
978
589
|
*/
|
|
979
590
|
function deepMerge(...sources: Mergeable[]): Mergeable {
|
|
980
591
|
const out: Mergeable = {};
|
|
981
592
|
for (const source of sources) {
|
|
982
593
|
for (const [key, value] of Object.entries(source)) {
|
|
983
|
-
if (value === undefined)
|
|
594
|
+
if (value === undefined) {
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
984
597
|
const existing = out[key];
|
|
985
598
|
if (isPlainObject(value)) {
|
|
986
599
|
// Recurse for any plain-object source. Using `existing` as the base
|
|
@@ -998,9 +611,9 @@ function deepMerge(...sources: Mergeable[]): Mergeable {
|
|
|
998
611
|
}
|
|
999
612
|
|
|
1000
613
|
/**
|
|
1001
|
-
* Cast helper that documents the intent: after merging
|
|
1002
|
-
* is `LLMConfigBase`) with optional fragments, every required field is
|
|
1003
|
-
* present, so the result satisfies `LLMConfigBase`.
|
|
614
|
+
* Cast helper that documents the intent: after merging the code-owned base
|
|
615
|
+
* (which is `LLMConfigBase`) with optional fragments, every required field is
|
|
616
|
+
* still present, so the result satisfies `LLMConfigBase`.
|
|
1004
617
|
*/
|
|
1005
618
|
function finalize(merged: Mergeable): z.infer<typeof LLMConfigBase> {
|
|
1006
619
|
return merged as unknown as z.infer<typeof LLMConfigBase>;
|