Initial project structure

Scaffold all modules, route stubs, data models, and config.
No logic implemented yet — all core methods raise NotImplementedError.
Establishes the full directory layout matching the architecture in CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaroslav Benes
2026-04-08 14:48:48 +02:00
commit 083cbb1fa7
32 changed files with 1507 additions and 0 deletions

83
fellowship/api/events.py Normal file
View File

@@ -0,0 +1,83 @@
"""
All WebSocket/SSE event types sent from Fellowship to connected members.
Every event is a Pydantic model serialized to JSON.
"""
from typing import Any, Literal
from pydantic import BaseModel
class HistoryEvent(BaseModel):
type: Literal["history"] = "history"
messages: list[dict[str, Any]]
class TurnStartEvent(BaseModel):
type: Literal["turn_start"] = "turn_start"
bot: str
turn: int
class BotMessageEvent(BaseModel):
type: Literal["bot_message"] = "bot_message"
bot: str
content: str
turn: int
class TokenEvent(BaseModel):
"""Only emitted when stream_tokens is enabled."""
type: Literal["token"] = "token"
bot: str
token: str
turn: int
class TurnEndEvent(BaseModel):
type: Literal["turn_end"] = "turn_end"
bot: str
turn: int
tokens: int
class TalkerMessageEvent(BaseModel):
type: Literal["talker_message"] = "talker_message"
talker_id: str
talker_name: str
content: str
turn: int
class MemberJoinedEvent(BaseModel):
type: Literal["member_joined"] = "member_joined"
role: Literal["talker", "observer"]
class MemberLeftEvent(BaseModel):
type: Literal["member_left"] = "member_left"
role: Literal["talker", "observer"]
class SessionPausedEvent(BaseModel):
type: Literal["session_paused"] = "session_paused"
class SessionResumedEvent(BaseModel):
type: Literal["session_resumed"] = "session_resumed"
class SessionEndEvent(BaseModel):
type: Literal["session_end"] = "session_end"
reason: Literal["max_turns", "max_time", "max_context", "orchestrator", "client_request"]
class ErrorEvent(BaseModel):
type: Literal["error"] = "error"
message: str
class DebugEvent(BaseModel):
"""Only emitted when debug mode is active."""
type: Literal["debug"] = "debug"
category: str
data: dict[str, Any]