MeridiansMeridians

AI model routing — tier · category · profile [Concept]

From the Meridians Wiki · Public · Maintained · joint

Every LLM call funnels through one boundary (callGenerate) and asks for its model by what kind of work it is, never by a hardcoded id. A three-level indirection turns "this is a prose call" into "run it on this OpenRouter model" — and lets the whole fleet re-tune with a one-line change or a profile swap.

flowchart LR
    Call["call site<br/>*'this is a **write** call'*"] -->|"modelFor('write')"| Resolver

    subgraph Resolver["model-resolver — a precomputed lookup"]
        direction TB
        Cat["**category** (12)<br/>generate · plan · extract · predict ·<br/>write · review · synthesis · gameTheory ·<br/>interaction · action · intuition · question"]
        Prof["**active profile**<br/>a full category → tier assignment<br/>*(app settings; balanced-smart default)*"]
        Tier["**tier** (4)<br/>budget · balanced · performance · frontier"]
        Cat -->|"profile maps category→tier"| Prof --> Tier
    end

    Tier -->|"TIER_MODEL[tier]"| Model(["concrete OpenRouter id<br/>e.g. google/gemini-2.5-flash"])
    Model --> Boundary["**callGenerate** — the one AI boundary<br/>+ named token budget · reasoning budget · websearch"]

The three levels — each swappable in isolation

LevelWhat it isChange it to…
Categorythe kind of work (12 modalities) — how a call site names its needadd a new modality of LLM work
Profilea complete category→tier assignment — the fleet's quality/cost postureshift the whole fleet up/down a rung, or pin a few categories
Tierbudget · balanced · performance · frontier — the quality/cost ladderretune every category on that rung via TIER_MODEL

Invariants

  • modelFor(category) is the only way to pick a model. Call sites never hardcode an id; standards §4 enforces it. This is what makes a profile swap re-route every call of a category live.
  • Impact grouping guides the ladder. Categories are tagged by how much dropping their tier costs downstream — substrate work (generate, plan, extract, predict) compounds and is protected; additive/ephemeral work (gameTheory, question) can ride a cheaper tier.
  • Token limits and reasoning budgets are fleet settings, not call-site magic numbers. MAX_TOKENS_*, resolveReasoningBudget, resolveWebsearch resolve at the boundary; JSON is parsed strictly and malformed output follows the caller's ordinary retry policy.

Where it lives: src/lib/core/ai-profiles.ts (tiers · categories · profiles · TIER_MODEL), src/lib/core/model-resolver.ts (modelFor, precomputed category→model map), src/lib/engine/ai/infra/api.ts (callGenerate + budget/websearch resolvers). The call-site inventory and cost ladder are owned by AI_MODELS.md; the discipline by the standards skill. High-level engine flow: engine-pipeline.