myrmidon / python /src /server /services /prompt_service.py
tek Atrust
chore(deploy): build monolithic server for Hugging Face
d5ef46f
Raw
History Blame Contribute Delete
3.34 kB
# python/src/server/services/prompt_service.py
from datetime import datetime
from typing import Any
from unittest.mock import MagicMock
from src.server.repositories.base_repository import BaseRepository
from ..config.logfire_config import get_logger
from ..utils import get_supabase_client
logger = get_logger(__name__)
class PromptService(BaseRepository):
"""Service for managing AI agent prompts."""
_instance = None
_prompts: dict[str, str] = {}
_last_loaded: datetime | None = None
def __init__(self, supabase_client=None):
super().__init__(supabase_client or get_supabase_client())
@classmethod
def _reset_for_testing(cls):
"""Internal helper to reset singleton state between tests."""
cls._prompts = {}
cls._last_loaded = None
cls._instance = None
async def load_prompts(self):
"""Mock-compatible method for tests to simulate loading."""
success, res = await self.list_prompts()
if success:
for p in res.get("prompts", []):
# DB schema: prompt_name, prompt
text = p.get("prompt")
if text:
self._prompts[p.get("prompt_name", "")] = text
self._last_loaded = datetime.utcnow()
async def list_prompts(self) -> tuple[bool, dict[str, Any]]:
"""List all system prompts from the database."""
def _query():
return self.supabase_client.table("archon_prompts").select("*").execute()
success, result = self.execute_query(_query, "Failed to list prompts")
if success:
return True, {"prompts": result["data"]}
return False, result
def get_prompt(self, name: str, default: str | None = None) -> str:
"""Get a prompt by name (cached or direct)."""
try:
# First try cache
if name in self._prompts:
return self._prompts[name]
# Fallback to direct DB call - Schema: prompt_name, prompt
res = self.supabase_client.table("archon_prompts").select("prompt").eq("prompt_name", name).execute()
# DEFENSIVE: Check if res.data is a real dict and not a MagicMock
if res.data and not isinstance(res.data, MagicMock) and len(res.data) > 0:
return res.data[0].get("prompt") or default or ""
except Exception:
pass
return default or "You are a helpful AI assistant."
async def update_prompt(
self, prompt_name: str, content: str, description: str | None = None
) -> tuple[bool, dict[str, Any]]:
"""Update a system prompt."""
def _query():
# DB schema uses 'prompt' for the content and 'prompt_name' for identity
update_data = {"prompt": content}
if description:
update_data["description"] = description
return (
self.supabase_client.table("archon_prompts")
.update(update_data)
.eq("prompt_name", prompt_name)
.execute()
)
success, result = self.execute_query(_query, f"Failed to update prompt {prompt_name}")
if success:
self._prompts[prompt_name] = content # Sync cache
return success, result
prompt_service = PromptService()