@caupulican/pi-adaptative 0.81.26 → 0.81.29
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 +45 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +3 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +4 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +19 -2
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +30 -12
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +128 -36
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +6 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +35 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
- package/dist/core/autonomy/bounded-completion.js +59 -19
- package/dist/core/autonomy/bounded-completion.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +2 -0
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/autonomy/lane-tool-surface.d.ts +31 -0
- package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -0
- package/dist/core/autonomy/lane-tool-surface.js +96 -0
- package/dist/core/autonomy/lane-tool-surface.js.map +1 -0
- package/dist/core/autonomy/lane-tracker.d.ts +5 -0
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +14 -3
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +28 -4
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +237 -28
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/billing-failover-controller.d.ts.map +1 -1
- package/dist/core/billing-failover-controller.js +1 -1
- package/dist/core/billing-failover-controller.js.map +1 -1
- package/dist/core/context/current-work-memory.d.ts +9 -0
- package/dist/core/context/current-work-memory.d.ts.map +1 -0
- package/dist/core/context/current-work-memory.js +61 -0
- package/dist/core/context/current-work-memory.js.map +1 -0
- package/dist/core/context/file-store-memory-provider.d.ts +9 -0
- package/dist/core/context/file-store-memory-provider.d.ts.map +1 -0
- package/dist/core/context/file-store-memory-provider.js +106 -0
- package/dist/core/context/file-store-memory-provider.js.map +1 -0
- package/dist/core/context/long-term-memory-trigger.d.ts +15 -0
- package/dist/core/context/long-term-memory-trigger.d.ts.map +1 -0
- package/dist/core/context/long-term-memory-trigger.js +39 -0
- package/dist/core/context/long-term-memory-trigger.js.map +1 -0
- package/dist/core/context/memory-prompt-block.d.ts +3 -1
- package/dist/core/context/memory-prompt-block.d.ts.map +1 -1
- package/dist/core/context/memory-prompt-block.js +20 -3
- package/dist/core/context/memory-prompt-block.js.map +1 -1
- package/dist/core/context/memory-prompt-budget.d.ts +17 -0
- package/dist/core/context/memory-prompt-budget.d.ts.map +1 -0
- package/dist/core/context/memory-prompt-budget.js +64 -0
- package/dist/core/context/memory-prompt-budget.js.map +1 -0
- package/dist/core/context/memory-provider-contract.d.ts.map +1 -1
- package/dist/core/context/memory-provider-contract.js +2 -5
- package/dist/core/context/memory-provider-contract.js.map +1 -1
- package/dist/core/context/memory-tier-composer.d.ts +27 -0
- package/dist/core/context/memory-tier-composer.d.ts.map +1 -0
- package/dist/core/context/memory-tier-composer.js +79 -0
- package/dist/core/context/memory-tier-composer.js.map +1 -0
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +2 -0
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +5 -3
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +15 -5
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/cost/cost-summary.d.ts +3 -1
- package/dist/core/cost/cost-summary.d.ts.map +1 -1
- package/dist/core/cost/cost-summary.js +3 -3
- package/dist/core/cost/cost-summary.js.map +1 -1
- package/dist/core/cost-guard.d.ts +17 -7
- package/dist/core/cost-guard.d.ts.map +1 -1
- package/dist/core/cost-guard.js +33 -10
- package/dist/core/cost-guard.js.map +1 -1
- package/dist/core/default-tool-surface.d.ts +9 -0
- package/dist/core/default-tool-surface.d.ts.map +1 -0
- package/dist/core/default-tool-surface.js +18 -0
- package/dist/core/default-tool-surface.js.map +1 -0
- package/dist/core/delegation/worker-result.d.ts.map +1 -1
- package/dist/core/delegation/worker-result.js +3 -0
- package/dist/core/delegation/worker-result.js.map +1 -1
- package/dist/core/delegation/worker-runner.d.ts +11 -5
- package/dist/core/delegation/worker-runner.d.ts.map +1 -1
- package/dist/core/delegation/worker-runner.js +77 -16
- package/dist/core/delegation/worker-runner.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +15 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +2 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +9 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/failure-corpus.d.ts.map +1 -1
- package/dist/core/failure-corpus.js +2 -4
- package/dist/core/failure-corpus.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +9 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +4 -3
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts +12 -0
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +42 -4
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +16 -0
- package/dist/core/local-runtime-controller.d.ts.map +1 -1
- package/dist/core/local-runtime-controller.js +107 -28
- package/dist/core/local-runtime-controller.js.map +1 -1
- package/dist/core/memory/memory-manager.d.ts +8 -3
- package/dist/core/memory/memory-manager.d.ts.map +1 -1
- package/dist/core/memory/memory-manager.js +27 -11
- package/dist/core/memory/memory-manager.js.map +1 -1
- package/dist/core/memory/memory-provider.d.ts +5 -1
- package/dist/core/memory/memory-provider.d.ts.map +1 -1
- package/dist/core/memory/memory-provider.js.map +1 -1
- package/dist/core/memory/providers/file-store.d.ts +3 -1
- package/dist/core/memory/providers/file-store.d.ts.map +1 -1
- package/dist/core/memory/providers/file-store.js +7 -2
- package/dist/core/memory/providers/file-store.js.map +1 -1
- package/dist/core/memory/providers/transcript-recall.d.ts +1 -0
- package/dist/core/memory/providers/transcript-recall.d.ts.map +1 -1
- package/dist/core/memory/providers/transcript-recall.js +4 -7
- package/dist/core/memory/providers/transcript-recall.js.map +1 -1
- package/dist/core/memory-controller.d.ts +36 -10
- package/dist/core/memory-controller.d.ts.map +1 -1
- package/dist/core/memory-controller.js +137 -21
- package/dist/core/memory-controller.js.map +1 -1
- package/dist/core/model-registry.d.ts +25 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +91 -8
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +30 -11
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-router-controller.d.ts.map +1 -1
- package/dist/core/model-router-controller.js +33 -29
- package/dist/core/model-router-controller.js.map +1 -1
- package/dist/core/model-selection-controller.d.ts +3 -0
- package/dist/core/model-selection-controller.d.ts.map +1 -1
- package/dist/core/model-selection-controller.js +8 -1
- package/dist/core/model-selection-controller.js.map +1 -1
- package/dist/core/models/local-runtime.d.ts +2 -0
- package/dist/core/models/local-runtime.d.ts.map +1 -1
- package/dist/core/models/local-runtime.js +10 -4
- package/dist/core/models/local-runtime.js.map +1 -1
- package/dist/core/models/perf-profile.d.ts.map +1 -1
- package/dist/core/models/perf-profile.js +95 -33
- package/dist/core/models/perf-profile.js.map +1 -1
- package/dist/core/models/runtime-arbiter.d.ts +11 -0
- package/dist/core/models/runtime-arbiter.d.ts.map +1 -1
- package/dist/core/models/runtime-arbiter.js +35 -13
- package/dist/core/models/runtime-arbiter.js.map +1 -1
- package/dist/core/profile-filter-controller.d.ts +11 -0
- package/dist/core/profile-filter-controller.d.ts.map +1 -1
- package/dist/core/profile-filter-controller.js +56 -11
- package/dist/core/profile-filter-controller.js.map +1 -1
- package/dist/core/profile-registry.d.ts +2 -2
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +58 -7
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +9 -7
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +81 -12
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/research/research-runner.d.ts +2 -2
- package/dist/core/research/research-runner.d.ts.map +1 -1
- package/dist/core/research/research-runner.js +8 -6
- package/dist/core/research/research-runner.js.map +1 -1
- package/dist/core/resource-loader.d.ts +4 -2
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +11 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +30 -3
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +140 -40
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/sdk.d.ts +8 -7
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +38 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/security/secret-text.d.ts +3 -0
- package/dist/core/security/secret-text.d.ts.map +1 -0
- package/dist/core/security/secret-text.js +26 -0
- package/dist/core/security/secret-text.js.map +1 -0
- package/dist/core/settings-manager.d.ts +59 -17
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +300 -51
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +1 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +7 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.js +23 -1
- package/dist/core/system-prompt-builder.js.map +1 -1
- package/dist/core/tool-gate-controller.d.ts +3 -0
- package/dist/core/tool-gate-controller.d.ts.map +1 -1
- package/dist/core/tool-gate-controller.js +20 -15
- package/dist/core/tool-gate-controller.js.map +1 -1
- package/dist/core/tool-selection/expected-utility.d.ts +51 -0
- package/dist/core/tool-selection/expected-utility.d.ts.map +1 -0
- package/dist/core/tool-selection/expected-utility.js +85 -0
- package/dist/core/tool-selection/expected-utility.js.map +1 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts +82 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -0
- package/dist/core/tool-selection/tool-performance-store.js +249 -0
- package/dist/core/tool-selection/tool-performance-store.js.map +1 -0
- package/dist/core/tool-selection/tool-selection-controller.d.ts +41 -0
- package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -0
- package/dist/core/tool-selection/tool-selection-controller.js +199 -0
- package/dist/core/tool-selection/tool-selection-controller.js.map +1 -0
- package/dist/core/tools/delegate-status.d.ts +9 -0
- package/dist/core/tools/delegate-status.d.ts.map +1 -0
- package/dist/core/tools/delegate-status.js +52 -0
- package/dist/core/tools/delegate-status.js.map +1 -0
- package/dist/core/tools/delegate.d.ts +10 -0
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +36 -13
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/run-toolkit-script.d.ts +3 -0
- package/dist/core/tools/run-toolkit-script.d.ts.map +1 -1
- package/dist/core/tools/run-toolkit-script.js +17 -7
- package/dist/core/tools/run-toolkit-script.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +69 -29
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +2 -0
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/config-backup.d.ts +7 -1
- package/dist/modes/interactive/config-backup.d.ts.map +1 -1
- package/dist/modes/interactive/config-backup.js +196 -32
- package/dist/modes/interactive/config-backup.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +22 -28
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
- package/dist/modes/interactive/local-model-commands.js +2 -0
- package/dist/modes/interactive/local-model-commands.js.map +1 -1
- package/dist/modes/interactive/profile-menu-controller.d.ts +6 -4
- package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
- package/dist/modes/interactive/profile-menu-controller.js +248 -65
- package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
- package/dist/modes/interactive/report-commands.d.ts.map +1 -1
- package/dist/modes/interactive/report-commands.js +8 -2
- package/dist/modes/interactive/report-commands.js.map +1 -1
- package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -1
- package/dist/modes/interactive/settings-selector-flow.js +8 -0
- package/dist/modes/interactive/settings-selector-flow.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +3 -1
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/docs/extensions.md +32 -0
- package/docs/integration-sweep-builder-blueprint-2026-07-09.md +365 -0
- package/docs/integration-sweep-resume-2026-07-09.md +407 -0
- package/docs/resources.md +15 -7
- package/docs/settings.md +56 -5
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/preset.ts +2 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +44 -35
- package/package.json +4 -4
|
@@ -13,7 +13,7 @@ export const defaultModelPerProvider = {
|
|
|
13
13
|
openai: "gpt-5.4",
|
|
14
14
|
fugu: "fugu",
|
|
15
15
|
"azure-openai-responses": "gpt-5.4",
|
|
16
|
-
"openai-codex": "gpt-5.
|
|
16
|
+
"openai-codex": "gpt-5.6-sol",
|
|
17
17
|
deepseek: "deepseek-v4-pro",
|
|
18
18
|
google: "gemini-3.1-pro-preview",
|
|
19
19
|
"google-vertex": "gemini-3.1-pro-preview",
|
|
@@ -472,6 +472,9 @@ export function resolveCliProviderDefault(options) {
|
|
|
472
472
|
const model = (defaultId ? providerModels.find((candidate) => candidate.id === defaultId) : undefined) ?? providerModels[0];
|
|
473
473
|
return { model, warning: undefined, thinkingLevel: undefined, error: undefined };
|
|
474
474
|
}
|
|
475
|
+
function resolveInitialThinkingLevel(model, explicitThinkingLevel) {
|
|
476
|
+
return explicitThinkingLevel ?? model.defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL;
|
|
477
|
+
}
|
|
475
478
|
/**
|
|
476
479
|
* Find the initial model to use based on priority:
|
|
477
480
|
* 1. CLI args (provider + optional model)
|
|
@@ -483,7 +486,6 @@ export function resolveCliProviderDefault(options) {
|
|
|
483
486
|
export async function findInitialModel(options) {
|
|
484
487
|
const { cliProvider, cliModel, scopedModels, isContinuing, defaultProvider, defaultModelId, defaultThinkingLevel, modelRegistry, } = options;
|
|
485
488
|
let model;
|
|
486
|
-
let thinkingLevel = DEFAULT_THINKING_LEVEL;
|
|
487
489
|
// 1. CLI args take priority
|
|
488
490
|
if (cliProvider || cliModel) {
|
|
489
491
|
const resolved = cliModel
|
|
@@ -498,14 +500,18 @@ export async function findInitialModel(options) {
|
|
|
498
500
|
process.exit(1);
|
|
499
501
|
}
|
|
500
502
|
if (resolved.model) {
|
|
501
|
-
return {
|
|
503
|
+
return {
|
|
504
|
+
model: resolved.model,
|
|
505
|
+
thinkingLevel: resolveInitialThinkingLevel(resolved.model, resolved.thinkingLevel ?? defaultThinkingLevel),
|
|
506
|
+
fallbackMessage: undefined,
|
|
507
|
+
};
|
|
502
508
|
}
|
|
503
509
|
}
|
|
504
510
|
// 2. Use first model from scoped models (skip if continuing/resuming)
|
|
505
511
|
if (scopedModels.length > 0 && !isContinuing) {
|
|
506
512
|
return {
|
|
507
513
|
model: scopedModels[0].model,
|
|
508
|
-
thinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel
|
|
514
|
+
thinkingLevel: resolveInitialThinkingLevel(scopedModels[0].model, scopedModels[0].thinkingLevel ?? defaultThinkingLevel),
|
|
509
515
|
fallbackMessage: undefined,
|
|
510
516
|
};
|
|
511
517
|
}
|
|
@@ -514,10 +520,11 @@ export async function findInitialModel(options) {
|
|
|
514
520
|
const found = modelRegistry.find(defaultProvider, defaultModelId);
|
|
515
521
|
if (found) {
|
|
516
522
|
model = found;
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
523
|
+
return {
|
|
524
|
+
model,
|
|
525
|
+
thinkingLevel: resolveInitialThinkingLevel(model, defaultThinkingLevel),
|
|
526
|
+
fallbackMessage: undefined,
|
|
527
|
+
};
|
|
521
528
|
}
|
|
522
529
|
}
|
|
523
530
|
// 4. Try first available model with valid API key
|
|
@@ -528,14 +535,26 @@ export async function findInitialModel(options) {
|
|
|
528
535
|
const defaultId = defaultModelPerProvider[provider];
|
|
529
536
|
const match = availableModels.find((m) => m.provider === provider && m.id === defaultId);
|
|
530
537
|
if (match) {
|
|
531
|
-
return {
|
|
538
|
+
return {
|
|
539
|
+
model: match,
|
|
540
|
+
thinkingLevel: resolveInitialThinkingLevel(match, defaultThinkingLevel),
|
|
541
|
+
fallbackMessage: undefined,
|
|
542
|
+
};
|
|
532
543
|
}
|
|
533
544
|
}
|
|
534
545
|
// If no default found, use first available
|
|
535
|
-
return {
|
|
546
|
+
return {
|
|
547
|
+
model: availableModels[0],
|
|
548
|
+
thinkingLevel: resolveInitialThinkingLevel(availableModels[0], defaultThinkingLevel),
|
|
549
|
+
fallbackMessage: undefined,
|
|
550
|
+
};
|
|
536
551
|
}
|
|
537
552
|
// 5. No model found
|
|
538
|
-
return {
|
|
553
|
+
return {
|
|
554
|
+
model: undefined,
|
|
555
|
+
thinkingLevel: defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,
|
|
556
|
+
fallbackMessage: undefined,
|
|
557
|
+
};
|
|
539
558
|
}
|
|
540
559
|
/**
|
|
541
560
|
* Restore model from session, with fallback to available models
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport chalk from \"chalk\";\nimport { minimatch } from \"minimatch\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport type { ProfileRegistry } from \"./profile-registry.ts\";\n\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\n\tanthropic: \"claude-opus-4-8\",\n\topenai: \"gpt-5.4\",\n\tfugu: \"fugu\",\n\t\"azure-openai-responses\": \"gpt-5.4\",\n\t\"openai-codex\": \"gpt-5.5\",\n\tdeepseek: \"deepseek-v4-pro\",\n\tgoogle: \"gemini-3.1-pro-preview\",\n\t\"google-vertex\": \"gemini-3.1-pro-preview\",\n\t\"github-copilot\": \"gpt-5.4\",\n\topenrouter: \"moonshotai/kimi-k2.6\",\n\t\"vercel-ai-gateway\": \"zai/glm-5.1\",\n\txai: \"grok-4.20-0309-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.7\",\n\tzai: \"glm-5.1\",\n\tmistral: \"devstral-medium-latest\",\n\tminimax: \"MiniMax-M2.7\",\n\t\"minimax-cn\": \"MiniMax-M2.7\",\n\tmoonshotai: \"kimi-k2.6\",\n\t\"moonshotai-cn\": \"kimi-k2.6\",\n\thuggingface: \"moonshotai/Kimi-K2.6\",\n\tfireworks: \"accounts/fireworks/models/kimi-k2p6\",\n\ttogether: \"moonshotai/Kimi-K2.6\",\n\topencode: \"kimi-k2.6\",\n\t\"opencode-go\": \"kimi-k2.6\",\n\t\"kimi-coding\": \"kimi-for-coding\",\n\t\"llama-cpp\": \"local\",\n\t\"cloudflare-workers-ai\": \"@cf/moonshotai/kimi-k2.6\",\n\t\"cloudflare-ai-gateway\": \"workers-ai/@cf/moonshotai/kimi-k2.6\",\n\txiaomi: \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-cn\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-ams\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-sgp\": \"mimo-v2.5-pro\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n}\n\n/** User-friendly aliases for CLI provider names. Keep canonical provider IDs authoritative. */\nexport const cliProviderAliases: Record<string, string> = {\n\tchatgpt: \"openai-codex\",\n\tcodex: \"openai-codex\",\n\t\"openai-codex-subscription\": \"openai-codex\",\n\t\"openai-subscription\": \"openai-codex\",\n\tclaude: \"anthropic\",\n\t\"claude-pro\": \"anthropic\",\n\t\"claude-max\": \"anthropic\",\n};\n\nfunction buildProviderLookup(availableModels: Model<Api>[]): Map<string, string> {\n\tconst providerMap = new Map<string, string>();\n\tfor (const model of availableModels) {\n\t\tproviderMap.set(model.provider.toLowerCase(), model.provider);\n\t}\n\tfor (const [alias, canonical] of Object.entries(cliProviderAliases)) {\n\t\tconst normalizedAlias = alias.toLowerCase();\n\t\tif (providerMap.has(normalizedAlias)) continue;\n\t\tconst resolvedCanonical = providerMap.get(canonical.toLowerCase());\n\t\tif (resolvedCanonical) {\n\t\t\tproviderMap.set(normalizedAlias, resolvedCanonical);\n\t\t}\n\t}\n\treturn providerMap;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Find an exact model reference match.\n * Supports either a bare model id or a canonical provider/modelId reference.\n * When matching by bare id, ambiguous matches across providers are rejected.\n */\nexport function findExactModelReferenceMatch(\n\tmodelReference: string,\n\tavailableModels: Model<Api>[],\n): Model<Api> | undefined {\n\tconst trimmedReference = modelReference.trim();\n\tif (!trimmedReference) {\n\t\treturn undefined;\n\t}\n\n\tconst normalizedReference = trimmedReference.toLowerCase();\n\n\tconst canonicalMatches = availableModels.filter(\n\t\t(model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,\n\t);\n\tif (canonicalMatches.length === 1) {\n\t\treturn canonicalMatches[0];\n\t}\n\tif (canonicalMatches.length > 1) {\n\t\treturn undefined;\n\t}\n\n\tconst slashIndex = trimmedReference.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = trimmedReference.substring(0, slashIndex).trim();\n\t\tconst modelId = trimmedReference.substring(slashIndex + 1).trim();\n\t\tif (provider && modelId) {\n\t\t\tconst providerMatches = availableModels.filter(\n\t\t\t\t(model) =>\n\t\t\t\t\tmodel.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\t\tmodel.id.toLowerCase() === modelId.toLowerCase(),\n\t\t\t);\n\t\t\tif (providerMatches.length === 1) {\n\t\t\t\treturn providerMatches[0];\n\t\t\t}\n\t\t\tif (providerMatches.length > 1) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n\treturn idMatches.length === 1 ? idMatches[0] : undefined;\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or undefined if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst exactMatch = findExactModelReferenceMatch(modelPattern, availableModels);\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | undefined;\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n}\n\nfunction buildFallbackModel(provider: string, modelId: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst providerModels = availableModels.filter((m) => m.provider === provider);\n\tif (providerModels.length === 0) return undefined;\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst baseModel = defaultId\n\t\t? (providerModels.find((m) => m.id === defaultId) ?? providerModels[0])\n\t\t: providerModels[0];\n\n\treturn {\n\t\t...baseModel,\n\t\tid: modelId,\n\t\tname: modelId,\n\t};\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(\n\tpattern: string,\n\tavailableModels: Model<Api>[],\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\n): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\n\t\tif (!allowFallback) {\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\n\t\t\t// This avoids accidentally resolving to a different model.\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t\t}\n\n\t\t// Scope mode: recurse on prefix and warn\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\t// Check if pattern contains glob characters\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\n\t\t\tlet globPattern = pattern;\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\n\n\t\t\tif (colonIdx !== -1) {\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\n\t\t\t\t\tthinkingLevel = suffix;\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\n\t\t\tconst matchingModels = availableModels.filter((m) => {\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\n\t\t\t});\n\n\t\t\tif (matchingModels.length === 0) {\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const model of matchingModels) {\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface ResolveCliModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n\t/**\n\t * Error message suitable for CLI display.\n\t * When set, model will be undefined.\n\t */\n\terror: string | undefined;\n}\n\nfunction formatAmbiguousModelReferenceError(modelReference: string, matches: Model<Api>[]): string {\n\tconst candidates = matches.map((model) => `${model.provider}/${model.id}`).sort();\n\treturn `Model \"${modelReference}\" is ambiguous. Use one of: ${candidates.join(\", \")}.`;\n}\n\n/**\n * Resolve a single model from CLI flags.\n *\n * Supports:\n * - --provider <provider> --model <pattern>\n * - --model <provider>/<pattern>\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\n *\n * Note: This does not apply the thinking level by itself, but it may *parse* and\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\n */\nexport function resolveCliModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, cliModel, modelRegistry } = options;\n\n\tif (!cliModel) {\n\t\treturn { model: undefined, warning: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--api-key\" to be used for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\t// Build canonical provider lookup (case-insensitive), including friendly aliases.\n\tconst providerMap = buildProviderLookup(availableModels);\n\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\n\tif (cliProvider && !provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\t// If no explicit --provider, try to interpret \"provider/model\" format first.\n\t// When the prefix before the first slash matches a known provider, prefer that\n\t// interpretation over matching models whose IDs literally contain slashes\n\t// (e.g. \"zai/glm-5\" should resolve to provider=zai, model=glm-5, not to a\n\t// vercel-ai-gateway model with id \"zai/glm-5\").\n\tlet pattern = cliModel;\n\tlet inferredProvider = false;\n\n\tif (!provider) {\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\n\t\tif (slashIndex !== -1) {\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\n\t\t\tif (canonical) {\n\t\t\t\tprovider = canonical;\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\n\t\t\t\tinferredProvider = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// If no provider was inferred from the slash, try exact matches without provider inference.\n\t// This handles models whose IDs naturally contain slashes (e.g. OpenRouter-style IDs).\n\tif (!provider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exactReferenceMatches = availableModels.filter((m) => `${m.provider}/${m.id}`.toLowerCase() === lower);\n\t\tif (exactReferenceMatches.length === 1) {\n\t\t\treturn { model: exactReferenceMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (exactReferenceMatches.length > 1) {\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, exactReferenceMatches),\n\t\t\t};\n\t\t}\n\n\t\tconst idMatches = availableModels.filter((m) => m.id.toLowerCase() === lower);\n\t\tif (idMatches.length === 1) {\n\t\t\treturn { model: idMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (idMatches.length > 1) {\n\t\t\tconst authenticatedMatches = modelRegistry\n\t\t\t\t.getAvailable()\n\t\t\t\t.filter((available) => idMatches.some((match) => modelsAreEqual(available, match)));\n\t\t\tif (authenticatedMatches.length === 1) {\n\t\t\t\treturn { model: authenticatedMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, idMatches),\n\t\t\t};\n\t\t}\n\t}\n\n\tif (cliProvider && provider) {\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping\n\t\t// either the canonical provider prefix or the user-entered alias prefix.\n\t\tconst prefixes = Array.from(new Set([provider, cliProvider].filter((value) => value.length > 0)));\n\t\tfor (const candidatePrefix of prefixes) {\n\t\t\tconst prefix = `${candidatePrefix}/`;\n\t\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\n\t\t\t\tpattern = cliModel.substring(prefix.length);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\n\t\tallowInvalidThinkingLevelFallback: false,\n\t});\n\n\tif (model) {\n\t\treturn { model, thinkingLevel, warning, error: undefined };\n\t}\n\n\t// If we inferred a provider from the slash but found no match within that provider,\n\t// fall back to matching the full input as a raw model id across all models.\n\t// This handles OpenRouter-style IDs like \"openai/gpt-4o:extended\" where \"openai\"\n\t// looks like a provider but the full string is actually a model id on openrouter.\n\tif (inferredProvider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\t// Also try parseModelPattern on the full input against all models\n\t\tconst fallback = parseModelPattern(cliModel, availableModels, {\n\t\t\tallowInvalidThinkingLevelFallback: false,\n\t\t});\n\t\tif (fallback.model) {\n\t\t\treturn {\n\t\t\t\tmodel: fallback.model,\n\t\t\t\tthinkingLevel: fallback.thinkingLevel,\n\t\t\t\twarning: fallback.warning,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (provider) {\n\t\tconst fallbackModel = buildFallbackModel(provider, pattern, availableModels);\n\t\tif (fallbackModel) {\n\t\t\tconst fallbackWarning = warning\n\t\t\t\t? `${warning} Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`\n\t\t\t\t: `Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`;\n\t\t\treturn { model: fallbackModel, thinkingLevel: undefined, warning: fallbackWarning, error: undefined };\n\t\t}\n\t}\n\n\tconst display = provider ? `${provider}/${pattern}` : cliModel;\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: undefined,\n\t\twarning,\n\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\n\t};\n}\n\nexport function resolveCliProviderDefault(options: {\n\tcliProvider?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, modelRegistry } = options;\n\tif (!cliProvider) {\n\t\treturn { model: undefined, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--provider <name> --api-key <key>\" to work for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\tconst providerMap = buildProviderLookup(availableModels);\n\tconst provider = providerMap.get(cliProvider.toLowerCase());\n\tif (!provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst providerModels = availableModels.filter((model) => model.provider === provider);\n\tif (providerModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `No models found for provider \"${provider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst model =\n\t\t(defaultId ? providerModels.find((candidate) => candidate.id === defaultId) : undefined) ?? providerModels[0];\n\treturn { model, warning: undefined, thinkingLevel: undefined, error: undefined };\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | undefined;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + optional model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | undefined;\n\tlet thinkingLevel: ThinkingLevel = DEFAULT_THINKING_LEVEL;\n\n\t// 1. CLI args take priority\n\tif (cliProvider || cliModel) {\n\t\tconst resolved = cliModel\n\t\t\t? resolveCliModel({\n\t\t\t\t\tcliProvider,\n\t\t\t\t\tcliModel,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t})\n\t\t\t: resolveCliProviderDefault({ cliProvider, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tconsole.error(chalk.red(resolved.error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (resolved.model) {\n\t\t\treturn { model: resolved.model, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n\t\t}\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\tif (defaultThinkingLevel) {\n\t\t\t\tthinkingLevel = defaultThinkingLevel;\n\t\t\t}\n\t\t\treturn { model, thinkingLevel, fallbackMessage: undefined };\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn { model: match, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\treturn { model: availableModels[0], thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n\t}\n\n\t// 5. No model found\n\treturn { model: undefined, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | undefined,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and still has auth configured\n\tconst hasConfiguredAuth = restoredModel ? modelRegistry.hasConfiguredAuth(restoredModel) : false;\n\n\tif (restoredModel && hasConfiguredAuth) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no auth configured\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | undefined;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: undefined, fallbackMessage: undefined };\n}\n\nexport interface ResolvedProfileModelSettings {\n\tmodel?: Model<any>;\n\tthinkingLevel?: ThinkingLevel;\n\twarning?: string;\n\terror?: string;\n}\n\nexport function resolveProfileModelSettings(options: {\n\tactiveProfileNames: string[];\n\tregistry: ProfileRegistry;\n\tmodelRegistry: ModelRegistry;\n\tcwd: string;\n}): ResolvedProfileModelSettings {\n\tconst { activeProfileNames, registry, modelRegistry, cwd } = options;\n\tlet modelString: string | undefined;\n\tlet thinking: ThinkingLevel | undefined;\n\n\tfor (const profileName of activeProfileNames) {\n\t\tconst profile =\n\t\t\tprofileName.startsWith(\"./\") || profileName.startsWith(\"../\")\n\t\t\t\t? registry.resolveProfileRef(profileName, cwd)\n\t\t\t\t: registry.getProfile(profileName);\n\t\tif (profile) {\n\t\t\tif (!modelString && profile.model) {\n\t\t\t\tmodelString = profile.model;\n\t\t\t}\n\t\t\tif (!thinking && profile.thinking) {\n\t\t\t\tthinking = profile.thinking;\n\t\t\t}\n\t\t\tif (modelString && thinking) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!modelString && !thinking) {\n\t\treturn {};\n\t}\n\n\tconst result: ResolvedProfileModelSettings = {};\n\tif (modelString) {\n\t\tconst resolved = resolveCliModel({ cliModel: modelString, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tresult.error = resolved.error;\n\t\t}\n\t\tif (resolved.warning) {\n\t\t\tresult.warning = resolved.warning;\n\t\t}\n\t\tif (resolved.model) {\n\t\t\tresult.model = resolved.model;\n\t\t}\n\t\tif (resolved.thinkingLevel && !thinking) {\n\t\t\tthinking = resolved.thinkingLevel;\n\t\t}\n\t}\n\n\tif (thinking) {\n\t\tresult.thinkingLevel = thinking;\n\t}\n\n\treturn result;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport chalk from \"chalk\";\nimport { minimatch } from \"minimatch\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport type { ProfileRegistry } from \"./profile-registry.ts\";\n\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\n\tanthropic: \"claude-opus-4-8\",\n\topenai: \"gpt-5.4\",\n\tfugu: \"fugu\",\n\t\"azure-openai-responses\": \"gpt-5.4\",\n\t\"openai-codex\": \"gpt-5.6-sol\",\n\tdeepseek: \"deepseek-v4-pro\",\n\tgoogle: \"gemini-3.1-pro-preview\",\n\t\"google-vertex\": \"gemini-3.1-pro-preview\",\n\t\"github-copilot\": \"gpt-5.4\",\n\topenrouter: \"moonshotai/kimi-k2.6\",\n\t\"vercel-ai-gateway\": \"zai/glm-5.1\",\n\txai: \"grok-4.20-0309-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.7\",\n\tzai: \"glm-5.1\",\n\tmistral: \"devstral-medium-latest\",\n\tminimax: \"MiniMax-M2.7\",\n\t\"minimax-cn\": \"MiniMax-M2.7\",\n\tmoonshotai: \"kimi-k2.6\",\n\t\"moonshotai-cn\": \"kimi-k2.6\",\n\thuggingface: \"moonshotai/Kimi-K2.6\",\n\tfireworks: \"accounts/fireworks/models/kimi-k2p6\",\n\ttogether: \"moonshotai/Kimi-K2.6\",\n\topencode: \"kimi-k2.6\",\n\t\"opencode-go\": \"kimi-k2.6\",\n\t\"kimi-coding\": \"kimi-for-coding\",\n\t\"llama-cpp\": \"local\",\n\t\"cloudflare-workers-ai\": \"@cf/moonshotai/kimi-k2.6\",\n\t\"cloudflare-ai-gateway\": \"workers-ai/@cf/moonshotai/kimi-k2.6\",\n\txiaomi: \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-cn\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-ams\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-sgp\": \"mimo-v2.5-pro\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n}\n\n/** User-friendly aliases for CLI provider names. Keep canonical provider IDs authoritative. */\nexport const cliProviderAliases: Record<string, string> = {\n\tchatgpt: \"openai-codex\",\n\tcodex: \"openai-codex\",\n\t\"openai-codex-subscription\": \"openai-codex\",\n\t\"openai-subscription\": \"openai-codex\",\n\tclaude: \"anthropic\",\n\t\"claude-pro\": \"anthropic\",\n\t\"claude-max\": \"anthropic\",\n};\n\nfunction buildProviderLookup(availableModels: Model<Api>[]): Map<string, string> {\n\tconst providerMap = new Map<string, string>();\n\tfor (const model of availableModels) {\n\t\tproviderMap.set(model.provider.toLowerCase(), model.provider);\n\t}\n\tfor (const [alias, canonical] of Object.entries(cliProviderAliases)) {\n\t\tconst normalizedAlias = alias.toLowerCase();\n\t\tif (providerMap.has(normalizedAlias)) continue;\n\t\tconst resolvedCanonical = providerMap.get(canonical.toLowerCase());\n\t\tif (resolvedCanonical) {\n\t\t\tproviderMap.set(normalizedAlias, resolvedCanonical);\n\t\t}\n\t}\n\treturn providerMap;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Find an exact model reference match.\n * Supports either a bare model id or a canonical provider/modelId reference.\n * When matching by bare id, ambiguous matches across providers are rejected.\n */\nexport function findExactModelReferenceMatch(\n\tmodelReference: string,\n\tavailableModels: Model<Api>[],\n): Model<Api> | undefined {\n\tconst trimmedReference = modelReference.trim();\n\tif (!trimmedReference) {\n\t\treturn undefined;\n\t}\n\n\tconst normalizedReference = trimmedReference.toLowerCase();\n\n\tconst canonicalMatches = availableModels.filter(\n\t\t(model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,\n\t);\n\tif (canonicalMatches.length === 1) {\n\t\treturn canonicalMatches[0];\n\t}\n\tif (canonicalMatches.length > 1) {\n\t\treturn undefined;\n\t}\n\n\tconst slashIndex = trimmedReference.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = trimmedReference.substring(0, slashIndex).trim();\n\t\tconst modelId = trimmedReference.substring(slashIndex + 1).trim();\n\t\tif (provider && modelId) {\n\t\t\tconst providerMatches = availableModels.filter(\n\t\t\t\t(model) =>\n\t\t\t\t\tmodel.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\t\tmodel.id.toLowerCase() === modelId.toLowerCase(),\n\t\t\t);\n\t\t\tif (providerMatches.length === 1) {\n\t\t\t\treturn providerMatches[0];\n\t\t\t}\n\t\t\tif (providerMatches.length > 1) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n\treturn idMatches.length === 1 ? idMatches[0] : undefined;\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or undefined if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst exactMatch = findExactModelReferenceMatch(modelPattern, availableModels);\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | undefined;\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n}\n\nfunction buildFallbackModel(provider: string, modelId: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst providerModels = availableModels.filter((m) => m.provider === provider);\n\tif (providerModels.length === 0) return undefined;\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst baseModel = defaultId\n\t\t? (providerModels.find((m) => m.id === defaultId) ?? providerModels[0])\n\t\t: providerModels[0];\n\n\treturn {\n\t\t...baseModel,\n\t\tid: modelId,\n\t\tname: modelId,\n\t};\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(\n\tpattern: string,\n\tavailableModels: Model<Api>[],\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\n): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\n\t\tif (!allowFallback) {\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\n\t\t\t// This avoids accidentally resolving to a different model.\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t\t}\n\n\t\t// Scope mode: recurse on prefix and warn\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\t// Check if pattern contains glob characters\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\n\t\t\tlet globPattern = pattern;\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\n\n\t\t\tif (colonIdx !== -1) {\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\n\t\t\t\t\tthinkingLevel = suffix;\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\n\t\t\tconst matchingModels = availableModels.filter((m) => {\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\n\t\t\t});\n\n\t\t\tif (matchingModels.length === 0) {\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const model of matchingModels) {\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface ResolveCliModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n\t/**\n\t * Error message suitable for CLI display.\n\t * When set, model will be undefined.\n\t */\n\terror: string | undefined;\n}\n\nfunction formatAmbiguousModelReferenceError(modelReference: string, matches: Model<Api>[]): string {\n\tconst candidates = matches.map((model) => `${model.provider}/${model.id}`).sort();\n\treturn `Model \"${modelReference}\" is ambiguous. Use one of: ${candidates.join(\", \")}.`;\n}\n\n/**\n * Resolve a single model from CLI flags.\n *\n * Supports:\n * - --provider <provider> --model <pattern>\n * - --model <provider>/<pattern>\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\n *\n * Note: This does not apply the thinking level by itself, but it may *parse* and\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\n */\nexport function resolveCliModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, cliModel, modelRegistry } = options;\n\n\tif (!cliModel) {\n\t\treturn { model: undefined, warning: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--api-key\" to be used for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\t// Build canonical provider lookup (case-insensitive), including friendly aliases.\n\tconst providerMap = buildProviderLookup(availableModels);\n\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\n\tif (cliProvider && !provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\t// If no explicit --provider, try to interpret \"provider/model\" format first.\n\t// When the prefix before the first slash matches a known provider, prefer that\n\t// interpretation over matching models whose IDs literally contain slashes\n\t// (e.g. \"zai/glm-5\" should resolve to provider=zai, model=glm-5, not to a\n\t// vercel-ai-gateway model with id \"zai/glm-5\").\n\tlet pattern = cliModel;\n\tlet inferredProvider = false;\n\n\tif (!provider) {\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\n\t\tif (slashIndex !== -1) {\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\n\t\t\tif (canonical) {\n\t\t\t\tprovider = canonical;\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\n\t\t\t\tinferredProvider = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// If no provider was inferred from the slash, try exact matches without provider inference.\n\t// This handles models whose IDs naturally contain slashes (e.g. OpenRouter-style IDs).\n\tif (!provider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exactReferenceMatches = availableModels.filter((m) => `${m.provider}/${m.id}`.toLowerCase() === lower);\n\t\tif (exactReferenceMatches.length === 1) {\n\t\t\treturn { model: exactReferenceMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (exactReferenceMatches.length > 1) {\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, exactReferenceMatches),\n\t\t\t};\n\t\t}\n\n\t\tconst idMatches = availableModels.filter((m) => m.id.toLowerCase() === lower);\n\t\tif (idMatches.length === 1) {\n\t\t\treturn { model: idMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (idMatches.length > 1) {\n\t\t\tconst authenticatedMatches = modelRegistry\n\t\t\t\t.getAvailable()\n\t\t\t\t.filter((available) => idMatches.some((match) => modelsAreEqual(available, match)));\n\t\t\tif (authenticatedMatches.length === 1) {\n\t\t\t\treturn { model: authenticatedMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, idMatches),\n\t\t\t};\n\t\t}\n\t}\n\n\tif (cliProvider && provider) {\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping\n\t\t// either the canonical provider prefix or the user-entered alias prefix.\n\t\tconst prefixes = Array.from(new Set([provider, cliProvider].filter((value) => value.length > 0)));\n\t\tfor (const candidatePrefix of prefixes) {\n\t\t\tconst prefix = `${candidatePrefix}/`;\n\t\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\n\t\t\t\tpattern = cliModel.substring(prefix.length);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\n\t\tallowInvalidThinkingLevelFallback: false,\n\t});\n\n\tif (model) {\n\t\treturn { model, thinkingLevel, warning, error: undefined };\n\t}\n\n\t// If we inferred a provider from the slash but found no match within that provider,\n\t// fall back to matching the full input as a raw model id across all models.\n\t// This handles OpenRouter-style IDs like \"openai/gpt-4o:extended\" where \"openai\"\n\t// looks like a provider but the full string is actually a model id on openrouter.\n\tif (inferredProvider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\t// Also try parseModelPattern on the full input against all models\n\t\tconst fallback = parseModelPattern(cliModel, availableModels, {\n\t\t\tallowInvalidThinkingLevelFallback: false,\n\t\t});\n\t\tif (fallback.model) {\n\t\t\treturn {\n\t\t\t\tmodel: fallback.model,\n\t\t\t\tthinkingLevel: fallback.thinkingLevel,\n\t\t\t\twarning: fallback.warning,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (provider) {\n\t\tconst fallbackModel = buildFallbackModel(provider, pattern, availableModels);\n\t\tif (fallbackModel) {\n\t\t\tconst fallbackWarning = warning\n\t\t\t\t? `${warning} Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`\n\t\t\t\t: `Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`;\n\t\t\treturn { model: fallbackModel, thinkingLevel: undefined, warning: fallbackWarning, error: undefined };\n\t\t}\n\t}\n\n\tconst display = provider ? `${provider}/${pattern}` : cliModel;\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: undefined,\n\t\twarning,\n\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\n\t};\n}\n\nexport function resolveCliProviderDefault(options: {\n\tcliProvider?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, modelRegistry } = options;\n\tif (!cliProvider) {\n\t\treturn { model: undefined, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--provider <name> --api-key <key>\" to work for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\tconst providerMap = buildProviderLookup(availableModels);\n\tconst provider = providerMap.get(cliProvider.toLowerCase());\n\tif (!provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst providerModels = availableModels.filter((model) => model.provider === provider);\n\tif (providerModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `No models found for provider \"${provider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst model =\n\t\t(defaultId ? providerModels.find((candidate) => candidate.id === defaultId) : undefined) ?? providerModels[0];\n\treturn { model, warning: undefined, thinkingLevel: undefined, error: undefined };\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | undefined;\n}\n\nfunction resolveInitialThinkingLevel(model: Model<Api>, explicitThinkingLevel?: ThinkingLevel): ThinkingLevel {\n\treturn explicitThinkingLevel ?? model.defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + optional model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | undefined;\n\n\t// 1. CLI args take priority\n\tif (cliProvider || cliModel) {\n\t\tconst resolved = cliModel\n\t\t\t? resolveCliModel({\n\t\t\t\t\tcliProvider,\n\t\t\t\t\tcliModel,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t})\n\t\t\t: resolveCliProviderDefault({ cliProvider, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tconsole.error(chalk.red(resolved.error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (resolved.model) {\n\t\t\treturn {\n\t\t\t\tmodel: resolved.model,\n\t\t\t\tthinkingLevel: resolveInitialThinkingLevel(resolved.model, resolved.thinkingLevel ?? defaultThinkingLevel),\n\t\t\t\tfallbackMessage: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: resolveInitialThinkingLevel(\n\t\t\t\tscopedModels[0].model,\n\t\t\t\tscopedModels[0].thinkingLevel ?? defaultThinkingLevel,\n\t\t\t),\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\treturn {\n\t\t\t\tmodel,\n\t\t\t\tthinkingLevel: resolveInitialThinkingLevel(model, defaultThinkingLevel),\n\t\t\t\tfallbackMessage: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn {\n\t\t\t\t\tmodel: match,\n\t\t\t\t\tthinkingLevel: resolveInitialThinkingLevel(match, defaultThinkingLevel),\n\t\t\t\t\tfallbackMessage: undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\treturn {\n\t\t\tmodel: availableModels[0],\n\t\t\tthinkingLevel: resolveInitialThinkingLevel(availableModels[0], defaultThinkingLevel),\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 5. No model found\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\n\t\tfallbackMessage: undefined,\n\t};\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | undefined,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and still has auth configured\n\tconst hasConfiguredAuth = restoredModel ? modelRegistry.hasConfiguredAuth(restoredModel) : false;\n\n\tif (restoredModel && hasConfiguredAuth) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no auth configured\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | undefined;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: undefined, fallbackMessage: undefined };\n}\n\nexport interface ResolvedProfileModelSettings {\n\tmodel?: Model<any>;\n\tthinkingLevel?: ThinkingLevel;\n\twarning?: string;\n\terror?: string;\n}\n\nexport function resolveProfileModelSettings(options: {\n\tactiveProfileNames: string[];\n\tregistry: ProfileRegistry;\n\tmodelRegistry: ModelRegistry;\n\tcwd: string;\n}): ResolvedProfileModelSettings {\n\tconst { activeProfileNames, registry, modelRegistry, cwd } = options;\n\tlet modelString: string | undefined;\n\tlet thinking: ThinkingLevel | undefined;\n\n\tfor (const profileName of activeProfileNames) {\n\t\tconst profile =\n\t\t\tprofileName.startsWith(\"./\") || profileName.startsWith(\"../\")\n\t\t\t\t? registry.resolveProfileRef(profileName, cwd)\n\t\t\t\t: registry.getProfile(profileName);\n\t\tif (profile) {\n\t\t\tif (!modelString && profile.model) {\n\t\t\t\tmodelString = profile.model;\n\t\t\t}\n\t\t\tif (!thinking && profile.thinking) {\n\t\t\t\tthinking = profile.thinking;\n\t\t\t}\n\t\t\tif (modelString && thinking) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!modelString && !thinking) {\n\t\treturn {};\n\t}\n\n\tconst result: ResolvedProfileModelSettings = {};\n\tif (modelString) {\n\t\tconst resolved = resolveCliModel({ cliModel: modelString, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tresult.error = resolved.error;\n\t\t}\n\t\tif (resolved.warning) {\n\t\t\tresult.warning = resolved.warning;\n\t\t}\n\t\tif (resolved.model) {\n\t\t\tresult.model = resolved.model;\n\t\t}\n\t\tif (resolved.thinkingLevel && !thinking) {\n\t\t\tthinking = resolved.thinkingLevel;\n\t\t}\n\t}\n\n\tif (thinking) {\n\t\tresult.thinkingLevel = thinking;\n\t}\n\n\treturn result;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-router-controller.d.ts","sourceRoot":"","sources":["../../src/core/model-router-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model-router turn routing: the session's per-turn model-selection subsystem — the regex/executor\n * route resolver, the optional bounded routing judge, the executor lane (Level-0 toolkit direct hit\n * + speculative brain-refined retry), the per-tier thinking/tool-surface swap around a routed turn,\n * the cheap-research-turn session buffer with mutating-tool escalation to an expensive retry, and\n * the router status/diagnostics report.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the transient per-turn\n * route state — the active intent/route, the cheap-turn session buffer, the escalation-requested and\n * retry-in-flight flags — and the sticky last-decision/last-skip-reason/last-intent used by the\n * status report. Everything else it needs — the live agent + its state, the current model, the\n * session/settings managers, the model registry, the agent dir, the reflection abort signal, the\n * base system prompt, the isolated-completion primitive, spawned-usage accounting, the event/telemetry\n * emitters, and the recently-extracted BackgroundLaneController (resolveLaneModel) / ContextPipeline\n * (resolveCurationModelIfFit) collaborators — is reached through narrow deps accessors rather than the\n * whole AgentSession.\n *\n * Drive-path boundary (deliberate): the actual agent.prompt()/continue() loop stays host-side in\n * AgentSession._runAgentPrompt; this controller's parallel routed drive path ({@link runRoutedTurn})\n * owns only the route decision/escalation/tier bookkeeping and delegates every agent turn back through\n * {@link ModelRouterControllerDeps.runAgentPrompt}, so the drive-loop logic is never duplicated. The\n * host keeps a one-line delegation at each call-in: the routing prep + routed-turn entry in\n * _promptUnserialized, the beforeToolCall escalation branch ({@link maybeEscalateToolCall}), the\n * message_end cheap-turn buffering ({@link captureSessionMessage}), the retry-event suppression\n * ({@link isRetryInFlight}), and the public getModelRouterStatus / autonomy-telemetry reads.\n */\n\nimport type { Agent, AgentMessage, ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Api, Message, Model, Usage } from \"@caupulican/pi-ai\";\nimport { clampThinkingLevel, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport type { AgentSessionEvent, IsolatedCompletionOptions, IsolatedCompletionResult } from \"./agent-session.ts\";\nimport type { RouteDecision } from \"./autonomy/contracts.ts\";\nimport { AUTONOMY_TELEMETRY_EVENT_TYPES, type AutonomyTelemetryEvent } from \"./autonomy/telemetry-events.ts\";\nimport { latestUserPromptText } from \"./context-pipeline.ts\";\nimport { deriveModelCapabilityProfile, filterToolNamesForCapability } from \"./model-capability.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { resolveCliModel } from \"./model-resolver.ts\";\nimport { collectModelRouterConfigDiagnostics } from \"./model-router/config-diagnostics.ts\";\nimport { classifyExecutorTurn } from \"./model-router/executor-route.ts\";\nimport {\n\tevaluateSurfaceFitness,\n\ttype FitnessGatedSurface,\n\ttype FitnessGateVerdict,\n} from \"./model-router/fitness-gate.ts\";\nimport { classifyModelRouterRoute, type ModelRouterIntent } from \"./model-router/intent-classifier.ts\";\nimport { ROUTE_JUDGE_MAX_OUTPUT_TOKENS, runRouteJudge } from \"./model-router/route-judge.ts\";\nimport {\n\tbufferModelRouterSessionCustomMessage,\n\tbufferModelRouterSessionMessage,\n\tcreateModelRouterSessionBuffer,\n\tflushModelRouterSessionBuffer,\n\ttype ModelRouterSessionBuffer,\n} from \"./model-router/session-buffer.ts\";\nimport {\n\tformatModelRouterStatus,\n\tgetRecentModelRouterDecisions,\n\tMODEL_ROUTER_DECISION_CUSTOM_TYPE,\n\ttype ModelRouterDecisionStatus,\n\ttype ModelRouterFailoverStatus,\n\ttype ModelRouterFitnessStatuses,\n} from \"./model-router/status.ts\";\nimport { shouldEscalateModelRouterTool } from \"./model-router/tool-escalation.ts\";\nimport { FitnessStore } from \"./models/fitness-store.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport {\n\tbuildReflexUserPrompt,\n\tparseReflexPlan,\n\tREFLEX_INTERPRETER_SYSTEM_PROMPT,\n} from \"./toolkit/reflex-interpreter.ts\";\n\n/** Canonical `provider/id` label for a routed/resolved model, as it appears in decisions and status. */\nexport function formatModelRouterModel(model: Model<Api>): string {\n\treturn `${model.provider}/${model.id}`;\n}\n\nconst ROUTE_JUDGE_STATIC_FAST_PATH_REASON_CODES = new Set([\n\t\"empty_prompt\",\n\t\"read_only_question\",\n\t\"release_or_publish\",\n\t\"security_or_auth\",\n\t\"destructive_or_git_history\",\n\t\"settings_or_self_modification\",\n\t\"architecture_or_ambiguous\",\n]);\n\nfunction shouldSkipRouteJudgeForStaticDecision(decision: RouteDecision): boolean {\n\treturn ROUTE_JUDGE_STATIC_FAST_PATH_REASON_CODES.has(decision.reasonCode);\n}\n\nfunction withJudgeUnavailableFallback(decision: RouteDecision, reason: string): RouteDecision {\n\treturn {\n\t\t...decision,\n\t\treasonCode: \"judge_unavailable_fallback\",\n\t\treasons: [...decision.reasons, reason],\n\t};\n}\n\nfunction persistModelRouterDecision(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tdecision: ModelRouterDecisionStatus,\n): void {\n\tsessionManager.appendCustomEntry(MODEL_ROUTER_DECISION_CUSTOM_TYPE, decision);\n}\n\nexport interface ModelRouterControllerDeps {\n\t/** Live agent — the controller reads/writes agent.state.{model,thinkingLevel,tools,systemPrompt,messages}\n\t * for the per-turn tier swap and aborts it on a mutating-tool escalation. */\n\tgetAgent(): Agent;\n\t/** Current session model, used to decide whether a routed turn actually swaps the model. */\n\tgetModel(): Model<Api> | undefined;\n\t/** Router/executor/judge/thinking settings + capability mode (all opt-in gates). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Session log: routed-turn message buffering/persistence, decision persistence, recent-decision status. */\n\tgetSessionManager(): SessionManager;\n\t/** Resolves configured route/judge/executor model patterns against configured auth. */\n\tgetModelRegistry(): ModelRegistry;\n\t/** Session-scoped provider/model quota exhaustion guard. */\n\tisModelExhausted(model: Model<Api>): boolean;\n\t/** Status snapshot for B5 exhausted models and the last failover notice. */\n\tgetFailoverStatus(): ModelRouterFailoverStatus;\n\t/** Root dir the host-keyed {@link FitnessStore} lives under (executor tool-call fitness gate). */\n\tgetAgentDir(): string;\n\t/** Aborts the judge's bounded completion when the session is disposed. */\n\tgetReflectionSignal(): AbortSignal;\n\t/** Base (extension-free) system prompt — the tier swap only sheds tools when the turn is on it. */\n\tgetBaseSystemPrompt(): string;\n\t/** The host-side drive loop (agent.prompt()/continue()); the routed drive path delegates every turn here. */\n\trunAgentPrompt(messages: AgentMessage | AgentMessage[]): Promise<void>;\n\t/** Rebuilds the system prompt for a filtered tool surface (routed-model capability shedding). */\n\tbuildSystemPromptForToolNames(toolNames: string[]): string;\n\t/** Re-resolves the restored model against the registry after a routed turn (provider override safety). */\n\trefreshCurrentModelFromRegistry(): void;\n\t/** One-shot, tool-less LLM call — the routing judge and the executor reflex-brain warmup ride this. */\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n\t/** Rolls judge/brain spend into spawned-usage accounting. */\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts?: { label?: string; sourceSessionId?: string; reportId?: string },\n\t): string | undefined;\n\t/** Session event stream (executor-miss warning). */\n\temit(event: AgentSessionEvent): void;\n\t/** Autonomy telemetry stream (one route-decision event per user-facing routed turn). */\n\temitAutonomyTelemetry(event: AutonomyTelemetryEvent): void;\n\t/** Resolves the judge model pattern via {@link BackgroundLaneController}. */\n\tresolveLaneModel(pattern: string): Model<Api> | undefined;\n\t/** Fitness-gated reflex-brain model via {@link ContextPipeline} (executor speculative refinement). */\n\tresolveCurationModelIfFit(): Model<Api> | undefined;\n}\n\n/**\n * Owns the model-router turn routing extracted from {@link AgentSession}. See the module header for the\n * drive-path boundary that keeps the agent.prompt()/continue() loop host-side.\n */\nexport class ModelRouterController {\n\t/** Active model-router intent for the current transient routed turn, if any. */\n\tprivate _activeModelRouterIntent?: ModelRouterIntent;\n\tprivate _activeModelRouterRoute?: RouteDecision;\n\tprivate _modelRouterSessionBuffer?: ModelRouterSessionBuffer;\n\tprivate _modelRouterEscalationRequested = false;\n\tprivate _isModelRouterRetry = false;\n\tprivate _lastModelRouterDecision?: ModelRouterDecisionStatus;\n\tprivate _lastModelRouterSkipReason?: string;\n\tprivate _lastModelRouterIntent?: ModelRouterIntent;\n\n\tprivate readonly deps: ModelRouterControllerDeps;\n\n\tconstructor(deps: ModelRouterControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** True while the escalation retry turn is running, so the host can suppress its duplicate prompt events. */\n\tisRetryInFlight(): boolean {\n\t\treturn this._isModelRouterRetry;\n\t}\n\n\t/** Latest completed route decision (sticky), for the autonomy telemetry snapshot. */\n\tgetLastDecision(): ModelRouterDecisionStatus | undefined {\n\t\treturn this._lastModelRouterDecision;\n\t}\n\n\t/**\n\t * beforeToolCall escalation gate: a cheap research turn that reaches for a mutating tool aborts the\n\t * turn and requests a retry on the expensive model. Returns the block result the host hook forwards,\n\t * or undefined when no escalation is required.\n\t */\n\tmaybeEscalateToolCall(toolName: string, args: unknown): { block: true; reason: string } | undefined {\n\t\tif (\n\t\t\tthis._activeModelRouterRoute &&\n\t\t\tshouldEscalateModelRouterTool({\n\t\t\t\ttier: this._activeModelRouterRoute.tier,\n\t\t\t\ttoolName,\n\t\t\t\targs,\n\t\t\t\treasonCode: this._activeModelRouterRoute.reasonCode,\n\t\t\t})\n\t\t) {\n\t\t\tthis._modelRouterEscalationRequested = true;\n\t\t\tthis.deps.getAgent().abort();\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason:\n\t\t\t\t\t\"Model router escalation required: a cheap research turn attempted a mutating tool. Retry the turn on the configured expensive model.\",\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * message_end hook: while a cheap routed turn is buffering, capture its messages into the session\n\t * buffer instead of persisting them (they are flushed on success or discarded on escalation).\n\t * Returns true when the message was buffered, so the host skips its own persistence.\n\t */\n\tcaptureSessionMessage(message: AgentMessage): boolean {\n\t\tconst modelRouterBuffer = this._modelRouterSessionBuffer;\n\t\tif (!modelRouterBuffer) return false;\n\t\tif (message.role === \"custom\") {\n\t\t\tbufferModelRouterSessionCustomMessage(modelRouterBuffer, message);\n\t\t\treturn true;\n\t\t}\n\t\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\") {\n\t\t\tbufferModelRouterSessionMessage(modelRouterBuffer, message as Message);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _isModelAvailableAndAuthed(pattern: string): boolean {\n\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return false;\n\t\treturn this.deps.getModelRegistry().hasConfiguredAuth(resolved.model);\n\t}\n\n\tprivate _evaluateModelFitness(surface: FitnessGatedSurface, model: Model<Api>): FitnessGateVerdict {\n\t\tconst fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t.getForHost()\n\t\t\t.find((entry) => entry.model === formatModelRouterModel(model));\n\t\treturn evaluateSurfaceFitness(surface, fitness?.report);\n\t}\n\n\tprivate _formatFitnessFailure(verdict: Exclude<FitnessGateVerdict, { fit: true }>): string {\n\t\treturn verdict.reason === \"unprobed\" ? \"unprobed\" : `${verdict.lane} ${verdict.succeeded}/${verdict.total}`;\n\t}\n\n\tprivate _routerSurfaceForTier(tier: \"cheap\" | \"medium\" | \"expensive\"): FitnessGatedSurface {\n\t\treturn tier === \"cheap\" ? \"router_cheap\" : tier === \"medium\" ? \"router_medium\" : \"router_expensive\";\n\t}\n\n\tprivate _getRouterTierFitnessStatuses(): ModelRouterFitnessStatuses {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst statuses: ModelRouterFitnessStatuses = {};\n\t\tfor (const tier of [\"cheap\", \"medium\", \"expensive\"] as const) {\n\t\t\tconst pattern =\n\t\t\t\ttier === \"cheap\" ? settings.cheapModel : tier === \"medium\" ? settings.mediumModel : settings.expensiveModel;\n\t\t\tif (!pattern) continue;\n\t\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\t\tif (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) continue;\n\t\t\tconst verdict = this._evaluateModelFitness(this._routerSurfaceForTier(tier), resolved.model);\n\t\t\tstatuses[tier] = verdict.fit\n\t\t\t\t? { status: verdict.probed ? \"fit\" : \"unprobed\" }\n\t\t\t\t: verdict.reason === \"unprobed\"\n\t\t\t\t\t? { status: \"unprobed\" }\n\t\t\t\t\t: { status: \"unfit\", lane: verdict.lane, succeeded: verdict.succeeded, total: verdict.total };\n\t\t}\n\t\treturn statuses;\n\t}\n\n\tprivate _resolveExpensiveFallbackRoute(\n\t\tdecision: RouteDecision,\n\t\treasonCode: string,\n\t\treason: string,\n\t): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst expensivePattern = settings.expensiveModel;\n\t\tif (!expensivePattern || !this._isModelAvailableAndAuthed(expensivePattern)) return undefined;\n\t\tconst resolvedExpensive = resolveCliModel({\n\t\t\tcliModel: expensivePattern,\n\t\t\tmodelRegistry: this.deps.getModelRegistry(),\n\t\t});\n\t\tif (!resolvedExpensive.model) return undefined;\n\t\tif (this.deps.isModelExhausted(resolvedExpensive.model)) {\n\t\t\tthis._lastModelRouterSkipReason = \"expensive model exhausted: quota\";\n\t\t\treturn undefined;\n\t\t}\n\t\tif (settings.fitnessGate) {\n\t\t\tconst verdict = this._evaluateModelFitness(\"router_expensive\", resolvedExpensive.model);\n\t\t\tif (!verdict.fit) {\n\t\t\t\tthis._lastModelRouterSkipReason = `expensive model unfit: ${this._formatFitnessFailure(verdict)} (fitness gate)`;\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t\tdecision.fallbackFrom = \"medium\";\n\t\tdecision.tier = \"expensive\";\n\t\tdecision.reasonCode = reasonCode;\n\t\tdecision.reasons = [...decision.reasons, reason];\n\t\tdecision.model = formatModelRouterModel(resolvedExpensive.model);\n\t\tthis._lastModelRouterSkipReason = undefined;\n\t\treturn { decision, model: resolvedExpensive.model };\n\t}\n\n\tprivate _resolveExecutorRoute(\n\t\tprompt: string,\n\t\texecutorPattern: string | undefined,\n\t): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tif (!executorPattern) return undefined;\n\t\ttry {\n\t\t\tconst verdict = classifyExecutorTurn(prompt, this.deps.getSettingsManager().getToolkitScripts());\n\t\t\tif (!verdict.execute) return undefined;\n\t\t\tconst resolved = resolveCliModel({ cliModel: executorPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\t\tif (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\t\t// Fitness gate: the executor must have PROVEN tool-calling on this host (same\n\t\t\t// canonical-ref discipline as the curation gate).\n\t\t\tif (!this._evaluateModelFitness(\"executor\", resolved.model).fit) return undefined;\n\t\t\tthis._lastModelRouterIntent = \"research\";\n\t\t\treturn {\n\t\t\t\tdecision: {\n\t\t\t\t\ttier: \"cheap\",\n\t\t\t\t\trisk: \"scoped-write\",\n\t\t\t\t\tconfidence: 1,\n\t\t\t\t\treasonCode: \"executor_direct\",\n\t\t\t\t\treasons: [`Executor lane: Level-0 direct hit on toolkit script \"${verdict.scriptName}\"`],\n\t\t\t\t},\n\t\t\t\tmodel: resolved.model,\n\t\t\t};\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/** True if a run_toolkit_script tool result since `fromIndex` actually EXECUTED (not error/ambiguous). */\n\tprivate _executorTurnExecutedScript(fromIndex: number): boolean {\n\t\tfor (const message of this.deps.getAgent().state.messages.slice(fromIndex)) {\n\t\t\tif ((message as { role?: string }).role !== \"toolResult\") continue;\n\t\t\tif ((message as { toolName?: string }).toolName !== \"run_toolkit_script\") continue;\n\t\t\tif ((message as { isError?: boolean }).isError === true) continue;\n\t\t\tconst outcome = (message as { details?: { outcome?: unknown } }).details?.outcome;\n\t\t\tif (outcome === \"executed\") return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** Ask the reflex brain to refine the last user request into an explicit toolkit instruction. */\n\tprivate async _buildExecutorRefinedPrompt(messages: AgentMessage | AgentMessage[]): Promise<string | undefined> {\n\t\ttry {\n\t\t\tconst model = this.deps.resolveCurationModelIfFit();\n\t\t\tif (!model) return undefined;\n\t\t\tconst list = Array.isArray(messages) ? messages : [messages];\n\t\t\tconst request = latestUserPromptText(list.filter((m): m is AgentMessage => true));\n\t\t\tif (!request) return undefined;\n\t\t\tconst scripts = this.deps.getSettingsManager().getToolkitScripts();\n\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\tsystemPrompt: REFLEX_INTERPRETER_SYSTEM_PROMPT,\n\t\t\t\tmessages: [\n\t\t\t\t\t{\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: buildReflexUserPrompt(request, scripts) }],\n\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tmodel,\n\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\tmaxTokens: 256,\n\t\t\t\tcacheRetention: \"short\",\n\t\t\t});\n\t\t\tif (completion.usage.cost.total > 0 || completion.usage.totalTokens > 0) {\n\t\t\t\tthis.deps.addSpawnedUsage(completion.usage, { label: \"executor-brain-warmup\" });\n\t\t\t}\n\t\t\tconst plan = parseReflexPlan(completion.text);\n\t\t\tif (!plan || plan.script === \"none\") return undefined;\n\t\t\tconst argHint = plan.args.length > 0 ? ` with args ${JSON.stringify(plan.args)}` : \"\";\n\t\t\treturn `Run the toolkit script \"${plan.script}\"${argHint} using run_toolkit_script, then report its result exactly.`;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate _resolveModelRouterTurnRoute(prompt: string): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._lastModelRouterSkipReason = \"disabled\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// G16 executor lane: a Level-0 DIRECT toolkit hit on a command-shaped prompt routes the\n\t\t// whole turn to the configured local executor (tool-call-fitness-gated) instead of\n\t\t// spending the frontier model on a one-tool reflex. Ambiguity never routes here — it\n\t\t// stays with the big model and the reflex brain. Deterministic, so the judge is skipped.\n\t\tconst executorRoute = this._resolveExecutorRoute(prompt, settings.executorModel);\n\t\tif (executorRoute) return executorRoute;\n\n\t\tconst decision = classifyModelRouterRoute(prompt);\n\t\tthis._lastModelRouterIntent = decision.tier === \"cheap\" ? \"research\" : \"modify\";\n\n\t\t// Learning tier must not be selected for normal user prompts\n\t\tif (decision.tier === \"learning\") {\n\t\t\tthis._lastModelRouterSkipReason = \"learning tier not supported for user prompts\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst modelPattern =\n\t\t\tsettings[\n\t\t\t\tdecision.tier === \"cheap\" ? \"cheapModel\" : decision.tier === \"medium\" ? \"mediumModel\" : \"expensiveModel\"\n\t\t\t];\n\t\tconst label =\n\t\t\tdecision.tier === \"cheap\" ? \"cheap model\" : decision.tier === \"medium\" ? \"medium model\" : \"expensive model\";\n\n\t\tif (decision.tier === \"medium\" && (!modelPattern || !this._isModelAvailableAndAuthed(modelPattern))) {\n\t\t\tconst fallback = this._resolveExpensiveFallbackRoute(\n\t\t\t\tdecision,\n\t\t\t\t\"medium_unavailable_fallback_expensive\",\n\t\t\t\t\"Medium model is unavailable, falling back to expensive model\",\n\t\t\t);\n\t\t\tif (fallback) return fallback;\n\t\t\tthis._lastModelRouterSkipReason ??= \"medium model and expensive fallback are unavailable\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!modelPattern) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} unset`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} unresolved: ${modelPattern}`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst resolvedName = formatModelRouterModel(resolved.model);\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} missing auth: ${resolvedName}`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (this.deps.isModelExhausted(resolved.model)) {\n\t\t\tif (decision.tier === \"medium\") {\n\t\t\t\tconst fallback = this._resolveExpensiveFallbackRoute(\n\t\t\t\t\tdecision,\n\t\t\t\t\t\"medium_exhausted_fallback_expensive\",\n\t\t\t\t\t\"Medium model exhausted: quota; falling back to expensive model\",\n\t\t\t\t);\n\t\t\t\tif (fallback) return fallback;\n\t\t\t}\n\t\t\tthis._lastModelRouterSkipReason = `${decision.tier} model exhausted: quota`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (settings.fitnessGate) {\n\t\t\tconst verdict = this._evaluateModelFitness(this._routerSurfaceForTier(decision.tier), resolved.model);\n\t\t\tif (!verdict.fit) {\n\t\t\t\tif (decision.tier === \"medium\") {\n\t\t\t\t\tconst failure = this._formatFitnessFailure(verdict);\n\t\t\t\t\tconst fallback = this._resolveExpensiveFallbackRoute(\n\t\t\t\t\t\tdecision,\n\t\t\t\t\t\t\"medium_unfit_fallback_expensive\",\n\t\t\t\t\t\t`Medium model is unfit (${failure}); falling back to expensive model`,\n\t\t\t\t\t);\n\t\t\t\t\tif (fallback) return fallback;\n\t\t\t\t}\n\t\t\t\tthis._lastModelRouterSkipReason = `${decision.tier} model unfit: ${this._formatFitnessFailure(verdict)} (fitness gate)`;\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\tthis._lastModelRouterSkipReason = undefined;\n\t\tdecision.model = resolvedName;\n\t\treturn { decision, model: resolved.model };\n\t}\n\n\tprivate _resolveModelRouterModelForIntent(intent: ModelRouterIntent): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst modelPattern = intent === \"research\" ? settings.cheapModel : settings.expensiveModel;\n\t\tif (!modelPattern) return undefined;\n\t\tconst resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return undefined;\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\treturn this.deps.isModelExhausted(resolved.model) ? undefined : resolved.model;\n\t}\n\n\tresolveConfiguredTierModel(tier: \"cheap\" | \"medium\" | \"expensive\"): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst pattern =\n\t\t\ttier === \"cheap\" ? settings.cheapModel : tier === \"medium\" ? settings.mediumModel : settings.expensiveModel;\n\t\tif (!pattern) return undefined;\n\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return undefined;\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\treturn this.deps.isModelExhausted(resolved.model) ? undefined : resolved.model;\n\t}\n\n\t/**\n\t * Router resolution with the routing judge (auto-on with the router): the regex classifier's\n\t * decision is the baseline; when a judge model resolves (judgeModel, else mediumModel), one\n\t * bounded, tool-less completion may move the tier between cheap/medium/expensive — never to\n\t * learning. Core rule encoded in the judge prompt: planning is never cheap unless genuinely\n\t * trivial. Every fallback stays visible in the decision reasons, and judge spend reports\n\t * through spawned-usage accounting.\n\t */\n\tasync resolveTurnRouteJudged(\n\t\tprompt: string,\n\t\toptions?: { skipJudge?: boolean },\n\t): Promise<{ decision: RouteDecision; model: Model<Api> } | undefined> {\n\t\tconst baseline = this._resolveModelRouterTurnRoute(prompt);\n\t\tif (!baseline) return undefined;\n\t\tif (options?.skipJudge) return baseline;\n\t\t// Deterministic executor routes need no judge (Level-0 already decided).\n\t\tif (baseline.decision.reasonCode === \"executor_direct\") return baseline;\n\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tif (!settings.judgeEnabled) return baseline;\n\t\tif (shouldSkipRouteJudgeForStaticDecision(baseline.decision)) return baseline;\n\t\tconst judgePattern = settings.judgeModel ?? settings.mediumModel;\n\t\tif (!judgePattern) return baseline;\n\t\tconst judgeModel = this.deps.resolveLaneModel(judgePattern);\n\t\tif (!judgeModel) {\n\t\t\treturn {\n\t\t\t\tdecision: withJudgeUnavailableFallback(\n\t\t\t\t\tbaseline.decision,\n\t\t\t\t\t`routing judge unavailable: ${judgePattern} did not resolve; baseline kept`,\n\t\t\t\t),\n\t\t\t\tmodel: baseline.model,\n\t\t\t};\n\t\t}\n\t\tif (settings.fitnessGate) {\n\t\t\tconst verdict = this._evaluateModelFitness(\"router_judge\", judgeModel);\n\t\t\tif (!verdict.fit) {\n\t\t\t\treturn {\n\t\t\t\t\tdecision: {\n\t\t\t\t\t\t...baseline.decision,\n\t\t\t\t\t\treasons: [\n\t\t\t\t\t\t\t...baseline.decision.reasons,\n\t\t\t\t\t\t\t`routing judge skipped: ${formatModelRouterModel(judgeModel)} unfit (${this._formatFitnessFailure(verdict)})`,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tmodel: baseline.model,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tlet spentUsage: Usage | undefined;\n\t\tconst judged = await runRouteJudge({\n\t\t\tprompt,\n\t\t\tbaseline: baseline.decision,\n\t\t\tsignal: this.deps.getReflectionSignal(),\n\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\tsystemPrompt,\n\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\tmodel: judgeModel,\n\t\t\t\t\t// Per-tier thinking (R1): judgeThinking overrides the judge's own completion; unset\n\t\t\t\t\t// keeps today's \"off\" (the judge is a cheap classification call by default).\n\t\t\t\t\tthinkingLevel: settings.judgeThinking ?? \"off\",\n\t\t\t\t\tmaxTokens: ROUTE_JUDGE_MAX_OUTPUT_TOKENS,\n\t\t\t\t\tsignal,\n\t\t\t\t\t// The judge system prompt is static — the provider can cache the prefix.\n\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t});\n\t\t\t\tspentUsage = completion.usage;\n\t\t\t\treturn {\n\t\t\t\t\ttext: completion.text,\n\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t\tif (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {\n\t\t\tthis.deps.addSpawnedUsage(spentUsage, { label: \"router-judge\" });\n\t\t}\n\n\t\tif (!judged.verdict || judged.decision.tier === baseline.decision.tier) {\n\t\t\t// Same tier (or judge fell back): keep the baseline model, carry the annotated decision.\n\t\t\treturn { decision: judged.decision, model: baseline.model };\n\t\t}\n\n\t\tconst judgedTier = judged.decision.tier;\n\t\tif (judgedTier !== \"cheap\" && judgedTier !== \"medium\" && judgedTier !== \"expensive\") {\n\t\t\treturn { decision: baseline.decision, model: baseline.model };\n\t\t}\n\t\tconst judgedModel = this.resolveConfiguredTierModel(judgedTier);\n\t\tif (!judgedModel) {\n\t\t\treturn {\n\t\t\t\tdecision: {\n\t\t\t\t\t...baseline.decision,\n\t\t\t\t\treasons: [\n\t\t\t\t\t\t...baseline.decision.reasons,\n\t\t\t\t\t\t`Route judge chose ${judgedTier} but no model resolves for that tier; baseline kept`,\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tmodel: baseline.model,\n\t\t\t};\n\t\t}\n\t\treturn { decision: { ...judged.decision, model: formatModelRouterModel(judgedModel) }, model: judgedModel };\n\t}\n\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: test seam\n\tprivate _resolveModelRouterTurnModel(prompt: string): Model<Api> | undefined {\n\t\tconst resolved = this._resolveModelRouterTurnRoute(prompt);\n\t\treturn resolved?.model;\n\t}\n\n\tgetStatus(formatLabel?: (label: string) => string): string {\n\t\tconst recentDecisions = getRecentModelRouterDecisions(this.deps.getSessionManager().getEntries());\n\t\tconst lastDecision = this._lastModelRouterDecision ?? recentDecisions.at(-1);\n\t\tconst historicalDecisions = this._lastModelRouterDecision ? recentDecisions : recentDecisions.slice(0, -1);\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst lines = [\n\t\t\tformatModelRouterStatus(\n\t\t\t\tsettings,\n\t\t\t\tlastDecision,\n\t\t\t\tformatLabel,\n\t\t\t\thistoricalDecisions,\n\t\t\t\tthis._lastModelRouterSkipReason,\n\t\t\t\tthis._lastModelRouterIntent ?? lastDecision?.intent,\n\t\t\t\tsettings.fitnessGate ? this._getRouterTierFitnessStatuses() : undefined,\n\t\t\t\tthis.deps.getFailoverStatus(),\n\t\t\t),\n\t\t];\n\t\tconst diagnostics = collectModelRouterConfigDiagnostics(\n\t\t\tsettings,\n\t\t\tthis.deps.getModelRegistry(),\n\t\t\tthis.deps.getAgentDir(),\n\t\t);\n\t\tif (diagnostics.length > 0) {\n\t\t\tlines.push(formatLabel ? formatLabel(\"Config diagnostics:\") : \"Config diagnostics:\");\n\t\t\tfor (const diagnostic of diagnostics) {\n\t\t\t\tlines.push(`- ${diagnostic}`);\n\t\t\t}\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tasync runRoutedTurn(\n\t\tmessages: AgentMessage | AgentMessage[],\n\t\troutedModel: Model<Api> | undefined,\n\t\trouteDecision: RouteDecision | undefined,\n\t\tpersistDecision = true,\n\t): Promise<void> {\n\t\tif (!routedModel) {\n\t\t\tawait this.deps.runAgentPrompt(messages);\n\t\t\treturn;\n\t\t}\n\n\t\tconst agent = this.deps.getAgent();\n\t\tconst previousModel = agent.state.model;\n\t\tconst previousThinkingLevel = agent.state.thinkingLevel;\n\t\tconst previousTurnTools = agent.state.tools;\n\t\tconst previousSystemPrompt = agent.state.systemPrompt;\n\t\t// G4 swap bookkeeping (Bug G): the exact references the swap below assigns, so the finally can\n\t\t// restore ONLY what IT put there — never assigned when no swap happens (e.g. a full-class\n\t\t// routed profile).\n\t\tlet swappedTools: typeof previousTurnTools | undefined;\n\t\tlet swappedSystemPrompt: typeof previousSystemPrompt | undefined;\n\t\tconst previousActiveModelRouterIntent = this._activeModelRouterIntent;\n\t\tconst previousActiveModelRouterRoute = this._activeModelRouterRoute;\n\t\tconst previousModelRouterSessionBuffer = this._modelRouterSessionBuffer;\n\t\tconst previousModelRouterEscalationRequested = this._modelRouterEscalationRequested;\n\t\tconst bufferRoutedTurn = routeDecision?.tier === \"cheap\";\n\t\tconst originalHistoryLength = agent.state.messages.length;\n\t\tlet retryModel: Model<Api> | undefined;\n\t\tlet completedDecision: ModelRouterDecisionStatus | undefined = routeDecision\n\t\t\t? {\n\t\t\t\t\troute: routeDecision,\n\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\toutcome: \"routed\",\n\t\t\t\t\tintent: routeDecision.tier === \"cheap\" ? \"research\" : \"modify\",\n\t\t\t\t}\n\t\t\t: undefined;\n\t\tlet thrownError: unknown;\n\t\tif (routeDecision) {\n\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t}\n\t\tthis._activeModelRouterIntent = routeDecision\n\t\t\t? routeDecision.tier === \"cheap\"\n\t\t\t\t? \"research\"\n\t\t\t\t: \"modify\"\n\t\t\t: undefined;\n\t\tthis._activeModelRouterRoute = routeDecision;\n\t\tif (bufferRoutedTurn) {\n\t\t\tthis._modelRouterSessionBuffer = createModelRouterSessionBuffer();\n\t\t\tthis._modelRouterEscalationRequested = false;\n\t\t}\n\t\tif (!modelsAreEqual(this.deps.getModel(), routedModel)) {\n\t\t\tagent.state.model = routedModel;\n\t\t\t// Per-tier thinking (R1): a configured tier/executor thinking level overrides the inherited\n\t\t\t// session thinking for THIS routed turn only; unset falls back to exactly today's\n\t\t\t// inherit-and-clamp behavior. Executor routes carry tier \"cheap\" too, so reasonCode is\n\t\t\t// checked first — otherwise an executor turn would silently pick up cheapThinking instead.\n\t\t\t// The judge's own completion has a separate knob (judgeThinking) applied at its call site.\n\t\t\tconst routerThinkingSettings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\t\tconst configuredThinking = !routeDecision\n\t\t\t\t? undefined\n\t\t\t\t: routeDecision.reasonCode === \"executor_direct\"\n\t\t\t\t\t? routerThinkingSettings.executorThinking\n\t\t\t\t\t: routeDecision.tier === \"cheap\"\n\t\t\t\t\t\t? routerThinkingSettings.cheapThinking\n\t\t\t\t\t\t: routeDecision.tier === \"medium\"\n\t\t\t\t\t\t\t? routerThinkingSettings.mediumThinking\n\t\t\t\t\t\t\t: routeDecision.tier === \"expensive\"\n\t\t\t\t\t\t\t\t? routerThinkingSettings.expensiveThinking\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\tagent.state.thinkingLevel = clampThinkingLevel(\n\t\t\t\troutedModel,\n\t\t\t\tconfiguredThinking ?? previousThinkingLevel,\n\t\t\t) as ThinkingLevel;\n\t\t\t// G4: capability tool-filtering follows the ROUTED model for the turn. Without this a\n\t\t\t// cheap/local routed model inherits the session model's full tool surface — schemas it\n\t\t\t// pays for on every request and may not be able to drive at all.\n\t\t\tconst routedProfile = deriveModelCapabilityProfile({\n\t\t\t\tcontextWindow: routedModel.contextWindow,\n\t\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t\t});\n\t\t\tif (routedProfile.class !== \"full\") {\n\t\t\t\tconst allowed = new Set(\n\t\t\t\t\tfilterToolNamesForCapability(\n\t\t\t\t\t\tpreviousTurnTools.map((tool) => tool.name),\n\t\t\t\t\t\troutedProfile,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tswappedTools = previousTurnTools.filter((tool) => allowed.has(tool.name));\n\t\t\t\tagent.state.tools = swappedTools;\n\t\t\t\t// G4: the system prompt follows the ROUTED model's filtered surface too — otherwise the\n\t\t\t\t// cheap/local model is billed for (and told about) tool guidelines/snippets it can't call.\n\t\t\t\t// Per-turn only; restored in the finally. A live extension override of the prompt is left\n\t\t\t\t// alone (only shed when we're on the base prompt).\n\t\t\t\tif (agent.state.systemPrompt === this.deps.getBaseSystemPrompt()) {\n\t\t\t\t\tswappedSystemPrompt = this.deps.buildSystemPromptForToolNames(\n\t\t\t\t\t\tagent.state.tools.map((tool) => tool.name),\n\t\t\t\t\t);\n\t\t\t\t\tagent.state.systemPrompt = swappedSystemPrompt;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tawait this.deps.runAgentPrompt(messages);\n\t\t\t// Speculative muscle-retry (G16 refinement): an executor-routed turn is a bet that the\n\t\t\t// small model can run the toolkit command directly. If it ends WITHOUT a successful\n\t\t\t// run_toolkit_script execution, retry ONCE on the same executor with the brain's\n\t\t\t// refined instruction injected — the brain warms while the muscle tries, so the retry\n\t\t\t// pays only when the muscle actually missed.\n\t\t\tif (\n\t\t\t\trouteDecision?.reasonCode === \"executor_direct\" &&\n\t\t\t\t!this._isModelRouterRetry &&\n\t\t\t\t!this._executorTurnExecutedScript(originalHistoryLength)\n\t\t\t) {\n\t\t\t\tconst refined = await this._buildExecutorRefinedPrompt(messages);\n\t\t\t\tif (refined) {\n\t\t\t\t\tagent.state.messages.splice(originalHistoryLength);\n\t\t\t\t\tif (bufferRoutedTurn) this._modelRouterSessionBuffer = createModelRouterSessionBuffer();\n\t\t\t\t\tawait this.deps.runAgentPrompt([\n\t\t\t\t\t\t{ role: \"user\", content: [{ type: \"text\", text: refined }], timestamp: Date.now() },\n\t\t\t\t\t]);\n\t\t\t\t\tcompletedDecision = {\n\t\t\t\t\t\troute: {\n\t\t\t\t\t\t\t...routeDecision,\n\t\t\t\t\t\t\treasonCode: \"executor_speculative_retry\",\n\t\t\t\t\t\t\treasons: [\n\t\t\t\t\t\t\t\t...routeDecision.reasons,\n\t\t\t\t\t\t\t\t\"Executor missed on first try; retried with brain-refined instruction\",\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\t\toutcome: \"routed\",\n\t\t\t\t\t\tintent: \"research\",\n\t\t\t\t\t};\n\t\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t\t} else {\n\t\t\t\t\t// The muscle missed AND the reflex brain could not refine the request into a toolkit\n\t\t\t\t\t// instruction (no fit brain model, or no confident plan). There is deliberately NO\n\t\t\t\t\t// frontier fallback here, so surface the miss instead of letting it stand silently —\n\t\t\t\t\t// otherwise the routed turn just ends with an unrun command and no explanation.\n\t\t\t\t\tthis.deps.emit({\n\t\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Executor lane: the toolkit command did not run and the reflex brain could not refine it into an explicit instruction; leaving the turn as-is (no automatic escalation).\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bufferRoutedTurn && this._modelRouterEscalationRequested) {\n\t\t\t\tagent.state.messages.splice(originalHistoryLength);\n\t\t\t\tretryModel = this._resolveModelRouterModelForIntent(\"modify\") ?? previousModel;\n\t\t\t\tcompletedDecision = {\n\t\t\t\t\troute: routeDecision!,\n\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\toutcome: \"escalated\",\n\t\t\t\t\tretryModel: formatModelRouterModel(retryModel),\n\t\t\t\t\tintent: routeDecision!.tier === \"cheap\" ? \"research\" : \"modify\",\n\t\t\t\t};\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t} else if (bufferRoutedTurn && this._modelRouterSessionBuffer) {\n\t\t\t\tflushModelRouterSessionBuffer(\n\t\t\t\t\tthis._modelRouterSessionBuffer,\n\t\t\t\t\t(message) => {\n\t\t\t\t\t\tthis.deps.getSessionManager().appendMessage(message);\n\t\t\t\t\t},\n\t\t\t\t\t(customType, content, display, details) => {\n\t\t\t\t\t\tthis.deps.getSessionManager().appendCustomMessageEntry(customType, content, display, details);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrownError = error;\n\t\t\tif (completedDecision) {\n\t\t\t\tcompletedDecision = { ...completedDecision, outcome: \"failed\" };\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t}\n\t\t} finally {\n\t\t\t// Restore the pre-route model ONLY if the routed model is still in place: a command\n\t\t\t// handler may have legitimately changed the session model mid-turn (setModel or a\n\t\t\t// provider re-registration), and clobbering that would silently undo the change.\n\t\t\tif (modelsAreEqual(agent.state.model, routedModel)) {\n\t\t\t\tagent.state.model = previousModel;\n\t\t\t\tagent.state.thinkingLevel = previousThinkingLevel;\n\t\t\t\t// Symmetric restore (Bug G): undo tools/systemPrompt only if each is STILL the exact\n\t\t\t\t// reference/string the G4 swap above assigned (never assigned at all when the routed\n\t\t\t\t// profile was full-class — then there is nothing to restore either). An extension calling\n\t\t\t\t// setActiveToolsByName mid-turn reassigns both to its own values without touching the\n\t\t\t\t// model — the model guard above still passes, but that live change is legitimate and must\n\t\t\t\t// survive rather than being silently reverted to the stale pre-turn snapshot.\n\t\t\t\tif (swappedTools !== undefined && agent.state.tools === swappedTools) {\n\t\t\t\t\tagent.state.tools = previousTurnTools;\n\t\t\t\t}\n\t\t\t\tif (swappedSystemPrompt !== undefined && agent.state.systemPrompt === swappedSystemPrompt) {\n\t\t\t\t\tagent.state.systemPrompt = previousSystemPrompt;\n\t\t\t\t}\n\t\t\t\t// The registry may have changed mid-turn (command-time registerProvider): re-resolve\n\t\t\t\t// the restored model so a provider override is not dropped with the routed model.\n\t\t\t\tthis.deps.refreshCurrentModelFromRegistry();\n\t\t\t}\n\t\t\tthis._activeModelRouterIntent = previousActiveModelRouterIntent;\n\t\t\tthis._activeModelRouterRoute = previousActiveModelRouterRoute;\n\t\t\tthis._modelRouterSessionBuffer = previousModelRouterSessionBuffer;\n\t\t\tthis._modelRouterEscalationRequested = previousModelRouterEscalationRequested;\n\t\t}\n\n\t\tif (retryModel && !thrownError) {\n\t\t\tconst previousIsModelRouterRetry = this._isModelRouterRetry;\n\t\t\ttry {\n\t\t\t\tthis._isModelRouterRetry = true;\n\t\t\t\tconst retryDecision: RouteDecision = {\n\t\t\t\t\ttier: \"expensive\",\n\t\t\t\t\trisk: \"high-impact\",\n\t\t\t\t\tconfidence: 1.0,\n\t\t\t\t\treasonCode: \"cheap_mutating_tool_escalation\",\n\t\t\t\t\treasons: [\"Cheap research turn attempted a mutating tool and escalated\"],\n\t\t\t\t\tfallbackFrom: \"cheap\",\n\t\t\t\t\tmodel: formatModelRouterModel(retryModel),\n\t\t\t\t};\n\t\t\t\tawait this.runRoutedTurn(messages, retryModel, retryDecision, false);\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t} catch (error) {\n\t\t\t\tthrownError = error;\n\t\t\t\tif (completedDecision) {\n\t\t\t\t\tcompletedDecision = { ...completedDecision, outcome: \"failed\" };\n\t\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tthis._isModelRouterRetry = previousIsModelRouterRetry;\n\t\t\t}\n\t\t}\n\n\t\tif (persistDecision && completedDecision) {\n\t\t\tpersistModelRouterDecision(this.deps.getSessionManager(), completedDecision);\n\t\t\t// G3: one route event per user-facing routed turn (the escalation retry runs with\n\t\t\t// persistDecision=false, so it does not double-emit). Codes/numbers only — no prompt text.\n\t\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.routeDecision,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tpayload: {\n\t\t\t\t\ttier: completedDecision.route.tier,\n\t\t\t\t\trisk: completedDecision.route.risk,\n\t\t\t\t\treasonCode: completedDecision.route.reasonCode,\n\t\t\t\t\tconfidence: completedDecision.route.confidence,\n\t\t\t\t\toutcome: completedDecision.outcome,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tif (thrownError) {\n\t\t\tthrow thrownError;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-router-controller.d.ts","sourceRoot":"","sources":["../../src/core/model-router-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model-router turn routing: the session's per-turn model-selection subsystem — the regex/executor\n * route resolver, the optional bounded routing judge, the executor lane (Level-0 toolkit direct hit\n * + speculative brain-refined retry), the per-tier thinking/tool-surface swap around a routed turn,\n * the cheap-research-turn session buffer with mutating-tool escalation to an expensive retry, and\n * the router status/diagnostics report.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the transient per-turn\n * route state — the active intent/route, the cheap-turn session buffer, the escalation-requested and\n * retry-in-flight flags — and the sticky last-decision/last-skip-reason/last-intent used by the\n * status report. Everything else it needs — the live agent + its state, the current model, the\n * session/settings managers, the model registry, the agent dir, the reflection abort signal, the\n * base system prompt, the isolated-completion primitive, spawned-usage accounting, the event/telemetry\n * emitters, and the recently-extracted BackgroundLaneController (resolveLaneModel) / ContextPipeline\n * (resolveCurationModelIfFit) collaborators — is reached through narrow deps accessors rather than the\n * whole AgentSession.\n *\n * Drive-path boundary (deliberate): the actual agent.prompt()/continue() loop stays host-side in\n * AgentSession._runAgentPrompt; this controller's parallel routed drive path ({@link runRoutedTurn})\n * owns only the route decision/escalation/tier bookkeeping and delegates every agent turn back through\n * {@link ModelRouterControllerDeps.runAgentPrompt}, so the drive-loop logic is never duplicated. The\n * host keeps a one-line delegation at each call-in: the routing prep + routed-turn entry in\n * _promptUnserialized, the beforeToolCall escalation branch ({@link maybeEscalateToolCall}), the\n * message_end cheap-turn buffering ({@link captureSessionMessage}), the retry-event suppression\n * ({@link isRetryInFlight}), and the public getModelRouterStatus / autonomy-telemetry reads.\n */\n\nimport type { Agent, AgentMessage, ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Api, Message, Model, Usage } from \"@caupulican/pi-ai\";\nimport { clampThinkingLevel, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport type { AgentSessionEvent, IsolatedCompletionOptions, IsolatedCompletionResult } from \"./agent-session.ts\";\nimport type { RouteDecision } from \"./autonomy/contracts.ts\";\nimport { AUTONOMY_TELEMETRY_EVENT_TYPES, type AutonomyTelemetryEvent } from \"./autonomy/telemetry-events.ts\";\nimport { latestUserPromptText } from \"./context-pipeline.ts\";\nimport { deriveModelCapabilityProfile, filterToolNamesForCapability } from \"./model-capability.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { resolveCliModel } from \"./model-resolver.ts\";\nimport { collectModelRouterConfigDiagnostics } from \"./model-router/config-diagnostics.ts\";\nimport { classifyExecutorTurn } from \"./model-router/executor-route.ts\";\nimport {\n\tevaluateSurfaceFitness,\n\ttype FitnessGatedSurface,\n\ttype FitnessGateVerdict,\n} from \"./model-router/fitness-gate.ts\";\nimport { classifyModelRouterRoute, type ModelRouterIntent } from \"./model-router/intent-classifier.ts\";\nimport { ROUTE_JUDGE_MAX_OUTPUT_TOKENS, runRouteJudge } from \"./model-router/route-judge.ts\";\nimport {\n\tbufferModelRouterSessionCustomMessage,\n\tbufferModelRouterSessionMessage,\n\tcreateModelRouterSessionBuffer,\n\tflushModelRouterSessionBuffer,\n\ttype ModelRouterSessionBuffer,\n} from \"./model-router/session-buffer.ts\";\nimport {\n\tformatModelRouterStatus,\n\tgetRecentModelRouterDecisions,\n\tMODEL_ROUTER_DECISION_CUSTOM_TYPE,\n\ttype ModelRouterDecisionStatus,\n\ttype ModelRouterFailoverStatus,\n\ttype ModelRouterFitnessStatuses,\n} from \"./model-router/status.ts\";\nimport { shouldEscalateModelRouterTool } from \"./model-router/tool-escalation.ts\";\nimport { FitnessStore } from \"./models/fitness-store.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport {\n\tbuildReflexUserPrompt,\n\tparseReflexPlan,\n\tREFLEX_INTERPRETER_SYSTEM_PROMPT,\n} from \"./toolkit/reflex-interpreter.ts\";\n\n/** Canonical `provider/id` label for a routed/resolved model, as it appears in decisions and status. */\nexport function formatModelRouterModel(model: Model<Api>): string {\n\treturn `${model.provider}/${model.id}`;\n}\n\nconst ROUTE_JUDGE_STATIC_FAST_PATH_REASON_CODES = new Set([\n\t\"empty_prompt\",\n\t\"read_only_question\",\n\t\"release_or_publish\",\n\t\"security_or_auth\",\n\t\"destructive_or_git_history\",\n\t\"settings_or_self_modification\",\n\t\"architecture_or_ambiguous\",\n]);\n\nfunction shouldSkipRouteJudgeForStaticDecision(decision: RouteDecision): boolean {\n\treturn ROUTE_JUDGE_STATIC_FAST_PATH_REASON_CODES.has(decision.reasonCode);\n}\n\nfunction withJudgeUnavailableFallback(decision: RouteDecision, reason: string): RouteDecision {\n\treturn {\n\t\t...decision,\n\t\treasonCode: \"judge_unavailable_fallback\",\n\t\treasons: [...decision.reasons, reason],\n\t};\n}\n\nfunction persistModelRouterDecision(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tdecision: ModelRouterDecisionStatus,\n): void {\n\tsessionManager.appendCustomEntry(MODEL_ROUTER_DECISION_CUSTOM_TYPE, decision);\n}\n\nexport interface ModelRouterControllerDeps {\n\t/** Live agent — the controller reads/writes agent.state.{model,thinkingLevel,tools,systemPrompt,messages}\n\t * for the per-turn tier swap and aborts it on a mutating-tool escalation. */\n\tgetAgent(): Agent;\n\t/** Current session model, used to decide whether a routed turn actually swaps the model. */\n\tgetModel(): Model<Api> | undefined;\n\t/** Router/executor/judge/thinking settings + capability mode (all opt-in gates). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Session log: routed-turn message buffering/persistence, decision persistence, recent-decision status. */\n\tgetSessionManager(): SessionManager;\n\t/** Resolves configured route/judge/executor model patterns against configured auth. */\n\tgetModelRegistry(): ModelRegistry;\n\t/** Session-scoped provider/model quota exhaustion guard. */\n\tisModelExhausted(model: Model<Api>): boolean;\n\t/** Status snapshot for B5 exhausted models and the last failover notice. */\n\tgetFailoverStatus(): ModelRouterFailoverStatus;\n\t/** Root dir the host-keyed {@link FitnessStore} lives under (executor tool-call fitness gate). */\n\tgetAgentDir(): string;\n\t/** Aborts the judge's bounded completion when the session is disposed. */\n\tgetReflectionSignal(): AbortSignal;\n\t/** Base (extension-free) system prompt — the tier swap only sheds tools when the turn is on it. */\n\tgetBaseSystemPrompt(): string;\n\t/** The host-side drive loop (agent.prompt()/continue()); the routed drive path delegates every turn here. */\n\trunAgentPrompt(messages: AgentMessage | AgentMessage[]): Promise<void>;\n\t/** Rebuilds the system prompt for a filtered tool surface (routed-model capability shedding). */\n\tbuildSystemPromptForToolNames(toolNames: string[]): string;\n\t/** Re-resolves the restored model against the registry after a routed turn (provider override safety). */\n\trefreshCurrentModelFromRegistry(): void;\n\t/** One-shot, tool-less LLM call — the routing judge and the executor reflex-brain warmup ride this. */\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n\t/** Rolls judge/brain spend into spawned-usage accounting. */\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts?: { label?: string; sourceSessionId?: string; reportId?: string },\n\t): string | undefined;\n\t/** Session event stream (executor-miss warning). */\n\temit(event: AgentSessionEvent): void;\n\t/** Autonomy telemetry stream (one route-decision event per user-facing routed turn). */\n\temitAutonomyTelemetry(event: AutonomyTelemetryEvent): void;\n\t/** Resolves the judge model pattern via {@link BackgroundLaneController}. */\n\tresolveLaneModel(pattern: string): Model<Api> | undefined;\n\t/** Fitness-gated reflex-brain model via {@link ContextPipeline} (executor speculative refinement). */\n\tresolveCurationModelIfFit(): Model<Api> | undefined;\n}\n\n/**\n * Owns the model-router turn routing extracted from {@link AgentSession}. See the module header for the\n * drive-path boundary that keeps the agent.prompt()/continue() loop host-side.\n */\nexport class ModelRouterController {\n\t/** Active model-router intent for the current transient routed turn, if any. */\n\tprivate _activeModelRouterIntent?: ModelRouterIntent;\n\tprivate _activeModelRouterRoute?: RouteDecision;\n\tprivate _modelRouterSessionBuffer?: ModelRouterSessionBuffer;\n\tprivate _modelRouterEscalationRequested = false;\n\tprivate _isModelRouterRetry = false;\n\tprivate _lastModelRouterDecision?: ModelRouterDecisionStatus;\n\tprivate _lastModelRouterSkipReason?: string;\n\tprivate _lastModelRouterIntent?: ModelRouterIntent;\n\n\tprivate readonly deps: ModelRouterControllerDeps;\n\n\tconstructor(deps: ModelRouterControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** True while the escalation retry turn is running, so the host can suppress its duplicate prompt events. */\n\tisRetryInFlight(): boolean {\n\t\treturn this._isModelRouterRetry;\n\t}\n\n\t/** Latest completed route decision (sticky), for the autonomy telemetry snapshot. */\n\tgetLastDecision(): ModelRouterDecisionStatus | undefined {\n\t\treturn this._lastModelRouterDecision;\n\t}\n\n\t/**\n\t * beforeToolCall escalation gate: a cheap research turn that reaches for a mutating tool aborts the\n\t * turn and requests a retry on the expensive model. Returns the block result the host hook forwards,\n\t * or undefined when no escalation is required.\n\t */\n\tmaybeEscalateToolCall(toolName: string, args: unknown): { block: true; reason: string } | undefined {\n\t\tif (\n\t\t\tthis._activeModelRouterRoute &&\n\t\t\tshouldEscalateModelRouterTool({\n\t\t\t\ttier: this._activeModelRouterRoute.tier,\n\t\t\t\ttoolName,\n\t\t\t\targs,\n\t\t\t\treasonCode: this._activeModelRouterRoute.reasonCode,\n\t\t\t})\n\t\t) {\n\t\t\tthis._modelRouterEscalationRequested = true;\n\t\t\tthis.deps.getAgent().abort();\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason:\n\t\t\t\t\t\"Model router escalation required: a cheap research turn attempted a mutating tool. Retry the turn on the configured expensive model.\",\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * message_end hook: while a cheap routed turn is buffering, capture its messages into the session\n\t * buffer instead of persisting them (they are flushed on success or discarded on escalation).\n\t * Returns true when the message was buffered, so the host skips its own persistence.\n\t */\n\tcaptureSessionMessage(message: AgentMessage): boolean {\n\t\tconst modelRouterBuffer = this._modelRouterSessionBuffer;\n\t\tif (!modelRouterBuffer) return false;\n\t\tif (message.role === \"custom\") {\n\t\t\tbufferModelRouterSessionCustomMessage(modelRouterBuffer, message);\n\t\t\treturn true;\n\t\t}\n\t\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\") {\n\t\t\tbufferModelRouterSessionMessage(modelRouterBuffer, message as Message);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _isModelAvailableAndAuthed(pattern: string): boolean {\n\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return false;\n\t\treturn this.deps.getModelRegistry().hasConfiguredAuth(resolved.model);\n\t}\n\n\tprivate _evaluateModelFitness(surface: FitnessGatedSurface, model: Model<Api>): FitnessGateVerdict {\n\t\tconst fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t.getForHost()\n\t\t\t.find((entry) => entry.model === formatModelRouterModel(model));\n\t\treturn evaluateSurfaceFitness(surface, fitness?.report);\n\t}\n\n\tprivate _formatFitnessFailure(verdict: Exclude<FitnessGateVerdict, { fit: true }>): string {\n\t\treturn verdict.reason === \"unprobed\" ? \"unprobed\" : `${verdict.lane} ${verdict.succeeded}/${verdict.total}`;\n\t}\n\n\tprivate _routerSurfaceForTier(tier: \"cheap\" | \"medium\" | \"expensive\"): FitnessGatedSurface {\n\t\treturn tier === \"cheap\" ? \"router_cheap\" : tier === \"medium\" ? \"router_medium\" : \"router_expensive\";\n\t}\n\n\tprivate _getRouterTierFitnessStatuses(): ModelRouterFitnessStatuses {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst statuses: ModelRouterFitnessStatuses = {};\n\t\tfor (const tier of [\"cheap\", \"medium\", \"expensive\"] as const) {\n\t\t\tconst pattern =\n\t\t\t\ttier === \"cheap\" ? settings.cheapModel : tier === \"medium\" ? settings.mediumModel : settings.expensiveModel;\n\t\t\tif (!pattern) continue;\n\t\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\t\tif (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) continue;\n\t\t\tconst verdict = this._evaluateModelFitness(this._routerSurfaceForTier(tier), resolved.model);\n\t\t\tstatuses[tier] = verdict.fit\n\t\t\t\t? { status: verdict.probed ? \"fit\" : \"unprobed\" }\n\t\t\t\t: verdict.reason === \"unprobed\"\n\t\t\t\t\t? { status: \"unprobed\" }\n\t\t\t\t\t: { status: \"unfit\", lane: verdict.lane, succeeded: verdict.succeeded, total: verdict.total };\n\t\t}\n\t\treturn statuses;\n\t}\n\n\tprivate _resolveExpensiveFallbackRoute(\n\t\tdecision: RouteDecision,\n\t\treasonCode: string,\n\t\treason: string,\n\t): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst expensivePattern = settings.expensiveModel;\n\t\tif (!expensivePattern || !this._isModelAvailableAndAuthed(expensivePattern)) return undefined;\n\t\tconst resolvedExpensive = resolveCliModel({\n\t\t\tcliModel: expensivePattern,\n\t\t\tmodelRegistry: this.deps.getModelRegistry(),\n\t\t});\n\t\tif (!resolvedExpensive.model) return undefined;\n\t\tif (this.deps.isModelExhausted(resolvedExpensive.model)) {\n\t\t\tthis._lastModelRouterSkipReason = \"expensive model exhausted: quota\";\n\t\t\treturn undefined;\n\t\t}\n\t\tif (settings.fitnessGate) {\n\t\t\tconst verdict = this._evaluateModelFitness(\"router_expensive\", resolvedExpensive.model);\n\t\t\tif (!verdict.fit) {\n\t\t\t\tthis._lastModelRouterSkipReason = `expensive model unfit: ${this._formatFitnessFailure(verdict)} (fitness gate)`;\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t\tdecision.fallbackFrom = \"medium\";\n\t\tdecision.tier = \"expensive\";\n\t\tdecision.reasonCode = reasonCode;\n\t\tdecision.reasons = [...decision.reasons, reason];\n\t\tdecision.model = formatModelRouterModel(resolvedExpensive.model);\n\t\tthis._lastModelRouterSkipReason = undefined;\n\t\treturn { decision, model: resolvedExpensive.model };\n\t}\n\n\tprivate _resolveExecutorRoute(\n\t\tprompt: string,\n\t\texecutorPattern: string | undefined,\n\t): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tif (!executorPattern) return undefined;\n\t\ttry {\n\t\t\tconst verdict = classifyExecutorTurn(prompt, this.deps.getSettingsManager().getToolkitScripts());\n\t\t\tif (!verdict.execute) return undefined;\n\t\t\tconst resolved = resolveCliModel({ cliModel: executorPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\t\tif (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\t\t// Fitness gate: the executor must have PROVEN tool-calling on this host (same\n\t\t\t// canonical-ref discipline as the curation gate).\n\t\t\tif (!this._evaluateModelFitness(\"executor\", resolved.model).fit) return undefined;\n\t\t\tthis._lastModelRouterIntent = \"research\";\n\t\t\treturn {\n\t\t\t\tdecision: {\n\t\t\t\t\ttier: \"cheap\",\n\t\t\t\t\trisk: \"scoped-write\",\n\t\t\t\t\tconfidence: 1,\n\t\t\t\t\treasonCode: \"executor_direct\",\n\t\t\t\t\treasons: [`Executor lane: Level-0 direct hit on toolkit script \"${verdict.scriptName}\"`],\n\t\t\t\t},\n\t\t\t\tmodel: resolved.model,\n\t\t\t};\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/** True if a run_toolkit_script tool result since `fromIndex` actually EXECUTED (not error/ambiguous). */\n\tprivate _executorTurnExecutedScript(fromIndex: number): boolean {\n\t\tfor (const message of this.deps.getAgent().state.messages.slice(fromIndex)) {\n\t\t\tif ((message as { role?: string }).role !== \"toolResult\") continue;\n\t\t\tif ((message as { toolName?: string }).toolName !== \"run_toolkit_script\") continue;\n\t\t\tif ((message as { isError?: boolean }).isError === true) continue;\n\t\t\tconst outcome = (message as { details?: { outcome?: unknown } }).details?.outcome;\n\t\t\tif (outcome === \"executed\") return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** Ask the reflex brain to refine the last user request into an explicit toolkit instruction. */\n\tprivate async _buildExecutorRefinedPrompt(messages: AgentMessage | AgentMessage[]): Promise<string | undefined> {\n\t\ttry {\n\t\t\tconst model = this.deps.resolveCurationModelIfFit();\n\t\t\tif (!model) return undefined;\n\t\t\tconst list = Array.isArray(messages) ? messages : [messages];\n\t\t\tconst request = latestUserPromptText(list.filter((m): m is AgentMessage => true));\n\t\t\tif (!request) return undefined;\n\t\t\tconst scripts = this.deps.getSettingsManager().getToolkitScripts();\n\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\tsystemPrompt: REFLEX_INTERPRETER_SYSTEM_PROMPT,\n\t\t\t\tmessages: [\n\t\t\t\t\t{\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: buildReflexUserPrompt(request, scripts) }],\n\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tmodel,\n\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\tmaxTokens: 256,\n\t\t\t\tcacheRetention: \"short\",\n\t\t\t});\n\t\t\tif (completion.usage.cost.total > 0 || completion.usage.totalTokens > 0) {\n\t\t\t\tthis.deps.addSpawnedUsage(completion.usage, { label: \"executor-brain-warmup\" });\n\t\t\t}\n\t\t\tconst plan = parseReflexPlan(completion.text);\n\t\t\tif (!plan || plan.script === \"none\") return undefined;\n\t\t\tconst argHint = plan.args.length > 0 ? ` with args ${JSON.stringify(plan.args)}` : \"\";\n\t\t\treturn `Run the toolkit script \"${plan.script}\"${argHint} using run_toolkit_script, then report its result exactly.`;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate _resolveModelRouterTurnRoute(prompt: string): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._lastModelRouterSkipReason = \"disabled\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// G16 executor lane: a Level-0 DIRECT toolkit hit on a command-shaped prompt routes the\n\t\t// whole turn to the configured local executor (tool-call-fitness-gated) instead of\n\t\t// spending the frontier model on a one-tool reflex. Ambiguity never routes here — it\n\t\t// stays with the big model and the reflex brain. Deterministic, so the judge is skipped.\n\t\tconst executorRoute = this._resolveExecutorRoute(prompt, settings.executorModel);\n\t\tif (executorRoute) return executorRoute;\n\n\t\tconst decision = classifyModelRouterRoute(prompt);\n\t\tthis._lastModelRouterIntent = decision.tier === \"cheap\" ? \"research\" : \"modify\";\n\n\t\t// Learning tier must not be selected for normal user prompts\n\t\tif (decision.tier === \"learning\") {\n\t\t\tthis._lastModelRouterSkipReason = \"learning tier not supported for user prompts\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst modelPattern =\n\t\t\tsettings[\n\t\t\t\tdecision.tier === \"cheap\" ? \"cheapModel\" : decision.tier === \"medium\" ? \"mediumModel\" : \"expensiveModel\"\n\t\t\t];\n\t\tconst label =\n\t\t\tdecision.tier === \"cheap\" ? \"cheap model\" : decision.tier === \"medium\" ? \"medium model\" : \"expensive model\";\n\n\t\tif (decision.tier === \"medium\" && (!modelPattern || !this._isModelAvailableAndAuthed(modelPattern))) {\n\t\t\tconst fallback = this._resolveExpensiveFallbackRoute(\n\t\t\t\tdecision,\n\t\t\t\t\"medium_unavailable_fallback_expensive\",\n\t\t\t\t\"Medium model is unavailable, falling back to expensive model\",\n\t\t\t);\n\t\t\tif (fallback) return fallback;\n\t\t\tthis._lastModelRouterSkipReason ??= \"medium model and expensive fallback are unavailable\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!modelPattern) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} unset`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} unresolved: ${modelPattern}`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst resolvedName = formatModelRouterModel(resolved.model);\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} missing auth: ${resolvedName}`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (this.deps.isModelExhausted(resolved.model)) {\n\t\t\tif (decision.tier === \"medium\") {\n\t\t\t\tconst fallback = this._resolveExpensiveFallbackRoute(\n\t\t\t\t\tdecision,\n\t\t\t\t\t\"medium_exhausted_fallback_expensive\",\n\t\t\t\t\t\"Medium model exhausted: quota; falling back to expensive model\",\n\t\t\t\t);\n\t\t\t\tif (fallback) return fallback;\n\t\t\t}\n\t\t\tthis._lastModelRouterSkipReason = `${decision.tier} model exhausted: quota`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (settings.fitnessGate) {\n\t\t\tconst verdict = this._evaluateModelFitness(this._routerSurfaceForTier(decision.tier), resolved.model);\n\t\t\tif (!verdict.fit) {\n\t\t\t\tif (decision.tier === \"medium\") {\n\t\t\t\t\tconst failure = this._formatFitnessFailure(verdict);\n\t\t\t\t\tconst fallback = this._resolveExpensiveFallbackRoute(\n\t\t\t\t\t\tdecision,\n\t\t\t\t\t\t\"medium_unfit_fallback_expensive\",\n\t\t\t\t\t\t`Medium model is unfit (${failure}); falling back to expensive model`,\n\t\t\t\t\t);\n\t\t\t\t\tif (fallback) return fallback;\n\t\t\t\t}\n\t\t\t\tthis._lastModelRouterSkipReason = `${decision.tier} model unfit: ${this._formatFitnessFailure(verdict)} (fitness gate)`;\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\tthis._lastModelRouterSkipReason = undefined;\n\t\tdecision.model = resolvedName;\n\t\treturn { decision, model: resolved.model };\n\t}\n\n\tprivate _resolveModelRouterModelForIntent(intent: ModelRouterIntent): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst modelPattern = intent === \"research\" ? settings.cheapModel : settings.expensiveModel;\n\t\tif (!modelPattern) return undefined;\n\t\tconst resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return undefined;\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\treturn this.deps.isModelExhausted(resolved.model) ? undefined : resolved.model;\n\t}\n\n\tresolveConfiguredTierModel(tier: \"cheap\" | \"medium\" | \"expensive\"): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst pattern =\n\t\t\ttier === \"cheap\" ? settings.cheapModel : tier === \"medium\" ? settings.mediumModel : settings.expensiveModel;\n\t\tif (!pattern) return undefined;\n\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return undefined;\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\treturn this.deps.isModelExhausted(resolved.model) ? undefined : resolved.model;\n\t}\n\n\t/**\n\t * Router resolution with the routing judge (auto-on with the router): the regex classifier's\n\t * decision is the baseline; when a judge model resolves (judgeModel, else mediumModel), one\n\t * bounded, tool-less completion may move the tier between cheap/medium/expensive — never to\n\t * learning. Core rule encoded in the judge prompt: planning is never cheap unless genuinely\n\t * trivial. Every fallback stays visible in the decision reasons, and judge spend reports\n\t * through spawned-usage accounting.\n\t */\n\tasync resolveTurnRouteJudged(\n\t\tprompt: string,\n\t\toptions?: { skipJudge?: boolean },\n\t): Promise<{ decision: RouteDecision; model: Model<Api> } | undefined> {\n\t\tconst baseline = this._resolveModelRouterTurnRoute(prompt);\n\t\tif (!baseline) return undefined;\n\t\tif (options?.skipJudge) return baseline;\n\t\t// Deterministic executor routes need no judge (Level-0 already decided).\n\t\tif (baseline.decision.reasonCode === \"executor_direct\") return baseline;\n\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tif (!settings.judgeEnabled) return baseline;\n\t\tif (shouldSkipRouteJudgeForStaticDecision(baseline.decision)) return baseline;\n\t\tconst judgePattern = settings.judgeModel ?? settings.mediumModel;\n\t\tif (!judgePattern) return baseline;\n\t\tconst judgeModel = this.deps.resolveLaneModel(judgePattern);\n\t\tif (!judgeModel) {\n\t\t\treturn {\n\t\t\t\tdecision: withJudgeUnavailableFallback(\n\t\t\t\t\tbaseline.decision,\n\t\t\t\t\t`routing judge unavailable: ${judgePattern} did not resolve; baseline kept`,\n\t\t\t\t),\n\t\t\t\tmodel: baseline.model,\n\t\t\t};\n\t\t}\n\t\tif (settings.fitnessGate) {\n\t\t\tconst verdict = this._evaluateModelFitness(\"router_judge\", judgeModel);\n\t\t\tif (!verdict.fit) {\n\t\t\t\treturn {\n\t\t\t\t\tdecision: {\n\t\t\t\t\t\t...baseline.decision,\n\t\t\t\t\t\treasons: [\n\t\t\t\t\t\t\t...baseline.decision.reasons,\n\t\t\t\t\t\t\t`routing judge skipped: ${formatModelRouterModel(judgeModel)} unfit (${this._formatFitnessFailure(verdict)})`,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tmodel: baseline.model,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tlet spentUsage: Usage | undefined;\n\t\tconst judged = await runRouteJudge({\n\t\t\tprompt,\n\t\t\tbaseline: baseline.decision,\n\t\t\tsignal: this.deps.getReflectionSignal(),\n\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\tsystemPrompt,\n\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\tmodel: judgeModel,\n\t\t\t\t\t// Per-tier thinking (R1): judgeThinking overrides the judge's own completion; unset\n\t\t\t\t\t// keeps today's \"off\" (the judge is a cheap classification call by default).\n\t\t\t\t\tthinkingLevel: settings.judgeThinking ?? \"off\",\n\t\t\t\t\tmaxTokens: ROUTE_JUDGE_MAX_OUTPUT_TOKENS,\n\t\t\t\t\tsignal,\n\t\t\t\t\t// The judge system prompt is static — the provider can cache the prefix.\n\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t});\n\t\t\t\tspentUsage = completion.usage;\n\t\t\t\treturn {\n\t\t\t\t\ttext: completion.text,\n\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t\tif (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {\n\t\t\tthis.deps.addSpawnedUsage(spentUsage, { label: \"router-judge\" });\n\t\t}\n\n\t\tif (!judged.verdict || judged.decision.tier === baseline.decision.tier) {\n\t\t\t// Same tier (or judge fell back): keep the baseline model, carry the annotated decision.\n\t\t\treturn { decision: judged.decision, model: baseline.model };\n\t\t}\n\n\t\tconst judgedTier = judged.decision.tier;\n\t\tif (judgedTier !== \"cheap\" && judgedTier !== \"medium\" && judgedTier !== \"expensive\") {\n\t\t\treturn { decision: baseline.decision, model: baseline.model };\n\t\t}\n\t\tconst judgedModel = this.resolveConfiguredTierModel(judgedTier);\n\t\tif (!judgedModel) {\n\t\t\treturn {\n\t\t\t\tdecision: {\n\t\t\t\t\t...baseline.decision,\n\t\t\t\t\treasons: [\n\t\t\t\t\t\t...baseline.decision.reasons,\n\t\t\t\t\t\t`Route judge chose ${judgedTier} but no model resolves for that tier; baseline kept`,\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tmodel: baseline.model,\n\t\t\t};\n\t\t}\n\t\treturn { decision: { ...judged.decision, model: formatModelRouterModel(judgedModel) }, model: judgedModel };\n\t}\n\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: test seam\n\tprivate _resolveModelRouterTurnModel(prompt: string): Model<Api> | undefined {\n\t\tconst resolved = this._resolveModelRouterTurnRoute(prompt);\n\t\treturn resolved?.model;\n\t}\n\n\tgetStatus(formatLabel?: (label: string) => string): string {\n\t\tconst recentDecisions = getRecentModelRouterDecisions(this.deps.getSessionManager().getEntries());\n\t\tconst lastDecision = this._lastModelRouterDecision ?? recentDecisions.at(-1);\n\t\tconst historicalDecisions = this._lastModelRouterDecision ? recentDecisions : recentDecisions.slice(0, -1);\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst lines = [\n\t\t\tformatModelRouterStatus(\n\t\t\t\tsettings,\n\t\t\t\tlastDecision,\n\t\t\t\tformatLabel,\n\t\t\t\thistoricalDecisions,\n\t\t\t\tthis._lastModelRouterSkipReason,\n\t\t\t\tthis._lastModelRouterIntent ?? lastDecision?.intent,\n\t\t\t\tsettings.fitnessGate ? this._getRouterTierFitnessStatuses() : undefined,\n\t\t\t\tthis.deps.getFailoverStatus(),\n\t\t\t),\n\t\t];\n\t\tconst diagnostics = collectModelRouterConfigDiagnostics(\n\t\t\tsettings,\n\t\t\tthis.deps.getModelRegistry(),\n\t\t\tthis.deps.getAgentDir(),\n\t\t);\n\t\tif (diagnostics.length > 0) {\n\t\t\tlines.push(formatLabel ? formatLabel(\"Config diagnostics:\") : \"Config diagnostics:\");\n\t\t\tfor (const diagnostic of diagnostics) {\n\t\t\t\tlines.push(`- ${diagnostic}`);\n\t\t\t}\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tasync runRoutedTurn(\n\t\tmessages: AgentMessage | AgentMessage[],\n\t\troutedModel: Model<Api> | undefined,\n\t\trouteDecision: RouteDecision | undefined,\n\t\tpersistDecision = true,\n\t): Promise<void> {\n\t\tif (!routedModel) {\n\t\t\tawait this.deps.runAgentPrompt(messages);\n\t\t\treturn;\n\t\t}\n\n\t\tconst agent = this.deps.getAgent();\n\t\tconst previousModel = agent.state.model;\n\t\tconst previousThinkingLevel = agent.state.thinkingLevel;\n\t\tconst previousTurnTools = agent.state.tools;\n\t\tconst previousSystemPrompt = agent.state.systemPrompt;\n\t\t// G4 swap bookkeeping (Bug G): the exact references the swap below assigns, so the finally can\n\t\t// restore ONLY what IT put there — never assigned when no swap happens (e.g. a full-class\n\t\t// routed profile).\n\t\tlet swappedTools: typeof previousTurnTools | undefined;\n\t\tlet swappedSystemPrompt: typeof previousSystemPrompt | undefined;\n\t\tconst previousActiveModelRouterIntent = this._activeModelRouterIntent;\n\t\tconst previousActiveModelRouterRoute = this._activeModelRouterRoute;\n\t\tconst previousModelRouterSessionBuffer = this._modelRouterSessionBuffer;\n\t\tconst previousModelRouterEscalationRequested = this._modelRouterEscalationRequested;\n\t\tconst bufferRoutedTurn = routeDecision?.tier === \"cheap\";\n\t\tconst originalHistoryLength = agent.state.messages.length;\n\t\tlet retryModel: Model<Api> | undefined;\n\t\tlet completedDecision: ModelRouterDecisionStatus | undefined = routeDecision\n\t\t\t? {\n\t\t\t\t\troute: routeDecision,\n\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\toutcome: \"routed\",\n\t\t\t\t\tintent: routeDecision.tier === \"cheap\" ? \"research\" : \"modify\",\n\t\t\t\t}\n\t\t\t: undefined;\n\t\tlet thrownError: unknown;\n\t\tif (routeDecision) {\n\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t}\n\t\tthis._activeModelRouterIntent = routeDecision\n\t\t\t? routeDecision.tier === \"cheap\"\n\t\t\t\t? \"research\"\n\t\t\t\t: \"modify\"\n\t\t\t: undefined;\n\t\tthis._activeModelRouterRoute = routeDecision;\n\t\tif (bufferRoutedTurn) {\n\t\t\tthis._modelRouterSessionBuffer = createModelRouterSessionBuffer();\n\t\t\tthis._modelRouterEscalationRequested = false;\n\t\t}\n\t\tconst routerThinkingSettings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst configuredThinking = !routeDecision\n\t\t\t? undefined\n\t\t\t: routeDecision.reasonCode === \"executor_direct\"\n\t\t\t\t? routerThinkingSettings.executorThinking\n\t\t\t\t: routeDecision.tier === \"cheap\"\n\t\t\t\t\t? routerThinkingSettings.cheapThinking\n\t\t\t\t\t: routeDecision.tier === \"medium\"\n\t\t\t\t\t\t? routerThinkingSettings.mediumThinking\n\t\t\t\t\t\t: routeDecision.tier === \"expensive\"\n\t\t\t\t\t\t\t? routerThinkingSettings.expensiveThinking\n\t\t\t\t\t\t\t: undefined;\n\t\tconst routedThinkingLevel = clampThinkingLevel(\n\t\t\troutedModel,\n\t\t\tconfiguredThinking ?? previousThinkingLevel,\n\t\t) as ThinkingLevel;\n\t\tconst modelChanged = !modelsAreEqual(this.deps.getModel(), routedModel);\n\t\tconst thinkingChanged = routedThinkingLevel !== previousThinkingLevel;\n\t\tif (modelChanged || thinkingChanged) {\n\t\t\tagent.state.model = routedModel;\n\t\t\t// Per-tier thinking (R1): a configured tier/executor thinking level overrides the inherited\n\t\t\t// session thinking for THIS routed turn only; unset falls back to exactly today's\n\t\t\t// inherit-and-clamp behavior. Executor routes carry tier \"cheap\" too, so reasonCode is\n\t\t\t// checked first — otherwise an executor turn would silently pick up cheapThinking instead.\n\t\t\t// The judge's own completion has a separate knob (judgeThinking) applied at its call site.\n\t\t\tagent.state.thinkingLevel = routedThinkingLevel;\n\t\t\t// G4: capability tool-filtering follows the ROUTED model for the turn. Without this a\n\t\t\t// cheap/local routed model inherits the session model's full tool surface — schemas it\n\t\t\t// pays for on every request and may not be able to drive at all.\n\t\t\tif (modelChanged) {\n\t\t\t\tconst routedProfile = deriveModelCapabilityProfile({\n\t\t\t\t\tcontextWindow: routedModel.contextWindow,\n\t\t\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t\t\t});\n\t\t\t\tif (routedProfile.class !== \"full\") {\n\t\t\t\t\tconst allowed = new Set(\n\t\t\t\t\t\tfilterToolNamesForCapability(\n\t\t\t\t\t\t\tpreviousTurnTools.map((tool) => tool.name),\n\t\t\t\t\t\t\troutedProfile,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tswappedTools = previousTurnTools.filter((tool) => allowed.has(tool.name));\n\t\t\t\t\tagent.state.tools = swappedTools;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// The routed prompt follows both the routed tool surface and its effective thinking mode.\n\t\t\t// This removes an Ultra policy during max/Luna routes, including same-model tier overrides.\n\t\t\t// Per-turn only; a live extension override is preserved rather than silently replaced.\n\t\t\tif (agent.state.systemPrompt === this.deps.getBaseSystemPrompt()) {\n\t\t\t\tswappedSystemPrompt = this.deps.buildSystemPromptForToolNames(agent.state.tools.map((tool) => tool.name));\n\t\t\t\tagent.state.systemPrompt = swappedSystemPrompt;\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tawait this.deps.runAgentPrompt(messages);\n\t\t\t// Speculative muscle-retry (G16 refinement): an executor-routed turn is a bet that the\n\t\t\t// small model can run the toolkit command directly. If it ends WITHOUT a successful\n\t\t\t// run_toolkit_script execution, retry ONCE on the same executor with the brain's\n\t\t\t// refined instruction injected — the brain warms while the muscle tries, so the retry\n\t\t\t// pays only when the muscle actually missed.\n\t\t\tif (\n\t\t\t\trouteDecision?.reasonCode === \"executor_direct\" &&\n\t\t\t\t!this._isModelRouterRetry &&\n\t\t\t\t!this._executorTurnExecutedScript(originalHistoryLength)\n\t\t\t) {\n\t\t\t\tconst refined = await this._buildExecutorRefinedPrompt(messages);\n\t\t\t\tif (refined) {\n\t\t\t\t\tagent.state.messages.splice(originalHistoryLength);\n\t\t\t\t\tif (bufferRoutedTurn) this._modelRouterSessionBuffer = createModelRouterSessionBuffer();\n\t\t\t\t\tawait this.deps.runAgentPrompt([\n\t\t\t\t\t\t{ role: \"user\", content: [{ type: \"text\", text: refined }], timestamp: Date.now() },\n\t\t\t\t\t]);\n\t\t\t\t\tcompletedDecision = {\n\t\t\t\t\t\troute: {\n\t\t\t\t\t\t\t...routeDecision,\n\t\t\t\t\t\t\treasonCode: \"executor_speculative_retry\",\n\t\t\t\t\t\t\treasons: [\n\t\t\t\t\t\t\t\t...routeDecision.reasons,\n\t\t\t\t\t\t\t\t\"Executor missed on first try; retried with brain-refined instruction\",\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\t\toutcome: \"routed\",\n\t\t\t\t\t\tintent: \"research\",\n\t\t\t\t\t};\n\t\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t\t} else {\n\t\t\t\t\t// The muscle missed AND the reflex brain could not refine the request into a toolkit\n\t\t\t\t\t// instruction (no fit brain model, or no confident plan). There is deliberately NO\n\t\t\t\t\t// frontier fallback here, so surface the miss instead of letting it stand silently —\n\t\t\t\t\t// otherwise the routed turn just ends with an unrun command and no explanation.\n\t\t\t\t\tthis.deps.emit({\n\t\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Executor lane: the toolkit command did not run and the reflex brain could not refine it into an explicit instruction; leaving the turn as-is (no automatic escalation).\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bufferRoutedTurn && this._modelRouterEscalationRequested) {\n\t\t\t\tagent.state.messages.splice(originalHistoryLength);\n\t\t\t\tretryModel = this._resolveModelRouterModelForIntent(\"modify\") ?? previousModel;\n\t\t\t\tcompletedDecision = {\n\t\t\t\t\troute: routeDecision!,\n\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\toutcome: \"escalated\",\n\t\t\t\t\tretryModel: formatModelRouterModel(retryModel),\n\t\t\t\t\tintent: routeDecision!.tier === \"cheap\" ? \"research\" : \"modify\",\n\t\t\t\t};\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t} else if (bufferRoutedTurn && this._modelRouterSessionBuffer) {\n\t\t\t\tflushModelRouterSessionBuffer(\n\t\t\t\t\tthis._modelRouterSessionBuffer,\n\t\t\t\t\t(message) => {\n\t\t\t\t\t\tthis.deps.getSessionManager().appendMessage(message);\n\t\t\t\t\t},\n\t\t\t\t\t(customType, content, display, details) => {\n\t\t\t\t\t\tthis.deps.getSessionManager().appendCustomMessageEntry(customType, content, display, details);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrownError = error;\n\t\t\tif (completedDecision) {\n\t\t\t\tcompletedDecision = { ...completedDecision, outcome: \"failed\" };\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t}\n\t\t} finally {\n\t\t\t// Restore the pre-route model ONLY if the routed model is still in place: a command\n\t\t\t// handler may have legitimately changed the session model mid-turn (setModel or a\n\t\t\t// provider re-registration), and clobbering that would silently undo the change.\n\t\t\tif (modelsAreEqual(agent.state.model, routedModel)) {\n\t\t\t\tagent.state.model = previousModel;\n\t\t\t\tagent.state.thinkingLevel = previousThinkingLevel;\n\t\t\t\t// Symmetric restore (Bug G): undo tools/systemPrompt only if each is STILL the exact\n\t\t\t\t// reference/string the G4 swap above assigned (never assigned at all when the routed\n\t\t\t\t// profile was full-class — then there is nothing to restore either). An extension calling\n\t\t\t\t// setActiveToolsByName mid-turn reassigns both to its own values without touching the\n\t\t\t\t// model — the model guard above still passes, but that live change is legitimate and must\n\t\t\t\t// survive rather than being silently reverted to the stale pre-turn snapshot.\n\t\t\t\tif (swappedTools !== undefined && agent.state.tools === swappedTools) {\n\t\t\t\t\tagent.state.tools = previousTurnTools;\n\t\t\t\t}\n\t\t\t\tif (swappedSystemPrompt !== undefined && agent.state.systemPrompt === swappedSystemPrompt) {\n\t\t\t\t\tagent.state.systemPrompt = previousSystemPrompt;\n\t\t\t\t}\n\t\t\t\t// The registry may have changed mid-turn (command-time registerProvider): re-resolve\n\t\t\t\t// the restored model so a provider override is not dropped with the routed model.\n\t\t\t\tthis.deps.refreshCurrentModelFromRegistry();\n\t\t\t}\n\t\t\tthis._activeModelRouterIntent = previousActiveModelRouterIntent;\n\t\t\tthis._activeModelRouterRoute = previousActiveModelRouterRoute;\n\t\t\tthis._modelRouterSessionBuffer = previousModelRouterSessionBuffer;\n\t\t\tthis._modelRouterEscalationRequested = previousModelRouterEscalationRequested;\n\t\t}\n\n\t\tif (retryModel && !thrownError) {\n\t\t\tconst previousIsModelRouterRetry = this._isModelRouterRetry;\n\t\t\ttry {\n\t\t\t\tthis._isModelRouterRetry = true;\n\t\t\t\tconst retryDecision: RouteDecision = {\n\t\t\t\t\ttier: \"expensive\",\n\t\t\t\t\trisk: \"high-impact\",\n\t\t\t\t\tconfidence: 1.0,\n\t\t\t\t\treasonCode: \"cheap_mutating_tool_escalation\",\n\t\t\t\t\treasons: [\"Cheap research turn attempted a mutating tool and escalated\"],\n\t\t\t\t\tfallbackFrom: \"cheap\",\n\t\t\t\t\tmodel: formatModelRouterModel(retryModel),\n\t\t\t\t};\n\t\t\t\tawait this.runRoutedTurn(messages, retryModel, retryDecision, false);\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t} catch (error) {\n\t\t\t\tthrownError = error;\n\t\t\t\tif (completedDecision) {\n\t\t\t\t\tcompletedDecision = { ...completedDecision, outcome: \"failed\" };\n\t\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tthis._isModelRouterRetry = previousIsModelRouterRetry;\n\t\t\t}\n\t\t}\n\n\t\tif (persistDecision && completedDecision) {\n\t\t\tpersistModelRouterDecision(this.deps.getSessionManager(), completedDecision);\n\t\t\t// G3: one route event per user-facing routed turn (the escalation retry runs with\n\t\t\t// persistDecision=false, so it does not double-emit). Codes/numbers only — no prompt text.\n\t\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.routeDecision,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tpayload: {\n\t\t\t\t\ttier: completedDecision.route.tier,\n\t\t\t\t\trisk: completedDecision.route.risk,\n\t\t\t\t\treasonCode: completedDecision.route.reasonCode,\n\t\t\t\t\tconfidence: completedDecision.route.confidence,\n\t\t\t\t\toutcome: completedDecision.outcome,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tif (thrownError) {\n\t\t\tthrow thrownError;\n\t\t}\n\t}\n}\n"]}
|