diff --git a/src/agents/openclaw-tools.pdf-registration.test.ts b/src/agents/openclaw-tools.pdf-registration.test.ts index 096827d6c7d..e408f27ca7d 100644 --- a/src/agents/openclaw-tools.pdf-registration.test.ts +++ b/src/agents/openclaw-tools.pdf-registration.test.ts @@ -1,33 +1,21 @@ -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; import { describe, expect, it } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import "./test-helpers/fast-core-tools.js"; -import { createOpenClawTools } from "./openclaw-tools.js"; - -async function withTempAgentDir(run: (agentDir: string) => Promise): Promise { - const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-tools-pdf-")); - try { - return await run(agentDir); - } finally { - await fs.rm(agentDir, { recursive: true, force: true }); - } -} +import { collectPresentOpenClawTools } from "./openclaw-tools.registration.js"; +import { createPdfTool } from "./tools/pdf-tool.js"; describe("createOpenClawTools PDF registration", () => { - it("includes pdf tool when pdfModel is configured", async () => { - await withTempAgentDir(async (agentDir) => { - const cfg: OpenClawConfig = { + it("includes the pdf tool when the pdf factory returns a tool", () => { + const pdfTool = createPdfTool({ + agentDir: "/tmp/openclaw-agent-main", + config: { agents: { defaults: { pdfModel: { primary: "openai/gpt-5.4-mini" }, }, }, - }; - - const tools = createOpenClawTools({ config: cfg, agentDir }); - expect(tools.some((tool) => tool.name === "pdf")).toBe(true); + }, }); + + expect(pdfTool?.name).toBe("pdf"); + expect(collectPresentOpenClawTools([pdfTool]).map((tool) => tool.name)).toContain("pdf"); }); }); diff --git a/src/agents/openclaw-tools.registration.ts b/src/agents/openclaw-tools.registration.ts index 86b4915ba46..fdeb5fb6f07 100644 --- a/src/agents/openclaw-tools.registration.ts +++ b/src/agents/openclaw-tools.registration.ts @@ -1,3 +1,5 @@ +import type { OpenClawConfig } from "../config/config.js"; +import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; import type { AnyAgentTool } from "./tools/common.js"; export function collectPresentOpenClawTools( @@ -5,3 +7,19 @@ export function collectPresentOpenClawTools( ): AnyAgentTool[] { return candidates.filter((tool): tool is AnyAgentTool => tool !== null && tool !== undefined); } + +function isOpenAIProvider(provider?: string): boolean { + const normalized = normalizeOptionalLowercaseString(provider); + return normalized === "openai" || normalized === "openai-codex"; +} + +export function isUpdatePlanToolEnabledForOpenClawTools( + config: OpenClawConfig | undefined, + provider?: string, +): boolean { + const configured = config?.tools?.experimental?.planTool; + if (configured !== undefined) { + return configured; + } + return isOpenAIProvider(provider); +} diff --git a/src/agents/openclaw-tools.ts b/src/agents/openclaw-tools.ts index 68034db2cec..2268ddbaf85 100644 --- a/src/agents/openclaw-tools.ts +++ b/src/agents/openclaw-tools.ts @@ -1,12 +1,14 @@ import type { OpenClawConfig } from "../config/config.js"; import { callGateway } from "../gateway/call.js"; import { getActiveRuntimeWebToolsMetadata } from "../secrets/runtime.js"; -import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; import { normalizeDeliveryContext } from "../utils/delivery-context.js"; import type { GatewayMessageChannel } from "../utils/message-channel.js"; import { resolveAgentWorkspaceDir, resolveSessionAgentId } from "./agent-scope.js"; import { resolveOpenClawPluginToolsForOptions } from "./openclaw-plugin-tools.js"; -import { collectPresentOpenClawTools } from "./openclaw-tools.registration.js"; +import { + collectPresentOpenClawTools, + isUpdatePlanToolEnabledForOpenClawTools, +} from "./openclaw-tools.registration.js"; import type { SandboxFsBridge } from "./sandbox/fs-bridge.js"; import type { SpawnedToolContext } from "./spawned-context.js"; import type { ToolFsPolicy } from "./tool-fs-policy.js"; @@ -45,19 +47,6 @@ const defaultOpenClawToolsDeps: OpenClawToolsDeps = { let openClawToolsDeps: OpenClawToolsDeps = defaultOpenClawToolsDeps; -function isOpenAIProvider(provider?: string): boolean { - const normalized = normalizeOptionalLowercaseString(provider); - return normalized === "openai" || normalized === "openai-codex"; -} - -function isUpdatePlanToolEnabled(config: OpenClawConfig | undefined, provider?: string): boolean { - const configured = config?.tools?.experimental?.planTool; - if (configured !== undefined) { - return configured; - } - return isOpenAIProvider(provider); -} - export function createOpenClawTools( options?: { sandboxBrowserBridgeUrl?: string; @@ -245,7 +234,7 @@ export function createOpenClawTools( agentSessionKey: options?.agentSessionKey, requesterAgentIdOverride: options?.requesterAgentIdOverride, }), - ...(isUpdatePlanToolEnabled(resolvedConfig, options?.modelProvider) + ...(isUpdatePlanToolEnabledForOpenClawTools(resolvedConfig, options?.modelProvider) ? [createUpdatePlanTool()] : []), createSessionsListTool({ diff --git a/src/agents/openclaw-tools.update-plan.test.ts b/src/agents/openclaw-tools.update-plan.test.ts index a7f7d5fee0b..a508b89b494 100644 --- a/src/agents/openclaw-tools.update-plan.test.ts +++ b/src/agents/openclaw-tools.update-plan.test.ts @@ -1,63 +1,43 @@ import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; -import "./test-helpers/fast-core-tools.js"; -import { createOpenClawTools } from "./openclaw-tools.js"; +import { isUpdatePlanToolEnabledForOpenClawTools } from "./openclaw-tools.registration.js"; +import { createUpdatePlanTool } from "./tools/update-plan-tool.js"; describe("openclaw-tools update_plan gating", () => { it("keeps update_plan disabled by default", () => { - const tools = createOpenClawTools({ - config: {} as OpenClawConfig, - }); - - expect(tools.map((tool) => tool.name)).not.toContain("update_plan"); + expect(isUpdatePlanToolEnabledForOpenClawTools({} as OpenClawConfig)).toBe(false); }); it("registers update_plan when explicitly enabled", () => { - const tools = createOpenClawTools({ - config: { - tools: { - experimental: { - planTool: true, - }, + const config = { + tools: { + experimental: { + planTool: true, }, - } as OpenClawConfig, - }); + }, + } as OpenClawConfig; - const updatePlan = tools.find((tool) => tool.name === "update_plan"); - expect(updatePlan?.displaySummary).toBe("Track a short structured work plan."); + expect(isUpdatePlanToolEnabledForOpenClawTools(config)).toBe(true); + expect(createUpdatePlanTool().displaySummary).toBe("Track a short structured work plan."); }); it("auto-enables update_plan for OpenAI-family providers", () => { - const openaiTools = createOpenClawTools({ - config: {} as OpenClawConfig, - modelProvider: "openai", - }); - const codexTools = createOpenClawTools({ - config: {} as OpenClawConfig, - modelProvider: "openai-codex", - }); - const anthropicTools = createOpenClawTools({ - config: {} as OpenClawConfig, - modelProvider: "anthropic", - }); - - expect(openaiTools.map((tool) => tool.name)).toContain("update_plan"); - expect(codexTools.map((tool) => tool.name)).toContain("update_plan"); - expect(anthropicTools.map((tool) => tool.name)).not.toContain("update_plan"); + expect(isUpdatePlanToolEnabledForOpenClawTools({} as OpenClawConfig, "openai")).toBe(true); + expect(isUpdatePlanToolEnabledForOpenClawTools({} as OpenClawConfig, "openai-codex")).toBe( + true, + ); + expect(isUpdatePlanToolEnabledForOpenClawTools({} as OpenClawConfig, "anthropic")).toBe(false); }); it("lets config disable update_plan auto-enable", () => { - const tools = createOpenClawTools({ - config: { - tools: { - experimental: { - planTool: false, - }, + const config = { + tools: { + experimental: { + planTool: false, }, - } as OpenClawConfig, - modelProvider: "openai", - }); + }, + } as OpenClawConfig; - expect(tools.map((tool) => tool.name)).not.toContain("update_plan"); + expect(isUpdatePlanToolEnabledForOpenClawTools(config, "openai")).toBe(false); }); });