# multi-llama-swap-providers-model-favorites — tasks

## P0 — config and contracts

- [x] Add a shared local-provider config schema under `packages/contracts`.
- [x] Add `LLAMA_PROVIDERS_PATH` to `apps/server/src/config.ts` and
  `apps/coder/src/config.ts`.
- [x] Add `data/llama-providers.example.json` with `sam-desktop` and
  `embedding`.
- [x] Implement a loader that falls back to the legacy single-provider env vars
  when the shared file is missing.

## P1 — model identity helpers

- [x] Add shared parsing/formatting helpers for composite model IDs:
  `provider/model`.
- [x] Preserve indefinite support for legacy bare IDs by resolving them to the
  configured default provider.
- [x] Update display-name helpers to strip only the provider prefix intended for
  presentation, not for routing/cache identity.

## P2 — server model catalog and routing

- [x] Refactor `apps/server/src/routes/models.ts` to emit a provider-aware model
  catalog with composite IDs.
- [x] Refactor `apps/server/src/services/inference/provider.ts` to resolve route
  and base URL from provider identity instead of string heuristics alone.
- [x] Make sidecar routing a per-provider attribute so `embedding/*` never hits
  `LLAMA_SIDECAR_URL`.
- [x] Replace the bare `deepseek-` prefix special case with provider-aware
  handling for DeepSeek models.

## P3 — server call sites that currently assume one endpoint

- [x] Update `apps/server/src/services/model-context.ts` to fetch upstream props
  from the resolved provider and key caches by the full composite ID.
- [x] Update `apps/server/src/services/compaction.ts` to use the resolved
  provider endpoint for summaries.
- [x] Update `apps/server/src/services/task-model.ts` to resolve fallback models
  through the same provider-aware endpoint logic.
- [x] Verify any other direct `LLAMA_SWAP_URL` usage in `apps/server` is either
  migrated or explicitly documented as legacy-only.

## P4 — favorites persistence

- [x] Add `favorite_models` handling to `apps/server/src/routes/settings.ts`.
- [x] Define normalization rules for malformed, duplicate, or unavailable
  favorites.
- [x] Ensure unavailable favorites are hidden from visible picker sections but
  never auto-deleted from settings.
- [x] Keep favorites out of the server model-catalog payload; derive the
  Favorites section in the clients from settings + provider-aware inventory.

## P5 — BooChat UI

- [x] Update `apps/web/src/components/ModelPicker.tsx` to render:
  Favorites first, then provider sections.
- [x] Add a per-model favorite toggle wired to `PATCH /api/settings`.
- [x] Keep favorited models visible in their provider group as well as the
  Favorites section.
- [x] Verify session model changes write composite IDs for new selections.

## P6 — BooCoder snapshot, dispatch, and arena

- [x] Update `apps/coder/src/services/provider-snapshot.ts` so BooCode's local
  `boocode` provider models retain composite IDs in snapshot data.
- [x] Update the compact picker in
  `apps/web/src/components/AgentComposerBar.tsx` to match the grouped/favorite
  behavior used by BooChat for native local models.
- [x] Update `apps/coder/src/services/arena-model-call.ts` and
  `apps/coder/src/services/arena-analyzer.ts` to use provider-aware routing.

## P7 — external-agent parity decision (`opencode`)

- [x] Decide whether the first slice includes `opencode` multi-provider local
  models or explicitly limits parity to native `boocode`.
- [x] If `opencode` parity is included, add a provider-identity-preserving
  bridge instead of collapsing to `llama-swap/<wireModelId>`.
- [x] Preferred bridge: a BooCoder-hosted OpenAI-compatible local-model gateway
  for consumers that still assume one provider namespace.
- [x] If the bridge is deferred, stop advertising multi-provider local models
  under the `opencode` provider until the bridge exists.

## P8 — tests and verification

- [x] Add unit tests for model-ref parsing, legacy bare-ID fallback, and
  provider-aware routing.
- [x] Add tests covering the `embedding/deepseek-r1-qwen3-8b` collision case.
- [x] Add tests proving duplicate model names on two hosts do not share context
  cache entries.
- [x] Add UI or route tests for favorites hide-not-delete behavior.
  (`apps/server/src/routes/__tests__/settings-favorites.test.ts`, DB-gated:
  unavailable favorite persists through PATCH/GET and unrelated writes;
  removal is explicit-only.)
- [ ] Smoke test native BooChat/BooCoder against:
  `sam-desktop`, `embedding`, and DeepSeek-enabled configs.
  (API layer verified 2026-06-12: both hosts healthy, `/api/models` serving
  grouped composite ids live. Remaining: in-browser send-a-message pass per
  provider group + a DeepSeek-enabled config.)
- [x] If `opencode` parity ships in-scope, add a smoke test proving duplicate
  local model names still route to the intended provider.
  (`apps/coder/src/services/__tests__/local-gateway-routing.test.ts`:
  resolver + HTTP-route level — same wire name routes to distinct baseUrls
  with the bare wire id upstream; unknown provider → 400, no upstream call.)
