MatteoMass's picture
removed the tokens from env
9ad58d0
import os
import pprint
import uuid
from dotenv import load_dotenv
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import ToolNode
from langgraph.graph import MessagesState, END, StateGraph
from langchain_core.messages import HumanMessage
from langgraph.checkpoint.memory import MemorySaver
from pmcp.agents.executor import ExecutorAgent
from pmcp.agents.trello_agent import TrelloAgent
from pmcp.agents.github_agent import GithubAgent
from pmcp.agents.planner import PlannerAgent
from pmcp.nodes.human_interrupt_node import HumanInterruptNode
from pmcp.nodes.human_resume_node import HumanResumeNode
from pmcp.models.state import PlanningState
load_dotenv()
async def call_llm(llm_with_tools: ChatOpenAI, state: MessagesState):
response = llm_with_tools.invoke(state["messages"])
return {"messages": [response]}
async def main():
mcp_client_trello = MultiServerMCPClient(
{
"trello": {
"command": "python",
"args": ["pmcp/mcp_server/trello_server/mcp_trello_main.py"],
"transport": "stdio",
}
}
)
mcp_client_github = MultiServerMCPClient(
{
"github": {
"command": "python",
"args": ["pmcp/mcp_server/github_server/mcp_github_main.py"],
"transport": "stdio",
}
}
)
memory = MemorySaver()
trello_tools = await mcp_client_trello.get_tools()
github_tools = await mcp_client_github.get_tools()
tool_node = ToolNode(github_tools + trello_tools)
llm = ChatOpenAI(
model="Qwen/Qwen2.5-32B-Instruct",
temperature=0.0,
api_key=os.getenv("NEBIUS_API_KEY"),
base_url="https://api.studio.nebius.com/v1/",
)
trello_agent = TrelloAgent(
tools=trello_tools,
llm=llm,
)
github_agent = GithubAgent(llm=llm, tools=github_tools)
planner_agent = PlannerAgent(
llm=llm,
)
executor_agent = ExecutorAgent(llm=llm)
human_interrupt_node = HumanInterruptNode(
llm=llm,
)
human_resume_node = HumanResumeNode(llm=llm)
graph = StateGraph(MessagesState)
graph.add_node(planner_agent.agent.agent_name, planner_agent.acall_planner_agent)
graph.add_node(trello_agent.agent.agent_name, trello_agent.acall_trello_agent)
graph.add_node(github_agent.agent.agent_name, github_agent.acall_github_agent)
graph.add_node(executor_agent.agent.agent_name, executor_agent.acall_executor_agent)
graph.add_node("tool", tool_node)
graph.add_node("human_interrupt", human_interrupt_node.call_human_interrupt_agent)
graph.set_entry_point(planner_agent.agent.agent_name)
def should_continue(state: PlanningState):
last_message = state.messages[-1]
if last_message.tool_calls:
return "human_interrupt"
return executor_agent.agent.agent_name
def execute_agent(state: PlanningState):
if state.current_step:
return state.current_step.agent
return END
graph.add_conditional_edges(trello_agent.agent.agent_name, should_continue)
graph.add_conditional_edges(github_agent.agent.agent_name, should_continue)
graph.add_conditional_edges(executor_agent.agent.agent_name, execute_agent)
graph.add_edge("tool", trello_agent.agent.agent_name)
graph.add_edge("tool", github_agent.agent.agent_name)
graph.add_edge(planner_agent.agent.agent_name, executor_agent.agent.agent_name)
app = graph.compile(checkpointer=memory)
app.get_graph(xray=True).draw_mermaid()
user_input = input("user >")
config = {
"configurable": {"thread_id": f"{str(uuid.uuid4())}"},
"recursion_limit": 100,
}
is_message_command = False
while user_input.lower() != "q":
if is_message_command:
app_input = human_resume_node.call_human_interrupt_agent(
user_input
)
is_message_command = False
else:
app_input = {
"messages": [
HumanMessage(content=user_input),
]
}
async for res in app.astream(
app_input,
config=config,
stream_mode="values",
):
if "messages" in res:
pprint.pprint(res["messages"][-1])
else:
pprint.pprint(res["__interrupt__"][0])
is_message_command = True
pprint.pprint("-------------------------------------")
user_input = input("user >")
if __name__ == "__main__":
import asyncio
asyncio.run(main())