Implement Phase 1: LangGraph backend MVP
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
This commit is contained in:
parent
34dcfb3dcd
commit
797f02c74d
24 changed files with 1472 additions and 0 deletions
47
backend/state.py
Normal file
47
backend/state.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue