UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

241 lines (240 loc) 10.2 kB
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { F as buildRemoteBaseUrlPolicy } from "./gateway-startup-plugin-config-Bq9ZdScF.js"; import { d as normalizeProviderId } from "./provider-model-shared-fX-Ywqb3.js"; import "./ssrf-runtime-Bum5C6NN.js"; import "./logging-core-yEitd9NN.js"; import { a as normalizeEmbeddingModelWithPrefixes, f as embeddingProviderOwnsDestination, l as sanitizeEmbeddingCacheHeaders, n as createRemoteEmbeddingProvider } from "./memory-core-host-engine-embeddings-DwuZ1cl_.js"; import { n as resolveMemorySecretInputString } from "./secret-input-B_UskQwz.js"; import "./memory-core-host-secret-Bq5o_pya.js"; import { L as LMSTUDIO_PROVIDER_ID, S as resolveLmstudioInferenceBase, T as resolveLmstudioServerBase, d as hasLmstudioAuthorizationHeader, i as buildLmstudioAuthHeaders, k as LMSTUDIO_DEFAULT_EMBEDDING_MODEL, l as resolveLmstudioRuntimeApiKey, n as ensureLmstudioModelLoaded, o as resolveLmstudioConfiguredApiKeyForProvider, r as fetchLmstudioModels, s as resolveLmstudioProviderHeaders, u as sanitizeLmstudioStringHeaders, v as normalizeLmstudioConfiguredCatalogEntries, x as resolveLmstudioCanonicalModelKey } from "./models.fetch-DL1dYWdZ.js"; //#region extensions/lmstudio/src/embedding-provider.ts const log = createSubsystemLogger("memory/embeddings"); const DEFAULT_LMSTUDIO_EMBEDDING_MODEL = LMSTUDIO_DEFAULT_EMBEDDING_MODEL; /** Normalizes LM Studio embedding model refs and accepts `lmstudio/` prefix. */ function normalizeLmstudioModel(model, providerId) { return normalizeEmbeddingModelWithPrefixes({ model, defaultModel: DEFAULT_LMSTUDIO_EMBEDDING_MODEL, prefixes: [`${providerId?.trim() || "lmstudio"}/`, `${LMSTUDIO_PROVIDER_ID}/`] }); } /** Resolves API key (real or synthetic placeholder) from runtime/provider auth config. */ async function resolveLmstudioApiKey(options, providerId) { const selectedProviderId = providerId?.trim(); const selectedApiKey = selectedProviderId && selectedProviderId !== "lmstudio" ? options.config.models?.providers?.[selectedProviderId]?.apiKey : void 0; if (selectedProviderId && selectedProviderId !== "lmstudio") return selectedApiKey === void 0 || selectedApiKey === null ? void 0 : await resolveLmstudioConfiguredApiKeyForProvider({ providerId: selectedProviderId, config: options.config, env: process.env }); try { return await resolveLmstudioRuntimeApiKey({ config: options.config, agentDir: options.agentDir }); } catch (error) { if (/LM Studio API key is required/i.test(formatErrorMessage(error))) return; throw error; } } function resolveEmbeddingPreloadContextLength(params) { const configuredModel = normalizeLmstudioConfiguredCatalogEntries(params.models).find((entry) => normalizeLmstudioModel(entry.id) === params.model); if (configuredModel?.contextTokens !== void 0) return configuredModel.contextTokens; return configuredModel?.contextWindow; } function resolveConfiguredLmstudioProvider(options) { const providers = options.config.models?.providers; if (!providers) return; const providerId = options.provider?.trim() || "lmstudio"; const direct = providers[providerId]; if (direct) return { providerId, config: direct }; const normalized = normalizeProviderId(providerId); for (const [candidateId, candidate] of Object.entries(providers)) if (normalizeProviderId(candidateId) === normalized) return { providerId: candidateId, config: candidate }; const fallback = providers[LMSTUDIO_PROVIDER_ID]; return fallback ? { providerId: LMSTUDIO_PROVIDER_ID, config: fallback } : void 0; } function resolveLmstudioLocalServiceBaseUrl(configuredBaseUrl, inferenceBaseUrl) { const configured = configuredBaseUrl?.trim(); if (!configured) return inferenceBaseUrl; const configuredPath = configured.replace(/[?#].*$/u, "").replace(/\/+$/u, ""); const serverBaseUrl = resolveLmstudioServerBase(configured); return /\/api\/v1$/iu.test(configuredPath) ? `${serverBaseUrl}/api/v1` : `${serverBaseUrl}/v1`; } function resolveLmstudioEmbeddingBaseUrl(configuredBaseUrl) { const query = configuredBaseUrl?.match(/\?[^#]*/u)?.[0] ?? ""; return `${resolveLmstudioInferenceBase(configuredBaseUrl)}${query}`; } async function resolveLmstudioEmbeddingModelKey(params) { const discovered = await fetchLmstudioModels({ baseUrl: params.baseUrl, apiKey: params.apiKey, headers: params.headers, ssrfPolicy: params.ssrfPolicy }); if (!discovered.reachable || discovered.status !== void 0 && discovered.status >= 400) return params.model; return resolveLmstudioCanonicalModelKey({ modelKey: params.model, models: discovered.models }); } /** Creates the LM Studio embedding provider client and preloads the target model before return. */ async function createLmstudioEmbeddingProvider(options) { const resolvedProvider = resolveConfiguredLmstudioProvider(options); const providerConfig = resolvedProvider?.config; const providerBaseUrl = providerConfig?.baseUrl?.trim(); const isFallbackActivation = options.fallback === "lmstudio" && options.provider !== "lmstudio"; const remoteBaseUrl = options.remote?.baseUrl?.trim(); const remoteApiKey = !isFallbackActivation ? resolveMemorySecretInputString({ value: options.remote?.apiKey, path: "memory.search.remote.apiKey" }) : void 0; const baseUrlSource = !isFallbackActivation ? remoteBaseUrl : void 0; const baseUrl = resolveLmstudioEmbeddingBaseUrl(baseUrlSource && baseUrlSource.length > 0 ? baseUrlSource : providerBaseUrl && providerBaseUrl.length > 0 ? providerBaseUrl : void 0); const providerOwnedBaseUrl = resolveLmstudioEmbeddingBaseUrl(providerBaseUrl); const providerOwnsDestination = !baseUrlSource || embeddingProviderOwnsDestination({ baseUrl, providerBaseUrl: providerOwnedBaseUrl }); const model = normalizeLmstudioModel(options.model, resolvedProvider?.providerId); const providerHeaders = providerOwnsDestination ? await resolveLmstudioProviderHeaders({ config: options.config, env: process.env, headers: providerConfig?.headers }) : void 0; const headerOverrides = Object.assign({}, providerHeaders, !isFallbackActivation ? sanitizeLmstudioStringHeaders(options.remote?.headers) : void 0); const apiKey = hasLmstudioAuthorizationHeader(headerOverrides) ? void 0 : !isFallbackActivation ? remoteApiKey?.trim() || (providerOwnsDestination ? await resolveLmstudioApiKey(options, resolvedProvider?.providerId) : void 0) : await resolveLmstudioApiKey(options, resolvedProvider?.providerId); const headers = buildLmstudioAuthHeaders({ apiKey, json: true, headers: headerOverrides }) ?? {}; const ssrfPolicy = buildRemoteBaseUrlPolicy(baseUrl); const client = { baseUrl, model, headers, ssrfPolicy }; const requestedContextLength = resolveEmbeddingPreloadContextLength({ model, models: providerConfig?.models }); const localServiceTarget = providerConfig?.localService && !baseUrlSource ? { providerId: resolvedProvider?.providerId ?? "lmstudio", baseUrl: resolveLmstudioLocalServiceBaseUrl(providerBaseUrl, baseUrl), headers } : void 0; const acquireLocalService = options.acquireLocalService; const withLocalServiceLease = async (signal, action) => { const lease = localServiceTarget && acquireLocalService ? await acquireLocalService(localServiceTarget, signal) : void 0; try { return await action(); } finally { lease?.release(); } }; if (providerConfig?.params?.preload !== false) await withLocalServiceLease(void 0, async () => { try { client.model = await ensureLmstudioModelLoaded({ baseUrl, apiKey, headers: headerOverrides, ssrfPolicy, modelKey: model, requestedContextLength, timeoutMs: 12e4 }); } catch (error) { if (error instanceof Error && "resolvedModelKey" in error) { const resolvedModelKey = error.resolvedModelKey; if (typeof resolvedModelKey === "string" && resolvedModelKey.trim()) client.model = resolvedModelKey.trim(); } log.warn("lmstudio embeddings warmup failed; continuing without preload", { baseUrl, model, error: formatErrorMessage(error) }); } }); else if (model.includes("@")) try { await withLocalServiceLease(void 0, async () => { client.model = await resolveLmstudioEmbeddingModelKey({ baseUrl, apiKey, headers: headerOverrides, ssrfPolicy, model }); }); } catch (error) { log.debug("lmstudio embedding variant discovery failed; using requested model", { baseUrl, model, error: formatErrorMessage(error) }); } const remoteProvider = createRemoteEmbeddingProvider({ id: LMSTUDIO_PROVIDER_ID, client, errorPrefix: "lmstudio embeddings failed" }); const embed = async (input, callOptions) => await withLocalServiceLease(callOptions?.signal, async () => { return await remoteProvider.embed(input, callOptions); }); const embedBatch = async (inputs, callOptions) => { if (callOptions?.inputType === "query") return await Promise.all(inputs.map((input) => embed(input, callOptions))); return await withLocalServiceLease(callOptions?.signal, async () => { return await remoteProvider.embedBatch(inputs, callOptions); }); }; return { provider: { ...remoteProvider, embed, embedBatch }, client }; } //#endregion //#region extensions/lmstudio/memory-embedding-adapter.ts const lmstudioMemoryEmbeddingProviderAdapter = { id: "lmstudio", defaultModel: DEFAULT_LMSTUDIO_EMBEDDING_MODEL, transport: "remote", authProviderId: "lmstudio", allowExplicitWhenConfiguredAuto: true, create: async (options) => { const providerId = options.provider?.trim() || "lmstudio"; const { provider, client } = await createLmstudioEmbeddingProvider({ ...options, provider: providerId, fallback: "none" }); return { provider, runtime: { id: "lmstudio", inlineBatchTimeoutMs: 6e5, cacheKeyData: { provider: providerId, baseUrl: client.baseUrl, model: client.model, headers: sanitizeEmbeddingCacheHeaders(client.headers, ["authorization", "x-api-key"]) } } }; } }; //#endregion export { lmstudioMemoryEmbeddingProviderAdapter as t };