Model resolution (from oh-my-openagent/model-core): 6-step priority resolution pipeline (UI select -> user config -> category default -> user fallback -> policy chain -> system default), provider fallback chains, fuzzy model matching, error classification, provider-specific model ID transforms. 14 files, zero runtime deps. Multi-batch matcher (from boocontext-audit): 6 batch types (Observational, Actionable, PreviouslyApplied, Disambiguation, ResponseAnalysis, LowCriticality) for behavioral guideline evaluation. RelationalResolver with iterative convergence (DEPENDS_ON, PRIORITIZES, ENTAILS, TAG_ALL, TAG_PRIORITIZES). SchematicGenerator abstract class with retry and execution plans. 4 files.
110 lines
3.5 KiB
TypeScript
110 lines
3.5 KiB
TypeScript
import type { FallbackEntry } from "./model-requirement-types.js"
|
|
import type { FallbackModelObject } from "./fallback-model-object.js"
|
|
import { normalizeModel } from "./model-normalization.js"
|
|
import { resolveModelPipeline } from "./model-resolution-pipeline.js"
|
|
import { KNOWN_VARIANTS } from "./known-variants.js"
|
|
import type { ConnectedProvidersAdapter } from "./connected-providers-cache.js"
|
|
import * as connectedProvidersCache from "./connected-providers-cache.js"
|
|
|
|
export type ModelResolutionInput = {
|
|
userModel?: string
|
|
inheritedModel?: string
|
|
systemDefault?: string
|
|
}
|
|
|
|
export type ModelSource =
|
|
| "override"
|
|
| "category-default"
|
|
| "provider-fallback"
|
|
| "system-default"
|
|
|
|
export type ModelResolutionResult = {
|
|
model: string
|
|
source: ModelSource
|
|
variant?: string
|
|
}
|
|
|
|
export type ExtendedModelResolutionInput = {
|
|
uiSelectedModel?: string
|
|
userModel?: string
|
|
userFallbackModels?: string[]
|
|
categoryDefaultModel?: string
|
|
fallbackChain?: FallbackEntry[]
|
|
availableModels: Set<string>
|
|
systemDefaultModel?: string
|
|
}
|
|
|
|
|
|
export function resolveModel(input: ModelResolutionInput): string | undefined {
|
|
return (
|
|
normalizeModel(input.userModel) ??
|
|
normalizeModel(input.inheritedModel) ??
|
|
input.systemDefault
|
|
)
|
|
}
|
|
|
|
export function resolveModelWithFallback(
|
|
input: ExtendedModelResolutionInput,
|
|
connectedProvidersAdapter: ConnectedProvidersAdapter = connectedProvidersCache,
|
|
): ModelResolutionResult | undefined {
|
|
const { uiSelectedModel, userModel, userFallbackModels, categoryDefaultModel, fallbackChain, availableModels, systemDefaultModel } = input
|
|
const resolved = resolveModelPipeline({
|
|
intent: { uiSelectedModel, userModel, userFallbackModels, categoryDefaultModel },
|
|
constraints: { availableModels },
|
|
policy: { fallbackChain, systemDefaultModel },
|
|
}, connectedProvidersAdapter)
|
|
|
|
if (!resolved) {
|
|
return undefined
|
|
}
|
|
|
|
return {
|
|
model: resolved.model,
|
|
source: resolved.provenance,
|
|
variant: resolved.variant,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Normalizes fallback_models config to a mixed array.
|
|
* Accepts string, string[], or mixed arrays of strings and FallbackModelObject entries.
|
|
*/
|
|
export function normalizeFallbackModels(
|
|
models: string | (string | FallbackModelObject)[] | undefined,
|
|
): (string | FallbackModelObject)[] | undefined {
|
|
if (!models) return undefined
|
|
if (typeof models === "string") return [models]
|
|
return models
|
|
}
|
|
|
|
/**
|
|
* Extracts plain model strings from a mixed fallback models array.
|
|
* Object entries are flattened to "model" or "model(variant)" strings.
|
|
* Use this when consumers need string[] (e.g., resolveModelForDelegateTask).
|
|
*/
|
|
export function flattenToFallbackModelStrings(
|
|
models: (string | FallbackModelObject)[] | undefined,
|
|
): string[] | undefined {
|
|
if (!models) return undefined
|
|
return models.map((entry) => {
|
|
if (typeof entry === "string") return entry
|
|
const variant = entry.variant
|
|
if (variant) {
|
|
// Strip any supported inline variant syntax before appending explicit override.
|
|
// Supports both parenthesized and space-suffix forms so we don't emit
|
|
// invalid strings like "provider/model high(low)".
|
|
const model = entry.model
|
|
.replace(/\([^()]+\)\s*$/, "")
|
|
.replace(/\s+([a-z][a-z0-9_-]*)\s*$/i, (_match: string, suffix: string) => {
|
|
const normalized = String(suffix).toLowerCase()
|
|
return KNOWN_VARIANTS.has(normalized)
|
|
? ""
|
|
: _match
|
|
})
|
|
.trim()
|
|
return `${model}(${variant})`
|
|
}
|
|
return entry.model
|
|
})
|
|
}
|