# 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/`. - [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.)