added technical documentation
This commit is contained in:
431
docs/architecture.md
Normal file
431
docs/architecture.md
Normal file
@@ -0,0 +1,431 @@
|
||||
# Architecture Overview
|
||||
|
||||
This document provides a comprehensive overview of the Daemon Boyfriend Discord bot architecture.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [High-Level Architecture](#high-level-architecture)
|
||||
- [Directory Structure](#directory-structure)
|
||||
- [Core Components](#core-components)
|
||||
- [Data Flow](#data-flow)
|
||||
- [Design Patterns](#design-patterns)
|
||||
- [Component Interaction Diagram](#component-interaction-diagram)
|
||||
|
||||
---
|
||||
|
||||
## High-Level Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Discord API │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Discord Bot (bot.py) │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ AIChatCog │ │ MemoryCog │ │ StatusCog │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
▼ ▼ ▼
|
||||
┌───────────────────────┐ ┌─────────────────┐ ┌─────────────────────────────┐
|
||||
│ Core Services │ │ Living AI │ │ AI Providers │
|
||||
│ ┌─────────────────┐ │ │ Services │ │ ┌─────────────────────┐ │
|
||||
│ │ UserService │ │ │ ┌───────────┐ │ │ │ OpenAI Provider │ │
|
||||
│ │ DatabaseService│ │ │ │ MoodSvc │ │ │ │ OpenRouter Provider│ │
|
||||
│ │ ConversationMgr│ │ │ │ RelSvc │ │ │ │ Anthropic Provider │ │
|
||||
│ │ SearXNGService │ │ │ │ FactSvc │ │ │ │ Gemini Provider │ │
|
||||
│ └─────────────────┘ │ │ │ OpinionSvc│ │ │ └─────────────────────┘ │
|
||||
└───────────────────────┘ │ │ StyleSvc │ │ └─────────────────────────────┘
|
||||
│ │ ProactSvc │ │
|
||||
│ │ AssocSvc │ │
|
||||
│ │ SelfAware │ │
|
||||
│ └───────────┘ │
|
||||
└─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ PostgreSQL Database │
|
||||
│ ┌──────────────────────────────┐ ┌──────────────────────────────────────┐ │
|
||||
│ │ Core Tables │ │ Living AI Tables │ │
|
||||
│ │ users, guilds, conversations │ │ bot_states, user_relationships, │ │
|
||||
│ │ messages, user_facts │ │ mood_history, scheduled_events │ │
|
||||
│ └──────────────────────────────┘ └──────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
daemon-boyfriend/
|
||||
├── src/daemon_boyfriend/
|
||||
│ ├── __main__.py # Entry point
|
||||
│ ├── bot.py # Discord bot setup & cog loading
|
||||
│ ├── config.py # Pydantic settings configuration
|
||||
│ │
|
||||
│ ├── cogs/ # Discord command handlers
|
||||
│ │ ├── ai_chat.py # @mention response handler
|
||||
│ │ ├── memory.py # Memory management commands
|
||||
│ │ └── status.py # Bot status & health commands
|
||||
│ │
|
||||
│ ├── models/ # SQLAlchemy ORM models
|
||||
│ │ ├── base.py # Base model with PortableJSON
|
||||
│ │ ├── user.py # User, UserFact, UserPreference
|
||||
│ │ ├── conversation.py # Conversation, Message
|
||||
│ │ ├── guild.py # Guild, GuildMember
|
||||
│ │ └── living_ai.py # All Living AI models
|
||||
│ │
|
||||
│ └── services/ # Business logic layer
|
||||
│ ├── ai_service.py # AI provider factory
|
||||
│ ├── database.py # Database connection management
|
||||
│ ├── user_service.py # User CRUD operations
|
||||
│ ├── conversation.py # In-memory conversation manager
|
||||
│ ├── persistent_conversation.py # DB-backed conversations
|
||||
│ ├── searxng.py # Web search integration
|
||||
│ ├── monitoring.py # Health & metrics tracking
|
||||
│ │
|
||||
│ ├── providers/ # AI provider implementations
|
||||
│ │ ├── base.py # Abstract AIProvider
|
||||
│ │ ├── openai.py
|
||||
│ │ ├── openrouter.py
|
||||
│ │ ├── anthropic.py
|
||||
│ │ └── gemini.py
|
||||
│ │
|
||||
│ └── [Living AI Services]
|
||||
│ ├── mood_service.py
|
||||
│ ├── relationship_service.py
|
||||
│ ├── fact_extraction_service.py
|
||||
│ ├── opinion_service.py
|
||||
│ ├── communication_style_service.py
|
||||
│ ├── proactive_service.py
|
||||
│ ├── association_service.py
|
||||
│ └── self_awareness_service.py
|
||||
│
|
||||
├── alembic/ # Database migrations
|
||||
├── tests/ # Test suite
|
||||
├── schema.sql # Database schema definition
|
||||
├── docker-compose.yml # Docker deployment
|
||||
└── requirements.txt # Python dependencies
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. Discord Bot Layer
|
||||
|
||||
The bot uses [discord.py](https://discordpy.readthedocs.io/) with a cog-based architecture.
|
||||
|
||||
**Entry Point (`__main__.py`)**
|
||||
- Creates the bot instance
|
||||
- Initializes database connection
|
||||
- Starts the Discord event loop
|
||||
|
||||
**Bot Setup (`bot.py`)**
|
||||
- Configures Discord intents
|
||||
- Auto-loads all cogs from `cogs/` directory
|
||||
- Handles bot lifecycle events
|
||||
|
||||
**Cogs**
|
||||
|
||||
| Cog | Purpose | Trigger |
|
||||
|-----|---------|---------|
|
||||
| `AIChatCog` | Main conversation handler | `@mention` |
|
||||
| `MemoryCog` | User memory management | `!setname`, `!remember`, etc. |
|
||||
| `StatusCog` | Health & metrics | `!status` (admin) |
|
||||
|
||||
### 2. Service Layer
|
||||
|
||||
Services contain all business logic and are designed to be:
|
||||
- **Stateless**: No instance state, all state in database
|
||||
- **Async-first**: All I/O operations are async
|
||||
- **Testable**: Accept database sessions as parameters
|
||||
|
||||
**Core Services**
|
||||
|
||||
| Service | Responsibility |
|
||||
|---------|----------------|
|
||||
| `AIService` | Factory for AI providers, prompt enhancement |
|
||||
| `DatabaseService` | Connection pool, session management |
|
||||
| `UserService` | User CRUD, facts, preferences |
|
||||
| `ConversationManager` | In-memory conversation history |
|
||||
| `PersistentConversationManager` | Database-backed conversations |
|
||||
| `SearXNGService` | Web search for current information |
|
||||
| `MonitoringService` | Health checks, metrics, error tracking |
|
||||
|
||||
**Living AI Services** (see [Living AI documentation](living-ai/README.md))
|
||||
|
||||
| Service | Responsibility |
|
||||
|---------|----------------|
|
||||
| `MoodService` | Emotional state management |
|
||||
| `RelationshipService` | User relationship tracking |
|
||||
| `FactExtractionService` | Autonomous fact learning |
|
||||
| `OpinionService` | Topic sentiment tracking |
|
||||
| `CommunicationStyleService` | User style preferences |
|
||||
| `ProactiveService` | Scheduled events & follow-ups |
|
||||
| `AssociationService` | Cross-user memory linking |
|
||||
| `SelfAwarenessService` | Bot statistics & reflection |
|
||||
|
||||
### 3. AI Provider Layer
|
||||
|
||||
Uses the **Provider Pattern** to support multiple AI backends.
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ AIService │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ get_provider() → returns appropriate AIProvider │ │
|
||||
│ │ chat() → builds context and calls provider.generate │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌─────────────────┼─────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│ OpenAI Provider │ │ Anthropic Provider│ │ Gemini Provider │
|
||||
│ (+ OpenRouter) │ │ │ │ │
|
||||
└──────────────────┘ └──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
### 4. Data Layer
|
||||
|
||||
**Models** (`models/`)
|
||||
- SQLAlchemy ORM with async support
|
||||
- `PortableJSON` type for PostgreSQL/SQLite compatibility
|
||||
- Timezone-aware UTC timestamps
|
||||
|
||||
**Database** (`services/database.py`)
|
||||
- Async PostgreSQL via `asyncpg`
|
||||
- Connection pooling
|
||||
- Graceful fallback to in-memory when no database
|
||||
|
||||
---
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Message Processing Flow
|
||||
|
||||
```
|
||||
1. User sends @mention in Discord
|
||||
│
|
||||
▼
|
||||
2. AIChatCog.on_message() receives event
|
||||
│
|
||||
▼
|
||||
3. Get or create User via UserService
|
||||
│
|
||||
▼
|
||||
4. Get or create Conversation
|
||||
(PersistentConversationManager or ConversationManager)
|
||||
│
|
||||
▼
|
||||
5. Build conversation history from messages
|
||||
│
|
||||
▼
|
||||
6. [Optional] Check if web search needed
|
||||
└─► SearXNGService.search() → add results to context
|
||||
│
|
||||
▼
|
||||
7. Apply Living AI enhancements:
|
||||
├─► MoodService.get_current_mood()
|
||||
├─► RelationshipService.get_relationship()
|
||||
├─► CommunicationStyleService.get_style()
|
||||
└─► OpinionService.get_relevant_opinions()
|
||||
│
|
||||
▼
|
||||
8. Build enhanced system prompt with all context
|
||||
│
|
||||
▼
|
||||
9. AIService.chat() → Provider.generate()
|
||||
│
|
||||
▼
|
||||
10. Post-response processing:
|
||||
├─► MoodService.update_mood()
|
||||
├─► RelationshipService.record_interaction()
|
||||
├─► CommunicationStyleService.record_message()
|
||||
├─► FactExtractionService.maybe_extract_facts()
|
||||
└─► ProactiveService.check_for_events()
|
||||
│
|
||||
▼
|
||||
11. Split response if > 2000 chars
|
||||
│
|
||||
▼
|
||||
12. Send response(s) to Discord
|
||||
```
|
||||
|
||||
### Database Fallback Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Application Start │
|
||||
└─────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ DATABASE_URL set? │
|
||||
└────────────────────────┘
|
||||
│ │
|
||||
Yes No
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────────────┐ ┌───────────────────────┐
|
||||
│ PostgreSQL Mode │ │ In-Memory Mode │
|
||||
│ - Full persistence│ │ - ConversationManager │
|
||||
│ - Living AI state │ │ - No persistence │
|
||||
│ - User facts │ │ - Basic functionality │
|
||||
└───────────────────┘ └───────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Design Patterns
|
||||
|
||||
### 1. Provider Pattern (AI Services)
|
||||
|
||||
Abstract base class with multiple implementations.
|
||||
|
||||
```python
|
||||
# base.py
|
||||
class AIProvider(ABC):
|
||||
@abstractmethod
|
||||
async def generate(
|
||||
self,
|
||||
messages: list[Message],
|
||||
system_prompt: str | None = None,
|
||||
max_tokens: int = 1024,
|
||||
temperature: float = 0.7,
|
||||
) -> AIResponse:
|
||||
pass
|
||||
|
||||
# openai.py
|
||||
class OpenAIProvider(AIProvider):
|
||||
async def generate(...) -> AIResponse:
|
||||
# OpenAI-specific implementation
|
||||
```
|
||||
|
||||
### 2. Factory Pattern (AIService)
|
||||
|
||||
Creates the appropriate provider based on configuration.
|
||||
|
||||
```python
|
||||
class AIService:
|
||||
def __init__(self):
|
||||
self.provider = self._create_provider()
|
||||
|
||||
def _create_provider(self) -> AIProvider:
|
||||
match settings.ai_provider:
|
||||
case "openai": return OpenAIProvider()
|
||||
case "anthropic": return AnthropicProvider()
|
||||
# ...
|
||||
```
|
||||
|
||||
### 3. Repository Pattern (Services)
|
||||
|
||||
Services encapsulate data access logic.
|
||||
|
||||
```python
|
||||
class UserService:
|
||||
@staticmethod
|
||||
async def get_user(session: AsyncSession, discord_id: int) -> User | None:
|
||||
result = await session.execute(
|
||||
select(User).where(User.discord_id == discord_id)
|
||||
)
|
||||
return result.scalar_one_or_none()
|
||||
```
|
||||
|
||||
### 4. Cog Pattern (Discord.py)
|
||||
|
||||
Modular command grouping.
|
||||
|
||||
```python
|
||||
class MemoryCog(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command(name="setname")
|
||||
async def set_name(self, ctx, *, name: str):
|
||||
# Command implementation
|
||||
```
|
||||
|
||||
### 5. Graceful Degradation
|
||||
|
||||
System works with reduced functionality when components unavailable.
|
||||
|
||||
```python
|
||||
# Database fallback
|
||||
if settings.database_url:
|
||||
conversation_manager = PersistentConversationManager()
|
||||
else:
|
||||
conversation_manager = ConversationManager() # In-memory
|
||||
|
||||
# Feature toggles
|
||||
if settings.living_ai_enabled and settings.mood_enabled:
|
||||
mood = await MoodService.get_current_mood(session, guild_id)
|
||||
else:
|
||||
mood = None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Interaction Diagram
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ User Message │
|
||||
└──────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ AIChatCog │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
||||
│ │ UserService │ │ Conversation│ │ SearXNG │ │ AIService │ │
|
||||
│ │ │ │ Manager │ │ Service │ │ │ │
|
||||
│ │ get_user() │ │ get_history │ │ search() │ │ chat() ──────────┐ │ │
|
||||
│ │ get_context │ │ add_message │ │ │ │ │ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ └──────────────────│──┘ │
|
||||
│ │ │
|
||||
│ ┌────────────────────────────────────────────────────────────────────┼────┐ │
|
||||
│ │ Living AI Services │ │ │
|
||||
│ │ │ │ │
|
||||
│ │ ┌───────────┐ ┌──────────────┐ ┌───────────────┐ ┌────────────┐ │ │ │
|
||||
│ │ │ MoodSvc │ │ Relationship │ │ CommStyleSvc │ │ OpinionSvc │ │ │ │
|
||||
│ │ │ │ │ Svc │ │ │ │ │ │ │ │
|
||||
│ │ │get_mood() │ │get_relation()│ │ get_style() │ │get_opinions│ │ │ │
|
||||
│ │ │update() │ │record() │ │ record() │ │ update() │ │ │ │
|
||||
│ │ └───────────┘ └──────────────┘ └───────────────┘ └────────────┘ │ │ │
|
||||
│ │ │ │ │
|
||||
│ │ ┌───────────────┐ ┌────────────────┐ ┌───────────────────────┐ │ │ │
|
||||
│ │ │ FactExtract │ │ ProactiveSvc │ │ SelfAwarenessSvc │ │ │ │
|
||||
│ │ │ │ │ │ │ │ │ │ │
|
||||
│ │ │ extract() │ │ detect_events()│ │ get_stats() │ │ │ │
|
||||
│ │ └───────────────┘ └────────────────┘ └───────────────────────┘ │ │ │
|
||||
│ └────────────────────────────────────────────────────────────────────│────┘ │
|
||||
│ │ │
|
||||
└────────────────────────────────────────────────────────────────────────│──────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ AI Provider │
|
||||
│ (OpenAI / Anthropic / Gemini / OpenRouter) │
|
||||
└──────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ Response │
|
||||
└──────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Living AI System](living-ai/README.md) - Deep dive into the personality system
|
||||
- [Services Reference](services/README.md) - Detailed API documentation
|
||||
- [Database Schema](database.md) - Complete schema documentation
|
||||
- [Configuration Reference](configuration.md) - All configuration options
|
||||
- [Developer Guides](guides/README.md) - How to extend the system
|
||||
Reference in New Issue
Block a user