diff --git a/src/agents/tools/pdf-tool.model-config.test.ts b/src/agents/tools/pdf-tool.model-config.test.ts index b6f24287763..90668dc0007 100644 --- a/src/agents/tools/pdf-tool.model-config.test.ts +++ b/src/agents/tools/pdf-tool.model-config.test.ts @@ -1,35 +1,10 @@ -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../../config/config.js"; import { resolvePdfModelConfigForTool } from "./pdf-tool.model-config.js"; +import { resetPdfToolAuthEnv, withTempPdfAgentDir } from "./pdf-tool.test-support.js"; const ANTHROPIC_PDF_MODEL = "anthropic/claude-opus-4-6"; -async function withTempAgentDir(run: (agentDir: string) => Promise): Promise { - const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-pdf-")); - try { - return await run(agentDir); - } finally { - await fs.rm(agentDir, { recursive: true, force: true }); - } -} - -function resetAuthEnv() { - vi.stubEnv("OPENAI_API_KEY", ""); - vi.stubEnv("ANTHROPIC_API_KEY", ""); - vi.stubEnv("ANTHROPIC_OAUTH_TOKEN", ""); - vi.stubEnv("GEMINI_API_KEY", ""); - vi.stubEnv("GOOGLE_API_KEY", ""); - vi.stubEnv("MINIMAX_API_KEY", ""); - vi.stubEnv("ZAI_API_KEY", ""); - vi.stubEnv("Z_AI_API_KEY", ""); - vi.stubEnv("COPILOT_GITHUB_TOKEN", ""); - vi.stubEnv("GH_TOKEN", ""); - vi.stubEnv("GITHUB_TOKEN", ""); -} - function withDefaultModel(primary: string): OpenClawConfig { return { agents: { defaults: { model: { primary } } }, @@ -38,7 +13,7 @@ function withDefaultModel(primary: string): OpenClawConfig { describe("resolvePdfModelConfigForTool", () => { beforeEach(() => { - resetAuthEnv(); + resetPdfToolAuthEnv(); }); afterEach(() => { @@ -46,14 +21,14 @@ describe("resolvePdfModelConfigForTool", () => { }); it("returns null without any auth", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { const cfg = withDefaultModel("openai/gpt-5.4"); expect(resolvePdfModelConfigForTool({ cfg, agentDir })).toBeNull(); }); }); it("prefers explicit pdfModel config", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { const cfg = { agents: { defaults: { @@ -69,7 +44,7 @@ describe("resolvePdfModelConfigForTool", () => { }); it("falls back to imageModel config when no pdfModel set", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { const cfg = { agents: { defaults: { @@ -85,7 +60,7 @@ describe("resolvePdfModelConfigForTool", () => { }); it("prefers anthropic when available for native PDF support", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { vi.stubEnv("ANTHROPIC_API_KEY", "anthropic-test"); vi.stubEnv("OPENAI_API_KEY", "openai-test"); const cfg = withDefaultModel("openai/gpt-5.4"); @@ -94,7 +69,7 @@ describe("resolvePdfModelConfigForTool", () => { }); it("uses anthropic primary when provider is anthropic", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { vi.stubEnv("ANTHROPIC_API_KEY", "anthropic-test"); const cfg = withDefaultModel(ANTHROPIC_PDF_MODEL); expect(resolvePdfModelConfigForTool({ cfg, agentDir })?.primary).toBe(ANTHROPIC_PDF_MODEL); diff --git a/src/agents/tools/pdf-tool.test-support.ts b/src/agents/tools/pdf-tool.test-support.ts new file mode 100644 index 00000000000..cacb4e91011 --- /dev/null +++ b/src/agents/tools/pdf-tool.test-support.ts @@ -0,0 +1,27 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { vi } from "vitest"; + +export async function withTempPdfAgentDir(run: (agentDir: string) => Promise): Promise { + const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-pdf-")); + try { + return await run(agentDir); + } finally { + await fs.rm(agentDir, { recursive: true, force: true }); + } +} + +export function resetPdfToolAuthEnv(): void { + vi.stubEnv("OPENAI_API_KEY", ""); + vi.stubEnv("ANTHROPIC_API_KEY", ""); + vi.stubEnv("ANTHROPIC_OAUTH_TOKEN", ""); + vi.stubEnv("GEMINI_API_KEY", ""); + vi.stubEnv("GOOGLE_API_KEY", ""); + vi.stubEnv("MINIMAX_API_KEY", ""); + vi.stubEnv("ZAI_API_KEY", ""); + vi.stubEnv("Z_AI_API_KEY", ""); + vi.stubEnv("COPILOT_GITHUB_TOKEN", ""); + vi.stubEnv("GH_TOKEN", ""); + vi.stubEnv("GITHUB_TOKEN", ""); +} diff --git a/src/agents/tools/pdf-tool.test.ts b/src/agents/tools/pdf-tool.test.ts index 2d8adc7e176..e58dee5848b 100644 --- a/src/agents/tools/pdf-tool.test.ts +++ b/src/agents/tools/pdf-tool.test.ts @@ -9,6 +9,7 @@ import * as modelAuth from "../model-auth.js"; import * as modelsConfig from "../models-config.js"; import * as modelDiscovery from "../pi-model-discovery.js"; import * as pdfNativeProviders from "./pdf-native-providers.js"; +import { resetPdfToolAuthEnv, withTempPdfAgentDir } from "./pdf-tool.test-support.js"; const completeMock = vi.hoisted(() => vi.fn()); @@ -31,15 +32,6 @@ async function loadCreatePdfTool() { return createPdfTool; } -async function withTempAgentDir(run: (agentDir: string) => Promise): Promise { - const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-pdf-")); - try { - return await run(agentDir); - } finally { - await fs.rm(agentDir, { recursive: true, force: true }); - } -} - const ANTHROPIC_PDF_MODEL = "anthropic/claude-opus-4-6"; const OPENAI_PDF_MODEL = "openai/gpt-5.4-mini"; const FAKE_PDF_MEDIA = { @@ -66,27 +58,13 @@ type PdfToolInstance = ReturnType; async function withConfiguredPdfTool( run: (tool: PdfToolInstance, agentDir: string) => Promise, ) { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { const cfg = withPdfModel(ANTHROPIC_PDF_MODEL); const tool = requirePdfTool((await loadCreatePdfTool())({ config: cfg, agentDir })); await run(tool, agentDir); }); } -function resetAuthEnv() { - vi.stubEnv("OPENAI_API_KEY", ""); - vi.stubEnv("ANTHROPIC_API_KEY", ""); - vi.stubEnv("ANTHROPIC_OAUTH_TOKEN", ""); - vi.stubEnv("GEMINI_API_KEY", ""); - vi.stubEnv("GOOGLE_API_KEY", ""); - vi.stubEnv("MINIMAX_API_KEY", ""); - vi.stubEnv("ZAI_API_KEY", ""); - vi.stubEnv("Z_AI_API_KEY", ""); - vi.stubEnv("COPILOT_GITHUB_TOKEN", ""); - vi.stubEnv("GH_TOKEN", ""); - vi.stubEnv("GITHUB_TOKEN", ""); -} - function withPdfModel(primary: string): OpenClawConfig { return { agents: { defaults: { pdfModel: { primary } } }, @@ -132,7 +110,7 @@ describe("createPdfTool", () => { const priorFetch = global.fetch; beforeEach(() => { - resetAuthEnv(); + resetPdfToolAuthEnv(); completeMock.mockReset(); }); @@ -177,7 +155,7 @@ describe("createPdfTool", () => { }); it("respects fsPolicy.workspaceOnly for non-sandbox pdf paths", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-pdf-ws-")); const outsideDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-pdf-out-")); try { @@ -217,7 +195,7 @@ describe("createPdfTool", () => { }); it("uses native PDF path without eager extraction", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { await stubPdfToolInfra(agentDir, { provider: "anthropic", input: ["text", "document"] }); vi.spyOn(pdfNativeProviders, "anthropicAnalyzePdf").mockResolvedValue("native summary"); const extractSpy = vi.spyOn(pdfExtractModule, "extractPdfContent"); @@ -238,7 +216,7 @@ describe("createPdfTool", () => { }); it("rejects pages parameter for native PDF providers", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { await stubPdfToolInfra(agentDir, { provider: "anthropic", input: ["text", "document"] }); const cfg = withPdfModel(ANTHROPIC_PDF_MODEL); const tool = requirePdfTool((await loadCreatePdfTool())({ config: cfg, agentDir })); @@ -254,7 +232,7 @@ describe("createPdfTool", () => { }); it("uses extraction fallback for non-native models", async () => { - await withTempAgentDir(async (agentDir) => { + await withTempPdfAgentDir(async (agentDir) => { await stubPdfToolInfra(agentDir, { provider: "openai", input: ["text"] }); const extractSpy = vi.spyOn(pdfExtractModule, "extractPdfContent").mockResolvedValue({ text: "Extracted content",