import { describe, expect, it, vi } from "vitest"; const loadConfig = vi.fn(); const ensureClawdbotModelsJson = vi.fn().mockResolvedValue(undefined); const resolveClawdbotAgentDir = vi.fn().mockReturnValue("/tmp/clawdbot-agent"); const ensureAuthProfileStore = vi.fn().mockReturnValue({ version: 1, profiles: {} }); const listProfilesForProvider = vi.fn().mockReturnValue([]); const resolveAuthProfileDisplayLabel = vi.fn(({ profileId }: { profileId: string }) => profileId); const resolveAuthStorePathForDisplay = vi .fn() .mockReturnValue("/tmp/clawdbot-agent/auth-profiles.json"); const resolveProfileUnusableUntilForDisplay = vi.fn().mockReturnValue(null); const resolveEnvApiKey = vi.fn().mockReturnValue(undefined); const getCustomProviderApiKey = vi.fn().mockReturnValue(undefined); const discoverAuthStorage = vi.fn().mockReturnValue({}); const discoverModels = vi.fn(); vi.mock("../config/config.js", () => ({ CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", loadConfig, })); vi.mock("../agents/models-config.js", () => ({ ensureClawdbotModelsJson, })); vi.mock("../agents/agent-paths.js", () => ({ resolveClawdbotAgentDir, })); vi.mock("../agents/auth-profiles.js", () => ({ ensureAuthProfileStore, listProfilesForProvider, resolveAuthProfileDisplayLabel, resolveAuthStorePathForDisplay, resolveProfileUnusableUntilForDisplay, })); vi.mock("../agents/model-auth.js", () => ({ resolveEnvApiKey, getCustomProviderApiKey, })); vi.mock("@mariozechner/pi-coding-agent", () => ({ discoverAuthStorage, discoverModels, })); function makeRuntime() { return { log: vi.fn(), error: vi.fn(), }; } describe("models list/status", () => { it("models status resolves z.ai alias to canonical zai", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const { modelsStatusCommand } = await import("./models/list.js"); await modelsStatusCommand({ json: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0])); expect(payload.resolvedDefault).toBe("zai/glm-4.7"); }); it("models status plain outputs canonical zai model", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const { modelsStatusCommand } = await import("./models/list.js"); await modelsStatusCommand({ plain: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); expect(runtime.log.mock.calls[0]?.[0]).toBe("zai/glm-4.7"); }); it("models list outputs canonical zai key for configured z.ai model", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const model = { provider: "zai", id: "glm-4.7", name: "GLM-4.7", input: ["text"], baseUrl: "https://api.z.ai/v1", contextWindow: 128000, }; discoverModels.mockReturnValue({ getAll: () => [model], getAvailable: () => [model], }); const { modelsListCommand } = await import("./models/list.js"); await modelsListCommand({ json: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0])); expect(payload.models[0]?.key).toBe("zai/glm-4.7"); }); it("models list plain outputs canonical zai key", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const model = { provider: "zai", id: "glm-4.7", name: "GLM-4.7", input: ["text"], baseUrl: "https://api.z.ai/v1", contextWindow: 128000, }; discoverModels.mockReturnValue({ getAll: () => [model], getAvailable: () => [model], }); const { modelsListCommand } = await import("./models/list.js"); await modelsListCommand({ plain: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); expect(runtime.log.mock.calls[0]?.[0]).toBe("zai/glm-4.7"); }); it("models list provider filter normalizes z.ai alias", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const models = [ { provider: "zai", id: "glm-4.7", name: "GLM-4.7", input: ["text"], baseUrl: "https://api.z.ai/v1", contextWindow: 128000, }, { provider: "openai", id: "gpt-4.1-mini", name: "GPT-4.1 mini", input: ["text"], baseUrl: "https://api.openai.com/v1", contextWindow: 128000, }, ]; discoverModels.mockReturnValue({ getAll: () => models, getAvailable: () => models, }); const { modelsListCommand } = await import("./models/list.js"); await modelsListCommand({ all: true, provider: "z.ai", json: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0])); expect(payload.count).toBe(1); expect(payload.models[0]?.key).toBe("zai/glm-4.7"); }); it("models list provider filter normalizes Z.AI alias casing", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const models = [ { provider: "zai", id: "glm-4.7", name: "GLM-4.7", input: ["text"], baseUrl: "https://api.z.ai/v1", contextWindow: 128000, }, { provider: "openai", id: "gpt-4.1-mini", name: "GPT-4.1 mini", input: ["text"], baseUrl: "https://api.openai.com/v1", contextWindow: 128000, }, ]; discoverModels.mockReturnValue({ getAll: () => models, getAvailable: () => models, }); const { modelsListCommand } = await import("./models/list.js"); await modelsListCommand({ all: true, provider: "Z.AI", json: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0])); expect(payload.count).toBe(1); expect(payload.models[0]?.key).toBe("zai/glm-4.7"); }); it("models list provider filter normalizes z-ai alias", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const models = [ { provider: "zai", id: "glm-4.7", name: "GLM-4.7", input: ["text"], baseUrl: "https://api.z.ai/v1", contextWindow: 128000, }, { provider: "openai", id: "gpt-4.1-mini", name: "GPT-4.1 mini", input: ["text"], baseUrl: "https://api.openai.com/v1", contextWindow: 128000, }, ]; discoverModels.mockReturnValue({ getAll: () => models, getAvailable: () => models, }); const { modelsListCommand } = await import("./models/list.js"); await modelsListCommand({ all: true, provider: "z-ai", json: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0])); expect(payload.count).toBe(1); expect(payload.models[0]?.key).toBe("zai/glm-4.7"); }); it("models list marks auth as unavailable when ZAI key is missing", async () => { loadConfig.mockReturnValue({ agents: { defaults: { model: "z.ai/glm-4.7" } }, }); const runtime = makeRuntime(); const model = { provider: "zai", id: "glm-4.7", name: "GLM-4.7", input: ["text"], baseUrl: "https://api.z.ai/v1", contextWindow: 128000, }; discoverModels.mockReturnValue({ getAll: () => [model], getAvailable: () => [], }); const { modelsListCommand } = await import("./models/list.js"); await modelsListCommand({ all: true, json: true }, runtime); expect(runtime.log).toHaveBeenCalledTimes(1); const payload = JSON.parse(String(runtime.log.mock.calls[0]?.[0])); expect(payload.models[0]?.available).toBe(false); }); });