feat(05-01): add round and message operations to discussion service

Add create_round, get_current_round, create_message, and get_round_messages
functions. All async with proper type hints and eager loading.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Mikkel Georgsen 2026-01-16 19:26:21 +00:00
parent 3258c3a596
commit baf02bb11f
2 changed files with 103 additions and 0 deletions

View file

@ -7,8 +7,12 @@ providing a clean interface for handlers to use.
from moai.core.services.discussion import ( from moai.core.services.discussion import (
complete_discussion, complete_discussion,
create_discussion, create_discussion,
create_message,
create_round,
get_active_discussion, get_active_discussion,
get_current_round,
get_discussion, get_discussion,
get_round_messages,
list_discussions, list_discussions,
) )
from moai.core.services.project import create_project, get_project, list_projects 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__ = [ __all__ = [
"complete_discussion", "complete_discussion",
"create_discussion", "create_discussion",
"create_message",
"create_project", "create_project",
"create_round",
"get_active_discussion", "get_active_discussion",
"get_current_round",
"get_discussion", "get_discussion",
"get_project", "get_project",
"get_round_messages",
"list_discussions", "list_discussions",
"list_projects", "list_projects",
] ]

View file

@ -11,7 +11,9 @@ from moai.core.models import (
Discussion, Discussion,
DiscussionStatus, DiscussionStatus,
DiscussionType, DiscussionType,
Message,
Round, Round,
RoundType,
) )
@ -122,3 +124,96 @@ async def complete_discussion(discussion_id: str) -> Discussion | None:
await session.flush() await session.flush()
await session.refresh(discussion) await session.refresh(discussion)
return 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())