TravelMind AI — About the Project

💡 Inspiration

Planning a trip almost always turns into five tabs open at once — one for flights, one for hotels, one for "things to do in ___", a spreadsheet for the budget, and a notes app for the itinerary. None of it talks to each other, and every trip means starting from scratch.

[Add your personal spark here — e.g. a specific trip you struggled to plan, a friend's complaint, or simply wanting to see what Gemini could actually do beyond a single chat reply.]

I wanted to see if a single natural-language request — "Plan a 5-day Goa trip from Delhi under ₹25,000 for 2 people" — could produce everything a person actually needs to leave the house: a day-by-day plan, a real cost breakdown, transport options, and local recommendations, without ten separate searches.


🏗️ What I Built

TravelMind AI is a full-stack MERN application (React + Node/Express + MongoDB) with a Gemini-powered planning pipeline at its core.

Instead of sending one giant prompt and hoping for a well-structured answer, I split the planning task into four specialized prompt modules, each with its own system prompt and a strict JSON responseSchema:

  • Communicator — classifies what the user actually wants (a greeting, a general travel question, a brand-new trip request, or an update to an existing plan) and extracts structured requirements (source, destination, budget, days, travelers, style), resolving anything left unsaid using the conversation history.
  • Itinerary Planner — builds the day-by-day plan, and on follow-up messages like "change Day 2 to adventure sports", revises just the relevant part of an existing itinerary instead of regenerating everything from scratch.
  • Logistics & Budget — produces a realistic cost breakdown, transport options, accommodation suggestions, safety notes, and visa info.
  • Local Discovery — surfaces hidden gems, food spots, and cultural tips that a generic search wouldn't easily give you.

An orchestrator layer runs the Itinerary, Logistics, and Local Discovery calls in parallel once the requirements are known, then merges all three JSON outputs into one unified trip plan that the frontend renders — complete with a live "reasoning steps" trace so the user can see the pipeline working, chat history persisted in MongoDB, and PDF export for the final plan.

$$ \text{Total Trip Cost} = \sum_{i=1}^{n} \left( \text{Transport}_i + \text{Hotel}_i + \text{Food}_i + \text{Activities}_i \right) + \text{Miscellaneous} $$

I'll be upfront about naming: I initially called this a "multi-agent" system, but architecturally it's a multi-prompt orchestration pipeline — the routing between modules is deterministic backend code, not autonomous agent decision-making. That's an honest distinction I only fully internalized partway through, and it's now explicitly the next milestone on my roadmap (a router/planner layer, tool-calling, and a self-critique loop for genuine agentic behavior).


📚 What I Learned

  • Structured output changes everything. Using Gemini's responseSchema (JSON mode) instead of parsing free text eliminated an entire category of bugs — no more regex, no more "the model added a stray sentence before the JSON."
  • Parallelizing independent LLM calls is free performance. Since the Itinerary, Logistics, and Discovery prompts don't depend on each other's output, running them with Promise.all instead of sequentially cut real wall-clock time.
  • ESM module loading order can silently break config. I hit a subtle bug where my Gemini client was constructed before dotenv had populated process.env, because in ES Modules, imports resolve before a file's own top-level code runs — so a value that "should" have existed was permanently empty. The fix was to load environment variables as the very first import, and to make the config read process.env lazily instead of caching it at construction.
  • "Agent" is an overloaded word. Working through this project taught me the real difference between a multi-prompt pipeline and an autonomous multi-agent system — autonomy, tool-calling, and self-correction loops are the actual bar, not just having multiple named roles.
  • Free-tier AI infrastructure moves fast. Model availability changed during development — a model I was using got deprecated for new users mid-project, which pushed me to make every model name configurable via .env rather than hardcoded.

🛠️ How I Built It

  1. Started from an existing MERN travel-app scaffold and audited it for hardcoded/mock data across both client/ and server/.
  2. Removed all static itinerary templates, fixed budget-split percentages, and the regex-based requirement parser that were standing in for real AI output.
  3. Designed four JSON schemas (Type.OBJECT / Type.ARRAY / etc. via the @google/genai SDK) — one per module — so every AI response is guaranteed-shape data, not text to parse.
  4. Wrote the four prompt modules and the orchestrator that sequences the Communicator first, then fans out to the other three in parallel and merges the results.
  5. Rebuilt chatController to persist each turn to MongoDB and replay recent history + the last saved trip plan as context, which is what makes "change Day 2 to adventure sports" work without re-specifying the whole trip.
  6. Rewired the dashboard to use real MongoDB aggregations (monthly trend, budget utilization) instead of a few hardcoded chart values that were sitting there from an earlier mock version.

🚧 Challenges I Faced

  • A silent config bug. The Gemini client was reporting "not configured" even with a correct key in .env, purely because of when in the module load order the key was read. This took careful tracing of ESM import semantics to find — not a typo, a load-order bug.
  • Model churn. Mid-build, the Pro-tier model I was using returned a 404 telling me it was "no longer available to new users," and shortly after that, a 429 quota error revealed the replacement Pro model wasn't available on the free tier at all (limit: 0) — only Flash-tier models are. I ended up making every model name an environment variable so a provider-side change never requires a code change again.
  • Being honest about the architecture. It was tempting to keep calling this "multi-agent" because it sounds more impressive — but once I understood the real definition (autonomy, tool-calling, self-correction, agent-to-agent communication), I rewrote the README and my own pitch to describe exactly what's true: a multi-role, multi-prompt orchestration pipeline, with genuine agentic behavior as an explicit next milestone rather than a claim I couldn't back up under questioning.
  • Occasional upstream instability. Even with everything configured correctly, Gemini's API itself returns transient 503 UNAVAILABLE errors during high demand — a good reminder that production AI features need retry/backoff logic, not just a correct integration.

🔮 What's Next

Turning this from a multi-prompt pipeline into a genuinely agentic system: a router module that dynamically decides which sub-modules to invoke, real tool-calling (e.g. live price lookups), and a self-critique loop where the itinerary is checked against budget and revised automatically if it doesn't fit — plus flight/hotel booking integration and collaborative group trip planning.

Share this project:

Updates

Submission history