@gajae-code/coding-agent 0.18.10 → 0.18.12
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/CHANGELOG.md +295 -0
- package/dist/types/async/job-manager.d.ts +7 -3
- package/dist/types/async/result-formatting.d.ts +2 -0
- package/dist/types/autoresearch/git.d.ts +1 -1
- package/dist/types/capability/fs.d.ts +2 -2
- package/dist/types/cli/accounts-cli.d.ts +2 -2
- package/dist/types/cli/doctor/install-repairs.d.ts +4 -1
- package/dist/types/cli/install-activation.d.ts +10 -4
- package/dist/types/cli/public-command-errors.d.ts +1 -0
- package/dist/types/cli/update-cli.d.ts +14 -1
- package/dist/types/cli-ordinary.d.ts +2 -2
- package/dist/types/commands/accounts.d.ts +2 -1
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +5 -0
- package/dist/types/commit/changelog/index.d.ts +1 -0
- package/dist/types/config/autorouting-tier-map.d.ts +30 -0
- package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
- package/dist/types/config/config-hot-reload.d.ts +39 -0
- package/dist/types/config/file-lock.d.ts +8 -1
- package/dist/types/config/model-discovery-manager.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +62 -6
- package/dist/types/config/model-registry.d.ts +56 -5
- package/dist/types/config/model-resolver.d.ts +2 -0
- package/dist/types/config/models-config-schema.d.ts +10 -0
- package/dist/types/config/settings-schema.d.ts +46 -3
- package/dist/types/config/settings.d.ts +33 -1
- package/dist/types/dap/config.d.ts +8 -4
- package/dist/types/debug/system-info.d.ts +6 -1
- package/dist/types/discovery/mcp-compat.d.ts +3 -1
- package/dist/types/edit/modes/patch.d.ts +5 -0
- package/dist/types/edit/modes/replace.d.ts +3 -0
- package/dist/types/exec/bash-executor.d.ts +12 -0
- package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +0 -2
- package/dist/types/migrate/adapters/codex.d.ts +2 -1
- package/dist/types/migrate/adapters/index.d.ts +10 -1
- package/dist/types/migrate/executor.d.ts +3 -1
- package/dist/types/migrate/types.d.ts +15 -3
- package/dist/types/modes/components/settings-selector.d.ts +6 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/runtime-mcp/content-limits.d.ts +4 -0
- package/dist/types/runtime-mcp/manager.d.ts +7 -0
- package/dist/types/runtime-mcp/plugin-mcp-name-filter.d.ts +22 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +4 -0
- package/dist/types/sdk/broker/broker-exit.d.ts +2 -2
- package/dist/types/sdk/broker/broker.d.ts +7 -1
- package/dist/types/sdk/broker/daemon-entry.d.ts +11 -1
- package/dist/types/sdk/broker/doctor-restart.d.ts +1 -1
- package/dist/types/sdk/broker/ensure.d.ts +136 -7
- package/dist/types/sdk/broker/hop.d.ts +36 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
- package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
- package/dist/types/sdk/broker/session-index.d.ts +4 -1
- package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
- package/dist/types/sdk/bus/index.d.ts +23 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/cli/session-cli.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.d.ts +32 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +42 -4
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -0
- package/dist/types/sdk/protocol/adapter-validation.d.ts +10 -4
- package/dist/types/sdk/reconciliation-extensions.d.ts +1 -1
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +58 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +2 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +1 -1
- package/dist/types/session/internal/native-publish-outcome.d.ts +1 -1
- package/dist/types/session/messages.d.ts +5 -1
- package/dist/types/session/session-manager.d.ts +13 -3
- package/dist/types/session/startup-auth-config.d.ts +24 -2
- package/dist/types/session/streaming-output.d.ts +11 -0
- package/dist/types/session/terminal-abort.d.ts +3 -1
- package/dist/types/session-import/service.d.ts +1 -1
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +7 -3
- package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
- package/dist/types/task/executor.d.ts +19 -2
- package/dist/types/tools/ast-edit-write-path.d.ts +10 -0
- package/dist/types/tools/atomic-file-write.d.ts +9 -7
- package/dist/types/tools/bash-allowed-prefixes.d.ts +11 -0
- package/dist/types/tools/descriptors.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/python.d.ts +1 -1
- package/dist/types/tools/report-issue.d.ts +41 -0
- package/dist/types/tools/subagent.d.ts +23 -0
- package/dist/types/web/scrapers/types.d.ts +8 -1
- package/dist/types/web/search/providers/insane.d.ts +7 -1
- package/dist/types/web/search/providers/searxng.d.ts +5 -0
- package/package.json +8 -8
- package/scripts/build-binary.ts +2 -1
- package/scripts/capture-subagent-compact-panel-showcase.ts +105 -0
- package/scripts/generate-docs-index.ts +8 -1
- package/scripts/generate-sdk-operation-inventory.ts +22 -4
- package/src/async/job-manager.ts +356 -56
- package/src/async/result-formatting.ts +40 -0
- package/src/autoresearch/git.ts +9 -2
- package/src/autoresearch/prompts/prompt-setup.md +1 -1
- package/src/capability/fs.ts +27 -19
- package/src/capability/index.ts +2 -2
- package/src/cli/accounts-cli.ts +176 -8
- package/src/cli/auth-broker-cli.ts +21 -11
- package/src/cli/doctor/install-repairs.ts +35 -5
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/install-activation.ts +47 -4
- package/src/cli/migrate-cli.ts +7 -5
- package/src/cli/public-command-errors.ts +4 -0
- package/src/cli/root-flags.ts +2 -2
- package/src/cli/stats-cli.ts +9 -5
- package/src/cli/update-cli.ts +224 -7
- package/src/cli-ordinary.ts +7 -2
- package/src/commands/accounts.ts +10 -5
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +199 -42
- package/src/commands/ultragoal.ts +16 -8
- package/src/commit/changelog/index.ts +39 -1
- package/src/commit/message.ts +10 -3
- package/src/config/autorouting-tier-map.ts +30 -0
- package/src/config/config-hot-reload-trust.ts +148 -0
- package/src/config/config-hot-reload.ts +734 -0
- package/src/config/file-lock.ts +216 -56
- package/src/config/model-bindings-applier.ts +85 -47
- package/src/config/model-discovery-manager.ts +10 -0
- package/src/config/model-profile-activation.ts +716 -113
- package/src/config/model-registry.ts +1334 -158
- package/src/config/model-resolver.ts +3 -1
- package/src/config/models-config-schema.ts +6 -0
- package/src/config/settings-schema.ts +60 -3
- package/src/config/settings.ts +458 -24
- package/src/coordinator-mcp/policy.ts +26 -1
- package/src/crash/sanitize.ts +4 -0
- package/src/customization/import.ts +3 -1
- package/src/dap/config.ts +31 -11
- package/src/dap/defaults.json +1 -1
- package/src/debug/crash-diagnostics.ts +2 -1
- package/src/debug/report-bundle.ts +19 -0
- package/src/debug/system-info.ts +8 -3
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +21 -7
- package/src/discovery/agents-md.ts +1 -1
- package/src/discovery/helpers.ts +1 -2
- package/src/discovery/mcp-compat.ts +120 -17
- package/src/edit/apply-patch/index.ts +12 -1
- package/src/edit/index.ts +13 -17
- package/src/edit/modes/patch.ts +187 -8
- package/src/edit/modes/replace.ts +136 -0
- package/src/eval/js/context-manager.ts +29 -3
- package/src/eval/js/worker-entry.ts +51 -18
- package/src/eval/py/executor.ts +14 -4
- package/src/eval/py/runner.py +144 -5
- package/src/exec/bash-executor.ts +81 -4
- package/src/exec/bash-shell-guardian.ts +4 -1
- package/src/exec/bash-shell-supervisor.ts +8 -4
- package/src/exec/isolated-shell.ts +5 -1
- package/src/export/html/index.ts +46 -6
- package/src/extensibility/custom-tools/wrapper.ts +3 -1
- package/src/extensibility/extensions/loader.ts +8 -1
- package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
- package/src/gjc-runtime/gc-runtime.ts +33 -6
- package/src/gjc-runtime/launch-tmux.ts +7 -2
- package/src/gjc-runtime/launch-worktree.test.ts +148 -0
- package/src/gjc-runtime/launch-worktree.ts +101 -14
- package/src/gjc-runtime/managed-owner-admission.ts +46 -2
- package/src/gjc-runtime/session-resolution.ts +38 -6
- package/src/gjc-runtime/session-state-lock.ts +59 -14
- package/src/gjc-runtime/state-runtime.ts +23 -19
- package/src/hooks/native-skill-hook.ts +14 -11
- package/src/internal-urls/docs-index.generated.ts +14 -13
- package/src/internal-urls/local-protocol.ts +142 -8
- package/src/lsp/index.ts +29 -0
- package/src/lsp/workspace-path.ts +23 -0
- package/src/migrate/action-planner.ts +57 -0
- package/src/migrate/adapters/claude-code.ts +23 -4
- package/src/migrate/adapters/codex.ts +22 -4
- package/src/migrate/adapters/index.ts +22 -4
- package/src/migrate/adapters/opencode.ts +6 -1
- package/src/migrate/executor.ts +84 -7
- package/src/migrate/report.ts +19 -2
- package/src/migrate/types.ts +14 -4
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/permission-mode.ts +18 -1
- package/src/modes/components/assistant-message.ts +55 -1
- package/src/modes/components/settings-selector.ts +103 -37
- package/src/modes/controllers/command-controller.ts +38 -2
- package/src/modes/controllers/plan-mode-controller.ts +17 -7
- package/src/modes/controllers/selector-controller.ts +62 -6
- package/src/modes/interactive-mode.ts +68 -0
- package/src/modes/theme/theme.ts +15 -0
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/report-issue.md +13 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-credential-selector.ts +2 -2
- package/src/runtime-mcp/content-limits.ts +7 -0
- package/src/runtime-mcp/manager-pool.test.ts +5 -4
- package/src/runtime-mcp/manager.ts +32 -0
- package/src/runtime-mcp/oauth-flow.ts +32 -6
- package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
- package/src/runtime-mcp/render.ts +16 -1
- package/src/runtime-mcp/tool-bridge.ts +126 -17
- package/src/sdk/broker/broker-exit.ts +8 -5
- package/src/sdk/broker/broker.ts +342 -82
- package/src/sdk/broker/daemon-entry.ts +338 -116
- package/src/sdk/broker/doctor-restart.ts +2 -1
- package/src/sdk/broker/ensure.ts +1143 -265
- package/src/sdk/broker/hop.ts +274 -0
- package/src/sdk/broker/lifecycle-ledger.ts +35 -11
- package/src/sdk/broker/lock-host-identity.ts +29 -0
- package/src/sdk/broker/session-index.ts +62 -12
- package/src/sdk/bus/chat-command-policy.ts +16 -3
- package/src/sdk/bus/index.ts +52 -21
- package/src/sdk/bus/reconciliation-store.ts +201 -8
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/cli/session-cli.ts +21 -6
- package/src/sdk/host/session-runtime.test.ts +118 -23
- package/src/sdk/host/session-runtime.ts +352 -47
- package/src/sdk/lifecycle/service.ts +1 -0
- package/src/sdk/prompt-deadline-flush.ts +78 -5
- package/src/sdk/prompt-deadline-manager.ts +68 -14
- package/src/sdk/protocol/adapter-validation.ts +53 -11
- package/src/sdk/protocol/operation-inventory.generated.json +101 -2
- package/src/sdk/reconciliation-extensions.ts +1 -0
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +114 -61
- package/src/session/agent-session.ts +1043 -81
- package/src/session/internal/managed-session-scope.ts +126 -39
- package/src/session/internal/managed-session-storage.ts +14 -11
- package/src/session/internal/native-publish-outcome.ts +5 -1
- package/src/session/messages.ts +47 -6
- package/src/session/session-manager.ts +236 -14
- package/src/session/startup-auth-config.ts +116 -8
- package/src/session/streaming-output.ts +262 -4
- package/src/session/terminal-abort.ts +14 -2
- package/src/session-import/service.ts +1 -0
- package/src/skill-state/workflow-mutation-guard.ts +491 -32
- package/src/slash-commands/builtin-registry.ts +15 -3
- package/src/slash-commands/helpers/credential-switch.ts +10 -5
- package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
- package/src/task/executor.ts +103 -12
- package/src/task/index.ts +389 -175
- package/src/tools/ast-edit-write-path.ts +64 -0
- package/src/tools/ast-edit.ts +18 -1
- package/src/tools/atomic-file-write.ts +46 -15
- package/src/tools/auto-generated-guard.ts +3 -0
- package/src/tools/bash-allowed-prefixes.ts +153 -5
- package/src/tools/bash-interactive.ts +14 -2
- package/src/tools/bash.ts +14 -0
- package/src/tools/debug.ts +7 -6
- package/src/tools/descriptors.test.ts +44 -0
- package/src/tools/descriptors.ts +34 -2
- package/src/tools/fetch.ts +3 -2
- package/src/tools/index.ts +2 -0
- package/src/tools/output-meta.ts +23 -2
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +17 -35
- package/src/tools/report-issue.ts +184 -0
- package/src/tools/subagent-render.ts +114 -12
- package/src/tools/subagent.ts +108 -1
- package/src/tools/todo-write.ts +41 -3
- package/src/tools/tool-catalog.generated.ts +31 -3
- package/src/tools/write.ts +35 -3
- package/src/utils/commit-message-generator.ts +9 -2
- package/src/utils/file-mentions.ts +29 -1
- package/src/utils/title-generator.ts +7 -2
- package/src/web/scrapers/index.ts +3 -1
- package/src/web/scrapers/types.ts +8 -0
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/insane.ts +91 -28
- package/src/web/search/providers/searxng.ts +62 -10
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import * as util from "node:util";
|
|
1
2
|
import { ThinkingLevel } from "@gajae-code/agent-core";
|
|
2
3
|
import { type Api, isKnownProvider, type Model } from "@gajae-code/ai/core";
|
|
3
4
|
import { logger } from "@gajae-code/utils";
|
|
4
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
AgentSession,
|
|
7
|
+
AgentSessionProfileInstalledOverrideState,
|
|
8
|
+
DefaultFallbackRuntimeState,
|
|
9
|
+
} from "../session/agent-session";
|
|
5
10
|
import { clampExplicitThinkingLevelForModel, formatClampedModelSelector } from "../thinking";
|
|
6
11
|
import { validateModelProfileName } from "./model-profile-contract";
|
|
7
12
|
import {
|
|
@@ -55,20 +60,36 @@ type ModelProfileActivationSession = Pick<
|
|
|
55
60
|
modelRoles: readonly string[],
|
|
56
61
|
agentModelOverrides: readonly string[],
|
|
57
62
|
preProfileModel: Model<Api> | undefined,
|
|
63
|
+
baseline?: {
|
|
64
|
+
modelRoles: Readonly<Record<string, ModelSelectorValue>>;
|
|
65
|
+
agentModelOverrides: Readonly<Record<string, ModelSelectorValue>>;
|
|
66
|
+
},
|
|
67
|
+
installed?: {
|
|
68
|
+
modelRoles: Readonly<Record<string, ModelSelectorValue>>;
|
|
69
|
+
agentModelOverrides: Readonly<Record<string, ModelSelectorValue>>;
|
|
70
|
+
},
|
|
71
|
+
manual?: { modelRoles: readonly string[]; agentModelOverrides: readonly string[] },
|
|
58
72
|
) => void;
|
|
59
73
|
/** Drop the recorded profile-installed override keys (e.g. after materialization). */
|
|
60
74
|
clearProfileInstalledOverrides?: () => void;
|
|
61
75
|
/** Current profile-installed override keys, for deriving the activation base. */
|
|
62
76
|
getProfileInstalledOverrideKeys?: () => { modelRoles: readonly string[]; agentModelOverrides: readonly string[] };
|
|
77
|
+
/** Profile-installed baselines, preserved when a refreshed profile drops an assignment. */
|
|
78
|
+
getProfileInstalledOverrideState?: () => AgentSessionProfileInstalledOverrideState;
|
|
79
|
+
restoreProfileInstalledOverrideState?: (state: AgentSessionProfileInstalledOverrideState) => void;
|
|
63
80
|
/** Re-apply vendor-separated delegation (task tool + prompt) after the role layer changed. */
|
|
64
81
|
syncEagerDelegation?: () => Promise<void>;
|
|
65
82
|
getSessionDefaultModelSelector?: () => string | undefined;
|
|
66
83
|
recordResumeDefaultModel?: (selector: string | undefined) => void;
|
|
67
84
|
getUserCanonicalVariantSelection?: () => UserCanonicalVariantSelection;
|
|
85
|
+
getUserModelSelectionRevision?: () => number;
|
|
68
86
|
seedDefaultFallbackResolution?: (activeIndex: number, skips: Array<{ selector: string; reason: string }>) => void;
|
|
69
87
|
getDefaultFallbackRuntimeState?: () => DefaultFallbackRuntimeState;
|
|
70
88
|
restoreDefaultFallbackRuntimeState?: (state: DefaultFallbackRuntimeState) => void;
|
|
71
89
|
restoreModelSelectionForRollback?: AgentSession["restoreModelSelectionForRollback"];
|
|
90
|
+
prepareModelSelectionForProfileActivation?: AgentSession["prepareModelSelectionForProfileActivation"];
|
|
91
|
+
commitPreparedProfileModelSelection?: AgentSession["commitPreparedProfileModelSelection"];
|
|
92
|
+
finishPreparedProfileModelSelection?: AgentSession["finishPreparedProfileModelSelection"];
|
|
72
93
|
modelRegistry?: Pick<
|
|
73
94
|
ModelRegistry,
|
|
74
95
|
| "getSessionCanonicalVariant"
|
|
@@ -79,7 +100,8 @@ type ModelProfileActivationSession = Pick<
|
|
|
79
100
|
| "resolveModelByLookupAlias"
|
|
80
101
|
| "authStorage"
|
|
81
102
|
| "isCredentiallessProvider"
|
|
82
|
-
|
|
103
|
+
> &
|
|
104
|
+
Partial<Pick<ModelRegistry, "seedCanonicalVariant">>;
|
|
83
105
|
getConfiguredModelChainState?: (role: string) => ConfiguredModelChainState | undefined;
|
|
84
106
|
};
|
|
85
107
|
|
|
@@ -90,6 +112,24 @@ type ConfiguredModelChainState = {
|
|
|
90
112
|
explicitHead: boolean;
|
|
91
113
|
};
|
|
92
114
|
|
|
115
|
+
type PublishedModelProfileActivationState = {
|
|
116
|
+
model: Model<Api> | undefined;
|
|
117
|
+
thinkingLevel: ThinkingLevel | undefined;
|
|
118
|
+
modelRolesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
119
|
+
agentModelOverridesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
120
|
+
defaultChainState: ConfiguredModelChainState | undefined;
|
|
121
|
+
defaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
122
|
+
activeModelProfile: string | undefined;
|
|
123
|
+
profileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
124
|
+
sessionDefaultModel: string | undefined;
|
|
125
|
+
persistedModelRoles: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
126
|
+
persistedAgentModelOverrides: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
127
|
+
persistedDefaultProfile: string | undefined;
|
|
128
|
+
persistedDefaultThinkingLevel: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
129
|
+
defaultThinkingLevelOverride: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
130
|
+
defaultProfileOverride: string | undefined;
|
|
131
|
+
};
|
|
132
|
+
|
|
93
133
|
export interface PrepareModelProfileActivationOptions {
|
|
94
134
|
session: ModelProfileActivationSession;
|
|
95
135
|
modelRegistry: Pick<
|
|
@@ -108,6 +148,8 @@ export interface PrepareModelProfileActivationOptions {
|
|
|
108
148
|
Pick<
|
|
109
149
|
ModelRegistry,
|
|
110
150
|
| "getAvailable"
|
|
151
|
+
| "hasUsableAuthForProvider"
|
|
152
|
+
| "isStagedReloadCandidate"
|
|
111
153
|
| "resolveModelByLookupAlias"
|
|
112
154
|
| "lookupAliasExists"
|
|
113
155
|
| "clearCanonicalVariant"
|
|
@@ -115,6 +157,7 @@ export interface PrepareModelProfileActivationOptions {
|
|
|
115
157
|
| "getSessionCanonicalVariant"
|
|
116
158
|
| "restoreSessionCanonicalVariant"
|
|
117
159
|
| "getConfiguredProviderIds"
|
|
160
|
+
| "getConfiguredModelBindings"
|
|
118
161
|
| "isKnownProvider"
|
|
119
162
|
>
|
|
120
163
|
> & {
|
|
@@ -122,11 +165,21 @@ export interface PrepareModelProfileActivationOptions {
|
|
|
122
165
|
authStorage?: ModelRegistry["authStorage"];
|
|
123
166
|
};
|
|
124
167
|
settings: Pick<Settings, "get" | "getGlobal" | "getOverride">;
|
|
168
|
+
/** Live mutation target when `settings` is a validated staged view. */
|
|
169
|
+
settingsForApply?: Settings;
|
|
170
|
+
prepareSessionModelSelection?: boolean;
|
|
171
|
+
preserveManualOverrides?: boolean;
|
|
172
|
+
preserveCanonicalVariant?: boolean;
|
|
173
|
+
signal?: AbortSignal;
|
|
125
174
|
profileName: string;
|
|
126
175
|
}
|
|
127
176
|
export interface ApplyModelProfileActivationOptions {
|
|
128
177
|
persistDefault?: boolean;
|
|
129
178
|
thinkingLevelOverride?: ThinkingLevel;
|
|
179
|
+
preserveDefaultModelSelection?: boolean;
|
|
180
|
+
preserveLiveModelSelection?: boolean;
|
|
181
|
+
deferRuntimePublication?: boolean;
|
|
182
|
+
signal?: AbortSignal;
|
|
130
183
|
/** Cancels deferred activation if a newer user model selection exists. */
|
|
131
184
|
isCurrent?: () => boolean;
|
|
132
185
|
}
|
|
@@ -148,11 +201,18 @@ export interface PreparedModelProfileActivation {
|
|
|
148
201
|
previousDefaultProfileOverride: string | undefined;
|
|
149
202
|
previousPersistedDefaultProfile: string | undefined;
|
|
150
203
|
previousPersistedDefaultThinkingLevel: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
151
|
-
previousDefaultThinkingLevelOverride: ThinkingLevel | undefined;
|
|
204
|
+
previousDefaultThinkingLevelOverride: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
152
205
|
baseAgentModelOverrides: Record<string, ModelSelectorValue>;
|
|
153
206
|
baseModelRoles: Record<string, ModelSelectorValue>;
|
|
154
207
|
previousDefaultChain: readonly string[] | undefined;
|
|
155
208
|
previousDefaultChainState: ConfiguredModelChainState | undefined;
|
|
209
|
+
previousProfileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
210
|
+
preparedDefaultModelSelection:
|
|
211
|
+
| Awaited<ReturnType<NonNullable<ModelProfileActivationSession["prepareModelSelectionForProfileActivation"]>>>
|
|
212
|
+
| undefined;
|
|
213
|
+
defaultChainPublished: boolean;
|
|
214
|
+
defaultModelPublished: boolean;
|
|
215
|
+
publishedState: PublishedModelProfileActivationState | undefined;
|
|
156
216
|
previousDefaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
157
217
|
defaultModel: Model<Api> | undefined;
|
|
158
218
|
defaultThinkingLevel: ThinkingLevel | undefined;
|
|
@@ -164,6 +224,8 @@ export interface PreparedModelProfileActivation {
|
|
|
164
224
|
defaultResolutionSkips: Array<{ selector: string; reason: string }>;
|
|
165
225
|
modelRoles: Record<string, ModelSelectorValue>;
|
|
166
226
|
agentModelOverrides: Record<string, ModelSelectorValue>;
|
|
227
|
+
manualModelRoleOverrides: ReadonlySet<string>;
|
|
228
|
+
manualAgentModelOverrides: ReadonlySet<string>;
|
|
167
229
|
previousActiveModelProfile: string | undefined;
|
|
168
230
|
/**
|
|
169
231
|
* The session resume default ("provider/id") captured BEFORE activation —
|
|
@@ -528,6 +590,17 @@ async function getProfileProviderApiKey(
|
|
|
528
590
|
}
|
|
529
591
|
}
|
|
530
592
|
|
|
593
|
+
function isStagedProviderAuthAvailable(
|
|
594
|
+
registry: PrepareModelProfileActivationOptions["modelRegistry"],
|
|
595
|
+
provider: string,
|
|
596
|
+
sessionId: string,
|
|
597
|
+
): boolean {
|
|
598
|
+
return (
|
|
599
|
+
registry.isStagedReloadCandidate?.() === true &&
|
|
600
|
+
(registry.hasUsableAuthForProvider?.(provider, sessionId) ?? false)
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
|
|
531
604
|
export function formatModelProfileCredentialError(profileLabel: string, providers: readonly string[]): string {
|
|
532
605
|
return `Model profile "${profileLabel}" requires credentials for: ${providers.join(", ")}. Run /login and configure the missing provider(s), then retry.`;
|
|
533
606
|
}
|
|
@@ -825,7 +898,8 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
825
898
|
if (requiredProviderSet.has(provider) && !alternativeSet.has(provider)) throw error;
|
|
826
899
|
continue;
|
|
827
900
|
}
|
|
828
|
-
|
|
901
|
+
const hasUsableAuth = isStagedProviderAuthAvailable(options.modelRegistry, provider, options.credentialSessionId);
|
|
902
|
+
if (apiKey === kNoAuth || isAuthenticated(apiKey) || hasUsableAuth) authenticatedProviders.add(provider);
|
|
829
903
|
else if (requiredProviderSet.has(provider)) missingProviders.push(provider);
|
|
830
904
|
}
|
|
831
905
|
const proxyProvider = profile.source !== "user" ? resolveProxyProviderId(options.settings) : undefined;
|
|
@@ -851,6 +925,9 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
851
925
|
options.credentialSessionId,
|
|
852
926
|
profileLabel,
|
|
853
927
|
);
|
|
928
|
+
const proxyHasUsableAuth =
|
|
929
|
+
proxyProvider !== undefined &&
|
|
930
|
+
isStagedProviderAuthAvailable(options.modelRegistry, proxyProvider, options.credentialSessionId);
|
|
854
931
|
if (
|
|
855
932
|
proxyProvider !== undefined &&
|
|
856
933
|
!isModelProfileProxyConfigured(proxyProvider, configuredProviderIds, proxyApiKey === kNoAuth)
|
|
@@ -859,7 +936,8 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
859
936
|
`modelProfile.proxyProvider "${proxyProvider}" is not configured. Configure it with \`gjc setup provider\` before activating a preset.`,
|
|
860
937
|
);
|
|
861
938
|
}
|
|
862
|
-
const proxyAuthenticated =
|
|
939
|
+
const proxyAuthenticated =
|
|
940
|
+
(proxyApiKey !== undefined && (proxyApiKey === kNoAuth || isAuthenticated(proxyApiKey))) || proxyHasUsableAuth;
|
|
863
941
|
if (proxyMode === "always" && !proxyAuthenticated)
|
|
864
942
|
throw new ModelProfileCredentialError(profileLabel, [proxyProvider!]);
|
|
865
943
|
const strictMissing = missingProviders.filter(
|
|
@@ -948,6 +1026,8 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
948
1026
|
credentialSessionId: options.credentialSessionId,
|
|
949
1027
|
isCredentialUnavailable: provider =>
|
|
950
1028
|
isSessionCredentialPinBlocking(options.modelRegistry, provider, options.credentialSessionId),
|
|
1029
|
+
isProviderAuthAvailable: provider =>
|
|
1030
|
+
isStagedProviderAuthAvailable(options.modelRegistry, provider, options.credentialSessionId),
|
|
951
1031
|
},
|
|
952
1032
|
);
|
|
953
1033
|
return { profileName, entries: defaultChain, ...resolution };
|
|
@@ -1147,6 +1227,8 @@ async function resolveAndClampSelectorValue(
|
|
|
1147
1227
|
credentialSessionId: options.credentialSessionId,
|
|
1148
1228
|
isCredentialUnavailable: provider =>
|
|
1149
1229
|
isSessionCredentialPinBlocking(options.modelRegistry, provider, options.credentialSessionId),
|
|
1230
|
+
isProviderAuthAvailable: provider =>
|
|
1231
|
+
isStagedProviderAuthAvailable(options.modelRegistry, provider, options.credentialSessionId),
|
|
1150
1232
|
},
|
|
1151
1233
|
);
|
|
1152
1234
|
resolved = {
|
|
@@ -1279,6 +1361,8 @@ async function concretizeProfileSelectorValue(
|
|
|
1279
1361
|
credentialSessionId,
|
|
1280
1362
|
isCredentialUnavailable: provider =>
|
|
1281
1363
|
isSessionCredentialPinBlocking(prepared.modelRegistry, provider, credentialSessionId),
|
|
1364
|
+
isProviderAuthAvailable: provider =>
|
|
1365
|
+
isStagedProviderAuthAvailable(prepared.modelRegistry, provider, credentialSessionId),
|
|
1282
1366
|
},
|
|
1283
1367
|
)
|
|
1284
1368
|
: resolveModelRoleValue(selector, candidates, {
|
|
@@ -1314,7 +1398,7 @@ async function concretizeProfileSelectorValue(
|
|
|
1314
1398
|
* variant is cleared so a previous provider cannot silently resurrect.
|
|
1315
1399
|
*/
|
|
1316
1400
|
function restoreCanonicalVariant(
|
|
1317
|
-
modelRegistry:
|
|
1401
|
+
modelRegistry: Partial<Pick<ModelRegistry, "restoreSessionCanonicalVariant" | "clearCanonicalVariant">>,
|
|
1318
1402
|
sessionId: string,
|
|
1319
1403
|
previousCanonicalVariant: string | undefined,
|
|
1320
1404
|
): void {
|
|
@@ -1326,8 +1410,18 @@ function restoreCanonicalVariant(
|
|
|
1326
1410
|
}
|
|
1327
1411
|
}
|
|
1328
1412
|
|
|
1413
|
+
function selectorValuesEqual(left: ModelSelectorValue | undefined, right: ModelSelectorValue | undefined): boolean {
|
|
1414
|
+
if (left === undefined || right === undefined) return left === right;
|
|
1415
|
+
const leftSelectors = normalizeModelSelectorValue(left);
|
|
1416
|
+
const rightSelectors = normalizeModelSelectorValue(right);
|
|
1417
|
+
return (
|
|
1418
|
+
leftSelectors.length === rightSelectors.length &&
|
|
1419
|
+
leftSelectors.every((selector, index) => selector === rightSelectors[index])
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1329
1423
|
function restoreCanonicalVariantAfterPreparation(
|
|
1330
|
-
modelRegistry:
|
|
1424
|
+
modelRegistry: Partial<Pick<ModelRegistry, "restoreSessionCanonicalVariant" | "clearCanonicalVariant">>,
|
|
1331
1425
|
session: ModelProfileActivationSession,
|
|
1332
1426
|
previousCanonicalVariant: string | undefined,
|
|
1333
1427
|
previousUserSelection: UserCanonicalVariantSelection | undefined,
|
|
@@ -1343,7 +1437,6 @@ function restoreCanonicalVariantAfterPreparation(
|
|
|
1343
1437
|
userSelectionChanged ? currentUserSelection.canonicalVariant : previousCanonicalVariant,
|
|
1344
1438
|
);
|
|
1345
1439
|
}
|
|
1346
|
-
|
|
1347
1440
|
export async function prepareModelProfileActivation(
|
|
1348
1441
|
options: PrepareModelProfileActivationOptions,
|
|
1349
1442
|
): Promise<PreparedModelProfileActivation> {
|
|
@@ -1353,6 +1446,7 @@ export async function prepareModelProfileActivation(
|
|
|
1353
1446
|
const profileLabel = formatModelProfileDisplayLabel(profile);
|
|
1354
1447
|
|
|
1355
1448
|
const previousModel = options.session.model;
|
|
1449
|
+
const applySettings = options.settingsForApply ?? (options.settings as Settings);
|
|
1356
1450
|
// Snapshot the exact pre-clear sticky selector (verbatim, not re-derived from
|
|
1357
1451
|
// the live model) so a failed prepare/apply/materialize rollback restores the
|
|
1358
1452
|
// genuinely-sticky provider even when the live model is a transient switch.
|
|
@@ -1363,7 +1457,7 @@ export async function prepareModelProfileActivation(
|
|
|
1363
1457
|
// Explicit profile activation/reselection invalidates the session's sticky
|
|
1364
1458
|
// canonical variant BEFORE the new profile's aliases resolve, so the old
|
|
1365
1459
|
// provider's sticky variant cannot win the new profile's resolution.
|
|
1366
|
-
options.modelRegistry.clearCanonicalVariant?.(options.session.sessionId);
|
|
1460
|
+
if (!options.preserveCanonicalVariant) options.modelRegistry.clearCanonicalVariant?.(options.session.sessionId);
|
|
1367
1461
|
|
|
1368
1462
|
try {
|
|
1369
1463
|
const requiredProviders = aggregateModelProfileRequiredProviders(profile.requiredProviders, profile);
|
|
@@ -1413,7 +1507,8 @@ export async function prepareModelProfileActivation(
|
|
|
1413
1507
|
if (requiredProviderSet.has(provider) && !alternativeSet.has(provider)) throw error;
|
|
1414
1508
|
continue;
|
|
1415
1509
|
}
|
|
1416
|
-
|
|
1510
|
+
const hasUsableAuth = isStagedProviderAuthAvailable(options.modelRegistry, provider, credentialSessionId);
|
|
1511
|
+
if (apiKey !== kNoAuth && !isAuthenticated(apiKey) && !hasUsableAuth) {
|
|
1417
1512
|
if (requiredProviderSet.has(provider)) missingProviders.push(provider);
|
|
1418
1513
|
} else {
|
|
1419
1514
|
authenticatedProviders.push(provider);
|
|
@@ -1444,6 +1539,9 @@ export async function prepareModelProfileActivation(
|
|
|
1444
1539
|
proxyProvider === undefined
|
|
1445
1540
|
? undefined
|
|
1446
1541
|
: await getProfileProviderApiKey(options.modelRegistry, proxyProvider, credentialSessionId, profileLabel);
|
|
1542
|
+
const proxyHasUsableAuth =
|
|
1543
|
+
proxyProvider !== undefined &&
|
|
1544
|
+
isStagedProviderAuthAvailable(options.modelRegistry, proxyProvider, credentialSessionId);
|
|
1447
1545
|
if (proxyProvider !== undefined) {
|
|
1448
1546
|
const configuredProxyProviders = options.modelRegistry.getConfiguredProviderIds?.();
|
|
1449
1547
|
if (!isModelProfileProxyConfigured(proxyProvider, configuredProxyProviders, proxyApiKey === kNoAuth)) {
|
|
@@ -1454,8 +1552,8 @@ export async function prepareModelProfileActivation(
|
|
|
1454
1552
|
}
|
|
1455
1553
|
const proxyAuthenticated =
|
|
1456
1554
|
proxyProvider !== undefined &&
|
|
1457
|
-
proxyApiKey !== undefined &&
|
|
1458
|
-
|
|
1555
|
+
((proxyApiKey !== undefined && (proxyApiKey === kNoAuth || isAuthenticated(proxyApiKey))) ||
|
|
1556
|
+
proxyHasUsableAuth);
|
|
1459
1557
|
if (proxyMode === "always" && !proxyAuthenticated) {
|
|
1460
1558
|
throw new ModelProfileCredentialError(profileLabel, [proxyProvider!]);
|
|
1461
1559
|
}
|
|
@@ -1547,6 +1645,8 @@ export async function prepareModelProfileActivation(
|
|
|
1547
1645
|
credentialSessionId,
|
|
1548
1646
|
isCredentialUnavailable: provider =>
|
|
1549
1647
|
isSessionCredentialPinBlocking(options.modelRegistry, provider, credentialSessionId),
|
|
1648
|
+
isProviderAuthAvailable: provider =>
|
|
1649
|
+
isStagedProviderAuthAvailable(options.modelRegistry, provider, credentialSessionId),
|
|
1550
1650
|
},
|
|
1551
1651
|
);
|
|
1552
1652
|
const defaultModel = defaultResolution.model;
|
|
@@ -1573,49 +1673,129 @@ export async function prepareModelProfileActivation(
|
|
|
1573
1673
|
credentialSessionId,
|
|
1574
1674
|
profileLabel,
|
|
1575
1675
|
});
|
|
1676
|
+
const installedKeys = options.session.getProfileInstalledOverrideKeys?.();
|
|
1677
|
+
const installedState = options.session.getProfileInstalledOverrideState?.();
|
|
1678
|
+
const baseModelRoles = { ...(options.settings.getOverride("modelRoles") ?? {}) };
|
|
1679
|
+
const baseAgentModelOverrides = { ...(options.settings.getOverride("task.agentModelOverrides") ?? {}) };
|
|
1680
|
+
const manualModelRoleOverrides = new Set(
|
|
1681
|
+
options.preserveManualOverrides ? (installedState?.manualModelRoles ?? []) : [],
|
|
1682
|
+
);
|
|
1683
|
+
const manualAgentModelOverrides = new Set(
|
|
1684
|
+
options.preserveManualOverrides ? (installedState?.manualAgentModelOverrides ?? []) : [],
|
|
1685
|
+
);
|
|
1686
|
+
const configuredAgentModelOverrides = options.modelRegistry?.getConfiguredModelBindings?.()?.agentModelOverrides;
|
|
1687
|
+
for (const role of installedKeys?.modelRoles ?? []) {
|
|
1688
|
+
if (options.preserveManualOverrides && manualModelRoleOverrides.has(role)) continue;
|
|
1689
|
+
const installed = installedState?.installedModelRoles.get(role);
|
|
1690
|
+
if (
|
|
1691
|
+
options.preserveManualOverrides &&
|
|
1692
|
+
installed !== undefined &&
|
|
1693
|
+
!selectorValuesEqual(baseModelRoles[role], installed)
|
|
1694
|
+
) {
|
|
1695
|
+
manualModelRoleOverrides.add(role);
|
|
1696
|
+
continue;
|
|
1697
|
+
}
|
|
1698
|
+
delete baseModelRoles[role];
|
|
1699
|
+
}
|
|
1700
|
+
for (const role of installedKeys?.agentModelOverrides ?? []) {
|
|
1701
|
+
if (options.preserveManualOverrides && manualAgentModelOverrides.has(role)) continue;
|
|
1702
|
+
const installed = installedState?.installedAgentModelOverrides.get(role);
|
|
1703
|
+
if (
|
|
1704
|
+
options.preserveManualOverrides &&
|
|
1705
|
+
installed !== undefined &&
|
|
1706
|
+
!selectorValuesEqual(baseAgentModelOverrides[role], installed)
|
|
1707
|
+
) {
|
|
1708
|
+
manualAgentModelOverrides.add(role);
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
delete baseAgentModelOverrides[role];
|
|
1712
|
+
}
|
|
1713
|
+
// Compare the current session override with the installed profile value
|
|
1714
|
+
// before excluding configured bindings from the successor baseline. The
|
|
1715
|
+
// current value may itself be the installed profile value; filtering first
|
|
1716
|
+
// would misclassify that role as a manual override during configuration reload.
|
|
1717
|
+
for (const role of Object.keys(configuredAgentModelOverrides ?? {})) {
|
|
1718
|
+
if (!manualAgentModelOverrides.has(role)) delete baseAgentModelOverrides[role];
|
|
1719
|
+
}
|
|
1720
|
+
for (const [role, value] of installedState?.modelRoles ?? []) {
|
|
1721
|
+
if (manualModelRoleOverrides.has(role)) continue;
|
|
1722
|
+
if (value === undefined) delete baseModelRoles[role];
|
|
1723
|
+
else baseModelRoles[role] = value;
|
|
1724
|
+
}
|
|
1725
|
+
for (const [role, value] of installedState?.agentModelOverrides ?? []) {
|
|
1726
|
+
if (manualAgentModelOverrides.has(role)) continue;
|
|
1727
|
+
const configuredBinding = configuredAgentModelOverrides?.[role];
|
|
1728
|
+
if (configuredBinding !== undefined) {
|
|
1729
|
+
// Configured bindings are reapplied when the active profile is cleared;
|
|
1730
|
+
// leaving them in this baseline makes omitted successor roles stay live.
|
|
1731
|
+
delete baseAgentModelOverrides[role];
|
|
1732
|
+
} else if (installedState?.configuredAgentModelOverrides.has(role)) {
|
|
1733
|
+
// A removed binding must not revive its former value from the profile
|
|
1734
|
+
// baseline after a configuration reload.
|
|
1735
|
+
delete baseAgentModelOverrides[role];
|
|
1736
|
+
} else if (value === undefined) {
|
|
1737
|
+
delete baseAgentModelOverrides[role];
|
|
1738
|
+
} else {
|
|
1739
|
+
baseAgentModelOverrides[role] = value;
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
const preparedDefaultModelSelection =
|
|
1743
|
+
options.prepareSessionModelSelection && defaultModel
|
|
1744
|
+
? await options.session.prepareModelSelectionForProfileActivation?.(
|
|
1745
|
+
defaultModel,
|
|
1746
|
+
defaultThinkingLevel,
|
|
1747
|
+
options.signal,
|
|
1748
|
+
)
|
|
1749
|
+
: undefined;
|
|
1750
|
+
if (options.prepareSessionModelSelection && defaultModel && !preparedDefaultModelSelection) {
|
|
1751
|
+
throw new Error("Session cannot prepare a synchronous profile model selection");
|
|
1752
|
+
}
|
|
1753
|
+
options.signal?.throwIfAborted();
|
|
1754
|
+
const nextModelRoles = { ...modelRoles };
|
|
1755
|
+
const nextAgentModelOverrides = { ...agentModelOverrides };
|
|
1756
|
+
for (const role of manualModelRoleOverrides) delete nextModelRoles[role];
|
|
1757
|
+
for (const role of manualAgentModelOverrides) delete nextAgentModelOverrides[role];
|
|
1576
1758
|
|
|
1577
1759
|
return {
|
|
1578
1760
|
profileName,
|
|
1579
1761
|
session: options.session as PreparedModelProfileActivation["session"],
|
|
1580
|
-
settings:
|
|
1762
|
+
settings: applySettings as PreparedModelProfileActivation["settings"],
|
|
1581
1763
|
modelRegistry: options.modelRegistry,
|
|
1582
1764
|
previousModel,
|
|
1583
1765
|
previousCanonicalVariant,
|
|
1584
1766
|
previousUserCanonicalVariantSelection,
|
|
1585
1767
|
previousThinkingLevel: options.session.thinkingLevel,
|
|
1586
|
-
previousAgentModelOverrides: { ...
|
|
1587
|
-
previousModelRoles: { ...
|
|
1588
|
-
baseAgentModelOverrides
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
),
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
),
|
|
1598
|
-
),
|
|
1599
|
-
previousPersistedModelRoles: options.settings.getGlobal("modelRoles"),
|
|
1600
|
-
previousPersistedAgentModelOverrides: options.settings.getGlobal("task.agentModelOverrides"),
|
|
1601
|
-
previousModelRolesOverride: options.settings.getOverride("modelRoles"),
|
|
1602
|
-
previousAgentModelOverridesOverride: options.settings.getOverride("task.agentModelOverrides"),
|
|
1603
|
-
previousDefaultProfileOverride: options.settings.getOverride("modelProfile.default"),
|
|
1604
|
-
previousPersistedDefaultProfile: options.settings.getGlobal("modelProfile.default"),
|
|
1605
|
-
previousPersistedDefaultThinkingLevel: options.settings.getGlobal("defaultThinkingLevel") as
|
|
1768
|
+
previousAgentModelOverrides: { ...applySettings.get("task.agentModelOverrides") },
|
|
1769
|
+
previousModelRoles: { ...applySettings.get("modelRoles") },
|
|
1770
|
+
baseAgentModelOverrides,
|
|
1771
|
+
baseModelRoles,
|
|
1772
|
+
previousPersistedModelRoles: applySettings.getGlobal("modelRoles"),
|
|
1773
|
+
previousPersistedAgentModelOverrides: applySettings.getGlobal("task.agentModelOverrides"),
|
|
1774
|
+
previousModelRolesOverride: applySettings.getOverride("modelRoles"),
|
|
1775
|
+
previousAgentModelOverridesOverride: applySettings.getOverride("task.agentModelOverrides"),
|
|
1776
|
+
previousDefaultProfileOverride: applySettings.getOverride("modelProfile.default"),
|
|
1777
|
+
previousPersistedDefaultProfile: applySettings.getGlobal("modelProfile.default"),
|
|
1778
|
+
previousPersistedDefaultThinkingLevel: applySettings.getGlobal("defaultThinkingLevel") as
|
|
1606
1779
|
| Exclude<ThinkingLevel, "inherit">
|
|
1607
1780
|
| undefined,
|
|
1608
|
-
previousDefaultThinkingLevelOverride:
|
|
1781
|
+
previousDefaultThinkingLevelOverride: applySettings.getOverride("defaultThinkingLevel"),
|
|
1609
1782
|
previousDefaultChain: options.session.getConfiguredModelChain("default"),
|
|
1610
1783
|
previousDefaultChainState: options.session.getConfiguredModelChainState?.("default"),
|
|
1784
|
+
previousProfileInstalledOverrideState: installedState,
|
|
1785
|
+
preparedDefaultModelSelection,
|
|
1786
|
+
defaultChainPublished: false,
|
|
1787
|
+
defaultModelPublished: false,
|
|
1788
|
+
publishedState: undefined,
|
|
1611
1789
|
|
|
1612
1790
|
defaultModel,
|
|
1613
1791
|
defaultThinkingLevel,
|
|
1614
1792
|
defaultActiveIndex,
|
|
1615
1793
|
defaultResolutionSkips,
|
|
1616
1794
|
defaultChain,
|
|
1617
|
-
modelRoles,
|
|
1618
|
-
agentModelOverrides,
|
|
1795
|
+
modelRoles: nextModelRoles,
|
|
1796
|
+
agentModelOverrides: nextAgentModelOverrides,
|
|
1797
|
+
manualModelRoleOverrides,
|
|
1798
|
+
manualAgentModelOverrides,
|
|
1619
1799
|
previousActiveModelProfile: options.session.getActiveModelProfile?.(),
|
|
1620
1800
|
previousSessionDefaultModel: options.session.getSessionDefaultModelSelector?.(),
|
|
1621
1801
|
previousDefaultFallbackRuntimeState: options.session.getDefaultFallbackRuntimeState?.(),
|
|
@@ -1707,34 +1887,44 @@ function restoreConcurrentProfileOverrides(
|
|
|
1707
1887
|
return Object.keys(restored).length > 0 || previous !== undefined ? restored : undefined;
|
|
1708
1888
|
}
|
|
1709
1889
|
|
|
1710
|
-
|
|
1890
|
+
function capturePublishedModelProfileActivationState(
|
|
1711
1891
|
prepared: PreparedModelProfileActivation,
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1892
|
+
): PublishedModelProfileActivationState {
|
|
1893
|
+
return {
|
|
1894
|
+
model: prepared.session.model,
|
|
1895
|
+
thinkingLevel: prepared.session.thinkingLevel,
|
|
1896
|
+
modelRolesOverride: prepared.settings.getOverride("modelRoles"),
|
|
1897
|
+
agentModelOverridesOverride: prepared.settings.getOverride("task.agentModelOverrides"),
|
|
1898
|
+
defaultChainState: prepared.session.getConfiguredModelChainState?.("default"),
|
|
1899
|
+
defaultFallbackRuntimeState: prepared.session.getDefaultFallbackRuntimeState?.(),
|
|
1900
|
+
activeModelProfile: prepared.session.getActiveModelProfile?.(),
|
|
1901
|
+
profileInstalledOverrideState: prepared.session.getProfileInstalledOverrideState?.(),
|
|
1902
|
+
sessionDefaultModel: prepared.session.getSessionDefaultModelSelector?.(),
|
|
1903
|
+
persistedModelRoles: prepared.settings.getGlobal("modelRoles"),
|
|
1904
|
+
persistedAgentModelOverrides: prepared.settings.getGlobal("task.agentModelOverrides"),
|
|
1905
|
+
persistedDefaultProfile: prepared.settings.getGlobal("modelProfile.default"),
|
|
1906
|
+
persistedDefaultThinkingLevel: prepared.settings.getGlobal("defaultThinkingLevel"),
|
|
1907
|
+
defaultThinkingLevelOverride: prepared.settings.getOverride("defaultThinkingLevel"),
|
|
1908
|
+
defaultProfileOverride: prepared.settings.getOverride("modelProfile.default"),
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1726
1911
|
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1912
|
+
/** Publish the prepared model selection and role layer without awaiting. */
|
|
1913
|
+
export function publishPreparedModelProfileActivation(
|
|
1914
|
+
prepared: PreparedModelProfileActivation,
|
|
1915
|
+
options: Pick<
|
|
1916
|
+
ApplyModelProfileActivationOptions,
|
|
1917
|
+
"preserveDefaultModelSelection" | "preserveLiveModelSelection"
|
|
1918
|
+
> = {},
|
|
1919
|
+
): void {
|
|
1920
|
+
if (!options.preserveDefaultModelSelection && prepared.preparedDefaultModelSelection) {
|
|
1731
1921
|
const ownedDefaultChain =
|
|
1732
1922
|
prepared.defaultChain.length > 0
|
|
1733
1923
|
? prepared.defaultChain
|
|
1734
1924
|
: (prepared.previousDefaultChain ??
|
|
1735
1925
|
(prepared.previousModel ? [formatModelString(prepared.previousModel)] : []));
|
|
1736
1926
|
if (ownedDefaultChain.length > 0) {
|
|
1737
|
-
|
|
1927
|
+
prepared.defaultChainPublished = true;
|
|
1738
1928
|
prepared.session.setConfiguredModelChain(
|
|
1739
1929
|
"default",
|
|
1740
1930
|
ownedDefaultChain,
|
|
@@ -1748,44 +1938,151 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1748
1938
|
prepared.defaultResolutionSkips,
|
|
1749
1939
|
);
|
|
1750
1940
|
}
|
|
1751
|
-
activatedDefaultChainState = prepared.session.getConfiguredModelChainState?.("default");
|
|
1752
|
-
activatedFallbackRuntimeState = prepared.session.getDefaultFallbackRuntimeState?.();
|
|
1753
1941
|
}
|
|
1754
|
-
|
|
1942
|
+
}
|
|
1943
|
+
if (
|
|
1944
|
+
!options.preserveDefaultModelSelection &&
|
|
1945
|
+
!options.preserveLiveModelSelection &&
|
|
1946
|
+
prepared.preparedDefaultModelSelection
|
|
1947
|
+
) {
|
|
1948
|
+
prepared.defaultModelPublished = true;
|
|
1949
|
+
if (!prepared.session.commitPreparedProfileModelSelection) {
|
|
1950
|
+
throw new Error("Session cannot commit a prepared profile model selection");
|
|
1951
|
+
}
|
|
1952
|
+
prepared.session.commitPreparedProfileModelSelection(prepared.preparedDefaultModelSelection);
|
|
1953
|
+
(prepared.session.modelRegistry ?? prepared.modelRegistry).seedCanonicalVariant?.(
|
|
1954
|
+
prepared.session.sessionId,
|
|
1955
|
+
prepared.defaultModel!,
|
|
1956
|
+
);
|
|
1957
|
+
prepared.session.recordResumeDefaultModel?.(`${prepared.defaultModel!.provider}/${prepared.defaultModel!.id}`);
|
|
1958
|
+
}
|
|
1959
|
+
prepared.settings.override("modelRoles", {
|
|
1960
|
+
...prepared.baseModelRoles,
|
|
1961
|
+
...prepared.modelRoles,
|
|
1962
|
+
});
|
|
1963
|
+
prepared.settings.override("task.agentModelOverrides", {
|
|
1964
|
+
...prepared.baseAgentModelOverrides,
|
|
1965
|
+
...prepared.agentModelOverrides,
|
|
1966
|
+
});
|
|
1967
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName);
|
|
1968
|
+
prepared.session.noteProfileInstalledOverrides?.(
|
|
1969
|
+
Object.keys(prepared.modelRoles),
|
|
1970
|
+
Object.keys(prepared.agentModelOverrides),
|
|
1971
|
+
prepared.previousModel,
|
|
1972
|
+
{ modelRoles: prepared.baseModelRoles, agentModelOverrides: prepared.baseAgentModelOverrides },
|
|
1973
|
+
{ modelRoles: prepared.modelRoles, agentModelOverrides: prepared.agentModelOverrides },
|
|
1974
|
+
{
|
|
1975
|
+
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
1976
|
+
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
1977
|
+
},
|
|
1978
|
+
);
|
|
1979
|
+
prepared.publishedState = capturePublishedModelProfileActivationState(prepared);
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
export async function finishPreparedModelProfileActivation(prepared: PreparedModelProfileActivation): Promise<void> {
|
|
1983
|
+
if (prepared.defaultModelPublished && prepared.preparedDefaultModelSelection) {
|
|
1984
|
+
try {
|
|
1985
|
+
await prepared.session.finishPreparedProfileModelSelection?.(prepared.preparedDefaultModelSelection);
|
|
1986
|
+
} catch (error) {
|
|
1987
|
+
logger.warn("Failed to refresh session tools after model profile activation", {
|
|
1988
|
+
profile: prepared.profileName,
|
|
1989
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
try {
|
|
1994
|
+
await prepared.session.syncEagerDelegation?.();
|
|
1995
|
+
} catch (error) {
|
|
1996
|
+
logger.warn("Failed to sync eager delegation after model profile activation", {
|
|
1997
|
+
profile: prepared.profileName,
|
|
1998
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
export async function applyPreparedModelProfileActivation(
|
|
2004
|
+
prepared: PreparedModelProfileActivation,
|
|
2005
|
+
options: ApplyModelProfileActivationOptions = {},
|
|
2006
|
+
): Promise<void> {
|
|
2007
|
+
let activationStage = "default chain";
|
|
2008
|
+
let modelMutationStarted = false;
|
|
2009
|
+
let overridesChanged = false;
|
|
2010
|
+
let modelRolesChanged = false;
|
|
2011
|
+
let persistentMutationStarted = false;
|
|
2012
|
+
let defaultChainChanged = false;
|
|
2013
|
+
let resumeDefaultChanged = false;
|
|
2014
|
+
let activatedDefaultChainState: ConfiguredModelChainState | undefined;
|
|
2015
|
+
let activatedFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
2016
|
+
let activatedModelRolesOverride: unknown;
|
|
2017
|
+
let activatedAgentModelOverridesOverride: unknown;
|
|
2018
|
+
let activatedProfileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
2019
|
+
let activatedResumeDefaultModel: string | undefined;
|
|
2020
|
+
|
|
2021
|
+
try {
|
|
2022
|
+
if (!options.deferRuntimePublication && !options.preserveDefaultModelSelection) {
|
|
2023
|
+
const ownedDefaultChain =
|
|
2024
|
+
prepared.defaultChain.length > 0
|
|
2025
|
+
? prepared.defaultChain
|
|
2026
|
+
: (prepared.previousDefaultChain ??
|
|
2027
|
+
(prepared.previousModel ? [formatModelString(prepared.previousModel)] : []));
|
|
2028
|
+
if (ownedDefaultChain.length > 0) {
|
|
2029
|
+
defaultChainChanged = true;
|
|
2030
|
+
prepared.session.setConfiguredModelChain(
|
|
2031
|
+
"default",
|
|
2032
|
+
ownedDefaultChain,
|
|
2033
|
+
"profile-activation",
|
|
2034
|
+
prepared.profileName,
|
|
2035
|
+
true,
|
|
2036
|
+
);
|
|
2037
|
+
if (prepared.defaultActiveIndex !== undefined) {
|
|
2038
|
+
prepared.session.seedDefaultFallbackResolution?.(
|
|
2039
|
+
prepared.defaultActiveIndex,
|
|
2040
|
+
prepared.defaultResolutionSkips,
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
activatedDefaultChainState = prepared.session.getConfiguredModelChainState?.("default");
|
|
2044
|
+
activatedFallbackRuntimeState = prepared.session.getDefaultFallbackRuntimeState?.();
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
if (
|
|
2048
|
+
!options.deferRuntimePublication &&
|
|
2049
|
+
!options.preserveDefaultModelSelection &&
|
|
2050
|
+
!options.preserveLiveModelSelection &&
|
|
2051
|
+
prepared.defaultModel
|
|
2052
|
+
) {
|
|
1755
2053
|
activationStage = "model selection";
|
|
1756
2054
|
await prepared.session.setModelTemporary(
|
|
1757
2055
|
prepared.defaultModel,
|
|
1758
2056
|
options.thinkingLevelOverride ?? prepared.defaultThinkingLevel,
|
|
1759
2057
|
{
|
|
1760
2058
|
cause: "profile-activation",
|
|
2059
|
+
signal: options.signal,
|
|
1761
2060
|
shouldMutate: options.isCurrent,
|
|
1762
2061
|
onMutationStarted: () => {
|
|
1763
2062
|
modelMutationStarted = true;
|
|
1764
2063
|
},
|
|
1765
2064
|
},
|
|
1766
2065
|
);
|
|
2066
|
+
options.signal?.throwIfAborted();
|
|
1767
2067
|
if (options.isCurrent && !modelMutationStarted) throw new ModelProfileActivationSupersededError();
|
|
1768
2068
|
if (options.isCurrent && !options.isCurrent()) throw new ModelProfileActivationSupersededError();
|
|
1769
2069
|
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
});
|
|
1787
|
-
activatedAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
1788
|
-
overridesChanged = true;
|
|
2070
|
+
if (!options.deferRuntimePublication) {
|
|
2071
|
+
activationStage = "model role overrides";
|
|
2072
|
+
prepared.settings.override("modelRoles", {
|
|
2073
|
+
...prepared.baseModelRoles,
|
|
2074
|
+
...prepared.modelRoles,
|
|
2075
|
+
});
|
|
2076
|
+
activatedModelRolesOverride = prepared.settings.getOverride("modelRoles");
|
|
2077
|
+
modelRolesChanged = true;
|
|
2078
|
+
activationStage = "agent role overrides";
|
|
2079
|
+
prepared.settings.override("task.agentModelOverrides", {
|
|
2080
|
+
...prepared.baseAgentModelOverrides,
|
|
2081
|
+
...prepared.agentModelOverrides,
|
|
2082
|
+
});
|
|
2083
|
+
activatedAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2084
|
+
overridesChanged = true;
|
|
2085
|
+
}
|
|
1789
2086
|
if (options.persistDefault) {
|
|
1790
2087
|
persistentMutationStarted = true;
|
|
1791
2088
|
activationStage = "persist model roles";
|
|
@@ -1802,28 +2099,46 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1802
2099
|
await prepared.settings.flushOrThrow();
|
|
1803
2100
|
}
|
|
1804
2101
|
if (options.isCurrent && !options.isCurrent()) throw new ModelProfileActivationSupersededError();
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
2102
|
+
if (!options.deferRuntimePublication) {
|
|
2103
|
+
activationStage = "active profile marker";
|
|
2104
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName);
|
|
2105
|
+
activationStage = "installed role tracking";
|
|
2106
|
+
prepared.session.noteProfileInstalledOverrides?.(
|
|
2107
|
+
Object.keys(prepared.modelRoles),
|
|
2108
|
+
Object.keys(prepared.agentModelOverrides),
|
|
2109
|
+
prepared.previousModel,
|
|
2110
|
+
{ modelRoles: prepared.baseModelRoles, agentModelOverrides: prepared.baseAgentModelOverrides },
|
|
2111
|
+
{ modelRoles: prepared.modelRoles, agentModelOverrides: prepared.agentModelOverrides },
|
|
2112
|
+
{
|
|
2113
|
+
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
2114
|
+
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
2115
|
+
},
|
|
2116
|
+
);
|
|
2117
|
+
activatedProfileInstalledOverrideState = prepared.session.getProfileInstalledOverrideState?.();
|
|
2118
|
+
}
|
|
2119
|
+
if (
|
|
2120
|
+
!options.deferRuntimePublication &&
|
|
2121
|
+
!options.preserveDefaultModelSelection &&
|
|
2122
|
+
!options.preserveLiveModelSelection &&
|
|
2123
|
+
prepared.defaultModel
|
|
2124
|
+
) {
|
|
1808
2125
|
activationStage = "canonical model variant";
|
|
1809
2126
|
prepared.modelRegistry.seedCanonicalVariant?.(prepared.session.sessionId, prepared.defaultModel);
|
|
1810
2127
|
resumeDefaultChanged = true;
|
|
1811
2128
|
activationStage = "resume default model";
|
|
1812
|
-
|
|
2129
|
+
activatedResumeDefaultModel = `${prepared.defaultModel.provider}/${prepared.defaultModel.id}`;
|
|
2130
|
+
prepared.session.recordResumeDefaultModel?.(activatedResumeDefaultModel);
|
|
1813
2131
|
}
|
|
1814
|
-
|
|
1815
|
-
prepared.session.noteProfileInstalledOverrides?.(
|
|
1816
|
-
Object.keys(prepared.modelRoles),
|
|
1817
|
-
Object.keys(prepared.agentModelOverrides),
|
|
1818
|
-
prepared.previousModel,
|
|
1819
|
-
);
|
|
2132
|
+
prepared.publishedState = capturePublishedModelProfileActivationState(prepared);
|
|
1820
2133
|
} catch (error) {
|
|
1821
2134
|
const activationWasCancelled = error instanceof ModelProfileActivationSupersededError;
|
|
1822
|
-
const
|
|
2135
|
+
const selectionIsCurrent = () => options.isCurrent?.() !== false;
|
|
1823
2136
|
const shouldRestoreFallbackRuntimeState =
|
|
1824
2137
|
prepared.previousDefaultFallbackRuntimeState !== undefined &&
|
|
1825
|
-
(
|
|
2138
|
+
(selectionIsCurrent() ||
|
|
1826
2139
|
sameSerializedValue(prepared.session.getDefaultFallbackRuntimeState?.(), activatedFallbackRuntimeState));
|
|
2140
|
+
let modelRollbackSelectionRevision: number | undefined;
|
|
2141
|
+
let modelRollbackSelectionWasCurrent = false;
|
|
1827
2142
|
const rollbackErrors: Array<{ stage: string; error: unknown }> = [];
|
|
1828
2143
|
const restore = (stage: string, action: () => void): void => {
|
|
1829
2144
|
try {
|
|
@@ -1834,7 +2149,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1834
2149
|
};
|
|
1835
2150
|
if (persistentMutationStarted) {
|
|
1836
2151
|
if (
|
|
1837
|
-
|
|
2152
|
+
selectionIsCurrent() ||
|
|
1838
2153
|
sameSerializedValue(prepared.settings.getGlobal("modelProfile.default"), prepared.profileName)
|
|
1839
2154
|
) {
|
|
1840
2155
|
restore("restore default profile setting", () =>
|
|
@@ -1845,7 +2160,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1845
2160
|
}
|
|
1846
2161
|
const currentPersistedModelRoles = prepared.settings.getGlobal("modelRoles");
|
|
1847
2162
|
const restoredModelRoles =
|
|
1848
|
-
|
|
2163
|
+
!selectionIsCurrent() && currentPersistedModelRoles && !sameSerializedValue(currentPersistedModelRoles, {})
|
|
1849
2164
|
? { ...(prepared.previousPersistedModelRoles ?? {}), ...currentPersistedModelRoles }
|
|
1850
2165
|
: prepared.previousPersistedModelRoles;
|
|
1851
2166
|
restore("restore model role setting", () =>
|
|
@@ -1855,7 +2170,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1855
2170
|
);
|
|
1856
2171
|
const currentPersistedAgentModelOverrides = prepared.settings.getGlobal("task.agentModelOverrides");
|
|
1857
2172
|
const restoredPersistedAgentModelOverrides =
|
|
1858
|
-
|
|
2173
|
+
!selectionIsCurrent() &&
|
|
1859
2174
|
currentPersistedAgentModelOverrides &&
|
|
1860
2175
|
!sameSerializedValue(currentPersistedAgentModelOverrides, {})
|
|
1861
2176
|
? {
|
|
@@ -1873,7 +2188,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1873
2188
|
? prepared.defaultThinkingLevel
|
|
1874
2189
|
: prepared.previousPersistedDefaultThinkingLevel;
|
|
1875
2190
|
if (
|
|
1876
|
-
|
|
2191
|
+
selectionIsCurrent() ||
|
|
1877
2192
|
sameSerializedValue(prepared.settings.getGlobal("defaultThinkingLevel"), activatedThinkingLevel)
|
|
1878
2193
|
) {
|
|
1879
2194
|
restore("restore thinking level setting", () =>
|
|
@@ -1885,7 +2200,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1885
2200
|
}
|
|
1886
2201
|
if (
|
|
1887
2202
|
modelRolesChanged &&
|
|
1888
|
-
(
|
|
2203
|
+
(selectionIsCurrent() ||
|
|
1889
2204
|
sameSerializedValue(prepared.settings.getOverride("modelRoles"), activatedModelRolesOverride))
|
|
1890
2205
|
) {
|
|
1891
2206
|
restore("restore model role overrides", () =>
|
|
@@ -1896,7 +2211,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1896
2211
|
}
|
|
1897
2212
|
if (
|
|
1898
2213
|
overridesChanged &&
|
|
1899
|
-
(
|
|
2214
|
+
(selectionIsCurrent() ||
|
|
1900
2215
|
sameSerializedValue(
|
|
1901
2216
|
prepared.settings.getOverride("task.agentModelOverrides"),
|
|
1902
2217
|
activatedAgentModelOverridesOverride,
|
|
@@ -1908,7 +2223,9 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1908
2223
|
: prepared.settings.override("task.agentModelOverrides", prepared.previousAgentModelOverridesOverride),
|
|
1909
2224
|
);
|
|
1910
2225
|
}
|
|
1911
|
-
if (modelMutationStarted &&
|
|
2226
|
+
if (modelMutationStarted && selectionIsCurrent()) {
|
|
2227
|
+
modelRollbackSelectionWasCurrent = selectionIsCurrent();
|
|
2228
|
+
modelRollbackSelectionRevision = prepared.session.getUserModelSelectionRevision?.();
|
|
1912
2229
|
try {
|
|
1913
2230
|
if (prepared.session.restoreModelSelectionForRollback) {
|
|
1914
2231
|
await prepared.session.restoreModelSelectionForRollback(
|
|
@@ -1918,6 +2235,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1918
2235
|
} else if (prepared.previousModel) {
|
|
1919
2236
|
await prepared.session.setModelTemporary(prepared.previousModel, prepared.previousThinkingLevel, {
|
|
1920
2237
|
cause: "rollback",
|
|
2238
|
+
shouldMutate: selectionIsCurrent,
|
|
1921
2239
|
});
|
|
1922
2240
|
} else {
|
|
1923
2241
|
throw new Error("Model-less profile activation rollback is unavailable");
|
|
@@ -1926,14 +2244,18 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1926
2244
|
rollbackErrors.push({ stage: "restore live model", error: rollbackError });
|
|
1927
2245
|
}
|
|
1928
2246
|
}
|
|
1929
|
-
if (
|
|
2247
|
+
if (
|
|
2248
|
+
resumeDefaultChanged &&
|
|
2249
|
+
selectionIsCurrent() &&
|
|
2250
|
+
sameSerializedValue(prepared.session.getSessionDefaultModelSelector?.(), activatedResumeDefaultModel)
|
|
2251
|
+
) {
|
|
1930
2252
|
restore("restore resume default", () =>
|
|
1931
2253
|
prepared.session.recordResumeDefaultModel?.(prepared.previousSessionDefaultModel),
|
|
1932
2254
|
);
|
|
1933
2255
|
}
|
|
1934
2256
|
if (
|
|
1935
2257
|
defaultChainChanged &&
|
|
1936
|
-
(
|
|
2258
|
+
(selectionIsCurrent() ||
|
|
1937
2259
|
sameSerializedValue(prepared.session.getConfiguredModelChainState?.("default"), activatedDefaultChainState))
|
|
1938
2260
|
) {
|
|
1939
2261
|
const previousChain = prepared.previousDefaultChainState;
|
|
@@ -1949,16 +2271,33 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1949
2271
|
),
|
|
1950
2272
|
);
|
|
1951
2273
|
}
|
|
1952
|
-
|
|
2274
|
+
const userSelectionChangedDuringModelRollback =
|
|
2275
|
+
modelRollbackSelectionRevision !== undefined
|
|
2276
|
+
? prepared.session.getUserModelSelectionRevision?.() !== modelRollbackSelectionRevision
|
|
2277
|
+
: modelRollbackSelectionWasCurrent && !selectionIsCurrent();
|
|
2278
|
+
if (shouldRestoreFallbackRuntimeState && !userSelectionChangedDuringModelRollback) {
|
|
1953
2279
|
restore("restore fallback runtime", () =>
|
|
1954
2280
|
prepared.session.restoreDefaultFallbackRuntimeState?.(prepared.previousDefaultFallbackRuntimeState!),
|
|
1955
2281
|
);
|
|
1956
2282
|
}
|
|
1957
|
-
if (
|
|
2283
|
+
if (selectionIsCurrent()) {
|
|
1958
2284
|
restore("restore active profile", () =>
|
|
1959
2285
|
prepared.session.setActiveModelProfile?.(prepared.previousActiveModelProfile),
|
|
1960
2286
|
);
|
|
1961
2287
|
}
|
|
2288
|
+
if (
|
|
2289
|
+
prepared.previousProfileInstalledOverrideState &&
|
|
2290
|
+
(selectionIsCurrent() ||
|
|
2291
|
+
(activatedProfileInstalledOverrideState !== undefined &&
|
|
2292
|
+
util.isDeepStrictEqual(
|
|
2293
|
+
prepared.session.getProfileInstalledOverrideState?.(),
|
|
2294
|
+
activatedProfileInstalledOverrideState,
|
|
2295
|
+
)))
|
|
2296
|
+
) {
|
|
2297
|
+
restore("restore installed role tracking", () =>
|
|
2298
|
+
prepared.session.restoreProfileInstalledOverrideState?.(prepared.previousProfileInstalledOverrideState!),
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
1962
2301
|
restore("restore canonical model variant", () =>
|
|
1963
2302
|
restoreCanonicalVariantAfterPreparation(
|
|
1964
2303
|
prepared.modelRegistry,
|
|
@@ -1980,17 +2319,254 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1980
2319
|
if (activationWasCancelled) return;
|
|
1981
2320
|
throw error;
|
|
1982
2321
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2322
|
+
if (!options.deferRuntimePublication) await finishPreparedModelProfileActivation(prepared);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
/** Restore an applied activation when its enclosing settings/registry commit fails. */
|
|
2326
|
+
export async function rollbackPreparedModelProfileActivation(
|
|
2327
|
+
prepared: PreparedModelProfileActivation,
|
|
2328
|
+
options: ApplyModelProfileActivationOptions = {},
|
|
2329
|
+
): Promise<void> {
|
|
2330
|
+
const failures: Array<{ stage: string; error: unknown }> = [];
|
|
2331
|
+
const restore = (stage: string, action: () => void): void => {
|
|
2332
|
+
try {
|
|
2333
|
+
action();
|
|
2334
|
+
} catch (error) {
|
|
2335
|
+
failures.push({ stage, error });
|
|
2336
|
+
}
|
|
2337
|
+
};
|
|
2338
|
+
const restoreAsync = async (stage: string, action: () => Promise<void>): Promise<void> => {
|
|
2339
|
+
try {
|
|
2340
|
+
await action();
|
|
2341
|
+
} catch (error) {
|
|
2342
|
+
failures.push({ stage, error });
|
|
2343
|
+
}
|
|
2344
|
+
};
|
|
2345
|
+
const selectionIsCurrent = () => options.isCurrent?.() !== false;
|
|
2346
|
+
const publishedState = prepared.publishedState;
|
|
2347
|
+
const canRestorePublishedState = (current: unknown, activated: unknown): boolean =>
|
|
2348
|
+
publishedState === undefined ? selectionIsCurrent() : util.isDeepStrictEqual(current, activated);
|
|
2349
|
+
const canRollbackPublishedProfile = (): boolean =>
|
|
2350
|
+
publishedState === undefined
|
|
2351
|
+
? selectionIsCurrent()
|
|
2352
|
+
: util.isDeepStrictEqual(prepared.session.getActiveModelProfile?.(), publishedState.activeModelProfile);
|
|
2353
|
+
|
|
2354
|
+
if (options.persistDefault) {
|
|
2355
|
+
if (
|
|
2356
|
+
canRestorePublishedState(
|
|
2357
|
+
prepared.settings.getGlobal("modelProfile.default"),
|
|
2358
|
+
publishedState?.persistedDefaultProfile,
|
|
2359
|
+
)
|
|
2360
|
+
) {
|
|
2361
|
+
restore("restore persisted default profile", () =>
|
|
2362
|
+
prepared.previousPersistedDefaultProfile === undefined
|
|
2363
|
+
? prepared.settings.unset("modelProfile.default")
|
|
2364
|
+
: prepared.settings.set("modelProfile.default", prepared.previousPersistedDefaultProfile),
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
const currentPersistedModelRoles = prepared.settings.getGlobal("modelRoles");
|
|
2368
|
+
const restoredPersistedModelRoles =
|
|
2369
|
+
publishedState && canRollbackPublishedProfile()
|
|
2370
|
+
? restoreConcurrentProfileOverrides(
|
|
2371
|
+
prepared.previousPersistedModelRoles,
|
|
2372
|
+
publishedState.persistedModelRoles,
|
|
2373
|
+
currentPersistedModelRoles,
|
|
2374
|
+
)
|
|
2375
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2376
|
+
? prepared.previousPersistedModelRoles
|
|
2377
|
+
: currentPersistedModelRoles;
|
|
2378
|
+
if (!util.isDeepStrictEqual(restoredPersistedModelRoles, currentPersistedModelRoles)) {
|
|
2379
|
+
restore("restore persisted model roles", () =>
|
|
2380
|
+
restoredPersistedModelRoles === undefined
|
|
2381
|
+
? prepared.settings.unset("modelRoles")
|
|
2382
|
+
: prepared.settings.set("modelRoles", restoredPersistedModelRoles),
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
const currentPersistedAgentOverrides = prepared.settings.getGlobal("task.agentModelOverrides");
|
|
2386
|
+
const restoredPersistedAgentOverrides =
|
|
2387
|
+
publishedState && canRollbackPublishedProfile()
|
|
2388
|
+
? restoreConcurrentProfileOverrides(
|
|
2389
|
+
prepared.previousPersistedAgentModelOverrides,
|
|
2390
|
+
publishedState.persistedAgentModelOverrides,
|
|
2391
|
+
currentPersistedAgentOverrides,
|
|
2392
|
+
)
|
|
2393
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2394
|
+
? prepared.previousPersistedAgentModelOverrides
|
|
2395
|
+
: currentPersistedAgentOverrides;
|
|
2396
|
+
if (!util.isDeepStrictEqual(restoredPersistedAgentOverrides, currentPersistedAgentOverrides)) {
|
|
2397
|
+
restore("restore persisted agent overrides", () =>
|
|
2398
|
+
restoredPersistedAgentOverrides === undefined
|
|
2399
|
+
? prepared.settings.unset("task.agentModelOverrides")
|
|
2400
|
+
: prepared.settings.set("task.agentModelOverrides", restoredPersistedAgentOverrides),
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
if (
|
|
2404
|
+
canRestorePublishedState(
|
|
2405
|
+
prepared.settings.getGlobal("defaultThinkingLevel"),
|
|
2406
|
+
publishedState?.persistedDefaultThinkingLevel,
|
|
2407
|
+
)
|
|
2408
|
+
) {
|
|
2409
|
+
restore("restore persisted thinking level", () =>
|
|
2410
|
+
prepared.previousPersistedDefaultThinkingLevel === undefined
|
|
2411
|
+
? prepared.settings.unset("defaultThinkingLevel")
|
|
2412
|
+
: prepared.settings.set("defaultThinkingLevel", prepared.previousPersistedDefaultThinkingLevel),
|
|
2413
|
+
);
|
|
2414
|
+
}
|
|
2415
|
+
if (
|
|
2416
|
+
canRestorePublishedState(
|
|
2417
|
+
prepared.settings.getOverride("defaultThinkingLevel"),
|
|
2418
|
+
publishedState?.defaultThinkingLevelOverride,
|
|
2419
|
+
)
|
|
2420
|
+
) {
|
|
2421
|
+
restore("restore thinking level override", () =>
|
|
2422
|
+
prepared.previousDefaultThinkingLevelOverride === undefined
|
|
2423
|
+
? prepared.settings.clearOverride("defaultThinkingLevel")
|
|
2424
|
+
: prepared.settings.override("defaultThinkingLevel", prepared.previousDefaultThinkingLevelOverride),
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
const currentModelRolesOverride = prepared.settings.getOverride("modelRoles");
|
|
2429
|
+
const restoredModelRolesOverride =
|
|
2430
|
+
publishedState && canRollbackPublishedProfile()
|
|
2431
|
+
? restoreConcurrentProfileOverrides(
|
|
2432
|
+
prepared.previousModelRolesOverride,
|
|
2433
|
+
publishedState.modelRolesOverride,
|
|
2434
|
+
currentModelRolesOverride,
|
|
2435
|
+
)
|
|
2436
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2437
|
+
? prepared.previousModelRolesOverride
|
|
2438
|
+
: currentModelRolesOverride;
|
|
2439
|
+
if (!util.isDeepStrictEqual(restoredModelRolesOverride, currentModelRolesOverride)) {
|
|
2440
|
+
restore("restore model role overrides", () =>
|
|
2441
|
+
restoredModelRolesOverride === undefined
|
|
2442
|
+
? prepared.settings.clearOverride("modelRoles")
|
|
2443
|
+
: prepared.settings.override("modelRoles", restoredModelRolesOverride),
|
|
2444
|
+
);
|
|
2445
|
+
}
|
|
2446
|
+
const currentAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2447
|
+
const restoredAgentModelOverridesOverride =
|
|
2448
|
+
publishedState && canRollbackPublishedProfile()
|
|
2449
|
+
? restoreConcurrentProfileOverrides(
|
|
2450
|
+
prepared.previousAgentModelOverridesOverride,
|
|
2451
|
+
publishedState.agentModelOverridesOverride,
|
|
2452
|
+
currentAgentModelOverridesOverride,
|
|
2453
|
+
)
|
|
2454
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2455
|
+
? prepared.previousAgentModelOverridesOverride
|
|
2456
|
+
: currentAgentModelOverridesOverride;
|
|
2457
|
+
if (!util.isDeepStrictEqual(restoredAgentModelOverridesOverride, currentAgentModelOverridesOverride)) {
|
|
2458
|
+
restore("restore agent role overrides", () =>
|
|
2459
|
+
restoredAgentModelOverridesOverride === undefined
|
|
2460
|
+
? prepared.settings.clearOverride("task.agentModelOverrides")
|
|
2461
|
+
: prepared.settings.override("task.agentModelOverrides", restoredAgentModelOverridesOverride),
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2464
|
+
if (!options.preserveDefaultModelSelection) {
|
|
2465
|
+
const previousChain = prepared.previousDefaultChainState;
|
|
2466
|
+
if (
|
|
2467
|
+
prepared.defaultChainPublished &&
|
|
2468
|
+
canRollbackPublishedProfile() &&
|
|
2469
|
+
canRestorePublishedState(
|
|
2470
|
+
prepared.session.getConfiguredModelChainState?.("default"),
|
|
2471
|
+
publishedState?.defaultChainState,
|
|
2472
|
+
)
|
|
2473
|
+
) {
|
|
2474
|
+
restore("restore default chain", () =>
|
|
2475
|
+
prepared.session.setConfiguredModelChain(
|
|
2476
|
+
"default",
|
|
2477
|
+
previousChain?.entries ??
|
|
2478
|
+
prepared.previousDefaultChain ??
|
|
2479
|
+
(prepared.previousModel ? [`${prepared.previousModel.provider}/${prepared.previousModel.id}`] : []),
|
|
2480
|
+
previousChain?.origin ?? "rollback",
|
|
2481
|
+
previousChain?.identity,
|
|
2482
|
+
previousChain?.explicitHead ?? true,
|
|
2483
|
+
),
|
|
2484
|
+
);
|
|
2485
|
+
}
|
|
2486
|
+
if (
|
|
2487
|
+
!options.preserveLiveModelSelection &&
|
|
2488
|
+
selectionIsCurrent() &&
|
|
2489
|
+
prepared.defaultModelPublished &&
|
|
2490
|
+
prepared.defaultModel
|
|
2491
|
+
) {
|
|
2492
|
+
await restoreAsync("restore live model", async () => {
|
|
2493
|
+
if (prepared.session.restoreModelSelectionForRollback) {
|
|
2494
|
+
await prepared.session.restoreModelSelectionForRollback(
|
|
2495
|
+
prepared.previousModel,
|
|
2496
|
+
prepared.previousThinkingLevel,
|
|
2497
|
+
);
|
|
2498
|
+
} else if (prepared.previousModel) {
|
|
2499
|
+
await prepared.session.setModelTemporary(prepared.previousModel, prepared.previousThinkingLevel, {
|
|
2500
|
+
cause: "rollback",
|
|
2501
|
+
shouldMutate: selectionIsCurrent,
|
|
2502
|
+
});
|
|
2503
|
+
} else {
|
|
2504
|
+
throw new Error("Model-less profile activation rollback is unavailable");
|
|
2505
|
+
}
|
|
2506
|
+
});
|
|
2507
|
+
if (
|
|
2508
|
+
selectionIsCurrent() &&
|
|
2509
|
+
canRestorePublishedState(
|
|
2510
|
+
prepared.session.getSessionDefaultModelSelector?.(),
|
|
2511
|
+
publishedState?.sessionDefaultModel,
|
|
2512
|
+
)
|
|
2513
|
+
) {
|
|
2514
|
+
restore("restore session resume default", () =>
|
|
2515
|
+
prepared.session.recordResumeDefaultModel?.(prepared.previousSessionDefaultModel),
|
|
2516
|
+
);
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
if (
|
|
2520
|
+
(prepared.defaultChainPublished || prepared.defaultModelPublished) &&
|
|
2521
|
+
prepared.previousDefaultFallbackRuntimeState &&
|
|
2522
|
+
canRollbackPublishedProfile() &&
|
|
2523
|
+
canRestorePublishedState(
|
|
2524
|
+
prepared.session.getDefaultFallbackRuntimeState?.(),
|
|
2525
|
+
publishedState?.defaultFallbackRuntimeState,
|
|
2526
|
+
)
|
|
2527
|
+
) {
|
|
2528
|
+
restore("restore fallback runtime", () =>
|
|
2529
|
+
prepared.session.restoreDefaultFallbackRuntimeState?.(prepared.previousDefaultFallbackRuntimeState!),
|
|
2530
|
+
);
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
if (
|
|
2534
|
+
selectionIsCurrent() &&
|
|
2535
|
+
canRollbackPublishedProfile() &&
|
|
2536
|
+
canRestorePublishedState(prepared.session.getActiveModelProfile?.(), publishedState?.activeModelProfile)
|
|
2537
|
+
) {
|
|
2538
|
+
restore("restore active profile", () =>
|
|
2539
|
+
prepared.session.setActiveModelProfile?.(prepared.previousActiveModelProfile),
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
if (
|
|
2543
|
+
prepared.previousProfileInstalledOverrideState &&
|
|
2544
|
+
canRollbackPublishedProfile() &&
|
|
2545
|
+
canRestorePublishedState(
|
|
2546
|
+
prepared.session.getProfileInstalledOverrideState?.(),
|
|
2547
|
+
publishedState?.profileInstalledOverrideState,
|
|
2548
|
+
)
|
|
2549
|
+
) {
|
|
2550
|
+
restore("restore installed role tracking", () =>
|
|
2551
|
+
prepared.session.restoreProfileInstalledOverrideState?.(prepared.previousProfileInstalledOverrideState!),
|
|
2552
|
+
);
|
|
2553
|
+
}
|
|
2554
|
+
restore("restore canonical model variant", () =>
|
|
2555
|
+
restoreCanonicalVariantAfterPreparation(
|
|
2556
|
+
prepared.session.modelRegistry ?? prepared.modelRegistry,
|
|
2557
|
+
prepared.session,
|
|
2558
|
+
prepared.previousCanonicalVariant,
|
|
2559
|
+
prepared.previousUserCanonicalVariantSelection,
|
|
2560
|
+
),
|
|
2561
|
+
);
|
|
2562
|
+
if (options.persistDefault) {
|
|
2563
|
+
await restoreAsync("restore persisted settings", () => prepared.settings.flushOrThrow());
|
|
2564
|
+
}
|
|
2565
|
+
if (failures.length > 0) {
|
|
2566
|
+
throw new AggregateError(
|
|
2567
|
+
failures.map(failure => failure.error),
|
|
2568
|
+
`Failed to fully roll back model profile activation: ${failures.map(failure => failure.stage).join(", ")}`,
|
|
2569
|
+
);
|
|
1994
2570
|
}
|
|
1995
2571
|
}
|
|
1996
2572
|
|
|
@@ -2009,6 +2585,7 @@ export interface MaterializeModelProfileForDeletionResult {
|
|
|
2009
2585
|
previousActiveModelProfile: string | undefined;
|
|
2010
2586
|
previousDefaultChainState: ConfiguredModelChainState | undefined;
|
|
2011
2587
|
previousDefaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
2588
|
+
previousProfileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
2012
2589
|
/**
|
|
2013
2590
|
* Restores the session sticky canonical variant that was snapshotted before
|
|
2014
2591
|
* materialization cleared it. Internal closure capturing the registry,
|
|
@@ -2138,6 +2715,11 @@ export async function materializeModelProfileForDeletion(
|
|
|
2138
2715
|
: prepared.settings.override("modelProfile.default", prepared.previousDefaultProfileOverride),
|
|
2139
2716
|
);
|
|
2140
2717
|
restore(() => prepared.session.setActiveModelProfile?.(prepared.previousActiveModelProfile));
|
|
2718
|
+
if (prepared.previousProfileInstalledOverrideState) {
|
|
2719
|
+
restore(() =>
|
|
2720
|
+
prepared.session.restoreProfileInstalledOverrideState?.(prepared.previousProfileInstalledOverrideState!),
|
|
2721
|
+
);
|
|
2722
|
+
}
|
|
2141
2723
|
try {
|
|
2142
2724
|
await prepared.settings.flushOrThrow();
|
|
2143
2725
|
} catch (rollbackError) {
|
|
@@ -2167,6 +2749,7 @@ export async function materializeModelProfileForDeletion(
|
|
|
2167
2749
|
previousActiveModelProfile: prepared.previousActiveModelProfile,
|
|
2168
2750
|
previousDefaultChainState: prepared.previousDefaultChainState,
|
|
2169
2751
|
previousDefaultFallbackRuntimeState: prepared.previousDefaultFallbackRuntimeState,
|
|
2752
|
+
previousProfileInstalledOverrideState: prepared.previousProfileInstalledOverrideState,
|
|
2170
2753
|
restoreSessionCanonicalVariant: () =>
|
|
2171
2754
|
restoreCanonicalVariant(prepared.modelRegistry, prepared.session.sessionId, prepared.previousCanonicalVariant),
|
|
2172
2755
|
};
|
|
@@ -2176,7 +2759,10 @@ export async function restoreMaterializedModelProfileForDeletion(options: {
|
|
|
2176
2759
|
settings: Pick<Settings, "clearOverride" | "flushOrThrow" | "override" | "set" | "unset">;
|
|
2177
2760
|
session: Pick<
|
|
2178
2761
|
ModelProfileActivationSession,
|
|
2179
|
-
|
|
2762
|
+
| "setActiveModelProfile"
|
|
2763
|
+
| "setConfiguredModelChain"
|
|
2764
|
+
| "restoreDefaultFallbackRuntimeState"
|
|
2765
|
+
| "restoreProfileInstalledOverrideState"
|
|
2180
2766
|
>;
|
|
2181
2767
|
snapshot: MaterializeModelProfileForDeletionResult;
|
|
2182
2768
|
}): Promise<void> {
|
|
@@ -2231,6 +2817,13 @@ export async function restoreMaterializedModelProfileForDeletion(options: {
|
|
|
2231
2817
|
: options.settings.override("modelProfile.default", options.snapshot.previousDefaultProfileOverride),
|
|
2232
2818
|
);
|
|
2233
2819
|
restore(() => options.session.setActiveModelProfile?.(options.snapshot.previousActiveModelProfile));
|
|
2820
|
+
if (options.snapshot.previousProfileInstalledOverrideState) {
|
|
2821
|
+
restore(() =>
|
|
2822
|
+
options.session.restoreProfileInstalledOverrideState?.(
|
|
2823
|
+
options.snapshot.previousProfileInstalledOverrideState!,
|
|
2824
|
+
),
|
|
2825
|
+
);
|
|
2826
|
+
}
|
|
2234
2827
|
try {
|
|
2235
2828
|
await options.settings.flushOrThrow();
|
|
2236
2829
|
} catch (error) {
|
|
@@ -2270,6 +2863,7 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2270
2863
|
const previousModelRolesOverride = prepared.settings.getOverride("modelRoles");
|
|
2271
2864
|
const previousAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2272
2865
|
const previousActiveModelProfile = prepared.session.getActiveModelProfile?.();
|
|
2866
|
+
const previousProfileInstalledOverrideState = prepared.session.getProfileInstalledOverrideState?.();
|
|
2273
2867
|
let activatedModelRolesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
2274
2868
|
let activatedAgentModelOverridesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
2275
2869
|
try {
|
|
@@ -2312,6 +2906,9 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2312
2906
|
if (prepared.session.getActiveModelProfile?.() === prepared.profileName) {
|
|
2313
2907
|
prepared.session.setActiveModelProfile?.(previousActiveModelProfile);
|
|
2314
2908
|
}
|
|
2909
|
+
if (previousProfileInstalledOverrideState) {
|
|
2910
|
+
prepared.session.restoreProfileInstalledOverrideState?.(previousProfileInstalledOverrideState);
|
|
2911
|
+
}
|
|
2315
2912
|
try {
|
|
2316
2913
|
await prepared.session.syncEagerDelegation?.();
|
|
2317
2914
|
} catch (error) {
|
|
@@ -2326,6 +2923,12 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2326
2923
|
Object.keys(prepared.modelRoles),
|
|
2327
2924
|
Object.keys(prepared.agentModelOverrides),
|
|
2328
2925
|
prepared.previousModel,
|
|
2926
|
+
{ modelRoles: prepared.baseModelRoles, agentModelOverrides: prepared.baseAgentModelOverrides },
|
|
2927
|
+
{ modelRoles: prepared.modelRoles, agentModelOverrides: prepared.agentModelOverrides },
|
|
2928
|
+
{
|
|
2929
|
+
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
2930
|
+
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
2931
|
+
},
|
|
2329
2932
|
);
|
|
2330
2933
|
} finally {
|
|
2331
2934
|
if (isCurrent && !isCurrent()) {
|