Skip to content

// projects · case study

Travel plans built around real places

01 / client name private

Back to all projects
case-01.travel-planner
01

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.map
01

Architecture inspection

The model is one participant in a typed workflow. These notes mark where responsibility, authority, and recovery live.

// system mapResearch itinerary graphTravel plans built around real places
  1. sourceTrip intentplace · pace · dates
  2. agentResearch briefquestions + constraints
  3. parallel research
    • agentPlacesfit + hours
    • agentContexthistory + culture
    • agentTransittime + access
  4. logicCoverage checkrequired fields complete
    gaps retry research
  5. logicScore + clustergeo · time · relevance
  6. outputItineraryordered + source-backed
  1. 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.
  2. 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.
  3. 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.
  4. 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.
decision-authority.ledger
02

Decisions and authority

The important choices are explicit: what the system optimizes, what it refuses to improvise, and where people retain control.

  1. 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.

  2. 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.

  3. 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-stack.inventory
03

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-recovery.runbook
04

Safeguards and recovery

Reliable behavior includes the unhappy path: how faults are detected, contained, retried, or handed back to an operator.

Failure runbook

  1. 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.
  2. 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.
  3. 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-evidence.report

// 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.
next-system.request

// 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.