@gajae-code/coding-agent 0.18.12 → 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 +467 -0
- package/dist/types/capability/rule.d.ts +7 -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/public-command-errors.d.ts +1 -0
- package/dist/types/cli/root-flags.d.ts +0 -12
- package/dist/types/cli/update-cli.d.ts +7 -2
- package/dist/types/cli-main.d.ts +0 -6
- 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 +8 -0
- package/dist/types/commit/map-reduce/index.d.ts +4 -4
- package/dist/types/config/autorouting-tier-map.d.ts +23 -1
- package/dist/types/config/config-hot-reload.d.ts +5 -0
- package/dist/types/config/file-lock.d.ts +44 -2
- package/dist/types/config/model-profile-activation.d.ts +19 -5
- package/dist/types/config/model-registry.d.ts +16 -3
- package/dist/types/config/model-resolver.d.ts +5 -4
- package/dist/types/config/settings-schema.d.ts +11 -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/session.d.ts +11 -2
- package/dist/types/discovery/helpers.d.ts +7 -2
- package/dist/types/edit/index.d.ts +5 -0
- package/dist/types/edit/modes/patch.d.ts +9 -0
- package/dist/types/eval/py/runtime.d.ts +9 -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/ralplan-current-final.d.ts +54 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
- 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 +1 -1
- package/dist/types/migrate/adapters/index.d.ts +35 -3
- 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 +69 -2
- 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/prompt-suggestion-controller.d.ts +1 -1
- package/dist/types/modes/utils/host-status.d.ts +15 -11
- package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
- package/dist/types/sdk/broker/broker-exit.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +22 -1
- package/dist/types/sdk/broker/ensure.d.ts +5 -2
- package/dist/types/sdk/broker/hop.d.ts +9 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
- package/dist/types/sdk/broker/session-index.d.ts +2 -0
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/index.d.ts +21 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -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/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 +8 -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-status.d.ts +11 -4
- package/dist/types/session/agent-session.d.ts +50 -8
- package/dist/types/session/session-manager.d.ts +16 -0
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +13 -1
- package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
- package/dist/types/ssh/ssh-executor.d.ts +8 -1
- package/dist/types/system-prompt.d.ts +3 -2
- package/dist/types/task/role-body.d.ts +11 -0
- package/dist/types/tools/awaiting-input.d.ts +28 -0
- package/dist/types/tools/bash-allowed-prefixes.d.ts +6 -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 +13 -2
- package/dist/types/tools/fetch.d.ts +6 -0
- package/dist/types/tools/irc.d.ts +5 -3
- 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/search/providers/codex.d.ts +6 -7
- package/package.json +9 -8
- package/scripts/acp-conformance-agent.ts +12 -2
- package/scripts/generate-sdk-operation-inventory.ts +16 -0
- package/src/capability/fs.ts +31 -3
- package/src/capability/rule.ts +11 -2
- package/src/cli/append-system-prompt.ts +12 -0
- package/src/cli/args.ts +11 -7
- package/src/cli/customize-doctor-precedence.ts +31 -0
- package/src/cli/customize-doctor.ts +49 -39
- package/src/cli/fast-help.ts +0 -2
- package/src/cli/migrate-cli.ts +14 -3
- package/src/cli/public-command-errors.ts +2 -0
- package/src/cli/root-flags.ts +0 -2
- package/src/cli/update-cli.ts +247 -6
- package/src/commands/harness.ts +25 -15
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +81 -11
- package/src/commit/agentic/agent.ts +6 -6
- package/src/commit/analysis/conventional.ts +14 -5
- package/src/commit/map-reduce/index.ts +7 -7
- package/src/commit/pipeline.ts +12 -12
- package/src/config/autorouting-tier-map.ts +20 -1
- package/src/config/config-file.ts +106 -3
- package/src/config/config-hot-reload.ts +8 -0
- package/src/config/file-lock.ts +1431 -304
- package/src/config/keybindings.ts +154 -7
- package/src/config/model-profile-activation.ts +177 -39
- package/src/config/model-registry.ts +380 -55
- package/src/config/model-resolver.ts +49 -21
- package/src/config/settings-schema.ts +13 -1
- package/src/config/settings.ts +2 -0
- package/src/coordinator-mcp/server.ts +37 -2
- package/src/crash/sanitize.ts +3 -1
- package/src/customization/import.ts +276 -7
- package/src/customization/inventory.ts +24 -8
- package/src/customization/types.ts +1 -0
- package/src/dap/client.ts +3 -2
- package/src/dap/session.ts +161 -36
- package/src/debug/crash-diagnostics.ts +87 -5
- package/src/debug/report-bundle.ts +71 -2
- package/src/discovery/builtin.ts +4 -3
- package/src/discovery/helpers.ts +24 -14
- package/src/edit/index.ts +191 -5
- package/src/edit/modes/patch.ts +27 -0
- package/src/eval/py/runtime.ts +44 -4
- package/src/exec/non-interactive-env.ts +0 -1
- package/src/export/html/index.ts +60 -20
- package/src/export/ttsr.ts +176 -1
- package/src/extensibility/extensions/loader.ts +2 -0
- 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/manager.ts +36 -10
- package/src/extensibility/slash-commands.ts +5 -0
- package/src/gjc-runtime/gc-runtime.ts +4 -1
- package/src/gjc-runtime/launch-tmux.ts +23 -13
- package/src/gjc-runtime/ralplan-current-final.ts +294 -0
- package/src/gjc-runtime/ralplan-runtime.ts +95 -1
- 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 +3 -1
- package/src/internal-urls/artifact-protocol.ts +3 -1
- package/src/internal-urls/docs-index.generated.ts +14 -14
- package/src/internal-urls/local-protocol.ts +28 -3
- 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/main.ts +330 -92
- package/src/memories/index.ts +25 -2
- package/src/migrate/action-planner.ts +517 -2
- package/src/migrate/adapters/claude-code.ts +141 -3
- package/src/migrate/adapters/codex.ts +57 -5
- package/src/migrate/adapters/index.ts +240 -5
- package/src/migrate/adapters/opencode.ts +4 -0
- package/src/migrate/executor.ts +141 -3
- package/src/migrate/hook-module.ts +193 -0
- package/src/migrate/report.ts +45 -1
- package/src/migrate/types.ts +73 -3
- package/src/modes/acp/acp-agent.ts +10 -1
- package/src/modes/components/agent-dashboard.ts +20 -4
- 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/welcome.ts +3 -1
- package/src/modes/controllers/command-controller.ts +271 -16
- 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 +49 -4
- package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
- package/src/modes/controllers/selector-controller.ts +14 -1
- package/src/modes/interactive-mode.ts +55 -4
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +5 -1
- 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/irc.md +1 -1
- package/src/runtime-mcp/manager.ts +8 -3
- package/src/runtime-mcp/project-host-values.ts +12 -8
- package/src/runtime-mcp/tool-bridge.ts +68 -4
- package/src/runtime-mcp/transports/stdio.ts +2 -1
- package/src/sdk/broker/broker-exit.ts +2 -0
- package/src/sdk/broker/broker.ts +143 -4
- package/src/sdk/broker/ensure.ts +74 -6
- package/src/sdk/broker/hop.ts +13 -1
- package/src/sdk/broker/lifecycle-ledger.ts +3 -0
- package/src/sdk/broker/lifecycle.ts +102 -6
- package/src/sdk/broker/session-index.ts +29 -4
- package/src/sdk/broker/transport.ts +17 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +408 -14
- 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 +7 -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 +2 -0
- 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 +1537 -24
- package/src/sdk/host/session-runtime.ts +332 -36
- 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 +14 -1
- package/src/sdk/prompt-status.ts +6 -4
- package/src/sdk/protocol/adapter-validation.ts +28 -1
- package/src/sdk/protocol/operation-inventory.generated.json +160 -0
- package/src/sdk/protocol/operation-registry.ts +33 -3
- package/src/sdk/session.ts +123 -36
- package/src/session/agent-session.ts +1614 -329
- package/src/session/history-storage.ts +182 -12
- package/src/session/internal/managed-session-scope.ts +47 -18
- package/src/session/internal/managed-session-storage.ts +71 -1
- package/src/session/session-manager.ts +90 -5
- package/src/session-import/redact.ts +53 -2
- package/src/skill-state/workflow-mutation-guard.ts +1498 -18
- package/src/slash-commands/builtin-registry.ts +6 -3
- package/src/slash-commands/helpers/mcp.ts +11 -3
- 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 +12 -8
- 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-grep.ts +7 -2
- package/src/tools/auto-generated-guard.ts +12 -3
- package/src/tools/awaiting-input.ts +114 -0
- package/src/tools/bash-allowed-prefixes.ts +61 -1
- package/src/tools/bash-skill-urls.ts +58 -5
- package/src/tools/bash.ts +99 -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 +9 -2
- package/src/tools/descriptors.test.ts +4 -4
- package/src/tools/descriptors.ts +16 -4
- package/src/tools/eval.ts +15 -0
- package/src/tools/fetch.ts +90 -2
- package/src/tools/gh.ts +27 -12
- package/src/tools/image-gen.ts +20 -6
- package/src/tools/irc.ts +5 -3
- package/src/tools/monitor.ts +9 -1
- package/src/tools/output-meta.ts +51 -3
- package/src/tools/read.ts +9 -2
- package/src/tools/recipe/runner.ts +23 -12
- package/src/tools/render-utils.ts +2 -2
- package/src/tools/search.ts +3 -2
- package/src/tools/ssh.ts +274 -8
- package/src/tools/subagent.ts +10 -4
- package/src/tools/tmux-self-injection-guard.ts +3301 -122
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/ultragoal-ask-guard.ts +13 -1
- package/src/tools/write.ts +7 -0
- package/src/tui/tree-list.ts +15 -1
- package/src/utils/commit-message-generator.ts +3 -2
- package/src/utils/external-editor.ts +21 -7
- package/src/utils/file-mentions.ts +46 -6
- 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 +65 -20
- package/src/web/search/index.ts +2 -1
- package/src/web/search/providers/codex.ts +29 -32
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
closeSync,
|
|
3
|
+
constants,
|
|
4
|
+
existsSync,
|
|
5
|
+
fchmodSync,
|
|
6
|
+
fstatSync,
|
|
7
|
+
ftruncateSync,
|
|
8
|
+
lstatSync,
|
|
9
|
+
openSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
unlinkSync,
|
|
13
|
+
writeSync,
|
|
14
|
+
} from "node:fs";
|
|
2
15
|
import * as path from "node:path";
|
|
3
16
|
import {
|
|
4
17
|
type Keybinding,
|
|
@@ -469,22 +482,156 @@ function loadRawConfig(filePath: string): unknown {
|
|
|
469
482
|
}
|
|
470
483
|
}
|
|
471
484
|
|
|
485
|
+
const KEYBINDINGS_MARKER_MODE = 0o600;
|
|
486
|
+
|
|
487
|
+
type KeybindingsLeaf = "absent" | "file" | "symlink" | "other";
|
|
488
|
+
|
|
489
|
+
function keybindingsLeaf(filePath: string): KeybindingsLeaf {
|
|
490
|
+
try {
|
|
491
|
+
const stat = lstatSync(filePath);
|
|
492
|
+
if (stat.isSymbolicLink()) return "symlink";
|
|
493
|
+
if (stat.isFile()) return "file";
|
|
494
|
+
return "other";
|
|
495
|
+
} catch (error) {
|
|
496
|
+
if (isEnoent(error)) return "absent";
|
|
497
|
+
throw error;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function writeAllSync(fd: number, content: string | Buffer): void {
|
|
502
|
+
const buffer = typeof content === "string" ? Buffer.from(content) : content;
|
|
503
|
+
let offset = 0;
|
|
504
|
+
while (offset < buffer.length) {
|
|
505
|
+
const wrote = writeSync(fd, buffer, offset, buffer.length - offset);
|
|
506
|
+
if (wrote <= 0) throw new Error("keybindings migration write was incomplete");
|
|
507
|
+
offset += wrote;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/** Create a new file. O_NOFOLLOW refuses a final symlink. A set mode is fchmod'd. */
|
|
512
|
+
function writeExclusiveNoFollow(filePath: string, content: string | Buffer, mode: number | undefined): void {
|
|
513
|
+
const noFollow = process.platform === "win32" ? 0 : (constants.O_NOFOLLOW ?? 0);
|
|
514
|
+
const fd = openSync(filePath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | noFollow, mode ?? 0o666);
|
|
515
|
+
try {
|
|
516
|
+
writeAllSync(fd, content);
|
|
517
|
+
if (mode !== undefined && process.platform !== "win32") fchmodSync(fd, mode);
|
|
518
|
+
} finally {
|
|
519
|
+
closeSync(fd);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/** Copy bytes to the backup. A final symlink at either path is not opened for write. */
|
|
524
|
+
function copyKeybindingsBackup(
|
|
525
|
+
source: string,
|
|
526
|
+
dest: string,
|
|
527
|
+
sourceKind: KeybindingsLeaf,
|
|
528
|
+
destKind: KeybindingsLeaf,
|
|
529
|
+
): void {
|
|
530
|
+
const noFollow = process.platform === "win32" ? 0 : (constants.O_NOFOLLOW ?? 0);
|
|
531
|
+
// A symlinked config is still backed up from its target. The backup path itself stays no-follow.
|
|
532
|
+
const sourceFlags = constants.O_RDONLY | (sourceKind === "file" ? noFollow : 0);
|
|
533
|
+
const srcFd = openSync(source, sourceFlags);
|
|
534
|
+
try {
|
|
535
|
+
const stat = fstatSync(srcFd);
|
|
536
|
+
if (!stat.isFile()) throw new Error("keybindings migration target is not a regular file");
|
|
537
|
+
const bytes = readFileSync(srcFd);
|
|
538
|
+
const mode = stat.mode & 0o777;
|
|
539
|
+
if (destKind === "absent") {
|
|
540
|
+
writeExclusiveNoFollow(dest, bytes, mode);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const fd = openSync(dest, constants.O_WRONLY | noFollow);
|
|
544
|
+
try {
|
|
545
|
+
const destStat = fstatSync(fd);
|
|
546
|
+
if (!destStat.isFile()) throw new Error("keybindings migration target is not a regular file");
|
|
547
|
+
if (destStat.dev === stat.dev && destStat.ino === stat.ino) return;
|
|
548
|
+
ftruncateSync(fd, 0);
|
|
549
|
+
writeAllSync(fd, bytes);
|
|
550
|
+
if (process.platform !== "win32") fchmodSync(fd, mode);
|
|
551
|
+
} finally {
|
|
552
|
+
closeSync(fd);
|
|
553
|
+
}
|
|
554
|
+
} finally {
|
|
555
|
+
closeSync(srcFd);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function migrationMarkerState(markerPath: string): { present: boolean; kind: KeybindingsLeaf } {
|
|
560
|
+
const kind = keybindingsLeaf(markerPath);
|
|
561
|
+
// A symlink is not a completed marker. existsSync only preserves the historical
|
|
562
|
+
// skip when that link already names a real target. The write path never opens it.
|
|
563
|
+
const present = kind === "file" || kind === "other" || (kind === "symlink" && existsSync(markerPath));
|
|
564
|
+
return { present, kind };
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function writeMigratedKeybindings(
|
|
568
|
+
filePath: string,
|
|
569
|
+
markerPath: string,
|
|
570
|
+
markerKind: KeybindingsLeaf,
|
|
571
|
+
body: string,
|
|
572
|
+
): void {
|
|
573
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
574
|
+
const bakPath = `${filePath}.bak`;
|
|
575
|
+
const bakKind = keybindingsLeaf(bakPath);
|
|
576
|
+
const tempKind = keybindingsLeaf(tempPath);
|
|
577
|
+
const sourceKind = keybindingsLeaf(filePath);
|
|
578
|
+
if (
|
|
579
|
+
bakKind === "symlink" ||
|
|
580
|
+
bakKind === "other" ||
|
|
581
|
+
tempKind === "symlink" ||
|
|
582
|
+
tempKind === "other" ||
|
|
583
|
+
(sourceKind !== "file" && sourceKind !== "symlink")
|
|
584
|
+
) {
|
|
585
|
+
throw new Error("keybindings migration target is not a regular file");
|
|
586
|
+
}
|
|
587
|
+
if (tempKind === "file") unlinkSync(tempPath);
|
|
588
|
+
if (keybindingsLeaf(filePath) !== sourceKind) {
|
|
589
|
+
throw new Error("keybindings migration target is not a regular file");
|
|
590
|
+
}
|
|
591
|
+
const mode = sourceKind === "file" ? lstatSync(filePath).mode & 0o777 : undefined;
|
|
592
|
+
try {
|
|
593
|
+
copyKeybindingsBackup(filePath, bakPath, sourceKind, bakKind);
|
|
594
|
+
writeExclusiveNoFollow(tempPath, body, mode);
|
|
595
|
+
const current = lstatSync(filePath);
|
|
596
|
+
if (sourceKind === "file" && (current.isSymbolicLink() || !current.isFile())) {
|
|
597
|
+
throw new Error("keybindings migration target is not a regular file");
|
|
598
|
+
}
|
|
599
|
+
renameSync(tempPath, filePath);
|
|
600
|
+
if (markerKind === "absent") writeExclusiveNoFollow(markerPath, "v1\n", KEYBINDINGS_MARKER_MODE);
|
|
601
|
+
} catch (error) {
|
|
602
|
+
if (keybindingsLeaf(tempPath) === "file") {
|
|
603
|
+
try {
|
|
604
|
+
unlinkSync(tempPath);
|
|
605
|
+
} catch {
|
|
606
|
+
// Best-effort removal of the unreplaced temp file.
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
throw error;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
472
613
|
/** Migrate legacy keybindings once, preserving the original file as .bak. */
|
|
473
614
|
function loadKeybindingsConfig(filePath: string, writeBack: boolean): KeybindingsConfig {
|
|
474
615
|
const rawConfig = loadRawConfig(filePath);
|
|
475
616
|
if (rawConfig === null) return {};
|
|
476
617
|
const markerPath = `${filePath}.migration-v1`;
|
|
477
|
-
|
|
618
|
+
let markerKind: KeybindingsLeaf = "absent";
|
|
619
|
+
let markerPresent = false;
|
|
620
|
+
try {
|
|
621
|
+
const marker = migrationMarkerState(markerPath);
|
|
622
|
+
markerKind = marker.kind;
|
|
623
|
+
markerPresent = marker.present;
|
|
624
|
+
} catch (error) {
|
|
625
|
+
logger.warn("Failed to read keybindings migration marker", { path: markerPath, error: String(error) });
|
|
626
|
+
return toKeybindingsConfig(rawConfig);
|
|
627
|
+
}
|
|
628
|
+
const { config: migratedConfig, migrated } = markerPresent
|
|
478
629
|
? { config: toKeybindingsConfig(rawConfig), migrated: false }
|
|
479
630
|
: migrateKeybindingNames(rawConfig);
|
|
480
631
|
if (writeBack && migrated) {
|
|
481
632
|
const ordered = orderKeybindingsConfig(migratedConfig);
|
|
482
|
-
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
483
633
|
try {
|
|
484
|
-
|
|
485
|
-
writeFileSync(tempPath, `${JSON.stringify(ordered, null, 2)}\n`, "utf-8");
|
|
486
|
-
renameSync(tempPath, filePath);
|
|
487
|
-
writeFileSync(markerPath, "v1\n", "utf-8");
|
|
634
|
+
writeMigratedKeybindings(filePath, markerPath, markerKind, `${JSON.stringify(ordered, null, 2)}\n`);
|
|
488
635
|
logger.debug("Migrated keybindings config", { path: filePath });
|
|
489
636
|
} catch (error) {
|
|
490
637
|
logger.warn("Failed to write migrated keybindings config", { path: filePath, error: String(error) });
|
|
@@ -53,8 +53,9 @@ type ModelProfileActivationSession = Pick<
|
|
|
53
53
|
> & {
|
|
54
54
|
credentialSessionId?: string;
|
|
55
55
|
setModelTemporary?: AgentSession["setModelTemporary"];
|
|
56
|
-
setActiveModelProfile?: (name: string | undefined) => void;
|
|
56
|
+
setActiveModelProfile?: (name: string | undefined, activatedByThisProcess?: boolean) => void;
|
|
57
57
|
getActiveModelProfile?: () => string | undefined;
|
|
58
|
+
getActivatedModelProfile?: () => string | undefined;
|
|
58
59
|
/** Record which runtime override keys this activation installed (session-scoped). */
|
|
59
60
|
noteProfileInstalledOverrides?: (
|
|
60
61
|
modelRoles: readonly string[],
|
|
@@ -69,6 +70,7 @@ type ModelProfileActivationSession = Pick<
|
|
|
69
70
|
agentModelOverrides: Readonly<Record<string, ModelSelectorValue>>;
|
|
70
71
|
},
|
|
71
72
|
manual?: { modelRoles: readonly string[]; agentModelOverrides: readonly string[] },
|
|
73
|
+
configuredDefaultChain?: readonly string[],
|
|
72
74
|
) => void;
|
|
73
75
|
/** Drop the recorded profile-installed override keys (e.g. after materialization). */
|
|
74
76
|
clearProfileInstalledOverrides?: () => void;
|
|
@@ -95,6 +97,7 @@ type ModelProfileActivationSession = Pick<
|
|
|
95
97
|
| "getSessionCanonicalVariant"
|
|
96
98
|
| "restoreSessionCanonicalVariant"
|
|
97
99
|
| "clearCanonicalVariant"
|
|
100
|
+
| "getModelProfile"
|
|
98
101
|
| "getAvailable"
|
|
99
102
|
| "lookupAliasExists"
|
|
100
103
|
| "resolveModelByLookupAlias"
|
|
@@ -120,6 +123,7 @@ type PublishedModelProfileActivationState = {
|
|
|
120
123
|
defaultChainState: ConfiguredModelChainState | undefined;
|
|
121
124
|
defaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
122
125
|
activeModelProfile: string | undefined;
|
|
126
|
+
activatedModelProfile: string | undefined;
|
|
123
127
|
profileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
124
128
|
sessionDefaultModel: string | undefined;
|
|
125
129
|
persistedModelRoles: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
@@ -227,6 +231,7 @@ export interface PreparedModelProfileActivation {
|
|
|
227
231
|
manualModelRoleOverrides: ReadonlySet<string>;
|
|
228
232
|
manualAgentModelOverrides: ReadonlySet<string>;
|
|
229
233
|
previousActiveModelProfile: string | undefined;
|
|
234
|
+
previousActivatedModelProfile: string | undefined;
|
|
230
235
|
/**
|
|
231
236
|
* The session resume default ("provider/id") captured BEFORE activation —
|
|
232
237
|
* the model resume would restore prior to this profile. Snapshotted
|
|
@@ -260,6 +265,8 @@ export interface MaterializeModelProfileAssignmentOptions {
|
|
|
260
265
|
| "setConfiguredModelChain"
|
|
261
266
|
| "setActiveModelProfile"
|
|
262
267
|
| "getActiveModelProfile"
|
|
268
|
+
| "getActivatedModelProfile"
|
|
269
|
+
| "getProfileInstalledOverrideState"
|
|
263
270
|
| "getDefaultFallbackRuntimeState"
|
|
264
271
|
| "restoreDefaultFallbackRuntimeState"
|
|
265
272
|
| "modelRegistry"
|
|
@@ -282,6 +289,8 @@ export interface MaterializeModelProfileAssignmentsOptions {
|
|
|
282
289
|
| "setConfiguredModelChain"
|
|
283
290
|
| "setActiveModelProfile"
|
|
284
291
|
| "getActiveModelProfile"
|
|
292
|
+
| "getActivatedModelProfile"
|
|
293
|
+
| "getProfileInstalledOverrideState"
|
|
285
294
|
| "getDefaultFallbackRuntimeState"
|
|
286
295
|
| "restoreDefaultFallbackRuntimeState"
|
|
287
296
|
| "modelRegistry"
|
|
@@ -310,9 +319,80 @@ function getMaterializedAssignments(
|
|
|
310
319
|
return result;
|
|
311
320
|
}
|
|
312
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
|
+
|
|
313
389
|
function materializeConfiguredDefaultChain(
|
|
314
|
-
session: Pick<
|
|
390
|
+
session: Pick<
|
|
391
|
+
ModelProfileActivationSession,
|
|
392
|
+
"model" | "thinkingLevel" | "getConfiguredModelChain" | "getConfiguredModelChainState"
|
|
393
|
+
>,
|
|
315
394
|
): ModelSelectorValue | undefined {
|
|
395
|
+
if (session.getConfiguredModelChainState?.("default")?.origin === "startup-override") return undefined;
|
|
316
396
|
if (!session.model) return undefined;
|
|
317
397
|
return formatModelSelectorValue(`${session.model.provider}/${session.model.id}`, session.thinkingLevel);
|
|
318
398
|
}
|
|
@@ -328,7 +408,7 @@ function concretizeMaterializedAssignmentValues(
|
|
|
328
408
|
// Materialized assignments are persisted into `modelRoles` and
|
|
329
409
|
// `task.agentModelOverrides` and later consumed by profile execution, so they
|
|
330
410
|
// resolve against the same catalog profile activation uses.
|
|
331
|
-
const availableModels = modelRegistry.getAvailable();
|
|
411
|
+
const availableModels = modelRegistry.getAvailable(credentialSessionId);
|
|
332
412
|
const authenticatedModels = availableModels.filter(model => {
|
|
333
413
|
const isCredentiallessProvider = modelRegistry.isCredentiallessProvider?.bind(modelRegistry);
|
|
334
414
|
const hasUsableAuth = modelRegistry.authStorage?.hasUsableAuth?.bind(modelRegistry.authStorage);
|
|
@@ -368,6 +448,7 @@ function commitMaterializedProfileAssignments(
|
|
|
368
448
|
options: MaterializeModelProfileAssignmentOptions | MaterializeModelProfileAssignmentsOptions,
|
|
369
449
|
modelRoles: Record<string, ModelSelectorValue>,
|
|
370
450
|
agentModelOverrides: Record<string, ModelSelectorValue>,
|
|
451
|
+
preserveStartupOverrideChain = false,
|
|
371
452
|
): boolean {
|
|
372
453
|
const previousPersistedModelRoles = options.settings.getGlobal("modelRoles");
|
|
373
454
|
const previousPersistedAgentModelOverrides = options.settings.getGlobal("task.agentModelOverrides");
|
|
@@ -376,6 +457,7 @@ function commitMaterializedProfileAssignments(
|
|
|
376
457
|
const previousAgentModelOverridesOverride = options.settings.getOverride("task.agentModelOverrides");
|
|
377
458
|
const previousDefaultProfileOverride = options.settings.getOverride("modelProfile.default");
|
|
378
459
|
const previousActiveProfile = options.session.getActiveModelProfile?.();
|
|
460
|
+
const previousActivatedProfile = options.session.getActivatedModelProfile?.();
|
|
379
461
|
const previousChain = options.session.getConfiguredModelChainState?.("default");
|
|
380
462
|
const previousFallbackRuntimeState = options.session.getDefaultFallbackRuntimeState?.();
|
|
381
463
|
const previousCanonicalVariant = options.session.modelRegistry?.getSessionCanonicalVariant?.(
|
|
@@ -390,13 +472,17 @@ function commitMaterializedProfileAssignments(
|
|
|
390
472
|
options.settings.clearOverride("modelProfile.default");
|
|
391
473
|
options.settings.override("modelRoles", nextModelRoles);
|
|
392
474
|
options.settings.override("task.agentModelOverrides", nextAgentModelOverrides);
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
+
}
|
|
400
486
|
options.session.setActiveModelProfile?.(undefined);
|
|
401
487
|
return true;
|
|
402
488
|
} catch (error) {
|
|
@@ -461,7 +547,12 @@ function commitMaterializedProfileAssignments(
|
|
|
461
547
|
? options.settings.clearOverride("modelProfile.default")
|
|
462
548
|
: options.settings.override("modelProfile.default", previousDefaultProfileOverride),
|
|
463
549
|
);
|
|
464
|
-
restore(() =>
|
|
550
|
+
restore(() =>
|
|
551
|
+
options.session.setActiveModelProfile?.(
|
|
552
|
+
previousActiveProfile,
|
|
553
|
+
previousActivatedProfile === previousActiveProfile,
|
|
554
|
+
),
|
|
555
|
+
);
|
|
465
556
|
if (rollbackErrors.length > 0) {
|
|
466
557
|
throw new AggregateError(
|
|
467
558
|
[error, ...rollbackErrors],
|
|
@@ -473,10 +564,9 @@ function commitMaterializedProfileAssignments(
|
|
|
473
564
|
}
|
|
474
565
|
|
|
475
566
|
export function materializeActiveModelProfileAssignment(options: MaterializeModelProfileAssignmentOptions): boolean {
|
|
476
|
-
|
|
477
|
-
if (!activeProfile) return false;
|
|
567
|
+
if (!resolveMaterializationProfile(options, options.role === "default")) return false;
|
|
478
568
|
|
|
479
|
-
const nextModelRoles =
|
|
569
|
+
const nextModelRoles = modelRolesForMaterialization(options);
|
|
480
570
|
const nextAgentModelOverrides = { ...options.settings.get("task.agentModelOverrides") };
|
|
481
571
|
const target = GJC_MODEL_ASSIGNMENT_TARGETS[options.role];
|
|
482
572
|
|
|
@@ -493,21 +583,24 @@ export function materializeActiveModelProfileAssignment(options: MaterializeMode
|
|
|
493
583
|
nextAgentModelOverrides[options.role] = options.selector;
|
|
494
584
|
}
|
|
495
585
|
|
|
496
|
-
const committed = commitMaterializedProfileAssignments(
|
|
586
|
+
const committed = commitMaterializedProfileAssignments(
|
|
587
|
+
options,
|
|
588
|
+
nextModelRoles,
|
|
589
|
+
nextAgentModelOverrides,
|
|
590
|
+
options.role !== "default",
|
|
591
|
+
);
|
|
497
592
|
if (committed) options.session.clearProfileInstalledOverrides?.();
|
|
498
593
|
return committed;
|
|
499
594
|
}
|
|
500
595
|
|
|
501
596
|
export function materializeActiveModelProfileAssignments(options: MaterializeModelProfileAssignmentsOptions): boolean {
|
|
502
|
-
const activeProfile = options.session.getActiveModelProfile?.() ?? options.settings.get("modelProfile.default");
|
|
503
|
-
if (!activeProfile) return false;
|
|
504
|
-
|
|
505
597
|
const materializedAssignments = getMaterializedAssignments(options.assignments);
|
|
598
|
+
const includesDefault = materializedAssignments.some(([role]) => role === "default");
|
|
599
|
+
if (!resolveMaterializationProfile(options, includesDefault)) return false;
|
|
506
600
|
if (materializedAssignments.length === 0) return true;
|
|
507
601
|
|
|
508
|
-
const nextModelRoles =
|
|
602
|
+
const nextModelRoles = modelRolesForMaterialization(options);
|
|
509
603
|
const nextAgentModelOverrides = { ...options.settings.get("task.agentModelOverrides") };
|
|
510
|
-
const includesDefault = materializedAssignments.some(([role]) => role === "default");
|
|
511
604
|
|
|
512
605
|
if (!includesDefault && !nextModelRoles.default) {
|
|
513
606
|
const defaultChain = materializeConfiguredDefaultChain(options.session);
|
|
@@ -523,7 +616,12 @@ export function materializeActiveModelProfileAssignments(options: MaterializeMod
|
|
|
523
616
|
}
|
|
524
617
|
}
|
|
525
618
|
|
|
526
|
-
const committed = commitMaterializedProfileAssignments(
|
|
619
|
+
const committed = commitMaterializedProfileAssignments(
|
|
620
|
+
options,
|
|
621
|
+
nextModelRoles,
|
|
622
|
+
nextAgentModelOverrides,
|
|
623
|
+
!includesDefault,
|
|
624
|
+
);
|
|
527
625
|
if (committed) options.session.clearProfileInstalledOverrides?.();
|
|
528
626
|
return committed;
|
|
529
627
|
}
|
|
@@ -801,7 +899,7 @@ export async function resolveMissingSessionModelRecovery(options: {
|
|
|
801
899
|
options.skips.length === options.defaultEntries.length &&
|
|
802
900
|
options.skips.every(skip => skip.reason === "unknown_model");
|
|
803
901
|
if (!allSelectorsUnknown) return undefined;
|
|
804
|
-
const fullCatalog = options.modelRegistry.getAll();
|
|
902
|
+
const fullCatalog = options.modelRegistry.getAll(options.credentialSessionId);
|
|
805
903
|
const catalogIndex = createRegistrySelectorIndex(fullCatalog);
|
|
806
904
|
const savedSelectorsMissingFromCatalog = resolveConfiguredModelPatterns(
|
|
807
905
|
options.defaultEntries,
|
|
@@ -962,7 +1060,9 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
962
1060
|
allRoutable && proxyProvider !== undefined ? [proxyProvider] : [...group],
|
|
963
1061
|
);
|
|
964
1062
|
}
|
|
965
|
-
const availableModels =
|
|
1063
|
+
const availableModels =
|
|
1064
|
+
options.modelRegistry.getAvailable?.(options.credentialSessionId) ??
|
|
1065
|
+
options.modelRegistry.getAll(options.credentialSessionId);
|
|
966
1066
|
let bindings = resolveProfileBindings(profile);
|
|
967
1067
|
if (alternativeGroups.length > 0)
|
|
968
1068
|
bindings = rewriteBindingsProviders(bindings, authenticatedProviders, alternativeGroups);
|
|
@@ -979,7 +1079,7 @@ export async function resolveModelProfileDefaultChain(options: {
|
|
|
979
1079
|
await preflightModelProfileRoleBindings({
|
|
980
1080
|
profile,
|
|
981
1081
|
bindings,
|
|
982
|
-
roleCatalogModels: options.modelRegistry.getAll(),
|
|
1082
|
+
roleCatalogModels: options.modelRegistry.getAll(options.credentialSessionId),
|
|
983
1083
|
settings: options.settings as Settings,
|
|
984
1084
|
modelRegistry: options.modelRegistry as ModelRegistry,
|
|
985
1085
|
sessionId: "",
|
|
@@ -1165,11 +1265,15 @@ function formatMaterializedSelector(selector: string, model: Model<Api>): string
|
|
|
1165
1265
|
if (!explicitThinkingLevel || parseModelString(clampedSelector)?.thinkingLevel) return clampedSelector;
|
|
1166
1266
|
return formatModelSelectorValue(clampedSelector, explicitThinkingLevel);
|
|
1167
1267
|
}
|
|
1168
|
-
function getBareSelectorCredentialProviders(
|
|
1268
|
+
function getBareSelectorCredentialProviders(
|
|
1269
|
+
selector: string,
|
|
1270
|
+
modelRegistry: ModelRegistry,
|
|
1271
|
+
credentialSessionId?: string,
|
|
1272
|
+
): string[] {
|
|
1169
1273
|
const suffix = splitSelectorThinkingSuffix(selector);
|
|
1170
1274
|
const alias = (suffix.thinkingLevel ? suffix.selector : selector).trim().toLowerCase();
|
|
1171
1275
|
const providers = modelRegistry
|
|
1172
|
-
.getAll()
|
|
1276
|
+
.getAll(credentialSessionId)
|
|
1173
1277
|
.filter(model => {
|
|
1174
1278
|
const modelId = model.id.trim().toLowerCase();
|
|
1175
1279
|
return modelId === alias || modelId.slice(modelId.lastIndexOf("/") + 1) === alias;
|
|
@@ -1240,7 +1344,11 @@ async function resolveAndClampSelectorValue(
|
|
|
1240
1344
|
}
|
|
1241
1345
|
if (!resolved.model) {
|
|
1242
1346
|
if (bareAlias) {
|
|
1243
|
-
const providers = getBareSelectorCredentialProviders(
|
|
1347
|
+
const providers = getBareSelectorCredentialProviders(
|
|
1348
|
+
selector,
|
|
1349
|
+
options.modelRegistry,
|
|
1350
|
+
options.credentialSessionId,
|
|
1351
|
+
);
|
|
1244
1352
|
const selectorSuffix = splitSelectorThinkingSuffix(selector);
|
|
1245
1353
|
const bareSelector = selectorSuffix.thinkingLevel ? selectorSuffix.selector : selector;
|
|
1246
1354
|
const aliasKnown =
|
|
@@ -1332,8 +1440,9 @@ async function concretizeProfileSelectorValue(
|
|
|
1332
1440
|
selectorValue: ModelSelectorValue,
|
|
1333
1441
|
prepared: PreparedModelProfileActivation,
|
|
1334
1442
|
): Promise<ModelSelectorValue> {
|
|
1335
|
-
const candidates = prepared.modelRegistry.getAvailable?.() ?? prepared.modelRegistry.getAll();
|
|
1336
1443
|
const credentialSessionId = prepared.session.credentialSessionId ?? prepared.session.sessionId;
|
|
1444
|
+
const candidates =
|
|
1445
|
+
prepared.modelRegistry.getAvailable?.(credentialSessionId) ?? prepared.modelRegistry.getAll(credentialSessionId);
|
|
1337
1446
|
const concrete = await Promise.all(
|
|
1338
1447
|
normalizeModelSelectorValue(selectorValue).map(async selector => {
|
|
1339
1448
|
const bareAlias = !splitSelectorThinkingSuffix(selector).selector.includes("/");
|
|
@@ -1584,8 +1693,9 @@ export async function prepareModelProfileActivation(
|
|
|
1584
1693
|
);
|
|
1585
1694
|
}
|
|
1586
1695
|
|
|
1587
|
-
const availableModels =
|
|
1588
|
-
|
|
1696
|
+
const availableModels =
|
|
1697
|
+
options.modelRegistry.getAvailable?.(credentialSessionId) ?? options.modelRegistry.getAll(credentialSessionId);
|
|
1698
|
+
const roleCatalogModels = options.modelRegistry.getAll(credentialSessionId);
|
|
1589
1699
|
let bindings = resolveProfileBindings(profile);
|
|
1590
1700
|
if (alternativeGroups.length > 0) {
|
|
1591
1701
|
bindings = rewriteBindingsProviders(bindings, new Set(authenticatedProviders), alternativeGroups);
|
|
@@ -1797,6 +1907,7 @@ export async function prepareModelProfileActivation(
|
|
|
1797
1907
|
manualModelRoleOverrides,
|
|
1798
1908
|
manualAgentModelOverrides,
|
|
1799
1909
|
previousActiveModelProfile: options.session.getActiveModelProfile?.(),
|
|
1910
|
+
previousActivatedModelProfile: options.session.getActivatedModelProfile?.(),
|
|
1800
1911
|
previousSessionDefaultModel: options.session.getSessionDefaultModelSelector?.(),
|
|
1801
1912
|
previousDefaultFallbackRuntimeState: options.session.getDefaultFallbackRuntimeState?.(),
|
|
1802
1913
|
};
|
|
@@ -1898,6 +2009,7 @@ function capturePublishedModelProfileActivationState(
|
|
|
1898
2009
|
defaultChainState: prepared.session.getConfiguredModelChainState?.("default"),
|
|
1899
2010
|
defaultFallbackRuntimeState: prepared.session.getDefaultFallbackRuntimeState?.(),
|
|
1900
2011
|
activeModelProfile: prepared.session.getActiveModelProfile?.(),
|
|
2012
|
+
activatedModelProfile: prepared.session.getActivatedModelProfile?.(),
|
|
1901
2013
|
profileInstalledOverrideState: prepared.session.getProfileInstalledOverrideState?.(),
|
|
1902
2014
|
sessionDefaultModel: prepared.session.getSessionDefaultModelSelector?.(),
|
|
1903
2015
|
persistedModelRoles: prepared.settings.getGlobal("modelRoles"),
|
|
@@ -1964,7 +2076,7 @@ export function publishPreparedModelProfileActivation(
|
|
|
1964
2076
|
...prepared.baseAgentModelOverrides,
|
|
1965
2077
|
...prepared.agentModelOverrides,
|
|
1966
2078
|
});
|
|
1967
|
-
prepared.session.setActiveModelProfile?.(prepared.profileName);
|
|
2079
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName, true);
|
|
1968
2080
|
prepared.session.noteProfileInstalledOverrides?.(
|
|
1969
2081
|
Object.keys(prepared.modelRoles),
|
|
1970
2082
|
Object.keys(prepared.agentModelOverrides),
|
|
@@ -1975,6 +2087,7 @@ export function publishPreparedModelProfileActivation(
|
|
|
1975
2087
|
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
1976
2088
|
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
1977
2089
|
},
|
|
2090
|
+
prepared.defaultChain,
|
|
1978
2091
|
);
|
|
1979
2092
|
prepared.publishedState = capturePublishedModelProfileActivationState(prepared);
|
|
1980
2093
|
}
|
|
@@ -2101,7 +2214,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
2101
2214
|
if (options.isCurrent && !options.isCurrent()) throw new ModelProfileActivationSupersededError();
|
|
2102
2215
|
if (!options.deferRuntimePublication) {
|
|
2103
2216
|
activationStage = "active profile marker";
|
|
2104
|
-
prepared.session.setActiveModelProfile?.(prepared.profileName);
|
|
2217
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName, true);
|
|
2105
2218
|
activationStage = "installed role tracking";
|
|
2106
2219
|
prepared.session.noteProfileInstalledOverrides?.(
|
|
2107
2220
|
Object.keys(prepared.modelRoles),
|
|
@@ -2113,6 +2226,7 @@ export async function applyPreparedModelProfileActivation(
|
|
|
2113
2226
|
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
2114
2227
|
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
2115
2228
|
},
|
|
2229
|
+
prepared.defaultChain,
|
|
2116
2230
|
);
|
|
2117
2231
|
activatedProfileInstalledOverrideState = prepared.session.getProfileInstalledOverrideState?.();
|
|
2118
2232
|
}
|
|
@@ -2282,7 +2396,10 @@ export async function applyPreparedModelProfileActivation(
|
|
|
2282
2396
|
}
|
|
2283
2397
|
if (selectionIsCurrent()) {
|
|
2284
2398
|
restore("restore active profile", () =>
|
|
2285
|
-
prepared.session.setActiveModelProfile?.(
|
|
2399
|
+
prepared.session.setActiveModelProfile?.(
|
|
2400
|
+
prepared.previousActiveModelProfile,
|
|
2401
|
+
prepared.previousActivatedModelProfile === prepared.previousActiveModelProfile,
|
|
2402
|
+
),
|
|
2286
2403
|
);
|
|
2287
2404
|
}
|
|
2288
2405
|
if (
|
|
@@ -2349,7 +2466,8 @@ export async function rollbackPreparedModelProfileActivation(
|
|
|
2349
2466
|
const canRollbackPublishedProfile = (): boolean =>
|
|
2350
2467
|
publishedState === undefined
|
|
2351
2468
|
? selectionIsCurrent()
|
|
2352
|
-
: util.isDeepStrictEqual(prepared.session.getActiveModelProfile?.(), publishedState.activeModelProfile)
|
|
2469
|
+
: util.isDeepStrictEqual(prepared.session.getActiveModelProfile?.(), publishedState.activeModelProfile) &&
|
|
2470
|
+
util.isDeepStrictEqual(prepared.session.getActivatedModelProfile?.(), publishedState.activatedModelProfile);
|
|
2353
2471
|
|
|
2354
2472
|
if (options.persistDefault) {
|
|
2355
2473
|
if (
|
|
@@ -2536,7 +2654,10 @@ export async function rollbackPreparedModelProfileActivation(
|
|
|
2536
2654
|
canRestorePublishedState(prepared.session.getActiveModelProfile?.(), publishedState?.activeModelProfile)
|
|
2537
2655
|
) {
|
|
2538
2656
|
restore("restore active profile", () =>
|
|
2539
|
-
prepared.session.setActiveModelProfile?.(
|
|
2657
|
+
prepared.session.setActiveModelProfile?.(
|
|
2658
|
+
prepared.previousActiveModelProfile,
|
|
2659
|
+
prepared.previousActivatedModelProfile === prepared.previousActiveModelProfile,
|
|
2660
|
+
),
|
|
2540
2661
|
);
|
|
2541
2662
|
}
|
|
2542
2663
|
if (
|
|
@@ -2583,6 +2704,7 @@ export interface MaterializeModelProfileForDeletionResult {
|
|
|
2583
2704
|
previousDefaultProfile: string | undefined;
|
|
2584
2705
|
previousPersistedDefaultProfile: string | undefined;
|
|
2585
2706
|
previousActiveModelProfile: string | undefined;
|
|
2707
|
+
previousActivatedModelProfile: string | undefined;
|
|
2586
2708
|
previousDefaultChainState: ConfiguredModelChainState | undefined;
|
|
2587
2709
|
previousDefaultFallbackRuntimeState: DefaultFallbackRuntimeState | undefined;
|
|
2588
2710
|
previousProfileInstalledOverrideState: AgentSessionProfileInstalledOverrideState | undefined;
|
|
@@ -2714,7 +2836,12 @@ export async function materializeModelProfileForDeletion(
|
|
|
2714
2836
|
? prepared.settings.clearOverride("modelProfile.default")
|
|
2715
2837
|
: prepared.settings.override("modelProfile.default", prepared.previousDefaultProfileOverride),
|
|
2716
2838
|
);
|
|
2717
|
-
restore(() =>
|
|
2839
|
+
restore(() =>
|
|
2840
|
+
prepared.session.setActiveModelProfile?.(
|
|
2841
|
+
prepared.previousActiveModelProfile,
|
|
2842
|
+
prepared.previousActivatedModelProfile === prepared.previousActiveModelProfile,
|
|
2843
|
+
),
|
|
2844
|
+
);
|
|
2718
2845
|
if (prepared.previousProfileInstalledOverrideState) {
|
|
2719
2846
|
restore(() =>
|
|
2720
2847
|
prepared.session.restoreProfileInstalledOverrideState?.(prepared.previousProfileInstalledOverrideState!),
|
|
@@ -2747,6 +2874,7 @@ export async function materializeModelProfileForDeletion(
|
|
|
2747
2874
|
previousDefaultProfile,
|
|
2748
2875
|
previousPersistedDefaultProfile,
|
|
2749
2876
|
previousActiveModelProfile: prepared.previousActiveModelProfile,
|
|
2877
|
+
previousActivatedModelProfile: prepared.previousActivatedModelProfile,
|
|
2750
2878
|
previousDefaultChainState: prepared.previousDefaultChainState,
|
|
2751
2879
|
previousDefaultFallbackRuntimeState: prepared.previousDefaultFallbackRuntimeState,
|
|
2752
2880
|
previousProfileInstalledOverrideState: prepared.previousProfileInstalledOverrideState,
|
|
@@ -2816,7 +2944,12 @@ export async function restoreMaterializedModelProfileForDeletion(options: {
|
|
|
2816
2944
|
? options.settings.clearOverride("modelProfile.default")
|
|
2817
2945
|
: options.settings.override("modelProfile.default", options.snapshot.previousDefaultProfileOverride),
|
|
2818
2946
|
);
|
|
2819
|
-
restore(() =>
|
|
2947
|
+
restore(() =>
|
|
2948
|
+
options.session.setActiveModelProfile?.(
|
|
2949
|
+
options.snapshot.previousActiveModelProfile,
|
|
2950
|
+
options.snapshot.previousActivatedModelProfile === options.snapshot.previousActiveModelProfile,
|
|
2951
|
+
),
|
|
2952
|
+
);
|
|
2820
2953
|
if (options.snapshot.previousProfileInstalledOverrideState) {
|
|
2821
2954
|
restore(() =>
|
|
2822
2955
|
options.session.restoreProfileInstalledOverrideState?.(
|
|
@@ -2863,6 +2996,7 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2863
2996
|
const previousModelRolesOverride = prepared.settings.getOverride("modelRoles");
|
|
2864
2997
|
const previousAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2865
2998
|
const previousActiveModelProfile = prepared.session.getActiveModelProfile?.();
|
|
2999
|
+
const previousActivatedModelProfile = prepared.session.getActivatedModelProfile?.();
|
|
2866
3000
|
const previousProfileInstalledOverrideState = prepared.session.getProfileInstalledOverrideState?.();
|
|
2867
3001
|
let activatedModelRolesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
2868
3002
|
let activatedAgentModelOverridesOverride: Readonly<Record<string, ModelSelectorValue>> | undefined;
|
|
@@ -2878,7 +3012,7 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2878
3012
|
...prepared.agentModelOverrides,
|
|
2879
3013
|
});
|
|
2880
3014
|
activatedAgentModelOverridesOverride = prepared.settings.getOverride("task.agentModelOverrides");
|
|
2881
|
-
prepared.session.setActiveModelProfile?.(prepared.profileName);
|
|
3015
|
+
prepared.session.setActiveModelProfile?.(prepared.profileName, true);
|
|
2882
3016
|
try {
|
|
2883
3017
|
await prepared.session.syncEagerDelegation?.();
|
|
2884
3018
|
} catch (error) {
|
|
@@ -2904,7 +3038,10 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2904
3038
|
prepared.settings.clearOverride("task.agentModelOverrides");
|
|
2905
3039
|
else prepared.settings.override("task.agentModelOverrides", restoredAgentModelOverridesOverride);
|
|
2906
3040
|
if (prepared.session.getActiveModelProfile?.() === prepared.profileName) {
|
|
2907
|
-
prepared.session.setActiveModelProfile?.(
|
|
3041
|
+
prepared.session.setActiveModelProfile?.(
|
|
3042
|
+
previousActiveModelProfile,
|
|
3043
|
+
previousActivatedModelProfile === previousActiveModelProfile,
|
|
3044
|
+
);
|
|
2908
3045
|
}
|
|
2909
3046
|
if (previousProfileInstalledOverrideState) {
|
|
2910
3047
|
prepared.session.restoreProfileInstalledOverrideState?.(previousProfileInstalledOverrideState);
|
|
@@ -2929,6 +3066,7 @@ export async function applyModelProfileRuntimeBindings(
|
|
|
2929
3066
|
modelRoles: [...prepared.manualModelRoleOverrides],
|
|
2930
3067
|
agentModelOverrides: [...prepared.manualAgentModelOverrides],
|
|
2931
3068
|
},
|
|
3069
|
+
prepared.defaultChain,
|
|
2932
3070
|
);
|
|
2933
3071
|
} finally {
|
|
2934
3072
|
if (isCurrent && !isCurrent()) {
|