openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
126 lines (125 loc) • 6.67 kB
JavaScript
import { l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs";
import { a as asOptionalRecord } from "./record-coerce-TIsquoVR.mjs";
import { r as normalizeProviderId } from "./provider-id-D1VImdKk.mjs";
import { t as splitTrailingAuthProfile } from "./model-ref-profile-BNjB2hED.mjs";
import { r as isModelThinkingFormat } from "./model-config-vocabulary-Cb5jWCSz.mjs";
import "./types.models-BqvzicE8.mjs";
import { n as modelTransportRoutesMatch } from "./model-compat-catalog-Dfj3P1T4.mjs";
import { i as resolveProviderModelPolicySurface, r as resolveProviderModelCatalogId } from "./provider-model-routes-C609Pdvh.mjs";
import { t as canonicalizeProviderModelId } from "./provider-model-route-Bjk37zK0.mjs";
import { t as createModelCatalogIdentityKeyResolver } from "./openai-model-routes-C1mdGNT1.mjs";
//#region src/agents/model-catalog-lookup.ts
/**
* Looks up model catalog entries and input capability support.
*/
/** Projects only thinking policy fields from broader model compatibility metadata. */
function projectModelThinkingCompat(compat) {
const record = asOptionalRecord(compat);
if (!record) return;
const projected = {};
if (typeof record.thinkingFormat === "string" && isModelThinkingFormat(record.thinkingFormat)) projected.thinkingFormat = record.thinkingFormat;
if (record.supportedReasoningEfforts === null) projected.supportedReasoningEfforts = null;
else if (Array.isArray(record.supportedReasoningEfforts) && record.supportedReasoningEfforts.every((effort) => typeof effort === "string")) projected.supportedReasoningEfforts = [...record.supportedReasoningEfforts];
return Object.keys(projected).length > 0 ? projected : void 0;
}
/** Freezes thinking capability from the selected prepared catalog row. */
function prepareModelThinkingCapability(params) {
const compat = projectModelThinkingCompat(params.entry?.compat);
const provider = normalizeProviderId(params.entry?.provider ?? "");
const modelId = normalizeOptionalString(params.entry?.id);
const agentRuntime = normalizeLowercaseStringOrEmpty(params.agentRuntime);
if (!compat || !provider || !modelId || !agentRuntime) return;
const routeSource = params.route ?? (agentRuntime === "openclaw" ? params.entry : void 0);
const api = normalizeOptionalString(routeSource?.api);
const baseUrl = normalizeOptionalString(routeSource?.baseUrl);
if (agentRuntime === "openclaw" && (!api || !baseUrl)) return;
return {
provider,
modelId,
agentRuntime,
...api && baseUrl ? { route: {
api,
baseUrl
} } : {},
compat
};
}
/** Resolves prepared thinking metadata only for the exact final model route and harness. */
function resolvePreparedModelThinkingCompat(params) {
const capability = params.capability;
if (!capability) return;
const runtimeModelId = canonicalizeProviderModelId(capability.provider, params.model.id);
const preparedModelId = canonicalizeProviderModelId(capability.provider, capability.modelId);
if (normalizeProviderId(params.model.provider) !== capability.provider || runtimeModelId !== preparedModelId || normalizeLowercaseStringOrEmpty(params.agentRuntime) !== capability.agentRuntime || capability.route && !modelTransportRoutesMatch(params.model, capability.route)) return;
const { supportedReasoningEfforts: efforts, ...compat } = capability.compat;
if (efforts === void 0) return compat;
const routeEfforts = projectModelThinkingCompat(params.model.compat)?.supportedReasoningEfforts;
const enabledEfforts = efforts?.filter((effort) => effort !== "none");
return {
...compat,
supportedReasoningEfforts: capability.route ? efforts?.slice() : routeEfforts?.includes("none") ? ["none", ...enabledEfforts ?? []] : enabledEfforts
};
}
/** Projects the prepared capabilities needed by one selected run candidate. */
function prepareModelRunCapabilities([catalog, configuredCatalog], [provider, modelId, agentRuntime]) {
const entry = findModelInCatalog(catalog ?? [], provider, modelId);
const configuredEntry = findModelInCatalog(configuredCatalog, provider, modelId);
return {
modelHasVision: modelSupportsInput(entry, "image"),
modelThinkingCapability: prepareModelThinkingCapability({
entry: entry ?? configuredEntry,
route: agentRuntime === "openclaw" ? configuredEntry ?? entry : void 0,
agentRuntime
})
};
}
/** Returns whether a catalog entry declares support for an input modality. */
function modelSupportsInput(entry, input) {
return entry?.input?.includes(input) ?? false;
}
/** Prefers canonical identity; the shipped SDK's case-insensitive fallback must be unique. */
function findModelInCatalog(catalog, provider, modelId) {
const normalizedProvider = normalizeProviderId(provider);
const trimmedModelId = modelId.trim();
const providerCatalog = [];
let literal;
catalog.some((entry) => {
if (normalizeProviderId(entry.provider) !== normalizedProvider) return false;
if (entry.id === trimmedModelId) {
literal = entry;
return true;
}
providerCatalog.push(entry);
return false;
});
if (literal) return literal;
const surface = resolveProviderModelPolicySurface(normalizedProvider);
const identityOf = (id) => resolveProviderModelCatalogId({
provider: normalizedProvider,
modelId: splitTrailingAuthProfile(id).model,
surface
}) ?? id;
const identity = identityOf(trimmedModelId);
const exact = providerCatalog.find((entry) => identityOf(entry.id) === identity);
if (exact) return exact;
const normalizedModelId = normalizeLowercaseStringOrEmpty(modelId);
const matches = providerCatalog.filter((entry) => normalizeLowercaseStringOrEmpty(entry.id) === normalizedModelId);
return matches.length === 1 ? matches[0] : void 0;
}
/** Finds a model entry, requiring uniqueness when provider is omitted. */
function findModelCatalogEntry(catalog, params) {
const modelId = normalizeOptionalString(params.modelId) ?? "";
if (!modelId) return;
const provider = normalizeOptionalString(params.provider);
if (provider) return findModelInCatalog(catalog, provider, modelId);
const keyOf = createModelCatalogIdentityKeyResolver();
const exact = catalog.filter((entry) => keyOf(entry) === keyOf({
provider: entry.provider,
id: modelId
}));
const normalizedModelId = normalizeLowercaseStringOrEmpty(modelId);
const matches = exact.length ? exact : catalog.filter((entry) => normalizeLowercaseStringOrEmpty(entry.id) === normalizedModelId);
return matches.length === 1 ? matches[0] : void 0;
}
//#endregion
export { projectModelThinkingCompat as a, prepareModelRunCapabilities as i, findModelInCatalog as n, resolvePreparedModelThinkingCompat as o, modelSupportsInput as r, findModelCatalogEntry as t };