perf: reuse run auth store for media tool availability

This commit is contained in:
Shakker
2026-05-01 18:51:21 +01:00
parent 0a2bbb87c7
commit 186b8e44dc
15 changed files with 140 additions and 10 deletions

View File

@@ -159,6 +159,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Agents/tools: reuse the auth profile store already loaded for the active run when deciding media and generation tool availability, avoiding repeated provider-auth runtime discovery during reply startup. Thanks @shakkernerd.
- Agents/tools: keep image, video, and music generation tool registration on manifest/auth control-plane checks instead of loading runtime provider registries during reply startup, reducing live-path tool-prep blocking while leaving provider runtime resolution for execution and list actions. Thanks @shakkernerd.
- fix: block workspace CLOUDSDK_PYTHON override and always set trusted interpreter for gcloud. (#74492) Thanks @pgondhi987.
- Providers/Z.AI: move the bundled GLM catalog and auth env metadata into the plugin manifest, so `models list --all --provider zai` shows the full known catalog without duplicated runtime seed data. Thanks @shakkernerd.

View File

@@ -5,6 +5,7 @@ import { getActiveRuntimeWebToolsMetadata } from "../secrets/runtime.js";
import { normalizeDeliveryContext } from "../utils/delivery-context.js";
import type { GatewayMessageChannel } from "../utils/message-channel.js";
import { resolveAgentWorkspaceDir, resolveSessionAgentIds } from "./agent-scope.js";
import type { AuthProfileStore } from "./auth-profiles/types.js";
import { resolveOpenClawPluginToolsForOptions } from "./openclaw-plugin-tools.js";
import { applyNodesToolWorkspaceGuard } from "./openclaw-tools.nodes-workspace-guard.js";
import {
@@ -104,6 +105,8 @@ export function createOpenClawTools(
recordToolPrepStage?: (name: string) => void;
/** Trusted sender id from inbound context (not tool args). */
requesterSenderId?: string | null;
/** Auth profiles already loaded for this run; used for prompt-time tool availability. */
authProfileStore?: AuthProfileStore;
/** Whether the requesting sender is an owner. */
senderIsOwner?: boolean;
/** Ephemeral session UUID — regenerated on /new and /reset. */
@@ -153,6 +156,7 @@ export function createOpenClawTools(
? createImageTool({
config: options?.config,
agentDir: options.agentDir,
authProfileStore: options?.authProfileStore,
workspaceDir,
sandbox,
fsPolicy: options?.fsPolicy,
@@ -163,6 +167,7 @@ export function createOpenClawTools(
const imageGenerateTool = createImageGenerateTool({
config: options?.config,
agentDir: options?.agentDir,
authProfileStore: options?.authProfileStore,
workspaceDir,
sandbox,
fsPolicy: options?.fsPolicy,
@@ -171,6 +176,7 @@ export function createOpenClawTools(
const videoGenerateTool = createVideoGenerateTool({
config: options?.config,
agentDir: options?.agentDir,
authProfileStore: options?.authProfileStore,
agentSessionKey: options?.agentSessionKey,
requesterOrigin: deliveryContext ?? undefined,
workspaceDir,
@@ -181,6 +187,7 @@ export function createOpenClawTools(
const musicGenerateTool = createMusicGenerateTool({
config: options?.config,
agentDir: options?.agentDir,
authProfileStore: options?.authProfileStore,
agentSessionKey: options?.agentSessionKey,
requesterOrigin: deliveryContext ?? undefined,
workspaceDir,
@@ -192,6 +199,7 @@ export function createOpenClawTools(
? createPdfTool({
config: options?.config,
agentDir: options.agentDir,
authProfileStore: options?.authProfileStore,
workspaceDir,
sandbox,
fsPolicy: options?.fsPolicy,

View File

@@ -1078,6 +1078,7 @@ export async function runEmbeddedPiAgent(
authProfileIdSource: lockedProfileId ? "user" : "auto",
initialReplayState: accumulatedReplayState,
authStorage,
authProfileStore: authStore,
modelRegistry,
agentId: workspaceResolution.agentId,
legacyBeforeAgentStartResult,

View File

@@ -918,6 +918,7 @@ export async function runEmbeddedAttempt(
params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
disableMessageTool: params.disableMessageTool,
forceMessageTool: params.forceMessageTool,
authProfileStore: params.authProfileStore,
recordToolPrepStage: (name) => corePluginToolStages.mark(name),
onYield: (message) => {
yieldDetected = true;

View File

@@ -7,6 +7,7 @@ import type { SessionSystemPromptReport } from "../../../config/sessions/types.j
import type { ContextEngine, ContextEnginePromptCacheInfo } from "../../../context-engine/types.js";
import type { DiagnosticTraceContext } from "../../../infra/diagnostic-trace-context.js";
import type { PluginHookBeforeAgentStartResult } from "../../../plugins/hook-before-agent-start.types.js";
import type { AuthProfileStore } from "../../auth-profiles/types.js";
import type { MessagingToolSend } from "../../pi-embedded-messaging.types.js";
import type { AgentRuntimePlan } from "../../runtime-plan/types.js";
import type { ToolErrorSummary } from "../../tool-error-summary.js";
@@ -41,6 +42,8 @@ export type EmbeddedRunAttemptParams = EmbeddedRunAttemptBase & {
runtimePlan?: AgentRuntimePlan;
model: Model<Api>;
authStorage: AuthStorage;
/** Auth profile store already resolved during startup for this attempt. */
authProfileStore: AuthProfileStore;
modelRegistry: ModelRegistry;
thinkLevel: ThinkLevel;
legacyBeforeAgentStartResult?: PluginHookBeforeAgentStartResult;

View File

@@ -3,6 +3,7 @@ import { HEARTBEAT_RESPONSE_TOOL_NAME } from "../auto-reply/heartbeat-tool-respo
import type { ModelCompatConfig } from "../config/types.models.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { ToolLoopDetectionConfig } from "../config/types.tools.js";
import type { AuthProfileStore } from "./auth-profiles/types.js";
import type { DiagnosticTraceContext } from "../infra/diagnostic-trace-context.js";
import { resolveMergedSafeBinProfileFixtures } from "../infra/exec-safe-bin-runtime-policy.js";
import { logWarn } from "../logger.js";
@@ -362,6 +363,8 @@ export function createOpenClawCodingTools(options?: {
* Keep this narrowly scoped; it is not a replacement for sender ownership.
*/
ownerOnlyToolAllowlist?: string[];
/** Auth profiles already loaded for this run; used for prompt-time tool availability. */
authProfileStore?: AuthProfileStore;
/** Callback invoked when sessions_yield tool is called. */
onYield?: (message: string) => Promise<void> | void;
}): AnyAgentTool[] {
@@ -711,6 +714,7 @@ export function createOpenClawCodingTools(options?: {
...(cronSelfRemoveOnlyJobId ? { cronSelfRemoveOnlyJobId } : {}),
requesterAgentIdOverride: agentId,
requesterSenderId: options?.senderId,
authProfileStore: options?.authProfileStore,
senderIsOwner: options?.senderIsOwner,
sessionId: options?.sessionId,
onYield: options?.onYield,

View File

@@ -33,6 +33,7 @@ import { saveMediaBuffer } from "../../media/store.js";
import { loadWebMedia } from "../../media/web-media.js";
import { getProviderEnvVars } from "../../secrets/provider-env-vars.js";
import { resolveUserPath } from "../../utils.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import { optionalStringEnum } from "../schema/string-enum.js";
import { ToolInputError, readNumberParam, readStringParam } from "./common.js";
import { decodeDataUrl } from "./image-tool.helpers.js";
@@ -195,10 +196,12 @@ function formatImageGenerationAuthHint(provider: {
export function resolveImageGenerationModelConfigForTool(params: {
cfg?: OpenClawConfig;
agentDir?: string;
authStore?: AuthProfileStore;
}): ToolModelConfig | null {
return resolveCapabilityModelConfigForTool({
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
modelConfig: params.cfg?.agents?.defaults?.imageGenerationModel,
providers: listRuntimeImageGenerationProviders({ config: params.cfg }),
});
@@ -563,6 +566,7 @@ async function inferResolutionFromInputImages(
export function createImageGenerateTool(options?: {
config?: OpenClawConfig;
agentDir?: string;
authProfileStore?: AuthProfileStore;
workspaceDir?: string;
sandbox?: ImageGenerateSandboxConfig;
fsPolicy?: ToolFsPolicy;
@@ -572,6 +576,7 @@ export function createImageGenerateTool(options?: {
!hasGenerationToolAvailability({
cfg,
agentDir: options?.agentDir,
authStore: options?.authProfileStore,
modelConfig: cfg.agents?.defaults?.imageGenerationModel,
providerKey: "imageGenerationProviders",
})
@@ -610,6 +615,7 @@ export function createImageGenerateTool(options?: {
provider,
cfg,
agentDir: options?.agentDir,
authStore: options?.authProfileStore,
}),
authEnvVars: getImageGenerationProviderAuthEnvVars(provider.id),
capabilities: provider.capabilities,
@@ -661,6 +667,7 @@ export function createImageGenerateTool(options?: {
const imageGenerationModelConfig = resolveImageGenerationModelConfigForTool({
cfg,
agentDir: options?.agentDir,
authStore: options?.authProfileStore,
});
if (!imageGenerationModelConfig) {
throw new ToolInputError("No image-generation model configured.");

View File

@@ -23,6 +23,7 @@ import {
type MediaUnderstandingProvider,
} from "../../plugin-sdk/media-understanding.js";
import { resolveUserPath } from "../../utils.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import { isMinimaxVlmProvider } from "../minimax-vlm.js";
import {
coerceImageAssistantText,
@@ -117,6 +118,7 @@ function resolveImageToolMaxTokens(modelMaxTokens: number | undefined, requested
export function resolveImageModelConfigForTool(params: {
cfg?: OpenClawConfig;
agentDir: string;
authStore?: AuthProfileStore;
}): ImageModelConfig | null {
// Note: We intentionally do NOT gate based on primarySupportsImages here.
// Even when the primary model supports images, we keep the tool available
@@ -171,6 +173,7 @@ export function resolveImageModelConfigForTool(params: {
return buildToolModelConfigFromCandidates({
explicit,
agentDir: params.agentDir,
authStore: params.authStore,
candidates: [...primaryCandidates, ...autoCandidates],
});
}
@@ -366,6 +369,7 @@ async function runImagePrompt(params: {
export function createImageTool(options?: {
config?: OpenClawConfig;
agentDir?: string;
authProfileStore?: AuthProfileStore;
workspaceDir?: string;
sandbox?: ImageSandboxConfig;
fsPolicy?: ToolFsPolicy;
@@ -383,6 +387,7 @@ export function createImageTool(options?: {
const imageModelConfig = resolveImageModelConfigForTool({
cfg: options?.config,
agentDir,
authStore: options?.authProfileStore,
});
if (!imageModelConfig) {
return null;

View File

@@ -146,4 +146,23 @@ describe("hasGenerationToolAvailability", () => {
).toBe(true);
expect(loadProviders).not.toHaveBeenCalled();
});
it("checks configured runtime providers against the supplied auth store", () => {
expect(
hasGenerationToolAvailability({
providerKey: "imageGenerationProviders",
authStore: {
version: 1,
profiles: {
"local-image:default": {
provider: "local-image",
type: "api_key",
key: "test",
},
},
},
providers: [{ id: "local-image", defaultModel: "workflow" }],
}),
).toBe(true);
});
});

View File

@@ -9,6 +9,7 @@ import {
normalizeOptionalLowercaseString,
normalizeOptionalString,
} from "../../shared/string-coerce.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import { normalizeModelRef } from "../model-selection.js";
import { normalizeProviderId } from "../provider-id.js";
import {
@@ -155,6 +156,7 @@ export function isCapabilityProviderConfigured<T extends CapabilityProvider>(par
providerId?: string;
cfg?: OpenClawConfig;
agentDir?: string;
authStore?: AuthProfileStore;
}): boolean {
const provider =
params.provider ??
@@ -164,7 +166,11 @@ export function isCapabilityProviderConfigured<T extends CapabilityProvider>(par
});
if (!provider) {
return params.providerId
? hasAuthForProvider({ provider: params.providerId, agentDir: params.agentDir })
? hasAuthForProvider({
provider: params.providerId,
agentDir: params.agentDir,
authStore: params.authStore,
})
: false;
}
if (provider.isConfigured) {
@@ -173,7 +179,11 @@ export function isCapabilityProviderConfigured<T extends CapabilityProvider>(par
agentDir: params.agentDir,
});
}
return hasAuthForProvider({ provider: provider.id, agentDir: params.agentDir });
return hasAuthForProvider({
provider: provider.id,
agentDir: params.agentDir,
authStore: params.authStore,
});
}
export function resolveSelectedCapabilityProvider<T extends CapabilityProvider>(params: {
@@ -196,6 +206,7 @@ export function resolveSelectedCapabilityProvider<T extends CapabilityProvider>(
export function resolveCapabilityModelCandidatesForTool(params: {
cfg?: OpenClawConfig;
agentDir?: string;
authStore?: AuthProfileStore;
providers: CapabilityProvider[];
}): string[] {
const providerDefaults = new Map<string, { ref: string; aliases: string[] }>();
@@ -211,6 +222,7 @@ export function resolveCapabilityModelCandidatesForTool(params: {
provider,
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
})
) {
continue;
@@ -252,6 +264,7 @@ export function resolveCapabilityModelCandidatesForTool(params: {
export function resolveCapabilityModelConfigForTool(params: {
cfg?: OpenClawConfig;
agentDir?: string;
authStore?: AuthProfileStore;
modelConfig?: AgentModelConfig;
providers: CapabilityProvider[];
}): ToolModelConfig | null {
@@ -262,9 +275,11 @@ export function resolveCapabilityModelConfigForTool(params: {
return buildToolModelConfigFromCandidates({
explicit,
agentDir: params.agentDir,
authStore: params.authStore,
candidates: resolveCapabilityModelCandidatesForTool({
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
providers: params.providers,
}),
isProviderConfigured: (providerId) =>
@@ -273,6 +288,7 @@ export function resolveCapabilityModelConfigForTool(params: {
providerId,
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
}),
});
}
@@ -280,6 +296,7 @@ export function resolveCapabilityModelConfigForTool(params: {
export function hasGenerationToolAvailability(params: {
cfg?: OpenClawConfig;
agentDir?: string;
authStore?: AuthProfileStore;
modelConfig?: AgentModelConfig;
providers?: CapabilityProvider[] | (() => CapabilityProvider[]);
providerKey: GenerationCapabilityProviderKey;
@@ -295,13 +312,20 @@ export function hasGenerationToolAvailability(params: {
provider,
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
}),
);
}
return resolveBundledCapabilityProviderIds({
key: params.providerKey,
cfg: params.cfg,
}).some((providerId) => hasAuthForProvider({ provider: providerId, agentDir: params.agentDir }));
}).some((providerId) =>
hasAuthForProvider({
provider: providerId,
agentDir: params.agentDir,
authStore: params.authStore,
}),
);
}
function formatQuotedList(values: readonly string[]): string {

View File

@@ -11,6 +11,7 @@ import {
hasAnyAuthProfileStoreSource,
listProfilesForProvider,
} from "../auth-profiles.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../defaults.js";
import { resolveEnvApiKey } from "../model-auth.js";
import { resolveConfiguredModelRef } from "../model-selection.js";
@@ -35,10 +36,17 @@ export function resolveDefaultModelRef(cfg?: OpenClawConfig): { provider: string
return { provider: DEFAULT_PROVIDER, model: DEFAULT_MODEL };
}
export function hasAuthForProvider(params: { provider: string; agentDir?: string }): boolean {
export function hasAuthForProvider(params: {
provider: string;
agentDir?: string;
authStore?: AuthProfileStore;
}): boolean {
if (resolveEnvApiKey(params.provider)?.apiKey) {
return true;
}
if (params.authStore) {
return listProfilesForProvider(params.authStore, params.provider).length > 0;
}
const agentDir = params.agentDir?.trim();
if (!agentDir) {
return false;
@@ -66,6 +74,7 @@ export function coerceToolModelConfig(model?: AgentModelConfig): ToolModelConfig
export function buildToolModelConfigFromCandidates(params: {
explicit: ToolModelConfig;
agentDir?: string;
authStore?: AuthProfileStore;
candidates: Array<string | null | undefined>;
isProviderConfigured?: (provider: string) => boolean;
}): ToolModelConfig | null {
@@ -82,7 +91,11 @@ export function buildToolModelConfigFromCandidates(params: {
const provider = trimmed.slice(0, trimmed.indexOf("/")).trim();
const providerConfigured =
params.isProviderConfigured?.(provider) ??
hasAuthForProvider({ provider, agentDir: params.agentDir });
hasAuthForProvider({
provider,
agentDir: params.agentDir,
authStore: params.authStore,
});
if (!provider || !providerConfigured) {
continue;
}

View File

@@ -26,6 +26,7 @@ import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js"
import { resolveUserPath } from "../../utils.js";
import type { DeliveryContext } from "../../utils/delivery-context.js";
import { buildTimeoutAbortSignal } from "../../utils/fetch-timeout.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import { ToolInputError, readNumberParam, readStringParam } from "./common.js";
import { decodeDataUrl } from "./image-tool.helpers.js";
import { withMediaGenerationTaskKeepalive } from "./media-generate-background-shared.js";
@@ -131,10 +132,12 @@ const MusicGenerateToolSchema = Type.Object({
export function resolveMusicGenerationModelConfigForTool(params: {
cfg?: OpenClawConfig;
agentDir?: string;
authStore?: AuthProfileStore;
}): ToolModelConfig | null {
return resolveCapabilityModelConfigForTool({
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
modelConfig: params.cfg?.agents?.defaults?.musicGenerationModel,
providers: listRuntimeMusicGenerationProviders({ config: params.cfg }),
});
@@ -488,6 +491,7 @@ async function executeMusicGenerationJob(params: {
export function createMusicGenerateTool(options?: {
config?: OpenClawConfig;
agentDir?: string;
authProfileStore?: AuthProfileStore;
agentSessionKey?: string;
requesterOrigin?: DeliveryContext;
workspaceDir?: string;
@@ -500,6 +504,7 @@ export function createMusicGenerateTool(options?: {
!hasGenerationToolAvailability({
cfg,
agentDir: options?.agentDir,
authStore: options?.authProfileStore,
modelConfig: cfg.agents?.defaults?.musicGenerationModel,
providerKey: "musicGenerationProviders",
})
@@ -539,6 +544,7 @@ export function createMusicGenerateTool(options?: {
const musicGenerationModelConfig = resolveMusicGenerationModelConfigForTool({
cfg,
agentDir: options?.agentDir,
authStore: options?.authProfileStore,
});
if (!musicGenerationModelConfig) {
throw new ToolInputError("No music-generation model configured.");

View File

@@ -4,6 +4,7 @@ import {
resolveAutoMediaKeyProviders,
resolveDefaultMediaModel,
} from "../../media-understanding/defaults.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import {
coerceImageModelConfig,
type ImageModelConfig,
@@ -16,11 +17,18 @@ import { coercePdfModelConfig } from "./pdf-tool.helpers.js";
function resolveImageCandidateRefs(params: {
cfg?: OpenClawConfig;
agentDir: string;
authStore?: AuthProfileStore;
filter?: (providerId: string) => boolean;
}): string[] {
return resolveAutoMediaKeyProviders({ capability: "image", cfg: params.cfg })
.filter((providerId) => !params.filter || params.filter(providerId))
.filter((providerId) => hasAuthForProvider({ provider: providerId, agentDir: params.agentDir }))
.filter((providerId) =>
hasAuthForProvider({
provider: providerId,
agentDir: params.agentDir,
authStore: params.authStore,
}),
)
.map((providerId) => {
const modelId =
resolveProviderVisionModelFromConfig({
@@ -40,6 +48,7 @@ function resolveImageCandidateRefs(params: {
export function resolvePdfModelConfigForTool(params: {
cfg?: OpenClawConfig;
agentDir: string;
authStore?: AuthProfileStore;
}): ImageModelConfig | null {
const explicitPdf = coercePdfModelConfig(params.cfg);
if (explicitPdf.primary?.trim() || (explicitPdf.fallbacks?.length ?? 0) > 0) {
@@ -58,7 +67,11 @@ export function resolvePdfModelConfigForTool(params: {
}
const primary = resolveDefaultModelRef(params.cfg);
const googleOk = hasAuthForProvider({ provider: "google", agentDir: params.agentDir });
const googleOk = hasAuthForProvider({
provider: "google",
agentDir: params.agentDir,
authStore: params.authStore,
});
const fallbacks: string[] = [];
const addFallback = (ref: string) => {
@@ -70,7 +83,11 @@ export function resolvePdfModelConfigForTool(params: {
let preferred: string | null = null;
const providerOk = hasAuthForProvider({ provider: primary.provider, agentDir: params.agentDir });
const providerOk = hasAuthForProvider({
provider: primary.provider,
agentDir: params.agentDir,
authStore: params.authStore,
});
const providerVision = resolveProviderVisionModelFromConfig({
cfg: params.cfg,
provider: primary.provider,
@@ -89,17 +106,26 @@ export function resolvePdfModelConfigForTool(params: {
const nativePdfCandidates = resolveImageCandidateRefs({
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
filter: (providerId) => providerSupportsNativePdfDocument({ cfg: params.cfg, providerId }),
});
const genericImageCandidates = resolveImageCandidateRefs({
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
});
if (params.cfg?.models?.providers && typeof params.cfg.models.providers === "object") {
for (const [providerKey, providerCfg] of Object.entries(params.cfg.models.providers)) {
const providerId = providerKey.trim();
if (!providerId || !hasAuthForProvider({ provider: providerId, agentDir: params.agentDir })) {
if (
!providerId ||
!hasAuthForProvider({
provider: providerId,
agentDir: params.agentDir,
authStore: params.authStore,
})
) {
continue;
}
const models = providerCfg?.models ?? [];

View File

@@ -12,6 +12,7 @@ import {
normalizeOptionalString,
} from "../../shared/string-coerce.js";
import { resolveUserPath } from "../../utils.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import { type ImageModelConfig } from "./image-tool.helpers.js";
import {
applyImageModelConfigDefaults,
@@ -244,6 +245,7 @@ async function runPdfPrompt(params: {
export function createPdfTool(options?: {
config?: OpenClawConfig;
agentDir?: string;
authProfileStore?: AuthProfileStore;
workspaceDir?: string;
sandbox?: PdfSandboxConfig;
fsPolicy?: ToolFsPolicy;
@@ -257,7 +259,11 @@ export function createPdfTool(options?: {
return null;
}
const pdfModelConfig = resolvePdfModelConfigForTool({ cfg: options?.config, agentDir });
const pdfModelConfig = resolvePdfModelConfigForTool({
cfg: options?.config,
agentDir,
authStore: options?.authProfileStore,
});
if (!pdfModelConfig) {
return null;
}

View File

@@ -29,6 +29,7 @@ import type {
VideoGenerationResolution,
VideoGenerationSourceAsset,
} from "../../video-generation/types.js";
import type { AuthProfileStore } from "../auth-profiles/types.js";
import { ToolInputError, readNumberParam, readStringParam } from "./common.js";
import { decodeDataUrl } from "./image-tool.helpers.js";
import { withMediaGenerationTaskKeepalive } from "./media-generate-background-shared.js";
@@ -225,10 +226,12 @@ const VideoGenerateToolSchema = Type.Object({
export function resolveVideoGenerationModelConfigForTool(params: {
cfg?: OpenClawConfig;
agentDir?: string;
authStore?: AuthProfileStore;
}): ToolModelConfig | null {
return resolveCapabilityModelConfigForTool({
cfg: params.cfg,
agentDir: params.agentDir,
authStore: params.authStore,
modelConfig: params.cfg?.agents?.defaults?.videoGenerationModel,
providers: listRuntimeVideoGenerationProviders({ config: params.cfg }),
});
@@ -795,6 +798,7 @@ async function executeVideoGenerationJob(params: {
export function createVideoGenerateTool(options?: {
config?: OpenClawConfig;
agentDir?: string;
authProfileStore?: AuthProfileStore;
agentSessionKey?: string;
requesterOrigin?: DeliveryContext;
workspaceDir?: string;
@@ -807,6 +811,7 @@ export function createVideoGenerateTool(options?: {
!hasGenerationToolAvailability({
cfg,
agentDir: options?.agentDir,
authStore: options?.authProfileStore,
modelConfig: cfg.agents?.defaults?.videoGenerationModel,
providerKey: "videoGenerationProviders",
})
@@ -846,6 +851,7 @@ export function createVideoGenerateTool(options?: {
const videoGenerationModelConfig = resolveVideoGenerationModelConfigForTool({
cfg,
agentDir: options?.agentDir,
authStore: options?.authProfileStore,
});
if (!videoGenerationModelConfig) {
throw new ToolInputError("No video-generation model configured.");