Sregmi12334's picture
Update supervisor.py
6d801b1 verified
Raw
History Blame Contribute Delete
3.34 kB
"""
Supervisor (orchestrator) agent built with LangGraph.
Routes requests to:
β€’ "summariser" β†’ PaperSummarizerAgent
β€’ "code_explainer" β†’ CodeExplainerAgent
β€’ "FINISH" β†’ return final answer
"""
from __future__ import annotations
import operator
from typing import Annotated, Literal, TypedDict
from langchain_core.messages import AIMessage, BaseMessage, SystemMessage
from langchain_openai import ChatOpenAI
from langchain_groq import ChatGroq
from langgraph.graph import END, StateGraph
from agents import build_code_explainer, build_paper_summariser
class SupervisorState(TypedDict):
messages: Annotated[list[BaseMessage], operator.add]
next_agent: str
iteration: int
_SUPERVISOR_SYSTEM = """
You are a research orchestrator that coordinates two specialist agents:
β€’ summariser – fetches and summarises research papers (arXiv, PDF)
β€’ code_explainer – finds GitHub repos linked in the paper, explains algorithms,
and produces how-to-run guides
β€’ FINISH – use this when the task is fully complete
Given the conversation history, decide which agent to call next, OR output
FINISH if the task is fully complete.
Reply with EXACTLY one of: summariser | code_explainer | FINISH
No other text.
""".strip()
# _supervisor_llm = ChatOpenAI(model="gpt-4o", temperature=0)
_supervisor_llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
def supervisor_node(state: SupervisorState) -> SupervisorState:
messages = [SystemMessage(content=_SUPERVISOR_SYSTEM)] + state["messages"]
response = _supervisor_llm.invoke(messages)
next_agent = response.content.strip()
iteration = state.get("iteration", 0) + 1
if iteration > 6 or next_agent not in {"summariser", "code_explainer"}:
next_agent = "FINISH"
return {**state, "next_agent": next_agent, "iteration": iteration}
_summariser = build_paper_summariser()
_code_explainer = build_code_explainer()
def _run_agent(agent, state: SupervisorState) -> SupervisorState:
result = agent.invoke({"messages": state["messages"]})
agent_messages = result.get("messages", [])
last = next(
(m for m in reversed(agent_messages) if isinstance(m, AIMessage)),
AIMessage(content="(no response)"),
)
return {**state, "messages": state["messages"] + [last]}
def summariser_node(state: SupervisorState) -> SupervisorState:
return _run_agent(_summariser, state)
def code_explainer_node(state: SupervisorState) -> SupervisorState:
return _run_agent(_code_explainer, state)
def route(state: SupervisorState) -> Literal["summariser", "code_explainer", "__end__"]:
nxt = state.get("next_agent", "FINISH")
if nxt == "summariser":
return "summariser"
if nxt == "code_explainer":
return "code_explainer"
return END
def build_supervisor_graph() -> StateGraph:
graph = StateGraph(SupervisorState)
graph.add_node("supervisor", supervisor_node)
graph.add_node("summariser", summariser_node)
graph.add_node("code_explainer", code_explainer_node)
graph.set_entry_point("supervisor")
graph.add_conditional_edges("supervisor", route)
graph.add_edge("summariser", "supervisor")
graph.add_edge("code_explainer", "supervisor")
return graph.compile()