UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

218 lines (217 loc) 9.11 kB
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import { s as coerceSecretRef } from "./types.secrets-kC0nOetj.js"; import { s as isLoopbackHost } from "./net-DbNPs6Xm.js"; import "./string-coerce-runtime-GQa0ehRA.js"; import "./ssrf-runtime-Bum5C6NN.js"; import { r as getCachedLiveCatalogValue } from "./provider-catalog-shared-B4jeC2Nd.js"; import "./secret-input-runtime-Clavxxg-.js"; import { a as OLLAMA_DEFAULT_API_KEY, o as OLLAMA_DEFAULT_BASE_URL } from "./defaults-BiE2_Zq0.js"; import { t as readProviderBaseUrl } from "./provider-base-url-E6aWTKii.js"; import { y as resolveOllamaApiBase } from "./provider-models-BK60TdeT.js"; //#region extensions/ollama/src/discovery-shared.ts const OLLAMA_PROVIDER_ID = "ollama"; function readOllamaStringValue(value) { if (typeof value === "string") return normalizeOptionalString(value); if (value && typeof value === "object" && "value" in value) return normalizeOptionalString(value.value); } function isOllamaApiKeyMarker(value) { return value === "OLLAMA_API_KEY" || value === "ollama-local"; } function resolveOllamaRuntimeBaseUrl(params) { if (params.configuredBaseUrl && params.api && params.api !== "ollama") return params.configuredBaseUrl; return params.discoveredBaseUrl; } function resolveOllamaDiscoveryAuth(params) { const envValue = normalizeOptionalString(params.env.OLLAMA_API_KEY); const resolvedApiKey = normalizeOptionalString(params.resolvedAuth.apiKey); const resolvedDiscoveryApiKey = normalizeOptionalString(params.resolvedAuth.discoveryApiKey); const explicitRef = coerceSecretRef(params.explicitApiKey); const explicitApiKey = explicitRef ? resolvedDiscoveryApiKey : readOllamaStringValue(params.explicitApiKey); if (explicitRef && !explicitApiKey) return null; if (explicitApiKey && (explicitRef || !isOllamaApiKeyMarker(explicitApiKey))) return { apiKey: explicitRef ?? explicitApiKey, discoveryApiKey: explicitApiKey }; if (!isLocalOllamaBaseUrl(params.baseUrl)) { if (resolvedDiscoveryApiKey) return { apiKey: resolvedApiKey, discoveryApiKey: resolvedDiscoveryApiKey }; if (resolvedApiKey && !isOllamaApiKeyMarker(resolvedApiKey)) return { apiKey: resolvedApiKey, discoveryApiKey: resolvedApiKey }; return envValue && envValue !== "ollama-local" ? { apiKey: "OLLAMA_API_KEY", discoveryApiKey: envValue } : {}; } if (resolvedApiKey && resolvedApiKey !== envValue && !isOllamaApiKeyMarker(resolvedApiKey)) return { apiKey: resolvedApiKey, discoveryApiKey: resolvedDiscoveryApiKey ?? resolvedApiKey }; return { apiKey: OLLAMA_DEFAULT_API_KEY }; } function shouldSkipAmbientOllamaDiscovery(env) { return Boolean(env.VITEST) || env.NODE_ENV === "test"; } const LOCAL_OLLAMA_HOSTNAMES = /* @__PURE__ */ new Set([ "localhost", "0.0.0.0", "::1", "::", "docker.orb.internal", "host.docker.internal", "host.orb.internal" ]); const LOOPBACK_OLLAMA_HOSTNAMES = /* @__PURE__ */ new Set([ "localhost", "127.0.0.1", "0.0.0.0", "::1", "::" ]); function isIpv4PrivateRange(host) { if (!/^\d+\.\d+\.\d+\.\d+$/.test(host)) return false; const octets = host.split(".").map((part) => Number.parseInt(part, 10)); if (octets.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return false; const [a, b] = octets; if (a === void 0 || b === void 0) return false; return a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168; } function isIpv6LocalRange(host) { const lower = host.toLowerCase(); return /^fe[89ab][0-9a-f]:/.test(lower) || /^f[cd][0-9a-f]{2}:/.test(lower); } function isLocalOllamaBaseUrl(baseUrl) { if (!baseUrl) return true; let parsed; try { parsed = new URL(baseUrl); } catch { return false; } let host = parsed.hostname.toLowerCase(); if (host.startsWith("[") && host.endsWith("]")) host = host.slice(1, -1); return LOCAL_OLLAMA_HOSTNAMES.has(host) || isLoopbackHost(host) || host.endsWith(".local") || isIpv4PrivateRange(host) || isIpv6LocalRange(host) || !host.includes(".") && !host.includes(":"); } const HOSTED_OLLAMA_CLOUD_HOSTNAMES = /* @__PURE__ */ new Set(["ollama.com", "api.ollama.com"]); function isHostedOllamaCloud(baseUrl) { if (!baseUrl) return false; let parsed; try { parsed = new URL(baseUrl); } catch { return false; } const host = parsed.hostname.toLowerCase(); return HOSTED_OLLAMA_CLOUD_HOSTNAMES.has(host) || host.endsWith(".ollama.com"); } function isLoopbackOllamaBaseUrl(baseUrl) { if (!baseUrl) return true; let parsed; try { parsed = new URL(baseUrl); } catch { return false; } let host = parsed.hostname.toLowerCase(); if (host.startsWith("[") && host.endsWith("]")) host = host.slice(1, -1); return LOOPBACK_OLLAMA_HOSTNAMES.has(host) || isLoopbackHost(host); } function hasExplicitRemoteOllamaApiProvider(providers) { if (!providers) return false; for (const [providerId, provider] of Object.entries(providers)) { if (providerId === "ollama" || !provider) continue; if (normalizeOptionalString(provider.api)?.toLowerCase() !== "ollama") continue; const baseUrl = readProviderBaseUrl(provider); if (baseUrl && !isLoopbackOllamaBaseUrl(baseUrl)) return true; } return false; } function shouldUseSyntheticOllamaAuth(providerConfig) { const apiKey = readOllamaStringValue(providerConfig?.apiKey); if (coerceSecretRef(providerConfig?.apiKey) || apiKey && !isOllamaApiKeyMarker(apiKey) || !hasMeaningfulExplicitOllamaConfig(providerConfig)) return false; return isLocalOllamaBaseUrl(readProviderBaseUrl(providerConfig)); } function hasMeaningfulExplicitOllamaConfig(providerConfig) { if (!providerConfig) return false; if (Array.isArray(providerConfig.models) && providerConfig.models.length > 0) return true; const baseUrl = readProviderBaseUrl(providerConfig); if (baseUrl) return resolveOllamaApiBase(baseUrl) !== OLLAMA_DEFAULT_BASE_URL; if (readOllamaStringValue(providerConfig.apiKey)) return true; if (providerConfig.auth) return true; if (typeof providerConfig.authHeader === "boolean") return true; if (providerConfig.headers && typeof providerConfig.headers === "object" && Object.keys(providerConfig.headers).length > 0) return true; if (providerConfig.request) return true; if (typeof providerConfig.injectNumCtxForOpenAICompat === "boolean") return true; return false; } async function resolveOllamaDiscoveryResult(params) { const explicit = params.ctx.config.models?.providers?.ollama; const hasExplicitModels = Array.isArray(explicit?.models) && explicit.models.length > 0; const hasMeaningfulExplicitConfig = hasMeaningfulExplicitOllamaConfig(explicit); const hasRemoteOllamaApiProvider = hasExplicitRemoteOllamaApiProvider(params.ctx.config.models?.providers); const discoveryEnabled = params.pluginConfig.discovery?.enabled; if (!hasExplicitModels && discoveryEnabled === false) return null; const configuredBaseUrl = readProviderBaseUrl(explicit); if (!hasExplicitModels && configuredBaseUrl && isHostedOllamaCloud(configuredBaseUrl)) return null; const resolvedOllamaAuth = params.ctx.resolveProviderApiKey(OLLAMA_PROVIDER_ID); const ollamaKey = resolvedOllamaAuth.apiKey; const hasOllamaDiscoveryOptIn = typeof ollamaKey === "string" && ollamaKey.trim().length > 0; const hasRealOllamaKey = typeof ollamaKey === "string" && ollamaKey.trim().length > 0 && ollamaKey.trim() !== "ollama-local"; const auth = resolveOllamaDiscoveryAuth({ env: params.ctx.env, baseUrl: configuredBaseUrl, explicitApiKey: explicit?.apiKey, resolvedAuth: resolvedOllamaAuth }); if (!auth) return null; const { apiKey, discoveryApiKey } = auth; if (hasExplicitModels && explicit) { const discoveredBaseUrl = resolveOllamaApiBase(configuredBaseUrl); const api = explicit.api ?? "ollama"; return { provider: { ...explicit, models: explicit.models ?? [], baseUrl: resolveOllamaRuntimeBaseUrl({ api, configuredBaseUrl, discoveredBaseUrl }), api, ...apiKey ? { apiKey } : {} } }; } if (!hasMeaningfulExplicitConfig && hasRemoteOllamaApiProvider) return null; if (!hasOllamaDiscoveryOptIn && !hasMeaningfulExplicitConfig) return null; if (!hasRealOllamaKey && !hasMeaningfulExplicitConfig && shouldSkipAmbientOllamaDiscovery(params.ctx.env)) return null; const quiet = !hasRealOllamaKey && !hasMeaningfulExplicitConfig; const provider = await getCachedLiveCatalogValue({ keyParts: [ OLLAMA_PROVIDER_ID, "models", resolveOllamaApiBase(configuredBaseUrl), discoveryApiKey, quiet ], load: async () => await params.buildProvider(configuredBaseUrl, { quiet, ...discoveryApiKey ? { apiKey: discoveryApiKey } : {} }) }); if (provider.models?.length === 0 && !ollamaKey && !explicit?.apiKey) return null; const api = explicit?.api ?? provider.api; return { provider: { ...provider, baseUrl: resolveOllamaRuntimeBaseUrl({ api, configuredBaseUrl, discoveredBaseUrl: provider.baseUrl }), api, ...apiKey ? { apiKey } : {} } }; } //#endregion export { shouldUseSyntheticOllamaAuth as a, resolveOllamaRuntimeBaseUrl as i, isLocalOllamaBaseUrl as n, resolveOllamaDiscoveryResult as r, OLLAMA_PROVIDER_ID as t };