mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:30:42 +00:00
refactor: share ollama discovery logic
This commit is contained in:
@@ -7,24 +7,25 @@ import {
|
||||
type ProviderDiscoveryContext,
|
||||
} from "openclaw/plugin-sdk/plugin-entry";
|
||||
import { buildApiKeyCredential } from "openclaw/plugin-sdk/provider-auth";
|
||||
import {
|
||||
OPENAI_COMPATIBLE_REPLAY_HOOKS,
|
||||
type ModelProviderConfig,
|
||||
} from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { OPENAI_COMPATIBLE_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import {
|
||||
buildOllamaProvider,
|
||||
configureOllamaNonInteractive,
|
||||
ensureOllamaModelPulled,
|
||||
promptAndConfigureOllama,
|
||||
} from "./api.js";
|
||||
import { OLLAMA_DEFAULT_BASE_URL } from "./src/defaults.js";
|
||||
import {
|
||||
OLLAMA_DEFAULT_API_KEY,
|
||||
OLLAMA_PROVIDER_ID,
|
||||
hasMeaningfulExplicitOllamaConfig,
|
||||
resolveOllamaDiscoveryResult,
|
||||
type OllamaPluginConfig,
|
||||
} from "./src/discovery-shared.js";
|
||||
import {
|
||||
DEFAULT_OLLAMA_EMBEDDING_MODEL,
|
||||
createOllamaEmbeddingProvider,
|
||||
} from "./src/embedding-provider.js";
|
||||
import { ollamaMemoryEmbeddingProviderAdapter } from "./src/memory-embedding-adapter.js";
|
||||
import { resolveOllamaApiBase } from "./src/provider-models.js";
|
||||
import {
|
||||
createConfiguredOllamaCompatStreamWrapper,
|
||||
createConfiguredOllamaStreamFn,
|
||||
@@ -33,67 +34,6 @@ import {
|
||||
} from "./src/stream.js";
|
||||
import { createOllamaWebSearchProvider } from "./src/web-search-provider.js";
|
||||
|
||||
const PROVIDER_ID = "ollama";
|
||||
const DEFAULT_API_KEY = "ollama-local";
|
||||
|
||||
type OllamaPluginConfig = {
|
||||
discovery?: {
|
||||
enabled?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
type OllamaProviderLikeConfig = ModelProviderConfig;
|
||||
|
||||
function resolveOllamaDiscoveryApiKey(params: {
|
||||
env: NodeJS.ProcessEnv;
|
||||
explicitApiKey?: string;
|
||||
resolvedApiKey?: string;
|
||||
}): string {
|
||||
const envApiKey = params.env.OLLAMA_API_KEY?.trim() ? "OLLAMA_API_KEY" : undefined;
|
||||
const explicitApiKey = normalizeOptionalString(params.explicitApiKey);
|
||||
const resolvedApiKey = normalizeOptionalString(params.resolvedApiKey);
|
||||
return envApiKey ?? explicitApiKey ?? resolvedApiKey ?? DEFAULT_API_KEY;
|
||||
}
|
||||
|
||||
function shouldSkipAmbientOllamaDiscovery(env: NodeJS.ProcessEnv): boolean {
|
||||
return Boolean(env.VITEST) || env.NODE_ENV === "test";
|
||||
}
|
||||
|
||||
function hasMeaningfulExplicitOllamaConfig(providerConfig?: OllamaProviderLikeConfig): boolean {
|
||||
if (!providerConfig) {
|
||||
return false;
|
||||
}
|
||||
if (Array.isArray(providerConfig.models) && providerConfig.models.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (typeof providerConfig.baseUrl === "string" && providerConfig.baseUrl.trim()) {
|
||||
return resolveOllamaApiBase(providerConfig.baseUrl) !== OLLAMA_DEFAULT_BASE_URL;
|
||||
}
|
||||
if (readStringValue(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;
|
||||
}
|
||||
|
||||
function usesOllamaOpenAICompatTransport(model: {
|
||||
api?: unknown;
|
||||
provider?: unknown;
|
||||
@@ -118,7 +58,7 @@ export default definePluginEntry({
|
||||
const pluginConfig = (api.pluginConfig ?? {}) as OllamaPluginConfig;
|
||||
api.registerWebSearchProvider(createOllamaWebSearchProvider());
|
||||
api.registerProvider({
|
||||
id: PROVIDER_ID,
|
||||
id: OLLAMA_PROVIDER_ID,
|
||||
label: "Ollama",
|
||||
docsPath: "/providers/ollama",
|
||||
envVars: ["OLLAMA_API_KEY"],
|
||||
@@ -142,7 +82,7 @@ export default definePluginEntry({
|
||||
{
|
||||
profileId: "ollama:default",
|
||||
credential: buildApiKeyCredential(
|
||||
PROVIDER_ID,
|
||||
OLLAMA_PROVIDER_ID,
|
||||
result.credential,
|
||||
undefined,
|
||||
result.credentialMode
|
||||
@@ -172,63 +112,12 @@ export default definePluginEntry({
|
||||
],
|
||||
discovery: {
|
||||
order: "late",
|
||||
run: async (ctx: ProviderDiscoveryContext) => {
|
||||
const explicit = ctx.config.models?.providers?.ollama;
|
||||
const hasExplicitModels = Array.isArray(explicit?.models) && explicit.models.length > 0;
|
||||
const hasMeaningfulExplicitConfig = hasMeaningfulExplicitOllamaConfig(explicit);
|
||||
const discoveryEnabled =
|
||||
pluginConfig.discovery?.enabled ?? ctx.config.models?.ollamaDiscovery?.enabled;
|
||||
if (!hasExplicitModels && discoveryEnabled === false) {
|
||||
return null;
|
||||
}
|
||||
const ollamaKey = ctx.resolveProviderApiKey(PROVIDER_ID).apiKey;
|
||||
const hasRealOllamaKey =
|
||||
typeof ollamaKey === "string" &&
|
||||
ollamaKey.trim().length > 0 &&
|
||||
ollamaKey.trim() !== DEFAULT_API_KEY;
|
||||
const explicitApiKey = readStringValue(explicit?.apiKey);
|
||||
if (hasExplicitModels && explicit) {
|
||||
return {
|
||||
provider: {
|
||||
...explicit,
|
||||
baseUrl:
|
||||
typeof explicit.baseUrl === "string" && explicit.baseUrl.trim()
|
||||
? resolveOllamaApiBase(explicit.baseUrl)
|
||||
: OLLAMA_DEFAULT_BASE_URL,
|
||||
api: explicit.api ?? "ollama",
|
||||
apiKey: resolveOllamaDiscoveryApiKey({
|
||||
env: ctx.env,
|
||||
explicitApiKey,
|
||||
resolvedApiKey: ollamaKey,
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
if (
|
||||
!hasRealOllamaKey &&
|
||||
!hasMeaningfulExplicitConfig &&
|
||||
shouldSkipAmbientOllamaDiscovery(ctx.env)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const provider = await buildOllamaProvider(explicit?.baseUrl, {
|
||||
quiet: !hasRealOllamaKey && !hasMeaningfulExplicitConfig,
|
||||
});
|
||||
if (provider.models.length === 0 && !ollamaKey && !explicit?.apiKey) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
provider: {
|
||||
...provider,
|
||||
apiKey: resolveOllamaDiscoveryApiKey({
|
||||
env: ctx.env,
|
||||
explicitApiKey,
|
||||
resolvedApiKey: ollamaKey,
|
||||
}),
|
||||
},
|
||||
};
|
||||
},
|
||||
run: async (ctx: ProviderDiscoveryContext) =>
|
||||
await resolveOllamaDiscoveryResult({
|
||||
ctx,
|
||||
pluginConfig,
|
||||
buildProvider: buildOllamaProvider,
|
||||
}),
|
||||
},
|
||||
wizard: {
|
||||
setup: {
|
||||
@@ -287,13 +176,13 @@ export default definePluginEntry({
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
apiKey: DEFAULT_API_KEY,
|
||||
apiKey: OLLAMA_DEFAULT_API_KEY,
|
||||
source: "models.providers.ollama (synthetic local key)",
|
||||
mode: "api-key",
|
||||
};
|
||||
},
|
||||
shouldDeferSyntheticProfileAuth: ({ resolvedApiKey }) =>
|
||||
resolvedApiKey?.trim() === DEFAULT_API_KEY,
|
||||
resolvedApiKey?.trim() === OLLAMA_DEFAULT_API_KEY,
|
||||
buildUnknownModelHint: () =>
|
||||
"Ollama requires authentication to be registered as a provider. " +
|
||||
'Set OLLAMA_API_KEY="ollama-local" (any value works) or run "openclaw configure". ' +
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { ProviderCatalogContext } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { OLLAMA_DEFAULT_BASE_URL } from "./src/defaults.js";
|
||||
import {
|
||||
OLLAMA_PROVIDER_ID,
|
||||
resolveOllamaDiscoveryResult,
|
||||
type OllamaPluginConfig,
|
||||
} from "./src/discovery-shared.js";
|
||||
import {
|
||||
buildOllamaModelDefinition,
|
||||
enrichOllamaModelsWithContext,
|
||||
@@ -8,17 +12,8 @@ import {
|
||||
resolveOllamaApiBase,
|
||||
} from "./src/provider-models.js";
|
||||
|
||||
const PROVIDER_ID = "ollama";
|
||||
const DEFAULT_API_KEY = "ollama-local";
|
||||
const OLLAMA_CONTEXT_ENRICH_LIMIT = 200;
|
||||
|
||||
type OllamaPluginConfig = {
|
||||
discovery?: {
|
||||
enabled?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
type OllamaProviderLikeConfig = ModelProviderConfig;
|
||||
type OllamaProviderPlugin = {
|
||||
id: string;
|
||||
label: string;
|
||||
@@ -31,70 +26,6 @@ type OllamaProviderPlugin = {
|
||||
};
|
||||
};
|
||||
|
||||
function normalizeOptionalString(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
function readStringValue(value: unknown): string | undefined {
|
||||
if (typeof value === "string") {
|
||||
return normalizeOptionalString(value);
|
||||
}
|
||||
if (value && typeof value === "object" && "value" in value) {
|
||||
return normalizeOptionalString((value as { value?: unknown }).value);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveOllamaDiscoveryApiKey(params: {
|
||||
env: NodeJS.ProcessEnv;
|
||||
explicitApiKey?: string;
|
||||
resolvedApiKey?: string;
|
||||
}): string {
|
||||
const envApiKey = params.env.OLLAMA_API_KEY?.trim() ? "OLLAMA_API_KEY" : undefined;
|
||||
return envApiKey ?? params.explicitApiKey ?? params.resolvedApiKey ?? DEFAULT_API_KEY;
|
||||
}
|
||||
|
||||
function shouldSkipAmbientOllamaDiscovery(env: NodeJS.ProcessEnv): boolean {
|
||||
return Boolean(env.VITEST) || env.NODE_ENV === "test";
|
||||
}
|
||||
|
||||
function hasMeaningfulExplicitOllamaConfig(
|
||||
providerConfig: OllamaProviderLikeConfig | undefined,
|
||||
): boolean {
|
||||
if (!providerConfig) {
|
||||
return false;
|
||||
}
|
||||
if (Array.isArray(providerConfig.models) && providerConfig.models.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (typeof providerConfig.baseUrl === "string" && providerConfig.baseUrl.trim()) {
|
||||
return resolveOllamaApiBase(providerConfig.baseUrl) !== OLLAMA_DEFAULT_BASE_URL;
|
||||
}
|
||||
if (readStringValue(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 buildOllamaProvider(
|
||||
configuredBaseUrl?: string,
|
||||
opts?: { quiet?: boolean },
|
||||
@@ -126,66 +57,15 @@ function resolveOllamaPluginConfig(ctx: ProviderCatalogContext): OllamaPluginCon
|
||||
}
|
||||
|
||||
async function runOllamaDiscovery(ctx: ProviderCatalogContext) {
|
||||
const pluginConfig = resolveOllamaPluginConfig(ctx);
|
||||
const explicit = ctx.config.models?.providers?.ollama;
|
||||
const hasExplicitModels = Array.isArray(explicit?.models) && explicit.models.length > 0;
|
||||
const hasMeaningfulExplicitConfig = hasMeaningfulExplicitOllamaConfig(explicit);
|
||||
const discoveryEnabled =
|
||||
pluginConfig.discovery?.enabled ?? ctx.config.models?.ollamaDiscovery?.enabled;
|
||||
if (!hasExplicitModels && discoveryEnabled === false) {
|
||||
return null;
|
||||
}
|
||||
const ollamaKey = ctx.resolveProviderApiKey(PROVIDER_ID).apiKey;
|
||||
const hasRealOllamaKey =
|
||||
typeof ollamaKey === "string" &&
|
||||
ollamaKey.trim().length > 0 &&
|
||||
ollamaKey.trim() !== DEFAULT_API_KEY;
|
||||
const explicitApiKey = readStringValue(explicit?.apiKey);
|
||||
if (hasExplicitModels && explicit) {
|
||||
return {
|
||||
provider: {
|
||||
...explicit,
|
||||
baseUrl:
|
||||
typeof explicit.baseUrl === "string" && explicit.baseUrl.trim()
|
||||
? resolveOllamaApiBase(explicit.baseUrl)
|
||||
: OLLAMA_DEFAULT_BASE_URL,
|
||||
api: explicit.api ?? "ollama",
|
||||
apiKey: resolveOllamaDiscoveryApiKey({
|
||||
env: ctx.env,
|
||||
explicitApiKey,
|
||||
resolvedApiKey: ollamaKey,
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
if (
|
||||
!hasRealOllamaKey &&
|
||||
!hasMeaningfulExplicitConfig &&
|
||||
shouldSkipAmbientOllamaDiscovery(ctx.env)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const provider = await buildOllamaProvider(explicit?.baseUrl, {
|
||||
quiet: !hasRealOllamaKey && !hasMeaningfulExplicitConfig,
|
||||
return await resolveOllamaDiscoveryResult({
|
||||
ctx,
|
||||
pluginConfig: resolveOllamaPluginConfig(ctx),
|
||||
buildProvider: buildOllamaProvider,
|
||||
});
|
||||
if (provider.models?.length === 0 && !ollamaKey && !explicit?.apiKey) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
provider: {
|
||||
...provider,
|
||||
apiKey: resolveOllamaDiscoveryApiKey({
|
||||
env: ctx.env,
|
||||
explicitApiKey,
|
||||
resolvedApiKey: ollamaKey,
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const ollamaProviderDiscovery: OllamaProviderPlugin = {
|
||||
id: PROVIDER_ID,
|
||||
id: OLLAMA_PROVIDER_ID,
|
||||
label: "Ollama",
|
||||
docsPath: "/providers/ollama",
|
||||
envVars: ["OLLAMA_API_KEY"],
|
||||
|
||||
157
extensions/ollama/src/discovery-shared.ts
Normal file
157
extensions/ollama/src/discovery-shared.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { OLLAMA_DEFAULT_BASE_URL } from "./defaults.js";
|
||||
import { resolveOllamaApiBase } from "./provider-models.js";
|
||||
|
||||
export const OLLAMA_PROVIDER_ID = "ollama";
|
||||
export const OLLAMA_DEFAULT_API_KEY = "ollama-local";
|
||||
|
||||
export type OllamaPluginConfig = {
|
||||
discovery?: {
|
||||
enabled?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
type OllamaDiscoveryContext = {
|
||||
config: {
|
||||
models?: {
|
||||
providers?: {
|
||||
ollama?: ModelProviderConfig;
|
||||
};
|
||||
ollamaDiscovery?: {
|
||||
enabled?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
env: NodeJS.ProcessEnv;
|
||||
resolveProviderApiKey: (providerId: string) => { apiKey?: unknown };
|
||||
};
|
||||
|
||||
function normalizeOptionalString(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
function readStringValue(value: unknown): string | undefined {
|
||||
if (typeof value === "string") {
|
||||
return normalizeOptionalString(value);
|
||||
}
|
||||
if (value && typeof value === "object" && "value" in value) {
|
||||
return normalizeOptionalString((value as { value?: unknown }).value);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function resolveOllamaDiscoveryApiKey(params: {
|
||||
env: NodeJS.ProcessEnv;
|
||||
explicitApiKey?: string;
|
||||
resolvedApiKey?: unknown;
|
||||
}): string {
|
||||
const envApiKey = params.env.OLLAMA_API_KEY?.trim() ? "OLLAMA_API_KEY" : undefined;
|
||||
const resolvedApiKey = normalizeOptionalString(params.resolvedApiKey);
|
||||
return envApiKey ?? params.explicitApiKey ?? resolvedApiKey ?? OLLAMA_DEFAULT_API_KEY;
|
||||
}
|
||||
|
||||
function shouldSkipAmbientOllamaDiscovery(env: NodeJS.ProcessEnv): boolean {
|
||||
return Boolean(env.VITEST) || env.NODE_ENV === "test";
|
||||
}
|
||||
|
||||
export function hasMeaningfulExplicitOllamaConfig(
|
||||
providerConfig: ModelProviderConfig | undefined,
|
||||
): boolean {
|
||||
if (!providerConfig) {
|
||||
return false;
|
||||
}
|
||||
if (Array.isArray(providerConfig.models) && providerConfig.models.length > 0) {
|
||||
return true;
|
||||
}
|
||||
if (typeof providerConfig.baseUrl === "string" && providerConfig.baseUrl.trim()) {
|
||||
return resolveOllamaApiBase(providerConfig.baseUrl) !== OLLAMA_DEFAULT_BASE_URL;
|
||||
}
|
||||
if (readStringValue(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;
|
||||
}
|
||||
|
||||
export async function resolveOllamaDiscoveryResult(params: {
|
||||
ctx: OllamaDiscoveryContext;
|
||||
pluginConfig: OllamaPluginConfig;
|
||||
buildProvider: (
|
||||
configuredBaseUrl?: string,
|
||||
opts?: { quiet?: boolean },
|
||||
) => Promise<ModelProviderConfig>;
|
||||
}): Promise<{ provider: ModelProviderConfig } | null> {
|
||||
const explicit = params.ctx.config.models?.providers?.ollama;
|
||||
const hasExplicitModels = Array.isArray(explicit?.models) && explicit.models.length > 0;
|
||||
const hasMeaningfulExplicitConfig = hasMeaningfulExplicitOllamaConfig(explicit);
|
||||
const discoveryEnabled =
|
||||
params.pluginConfig.discovery?.enabled ?? params.ctx.config.models?.ollamaDiscovery?.enabled;
|
||||
if (!hasExplicitModels && discoveryEnabled === false) {
|
||||
return null;
|
||||
}
|
||||
const ollamaKey = params.ctx.resolveProviderApiKey(OLLAMA_PROVIDER_ID).apiKey;
|
||||
const hasRealOllamaKey =
|
||||
typeof ollamaKey === "string" &&
|
||||
ollamaKey.trim().length > 0 &&
|
||||
ollamaKey.trim() !== OLLAMA_DEFAULT_API_KEY;
|
||||
const explicitApiKey = readStringValue(explicit?.apiKey);
|
||||
if (hasExplicitModels && explicit) {
|
||||
return {
|
||||
provider: {
|
||||
...explicit,
|
||||
baseUrl:
|
||||
typeof explicit.baseUrl === "string" && explicit.baseUrl.trim()
|
||||
? resolveOllamaApiBase(explicit.baseUrl)
|
||||
: OLLAMA_DEFAULT_BASE_URL,
|
||||
api: explicit.api ?? "ollama",
|
||||
apiKey: resolveOllamaDiscoveryApiKey({
|
||||
env: params.ctx.env,
|
||||
explicitApiKey,
|
||||
resolvedApiKey: ollamaKey,
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
if (
|
||||
!hasRealOllamaKey &&
|
||||
!hasMeaningfulExplicitConfig &&
|
||||
shouldSkipAmbientOllamaDiscovery(params.ctx.env)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const provider = await params.buildProvider(explicit?.baseUrl, {
|
||||
quiet: !hasRealOllamaKey && !hasMeaningfulExplicitConfig,
|
||||
});
|
||||
if (provider.models?.length === 0 && !ollamaKey && !explicit?.apiKey) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
provider: {
|
||||
...provider,
|
||||
apiKey: resolveOllamaDiscoveryApiKey({
|
||||
env: params.ctx.env,
|
||||
explicitApiKey,
|
||||
resolvedApiKey: ollamaKey,
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user