@@ -127,4 +127,234 @@ describe("configured model manifest workspace scope", () => {
127127 ] ) ;
128128 expect ( loadManifestMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
129129 } ) ;
130+
131+ it ( "does not load manifest metadata for empty configured model aliases" , async ( ) => {
132+ const { buildModelAliasIndex } = await import ( "./model-selection-shared.js" ) ;
133+ const cfg = { } as unknown as OpenClawConfig ;
134+
135+ const aliases = buildModelAliasIndex ( { cfg, defaultProvider : "anthropic" } ) ;
136+
137+ expect ( aliases . byAlias . size ) . toBe ( 0 ) ;
138+ expect ( aliases . byKey . size ) . toBe ( 0 ) ;
139+ expect ( getCurrentPluginMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
140+ expect ( loadManifestMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
141+ } ) ;
142+
143+ it ( "does not load manifest metadata for wildcard-only configured model aliases" , async ( ) => {
144+ const { buildModelAliasIndex } = await import ( "./model-selection-shared.js" ) ;
145+ const cfg = {
146+ agents : {
147+ defaults : {
148+ models : {
149+ "anthropic/*" : { } ,
150+ } ,
151+ } ,
152+ } ,
153+ } as unknown as OpenClawConfig ;
154+
155+ const aliases = buildModelAliasIndex ( { cfg, defaultProvider : "anthropic" } ) ;
156+
157+ expect ( aliases . byAlias . size ) . toBe ( 0 ) ;
158+ expect ( aliases . byKey . size ) . toBe ( 0 ) ;
159+ expect ( getCurrentPluginMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
160+ expect ( loadManifestMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
161+ } ) ;
162+
163+ it ( "does not load manifest metadata for configured model entries without aliases" , async ( ) => {
164+ const { buildModelAliasIndex } = await import ( "./model-selection-shared.js" ) ;
165+ const cfg = {
166+ agents : {
167+ defaults : {
168+ models : {
169+ "anthropic/sonnet-4.6" : { } ,
170+ } ,
171+ } ,
172+ } ,
173+ } as unknown as OpenClawConfig ;
174+
175+ const aliases = buildModelAliasIndex ( { cfg, defaultProvider : "anthropic" } ) ;
176+
177+ expect ( aliases . byAlias . size ) . toBe ( 0 ) ;
178+ expect ( aliases . byKey . size ) . toBe ( 0 ) ;
179+ expect ( getCurrentPluginMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
180+ expect ( loadManifestMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
181+ } ) ;
182+
183+ it ( "does not load manifest metadata for statically resolved primary models" , async ( ) => {
184+ const { resolveConfiguredModelRef } = await import ( "./model-selection-shared.js" ) ;
185+ const cases : Array < { cfg : OpenClawConfig ; expected : { provider : string ; model : string } } > = [
186+ {
187+ cfg : {
188+ agents : { defaults : { model : { primary : "sonnet-4.6" } } } ,
189+ } as unknown as OpenClawConfig ,
190+ expected : { provider : "anthropic" , model : "sonnet-4.6" } ,
191+ } ,
192+ {
193+ cfg : {
194+ agents : { defaults : { model : { primary : "gpt-5.5" } } } ,
195+ models : { providers : { openai : { models : [ { id : "gpt-5.5" } ] } } } ,
196+ } as unknown as OpenClawConfig ,
197+ expected : { provider : "openai" , model : "gpt-5.5" } ,
198+ } ,
199+ ] ;
200+
201+ for ( const { cfg, expected } of cases ) {
202+ getCurrentPluginMetadataSnapshotMock . mockClear ( ) ;
203+ loadManifestMetadataSnapshotMock . mockClear ( ) ;
204+ expect (
205+ resolveConfiguredModelRef ( {
206+ cfg,
207+ defaultProvider : "anthropic" ,
208+ defaultModel : "claude-sonnet-4-6" ,
209+ } ) ,
210+ ) . toEqual ( expected ) ;
211+ expect ( getCurrentPluginMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
212+ expect ( loadManifestMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
213+ }
214+ } ) ;
215+
216+ it ( "does not load manifest metadata for non-alias primary models with configured aliases" , async ( ) => {
217+ const { resolveConfiguredModelRef } = await import ( "./model-selection-shared.js" ) ;
218+ const cfg = {
219+ agents : {
220+ defaults : {
221+ model : { primary : "haiku-4.6" } ,
222+ models : {
223+ "anthropic/sonnet-4.6" : { alias : "sonnet" } ,
224+ } ,
225+ } ,
226+ } ,
227+ } as unknown as OpenClawConfig ;
228+
229+ expect (
230+ resolveConfiguredModelRef ( {
231+ cfg,
232+ defaultProvider : "anthropic" ,
233+ defaultModel : "claude-sonnet-4-6" ,
234+ } ) ,
235+ ) . toEqual ( { provider : "anthropic" , model : "haiku-4.6" } ) ;
236+ expect ( getCurrentPluginMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
237+ expect ( loadManifestMetadataSnapshotMock ) . not . toHaveBeenCalled ( ) ;
238+ } ) ;
239+
240+ it ( "uses manifest-normalized configured refs to infer providers for bare defaults" , async ( ) => {
241+ loadManifestMetadataSnapshotMock . mockReturnValue ( {
242+ plugins : [
243+ {
244+ modelIdNormalization : {
245+ providers : {
246+ anthropic : {
247+ aliases : {
248+ "sonnet-4.6" : "claude-sonnet-4-6" ,
249+ } ,
250+ } ,
251+ } ,
252+ } ,
253+ } ,
254+ ] ,
255+ } ) ;
256+ const { resolveConfiguredModelRef } = await import ( "./model-selection-shared.js" ) ;
257+ const cfg = {
258+ agents : {
259+ defaults : {
260+ model : { primary : "claude-sonnet-4-6" } ,
261+ models : {
262+ "anthropic/sonnet-4.6" : { } ,
263+ } ,
264+ } ,
265+ } ,
266+ } as unknown as OpenClawConfig ;
267+
268+ expect (
269+ resolveConfiguredModelRef ( {
270+ cfg,
271+ defaultProvider : "openai" ,
272+ defaultModel : "gpt-5.4" ,
273+ } ) ,
274+ ) . toEqual ( { provider : "anthropic" , model : "claude-sonnet-4-6" } ) ;
275+ expect ( loadManifestMetadataSnapshotMock ) . toHaveBeenCalledTimes ( 1 ) ;
276+ } ) ;
277+
278+ it ( "reuses resolved manifest plugins while resolving configured model aliases" , async ( ) => {
279+ loadManifestMetadataSnapshotMock . mockReturnValue ( {
280+ plugins : [
281+ {
282+ modelIdNormalization : {
283+ providers : {
284+ anthropic : {
285+ aliases : {
286+ "sonnet-4.6" : "claude-sonnet-4-6" ,
287+ } ,
288+ } ,
289+ openrouter : {
290+ prefixWhenBare : "openrouter" ,
291+ } ,
292+ } ,
293+ } ,
294+ } ,
295+ ] ,
296+ } ) ;
297+ const { resolveConfiguredModelRef } = await import ( "./model-selection-shared.js" ) ;
298+ const cfg = {
299+ agents : {
300+ defaults : {
301+ model : { primary : "router-auto" } ,
302+ models : {
303+ "anthropic/sonnet-4.6" : { alias : "sonnet" } ,
304+ "openrouter:auto" : { alias : "router-auto" } ,
305+ } ,
306+ } ,
307+ } ,
308+ } as unknown as OpenClawConfig ;
309+
310+ expect (
311+ resolveConfiguredModelRef ( {
312+ cfg,
313+ defaultProvider : "anthropic" ,
314+ defaultModel : "claude-sonnet-4-6" ,
315+ } ) ,
316+ ) . toEqual ( { provider : "openrouter" , model : "openrouter/auto" } ) ;
317+ expect ( loadManifestMetadataSnapshotMock ) . toHaveBeenCalledTimes ( 1 ) ;
318+ } ) ;
319+
320+ it ( "reuses resolved manifest plugins while resolving direct primary models" , async ( ) => {
321+ loadManifestMetadataSnapshotMock . mockReturnValue ( {
322+ plugins : [
323+ {
324+ modelIdNormalization : {
325+ providers : {
326+ anthropic : {
327+ aliases : {
328+ "sonnet-4.6" : "claude-sonnet-4-6" ,
329+ } ,
330+ } ,
331+ openrouter : {
332+ prefixWhenBare : "openrouter" ,
333+ } ,
334+ } ,
335+ } ,
336+ } ,
337+ ] ,
338+ } ) ;
339+ const { resolveConfiguredModelRef } = await import ( "./model-selection-shared.js" ) ;
340+ const cfg = {
341+ agents : {
342+ defaults : {
343+ model : { primary : "openrouter:auto" } ,
344+ models : {
345+ "anthropic/sonnet-4.6" : { alias : "sonnet" } ,
346+ } ,
347+ } ,
348+ } ,
349+ } as unknown as OpenClawConfig ;
350+
351+ expect (
352+ resolveConfiguredModelRef ( {
353+ cfg,
354+ defaultProvider : "anthropic" ,
355+ defaultModel : "claude-sonnet-4-6" ,
356+ } ) ,
357+ ) . toEqual ( { provider : "openrouter" , model : "openrouter/auto" } ) ;
358+ expect ( loadManifestMetadataSnapshotMock ) . toHaveBeenCalledTimes ( 1 ) ;
359+ } ) ;
130360} ) ;
0 commit comments