src/vs/workbench/contrib/chat/common/modelSelection.ts

382 LOC · 325 covered · 57 uncovered · 79 ranges · 39 concepts · 35 introducers · 16 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/workbench/contrib/chat/common/languageModels.ts · 2510 LOCcommon/languageModels.tsmodelSelection.ts ×1 · 2 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 2 introduced LOCmodelSelection.ts ×1modelSelection.ts ×2 · 11 introduced LOCmodelSelection.ts ×2modelSelection.test|title=ModelSelection configured default applies to fresh conversations but not restored drafts or existing sessions|occurrence=1 · 0 introduced LOCmodelSelection.test|titl…modelSelection.test|title=ModelSelection falls back when a configured model is inapplicable to an authoritative provider pool|occurrence=1 · 0 introduced LOCmodelSelection.test|titl…modelSelection.ts ×4 · 6 introduced LOCmodelSelection.ts ×4modelSelection.test|title=ModelSelection same-chat automatic selection still upgrades to the configured default|occurrence=1 · 0 introduced LOCmodelSelection.test|titl…modelSelection.ts ×2 · 4 introduced LOCmodelSelection.ts ×2modelSelection.test|title=ModelSelection a new conversation reapplies the configured default after an explicit selection|occurrence=1 · 0 introduced LOCmodelSelection.test|titl…modelSelection.ts ×2 · 12 introduced LOCmodelSelection.ts ×2modelSelection.ts ×1 · 2 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 3 introduced LOCmodelSelection.ts ×1modelSelection.ts ×2 · 3 introduced LOCmodelSelection.ts ×2modelSelection.ts ×2 · 11 introduced LOCmodelSelection.ts ×2modelSelection.ts ×1 · 1 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 9 introduced LOCmodelSelection.ts ×1modelSelection.ts ×2 · 4 introduced LOCmodelSelection.ts ×2modelSelection.ts ×1 · 4 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 9 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 1 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 1 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 1 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 1 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 1 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 1 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 2 introduced LOCmodelSelection.ts ×1modelSelection.ts ×1 · 8 introduced LOCmodelSelection.ts ×1modelSelection.ts ×2 · 25 introduced LOCmodelSelection.ts ×2modelSelection.ts ×11 · 22 introduced LOCmodelSelection.ts ×11modelSelection.ts ×4 · 18 introduced LOCmodelSelection.ts ×4modelSelection.ts ×1 · 2 introduced LOCmodelSelection.ts ×1modelSelection.ts ×2 · 4 introduced LOCmodelSelection.ts ×2modelSelection.ts ×2 · 4 introduced LOCmodelSelection.ts ×2modelSelection.ts ×1 · 2 introduced LOCmodelSelection.ts ×1modelSelection.ts ×2 · 4 introduced LOCmodelSelection.ts ×2modelSelection.ts ×5 · 6 introduced LOCmodelSelection.ts ×5modelSelection.ts ×4 · 11 introduced LOCmodelSelection.ts ×4modelSelection.ts ×3 · 13 introduced LOCmodelSelection.ts ×3modelSelection.ts ×10 · 117 introduced LOCmodelSelection.ts ×10modelSelection.test|title=ModelSelection a new conversation reapplies the configured default after an explicit selection|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection a new conversation reapplies the configured default after an explicit selection|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection configured default applies to fresh conversations but not restored drafts or existing sessions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection configured default applies to fresh conversations but not restored drafts or existing sessions|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection does not reapply an unchanged configured model for the same chat|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection does not reapply an unchanged configured model for the same chat|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection falls back when a configured model is inapplicable to an authoritative provider pool|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection falls back when a configured model is inapplicable to an authoritative provider pool|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection preserves pending restoration for an empty existing-session catalog|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection preserves pending restoration for an empty existing-session catalog|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection repairs a stale current model while other models remain available|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection repairs a stale current model while other models remain available|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection resets on scope change, clears empty pools, and re-pushes reused chats|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection resets on scope change, clears empty pools, and re-pushes reused chats|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection resolves configured model ids, families, and auto|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection resolves configured model ids, families, and auto|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection resolves identifier availability states|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection resolves identifier availability states|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection restores, waits for, and repairs existing-session models|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection restores, waits for, and repairs existing-session models|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection same-chat automatic selection still upgrades to the configured default|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection same-chat automatic selection still upgrades to the configured default|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection shares configured, desired, pending, then fallback precedence|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection shares configured, desired, pending, then fallback precedence|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection switching untitled drafts for the same provider restores the incoming draft model|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection switching untitled drafts for the same provider restores the incoming draft model|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection treats a resolved-but-empty agent-host vendor as still loading (pending)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection treats a resolved-but-empty agent-host vendor as still loading (pending)|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection uses shared vendor readiness for empty and live catalogs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection uses shared vendor readiness for empty and live catalogs|occurrence=1modelSelection.test|titl…modelSelection.test|title=ModelSelection uses the same new-conversation policy for configured, remembered, pending, and fallback models|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/modelSelection.test|title=ModelSelection uses the same new-conversation policy for configured, remembered, pending, and fallback models|occurrence=1modelSelection.test|titl…Focused file · src/vs/workbench/contrib/chat/common/modelSelection.ts · 382 LOCcommon/modelSelection.ts

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- modelSelection.ts ×10
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ILanguageModelChatMetadataAndIdentifier, ILanguageModelsService, isLanguageModelVendorAbsenceConclusive } from './languageModels.js';
7 > import { isAgentHostTarget } from './chatSessionsService.js';
8 >
9 > export type ModelIdentifierResolution =
10 > | { readonly kind: 'notRequested' }
11 > | { readonly kind: 'pending'; readonly identifier: string }
12 > | { readonly kind: 'available'; readonly model: ILanguageModelChatMetadataAndIdentifier }
13 > | { readonly kind: 'unavailable'; readonly identifier: string };
14 >
15 > export interface IModelVendorResolution {
16 > hasLiveModels(vendor: string): boolean;
17 > hasResolved(vendor: string): boolean;
18 > }
19 >
20 > /** Resolves a requested model identifier against the current model catalog. */
21 > export function resolveModelIdentifier(
22 > models: readonly ILanguageModelChatMetadataAndIdentifier[], modelSelection.ts ×3
23 > identifier: string | undefined,
24 > isAbsenceConclusive: boolean,
25 > ): ModelIdentifierResolution {
26 > if (!identifier) {
27 > return { kind: 'notRequested' }; modelSelection.ts ×2
28 > }
30 > const model = models.find(model => model.identifier === identifier);
31 > if (model) {
32 > return { kind: 'available', model }; modelSelection.ts ×2
33 > }
35 > return isAbsenceConclusive
36 > ? { kind: 'unavailable', identifier }
37 > : { kind: 'pending', identifier };
38 > }
40 > /** Resolves a model identifier using vendor-level catalog readiness. */
41 > export function resolveModelIdentifierFromCatalog(
42 > models: readonly ILanguageModelChatMetadataAndIdentifier[], modelSelection.ts ×2
43 > identifier: string | undefined,
44 > vendorResolution: IModelVendorResolution,
45 > ): ModelIdentifierResolution {
46 > if (!identifier) {
47 return { kind: 'notRequested' };
48 }
50 > const separator = identifier.search(/[/:]/);
51 > const vendor = separator === -1 ? undefined : identifier.substring(0, separator);
52 > const hasLive = vendor ? vendorResolution.hasLiveModels(vendor) : false;
53 > // Agent-host vendors publish their models asynchronously after the agent host connects, so an
54 > // empty (not-yet-populated) list is transient: keep the remembered/restored model `pending`
55 > // (wait) rather than `unavailable` (give up). Once the vendor HAS live models, an absent model
56 > // is genuinely gone, so stay conclusive. This grace is scoped to restore *resolution* only —
57 > // cache-retention (`mergeModelsWithCache`) and send-availability keep treating a resolved-empty
58 > // list as authoritative. The vendor id equals the session type for agent-host models, so
59 > // `isAgentHostTarget` classifies it directly.
60 > const isAbsenceConclusive = !vendor || (isLanguageModelVendorAbsenceConclusive(
61 > vendor,
62 > hasLive,
63 > vendorResolution.hasResolved(vendor),
64 > ) && (hasLive || !isAgentHostTarget(vendor)));
65 > return resolveModelIdentifier(models, identifier, isAbsenceConclusive);
66 > }
68 > export function getRegisteredLanguageModels(languageModelsService: Pick<ILanguageModelsService, 'getLanguageModelIds' | 'lookupLanguageModel'>): ILanguageModelChatMetadataAndIdentifier[] {
69 return languageModelsService.getLanguageModelIds()
70 .map(identifier => {
71 const metadata = languageModelsService.lookupLanguageModel(identifier);
72 return metadata ? { identifier, metadata } : undefined;
73 })
74 .filter(model => model !== undefined);
75 }
77 > export function resolveModelIdentifierFromLanguageModels(
78 models: readonly ILanguageModelChatMetadataAndIdentifier[],
79 identifier: string | undefined,
80 languageModelsService: Pick<ILanguageModelsService, 'hasResolvedVendor'>,
81 allModels: readonly ILanguageModelChatMetadataAndIdentifier[],
82 ): ModelIdentifierResolution {
83 const liveVendors = new Set(allModels.map(model => model.metadata.vendor));
84 return resolveModelIdentifierFromCatalog(models, identifier, {
85 hasLiveModels: vendor => liveVendors.has(vendor),
86 hasResolved: vendor => languageModelsService.hasResolvedVendor(vendor),
87 });
88 }
90 > const AUTO_MODEL_ID = 'auto';
91 >
92 > function compareModelVersions(a: string | undefined, b: string | undefined): number { modelSelection.ts ×4
93 > const rawA = a ?? '';
94 > const rawB = b ?? '';
95 > const segmentsA = rawA.match(/\d+/g)?.map(Number) ?? [];
96 > const segmentsB = rawB.match(/\d+/g)?.map(Number) ?? [];
97 > const length = Math.max(segmentsA.length, segmentsB.length);
98 > for (let index = 0; index < length; index++) {
99 > const numberA = segmentsA[index] ?? 0;
100 > const numberB = segmentsB[index] ?? 0;
101 > if (numberA !== numberB) {
102 > return numberA - numberB;
103 > }
104 > }
105 return rawA.localeCompare(rawB);
106 }
108 > /** Resolves a configured model id, family, or `auto` value against a model pool. */
109 > export function resolveConfiguredModel(
110 > configuredValue: string | undefined, modelSelection.ts ×4
111 > models: readonly ILanguageModelChatMetadataAndIdentifier[],
112 > ): ILanguageModelChatMetadataAndIdentifier | undefined {
113 > const value = configuredValue?.trim().toLowerCase();
114 > if (!value) {
115 > return undefined; modelSelection.ts ×4
116 > }
118 > if (value === AUTO_MODEL_ID) {
119 > return models.find(model => model.metadata.id?.trim().toLowerCase() === AUTO_MODEL_ID); modelSelection.ts ×4
120 > }
122 > const byId = models.find(model => model.metadata.id?.trim().toLowerCase() === value);
123 > if (byId) {
124 > return byId; modelSelection.ts ×1
125 > }
127 > const family = models.filter(model => model.metadata.family?.trim().toLowerCase() === value);
128 > return family.length > 0
129 > ? family.reduce((latest, candidate) => compareModelVersions(candidate.metadata.version, latest.metadata.version) > 0 ? candidate : latest) modelSelection.ts ×4
130 > : undefined; modelSelection.ts ×2
133 > export const enum ModelSelectionReason {
134 > ConfiguredDefault = 'configuredDefault',
135 > FirstAvailable = 'firstAvailable',
136 > NoModels = 'noModels',
137 > ProgrammaticSelection = 'programmaticSelection',
138 > Remembered = 'remembered',
139 > RemovedModelFallback = 'removedModelFallback',
140 > SessionRestore = 'sessionRestore',
141 > NewChatRepush = 'newChatRepush',
142 > UserSelection = 'userSelection',
143 > }
144 >
145 > export type ModelSelectionApplyReason = Exclude<ModelSelectionReason, ModelSelectionReason.NoModels>;
146 >
147 > export function isAuthoritativeModelSelectionReason(reason: ModelSelectionApplyReason | undefined): boolean {
148 > return reason === ModelSelectionReason.ProgrammaticSelection modelSelection.ts ×1
149 > || reason === ModelSelectionReason.SessionRestore
150 > || reason === ModelSelectionReason.UserSelection;
151 > }
153 > export interface IPendingModelSelection {
154 > readonly reference: string;
155 > }
156 >
157 > export type InitialModelSelectionResult =
158 > | { readonly kind: 'none' }
159 > | { readonly kind: 'pending'; readonly selection: IPendingModelSelection }
160 > | { readonly kind: 'apply'; readonly model: ILanguageModelChatMetadataAndIdentifier; readonly reason: ModelSelectionApplyReason };
161 >
162 > export interface IInitialModelSelectionInput {
163 > readonly configuredModel: ILanguageModelChatMetadataAndIdentifier | undefined;
164 > readonly desiredModelResolution: ModelIdentifierResolution;
165 > readonly desiredReason: ModelSelectionReason.SessionRestore | ModelSelectionReason.Remembered;
166 > readonly fallbackModel: ILanguageModelChatMetadataAndIdentifier | undefined;
167 > readonly fallbackReason: ModelSelectionReason.FirstAvailable | ModelSelectionReason.RemovedModelFallback;
168 > }
169 >
170 > /** Applies the shared configured, desired, pending, then fallback precedence. */
171 > export function resolveInitialModelSelection(input: IInitialModelSelectionInput): InitialModelSelectionResult {
172 > if (input.configuredModel) { modelSelection.ts ×5
173 > return { kind: 'apply', model: input.configuredModel, reason: ModelSelectionReason.ConfiguredDefault }; modelSelection.ts ×1
174 > }
175 > if (input.desiredModelResolution.kind === 'available') { modelSelection.ts ×5
176 > return { kind: 'apply', model: input.desiredModelResolution.model, reason: input.desiredReason }; modelSelection.ts ×2
177 > }
178 > if (input.desiredModelResolution.kind === 'pending') { modelSelection.ts ×5
179 > return { kind: 'pending', selection: { reference: input.desiredModelResolution.identifier } }; modelSelection.ts ×2
180 > }
181 > return input.fallbackModel modelSelection.ts ×5
182 > ? { kind: 'apply', model: input.fallbackModel, reason: input.fallbackReason }
183 : { kind: 'none' };
186 > export type ModelSelectionEffect =
187 > | { readonly kind: 'none' }
188 > | { readonly kind: 'clear'; readonly reason: ModelSelectionReason.NoModels | ModelSelectionReason.SessionRestore }
189 > | { readonly kind: 'apply'; readonly model: ILanguageModelChatMetadataAndIdentifier; readonly reason: ModelSelectionApplyReason };
190 >
191 > export type IModelSelectionSessionContext =
192 > | { readonly kind: 'none' }
193 > | {
194 > readonly kind: 'untitled' | 'existing';
195 > readonly key: string;
196 > readonly chatKey: string | undefined;
197 > readonly modelId: string | undefined;
198 > };
199 >
200 > export interface IModelSelectionModelsContext {
201 > readonly available: readonly ILanguageModelChatMetadataAndIdentifier[];
202 > readonly configuredModel: string | undefined;
203 > readonly rememberedModelId: string | undefined;
204 > readonly desiredModelResolution: ModelIdentifierResolution;
205 > readonly fallbackModel: ILanguageModelChatMetadataAndIdentifier | undefined;
206 > }
207 >
208 > export interface IModelSelectionMemory {
209 > readonly sessionKey: string | undefined;
210 > readonly lastPushedChatKey: string | undefined;
211 > readonly currentModel: ILanguageModelChatMetadataAndIdentifier | undefined;
212 > readonly currentReason: ModelSelectionApplyReason | undefined;
213 > }
214 >
215 > export interface IModelSelectionTransitionInput {
216 > readonly session: IModelSelectionSessionContext;
217 > readonly models: IModelSelectionModelsContext;
218 > readonly previous: IModelSelectionMemory;
219 > }
220 >
221 > export interface IModelSelectionTransitionResult {
222 > readonly currentModel: ILanguageModelChatMetadataAndIdentifier | undefined;
223 > readonly currentReason: ModelSelectionApplyReason | undefined;
224 > readonly pendingSelection: IPendingModelSelection | undefined;
225 > readonly effect: ModelSelectionEffect;
226 > readonly sessionKey: string | undefined;
227 > readonly lastPushedChatKey: string | undefined;
228 > }
229 >
230 > export function transitionModelSelection(input: IModelSelectionTransitionInput): IModelSelectionTransitionResult {
231 > const { session, models, previous } = input; modelSelection.ts ×11
232 > const sessionKey = session.kind === 'none' ? undefined : session.key;
233 > const chatKey = session.kind === 'none' ? undefined : session.chatKey;
234 > const sessionModelId = session.kind === 'none' ? undefined : session.modelId;
235 > const sessionChanged = sessionKey !== previous.sessionKey;
236 > const currentModel = sessionChanged ? undefined : previous.currentModel;
237 > const currentReason = sessionChanged ? undefined : previous.currentReason;
238 > const sessionModel = sessionModelId ? models.available.find(model => model.identifier === sessionModelId) : undefined;
239 > const fallbackModel = models.available.find(model => model.identifier === models.rememberedModelId) ?? models.fallbackModel;
240 > const newConversation = session.kind === 'untitled' && !sessionChanged && chatKey !== previous.lastPushedChatKey;
241 > const automaticSelection = currentReason === ModelSelectionReason.ConfiguredDefault
242 > || currentReason === ModelSelectionReason.FirstAvailable
243 > || currentReason === ModelSelectionReason.Remembered modelSelection.ts ×1
244 > || currentReason === ModelSelectionReason.NewChatRepush;
245 > const configuredModelValue = session.kind === 'untitled' modelSelection.ts ×11
246 > && (newConversation modelSelection.ts ×1
247 > || (!newConversation && (!sessionModelId || automaticSelection) && !isAuthoritativeModelSelectionReason(currentReason))) modelSelection.ts ×1
248 > ? models.configuredModel modelSelection.ts ×1
249 > : undefined; modelSelection.ts ×1
250 > const configuredModel = configuredModelValue modelSelection.ts ×11
251 > ? resolveConfiguredModel(models.configuredModel, models.available) modelSelection.ts ×1
252 > : undefined; modelSelection.ts ×1
253 > if (configuredModel) { modelSelection.ts ×11
254 > if (chatKey === previous.lastPushedChatKey && currentReason === ModelSelectionReason.ConfiguredDefault && currentModel?.identifier === configuredModel.identifier) { modelSelection.ts ×2
255 > return { currentModel, currentReason, pendingSelection: undefined, effect: { kind: 'none' }, sessionKey, lastPushedChatKey: previous.lastPushedChatKey }; modelSelection.ts ×1
256 > }
257 > return applyResult(sessionKey, chatKey, configuredModel, ModelSelectionReason.ConfiguredDefault); modelSelection.ts ×2
258 > }
259 > if (session.kind === 'existing' && models.desiredModelResolution.kind === 'pending') { modelSelection.ts ×11
260 > return { modelSelection.ts ×1
261 > currentModel: undefined,
262 > currentReason: undefined,
263 > pendingSelection: { reference: models.desiredModelResolution.identifier },
264 > effect: currentModel ? { kind: 'clear', reason: ModelSelectionReason.SessionRestore } : { kind: 'none' },
265 > sessionKey,
266 > lastPushedChatKey: chatKey,
267 > };
268 > }
269 > if (!currentModel && session.kind === 'untitled' && sessionModel) { modelSelection.ts ×11
270 > return { modelSelection.ts ×1
271 > currentModel: sessionModel,
272 > currentReason: ModelSelectionReason.SessionRestore,
273 > pendingSelection: undefined,
274 > effect: { kind: 'none' },
275 > sessionKey,
276 > lastPushedChatKey: chatKey,
277 > };
278 > }
280 > if (!currentModel && session.kind === 'untitled') { modelSelection.ts ×11
281 > const initial = resolveInitialModelSelection({ modelSelection.ts ×2
282 > configuredModel,
283 > desiredModelResolution: models.desiredModelResolution,
284 > desiredReason: sessionModelId ? ModelSelectionReason.SessionRestore : ModelSelectionReason.Remembered,
285 > fallbackModel,
286 > fallbackReason: ModelSelectionReason.FirstAvailable,
287 > });
288 > if (initial.kind === 'pending') {
289 > return { currentModel: undefined, currentReason: undefined, pendingSelection: initial.selection, effect: { kind: 'none' }, sessionKey, lastPushedChatKey: previous.lastPushedChatKey }; modelSelection.ts ×1
290 > }
291 > if (initial.kind === 'apply') { modelSelection.ts ×2
292 > return applyResult(sessionKey, chatKey, initial.model, initial.reason);
293 > }
294 > }
296 > if (models.available.length === 0) {
297 > return { modelSelection.ts ×2
298 > currentModel: undefined,
299 > currentReason: undefined,
300 > pendingSelection: undefined,
301 > effect: currentModel ? { kind: 'clear', reason: ModelSelectionReason.NoModels } : { kind: 'none' },
302 > sessionKey,
303 > lastPushedChatKey: previous.lastPushedChatKey,
304 > };
305 > }
307 > if (session.kind === 'existing') {
308 > if (sessionModel) { modelSelection.ts ×2
309 > return {
310 > currentModel: sessionModel,
311 > currentReason: ModelSelectionReason.SessionRestore,
312 > pendingSelection: undefined,
313 > effect: { kind: 'none' },
314 > sessionKey,
315 > lastPushedChatKey: chatKey,
316 > };
317 > }
318 > if (fallbackModel) { modelSelection.ts ×1
319 > return applyResult(sessionKey, chatKey, fallbackModel, sessionModelId ? ModelSelectionReason.RemovedModelFallback : ModelSelectionReason.FirstAvailable);
320 > }
323 > const currentModelAvailable = !!currentModel && models.available.some(model => model.identifier === currentModel.identifier);
324 > if (currentModel && !currentModelAvailable) { modelSelection.ts ×11
325 > if (models.desiredModelResolution.kind === 'pending') { modelSelection.ts ×2
326 return {
327 currentModel: undefined,
328 currentReason: undefined,
329 pendingSelection: { reference: models.desiredModelResolution.identifier },
330 effect: { kind: 'clear', reason: ModelSelectionReason.SessionRestore },
331 sessionKey,
332 lastPushedChatKey: previous.lastPushedChatKey,
333 };
334 }
335 > if (fallbackModel) { modelSelection.ts ×2
336 > return applyResult(sessionKey, chatKey, fallbackModel, ModelSelectionReason.RemovedModelFallback);
337 > }
338 return {
339 currentModel: undefined,
340 currentReason: undefined,
341 pendingSelection: undefined,
342 effect: { kind: 'clear', reason: ModelSelectionReason.NoModels },
343 sessionKey,
344 lastPushedChatKey: previous.lastPushedChatKey,
345 };
346 }
348 > if (session.kind === 'untitled' && currentModel && currentReason === ModelSelectionReason.FirstAvailable) { modelSelection.ts ×11
349 const initial = resolveInitialModelSelection({
350 configuredModel,
351 desiredModelResolution: models.desiredModelResolution,
352 desiredReason: ModelSelectionReason.Remembered,
353 fallbackModel,
354 fallbackReason: ModelSelectionReason.FirstAvailable,
355 });
356 if (initial.kind === 'pending') {
357 return { currentModel: undefined, currentReason: undefined, pendingSelection: initial.selection, effect: { kind: 'clear', reason: ModelSelectionReason.SessionRestore }, sessionKey, lastPushedChatKey: previous.lastPushedChatKey };
358 }
359 if (initial.kind === 'apply' && initial.model.identifier !== currentModel.identifier) {
360 return applyResult(sessionKey, chatKey, initial.model, initial.reason);
361 }
362 }
364 > if (sessionModel && currentModel && sessionModel.identifier !== currentModel.identifier) { modelSelection.ts ×11
365 return { currentModel: sessionModel, currentReason: ModelSelectionReason.SessionRestore, pendingSelection: undefined, effect: { kind: 'none' }, sessionKey, lastPushedChatKey: chatKey };
366 }
368 > if (session.kind === 'untitled' && chatKey !== previous.lastPushedChatKey && currentModel && models.available.some(model => model.identifier === currentModel.identifier)) { modelSelection.ts ×11
369 > return applyResult(sessionKey, chatKey, currentModel, ModelSelectionReason.NewChatRepush); modelSelection.ts ×2
370 > }
372 > return { currentModel, currentReason, pendingSelection: undefined, effect: { kind: 'none' }, sessionKey, lastPushedChatKey: previous.lastPushedChatKey };
373 > }
375 > function applyResult( modelSelection.ts ×1
376 > sessionKey: string | undefined,
377 > chatKey: string | undefined,
378 > model: ILanguageModelChatMetadataAndIdentifier,
379 > reason: ModelSelectionApplyReason,
380 > ): IModelSelectionTransitionResult {
381 > return { currentModel: model, currentReason: reason, pendingSelection: undefined, effect: { kind: 'apply', model, reason }, sessionKey, lastPushedChatKey: chatKey };
382 > }