Skip to content

Commit 95dd707

Browse files
committed
workforce added
1 parent fe9e5d4 commit 95dd707

File tree

6 files changed

+215
-15
lines changed

6 files changed

+215
-15
lines changed

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Why build AI agent with AgentX?
1717
- Support all running MCP (model context protocol).
1818
- Support RAG with built-in re-rank.
1919
- Multi-agent workforce orchestration.
20+
- Multiple agents working together with a designated manager agent.
21+
- Cross vendor LLM orchestration.
2022

2123
## Installation
2224

@@ -85,3 +87,50 @@ text=None cot=None botId='xxx'
8587
```
8688

8789
\*`cot` stands for chain-of-thoughts
90+
91+
### Workforce
92+
93+
A Workforce (team) consists of multiple agents working together with a designated manager agent.
94+
95+
```python
96+
from agentx import AgentX
97+
98+
client = AgentX(api_key="<your api key here>")
99+
100+
# Get the list of workforces/teams you have
101+
workforces = client.list_workforces()
102+
print(workforces)
103+
104+
# Get a specific workforce
105+
workforce = workforces[0] # or any specific workforce
106+
print(f"Workforce: {workforce.name}")
107+
print(f"Manager: {workforce.manager.name}")
108+
print(f"Agents: {[agent.name for agent in workforce.agents]}")
109+
```
110+
111+
#### Workforce Conversations
112+
113+
```python
114+
# Create a new conversation with the workforce
115+
conversation = workforce.new_conversation()
116+
117+
# List all existing conversations for the workforce
118+
conversations = workforce.list_conversations()
119+
print(conversations)
120+
```
121+
122+
#### Chat with Workforce
123+
124+
Chat with the entire workforce team and get streaming responses from all agents.
125+
126+
```python
127+
# Stream chat with the workforce
128+
response = workforce.chat_stream(conversation.id, "How can you help me with this project?")
129+
for chunk in response:
130+
if chunk.text:
131+
print(chunk.text, end="")
132+
if chunk.cot:
133+
print(f" [COT: {chunk.cot}]")
134+
```
135+
136+
The workforce chat allows you to leverage multiple specialized agents working together to provide comprehensive responses to your queries.

agentx/agentx.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from agentx.util import get_headers
77
from agentx.resources.agent import Agent
8+
from agentx.resources.workforce import Workforce
89

910

1011
class AgentX:
@@ -37,15 +38,29 @@ def list_agents(self) -> List[Agent]:
3738
response = requests.get(url, headers=get_headers())
3839
# Check if response was successful
3940
if response.status_code == 200:
40-
return [
41-
Agent(
42-
id=agent_res.get("_id"),
43-
name=agent_res.get("name"),
44-
avatar=agent_res.get("avatar"),
45-
createdAt=agent_res.get("createdAt"),
46-
updatedAt=agent_res.get("updatedAt"),
47-
)
48-
for agent_res in response.json()
49-
]
41+
return [Agent(**agent) for agent in response.json()]
5042
else:
5143
raise Exception(f"Failed to list agents: {response.reason}")
44+
45+
@staticmethod
46+
def list_workforces() -> List["Workforce"]:
47+
"""List all workforces/teams."""
48+
url = "https://api.agentx.so/api/v1/access/teams"
49+
response = requests.get(url, headers=get_headers())
50+
if response.status_code == 200:
51+
return [Workforce(**workforce) for workforce in response.json()]
52+
else:
53+
raise Exception(
54+
f"Failed to list workforces: {response.status_code} - {response.reason}"
55+
)
56+
57+
def get_profile(self):
58+
"""Get the current user's profile information."""
59+
url = "https://api.agentx.so/api/v1/access/getProfile"
60+
response = requests.get(url, headers=get_headers())
61+
if response.status_code == 200:
62+
return response.json()
63+
else:
64+
raise Exception(
65+
f"Failed to get profile: {response.status_code} - {response.reason}"
66+
)

agentx/resources/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
@dataclass
1212
class Agent(BaseModel):
13-
id: str
13+
id: str = Field(alias="_id")
1414
name: str
1515
avatar: Optional[str]
1616
createdAt: Optional[str]

agentx/resources/workforce.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from typing import Optional, List, Dict, Any, Iterator
2+
from pydantic import BaseModel, Field
3+
import requests
4+
import os
5+
import json
6+
import logging
7+
from agentx.util import get_headers
8+
from agentx.resources.agent import Agent
9+
from agentx.resources.conversation import Conversation, ChatResponse
10+
11+
12+
class User(BaseModel):
13+
id: str = Field(alias="_id")
14+
name: str
15+
email: str
16+
deleted: bool
17+
createdAt: str
18+
updatedAt: str
19+
avatar: str
20+
status: int
21+
customer: str
22+
resetPwdToken: Optional[str] = None
23+
defaultWorkspace: str
24+
workspaces: List[str]
25+
26+
class Config:
27+
populate_by_name = True
28+
extra = "ignore"
29+
30+
31+
class Workforce(BaseModel):
32+
id: str = Field(alias="_id")
33+
agents: List[Agent]
34+
name: str
35+
image: str
36+
description: str
37+
manager: Agent
38+
creator: User
39+
context: int
40+
references: bool
41+
workspace: str
42+
createdAt: str
43+
updatedAt: str
44+
45+
class Config:
46+
populate_by_name = True
47+
extra = "ignore"
48+
49+
def new_conversation(self) -> Conversation:
50+
"""Create a new conversation for this workforce."""
51+
url = f"https://api.agentx.so/api/v1/access/teams/{self.id}/conversations/new"
52+
response = requests.post(
53+
url,
54+
headers=get_headers(),
55+
json={"type": "chat"},
56+
)
57+
if response.status_code == 200:
58+
conv_data = response.json()
59+
# Set the agent_id to the manager's ID since this is a workforce conversation
60+
conv_data["agent_id"] = self.manager.id
61+
return Conversation(**conv_data)
62+
else:
63+
raise Exception(
64+
f"Failed to create new conversation: {response.status_code} - {response.reason}"
65+
)
66+
67+
def list_conversations(self) -> List[Conversation]:
68+
"""List all conversations for this workforce."""
69+
url = f"https://api.agentx.so/api/v1/access/teams/{self.id}/conversations"
70+
response = requests.get(url, headers=get_headers())
71+
if response.status_code == 200:
72+
conversations = []
73+
for conv_data in response.json():
74+
# Set the agent_id to the manager's ID since this is a workforce conversation
75+
conv_data["agent_id"] = self.manager.id
76+
conversations.append(Conversation(**conv_data))
77+
return conversations
78+
else:
79+
raise Exception(
80+
f"Failed to list conversations: {response.status_code} - {response.reason}"
81+
)
82+
83+
def chat_stream(
84+
self, conversation_id: str, message: str, context: int = -1
85+
) -> Iterator[ChatResponse]:
86+
"""Send a message to a team conversation and stream the response."""
87+
url = f"https://api.agentx.so/api/v1/access/teams/conversations/{conversation_id}/jsonmessagesse"
88+
response = requests.post(
89+
url, headers=get_headers(), json={"message": message, "context": context}
90+
)
91+
result = ""
92+
if response.status_code == 200:
93+
buf = b""
94+
for chunk in response.iter_content():
95+
buf += chunk
96+
try:
97+
chunk = buf.decode("utf-8")
98+
except UnicodeDecodeError:
99+
continue
100+
result += chunk
101+
buf = b""
102+
try:
103+
if result.count("{") == result.count("}"):
104+
catch_json = json.loads(result)
105+
if catch_json:
106+
result = ""
107+
yield ChatResponse(
108+
text=catch_json.get("text"),
109+
cot=catch_json.get("cot"),
110+
botId=catch_json.get("botId"),
111+
reference=catch_json.get("reference"),
112+
tasks=catch_json.get("tasks"),
113+
)
114+
except json.JSONDecodeError:
115+
continue
116+
else:
117+
raise Exception(
118+
f"Failed to send message: {response.status_code} - {response.reason}"
119+
)

agentx/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = "0.3.0"
1+
VERSION = "0.4.0"

setup.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
from setuptools import setup, find_packages
22

3+
4+
def get_version():
5+
"""Read version from version.py file"""
6+
version_file = "agentx/version.py"
7+
with open(version_file, "r", encoding="utf-8") as f:
8+
for line in f:
9+
if line.startswith("VERSION"):
10+
return line.split("=")[1].strip().strip('"').strip("'")
11+
raise RuntimeError("Unable to find version string.")
12+
13+
14+
def get_long_description():
15+
"""Read README.md file"""
16+
with open("README.md", "r", encoding="utf-8") as f:
17+
return f.read()
18+
19+
320
setup(
421
name="agentx-python",
5-
version="0.3.3", # Update this version number each time you make a release
22+
version=get_version(),
623
packages=find_packages(),
724
install_requires=[
825
"urllib3>=1.26.11",
926
"certifi",
1027
],
1128
author="Robin Wang and AgentX Team",
1229
author_email="[email protected]",
13-
description="Offical Python SDK for AgentX (https://www.agentx.so/)",
14-
long_description=open("README.md").read(),
30+
description="Official Python SDK for AgentX (https://www.agentx.so/)",
31+
long_description=get_long_description(),
1532
long_description_content_type="text/markdown",
1633
url="https://github.com/AgentX-ai/AgentX-python-sdk",
1734
classifiers=[

0 commit comments

Comments
 (0)