Files
ai-agent/backend/models/routes.py
Gabriel Vidal 0ff9e40242 refactor(backend): split main.py into domain packages with app.state injection
main.py (5146 lines, 106 routes) becomes an assembly only: one package per
domain — core, files, settings, dashboards, conversations, diff,
notifications, forms, runs, accounts, workers, models, cron, agents,
projects, services, goals, memories, plans, templates — each exposing an
APIRouter; the flat domain modules move into their package behind a barrel
that keeps the old `import conversations` / `import projects` spellings.

The shared singletons (store, meta_store, hub, indexer, …) are built once by
core.state.build_state() and attached to app.state.ai; routes take them as
the `deps: State` dependency and helpers as an explicit `deps: AppState`.
conversations/pricing.py carries the per-model rates out of the parser.

Verified: route table and OpenAPI byte-identical; 90 read endpoints
golden-diffed against the monolith on a copy of the live data (identical);
write routes smoke-tested; 66 backend tests pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 23:55:47 +02:00

39 lines
1.4 KiB
Python

"""The models a session can run on, and the OpenRouter catalogue."""
from fastapi import APIRouter
import models as models_mod
import schemas
from core.http import _r
from models import openrouter as openrouter_mod
router = APIRouter()
@router.get("/api/models", responses=_r(schemas.ModelsResponse))
def list_models():
"""The models a session can be spawned/resumed on (a tag each in the composer).
Fetched from the Anthropic API and cached in-process (see models.py), so the
picker follows new releases without a redeploy. `default` is what a run uses
when no model tag is picked."""
return {"models": models_mod.list_models(),
"default": models_mod.DEFAULT_MODEL}
@router.get("/api/models/openrouter",
responses=_r(schemas.OpenRouterModelsResponse))
def list_openrouter_models():
"""Every model a pi.dev session can run on OpenRouter, cheapest first.
Not part of `/api/models` on purpose: that endpoint is the composer's short
pickable list (one chip per Claude family + the curated pi entries), while
this is a few hundred models the model browser searches through. Prices
($/Mtok in / out / cache), context window and parameter size all come from
APPE's catalogue — the homelab's model-data source of truth (openrouter.py).
"""
return {"models": openrouter_mod.catalogue(),
"source": openrouter_mod.CATALOGUE_URL,
"generatedAt": openrouter_mod.generated_at()}