Modern Architecture • Agentic Multi-Agent Search • Configurable Providers • Open-Source
TripSage AI is a travel planning platform that combines the power of modern AI agents with rich AI SDK v6 tools and all-in-one travel services.
- Multi-Provider AI Routing: Vercel AI Gateway with automatic fallback across OpenAI, Anthropic, xAI, and OpenRouter—BYOK support with encrypted key storage
- Agentic Tool Orchestration: 15+ production-ready tools via AI SDK v6 with Zod validation—flights (Duffel), accommodations, weather, maps, planning, and memory
- Hybrid RAG Pipeline: Vector similarity search with Supabase pgvector + keyword fusion, Cohere Rerank v3.5 for optimal retrieval accuracy
- Structured Outputs: Schema-first LLM responses with
generateObjectfor deterministic parsing and type-safe validation - Streaming Intelligence: Real-time SSE streaming with interleaved tool calls and generative UI components
- Supabase PostgreSQL + pgvector: Managed database with HNSW indexes for semantic search, embeddings storage, and vector similarity queries
- Supabase Auth & Vault: Server-side authentication with SSR clients (
@supabase/ssr), encrypted BYOK secrets in Vault with RLS-gated access - Supabase Realtime: Private channels with Row Level Security for multi-user collaboration, presence tracking, and broadcast events
- Supabase Storage: File uploads with signed URL access, metadata persistence, and server-enforced access control
- Upstash Redis: Serverless HTTP Redis for sub-10ms global caching, sliding-window rate limiting, and deduplication keys
- Upstash QStash: Webhook-driven background jobs with signature verification, Redis idempotency gates, and batch processing (memory sync, async tasks)
- Edge-First Architecture: Next.js 16 Edge runtime support, Vercel deployment with global CDN, optimized for low-latency responses
- React Compiler: Automatic memoization and zero-overhead reactive rendering for optimal performance
- Zero-Trust Architecture: BYOK keys never touch client; server-only routes with
"server-only"imports and dynamic execution - Row Level Security: Supabase RLS policies enforce per-user data isolation; security-definer RPCs guard Vault access
- Rate Limiting: Upstash Ratelimit with tiered budgets (40 req/min streaming, 20 req/min validation) per user/IP
- OpenTelemetry: Distributed tracing with PII redaction, span instrumentation, and Trace Drains for observability without data leakage
- Tool Approval Flows: Sensitive operations (bookings, payments) pause streaming and require explicit user consent
- Next.js 16 + React 19: App Router with RSC-first architecture, Server Components by default, React Compiler enabled
- TypeScript 5.9: Strict mode with end-to-end type safety, Zod schemas as single source of truth
- AI SDK v6 Native: Complete TypeScript migration from Python—unified provider API, native streaming, edge runtime support
- Node.js 24.x (see
.nvmrc) with pnpm 10.x (seepackage.json#packageManager) - PostgreSQL 15+ (or Supabase account)
- Upstash Redis for caching (via Vercel integration)
# Clone the repository
git clone https://github.com/BjornMelin/tripsage-ai.git
cd tripsage-ai
# Install dependencies
pnpm install --frozen-lockfile # Install Node.js dependencies
cp .env.local.example .env.local # Configure environment
# Start development server (includes API routes)
pnpm dev # Next.js app + API routes (port 3000)# Frontend access
open http://localhost:3000Single-runtime, server-first stack optimized for edge deployment:
- Backend & UI: Next.js 16 App Router (React 19) with Vercel AI SDK v6 RSC/actions and React Compiler
- AI Routing: Vercel AI Gateway for multi-provider orchestration with automatic fallback, BYOK support via Supabase Vault
- Database & Auth: Supabase PostgreSQL with pgvector (HNSW indexes), SSR clients (
@supabase/ssr), Realtime channels, Storage buckets - Cache & Rate Limiting: Upstash Redis (HTTP) for serverless caching and Upstash Ratelimit for sliding-window throttling
- Background Jobs: Upstash QStash for webhook-driven async tasks with idempotency guarantees
- Observability: OpenTelemetry with Vercel Trace Drains, span instrumentation, and PII redaction
# Frontend / API (single app at root)
pnpm install --frozen-lockfile
pnpm dev # Next.js dev server (includes API routes)
pnpm type-check
pnpm biome:fix # Format/lint (CI enforces clean diffs)
pnpm test # Vitest
pnpm exec playwright install chromium # one-time browser install (fresh machine)
pnpm test:e2e:chromium # Playwright (Chromium-only; recommended local default)
pnpm test:e2e # Playwright (all configured browsers)
# Supabase tooling (optional)
make supa.link PROJECT_REF=...
make supa.db.pushIf pnpm is not already on your PATH, use corepack pnpm ... instead of npx pnpm .... The repo root .npmrc intentionally contains pnpm-only config, and npx will make npm parse it and print warnings. You can also run corepack enable once to install the pnpm shim so pnpm is available directly on your PATH, which matters for tools like pre-commit hooks and CI scripts that invoke pnpm without the corepack prefix.
Server-side tracing is registered via src/instrumentation.ts using @vercel/otel. Client-side tracing is initialized via TelemetryProvider (mounted from src/app/layout.tsx) and exports browser spans with OTLP/HTTP.
Local tracing (Collector + Jaeger):
docker compose up -d otel-collector jaeger
open http://localhost:16686Enable browser tracing (optional):
# Either is accepted (client normalizes to `/v1/traces`)
NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
# or
NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces
# (also accepted)
NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces/To disable browser tracing in production, leave NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT unset.
Run pnpm biome:fix before committing. CI runs pnpm biome:fix and then checks for a clean working tree with git diff --exit-code, so any formatting changes produced locally will fail CI if not committed.
tripsage-ai/
├── src/ # Next.js 16 + AI SDK v6 source code
├── public/ # Static assets
├── e2e/ # Playwright E2E tests
├── supabase/ # Supabase migrations/config
├── docker/ # OTEL/Jaeger compose
├── .github/ # CI/CD
├── package.json # Node.js dependencies
└── Makefile # Supabase ops shortcuts
- Server-first: Route handlers and Server Actions own data fetching and AI calls. Use
createAI/streamTextwith Zod v4 validation. - Auth/DB:
@supabase/ssronly; no auth-helpers. - Cache/jobs: Upstash HTTP clients only (
Redis.fromEnv, QStash SDK). - Logging: OTEL exporters; no
console.login server code. - Tests: Vitest/Playwright only (no pytest/ruff/uv).
# Build and run with Docker Compose
docker-compose up -d
# Production build
docker build -t tripsage-ai .
docker run -p 3000:3000 --env-file .env.production tripsage-ai# Apply Kubernetes manifests
kubectl apply -f k8s/
# Check deployment status
kubectl get pods -l app=tripsage-ai| Variable | Description | Required |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Supabase project URL | ✅ |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Supabase anonymous key | ✅ |
SUPABASE_SERVICE_ROLE_KEY |
Supabase service role key | ✅ |
AI_GATEWAY_API_KEY |
Vercel AI Gateway key | ✅ |
DUFFEL_ACCESS_TOKEN |
Duffel API token for flights | |
UPSTASH_REDIS_REST_URL |
Upstash Redis REST URL | |
UPSTASH_REDIS_REST_TOKEN |
Upstash Redis REST token | |
NEXT_PUBLIC_STREAMDOWN_ALLOWED_LINK_PREFIXES |
Extra link prefix allowlist for markdown hardening (comma-separated) | |
NEXT_PUBLIC_STREAMDOWN_ALLOWED_IMAGE_PREFIXES |
Image prefix allowlist for markdown hardening (comma-separated) |
✅ Required |
Notes:
- All routes use Upstash REST credentials for rate limiting and caching via
@upstash/redisand@upstash/ratelimit. - BYOK keys are stored encrypted in Supabase Vault and resolved server-side only.
- Markdown rendering uses Streamdown v2.1+ and its plugin architecture (
@streamdown/code,@streamdown/mermaid,@streamdown/math).
# Authentication
POST /api/auth/login # User login
POST /api/auth/register # User registration
POST /api/auth/refresh # Token refresh
# Trip Management
GET /api/trips/suggestions # AI-powered trip suggestions (read-only)
# Note: Trip CRUD, collaborators, and itinerary mutations use Next.js Server Actions (no internal REST).
# Flight Services
GET /api/flights/search # Search flights
POST /api/flights/book # Book selected flight
GET /api/flights/bookings # List user bookings
# AI Chat & Memory
POST /api/chat/completions # AI chat interface
POST /api/memory/conversation # Store conversation
GET /api/memory/context # Get user contextimport { createClient } from '@supabase/supabase-js'
const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!)
// authorize realtime with access token via RealtimeAuthProvider in app
const channel = supabase.channel(`user:${userId}`, { config: { private: true } })
channel.on('broadcast', { event: 'chat:message' }, ({ payload }) => console.log(payload))
channel.subscribe()We welcome contributions! See the Development Guide for the full workflow, code standards, and testing details.
TripSage AI is optimized for high performance and global scalability:
- Response Times: Sub-200ms for cached requests via Upstash Redis HTTP API
- Edge Performance: Sub-10ms global latency with Vercel Edge runtime and Upstash Redis distributed caching
- Throughput: 1000+ requests/second on standard hardware with Upstash serverless scaling
- Vector Search: Supabase pgvector with HNSW indexes for sub-50ms semantic similarity queries
- Streaming: Real-time SSE with AI SDK v6, interleaved tool calls, and progressive UI rendering
- Background Processing: Upstash QStash handles async jobs (memory sync, batch operations) with guaranteed delivery
# Performance testing via load testing tools
pnpm test --grep performance
# Or use external load testing
autocannon -c 100 -d 30 http://localhost:3000/api/healthZero-trust architecture with defense-in-depth security:
- BYOK Architecture: User API keys encrypted in Supabase Vault, accessed only via SECURITY DEFINER RPCs with PostgREST JWT claims validation—keys never reach client
- Row Level Security: Supabase RLS policies enforce per-user data isolation; all tables protected by default
- Rate Limiting: Upstash Ratelimit with sliding-window counters, tiered budgets (40 req/min streaming, 20 req/min validation) per user/IP
- Server-Only Secrets: BYOK routes import
"server-only"and run withdynamic = "force-dynamic"to ensure secrets processed per-request - PII Redaction: OpenTelemetry spans automatically redact sensitive data; structured logging with correlation IDs
- Tool Approval Gates: Critical operations (bookings, payments) pause streaming and require explicit user consent
- Dependency Security: Dependabot provides automated vulnerability scanning in CI;
pnpm auditis available for local/manual checks (not run in CI)
# Security verification (ensure no hardcoded secrets)
git grep -i "fallback-secret\|development-only" . # Should return empty
# Dependency audit
pnpm audit
# Run security-focused tests
pnpm test --grep security- Unified result model: Both API key validation and external service health checks return an
ApiValidationResult, eliminating duplicate response types. - Context-aware fields: Validation flows populate
is_valid,status, andvalidated_at, while health probes usehealth_status,checked_at, and leave validation-only fields unset (None). - Shared metadata: Rate-limit quotas, capability discovery, latency timing, and diagnostic details flow through identical fields for streamlined analytics and caching.
- Computed insights:
success_rate_categoryandis_healthycomputed fields provide quick rollups regardless of whether the result originated from validation or monitoring.
- Health Checks: Endpoint monitoring with health checks
- Logging: Structured logging with correlation IDs
- Metrics: Custom business metrics and performance tracking
- Error Tracking: Detailed error reporting and alerting
This project is licensed under the MIT License - see the LICENSE file for details.
Built by Bjorn Melin as an exploration of AI-driven travel planning.