AI System
Agent-based AI system for generating travel product content, parsing trip descriptions, and providing an interactive travel consultant. Built on laravel/ai with Gemini as default provider.
When to Use
Section titled “When to Use”- TCAI Chat Modal — Create or edit a SupplierTour with an interactive AI conversation that confirms destinations before generating (primary workflow)
- Parse raw trip text (e.g., “Asia India 9N - 2 Delhi - 3 Jaipur”) into itinerary-only data
- Refine individual product template fields with AI assistance (sparkles icons in admin)
- Interactive travel planning via the standalone Travel Consultant chat page
Configuration
Section titled “Configuration”Environment Variables (.env)
Section titled “Environment Variables (.env)”# Default provider is openrouter (configured in config/ai.php)OPENROUTER_API_KEY=your_keyOPENROUTER_BASE_URL=https://openrouter.ai/api/v1OPENROUTER_MODEL="openai/gpt-4o-mini"
# Alternative provider for image tasksGEMINI_API_KEY=your_keyConfig File: config/ai.php
The UsesConfiguredModel concern reads config('ai.model') which resolves to OPENROUTER_MODEL env var.
Source: backend/app/Ai/Concerns/UsesConfiguredModel.php
Architecture
Section titled “Architecture”All agents implement Laravel\Ai\Contracts\Agent and use the Promptable trait with the UsesConfiguredModel concern.
Agents
Section titled “Agents”| Agent | Type | Tokens | Temp | Timeout | Purpose |
|---|---|---|---|---|---|
TravelConsultantAgent | Conversational + Tools | 4000 | 0.7 | 120s | Interactive travel planning with multi-turn chat and tool use |
TripParserAgent | Structured | 16000 | 0.3 | 60s | Parse raw trip text into product template data |
TravelContentAgent | Structured | 4000 | 0.7 | 60s | Generate marketing content from a title |
FieldContentAgent | Structured | 2000 | 0.7 | 30s | Refine/generate a single form field |
HotelGeneratorAgent | Structured | 4000 | 0.7 | 120s | Generate hotel data |
TranslationAgent | Structured | 2800 | 0.3 | 120s | Translate travel product content |
DayContentAgent | Structured | 4000 | 0.3 | 90s | Generate per-day content (label, title, description) when parser truncates |
ContentRephraseAgent | Structured + Tools | 8000 | 0.7 | 120s | Rephrase content fields using brand voice, content rules, and self-correction (details) |
Source: backend/app/Ai/Agents/
Tools (TravelConsultantAgent only)
Section titled “Tools (TravelConsultantAgent only)”| Tool | Purpose |
|---|---|
SearchDestinationsTool | Search POIs by keyword |
SearchHotelsTool | Search hotels by city |
GetExistingTemplatesTool | Find existing templates to avoid duplicates |
GenerateFormContentTool | Generate structured form data (title, descriptions, itinerary) for the TCAI chat modal — returns data without persisting to DB |
CreateProductTemplateTool | Create a ProductTemplate from trip description (standalone chat page) |
Itinerary Builder Tools
Section titled “Itinerary Builder Tools”Step-by-step tools for constructing itineraries with airport resolution and hotel matching. Used in the TCAI chat modal flow.
| Tool | Purpose |
|---|---|
StartItineraryTool | Create a builder session, store raw text and supplier IDs. Returns builder_id for subsequent calls. |
SetArrivalCityTool | Resolve first in-destination city to airport IATA code |
SetDepartureCityTool | Resolve last in-destination city to airport IATA code |
MatchHotelsTool | Fuzzy-match hotel names from raw text against supplier hotel database |
BuildFullItineraryTool | Build the complete itinerary in one call — parses text, generates content, applies airport overrides and hotel matches |
The agent must call tools in this order: start_itinerary -> set_arrival_city / set_departure_city / match_hotels -> build_full_itinerary.
Source: backend/app/Ai/Tools/, backend/app/Ai/Tools/Itinerary/
Content Rephrase Tools (ContentRephraseAgent)
Section titled “Content Rephrase Tools (ContentRephraseAgent)”| Tool | Purpose |
|---|---|
GetBrandVoiceTool | Fetch global + service-specific brand voice |
GetContentRulesTool | Fetch per-field constraints (length, format, forbidden words) |
GetEntityContextTool | Load entity data with relationships |
SearchSimilarContentTool | Find similar entities to differentiate content |
GetExampleContentTool | Fetch high-quality examples as style reference |
ValidateContentTool | Deterministic PHP validation for self-correction loop |
See Content Management for the full tool workflow.
Source: backend/app/Ai/Tools/Content/
Services
Section titled “Services”ProductTemplateAIService
Section titled “ProductTemplateAIService”Orchestrates content generation for product templates. All methods accept an optional TcaiProfile for style customization.
| Method | Agent Used | Description |
|---|---|---|
generateContent(title, profile?) | TravelContentAgent | Generate marketing fields from a product title |
generateFromRawInput(rawText, profile?, locale?) | TripParserAgent + TripContentAgent | Parse raw trip text into full template data with resolved itinerary. Used by GenerateFormContentTool in the TCAI chat flow. |
generateItineraryFromRawInput(rawText, profile?, locale?) | TripParserAgent | Generate itinerary-only data (no marketing content). Used by the standalone “Generate Itinerary” action. |
refineField(fieldName, currentValue, instructions, context, profile?) | FieldContentAgent | AI-assisted refinement for a single form field |
generateFromRawInput post-processes itineraries through ItineraryResolver to normalize the schema, ensure route continuity between days, and resolve city names to POI IDs via database lookup and Google Places. It includes a fallback parser for shorthand formats like 5N, 7D, and dash-separated N City patterns (e.g., 3 Bogota - 2 Medellin).
Source: backend/app/Services/ProductTemplateAIService.php
TravelConsultantService
Section titled “TravelConsultantService”Wraps TravelConsultantAgent with three modes:
| Method | Purpose |
|---|---|
prompt(message, profile?) | One-shot text response (standalone chat page) |
startConversation(message, user, profile?, locale?) | Start a new streaming conversation. Prepends locale context. Returns StreamableAgentResponse. |
continueConversation(message, conversationId, user, profile?, locale?) | Continue an existing conversation by ID. Returns StreamableAgentResponse. |
The streaming methods use RemembersConversations on the agent to maintain multi-turn chat history. Conversation state is tied to the authenticated user via forUser() / continue().
Source: backend/app/Services/TravelConsultantService.php
ItineraryBuilderService
Section titled “ItineraryBuilderService”Cache-based state management for the itinerary builder tool pipeline. Each builder session stores arrival/departure airports, stops, raw text, locale, and supplier IDs with a 30-minute TTL.
| Method | Description |
|---|---|
create() | Create a new session, return UUID builder ID |
get($builderId) | Retrieve session state from cache |
setRawText($builderId, $text, $locale) | Store raw trip text for content generation |
setSupplierIds($builderId, $ids) | Store supplier IDs for hotel matching |
setArrival($builderId, $city) | Resolve arrival city to airport-linked POI |
setDeparture($builderId, $city) | Resolve departure city to airport-linked POI |
getSummary($builderId) | Return route summary string |
Source: backend/app/Services/ItineraryBuilderService.php
HotelMatcherService
Section titled “HotelMatcherService”Deterministic fuzzy matching of hotel names mentioned in raw itinerary text against the supplier hotel database. Uses string similarity scoring (threshold >= 0.6) to find best matches.
Input: Raw text + array of supplier IDs
Output: Map of poi_id => supplier_hotel_id for the best match at each location
Used by MatchHotelsTool during the TCAI builder flow and by HandlesTcaiContent when applying generated content to the form.
Source: backend/app/Services/HotelMatcherService.php
ItineraryResolver
Section titled “ItineraryResolver”Support class that bridges AI output and the itinerary data model:
normalizeRawItinerary()— converts AI raw output to proper schemaensureRouteContinuity()— fills gaps between days with connecting routesresolveItineraryLocations()— resolves city names to POI IDs via database/Google Places
Source: backend/app/Support/ItineraryResolver.php
TCAI Profiles
Section titled “TCAI Profiles”TCAI (Travel Consultant AI) Profiles store reusable personality and style configurations that customize agent behavior. Profiles also power the brand voice and content rephrasing system.
Table: tcai_profiles — columns: name, description, custom_instructions (text), brand_voice (JSON), service_type (nullable enum), is_default (boolean)
service_typediscriminator:null= global brand voice, or aContentServiceTypevalue (hotel,activity,transfer,cms_home,cms_about_us,cms_legal) for service-specific guidelinesbrand_voiceJSON stores structured fields: tone, target audience, vocabulary, forbidden words, personality traits, communication standards, formatting rules, before/after examplesgetBrandVoicePrompt()compiles the structured brand_voice + custom_instructions into a single prompt stringTcaiProfile::getDefault()returns the global default profileTcaiProfile::getDefaultForServiceType($type)returns the default profile for a specific service typemarkAsDefault()sets this profile as default (unsets others in a transaction)- Has many
ProductTemplaterecords viatcai_profile_idFK - Managed in admin at
/admin/tcai-profiles(4-tab form: Profile, Brand Voice, Examples, Custom Instructions)
See Content Management for brand voice configuration details, content rules, and the rephrasing system.
Source: backend/app/Models/TcaiProfile.php
Admin Integration
Section titled “Admin Integration”TCAI Chatbox Modal (Supplier Tours)
Section titled “TCAI Chatbox Modal (Supplier Tours)”The primary TCAI workflow is an interactive chat modal embedded in the SupplierTour create/edit forms. When an admin pastes raw tour info and clicks “Generate with TCAI”:
- A Filament action modal opens containing the
TcaiChatLivewire component - The agent calls itinerary builder tools in sequence:
start_itinerary(stores raw text + supplier IDs),set_arrival_city,set_departure_city,match_hotels - The agent presents the plan with matched hotels for admin confirmation
- On confirmation, PHP intercepts the message directly (bypasses AI) and calls
BuildFullItineraryToolto generate form data - A green “Apply to Form” button appears — clicking it dispatches a
tcai-content-generatedevent - The
HandlesTcaiContenttrait (shared byCreateSupplierTourandEditSupplierTour) receives the event and populates all form fields including repeaters (itinerary, hotel assignments, activity assignments, transfer assignments)
PHP confirmation interception: When the user sends a confirmation message (“yes”, “ok”, “si”, etc.) and a builder_id exists, TcaiChat bypasses the AI agent entirely and calls BuildFullItineraryTool directly in PHP. This ensures reliable “yes” handling without depending on the AI to interpret confirmations correctly.
Tool progress streaming: During the builder tool sequence, tool results (arrival set, departure set, hotel matches) are streamed to the chat UI so the admin sees progress.
Key components:
TcaiChatLivewire component — manages chat state, streams AI responses viawire:stream, intercepts confirmations, tracksitineraryBuilderIdHandlesTcaiContenttrait — event listener that maps AI output to Filament form fields, handles UUID-keyed repeater state, applies hotel matches fromHotelMatcherServiceBuildFullItineraryTool— orchestrates content generation using stored builder state (raw text, airports, hotel matches)
Source: backend/app/Livewire/TcaiChat.php, backend/app/Filament/Resources/Suppliers/SupplierTours/Concerns/HandlesTcaiContent.php
Travel Consultant Chat Page (Standalone)
Section titled “Travel Consultant Chat Page (Standalone)”Chat-style Livewire page at /admin/ai/travel-consultant (nav group: “AI Tools”). Users select a TCAI Profile from a dropdown and interact with the TravelConsultantAgent. This page uses CreateProductTemplateTool which persists directly to the database (unlike the chatbox modal flow).
Permission required: use_travel_consultant
Per-Field Refinement (RefineFieldAction)
Section titled “Per-Field Refinement (RefineFieldAction)”Sparkles icon buttons on ProductTemplate form fields open a modal with an instructions textarea and TCAI profile selector. Calls ProductTemplateAIService::refineField() and updates the form field in place.
Permissions
Section titled “Permissions”| Permission | Scope |
|---|---|
view_tcai_profile | View TCAI profiles |
create_tcai_profile | Create TCAI profiles |
update_tcai_profile | Update TCAI profiles |
delete_tcai_profile | Delete TCAI profiles |
use_travel_consultant | Access Travel Consultant chat page |
Related
Section titled “Related”- Content Management — Brand voice, content rules, and AI rephrasing
- Product Templates — AI content generation for templates
- Roles and Permissions — TCAI permissions
- Suppliers — Multi-supplier tours and service assignments
- Source:
backend/app/Ai/— all agents, tools, and concerns - Source:
backend/app/Ai/Tools/Itinerary/— itinerary builder tools - Source:
backend/app/Services/ProductTemplateAIService.php - Source:
backend/app/Services/TravelConsultantService.php - Source:
backend/app/Services/ItineraryBuilderService.php - Source:
backend/app/Services/HotelMatcherService.php - Source:
backend/app/Livewire/TcaiChat.php - Source:
backend/app/Filament/Resources/Suppliers/SupplierTours/Concerns/HandlesTcaiContent.php - Source:
backend/app/Support/ItineraryResolver.php