From 2390f3d938d2d2dc4aeca1cac9925fa8fd636a16 Mon Sep 17 00:00:00 2001 From: Shakker <165377636+shakkernerd@users.noreply.github.com> Date: Tue, 25 Aug 2026 15:30:08 +0100 Subject: [PATCH] refactor: isolate native CLI availability resolver (#129374) Moved native CLI availability ownership resolution into the model-list auth owner and removed the stale test callback, restoring lint without changing behavior. Refs #129332. --- .../models-list-auth-resolver.ts | 47 +++++++++++++ .../server-methods/models-list-result.ts | 66 ++++--------------- src/gateway/server-methods/models.test.ts | 2 +- 3 files changed, 60 insertions(+), 55 deletions(-) diff --git a/src/gateway/server-methods/models-list-auth-resolver.ts b/src/gateway/server-methods/models-list-auth-resolver.ts index a17c4b877047..bbddd44d6421 100644 --- a/src/gateway/server-methods/models-list-auth-resolver.ts +++ b/src/gateway/server-methods/models-list-auth-resolver.ts @@ -1,3 +1,4 @@ +import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id"; import type { PreparedAgentCredentialModes } from "../../agents/agent-auth-credential-modes.js"; import { resolveAgentDir } from "../../agents/agent-scope.js"; import { resolveExternalCliAuthScopeFromConfig } from "../../agents/auth-profiles/external-cli-scope.js"; @@ -7,9 +8,13 @@ import { createModelAuthAvailabilityResolver, type ModelAuthAvailabilityResolver, } from "../../agents/model-auth-availability.js"; +import type { ModelCatalogEntry } from "../../agents/model-catalog.types.js"; import { createOpenAIModelRoutesResolver } from "../../agents/openai-model-routes.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import { normalizePluginsConfig } from "../../plugins/config-state.js"; +import { isActivatedManifestOwner } from "../../plugins/manifest-owner-policy.js"; import type { PluginMetadataSnapshot } from "../../plugins/plugin-metadata-snapshot.types.js"; +import { resolveModelChoiceAgentRuntime } from "./models-list-public-projection.js"; function listEnabledSyntheticAuthProviderRefs( metadataSnapshot: PluginMetadataSnapshot, @@ -19,6 +24,48 @@ function listEnabledSyntheticAuthProviderRefs( .flatMap((plugin) => plugin.syntheticAuthRefs ?? []); } +export function createPreparedSyntheticCliRuntimeResolver(params: { + cfg: OpenClawConfig; + agentId: string; + metadataSnapshot: PluginMetadataSnapshot; +}): (entry: ModelCatalogEntry) => string | undefined { + const normalizedPluginConfig = normalizePluginsConfig(params.cfg.plugins); + const activatedPluginIds = new Set( + params.metadataSnapshot.plugins + .filter((plugin) => + isActivatedManifestOwner({ + plugin, + normalizedConfig: normalizedPluginConfig, + rootConfig: params.cfg, + }), + ) + .map((plugin) => plugin.id), + ); + return (entry) => { + const runtime = normalizeProviderId( + resolveModelChoiceAgentRuntime({ + cfg: params.cfg, + agentId: params.agentId, + entry, + })?.id ?? "", + ); + if (!runtime || runtime === "openclaw") { + return undefined; + } + const provider = normalizeProviderId(entry.provider); + const providerOwners = new Set(params.metadataSnapshot.owners.providers.get(provider) ?? []); + const owners = (params.metadataSnapshot.owners.cliBackends.get(runtime) ?? []).filter( + (pluginId) => + providerOwners.has(pluginId) && + activatedPluginIds.has(pluginId) && + params.metadataSnapshot.byPluginId + .get(pluginId) + ?.syntheticAuthRefs?.some((candidate) => normalizeProviderId(candidate) === runtime), + ); + return owners.length === 1 ? runtime : undefined; + }; +} + export function createModelsListAuthResolver(params: { cfg: OpenClawConfig; agentId: string; diff --git a/src/gateway/server-methods/models-list-result.ts b/src/gateway/server-methods/models-list-result.ts index 3c68b68d8c30..363caf08cabc 100644 --- a/src/gateway/server-methods/models-list-result.ts +++ b/src/gateway/server-methods/models-list-result.ts @@ -45,15 +45,16 @@ import { preparedModelRuntimeConfigsMatch } from "../../agents/prepared-model-ru import { resolveDefaultAgentWorkspaceDir } from "../../agents/workspace.js"; import { getRuntimeConfigSourceSnapshot } from "../../config/config.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; -import { normalizePluginsConfig } from "../../plugins/config-state.js"; -import { isActivatedManifestOwner } from "../../plugins/manifest-owner-policy.js"; import type { PluginMetadataSnapshot } from "../../plugins/plugin-metadata-snapshot.types.js"; import type { ProviderCatalogOutcome } from "../../plugins/provider-catalog.types.js"; import { normalizeAgentId } from "../../routing/session-key.js"; import { loadDeferredCatalog, readPreparedCatalog } from "../server-model-catalog-auth.js"; import { resolveGatewayModelThinkingProfile } from "../session-utils-model.js"; import { resolveModelProviderCapabilities } from "./model-provider-capabilities.js"; -import { createModelsListAuthResolver } from "./models-list-auth-resolver.js"; +import { + createModelsListAuthResolver, + createPreparedSyntheticCliRuntimeResolver, +} from "./models-list-auth-resolver.js"; import { prepareModelsListHarnessCatalog } from "./models-list-harness-catalog.js"; import { buildPublicModelProjection, @@ -73,36 +74,6 @@ type ModelsListResult = { let loggedSlowModelsListCatalog = false; -function resolvePreparedSyntheticCliRuntime(params: { - cfg: OpenClawConfig; - agentId: string; - entry: ModelCatalogEntry; - metadataSnapshot: PluginMetadataSnapshot; - activatedPluginIds: ReadonlySet; -}): string | undefined { - const runtime = normalizeProviderId( - resolveModelChoiceAgentRuntime({ - cfg: params.cfg, - agentId: params.agentId, - entry: params.entry, - })?.id ?? "", - ); - if (!runtime || runtime === "openclaw") { - return undefined; - } - const provider = normalizeProviderId(params.entry.provider); - const providerOwners = new Set(params.metadataSnapshot.owners.providers.get(provider) ?? []); - const owners = (params.metadataSnapshot.owners.cliBackends.get(runtime) ?? []).filter( - (pluginId) => - providerOwners.has(pluginId) && - params.activatedPluginIds.has(pluginId) && - params.metadataSnapshot.byPluginId - .get(pluginId) - ?.syntheticAuthRefs?.some((candidate) => normalizeProviderId(candidate) === runtime), - ); - return owners.length === 1 ? runtime : undefined; -} - function resolveModelsListView(params: Record): ModelCatalogBrowseView { const view = params.view; return view === "configured" || view === "provider-config" || view === "all" ? view : "default"; @@ -115,19 +86,13 @@ function resolveLegacyEntryAvailability(params: { cfg: OpenClawConfig; agentId: string; metadataSnapshot: PluginMetadataSnapshot; - activatedPluginIds: ReadonlySet; + resolvePreparedSyntheticCliRuntime: (entry: ModelCatalogEntry) => string | undefined; }): ModelAuthAvailability { if (params.primaryAvailability === true) { return true; } let available = params.primaryAvailability; - const preparedSyntheticRuntime = resolvePreparedSyntheticCliRuntime({ - cfg: params.cfg, - agentId: params.agentId, - entry: params.entry, - metadataSnapshot: params.metadataSnapshot, - activatedPluginIds: params.activatedPluginIds, - }); + const preparedSyntheticRuntime = params.resolvePreparedSyntheticCliRuntime(params.entry); const runtimeProvider = resolveCliRuntimeExecutionProvider({ provider: params.entry.provider, @@ -163,18 +128,11 @@ function createModelsListEntryEvaluator(params: { entry: ModelCatalogEntry, routeVariants?: readonly ModelCatalogEntry[], ) => Promise { - const normalizedPluginConfig = normalizePluginsConfig(params.cfg.plugins); - const activatedPluginIds = new Set( - params.metadataSnapshot.plugins - .filter((plugin) => - isActivatedManifestOwner({ - plugin, - normalizedConfig: normalizedPluginConfig, - rootConfig: params.cfg, - }), - ) - .map((plugin) => plugin.id), - ); + const resolvePreparedSyntheticCliRuntime = createPreparedSyntheticCliRuntimeResolver({ + cfg: params.cfg, + agentId: params.agentId, + metadataSnapshot: params.metadataSnapshot, + }); const pending = new Map>(); return (entry, routeVariants = [entry]) => { const identity = openAIModelCatalogRoutePolicy.resolveIdentity(entry); @@ -204,7 +162,7 @@ function createModelsListEntryEvaluator(params: { cfg: params.cfg, agentId: params.agentId, metadataSnapshot: params.metadataSnapshot, - activatedPluginIds, + resolvePreparedSyntheticCliRuntime, }), } : evaluation; diff --git a/src/gateway/server-methods/models.test.ts b/src/gateway/server-methods/models.test.ts index 805e66be48db..fff113de6e0c 100644 --- a/src/gateway/server-methods/models.test.ts +++ b/src/gateway/server-methods/models.test.ts @@ -1641,7 +1641,7 @@ describe("models.list", () => { prefix: "openclaw-models-list-cli-runtime-", agentEnv: "main", }, - async (state) => { + async () => { const runtimeConfig = { agents: { defaults: {