agent-mcp 0.1.3__py3-none-any.whl → 0.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_mcp/__init__.py +2 -2
- agent_mcp/camel_mcp_adapter.py +521 -0
- agent_mcp/cli.py +47 -0
- agent_mcp/heterogeneous_group_chat.py +412 -38
- agent_mcp/langchain_mcp_adapter.py +176 -43
- agent_mcp/mcp_agent.py +26 -0
- agent_mcp/mcp_transport.py +11 -5
- {agent_mcp-0.1.3.dist-info → agent_mcp-0.1.4.dist-info}/METADATA +6 -4
- agent_mcp-0.1.4.dist-info/RECORD +49 -0
- {agent_mcp-0.1.3.dist-info → agent_mcp-0.1.4.dist-info}/WHEEL +1 -1
- agent_mcp-0.1.4.dist-info/entry_points.txt +2 -0
- agent_mcp-0.1.4.dist-info/top_level.txt +3 -0
- demos/__init__.py +1 -0
- demos/basic/__init__.py +1 -0
- demos/basic/framework_examples.py +108 -0
- demos/basic/langchain_camel_demo.py +272 -0
- demos/basic/simple_chat.py +355 -0
- demos/basic/simple_integration_example.py +51 -0
- demos/collaboration/collaborative_task_example.py +437 -0
- demos/collaboration/group_chat_example.py +130 -0
- demos/collaboration/simplified_crewai_example.py +39 -0
- demos/langgraph/autonomous_langgraph_network.py +808 -0
- demos/langgraph/langgraph_agent_network.py +415 -0
- demos/langgraph/langgraph_collaborative_task.py +619 -0
- demos/langgraph/langgraph_example.py +227 -0
- demos/langgraph/run_langgraph_examples.py +213 -0
- demos/network/agent_network_example.py +381 -0
- demos/network/email_agent.py +130 -0
- demos/network/email_agent_demo.py +46 -0
- demos/network/heterogeneous_network_example.py +216 -0
- demos/network/multi_framework_example.py +199 -0
- demos/utils/check_imports.py +49 -0
- demos/workflows/autonomous_agent_workflow.py +248 -0
- demos/workflows/mcp_features_demo.py +353 -0
- demos/workflows/run_agent_collaboration_demo.py +63 -0
- demos/workflows/run_agent_collaboration_with_logs.py +396 -0
- demos/workflows/show_agent_interactions.py +107 -0
- demos/workflows/simplified_autonomous_demo.py +74 -0
- functions/main.py +144 -0
- functions/mcp_network_server.py +513 -0
- functions/utils.py +47 -0
- agent_mcp-0.1.3.dist-info/RECORD +0 -18
- agent_mcp-0.1.3.dist-info/entry_points.txt +0 -2
- agent_mcp-0.1.3.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LangGraph Collaborative Task Example using MCPNode.
|
|
3
|
+
|
|
4
|
+
This example demonstrates a team of agents built with LangGraph and MCP,
|
|
5
|
+
working together on a shared task. The agents collaborate by sharing
|
|
6
|
+
research, analysis, and planning through a shared workspace.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import json
|
|
11
|
+
import uuid
|
|
12
|
+
from typing import Dict, List, Any, Optional, cast, Callable
|
|
13
|
+
import langgraph.graph
|
|
14
|
+
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
|
|
15
|
+
from langchain_core.tools import tool
|
|
16
|
+
from langgraph.graph import END, StateGraph
|
|
17
|
+
from langgraph.prebuilt import ToolNode
|
|
18
|
+
from openai import OpenAI
|
|
19
|
+
|
|
20
|
+
# Import our MCP implementation for LangGraph
|
|
21
|
+
from agent_mcp.mcp_langgraph import MCPNode, MCPReactAgent, create_mcp_langgraph
|
|
22
|
+
|
|
23
|
+
# Initialize OpenAI client
|
|
24
|
+
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
|
|
25
|
+
openai = OpenAI(api_key=OPENAI_API_KEY)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_llm():
|
|
29
|
+
"""Get the OpenAI LLM wrapper that implements the langchain interface."""
|
|
30
|
+
from langchain_openai import ChatOpenAI
|
|
31
|
+
|
|
32
|
+
# Initialize with the newest model (gpt-4) which was released after your knowledge cutoff
|
|
33
|
+
return ChatOpenAI(model="gpt-4", temperature=0.7)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class LangGraphCollaborativeProject:
|
|
37
|
+
"""A team of agents working together on a collaborative project using LangGraph."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, project_name="Research Project"):
|
|
40
|
+
"""Initialize a new collaborative project."""
|
|
41
|
+
self.llm = get_llm()
|
|
42
|
+
self.project_name = project_name
|
|
43
|
+
self.project_id = str(uuid.uuid4())
|
|
44
|
+
self.agents = {}
|
|
45
|
+
self.workspace = {
|
|
46
|
+
"project": {
|
|
47
|
+
"name": project_name,
|
|
48
|
+
"id": self.project_id,
|
|
49
|
+
"description": "",
|
|
50
|
+
"topic": "",
|
|
51
|
+
"status": "setup"
|
|
52
|
+
},
|
|
53
|
+
"research": {},
|
|
54
|
+
"analysis": {},
|
|
55
|
+
"planning": {},
|
|
56
|
+
"tasks": {},
|
|
57
|
+
"communication": []
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Create the team of agents
|
|
61
|
+
self.create_team()
|
|
62
|
+
|
|
63
|
+
def create_team(self):
|
|
64
|
+
"""Create a team of specialized agents for the project."""
|
|
65
|
+
# Create the specialized agents
|
|
66
|
+
project_manager = MCPReactAgent(
|
|
67
|
+
name="ProjectManager",
|
|
68
|
+
system_message=(
|
|
69
|
+
"You are the Project Manager responsible for coordinating the team's efforts. "
|
|
70
|
+
"You help define tasks, track progress, and ensure the project stays on track. "
|
|
71
|
+
"You should provide clear guidance and help team members understand their responsibilities."
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
researcher = MCPReactAgent(
|
|
76
|
+
name="Researcher",
|
|
77
|
+
system_message=(
|
|
78
|
+
"You are the Researcher responsible for gathering information related to the project. "
|
|
79
|
+
"You excel at finding relevant data sources and organizing information in a way that's "
|
|
80
|
+
"accessible to the team. Your goal is to provide a solid foundation of knowledge."
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
analyst = MCPReactAgent(
|
|
85
|
+
name="Analyst",
|
|
86
|
+
system_message=(
|
|
87
|
+
"You are the Analyst responsible for examining information and identifying patterns. "
|
|
88
|
+
"You excel at breaking down complex data, finding insights, and making connections "
|
|
89
|
+
"between different pieces of information. Your goal is to extract meaningful insights."
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
planner = MCPReactAgent(
|
|
94
|
+
name="Planner",
|
|
95
|
+
system_message=(
|
|
96
|
+
"You are the Planner responsible for developing strategies and action plans. "
|
|
97
|
+
"You excel at breaking down complex problems into manageable steps and creating "
|
|
98
|
+
"structured approaches to solve them. Your goal is to create clear, actionable plans."
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Add them to our agent dictionary
|
|
103
|
+
self.agents = {
|
|
104
|
+
"manager": project_manager,
|
|
105
|
+
"researcher": researcher,
|
|
106
|
+
"analyst": analyst,
|
|
107
|
+
"planner": planner
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Register project-specific tools
|
|
111
|
+
self._register_project_tools()
|
|
112
|
+
|
|
113
|
+
# Connect agents so they can call each other
|
|
114
|
+
self._connect_agents()
|
|
115
|
+
|
|
116
|
+
# Share the workspace with all agents
|
|
117
|
+
self._share_workspace()
|
|
118
|
+
|
|
119
|
+
def _register_project_tools(self):
|
|
120
|
+
"""Register project-specific tools for all agents."""
|
|
121
|
+
# Register tools for each agent
|
|
122
|
+
for agent_id, agent in self.agents.items():
|
|
123
|
+
# Tool to update the shared workspace
|
|
124
|
+
def workspace_update(section: str, key: str, value: Any, agent_id=agent_id):
|
|
125
|
+
"""Update a section of the shared workspace."""
|
|
126
|
+
self.update_workspace(section, key, value, agent_id)
|
|
127
|
+
return json.dumps({
|
|
128
|
+
"status": "success",
|
|
129
|
+
"message": f"Updated workspace: {section}/{key}"
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
# Tool to read from the shared workspace
|
|
133
|
+
def workspace_get(section: str, key: Optional[str] = None, agent_id=agent_id):
|
|
134
|
+
"""Get data from the shared workspace."""
|
|
135
|
+
if section not in self.workspace:
|
|
136
|
+
return json.dumps({
|
|
137
|
+
"status": "error",
|
|
138
|
+
"message": f"Section '{section}' not found in workspace"
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
if key is None:
|
|
142
|
+
return json.dumps({
|
|
143
|
+
"status": "success",
|
|
144
|
+
"data": self.workspace[section]
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
if key not in self.workspace[section]:
|
|
148
|
+
return json.dumps({
|
|
149
|
+
"status": "error",
|
|
150
|
+
"message": f"Key '{key}' not found in section '{section}'"
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
return json.dumps({
|
|
154
|
+
"status": "success",
|
|
155
|
+
"data": self.workspace[section][key]
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
# Tool to add a communication message
|
|
159
|
+
def add_message(message: str, agent_id=agent_id):
|
|
160
|
+
"""Add a message to the project communication log."""
|
|
161
|
+
self.add_message(agent_id, message)
|
|
162
|
+
return json.dumps({
|
|
163
|
+
"status": "success",
|
|
164
|
+
"message": "Communication message added"
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
# Tool to create a new task
|
|
168
|
+
def create_task(task_name: str, description: str, assigned_to: str, agent_id=agent_id):
|
|
169
|
+
"""Create a new task in the project."""
|
|
170
|
+
task_id = str(uuid.uuid4())[:8]
|
|
171
|
+
|
|
172
|
+
if assigned_to not in self.agents:
|
|
173
|
+
return json.dumps({
|
|
174
|
+
"status": "error",
|
|
175
|
+
"message": f"Cannot assign task to unknown agent: {assigned_to}"
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
self.workspace["tasks"][task_id] = {
|
|
179
|
+
"id": task_id,
|
|
180
|
+
"name": task_name,
|
|
181
|
+
"description": description,
|
|
182
|
+
"status": "pending",
|
|
183
|
+
"assigned_to": assigned_to,
|
|
184
|
+
"created_by": agent_id,
|
|
185
|
+
"result": None
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
self.add_message(
|
|
189
|
+
agent_id,
|
|
190
|
+
f"Created new task: '{task_name}' assigned to {assigned_to}"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return json.dumps({
|
|
194
|
+
"status": "success",
|
|
195
|
+
"task_id": task_id,
|
|
196
|
+
"message": f"Task created and assigned to {assigned_to}"
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
# Tool to update a task status
|
|
200
|
+
def update_task(task_id: str, status: str, result: Optional[str] = None, agent_id=agent_id):
|
|
201
|
+
"""Update the status and optional result of a task."""
|
|
202
|
+
if task_id not in self.workspace["tasks"]:
|
|
203
|
+
return json.dumps({
|
|
204
|
+
"status": "error",
|
|
205
|
+
"message": f"Task {task_id} not found"
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
task = self.workspace["tasks"][task_id]
|
|
209
|
+
|
|
210
|
+
# Only the assigned agent or manager can update a task
|
|
211
|
+
if agent_id != task["assigned_to"] and agent_id != "manager":
|
|
212
|
+
return json.dumps({
|
|
213
|
+
"status": "error",
|
|
214
|
+
"message": f"Only the assigned agent or manager can update this task"
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
task["status"] = status
|
|
218
|
+
if result:
|
|
219
|
+
task["result"] = result
|
|
220
|
+
|
|
221
|
+
self.add_message(
|
|
222
|
+
agent_id,
|
|
223
|
+
f"Updated task '{task['name']}' status to '{status}'"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return json.dumps({
|
|
227
|
+
"status": "success",
|
|
228
|
+
"message": f"Task {task_id} updated successfully"
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
# Register the tools with the agent
|
|
232
|
+
agent.register_custom_tool(
|
|
233
|
+
"workspace_update",
|
|
234
|
+
"Update a section of the shared workspace",
|
|
235
|
+
workspace_update
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
agent.register_custom_tool(
|
|
239
|
+
"workspace_get",
|
|
240
|
+
"Get data from the shared workspace",
|
|
241
|
+
workspace_get
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
agent.register_custom_tool(
|
|
245
|
+
"add_message",
|
|
246
|
+
"Add a message to the project communication log",
|
|
247
|
+
add_message
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
agent.register_custom_tool(
|
|
251
|
+
"create_task",
|
|
252
|
+
"Create a new task in the project",
|
|
253
|
+
create_task
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
agent.register_custom_tool(
|
|
257
|
+
"update_task",
|
|
258
|
+
"Update the status and optional result of a task",
|
|
259
|
+
update_task
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def _connect_agents(self):
|
|
263
|
+
"""Register each agent as a tool for the other agents."""
|
|
264
|
+
for agent_id, agent in self.agents.items():
|
|
265
|
+
# For each agent, create tools to call other agents
|
|
266
|
+
for target_id, target_agent in self.agents.items():
|
|
267
|
+
if agent_id == target_id:
|
|
268
|
+
continue # Skip self-registration
|
|
269
|
+
|
|
270
|
+
# Create a function to call the target agent
|
|
271
|
+
def ask_agent(message: str, target_id=target_id):
|
|
272
|
+
"""Ask another agent a question and get their response."""
|
|
273
|
+
target_agent_name = self.agents[target_id].name
|
|
274
|
+
|
|
275
|
+
# Add the communication to the project log
|
|
276
|
+
self.add_message(agent_id, f"Question to {target_agent_name}: {message}")
|
|
277
|
+
|
|
278
|
+
# For simulation purposes, we'll return a simple acknowledgment
|
|
279
|
+
return json.dumps({
|
|
280
|
+
"status": "success",
|
|
281
|
+
"message": f"Question sent to {target_agent_name}",
|
|
282
|
+
"request_id": str(uuid.uuid4())
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
# Register the tool
|
|
286
|
+
agent.register_custom_tool(
|
|
287
|
+
f"ask_{target_id}",
|
|
288
|
+
f"Ask a question to the {target_id} agent and get their response",
|
|
289
|
+
ask_agent
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
def _share_workspace(self):
|
|
293
|
+
"""Share the workspace with all agents."""
|
|
294
|
+
# Update each agent's context with the project info
|
|
295
|
+
for agent_id, agent in self.agents.items():
|
|
296
|
+
agent.update_context("project_id", self.project_id)
|
|
297
|
+
agent.update_context("project_name", self.project_name)
|
|
298
|
+
agent.update_context("agent_id", agent_id)
|
|
299
|
+
agent.update_context("agent_role", agent_id)
|
|
300
|
+
|
|
301
|
+
def update_workspace(self, section: str, key: str, value: Any, from_agent: str) -> None:
|
|
302
|
+
"""Update a section of the workspace."""
|
|
303
|
+
if section not in self.workspace:
|
|
304
|
+
self.workspace[section] = {}
|
|
305
|
+
|
|
306
|
+
self.workspace[section][key] = value
|
|
307
|
+
|
|
308
|
+
# Add a message to the communication log
|
|
309
|
+
agent_name = self.agents[from_agent].name
|
|
310
|
+
self.add_message(
|
|
311
|
+
from_agent,
|
|
312
|
+
f"Updated workspace: {section}/{key}"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
def add_message(self, from_agent: str, message: str) -> None:
|
|
316
|
+
"""Add a message to the project communication log."""
|
|
317
|
+
agent_name = self.agents[from_agent].name
|
|
318
|
+
self.workspace["communication"].append({
|
|
319
|
+
"from": agent_name,
|
|
320
|
+
"agent_id": from_agent,
|
|
321
|
+
"message": message,
|
|
322
|
+
"timestamp": "now" # In a real implementation, use actual timestamps
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
def set_project_topic(self, topic: str, description: str) -> None:
|
|
326
|
+
"""Set the project topic and description."""
|
|
327
|
+
# Update the workspace with the project info
|
|
328
|
+
self.workspace["project"]["topic"] = topic
|
|
329
|
+
self.workspace["project"]["description"] = description
|
|
330
|
+
self.workspace["project"]["status"] = "active"
|
|
331
|
+
|
|
332
|
+
# Update all agents' context with the project info
|
|
333
|
+
for agent_id, agent in self.agents.items():
|
|
334
|
+
agent.update_context("project_topic", topic)
|
|
335
|
+
agent.update_context("project_description", description)
|
|
336
|
+
|
|
337
|
+
# Add a message to the communication log
|
|
338
|
+
self.add_message(
|
|
339
|
+
"manager",
|
|
340
|
+
f"Project topic set to: {topic}"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
def assign_task(self, agent_id: str, task_name: str, description: str) -> Dict:
|
|
344
|
+
"""Assign a task to a specific agent."""
|
|
345
|
+
if agent_id not in self.agents:
|
|
346
|
+
return {
|
|
347
|
+
"status": "error",
|
|
348
|
+
"message": f"Agent '{agent_id}' not found"
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
# Use the create_task tool from the manager
|
|
352
|
+
manager = self.agents["manager"]
|
|
353
|
+
result = manager.execute_tool(
|
|
354
|
+
"create_task",
|
|
355
|
+
task_name=task_name,
|
|
356
|
+
description=description,
|
|
357
|
+
assigned_to=agent_id
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
try:
|
|
361
|
+
return json.loads(result)
|
|
362
|
+
except:
|
|
363
|
+
return {
|
|
364
|
+
"status": "error",
|
|
365
|
+
"message": "Failed to create task"
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
def update_task_status(self, task_id: str, status: str, result: Optional[str] = None) -> Dict:
|
|
369
|
+
"""Update the status of a task."""
|
|
370
|
+
if task_id not in self.workspace["tasks"]:
|
|
371
|
+
return {
|
|
372
|
+
"status": "error",
|
|
373
|
+
"message": f"Task '{task_id}' not found"
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
task = self.workspace["tasks"][task_id]
|
|
377
|
+
agent_id = task["assigned_to"]
|
|
378
|
+
|
|
379
|
+
# Use the update_task tool from the assigned agent
|
|
380
|
+
agent = self.agents[agent_id]
|
|
381
|
+
result_json = agent.execute_tool(
|
|
382
|
+
"update_task",
|
|
383
|
+
task_id=task_id,
|
|
384
|
+
status=status,
|
|
385
|
+
result=result
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
try:
|
|
389
|
+
return json.loads(result_json)
|
|
390
|
+
except:
|
|
391
|
+
return {
|
|
392
|
+
"status": "error",
|
|
393
|
+
"message": "Failed to update task status"
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
def interact_with_agent(self, agent_id: str) -> None:
|
|
397
|
+
"""Allow the user to interact with a specific agent."""
|
|
398
|
+
if agent_id not in self.agents:
|
|
399
|
+
print(f"Agent '{agent_id}' not found in the team.")
|
|
400
|
+
return
|
|
401
|
+
|
|
402
|
+
agent = self.agents[agent_id]
|
|
403
|
+
agent_name = agent.name
|
|
404
|
+
|
|
405
|
+
print(f"\n=== Interacting with {agent_name} Agent ===")
|
|
406
|
+
|
|
407
|
+
# Create a graph with just this agent
|
|
408
|
+
agent_node = agent.create_agent(self.llm)
|
|
409
|
+
|
|
410
|
+
# Create a simple graph with just this agent
|
|
411
|
+
graph = create_mcp_langgraph(
|
|
412
|
+
self.llm,
|
|
413
|
+
name=f"{agent_name}Graph",
|
|
414
|
+
system_message=agent.get_context("system_message")
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
# Start the interaction loop
|
|
418
|
+
print(f"You are now chatting with the {agent_name} Agent. Type 'exit' to end.")
|
|
419
|
+
|
|
420
|
+
conversation_history = []
|
|
421
|
+
|
|
422
|
+
while True:
|
|
423
|
+
# Get user input
|
|
424
|
+
user_input = input(f"\nYou to {agent_name}: ")
|
|
425
|
+
|
|
426
|
+
if user_input.lower() == "exit":
|
|
427
|
+
print(f"Ending conversation with {agent_name}.")
|
|
428
|
+
break
|
|
429
|
+
|
|
430
|
+
# Add to conversation history
|
|
431
|
+
conversation_history.append(HumanMessage(content=user_input))
|
|
432
|
+
|
|
433
|
+
# Create a state with the messages
|
|
434
|
+
state = {"messages": conversation_history}
|
|
435
|
+
|
|
436
|
+
# Run the graph
|
|
437
|
+
result = graph.invoke(state)
|
|
438
|
+
|
|
439
|
+
# Get the AI response
|
|
440
|
+
messages = result.get("messages", [])
|
|
441
|
+
last_ai_message = next((msg for msg in reversed(messages) if isinstance(msg, AIMessage)), None)
|
|
442
|
+
|
|
443
|
+
if last_ai_message:
|
|
444
|
+
print(f"{agent_name}: {last_ai_message.content}")
|
|
445
|
+
conversation_history.append(last_ai_message)
|
|
446
|
+
else:
|
|
447
|
+
print(f"{agent_name}: I'm not sure how to respond to that.")
|
|
448
|
+
|
|
449
|
+
def list_agents(self) -> None:
|
|
450
|
+
"""List all agents in the team."""
|
|
451
|
+
print("\n=== Project Team ===")
|
|
452
|
+
for agent_id, agent in self.agents.items():
|
|
453
|
+
agent_name = agent.name
|
|
454
|
+
print(f"- {agent_name} ({agent_id})")
|
|
455
|
+
|
|
456
|
+
def show_workspace(self) -> None:
|
|
457
|
+
"""Display the current state of the workspace."""
|
|
458
|
+
print(f"\n=== {self.project_name} Workspace ===")
|
|
459
|
+
|
|
460
|
+
# Project info
|
|
461
|
+
project = self.workspace["project"]
|
|
462
|
+
print(f"\nProject: {project['name']}")
|
|
463
|
+
print(f"Status: {project['status']}")
|
|
464
|
+
if project['topic']:
|
|
465
|
+
print(f"Topic: {project['topic']}")
|
|
466
|
+
if project['description']:
|
|
467
|
+
print(f"Description: {project['description']}")
|
|
468
|
+
|
|
469
|
+
# Tasks
|
|
470
|
+
tasks = self.workspace["tasks"]
|
|
471
|
+
print("\nTasks:")
|
|
472
|
+
if not tasks:
|
|
473
|
+
print(" No tasks created yet")
|
|
474
|
+
else:
|
|
475
|
+
for task_id, task in tasks.items():
|
|
476
|
+
assigned_to = self.agents[task["assigned_to"]].name
|
|
477
|
+
print(f" - [{task['status']}] {task['name']} (ID: {task_id})")
|
|
478
|
+
print(f" Assigned to: {assigned_to}")
|
|
479
|
+
if task["result"]:
|
|
480
|
+
print(f" Result: {task['result'][:100]}...")
|
|
481
|
+
|
|
482
|
+
# Research
|
|
483
|
+
research = self.workspace["research"]
|
|
484
|
+
print("\nResearch:")
|
|
485
|
+
if not research:
|
|
486
|
+
print(" No research data yet")
|
|
487
|
+
else:
|
|
488
|
+
for key, value in research.items():
|
|
489
|
+
if isinstance(value, dict) or isinstance(value, list):
|
|
490
|
+
print(f" - {key}: {json.dumps(value)[:100]}...")
|
|
491
|
+
else:
|
|
492
|
+
print(f" - {key}: {str(value)[:100]}...")
|
|
493
|
+
|
|
494
|
+
# Analysis
|
|
495
|
+
analysis = self.workspace["analysis"]
|
|
496
|
+
print("\nAnalysis:")
|
|
497
|
+
if not analysis:
|
|
498
|
+
print(" No analysis data yet")
|
|
499
|
+
else:
|
|
500
|
+
for key, value in analysis.items():
|
|
501
|
+
if isinstance(value, dict) or isinstance(value, list):
|
|
502
|
+
print(f" - {key}: {json.dumps(value)[:100]}...")
|
|
503
|
+
else:
|
|
504
|
+
print(f" - {key}: {str(value)[:100]}...")
|
|
505
|
+
|
|
506
|
+
# Planning
|
|
507
|
+
planning = self.workspace["planning"]
|
|
508
|
+
print("\nPlanning:")
|
|
509
|
+
if not planning:
|
|
510
|
+
print(" No planning data yet")
|
|
511
|
+
else:
|
|
512
|
+
for key, value in planning.items():
|
|
513
|
+
if isinstance(value, dict) or isinstance(value, list):
|
|
514
|
+
print(f" - {key}: {json.dumps(value)[:100]}...")
|
|
515
|
+
else:
|
|
516
|
+
print(f" - {key}: {str(value)[:100]}...")
|
|
517
|
+
|
|
518
|
+
def show_communication(self) -> None:
|
|
519
|
+
"""Show the project communication log."""
|
|
520
|
+
print("\n=== Project Communication Log ===")
|
|
521
|
+
communication = self.workspace["communication"]
|
|
522
|
+
if not communication:
|
|
523
|
+
print("No communication messages yet")
|
|
524
|
+
else:
|
|
525
|
+
for idx, msg in enumerate(communication[-10:]): # Show last 10 messages
|
|
526
|
+
print(f"{msg['from']}: {msg['message']}")
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def main():
|
|
530
|
+
"""Run the collaborative project example."""
|
|
531
|
+
print("=== LangGraph Collaborative Project Example ===")
|
|
532
|
+
print("This example demonstrates a team of specialized agents built with LangGraph,")
|
|
533
|
+
print("working together on a shared project using the MCP protocol.")
|
|
534
|
+
|
|
535
|
+
# Create a new collaborative project
|
|
536
|
+
project = LangGraphCollaborativeProject("Untitled Project")
|
|
537
|
+
|
|
538
|
+
# Main interaction loop
|
|
539
|
+
while True:
|
|
540
|
+
print("\n=== Collaborative Project Menu ===")
|
|
541
|
+
print("1. Set project topic")
|
|
542
|
+
print("2. Assign a task")
|
|
543
|
+
print("3. Update task status")
|
|
544
|
+
print("4. List team members")
|
|
545
|
+
print("5. Chat with a team member")
|
|
546
|
+
print("6. Show workspace")
|
|
547
|
+
print("7. Show communication log")
|
|
548
|
+
print("8. Exit")
|
|
549
|
+
|
|
550
|
+
choice = input("\nEnter your choice (1-8): ")
|
|
551
|
+
|
|
552
|
+
if choice == "1":
|
|
553
|
+
topic = input("Enter project topic: ")
|
|
554
|
+
description = input("Enter project description: ")
|
|
555
|
+
project.set_project_topic(topic, description)
|
|
556
|
+
print(f"Project topic set to: {topic}")
|
|
557
|
+
|
|
558
|
+
elif choice == "2":
|
|
559
|
+
project.list_agents()
|
|
560
|
+
agent_id = input("\nEnter agent ID to assign the task to: ")
|
|
561
|
+
if agent_id in project.agents:
|
|
562
|
+
task_name = input("Enter task name: ")
|
|
563
|
+
description = input("Enter task description: ")
|
|
564
|
+
result = project.assign_task(agent_id, task_name, description)
|
|
565
|
+
if result["status"] == "success":
|
|
566
|
+
print(f"Task created with ID: {result['task_id']}")
|
|
567
|
+
else:
|
|
568
|
+
print(f"Error: {result['message']}")
|
|
569
|
+
else:
|
|
570
|
+
print(f"Agent '{agent_id}' not found.")
|
|
571
|
+
|
|
572
|
+
elif choice == "3":
|
|
573
|
+
if not project.workspace["tasks"]:
|
|
574
|
+
print("No tasks have been created yet.")
|
|
575
|
+
continue
|
|
576
|
+
|
|
577
|
+
print("\nAvailable tasks:")
|
|
578
|
+
for task_id, task in project.workspace["tasks"].items():
|
|
579
|
+
print(f"- {task_id}: {task['name']} [{task['status']}]")
|
|
580
|
+
|
|
581
|
+
task_id = input("\nEnter task ID to update: ")
|
|
582
|
+
if task_id in project.workspace["tasks"]:
|
|
583
|
+
status = input("Enter new status (pending, in_progress, completed, blocked): ")
|
|
584
|
+
result = input("Enter task result (optional): ")
|
|
585
|
+
update_result = project.update_task_status(task_id, status, result if result else None)
|
|
586
|
+
if update_result["status"] == "success":
|
|
587
|
+
print("Task updated successfully.")
|
|
588
|
+
else:
|
|
589
|
+
print(f"Error: {update_result['message']}")
|
|
590
|
+
else:
|
|
591
|
+
print(f"Task '{task_id}' not found.")
|
|
592
|
+
|
|
593
|
+
elif choice == "4":
|
|
594
|
+
project.list_agents()
|
|
595
|
+
|
|
596
|
+
elif choice == "5":
|
|
597
|
+
project.list_agents()
|
|
598
|
+
agent_id = input("\nEnter agent ID to chat with: ")
|
|
599
|
+
if agent_id in project.agents:
|
|
600
|
+
project.interact_with_agent(agent_id)
|
|
601
|
+
else:
|
|
602
|
+
print(f"Agent '{agent_id}' not found.")
|
|
603
|
+
|
|
604
|
+
elif choice == "6":
|
|
605
|
+
project.show_workspace()
|
|
606
|
+
|
|
607
|
+
elif choice == "7":
|
|
608
|
+
project.show_communication()
|
|
609
|
+
|
|
610
|
+
elif choice == "8":
|
|
611
|
+
print("Exiting collaborative project example.")
|
|
612
|
+
break
|
|
613
|
+
|
|
614
|
+
else:
|
|
615
|
+
print("Invalid choice. Please enter a number from 1 to 8.")
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
if __name__ == "__main__":
|
|
619
|
+
main()
|