Skip to content

Feature: chain virtual models (redirect targets referencing another virtual model) #773

Description

@weselben

Is your feature request related to a problem? Please describe.

Virtual models (redirects) can only target concrete provider models. A redirect whose target is another virtual model's source is rejected at validation time with target "<name>" refers to another virtual model (internal/virtualmodels/service.go, validateRedirectStructure; covered by TestService_RejectsRedirectTargetingAnotherRedirect). Self-targeting is rejected the same way. ValidateManagedConfig applies the same invariant to declarative config.yaml / VIRTUAL_MODELS entries, so chained managed configs fail startup too.

This forces duplicating target lists, weights, and strategies across virtual models for any layered routing. Examples:

  • An org-wide cheap alias (round-robin over small models) that should also serve as one fallback leg inside a smart-frugal group.
  • Team-scoped variants of a shared base alias — today each team variant restates the full target list.
  • A production alias pointing at a us-east alias that itself load-balances concrete models.

Every change to the underlying targets has to be edited in N places, and the copies drift.

Describe the solution you'd like

Allow a redirect target to reference another virtual model's source, resolved transitively at resolve time. Suggested guard rails:

  • Cycle detection: reject chains like a -> b -> a at upsert and at startup validation for managed config, with the offending chain spelled out in the error message.
  • Depth limit: cap chain length (e.g. 8 hops) so resolution stays bounded and cheap.
  • Strategy composition: the inner virtual model resolves to a concrete model first; the outer strategy (round-robin / cost / adaptive) then picks among its resolved concrete legs.
  • Scoping semantics documented: outer user_paths keep gating exposure; define how inner redirect scopes and policies interact when chained.
  • Disabled leg: a disabled virtual model inside a chain is treated as unavailable, the same as a skipped provider target today.

The structural checks are deliberately catalog-independent (they run before the async model catalog is warm). Cycle and depth validation fits into that same pass.

Describe alternatives you've considered

  • Duplicate target lists across virtual models (the current workaround) — works but drifts; one missed edit silently changes routing for one alias but not its siblings.
  • Flatten at write time: resolve the referenced virtual model into its concrete targets on upsert and store those. Loses live updates when the inner virtual model changes, which is the main point of chaining.
  • Layer outside the gateway (client-side fan-out or a second proxy) — defeats the purpose of a central routing layer.

Additional context

  • Enforcement lives in validateRedirectStructure (internal/virtualmodels/service.go), which rejects both self-targets and cross-redirect targets; ValidateManagedConfig reuses the same invariants for IaC-supplied virtual models.
  • Virtual models replaced the legacy aliases / model_overrides tables (ADR-0008, docs/adr/0008-virtual-models.md). Chaining was not part of that design, so this extends the redirect graph from a star to a DAG — no new entity.
  • Resolution is currently single-pass (ResolveModel, internal/virtualmodels/resolve.go). Chained resolution also needs a defined interaction with per-request override headers and with the Supports / ExposedModels projections (a chained alias should expose its leaf concrete models).

This issue was drafted with AI assistance (Kimi Code CLI). The AI analyzed the codebase at commit b289f466.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions