TravelTravel planning assistant
Client name private// what we built
We built a travel planner that turns a person’s dates, interests, pace, and priorities into a practical day-by-day itinerary using real places.
- Product
- Travel planning assistant
- Field
- Travel
- Technical layers
- 04
- Safeguards
- 05
The challenge
What the team needed to solve
Planning a good trip means balancing dates, pace, location, and personal interests. Generic suggestions are not enough: the itinerary has to fit the traveler without inventing places or sending them back and forth across a city.
What we built
How the product works
The planner turns a loose request into clear trip requirements, researches matching places, checks where options are missing, and organizes the strongest choices into sensible days. Every place in the final plan comes from the source data.
Architecture inspection
The model is one participant in a typed workflow. These notes mark where responsibility, authority, and recovery live.
- sourceTrip intentplace · pace · dates
- agentResearch briefquestions + constraints
- parallel research
- agentPlacesfit + hours
- agentContexthistory + culture
- agentTransittime + access
- logicCoverage checkrequired fields completegaps retry research
- logicScore + clustergeo · time · relevance
- outputItineraryordered + source-backed
01 Typed trip brief
- Responsibility
- Extract destination, dates, duration, pace, priorities, and search requirements into a validated state.
- Boundary
- Destination coordinates, positive duration, and date consistency are checked before research begins.
- Failure path
- Invalid or contradictory trip state stops before place retrieval and returns a workflow error.
02 Coverage-aware research loop
- Responsibility
- Search requirements in parallel, score their coverage, and retry the weakest high-priority gaps.
- Boundary
- Research is limited to three iterations with explicit similarity, radius, and target-requirement rules.
- Failure path
- Thin coverage remains visible to the composer; the workflow does not fill gaps with unsupported venues.
03 Score, cluster, and order
- Responsibility
- Balance semantic fit, distance, and category diversity before grouping places by trip scale.
- Boundary
- Only retrieved candidates enter scoring, scale-aware geographic clustering, and route ordering.
- Failure path
- Sparse or outlying candidates remain explicit instead of being forced into an implausible cluster.
04 Grounded itinerary output
- Responsibility
- Turn the selected places into a structured day-by-day plan with authoritative identifiers and coordinates.
- Boundary
- Generated place references are checked against the selected source records after model composition.
- Failure path
- Unknown identifiers are removed, coordinates are restored from source data, and extra itinerary days are trimmed.
Decisions and authority
The important choices are explicit: what the system optimizes, what it refuses to improvise, and where people retain control.
- 01
Constraint
Open-ended place research can keep expanding without improving the final itinerary.
Decision
Use a fixed research budget and retry only the weakest high-priority requirements.
Coverage scoring gives the workflow a measurable reason to continue or stop instead of relying on model confidence.
Trade-off
A plan may retain an acknowledged coverage gap when the iteration budget is exhausted.
- 02
Constraint
A single search threshold or radius behaves poorly across dense cities and country-scale trips.
Decision
Adapt semantic thresholds, search radius, shortlist size, and clustering scale to the trip context.
The same research graph can serve compact and dispersed destinations without treating distance uniformly.
Trade-off
Scale-aware rules add tuning work and still depend on the quality of retrieved place data.
- 03
Constraint
A fluent itinerary can still contain a place identifier or coordinate that was never retrieved.
Decision
Run deterministic grounding repair after model composition.
The source shortlist, not generated prose, remains authoritative for venue identity and location.
Trade-off
Unsupported details are removed even when that leaves a day less complete or less polished.
Capability and stack
Capabilities describe the work the system can perform. The stack notes explain why each technical layer is present.
Enabled capabilities
- Structured extraction of destination, dates, pace, constraints, and priorities
- Concurrent semantic place research with adaptive similarity thresholds and search radii
- Coverage-aware retries with explicit iteration and requirement budgets
- Relevance, distance, and diversity scoring with scale-aware geographic clustering
- Persistent chats, trip jobs, progress phases, and durable traveler preferences
- Grounding checks that remove unknown place identifiers and restore source coordinates
Stack rationale
Runtime
Expose a typed HTTP boundary and validate trip, chat, and job inputs.
TypeScript · Bun · Hono · Zod
AI orchestration
Coordinate routing, bounded research, structured plan generation, and durable preference memory.
LangGraph · OpenAI · OpenRouter · Mem0
Data and retrieval
Persist user-owned chats and jobs while retrieving place candidates for grounded planning.
Supabase · PostgreSQL · vector place search
Observability
Trace model runs, workflow phases, failures, and structured service events.
Langfuse · OpenTelemetry · Pino
Safeguards and recovery
Reliable behavior includes the unhappy path: how faults are detected, contained, retried, or handed back to an operator.
Failure runbook
- 01
- Condition
- A place-search request is rate-limited or returns a server error.
- Detection
- The place client classifies HTTP 429 and 5xx responses as retryable.
- Response
- Retry with exponential backoff and jitter, then surface the research failure when the request budget is exhausted.
- 02
- Condition
- A trip generation job or chat message remains in progress beyond its expected window.
- Detection
- Scheduled stale-state checks inspect persisted message and job timestamps.
- Response
- Mark stale work failed, retain its job identity, and use the idempotency key to avoid duplicate generation on retry.
- 03
- Condition
- The composed itinerary contains an unsupported place reference.
- Detection
- A post-generation guard compares identifiers and coordinates with the selected source records.
- Response
- Remove the unknown identifier, restore source coordinates, and keep the unsupported identifier out of the stored trip.
Principles in practice
Start with the workflow
A typed graph moves from understanding through search, coverage assessment, bounded retries, scoring, clustering, and formatting.
Show the sources
Retrieved place records remain authoritative for venue identity and coordinates in the final itinerary.
Put rules in code
Code owns input validation, iteration budgets, adaptive thresholds, shortlist scoring, and grounding repair.
Limit access by default
Chat, trip-job, and tool-output access is checked against the authenticated owner before data is returned or changed.
Plan for things to go wrong
Persisted job state, idempotency keys, checkpoints, progress phases, and stale-state cleanup make long work inspectable and retryable.
// validation signal
What was checked—and what was not.
Automated coverage exercises research retries, idempotent generation, persistence, and geographic clustering across dense, sparse, and edge-case coordinates.
Engineering validation in controlled fixtures; no production performance KPI is claimed.
Method
Automated Bun tests exercise the deterministic research, clustering, persistence, and API boundaries with controlled fixtures.
Checks performed
- Coverage assessment and bounded retry behavior
- Scale-aware clustering across dense, sparse, and geographic edge cases
- Idempotent job creation and persisted trip state
- Place-client timeout, retry, and response handling
Outside this claim
- The fixtures do not establish production latency, live place-data freshness, user adoption, or itinerary outcome quality.
// from difficult workflow to working product
Have a workflow like this?
We can help define the product, decide where AI adds value, and take it through a tested implementation.