Skip to content

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.

  • 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
Terminal window
# Default provider is openrouter (configured in config/ai.php)
OPENROUTER_API_KEY=your_key
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_MODEL="openai/gpt-4o-mini"
# Alternative provider for image tasks
GEMINI_API_KEY=your_key

Config 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

All agents implement Laravel\Ai\Contracts\Agent and use the Promptable trait with the UsesConfiguredModel concern.

AgentTypeTokensTempTimeoutPurpose
TravelConsultantAgentConversational + Tools40000.7120sInteractive travel planning with multi-turn chat and tool use
TripParserAgentStructured160000.360sParse raw trip text into product template data
TravelContentAgentStructured40000.760sGenerate marketing content from a title
FieldContentAgentStructured20000.730sRefine/generate a single form field
HotelGeneratorAgentStructured40000.7120sGenerate hotel data
TranslationAgentStructured28000.3120sTranslate travel product content
DayContentAgentStructured40000.390sGenerate per-day content (label, title, description) when parser truncates
ContentRephraseAgentStructured + Tools80000.7120sRephrase content fields using brand voice, content rules, and self-correction (details)

Source: backend/app/Ai/Agents/

ToolPurpose
SearchDestinationsToolSearch POIs by keyword
SearchHotelsToolSearch hotels by city
GetExistingTemplatesToolFind existing templates to avoid duplicates
GenerateFormContentToolGenerate structured form data (title, descriptions, itinerary) for the TCAI chat modal — returns data without persisting to DB
CreateProductTemplateToolCreate a ProductTemplate from trip description (standalone chat page)

Step-by-step tools for constructing itineraries with airport resolution and hotel matching. Used in the TCAI chat modal flow.

ToolPurpose
StartItineraryToolCreate a builder session, store raw text and supplier IDs. Returns builder_id for subsequent calls.
SetArrivalCityToolResolve first in-destination city to airport IATA code
SetDepartureCityToolResolve last in-destination city to airport IATA code
MatchHotelsToolFuzzy-match hotel names from raw text against supplier hotel database
BuildFullItineraryToolBuild 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)”
ToolPurpose
GetBrandVoiceToolFetch global + service-specific brand voice
GetContentRulesToolFetch per-field constraints (length, format, forbidden words)
GetEntityContextToolLoad entity data with relationships
SearchSimilarContentToolFind similar entities to differentiate content
GetExampleContentToolFetch high-quality examples as style reference
ValidateContentToolDeterministic PHP validation for self-correction loop

See Content Management for the full tool workflow.

Source: backend/app/Ai/Tools/Content/

Orchestrates content generation for product templates. All methods accept an optional TcaiProfile for style customization.

MethodAgent UsedDescription
generateContent(title, profile?)TravelContentAgentGenerate marketing fields from a product title
generateFromRawInput(rawText, profile?, locale?)TripParserAgent + TripContentAgentParse raw trip text into full template data with resolved itinerary. Used by GenerateFormContentTool in the TCAI chat flow.
generateItineraryFromRawInput(rawText, profile?, locale?)TripParserAgentGenerate itinerary-only data (no marketing content). Used by the standalone “Generate Itinerary” action.
refineField(fieldName, currentValue, instructions, context, profile?)FieldContentAgentAI-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

Wraps TravelConsultantAgent with three modes:

MethodPurpose
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

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.

MethodDescription
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

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

Support class that bridges AI output and the itinerary data model:

  • normalizeRawItinerary() — converts AI raw output to proper schema
  • ensureRouteContinuity() — fills gaps between days with connecting routes
  • resolveItineraryLocations() — resolves city names to POI IDs via database/Google Places

Source: backend/app/Support/ItineraryResolver.php

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_type discriminator: null = global brand voice, or a ContentServiceType value (hotel, activity, transfer, cms_home, cms_about_us, cms_legal) for service-specific guidelines
  • brand_voice JSON stores structured fields: tone, target audience, vocabulary, forbidden words, personality traits, communication standards, formatting rules, before/after examples
  • getBrandVoicePrompt() compiles the structured brand_voice + custom_instructions into a single prompt string
  • TcaiProfile::getDefault() returns the global default profile
  • TcaiProfile::getDefaultForServiceType($type) returns the default profile for a specific service type
  • markAsDefault() sets this profile as default (unsets others in a transaction)
  • Has many ProductTemplate records via tcai_profile_id FK
  • 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

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”:

  1. A Filament action modal opens containing the TcaiChat Livewire component
  2. The agent calls itinerary builder tools in sequence: start_itinerary (stores raw text + supplier IDs), set_arrival_city, set_departure_city, match_hotels
  3. The agent presents the plan with matched hotels for admin confirmation
  4. On confirmation, PHP intercepts the message directly (bypasses AI) and calls BuildFullItineraryTool to generate form data
  5. A green “Apply to Form” button appears — clicking it dispatches a tcai-content-generated event
  6. The HandlesTcaiContent trait (shared by CreateSupplierTour and EditSupplierTour) 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:

  • TcaiChat Livewire component — manages chat state, streams AI responses via wire:stream, intercepts confirmations, tracks itineraryBuilderId
  • HandlesTcaiContent trait — event listener that maps AI output to Filament form fields, handles UUID-keyed repeater state, applies hotel matches from HotelMatcherService
  • BuildFullItineraryTool — 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

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

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.

PermissionScope
view_tcai_profileView TCAI profiles
create_tcai_profileCreate TCAI profiles
update_tcai_profileUpdate TCAI profiles
delete_tcai_profileDelete TCAI profiles
use_travel_consultantAccess Travel Consultant chat page
  • 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