From 31c269f0ed7b187f1074fcbc76fb7430be4cd25f Mon Sep 17 00:00:00 2001 From: Mason Huang Date: Sat, 23 May 2026 14:27:03 +0800 Subject: [PATCH] fix(tools): honor config apiKey in media tool preflight (#85570) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - The branch adds a config-aware tool auth helper, routes image/PDF/media generation preflight and list selection through it, threads `workspaceDir`, and adds focused regression tests plus a changelog entry. - Reproducibility: yes. by source inspection. Current main gates affected media/PDF/generation preflight paths on env/profile auth while the runtime auth contract already accepts usable `models.providers.*.apiKey`. Automerge notes: - PR branch already contained follow-up commit before automerge: fix(tools): fall back to config apiKey in capability preflight - PR branch already contained follow-up commit before automerge: fix(tools): honor config apiKey in media tool preflight - PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8557… Validation: - ClawSweeper review passed for head b8c9242d77f25ea1650afd300a840d2027547222. - Required merge gates passed before the squash merge. Prepared head SHA: b8c9242d77f25ea1650afd300a840d2027547222 Review: https://github.com/openclaw/openclaw/pull/85570#issuecomment-4523770355 Co-authored-by: Mason Huang Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: hxy91819 Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com> --- CHANGELOG.md | 1 + .../tools/image-generate-tool.actions.ts | 2 + src/agents/tools/image-generate-tool.ts | 4 ++ src/agents/tools/image-tool.test.ts | 29 ++++++++++ src/agents/tools/image-tool.ts | 2 + .../media-generate-tool-actions-shared.ts | 2 + src/agents/tools/media-tool-shared.test.ts | 57 +++++++++++++++++++ src/agents/tools/media-tool-shared.ts | 23 ++++++-- src/agents/tools/model-config.helpers.test.ts | 47 +++++++++++++++ src/agents/tools/model-config.helpers.ts | 27 ++++++++- .../tools/music-generate-tool.actions.ts | 3 +- src/agents/tools/music-generate-tool.ts | 4 ++ .../tools/pdf-tool.model-config.test.ts | 35 +++++++++++- src/agents/tools/pdf-tool.model-config.ts | 18 ++++-- .../tools/video-generate-tool.actions.ts | 3 +- src/agents/tools/video-generate-tool.ts | 4 ++ 16 files changed, 247 insertions(+), 14 deletions(-) create mode 100644 src/agents/tools/model-config.helpers.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f84359f7dd7e..fd4d0faa5fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Agents/tools: honor configured custom provider API keys when deciding whether media, image-generation, video-generation, music-generation, and PDF tools are available. (#85570) - Windows installer: fail Git checkout installs when `pnpm install` or `pnpm build` fails instead of writing a wrapper to a missing CLI build. - Sessions: surface previous-transcript archive failures during `/new` rotation so disk rename errors are logged instead of silently hiding stranded transcript files. Fixes #81984. (#85586, from #82081) Thanks @0xghost42. - TUI/agents: mirror internal-ui message-tool replies into final chat output so message-tool-only agents remain visible in `openclaw tui`. Fixes #85538. Thanks @danpolasek. diff --git a/src/agents/tools/image-generate-tool.actions.ts b/src/agents/tools/image-generate-tool.actions.ts index d2685a63f256..8a84ac8b953e 100644 --- a/src/agents/tools/image-generate-tool.actions.ts +++ b/src/agents/tools/image-generate-tool.actions.ts @@ -64,6 +64,7 @@ export function summarizeImageGenerationCapabilities(provider: ImageGenerationPr export function createImageGenerateListActionResult(params: { cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; }): ImageGenerateActionResult { @@ -73,6 +74,7 @@ export function createImageGenerateListActionResult(params: { providers, emptyText: "No image-generation providers are registered.", cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, listModes: listSupportedImageGenerationModes, diff --git a/src/agents/tools/image-generate-tool.ts b/src/agents/tools/image-generate-tool.ts index c769482c9a9f..c52a7ace8bdd 100644 --- a/src/agents/tools/image-generate-tool.ts +++ b/src/agents/tools/image-generate-tool.ts @@ -208,11 +208,13 @@ const ImageGenerateToolSchema = Type.Object({ export function resolveImageGenerationModelConfigForTool(params: { cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; }): ToolModelConfig | null { return resolveCapabilityModelConfigForTool({ cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, modelConfig: params.cfg?.agents?.defaults?.imageGenerationModel, @@ -806,6 +808,7 @@ export function createImageGenerateTool(options?: { if (action === "list") { return createImageGenerateListActionResult({ cfg, + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authProfileStore, }); @@ -816,6 +819,7 @@ export function createImageGenerateTool(options?: { const imageGenerationModelConfig = resolveImageGenerationModelConfigForTool({ cfg, + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authProfileStore, }); diff --git a/src/agents/tools/image-tool.test.ts b/src/agents/tools/image-tool.test.ts index cc0404d95625..aa94175c493a 100644 --- a/src/agents/tools/image-tool.test.ts +++ b/src/agents/tools/image-tool.test.ts @@ -121,6 +121,11 @@ vi.mock("../auth-profiles.js", () => ({ })); vi.mock("../model-auth.js", () => ({ + hasUsableCustomProviderApiKey: (cfg?: OpenClawConfig, provider?: string) => { + const providerConfig = cfg?.models?.providers?.[provider ?? ""]; + const apiKey = providerConfig?.apiKey; + return typeof apiKey === "string" && apiKey.trim().length > 0; + }, resolveEnvApiKey: (provider: string) => { const envVarByProvider: Record = { anthropic: ["ANTHROPIC_API_KEY", "ANTHROPIC_OAUTH_TOKEN"], @@ -1060,6 +1065,30 @@ describe("image tool implicit imageModel config", () => { }); }); + it("pairs a custom provider when config declares its api key", async () => { + await withTempAgentDir(async (agentDir) => { + const cfg: OpenClawConfig = { + agents: { defaults: { model: { primary: "hatchery-qwen3.6-plus/text-1" } } }, + models: { + providers: { + "hatchery-qwen3.6-plus": { + baseUrl: "https://example.com", + apiKey: "sk-configured", // pragma: allowlist secret + models: [ + makeModelDefinition("text-1", ["text"]), + makeModelDefinition("qwen3.6-plus", ["text", "image"]), + ], + }, + }, + }, + }; + expect(resolveImageModelConfigForTool({ cfg, agentDir })).toEqual({ + primary: "hatchery-qwen3.6-plus/qwen3.6-plus", + }); + expect(typeof createImageTool({ config: cfg, agentDir })?.execute).toBe("function"); + }); + }); + it("does not double-prefix custom provider model IDs that already include the provider", async () => { await withTempAgentDir(async (agentDir) => { await writeAuthProfiles(agentDir, { diff --git a/src/agents/tools/image-tool.ts b/src/agents/tools/image-tool.ts index 401b0e83cd90..5d24587be050 100644 --- a/src/agents/tools/image-tool.ts +++ b/src/agents/tools/image-tool.ts @@ -239,6 +239,8 @@ export function resolveImageModelConfigForTool(params: { return buildToolModelConfigFromCandidates({ explicit, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, candidates: [...primaryAliasCandidates, ...primaryCandidates, ...remainingAutoCandidates], diff --git a/src/agents/tools/media-generate-tool-actions-shared.ts b/src/agents/tools/media-generate-tool-actions-shared.ts index d5f81782bfeb..5901fea97fde 100644 --- a/src/agents/tools/media-generate-tool-actions-shared.ts +++ b/src/agents/tools/media-generate-tool-actions-shared.ts @@ -45,6 +45,7 @@ export function createMediaGenerateProviderListActionResult< providers: TProvider[]; emptyText: string; cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; listModes: (provider: TProvider) => string[]; @@ -72,6 +73,7 @@ export function createMediaGenerateProviderListActionResult< providers: params.providers, provider, cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }), diff --git a/src/agents/tools/media-tool-shared.test.ts b/src/agents/tools/media-tool-shared.test.ts index a88427f83dd2..daf8c6fb0ff9 100644 --- a/src/agents/tools/media-tool-shared.test.ts +++ b/src/agents/tools/media-tool-shared.test.ts @@ -3,6 +3,8 @@ import { pathToFileURL } from "node:url"; import { afterEach, describe, expect, it, vi } from "vitest"; import { hasGenerationToolAvailability, + isCapabilityProviderConfigured, + resolveCapabilityModelConfigForTool, resolveMediaToolLocalRoots, resolveModelFromRegistry, } from "./media-tool-shared.js"; @@ -104,6 +106,61 @@ describe("resolveModelFromRegistry", () => { }); describe("hasGenerationToolAvailability", () => { + it("accepts config-backed custom provider auth for generation providers", () => { + const cfg = { + models: { + providers: { + "custom-image": { + baseUrl: "https://example.com/v1", + apiKey: "sk-configured", // pragma: allowlist secret + models: [], + }, + }, + }, + }; + + expect( + hasGenerationToolAvailability({ + providerKey: "imageGenerationProviders", + cfg, + providers: [{ id: "custom-image", defaultModel: "workflow" }], + }), + ).toBe(true); + }); + + it("preserves a provider-specific not-configured result over generic config auth", () => { + const cfg = { + models: { + providers: { + "workflow-image": { + baseUrl: "https://example.com/v1", + apiKey: "sk-configured", // pragma: allowlist secret + models: [], + }, + }, + }, + }; + const provider = { + id: "workflow-image", + defaultModel: "workflow", + isConfigured: () => false, + }; + + expect( + isCapabilityProviderConfigured({ + providers: [provider], + provider, + cfg, + }), + ).toBe(false); + expect( + resolveCapabilityModelConfigForTool({ + cfg, + providers: [provider], + }), + ).toBeNull(); + }); + it("allows generation tools for runtime providers configured without auth", () => { expect( hasGenerationToolAvailability({ diff --git a/src/agents/tools/media-tool-shared.ts b/src/agents/tools/media-tool-shared.ts index e0b35f72b6d0..1d94cbc3bf3a 100644 --- a/src/agents/tools/media-tool-shared.ts +++ b/src/agents/tools/media-tool-shared.ts @@ -27,7 +27,7 @@ import { import { buildToolModelConfigFromCandidates, coerceToolModelConfig, - hasAuthForProvider, + hasProviderAuthForTool, hasToolModelConfig, resolveDefaultModelRef, type ToolModelConfig, @@ -192,6 +192,7 @@ export function isCapabilityProviderConfigured(par provider?: T; providerId?: string; cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; }): boolean { @@ -203,8 +204,10 @@ export function isCapabilityProviderConfigured(par }); if (!provider) { return params.providerId - ? hasAuthForProvider({ + ? hasProviderAuthForTool({ provider: params.providerId, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }) @@ -216,8 +219,10 @@ export function isCapabilityProviderConfigured(par agentDir: params.agentDir, }); } - return hasAuthForProvider({ + return hasProviderAuthForTool({ provider: provider.id, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }); @@ -251,6 +256,7 @@ export function resolveSelectedCapabilityProvider( function resolveCapabilityModelCandidatesForTool(params: { cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; providers: CapabilityProvider[]; @@ -267,6 +273,7 @@ function resolveCapabilityModelCandidatesForTool(params: { providers: params.providers, provider, cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }) @@ -309,6 +316,7 @@ function resolveCapabilityModelCandidatesForTool(params: { export function resolveCapabilityModelConfigForTool(params: { cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; modelConfig?: AgentModelConfig; @@ -326,10 +334,13 @@ export function resolveCapabilityModelConfigForTool(params: { }; return buildToolModelConfigFromCandidates({ explicit, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, candidates: resolveCapabilityModelCandidatesForTool({ cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, providers: getProviders(), @@ -339,6 +350,7 @@ export function resolveCapabilityModelConfigForTool(params: { providers: getProviders(), providerId, cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }), @@ -367,6 +379,7 @@ export function hasGenerationToolAvailability(params: { providers, provider, cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }), @@ -396,8 +409,10 @@ export function hasGenerationToolAvailability(params: { contract: params.providerKey, config: params.cfg, }).some((providerId) => - hasAuthForProvider({ + hasProviderAuthForTool({ provider: providerId, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }), diff --git a/src/agents/tools/model-config.helpers.test.ts b/src/agents/tools/model-config.helpers.test.ts new file mode 100644 index 000000000000..7e013db6509d --- /dev/null +++ b/src/agents/tools/model-config.helpers.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import type { OpenClawConfig } from "../../config/config.js"; +import { hasProviderAuthForTool } from "./model-config.helpers.js"; + +describe("hasProviderAuthForTool", () => { + afterEach(() => { + vi.unstubAllEnvs(); + }); + + it("accepts config-backed custom provider auth", () => { + const cfg = { + models: { + providers: { + hatchery: { + baseUrl: "https://example.com/v1", + apiKey: "sk-configured", // pragma: allowlist secret + models: [], + }, + }, + }, + } as OpenClawConfig; + + expect(hasProviderAuthForTool({ provider: "hatchery", cfg })).toBe(true); + }); + + it("keeps auth-store profiles as valid tool auth", () => { + expect( + hasProviderAuthForTool({ + provider: "hatchery", + authStore: { + version: 1, + profiles: { + "hatchery:default": { + provider: "hatchery", + type: "api_key", + key: "sk-profile", // pragma: allowlist secret + }, + }, + }, + }), + ).toBe(true); + }); + + it("rejects providers without config, env, or profile auth", () => { + expect(hasProviderAuthForTool({ provider: "unconfigured-provider" })).toBe(false); + }); +}); diff --git a/src/agents/tools/model-config.helpers.ts b/src/agents/tools/model-config.helpers.ts index 94468b38cc7b..8b90281a9af1 100644 --- a/src/agents/tools/model-config.helpers.ts +++ b/src/agents/tools/model-config.helpers.ts @@ -14,7 +14,7 @@ import { } from "../auth-profiles.js"; import type { AuthProfileCredential, AuthProfileStore } from "../auth-profiles/types.js"; import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../defaults.js"; -import { resolveEnvApiKey } from "../model-auth.js"; +import { hasUsableCustomProviderApiKey, resolveEnvApiKey } from "../model-auth.js"; import { resolveConfiguredModelRef } from "../model-selection.js"; export type ToolModelConfig = { primary?: string; fallbacks?: string[]; timeoutMs?: number }; @@ -79,6 +79,25 @@ export function hasAuthProfileForProvider(params: { return profileIds.some((profileId) => store.profiles[profileId]?.type === params.type); } +export function hasProviderAuthForTool(params: { + provider: string; + cfg?: OpenClawConfig; + workspaceDir?: string; + agentDir?: string; + authStore?: AuthProfileStore; +}): boolean { + if ( + hasAuthForProvider({ + provider: params.provider, + agentDir: params.agentDir, + authStore: params.authStore, + }) + ) { + return true; + } + return hasUsableCustomProviderApiKey(params.cfg, params.provider); +} + export function coerceToolModelConfig(model?: AgentToolModelConfig): ToolModelConfig { const primary = resolveAgentModelPrimaryValue(model); const fallbacks = resolveAgentModelFallbackValues(model); @@ -92,6 +111,8 @@ export function coerceToolModelConfig(model?: AgentToolModelConfig): ToolModelCo export function buildToolModelConfigFromCandidates(params: { explicit: ToolModelConfig; + cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; candidates: Array; @@ -110,8 +131,10 @@ export function buildToolModelConfigFromCandidates(params: { const provider = trimmed.slice(0, trimmed.indexOf("/")).trim(); const providerConfigured = params.isProviderConfigured?.(provider) ?? - hasAuthForProvider({ + hasProviderAuthForTool({ provider, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }); diff --git a/src/agents/tools/music-generate-tool.actions.ts b/src/agents/tools/music-generate-tool.actions.ts index 70e35c33f6aa..3562f43ba7c4 100644 --- a/src/agents/tools/music-generate-tool.actions.ts +++ b/src/agents/tools/music-generate-tool.actions.ts @@ -58,7 +58,7 @@ function summarizeMusicGenerationCapabilities( export function createMusicGenerateListActionResult( config?: OpenClawConfig, - options?: { agentDir?: string; authStore?: AuthProfileStore }, + options?: { workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore }, ): MusicGenerateActionResult { const providers = listRuntimeMusicGenerationProviders({ config }); return createMediaGenerateProviderListActionResult({ @@ -66,6 +66,7 @@ export function createMusicGenerateListActionResult( providers, emptyText: "No music-generation providers are registered.", cfg: config, + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authStore, listModes: listSupportedMusicGenerationModes, diff --git a/src/agents/tools/music-generate-tool.ts b/src/agents/tools/music-generate-tool.ts index dd8a083e1a1e..e4ccb1beaad5 100644 --- a/src/agents/tools/music-generate-tool.ts +++ b/src/agents/tools/music-generate-tool.ts @@ -143,11 +143,13 @@ const MusicGenerateToolSchema = Type.Object({ function resolveMusicGenerationModelConfigForTool(params: { cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; }): ToolModelConfig | null { return resolveCapabilityModelConfigForTool({ cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, modelConfig: params.cfg?.agents?.defaults?.musicGenerationModel, @@ -614,6 +616,7 @@ export function createMusicGenerateTool(options?: { if (action === "list") { return createMusicGenerateListActionResult(cfg, { + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authProfileStore, }); @@ -625,6 +628,7 @@ export function createMusicGenerateTool(options?: { const musicGenerationModelConfig = resolveMusicGenerationModelConfigForTool({ cfg, + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authProfileStore, }); diff --git a/src/agents/tools/pdf-tool.model-config.test.ts b/src/agents/tools/pdf-tool.model-config.test.ts index e9bdad13a497..d2850c01590d 100644 --- a/src/agents/tools/pdf-tool.model-config.test.ts +++ b/src/agents/tools/pdf-tool.model-config.test.ts @@ -18,7 +18,11 @@ vi.mock("./model-config.helpers.js", () => ({ ...(objectModel?.fallbacks?.length ? { fallbacks: objectModel.fallbacks } : {}), }; }, - hasAuthForProvider: ({ provider }: { provider: string }) => { + hasProviderAuthForTool: ({ provider, cfg }: { provider: string; cfg?: OpenClawConfig }) => { + const providerCfg = cfg?.models?.providers?.[provider] as { apiKey?: string } | undefined; + if (providerCfg?.apiKey?.trim()) { + return true; + } if (provider === "anthropic") { return Boolean(process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_OAUTH_TOKEN); } @@ -137,4 +141,33 @@ describe("resolvePdfModelConfigForTool", () => { primary: "minimax/MiniMax-VL-01", }); }); + + it("uses a config-authenticated custom provider image model as a PDF fallback", () => { + const cfg = { + ...withDefaultModel("hatchery/text-1"), + models: { + providers: { + hatchery: { + baseUrl: "https://example.com/v1", + apiKey: "sk-configured", // pragma: allowlist secret + models: [ + { + id: "vision-1", + name: "Vision 1", + reasoning: false, + input: ["text", "image"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 32_000, + maxTokens: 4_096, + }, + ], + }, + }, + }, + } as OpenClawConfig; + + expect(resolvePdfModelConfigForTool({ cfg, agentDir: TEST_AGENT_DIR })).toEqual({ + primary: "hatchery/vision-1", + }); + }); }); diff --git a/src/agents/tools/pdf-tool.model-config.ts b/src/agents/tools/pdf-tool.model-config.ts index da9dc09cd77f..33d50b26205a 100644 --- a/src/agents/tools/pdf-tool.model-config.ts +++ b/src/agents/tools/pdf-tool.model-config.ts @@ -12,7 +12,7 @@ import { resolveConfiguredImageModelRefs, resolveProviderVisionModelFromConfig, } from "./image-tool.helpers.js"; -import { hasAuthForProvider, resolveDefaultModelRef } from "./model-config.helpers.js"; +import { hasProviderAuthForTool, resolveDefaultModelRef } from "./model-config.helpers.js"; import { coercePdfModelConfig } from "./pdf-tool.helpers.js"; function resolveImageCandidateRefs(params: { @@ -29,8 +29,10 @@ function resolveImageCandidateRefs(params: { }) .filter((providerId) => !params.filter || params.filter(providerId)) .filter((providerId) => - hasAuthForProvider({ + hasProviderAuthForTool({ provider: providerId, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }), @@ -76,8 +78,10 @@ export function resolvePdfModelConfigForTool(params: { } const primary = resolveDefaultModelRef(params.cfg); - const googleOk = hasAuthForProvider({ + const googleOk = hasProviderAuthForTool({ provider: "google", + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }); @@ -92,8 +96,10 @@ export function resolvePdfModelConfigForTool(params: { let preferred: string | null = null; - const providerOk = hasAuthForProvider({ + const providerOk = hasProviderAuthForTool({ provider: primary.provider, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }); @@ -140,8 +146,10 @@ export function resolvePdfModelConfigForTool(params: { if ( !providerId || isMinimaxVlmProvider(providerId) || - !hasAuthForProvider({ + !hasProviderAuthForTool({ provider: providerId, + cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, }) diff --git a/src/agents/tools/video-generate-tool.actions.ts b/src/agents/tools/video-generate-tool.actions.ts index dd047c21c17a..226eb61bef5a 100644 --- a/src/agents/tools/video-generate-tool.actions.ts +++ b/src/agents/tools/video-generate-tool.actions.ts @@ -81,7 +81,7 @@ function summarizeVideoGenerationCapabilities( export function createVideoGenerateListActionResult( config?: OpenClawConfig, - options?: { agentDir?: string; authStore?: AuthProfileStore }, + options?: { workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore }, ): VideoGenerateActionResult { const providers = listRuntimeVideoGenerationProviders({ config }); return createMediaGenerateProviderListActionResult({ @@ -89,6 +89,7 @@ export function createVideoGenerateListActionResult( providers, emptyText: "No video-generation providers are registered.", cfg: config, + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authStore, listModes: listSupportedVideoGenerationModes, diff --git a/src/agents/tools/video-generate-tool.ts b/src/agents/tools/video-generate-tool.ts index b20671dc3bbb..8875fff9f417 100644 --- a/src/agents/tools/video-generate-tool.ts +++ b/src/agents/tools/video-generate-tool.ts @@ -222,11 +222,13 @@ function createVideoGenerateToolSchema(params: { includeAudioReferences: boolean export function resolveVideoGenerationModelConfigForTool(params: { cfg?: OpenClawConfig; + workspaceDir?: string; agentDir?: string; authStore?: AuthProfileStore; }): ToolModelConfig | null { return resolveCapabilityModelConfigForTool({ cfg: params.cfg, + workspaceDir: params.workspaceDir, agentDir: params.agentDir, authStore: params.authStore, modelConfig: params.cfg?.agents?.defaults?.videoGenerationModel, @@ -958,6 +960,7 @@ export function createVideoGenerateTool(options?: { if (action === "list") { return createVideoGenerateListActionResult(cfg, { + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authProfileStore, }); @@ -969,6 +972,7 @@ export function createVideoGenerateTool(options?: { const videoGenerationModelConfig = resolveVideoGenerationModelConfigForTool({ cfg, + workspaceDir: options?.workspaceDir, agentDir: options?.agentDir, authStore: options?.authProfileStore, });