AkurAI Build
Menu

popagent

public

Latest change dc4b371554df3a78c40c29085ead1db3de7e24f8 - Add model routing policy, companyStatus tool, Markdown channel output, compact Runtime settings by AkurAI Build

# Models

LLM access, catalog, defaults, and the routing policy. Framework facts live in
[AGENTS_AGENT.md](AGENTS_AGENT.md).

## Provider and catalog

- LLM gateway: local **9Router** (`http://127.0.0.1:20128/v1`, OpenAI-compatible),
  via `createOpenAICompatible` from `@ai-sdk/openai-compatible`.
  Env: `NINEROUTER_URL`, `NINEROUTER_API_KEY` (see `.env.example`).
- The default model and model source are persisted in the singleton
  `popagent_agent_runtime_settings` row. The source can use the configured
  9Router model, force Titan's local Ornith route, or force 9Router's
  `auto/coding:free` route backed by currently available OpenRouter free coding
  models. `GET /api/models` merges the effective default with the gateway's
  current model IDs and context-window metadata; do not hard-code the catalog,
  default, or context limits in UI code.
- Per-request selection: `POST /api/chat` accepts an optional `model` body field;
  when omitted, the server reads the persisted effective default.
- Production agent profiles and system-owned self-update and Build-maintenance
  schedules use the configured cloud route (`cc/claude-sonnet-5`); Titan-local
  Ornith (`titan/ornith-1.0-9b-mtp-q4_k_m`) is reserved for scheduled work that
  needs little reasoning or tool use — currently the five nightly Simulation
  schedules — so cloud quota goes to reports, mail security, and self-update.
- `src/models.ts` admits at most `POPAGENT_LOCAL_MODEL_CONCURRENCY` local
  generations at once (default `2`, matching llama.cpp). Additional local calls
  wait FIFO without their own timeout, aborted waiters are removed, and a slot
  remains leased until the response stream ends or is cancelled. Remote models
  bypass this queue.
- A changed llama.cpp alias becomes selectable only after OmniRoute imports the
  upstream `/models` catalog.
- Bun's maximum 255-second idle timeout leaves enough time for slow local models
  to emit their first stream event.

## Model routing policy

- `popagent_agent_runtime_settings.model_routing` (JSONB, `ModelRouting`) holds
  `enabled`, `strategy` (`fallback` | `round-robin`), `cooldownMs`, and an
  ordered `routes[]` of `{ model, reasoningEffort }` where effort is
  `default | low | medium | high`. Edited under Settings → Runtime → Model
  routing; `PATCH /api/settings/agent-runtime` validates every route model
  against the catalog and refuses an empty enabled policy.
- The pseudo model id `policy/routing` (`ROUTING_MODEL_ID`) is listed in
  `GET /api/models` and accepted wherever a model is selectable (default model,
  agent profile, task, schedule, chat). `src/model-router.ts` resolves it per
  attempt: `fallback` returns the first route not cooling down; `round-robin`
  rotates through healthy routes; when every route is cooling down the one that
  recovers first is used. Concrete model ids pass through unchanged. With
  routing disabled or empty, the runtime default model is used and a warning is
  logged.
- A route's effective spec is `model@effort` (`modelSpec`/`parseModelSpec` in
  `api-types.ts`). `resolveModel` accepts the spec unchanged; `applyReasoningEffort`
  in `src/models.ts` strips the suffix on the wire and sends OpenAI-compatible
  `reasoning_effort`, so 9Router receives the real model id. `isKnownModel`
  validates the base id.
- `createAgentTaskExecutor` picks one spec per attempt (`task.model.routed`
  log, "Routing to …" progress line) and, on failure, calls
  `ModelRouter.reportFailure`: only rate-limit (429/usage-limit/quota) and
  unknown-model failures take a route out of rotation for `cooldownMs` (a
  "reset after Nm" hint extends it). Cooldowns are process-local; a restart
  clears them. `GET /api/models/routing` exposes per-route cooldown, last error,
  and pick counts, rendered as LEDs on the settings page.
- Contracts: `src/model-router.test.ts`, `src/agent-runtime-settings.test.ts`.