UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

127 lines (126 loc) 6.85 kB
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import "./error-runtime-Bz9Tw57Z.js"; import { f as selectPreferredLocalModelId } from "./provider-model-shared-fX-Ywqb3.js"; import { p as normalizeOllamaCloudModelId } from "./defaults-BiE2_Zq0.js"; import { c as enrichOllamaModelsWithContext, f as isOllamaEmbeddingOnlyModel, h as mergeOllamaModelShowInfo, m as isReasoningModelHeuristic, p as isOllamaRemoteModel, r as buildOllamaModelDefinition, t as buildDefaultOllamaCloudModelDefinition, u as fetchOllamaModels, v as readOllamaModelShowInfo, y as resolveOllamaApiBase } from "./provider-models-BK60TdeT.js"; //#region extensions/ollama/src/setup-model-selection.ts const OLLAMA_CONTEXT_ENRICH_LIMIT = 200; const OLLAMA_TOOLS_SCAN_CONCURRENCY = 8; const OLLAMA_APP_GUIDED_MIN_CONTEXT_TOKENS = 16384; function normalizeOllamaModelName(value) { const trimmed = value?.trim(); if (!trimmed) return; return trimmed.toLowerCase().startsWith("ollama/") ? trimmed.slice(7).trim() || void 0 : trimmed; } function getOllamaLatestDedupeKey(name) { const normalized = name.trim().toLowerCase(); return normalized.endsWith(":latest") ? normalized.slice(0, -7) : normalized; } function mergeUniqueModelNames(...groups) { const mergedByKey = /* @__PURE__ */ new Map(); for (const group of groups) for (const name of group) { const key = getOllamaLatestDedupeKey(name); const existing = mergedByKey.get(key); if (existing === void 0 || !existing.trim().toLowerCase().endsWith(":latest") && name.trim().toLowerCase().endsWith(":latest")) mergedByKey.set(key, name); } return [...mergedByKey.values()]; } function findAvailableOllamaModelName(modelName, availableModelNames) { const wantedKey = getOllamaLatestDedupeKey(modelName); for (const available of availableModelNames) if (getOllamaLatestDedupeKey(available) === wantedKey) return available; } function orderPreferredOllamaModelIds(modelIds) { const remaining = [...modelIds]; const ordered = []; while (remaining.length > 0) { const preferredId = selectPreferredLocalModelId(remaining); const preferredIndex = preferredId ? remaining.indexOf(preferredId) : 0; const [candidate] = remaining.splice(Math.max(preferredIndex, 0), 1); if (candidate) ordered.push(candidate); } return ordered; } function selectAppGuidedOllamaModelId(models) { const eligible = [...models].filter((model) => model.supportsTools === true && model.contextWindow !== void 0 && model.contextWindow >= 16384); const nonReasoning = eligible.filter((model) => model.reasoning !== true); const pool = nonReasoning.length > 0 ? nonReasoning : eligible; const measuredSizes = pool.map((model) => model.size).filter((size) => typeof size === "number" && size > 0); const smallestSize = measuredSizes.length > 0 ? Math.min(...measuredSizes) : void 0; return orderPreferredOllamaModelIds((smallestSize === void 0 ? pool : pool.filter((model) => model.size === smallestSize)).map((model) => model.id))[0]; } function isOllamaToolsCapableModel(model) { return !isOllamaEmbeddingOnlyModel(model) && model.capabilities?.includes("tools") === true; } function selectAppGuidedOllamaModelFromDiscovery(models) { return selectAppGuidedOllamaModelId([...models].map((model) => ({ id: model.name, contextWindow: model.contextWindow, supportsTools: isOllamaToolsCapableModel(model), reasoning: model.capabilities?.includes("thinking") ?? isReasoningModelHeuristic(model.name), size: model.size }))); } function buildOllamaModelsConfig(modelNames, discoveredModelsByName, defaultModels = []) { return modelNames.map((name) => { const discovered = discoveredModelsByName?.get(name); const defaultModel = defaultModels.find((model) => model.id === normalizeOllamaCloudModelId(name)); if (defaultModel && !discovered && defaultModel.id === name) return buildDefaultOllamaCloudModelDefinition(defaultModel); const capabilities = discovered?.capabilities ?? (defaultModel ? [...defaultModel.capabilities] : void 0); return buildOllamaModelDefinition(name, discovered?.contextWindow ?? defaultModel?.contextWindow, capabilities, { showInspectionFailed: discovered?.showInspectionFailed }); }); } async function inspectOllamaModelsForSetup(baseUrl, models, signal) { const apiBase = resolveOllamaApiBase(baseUrl); const inspected = []; const inspectionFailures = []; for (let index = 0; index < models.length; index += OLLAMA_TOOLS_SCAN_CONCURRENCY) { signal?.throwIfAborted(); const batch = models.slice(index, index + OLLAMA_TOOLS_SCAN_CONCURRENCY); const results = await Promise.all(batch.map(async (model) => { try { const showInfo = await readOllamaModelShowInfo(apiBase, model.name, { timeoutMs: 3e3, signal, auditContext: "ollama-setup.tools-scan" }); return mergeOllamaModelShowInfo(model, showInfo); } catch (error) { signal?.throwIfAborted(); inspectionFailures.push(`${model.name}: ${formatErrorMessage(error)}`); return mergeOllamaModelShowInfo(model, { showInspectionFailed: true }); } })); inspected.push(...results); } return { inspected, inspectionFailures }; } async function discoverOllamaModelsForSetup(params) { const { reachable, models: listedModels } = await fetchOllamaModels(params.baseUrl, { signal: params.signal }); const models = params.includeRemoteModels === false ? listedModels.filter((model) => !isOllamaRemoteModel(model)) : listedModels; const firstModels = models.slice(0, OLLAMA_CONTEXT_ENRICH_LIMIT); const inspection = !reachable ? { inspected: [], inspectionFailures: [] } : params.inspectTools ? await inspectOllamaModelsForSetup(params.baseUrl, firstModels, params.signal) : { inspected: await enrichOllamaModelsWithContext(params.baseUrl, firstModels, { signal: params.signal }), inspectionFailures: [] }; if (params.inspectTools && !inspection.inspected.some(isOllamaToolsCapableModel) && models.length > OLLAMA_CONTEXT_ENRICH_LIMIT) { const remainingScan = await inspectOllamaModelsForSetup(params.baseUrl, models.slice(OLLAMA_CONTEXT_ENRICH_LIMIT), params.signal); inspection.inspected.push(...remainingScan.inspected); inspection.inspectionFailures.push(...remainingScan.inspectionFailures); } return { reachable, models, inspectedModels: inspection.inspected, discoveredModelsByName: new Map(inspection.inspected.map((model) => [model.name, model])), inspectionFailures: inspection.inspectionFailures, hasToolsCapableModel: inspection.inspected.some(isOllamaToolsCapableModel) }; } //#endregion export { inspectOllamaModelsForSetup as a, orderPreferredOllamaModelIds as c, findAvailableOllamaModelName as i, selectAppGuidedOllamaModelFromDiscovery as l, buildOllamaModelsConfig as n, mergeUniqueModelNames as o, discoverOllamaModelsForSetup as r, normalizeOllamaModelName as s, OLLAMA_APP_GUIDED_MIN_CONTEXT_TOKENS as t };