@gajae-code/coding-agent 0.18.11 → 0.19.0
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 +760 -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/capability/rule.d.ts +7 -2
- package/dist/types/cli/accounts-cli.d.ts +2 -2
- package/dist/types/cli/append-system-prompt.d.ts +6 -0
- package/dist/types/cli/args.d.ts +7 -2
- package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
- package/dist/types/cli/customize-doctor.d.ts +4 -3
- 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 +2 -0
- package/dist/types/cli/root-flags.d.ts +0 -12
- package/dist/types/cli/update-cli.d.ts +21 -3
- package/dist/types/cli-main.d.ts +0 -6
- package/dist/types/cli-ordinary.d.ts +2 -2
- package/dist/types/commands/accounts.d.ts +2 -1
- package/dist/types/commands/launch.d.ts +0 -6
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +13 -0
- package/dist/types/commit/changelog/index.d.ts +1 -0
- package/dist/types/commit/map-reduce/index.d.ts +4 -4
- package/dist/types/config/autorouting-tier-map.d.ts +53 -1
- package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
- package/dist/types/config/config-hot-reload.d.ts +44 -0
- package/dist/types/config/file-lock.d.ts +52 -3
- package/dist/types/config/model-discovery-manager.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +79 -9
- package/dist/types/config/model-registry.d.ts +72 -8
- package/dist/types/config/model-resolver.d.ts +7 -4
- package/dist/types/config/models-config-schema.d.ts +10 -0
- package/dist/types/config/settings-schema.d.ts +57 -4
- package/dist/types/config/settings.d.ts +33 -1
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/customization/import.d.ts +2 -0
- package/dist/types/customization/types.d.ts +1 -1
- package/dist/types/dap/config.d.ts +8 -4
- package/dist/types/dap/session.d.ts +11 -2
- package/dist/types/debug/system-info.d.ts +6 -1
- package/dist/types/discovery/helpers.d.ts +7 -2
- package/dist/types/discovery/mcp-compat.d.ts +3 -1
- package/dist/types/edit/index.d.ts +5 -0
- package/dist/types/edit/modes/patch.d.ts +14 -0
- package/dist/types/edit/modes/replace.d.ts +3 -0
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +12 -0
- package/dist/types/export/ttsr.d.ts +19 -0
- package/dist/types/extensibility/extensions/types.d.ts +5 -1
- package/dist/types/extensibility/slash-commands.d.ts +1 -0
- package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -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/gjc-runtime/tmux-sessions.d.ts +24 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/content.d.ts +5 -6
- package/dist/types/internal-urls/types.d.ts +2 -0
- package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
- package/dist/types/main.d.ts +23 -18
- package/dist/types/migrate/action-planner.d.ts +10 -1
- package/dist/types/migrate/adapters/codex.d.ts +2 -1
- package/dist/types/migrate/adapters/index.d.ts +42 -1
- package/dist/types/migrate/executor.d.ts +3 -1
- package/dist/types/migrate/hook-module.d.ts +23 -0
- package/dist/types/migrate/report.d.ts +2 -1
- package/dist/types/migrate/types.d.ts +82 -3
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +43 -0
- 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/prompt-suggestion-controller.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/modes/utils/host-status.d.ts +15 -11
- 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/project-host-values.d.ts +11 -5
- package/dist/types/runtime-mcp/tool-bridge.d.ts +4 -0
- package/dist/types/sdk/broker/broker-exit.d.ts +3 -3
- package/dist/types/sdk/broker/broker.d.ts +29 -2
- 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 +141 -9
- package/dist/types/sdk/broker/hop.d.ts +45 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
- package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
- package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
- package/dist/types/sdk/broker/session-index.d.ts +6 -1
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
- package/dist/types/sdk/bus/index.d.ts +44 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
- package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
- package/dist/types/sdk/cli/session-cli.d.ts +0 -1
- package/dist/types/sdk/host/control/operations.d.ts +5 -1
- package/dist/types/sdk/host/events.d.ts +4 -0
- package/dist/types/sdk/host/host.d.ts +2 -1
- package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
- package/dist/types/sdk/host/session-runtime.d.ts +40 -8
- package/dist/types/sdk/host/surface-policy.d.ts +2 -1
- package/dist/types/sdk/lifecycle/service.d.ts +12 -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/prompt-status.d.ts +11 -4
- 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 +107 -9
- 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 +29 -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 +20 -4
- package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
- package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
- package/dist/types/ssh/ssh-executor.d.ts +8 -1
- package/dist/types/system-prompt.d.ts +3 -2
- package/dist/types/task/executor.d.ts +19 -2
- package/dist/types/task/role-body.d.ts +11 -0
- 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/awaiting-input.d.ts +28 -0
- package/dist/types/tools/bash-allowed-prefixes.d.ts +17 -0
- package/dist/types/tools/bash-skill-urls.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +7 -0
- package/dist/types/tools/descriptors.d.ts +15 -2
- package/dist/types/tools/fetch.d.ts +7 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/irc.d.ts +5 -3
- 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/tools/tmux-self-injection-guard.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/utils/file-mentions.d.ts +5 -0
- package/dist/types/utils/image-limits.d.ts +7 -0
- package/dist/types/utils/image-loading.d.ts +0 -1
- package/dist/types/utils/open.d.ts +0 -1
- package/dist/types/utils/pasted-image-loading.d.ts +1 -5
- package/dist/types/utils/prompt-suggestion.d.ts +2 -2
- package/dist/types/utils/shell-snapshot.d.ts +2 -0
- package/dist/types/utils/title-generator.d.ts +13 -3
- package/dist/types/web/scrapers/types.d.ts +8 -1
- package/dist/types/web/search/providers/codex.d.ts +6 -7
- 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 +10 -9
- package/scripts/acp-conformance-agent.ts +12 -2
- 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 +38 -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 +58 -22
- package/src/capability/index.ts +2 -2
- package/src/capability/rule.ts +11 -2
- package/src/cli/accounts-cli.ts +176 -8
- package/src/cli/append-system-prompt.ts +12 -0
- package/src/cli/args.ts +11 -7
- package/src/cli/auth-broker-cli.ts +21 -11
- package/src/cli/customize-doctor-precedence.ts +31 -0
- package/src/cli/customize-doctor.ts +49 -39
- package/src/cli/doctor/install-repairs.ts +35 -5
- package/src/cli/fast-help.ts +1 -3
- package/src/cli/install-activation.ts +47 -4
- package/src/cli/migrate-cli.ts +19 -6
- package/src/cli/public-command-errors.ts +6 -0
- package/src/cli/root-flags.ts +2 -4
- package/src/cli/stats-cli.ts +9 -5
- package/src/cli/update-cli.ts +471 -13
- package/src/cli-ordinary.ts +7 -2
- package/src/commands/accounts.ts +10 -5
- package/src/commands/harness.ts +25 -15
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +277 -50
- package/src/commands/ultragoal.ts +16 -8
- package/src/commit/agentic/agent.ts +6 -6
- package/src/commit/analysis/conventional.ts +14 -5
- package/src/commit/changelog/index.ts +39 -1
- package/src/commit/map-reduce/index.ts +7 -7
- package/src/commit/message.ts +10 -3
- package/src/commit/pipeline.ts +12 -12
- package/src/config/autorouting-tier-map.ts +50 -1
- package/src/config/config-file.ts +106 -3
- package/src/config/config-hot-reload-trust.ts +148 -0
- package/src/config/config-hot-reload.ts +742 -0
- package/src/config/file-lock.ts +1615 -328
- package/src/config/keybindings.ts +154 -7
- 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 +889 -148
- package/src/config/model-registry.ts +1706 -205
- package/src/config/model-resolver.ts +52 -22
- package/src/config/models-config-schema.ts +6 -0
- package/src/config/settings-schema.ts +73 -4
- package/src/config/settings.ts +460 -24
- package/src/coordinator-mcp/policy.ts +26 -1
- package/src/coordinator-mcp/server.ts +37 -2
- package/src/crash/sanitize.ts +7 -1
- package/src/customization/import.ts +279 -8
- package/src/customization/inventory.ts +24 -8
- package/src/customization/types.ts +1 -0
- package/src/dap/client.ts +3 -2
- package/src/dap/config.ts +31 -11
- package/src/dap/defaults.json +1 -1
- package/src/dap/session.ts +161 -36
- package/src/debug/crash-diagnostics.ts +89 -6
- package/src/debug/report-bundle.ts +90 -2
- 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/builtin.ts +4 -3
- package/src/discovery/helpers.ts +25 -16
- package/src/discovery/mcp-compat.ts +120 -17
- package/src/edit/apply-patch/index.ts +12 -1
- package/src/edit/index.ts +204 -22
- package/src/edit/modes/patch.ts +214 -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/eval/py/runtime.ts +44 -4
- 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/exec/non-interactive-env.ts +0 -1
- package/src/export/html/index.ts +86 -6
- package/src/export/ttsr.ts +176 -1
- package/src/extensibility/custom-tools/wrapper.ts +3 -1
- package/src/extensibility/extensions/loader.ts +10 -1
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
- package/src/extensibility/extensions/types.ts +5 -1
- package/src/extensibility/hooks/loader.ts +10 -2
- package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
- package/src/extensibility/plugins/marketplace/manager.ts +36 -10
- package/src/extensibility/slash-commands.ts +5 -0
- package/src/gjc-runtime/gc-runtime.ts +37 -7
- package/src/gjc-runtime/launch-tmux.ts +30 -15
- 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/ralplan-current-final.ts +294 -0
- package/src/gjc-runtime/ralplan-runtime.ts +95 -1
- 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/gjc-runtime/state-writer.ts +109 -5
- package/src/gjc-runtime/tmux-sessions.ts +93 -13
- package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
- package/src/gjc-runtime/ultragoal-guard.ts +9 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
- package/src/harness-control-plane/finalize.ts +11 -0
- package/src/harness-control-plane/receipt-spool.ts +105 -28
- package/src/harness-control-plane/storage.ts +124 -6
- package/src/hindsight/content.ts +116 -16
- package/src/hindsight/mental-models.ts +22 -10
- package/src/hindsight/state.ts +7 -4
- package/src/hooks/native-skill-hook.ts +17 -12
- package/src/internal-urls/artifact-protocol.ts +3 -1
- package/src/internal-urls/docs-index.generated.ts +23 -22
- package/src/internal-urls/local-protocol.ts +167 -8
- package/src/internal-urls/types.ts +2 -0
- package/src/lsp/client.ts +2 -1
- package/src/lsp/clients/biome-client.ts +2 -0
- package/src/lsp/clients/swiftlint-client.ts +2 -0
- package/src/lsp/index.ts +29 -0
- package/src/lsp/workspace-path.ts +23 -0
- package/src/main.ts +330 -92
- package/src/memories/index.ts +25 -2
- package/src/migrate/action-planner.ts +574 -2
- package/src/migrate/adapters/claude-code.ts +162 -5
- package/src/migrate/adapters/codex.ts +77 -7
- package/src/migrate/adapters/index.ts +258 -5
- package/src/migrate/adapters/opencode.ts +10 -1
- package/src/migrate/executor.ts +222 -7
- package/src/migrate/hook-module.ts +193 -0
- package/src/migrate/report.ts +63 -2
- package/src/migrate/types.ts +84 -4
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/acp-agent.ts +10 -1
- package/src/modes/acp/permission-mode.ts +18 -1
- package/src/modes/components/agent-dashboard.ts +20 -4
- package/src/modes/components/assistant-message.ts +55 -1
- package/src/modes/components/customization/customization-dashboard.ts +7 -0
- package/src/modes/components/customization/import-wizard.ts +29 -3
- package/src/modes/components/model-selector.ts +157 -103
- package/src/modes/components/settings-selector.ts +103 -37
- package/src/modes/components/welcome.ts +3 -1
- package/src/modes/controllers/command-controller.ts +300 -9
- package/src/modes/controllers/event-controller.ts +1 -1
- package/src/modes/controllers/extension-ui-controller.ts +31 -1
- package/src/modes/controllers/goal-mode-controller.ts +79 -10
- package/src/modes/controllers/input-controller.ts +2 -0
- package/src/modes/controllers/plan-mode-controller.ts +66 -11
- package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
- package/src/modes/controllers/selector-controller.ts +76 -7
- package/src/modes/interactive-mode.ts +123 -4
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +5 -1
- package/src/modes/theme/theme.ts +15 -0
- package/src/modes/utils/host-status.ts +21 -10
- package/src/prompts/agent-fragments/browser-aside.md +2 -2
- package/src/prompts/system/irc-incoming.md +3 -1
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/irc.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 +40 -3
- package/src/runtime-mcp/oauth-flow.ts +32 -6
- package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
- package/src/runtime-mcp/project-host-values.ts +12 -8
- package/src/runtime-mcp/render.ts +16 -1
- package/src/runtime-mcp/tool-bridge.ts +194 -21
- package/src/runtime-mcp/transports/stdio.ts +2 -1
- package/src/sdk/broker/broker-exit.ts +10 -5
- package/src/sdk/broker/broker.ts +484 -85
- package/src/sdk/broker/daemon-entry.ts +338 -116
- package/src/sdk/broker/doctor-restart.ts +2 -1
- package/src/sdk/broker/ensure.ts +1214 -268
- package/src/sdk/broker/hop.ts +286 -0
- package/src/sdk/broker/lifecycle-ledger.ts +38 -11
- package/src/sdk/broker/lifecycle.ts +102 -6
- package/src/sdk/broker/lock-host-identity.ts +29 -0
- package/src/sdk/broker/session-index.ts +91 -16
- package/src/sdk/broker/transport.ts +17 -1
- package/src/sdk/bus/chat-command-policy.ts +16 -3
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +460 -35
- package/src/sdk/bus/reconciliation-store.ts +201 -8
- package/src/sdk/bus/session-control.ts +2 -0
- package/src/sdk/bus/slack-daemon.ts +105 -9
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -2
- package/src/sdk/bus/threaded-render.ts +20 -1
- package/src/sdk/cli/session-cli.ts +23 -6
- package/src/sdk/host/control/dispatch.ts +13 -1
- package/src/sdk/host/control/operations.ts +10 -1
- package/src/sdk/host/events.ts +67 -4
- package/src/sdk/host/host.ts +8 -2
- package/src/sdk/host/prompt-image-upload.ts +438 -0
- package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
- package/src/sdk/host/session-runtime.test.ts +1737 -129
- package/src/sdk/host/session-runtime.ts +684 -83
- package/src/sdk/host/surface-policy.ts +4 -0
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
- package/src/sdk/host/websocket-transport.ts +19 -7
- package/src/sdk/lifecycle/service.ts +15 -1
- package/src/sdk/prompt-deadline-flush.ts +78 -5
- package/src/sdk/prompt-deadline-manager.ts +68 -14
- package/src/sdk/prompt-status.ts +6 -4
- package/src/sdk/protocol/adapter-validation.ts +81 -12
- package/src/sdk/protocol/operation-inventory.generated.json +261 -2
- package/src/sdk/protocol/operation-registry.ts +33 -3
- package/src/sdk/reconciliation-extensions.ts +1 -0
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +237 -97
- package/src/session/agent-session.ts +2726 -479
- package/src/session/history-storage.ts +182 -12
- package/src/session/internal/managed-session-scope.ts +173 -57
- package/src/session/internal/managed-session-storage.ts +85 -12
- package/src/session/internal/native-publish-outcome.ts +5 -1
- package/src/session/messages.ts +47 -6
- package/src/session/session-manager.ts +326 -19
- 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/redact.ts +53 -2
- package/src/session-import/service.ts +1 -0
- package/src/skill-state/workflow-mutation-guard.ts +2145 -206
- package/src/slash-commands/builtin-registry.ts +21 -6
- package/src/slash-commands/helpers/credential-switch.ts +10 -5
- package/src/slash-commands/helpers/mcp.ts +11 -3
- package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
- package/src/ssh/ssh-executor.ts +9 -2
- package/src/stt/recorder.ts +26 -9
- package/src/system-prompt.ts +61 -16
- package/src/task/executor.ts +115 -20
- package/src/task/index.ts +389 -175
- package/src/task/role-body.ts +84 -0
- package/src/task/token-log-mode.test.ts +162 -0
- package/src/task/token-log.ts +91 -2
- package/src/tools/archive-reader.ts +650 -37
- package/src/tools/ask.ts +1 -0
- package/src/tools/ast-edit-write-path.ts +64 -0
- package/src/tools/ast-edit.ts +18 -1
- package/src/tools/ast-grep.ts +7 -2
- package/src/tools/atomic-file-write.ts +46 -15
- package/src/tools/auto-generated-guard.ts +15 -3
- package/src/tools/awaiting-input.ts +114 -0
- package/src/tools/bash-allowed-prefixes.ts +214 -6
- package/src/tools/bash-interactive.ts +14 -2
- package/src/tools/bash-skill-urls.ts +58 -5
- package/src/tools/bash.ts +113 -26
- package/src/tools/browser/tab-worker.ts +39 -13
- package/src/tools/browser.ts +17 -7
- package/src/tools/cron.ts +10 -1
- package/src/tools/debug.ts +16 -8
- package/src/tools/descriptors.test.ts +44 -0
- package/src/tools/descriptors.ts +50 -6
- package/src/tools/eval.ts +15 -0
- package/src/tools/fetch.ts +93 -4
- package/src/tools/gh.ts +27 -12
- package/src/tools/image-gen.ts +20 -6
- package/src/tools/index.ts +2 -0
- package/src/tools/irc.ts +5 -3
- package/src/tools/monitor.ts +9 -1
- package/src/tools/output-meta.ts +74 -5
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +26 -37
- package/src/tools/recipe/runner.ts +23 -12
- package/src/tools/render-utils.ts +2 -2
- package/src/tools/report-issue.ts +184 -0
- package/src/tools/search.ts +3 -2
- package/src/tools/ssh.ts +274 -8
- package/src/tools/subagent-render.ts +114 -12
- package/src/tools/subagent.ts +118 -5
- package/src/tools/tmux-self-injection-guard.ts +3301 -122
- package/src/tools/todo-write.ts +41 -3
- package/src/tools/tool-catalog.generated.ts +32 -4
- package/src/tools/ultragoal-ask-guard.ts +13 -1
- package/src/tools/write.ts +42 -3
- package/src/tui/tree-list.ts +15 -1
- package/src/utils/commit-message-generator.ts +12 -4
- package/src/utils/external-editor.ts +21 -7
- package/src/utils/file-mentions.ts +75 -7
- package/src/utils/git.ts +38 -7
- package/src/utils/image-limits.ts +8 -0
- package/src/utils/image-loading.ts +1 -1
- package/src/utils/open.ts +73 -4
- package/src/utils/pasted-image-loading.ts +9 -8
- package/src/utils/prompt-suggestion.ts +5 -4
- package/src/utils/shell-snapshot.ts +9 -1
- package/src/utils/title-generator.ts +72 -22
- 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/index.ts +2 -1
- package/src/web/search/providers/codex.ts +29 -32
- 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 {
|
|
@@ -48,38 +53,58 @@ type ModelProfileActivationSession = Pick<
|
|
|
48
53
|
> & {
|
|
49
54
|
credentialSessionId?: string;
|
|
50
55
|
setModelTemporary?: AgentSession["setModelTemporary"];
|
|
51
|
-
setActiveModelProfile?: (name: string | undefined) => void;
|
|
56
|
+
setActiveModelProfile?: (name: string | undefined, activatedByThisProcess?: boolean) => void;
|
|
52
57
|
getActiveModelProfile?: () => string | undefined;
|
|
58
|
+
getActivatedModelProfile?: () => string | undefined;
|
|
53
59
|
/** Record which runtime override keys this activation installed (session-scoped). */
|
|
54
60
|
noteProfileInstalledOverrides?: (
|
|
55
61
|
modelRoles: readonly string[],
|
|
56
62
|
agentModelOverrides: readonly string[],
|
|
57
63
|
preProfileModel: Model<Api> | undefined,
|
|
64
|
+
baseline?: {
|
|
65
|
+
modelRoles: Readonly<Record<string, ModelSelectorValue>>;
|
|
66
|
+
agentModelOverrides: Readonly<Record<string, ModelSelectorValue>>;
|
|
67
|
+
},
|
|
68
|
+
installed?: {
|
|
69
|
+
modelRoles: Readonly<Record<string, ModelSelectorValue>>;
|
|
70
|
+
agentModelOverrides: Readonly<Record<string, ModelSelectorValue>>;
|
|
71
|
+
},
|
|
72
|
+
manual?: { modelRoles: readonly string[]; agentModelOverrides: readonly string[] },
|
|
73
|
+
configuredDefaultChain?: readonly string[],
|
|
58
74
|
) => void;
|
|
59
75
|
/** Drop the recorded profile-installed override keys (e.g. after materialization). */
|
|
60
76
|
clearProfileInstalledOverrides?: () => void;
|
|
61
77
|
/** Current profile-installed override keys, for deriving the activation base. */
|
|
62
78
|
getProfileInstalledOverrideKeys?: () => { modelRoles: readonly string[]; agentModelOverrides: readonly string[] };
|
|
79
|
+
/** Profile-installed baselines, preserved when a refreshed profile drops an assignment. */
|
|
80
|
+
getProfileInstalledOverrideState?: () => AgentSessionProfileInstalledOverrideState;
|
|
81
|
+
restoreProfileInstalledOverrideState?: (state: AgentSessionProfileInstalledOverrideState) => void;
|
|
63
82
|
/** Re-apply vendor-separated delegation (task tool + prompt) after the role layer changed. */
|
|
64
83
|
syncEagerDelegation?: () => Promise<void>;
|
|
65
84
|
getSessionDefaultModelSelector?: () => string | undefined;
|
|
66
85
|
recordResumeDefaultModel?: (selector: string | undefined) => void;
|
|
67
86
|
getUserCanonicalVariantSelection?: () => UserCanonicalVariantSelection;
|
|
87
|
+
getUserModelSelectionRevision?: () => number;
|
|
68
88
|
seedDefaultFallbackResolution?: (activeIndex: number, skips: Array<{ selector: string; reason: string }>) => void;
|
|
69
89
|
getDefaultFallbackRuntimeState?: () => DefaultFallbackRuntimeState;
|
|
70
90
|
restoreDefaultFallbackRuntimeState?: (state: DefaultFallbackRuntimeState) => void;
|
|
71
91
|
restoreModelSelectionForRollback?: AgentSession["restoreModelSelectionForRollback"];
|
|
92
|
+
prepareModelSelectionForProfileActivation?: AgentSession["prepareModelSelectionForProfileActivation"];
|
|
93
|
+
commitPreparedProfileModelSelection?: AgentSession["commitPreparedProfileModelSelection"];
|
|
94
|
+
finishPreparedProfileModelSelection?: AgentSession["finishPreparedProfileModelSelection"];
|
|
72
95
|
modelRegistry?: Pick<
|
|
73
96
|
ModelRegistry,
|
|
74
97
|
| "getSessionCanonicalVariant"
|
|
75
98
|
| "restoreSessionCanonicalVariant"
|
|
76
99
|
| "clearCanonicalVariant"
|
|
100
|
+
| "getModelProfile"
|
|
77
101
|
| "getAvailable"
|
|
78
102
|
| "lookupAliasExists"
|
|
79
103
|
| "resolveModelByLookupAlias"
|
|
80
104
|
| "authStorage"
|
|
81
105
|
| "isCredentiallessProvider"
|
|
82
|
-
|
|
106
|
+
> &
|
|
107
|
+
Partial<Pick<ModelRegistry, "seedCanonicalVariant">>;
|
|
83
108
|
getConfiguredModelChainState?: (role: string) => ConfiguredModelChainState | undefined;
|
|
84
109
|
};
|
|
85
110
|
|
|
@@ -90,6 +115,25 @@ type ConfiguredModelChainState = {
|
|
|
90
115
|
explicitHead: boolean;
|
|
91
116
|
};
|
|
92
117
|
|
|
118
|
+
type PublishedModelProfileActivationState = {
|
|
119
|
+
model: Model<Api> | undefined;
|
|
120
|
+
thinkingLevel: ThinkingLevel | undefined;
|
|
121
|
+
modelRolesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
122
|
+
agentModelOverridesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
123
|
+
defaultChainState: ConfiguredModelChainState | undefined;
|
|
124
|
+
defaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
125
|
+
activeModelProfile: string | undefined;
|
|
126
|
+
activatedModelProfile: string | undefined;
|
|
127
|
+
profileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
128
|
+
sessionDefaultModel: string | undefined;
|
|
129
|
+
persistedModelRoles: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
130
|
+
persistedAgentModelOverrides: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
131
|
+
persistedDefaultProfile: string | undefined;
|
|
132
|
+
persistedDefaultThinkingLevel: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
133
|
+
defaultThinkingLevelOverride: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
134
|
+
defaultProfileOverride: string | undefined;
|
|
135
|
+
};
|
|
136
|
+
|
|
93
137
|
export interface PrepareModelProfileActivationOptions {
|
|
94
138
|
session: ModelProfileActivationSession;
|
|
95
139
|
modelRegistry: Pick<
|
|
@@ -108,6 +152,8 @@ export interface PrepareModelProfileActivationOptions {
|
|
|
108
152
|
Pick<
|
|
109
153
|
ModelRegistry,
|
|
110
154
|
| "getAvailable"
|
|
155
|
+
| "hasUsableAuthForProvider"
|
|
156
|
+
| "isStagedReloadCandidate"
|
|
111
157
|
| "resolveModelByLookupAlias"
|
|
112
158
|
| "lookupAliasExists"
|
|
113
159
|
| "clearCanonicalVariant"
|
|
@@ -115,6 +161,7 @@ export interface PrepareModelProfileActivationOptions {
|
|
|
115
161
|
| "getSessionCanonicalVariant"
|
|
116
162
|
| "restoreSessionCanonicalVariant"
|
|
117
163
|
| "getConfiguredProviderIds"
|
|
164
|
+
| "getConfiguredModelBindings"
|
|
118
165
|
| "isKnownProvider"
|
|
119
166
|
>
|
|
120
167
|
> & {
|
|
@@ -122,11 +169,21 @@ export interface PrepareModelProfileActivationOptions {
|
|
|
122
169
|
authStorage?: ModelRegistry["authStorage"];
|
|
123
170
|
};
|
|
124
171
|
settings: Pick<Settings, "get" | "getGlobal" | "getOverride">;
|
|
172
|
+
/** Live mutation target when `settings` is a validated staged view. */
|
|
173
|
+
settingsForApply?: Settings;
|
|
174
|
+
prepareSessionModelSelection?: boolean;
|
|
175
|
+
preserveManualOverrides?: boolean;
|
|
176
|
+
preserveCanonicalVariant?: boolean;
|
|
177
|
+
signal?: AbortSignal;
|
|
125
178
|
profileName: string;
|
|
126
179
|
}
|
|
127
180
|
export interface ApplyModelProfileActivationOptions {
|
|
128
181
|
persistDefault?: boolean;
|
|
129
182
|
thinkingLevelOverride?: ThinkingLevel;
|
|
183
|
+
preserveDefaultModelSelection?: boolean;
|
|
184
|
+
preserveLiveModelSelection?: boolean;
|
|
185
|
+
deferRuntimePublication?: boolean;
|
|
186
|
+
signal?: AbortSignal;
|
|
130
187
|
/** Cancels deferred activation if a newer user model selection exists. */
|
|
131
188
|
isCurrent?: () => boolean;
|
|
132
189
|
}
|
|
@@ -148,11 +205,18 @@ export interface PreparedModelProfileActivation {
|
|
|
148
205
|
previousDefaultProfileOverride: string | undefined;
|
|
149
206
|
previousPersistedDefaultProfile: string | undefined;
|
|
150
207
|
previousPersistedDefaultThinkingLevel: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
151
|
-
previousDefaultThinkingLevelOverride: ThinkingLevel | undefined;
|
|
208
|
+
previousDefaultThinkingLevelOverride: Exclude<ThinkingLevel, "inherit"> | undefined;
|
|
152
209
|
baseAgentModelOverrides: Record<string, ModelSelectorValue>;
|
|
153
210
|
baseModelRoles: Record<string, ModelSelectorValue>;
|
|
154
211
|
previousDefaultChain: readonly string[] | undefined;
|
|
155
212
|
previousDefaultChainState: ConfiguredModelChainState | undefined;
|
|
213
|
+
previousProfileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
214
|
+
preparedDefaultModelSelection:
|
|
215
|
+
| Awaited<ReturnType<NonNullable<ModelProfileActivationSession["prepareModelSelectionForProfileActivation"]>>>
|
|
216
|
+
| undefined;
|
|
217
|
+
defaultChainPublished: boolean;
|
|
218
|
+
defaultModelPublished: boolean;
|
|
219
|
+
publishedState: PublishedModelProfileActivationState | undefined;
|
|
156
220
|
previousDefaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
157
221
|
defaultModel: Model<Api> | undefined;
|
|
158
222
|
defaultThinkingLevel: ThinkingLevel | undefined;
|
|
@@ -164,7 +228,10 @@ export interface PreparedModelProfileActivation {
|
|
|
164
228
|
defaultResolutionSkips: Array<{ selector: string; reason: string }>;
|
|
165
229
|
modelRoles: Record<string, ModelSelectorValue>;
|
|
166
230
|
agentModelOverrides: Record<string, ModelSelectorValue>;
|
|
231
|
+
manualModelRoleOverrides: ReadonlySet<string>;
|
|
232
|
+
manualAgentModelOverrides: ReadonlySet<string>;
|
|
167
233
|
previousActiveModelProfile: string | undefined;
|
|
234
|
+
previousActivatedModelProfile: string | undefined;
|
|
168
235
|
/**
|
|
169
236
|
* The session resume default ("provider/id") captured BEFORE activation —
|
|
170
237
|
* the model resume would restore prior to this profile. Snapshotted
|
|
@@ -198,6 +265,8 @@ export interface MaterializeModelProfileAssignmentOptions {
|
|
|
198
265
|
| "setConfiguredModelChain"
|
|
199
266
|
| "setActiveModelProfile"
|
|
200
267
|
| "getActiveModelProfile"
|
|
268
|
+
| "getActivatedModelProfile"
|
|
269
|
+
| "getProfileInstalledOverrideState"
|
|
201
270
|
| "getDefaultFallbackRuntimeState"
|
|
202
271
|
| "restoreDefaultFallbackRuntimeState"
|
|
203
272
|
| "modelRegistry"
|
|
@@ -220,6 +289,8 @@ export interface MaterializeModelProfileAssignmentsOptions {
|
|
|
220
289
|
| "setConfiguredModelChain"
|
|
221
290
|
| "setActiveModelProfile"
|
|
222
291
|
| "getActiveModelProfile"
|
|
292
|
+
| "getActivatedModelProfile"
|
|
293
|
+
| "getProfileInstalledOverrideState"
|
|
223
294
|
| "getDefaultFallbackRuntimeState"
|
|
224
295
|
| "restoreDefaultFallbackRuntimeState"
|
|
225
296
|
| "modelRegistry"
|
|
@@ -248,9 +319,80 @@ function getMaterializedAssignments(
|
|
|
248
319
|
return result;
|
|
249
320
|
}
|
|
250
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Resolve the profile a materialization may consume.
|
|
324
|
+
*
|
|
325
|
+
* Only a profile this process actually activated owns role-only materialization.
|
|
326
|
+
* A persisted profile whose activation failed or was only restored from history
|
|
327
|
+
* stays in place. An explicit default selection may supersede that durable profile.
|
|
328
|
+
*/
|
|
329
|
+
export function resolveMaterializationProfileIdentity(
|
|
330
|
+
activatedProfile: string | undefined,
|
|
331
|
+
durableProfile: string | undefined,
|
|
332
|
+
includesDefault: boolean,
|
|
333
|
+
): string | undefined {
|
|
334
|
+
if (activatedProfile) return activatedProfile;
|
|
335
|
+
return includesDefault ? durableProfile : undefined;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function resolveMaterializationProfile(
|
|
339
|
+
options: MaterializeModelProfileAssignmentOptions | MaterializeModelProfileAssignmentsOptions,
|
|
340
|
+
includesDefault: boolean,
|
|
341
|
+
): string | undefined {
|
|
342
|
+
return resolveMaterializationProfileIdentity(
|
|
343
|
+
options.session.getActivatedModelProfile?.(),
|
|
344
|
+
options.settings.get("modelProfile.default"),
|
|
345
|
+
includesDefault,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Resolve startup-override materialization in activated-chain, profile, then global-default order. */
|
|
350
|
+
export function resolveMaterializedDefaultSelector(
|
|
351
|
+
activatedDefaultChain: readonly string[] | undefined,
|
|
352
|
+
profileDefault: ModelSelectorValue | undefined,
|
|
353
|
+
globalDefault: ModelSelectorValue | undefined,
|
|
354
|
+
): ModelSelectorValue | undefined {
|
|
355
|
+
if (activatedDefaultChain?.length) {
|
|
356
|
+
return activatedDefaultChain.length === 1 ? activatedDefaultChain[0] : [...activatedDefaultChain];
|
|
357
|
+
}
|
|
358
|
+
return profileDefault ?? globalDefault;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function modelRolesForMaterialization(
|
|
362
|
+
options: MaterializeModelProfileAssignmentOptions | MaterializeModelProfileAssignmentsOptions,
|
|
363
|
+
): Record<string, ModelSelectorValue> {
|
|
364
|
+
const modelRoles = { ...options.settings.get("modelRoles") };
|
|
365
|
+
const defaultChain = options.session.getConfiguredModelChainState?.("default");
|
|
366
|
+
if (defaultChain?.origin !== "startup-override" || !defaultChain.entries[0]) return modelRoles;
|
|
367
|
+
|
|
368
|
+
// The merged runtime roles can still contain the CLI model; materialize the
|
|
369
|
+
// profile's default instead. Profile-derived defaults require an activated
|
|
370
|
+
// profile: a persisted profile that failed activation contributes nothing.
|
|
371
|
+
const activeProfile = options.session.getActivatedModelProfile?.();
|
|
372
|
+
let configuredDefault: ModelSelectorValue | undefined;
|
|
373
|
+
if (activeProfile) {
|
|
374
|
+
const activatedDefaultChain = options.session.getProfileInstalledOverrideState?.().configuredDefaultChain;
|
|
375
|
+
const profile = options.session.modelRegistry?.getModelProfile?.(activeProfile);
|
|
376
|
+
configuredDefault = resolveMaterializedDefaultSelector(
|
|
377
|
+
activatedDefaultChain,
|
|
378
|
+
profile ? resolveProfileBindings(profile).defaultSelector : undefined,
|
|
379
|
+
options.settings.getGlobal("modelRoles")?.default,
|
|
380
|
+
);
|
|
381
|
+
} else {
|
|
382
|
+
configuredDefault = options.settings.getGlobal("modelRoles")?.default;
|
|
383
|
+
}
|
|
384
|
+
if (configuredDefault === undefined) delete modelRoles.default;
|
|
385
|
+
else modelRoles.default = configuredDefault;
|
|
386
|
+
return modelRoles;
|
|
387
|
+
}
|
|
388
|
+
|
|
251
389
|
function materializeConfiguredDefaultChain(
|
|
252
|
-
session: Pick<
|
|
390
|
+
session: Pick<
|
|
391
|
+
ModelProfileActivationSession,
|
|
392
|
+
"model" | "thinkingLevel" | "getConfiguredModelChain" | "getConfiguredModelChainState"
|
|
393
|
+
>,
|
|
253
394
|
): ModelSelectorValue | undefined {
|
|
395
|
+
if (session.getConfiguredModelChainState?.("default")?.origin === "startup-override") return undefined;
|
|
254
396
|
if (!session.model) return undefined;
|
|
255
397
|
return formatModelSelectorValue(`${session.model.provider}/${session.model.id}`, session.thinkingLevel);
|
|
256
398
|
}
|
|
@@ -266,7 +408,7 @@ function concretizeMaterializedAssignmentValues(
|
|
|
266
408
|
// Materialized assignments are persisted into `modelRoles` and
|
|
267
409
|
// `task.agentModelOverrides` and later consumed by profile execution, so they
|
|
268
410
|
// resolve against the same catalog profile activation uses.
|
|
269
|
-
const availableModels = modelRegistry.getAvailable();
|
|
411
|
+
const availableModels = modelRegistry.getAvailable(credentialSessionId);
|
|
270
412
|
const authenticatedModels = availableModels.filter(model => {
|
|
271
413
|
const isCredentiallessProvider = modelRegistry.isCredentiallessProvider?.bind(modelRegistry);
|
|
272
414
|
const hasUsableAuth = modelRegistry.authStorage?.hasUsableAuth?.bind(modelRegistry.authStorage);
|
|
@@ -306,6 +448,7 @@ function commitMaterializedProfileAssignments(
|
|
|
306
448
|
options: MaterializeModelProfileAssignmentOptions | MaterializeModelProfileAssignmentsOptions,
|
|
307
449
|
modelRoles: Record<string, ModelSelectorValue>,
|
|
308
450
|
agentModelOverrides: Record<string, ModelSelectorValue>,
|
|
451
|
+
preserveStartupOverrideChain = false,
|
|
309
452
|
): boolean {
|
|
310
453
|
const previousPersistedModelRoles = options.settings.getGlobal("modelRoles");
|
|
311
454
|
const previousPersistedAgentModelOverrides = options.settings.getGlobal("task.agentModelOverrides");
|
|
@@ -314,6 +457,7 @@ function commitMaterializedProfileAssignments(
|
|
|
314
457
|
const previousAgentModelOverridesOverride = options.settings.getOverride("task.agentModelOverrides");
|
|
315
458
|
const previousDefaultProfileOverride = options.settings.getOverride("modelProfile.default");
|
|
316
459
|
const previousActiveProfile = options.session.getActiveModelProfile?.();
|
|
460
|
+
const previousActivatedProfile = options.session.getActivatedModelProfile?.();
|
|
317
461
|
const previousChain = options.session.getConfiguredModelChainState?.("default");
|
|
318
462
|
const previousFallbackRuntimeState = options.session.getDefaultFallbackRuntimeState?.();
|
|
319
463
|
const previousCanonicalVariant = options.session.modelRegistry?.getSessionCanonicalVariant?.(
|
|
@@ -328,13 +472,17 @@ function commitMaterializedProfileAssignments(
|
|
|
328
472
|
options.settings.clearOverride("modelProfile.default");
|
|
329
473
|
options.settings.override("modelRoles", nextModelRoles);
|
|
330
474
|
options.settings.override("task.agentModelOverrides", nextAgentModelOverrides);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
475
|
+
// Role-only materialization persists the profile default for future launches,
|
|
476
|
+
// but it must not replace the live run-scoped CLI model chain.
|
|
477
|
+
if (!preserveStartupOverrideChain || previousChain?.origin !== "startup-override") {
|
|
478
|
+
options.session.setConfiguredModelChain(
|
|
479
|
+
"default",
|
|
480
|
+
normalizeModelSelectorValue(nextModelRoles.default),
|
|
481
|
+
"modelRoles",
|
|
482
|
+
undefined,
|
|
483
|
+
true,
|
|
484
|
+
);
|
|
485
|
+
}
|
|
338
486
|
options.session.setActiveModelProfile?.(undefined);
|
|
339
487
|
return true;
|
|
340
488
|
} catch (error) {
|
|
@@ -399,7 +547,12 @@ function commitMaterializedProfileAssignments(
|
|
|
399
547
|
? options.settings.clearOverride("modelProfile.default")
|
|
400
548
|
: options.settings.override("modelProfile.default", previousDefaultProfileOverride),
|
|
401
549
|
);
|
|
402
|
-
restore(() =>
|
|
550
|
+
restore(() =>
|
|
551
|
+
options.session.setActiveModelProfile?.(
|
|
552
|
+
previousActiveProfile,
|
|
553
|
+
previousActivatedProfile === previousActiveProfile,
|
|
554
|
+
),
|
|
555
|
+
);
|
|
403
556
|
if (rollbackErrors.length > 0) {
|
|
404
557
|
throw new AggregateError(
|
|
405
558
|
[error, ...rollbackErrors],
|
|
@@ -411,10 +564,9 @@ function commitMaterializedProfileAssignments(
|
|
|
411
564
|
}
|
|
412
565
|
|
|
413
566
|
export function materializeActiveModelProfileAssignment(options: MaterializeModelProfileAssignmentOptions): boolean {
|
|
414
|
-
|
|
415
|
-
if (!activeProfile) return false;
|
|
567
|
+
if (!resolveMaterializationProfile(options, options.role === "default")) return false;
|
|
416
568
|
|
|
417
|
-
const nextModelRoles =
|
|
569
|
+
const nextModelRoles = modelRolesForMaterialization(options);
|
|
418
570
|
const nextAgentModelOverrides = { ...options.settings.get("task.agentModelOverrides") };
|
|
419
571
|
const target = GJC_MODEL_ASSIGNMENT_TARGETS[options.role];
|
|
420
572
|
|
|
@@ -431,21 +583,24 @@ export function materializeActiveModelProfileAssignment(options: MaterializeMode
|
|
|
431
583
|
nextAgentModelOverrides[options.role] = options.selector;
|
|
432
584
|
}
|
|
433
585
|
|
|
434
|
-
const committed = commitMaterializedProfileAssignments(
|
|
586
|
+
const committed = commitMaterializedProfileAssignments(
|
|
587
|
+
options,
|
|
588
|
+
nextModelRoles,
|
|
589
|
+
nextAgentModelOverrides,
|
|
590
|
+
options.role !== "default",
|
|
591
|
+
);
|
|
435
592
|
if (committed) options.session.clearProfileInstalledOverrides?.();
|
|
436
593
|
return committed;
|
|
437
594
|
}
|
|
438
595
|
|
|
439
596
|
export function materializeActiveModelProfileAssignments(options: MaterializeModelProfileAssignmentsOptions): boolean {
|
|
440
|
-
const activeProfile = options.session.getActiveModelProfile?.() ?? options.settings.get("modelProfile.default");
|
|
441
|
-
if (!activeProfile) return false;
|
|
442
|
-
|
|
443
597
|
const materializedAssignments = getMaterializedAssignments(options.assignments);
|
|
598
|
+
const includesDefault = materializedAssignments.some(([role]) => role === "default");
|
|
599
|
+
if (!resolveMaterializationProfile(options, includesDefault)) return false;
|
|
444
600
|
if (materializedAssignments.length === 0) return true;
|
|
445
601
|
|
|
446
|
-
const nextModelRoles =
|
|
602
|
+
const nextModelRoles = modelRolesForMaterialization(options);
|
|
447
603
|
const nextAgentModelOverrides = { ...options.settings.get("task.agentModelOverrides") };
|
|
448
|
-
const includesDefault = materializedAssignments.some(([role]) => role === "default");
|
|
449
604
|
|
|
450
605
|
if (!includesDefault && !nextModelRoles.default) {
|
|
451
606
|
const defaultChain = materializeConfiguredDefaultChain(options.session);
|
|
@@ -461,7 +616,12 @@ export function materializeActiveModelProfileAssignments(options: MaterializeMod
|
|
|
461
616
|
}
|
|
462
617
|
}
|
|
463
618
|
|
|
464
|
-
const committed = commitMaterializedProfileAssignments(
|
|
619
|
+
const committed = commitMaterializedProfileAssignments(
|
|
620
|
+
options,
|
|
621
|
+
nextModelRoles,
|
|
622
|
+
nextAgentModelOverrides,
|
|
623
|
+
!includesDefault,
|
|
624
|
+
);
|
|
465
625
|
if (committed) options.session.clearProfileInstalledOverrides?.();
|
|
466
626
|
return committed;
|
|
467
627
|
}
|
|
@@ -528,6 +688,17 @@ async function getProfileProviderApiKey(
|
|
|
528
688
|
}
|
|
529
689
|
}
|
|
530
690
|
|
|
691
|
+
function isStagedProviderAuthAvailable(
|
|
692
|
+
registry: PrepareModelProfileActivationOptions["modelRegistry"],
|
|
693
|
+
provider: string,
|
|
694
|
+
sessionId: string,
|
|
695
|
+
): boolean {
|
|
696
|
+
return (
|
|
697
|
+
registry.isStagedReloadCandidate?.() === true &&
|
|
698
|
+
(registry.hasUsableAuthForProvider?.(provider, sessionId) ?? false)
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
531
702
|
export function formatModelProfileCredentialError(profileLabel: string, providers: readonly string[]): string {
|
|
532
703
|
return `Model profile "${profileLabel}" requires credentials for: ${providers.join(", ")}. Run /login and configure the missing provider(s), then retry.`;
|
|
533
704
|
}
|
|
@@ -728,7 +899,7 @@ export async function resolveMissingSessionModelRecovery(options: {
|
|
|
728
899
|
options.skips.length === options.defaultEntries.length &&
|
|
729
900
|
options.skips.every(skip => skip.reason === "unknown_model");
|
|
730
901
|
if (!allSelectorsUnknown) return undefined;
|
|
731
|
-
const fullCatalog = options.modelRegistry.getAll();
|
|
902
|
+
const fullCatalog = options.modelRegistry.getAll(options.credentialSessionId);
|
|
732
903
|
const catalogIndex = createRegistrySelectorIndex(fullCatalog);
|
|
733
904
|
const savedSelectorsMissingFromCatalog = resolveConfiguredModelPatterns(
|
|
734
905
|
options.defaultEntries,
|
|
@@ -825,7 +996,8 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
825
996
|
if (requiredProviderSet.has(provider) && !alternativeSet.has(provider)) throw error;
|
|
826
997
|
continue;
|
|
827
998
|
}
|
|
828
|
-
|
|
999
|
+
const hasUsableAuth = isStagedProviderAuthAvailable(options.modelRegistry, provider, options.credentialSessionId);
|
|
1000
|
+
if (apiKey === kNoAuth || isAuthenticated(apiKey) || hasUsableAuth) authenticatedProviders.add(provider);
|
|
829
1001
|
else if (requiredProviderSet.has(provider)) missingProviders.push(provider);
|
|
830
1002
|
}
|
|
831
1003
|
const proxyProvider = profile.source !== "user" ? resolveProxyProviderId(options.settings) : undefined;
|
|
@@ -851,6 +1023,9 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
851
1023
|
options.credentialSessionId,
|
|
852
1024
|
profileLabel,
|
|
853
1025
|
);
|
|
1026
|
+
const proxyHasUsableAuth =
|
|
1027
|
+
proxyProvider !== undefined &&
|
|
1028
|
+
isStagedProviderAuthAvailable(options.modelRegistry, proxyProvider, options.credentialSessionId);
|
|
854
1029
|
if (
|
|
855
1030
|
proxyProvider !== undefined &&
|
|
856
1031
|
!isModelProfileProxyConfigured(proxyProvider, configuredProviderIds, proxyApiKey === kNoAuth)
|
|
@@ -859,7 +1034,8 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
859
1034
|
`modelProfile.proxyProvider "${proxyProvider}" is not configured. Configure it with \`gjc setup provider\` before activating a preset.`,
|
|
860
1035
|
);
|
|
861
1036
|
}
|
|
862
|
-
const proxyAuthenticated =
|
|
1037
|
+
const proxyAuthenticated =
|
|
1038
|
+
(proxyApiKey !== undefined && (proxyApiKey === kNoAuth || isAuthenticated(proxyApiKey))) || proxyHasUsableAuth;
|
|
863
1039
|
if (proxyMode === "always" && !proxyAuthenticated)
|
|
864
1040
|
throw new ModelProfileCredentialError(profileLabel, [proxyProvider!]);
|
|
865
1041
|
const strictMissing = missingProviders.filter(
|
|
@@ -884,7 +1060,9 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
884
1060
|
allRoutable && proxyProvider !== undefined ? [proxyProvider] : [...group],
|
|
885
1061
|
);
|
|
886
1062
|
}
|
|
887
|
-
const availableModels =
|
|
1063
|
+
const availableModels =
|
|
1064
|
+
options.modelRegistry.getAvailable?.(options.credentialSessionId) ??
|
|
1065
|
+
options.modelRegistry.getAll(options.credentialSessionId);
|
|
888
1066
|
let bindings = resolveProfileBindings(profile);
|
|
889
1067
|
if (alternativeGroups.length > 0)
|
|
890
1068
|
bindings = rewriteBindingsProviders(bindings, authenticatedProviders, alternativeGroups);
|
|
@@ -901,7 +1079,7 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
901
1079
|
await preflightModelProfileRoleBindings({
|
|
902
1080
|
profile,
|
|
903
1081
|
bindings,
|
|
904
|
-
roleCatalogModels: options.modelRegistry.getAll(),
|
|
1082
|
+
roleCatalogModels: options.modelRegistry.getAll(options.credentialSessionId),
|
|
905
1083
|
settings: options.settings as Settings,
|
|
906
1084
|
modelRegistry: options.modelRegistry as ModelRegistry,
|
|
907
1085
|
sessionId: "",
|
|
@@ -948,6 +1126,8 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
948
1126
|
credentialSessionId: options.credentialSessionId,
|
|
949
1127
|
isCredentialUnavailable: provider =>
|
|
950
1128
|
isSessionCredentialPinBlocking(options.modelRegistry, provider, options.credentialSessionId),
|
|
1129
|
+
isProviderAuthAvailable: provider =>
|
|
1130
|
+
isStagedProviderAuthAvailable(options.modelRegistry, provider, options.credentialSessionId),
|
|
951
1131
|
},
|
|
952
1132
|
);
|
|
953
1133
|
return { profileName, entries: defaultChain, ...resolution };
|
|
@@ -1085,11 +1265,15 @@ function formatMaterializedSelector(selector: string, model: Model<Api>): string
|
|
|
1085
1265
|
if (!explicitThinkingLevel || parseModelString(clampedSelector)?.thinkingLevel) return clampedSelector;
|
|
1086
1266
|
return formatModelSelectorValue(clampedSelector, explicitThinkingLevel);
|
|
1087
1267
|
}
|
|
1088
|
-
function getBareSelectorCredentialProviders(
|
|
1268
|
+
function getBareSelectorCredentialProviders(
|
|
1269
|
+
selector: string,
|
|
1270
|
+
modelRegistry: ModelRegistry,
|
|
1271
|
+
credentialSessionId?: string,
|
|
1272
|
+
): string[] {
|
|
1089
1273
|
const suffix = splitSelectorThinkingSuffix(selector);
|
|
1090
1274
|
const alias = (suffix.thinkingLevel ? suffix.selector : selector).trim().toLowerCase();
|
|
1091
1275
|
const providers = modelRegistry
|
|
1092
|
-
.getAll()
|
|
1276
|
+
.getAll(credentialSessionId)
|
|
1093
1277
|
.filter(model => {
|
|
1094
1278
|
const modelId = model.id.trim().toLowerCase();
|
|
1095
1279
|
return modelId === alias || modelId.slice(modelId.lastIndexOf("/") + 1) === alias;
|
|
@@ -1147,6 +1331,8 @@ async function resolveAndClampSelectorValue(
|
|
|
1147
1331
|
credentialSessionId: options.credentialSessionId,
|
|
1148
1332
|
isCredentialUnavailable: provider =>
|
|
1149
1333
|
isSessionCredentialPinBlocking(options.modelRegistry, provider, options.credentialSessionId),
|
|
1334
|
+
isProviderAuthAvailable: provider =>
|
|
1335
|
+
isStagedProviderAuthAvailable(options.modelRegistry, provider, options.credentialSessionId),
|
|
1150
1336
|
},
|
|
1151
1337
|
);
|
|
1152
1338
|
resolved = {
|
|
@@ -1158,7 +1344,11 @@ async function resolveAndClampSelectorValue(
|
|
|
1158
1344
|
}
|
|
1159
1345
|
if (!resolved.model) {
|
|
1160
1346
|
if (bareAlias) {
|
|
1161
|
-
const providers = getBareSelectorCredentialProviders(
|
|
1347
|
+
const providers = getBareSelectorCredentialProviders(
|
|
1348
|
+
selector,
|
|
1349
|
+
options.modelRegistry,
|
|
1350
|
+
options.credentialSessionId,
|
|
1351
|
+
);
|
|
1162
1352
|
const selectorSuffix = splitSelectorThinkingSuffix(selector);
|
|
1163
1353
|
const bareSelector = selectorSuffix.thinkingLevel ? selectorSuffix.selector : selector;
|
|
1164
1354
|
const aliasKnown =
|
|
@@ -1250,8 +1440,9 @@ async function concretizeProfileSelectorValue(
|
|
|
1250
1440
|
selectorValue: ModelSelectorValue,
|
|
1251
1441
|
prepared: PreparedModelProfileActivation,
|
|
1252
1442
|
): Promise<ModelSelectorValue> {
|
|
1253
|
-
const candidates = prepared.modelRegistry.getAvailable?.() ?? prepared.modelRegistry.getAll();
|
|
1254
1443
|
const credentialSessionId = prepared.session.credentialSessionId ?? prepared.session.sessionId;
|
|
1444
|
+
const candidates =
|
|
1445
|
+
prepared.modelRegistry.getAvailable?.(credentialSessionId) ?? prepared.modelRegistry.getAll(credentialSessionId);
|
|
1255
1446
|
const concrete = await Promise.all(
|
|
1256
1447
|
normalizeModelSelectorValue(selectorValue).map(async selector => {
|
|
1257
1448
|
const bareAlias = !splitSelectorThinkingSuffix(selector).selector.includes("/");
|
|
@@ -1279,6 +1470,8 @@ async function concretizeProfileSelectorValue(
|
|
|
1279
1470
|
credentialSessionId,
|
|
1280
1471
|
isCredentialUnavailable: provider =>
|
|
1281
1472
|
isSessionCredentialPinBlocking(prepared.modelRegistry, provider, credentialSessionId),
|
|
1473
|
+
isProviderAuthAvailable: provider =>
|
|
1474
|
+
isStagedProviderAuthAvailable(prepared.modelRegistry, provider, credentialSessionId),
|
|
1282
1475
|
},
|
|
1283
1476
|
)
|
|
1284
1477
|
: resolveModelRoleValue(selector, candidates, {
|
|
@@ -1314,7 +1507,7 @@ async function concretizeProfileSelectorValue(
|
|
|
1314
1507
|
* variant is cleared so a previous provider cannot silently resurrect.
|
|
1315
1508
|
*/
|
|
1316
1509
|
function restoreCanonicalVariant(
|
|
1317
|
-
modelRegistry:
|
|
1510
|
+
modelRegistry: Partial<Pick<ModelRegistry, "restoreSessionCanonicalVariant" | "clearCanonicalVariant">>,
|
|
1318
1511
|
sessionId: string,
|
|
1319
1512
|
previousCanonicalVariant: string | undefined,
|
|
1320
1513
|
): void {
|
|
@@ -1326,8 +1519,18 @@ function restoreCanonicalVariant(
|
|
|
1326
1519
|
}
|
|
1327
1520
|
}
|
|
1328
1521
|
|
|
1522
|
+
function selectorValuesEqual(left: ModelSelectorValue | undefined, right: ModelSelectorValue | undefined): boolean {
|
|
1523
|
+
if (left === undefined || right === undefined) return left === right;
|
|
1524
|
+
const leftSelectors = normalizeModelSelectorValue(left);
|
|
1525
|
+
const rightSelectors = normalizeModelSelectorValue(right);
|
|
1526
|
+
return (
|
|
1527
|
+
leftSelectors.length === rightSelectors.length &&
|
|
1528
|
+
leftSelectors.every((selector, index) => selector === rightSelectors[index])
|
|
1529
|
+
);
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1329
1532
|
function restoreCanonicalVariantAfterPreparation(
|
|
1330
|
-
modelRegistry:
|
|
1533
|
+
modelRegistry: Partial<Pick<ModelRegistry, "restoreSessionCanonicalVariant" | "clearCanonicalVariant">>,
|
|
1331
1534
|
session: ModelProfileActivationSession,
|
|
1332
1535
|
previousCanonicalVariant: string | undefined,
|
|
1333
1536
|
previousUserSelection: UserCanonicalVariantSelection | undefined,
|
|
@@ -1343,7 +1546,6 @@ function restoreCanonicalVariantAfterPreparation(
|
|
|
1343
1546
|
userSelectionChanged ? currentUserSelection.canonicalVariant : previousCanonicalVariant,
|
|
1344
1547
|
);
|
|
1345
1548
|
}
|
|
1346
|
-
|
|
1347
1549
|
export async function prepareModelProfileActivation(
|
|
1348
1550
|
options: PrepareModelProfileActivationOptions,
|
|
1349
1551
|
): Promise<PreparedModelProfileActivation> {
|
|
@@ -1353,6 +1555,7 @@ export async function prepareModelProfileActivation(
|
|
|
1353
1555
|
const profileLabel = formatModelProfileDisplayLabel(profile);
|
|
1354
1556
|
|
|
1355
1557
|
const previousModel = options.session.model;
|
|
1558
|
+
const applySettings = options.settingsForApply ?? (options.settings as Settings);
|
|
1356
1559
|
// Snapshot the exact pre-clear sticky selector (verbatim, not re-derived from
|
|
1357
1560
|
// the live model) so a failed prepare/apply/materialize rollback restores the
|
|
1358
1561
|
// genuinely-sticky provider even when the live model is a transient switch.
|
|
@@ -1363,7 +1566,7 @@ export async function prepareModelProfileActivation(
|
|
|
1363
1566
|
// Explicit profile activation/reselection invalidates the session's sticky
|
|
1364
1567
|
// canonical variant BEFORE the new profile's aliases resolve, so the old
|
|
1365
1568
|
// provider's sticky variant cannot win the new profile's resolution.
|
|
1366
|
-
options.modelRegistry.clearCanonicalVariant?.(options.session.sessionId);
|
|
1569
|
+
if (!options.preserveCanonicalVariant) options.modelRegistry.clearCanonicalVariant?.(options.session.sessionId);
|
|
1367
1570
|
|
|
1368
1571
|
try {
|
|
1369
1572
|
const requiredProviders = aggregateModelProfileRequiredProviders(profile.requiredProviders, profile);
|
|
@@ -1413,7 +1616,8 @@ export async function prepareModelProfileActivation(
|
|
|
1413
1616
|
if (requiredProviderSet.has(provider) && !alternativeSet.has(provider)) throw error;
|
|
1414
1617
|
continue;
|
|
1415
1618
|
}
|
|
1416
|
-
|
|
1619
|
+
const hasUsableAuth = isStagedProviderAuthAvailable(options.modelRegistry, provider, credentialSessionId);
|
|
1620
|
+
if (apiKey !== kNoAuth && !isAuthenticated(apiKey) && !hasUsableAuth) {
|
|
1417
1621
|
if (requiredProviderSet.has(provider)) missingProviders.push(provider);
|
|
1418
1622
|
} else {
|
|
1419
1623
|
authenticatedProviders.push(provider);
|
|
@@ -1444,6 +1648,9 @@ export async function prepareModelProfileActivation(
|
|
|
1444
1648
|
proxyProvider === undefined
|
|
1445
1649
|
? undefined
|
|
1446
1650
|
: await getProfileProviderApiKey(options.modelRegistry, proxyProvider, credentialSessionId, profileLabel);
|
|
1651
|
+
const proxyHasUsableAuth =
|
|
1652
|
+
proxyProvider !== undefined &&
|
|
1653
|
+
isStagedProviderAuthAvailable(options.modelRegistry, proxyProvider, credentialSessionId);
|
|
1447
1654
|
if (proxyProvider !== undefined) {
|
|
1448
1655
|
const configuredProxyProviders = options.modelRegistry.getConfiguredProviderIds?.();
|
|
1449
1656
|
if (!isModelProfileProxyConfigured(proxyProvider, configuredProxyProviders, proxyApiKey === kNoAuth)) {
|
|
@@ -1454,8 +1661,8 @@ export async function prepareModelProfileActivation(
|
|
|
1454
1661
|
}
|
|
1455
1662
|
const proxyAuthenticated =
|
|
1456
1663
|
proxyProvider !== undefined &&
|
|
1457
|
-
proxyApiKey !== undefined &&
|
|
1458
|
-
|
|
1664
|
+
((proxyApiKey !== undefined && (proxyApiKey === kNoAuth || isAuthenticated(proxyApiKey))) ||
|
|
1665
|
+
proxyHasUsableAuth);
|
|
1459
1666
|
if (proxyMode === "always" && !proxyAuthenticated) {
|
|
1460
1667
|
throw new ModelProfileCredentialError(profileLabel, [proxyProvider!]);
|
|
1461
1668
|
}
|
|
@@ -1486,8 +1693,9 @@ export async function prepareModelProfileActivation(
|
|
|
1486
1693
|
);
|
|
1487
1694
|
}
|
|
1488
1695
|
|
|
1489
|
-
const availableModels =
|
|
1490
|
-
|
|
1696
|
+
const availableModels =
|
|
1697
|
+
options.modelRegistry.getAvailable?.(credentialSessionId) ?? options.modelRegistry.getAll(credentialSessionId);
|
|
1698
|
+
const roleCatalogModels = options.modelRegistry.getAll(credentialSessionId);
|
|
1491
1699
|
let bindings = resolveProfileBindings(profile);
|
|
1492
1700
|
if (alternativeGroups.length > 0) {
|
|
1493
1701
|
bindings = rewriteBindingsProviders(bindings, new Set(authenticatedProviders), alternativeGroups);
|
|
@@ -1547,6 +1755,8 @@ export async function prepareModelProfileActivation(
|
|
|
1547
1755
|
credentialSessionId,
|
|
1548
1756
|
isCredentialUnavailable: provider =>
|
|
1549
1757
|
isSessionCredentialPinBlocking(options.modelRegistry, provider, credentialSessionId),
|
|
1758
|
+
isProviderAuthAvailable: provider =>
|
|
1759
|
+
isStagedProviderAuthAvailable(options.modelRegistry, provider, credentialSessionId),
|
|
1550
1760
|
},
|
|
1551
1761
|
);
|
|
1552
1762
|
const defaultModel = defaultResolution.model;
|
|
@@ -1573,50 +1783,131 @@ export async function prepareModelProfileActivation(
|
|
|
1573
1783
|
credentialSessionId,
|
|
1574
1784
|
profileLabel,
|
|
1575
1785
|
});
|
|
1786
|
+
const installedKeys = options.session.getProfileInstalledOverrideKeys?.();
|
|
1787
|
+
const installedState = options.session.getProfileInstalledOverrideState?.();
|
|
1788
|
+
const baseModelRoles = { ...(options.settings.getOverride("modelRoles") ?? {}) };
|
|
1789
|
+
const baseAgentModelOverrides = { ...(options.settings.getOverride("task.agentModelOverrides") ?? {}) };
|
|
1790
|
+
const manualModelRoleOverrides = new Set(
|
|
1791
|
+
options.preserveManualOverrides ? (installedState?.manualModelRoles ?? []) : [],
|
|
1792
|
+
);
|
|
1793
|
+
const manualAgentModelOverrides = new Set(
|
|
1794
|
+
options.preserveManualOverrides ? (installedState?.manualAgentModelOverrides ?? []) : [],
|
|
1795
|
+
);
|
|
1796
|
+
const configuredAgentModelOverrides = options.modelRegistry?.getConfiguredModelBindings?.()?.agentModelOverrides;
|
|
1797
|
+
for (const role of installedKeys?.modelRoles ?? []) {
|
|
1798
|
+
if (options.preserveManualOverrides && manualModelRoleOverrides.has(role)) continue;
|
|
1799
|
+
const installed = installedState?.installedModelRoles.get(role);
|
|
1800
|
+
if (
|
|
1801
|
+
options.preserveManualOverrides &&
|
|
1802
|
+
installed !== undefined &&
|
|
1803
|
+
!selectorValuesEqual(baseModelRoles[role], installed)
|
|
1804
|
+
) {
|
|
1805
|
+
manualModelRoleOverrides.add(role);
|
|
1806
|
+
continue;
|
|
1807
|
+
}
|
|
1808
|
+
delete baseModelRoles[role];
|
|
1809
|
+
}
|
|
1810
|
+
for (const role of installedKeys?.agentModelOverrides ?? []) {
|
|
1811
|
+
if (options.preserveManualOverrides && manualAgentModelOverrides.has(role)) continue;
|
|
1812
|
+
const installed = installedState?.installedAgentModelOverrides.get(role);
|
|
1813
|
+
if (
|
|
1814
|
+
options.preserveManualOverrides &&
|
|
1815
|
+
installed !== undefined &&
|
|
1816
|
+
!selectorValuesEqual(baseAgentModelOverrides[role], installed)
|
|
1817
|
+
) {
|
|
1818
|
+
manualAgentModelOverrides.add(role);
|
|
1819
|
+
continue;
|
|
1820
|
+
}
|
|
1821
|
+
delete baseAgentModelOverrides[role];
|
|
1822
|
+
}
|
|
1823
|
+
// Compare the current session override with the installed profile value
|
|
1824
|
+
// before excluding configured bindings from the successor baseline. The
|
|
1825
|
+
// current value may itself be the installed profile value; filtering first
|
|
1826
|
+
// would misclassify that role as a manual override during configuration reload.
|
|
1827
|
+
for (const role of Object.keys(configuredAgentModelOverrides ?? {})) {
|
|
1828
|
+
if (!manualAgentModelOverrides.has(role)) delete baseAgentModelOverrides[role];
|
|
1829
|
+
}
|
|
1830
|
+
for (const [role, value] of installedState?.modelRoles ?? []) {
|
|
1831
|
+
if (manualModelRoleOverrides.has(role)) continue;
|
|
1832
|
+
if (value === undefined) delete baseModelRoles[role];
|
|
1833
|
+
else baseModelRoles[role] = value;
|
|
1834
|
+
}
|
|
1835
|
+
for (const [role, value] of installedState?.agentModelOverrides ?? []) {
|
|
1836
|
+
if (manualAgentModelOverrides.has(role)) continue;
|
|
1837
|
+
const configuredBinding = configuredAgentModelOverrides?.[role];
|
|
1838
|
+
if (configuredBinding !== undefined) {
|
|
1839
|
+
// Configured bindings are reapplied when the active profile is cleared;
|
|
1840
|
+
// leaving them in this baseline makes omitted successor roles stay live.
|
|
1841
|
+
delete baseAgentModelOverrides[role];
|
|
1842
|
+
} else if (installedState?.configuredAgentModelOverrides.has(role)) {
|
|
1843
|
+
// A removed binding must not revive its former value from the profile
|
|
1844
|
+
// baseline after a configuration reload.
|
|
1845
|
+
delete baseAgentModelOverrides[role];
|
|
1846
|
+
} else if (value === undefined) {
|
|
1847
|
+
delete baseAgentModelOverrides[role];
|
|
1848
|
+
} else {
|
|
1849
|
+
baseAgentModelOverrides[role] = value;
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
const preparedDefaultModelSelection =
|
|
1853
|
+
options.prepareSessionModelSelection && defaultModel
|
|
1854
|
+
? await options.session.prepareModelSelectionForProfileActivation?.(
|
|
1855
|
+
defaultModel,
|
|
1856
|
+
defaultThinkingLevel,
|
|
1857
|
+
options.signal,
|
|
1858
|
+
)
|
|
1859
|
+
: undefined;
|
|
1860
|
+
if (options.prepareSessionModelSelection && defaultModel && !preparedDefaultModelSelection) {
|
|
1861
|
+
throw new Error("Session cannot prepare a synchronous profile model selection");
|
|
1862
|
+
}
|
|
1863
|
+
options.signal?.throwIfAborted();
|
|
1864
|
+
const nextModelRoles = { ...modelRoles };
|
|
1865
|
+
const nextAgentModelOverrides = { ...agentModelOverrides };
|
|
1866
|
+
for (const role of manualModelRoleOverrides) delete nextModelRoles[role];
|
|
1867
|
+
for (const role of manualAgentModelOverrides) delete nextAgentModelOverrides[role];
|
|
1576
1868
|
|
|
1577
1869
|
return {
|
|
1578
1870
|
profileName,
|
|
1579
1871
|
session: options.session as PreparedModelProfileActivation["session"],
|
|
1580
|
-
settings:
|
|
1872
|
+
settings: applySettings as PreparedModelProfileActivation["settings"],
|
|
1581
1873
|
modelRegistry: options.modelRegistry,
|
|
1582
1874
|
previousModel,
|
|
1583
1875
|
previousCanonicalVariant,
|
|
1584
1876
|
previousUserCanonicalVariantSelection,
|
|
1585
1877
|
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
|
|
1878
|
+
previousAgentModelOverrides: { ...applySettings.get("task.agentModelOverrides") },
|
|
1879
|
+
previousModelRoles: { ...applySettings.get("modelRoles") },
|
|
1880
|
+
baseAgentModelOverrides,
|
|
1881
|
+
baseModelRoles,
|
|
1882
|
+
previousPersistedModelRoles: applySettings.getGlobal("modelRoles"),
|
|
1883
|
+
previousPersistedAgentModelOverrides: applySettings.getGlobal("task.agentModelOverrides"),
|
|
1884
|
+
previousModelRolesOverride: applySettings.getOverride("modelRoles"),
|
|
1885
|
+
previousAgentModelOverridesOverride: applySettings.getOverride("task.agentModelOverrides"),
|
|
1886
|
+
previousDefaultProfileOverride: applySettings.getOverride("modelProfile.default"),
|
|
1887
|
+
previousPersistedDefaultProfile: applySettings.getGlobal("modelProfile.default"),
|
|
1888
|
+
previousPersistedDefaultThinkingLevel: applySettings.getGlobal("defaultThinkingLevel") as
|
|
1606
1889
|
| Exclude<ThinkingLevel, "inherit">
|
|
1607
1890
|
| undefined,
|
|
1608
|
-
previousDefaultThinkingLevelOverride:
|
|
1891
|
+
previousDefaultThinkingLevelOverride: applySettings.getOverride("defaultThinkingLevel"),
|
|
1609
1892
|
previousDefaultChain: options.session.getConfiguredModelChain("default"),
|
|
1610
1893
|
previousDefaultChainState: options.session.getConfiguredModelChainState?.("default"),
|
|
1894
|
+
previousProfileInstalledOverrideState: installedState,
|
|
1895
|
+
preparedDefaultModelSelection,
|
|
1896
|
+
defaultChainPublished: false,
|
|
1897
|
+
defaultModelPublished: false,
|
|
1898
|
+
publishedState: undefined,
|
|
1611
1899
|
|
|
1612
1900
|
defaultModel,
|
|
1613
1901
|
defaultThinkingLevel,
|
|
1614
1902
|
defaultActiveIndex,
|
|
1615
1903
|
defaultResolutionSkips,
|
|
1616
1904
|
defaultChain,
|
|
1617
|
-
modelRoles,
|
|
1618
|
-
agentModelOverrides,
|
|
1905
|
+
modelRoles: nextModelRoles,
|
|
1906
|
+
agentModelOverrides: nextAgentModelOverrides,
|
|
1907
|
+
manualModelRoleOverrides,
|
|
1908
|
+
manualAgentModelOverrides,
|
|
1619
1909
|
previousActiveModelProfile: options.session.getActiveModelProfile?.(),
|
|
1910
|
+
previousActivatedModelProfile: options.session.getActivatedModelProfile?.(),
|
|
1620
1911
|
previousSessionDefaultModel: options.session.getSessionDefaultModelSelector?.(),
|
|
1621
1912
|
previousDefaultFallbackRuntimeState: options.session.getDefaultFallbackRuntimeState?.(),
|
|
1622
1913
|
};
|
|
@@ -1707,34 +1998,45 @@ function restoreConcurrentProfileOverrides(
|
|
|
1707
1998
|
return Object.keys(restored).length > 0 || previous !== undefined ? restored : undefined;
|
|
1708
1999
|
}
|
|
1709
2000
|
|
|
1710
|
-
|
|
2001
|
+
function capturePublishedModelProfileActivationState(
|
|
1711
2002
|
prepared: PreparedModelProfileActivation,
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
2003
|
+
): PublishedModelProfileActivationState {
|
|
2004
|
+
return {
|
|
2005
|
+
model: prepared.session.model,
|
|
2006
|
+
thinkingLevel: prepared.session.thinkingLevel,
|
|
2007
|
+
modelRolesOverride: prepared.settings.getOverride("modelRoles"),
|
|
2008
|
+
agentModelOverridesOverride: prepared.settings.getOverride("task.agentModelOverrides"),
|
|
2009
|
+
defaultChainState: prepared.session.getConfiguredModelChainState?.("default"),
|
|
2010
|
+
defaultFallbackRuntimeState: prepared.session.getDefaultFallbackRuntimeState?.(),
|
|
2011
|
+
activeModelProfile: prepared.session.getActiveModelProfile?.(),
|
|
2012
|
+
activatedModelProfile: prepared.session.getActivatedModelProfile?.(),
|
|
2013
|
+
profileInstalledOverrideState: prepared.session.getProfileInstalledOverrideState?.(),
|
|
2014
|
+
sessionDefaultModel: prepared.session.getSessionDefaultModelSelector?.(),
|
|
2015
|
+
persistedModelRoles: prepared.settings.getGlobal("modelRoles"),
|
|
2016
|
+
persistedAgentModelOverrides: prepared.settings.getGlobal("task.agentModelOverrides"),
|
|
2017
|
+
persistedDefaultProfile: prepared.settings.getGlobal("modelProfile.default"),
|
|
2018
|
+
persistedDefaultThinkingLevel: prepared.settings.getGlobal("defaultThinkingLevel"),
|
|
2019
|
+
defaultThinkingLevelOverride: prepared.settings.getOverride("defaultThinkingLevel"),
|
|
2020
|
+
defaultProfileOverride: prepared.settings.getOverride("modelProfile.default"),
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
1726
2023
|
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
2024
|
+
/** Publish the prepared model selection and role layer without awaiting. */
|
|
2025
|
+
export function publishPreparedModelProfileActivation(
|
|
2026
|
+
prepared: PreparedModelProfileActivation,
|
|
2027
|
+
options: Pick<
|
|
2028
|
+
ApplyModelProfileActivationOptions,
|
|
2029
|
+
"preserveDefaultModelSelection" | "preserveLiveModelSelection"
|
|
2030
|
+
> = {},
|
|
2031
|
+
): void {
|
|
2032
|
+
if (!options.preserveDefaultModelSelection && prepared.preparedDefaultModelSelection) {
|
|
1731
2033
|
const ownedDefaultChain =
|
|
1732
2034
|
prepared.defaultChain.length > 0
|
|
1733
2035
|
? prepared.defaultChain
|
|
1734
2036
|
: (prepared.previousDefaultChain ??
|
|
1735
2037
|
(prepared.previousModel ? [formatModelString(prepared.previousModel)] : []));
|
|
1736
2038
|
if (ownedDefaultChain.length > 0) {
|
|
1737
|
-
|
|
2039
|
+
prepared.defaultChainPublished = true;
|
|
1738
2040
|
prepared.session.setConfiguredModelChain(
|
|
1739
2041
|
"default",
|
|
1740
2042
|
ownedDefaultChain,
|
|
@@ -1748,44 +2050,152 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1748
2050
|
prepared.defaultResolutionSkips,
|
|
1749
2051
|
);
|
|
1750
2052
|
}
|
|
1751
|
-
activatedDefaultChainState = prepared.session.getConfiguredModelChainState?.("default");
|
|
1752
|
-
activatedFallbackRuntimeState = prepared.session.getDefaultFallbackRuntimeState?.();
|
|
1753
2053
|
}
|
|
1754
|
-
|
|
2054
|
+
}
|
|
2055
|
+
if (
|
|
2056
|
+
!options.preserveDefaultModelSelection &&
|
|
2057
|
+
!options.preserveLiveModelSelection &&
|
|
2058
|
+
prepared.preparedDefaultModelSelection
|
|
2059
|
+
) {
|
|
2060
|
+
prepared.defaultModelPublished = true;
|
|
2061
|
+
if (!prepared.session.commitPreparedProfileModelSelection) {
|
|
2062
|
+
throw new Error("Session cannot commit a prepared profile model selection");
|
|
2063
|
+
}
|
|
2064
|
+
prepared.session.commitPreparedProfileModelSelection(prepared.preparedDefaultModelSelection);
|
|
2065
|
+
(prepared.session.modelRegistry ?? prepared.modelRegistry).seedCanonicalVariant?.(
|
|
2066
|
+
prepared.session.sessionId,
|
|
2067
|
+
prepared.defaultModel!,
|
|
2068
|
+
);
|
|
2069
|
+
prepared.session.recordResumeDefaultModel?.(`${prepared.defaultModel!.provider}/${prepared.defaultModel!.id}`);
|
|
2070
|
+
}
|
|
2071
|
+
prepared.settings.override("modelRoles", {
|
|
2072
|
+
...prepared.baseModelRoles,
|
|
2073
|
+
...prepared.modelRoles,
|
|
2074
|
+
});
|
|
2075
|
+
prepared.settings.override("task.agentModelOverrides", {
|
|
2076
|
+
...prepared.baseAgentModelOverrides,
|
|
2077
|
+
...prepared.agentModelOverrides,
|
|
2078
|
+
});
|
|
2079
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName, true);
|
|
2080
|
+
prepared.session.noteProfileInstalledOverrides?.(
|
|
2081
|
+
Object.keys(prepared.modelRoles),
|
|
2082
|
+
Object.keys(prepared.agentModelOverrides),
|
|
2083
|
+
prepared.previousModel,
|
|
2084
|
+
{ modelRoles: prepared.baseModelRoles, agentModelOverrides: prepared.baseAgentModelOverrides },
|
|
2085
|
+
{ modelRoles: prepared.modelRoles, agentModelOverrides: prepared.agentModelOverrides },
|
|
2086
|
+
{
|
|
2087
|
+
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
2088
|
+
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
2089
|
+
},
|
|
2090
|
+
prepared.defaultChain,
|
|
2091
|
+
);
|
|
2092
|
+
prepared.publishedState = capturePublishedModelProfileActivationState(prepared);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
export async function finishPreparedModelProfileActivation(prepared: PreparedModelProfileActivation): Promise<void> {
|
|
2096
|
+
if (prepared.defaultModelPublished && prepared.preparedDefaultModelSelection) {
|
|
2097
|
+
try {
|
|
2098
|
+
await prepared.session.finishPreparedProfileModelSelection?.(prepared.preparedDefaultModelSelection);
|
|
2099
|
+
} catch (error) {
|
|
2100
|
+
logger.warn("Failed to refresh session tools after model profile activation", {
|
|
2101
|
+
profile: prepared.profileName,
|
|
2102
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
try {
|
|
2107
|
+
await prepared.session.syncEagerDelegation?.();
|
|
2108
|
+
} catch (error) {
|
|
2109
|
+
logger.warn("Failed to sync eager delegation after model profile activation", {
|
|
2110
|
+
profile: prepared.profileName,
|
|
2111
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
export async function applyPreparedModelProfileActivation(
|
|
2117
|
+
prepared: PreparedModelProfileActivation,
|
|
2118
|
+
options: ApplyModelProfileActivationOptions = {},
|
|
2119
|
+
): Promise<void> {
|
|
2120
|
+
let activationStage = "default chain";
|
|
2121
|
+
let modelMutationStarted = false;
|
|
2122
|
+
let overridesChanged = false;
|
|
2123
|
+
let modelRolesChanged = false;
|
|
2124
|
+
let persistentMutationStarted = false;
|
|
2125
|
+
let defaultChainChanged = false;
|
|
2126
|
+
let resumeDefaultChanged = false;
|
|
2127
|
+
let activatedDefaultChainState: ConfiguredModelChainState | undefined;
|
|
2128
|
+
let activatedFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
2129
|
+
let activatedModelRolesOverride: unknown;
|
|
2130
|
+
let activatedAgentModelOverridesOverride: unknown;
|
|
2131
|
+
let activatedProfileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
2132
|
+
let activatedResumeDefaultModel: string | undefined;
|
|
2133
|
+
|
|
2134
|
+
try {
|
|
2135
|
+
if (!options.deferRuntimePublication && !options.preserveDefaultModelSelection) {
|
|
2136
|
+
const ownedDefaultChain =
|
|
2137
|
+
prepared.defaultChain.length > 0
|
|
2138
|
+
? prepared.defaultChain
|
|
2139
|
+
: (prepared.previousDefaultChain ??
|
|
2140
|
+
(prepared.previousModel ? [formatModelString(prepared.previousModel)] : []));
|
|
2141
|
+
if (ownedDefaultChain.length > 0) {
|
|
2142
|
+
defaultChainChanged = true;
|
|
2143
|
+
prepared.session.setConfiguredModelChain(
|
|
2144
|
+
"default",
|
|
2145
|
+
ownedDefaultChain,
|
|
2146
|
+
"profile-activation",
|
|
2147
|
+
prepared.profileName,
|
|
2148
|
+
true,
|
|
2149
|
+
);
|
|
2150
|
+
if (prepared.defaultActiveIndex !== undefined) {
|
|
2151
|
+
prepared.session.seedDefaultFallbackResolution?.(
|
|
2152
|
+
prepared.defaultActiveIndex,
|
|
2153
|
+
prepared.defaultResolutionSkips,
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
activatedDefaultChainState = prepared.session.getConfiguredModelChainState?.("default");
|
|
2157
|
+
activatedFallbackRuntimeState = prepared.session.getDefaultFallbackRuntimeState?.();
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
if (
|
|
2161
|
+
!options.deferRuntimePublication &&
|
|
2162
|
+
!options.preserveDefaultModelSelection &&
|
|
2163
|
+
!options.preserveLiveModelSelection &&
|
|
2164
|
+
prepared.defaultModel
|
|
2165
|
+
) {
|
|
1755
2166
|
activationStage = "model selection";
|
|
1756
2167
|
await prepared.session.setModelTemporary(
|
|
1757
2168
|
prepared.defaultModel,
|
|
1758
2169
|
options.thinkingLevelOverride ?? prepared.defaultThinkingLevel,
|
|
1759
2170
|
{
|
|
1760
2171
|
cause: "profile-activation",
|
|
2172
|
+
signal: options.signal,
|
|
1761
2173
|
shouldMutate: options.isCurrent,
|
|
1762
2174
|
onMutationStarted: () => {
|
|
1763
2175
|
modelMutationStarted = true;
|
|
1764
2176
|
},
|
|
1765
2177
|
},
|
|
1766
2178
|
);
|
|
2179
|
+
options.signal?.throwIfAborted();
|
|
1767
2180
|
if (options.isCurrent && !modelMutationStarted) throw new ModelProfileActivationSupersededError();
|
|
1768
2181
|
if (options.isCurrent && !options.isCurrent()) throw new ModelProfileActivationSupersededError();
|
|
1769
2182
|
}
|
|
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;
|
|
2183
|
+
if (!options.deferRuntimePublication) {
|
|
2184
|
+
activationStage = "model role overrides";
|
|
2185
|
+
prepared.settings.override("modelRoles", {
|
|
2186
|
+
...prepared.baseModelRoles,
|
|
2187
|
+
...prepared.modelRoles,
|
|
2188
|
+
});
|
|
2189
|
+
activatedModelRolesOverride = prepared.settings.getOverride("modelRoles");
|
|
2190
|
+
modelRolesChanged = true;
|
|
2191
|
+
activationStage = "agent role overrides";
|
|
2192
|
+
prepared.settings.override("task.agentModelOverrides", {
|
|
2193
|
+
...prepared.baseAgentModelOverrides,
|
|
2194
|
+
...prepared.agentModelOverrides,
|
|
2195
|
+
});
|
|
2196
|
+
activatedAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2197
|
+
overridesChanged = true;
|
|
2198
|
+
}
|
|
1789
2199
|
if (options.persistDefault) {
|
|
1790
2200
|
persistentMutationStarted = true;
|
|
1791
2201
|
activationStage = "persist model roles";
|
|
@@ -1802,28 +2212,47 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1802
2212
|
await prepared.settings.flushOrThrow();
|
|
1803
2213
|
}
|
|
1804
2214
|
if (options.isCurrent && !options.isCurrent()) throw new ModelProfileActivationSupersededError();
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
2215
|
+
if (!options.deferRuntimePublication) {
|
|
2216
|
+
activationStage = "active profile marker";
|
|
2217
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName, true);
|
|
2218
|
+
activationStage = "installed role tracking";
|
|
2219
|
+
prepared.session.noteProfileInstalledOverrides?.(
|
|
2220
|
+
Object.keys(prepared.modelRoles),
|
|
2221
|
+
Object.keys(prepared.agentModelOverrides),
|
|
2222
|
+
prepared.previousModel,
|
|
2223
|
+
{ modelRoles: prepared.baseModelRoles, agentModelOverrides: prepared.baseAgentModelOverrides },
|
|
2224
|
+
{ modelRoles: prepared.modelRoles, agentModelOverrides: prepared.agentModelOverrides },
|
|
2225
|
+
{
|
|
2226
|
+
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
2227
|
+
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
2228
|
+
},
|
|
2229
|
+
prepared.defaultChain,
|
|
2230
|
+
);
|
|
2231
|
+
activatedProfileInstalledOverrideState = prepared.session.getProfileInstalledOverrideState?.();
|
|
2232
|
+
}
|
|
2233
|
+
if (
|
|
2234
|
+
!options.deferRuntimePublication &&
|
|
2235
|
+
!options.preserveDefaultModelSelection &&
|
|
2236
|
+
!options.preserveLiveModelSelection &&
|
|
2237
|
+
prepared.defaultModel
|
|
2238
|
+
) {
|
|
1808
2239
|
activationStage = "canonical model variant";
|
|
1809
2240
|
prepared.modelRegistry.seedCanonicalVariant?.(prepared.session.sessionId, prepared.defaultModel);
|
|
1810
2241
|
resumeDefaultChanged = true;
|
|
1811
2242
|
activationStage = "resume default model";
|
|
1812
|
-
|
|
2243
|
+
activatedResumeDefaultModel = `${prepared.defaultModel.provider}/${prepared.defaultModel.id}`;
|
|
2244
|
+
prepared.session.recordResumeDefaultModel?.(activatedResumeDefaultModel);
|
|
1813
2245
|
}
|
|
1814
|
-
|
|
1815
|
-
prepared.session.noteProfileInstalledOverrides?.(
|
|
1816
|
-
Object.keys(prepared.modelRoles),
|
|
1817
|
-
Object.keys(prepared.agentModelOverrides),
|
|
1818
|
-
prepared.previousModel,
|
|
1819
|
-
);
|
|
2246
|
+
prepared.publishedState = capturePublishedModelProfileActivationState(prepared);
|
|
1820
2247
|
} catch (error) {
|
|
1821
2248
|
const activationWasCancelled = error instanceof ModelProfileActivationSupersededError;
|
|
1822
|
-
const
|
|
2249
|
+
const selectionIsCurrent = () => options.isCurrent?.() !== false;
|
|
1823
2250
|
const shouldRestoreFallbackRuntimeState =
|
|
1824
2251
|
prepared.previousDefaultFallbackRuntimeState !== undefined &&
|
|
1825
|
-
(
|
|
2252
|
+
(selectionIsCurrent() ||
|
|
1826
2253
|
sameSerializedValue(prepared.session.getDefaultFallbackRuntimeState?.(), activatedFallbackRuntimeState));
|
|
2254
|
+
let modelRollbackSelectionRevision: number | undefined;
|
|
2255
|
+
let modelRollbackSelectionWasCurrent = false;
|
|
1827
2256
|
const rollbackErrors: Array<{ stage: string; error: unknown }> = [];
|
|
1828
2257
|
const restore = (stage: string, action: () => void): void => {
|
|
1829
2258
|
try {
|
|
@@ -1834,7 +2263,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1834
2263
|
};
|
|
1835
2264
|
if (persistentMutationStarted) {
|
|
1836
2265
|
if (
|
|
1837
|
-
|
|
2266
|
+
selectionIsCurrent() ||
|
|
1838
2267
|
sameSerializedValue(prepared.settings.getGlobal("modelProfile.default"), prepared.profileName)
|
|
1839
2268
|
) {
|
|
1840
2269
|
restore("restore default profile setting", () =>
|
|
@@ -1845,7 +2274,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1845
2274
|
}
|
|
1846
2275
|
const currentPersistedModelRoles = prepared.settings.getGlobal("modelRoles");
|
|
1847
2276
|
const restoredModelRoles =
|
|
1848
|
-
|
|
2277
|
+
!selectionIsCurrent() && currentPersistedModelRoles && !sameSerializedValue(currentPersistedModelRoles, {})
|
|
1849
2278
|
? { ...(prepared.previousPersistedModelRoles ?? {}), ...currentPersistedModelRoles }
|
|
1850
2279
|
: prepared.previousPersistedModelRoles;
|
|
1851
2280
|
restore("restore model role setting", () =>
|
|
@@ -1855,7 +2284,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1855
2284
|
);
|
|
1856
2285
|
const currentPersistedAgentModelOverrides = prepared.settings.getGlobal("task.agentModelOverrides");
|
|
1857
2286
|
const restoredPersistedAgentModelOverrides =
|
|
1858
|
-
|
|
2287
|
+
!selectionIsCurrent() &&
|
|
1859
2288
|
currentPersistedAgentModelOverrides &&
|
|
1860
2289
|
!sameSerializedValue(currentPersistedAgentModelOverrides, {})
|
|
1861
2290
|
? {
|
|
@@ -1873,7 +2302,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1873
2302
|
? prepared.defaultThinkingLevel
|
|
1874
2303
|
: prepared.previousPersistedDefaultThinkingLevel;
|
|
1875
2304
|
if (
|
|
1876
|
-
|
|
2305
|
+
selectionIsCurrent() ||
|
|
1877
2306
|
sameSerializedValue(prepared.settings.getGlobal("defaultThinkingLevel"), activatedThinkingLevel)
|
|
1878
2307
|
) {
|
|
1879
2308
|
restore("restore thinking level setting", () =>
|
|
@@ -1885,7 +2314,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1885
2314
|
}
|
|
1886
2315
|
if (
|
|
1887
2316
|
modelRolesChanged &&
|
|
1888
|
-
(
|
|
2317
|
+
(selectionIsCurrent() ||
|
|
1889
2318
|
sameSerializedValue(prepared.settings.getOverride("modelRoles"), activatedModelRolesOverride))
|
|
1890
2319
|
) {
|
|
1891
2320
|
restore("restore model role overrides", () =>
|
|
@@ -1896,7 +2325,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1896
2325
|
}
|
|
1897
2326
|
if (
|
|
1898
2327
|
overridesChanged &&
|
|
1899
|
-
(
|
|
2328
|
+
(selectionIsCurrent() ||
|
|
1900
2329
|
sameSerializedValue(
|
|
1901
2330
|
prepared.settings.getOverride("task.agentModelOverrides"),
|
|
1902
2331
|
activatedAgentModelOverridesOverride,
|
|
@@ -1908,7 +2337,9 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1908
2337
|
: prepared.settings.override("task.agentModelOverrides", prepared.previousAgentModelOverridesOverride),
|
|
1909
2338
|
);
|
|
1910
2339
|
}
|
|
1911
|
-
if (modelMutationStarted &&
|
|
2340
|
+
if (modelMutationStarted && selectionIsCurrent()) {
|
|
2341
|
+
modelRollbackSelectionWasCurrent = selectionIsCurrent();
|
|
2342
|
+
modelRollbackSelectionRevision = prepared.session.getUserModelSelectionRevision?.();
|
|
1912
2343
|
try {
|
|
1913
2344
|
if (prepared.session.restoreModelSelectionForRollback) {
|
|
1914
2345
|
await prepared.session.restoreModelSelectionForRollback(
|
|
@@ -1918,6 +2349,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1918
2349
|
} else if (prepared.previousModel) {
|
|
1919
2350
|
await prepared.session.setModelTemporary(prepared.previousModel, prepared.previousThinkingLevel, {
|
|
1920
2351
|
cause: "rollback",
|
|
2352
|
+
shouldMutate: selectionIsCurrent,
|
|
1921
2353
|
});
|
|
1922
2354
|
} else {
|
|
1923
2355
|
throw new Error("Model-less profile activation rollback is unavailable");
|
|
@@ -1926,14 +2358,18 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1926
2358
|
rollbackErrors.push({ stage: "restore live model", error: rollbackError });
|
|
1927
2359
|
}
|
|
1928
2360
|
}
|
|
1929
|
-
if (
|
|
2361
|
+
if (
|
|
2362
|
+
resumeDefaultChanged &&
|
|
2363
|
+
selectionIsCurrent() &&
|
|
2364
|
+
sameSerializedValue(prepared.session.getSessionDefaultModelSelector?.(), activatedResumeDefaultModel)
|
|
2365
|
+
) {
|
|
1930
2366
|
restore("restore resume default", () =>
|
|
1931
2367
|
prepared.session.recordResumeDefaultModel?.(prepared.previousSessionDefaultModel),
|
|
1932
2368
|
);
|
|
1933
2369
|
}
|
|
1934
2370
|
if (
|
|
1935
2371
|
defaultChainChanged &&
|
|
1936
|
-
(
|
|
2372
|
+
(selectionIsCurrent() ||
|
|
1937
2373
|
sameSerializedValue(prepared.session.getConfiguredModelChainState?.("default"), activatedDefaultChainState))
|
|
1938
2374
|
) {
|
|
1939
2375
|
const previousChain = prepared.previousDefaultChainState;
|
|
@@ -1949,14 +2385,34 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1949
2385
|
),
|
|
1950
2386
|
);
|
|
1951
2387
|
}
|
|
1952
|
-
|
|
2388
|
+
const userSelectionChangedDuringModelRollback =
|
|
2389
|
+
modelRollbackSelectionRevision !== undefined
|
|
2390
|
+
? prepared.session.getUserModelSelectionRevision?.() !== modelRollbackSelectionRevision
|
|
2391
|
+
: modelRollbackSelectionWasCurrent && !selectionIsCurrent();
|
|
2392
|
+
if (shouldRestoreFallbackRuntimeState && !userSelectionChangedDuringModelRollback) {
|
|
1953
2393
|
restore("restore fallback runtime", () =>
|
|
1954
2394
|
prepared.session.restoreDefaultFallbackRuntimeState?.(prepared.previousDefaultFallbackRuntimeState!),
|
|
1955
2395
|
);
|
|
1956
2396
|
}
|
|
1957
|
-
if (
|
|
2397
|
+
if (selectionIsCurrent()) {
|
|
1958
2398
|
restore("restore active profile", () =>
|
|
1959
|
-
prepared.session.setActiveModelProfile?.(
|
|
2399
|
+
prepared.session.setActiveModelProfile?.(
|
|
2400
|
+
prepared.previousActiveModelProfile,
|
|
2401
|
+
prepared.previousActivatedModelProfile === prepared.previousActiveModelProfile,
|
|
2402
|
+
),
|
|
2403
|
+
);
|
|
2404
|
+
}
|
|
2405
|
+
if (
|
|
2406
|
+
prepared.previousProfileInstalledOverrideState &&
|
|
2407
|
+
(selectionIsCurrent() ||
|
|
2408
|
+
(activatedProfileInstalledOverrideState !== undefined &&
|
|
2409
|
+
util.isDeepStrictEqual(
|
|
2410
|
+
prepared.session.getProfileInstalledOverrideState?.(),
|
|
2411
|
+
activatedProfileInstalledOverrideState,
|
|
2412
|
+
)))
|
|
2413
|
+
) {
|
|
2414
|
+
restore("restore installed role tracking", () =>
|
|
2415
|
+
prepared.session.restoreProfileInstalledOverrideState?.(prepared.previousProfileInstalledOverrideState!),
|
|
1960
2416
|
);
|
|
1961
2417
|
}
|
|
1962
2418
|
restore("restore canonical model variant", () =>
|
|
@@ -1980,17 +2436,258 @@ export async function applyPreparedModelProfileActivation(
|
|
|
1980
2436
|
if (activationWasCancelled) return;
|
|
1981
2437
|
throw error;
|
|
1982
2438
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2439
|
+
if (!options.deferRuntimePublication) await finishPreparedModelProfileActivation(prepared);
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
/** Restore an applied activation when its enclosing settings/registry commit fails. */
|
|
2443
|
+
export async function rollbackPreparedModelProfileActivation(
|
|
2444
|
+
prepared: PreparedModelProfileActivation,
|
|
2445
|
+
options: ApplyModelProfileActivationOptions = {},
|
|
2446
|
+
): Promise<void> {
|
|
2447
|
+
const failures: Array<{ stage: string; error: unknown }> = [];
|
|
2448
|
+
const restore = (stage: string, action: () => void): void => {
|
|
2449
|
+
try {
|
|
2450
|
+
action();
|
|
2451
|
+
} catch (error) {
|
|
2452
|
+
failures.push({ stage, error });
|
|
2453
|
+
}
|
|
2454
|
+
};
|
|
2455
|
+
const restoreAsync = async (stage: string, action: () => Promise<void>): Promise<void> => {
|
|
2456
|
+
try {
|
|
2457
|
+
await action();
|
|
2458
|
+
} catch (error) {
|
|
2459
|
+
failures.push({ stage, error });
|
|
2460
|
+
}
|
|
2461
|
+
};
|
|
2462
|
+
const selectionIsCurrent = () => options.isCurrent?.() !== false;
|
|
2463
|
+
const publishedState = prepared.publishedState;
|
|
2464
|
+
const canRestorePublishedState = (current: unknown, activated: unknown): boolean =>
|
|
2465
|
+
publishedState === undefined ? selectionIsCurrent() : util.isDeepStrictEqual(current, activated);
|
|
2466
|
+
const canRollbackPublishedProfile = (): boolean =>
|
|
2467
|
+
publishedState === undefined
|
|
2468
|
+
? selectionIsCurrent()
|
|
2469
|
+
: util.isDeepStrictEqual(prepared.session.getActiveModelProfile?.(), publishedState.activeModelProfile) &&
|
|
2470
|
+
util.isDeepStrictEqual(prepared.session.getActivatedModelProfile?.(), publishedState.activatedModelProfile);
|
|
2471
|
+
|
|
2472
|
+
if (options.persistDefault) {
|
|
2473
|
+
if (
|
|
2474
|
+
canRestorePublishedState(
|
|
2475
|
+
prepared.settings.getGlobal("modelProfile.default"),
|
|
2476
|
+
publishedState?.persistedDefaultProfile,
|
|
2477
|
+
)
|
|
2478
|
+
) {
|
|
2479
|
+
restore("restore persisted default profile", () =>
|
|
2480
|
+
prepared.previousPersistedDefaultProfile === undefined
|
|
2481
|
+
? prepared.settings.unset("modelProfile.default")
|
|
2482
|
+
: prepared.settings.set("modelProfile.default", prepared.previousPersistedDefaultProfile),
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
const currentPersistedModelRoles = prepared.settings.getGlobal("modelRoles");
|
|
2486
|
+
const restoredPersistedModelRoles =
|
|
2487
|
+
publishedState && canRollbackPublishedProfile()
|
|
2488
|
+
? restoreConcurrentProfileOverrides(
|
|
2489
|
+
prepared.previousPersistedModelRoles,
|
|
2490
|
+
publishedState.persistedModelRoles,
|
|
2491
|
+
currentPersistedModelRoles,
|
|
2492
|
+
)
|
|
2493
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2494
|
+
? prepared.previousPersistedModelRoles
|
|
2495
|
+
: currentPersistedModelRoles;
|
|
2496
|
+
if (!util.isDeepStrictEqual(restoredPersistedModelRoles, currentPersistedModelRoles)) {
|
|
2497
|
+
restore("restore persisted model roles", () =>
|
|
2498
|
+
restoredPersistedModelRoles === undefined
|
|
2499
|
+
? prepared.settings.unset("modelRoles")
|
|
2500
|
+
: prepared.settings.set("modelRoles", restoredPersistedModelRoles),
|
|
2501
|
+
);
|
|
2502
|
+
}
|
|
2503
|
+
const currentPersistedAgentOverrides = prepared.settings.getGlobal("task.agentModelOverrides");
|
|
2504
|
+
const restoredPersistedAgentOverrides =
|
|
2505
|
+
publishedState && canRollbackPublishedProfile()
|
|
2506
|
+
? restoreConcurrentProfileOverrides(
|
|
2507
|
+
prepared.previousPersistedAgentModelOverrides,
|
|
2508
|
+
publishedState.persistedAgentModelOverrides,
|
|
2509
|
+
currentPersistedAgentOverrides,
|
|
2510
|
+
)
|
|
2511
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2512
|
+
? prepared.previousPersistedAgentModelOverrides
|
|
2513
|
+
: currentPersistedAgentOverrides;
|
|
2514
|
+
if (!util.isDeepStrictEqual(restoredPersistedAgentOverrides, currentPersistedAgentOverrides)) {
|
|
2515
|
+
restore("restore persisted agent overrides", () =>
|
|
2516
|
+
restoredPersistedAgentOverrides === undefined
|
|
2517
|
+
? prepared.settings.unset("task.agentModelOverrides")
|
|
2518
|
+
: prepared.settings.set("task.agentModelOverrides", restoredPersistedAgentOverrides),
|
|
2519
|
+
);
|
|
2520
|
+
}
|
|
2521
|
+
if (
|
|
2522
|
+
canRestorePublishedState(
|
|
2523
|
+
prepared.settings.getGlobal("defaultThinkingLevel"),
|
|
2524
|
+
publishedState?.persistedDefaultThinkingLevel,
|
|
2525
|
+
)
|
|
2526
|
+
) {
|
|
2527
|
+
restore("restore persisted thinking level", () =>
|
|
2528
|
+
prepared.previousPersistedDefaultThinkingLevel === undefined
|
|
2529
|
+
? prepared.settings.unset("defaultThinkingLevel")
|
|
2530
|
+
: prepared.settings.set("defaultThinkingLevel", prepared.previousPersistedDefaultThinkingLevel),
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
if (
|
|
2534
|
+
canRestorePublishedState(
|
|
2535
|
+
prepared.settings.getOverride("defaultThinkingLevel"),
|
|
2536
|
+
publishedState?.defaultThinkingLevelOverride,
|
|
2537
|
+
)
|
|
2538
|
+
) {
|
|
2539
|
+
restore("restore thinking level override", () =>
|
|
2540
|
+
prepared.previousDefaultThinkingLevelOverride === undefined
|
|
2541
|
+
? prepared.settings.clearOverride("defaultThinkingLevel")
|
|
2542
|
+
: prepared.settings.override("defaultThinkingLevel", prepared.previousDefaultThinkingLevelOverride),
|
|
2543
|
+
);
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
const currentModelRolesOverride = prepared.settings.getOverride("modelRoles");
|
|
2547
|
+
const restoredModelRolesOverride =
|
|
2548
|
+
publishedState && canRollbackPublishedProfile()
|
|
2549
|
+
? restoreConcurrentProfileOverrides(
|
|
2550
|
+
prepared.previousModelRolesOverride,
|
|
2551
|
+
publishedState.modelRolesOverride,
|
|
2552
|
+
currentModelRolesOverride,
|
|
2553
|
+
)
|
|
2554
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2555
|
+
? prepared.previousModelRolesOverride
|
|
2556
|
+
: currentModelRolesOverride;
|
|
2557
|
+
if (!util.isDeepStrictEqual(restoredModelRolesOverride, currentModelRolesOverride)) {
|
|
2558
|
+
restore("restore model role overrides", () =>
|
|
2559
|
+
restoredModelRolesOverride === undefined
|
|
2560
|
+
? prepared.settings.clearOverride("modelRoles")
|
|
2561
|
+
: prepared.settings.override("modelRoles", restoredModelRolesOverride),
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
const currentAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2565
|
+
const restoredAgentModelOverridesOverride =
|
|
2566
|
+
publishedState && canRollbackPublishedProfile()
|
|
2567
|
+
? restoreConcurrentProfileOverrides(
|
|
2568
|
+
prepared.previousAgentModelOverridesOverride,
|
|
2569
|
+
publishedState.agentModelOverridesOverride,
|
|
2570
|
+
currentAgentModelOverridesOverride,
|
|
2571
|
+
)
|
|
2572
|
+
: publishedState === undefined && selectionIsCurrent()
|
|
2573
|
+
? prepared.previousAgentModelOverridesOverride
|
|
2574
|
+
: currentAgentModelOverridesOverride;
|
|
2575
|
+
if (!util.isDeepStrictEqual(restoredAgentModelOverridesOverride, currentAgentModelOverridesOverride)) {
|
|
2576
|
+
restore("restore agent role overrides", () =>
|
|
2577
|
+
restoredAgentModelOverridesOverride === undefined
|
|
2578
|
+
? prepared.settings.clearOverride("task.agentModelOverrides")
|
|
2579
|
+
: prepared.settings.override("task.agentModelOverrides", restoredAgentModelOverridesOverride),
|
|
2580
|
+
);
|
|
2581
|
+
}
|
|
2582
|
+
if (!options.preserveDefaultModelSelection) {
|
|
2583
|
+
const previousChain = prepared.previousDefaultChainState;
|
|
2584
|
+
if (
|
|
2585
|
+
prepared.defaultChainPublished &&
|
|
2586
|
+
canRollbackPublishedProfile() &&
|
|
2587
|
+
canRestorePublishedState(
|
|
2588
|
+
prepared.session.getConfiguredModelChainState?.("default"),
|
|
2589
|
+
publishedState?.defaultChainState,
|
|
2590
|
+
)
|
|
2591
|
+
) {
|
|
2592
|
+
restore("restore default chain", () =>
|
|
2593
|
+
prepared.session.setConfiguredModelChain(
|
|
2594
|
+
"default",
|
|
2595
|
+
previousChain?.entries ??
|
|
2596
|
+
prepared.previousDefaultChain ??
|
|
2597
|
+
(prepared.previousModel ? [`${prepared.previousModel.provider}/${prepared.previousModel.id}`] : []),
|
|
2598
|
+
previousChain?.origin ?? "rollback",
|
|
2599
|
+
previousChain?.identity,
|
|
2600
|
+
previousChain?.explicitHead ?? true,
|
|
2601
|
+
),
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
if (
|
|
2605
|
+
!options.preserveLiveModelSelection &&
|
|
2606
|
+
selectionIsCurrent() &&
|
|
2607
|
+
prepared.defaultModelPublished &&
|
|
2608
|
+
prepared.defaultModel
|
|
2609
|
+
) {
|
|
2610
|
+
await restoreAsync("restore live model", async () => {
|
|
2611
|
+
if (prepared.session.restoreModelSelectionForRollback) {
|
|
2612
|
+
await prepared.session.restoreModelSelectionForRollback(
|
|
2613
|
+
prepared.previousModel,
|
|
2614
|
+
prepared.previousThinkingLevel,
|
|
2615
|
+
);
|
|
2616
|
+
} else if (prepared.previousModel) {
|
|
2617
|
+
await prepared.session.setModelTemporary(prepared.previousModel, prepared.previousThinkingLevel, {
|
|
2618
|
+
cause: "rollback",
|
|
2619
|
+
shouldMutate: selectionIsCurrent,
|
|
2620
|
+
});
|
|
2621
|
+
} else {
|
|
2622
|
+
throw new Error("Model-less profile activation rollback is unavailable");
|
|
2623
|
+
}
|
|
2624
|
+
});
|
|
2625
|
+
if (
|
|
2626
|
+
selectionIsCurrent() &&
|
|
2627
|
+
canRestorePublishedState(
|
|
2628
|
+
prepared.session.getSessionDefaultModelSelector?.(),
|
|
2629
|
+
publishedState?.sessionDefaultModel,
|
|
2630
|
+
)
|
|
2631
|
+
) {
|
|
2632
|
+
restore("restore session resume default", () =>
|
|
2633
|
+
prepared.session.recordResumeDefaultModel?.(prepared.previousSessionDefaultModel),
|
|
2634
|
+
);
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
if (
|
|
2638
|
+
(prepared.defaultChainPublished || prepared.defaultModelPublished) &&
|
|
2639
|
+
prepared.previousDefaultFallbackRuntimeState &&
|
|
2640
|
+
canRollbackPublishedProfile() &&
|
|
2641
|
+
canRestorePublishedState(
|
|
2642
|
+
prepared.session.getDefaultFallbackRuntimeState?.(),
|
|
2643
|
+
publishedState?.defaultFallbackRuntimeState,
|
|
2644
|
+
)
|
|
2645
|
+
) {
|
|
2646
|
+
restore("restore fallback runtime", () =>
|
|
2647
|
+
prepared.session.restoreDefaultFallbackRuntimeState?.(prepared.previousDefaultFallbackRuntimeState!),
|
|
2648
|
+
);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
if (
|
|
2652
|
+
selectionIsCurrent() &&
|
|
2653
|
+
canRollbackPublishedProfile() &&
|
|
2654
|
+
canRestorePublishedState(prepared.session.getActiveModelProfile?.(), publishedState?.activeModelProfile)
|
|
2655
|
+
) {
|
|
2656
|
+
restore("restore active profile", () =>
|
|
2657
|
+
prepared.session.setActiveModelProfile?.(
|
|
2658
|
+
prepared.previousActiveModelProfile,
|
|
2659
|
+
prepared.previousActivatedModelProfile === prepared.previousActiveModelProfile,
|
|
2660
|
+
),
|
|
2661
|
+
);
|
|
2662
|
+
}
|
|
2663
|
+
if (
|
|
2664
|
+
prepared.previousProfileInstalledOverrideState &&
|
|
2665
|
+
canRollbackPublishedProfile() &&
|
|
2666
|
+
canRestorePublishedState(
|
|
2667
|
+
prepared.session.getProfileInstalledOverrideState?.(),
|
|
2668
|
+
publishedState?.profileInstalledOverrideState,
|
|
2669
|
+
)
|
|
2670
|
+
) {
|
|
2671
|
+
restore("restore installed role tracking", () =>
|
|
2672
|
+
prepared.session.restoreProfileInstalledOverrideState?.(prepared.previousProfileInstalledOverrideState!),
|
|
2673
|
+
);
|
|
2674
|
+
}
|
|
2675
|
+
restore("restore canonical model variant", () =>
|
|
2676
|
+
restoreCanonicalVariantAfterPreparation(
|
|
2677
|
+
prepared.session.modelRegistry ?? prepared.modelRegistry,
|
|
2678
|
+
prepared.session,
|
|
2679
|
+
prepared.previousCanonicalVariant,
|
|
2680
|
+
prepared.previousUserCanonicalVariantSelection,
|
|
2681
|
+
),
|
|
2682
|
+
);
|
|
2683
|
+
if (options.persistDefault) {
|
|
2684
|
+
await restoreAsync("restore persisted settings", () => prepared.settings.flushOrThrow());
|
|
2685
|
+
}
|
|
2686
|
+
if (failures.length > 0) {
|
|
2687
|
+
throw new AggregateError(
|
|
2688
|
+
failures.map(failure => failure.error),
|
|
2689
|
+
`Failed to fully roll back model profile activation: ${failures.map(failure => failure.stage).join(", ")}`,
|
|
2690
|
+
);
|
|
1994
2691
|
}
|
|
1995
2692
|
}
|
|
1996
2693
|
|
|
@@ -2007,8 +2704,10 @@ export interface MaterializeModelProfileForDeletionResult {
|
|
|
2007
2704
|
previousDefaultProfile: string | undefined;
|
|
2008
2705
|
previousPersistedDefaultProfile: string | undefined;
|
|
2009
2706
|
previousActiveModelProfile: string | undefined;
|
|
2707
|
+
previousActivatedModelProfile: string | undefined;
|
|
2010
2708
|
previousDefaultChainState: ConfiguredModelChainState | undefined;
|
|
2011
2709
|
previousDefaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
2710
|
+
previousProfileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
2012
2711
|
/**
|
|
2013
2712
|
* Restores the session sticky canonical variant that was snapshotted before
|
|
2014
2713
|
* materialization cleared it. Internal closure capturing the registry,
|
|
@@ -2137,7 +2836,17 @@ export async function materializeModelProfileForDeletion(
|
|
|
2137
2836
|
? prepared.settings.clearOverride("modelProfile.default")
|
|
2138
2837
|
: prepared.settings.override("modelProfile.default", prepared.previousDefaultProfileOverride),
|
|
2139
2838
|
);
|
|
2140
|
-
restore(() =>
|
|
2839
|
+
restore(() =>
|
|
2840
|
+
prepared.session.setActiveModelProfile?.(
|
|
2841
|
+
prepared.previousActiveModelProfile,
|
|
2842
|
+
prepared.previousActivatedModelProfile === prepared.previousActiveModelProfile,
|
|
2843
|
+
),
|
|
2844
|
+
);
|
|
2845
|
+
if (prepared.previousProfileInstalledOverrideState) {
|
|
2846
|
+
restore(() =>
|
|
2847
|
+
prepared.session.restoreProfileInstalledOverrideState?.(prepared.previousProfileInstalledOverrideState!),
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2141
2850
|
try {
|
|
2142
2851
|
await prepared.settings.flushOrThrow();
|
|
2143
2852
|
} catch (rollbackError) {
|
|
@@ -2165,8 +2874,10 @@ export async function materializeModelProfileForDeletion(
|
|
|
2165
2874
|
previousDefaultProfile,
|
|
2166
2875
|
previousPersistedDefaultProfile,
|
|
2167
2876
|
previousActiveModelProfile: prepared.previousActiveModelProfile,
|
|
2877
|
+
previousActivatedModelProfile: prepared.previousActivatedModelProfile,
|
|
2168
2878
|
previousDefaultChainState: prepared.previousDefaultChainState,
|
|
2169
2879
|
previousDefaultFallbackRuntimeState: prepared.previousDefaultFallbackRuntimeState,
|
|
2880
|
+
previousProfileInstalledOverrideState: prepared.previousProfileInstalledOverrideState,
|
|
2170
2881
|
restoreSessionCanonicalVariant: () =>
|
|
2171
2882
|
restoreCanonicalVariant(prepared.modelRegistry, prepared.session.sessionId, prepared.previousCanonicalVariant),
|
|
2172
2883
|
};
|
|
@@ -2176,7 +2887,10 @@ export async function restoreMaterializedModelProfileForDeletion(options: {
|
|
|
2176
2887
|
settings: Pick<Settings, "clearOverride" | "flushOrThrow" | "override" | "set" | "unset">;
|
|
2177
2888
|
session: Pick<
|
|
2178
2889
|
ModelProfileActivationSession,
|
|
2179
|
-
|
|
2890
|
+
| "setActiveModelProfile"
|
|
2891
|
+
| "setConfiguredModelChain"
|
|
2892
|
+
| "restoreDefaultFallbackRuntimeState"
|
|
2893
|
+
| "restoreProfileInstalledOverrideState"
|
|
2180
2894
|
>;
|
|
2181
2895
|
snapshot: MaterializeModelProfileForDeletionResult;
|
|
2182
2896
|
}): Promise<void> {
|
|
@@ -2230,7 +2944,19 @@ export async function restoreMaterializedModelProfileForDeletion(options: {
|
|
|
2230
2944
|
? options.settings.clearOverride("modelProfile.default")
|
|
2231
2945
|
: options.settings.override("modelProfile.default", options.snapshot.previousDefaultProfileOverride),
|
|
2232
2946
|
);
|
|
2233
|
-
restore(() =>
|
|
2947
|
+
restore(() =>
|
|
2948
|
+
options.session.setActiveModelProfile?.(
|
|
2949
|
+
options.snapshot.previousActiveModelProfile,
|
|
2950
|
+
options.snapshot.previousActivatedModelProfile === options.snapshot.previousActiveModelProfile,
|
|
2951
|
+
),
|
|
2952
|
+
);
|
|
2953
|
+
if (options.snapshot.previousProfileInstalledOverrideState) {
|
|
2954
|
+
restore(() =>
|
|
2955
|
+
options.session.restoreProfileInstalledOverrideState?.(
|
|
2956
|
+
options.snapshot.previousProfileInstalledOverrideState!,
|
|
2957
|
+
),
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2234
2960
|
try {
|
|
2235
2961
|
await options.settings.flushOrThrow();
|
|
2236
2962
|
} catch (error) {
|
|
@@ -2270,6 +2996,8 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2270
2996
|
const previousModelRolesOverride = prepared.settings.getOverride("modelRoles");
|
|
2271
2997
|
const previousAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2272
2998
|
const previousActiveModelProfile = prepared.session.getActiveModelProfile?.();
|
|
2999
|
+
const previousActivatedModelProfile = prepared.session.getActivatedModelProfile?.();
|
|
3000
|
+
const previousProfileInstalledOverrideState = prepared.session.getProfileInstalledOverrideState?.();
|
|
2273
3001
|
let activatedModelRolesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
2274
3002
|
let activatedAgentModelOverridesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
2275
3003
|
try {
|
|
@@ -2284,7 +3012,7 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2284
3012
|
...prepared.agentModelOverrides,
|
|
2285
3013
|
});
|
|
2286
3014
|
activatedAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2287
|
-
prepared.session.setActiveModelProfile?.(prepared.profileName);
|
|
3015
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName, true);
|
|
2288
3016
|
try {
|
|
2289
3017
|
await prepared.session.syncEagerDelegation?.();
|
|
2290
3018
|
} catch (error) {
|
|
@@ -2310,7 +3038,13 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2310
3038
|
prepared.settings.clearOverride("task.agentModelOverrides");
|
|
2311
3039
|
else prepared.settings.override("task.agentModelOverrides", restoredAgentModelOverridesOverride);
|
|
2312
3040
|
if (prepared.session.getActiveModelProfile?.() === prepared.profileName) {
|
|
2313
|
-
prepared.session.setActiveModelProfile?.(
|
|
3041
|
+
prepared.session.setActiveModelProfile?.(
|
|
3042
|
+
previousActiveModelProfile,
|
|
3043
|
+
previousActivatedModelProfile === previousActiveModelProfile,
|
|
3044
|
+
);
|
|
3045
|
+
}
|
|
3046
|
+
if (previousProfileInstalledOverrideState) {
|
|
3047
|
+
prepared.session.restoreProfileInstalledOverrideState?.(previousProfileInstalledOverrideState);
|
|
2314
3048
|
}
|
|
2315
3049
|
try {
|
|
2316
3050
|
await prepared.session.syncEagerDelegation?.();
|
|
@@ -2326,6 +3060,13 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2326
3060
|
Object.keys(prepared.modelRoles),
|
|
2327
3061
|
Object.keys(prepared.agentModelOverrides),
|
|
2328
3062
|
prepared.previousModel,
|
|
3063
|
+
{ modelRoles: prepared.baseModelRoles, agentModelOverrides: prepared.baseAgentModelOverrides },
|
|
3064
|
+
{ modelRoles: prepared.modelRoles, agentModelOverrides: prepared.agentModelOverrides },
|
|
3065
|
+
{
|
|
3066
|
+
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
3067
|
+
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
3068
|
+
},
|
|
3069
|
+
prepared.defaultChain,
|
|
2329
3070
|
);
|
|
2330
3071
|
} finally {
|
|
2331
3072
|
if (isCurrent && !isCurrent()) {
|