Sets up the full backend foundation for CouncilOS:
- CouncilState TypedDict with all required fields and LangGraph reducers
- Three agent nodes: master_agent (drafts), critic_agent (scores + routes),
writer_agent (final polish)
- LangGraph graph with cyclic rework loop: Master → Critic → (score < 8:
back to Master | score ≥ 8: Writer → END)
- Safety valve: MAX_ITERATIONS=5 prevents infinite loops
- FastAPI app with REST endpoints (POST /api/councils/run, GET /api/councils/run/{id})
and WebSocket endpoint (/ws/council/{run_id}) for real-time agent status events
- In-memory RunStore for Phase 1 (PostgreSQL-backed in Phase 3)
- pytest test suite: state, routing logic, critic parser, agent nodes, API endpoints
- .env.example, .gitignore, docker-compose.yml, Dockerfile
https://claude.ai/code/session_01RfMpt3TbMjZEtK3CAyP5iQ
47 lines
1.8 KiB
Python
47 lines
1.8 KiB
Python
"""
|
||
CouncilState — the central data structure passed between all agents in LangGraph.
|
||
|
||
All agents must read from and write to this TypedDict. Agents must not store
|
||
state internally; everything passes through CouncilState.
|
||
"""
|
||
|
||
from typing import Annotated, List, Optional
|
||
import operator
|
||
from typing_extensions import TypedDict
|
||
|
||
|
||
class CouncilState(TypedDict):
|
||
"""
|
||
The global state shared across all agents in a council run.
|
||
|
||
Fields:
|
||
input_topic: The user's original prompt or uploaded PDF content.
|
||
current_draft: The document currently being worked on.
|
||
feedback_history: All critic feedback accumulated across loop iterations.
|
||
Agents append here — never overwrite.
|
||
route_decision: Routing signal used by conditional edges.
|
||
Values: "rework" | "approve" | custom strings.
|
||
messages: LLM message history (system prompts + responses).
|
||
Uses operator.add reducer so messages accumulate.
|
||
iteration_count: Tracks how many rework loops have occurred.
|
||
critic_score: The numeric score (0–10) assigned by the critic agent.
|
||
run_id: Unique identifier for this council run (for WebSocket events).
|
||
active_node: Name of the currently executing agent node (for UI updates).
|
||
"""
|
||
|
||
input_topic: str
|
||
current_draft: str
|
||
feedback_history: Annotated[List[str], operator.add]
|
||
route_decision: str
|
||
messages: Annotated[list, operator.add]
|
||
iteration_count: int
|
||
critic_score: Optional[float]
|
||
run_id: str
|
||
active_node: str
|
||
|
||
|
||
# Approval threshold: critic score must reach this value to exit the loop
|
||
APPROVAL_THRESHOLD = 8.0
|
||
|
||
# Safety limit: maximum number of rework iterations before forcing approval
|
||
MAX_ITERATIONS = 5
|