# AI Travel Agent Redesign Plan

## Vision Summary

Redesign the AI travel agent with two context-aware entry points, user preference learning, flexible provider configuration, extensibility for future integrations, web search capability, and multi-user collection support.

---

## Architecture Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                        ENTRY POINTS                              │
├─────────────────────────────┬───────────────────────────────────┤
│  Day-Level Suggestions      │  Collection-Level Chat            │
│  (new modal)                │  (improved Recommendations tab)   │
│  - Category filters         │  - Context-aware                  │
│  - Sub-filters              │  - Add to itinerary actions       │
│  - Add to day action        │                                   │
└─────────────────────────────┴───────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      AGENT CORE                                  │
├─────────────────────────────────────────────────────────────────┤
│  - LiteLLM backend (streaming SSE)                              │
│  - Tool calling (place search, web search, itinerary actions)   │
│  - Multi-user preference aggregation                            │
│  - Context injection (collection, dates, location)              │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                   CONFIGURATION LAYERS                           │
├─────────────────────────────────────────────────────────────────┤
│  Instance (.env)    →  VOYAGE_AI_PROVIDER                       │
│                      →  VOYAGE_AI_MODEL                         │
│                      →  VOYAGE_AI_API_KEY                       │
│  User (DB)          →  UserAPIKey.per-provider keys             │
│                      →  UserAISettings.model preference         │
│  Fallback: User key → Instance key → Error                      │
└─────────────────────────────────────────────────────────────────┘
```

---

## Workstreams

### WS1: Configuration Infrastructure

**Goal**: Support both instance-level and user-level provider/model configuration with proper fallback.

#### WS1-F1: Instance-level configuration
- Add env vars to `settings.py`:
  - `VOYAGE_AI_PROVIDER` (default: `openai`)
  - `VOYAGE_AI_MODEL` (default: `gpt-4o-mini`)
  - `VOYAGE_AI_API_KEY` (optional global key)
- Update `llm_client.py` to read instance defaults
- Add fallback chain: user key → instance key → error

#### WS1-F2: User-level model preferences
- Add `UserAISettings` model (OneToOne → CustomUser):
  - `preferred_provider` (CharField)
  - `preferred_model` (CharField)
- Create API endpoint: `POST /api/ai/settings/`
- Add UI in Settings → AI section for model selection

#### WS1-F3: Provider catalog enhancement
- Extend provider catalog response to include:
  - `instance_configured`: bool (has instance key)
  - `user_configured`: bool (has user key)
- Update frontend to show configuration status per provider

**Files**: `settings.py`, `llm_client.py`, `integrations/models.py`, `integrations/views/`, `frontend/src/routes/settings/`

---

### WS2: User Preference Learning

**Goal**: Capture and use user preferences in AI recommendations.

#### WS2-F1: Preference UI
- Add "AI Preferences" tab to Settings page
- Form fields: cuisines, interests, trip_style, notes
- Use tag input for cuisines/interests (better UX than free text)
- Connect to existing `/api/integrations/recommendation-preferences/`

Implementation notes (2026-03-08):
- Implemented in `frontend/src/routes/settings/+page.svelte` as `travel_preferences` section in the existing settings sidebar, with `savePreferences(event)` posting to `/api/integrations/recommendation-preferences/`.
- `interests` conversion is string↔array at UI boundary: load via `(profile.interests || []).join(', ')`; save via `.split(',').map((s) => s.trim()).filter(Boolean)`.
- SSR preload added in `frontend/src/routes/settings/+page.server.ts` using parallel fetch with API keys; returns `props.recommendationProfile` as first list element or `null`.
- Frontend typing added in `frontend/src/lib/types.ts` (`UserRecommendationPreferenceProfile`) and i18n strings added under `settings` in `frontend/src/locales/en.json`.
- See backend capability reference in [Project Knowledge — User Recommendation Preference Profile](../knowledge.md#user-recommendation-preference-profile).

#### WS2-F2: Preference injection
- Enhance `get_system_prompt()` to format preferences better
- Add preference summary in system prompt (structured, not just appended)

#### WS2-F3: Multi-user aggregation
- New function: `get_aggregated_preferences(collection)` 
- Returns combined preferences from all `collection.shared_with` users + owner
- Format: "Party preferences: User A likes X, User B prefers Y..."
- Inject into system prompt for shared collections

**Files**: `frontend/src/routes/settings/`, `chat/llm_client.py`, `integrations/models.py`

---

### WS3: Day-Level Suggestions Modal

**Goal**: Add "Suggest" option to itinerary day "Add" dropdown with category filters.

#### WS3-F1: Suggestion modal component
- Create `ItinerarySuggestionModal.svelte`
- Two-step flow:
  1. **Category selection**: Restaurant, Activity, Event, Lodging
  2. **Filter refinement**: 
     - Restaurant: cuisine type, price range, dietary restrictions
     - Activity: type (outdoor, cultural, etc.), duration
     - Event: type, date/time preference
     - Lodging: type, amenities
- "Any/Surprise me" option for each filter

#### WS3-F2: Add button integration
- Add "Get AI suggestions" option to `CollectionItineraryPlanner.svelte` Add dropdown
- Opens suggestion modal with target date pre-set
- Modal receives: `collectionId`, `targetDate`, `collectionLocation` (for context)

#### WS3-F3: Suggestion results display
- Show 3-5 suggestions as cards with:
  - Name, description, why it fits preferences
  - "Add to this day" button
  - "Add to different day" option
- On add: **direct REST API call** to `/api/itineraries/` (not agent tool)
- User must approve each item individually - no bulk/auto-add
- Close modal and refresh itinerary on success

#### WS3-F4: Backend suggestion endpoint
- New endpoint: `POST /api/ai/suggestions/day/`
- Params: `collection_id`, `date`, `category`, `filters`, `location_context`
- Returns structured suggestions (not chat, direct JSON)
- Uses agent internally but returns parsed results

**Files**: `CollectionItineraryPlanner.svelte`, `ItinerarySuggestionModal.svelte` (new), `chat/views.py`, `chat/agent_tools.py`

---

### WS3.5: Insertion Flow Clarification

**Two insertion paths exist:**

| Path | Entry Point | Mechanism | Use Case |
|------|-------------|-----------|----------|
| **User-approved** | Suggestions modal | Direct REST API call to `/api/itineraries/` | Day-level suggestions, user reviews and clicks Add |
| **Agent-initiated** | Chat (Recommendations tab) | `add_to_itinerary` tool via SSE streaming | Conversational adds when user says "add that place" |

**Why two paths:**
- Modal: Faster, simpler UX - no round-trip through agent, user stays in control
- Chat: Natural conversation flow - agent can add as part of dialogue

**No changes needed to agent tools** - `add_to_itinerary` already exists in `agent_tools.py` and works for chat-initiated adds.

---

### WS4: Collection-Level Chat Improvements

**Goal**: Make Recommendations tab chat context-aware and action-capable.

#### WS4-F1: Context injection
- Pass collection context to `AITravelChat.svelte`:
  - `collectionId`, `collectionName`, `startDate`, `endDate`
  - `destination` (from collection locations or user input)
- Inject into system prompt: "You are helping plan a trip to X from Y to Z"

Implementation notes (2026-03-08):
- `frontend/src/lib/components/AITravelChat.svelte` now exposes optional context props (`collectionId`, `collectionName`, `startDate`, `endDate`, `destination`) and includes them in `POST /api/chat/conversations/{id}/send_message/` payload.
- `frontend/src/routes/collections/[id]/+page.svelte` now passes collection context into `AITravelChat`; destination is derived via `deriveCollectionDestination(...)` from `city/country/location/name` on the first usable location.
- `backend/server/chat/views/__init__.py::ChatViewSet.send_message()` now accepts the same optional fields, resolves `collection_id` (owner/shared access only), and appends a `## Trip Context` block to the system prompt before streaming.
- Related architecture note: [Project Knowledge — AI Chat](../knowledge.md#ai-chat-collections--recommendations).

#### WS4-F2: Quick action buttons
- Add preset prompts above chat input:
  - "Suggest restaurants for this trip"
  - "Find activities near [destination]"
  - "What should I pack for [dates]?"
- Pre-fill input on click

#### WS4-F3: Add-to-itinerary from chat
- When agent suggests a place, show "Add to itinerary" button
- User selects date → calls `add_to_itinerary` tool
- Visual feedback on success

Implementation notes (2026-03-08):
- Implemented in `frontend/src/lib/components/AITravelChat.svelte` as an MVP direct frontend flow (no agent round-trip):
  - Adds `Add to Itinerary` button to `search_places` result cards when `collectionId` exists.
  - Opens a date picker modal (`showDateSelector`, `selectedPlaceToAdd`, `selectedDate`) constrained by trip date range (`min={startDate}`, `max={endDate}`).
  - On confirm, creates a location via `POST /api/locations/` then creates itinerary entry via `POST /api/itineraries/`.
  - Dispatches `itemAdded { locationId, date }` and shows success toast (`added_successfully`).
  - Guards against missing/invalid coordinates by disabling add action unless lat/lon parse successfully.
- i18n keys added in `frontend/src/locales/en.json`: `add_to_itinerary`, `add_to_which_day`, `added_successfully`.

#### WS4-F4: Improved UI
- Remove generic "robot" branding, use travel-themed design
- Show collection name in header
- Better tool result display (cards instead of raw JSON)

Implementation notes (2026-03-08):
- `frontend/src/lib/components/AITravelChat.svelte` header now uses travel branding with `✈️` and renders `Travel Assistant · {collectionName}` when collection context is present; destination is shown as a subtitle when provided.
- Robot icon usage in chat UI was replaced with travel-themed emoji (`✈️`, `🌍`, `🗺️`) while keeping existing layout structure.
- SSE `tool_result` chunks are now attached to the in-flight assistant message via `tool_results` and rendered inline as structured cards for `search_places` and `web_search`, with JSON `<pre>` fallback for unknown tools.
- Legacy persisted `role: 'tool'` messages are still supported via JSON parsing fallback and use the same card rendering logic.
- i18n root keys added in `frontend/src/locales/en.json`: `travel_assistant`, `quick_actions`.

See [Project Knowledge — WS4-F4 Chat UI Rendering](../knowledge.md#ws4-f4-chat-ui-rendering).

**Files**: `AITravelChat.svelte`, `chat/views.py`, `chat/llm_client.py`

---

### WS5: Web Search Capability

**Goal**: Enable agent to search the web for current information.

#### WS5-F1: Web search tool
- Add `web_search` tool to `agent_tools.py`:
  - Uses DuckDuckGo (free, no API key) or Brave Search API (env var)
  - Returns top 5 results with titles, snippets, URLs
- Tool schema:
  ```python
  {
      "name": "web_search",
      "description": "Search the web for current information about destinations, events, prices, etc.",
      "parameters": {
          "query": "string - search query",
          "location_context": "string - optional location to bias results"
      }
  }
  ```

#### WS5-F2: Tool integration
- Register in `AGENT_TOOLS` list
- Add to `execute_tool()` dispatcher
- Handle rate limiting gracefully

**Files**: `chat/agent_tools.py`, `requirements.txt` (add `duckduckgo-search`)

---

### WS6: Extensibility Architecture

**Goal**: Design for easy addition of future integrations.

#### WS6-F1: Plugin tool registry
- Refactor `agent_tools.py` to use decorator-based registration:
  ```python
  @agent_tool(name="web_search", description="...")
  def web_search(query: str, location_context: str = None):
      ...
  ```
- Tools auto-register on import
- Easy to add new tools in separate files

#### WS6-F2: Integration hooks
- Create `chat/integrations/` directory for future:
  - `tripadvisor.py` - TripAdvisor API integration
  - `flights.py` - Flight search (Skyscanner, etc.)
  - `weather.py` - Enhanced weather data
- Each integration exports tools via decorator

#### WS6-F3: Capability discovery
- Endpoint: `GET /api/ai/capabilities/`
- Returns list of available tools/integrations
- Frontend can show "Powered by X, Y, Z" dynamically

**Files**: `chat/tools/` (new directory), `chat/agent_tools.py` (refactor)

---

## File Changes Summary

### New Files
- `frontend/src/lib/components/collections/ItinerarySuggestionModal.svelte`
- `backend/server/chat/tools/__init__.py`
- `backend/server/chat/tools/web_search.py`
- `backend/server/integrations/models.py` (add UserAISettings)
- `backend/server/integrations/views/ai_settings_view.py`

### Modified Files
- `backend/server/main/settings.py` - Add AI env vars
- `backend/server/chat/llm_client.py` - Config fallback, preference aggregation
- `backend/server/chat/views.py` - New suggestion endpoint, context injection
- `backend/server/chat/agent_tools.py` - Web search tool, refactor
- `frontend/src/lib/components/AITravelChat.svelte` - Context awareness, actions
- `frontend/src/lib/components/collections/CollectionItineraryPlanner.svelte` - Add button
- `frontend/src/routes/settings/+page.svelte` - AI preferences UI, model selection
- `frontend/src/routes/collections/[id]/+page.svelte` - Pass collection context

---

## Migration Path

1. **Phase 1 - Foundation** (WS1, WS2)
   - Configuration infrastructure
   - Preference UI
   - No user-facing changes to chat yet

2. **Phase 2 - Day Suggestions** (WS3)
   - New modal, new entry point
   - Backend suggestion endpoint
   - Can ship independently

3. **Phase 3 - Chat Improvements** (WS4, WS5)
   - Context-aware chat
   - Web search capability
   - Better UX

4. **Phase 4 - Extensibility** (WS6)
   - Plugin architecture
   - Future integration prep

---

## Decisions (Confirmed)

| Decision | Choice | Rationale |
|----------|--------|-----------|
| Web search provider | **DuckDuckGo** | Free, no API key, good enough for travel info |
| Suggestion API | **Dedicated REST endpoint** | Simpler, faster, returns JSON directly |
| Multi-user conflicts | **List all preferences** | Transparency - AI navigates differing preferences |

---

## Out of Scope

- WSGI→ASGI migration (keep current async-in-sync pattern)
- Role-based permissions (all shared users have same access)
- Real-time collaboration (WebSocket sync)
- Mobile-specific optimizations
