# Plan: AI travel agent in Collections Recommendations

## Clarified requirements
- Move AI travel agent UX from standalone `/chat` tab/page into Collections → Recommendations.
- Remove the existing `/chat` route (not keep/redirect).
- Provider list should be dynamic and display all providers LiteLLM supports.
- Ensure OpenCode Zen is supported as a provider.

## Execution prerequisites
- In each worktree, run `cd frontend && npm install` before implementation to ensure node modules (including `@mdi/js`) are present and baseline build can run.

## Decomposition (approved by user)

### Workstream 1 — Collections recommendations chat integration (Frontend + route cleanup)
- **Worktree**: `.worktrees/collections-ai-agent`
- **Branch**: `feat/collections-ai-agent`
- **Risk**: Medium
- **Quality tier**: Tier 2
- **Task WS1-F1**: Embed AI chat experience inside Collections Recommendations UI.
  - **Acceptance criteria**:
    - Chat UI is available from Collections Recommendations section.
    - Existing recommendations functionality remains usable.
    - Chat interactions continue to work with existing backend chat APIs.
- **Task WS1-F2**: Remove standalone `/chat` route/page.
  - **Acceptance criteria**:
    - `/chat` page is removed from app routes/navigation.
    - No broken imports/navigation links remain.

### Workstream 2 — Provider catalog + Zen provider support (Backend + frontend settings/chat)
- **Worktree**: `.worktrees/litellm-provider-catalog`
- **Branch**: `feat/litellm-provider-catalog`
- **Risk**: Medium
- **Quality tier**: Tier 2 (promote to Tier 1 if auth/secret handling changes)
- **Task WS2-F1**: Implement dynamic provider listing based on LiteLLM-supported providers.
  - **Acceptance criteria**:
    - Backend exposes `GET /api/chat/providers/` using LiteLLM runtime provider list as source data.
    - Frontend provider selectors consume backend provider catalog rather than hardcoded arrays.
    - UI displays all LiteLLM provider IDs and metadata; non-chat-compatible providers are labeled unavailable.
    - Existing saved provider/API-key flows still function.
- **Task WS2-F2**: Add/confirm OpenCode Zen provider support end-to-end.
  - **Acceptance criteria**:
    - OpenCode Zen appears as provider id `opencode_zen`.
    - Backend model resolution and API-key lookup work for `opencode_zen`.
    - Zen calls use LiteLLM OpenAI-compatible routing with `api_base=https://opencode.ai/zen/v1`.
    - Chat requests using Zen provider are accepted without fallback/validation failures.

## Provider architecture decision
- Backend provider catalog endpoint `GET /api/chat/providers/` is the single source of truth for UI provider options.
- Endpoint response fields: `id`, `label`, `available_for_chat`, `needs_api_key`, `default_model`, `api_base`.
- All LiteLLM runtime providers are returned; entries without model mapping are `available_for_chat=false`.
- Chat send path only accepts providers where `available_for_chat=true`.

## Research findings (2026-03-08)
- LiteLLM provider enumeration is available at runtime (`litellm.provider_list`), currently 128 providers in this environment.
- OpenCode Zen is not a native LiteLLM provider alias; support should be implemented via OpenAI-compatible provider config and explicit `api_base`.
- Existing hardcoded provider duplication (backend + chat page + settings page) will be replaced by backend catalog consumption.
- Reference: [LiteLLM + Zen provider research](../research/litellm-zen-provider-catalog.md)

## Dependencies
- WS1 depends on existing chat API endpoint behavior and event streaming contract.
- WS2 depends on LiteLLM provider metadata/query capabilities and provider-catalog endpoint design.
- WS1-F1 depends on WS2 completion for dynamic provider selector integration.
- WS1-F2 depends on WS1-F1 completion.

## Human checkpoints
- No checkpoint required: Zen support path uses existing LiteLLM dependency via OpenAI-compatible API (no new SDK/service).

## Findings tracker
- WS1-F1 implemented in worktree `.worktrees/collections-ai-agent`:
  - Extracted chat route UI into reusable component `frontend/src/lib/components/AITravelChat.svelte`, preserving conversation list, message stream rendering, provider selector, conversation CRUD, and SSE send-message flow via `/api/chat/conversations/*`.
  - Updated `frontend/src/routes/chat/+page.svelte` to render the reusable component so existing `/chat` behavior remains intact for WS1-F1 scope (WS1-F2 route removal deferred).
  - Embedded `AITravelChat` into Collections Recommendations view in `frontend/src/routes/collections/[id]/+page.svelte` above `CollectionRecommendationView`, keeping existing recommendation search/map/create flows unchanged.
  - Reviewer warning resolved: removed redundant outer card wrapper around `AITravelChat` in Collections Recommendations embedding, eliminating nested card-in-card styling while preserving spacing and recommendations placement.
- WS1-F2 implemented in worktree `.worktrees/collections-ai-agent`:
  - Removed standalone chat route page by deleting `frontend/src/routes/chat/+page.svelte`.
  - Removed `/chat` navigation item from `frontend/src/lib/components/Navbar.svelte`, including the now-unused `mdiRobotOutline` icon import.
  - Verified embedded chat remains in Collections Recommendations via `AITravelChat` usage in `frontend/src/routes/collections/[id]/+page.svelte`; no remaining `/chat` route links/imports in `frontend/src`.
- WS2-F1 implemented in worktree `.worktrees/litellm-provider-catalog`:
  - Added backend provider catalog endpoint `GET /api/chat/providers/` from `litellm.provider_list` with response fields `id`, `label`, `available_for_chat`, `needs_api_key`, `default_model`, `api_base`.
  - Refactored chat provider model map into `CHAT_PROVIDER_CONFIG` in `backend/server/chat/llm_client.py` and reused it for both send-message routing and provider catalog metadata.
  - Updated chat/settings frontend provider consumers to fetch provider catalog dynamically and removed hardcoded provider arrays.
  - Chat UI now restricts provider selection/sending to `available_for_chat=true`; settings API key UI now lists full provider catalog (including unavailable-for-chat entries).
- WS2-F1 reviewer carry-forward fixes applied:
  - Fixed chat provider selection fallback timing in `frontend/src/routes/chat/+page.svelte` by computing `availableProviders` from local `catalog` response data instead of relying on reactive `chatProviders` immediately after assignment.
  - Applied low-risk settings improvement in `frontend/src/routes/settings/+page.svelte` by changing `await loadProviderCatalog()` to `void loadProviderCatalog()` in the second `onMount`, preventing provider fetch from delaying success toast logic.
- WS2-F2 implemented in worktree `.worktrees/litellm-provider-catalog`:
  - Added `opencode_zen` to `CHAT_PROVIDER_CONFIG` in `backend/server/chat/llm_client.py` with label `OpenCode Zen`, `needs_api_key=true`, `default_model=openai/gpt-4o-mini`, and `api_base=https://opencode.ai/zen/v1`.
  - Updated `get_provider_catalog()` to append configured chat providers not present in `litellm.provider_list`, ensuring OpenCode Zen appears in `GET /api/chat/providers/` even though it is an OpenAI-compatible alias rather than a native LiteLLM provider id.
  - Normalized provider IDs in `get_llm_api_key()` and `stream_chat_completion()` via `_normalize_provider_id()` to keep API-key lookup and LLM request routing consistent for `opencode_zen`.
- Consolidation completed in worktree `.worktrees/collections-ai-agent`:
  - Ported WS2 provider-catalog backend to `backend/server/chat` in the collections branch, including `GET /api/chat/providers/`, `CHAT_PROVIDER_CONFIG` metadata fields (`label`, `needs_api_key`, `default_model`, `api_base`), and chat-send validation to allow only `available_for_chat` providers.
  - Confirmed `opencode_zen` support in consolidated branch with `label=OpenCode Zen`, `default_model=openai/gpt-4o-mini`, `api_base=https://opencode.ai/zen/v1`, and API-key-required behavior.
  - Replaced hardcoded providers in `frontend/src/lib/components/AITravelChat.svelte` with dynamic `/api/chat/providers/` loading, preserving send guard to chat-available providers only.
  - Updated settings API-key provider dropdown in `frontend/src/routes/settings/+page.svelte` to load full provider catalog dynamically and added `ChatProviderCatalogEntry` type in `frontend/src/lib/types.ts`.
  - Preserved existing collections chat embedding and kept standalone `/chat` route removed (no route reintroduction in consolidation changes).

## Retry tracker
- WS1-F1: 0
- WS1-F2: 0
- WS2-F1: 0
- WS2-F2: 0

## Execution checklist
- [x] WS2-F1 Dynamic provider listing from LiteLLM (Tier 2)
- [x] WS2-F2 OpenCode Zen provider support (Tier 2)
- [x] WS1-F1 Embed AI chat into Collections Recommendations (Tier 2)
- [x] WS1-F2 Remove standalone `/chat` route (Tier 2)
- [x] Documentation coverage + knowledge sync (Librarian)
