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
63
backend/agents/writer_agent.py
Normal file
63
backend/agents/writer_agent.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
"""
|
||||
Writer Agent Node — final polishing of an approved draft.
|
||||
|
||||
This agent receives a critic-approved draft and produces the final,
|
||||
publication-ready version with polished formatting and language.
|
||||
"""
|
||||
|
||||
import os
|
||||
from langchain_anthropic import ChatAnthropic
|
||||
from langchain_core.messages import HumanMessage, SystemMessage
|
||||
|
||||
from state import CouncilState
|
||||
|
||||
|
||||
_SYSTEM_PROMPT = """You are the Writer AI in a council of expert AIs.
|
||||
You receive a draft that has already been approved for quality by the Critic AI.
|
||||
Your job is to give it a final professional polish:
|
||||
|
||||
- Improve sentence flow and readability
|
||||
- Ensure consistent formatting (headers, bullet points, paragraphs)
|
||||
- Fix any grammatical or stylistic issues
|
||||
- Do NOT change the factual content or overall structure
|
||||
- Preserve all key information from the draft
|
||||
|
||||
Return only the polished document — no meta-commentary."""
|
||||
|
||||
|
||||
def writer_agent_node(state: CouncilState) -> dict:
|
||||
"""
|
||||
LangGraph node function for the Writer Agent.
|
||||
|
||||
Receives the approved current_draft and returns a polished final version.
|
||||
|
||||
Args:
|
||||
state: The current CouncilState.
|
||||
|
||||
Returns:
|
||||
A dict with the final polished current_draft and updated messages.
|
||||
"""
|
||||
llm = ChatAnthropic(
|
||||
model="claude-3-5-sonnet-20241022",
|
||||
api_key=os.environ.get("ANTHROPIC_API_KEY"),
|
||||
temperature=0.4,
|
||||
max_tokens=4096,
|
||||
)
|
||||
|
||||
system_msg = SystemMessage(content=_SYSTEM_PROMPT)
|
||||
user_msg = HumanMessage(
|
||||
content=(
|
||||
f"Please give a final professional polish to this approved document "
|
||||
f"on the topic '{state['input_topic']}':\n\n"
|
||||
f"{state['current_draft']}"
|
||||
)
|
||||
)
|
||||
|
||||
response = llm.invoke([system_msg, user_msg])
|
||||
|
||||
return {
|
||||
"current_draft": response.content,
|
||||
"messages": [system_msg, user_msg, response],
|
||||
"active_node": "writer_agent",
|
||||
"route_decision": "done",
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue