https://github.com/langwatch/booking-agent-scenario-demo
https://github.com/langwatch/booking-agent-scenario-demo
Last synced: about 1 month ago
JSON representation
- Host: GitHub
- URL: https://github.com/langwatch/booking-agent-scenario-demo
- Owner: langwatch
- Created: 2025-09-23T12:11:58.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-09-23T13:00:29.000Z (11 months ago)
- Last Synced: 2025-09-23T14:48:29.368Z (11 months ago)
- Language: TypeScript
- Size: 94.7 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# From Scenario to Finished: Domain-Driven TDD for Agentic Development
> **A hands-on demonstration of how Scenario enables Domain-Driven Design for AI agents through Test-Driven Development**
This repository demonstrates how to build a flight booking agent from scratch using **Scenario** - a testing framework designed specifically for AI agents. Rather than traditional unit tests, we use scenario tests that define business capabilities and drive every implementation decision through TDD.
## ๐ฏ What This Demo Shows
- **Domain-Driven TDD**: How scenarios become your domain model, defining business language and rules
- **AI Agent Development**: Building a conversational booking agent with confidence
- **Scenario Testing**: Using `@langwatch/scenario` to test nondeterministic AI behavior
- **NestJS + TypeORM**: Clean architecture with proper domain modeling
- **Red-Green-Refactor**: Each failing test reveals missing domain knowledge
## ๐ Quick Start
### Prerequisites
- Node.js 18+
- pnpm
- Docker (for PostgreSQL)
- OpenAI API key
### Setup
1. **Clone and install dependencies**
```bash
git clone
cd booking-agent-scenario-demo
pnpm install
```
2. **Set up environment**
```bash
cp env.template .env
# Edit .env with your OpenAI API key
```
3. **Start the database**
```bash
docker-compose up -d
```
4. **Run the scenario tests**
```bash
# Run the complete flight booking scenario
pnpm test:scenario
# Or run individual tests
pnpm test:scenario:watch
```
## ๐ค๏ธ The Development Journey
This demo follows the exact process described in the article. Here's how the domain model emerged through scenario-driven development:
### Step 1: Hello World Foundation
```typescript
// First test - just verify the endpoint works
it('should handle hello world', async () => {
const result = await fetch(address);
expect(await result.text()).toBe('Hello World!');
});
```
### Step 2: Basic Conversation
```typescript
// Second test - agent should be polite and coherent
const result = await scenario.run({
setId: 'booking-agent-scenario-demo',
name: 'Simple Flight Booking',
description: 'A simple flight booking conversation',
agents: [
scenario.userSimulatorAgent(),
agentAdapter,
scenario.judgeAgent({
criteria: [
'The agent should be polite and greet the user',
'The agent should be able to have a coherent conversation',
],
}),
],
script: [scenario.proceed(5), scenario.judge()],
});
```
### Step 3: Complete Flight Booking Domain
```typescript
// Full domain scenario - defines the complete booking process
const result = await scenario.run({
setId: 'booking-agent-scenario-demo',
name: 'Book a flight',
description: `
The user (email: test-customer@test.com) wants to book a flight from New York to London.
IMPORTANT: The conversation can be long.
CRITICAL: DO NOT end the conversation or judge prematurely and allow the agent to complete the conversation.
The agent should say goodbye to the user when the conversation is complete.
`,
maxTurns: 100,
agents: [
scenario.userSimulatorAgent(),
agentAdapter,
scenario.judgeAgent({
criteria: [
"The agent should get the user's name",
'The agent should get the departure airport',
'The agent should get the destination airport',
'The agent should get the departure date',
'The agent should get the return date',
'The agent should get the number of passengers',
'The agent should get the class of service',
'The agent should get the special requests',
'The agent should make the booking',
'The agent should confirm the booking',
'The booking should be correct',
'The agent should say goodbye to the user when the conversation is complete',
],
}),
],
script: [scenario.proceed(100)],
});
```
## ๐๏ธ Domain Model That Emerged
Through scenario-driven development, these domain concepts naturally emerged:
### Aggregates
- **FlightBooking**: The main aggregate root managing the complete booking process
### Value Objects
- **Airport codes**: Origin and destination validation (JFK, LHR, etc.)
- **Dates**: Departure and return date handling
- **Passenger counts**: Number validation and business rules
- **Service classes**: Booking class options
### Domain Events
- **Booking initiated**: When user starts the process
- **Details collected**: When all required information is gathered
- **Booking confirmed**: When the booking is successfully created
### Bounded Contexts
- **Flight booking**: Separate from hotel or car rental booking
- **Customer management**: User information and preferences
## ๐งช How Scenario Testing Works
Scenario uses three key components:
1. **User Simulator Agent**: Acts like a real user, sending messages to your agent
2. **Your Agent**: The system under test (this NestJS application)
3. **Judge Agent**: Evaluates whether the conversation meets the criteria
```typescript
agents: [
scenario.userSimulatorAgent(), // Simulates user input
agentAdapter, // Your NestJS agent
scenario.judgeAgent({
// Evaluates success
criteria: [
'The agent should be polite and greet the user',
'The agent should get all required information',
// ... more business rules
],
}),
];
```
## ๐ง Key Implementation Details
### Agent Service (`src/agent/agent.service.ts`)
- **System Prompt**: Defines the agent's behavior and business rules
- **Tools**: Functions the agent can call (create customer, make booking)
- **Memory**: Maintains conversation history across turns
### Domain Entities
- **Customer** (`src/customer/customer.entity.ts`): User information
- **Booking** (`src/booking/booking.entity.ts`): Flight booking details
### Scenario Adapter
The `agentAdapter` bridges Scenario and your NestJS app:
```typescript
agentAdapter = {
role: AgentRole.AGENT,
call: async (input: AgentInput) => {
const response = await fetch(`${address}/invoke`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: input.messages[input.messages.length - 1].content,
threadId: input.threadId,
}),
});
const result = await response.json();
return result.message;
},
};
```
### Database Verification
After running scenarios, verify actual data persistence:
```typescript
// Verify the booking was actually created using TypeORM directly
const customer = await customerRepository.findOne({
where: { email: 'test-customer@test.com' },
relations: ['bookings'],
});
expect(customer).toBeDefined();
expect(customer?.email).toBe('test-customer@test.com');
expect(customer?.bookings.length).toBe(1);
const booking = customer?.bookings[0];
expect(booking?.transportationType).toBe(TransportationType.FLIGHT);
expect(booking?.origin).toBe('JFK');
expect(booking?.destination).toBe('LHR');
```
## ๐ Learning Outcomes
This demo demonstrates:
1. **Domain-First Development**: Scenarios define your business language before code
2. **TDD for AI**: Each failing test reveals missing domain knowledge
3. **Living Documentation**: Scenarios serve as both tests and specifications
4. **Confidence Through Testing**: Know your AI agent works before shipping
## ๐ฆ Running the Tests
```bash
# Run all scenario tests
pnpm test:scenario
# Run with watch mode (great for development)
pnpm test:scenario:watch
# Run regular unit tests
pnpm test
# Start the application
pnpm start:dev
```
## ๐ Further Reading
- [Scenario Documentation](https://docs.langwatch.ai/scenario)
- [Domain-Driven Design](https://martinfowler.com/bliki/DomainDrivenDesign.html)
- [Test-Driven Development](https://martinfowler.com/bliki/TestDrivenDevelopment.html)
## ๐ค Contributing
This is a teaching example! Feel free to:
- Add more scenario tests
- Experiment with different domain models
- Try different AI models
- Extend the booking domain (hotels, cars, etc.)
## ๐ License
MIT License - feel free to use this as a learning resource or starting point for your own projects.
---
**Ready to try domain-driven TDD with your own AI agents?** Start by writing a scenario that captures your domain's core business capabilities, then let the failing tests guide your implementation.