diff --git a/src/agents/agent-command.ts b/src/agents/agent-command.ts index 9d3895250e9..46159059250 100644 --- a/src/agents/agent-command.ts +++ b/src/agents/agent-command.ts @@ -73,6 +73,7 @@ import { AGENT_LANE_SUBAGENT } from "./lanes.js"; import { LiveSessionModelSwitchError } from "./live-model-switch.js"; import { loadManifestModelCatalog } from "./model-catalog.js"; import { runWithModelFallback } from "./model-fallback.js"; +import type { ModelManifestNormalizationContext } from "./model-selection-normalize.js"; import { buildConfiguredModelCatalog, modelKey, @@ -402,17 +403,19 @@ async function prepareAgentCommandExecution( workspaceDir, env: process.env, }); - const manifestPlugins = manifestMetadataSnapshot.plugins; + const modelManifestContext = { + manifestPlugins: manifestMetadataSnapshot.plugins, + } satisfies ModelManifestNormalizationContext; const configuredModel = resolveConfiguredModelRef({ cfg, defaultProvider: DEFAULT_PROVIDER, defaultModel: DEFAULT_MODEL, - manifestPlugins, + ...modelManifestContext, }); const configuredThinkingCatalog = buildConfiguredModelCatalog({ cfg, workspaceDir, - manifestPlugins, + ...modelManifestContext, }); const thinkingLevelsHint = formatThinkingLevels( configuredModel.provider, @@ -472,7 +475,7 @@ async function prepareAgentCommandExecution( outboundSession, workspaceDir, agentDir, - manifestPlugins, + modelManifestContext, runId, acpManager, acpResolution, @@ -512,7 +515,7 @@ async function agentCommandInternal( runId, acpManager, acpResolution, - manifestPlugins, + modelManifestContext, } = prepared; let sessionEntry = prepared.sessionEntry; @@ -764,12 +767,12 @@ async function agentCommandInternal( const configuredDefaultRef = resolveDefaultModelForAgent({ cfg, agentId: sessionAgentId, - manifestPlugins, + ...modelManifestContext, }); const { provider: defaultProvider, model: defaultModel } = normalizeModelRef( configuredDefaultRef.provider, configuredDefaultRef.model, - { manifestPlugins }, + modelManifestContext, ); let provider = defaultProvider; let model = defaultModel; @@ -802,7 +805,7 @@ async function agentCommandInternal( catalog: [], defaultProvider, defaultModel, - manifestPlugins, + ...modelManifestContext, }); if (needsModelCatalog) { @@ -813,7 +816,7 @@ async function agentCommandInternal( defaultProvider, defaultModel, agentId: sessionAgentId, - manifestPlugins, + ...modelManifestContext, }); allowedModelCatalog = visibilityPolicy.allowedCatalog; } @@ -836,9 +839,11 @@ async function agentCommandInternal( const overrideProvider = sessionEntry.providerOverride?.trim() || defaultProvider; const overrideModel = sessionEntry.modelOverride?.trim(); if (overrideModel) { - const normalizedOverride = normalizeModelRef(overrideProvider, overrideModel, { - manifestPlugins, - }); + const normalizedOverride = normalizeModelRef( + overrideProvider, + overrideModel, + modelManifestContext, + ); const key = modelKey(normalizedOverride.provider, normalizedOverride.model); if (!visibilityPolicy.allowsKey(key)) { const { updated } = applyModelOverrideToSessionEntry({ @@ -861,9 +866,11 @@ async function agentCommandInternal( let storedModelOverride = sessionEntry?.modelOverride?.trim(); if (storedModelOverride) { const candidateProvider = storedProviderOverride || defaultProvider; - const normalizedStored = normalizeModelRef(candidateProvider, storedModelOverride, { - manifestPlugins, - }); + const normalizedStored = normalizeModelRef( + candidateProvider, + storedModelOverride, + modelManifestContext, + ); const key = modelKey(normalizedStored.provider, normalizedStored.model); if (visibilityPolicy.allowsKey(key)) { provider = normalizedStored.provider; @@ -889,10 +896,10 @@ async function agentCommandInternal( if (hasExplicitRunOverride) { const explicitRef = explicitModelOverride ? explicitProviderOverride - ? normalizeModelRef(explicitProviderOverride, explicitModelOverride, { manifestPlugins }) - : parseModelRef(explicitModelOverride, provider, { manifestPlugins }) + ? normalizeModelRef(explicitProviderOverride, explicitModelOverride, modelManifestContext) + : parseModelRef(explicitModelOverride, provider, modelManifestContext) : explicitProviderOverride - ? normalizeModelRef(explicitProviderOverride, model, { manifestPlugins }) + ? normalizeModelRef(explicitProviderOverride, model, modelManifestContext) : null; if (!explicitRef) { throw new Error("Invalid model override."); @@ -1107,7 +1114,7 @@ async function agentCommandInternal( cfg, provider, model, - manifestPlugins, + ...modelManifestContext, runId, agentDir, fallbacksOverride: effectiveFallbacksOverride, @@ -1299,7 +1306,7 @@ async function agentCommandInternal( { cause: err }, ); } - const switchRef = normalizeModelRef(err.provider, err.model, { manifestPlugins }); + const switchRef = normalizeModelRef(err.provider, err.model, modelManifestContext); const switchKey = modelKey(switchRef.provider, switchRef.model); if (!visibilityPolicy.allowsKey(switchKey)) { log.info( diff --git a/src/agents/model-fallback.ts b/src/agents/model-fallback.ts index aad198d6ce6..102acf2b83b 100644 --- a/src/agents/model-fallback.ts +++ b/src/agents/model-fallback.ts @@ -6,7 +6,6 @@ import type { OpenClawConfig } from "../config/types.openclaw.js"; import { emitFailoverEvent } from "../infra/diagnostic-events.js"; import { formatErrorMessage } from "../infra/errors.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; import { isCommandLaneTaskTimeoutError } from "../process/command-queue.js"; import { createLazyImportLoader } from "../shared/lazy-promise.js"; import { normalizeOptionalString } from "../shared/string-coerce.js"; @@ -35,7 +34,11 @@ import { type ModelFallbackStepFields, } from "./model-fallback-observation.js"; import type { FallbackAttempt, ModelCandidate } from "./model-fallback.types.js"; -import { modelKey, normalizeModelRef } from "./model-selection-normalize.js"; +import { + type ModelManifestNormalizationContext, + modelKey, + normalizeModelRef, +} from "./model-selection-normalize.js"; import { buildConfiguredAllowlistKeys, buildModelAliasIndex, @@ -94,10 +97,6 @@ type ModelFallbackRunFn = ( options?: ModelFallbackRunOptions, ) => Promise; -type ManifestNormalizationContext = { - manifestPlugins?: readonly Pick[]; -}; - /** * Fallback abort check. Only treats explicit AbortError names as user aborts. * Message-based checks (e.g., "aborted") can mask timeouts and skip fallback. @@ -485,7 +484,7 @@ function resolveImageFallbackCandidates( cfg: OpenClawConfig | undefined; defaultProvider: string; modelOverride?: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelCandidate[] { const aliasIndex = buildModelAliasIndex({ cfg: params.cfg ?? {}, @@ -570,7 +569,7 @@ function resolveFallbackCandidates( model: string; /** Optional explicit fallbacks list; when provided (even empty), replaces agents.defaults.model.fallbacks. */ fallbacksOverride?: string[]; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelCandidate[] { const primary = params.cfg ? resolveConfiguredModelRef({ @@ -851,7 +850,7 @@ export async function runWithModelFallback( onError?: ModelFallbackErrorHandler; onFallbackStep?: ModelFallbackStepHandler; classifyResult?: ModelFallbackResultClassifier; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): Promise> { const candidates = resolveFallbackCandidates({ cfg: params.cfg, diff --git a/src/agents/model-selection-normalize.ts b/src/agents/model-selection-normalize.ts index 203803b929e..000631737a6 100644 --- a/src/agents/model-selection-normalize.ts +++ b/src/agents/model-selection-normalize.ts @@ -14,6 +14,10 @@ export type ModelRef = { model: string; }; +export type ModelManifestNormalizationContext = { + manifestPlugins?: readonly Pick[]; +}; + export function modelKey(provider: string, model: string) { return sharedModelKey(provider, model); } @@ -39,10 +43,9 @@ export { function normalizeProviderModelId( provider: string, model: string, - options?: { + options?: ModelManifestNormalizationContext & { allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - manifestPlugins?: readonly Pick[]; }, ): string { const staticModelId = normalizeStaticProviderModelId(provider, model, { @@ -63,10 +66,9 @@ function normalizeProviderModelId( ); } -type ModelRefNormalizeOptions = { +type ModelRefNormalizeOptions = ModelManifestNormalizationContext & { allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - manifestPlugins?: readonly Pick[]; }; export function normalizeModelRef( diff --git a/src/agents/model-selection-resolve.ts b/src/agents/model-selection-resolve.ts index c33d1419449..58cd3f14020 100644 --- a/src/agents/model-selection-resolve.ts +++ b/src/agents/model-selection-resolve.ts @@ -1,8 +1,7 @@ import { resolveAgentModelFallbackValues } from "../config/model-input.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; import type { ModelCatalogEntry } from "./model-catalog.types.js"; -import type { ModelRef } from "./model-selection-normalize.js"; +import type { ModelManifestNormalizationContext, ModelRef } from "./model-selection-normalize.js"; import { buildModelAliasIndex, getModelRefStatusWithFallbackModels, @@ -20,10 +19,6 @@ export { } from "./model-selection-shared.js"; export type { ModelRefStatus } from "./model-selection-shared.js"; -type ManifestNormalizationContext = { - manifestPlugins?: readonly Pick[]; -}; - function resolveDefaultFallbackModels(cfg: OpenClawConfig): string[] { return resolveAgentModelFallbackValues(cfg.agents?.defaults?.model); } @@ -35,7 +30,7 @@ export function getModelRefStatus( ref: ModelRef; defaultProvider: string; defaultModel?: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRefStatus { const { cfg, catalog, ref, defaultProvider, defaultModel, manifestPlugins } = params; return getModelRefStatusWithFallbackModels({ @@ -56,7 +51,7 @@ export function resolveAllowedModelRef( raw: string; defaultProvider: string; defaultModel?: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): | { ref: ModelRef; key: string } | { diff --git a/src/agents/model-selection-shared.ts b/src/agents/model-selection-shared.ts index c49699b6651..8c1205df5b1 100644 --- a/src/agents/model-selection-shared.ts +++ b/src/agents/model-selection-shared.ts @@ -3,7 +3,6 @@ import type { OpenClawConfig } from "../config/types.openclaw.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { getCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js"; import { loadManifestMetadataSnapshot } from "../plugins/manifest-contract-eligibility.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; import { getActivePluginRegistryWorkspaceDirFromState } from "../plugins/runtime-state.js"; import { normalizeLowercaseStringOrEmpty, @@ -20,6 +19,7 @@ import { normalizeStaticProviderModelId, } from "./model-ref-shared.js"; import { + type ModelManifestNormalizationContext, type ModelRef, findNormalizedProviderValue, modelKey, @@ -36,16 +36,13 @@ function getLog(): ReturnType { } const OPENROUTER_COMPAT_FREE_ALIAS = "openrouter:free"; +type ModelManifestPlugins = ModelManifestNormalizationContext["manifestPlugins"]; export type ModelAliasIndex = { byAlias: Map; byKey: Map; }; -type ManifestNormalizationContext = { - manifestPlugins?: readonly Pick[]; -}; - function sanitizeModelWarningValue(value: string): string { const stripped = value ? stripAnsi(value) : ""; let controlBoundary = -1; @@ -83,7 +80,7 @@ export function inferUniqueProviderFromConfiguredModels( params: { cfg: OpenClawConfig; model: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): string | undefined { const model = params.model.trim(); if (!model) { @@ -189,7 +186,7 @@ export function resolveBareModelDefaultProvider( catalog: readonly ModelCatalogEntry[]; model: string; defaultProvider: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): string { return ( inferUniqueProviderFromConfiguredModels({ @@ -212,7 +209,7 @@ function resolveConfiguredOpenRouterCompatFreeRef( defaultProvider: string; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef | null { const configuredModels = params.cfg.agents?.defaults?.models ?? {}; for (const raw of Object.keys(configuredModels)) { @@ -255,7 +252,7 @@ export function resolveConfiguredOpenRouterCompatAlias( defaultProvider: string; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef | null { const normalized = normalizeLowercaseStringOrEmpty(params.raw); if (normalized === "openrouter:auto") { @@ -284,7 +281,7 @@ function parseModelRefWithCompatAlias( defaultProvider: string; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef | null { return ( resolveConfiguredOpenRouterCompatAlias(params) ?? @@ -303,7 +300,7 @@ function resolveExactConfiguredProviderRef( raw: string; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef | null { const slash = params.raw.indexOf("/"); if (slash <= 0 || !params.cfg?.models?.providers) { @@ -350,7 +347,7 @@ export function resolveAllowlistModelKey( cfg?: OpenClawConfig; raw: string; defaultProvider: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): string | null { const parsed = parseModelRefWithCompatAlias({ cfg: params.cfg, @@ -368,7 +365,7 @@ export function buildConfiguredAllowlistKeys( params: { cfg: OpenClawConfig | undefined; defaultProvider: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): Set | null { const visibility = parseConfiguredModelVisibilityEntries({ cfg: params.cfg }); if (visibility.exactModelRefs.length === 0) { @@ -396,7 +393,7 @@ export function buildModelAliasIndex( defaultProvider: string; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelAliasIndex { const byAlias = new Map(); const byKey = new Map(); @@ -443,7 +440,7 @@ function buildModelCatalogMetadata( params: { cfg: OpenClawConfig; defaultProvider: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelCatalogMetadata { const configuredByKey = new Map(); for (const entry of buildConfiguredModelCatalog({ @@ -538,7 +535,7 @@ export function resolveModelRefFromString( aliasIndex?: ModelAliasIndex; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): { ref: ModelRef; alias?: string } | null { const { model } = splitTrailingAuthProfile(params.raw); if (!model) { @@ -570,7 +567,7 @@ export function resolveConfiguredModelRef( defaultModel: string; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef { const rawModel = resolveAgentModelPrimaryValue(params.cfg.agents?.defaults?.model) ?? ""; if (rawModel) { @@ -658,7 +655,7 @@ export function buildAllowedModelSetWithFallbacks( fallbackModels: readonly string[]; allowManifestNormalization?: boolean; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): { allowAny: boolean; allowedCatalog: ModelCatalogEntry[]; @@ -857,7 +854,7 @@ export function getModelRefStatusWithFallbackModels( defaultProvider: string; defaultModel?: string; fallbackModels: readonly string[]; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRefStatus { const allowed = buildAllowedModelSetWithFallbacks({ cfg: params.cfg, @@ -881,7 +878,7 @@ export function resolveAllowedModelRefFromAliasIndex( defaultProvider: string; aliasIndex: ModelAliasIndex; getStatus: (ref: ModelRef) => ModelRefStatus; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ResolveAllowedModelRefResult { const trimmed = params.raw.trim(); if (!trimmed) { @@ -926,8 +923,8 @@ export function hasConfiguredProviderModelRows(cfg: OpenClawConfig): boolean { function resolveConfiguredModelManifestPlugins(params: { cfg: OpenClawConfig; workspaceDir?: string; - manifestPlugins?: readonly Pick[]; -}): readonly Pick[] | undefined { + manifestPlugins?: ModelManifestPlugins; +}): ModelManifestPlugins { if (params.manifestPlugins) { return params.manifestPlugins; } @@ -953,7 +950,7 @@ function resolveConfiguredModelManifestPlugins(params: { export function buildConfiguredModelCatalog(params: { cfg: OpenClawConfig; workspaceDir?: string; - manifestPlugins?: readonly Pick[]; + manifestPlugins?: ModelManifestPlugins; }): ModelCatalogEntry[] { const providers = params.cfg.models?.providers; if (!providers || typeof providers !== "object") { @@ -1007,7 +1004,7 @@ export function resolveHooksGmailModel( params: { cfg: OpenClawConfig; defaultProvider: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef | null { const hooksModel = params.cfg.hooks?.gmail?.model; if (!hooksModel?.trim()) { @@ -1099,7 +1096,7 @@ export function resolveAllowedModelSelection( allowAny: boolean; allowedKeys: ReadonlySet; allowedCatalog: readonly ModelCatalogEntry[]; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef | null { const current = normalizeModelRef(params.provider, params.model, { manifestPlugins: params.manifestPlugins, @@ -1158,7 +1155,7 @@ export function createModelVisibilityPolicyWithFallbacks( defaultProvider: string; defaultModel?: string; fallbackModels: readonly string[]; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelVisibilityPolicy { const visibility = parseConfiguredModelVisibilityEntries({ cfg: params.cfg }); const allowed = buildAllowedModelSetWithFallbacks(params); diff --git a/src/agents/model-selection.ts b/src/agents/model-selection.ts index 33c2b0fab48..455685c30af 100644 --- a/src/agents/model-selection.ts +++ b/src/agents/model-selection.ts @@ -4,7 +4,6 @@ import { toAgentModelListLike, } from "../config/model-input.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, @@ -23,6 +22,7 @@ export { resolveThinkingDefaultWithRuntimeCatalog, } from "./model-thinking-default.js"; import { + type ModelManifestNormalizationContext, type ModelRef, findNormalizedProviderKey, findNormalizedProviderValue, @@ -53,11 +53,7 @@ import { type ModelRefStatus, } from "./model-selection-shared.js"; -export type { ModelAliasIndex, ModelRef, ModelRefStatus }; - -type ManifestNormalizationContext = { - manifestPlugins?: readonly Pick[]; -}; +export type { ModelAliasIndex, ModelManifestNormalizationContext, ModelRef, ModelRefStatus }; export type ThinkLevel = | "off" @@ -210,7 +206,7 @@ export function resolveAllowlistModelKey( raw: string, defaultProvider: string, cfg?: OpenClawConfig, - manifestPlugins?: readonly Pick[], + manifestPlugins?: ModelManifestNormalizationContext["manifestPlugins"], ): string | null { return resolveAllowlistModelKeyFromShared({ cfg, raw, defaultProvider, manifestPlugins }); } @@ -220,7 +216,7 @@ export function resolveDefaultModelForAgent( cfg: OpenClawConfig; agentId?: string; allowPluginNormalization?: boolean; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRef { const agentModelOverride = params.agentId ? resolveAgentEffectiveModelPrimary(params.cfg, params.agentId) @@ -387,7 +383,7 @@ export function buildAllowedModelSet( defaultProvider: string; defaultModel?: string; agentId?: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): { allowAny: boolean; allowedCatalog: ModelCatalogEntry[]; @@ -413,7 +409,7 @@ export function getModelRefStatus( ref: ModelRef; defaultProvider: string; defaultModel?: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): ModelRefStatus { return getModelRefStatusWithFallbackModels({ cfg: params.cfg, @@ -434,7 +430,7 @@ function getModelRefStatusForResolve( catalog: ModelCatalogEntry[]; defaultProvider: string; defaultModel?: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ref: ModelRef, ): ModelRefStatus { return getModelRefStatus({ @@ -454,7 +450,7 @@ export function resolveAllowedModelRef( raw: string; defaultProvider: string; defaultModel?: string; - } & ManifestNormalizationContext, + } & ModelManifestNormalizationContext, ): | { ref: ModelRef; key: string } | { diff --git a/src/agents/model-visibility-policy.ts b/src/agents/model-visibility-policy.ts index a28fcc0ab0d..3452efcfcef 100644 --- a/src/agents/model-visibility-policy.ts +++ b/src/agents/model-visibility-policy.ts @@ -1,8 +1,8 @@ import { resolveAgentModelFallbackValues } from "../config/model-input.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; import { resolveAgentModelFallbacksOverride } from "./agent-scope.js"; import type { ModelCatalogEntry } from "./model-catalog.types.js"; +import type { ModelManifestNormalizationContext } from "./model-selection-normalize.js"; import { createModelVisibilityPolicyWithFallbacks, type ModelVisibilityPolicy, @@ -18,14 +18,15 @@ function resolveAllowedFallbacks(params: { cfg: OpenClawConfig; agentId?: string return resolveAgentModelFallbackValues(params.cfg.agents?.defaults?.model); } -export function createModelVisibilityPolicy(params: { - cfg: OpenClawConfig; - catalog: ModelCatalogEntry[]; - defaultProvider: string; - defaultModel?: string; - agentId?: string; - manifestPlugins?: readonly Pick[]; -}): ModelVisibilityPolicy { +export function createModelVisibilityPolicy( + params: { + cfg: OpenClawConfig; + catalog: ModelCatalogEntry[]; + defaultProvider: string; + defaultModel?: string; + agentId?: string; + } & ModelManifestNormalizationContext, +): ModelVisibilityPolicy { return createModelVisibilityPolicyWithFallbacks({ cfg: params.cfg, catalog: params.catalog,