mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-12 17:20:44 +00:00
132 lines
4.5 KiB
TypeScript
132 lines
4.5 KiB
TypeScript
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
|
import {
|
|
bundledProviderSupportsNativePdfDocument,
|
|
resolveBundledAutoMediaKeyProviders,
|
|
resolveBundledDefaultMediaModel,
|
|
} from "../../media-understanding/bundled-defaults.js";
|
|
import {
|
|
coerceImageModelConfig,
|
|
type ImageModelConfig,
|
|
resolveProviderVisionModelFromConfig,
|
|
} from "./image-tool.helpers.js";
|
|
import { hasAuthForProvider, resolveDefaultModelRef } from "./model-config.helpers.js";
|
|
import { coercePdfModelConfig } from "./pdf-tool.helpers.js";
|
|
|
|
function resolveBundledImageCandidateRefs(params: {
|
|
cfg?: OpenClawConfig;
|
|
agentDir: string;
|
|
filter?: (providerId: string) => boolean;
|
|
}): string[] {
|
|
return resolveBundledAutoMediaKeyProviders("image")
|
|
.filter((providerId) => !params.filter || params.filter(providerId))
|
|
.filter((providerId) => hasAuthForProvider({ provider: providerId, agentDir: params.agentDir }))
|
|
.map((providerId) => {
|
|
const modelId =
|
|
resolveProviderVisionModelFromConfig({
|
|
cfg: params.cfg,
|
|
provider: providerId,
|
|
})?.split("/")[1] ??
|
|
resolveBundledDefaultMediaModel({
|
|
providerId,
|
|
capability: "image",
|
|
});
|
|
return modelId ? `${providerId}/${modelId}` : null;
|
|
})
|
|
.filter((value): value is string => Boolean(value));
|
|
}
|
|
|
|
export function resolvePdfModelConfigForTool(params: {
|
|
cfg?: OpenClawConfig;
|
|
agentDir: string;
|
|
}): ImageModelConfig | null {
|
|
const explicitPdf = coercePdfModelConfig(params.cfg);
|
|
if (explicitPdf.primary?.trim() || (explicitPdf.fallbacks?.length ?? 0) > 0) {
|
|
return explicitPdf;
|
|
}
|
|
|
|
const explicitImage = coerceImageModelConfig(params.cfg);
|
|
if (explicitImage.primary?.trim() || (explicitImage.fallbacks?.length ?? 0) > 0) {
|
|
return explicitImage;
|
|
}
|
|
|
|
const primary = resolveDefaultModelRef(params.cfg);
|
|
const googleOk = hasAuthForProvider({ provider: "google", agentDir: params.agentDir });
|
|
|
|
const fallbacks: string[] = [];
|
|
const addFallback = (ref: string) => {
|
|
const trimmed = ref.trim();
|
|
if (trimmed && !fallbacks.includes(trimmed)) {
|
|
fallbacks.push(trimmed);
|
|
}
|
|
};
|
|
|
|
let preferred: string | null = null;
|
|
|
|
const providerOk = hasAuthForProvider({ provider: primary.provider, agentDir: params.agentDir });
|
|
const providerVision = resolveProviderVisionModelFromConfig({
|
|
cfg: params.cfg,
|
|
provider: primary.provider,
|
|
});
|
|
const providerDefault =
|
|
providerVision?.split("/")[1] ??
|
|
resolveBundledDefaultMediaModel({
|
|
providerId: primary.provider,
|
|
capability: "image",
|
|
});
|
|
const primarySupportsNativePdf = bundledProviderSupportsNativePdfDocument(primary.provider);
|
|
const nativePdfCandidates = resolveBundledImageCandidateRefs({
|
|
cfg: params.cfg,
|
|
agentDir: params.agentDir,
|
|
filter: bundledProviderSupportsNativePdfDocument,
|
|
});
|
|
const genericImageCandidates = resolveBundledImageCandidateRefs({
|
|
cfg: params.cfg,
|
|
agentDir: params.agentDir,
|
|
});
|
|
|
|
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 })) {
|
|
continue;
|
|
}
|
|
const models = providerCfg?.models ?? [];
|
|
const modelId = models
|
|
.find(
|
|
(model) =>
|
|
Boolean(model?.id?.trim()) &&
|
|
Array.isArray(model?.input) &&
|
|
model.input.includes("image"),
|
|
)
|
|
?.id?.trim();
|
|
if (!modelId) {
|
|
continue;
|
|
}
|
|
const ref = `${providerId}/${modelId}`;
|
|
if (!genericImageCandidates.includes(ref)) {
|
|
genericImageCandidates.push(ref);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (primary.provider === "google" && googleOk && providerVision && primarySupportsNativePdf) {
|
|
preferred = providerVision;
|
|
} else if (providerOk && primarySupportsNativePdf && (providerVision || providerDefault)) {
|
|
preferred = providerVision ?? `${primary.provider}/${providerDefault}`;
|
|
} else {
|
|
preferred = nativePdfCandidates[0] ?? genericImageCandidates[0] ?? null;
|
|
}
|
|
|
|
if (preferred?.trim()) {
|
|
for (const candidate of [...nativePdfCandidates, ...genericImageCandidates]) {
|
|
if (candidate !== preferred) {
|
|
addFallback(candidate);
|
|
}
|
|
}
|
|
const pruned = fallbacks.filter((ref) => ref !== preferred);
|
|
return { primary: preferred, ...(pruned.length > 0 ? { fallbacks: pruned } : {}) };
|
|
}
|
|
|
|
return null;
|
|
}
|