An MVP implementation of a guideline-aware AI agent that dynamically incorporates behavioral guidelines into prompts for Claude AI, inspired by Parlant.io's implementation.
This AI agent system pulls behavioral guidelines from a PostgreSQL database and dynamically constructs system prompts based on those guidelines to provide context-aware responses for sales scenarios. The agent uses semantic similarity matching with embeddings to select the most relevant guidelines for each user message.
- Dynamic Guideline System: Store and retrieve behavioral guidelines with conditions and actions
- Semantic Matching: Uses AI embeddings to find contextually relevant guidelines (not just keyword matching)
- Conversation Context: Groups messages into chats with intelligent summaries to avoid repetition
- Priority System: Guidelines can have different priorities for better control
- Single-Use Guidelines: Prevent repetitive responses by marking guidelines as single-use
- Full Traceability: Complete audit trail of prompts, responses, and guideline usage
- Guidelines: Stored with condition/action pairs, embeddings for semantic search, and priority levels
- Chat System: Conversation grouping with customer-focused summaries
- Message Processing: Complete workflow from user input β guideline selection β prompt construction β AI response
- Semantic Search: Uses @xenova/transformers (all-MiniLM-L6-v2) embeddings with cosine similarity for guideline relevance
-- Guidelines with semantic embeddings
guideline {
id: UUID
condition: String // When to apply this guideline
action: String // What the AI should do
isActive: Boolean // Enable/disable guidelines
isSingleUse: Boolean // Use only once per chat
priority: Int // Higher priority guidelines preferred
embedding: Vector(384) // Semantic embedding for similarity search
}
-- Conversation management
chat {
id: UUID
summary: String // Customer-focused conversation summary
usedGuidelineIds: String[] // Track single-use guidelines
}
-- Message tracking with full context
message {
id: UUID
content: String // User message
prompt: String // Constructed prompt sent to Claude
response: String // AI response
userId: Int
chatId: UUID // Links to conversation
}- Domain Layer: Business entities (Message, Chat, Guideline)
- Application Layer: Business logic (buildPrompt, getApplicableGuidelines, generateSummary)
- Infrastructure Layer: External concerns (REST controllers, database, Claude API)
- Node.js 20.10.0+
- Docker and Docker Compose
- Anthropic API key for Claude integration
-
Clone and initial setup:
git clone <repository-url> cd uptail-ai-agent make run
This will install dependencies, create environment files, and start containers.
-
Configure API key:
# Edit .env.dev file and add your Anthropic API key ANTHROPIC_API_KEY=your_actual_api_key_here -
Start development server:
make watch
Server will be available at
http://localhost:8000 -
Populate with sample data:
make populate
Adds 10 sample guidelines, 3 chats, and 9 messages for testing.
make run- Initial setup: dependencies, env files, containersmake watch- Development server with file watchingmake test- Run test suite with watch modemake test/ci- CI testing with coverage (currently 97%+)make populate- Seed database with sample datamake down- Stop containersmake clean-db- Remove database volumes
POST /api/guideline
Content-Type: application/json
{
"condition": "Customer shows price objection",
"action": "Acknowledge the concern and highlight value proposition with ROI examples",
"isActive": true,
"isSingleUse": false
}Note: priority defaults to 0, and isSingleUse defaults to false if not specified.
POST /api/message
Content-Type: application/json
{
"message": "This seems too expensive for our budget",
"userId": 1,
"chatId": "123e4567-e89b-12d3-a456-426614174000"
}
# Response:
{
"response": "I understand your budget concerns. Let me show you how this investment typically pays for itself within 3 months through efficiency gains..."
}GET /api/chat/{chatId}
# Returns:
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"summary": "Customer interested in solution but concerned about pricing...",
"messages": [
{
"content": "Tell me about your product",
"response": "Our solution helps businesses...",
"createdAt": "2025-01-20T10:30:00Z"
}
]
}The project uses Test-Driven Development with comprehensive integration testing:
- 21 Integration Tests covering complete workflows
- 97%+ Code Coverage across all business logic
- Real PostgreSQL database via TestContainers
- Mocked External Services (Anthropic SDK)
# Run tests in watch mode
make test
# Run CI tests with coverage
make test/ci- User sends message via
/api/messagewith chatId - System retrieves active guidelines for the chat (excluding used single-use ones)
- Generates embedding for user message using @xenova/transformers (all-MiniLM-L6-v2)
- Calculates semantic similarity between message and all guideline embeddings using cosine similarity
- Selects relevant guidelines above 0.3 similarity threshold, sorted by priority then similarity
- Constructs dynamic prompt including guidelines and chat context
- Sends to Claude AI and returns response
- Updates chat summary and tracks guideline usage for single-use guidelines
User: "This is too expensive"
β
Semantic matching finds guideline: "price objection" β "show ROI examples"
β
Prompt: "You are a sales agent. Guidelines: When customer shows price objection, acknowledge concern and show ROI examples. Chat context: Customer interested but budget-conscious..."
β
Claude AI responds with value-focused answer
β
Response tracked, chat summary updated
- Semantic Understanding: Uses AI embeddings for contextual guideline matching, not just keywords
- Conversation Intelligence: Maintains context across messages with intelligent summaries
- Adaptive Guidelines: Single-use and priority systems prevent repetitive responses
- Production Ready: Clean architecture, comprehensive testing, full observability
- Backend: Node.js + Express + TypeScript
- Database: PostgreSQL with Prisma ORM + pgvector extension for vector operations
- AI Integration: Anthropic Claude API + @xenova/transformers (all-MiniLM-L6-v2) for embeddings
- Testing: Jest + TestContainers + Supertest
- Architecture: Clean Architecture with Domain-Driven Design