Skip to content

ADR-0008: Provider-agnostic `ModelTier`

Status: Accepted Date: 2026-04-20

The platform routes different tasks to different language models — cheap and fast for sub-agents, mid-range for main agents, top-tier for critical decisions. We also plan to use more than one provider: Anthropic for reasoning, OpenAI for image generation and embeddings, possibly others later.

If agent definitions name specific models ("claude-sonnet-4.5", "gpt-5"), every model upgrade requires editing every agent file. Worse, it couples agent configuration to provider identity — a pain point if we ever add a new provider or want to run a silent A/B.

Agent definitions declare a capability tier, not a model:

export type ModelTier = 'critical' | 'main' | 'sub';

The runtime maintains a mapping from ModelTier (and provider) to concrete model identifier. An agent asking for the main tier gets whatever we’ve decided is the right main-tier model at that moment.

  • Agent definitions survive model upgrades untouched.
  • Swapping providers is a runtime mapping change; agent YAML stays the same.
  • Routing logic — tier → model, with optional per-agent overrides and provider selection — lives in one place and is testable on its own.
  • We lose the ability to hard-code “this specific agent always uses Haiku.” Acceptable now; if we need fine-grained control later, we can add a per-agent override field without breaking the tier abstraction.
  • The three-tier bucket is a deliberately coarse choice. More tiers can be added, but “critical / main / sub” maps cleanly to how we actually reason about agent cost vs capability.
  • Direct model names in agent definitions: tight coupling, painful upgrades, fights portability.
  • Numeric tiers (1 / 2 / 3): semantically opaque; new contributors have to learn what the numbers mean.
  • Anthropic-specific tier names (opus / sonnet / haiku): works today but becomes a lie as soon as we route to OpenAI. The abstraction has to be vendor-neutral to be honest.
  • No abstraction; use the LLM SDK’s model field directly: same problem as direct model names, with worse ergonomics.