mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-29 02:41:07 +00:00
fix: stabilize implicit provider discovery merges
This commit is contained in:
@@ -20,6 +20,10 @@ import {
|
||||
const PROVIDER_ID = "ollama";
|
||||
const DEFAULT_API_KEY = "ollama-local";
|
||||
|
||||
function shouldSkipAmbientOllamaDiscovery(env: NodeJS.ProcessEnv): boolean {
|
||||
return Boolean(env.VITEST) || env.NODE_ENV === "test";
|
||||
}
|
||||
|
||||
async function loadProviderSetup() {
|
||||
return await import("openclaw/plugin-sdk/provider-setup");
|
||||
}
|
||||
@@ -95,6 +99,9 @@ export default definePluginEntry({
|
||||
},
|
||||
};
|
||||
}
|
||||
if (!ollamaKey && !explicit && shouldSkipAmbientOllamaDiscovery(ctx.env)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const providerSetup = await loadProviderSetup();
|
||||
const provider = await providerSetup.buildOllamaProvider(explicit?.baseUrl, {
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
|
||||
const OLLAMA_SUGGESTED_MODELS_LOCAL = [OLLAMA_DEFAULT_MODEL];
|
||||
const OLLAMA_SUGGESTED_MODELS_CLOUD = ["kimi-k2.5:cloud", "minimax-m2.5:cloud", "glm-5:cloud"];
|
||||
const OLLAMA_CONTEXT_ENRICH_LIMIT = 200;
|
||||
|
||||
type OllamaMode = "remote" | "local";
|
||||
type OllamaSetupOptions = {
|
||||
@@ -264,11 +265,17 @@ async function storeOllamaCredential(agentDir?: string): Promise<void> {
|
||||
|
||||
export async function buildOllamaProvider(
|
||||
configuredBaseUrl?: string,
|
||||
_opts?: { quiet?: boolean },
|
||||
opts?: { quiet?: boolean },
|
||||
): Promise<ProviderConfig> {
|
||||
const apiBase = resolveOllamaApiBase(configuredBaseUrl);
|
||||
const { models } = await fetchOllamaModels(apiBase);
|
||||
const discovered = await enrichOllamaModelsWithContext(apiBase, models.slice(0, 50));
|
||||
const { reachable, models } = await fetchOllamaModels(apiBase);
|
||||
if (!reachable && !opts?.quiet) {
|
||||
console.warn(`Ollama could not be reached at ${apiBase}.`);
|
||||
}
|
||||
const discovered = await enrichOllamaModelsWithContext(
|
||||
apiBase,
|
||||
models.slice(0, OLLAMA_CONTEXT_ENRICH_LIMIT),
|
||||
);
|
||||
return {
|
||||
baseUrl: apiBase,
|
||||
api: "ollama",
|
||||
@@ -308,7 +315,10 @@ export async function promptAndConfigureOllama(params: {
|
||||
throw new WizardCancelledError("Ollama not reachable");
|
||||
}
|
||||
|
||||
const enrichedModels = await enrichOllamaModelsWithContext(baseUrl, models.slice(0, 50));
|
||||
const enrichedModels = await enrichOllamaModelsWithContext(
|
||||
baseUrl,
|
||||
models.slice(0, OLLAMA_CONTEXT_ENRICH_LIMIT),
|
||||
);
|
||||
const discoveredModelsByName = new Map(enrichedModels.map((model) => [model.name, model]));
|
||||
const modelNames = models.map((model) => model.name);
|
||||
const mode = (await params.prompter.select({
|
||||
@@ -400,7 +410,10 @@ export async function configureOllamaNonInteractive(params: {
|
||||
|
||||
await storeOllamaCredential(params.agentDir);
|
||||
|
||||
const enrichedModels = await enrichOllamaModelsWithContext(baseUrl, models.slice(0, 50));
|
||||
const enrichedModels = await enrichOllamaModelsWithContext(
|
||||
baseUrl,
|
||||
models.slice(0, OLLAMA_CONTEXT_ENRICH_LIMIT),
|
||||
);
|
||||
const discoveredModelsByName = new Map(enrichedModels.map((model) => [model.name, model]));
|
||||
const modelNames = models.map((model) => model.name);
|
||||
const orderedModelNames = [
|
||||
|
||||
@@ -84,6 +84,8 @@ export async function withCopilotGithubToken<T>(
|
||||
}
|
||||
|
||||
export const MODELS_CONFIG_IMPLICIT_ENV_VARS = [
|
||||
"VITEST",
|
||||
"NODE_ENV",
|
||||
"AI_GATEWAY_API_KEY",
|
||||
"CLOUDFLARE_AI_GATEWAY_API_KEY",
|
||||
"COPILOT_GITHUB_TOKEN",
|
||||
@@ -114,6 +116,7 @@ export const MODELS_CONFIG_IMPLICIT_ENV_VARS = [
|
||||
"GOOGLE_CLOUD_LOCATION",
|
||||
"GOOGLE_CLOUD_PROJECT",
|
||||
"GOOGLE_CLOUD_PROJECT_ID",
|
||||
"ANTHROPIC_VERTEX_USE_GCP_METADATA",
|
||||
"VENICE_API_KEY",
|
||||
"VLLM_API_KEY",
|
||||
"XIAOMI_API_KEY",
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
createProviderApiKeyResolver,
|
||||
createProviderAuthResolver,
|
||||
} from "./models-config.providers.secrets.js";
|
||||
import { findNormalizedProviderValue } from "./provider-id.js";
|
||||
|
||||
const log = createSubsystemLogger("agents/model-providers");
|
||||
|
||||
@@ -30,6 +31,7 @@ const PROVIDER_IMPLICIT_MERGERS: Partial<
|
||||
>
|
||||
> = {
|
||||
"anthropic-vertex": mergeImplicitAnthropicVertexProvider,
|
||||
ollama: ({ implicit }) => implicit,
|
||||
};
|
||||
|
||||
const CORE_IMPLICIT_PROVIDER_RESOLVERS = [
|
||||
@@ -102,6 +104,61 @@ function mergeImplicitProviderSet(
|
||||
}
|
||||
}
|
||||
|
||||
function mergeImplicitProviderConfig(params: {
|
||||
providerId: string;
|
||||
existing: ProviderConfig | undefined;
|
||||
implicit: ProviderConfig;
|
||||
}): ProviderConfig {
|
||||
const { providerId, existing, implicit } = params;
|
||||
if (!existing) {
|
||||
return implicit;
|
||||
}
|
||||
const merge = PROVIDER_IMPLICIT_MERGERS[providerId];
|
||||
if (merge) {
|
||||
return merge({ existing, implicit });
|
||||
}
|
||||
return {
|
||||
...implicit,
|
||||
...existing,
|
||||
models:
|
||||
Array.isArray(existing.models) && existing.models.length > 0
|
||||
? existing.models
|
||||
: implicit.models,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveConfiguredImplicitProvider(params: {
|
||||
configuredProviders?: Record<string, ProviderConfig> | null;
|
||||
providerIds: readonly string[];
|
||||
}): ProviderConfig | undefined {
|
||||
for (const providerId of params.providerIds) {
|
||||
const configured = findNormalizedProviderValue(
|
||||
params.configuredProviders ?? undefined,
|
||||
providerId,
|
||||
);
|
||||
if (configured) {
|
||||
return configured;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveExistingImplicitProviderFromContext(params: {
|
||||
ctx: ImplicitProviderContext;
|
||||
providerIds: readonly string[];
|
||||
}): ProviderConfig | undefined {
|
||||
return (
|
||||
resolveConfiguredImplicitProvider({
|
||||
configuredProviders: params.ctx.explicitProviders,
|
||||
providerIds: params.providerIds,
|
||||
}) ??
|
||||
resolveConfiguredImplicitProvider({
|
||||
configuredProviders: params.ctx.config?.models?.providers,
|
||||
providerIds: params.providerIds,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async function resolvePluginImplicitProviders(
|
||||
ctx: ImplicitProviderContext,
|
||||
order: import("../plugins/types.js").ProviderDiscoveryOrder,
|
||||
@@ -132,13 +189,27 @@ async function resolvePluginImplicitProviders(
|
||||
if (!result) {
|
||||
continue;
|
||||
}
|
||||
mergeImplicitProviderSet(
|
||||
discovered,
|
||||
normalizePluginDiscoveryResult({
|
||||
provider,
|
||||
result,
|
||||
}),
|
||||
);
|
||||
const normalizedResult = normalizePluginDiscoveryResult({
|
||||
provider,
|
||||
result,
|
||||
});
|
||||
for (const [providerId, implicitProvider] of Object.entries(normalizedResult)) {
|
||||
discovered[providerId] = mergeImplicitProviderConfig({
|
||||
providerId,
|
||||
existing:
|
||||
discovered[providerId] ??
|
||||
resolveExistingImplicitProviderFromContext({
|
||||
ctx,
|
||||
providerIds: [
|
||||
providerId,
|
||||
provider.id,
|
||||
...(provider.aliases ?? []),
|
||||
...(provider.hookAliases ?? []),
|
||||
],
|
||||
}),
|
||||
implicit: implicitProvider,
|
||||
});
|
||||
}
|
||||
}
|
||||
return Object.keys(discovered).length > 0 ? discovered : undefined;
|
||||
}
|
||||
@@ -199,6 +270,7 @@ async function runProviderCatalogWithTimeout(
|
||||
|
||||
async function mergeCoreImplicitProviders(params: {
|
||||
config?: OpenClawConfig;
|
||||
explicitProviders?: Record<string, ProviderConfig> | null;
|
||||
env: NodeJS.ProcessEnv;
|
||||
providers: Record<string, ProviderConfig>;
|
||||
}): Promise<void> {
|
||||
@@ -208,12 +280,14 @@ async function mergeCoreImplicitProviders(params: {
|
||||
continue;
|
||||
}
|
||||
const merge = PROVIDER_IMPLICIT_MERGERS[provider.id];
|
||||
if (!merge) {
|
||||
params.providers[provider.id] = implicit;
|
||||
continue;
|
||||
}
|
||||
params.providers[provider.id] = merge({
|
||||
existing: params.providers[provider.id],
|
||||
params.providers[provider.id] = (merge ?? mergeImplicitProviderConfig)({
|
||||
providerId: provider.id,
|
||||
existing:
|
||||
params.providers[provider.id] ??
|
||||
resolveConfiguredImplicitProvider({
|
||||
configuredProviders: params.explicitProviders ?? params.config?.models?.providers,
|
||||
providerIds: [provider.id],
|
||||
}),
|
||||
implicit,
|
||||
});
|
||||
}
|
||||
@@ -241,6 +315,7 @@ export async function resolveImplicitProviders(
|
||||
|
||||
await mergeCoreImplicitProviders({
|
||||
config: params.config,
|
||||
explicitProviders: params.explicitProviders,
|
||||
env,
|
||||
providers,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user