
























@@ -286,6 +286,44 @@ describe("handleModelsCommand", () => {
286286expect(result?.reply?.text).toContain("Switch: /model <provider/model>");
287287});
288288289+it("does not list bare fallback models under the default provider when catalog ownership is unique", async () => {
290+modelCatalogMocks.loadModelCatalog.mockResolvedValue([
291+{ provider: "openai-codex", id: "gpt-5.4", name: "GPT-5.4" },
292+{ provider: "deepseek", id: "deepseek-v4-flash", name: "DeepSeek V4 Flash" },
293+{ provider: "deepseek", id: "deepseek-v4-pro", name: "DeepSeek V4 Pro" },
294+]);
295+const cfg = {
296+agents: {
297+defaults: {
298+model: {
299+primary: "openai-codex/gpt-5.4",
300+fallbacks: ["deepseek-v4-flash", "deepseek-v4-pro"],
301+},
302+models: {
303+"openai-codex/gpt-5.4": {},
304+},
305+},
306+},
307+} satisfies Partial<OpenClawConfig>;
308+309+const defaultProviderResult = await handleModelsCommand(
310+buildParams("/models openai-codex", cfg),
311+true,
312+);
313+const deepseekResult = await handleModelsCommand(buildParams("/models deepseek", cfg), true);
314+315+expect(defaultProviderResult?.reply?.text).toContain(
316+"Models (openai-codex) — showing 1-1 of 1 (page 1/1)",
317+);
318+expect(defaultProviderResult?.reply?.text).toContain("- openai-codex/gpt-5.4");
319+expect(defaultProviderResult?.reply?.text).not.toContain("openai-codex/deepseek-v4");
320+expect(deepseekResult?.reply?.text).toContain(
321+"Models (deepseek) — showing 1-2 of 2 (page 1/1)",
322+);
323+expect(deepseekResult?.reply?.text).toContain("- deepseek/deepseek-v4-flash");
324+expect(deepseekResult?.reply?.text).toContain("- deepseek/deepseek-v4-pro");
325+});
326+289327it("keeps /models list <provider> as an alias", async () => {
290328const result = await handleModelsCommand(buildParams("/models list anthropic"), true);
291329此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。