





















@@ -127,4 +127,234 @@ describe("configured model manifest workspace scope", () => {
127127]);
128128expect(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});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。