Files
voyage/.memory/plans/ai-travel-agent-redesign.md
alex wiesner c4d39f2812 changes
2026-03-13 20:15:22 +00:00

16 KiB

title, type, permalink
title type permalink
ai-travel-agent-redesign note voyage/plans/ai-travel-agent-redesign

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.

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.

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.

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:
    {
        "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:
    @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