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
| Level | What it is | Change it to… |
|---|---|---|
| Category | the kind of work (12 modalities) — how a call site names its need | add a new modality of LLM work |
| Profile | a complete category→tier assignment — the fleet's quality/cost posture | shift the whole fleet up/down a rung, or pin a few categories |
| Tier | budget · balanced · performance · frontier — the quality/cost ladder | retune 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,resolveWebsearchresolve 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.