Skip to content
OnDemandWorldPublic

About

ODW Desk - Self-hosted, WhatsApp-first AI customer support agent with full data sovereignty. Production-ready with PII detection, RAG-powered responses, human agent handoff, and GDPR compliance.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

30 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ODW Desk

Self-hosted, WhatsApp-first AI customer support agent with full data sovereignty.

Python 3.11+ FastAPI License: MIT

Overview

ODW Desk is a production-ready, self-hosted AI customer support platform that keeps all conversation data within your infrastructure while delivering intelligent, context-aware responses grounded in your organization's knowledge base.

Unlike cloud-based solutions that send customer data to third-party APIs, Desk maintains complete data sovereignty—ideal for regulated industries (healthcare, legal, fintech, government) where compliance and privacy are non-negotiable.

Status

⚠️ Early release. ODW Desk is an early, functional release — core features work, but it is not yet hardened for production. We are refining every module toward a first full public release in Q3 2026. Until then, it is best used as a foundation to build on with AI coding agents (see below).

Key Features

🤖 AI Intelligence Pipeline

  • PII Shield: Automatic detection and redaction of sensitive information (names, phones, emails, SSN, credit cards, medical IDs)
  • Model Router: Intelligent routing between local models (Ollama/vLLM) and frontier models (OpenAI/Anthropic) based on PII presence and complexity
  • Vault Integration: RAG-powered responses grounded in your organization's knowledge base
  • Confidence Scoring: Multi-factor confidence assessment with automatic escalation to human agents
  • Brand Persona: Configurable brand voice, tone, and vocabulary guidelines injected into AI responses
  • Response Policies: Pre/post-generation guardrails for compliance and content control

💬 Channel Support

  • WhatsApp Business API: Full support for Meta's official WhatsApp Business Platform
  • Web-chat (V1.3): WebSocket browser chat (WS /ws/chat/{visitor_id}) sharing the same conversation/agent pipeline as WhatsApp
  • Email (V1.5): RFC822 inbound parsing (desk.channels.email.parse_email_message) routed through the same conversation/agent pipeline (channel="email"), with reply threading via In-Reply-To/References (or sender+subject). Outbound replies go over SMTP (EmailChannel.send_reply, injectable/mockable); disabled by default (EMAIL_ENABLED=false) so development never requires a live mail server — sends are gracefully stubbed until configured.
  • Extensible Architecture: Plugin system ready for Telegram, Discord, Slack, Signal, and iMessage adapters
  • Real-time Updates: WebSocket-based live conversation monitoring for agents

⏱️ SLA Timing & Media (V1.1)

  • SLA Evaluation & Escalation: Conversations are evaluated against configurable first-response and resolution thresholds (SLA_FIRST_RESPONSE_MINUTES, SLA_RESOLUTION_HOURS). Breaches flip the conversation to the escalated state via the existing state machine and emit a best-effort sla.breach event (desk.sla.policy / desk.sla.service). desk.sla.checker.scan_due_conversations scans active conversations and escalates those in breach (scheduling is an ops concern).
  • Inbound Media: WhatsApp image/document/audio/video messages are parsed into media_id / mime_type / caption metadata; the Graph API download URL is resolved on demand via resolve_media_url (identifiers + metadata are stored, not large binaries).
  • Outbound Media: send_media(recipient, media_type, media_link, caption?) posts media messages through the WhatsApp Cloud API, falling back to a local stub when unconfigured.

🌍 Multilingual AI Replies (V1.2)

  • Language-Adaptive Responses: The AI detects the language of each inbound message and replies in kind (Chinese and English supported today). A lightweight "respond in {language}" instruction is injected into the LLM prompt (desk.ai.prompt_builder), and detection is a dependency-free Unicode heuristic (desk.i18n.detect) — text containing CJK ideographs is treated as Chinese, everything else as English.
  • Multilingual System/Fallback Messages: Stub, escalation, and policy-block messages are served from a string-resource table (desk.i18n.messages) via t(key, lang, **fmt) (desk.i18n.service). English is the source of truth and the fallback, so default behaviour is unchanged when detection fails or a language/key is missing. Add a language by extending the resource table.

👥 Human Agent Interface

  • Agent Inbox: REST API for conversation management, takeover, and response composition
  • Real-time Dashboard: WebSocket connections for live conversation monitoring
  • AI Feedback: Thumbs up/down feedback on AI responses for continuous improvement
  • Escalation Workflow: Seamless handoff from AI to human agents with full context

🔒 Compliance & Governance

  • GDPR Ready: Data export (Article 20) and deletion (Article 17) workflows
  • Tamper-Evident Audit: Hash-chained audit log for all system actions
  • Data Retention: Configurable retention policies with automatic enforcement
  • License Management: Tier-based feature gating (Free/Paid/Enterprise)

🚀 Production Ready

  • Docker Deployment: Multi-stage production Dockerfile with health checks
  • Kubernetes Native: Helm charts with configurable values for scaling
  • CI/CD Pipeline: GitHub Actions workflow with lint, test, and build stages
  • Observability: 25+ Prometheus metrics across all system components
  • Distributed Tracing (V1.5/V1.6): X-Trace-Id propagation (V1.5) plus a lightweight span model (V1.6 F-2) — desk.observability.tracing.start_span builds a sampled span tree around the AI pipeline and channel inbound, exported to the console (default) or best-effort OTLP/HTTP
  • Graceful Degradation: System continues operating when external services (LLM, Vault) are unavailable

Architecture

┌─────────────────┐
│  WhatsApp API   │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Channel Gateway │◄──── Other Channels (Telegram, Discord, etc.)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Message Router  │──── Customer Resolution
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Conversation    │◄──── State Machine (new → active → escalated → resolved)
│ Manager         │
└────────┬────────┘
         │
         ▼
┌─────────────────────────────────────────┐
│         AI Engine Orchestrator          │
├─────────────────────────────────────────┤
│  1. PII Shield (detect & redact)        │
│  2. Model Router (local vs frontier)    │
│  3. Vault Client (knowledge retrieval)  │
│  4. Prompt Builder (persona + context)  │
│  5. LLM Inference (Ollama/OpenAI)       │
│  6. Confidence Scorer (escalation)      │
│  7. Policy Engine (guardrails)          │
└────────┬────────────────────────────────┘
         │
         ▼
┌─────────────────┐
│ Outbound        │──── WhatsApp Response / Agent Notification
│ Dispatcher      │
└─────────────────┘

Core Components

Component Responsibility Technology
Channel Gateway Inbound/outbound message handling FastAPI, WebSockets
Message Router Customer resolution, context loading SQLAlchemy, Redis
Conversation Manager State machine, message persistence PostgreSQL, async/await
AI Engine Full RAG pipeline orchestration Presidio, LangChain
PII Shield PII detection and redaction Presidio Analyzer
Model Router Local/frontier model selection Complexity scoring
Vault Client Knowledge base retrieval HTTP, Redis cache
Agent Inbox Human agent interface REST API, WebSocket
Compliance Engine GDPR workflows, audit trails Hash-chained logging
License Manager Feature gating, tier enforcement Database-backed

Operator Console(操作员控制台)

人工坐席不需要 curl——Desk 自带零构建 Web 控制台(默认随服务启动):

  • http://localhost:8000/console — 坐席收件台:会话列表、消息历史、接管(Take over)、 回复(Send)、解决(Resolve)。首次打开输入 DESK_API_KEY 与角色(默认 agent)。
  • http://localhost:8000/console/webchat — 可嵌入 webchat 演示页:访客 WebSocket 客户端, 展示 AI 应答与坐席接管的全过程(对接 /ws/chat/{visitor_id})。

RBAC 提示:设置 DESK_API_KEY 后,admin/agent 路由需要 key;角色来自 JWT claim 或 X-Desk-Role 头,未知/缺失角色默认最小权限 agent(默认拒绝 admin, 单机开发可显式设 DESK_DEFAULT_ROLE=admin)。

Quick Start

Prerequisites

  • Python 3.11+ (3.12 recommended)
  • PostgreSQL 16+
  • Redis 7+
  • (Optional) Ollama or vLLM for local LLM inference
  • (Optional) ODW.ai Vault for knowledge base

Installation

  1. Clone the repository
git clone https://github.com/OnDemandWorld/odw-desk.git
cd odw-desk
  1. Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
  1. Install dependencies
pip install -r requirements.txt
  1. Configure environment
cp .env.example .env
# Edit .env with your configuration
  1. Provision infrastructure & initialize database
# PostgreSQL 与 Redis 必须先可用(可只起套件自带的基础设施:
#   docker compose -f docker-compose.dev.yml up -d postgres redis minio
# 然后创建数据库(alembic 只建表,不建库):
createdb -h localhost -U postgres desk   # 或 CREATE DATABASE desk;
alembic upgrade head   # alembic/env.py 会优先读取 DATABASE_URL
  1. Start the application
uvicorn desk.main:app --host 0.0.0.0 --port 8000 --reload

Docker Deployment

# Build the image
docker build -t odw-desk:latest .

# Run with Docker Compose (includes PostgreSQL and Redis)
docker-compose -f docker-compose.dev.yml up -d

Kubernetes Deployment

# Add Helm repository
helm repo add odw-desk ./k8s/helm

# Install with custom values
helm install desk odw-desk -f values-production.yaml

Configuration

All configuration is managed through environment variables. See .env.example for complete reference.

Essential Configuration

# Database
DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/desk

# Redis
REDIS_URL=redis://localhost:6379/0

# WhatsApp Business API
WHATSAPP_ACCESS_TOKEN=your_token
WHATSAPP_PHONE_NUMBER_ID=your_phone_id
WHATSAPP_WEBHOOK_VERIFY_TOKEN=your_verify_token

# Email Channel (V1.5) — disabled by default; outbound SMTP is stubbed in dev
EMAIL_ENABLED=false
EMAIL_SMTP_HOST=smtp.example.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USER=
EMAIL_SMTP_PASSWORD=
EMAIL_FROM=support@example.com

# AI Models
OLLAMA_ENDPOINT=http://localhost:11434
LOCAL_MODEL_NAME=llama-3.1-8b
LOCAL_MODEL_ENABLED=true

# Optional: Frontier Models
FRONTIER_ENABLED=false
FRONTIER_PROVIDER=openai  # or anthropic
FRONTIER_API_KEY=your_key
FRONTIER_MODEL_NAME=gpt-4o-mini

# Vault Integration
VAULT_URL=http://localhost:8765
VAULT_API_KEY=your_vault_key
VAULT_COLLECTION_ID=your_collection_id

# Security
SECRET_KEY=your_secret_key_min_32_chars

# Distributed Tracing Spans (V1.6 F-2) — best-effort, backward-compatible defaults
TRACE_SAMPLE_RATE=1.0            # fraction of traces sampled (1.0 = all, 0.0 = none)
TRACE_EXPORTER=console           # console | otlp | none
OTLP_ENDPOINT=                   # OTLP/HTTP endpoint used when TRACE_EXPORTER=otlp

API Documentation

Once running, access the interactive API documentation:

Key Endpoints

WhatsApp Webhook

POST /api/v1/webhooks/whatsapp

Receives incoming WhatsApp messages from Meta.

Agent Inbox

GET    /api/v1/agents/conversations
GET    /api/v1/agents/conversations/{id}
POST   /api/v1/agents/conversations/{id}/takeover
POST   /api/v1/agents/conversations/{id}/respond
POST   /api/v1/agents/conversations/{id}/resolve

Admin APIs

GET    /api/v1/admin/setup/status
POST   /api/v1/admin/setup/vault
POST   /api/v1/admin/setup/whatsapp
GET    /api/v1/admin/personas
GET    /api/v1/admin/policies
GET    /api/v1/admin/compliance/audit-logs
POST   /api/v1/admin/compliance/export
POST   /api/v1/admin/compliance/delete

WebSocket

WS /ws/agents/{agent_id}

Real-time conversation updates for agents.

WS /ws/chat/{visitor_id}

Web-chat channel (V1.3). Send plain-text frames as a visitor; each message is routed through the shared pipeline (channel webchat) and acknowledged with a {"type": "routed", "conversation_id": ...} envelope. Outbound replies are pushed back as {"type": "reply", "content": ...} frames.

Read receipts (V1.6 F-4). Clients mark a message read by sending {"type": "read", "message_id": "..."} (the message_id is the channel message id, or the message UUID). The server sets the message's read_at timestamp (idempotently — an already-read message keeps its first read_at) and replies with {"type": "read_ack", "message_id": ..., "read_at": ..., "status": "read"} (status is not_found when the message does not exist). Messages with no read event keep read_at = null (unread), so existing clients are unaffected.

Rich-media persistence (V1.6 F-4). Inbound image/file frames may carry url/mime/name/size; this metadata is now persisted on the message record (metadata.media) instead of living only in memory (V1.4), so sent images/files are queryable after the fact. Frames without media persist nothing extra.

Development

Project Structure

desk/
├── src/desk/
│   ├── ai/                    # AI Intelligence Pipeline
│   │   ├── engine.py         # Main orchestrator
│   │   ├── pii_shield.py     # PII detection & redaction
│   │   ├── model_router.py   # Model selection logic
│   │   ├── vault_client.py   # Knowledge retrieval
│   │   ├── prompt_builder.py # Prompt composition
│   │   ├── confidence_scorer.py
│   │   └── providers/        # LLM provider implementations
│   │       ├── ollama.py
│   │       └── openai.py
│   ├── agents/               # Human agent interfaces
│   │   ├── inbox_api.py      # REST API
│   │   └── websocket.py      # Real-time updates
│   ├── admin/                # Admin & configuration APIs
│   │   ├── api.py
│   │   └── persona_policy_api.py
│   ├── channels/             # Channel adapters
│   │   ├── base.py          # Abstract adapter interface
│   │   ├── whatsapp_business.py
│   │   ├── manager.py
│   │   └── outbound.py
│   ├── conversations/        # Conversation management
│   │   ├── manager.py
│   │   └── state_machine.py
│   ├── compliance/           # GDPR & audit
│   │   └── engine.py
│   ├── i18n/                 # Multilingual replies (V1.2)
│   │   ├── detect.py        # Dependency-free language detection
│   │   ├── messages.py      # String resources (en/zh)
│   │   └── service.py       # t() translation + reply_language()
│   ├── license/              # License management
│   │   └── manager.py
│   ├── persona/              # Brand persona
│   │   ├── service.py
│   │   └── integration.py
│   ├── policy/               # Response policies
│   │   └── engine.py
│   ├── observability/        # Metrics & monitoring
│   │   └── metrics.py
│   ├── models/               # SQLAlchemy models
│   ├── events/               # Event bus (Redis Streams)
│   └── utils/                # Utilities
├── tests/
│   ├── integration/          # Integration tests
│   └── e2e/                  # End-to-end tests
├── alembic/                  # Database migrations
├── k8s/helm/                 # Kubernetes Helm charts
└── .github/workflows/        # CI/CD pipeline

Running Tests

# Integration tests
pytest tests/integration/ -v

# End-to-end tests (requires running application)
pytest tests/e2e/ -v

# With coverage
pytest --cov=desk --cov-report=html

Code Quality

# Linting
ruff check src/desk/

# Auto-fix linting issues
ruff check src/desk/ --fix

# Type checking
mypy src/desk/

# Formatting
black src/desk/
isort src/desk/

Deployment

Production Checklist

  • Set ENVIRONMENT=production
  • Configure strong SECRET_KEY (32+ chars)
  • Set up PostgreSQL with SSL
  • Configure Redis with authentication
  • Set WHATSAPP_ACCESS_TOKEN and related credentials
  • Configure Vault connection (if using knowledge base)
  • Set up LLM provider (Ollama or frontier model)
  • Configure monitoring/alerting
  • Set up backup strategy for PostgreSQL
  • Review and configure data retention policies
  • Activate appropriate license tier

Scaling Considerations

  • Horizontal Scaling: Deploy multiple API instances behind load balancer
  • Database: Use connection pooling (configured via DATABASE_POOL_SIZE)
  • Redis: Cluster mode for high availability
  • Worker Processes: Adjust uvicorn workers based on CPU cores
  • Async Architecture: All I/O operations are non-blocking

Monitoring

Prometheus Metrics

Desk exposes 25+ metrics at /metrics endpoint:

  • desk_messages_received_total - Inbound message count
  • desk_ai_pipeline_duration_seconds - AI processing time
  • desk_pii_detected_total - PII detection events
  • desk_llm_requests_total - LLM API calls
  • desk_confidence_scores - Confidence distribution
  • desk_escalations_total - Human escalations
  • desk_active_conversations - Current conversation count
  • desk_online_agents - Agent availability

Health Checks

# Application health
curl http://localhost:8000/health

# Returns:
{
  "status": "healthy",
  "version": "1.0.0",
  "components": {
    "database": "healthy",
    "redis": "healthy",
    "event_bus": "healthy"
  }
}

Security

Data Sovereignty

  • All conversation data stored in your PostgreSQL instance
  • PII detection prevents sensitive data from reaching external APIs
  • Configurable routing: force local-only processing when PII detected
  • Encrypted API keys at rest (AES-256-GCM)

Compliance Features

  • GDPR Article 20: Data export in JSON/CSV format
  • GDPR Article 17: Right to erasure with audit trail
  • Audit Logging: Tamper-evident hash-chained logs
  • Data Retention: Automatic enforcement of retention policies

Access Control

  • License-based feature gating
  • Agent role management
  • API authentication (configurable)
  • Webhook signature verification (HMAC-SHA256)

Troubleshooting

Common Issues

Database connection failed

# Check PostgreSQL is running
pg_isready -h localhost -p 5432

# Verify DATABASE_URL in .env

Redis connection failed

# Check Redis is running
redis-cli ping

# Verify REDIS_URL in .env

WhatsApp webhook not receiving messages

# Verify webhook URL is publicly accessible
# Check WhatsApp Business API configuration in Meta Business Suite
# Verify WHATSAPP_WEBHOOK_VERIFY_TOKEN matches Meta configuration

LLM inference slow or failing

# Check Ollama is running
curl http://localhost:11434/api/tags

# Verify model is downloaded
ollama list

# Check logs for errors

Logs

All logs use structured format (JSON) via structlog:

# View application logs
tail -f logs/desk.log

# Filter by level
grep '"level": "error"' logs/desk.log

Contributing

Contributions welcome! Please see CONTRIBUTING.md for guidelines.

Development Workflow

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing-feature)
  3. Make changes and add tests
  4. Ensure all tests pass and linting is clean
  5. Commit changes (git commit -m 'Add amazing feature')
  6. Push to branch (git push origin feature/amazing-feature)
  7. Open Pull Request

Working with AI agents

This repository is built to be extended with AI coding agents. Rather than a turnkey product, ODW Desk is a working, well-structured codebase you can clone and adapt to your own needs with an agent like Claude Code. The repo includes agent context files (e.g. CLAUDE.md) and clear architecture docs so an agent can quickly understand the structure and help you customise, integrate, and extend it. To get started: clone the repo, open it with your coding agent, point it at this README and the docs, and describe what you want to build.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Roadmap

Completed (v1.0)

  • ✅ WhatsApp Business API integration
  • ✅ Full AI intelligence pipeline
  • ✅ Human agent interfaces
  • ✅ Compliance framework
  • ✅ Production deployment infrastructure

Planned (v1.1)

  • 🔜 Telegram Bot Adapter
  • 🔜 Discord Bot Adapter
  • 🔜 Slack App Adapter
  • 🔜 Signal Messenger Adapter
  • 🔜 iMessage Bridge Adapter
  • 🔜 Advanced persona versioning
  • 🔜 Intent classifier integration

Acknowledgments

Built with:


Made with ❤️ for organizations that value data sovereignty

About

ODW Desk - Self-hosted, WhatsApp-first AI customer support agent with full data sovereignty. Production-ready with PII detection, RAG-powered responses, human agent handoff, and GDPR compliance.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages