import { describe, expect, it, vi } from "vitest"; import type { MsgContext } from "../auto-reply/templating.js"; import type { OpenClawConfig } from "../config/config.js"; import { buildProviderRegistry, createMediaAttachmentCache, normalizeMediaAttachments, runCapability, } from "./runner.js"; const catalog = [ { id: "gpt-4.1", name: "GPT-4.1", provider: "openai", input: ["text", "image"] as const, }, ]; vi.mock("../agents/model-catalog.js", async () => { const actual = await vi.importActual( "../agents/model-catalog.js", ); return { ...actual, loadModelCatalog: vi.fn(async () => catalog), }; }); describe("runCapability image skip", () => { it("skips image understanding when the active model supports vision", async () => { const ctx: MsgContext = { MediaPath: "/tmp/image.png", MediaType: "image/png" }; const media = normalizeMediaAttachments(ctx); const cache = createMediaAttachmentCache(media); const cfg = {} as OpenClawConfig; try { const result = await runCapability({ capability: "image", cfg, ctx, attachments: cache, media, providerRegistry: buildProviderRegistry(), activeModel: { provider: "openai", model: "gpt-4.1" }, }); expect(result.outputs).toHaveLength(0); expect(result.decision.outcome).toBe("skipped"); expect(result.decision.attachments).toHaveLength(1); expect(result.decision.attachments[0]?.attachmentIndex).toBe(0); expect(result.decision.attachments[0]?.attempts[0]?.outcome).toBe("skipped"); expect(result.decision.attachments[0]?.attempts[0]?.reason).toBe( "primary model supports vision natively", ); } finally { await cache.cleanup(); } }); });