refactor(agents): absorb model helper fragments (#112805)

* refactor(agents): absorb model helper fragments

* refactor(agents): keep absorbed helpers internal
This commit is contained in:
Peter Steinberger
2026-07-22 21:06:33 -04:00
committed by GitHub
parent 19d17bc3c4
commit 9dd306de79
28 changed files with 144 additions and 212 deletions
+9 -15
View File
@@ -1,15 +1,9 @@
/**
* Runtime seam for auth-profile store loading.
* Tests can stub this facade without importing the full auth profile store
* implementation.
*/
import { ensureAuthProfileStore as ensureAuthProfileStoreImpl } from "./auth-profiles/store.js";
type EnsureAuthProfileStore = typeof import("./auth-profiles/store.js").ensureAuthProfileStore;
/** Ensure an auth-profile store using the production store implementation. */
export function ensureAuthProfileStore(
...args: Parameters<EnsureAuthProfileStore>
): ReturnType<EnsureAuthProfileStore> {
return ensureAuthProfileStoreImpl(...args);
}
/** Runtime auth-profile facade for lazy model selection and fallback paths. */
export { resolveAuthProfileOrder } from "./auth-profiles/order.js";
export { ensureAuthProfileStore, loadAuthProfileStoreForRuntime } from "./auth-profiles/store.js";
export {
getSoonestCooldownExpiry,
isProfileInCooldown,
maybeReprobeWhamBlockedProfiles,
resolveProfilesUnavailableReason,
} from "./auth-profiles/usage.js";
@@ -11,6 +11,7 @@ import { applyExtraParamsToAgent } from "./extra-params.js";
import type { ProviderThinkLevel } from "./utils.js";
type ExtraParamsTestApi = {
supportsGptParallelToolCallsPayload(api: unknown): boolean;
setProviderRuntimeDepsForTest(
deps:
| Partial<{
@@ -35,7 +35,6 @@ import {
} from "../../plugins/provider-hook-runtime.js";
import type { ProviderRuntimeModel } from "../../plugins/provider-runtime-model.types.js";
import { resolveModelExtraParamSources } from "../model-extra-params.js";
import { supportsGptParallelToolCallsPayload } from "../provider-api-families.js";
import { resolveProviderRequestPolicyConfig } from "../provider-request-config.js";
import type { AgentRuntimeTransport } from "../runtime-plan/types.js";
import type { StreamFn } from "../runtime/index.js";
@@ -63,8 +62,20 @@ const providerRuntimeDeps = {
let preparedExtraParamsCache = new WeakMap<OpenClawConfig, Map<string, Record<string, unknown>>>();
const REQUEST_SCOPED_EXTRA_PARAM_KEYS = new Set(["response_format", "responseFormat", "stop"]);
const GPT_PARALLEL_TOOL_CALLS_APIS = new Set([
"openai-completions",
"openai-responses",
"openai-chatgpt-responses",
"azure-openai-responses",
]);
/** True when a provider API accepts GPT parallel-tool-call payload settings. */
function supportsGptParallelToolCallsPayload(api: unknown): boolean {
return typeof api === "string" && GPT_PARALLEL_TOOL_CALLS_APIS.has(api);
}
const testing = {
supportsGptParallelToolCallsPayload,
setProviderRuntimeDepsForTest(
deps: Partial<typeof defaultProviderRuntimeDeps> | undefined,
): void {
-26
View File
@@ -1,26 +0,0 @@
/**
* Formats configured model aliases for prompt-visible model guidance.
*/
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import type { OpenClawConfig } from "../config/types.openclaw.js";
/** Builds deterministic prompt lines for configured model aliases. */
export function buildModelAliasLines(cfg?: OpenClawConfig) {
const models = cfg?.agents?.defaults?.models ?? {};
const entries: Array<{ alias: string; model: string }> = [];
for (const [keyRaw, entryRaw] of Object.entries(models)) {
const model = normalizeOptionalString(keyRaw) ?? "";
if (!model) {
continue;
}
const alias =
normalizeOptionalString((entryRaw as { alias?: string } | undefined)?.alias) ?? "";
if (!alias) {
continue;
}
entries.push({ alias, model });
}
return entries
.toSorted((a, b) => a.alias.localeCompare(b.alias))
.map((entry) => `- ${entry.alias}: ${entry.model}`);
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Verifies model catalog lookup scope for custom and manifest-owned models.
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolveModelCatalogScope } from "./model-catalog-scope.js";
import { resolveModelCatalogScope } from "./model-discovery-context.js";
describe("resolveModelCatalogScope", () => {
it("keeps explicit custom provider models scoped to that provider", () => {
-36
View File
@@ -1,36 +0,0 @@
/**
* Resolves model catalog scope from config and discovery options.
*/
import { findNormalizedProviderValue } from "@openclaw/model-catalog-core/provider-id";
import { normalizeUniqueSingleOrTrimmedStringList } from "@openclaw/normalization-core/string-normalization";
import type { OpenClawConfig } from "../config/types.openclaw.js";
function providerConfigDeclaresModel(
providerConfig: { models?: readonly { id?: string }[] } | undefined,
model: string,
): boolean {
const trimmedModel = model.trim();
return Boolean(
trimmedModel &&
providerConfig?.models?.some((candidate) => candidate.id?.trim() === trimmedModel),
);
}
/** Resolves provider/model refs used to scope model catalog discovery. */
export function resolveModelCatalogScope(params: {
cfg?: OpenClawConfig;
provider: string;
model: string;
}): { providerRefs: string[]; modelRefs: string[] } {
const provider = params.provider.trim();
const model = params.model.trim();
const providerConfig = findNormalizedProviderValue(params.cfg?.models?.providers, provider);
const modelRefs = providerConfigDeclaresModel(providerConfig, model)
? [provider && model ? `${provider}/${model}` : model]
: [provider && model ? `${provider}/${model}` : model, model];
// Scope ordering feeds deterministic discovery and prompt/cache inputs.
return {
providerRefs: normalizeUniqueSingleOrTrimmedStringList([provider, providerConfig?.api]),
modelRefs: normalizeUniqueSingleOrTrimmedStringList(modelRefs),
};
}
+32
View File
@@ -3,6 +3,8 @@
* Keeps callers from reaching into runtime config or plugin metadata snapshot
* plumbing directly.
*/
import { findNormalizedProviderValue } from "@openclaw/model-catalog-core/provider-id";
import { normalizeUniqueSingleOrTrimmedStringList } from "@openclaw/normalization-core/string-normalization";
import { getRuntimeConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { getCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js";
@@ -10,6 +12,36 @@ import { resolvePluginMetadataSnapshot } from "../plugins/plugin-metadata-snapsh
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "./agent-scope.js";
import type { PluginModelCatalogMetadataSnapshot } from "./plugin-model-catalog.js";
function providerConfigDeclaresModel(
providerConfig: { models?: readonly { id?: string }[] } | undefined,
model: string,
): boolean {
const trimmedModel = model.trim();
return Boolean(
trimmedModel &&
providerConfig?.models?.some((candidate) => candidate.id?.trim() === trimmedModel),
);
}
/** Resolves provider/model refs used to scope model catalog discovery. */
export function resolveModelCatalogScope(params: {
cfg?: OpenClawConfig;
provider: string;
model: string;
}): { providerRefs: string[]; modelRefs: string[] } {
const provider = params.provider.trim();
const model = params.model.trim();
const providerConfig = findNormalizedProviderValue(params.cfg?.models?.providers, provider);
const modelRefs = providerConfigDeclaresModel(providerConfig, model)
? [provider && model ? `${provider}/${model}` : model]
: [provider && model ? `${provider}/${model}` : model, model];
// Scope ordering feeds deterministic discovery and prompt/cache inputs.
return {
providerRefs: normalizeUniqueSingleOrTrimmedStringList([provider, providerConfig?.api]),
modelRefs: normalizeUniqueSingleOrTrimmedStringList(modelRefs),
};
}
/** Resolve the workspace directory model discovery should use for agent scope. */
export function resolveModelWorkspaceDir(
cfg: OpenClawConfig | undefined,
-14
View File
@@ -1,14 +0,0 @@
/**
* Runtime auth profile barrel for fallback/provider selection code.
*
* These exports keep the hot runtime path on the auth-profile submodules without
* pulling the broader model config surface into provider fallback logic.
*/
export { resolveAuthProfileOrder } from "./auth-profiles/order.js";
export { ensureAuthProfileStore, loadAuthProfileStoreForRuntime } from "./auth-profiles/store.js";
export {
getSoonestCooldownExpiry,
isProfileInCooldown,
maybeReprobeWhamBlockedProfiles,
resolveProfilesUnavailableReason,
} from "./auth-profiles/usage.js";
+1 -1
View File
@@ -16,7 +16,7 @@ type ModelFallbackTestApi = {
hasFallbackCandidates: boolean;
now: number;
probeThrottleKey: string;
authRuntime: typeof import("./model-fallback-auth.runtime.js");
authRuntime: typeof import("./auth-profiles.runtime.js");
authStore: AuthProfileStore;
profileIds: string[];
}): CooldownDecision;
+1 -1
View File
@@ -200,7 +200,7 @@ const authRuntimeMock = vi.hoisted(() => {
};
});
vi.mock("./model-fallback-auth.runtime.js", () => authRuntimeMock.runtime);
vi.mock("./auth-profiles.runtime.js", () => authRuntimeMock.runtime);
const makeCfg = makeModelFallbackCfg;
let authTempRoot = "";
+2 -2
View File
@@ -361,10 +361,10 @@ type ModelFallbackClassifiedResult<T> = Pick<
"result" | "provider" | "model"
>;
type ModelFallbackAuthRuntime = typeof import("./model-fallback-auth.runtime.js");
type ModelFallbackAuthRuntime = typeof import("./auth-profiles.runtime.js");
const modelFallbackAuthRuntimeLoader = createLazyImportLoader<ModelFallbackAuthRuntime>(
() => import("./model-fallback-auth.runtime.js"),
() => import("./auth-profiles.runtime.js"),
);
const MAX_FALLBACK_CANDIDATE_CACHE_ENTRIES = 256;
const fallbackCandidateCache = new Map<string, ModelCandidate[]>();
-32
View File
@@ -1,32 +0,0 @@
/**
* Filters provider/model refs for model picker visibility.
*/
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { listCliRuntimeProviderIds } from "./cli-backends.js";
// Retired provider ids and CLI runtime aliases are implementation surfaces, not
// model picker choices. Hide them while keeping real provider/model refs visible.
const RETIRED_MODEL_PICKER_PROVIDERS = new Set(["codex", "codex-cli"]);
/** True for retired provider ids that should stay out of model selection surfaces. */
export function isRetiredModelPickerProvider(provider: string): boolean {
return RETIRED_MODEL_PICKER_PROVIDERS.has(normalizeProviderId(provider));
}
/** Creates a provider visibility predicate for model picker rendering. */
export function createModelPickerVisibleProviderPredicate(
params: { config?: OpenClawConfig; env?: NodeJS.ProcessEnv; includeSetupRegistry?: boolean } = {},
): (provider: string) => boolean {
const cliRuntimeProviders = new Set(
listCliRuntimeProviderIds({
config: params.config,
env: params.env,
includeSetupRegistry: params.includeSetupRegistry ?? false,
}),
);
return (provider: string): boolean => {
const normalized = normalizeProviderId(provider);
return !isRetiredModelPickerProvider(normalized) && !cliRuntimeProviders.has(normalized);
};
}
-20
View File
@@ -1,20 +0,0 @@
/** Lifecycle-backed model-registry view for command paths. */
import type { OpenClawConfig } from "../config/types.openclaw.js";
import {
loadPreparedAgentModelRegistry,
type LoadPreparedAgentModelRegistryOptions,
} from "./prepared-model-registry.js";
import type { ModelRegistry } from "./sessions/index.js";
/** Options controlling the prepared registry view. */
type LoadAgentModelRegistryOptions = LoadPreparedAgentModelRegistryOptions & {
readOnly?: boolean;
};
/** Forks a registry from the generation prepared by the owning command lifecycle. */
export async function loadAgentModelRegistry(
config: OpenClawConfig,
options: LoadAgentModelRegistryOptions = {},
): Promise<{ agentDir: string; config: OpenClawConfig; registry: ModelRegistry }> {
return await loadPreparedAgentModelRegistry(config, options);
}
+1 -1
View File
@@ -5,7 +5,7 @@ import { testing as cliBackendsTesting } from "./cli-backends.test-support.js";
import {
createModelPickerVisibleProviderPredicate,
isRetiredModelPickerProvider,
} from "./model-picker-visibility.js";
} from "./model-runtime-aliases.js";
import {
areRuntimeModelRefsEquivalent,
isCliRuntimeProvider,
+24
View File
@@ -15,6 +15,30 @@ import {
import { resolveModelRuntimePolicy } from "./model-runtime-policy.js";
import { resolveProviderIdForAuth } from "./provider-auth-aliases.js";
const RETIRED_MODEL_PICKER_PROVIDERS = new Set(["codex", "codex-cli"]);
/** True for retired provider ids that should stay out of model selection surfaces. */
export function isRetiredModelPickerProvider(provider: string): boolean {
return RETIRED_MODEL_PICKER_PROVIDERS.has(normalizeProviderId(provider));
}
/** Creates a provider visibility predicate for model picker rendering. */
export function createModelPickerVisibleProviderPredicate(
params: { config?: OpenClawConfig; env?: NodeJS.ProcessEnv; includeSetupRegistry?: boolean } = {},
): (provider: string) => boolean {
const cliRuntimeProviders = new Set(
listCliRuntimeProviderIds({
config: params.config,
env: params.env,
includeSetupRegistry: params.includeSetupRegistry ?? false,
}),
);
return (provider: string): boolean => {
const normalized = normalizeProviderId(provider);
return !isRetiredModelPickerProvider(normalized) && !cliRuntimeProviders.has(normalized);
};
}
/** True for CLI runtime provider ids such as `claude-cli` and `google-gemini-cli`. */
export function isCliRuntimeProvider(
provider: string,
+28 -1
View File
@@ -3,12 +3,39 @@
* preserved secret fields. Setup and doctor flows use this boundary to update
* model catalogs without discarding existing credentials.
*/
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import { isNonSecretApiKeyMarker } from "./model-auth-markers.js";
import { resolveCatalogOwnedModelCompat } from "./model-compat-catalog.js";
import { normalizeProviderMapKeys } from "./models-config.providers.keys.js";
import type { ProviderConfig } from "./models-config.providers.secrets.js";
export function normalizeProviderMapKeys<T>(
providers: Record<string, T> | null | undefined,
): Record<string, T> {
const normalized: Record<string, T> = {};
const canonicalKeys = new Set<string>();
for (const [key, value] of Object.entries(providers ?? {})) {
const providerKey = normalizeProviderId(key);
if (!providerKey) {
continue;
}
if (key === providerKey) {
canonicalKeys.add(providerKey);
// A prior alias inserted this key at the alias's position. Reinsert it so
// canonical spelling also controls deterministic provider order.
delete normalized[providerKey];
normalized[providerKey] = value;
continue;
}
// Exact canonical spelling wins over aliases regardless of object order.
// Without one, the later variant wins, matching existing trim-collision behavior.
if (!canonicalKeys.has(providerKey)) {
normalized[providerKey] = value;
}
}
return normalized;
}
/** Existing provider config shape that may carry persisted secret/base URL fields. */
export type ExistingProviderConfig = ProviderConfig & {
apiKey?: string;
@@ -1,29 +0,0 @@
/** Canonical provider-key handling shared by models.json merge boundaries. */
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
export function normalizeProviderMapKeys<T>(
providers: Record<string, T> | null | undefined,
): Record<string, T> {
const normalized: Record<string, T> = {};
const canonicalKeys = new Set<string>();
for (const [key, value] of Object.entries(providers ?? {})) {
const providerKey = normalizeProviderId(key);
if (!providerKey) {
continue;
}
if (key === providerKey) {
canonicalKeys.add(providerKey);
// A prior alias inserted this key at the alias's position. Reinsert it so
// canonical spelling also controls deterministic provider order.
delete normalized[providerKey];
normalized[providerKey] = value;
continue;
}
// Exact canonical spelling wins over aliases regardless of object order.
// Without one, the later variant wins, matching existing trim-collision behavior.
if (!canonicalKeys.has(providerKey)) {
normalized[providerKey] = value;
}
}
return normalized;
}
@@ -10,7 +10,7 @@ import {
resolveNonEnvSecretRefHeaderValueMarker,
resolveEnvSecretRefHeaderValueMarker,
} from "./model-auth-markers.js";
import { normalizeProviderMapKeys } from "./models-config.providers.keys.js";
import { normalizeProviderMapKeys } from "./models-config.merge.js";
import type { ProviderConfig, SecretDefaults } from "./models-config.providers.secrets.js";
/**
+1 -1
View File
@@ -18,7 +18,7 @@ import {
} from "./prepared-model-runtime.js";
import { AuthStorage, type ModelRegistry } from "./sessions/index.js";
export type LoadPreparedAgentModelRegistryOptions = {
type LoadPreparedAgentModelRegistryOptions = {
agentId?: string;
agentDir?: string;
loadAvailability?: boolean;
+6 -4
View File
@@ -1,6 +1,6 @@
// Verifies provider API family helpers gate GPT parallel tool-call payloads.
import { describe, expect, it } from "vitest";
import { supportsGptParallelToolCallsPayload } from "./provider-api-families.js";
import { testing as extraParamsTesting } from "./embedded-agent-runner/extra-params.test-support.js";
describe("provider api families", () => {
it.each([
@@ -9,11 +9,13 @@ describe("provider api families", () => {
"openai-chatgpt-responses",
"azure-openai-responses",
])("classifies %s as supporting the GPT parallel_tool_calls payload patch", (api) => {
expect(supportsGptParallelToolCallsPayload(api)).toBe(true);
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(api)).toBe(true);
});
it("rejects unrelated APIs", () => {
expect(supportsGptParallelToolCallsPayload("anthropic-messages")).toBe(false);
expect(supportsGptParallelToolCallsPayload(undefined)).toBe(false);
expect(extraParamsTesting.supportsGptParallelToolCallsPayload("anthropic-messages")).toBe(
false,
);
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(undefined)).toBe(false);
});
});
-15
View File
@@ -1,15 +0,0 @@
/**
* Small API-family predicates used when constructing provider payloads. The
* sets here encode transport-level compatibility, not provider identity.
*/
const GPT_PARALLEL_TOOL_CALLS_APIS = new Set([
"openai-completions",
"openai-responses",
"openai-chatgpt-responses",
"azure-openai-responses",
]);
/** True when a provider API accepts GPT parallel-tool-call payload settings. */
export function supportsGptParallelToolCallsPayload(api: unknown): boolean {
return typeof api === "string" && GPT_PARALLEL_TOOL_CALLS_APIS.has(api);
}
+15 -1
View File
@@ -4,10 +4,10 @@
* This module gathers agent/config knobs before rendering the canonical system
* prompt so callers do not duplicate owner, TTS, alias, memory, or FS policy.
*/
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { buildTtsSystemPromptHint } from "../tts/tts-settings.js";
import { resolveAgentConfig } from "./agent-scope.js";
import { buildModelAliasLines } from "./model-alias-lines.js";
import { resolveOwnerDisplaySetting } from "./owner-display.js";
import { buildAgentSystemPrompt } from "./system-prompt.js";
import { resolveEffectiveToolFsWorkspaceOnly } from "./tool-fs-policy.js";
@@ -31,6 +31,20 @@ type ConfiguredAgentSystemPromptParams = AgentSystemPromptRenderParams & {
agentId?: string;
};
function buildModelAliasLines(cfg?: OpenClawConfig) {
const entries: Array<{ alias: string; model: string }> = [];
for (const [keyRaw, entryRaw] of Object.entries(cfg?.agents?.defaults?.models ?? {})) {
const model = normalizeOptionalString(keyRaw) ?? "";
const alias = normalizeOptionalString(entryRaw?.alias) ?? "";
if (model && alias) {
entries.push({ alias, model });
}
}
return entries
.toSorted((a, b) => a.alias.localeCompare(b.alias))
.map((entry) => `- ${entry.alias}: ${entry.model}`);
}
/** Resolves all config-derived system prompt fields for an agent. */
function resolveAgentSystemPromptConfig(params: {
config?: OpenClawConfig;
@@ -17,7 +17,6 @@ import {
resolvePreparedExtraParams,
} from "./embedded-agent-runner/extra-params.js";
import { testing as extraParamsTesting } from "./embedded-agent-runner/extra-params.test-support.js";
import { supportsGptParallelToolCallsPayload } from "./provider-api-families.js";
beforeEach(() => {
installNoopProviderRuntimeDeps();
@@ -74,14 +73,14 @@ describe("transport params runtime contract (embedded OpenClaw/OpenAI path)", ()
it.each(GPT_PARALLEL_TOOL_CALLS_PAYLOAD_APIS)(
"advertises %s as accepting the GPT parallel_tool_calls payload patch",
(api) => {
expect(supportsGptParallelToolCallsPayload(api)).toBe(true);
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(api)).toBe(true);
},
);
it.each(UNRELATED_TOOL_CALLS_PAYLOAD_APIS)(
"does not advertise %s as accepting the GPT parallel_tool_calls payload patch",
(api) => {
expect(supportsGptParallelToolCallsPayload(api)).toBe(false);
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(api)).toBe(false);
},
);
+1 -1
View File
@@ -18,8 +18,8 @@ import {
resolveLogicalVisibleModelCatalog,
type ModelCatalogAuthChecker,
} from "../../agents/model-catalog-visibility.js";
import { isRetiredModelPickerProvider } from "../../agents/model-picker-visibility.js";
import { createProviderAuthChecker } from "../../agents/model-provider-auth.js";
import { isRetiredModelPickerProvider } from "../../agents/model-runtime-aliases.js";
import { modelCatalogLogicalKey } from "../../agents/model-selection-shared.js";
import {
buildModelAliasIndex,
+2 -2
View File
@@ -1,6 +1,6 @@
/** Registry-loading adapters for model-list row construction. */
import { loadAgentModelRegistry } from "../../agents/model-registry-loader.js";
import { shouldSuppressBuiltInModel } from "../../agents/model-suppression.js";
/** Registry-loading adapters for model-list row construction. */
import { loadPreparedAgentModelRegistry as loadAgentModelRegistry } from "../../agents/prepared-model-registry.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { ModelRegistry } from "../../llm/model-registry.js";
import type { Model } from "../../llm/types.js";
+2 -2
View File
@@ -1,9 +1,9 @@
/** Model registry access helpers for `openclaw models list`. */
import { loadAgentModelRegistry } from "../../agents/model-registry-loader.js";
import {
shouldSuppressBuiltInModel,
shouldSuppressBuiltInModelFromManifest,
} from "../../agents/model-suppression.js";
/** Model registry access helpers for `openclaw models list`. */
import { loadPreparedAgentModelRegistry as loadAgentModelRegistry } from "../../agents/prepared-model-registry.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { ModelRegistry } from "../../llm/model-registry.js";
import type { Model } from "../../llm/types.js";
+1 -1
View File
@@ -11,12 +11,12 @@ import {
} from "../agents/model-catalog-visibility.js";
import type { ModelCatalogEntry } from "../agents/model-catalog.js";
import type { ModelCatalogSnapshot } from "../agents/model-catalog.types.js";
import { createModelPickerVisibleProviderPredicate } from "../agents/model-picker-visibility.js";
import {
createProviderAuthChecker,
type ProviderModelAuthChecker,
} from "../agents/model-provider-auth.js";
import { formatLiteralProviderPrefixedModelRef } from "../agents/model-ref-shared.js";
import { createModelPickerVisibleProviderPredicate } from "../agents/model-runtime-aliases.js";
import {
buildConfiguredModelCatalog,
buildModelAliasIndex,
+1 -1
View File
@@ -7,7 +7,7 @@ import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
} from "@openclaw/normalization-core/string-coerce";
import { resolveModelCatalogScope } from "../agents/model-catalog-scope.js";
import { resolveModelCatalogScope } from "../agents/model-discovery-context.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { getLoadedRuntimePluginRegistry } from "./active-runtime-registry.js";
import {