diff --git a/src/moai/core/services/__init__.py b/src/moai/core/services/__init__.py index e4573f3..b814320 100644 --- a/src/moai/core/services/__init__.py +++ b/src/moai/core/services/__init__.py @@ -7,8 +7,12 @@ providing a clean interface for handlers to use. from moai.core.services.discussion import ( complete_discussion, create_discussion, + create_message, + create_round, get_active_discussion, + get_current_round, get_discussion, + get_round_messages, list_discussions, ) from moai.core.services.project import create_project, get_project, list_projects @@ -16,10 +20,14 @@ from moai.core.services.project import create_project, get_project, list_project __all__ = [ "complete_discussion", "create_discussion", + "create_message", "create_project", + "create_round", "get_active_discussion", + "get_current_round", "get_discussion", "get_project", + "get_round_messages", "list_discussions", "list_projects", ] diff --git a/src/moai/core/services/discussion.py b/src/moai/core/services/discussion.py index 71a6ddf..bf84885 100644 --- a/src/moai/core/services/discussion.py +++ b/src/moai/core/services/discussion.py @@ -11,7 +11,9 @@ from moai.core.models import ( Discussion, DiscussionStatus, DiscussionType, + Message, Round, + RoundType, ) @@ -122,3 +124,96 @@ async def complete_discussion(discussion_id: str) -> Discussion | None: await session.flush() await session.refresh(discussion) return discussion + + +async def create_round( + discussion_id: str, + round_number: int, + round_type: RoundType, +) -> Round: + """Create a new round within a discussion. + + Args: + discussion_id: The parent discussion's UUID. + round_number: Sequential round number within the discussion. + round_type: Whether this round is PARALLEL or SEQUENTIAL. + + Returns: + The created Round object. + """ + async with get_session() as session: + round_ = Round( + discussion_id=discussion_id, + round_number=round_number, + type=round_type, + ) + session.add(round_) + await session.flush() + await session.refresh(round_) + return round_ + + +async def get_current_round(discussion_id: str) -> Round | None: + """Get the current (most recent) round for a discussion. + + Args: + discussion_id: The discussion's UUID. + + Returns: + The most recent Round object if found, None otherwise. + """ + async with get_session() as session: + result = await session.execute( + select(Round) + .where(Round.discussion_id == discussion_id) + .order_by(Round.round_number.desc()) + .limit(1) + .options(selectinload(Round.messages)) + ) + return result.scalar_one_or_none() + + +async def create_message( + round_id: str, + model: str, + content: str, + is_direct: bool = False, +) -> Message: + """Create a new message within a round. + + Args: + round_id: The parent round's UUID. + model: AI model identifier (e.g., "claude", "gpt", "gemini"). + content: The message content. + is_direct: True if this was a direct @mention to this model. + + Returns: + The created Message object. + """ + async with get_session() as session: + message = Message( + round_id=round_id, + model=model, + content=content, + is_direct=is_direct, + ) + session.add(message) + await session.flush() + await session.refresh(message) + return message + + +async def get_round_messages(round_id: str) -> list[Message]: + """Get all messages for a round ordered by timestamp. + + Args: + round_id: The round's UUID. + + Returns: + List of Message objects ordered by timestamp. + """ + async with get_session() as session: + result = await session.execute( + select(Message).where(Message.round_id == round_id).order_by(Message.timestamp) + ) + return list(result.scalars().all())