@gajae-code/coding-agent 0.12.21 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -2
- package/dist/types/cli/args.d.ts +5 -2
- package/dist/types/cli/root-flags.d.ts +246 -0
- package/dist/types/cli.d.ts +11 -19
- package/dist/types/commands/daemon.d.ts +0 -30
- package/dist/types/commands/launch.d.ts +11 -19
- package/dist/types/commands/quick-lane.d.ts +32 -0
- package/dist/types/commands/sdk.d.ts +21 -15
- package/dist/types/config/file-lock-gc.d.ts +2 -0
- package/dist/types/config/model-equivalence.d.ts +20 -0
- package/dist/types/config/model-profile-activation.d.ts +62 -17
- package/dist/types/config/model-profiles.d.ts +10 -0
- package/dist/types/config/model-registry.d.ts +68 -1
- package/dist/types/config/model-resolver.d.ts +15 -4
- package/dist/types/config/models-config-schema.d.ts +7 -2
- package/dist/types/config/provider-selection-policy.d.ts +62 -0
- package/dist/types/config/settings-schema.d.ts +36 -78
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/edit/renderer.d.ts +5 -2
- package/dist/types/edit/streaming.d.ts +13 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -0
- package/dist/types/extensibility/extensions/compact-handler.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +19 -5
- package/dist/types/internal-urls/local-protocol.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +0 -2
- package/dist/types/modes/components/provider-order-context.d.ts +45 -0
- package/dist/types/modes/components/provider-order-editor.d.ts +24 -0
- package/dist/types/modes/components/settings-defs.d.ts +5 -1
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/quick-lane/classify.d.ts +40 -0
- package/dist/types/runtime/stt-settings-setup.d.ts +18 -0
- package/dist/types/sdk/broker/broker.d.ts +56 -2
- package/dist/types/sdk/broker/operation-receipt-ledger.d.ts +25 -0
- package/dist/types/sdk/broker/session-index.d.ts +83 -2
- package/dist/types/sdk/broker/state-version.d.ts +1 -1
- package/dist/types/sdk/bus/notification-service.d.ts +6 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +8 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +4 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +26 -0
- package/dist/types/sdk/cli/rows.d.ts +98 -0
- package/dist/types/sdk/cli/session-cli.d.ts +35 -3
- package/dist/types/sdk/elevation/allowlist.d.ts +20 -0
- package/dist/types/sdk/elevation/audit.d.ts +93 -0
- package/dist/types/sdk/elevation/capability.d.ts +3 -0
- package/dist/types/sdk/elevation/digest.d.ts +72 -0
- package/dist/types/sdk/elevation/dispatch-receipt.d.ts +85 -0
- package/dist/types/sdk/elevation/grant-ledger.d.ts +163 -0
- package/dist/types/sdk/elevation/owner.d.ts +48 -0
- package/dist/types/sdk/guides/cache.d.ts +98 -0
- package/dist/types/sdk/guides/catalog.d.ts +156 -0
- package/dist/types/sdk/guides/cli.d.ts +39 -0
- package/dist/types/sdk/guides/manifest.d.ts +66 -0
- package/dist/types/sdk/guides/verify.d.ts +66 -0
- package/dist/types/sdk/host/control/dispatch.d.ts +8 -0
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +3 -2
- package/dist/types/sdk/host/query/cursor.d.ts +10 -0
- package/dist/types/sdk/host/query/handlers.d.ts +21 -0
- package/dist/types/sdk/host/session-runtime.d.ts +9 -0
- package/dist/types/sdk/mcp/server.d.ts +2 -2
- package/dist/types/sdk/prompt-status.d.ts +11 -0
- package/dist/types/sdk/session.d.ts +4 -0
- package/dist/types/sdk/transport/index.d.ts +1 -0
- package/dist/types/sdk/transport/relay.d.ts +1 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +20 -1
- package/dist/types/session/agent-session.d.ts +32 -18
- package/dist/types/session/blob-store.d.ts +13 -7
- package/dist/types/session/fallback-chain-controller.d.ts +15 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +25 -1
- package/dist/types/session/internal/session-memory-sidecar.d.ts +5 -5
- package/dist/types/session/session-manager.d.ts +139 -10
- package/dist/types/session/session-storage.d.ts +48 -0
- package/dist/types/setup/provider-onboarding.d.ts +7 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +14 -0
- package/dist/types/stt/setup.d.ts +2 -0
- package/dist/types/task/executor.d.ts +10 -2
- package/dist/types/tools/browser/runtime-diagnostics.d.ts +65 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +2 -0
- package/dist/types/tools/browser/tab-worker.d.ts +2 -0
- package/dist/types/tools/browser.d.ts +2 -0
- package/dist/types/tools/image-gen.d.ts +14 -18
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/resource-gc.d.ts +2 -0
- package/dist/types/utils/pasted-image-path.d.ts +6 -0
- package/package.json +9 -9
- package/scripts/generate-sdk-operation-inventory.ts +8 -0
- package/scripts/run-test-manifest.ts +61 -21
- package/scripts/verify-gjc-sdk-canonicalization.ts +9 -4
- package/src/cli/args.ts +62 -9
- package/src/cli/completion-cli.ts +1 -0
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/root-flags.ts +100 -0
- package/src/cli/setup-cli.ts +6 -2
- package/src/cli.ts +42 -65
- package/src/commands/acp.ts +1 -1
- package/src/commands/daemon.ts +2 -31
- package/src/commands/gc.ts +1 -1
- package/src/commands/launch.ts +8 -129
- package/src/commands/quick-lane.ts +51 -0
- package/src/commands/sdk.ts +200 -26
- package/src/commands/setup.ts +4 -2
- package/src/config/file-lock-gc.ts +4 -1
- package/src/config/model-equivalence.ts +76 -7
- package/src/config/model-profile-activation.ts +1115 -265
- package/src/config/model-profiles.ts +134 -2
- package/src/config/model-registry.ts +352 -50
- package/src/config/model-resolver.ts +289 -38
- package/src/config/models-config-schema.ts +11 -4
- package/src/config/provider-selection-policy.ts +146 -0
- package/src/config/settings-schema.ts +50 -77
- package/src/config/settings.ts +40 -0
- package/src/coordinator-mcp/server.ts +32 -2
- package/src/edit/renderer.ts +175 -223
- package/src/edit/streaming.ts +108 -1
- package/src/export/html/index.ts +57 -7
- package/src/extensibility/custom-tools/types.ts +2 -0
- package/src/extensibility/extensions/compact-handler.ts +3 -2
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/gjc-runtime/gc-runtime.ts +379 -20
- package/src/gjc-runtime/launch-worktree.ts +5 -1
- package/src/gjc-runtime/team-runtime.ts +59 -2
- package/src/gjc-runtime/tmux-owner-isolation.ts +19 -0
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +16 -1
- package/src/internal-urls/docs-index.generated.ts +17 -13
- package/src/internal-urls/local-protocol.ts +1 -0
- package/src/main.ts +40 -3
- package/src/memories/index.ts +4 -2
- package/src/modes/acp/acp-agent.ts +235 -91
- package/src/modes/components/model-selector.ts +206 -42
- package/src/modes/components/provider-order-context.ts +197 -0
- package/src/modes/components/provider-order-editor.ts +441 -0
- package/src/modes/components/settings-defs.ts +21 -1
- package/src/modes/components/settings-selector.ts +45 -2
- package/src/modes/components/tool-execution.ts +47 -15
- package/src/modes/controllers/command-controller.ts +6 -3
- package/src/modes/controllers/extension-ui-controller.ts +2 -0
- package/src/modes/controllers/input-controller.ts +73 -2
- package/src/modes/controllers/selector-controller.ts +260 -153
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +18 -0
- package/src/prompts/tools/browser.md +1 -0
- package/src/quick-lane/classify.ts +257 -0
- package/src/rlm/index.ts +1 -1
- package/src/runtime/stt-settings-setup.ts +57 -0
- package/src/sdk/acp/adapter.ts +2 -1
- package/src/sdk/broker/broker.ts +780 -12
- package/src/sdk/broker/lifecycle.ts +70 -29
- package/src/sdk/broker/operation-receipt-ledger.ts +144 -0
- package/src/sdk/broker/session-index.ts +463 -48
- package/src/sdk/broker/state-version.ts +13 -9
- package/src/sdk/broker/transport.ts +14 -1
- package/src/sdk/bus/index.ts +34 -13
- package/src/sdk/bus/kind-aware-reconciliation.ts +21 -2
- package/src/sdk/bus/notification-service.ts +47 -1
- package/src/sdk/bus/prompt-reconciliation.ts +22 -3
- package/src/sdk/bus/telegram-daemon-contract.ts +4 -1
- package/src/sdk/bus/telegram-daemon.ts +54 -3
- package/src/sdk/cli/rows.ts +247 -0
- package/src/sdk/cli/session-cli.ts +930 -79
- package/src/sdk/elevation/allowlist.ts +54 -0
- package/src/sdk/elevation/audit.ts +208 -0
- package/src/sdk/elevation/capability.ts +41 -0
- package/src/sdk/elevation/digest.ts +129 -0
- package/src/sdk/elevation/dispatch-receipt.ts +184 -0
- package/src/sdk/elevation/grant-ledger.ts +1142 -0
- package/src/sdk/elevation/owner.ts +109 -0
- package/src/sdk/guides/cache.ts +363 -0
- package/src/sdk/guides/catalog.ts +554 -0
- package/src/sdk/guides/cli.ts +235 -0
- package/src/sdk/guides/manifest.ts +152 -0
- package/src/sdk/guides/verify.ts +178 -0
- package/src/sdk/host/control/dispatch.ts +49 -1
- package/src/sdk/host/control/index.ts +1 -0
- package/src/sdk/host/control/operations.ts +8 -1
- package/src/sdk/host/query/cursor.ts +47 -3
- package/src/sdk/host/query/handlers.ts +155 -2
- package/src/sdk/host/sdk-surface-parity.test.ts +1 -0
- package/src/sdk/host/session-runtime.test.ts +391 -1
- package/src/sdk/host/session-runtime.ts +308 -73
- package/src/sdk/host/surface-policy.ts +3 -0
- package/src/sdk/host/websocket-transport.ts +7 -1
- package/src/sdk/mcp/server.ts +88 -15
- package/src/sdk/prompt-status.ts +8 -0
- package/src/sdk/protocol/operation-inventory.generated.json +62 -0
- package/src/sdk/protocol/operation-registry.ts +3 -2
- package/src/sdk/session.ts +87 -39
- package/src/sdk/transport/index.ts +1 -0
- package/src/sdk/transport/relay.ts +3 -0
- package/src/sdk/transport/serve-cli.ts +111 -24
- package/src/secrets/obfuscator.ts +92 -12
- package/src/session/agent-session.ts +322 -93
- package/src/session/blob-store.ts +60 -8
- package/src/session/fallback-chain-controller.ts +35 -0
- package/src/session/internal/managed-session-scope.ts +25 -3
- package/src/session/internal/managed-session-storage.ts +574 -73
- package/src/session/internal/session-memory-sidecar.ts +19 -29
- package/src/session/session-manager.ts +2166 -743
- package/src/session/session-storage.ts +715 -48
- package/src/setup/provider-onboarding.ts +19 -3
- package/src/setup/provider-presets.json +3 -1
- package/src/slash-commands/builtin-registry.ts +85 -3
- package/src/stt/downloader.ts +2 -3
- package/src/stt/setup.ts +29 -4
- package/src/task/executor.ts +22 -18
- package/src/task/index.ts +24 -1
- package/src/tools/archive-reader.ts +11 -2
- package/src/tools/browser/runtime-diagnostics.ts +249 -0
- package/src/tools/browser/tab-protocol.ts +4 -0
- package/src/tools/browser/tab-supervisor.ts +5 -0
- package/src/tools/browser/tab-worker.ts +36 -1
- package/src/tools/browser.ts +7 -0
- package/src/tools/image-gen.ts +110 -166
- package/src/tools/index.ts +2 -0
- package/src/tools/read.ts +1 -1
- package/src/tools/resource-gc.ts +6 -1
- package/src/tools/tool-catalog.generated.ts +5 -1
- package/src/utils/pasted-image-path.ts +93 -0
- package/src/web/search/index.ts +3 -3
|
@@ -6,13 +6,16 @@ import {
|
|
|
6
6
|
type AuthCredentialSelector,
|
|
7
7
|
applyFinalCodexGpt56ContextCap,
|
|
8
8
|
type CacheRetention,
|
|
9
|
+
CODEX_GPT_5_6_CONTEXT_CAP,
|
|
9
10
|
type Context,
|
|
11
|
+
codexContextOverrideKey,
|
|
10
12
|
createModelManager,
|
|
11
13
|
enrichModelThinking,
|
|
12
14
|
getBundledModels,
|
|
13
15
|
getBundledProviders,
|
|
14
16
|
googleAntigravityModelManagerOptions,
|
|
15
17
|
googleGeminiCliModelManagerOptions,
|
|
18
|
+
isCodexGpt56Tier,
|
|
16
19
|
isKnownProvider,
|
|
17
20
|
type Model,
|
|
18
21
|
type ModelManagerOptions,
|
|
@@ -76,8 +79,15 @@ import {
|
|
|
76
79
|
type ProviderAuthMode,
|
|
77
80
|
type ProviderDiscovery,
|
|
78
81
|
} from "./models-config-schema";
|
|
82
|
+
import {
|
|
83
|
+
buildProviderSelectionCatalog,
|
|
84
|
+
createProviderSelectionPolicy,
|
|
85
|
+
type EffectiveProviderAuth,
|
|
86
|
+
type ProviderSelectionPolicy,
|
|
87
|
+
} from "./provider-selection-policy";
|
|
79
88
|
import { type Settings, settings } from "./settings";
|
|
80
89
|
|
|
90
|
+
export type { EffectiveProviderAuth, ProviderSelectionPolicy } from "./provider-selection-policy";
|
|
81
91
|
export type { CanonicalModelIndex, CanonicalModelRecord, CanonicalModelVariant, ModelEquivalenceConfig };
|
|
82
92
|
|
|
83
93
|
export { isAuthenticated, kNoAuth };
|
|
@@ -158,6 +168,7 @@ export const GJC_MODEL_ASSIGNMENT_TARGETS: Record<GjcModelAssignmentTargetId, Gj
|
|
|
158
168
|
settingsPath: "task.agentModelOverrides",
|
|
159
169
|
},
|
|
160
170
|
critic: { id: "critic", tag: "CRITIC", name: "Critic", color: "error", settingsPath: "task.agentModelOverrides" },
|
|
171
|
+
image: { id: "image", tag: "IMAGE", name: "Image", color: "accent", settingsPath: "modelRoles" },
|
|
161
172
|
};
|
|
162
173
|
|
|
163
174
|
/** Alias for ModelRoleInfo - used for both built-in and custom roles */
|
|
@@ -651,6 +662,8 @@ export interface CanonicalModelQueryOptions {
|
|
|
651
662
|
candidates?: readonly Model<Api>[];
|
|
652
663
|
/** Stable session identity used to keep a canonical variant sticky within a session. */
|
|
653
664
|
sessionId?: string;
|
|
665
|
+
/** Credential-selection session used to classify effective provider auth. Defaults to sessionId. */
|
|
666
|
+
credentialSessionId?: string;
|
|
654
667
|
}
|
|
655
668
|
|
|
656
669
|
/** Result of loading custom models from models.json */
|
|
@@ -851,7 +864,18 @@ function applyModelOverride(model: Model<Api>, override: ModelOverride): Model<A
|
|
|
851
864
|
if (override.input !== undefined) result.input = override.input as ("text" | "image")[];
|
|
852
865
|
if (override.output !== undefined) result.output = override.output as ("text" | "image")[];
|
|
853
866
|
if (override.cacheRetention !== undefined) result.cacheRetention = override.cacheRetention;
|
|
854
|
-
|
|
867
|
+
const contextWindowOverride = toPositiveNumberOrUndefined(override.contextWindow);
|
|
868
|
+
if (contextWindowOverride !== undefined) {
|
|
869
|
+
result.contextWindow = contextWindowOverride;
|
|
870
|
+
} else if (override.contextWindow !== undefined && !isCodexGpt56Tier({ id: model.id })) {
|
|
871
|
+
// Codex-tier invalid overrides are diagnosed in #collectCodexContextWindowOverrides;
|
|
872
|
+
// every other provider is diagnosed here so an ignored override is never silent.
|
|
873
|
+
logger.warn("model context-window override ignored: value must be a positive finite number", {
|
|
874
|
+
model: model.id,
|
|
875
|
+
provider: model.provider,
|
|
876
|
+
override: override.contextWindow,
|
|
877
|
+
});
|
|
878
|
+
}
|
|
855
879
|
if (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;
|
|
856
880
|
if (override.contextPromotionTarget !== undefined) result.contextPromotionTarget = override.contextPromotionTarget;
|
|
857
881
|
if (override.wireModelId !== undefined) result.wireModelId = override.wireModelId;
|
|
@@ -871,6 +895,26 @@ function applyModelOverride(model: Model<Api>, override: ModelOverride): Model<A
|
|
|
871
895
|
result.compat = mergeCompat(model.compat, override.compat);
|
|
872
896
|
return enrichModelThinking(result);
|
|
873
897
|
}
|
|
898
|
+
/**
|
|
899
|
+
* Normalizes `modelOverrides` keys to lowercase so override matching is
|
|
900
|
+
* case-insensitive everywhere (the Codex cap exemption is keyed by
|
|
901
|
+
* `codexContextOverrideKey`, which lowercases both sides). Without this,
|
|
902
|
+
* a mixed-case config key is exempted from the cap without its value ever
|
|
903
|
+
* being merged into the model.
|
|
904
|
+
*/
|
|
905
|
+
function normalizeModelOverrideKeys(
|
|
906
|
+
modelOverrides: Map<string, Map<string, ModelOverride>>,
|
|
907
|
+
): Map<string, Map<string, ModelOverride>> {
|
|
908
|
+
const normalized = new Map<string, Map<string, ModelOverride>>();
|
|
909
|
+
for (const [provider, perModel] of modelOverrides) {
|
|
910
|
+
const perProvider = new Map<string, ModelOverride>();
|
|
911
|
+
for (const [modelId, override] of perModel) {
|
|
912
|
+
perProvider.set(modelId.toLowerCase(), override);
|
|
913
|
+
}
|
|
914
|
+
normalized.set(provider.toLowerCase(), perProvider);
|
|
915
|
+
}
|
|
916
|
+
return normalized;
|
|
917
|
+
}
|
|
874
918
|
|
|
875
919
|
interface CustomModelDefinitionLike {
|
|
876
920
|
id: string;
|
|
@@ -1149,7 +1193,8 @@ function getDisabledProviderIdsFromSettings(): Set<string> {
|
|
|
1149
1193
|
|
|
1150
1194
|
function getConfiguredProviderOrderFromSettings(): string[] {
|
|
1151
1195
|
try {
|
|
1152
|
-
|
|
1196
|
+
const configured = settings.getGlobal("modelProviderOrder");
|
|
1197
|
+
return Array.isArray(configured) ? configured.filter((value): value is string => typeof value === "string") : [];
|
|
1153
1198
|
} catch {
|
|
1154
1199
|
return [];
|
|
1155
1200
|
}
|
|
@@ -1178,7 +1223,12 @@ interface ModelManagerDiscoveryOptions {
|
|
|
1178
1223
|
*/
|
|
1179
1224
|
export class ModelRegistry {
|
|
1180
1225
|
#models: Model<Api>[] = [];
|
|
1181
|
-
#canonicalIndex: CanonicalModelIndex = {
|
|
1226
|
+
#canonicalIndex: CanonicalModelIndex = {
|
|
1227
|
+
records: [],
|
|
1228
|
+
byId: new Map(),
|
|
1229
|
+
bySelector: new Map(),
|
|
1230
|
+
aliases: new Map(),
|
|
1231
|
+
};
|
|
1182
1232
|
#availableModelsCache: Model<Api>[] | undefined;
|
|
1183
1233
|
#availableModelsDisabledProviders: string | undefined;
|
|
1184
1234
|
#availableModelsEnvFingerprint: string | undefined;
|
|
@@ -1205,6 +1255,7 @@ export class ModelRegistry {
|
|
|
1205
1255
|
#customModelOverlays: CustomModelOverlay[] = [];
|
|
1206
1256
|
#providerOverrides: Map<string, ProviderOverride> = new Map();
|
|
1207
1257
|
#modelOverrides: Map<string, Map<string, ModelOverride>> = new Map();
|
|
1258
|
+
#codexContextWindowOverrides: Map<string, number> = new Map();
|
|
1208
1259
|
#equivalenceConfig: ModelEquivalenceConfig | undefined;
|
|
1209
1260
|
#modelBindingsApplier = new ModelBindingsApplier();
|
|
1210
1261
|
#modelProfiles: Map<string, ModelProfileDefinition> = mergeModelProfiles();
|
|
@@ -1345,17 +1396,20 @@ export class ModelRegistry {
|
|
|
1345
1396
|
// removed from models.yml must actually disappear from the resolver, not
|
|
1346
1397
|
// linger from the previous parse. The post-load setters below repopulate.
|
|
1347
1398
|
this.authStorage.clearConfigApiKeys();
|
|
1348
|
-
//
|
|
1349
|
-
//
|
|
1350
|
-
for (const [k, v] of this.#runtimeProviderApiKeys) {
|
|
1351
|
-
this.#customProviderApiKeys.set(k, v);
|
|
1352
|
-
}
|
|
1399
|
+
// Runtime provider keys are reapplied after #loadModels so they retain
|
|
1400
|
+
// registration-time precedence over colliding static provider keys.
|
|
1353
1401
|
this.#providerOverrides.clear();
|
|
1354
1402
|
this.#modelOverrides.clear();
|
|
1355
1403
|
this.#equivalenceConfig = undefined;
|
|
1356
1404
|
this.#modelBindingsApplier.setBindings(undefined);
|
|
1357
1405
|
this.#configError = undefined;
|
|
1358
1406
|
this.#loadModels();
|
|
1407
|
+
for (const [provider, apiKeyConfig] of this.#runtimeProviderApiKeys) {
|
|
1408
|
+
const resolved = resolveApiKeyConfig(apiKeyConfig);
|
|
1409
|
+
if (!resolved) continue;
|
|
1410
|
+
this.#customProviderApiKeys.set(provider, resolved);
|
|
1411
|
+
this.authStorage.setConfigApiKey(provider, resolved);
|
|
1412
|
+
}
|
|
1359
1413
|
this.#lastDisabledProviderKey = disabledProviderKey;
|
|
1360
1414
|
}
|
|
1361
1415
|
|
|
@@ -1387,7 +1441,8 @@ export class ModelRegistry {
|
|
|
1387
1441
|
this.#configuredDiscoveryProviderIds = new Set(discoverableProviders.map(provider => provider.provider));
|
|
1388
1442
|
this.#customModelOverlays = customModels;
|
|
1389
1443
|
this.#providerOverrides = overrides;
|
|
1390
|
-
this.#modelOverrides = modelOverrides;
|
|
1444
|
+
this.#modelOverrides = normalizeModelOverrideKeys(modelOverrides);
|
|
1445
|
+
this.#codexContextWindowOverrides = this.#collectCodexContextWindowOverrides();
|
|
1391
1446
|
this.#equivalenceConfig = equivalence;
|
|
1392
1447
|
this.#modelBindingsApplier.setBindings(modelBindings);
|
|
1393
1448
|
this.#modelProfiles = mergeModelProfiles(profiles);
|
|
@@ -1404,7 +1459,11 @@ export class ModelRegistry {
|
|
|
1404
1459
|
// Merge runtime extension models so they survive refresh() cycles
|
|
1405
1460
|
const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
|
|
1406
1461
|
const withModelOverrides = this.#applyModelOverrides(combined, this.#modelOverrides);
|
|
1407
|
-
this.#models = applyFinalCodexGpt56ContextCap(
|
|
1462
|
+
this.#models = applyFinalCodexGpt56ContextCap(
|
|
1463
|
+
this.#applyRuntimeProviderOverrides(withModelOverrides),
|
|
1464
|
+
undefined,
|
|
1465
|
+
this.#codexContextWindowOverrides,
|
|
1466
|
+
);
|
|
1408
1467
|
this.#rebuildProviderActivity();
|
|
1409
1468
|
this.#rebuildCanonicalIndex();
|
|
1410
1469
|
this.#lastStaticLoadMtime = this.#modelsConfigFile.getMtimeMs();
|
|
@@ -2161,7 +2220,11 @@ export class ModelRegistry {
|
|
|
2161
2220
|
// Merge runtime extension models so they survive online discovery completion
|
|
2162
2221
|
const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
|
|
2163
2222
|
const withModelOverrides = this.#applyModelOverrides(combined, this.#modelOverrides);
|
|
2164
|
-
this.#models = applyFinalCodexGpt56ContextCap(
|
|
2223
|
+
this.#models = applyFinalCodexGpt56ContextCap(
|
|
2224
|
+
this.#applyRuntimeProviderOverrides(withModelOverrides),
|
|
2225
|
+
undefined,
|
|
2226
|
+
this.#codexContextWindowOverrides,
|
|
2227
|
+
);
|
|
2165
2228
|
this.#rebuildCanonicalIndex();
|
|
2166
2229
|
}
|
|
2167
2230
|
|
|
@@ -3007,10 +3070,10 @@ export class ModelRegistry {
|
|
|
3007
3070
|
}
|
|
3008
3071
|
|
|
3009
3072
|
#applyProviderModelOverrides(provider: string, models: Model<Api>[]): Model<Api>[] {
|
|
3010
|
-
const overrides = this.#modelOverrides.get(provider);
|
|
3073
|
+
const overrides = this.#modelOverrides.get(provider.toLowerCase());
|
|
3011
3074
|
if (!overrides || overrides.size === 0) return models;
|
|
3012
3075
|
return models.map(model => {
|
|
3013
|
-
const override = overrides.get(model.id);
|
|
3076
|
+
const override = overrides.get(model.id.toLowerCase());
|
|
3014
3077
|
if (!override) return model;
|
|
3015
3078
|
return applyModelOverride(model, override);
|
|
3016
3079
|
});
|
|
@@ -3098,7 +3161,7 @@ export class ModelRegistry {
|
|
|
3098
3161
|
}
|
|
3099
3162
|
#applyRuntimeProviderOverride(model: Model<Api>, override: ProviderOverride): Model<Api> {
|
|
3100
3163
|
const withTransportOverride = this.#applyProviderTransportOverride(model, override);
|
|
3101
|
-
const modelCompat = this.#modelOverrides.get(model.provider)?.get(model.id)?.compat;
|
|
3164
|
+
const modelCompat = this.#modelOverrides.get(model.provider.toLowerCase())?.get(model.id.toLowerCase())?.compat;
|
|
3102
3165
|
return modelCompat
|
|
3103
3166
|
? { ...withTransportOverride, compat: mergeCompat(withTransportOverride.compat, modelCompat) }
|
|
3104
3167
|
: withTransportOverride;
|
|
@@ -3111,12 +3174,52 @@ export class ModelRegistry {
|
|
|
3111
3174
|
return this.#applyRuntimeProviderOverride(model, override);
|
|
3112
3175
|
});
|
|
3113
3176
|
}
|
|
3177
|
+
/**
|
|
3178
|
+
* Collects explicit user `contextWindow` overrides keyed by provider + model
|
|
3179
|
+
* id (`codexContextOverrideKey`), and surfaces diagnostics when one applies
|
|
3180
|
+
* to a Codex GPT-5.6 tier
|
|
3181
|
+
* model. The map is computed once per config load and feeds the final
|
|
3182
|
+
* context cap so an explicit override is never silently re-clamped.
|
|
3183
|
+
*/
|
|
3184
|
+
#collectCodexContextWindowOverrides(): Map<string, number> {
|
|
3185
|
+
const result = new Map<string, number>();
|
|
3186
|
+
for (const [provider, providerOverrides] of this.#modelOverrides) {
|
|
3187
|
+
for (const [modelId, override] of providerOverrides) {
|
|
3188
|
+
if (override.contextWindow === undefined) {
|
|
3189
|
+
continue;
|
|
3190
|
+
}
|
|
3191
|
+
const normalizedId = modelId.toLowerCase();
|
|
3192
|
+
const value = toPositiveNumberOrUndefined(override.contextWindow);
|
|
3193
|
+
if (value === undefined) {
|
|
3194
|
+
if (isCodexGpt56Tier({ id: normalizedId })) {
|
|
3195
|
+
logger.warn("codex gpt-5.6 context-window override ignored: value must be a positive finite number", {
|
|
3196
|
+
model: modelId,
|
|
3197
|
+
provider,
|
|
3198
|
+
override: override.contextWindow,
|
|
3199
|
+
});
|
|
3200
|
+
}
|
|
3201
|
+
continue;
|
|
3202
|
+
}
|
|
3203
|
+
result.set(codexContextOverrideKey(provider, modelId), value);
|
|
3204
|
+
if (!isCodexGpt56Tier({ id: normalizedId })) {
|
|
3205
|
+
continue;
|
|
3206
|
+
}
|
|
3207
|
+
logger.warn("codex gpt-5.6 context-window override active; verify it against the live product limit", {
|
|
3208
|
+
model: modelId,
|
|
3209
|
+
provider,
|
|
3210
|
+
override: override.contextWindow,
|
|
3211
|
+
enforced: CODEX_GPT_5_6_CONTEXT_CAP.enforced,
|
|
3212
|
+
});
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
return result;
|
|
3216
|
+
}
|
|
3114
3217
|
#applyModelOverrides(models: Model<Api>[], overrides: Map<string, Map<string, ModelOverride>>): Model<Api>[] {
|
|
3115
3218
|
if (overrides.size === 0) return models;
|
|
3116
3219
|
return models.map(model => {
|
|
3117
|
-
const providerOverrides = overrides.get(model.provider);
|
|
3220
|
+
const providerOverrides = overrides.get(model.provider.toLowerCase());
|
|
3118
3221
|
if (!providerOverrides) return model;
|
|
3119
|
-
const override = providerOverrides.get(model.id);
|
|
3222
|
+
const override = providerOverrides.get(model.id.toLowerCase());
|
|
3120
3223
|
if (!override) return model;
|
|
3121
3224
|
return applyModelOverride(model, override);
|
|
3122
3225
|
});
|
|
@@ -3129,7 +3232,7 @@ export class ModelRegistry {
|
|
|
3129
3232
|
if (model.id !== "gpt-5.4" || model.provider === "github-copilot" || model.provider === "jetbrains-junie") {
|
|
3130
3233
|
return model;
|
|
3131
3234
|
}
|
|
3132
|
-
const overrides = this.#modelOverrides.get(model.provider)?.get(model.id);
|
|
3235
|
+
const overrides = this.#modelOverrides.get(model.provider.toLowerCase())?.get(model.id.toLowerCase());
|
|
3133
3236
|
if (!overrides) {
|
|
3134
3237
|
return applyModelOverride(model, { contextWindow: 1_000_000 });
|
|
3135
3238
|
}
|
|
@@ -3245,54 +3348,113 @@ export class ModelRegistry {
|
|
|
3245
3348
|
});
|
|
3246
3349
|
}
|
|
3247
3350
|
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3351
|
+
/**
|
|
3352
|
+
* Effective credential provenance for a provider, derived from existing
|
|
3353
|
+
* AuthStorage/session credential surfaces — never from token shape.
|
|
3354
|
+
*
|
|
3355
|
+
* Precedence mirrors actual credential selection (`getApiKey`):
|
|
3356
|
+
* 1. Runtime/config API-key overrides (the actual credential resolver's
|
|
3357
|
+
* highest-priority surfaces)
|
|
3358
|
+
* 2. Session-recorded stored credential type
|
|
3359
|
+
* 3. Stored/custom API-key surfaces
|
|
3360
|
+
* 4. OAuth, only when it is the effective remaining stored credential
|
|
3361
|
+
* 5. Keyless providers
|
|
3362
|
+
* 6. Unknown (no credential surface)
|
|
3363
|
+
*/
|
|
3364
|
+
#effectiveProviderAuth(provider: string, sessionId?: string): EffectiveProviderAuth {
|
|
3365
|
+
const credentialType = this.authStorage.getEffectiveCredentialType(provider, sessionId);
|
|
3366
|
+
if (credentialType === "api_key") return "key";
|
|
3367
|
+
if (credentialType === "oauth") return "oauth";
|
|
3368
|
+
if (this.#keylessProviders.has(provider)) return "keyless";
|
|
3369
|
+
return "unknown";
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
/**
|
|
3373
|
+
* Build the pure provider selection policy from the registry catalog order,
|
|
3374
|
+
* configured `modelProviderOrder`, and effective credential provenance for
|
|
3375
|
+
* the given session. Caller candidate order never influences the resulting
|
|
3376
|
+
* ranks or tie data; session provenance can (a session that authenticated
|
|
3377
|
+
* with an API key moves a mixed-credential provider out of the OAuth band).
|
|
3378
|
+
*/
|
|
3379
|
+
#buildProviderSelectionPolicy(sessionId?: string): ProviderSelectionPolicy {
|
|
3380
|
+
const { catalogProviders, catalogModels } = buildProviderSelectionCatalog(this.#models);
|
|
3381
|
+
const effectiveAuth = new Map<string, EffectiveProviderAuth>();
|
|
3382
|
+
for (const model of this.#models) {
|
|
3383
|
+
const providerKey = model.provider.trim().toLowerCase();
|
|
3384
|
+
if (!providerKey || effectiveAuth.has(providerKey)) {
|
|
3255
3385
|
continue;
|
|
3256
3386
|
}
|
|
3257
|
-
|
|
3258
|
-
nextRank += 1;
|
|
3387
|
+
effectiveAuth.set(providerKey, this.#effectiveProviderAuth(model.provider, sessionId));
|
|
3259
3388
|
}
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3389
|
+
return createProviderSelectionPolicy({
|
|
3390
|
+
explicitProviderOrder: getConfiguredProviderOrderFromSettings(),
|
|
3391
|
+
effectiveAuth,
|
|
3392
|
+
catalogProviders,
|
|
3393
|
+
catalogModels,
|
|
3394
|
+
});
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3397
|
+
#providerRankMap(policy: ProviderSelectionPolicy): Map<string, number> {
|
|
3398
|
+
const providerRank = new Map<string, number>();
|
|
3399
|
+
for (const provider of policy.orderedProviders()) {
|
|
3400
|
+
if (!providerRank.has(provider)) {
|
|
3401
|
+
providerRank.set(provider, policy.rank(provider));
|
|
3264
3402
|
}
|
|
3265
|
-
result.set(normalized, nextRank);
|
|
3266
|
-
nextRank += 1;
|
|
3267
3403
|
}
|
|
3268
|
-
return
|
|
3404
|
+
return providerRank;
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
/** Stable model order from the registry catalog (never caller candidate order). */
|
|
3408
|
+
#catalogModelOrder(): Map<string, number> {
|
|
3409
|
+
const modelOrder = new Map<string, number>();
|
|
3410
|
+
for (let index = 0; index < this.#models.length; index += 1) {
|
|
3411
|
+
const selector = formatCanonicalVariantSelector(this.#models[index]!);
|
|
3412
|
+
if (!modelOrder.has(selector)) {
|
|
3413
|
+
modelOrder.set(selector, index);
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
return modelOrder;
|
|
3269
3417
|
}
|
|
3270
3418
|
|
|
3271
3419
|
#rememberCanonicalVariant(sessionId: string, selector: string): void {
|
|
3272
|
-
|
|
3273
|
-
|
|
3420
|
+
const normalizedSessionId = sessionId.trim();
|
|
3421
|
+
if (!normalizedSessionId) return;
|
|
3422
|
+
this.#sessionCanonicalVariants.delete(normalizedSessionId);
|
|
3423
|
+
this.#sessionCanonicalVariants.set(normalizedSessionId, selector);
|
|
3274
3424
|
if (this.#sessionCanonicalVariants.size > MAX_SESSION_CANONICAL_VARIANTS) {
|
|
3275
3425
|
this.#sessionCanonicalVariants.delete(this.#sessionCanonicalVariants.keys().next().value!);
|
|
3276
3426
|
}
|
|
3277
3427
|
}
|
|
3428
|
+
|
|
3429
|
+
/**
|
|
3430
|
+
* Resolve the winning variant among equivalent candidates. Session stickiness
|
|
3431
|
+
* wins when the remembered selector is still eligible; otherwise the variant
|
|
3432
|
+
* is ranked with provider-rank-first axis order when `providerRankFirst` is
|
|
3433
|
+
* set (alias resolution), or the legacy vision-first order by default
|
|
3434
|
+
* (canonical resolution). `exactnessKey` (the alias lookup key) replaces the
|
|
3435
|
+
* canonical-id exactness axis so `model.id === alias` beats slash-prefixed
|
|
3436
|
+
* ids before source/cost/catalog ties. Provider/model tie data always comes
|
|
3437
|
+
* from the registry catalog.
|
|
3438
|
+
*/
|
|
3278
3439
|
#resolveCanonicalVariant(
|
|
3279
3440
|
variants: readonly CanonicalModelVariant[],
|
|
3280
|
-
allCandidates: readonly Model<Api>[],
|
|
3281
3441
|
sessionId?: string,
|
|
3442
|
+
options: { providerRankFirst?: boolean; exactnessKey?: string; credentialSessionId?: string } = {},
|
|
3282
3443
|
): CanonicalModelVariant | undefined {
|
|
3283
3444
|
if (variants.length === 0) return undefined;
|
|
3284
|
-
const
|
|
3285
|
-
const
|
|
3445
|
+
const normalizedSessionId = sessionId?.trim();
|
|
3446
|
+
const stickySelector = normalizedSessionId ? this.#sessionCanonicalVariants.get(normalizedSessionId) : undefined;
|
|
3447
|
+
const stickyVariant = stickySelector
|
|
3448
|
+
? variants.find(variant => variant.selector.toLowerCase() === stickySelector.toLowerCase())
|
|
3449
|
+
: undefined;
|
|
3286
3450
|
if (stickyVariant) {
|
|
3287
|
-
this.#rememberCanonicalVariant(
|
|
3451
|
+
this.#rememberCanonicalVariant(normalizedSessionId!, stickyVariant.selector);
|
|
3288
3452
|
return stickyVariant;
|
|
3289
3453
|
}
|
|
3290
|
-
if (
|
|
3291
|
-
const
|
|
3292
|
-
const
|
|
3293
|
-
|
|
3294
|
-
modelOrder.set(formatCanonicalVariantSelector(allCandidates[index]!), index);
|
|
3295
|
-
}
|
|
3454
|
+
if (normalizedSessionId && stickySelector) this.#sessionCanonicalVariants.delete(normalizedSessionId);
|
|
3455
|
+
const policy = this.#buildProviderSelectionPolicy(options.credentialSessionId ?? normalizedSessionId);
|
|
3456
|
+
const providerRank = this.#providerRankMap(policy);
|
|
3457
|
+
const modelOrder = this.#catalogModelOrder();
|
|
3296
3458
|
const sourceRank: Record<CanonicalModelVariant["source"], number> = {
|
|
3297
3459
|
override: 1,
|
|
3298
3460
|
bundled: 1,
|
|
@@ -3301,8 +3463,10 @@ export class ModelRegistry {
|
|
|
3301
3463
|
};
|
|
3302
3464
|
return [...variants].sort((left, right) =>
|
|
3303
3465
|
compareEquivalentModelVariants(left.model, right.model, {
|
|
3466
|
+
providerRankFirst: options.providerRankFirst,
|
|
3304
3467
|
providerRank,
|
|
3305
|
-
canonicalId:
|
|
3468
|
+
canonicalId:
|
|
3469
|
+
options.exactnessKey ?? (left.canonicalId === right.canonicalId ? left.canonicalId : undefined),
|
|
3306
3470
|
leftSourceRank: sourceRank[left.source],
|
|
3307
3471
|
rightSourceRank: sourceRank[right.source],
|
|
3308
3472
|
includeCost: true,
|
|
@@ -3335,15 +3499,142 @@ export class ModelRegistry {
|
|
|
3335
3499
|
return this.#filterCanonicalVariants(record, options);
|
|
3336
3500
|
}
|
|
3337
3501
|
|
|
3502
|
+
/**
|
|
3503
|
+
* Resolve an exact canonical id to a concrete model.
|
|
3504
|
+
*
|
|
3505
|
+
* Canonical ids remain exact lookup keys, but their provider variant uses the
|
|
3506
|
+
* same provider-rank-first policy as preset aliases. Availability filtering
|
|
3507
|
+
* remains opt-in through `availableOnly`; final-segment aliases never fall
|
|
3508
|
+
* back implicitly — use {@link resolveModelByLookupAlias} for alias intent.
|
|
3509
|
+
*/
|
|
3338
3510
|
resolveCanonicalModel(canonicalId: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined {
|
|
3339
3511
|
const variants = this.getCanonicalVariants(canonicalId, options);
|
|
3340
3512
|
if (variants.length === 0) return undefined;
|
|
3341
|
-
const
|
|
3342
|
-
|
|
3513
|
+
const resolved = this.#resolveCanonicalVariant(variants, options?.sessionId, {
|
|
3514
|
+
providerRankFirst: true,
|
|
3515
|
+
credentialSessionId: options?.credentialSessionId,
|
|
3516
|
+
});
|
|
3343
3517
|
if (resolved && options?.sessionId) this.#rememberCanonicalVariant(options.sessionId, resolved.selector);
|
|
3344
3518
|
return resolved?.model;
|
|
3345
3519
|
}
|
|
3346
3520
|
|
|
3521
|
+
/**
|
|
3522
|
+
* Resolve a final-slash-segment alias to a concrete model, explicitly.
|
|
3523
|
+
*
|
|
3524
|
+
* The alias gathers every matching variant selector from the variant-level
|
|
3525
|
+
* alias index — never sibling variants in the same canonical record that end
|
|
3526
|
+
* in a different segment — then ranks all eligible variants together by the
|
|
3527
|
+
* centralized provider policy (provider-rank-first axis order), with the
|
|
3528
|
+
* canonical/exactness axis preserved relative to the alias lookup key
|
|
3529
|
+
* (`model.id === alias` beats slash-prefixed ids before source/cost/catalog
|
|
3530
|
+
* ties). Fails closed: availability/disabled filtering applies even to
|
|
3531
|
+
* supplied candidate arrays, alias variants are intersected with the
|
|
3532
|
+
* filtered candidate selectors before ranking, and zero eligible candidates
|
|
3533
|
+
* returns an authoritative `undefined` without rewriting the variant's
|
|
3534
|
+
* model/wire ids. Winners stay sticky per session.
|
|
3535
|
+
*/
|
|
3536
|
+
resolveModelByLookupAlias(alias: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined {
|
|
3537
|
+
const normalizedAlias = alias.trim().toLowerCase();
|
|
3538
|
+
const aliasSelectors = this.#canonicalIndex.aliases.get(normalizedAlias);
|
|
3539
|
+
if (!aliasSelectors || aliasSelectors.length === 0) return undefined;
|
|
3540
|
+
|
|
3541
|
+
const candidateKeys = options?.candidates
|
|
3542
|
+
? new Set(
|
|
3543
|
+
options.candidates
|
|
3544
|
+
.filter(candidate => this.#isModelAvailable(candidate))
|
|
3545
|
+
.map(candidate => formatCanonicalVariantSelector(candidate)),
|
|
3546
|
+
)
|
|
3547
|
+
: undefined;
|
|
3548
|
+
const eligible: CanonicalModelVariant[] = [];
|
|
3549
|
+
for (const aliasSelector of aliasSelectors) {
|
|
3550
|
+
const canonicalId = this.#canonicalIndex.bySelector.get(aliasSelector);
|
|
3551
|
+
if (canonicalId === undefined) continue;
|
|
3552
|
+
const record = this.#canonicalIndex.byId.get(canonicalId.trim().toLowerCase());
|
|
3553
|
+
if (!record) continue;
|
|
3554
|
+
const variant = record.variants.find(entry => entry.selector.toLowerCase() === aliasSelector);
|
|
3555
|
+
if (!variant) continue;
|
|
3556
|
+
if (candidateKeys && !candidateKeys.has(variant.selector)) continue;
|
|
3557
|
+
if (!this.#isModelAvailable(variant.model)) continue;
|
|
3558
|
+
eligible.push(variant);
|
|
3559
|
+
}
|
|
3560
|
+
if (eligible.length === 0) return undefined;
|
|
3561
|
+
|
|
3562
|
+
const resolved = this.#resolveCanonicalVariant(eligible, options?.sessionId, {
|
|
3563
|
+
providerRankFirst: true,
|
|
3564
|
+
exactnessKey: normalizedAlias,
|
|
3565
|
+
credentialSessionId: options?.credentialSessionId,
|
|
3566
|
+
});
|
|
3567
|
+
if (resolved && options?.sessionId) this.#rememberCanonicalVariant(options.sessionId, resolved.selector);
|
|
3568
|
+
return resolved?.model;
|
|
3569
|
+
}
|
|
3570
|
+
|
|
3571
|
+
/**
|
|
3572
|
+
* Whether a final-slash-segment alias is known in the current canonical
|
|
3573
|
+
* index. Knownness is decided from the full multi-target alias index and is
|
|
3574
|
+
* independent of availability: a known-but-unavailable alias still reports
|
|
3575
|
+
* `true` while {@link resolveModelByLookupAlias} returns an authoritative
|
|
3576
|
+
* `undefined`.
|
|
3577
|
+
*/
|
|
3578
|
+
lookupAliasExists(alias: string): boolean {
|
|
3579
|
+
const normalized = alias.trim().toLowerCase();
|
|
3580
|
+
return this.#canonicalIndex.aliases.has(normalized);
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
/**
|
|
3584
|
+
* Effective credential provenance for a provider, derived from existing
|
|
3585
|
+
* AuthStorage/session credential surfaces (never from token shape).
|
|
3586
|
+
* Session-specific provenance wins; API-key surfaces (runtime, config,
|
|
3587
|
+
* custom/manual, stored api_key) beat OAuth presence; OAuth remains the
|
|
3588
|
+
* provenance when it is the effective remaining stored credential;
|
|
3589
|
+
* unknown/keyless providers fall back to non-OAuth.
|
|
3590
|
+
*/
|
|
3591
|
+
getEffectiveProviderAuth(provider: string, sessionId?: string): EffectiveProviderAuth {
|
|
3592
|
+
return this.#effectiveProviderAuth(provider, sessionId);
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3595
|
+
/**
|
|
3596
|
+
* Forget a session's remembered canonical variant so the next resolution
|
|
3597
|
+
* for that session re-ranks from scratch (explicit reselection
|
|
3598
|
+
* integration). Returns whether an entry was actually removed.
|
|
3599
|
+
*/
|
|
3600
|
+
clearCanonicalVariant(sessionId: string): boolean {
|
|
3601
|
+
const scope = sessionId.trim();
|
|
3602
|
+
if (!scope) return false;
|
|
3603
|
+
return this.#sessionCanonicalVariants.delete(scope);
|
|
3604
|
+
}
|
|
3605
|
+
/**
|
|
3606
|
+
* Snapshot a session's remembered sticky canonical variant selector — the exact
|
|
3607
|
+
* concrete "provider/id" selector, captured verbatim rather than re-derived
|
|
3608
|
+
* from any live model. Returns undefined when the session has no remembered
|
|
3609
|
+
* variant. The caller owns restoring it later via
|
|
3610
|
+
* {@link restoreSessionCanonicalVariant}.
|
|
3611
|
+
*/
|
|
3612
|
+
getSessionCanonicalVariant(sessionId: string): string | undefined {
|
|
3613
|
+
const scope = sessionId.trim();
|
|
3614
|
+
if (!scope) return undefined;
|
|
3615
|
+
return this.#sessionCanonicalVariants.get(scope);
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3618
|
+
/**
|
|
3619
|
+
* Restore a session's sticky canonical variant selector exactly, preserving the
|
|
3620
|
+
* concrete provider/model previously remembered (never re-derived from a live
|
|
3621
|
+
* model). The selector must still be present in the canonical index, otherwise
|
|
3622
|
+
* the stale variant is left untouched and `false` is returned.
|
|
3623
|
+
*/
|
|
3624
|
+
restoreSessionCanonicalVariant(sessionId: string, selector: string): boolean {
|
|
3625
|
+
const scope = sessionId.trim();
|
|
3626
|
+
if (!scope) return false;
|
|
3627
|
+
const normalized = selector.trim();
|
|
3628
|
+
if (!normalized) return false;
|
|
3629
|
+
const canonicalId = this.#canonicalIndex.bySelector.get(normalized.toLowerCase());
|
|
3630
|
+
if (!canonicalId) return false;
|
|
3631
|
+
const record = this.#canonicalIndex.byId.get(canonicalId.trim().toLowerCase());
|
|
3632
|
+
const variant = record?.variants.find(candidate => candidate.selector.toLowerCase() === normalized.toLowerCase());
|
|
3633
|
+
if (!variant) return false;
|
|
3634
|
+
this.#rememberCanonicalVariant(scope, variant.selector);
|
|
3635
|
+
return true;
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3347
3638
|
getCanonicalId(model: Model<Api>): string | undefined {
|
|
3348
3639
|
return this.#canonicalIndex.bySelector.get(formatCanonicalVariantSelector(model).toLowerCase());
|
|
3349
3640
|
}
|
|
@@ -3499,6 +3790,10 @@ export class ModelRegistry {
|
|
|
3499
3790
|
return this.#keylessProviders.has(provider) || this.authStorage.hasAuth(provider);
|
|
3500
3791
|
}
|
|
3501
3792
|
|
|
3793
|
+
isCredentiallessProvider(provider: string): boolean {
|
|
3794
|
+
return this.#isCredentiallessProvider(provider);
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3502
3797
|
getDiscoverableProviders(): string[] {
|
|
3503
3798
|
const disabledProviders = getDisabledProviderIdsFromSettings();
|
|
3504
3799
|
return this.#discoveryManager.providers
|
|
@@ -3796,12 +4091,15 @@ export class ModelRegistry {
|
|
|
3796
4091
|
return this.#applyRuntimeProviderOverride(model, runtimeTransportOverride);
|
|
3797
4092
|
})
|
|
3798
4093
|
: nextModels;
|
|
4094
|
+
const withModelOverrides = this.#applyProviderModelOverrides(providerName, withRuntimeTransportOverride);
|
|
3799
4095
|
|
|
3800
4096
|
if (config.oauth?.modifyModels) {
|
|
3801
4097
|
const credential = this.authStorage.getOAuthCredential(providerName);
|
|
3802
4098
|
if (credential) {
|
|
3803
4099
|
this.#models = applyFinalCodexGpt56ContextCap(
|
|
3804
|
-
config.oauth.modifyModels(
|
|
4100
|
+
config.oauth.modifyModels(withModelOverrides, credential),
|
|
4101
|
+
undefined,
|
|
4102
|
+
this.#codexContextWindowOverrides,
|
|
3805
4103
|
);
|
|
3806
4104
|
this.#rebuildCanonicalIndex();
|
|
3807
4105
|
this.#rebuildProviderActivity();
|
|
@@ -3809,7 +4107,11 @@ export class ModelRegistry {
|
|
|
3809
4107
|
}
|
|
3810
4108
|
}
|
|
3811
4109
|
|
|
3812
|
-
this.#models = applyFinalCodexGpt56ContextCap(
|
|
4110
|
+
this.#models = applyFinalCodexGpt56ContextCap(
|
|
4111
|
+
withModelOverrides,
|
|
4112
|
+
undefined,
|
|
4113
|
+
this.#codexContextWindowOverrides,
|
|
4114
|
+
);
|
|
3813
4115
|
this.#rebuildCanonicalIndex();
|
|
3814
4116
|
this.#rebuildProviderActivity();
|
|
3815
4117
|
return;
|