modelcatalog

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package modelcatalog holds source-neutral model capability facts, match metadata, and consumer-owned snapshot ports used by the core catalog runtime. It must not import provider SDKs, backend plugins, frontend plugins, or concrete HTTP/filesystem adapters (those live under internal/infra).

Matching and resolution: DefaultMatcher (exact then normalized catalog ids), OverrideResolver for administrator pair/model overrides, CatalogResolverImpl (from NewCatalogResolver) for effective capabilities vs backend caps, and DefaultVendorResolver (from NewVendorResolver) for catalog-backed vendor/model canonicalization with optional VendorPolicy hooks for provider-specific alias and keyword rules.

Lifecycle: CatalogRuntime loads the local cache; the composition root runs periodic refresh via SnapshotSource / SnapshotCache, and publishes an immutable active Snapshot for readers.

Request sizing and routing: DefaultSizeEstimator and NewEligibilityResolver implement conservative pre-upstream context-limit eligibility on top of already-resolved EffectiveFacts.

Constructor shape: NewCatalogResolver, NewEligibilityResolver, and NewOverrideResolver return narrow interface types (ports) rather than concrete structs. That intentionally trades the usual “return structs, accept interfaces” rule for a smaller, sealed substitution surface at the composition root.

Index

Constants

View Source
const (
	EstimateBasisCanonicalUTF8                  = "canonical_utf8_bytes"
	EstimateBasisCanonicalUTF8AndTools          = "canonical_utf8_bytes+tools_json_bytes"
	EstimateBasisCanonicalUTF8AndSession        = "canonical_utf8_bytes+session_bytes"
	EstimateBasisSessionContributionUnavailable = "session_contribution_unavailable"
)

EstimateBasis documents how SizeEstimate.Input was derived (requirement 7.7).

Variables

This section is empty.

Functions

func CloneBackendCaps

func CloneBackendCaps(b lipapi.BackendCaps) lipapi.BackendCaps

CloneBackendCaps returns a shallow copy of caps for safe in-place mutation, or nil when caps is nil.

func NormalizeStripOneProviderPrefix

func NormalizeStripOneProviderPrefix(s string) string

NormalizeStripOneProviderPrefix removes one leading `provider/` segment (first '/'). If there is no '/', the string is returned trimmed unchanged.

func RedactSourceURL

func RedactSourceURL(raw string) string

RedactSourceURL returns a userinfo-free URL string for operator display, or empty when input is empty.

func SuffixLookupKeys

func SuffixLookupKeys(suffix string) []string

func WithBoundView

func WithBoundView(ctx context.Context, v BoundView) context.Context

WithBoundView attaches v to ctx for request-scoped consumers.

func WithSessionSizeContribution

func WithSessionSizeContribution(ctx context.Context, contributionBytes int64) context.Context

WithSessionSizeContribution attaches a proxy-known byte contribution for resumed or continuous sessions. When the call carries session or continuity hints, this value must be present for an available estimate.

Types

type ActiveSnapshotProvider

type ActiveSnapshotProvider interface {
	ActiveIndex() (*SnapshotIndex, SnapshotRef)
}

ActiveSnapshotProvider supplies the current immutable catalog index for each CatalogResolverImpl.Resolve call. Implementations typically read an atomically published snapshot (CatalogRuntime) so refresh updates affect subsequent routing decisions without per-resolve I/O.

type BoundView

type BoundView struct {
	// contains filtered or unexported fields
}

BoundView is an immutable, request-scoped catalog publication. It freezes the active snapshot index/generation (or explicit no-snapshot state) so a later CatalogRuntime refresh cannot alter an in-flight request.

BoundView never exposes the mutable CatalogRuntime, its mutexes, or atomics.

func BoundViewFromContext

func BoundViewFromContext(ctx context.Context) (BoundView, bool)

BoundViewFromContext returns the request-bound catalog view when present.

func EmptyBoundView

func EmptyBoundView() BoundView

EmptyBoundView returns a safe empty view (nil/unavailable runtime).

func (BoundView) Active

func (v BoundView) Active() bool

Active reports whether a snapshot was bound.

func (BoundView) ActiveIndex

func (v BoundView) ActiveIndex() (*SnapshotIndex, SnapshotRef)

ActiveIndex implements ActiveSnapshotProvider for the frozen snapshot.

func (BoundView) Generation

func (v BoundView) Generation() string

Generation returns the frozen catalog snapshot generation.

func (BoundView) Snapshot

func (v BoundView) Snapshot() (Snapshot, bool)

Snapshot returns a deep-cloned snapshot value so callers cannot mutate the active publication through BoundView (WirePayload is cloned; Index is immutable).

type CapabilityTriState

type CapabilityTriState uint8

CapabilityTriState is an explicit tri-state for protocol-neutral capabilities (unknown vs explicit false).

const (
	// CapabilityUnknown means the catalog or override did not establish support or denial.
	CapabilityUnknown CapabilityTriState = iota
	// CapabilityUnsupported means the model is explicitly known not to support the capability.
	CapabilityUnsupported
	// CapabilitySupported means the model is explicitly known to support the capability.
	CapabilitySupported
)

type CatalogDiagnosticsJSON

type CatalogDiagnosticsJSON struct {
	UsageEnabled bool `json:"usage_enabled"`

	// Status is disabled when model_catalog.enabled is false; otherwise reflects snapshot presence and freshness.
	Status CatalogDiagnosticsStatus `json:"status"`

	// Snapshot is set when a valid local/remote catalog snapshot is active in the runtime.
	Snapshot *CatalogSnapshotDiagnostics `json:"snapshot,omitempty"`

	// LastRefreshErrorCategory is empty when the last refresh completed successfully.
	LastRefreshErrorCategory RefreshFailureCategory `json:"last_refresh_error_category,omitempty"`

	// SourceURLRedacted never includes userinfo (requirement 10.4).
	SourceURLRedacted string `json:"source_url_redacted,omitempty"`

	ExternalUpdatesEnabled bool `json:"external_updates_enabled"`
	// UpdateIntervalSeconds is 0 when unset or invalid in config.
	UpdateIntervalSeconds float64 `json:"update_interval_seconds,omitempty"`

	// Aggregate model-view identity (req 9.6); set only when PreferBound + identity present.
	ModelViewDigest    string `json:"model_view_digest,omitempty"`
	ConfigGeneration   string `json:"config_generation,omitempty"`
	ConfigFingerprint  string `json:"config_fingerprint,omitempty"`
	RegistryGeneration string `json:"registry_generation,omitempty"`
}

CatalogDiagnosticsJSON is the operator JSON for GET model_catalog.diagnostics_path (not a stable public API).

func BuildCatalogDiagnosticsJSON

func BuildCatalogDiagnosticsJSON(cfg CatalogStatusHandlerConfig) CatalogDiagnosticsJSON

BuildCatalogDiagnosticsJSON builds the JSON DTO for the current moment (no prompt/session content). When PreferBound is set, the request-bound snapshot is used instead of the live runtime.

type CatalogDiagnosticsStatus

type CatalogDiagnosticsStatus string

CatalogDiagnosticsStatus is the high-level operator-visible catalog state (requirements 9.1).

const (
	CatalogDiagDisabled    CatalogDiagnosticsStatus = "disabled"
	CatalogDiagUnavailable CatalogDiagnosticsStatus = "unavailable"
	CatalogDiagStale       CatalogDiagnosticsStatus = "stale"
	CatalogDiagEnabled     CatalogDiagnosticsStatus = "enabled"
)

type CatalogResolverImpl

type CatalogResolverImpl struct {
	// contains filtered or unexported fields
}

CatalogResolverImpl combines overrides, catalog matching, and backend capability intersection. Wire it into github.com/matdev83/go-llm-interactive-proxy/internal/core/runtime.Executor.CatalogResolver.

func NewCatalogResolver

func NewCatalogResolver(
	m Matcher,
	ovr OverrideResolver,
	catalogEnabled bool,
	active ActiveSnapshotProvider,
) *CatalogResolverImpl

NewCatalogResolver builds a resolver. When catalogEnabled is false, catalog matching is skipped and effective capabilities mirror backend declarations. active may be nil (no snapshot) or supply a nil index when no valid local catalog is published (Req 1.4).

func (*CatalogResolverImpl) Resolve

Resolve implements the executor catalog merge contract. When a request-bound catalog view is present on ctx it is preferred so failover/parallel attempts observe one immutable snapshot (req 9.4-9.5). Compatibility callers without a bound view still read the live provider.

type CatalogRuntime

type CatalogRuntime struct {
	// contains filtered or unexported fields
}

CatalogRuntime coordinates local cache loading and publication of the active immutable snapshot for request-time readers. Background refresh ticks are started by the composition root (see internal/infra/runtimebundle), which calls CatalogRuntime.RunRefresh on a schedule.

func NewCatalogRuntime

func NewCatalogRuntime(cfg RuntimeConfig) *CatalogRuntime

NewCatalogRuntime builds a coordinator. Source and Cache may be nil when updates are disabled and no cache load is required (callers should still pass non-nil cache for typical startup).

func (*CatalogRuntime) Active

func (r *CatalogRuntime) Active() (Snapshot, bool)

Active returns the current immutable snapshot handle for routing-time use. The second result is false when no snapshot has been published yet.

func (*CatalogRuntime) ActiveIndex

func (r *CatalogRuntime) ActiveIndex() (*SnapshotIndex, SnapshotRef)

ActiveIndex implements ActiveSnapshotProvider: the current catalog index and generation for routing.

func (*CatalogRuntime) BoundView

func (r *CatalogRuntime) BoundView() BoundView

BoundView captures the current catalog snapshot pointer exactly once. A nil receiver returns an empty view.

func (*CatalogRuntime) Close

func (r *CatalogRuntime) Close() error

Close marks the runtime stopped. External refresh workers must be stopped separately by the composition root.

func (*CatalogRuntime) LastRefreshFailure

func (r *CatalogRuntime) LastRefreshFailure() RefreshFailureCategory

LastRefreshFailure returns the failure category from the most recent refresh attempt.

func (*CatalogRuntime) PublishSnapshot

func (r *CatalogRuntime) PublishSnapshot(snap Snapshot)

PublishSnapshot atomically publishes snap as the active catalog view. Production refresh uses CatalogRuntime.RunRefresh; this helper supports composition-root seeding and deterministic tests without network I/O.

func (*CatalogRuntime) RunRefresh

func (r *CatalogRuntime) RunRefresh(ctx context.Context)

RunRefresh fetches a remote snapshot when a source is configured, validates it, persists via cache, and publishes the active view. ctx governs fetch/save cancellation.

func (*CatalogRuntime) Start

func (r *CatalogRuntime) Start(parent context.Context) error

Start loads the local cache once and publishes a valid snapshot when present. It does not run network refresh; the composition root calls CatalogRuntime.RunRefresh when configured.

type CatalogSnapshotDiagnostics

type CatalogSnapshotDiagnostics struct {
	Generation  string    `json:"generation"`
	FetchedAt   time.Time `json:"fetched_at"`
	ContentHash string    `json:"content_hash,omitempty"`
}

CatalogSnapshotDiagnostics is non-request content: generation and fetch metadata only.

type CatalogStatusHandlerConfig

type CatalogStatusHandlerConfig struct {
	Runtime *CatalogRuntime

	UsageEnabled           bool
	ExternalUpdatesEnabled bool
	UpdateInterval         time.Duration
	SourceURL              string

	// Now defaults to time.Now if nil (tests may inject a fixed clock).
	Now func() time.Time

	// PreferBound uses BoundSnapshot instead of rereading Runtime when true.
	PreferBound bool
	// BoundSnapshot is the request-bound catalog view (ignored unless PreferBound).
	BoundSnapshot BoundView
	// ModelViewIdentity attaches safe aggregate identity fields when set.
	ModelViewIdentity map[string]string
}

CatalogStatusHandlerConfig configures BuildCatalogDiagnosticsJSON for the operator HTTP handler (internal/stdhttp: NewCatalogStatusHandler).

type DefaultMatcher

type DefaultMatcher struct{}

DefaultMatcher implements exact-then-normalized deterministic matching.

func (DefaultMatcher) Match

Match implements Matcher.

type DefaultSizeEstimator

type DefaultSizeEstimator struct{}

DefaultSizeEstimator implements conservative sizing using UTF-8 byte counts of canonical message content plus tool declaration JSON-ish footprint. Non-text parts use deterministic byte proxies.

func (DefaultSizeEstimator) Estimate

func (DefaultSizeEstimator) EstimateRequestTokens

func (e DefaultSizeEstimator) EstimateRequestTokens(ctx context.Context, call lipapi.Call) SizeEstimate

type DefaultVendorResolver

type DefaultVendorResolver struct {
	// contains filtered or unexported fields
}

func NewVendorResolver

func NewVendorResolver(active ActiveSnapshotProvider, keywordFallback bool, policy VendorPolicy) *DefaultVendorResolver

func (*DefaultVendorResolver) Resolve

type EffectiveFacts

type EffectiveFacts struct {
	Facts         ModelFacts
	BackendCaps   lipapi.BackendCaps
	EffectiveCaps lipapi.BackendCaps
	Matched       bool
	Match         MatchResult
	Snapshot      SnapshotRef
}

EffectiveFacts is the source-aware capability surface for one candidate (design §CatalogResolver).

type EligibilityDecision

type EligibilityDecision struct {
	IsEligible bool              `json:"eligible"`
	Reason     EligibilityReason `json:"reason,omitempty"`
	Facts      EffectiveFacts    `json:"facts,omitzero"`
	Estimate   SizeEstimate      `json:"estimate,omitzero"`
}

EligibilityDecision is the routing-time outcome for context limits before backend open.

type EligibilityReason

type EligibilityReason uint8

EligibilityReason is a compact routing-time outcome for context limits (executor integration later).

const (
	EligibilityUnknown EligibilityReason = iota
	EligibilityEligible
	EligibilityContextLimitExceeded
)

func (EligibilityReason) String

func (r EligibilityReason) String() string

String returns a stable eligibility reason label.

type EligibilityResolverImpl

type EligibilityResolverImpl struct {
	// contains filtered or unexported fields
}

EligibilityResolverImpl decides context-limit eligibility from already-resolved EffectiveFacts (design §EligibilityResolver). Wire it into github.com/matdev83/go-llm-interactive-proxy/internal/core/runtime.Executor.EligibilityResolver.

func NewEligibilityResolver

func NewEligibilityResolver(est sizeEstimator) *EligibilityResolverImpl

NewEligibilityResolver returns a resolver that never performs capability negotiation; it only compares a conservative size estimate to a known context limit from facts.

func (*EligibilityResolverImpl) Check

Check implements the executor eligibility contract.

type FactSource

type FactSource uint8

FactSource identifies where effective model facts originated (requirement 9.7).

const (
	// FactSourceNone means no catalog or override facts apply for this evaluation branch.
	FactSourceNone FactSource = iota
	// FactSourcePairOverride is a backend+model administrator override.
	FactSourcePairOverride
	// FactSourceModelOverride is a model-name-only administrator override.
	FactSourceModelOverride
	// FactSourceCatalog is a matching models.dev catalog entry after normalization.
	FactSourceCatalog
	// FactSourceBackendDeclaration is the backend adapter capability surface only.
	FactSourceBackendDeclaration
)

func (FactSource) String

func (f FactSource) String() string

String returns a stable label for operator diagnostics (not localized).

type LimitFact

type LimitFact struct {
	State  LimitTriState
	Tokens int64
}

LimitFact carries limit state separate from "unknown" (requirement 3.6).

type LimitTriState

type LimitTriState uint8

LimitTriState distinguishes unknown limits, explicit lack of a limit concept, and a known numeric limit.

const (
	// LimitUnknown means no reliable limit was derived from catalog or overrides.
	LimitUnknown LimitTriState = iota
	// LimitUnsupported means the source explicitly indicates no context limit applies for this model path.
	LimitUnsupported
	// LimitPresent means Tokens holds a positive context token budget (or provider-normalized unit).
	LimitPresent
)

type MatchKind

type MatchKind uint8

MatchKind classifies catalog model id matching for diagnostics (requirements 4.x).

const (
	// MatchNone means no catalog match classification applies (backend-only path).
	MatchNone MatchKind = iota
	// MatchNoMatch means no catalog entry matched the route model.
	MatchNoMatch
	// MatchExact is a full string identity match against catalog model ids.
	MatchExact
	// MatchNonExact is a deterministic normalized match with a single catalog candidate.
	MatchNonExact
	// MatchAmbiguous means normalized matching produced multiple catalog ids.
	MatchAmbiguous
)

func (MatchKind) String

func (k MatchKind) String() string

String returns a stable match classification label.

type MatchResult

type MatchResult struct {
	Kind       MatchKind
	InputModel string
	MatchedID  string
	Candidates []string
}

MatchResult classifies catalog matching for a route model (design §Matcher).

type Matcher

type Matcher interface {
	Match(candidate routing.AttemptCandidate, index *SnapshotIndex) MatchResult
}

Matcher resolves route model strings to catalog entries without mutating the candidate.

type ModelFacts

type ModelFacts struct {
	Tools             CapabilityTriState
	StructuredOutputs CapabilityTriState
	Reasoning         CapabilityTriState
	Vision            CapabilityTriState
	Documents         CapabilityTriState
	ContextLimit      LimitFact
	InputLimit        LimitFact
	OutputLimit       LimitFact
	Source            FactSource
	MatchKind         MatchKind
}

ModelFacts is protocol-neutral state used for compatibility and diagnostics (design §ModelFacts).

type OverrideResolver

type OverrideResolver interface {
	Resolve(candidate routing.AttemptCandidate) (ModelFacts, bool)
}

OverrideResolver applies pair-then-model override precedence (design §OverrideResolver).

func NewOverrideResolver

func NewOverrideResolver(set OverrideSet) OverrideResolver

NewOverrideResolver returns a resolver for the given set (nil maps are treated as empty).

type OverrideSet

type OverrideSet struct {
	Pair  map[string]ModelFacts
	Model map[string]ModelFacts
}

OverrideSet holds administrator facts keyed by backend:model pair or model name only. Pair keys use routing.Primary backend and model with surrounding space trimmed; query params are ignored.

type RefreshFailureCategory

type RefreshFailureCategory string

RefreshFailureCategory classifies the last catalog refresh failure for diagnostics.

const (
	// RefreshFailureNone means no failure since the last successful refresh (or startup).
	RefreshFailureNone RefreshFailureCategory = ""
	// RefreshFailureFetch indicates a transport or HTTP-layer failure from the snapshot source.
	RefreshFailureFetch RefreshFailureCategory = "fetch"
	// RefreshFailureParse indicates decode, validation, or unsupported schema from fetched bytes.
	RefreshFailureParse RefreshFailureCategory = "parse"
	// RefreshFailureCache indicates a local persistence failure after a successful fetch.
	RefreshFailureCache RefreshFailureCategory = "cache"
)

type RuntimeConfig

type RuntimeConfig struct {
	Source SnapshotSource
	Cache  SnapshotCache
}

RuntimeConfig wires optional catalog refresh for CatalogRuntime.

type SizeEstimate

type SizeEstimate struct {
	Available bool
	Units     string
	Input     int64
	Basis     string
}

SizeEstimate is a deterministic, diagnostics-friendly size view (design §SizeEstimate).

type Snapshot

type Snapshot struct {
	Generation  string
	FetchedAt   time.Time
	ContentHash string
	Index       *SnapshotIndex
	// WirePayload holds the original catalog JSON object bytes used to build this snapshot for disk cache round-trips.
	WirePayload []byte
}

Snapshot is an immutable, validated catalog view for one refresh generation.

type SnapshotCache

type SnapshotCache interface {
	Load(ctx context.Context) (Snapshot, error)
	Save(ctx context.Context, snapshot Snapshot) error
}

SnapshotCache loads and persists validated snapshots locally. Implementations live outside this package.

type SnapshotIndex

type SnapshotIndex struct {
	// contains filtered or unexported fields
}

SnapshotIndex is a read-only view of catalog model ids to facts for deterministic matching.

func NewSnapshotIndex

func NewSnapshotIndex(catalog map[string]ModelFacts) *SnapshotIndex

NewSnapshotIndex returns an index backed by a defensive copy of catalog entries.

func (*SnapshotIndex) CatalogIDsForSuffixLookup

func (s *SnapshotIndex) CatalogIDsForSuffixLookup(suffix string) []string

CatalogIDsForSuffixLookup returns sorted catalog ids whose model suffix matches lookup keys (including dotted/dashed numeric variants). Nil when the index or suffix is empty.

func (*SnapshotIndex) FactsByCatalogModelID

func (s *SnapshotIndex) FactsByCatalogModelID(catalogModelID string) (ModelFacts, bool)

FactsByCatalogModelID returns catalog-derived facts for an exact catalog model id key.

type SnapshotRef

type SnapshotRef struct {
	Generation string
}

SnapshotRef is a lightweight handle to the snapshot generation used for a routing decision.

type SnapshotSource

type SnapshotSource interface {
	Fetch(ctx context.Context) (Snapshot, error)
}

SnapshotSource fetches a remote catalog snapshot. Implementations live outside this package (infra).

type StaticActiveSnapshotProvider

type StaticActiveSnapshotProvider struct {
	Index *SnapshotIndex
	Ref   SnapshotRef
}

StaticActiveSnapshotProvider returns a fixed index/ref (tests and static catalogs).

func (StaticActiveSnapshotProvider) ActiveIndex

ActiveIndex implements ActiveSnapshotProvider.

type VendorPolicy

type VendorPolicy struct {
	MapVendor            func(vendor string) string
	SuffixLookupVariants func(suffix string) []string
	KeywordFallback      func(model string) (canonical string, ok bool)
}

type VendorResolveKind

type VendorResolveKind uint8
const (
	VendorResolveNoMatch VendorResolveKind = iota
	VendorResolveExact
	VendorResolveCatalogSuffix
	VendorResolveVendorAlias
	VendorResolveAmbiguous
	VendorResolveKeywordFallback
)

func (VendorResolveKind) String

func (k VendorResolveKind) String() string

type VendorResolveResult

type VendorResolveResult struct {
	Kind           VendorResolveKind
	InputModel     string
	CanonicalID    string
	RouteModel     string
	MatchedCatalog string
	CatalogVendor  string
	Candidates     []string
}

type VendorResolver

type VendorResolver interface {
	Resolve(model string) VendorResolveResult
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL