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.pyto read instance defaults - Add fallback chain: user key → instance key → error
WS1-F2: User-level model preferences
- Add
UserAISettingsmodel (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.svelteastravel_preferencessection in the existing settings sidebar, withsavePreferences(event)posting to/api/integrations/recommendation-preferences/. interestsconversion 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.tsusing parallel fetch with API keys; returnsprops.recommendationProfileas first list element ornull. - Frontend typing added in
frontend/src/lib/types.ts(UserRecommendationPreferenceProfile) and i18n strings added undersettingsinfrontend/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_withusers + 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:
- Category selection: Restaurant, Activity, Event, Lodging
- 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.svelteAdd 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,endDatedestination(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.sveltenow exposes optional context props (collectionId,collectionName,startDate,endDate,destination) and includes them inPOST /api/chat/conversations/{id}/send_message/payload.frontend/src/routes/collections/[id]/+page.sveltenow passes collection context intoAITravelChat; destination is derived viaderiveCollectionDestination(...)fromcity/country/location/nameon the first usable location.backend/server/chat/views/__init__.py::ChatViewSet.send_message()now accepts the same optional fields, resolvescollection_id(owner/shared access only), and appends a## Trip Contextblock 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_itinerarytool - Visual feedback on success
Implementation notes (2026-03-08):
- Implemented in
frontend/src/lib/components/AITravelChat.svelteas an MVP direct frontend flow (no agent round-trip):- Adds
Add to Itinerarybutton tosearch_placesresult cards whencollectionIdexists. - 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 viaPOST /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.
- Adds
- 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.svelteheader now uses travel branding with✈️and rendersTravel 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_resultchunks are now attached to the in-flight assistant message viatool_resultsand rendered inline as structured cards forsearch_placesandweb_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_searchtool toagent_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_TOOLSlist - 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.pyto 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 integrationflights.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.sveltebackend/server/chat/tools/__init__.pybackend/server/chat/tools/web_search.pybackend/server/integrations/models.py(add UserAISettings)backend/server/integrations/views/ai_settings_view.py
Modified Files
backend/server/main/settings.py- Add AI env varsbackend/server/chat/llm_client.py- Config fallback, preference aggregationbackend/server/chat/views.py- New suggestion endpoint, context injectionbackend/server/chat/agent_tools.py- Web search tool, refactorfrontend/src/lib/components/AITravelChat.svelte- Context awareness, actionsfrontend/src/lib/components/collections/CollectionItineraryPlanner.svelte- Add buttonfrontend/src/routes/settings/+page.svelte- AI preferences UI, model selectionfrontend/src/routes/collections/[id]/+page.svelte- Pass collection context
Migration Path
-
Phase 1 - Foundation (WS1, WS2)
- Configuration infrastructure
- Preference UI
- No user-facing changes to chat yet
-
Phase 2 - Day Suggestions (WS3)
- New modal, new entry point
- Backend suggestion endpoint
- Can ship independently
-
Phase 3 - Chat Improvements (WS4, WS5)
- Context-aware chat
- Web search capability
- Better UX
-
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