mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(tools): honor config apiKey in media tool preflight (#85570)
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 headb8c9242d77. - Required merge gates passed before the squash merge. Prepared head SHA:b8c9242d77Review: https://github.com/openclaw/openclaw/pull/85570#issuecomment-4523770355 Co-authored-by: Mason Huang <masonxhuang@tencent.com> 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>
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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<string, string[]> = {
|
||||
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, {
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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,
|
||||
}),
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
import {
|
||||
buildToolModelConfigFromCandidates,
|
||||
coerceToolModelConfig,
|
||||
hasAuthForProvider,
|
||||
hasProviderAuthForTool,
|
||||
hasToolModelConfig,
|
||||
resolveDefaultModelRef,
|
||||
type ToolModelConfig,
|
||||
@@ -192,6 +192,7 @@ export function isCapabilityProviderConfigured<T extends CapabilityProvider>(par
|
||||
provider?: T;
|
||||
providerId?: string;
|
||||
cfg?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
agentDir?: string;
|
||||
authStore?: AuthProfileStore;
|
||||
}): boolean {
|
||||
@@ -203,8 +204,10 @@ export function isCapabilityProviderConfigured<T extends CapabilityProvider>(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<T extends CapabilityProvider>(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<T extends CapabilityProvider>(
|
||||
|
||||
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,
|
||||
}),
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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<string | null | undefined>;
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user