# Services Reference This document provides detailed API documentation for all services in the Daemon Boyfriend bot. ## Table of Contents - [Core Services](#core-services) - [AIService](#aiservice) - [DatabaseService](#databaseservice) - [UserService](#userservice) - [ConversationManager](#conversationmanager) - [PersistentConversationManager](#persistentconversationmanager) - [SearXNGService](#searxngservice) - [MonitoringService](#monitoringservice) - [AI Providers](#ai-providers) - [Living AI Services](#living-ai-services) --- ## Core Services ### AIService **File:** `services/ai_service.py` Factory and facade for AI providers. Manages provider creation, switching, and provides a unified interface for generating responses. #### Initialization ```python from loyal_companion.services.ai_service import AIService from loyal_companion.config import settings # Use default settings ai_service = AIService() # Or with custom settings ai_service = AIService(config=custom_settings) ``` #### Properties | Property | Type | Description | |----------|------|-------------| | `provider` | `AIProvider` | Current AI provider instance | | `provider_name` | `str` | Name of current provider | | `model` | `str` | Current model name | #### Methods ##### `chat(messages, system_prompt) -> AIResponse` Generate a chat response. ```python from loyal_companion.services.providers import Message response = await ai_service.chat( messages=[ Message(role="user", content="Hello!"), ], system_prompt="You are a helpful assistant." ) print(response.content) # AI's response print(response.model) # Model used print(response.usage) # Token usage ``` ##### `get_system_prompt() -> str` Get the base system prompt for the bot. ```python prompt = ai_service.get_system_prompt() # Returns: "You are Daemon, a friendly and helpful Discord bot..." ``` ##### `get_enhanced_system_prompt(...) -> str` Build system prompt with all personality modifiers. ```python enhanced_prompt = ai_service.get_enhanced_system_prompt( mood=mood_state, relationship=(relationship_level, relationship_record), communication_style=user_style, bot_opinions=relevant_opinions ) ``` **Parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `mood` | `MoodState \| None` | Current mood state | | `relationship` | `tuple[RelationshipLevel, UserRelationship] \| None` | Relationship info | | `communication_style` | `UserCommunicationStyle \| None` | User's preferences | | `bot_opinions` | `list[BotOpinion] \| None` | Relevant opinions | --- ### DatabaseService **File:** `services/database.py` Manages database connections and sessions. #### Global Instance ```python from loyal_companion.services.database import db, get_db # Get global instance db_service = get_db() ``` #### Properties | Property | Type | Description | |----------|------|-------------| | `is_configured` | `bool` | Whether DATABASE_URL is set | | `is_initialized` | `bool` | Whether connection is initialized | #### Methods ##### `init() -> None` Initialize database connection. ```python await db.init() ``` ##### `close() -> None` Close database connection. ```python await db.close() ``` ##### `create_tables() -> None` Create all tables from `schema.sql`. ```python await db.create_tables() ``` ##### `session() -> AsyncGenerator[AsyncSession, None]` Get a database session with automatic commit/rollback. ```python async with db.session() as session: # Use session for database operations user = await session.execute(select(User).where(...)) # Auto-commits on exit, auto-rollbacks on exception ``` --- ### UserService **File:** `services/user_service.py` Service for user-related operations. #### Initialization ```python from loyal_companion.services.user_service import UserService async with db.session() as session: user_service = UserService(session) ``` #### Methods ##### `get_or_create_user(discord_id, username, display_name) -> User` Get existing user or create new one. ```python user = await user_service.get_or_create_user( discord_id=123456789, username="john_doe", display_name="John" ) ``` ##### `get_user_by_discord_id(discord_id) -> User | None` Get a user by their Discord ID. ```python user = await user_service.get_user_by_discord_id(123456789) ``` ##### `set_custom_name(discord_id, custom_name) -> User | None` Set a custom name for a user. ```python user = await user_service.set_custom_name(123456789, "Johnny") # Or clear custom name user = await user_service.set_custom_name(123456789, None) ``` ##### `add_fact(user, fact_type, fact_content, source, confidence) -> UserFact` Add a fact about a user. ```python fact = await user_service.add_fact( user=user, fact_type="hobby", fact_content="enjoys playing chess", source="conversation", confidence=0.9 ) ``` ##### `get_user_facts(user, fact_type, active_only) -> list[UserFact]` Get facts about a user. ```python # All active facts facts = await user_service.get_user_facts(user) # Only hobby facts hobby_facts = await user_service.get_user_facts(user, fact_type="hobby") # Including inactive facts all_facts = await user_service.get_user_facts(user, active_only=False) ``` ##### `delete_user_facts(user) -> int` Soft-delete all facts for a user. ```python count = await user_service.delete_user_facts(user) print(f"Deactivated {count} facts") ``` ##### `set_preference(user, key, value) -> UserPreference` Set a user preference. ```python await user_service.set_preference(user, "theme", "dark") ``` ##### `get_preference(user, key) -> str | None` Get a user preference value. ```python theme = await user_service.get_preference(user, "theme") ``` ##### `get_user_context(user) -> str` Build a context string about a user for the AI. ```python context = await user_service.get_user_context(user) # Returns: # User's preferred name: John # (You should address them as: Johnny) # # Known facts about this user: # - [hobby] enjoys playing chess # - [work] software developer ``` ##### `get_user_with_facts(discord_id) -> User | None` Get a user with their facts eagerly loaded. ```python user = await user_service.get_user_with_facts(123456789) print(user.facts) # Facts already loaded ``` --- ### ConversationManager **File:** `services/conversation.py` In-memory conversation history manager (used when no database). #### Initialization ```python from loyal_companion.services.conversation import ConversationManager conversation_manager = ConversationManager(max_history=50) ``` #### Methods ##### `add_message(user_id, role, content) -> None` Add a message to a user's conversation history. ```python conversation_manager.add_message( user_id=123456789, role="user", content="Hello!" ) ``` ##### `get_history(user_id) -> list[dict]` Get conversation history for a user. ```python history = conversation_manager.get_history(123456789) # Returns: [{"role": "user", "content": "Hello!"}, ...] ``` ##### `clear_history(user_id) -> None` Clear conversation history for a user. ```python conversation_manager.clear_history(123456789) ``` --- ### PersistentConversationManager **File:** `services/persistent_conversation.py` Database-backed conversation manager. #### Key Features - Conversations persist across restarts - Timeout-based conversation separation (60 min default) - Per-guild conversation tracking #### Methods ##### `get_or_create_conversation(session, user, guild_id) -> Conversation` Get active conversation or create new one. ```python conversation = await pcm.get_or_create_conversation( session=session, user=user, guild_id=123456789 ) ``` ##### `add_message(session, conversation, role, content) -> Message` Add a message to a conversation. ```python message = await pcm.add_message( session=session, conversation=conversation, role="user", content="Hello!" ) ``` ##### `get_recent_messages(session, conversation, limit) -> list[Message]` Get recent messages from a conversation. ```python messages = await pcm.get_recent_messages( session=session, conversation=conversation, limit=20 ) ``` --- ### SearXNGService **File:** `services/searxng.py` Web search integration using SearXNG. #### Initialization ```python from loyal_companion.services.searxng import SearXNGService searxng = SearXNGService() ``` #### Properties | Property | Type | Description | |----------|------|-------------| | `is_configured` | `bool` | Whether SEARXNG_URL is set | #### Methods ##### `search(query, num_results) -> list[SearchResult]` Search the web for a query. ```python if searxng.is_configured: results = await searxng.search( query="Python 3.12 new features", num_results=5 ) for result in results: print(f"{result.title}: {result.url}") print(f" {result.snippet}") ``` --- ### MonitoringService **File:** `services/monitoring.py` Health checks and metrics tracking. #### Features - Request counting - Response time tracking - Error rate monitoring - Health status checks #### Usage ```python from loyal_companion.services.monitoring import MonitoringService monitoring = MonitoringService() # Record a request monitoring.record_request() # Record response time monitoring.record_response_time(0.5) # 500ms # Record an error monitoring.record_error("API timeout") # Get health status status = monitoring.get_health_status() print(status) # { # "status": "healthy", # "uptime": 3600, # "total_requests": 100, # "avg_response_time": 0.3, # "error_rate": 0.02, # "recent_errors": [...] # } ``` --- ## AI Providers **Location:** `services/providers/` ### Base Classes ```python from loyal_companion.services.providers import ( AIProvider, # Abstract base class Message, # Chat message AIResponse, # Response from provider ImageAttachment, # Image attachment ) ``` ### Message Class ```python @dataclass class Message: role: str # "user", "assistant", "system" content: str # Message content images: list[ImageAttachment] = [] # Optional image attachments ``` ### AIResponse Class ```python @dataclass class AIResponse: content: str # Generated response model: str # Model used usage: dict[str, int] # Token usage info ``` ### Available Providers | Provider | Class | Description | |----------|-------|-------------| | OpenAI | `OpenAIProvider` | GPT models via OpenAI API | | OpenRouter | `OpenRouterProvider` | Multiple models via OpenRouter | | Anthropic | `AnthropicProvider` | Claude models via Anthropic API | | Gemini | `GeminiProvider` | Gemini models via Google API | ### Provider Interface All providers implement: ```python 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 @property @abstractmethod def provider_name(self) -> str: pass ``` ### Example: Direct Provider Usage ```python from loyal_companion.services.providers import OpenAIProvider, Message provider = OpenAIProvider( api_key="sk-...", model="gpt-4" ) response = await provider.generate( messages=[Message(role="user", content="Hello!")], system_prompt="You are helpful.", max_tokens=500, temperature=0.7 ) print(response.content) ``` --- ## Living AI Services See [Living AI Documentation](../living-ai/README.md) for detailed coverage: | Service | Documentation | |---------|--------------| | MoodService | [mood-system.md](../living-ai/mood-system.md) | | RelationshipService | [relationship-system.md](../living-ai/relationship-system.md) | | FactExtractionService | [fact-extraction.md](../living-ai/fact-extraction.md) | | OpinionService | [opinion-system.md](../living-ai/opinion-system.md) | | CommunicationStyleService | [Living AI README](../living-ai/README.md#5-communication-style-system) | | ProactiveService | [Living AI README](../living-ai/README.md#6-proactive-events-system) | | AssociationService | [Living AI README](../living-ai/README.md#7-association-system) | | SelfAwarenessService | [Living AI README](../living-ai/README.md#8-self-awareness-system) | --- ## Service Dependency Graph ``` ┌────────────────────────────────────────────────────────────────────────┐ │ AIChatCog │ └────────────────────────────────────────────────────────────────────────┘ │ ┌───────────────────────┼───────────────────────┐ │ │ │ ▼ ▼ ▼ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ UserService │ │ AIService │ │ Conversation │ │ │ │ │ │ Manager │ │ - get_user │ │ - chat │ │ │ │ - get_context │ │ - get_prompt │ │ - get_history │ └───────────────┘ └───────────────┘ └───────────────┘ │ │ │ │ ┌────────┴────────┐ │ │ │ │ │ │ ▼ ▼ │ │ ┌───────────────┐ ┌───────────────┐ │ │ │ Provider │ │ Living AI │ │ │ │ (OpenAI, │ │ Services │ │ │ │ Anthropic) │ │ │ │ │ └───────────────┘ └───────────────┘ │ │ │ └──────────────────┬───────────────────────────┘ │ ▼ ┌───────────────┐ │ Database │ │ Service │ │ │ │ - session() │ └───────────────┘ ```