Files
openclaw/src/agents/tools/model-config.helpers.ts
2026-04-25 18:25:26 +01:00

103 lines
3.3 KiB
TypeScript

import {
resolveAgentModelFallbackValues,
resolveAgentModelPrimaryValue,
resolveAgentModelTimeoutMsValue,
} from "../../config/model-input.js";
import type { AgentModelConfig } from "../../config/types.agents-shared.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import {
ensureAuthProfileStore,
hasAnyAuthProfileStoreSource,
listProfilesForProvider,
} from "../auth-profiles.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../defaults.js";
import { resolveEnvApiKey } from "../model-auth.js";
import { resolveConfiguredModelRef } from "../model-selection.js";
export type ToolModelConfig = { primary?: string; fallbacks?: string[]; timeoutMs?: number };
export function hasToolModelConfig(model: ToolModelConfig | undefined): boolean {
return Boolean(
model?.primary?.trim() || (model?.fallbacks ?? []).some((entry) => entry.trim().length > 0),
);
}
export function resolveDefaultModelRef(cfg?: OpenClawConfig): { provider: string; model: string } {
if (cfg) {
const resolved = resolveConfiguredModelRef({
cfg,
defaultProvider: DEFAULT_PROVIDER,
defaultModel: DEFAULT_MODEL,
});
return { provider: resolved.provider, model: resolved.model };
}
return { provider: DEFAULT_PROVIDER, model: DEFAULT_MODEL };
}
export function hasAuthForProvider(params: { provider: string; agentDir?: string }): boolean {
if (resolveEnvApiKey(params.provider)?.apiKey) {
return true;
}
const agentDir = params.agentDir?.trim();
if (!agentDir) {
return false;
}
if (!hasAnyAuthProfileStoreSource(agentDir)) {
return false;
}
const store = ensureAuthProfileStore(agentDir, {
allowKeychainPrompt: false,
});
return listProfilesForProvider(store, params.provider).length > 0;
}
export function coerceToolModelConfig(model?: AgentModelConfig): ToolModelConfig {
const primary = resolveAgentModelPrimaryValue(model);
const fallbacks = resolveAgentModelFallbackValues(model);
const timeoutMs = resolveAgentModelTimeoutMsValue(model);
return {
...(primary?.trim() ? { primary: primary.trim() } : {}),
...(fallbacks.length > 0 ? { fallbacks } : {}),
...(timeoutMs !== undefined ? { timeoutMs } : {}),
};
}
export function buildToolModelConfigFromCandidates(params: {
explicit: ToolModelConfig;
agentDir?: string;
candidates: Array<string | null | undefined>;
isProviderConfigured?: (provider: string) => boolean;
}): ToolModelConfig | null {
if (hasToolModelConfig(params.explicit)) {
return params.explicit;
}
const deduped: string[] = [];
for (const candidate of params.candidates) {
const trimmed = candidate?.trim();
if (!trimmed || !trimmed.includes("/")) {
continue;
}
const provider = trimmed.slice(0, trimmed.indexOf("/")).trim();
const providerConfigured =
params.isProviderConfigured?.(provider) ??
hasAuthForProvider({ provider, agentDir: params.agentDir });
if (!provider || !providerConfigured) {
continue;
}
if (!deduped.includes(trimmed)) {
deduped.push(trimmed);
}
}
if (deduped.length === 0) {
return null;
}
return {
primary: deduped[0],
...(deduped.length > 1 ? { fallbacks: deduped.slice(1) } : {}),
...(params.explicit.timeoutMs !== undefined ? { timeoutMs: params.explicit.timeoutMs } : {}),
};
}