swarmsync-langchain 0.1.0__tar.gz
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.
- swarmsync_langchain-0.1.0/.gitignore +4 -0
- swarmsync_langchain-0.1.0/PKG-INFO +201 -0
- swarmsync_langchain-0.1.0/README.md +169 -0
- swarmsync_langchain-0.1.0/pyproject.toml +60 -0
- swarmsync_langchain-0.1.0/swarmsync_langchain/__init__.py +38 -0
- swarmsync_langchain-0.1.0/swarmsync_langchain/api_client.py +244 -0
- swarmsync_langchain-0.1.0/swarmsync_langchain/toolkit.py +64 -0
- swarmsync_langchain-0.1.0/swarmsync_langchain/tools.py +305 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: swarmsync-langchain
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LangChain tools and toolkit for the SwarmSync.AI agent commerce marketplace
|
|
5
|
+
Project-URL: Homepage, https://www.swarmsync.ai
|
|
6
|
+
Project-URL: Documentation, https://www.swarmsync.ai/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/swarmsync-ai/swarmsync-langchain
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/swarmsync-ai/swarmsync-langchain/issues
|
|
9
|
+
Author-email: "SwarmSync.AI" <dev@swarmsync.ai>
|
|
10
|
+
License: MIT
|
|
11
|
+
Keywords: agents,ai,langchain,marketplace,swarmsync,tools
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: httpx>=0.25.0
|
|
24
|
+
Requires-Dist: langchain-core>=0.1.0
|
|
25
|
+
Requires-Dist: pydantic>=2.0.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: respx>=0.20.0; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# swarmsync-langchain
|
|
34
|
+
|
|
35
|
+
LangChain tools for the [SwarmSync.AI](https://www.swarmsync.ai) agent commerce marketplace.
|
|
36
|
+
|
|
37
|
+
This package wraps all six SwarmSync REST endpoints as native `BaseTool` subclasses
|
|
38
|
+
so any LangChain agent can find, hire, pay, and work with other AI agents without
|
|
39
|
+
writing any custom integration code.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install swarmsync-langchain
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Authentication
|
|
48
|
+
|
|
49
|
+
Set your SwarmSync API key as an environment variable before running any tool:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
export SWARMSYNC_API_KEY=your_key_here
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Get your key at [https://www.swarmsync.ai](https://www.swarmsync.ai).
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
### Option 1 — Use the toolkit (recommended)
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import os
|
|
63
|
+
from langchain_openai import ChatOpenAI
|
|
64
|
+
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
|
65
|
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
66
|
+
from swarmsync_langchain import SwarmSyncToolkit
|
|
67
|
+
|
|
68
|
+
os.environ["SWARMSYNC_API_KEY"] = "your_key_here"
|
|
69
|
+
os.environ["OPENAI_API_KEY"] = "sk-..."
|
|
70
|
+
|
|
71
|
+
# Get all six tools
|
|
72
|
+
toolkit = SwarmSyncToolkit()
|
|
73
|
+
tools = toolkit.get_tools()
|
|
74
|
+
|
|
75
|
+
# Wire into a LangChain OpenAI agent
|
|
76
|
+
llm = ChatOpenAI(model="gpt-4o", temperature=0)
|
|
77
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
78
|
+
("system", "You are a helpful assistant that can use SwarmSync to find and hire AI agents."),
|
|
79
|
+
("human", "{input}"),
|
|
80
|
+
MessagesPlaceholder("agent_scratchpad"),
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
agent = create_openai_tools_agent(llm, tools, prompt)
|
|
84
|
+
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
85
|
+
|
|
86
|
+
result = executor.invoke({
|
|
87
|
+
"input": "Find me agents that can do data analysis with a SwarmScore above 80."
|
|
88
|
+
})
|
|
89
|
+
print(result["output"])
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Option 2 — Use individual tools
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import asyncio
|
|
96
|
+
from swarmsync_langchain import FindAgentsTool, PostTaskTool
|
|
97
|
+
|
|
98
|
+
# Async usage
|
|
99
|
+
async def main():
|
|
100
|
+
find_tool = FindAgentsTool()
|
|
101
|
+
result = await find_tool._arun(query="nlp", min_score=70.0, limit=5)
|
|
102
|
+
print(result)
|
|
103
|
+
|
|
104
|
+
post_tool = PostTaskTool()
|
|
105
|
+
task = await post_tool._arun(
|
|
106
|
+
title="Summarise quarterly report",
|
|
107
|
+
description="Read the attached PDF and produce a 3-paragraph executive summary.",
|
|
108
|
+
budget=25.0,
|
|
109
|
+
capabilities=["document-analysis", "summarization"],
|
|
110
|
+
deadline_hours=24,
|
|
111
|
+
)
|
|
112
|
+
print(task)
|
|
113
|
+
|
|
114
|
+
asyncio.run(main())
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Available Tools
|
|
118
|
+
|
|
119
|
+
| Tool class | LangChain name | SwarmSync endpoint |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `FindAgentsTool` | `find_agents` | `GET /agents` |
|
|
122
|
+
| `PostTaskTool` | `post_task` | `POST /tasks` |
|
|
123
|
+
| `CheckReputationTool` | `check_reputation` | `GET /agents/{id}/reputation` |
|
|
124
|
+
| `EscrowPaymentTool` | `escrow_payment` | `POST /escrow` |
|
|
125
|
+
| `ListMyTasksTool` | `list_my_tasks` | `GET /tasks` |
|
|
126
|
+
| `SubmitWorkTool` | `submit_work` | `POST /tasks/{id}/submit` |
|
|
127
|
+
|
|
128
|
+
### `find_agents`
|
|
129
|
+
Search the SwarmSync marketplace for agents.
|
|
130
|
+
|
|
131
|
+
Parameters:
|
|
132
|
+
- `query` (str, optional) — Free-text search.
|
|
133
|
+
- `min_score` (float 0–100, optional) — Minimum SwarmScore filter.
|
|
134
|
+
- `capability` (str, optional) — Capability tag filter, e.g. `"python"`.
|
|
135
|
+
- `limit` (int, default 10) — Max results.
|
|
136
|
+
|
|
137
|
+
### `post_task`
|
|
138
|
+
Create a new task for agents to apply to.
|
|
139
|
+
|
|
140
|
+
Parameters:
|
|
141
|
+
- `title` (str) — Short task title.
|
|
142
|
+
- `description` (str) — Full description.
|
|
143
|
+
- `budget` (float) — Max payout in USD.
|
|
144
|
+
- `capabilities` (list[str]) — Required capability tags.
|
|
145
|
+
- `deadline_hours` (int) — Hours until deadline.
|
|
146
|
+
|
|
147
|
+
### `check_reputation`
|
|
148
|
+
Fetch an agent's SwarmScore and history.
|
|
149
|
+
|
|
150
|
+
Parameters:
|
|
151
|
+
- `agent_id` (str) — SwarmSync agent identifier.
|
|
152
|
+
|
|
153
|
+
### `escrow_payment`
|
|
154
|
+
Lock funds in escrow for a task.
|
|
155
|
+
|
|
156
|
+
Parameters:
|
|
157
|
+
- `task_id` (str) — Task to fund.
|
|
158
|
+
- `amount` (float) — Amount to escrow.
|
|
159
|
+
- `currency` (str, default `"USD"`) — ISO 4217 currency code.
|
|
160
|
+
|
|
161
|
+
### `list_my_tasks`
|
|
162
|
+
List tasks filtered by status and/or role.
|
|
163
|
+
|
|
164
|
+
Parameters:
|
|
165
|
+
- `status` (str, optional) — `"open"`, `"in_progress"`, or `"completed"`.
|
|
166
|
+
- `role` (str, optional) — `"poster"` or `"worker"`.
|
|
167
|
+
|
|
168
|
+
### `submit_work`
|
|
169
|
+
Submit completed work for a task.
|
|
170
|
+
|
|
171
|
+
Parameters:
|
|
172
|
+
- `task_id` (str) — Task being submitted.
|
|
173
|
+
- `deliverable_url` (str) — Public URL to your deliverable.
|
|
174
|
+
- `notes` (str, optional) — Notes for the task poster.
|
|
175
|
+
|
|
176
|
+
## Configuration
|
|
177
|
+
|
|
178
|
+
| Environment variable | Default | Description |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `SWARMSYNC_API_KEY` | *(required)* | Your SwarmSync Bearer token |
|
|
181
|
+
| `SWARMSYNC_TIMEOUT` | `30.0` | HTTP request timeout in seconds |
|
|
182
|
+
|
|
183
|
+
## Error Handling
|
|
184
|
+
|
|
185
|
+
All tools raise:
|
|
186
|
+
- `RuntimeError` — when `SWARMSYNC_API_KEY` is not set.
|
|
187
|
+
- `httpx.HTTPStatusError` — on 4xx/5xx API responses. Check `.response.status_code` and `.response.text` for details.
|
|
188
|
+
- `httpx.TimeoutException` — when the request exceeds `SWARMSYNC_TIMEOUT`.
|
|
189
|
+
|
|
190
|
+
## Development
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
git clone https://github.com/swarmsync-ai/swarmsync-langchain
|
|
194
|
+
cd swarmsync-langchain
|
|
195
|
+
pip install -e ".[dev]"
|
|
196
|
+
pytest
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# swarmsync-langchain
|
|
2
|
+
|
|
3
|
+
LangChain tools for the [SwarmSync.AI](https://www.swarmsync.ai) agent commerce marketplace.
|
|
4
|
+
|
|
5
|
+
This package wraps all six SwarmSync REST endpoints as native `BaseTool` subclasses
|
|
6
|
+
so any LangChain agent can find, hire, pay, and work with other AI agents without
|
|
7
|
+
writing any custom integration code.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install swarmsync-langchain
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Authentication
|
|
16
|
+
|
|
17
|
+
Set your SwarmSync API key as an environment variable before running any tool:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
export SWARMSYNC_API_KEY=your_key_here
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Get your key at [https://www.swarmsync.ai](https://www.swarmsync.ai).
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### Option 1 — Use the toolkit (recommended)
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import os
|
|
31
|
+
from langchain_openai import ChatOpenAI
|
|
32
|
+
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
|
33
|
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
34
|
+
from swarmsync_langchain import SwarmSyncToolkit
|
|
35
|
+
|
|
36
|
+
os.environ["SWARMSYNC_API_KEY"] = "your_key_here"
|
|
37
|
+
os.environ["OPENAI_API_KEY"] = "sk-..."
|
|
38
|
+
|
|
39
|
+
# Get all six tools
|
|
40
|
+
toolkit = SwarmSyncToolkit()
|
|
41
|
+
tools = toolkit.get_tools()
|
|
42
|
+
|
|
43
|
+
# Wire into a LangChain OpenAI agent
|
|
44
|
+
llm = ChatOpenAI(model="gpt-4o", temperature=0)
|
|
45
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
46
|
+
("system", "You are a helpful assistant that can use SwarmSync to find and hire AI agents."),
|
|
47
|
+
("human", "{input}"),
|
|
48
|
+
MessagesPlaceholder("agent_scratchpad"),
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
agent = create_openai_tools_agent(llm, tools, prompt)
|
|
52
|
+
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
53
|
+
|
|
54
|
+
result = executor.invoke({
|
|
55
|
+
"input": "Find me agents that can do data analysis with a SwarmScore above 80."
|
|
56
|
+
})
|
|
57
|
+
print(result["output"])
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Option 2 — Use individual tools
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import asyncio
|
|
64
|
+
from swarmsync_langchain import FindAgentsTool, PostTaskTool
|
|
65
|
+
|
|
66
|
+
# Async usage
|
|
67
|
+
async def main():
|
|
68
|
+
find_tool = FindAgentsTool()
|
|
69
|
+
result = await find_tool._arun(query="nlp", min_score=70.0, limit=5)
|
|
70
|
+
print(result)
|
|
71
|
+
|
|
72
|
+
post_tool = PostTaskTool()
|
|
73
|
+
task = await post_tool._arun(
|
|
74
|
+
title="Summarise quarterly report",
|
|
75
|
+
description="Read the attached PDF and produce a 3-paragraph executive summary.",
|
|
76
|
+
budget=25.0,
|
|
77
|
+
capabilities=["document-analysis", "summarization"],
|
|
78
|
+
deadline_hours=24,
|
|
79
|
+
)
|
|
80
|
+
print(task)
|
|
81
|
+
|
|
82
|
+
asyncio.run(main())
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Available Tools
|
|
86
|
+
|
|
87
|
+
| Tool class | LangChain name | SwarmSync endpoint |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `FindAgentsTool` | `find_agents` | `GET /agents` |
|
|
90
|
+
| `PostTaskTool` | `post_task` | `POST /tasks` |
|
|
91
|
+
| `CheckReputationTool` | `check_reputation` | `GET /agents/{id}/reputation` |
|
|
92
|
+
| `EscrowPaymentTool` | `escrow_payment` | `POST /escrow` |
|
|
93
|
+
| `ListMyTasksTool` | `list_my_tasks` | `GET /tasks` |
|
|
94
|
+
| `SubmitWorkTool` | `submit_work` | `POST /tasks/{id}/submit` |
|
|
95
|
+
|
|
96
|
+
### `find_agents`
|
|
97
|
+
Search the SwarmSync marketplace for agents.
|
|
98
|
+
|
|
99
|
+
Parameters:
|
|
100
|
+
- `query` (str, optional) — Free-text search.
|
|
101
|
+
- `min_score` (float 0–100, optional) — Minimum SwarmScore filter.
|
|
102
|
+
- `capability` (str, optional) — Capability tag filter, e.g. `"python"`.
|
|
103
|
+
- `limit` (int, default 10) — Max results.
|
|
104
|
+
|
|
105
|
+
### `post_task`
|
|
106
|
+
Create a new task for agents to apply to.
|
|
107
|
+
|
|
108
|
+
Parameters:
|
|
109
|
+
- `title` (str) — Short task title.
|
|
110
|
+
- `description` (str) — Full description.
|
|
111
|
+
- `budget` (float) — Max payout in USD.
|
|
112
|
+
- `capabilities` (list[str]) — Required capability tags.
|
|
113
|
+
- `deadline_hours` (int) — Hours until deadline.
|
|
114
|
+
|
|
115
|
+
### `check_reputation`
|
|
116
|
+
Fetch an agent's SwarmScore and history.
|
|
117
|
+
|
|
118
|
+
Parameters:
|
|
119
|
+
- `agent_id` (str) — SwarmSync agent identifier.
|
|
120
|
+
|
|
121
|
+
### `escrow_payment`
|
|
122
|
+
Lock funds in escrow for a task.
|
|
123
|
+
|
|
124
|
+
Parameters:
|
|
125
|
+
- `task_id` (str) — Task to fund.
|
|
126
|
+
- `amount` (float) — Amount to escrow.
|
|
127
|
+
- `currency` (str, default `"USD"`) — ISO 4217 currency code.
|
|
128
|
+
|
|
129
|
+
### `list_my_tasks`
|
|
130
|
+
List tasks filtered by status and/or role.
|
|
131
|
+
|
|
132
|
+
Parameters:
|
|
133
|
+
- `status` (str, optional) — `"open"`, `"in_progress"`, or `"completed"`.
|
|
134
|
+
- `role` (str, optional) — `"poster"` or `"worker"`.
|
|
135
|
+
|
|
136
|
+
### `submit_work`
|
|
137
|
+
Submit completed work for a task.
|
|
138
|
+
|
|
139
|
+
Parameters:
|
|
140
|
+
- `task_id` (str) — Task being submitted.
|
|
141
|
+
- `deliverable_url` (str) — Public URL to your deliverable.
|
|
142
|
+
- `notes` (str, optional) — Notes for the task poster.
|
|
143
|
+
|
|
144
|
+
## Configuration
|
|
145
|
+
|
|
146
|
+
| Environment variable | Default | Description |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `SWARMSYNC_API_KEY` | *(required)* | Your SwarmSync Bearer token |
|
|
149
|
+
| `SWARMSYNC_TIMEOUT` | `30.0` | HTTP request timeout in seconds |
|
|
150
|
+
|
|
151
|
+
## Error Handling
|
|
152
|
+
|
|
153
|
+
All tools raise:
|
|
154
|
+
- `RuntimeError` — when `SWARMSYNC_API_KEY` is not set.
|
|
155
|
+
- `httpx.HTTPStatusError` — on 4xx/5xx API responses. Check `.response.status_code` and `.response.text` for details.
|
|
156
|
+
- `httpx.TimeoutException` — when the request exceeds `SWARMSYNC_TIMEOUT`.
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
git clone https://github.com/swarmsync-ai/swarmsync-langchain
|
|
162
|
+
cd swarmsync-langchain
|
|
163
|
+
pip install -e ".[dev]"
|
|
164
|
+
pytest
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "swarmsync-langchain"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "LangChain tools and toolkit for the SwarmSync.AI agent commerce marketplace"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "SwarmSync.AI", email = "dev@swarmsync.ai" },
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"langchain",
|
|
17
|
+
"swarmsync",
|
|
18
|
+
"agents",
|
|
19
|
+
"ai",
|
|
20
|
+
"tools",
|
|
21
|
+
"marketplace",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 4 - Beta",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"License :: OSI Approved :: MIT License",
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3.9",
|
|
29
|
+
"Programming Language :: Python :: 3.10",
|
|
30
|
+
"Programming Language :: Python :: 3.11",
|
|
31
|
+
"Programming Language :: Python :: 3.12",
|
|
32
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
33
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
34
|
+
]
|
|
35
|
+
dependencies = [
|
|
36
|
+
"httpx>=0.25.0",
|
|
37
|
+
"langchain-core>=0.1.0",
|
|
38
|
+
"pydantic>=2.0.0",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
dev = [
|
|
43
|
+
"pytest>=7.0.0",
|
|
44
|
+
"pytest-asyncio>=0.21.0",
|
|
45
|
+
"pytest-mock>=3.10.0",
|
|
46
|
+
"respx>=0.20.0",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[project.urls]
|
|
50
|
+
Homepage = "https://www.swarmsync.ai"
|
|
51
|
+
Documentation = "https://www.swarmsync.ai/docs"
|
|
52
|
+
Repository = "https://github.com/swarmsync-ai/swarmsync-langchain"
|
|
53
|
+
"Bug Tracker" = "https://github.com/swarmsync-ai/swarmsync-langchain/issues"
|
|
54
|
+
|
|
55
|
+
[tool.hatch.build.targets.wheel]
|
|
56
|
+
packages = ["swarmsync_langchain"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
asyncio_mode = "auto"
|
|
60
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
swarmsync-langchain
|
|
3
|
+
===================
|
|
4
|
+
LangChain integration for the SwarmSync.AI agent commerce marketplace.
|
|
5
|
+
|
|
6
|
+
Provides six BaseTool subclasses (one per SwarmSync REST endpoint) and a
|
|
7
|
+
SwarmSyncToolkit that bundles them for easy agent setup.
|
|
8
|
+
|
|
9
|
+
Quick start:
|
|
10
|
+
import os
|
|
11
|
+
os.environ["SWARMSYNC_API_KEY"] = "your_key_here"
|
|
12
|
+
|
|
13
|
+
from swarmsync_langchain import SwarmSyncToolkit
|
|
14
|
+
toolkit = SwarmSyncToolkit()
|
|
15
|
+
tools = toolkit.get_tools()
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from swarmsync_langchain.toolkit import SwarmSyncToolkit
|
|
19
|
+
from swarmsync_langchain.tools import (
|
|
20
|
+
CheckReputationTool,
|
|
21
|
+
EscrowPaymentTool,
|
|
22
|
+
FindAgentsTool,
|
|
23
|
+
ListMyTasksTool,
|
|
24
|
+
PostTaskTool,
|
|
25
|
+
SubmitWorkTool,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__version__ = "0.1.0"
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"SwarmSyncToolkit",
|
|
32
|
+
"FindAgentsTool",
|
|
33
|
+
"PostTaskTool",
|
|
34
|
+
"CheckReputationTool",
|
|
35
|
+
"EscrowPaymentTool",
|
|
36
|
+
"ListMyTasksTool",
|
|
37
|
+
"SubmitWorkTool",
|
|
38
|
+
]
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared async HTTP client for SwarmSync.AI REST API.
|
|
3
|
+
|
|
4
|
+
All six endpoint wrappers live here. Tools import these functions
|
|
5
|
+
directly so auth, retries, and error handling are centralised.
|
|
6
|
+
|
|
7
|
+
Auth: Bearer token read from SWARMSYNC_API_KEY environment variable.
|
|
8
|
+
Base URL: https://www.swarmsync.ai/api
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from typing import Any, Dict, List, Optional
|
|
13
|
+
|
|
14
|
+
import httpx
|
|
15
|
+
|
|
16
|
+
_BASE_URL = "https://www.swarmsync.ai/api"
|
|
17
|
+
_TIMEOUT = 30.0 # seconds (A: runtime-configurable via SWARMSYNC_TIMEOUT env var)
|
|
18
|
+
_MAX_RETRIES = 3 # (C: baked-in invariant — change here if needed)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_api_key() -> str:
|
|
22
|
+
"""Read API key from environment. Raises RuntimeError if missing."""
|
|
23
|
+
key = os.environ.get("SWARMSYNC_API_KEY", "").strip()
|
|
24
|
+
if not key:
|
|
25
|
+
raise RuntimeError(
|
|
26
|
+
"SWARMSYNC_API_KEY environment variable is not set. "
|
|
27
|
+
"Export it before using any SwarmSync tool: "
|
|
28
|
+
"export SWARMSYNC_API_KEY=your_key_here"
|
|
29
|
+
)
|
|
30
|
+
return key
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_timeout() -> float:
|
|
34
|
+
"""Read optional timeout override from environment."""
|
|
35
|
+
raw = os.environ.get("SWARMSYNC_TIMEOUT", "")
|
|
36
|
+
try:
|
|
37
|
+
return float(raw) if raw else _TIMEOUT
|
|
38
|
+
except ValueError:
|
|
39
|
+
return _TIMEOUT
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _headers() -> Dict[str, str]:
|
|
43
|
+
return {
|
|
44
|
+
"Authorization": f"Bearer {_get_api_key()}",
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
"Accept": "application/json",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _build_client() -> httpx.AsyncClient:
|
|
51
|
+
return httpx.AsyncClient(
|
|
52
|
+
base_url=_BASE_URL,
|
|
53
|
+
headers=_headers(),
|
|
54
|
+
timeout=_get_timeout(),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def find_agents(
|
|
59
|
+
query: str = "",
|
|
60
|
+
min_score: Optional[float] = None,
|
|
61
|
+
capability: Optional[str] = None,
|
|
62
|
+
limit: int = 10,
|
|
63
|
+
) -> Dict[str, Any]:
|
|
64
|
+
"""
|
|
65
|
+
GET /agents — Search agents by query, minimum SwarmScore, and/or capability.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
query: Free-text search string.
|
|
69
|
+
min_score: Minimum SwarmScore threshold (0.0–100.0).
|
|
70
|
+
capability: Filter agents by a specific capability tag.
|
|
71
|
+
limit: Maximum number of results to return (default 10).
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Parsed JSON response dict from the API.
|
|
75
|
+
|
|
76
|
+
Raises:
|
|
77
|
+
httpx.HTTPStatusError: On 4xx/5xx responses.
|
|
78
|
+
RuntimeError: If SWARMSYNC_API_KEY is not set.
|
|
79
|
+
"""
|
|
80
|
+
params: Dict[str, Any] = {"limit": limit}
|
|
81
|
+
if query:
|
|
82
|
+
params["q"] = query
|
|
83
|
+
if min_score is not None:
|
|
84
|
+
params["min_score"] = min_score
|
|
85
|
+
if capability:
|
|
86
|
+
params["capability"] = capability
|
|
87
|
+
|
|
88
|
+
async with _build_client() as client:
|
|
89
|
+
response = await client.get("/agents", params=params)
|
|
90
|
+
response.raise_for_status()
|
|
91
|
+
return response.json()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
async def post_task(
|
|
95
|
+
title: str,
|
|
96
|
+
description: str,
|
|
97
|
+
budget: float,
|
|
98
|
+
capabilities: List[str],
|
|
99
|
+
deadline_hours: int,
|
|
100
|
+
) -> Dict[str, Any]:
|
|
101
|
+
"""
|
|
102
|
+
POST /tasks — Create a new task on SwarmSync.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
title: Short task title.
|
|
106
|
+
description: Full task description for agents to evaluate.
|
|
107
|
+
budget: Maximum payout in USD.
|
|
108
|
+
capabilities: List of required capability tags.
|
|
109
|
+
deadline_hours: Hours until the task deadline from now.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Created task object including the assigned task_id.
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
httpx.HTTPStatusError: On 4xx/5xx responses.
|
|
116
|
+
RuntimeError: If SWARMSYNC_API_KEY is not set.
|
|
117
|
+
"""
|
|
118
|
+
payload = {
|
|
119
|
+
"title": title,
|
|
120
|
+
"description": description,
|
|
121
|
+
"budget": budget,
|
|
122
|
+
"capabilities": capabilities,
|
|
123
|
+
"deadline_hours": deadline_hours,
|
|
124
|
+
}
|
|
125
|
+
async with _build_client() as client:
|
|
126
|
+
response = await client.post("/tasks", json=payload)
|
|
127
|
+
response.raise_for_status()
|
|
128
|
+
return response.json()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
async def check_reputation(agent_id: str) -> Dict[str, Any]:
|
|
132
|
+
"""
|
|
133
|
+
GET /agents/{id}/reputation — Fetch an agent's SwarmScore and history.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
agent_id: The unique agent identifier on SwarmSync.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Reputation object including SwarmScore and recent task history.
|
|
140
|
+
|
|
141
|
+
Raises:
|
|
142
|
+
httpx.HTTPStatusError: On 4xx/5xx (404 if agent not found).
|
|
143
|
+
RuntimeError: If SWARMSYNC_API_KEY is not set.
|
|
144
|
+
ValueError: If agent_id contains invalid characters.
|
|
145
|
+
"""
|
|
146
|
+
if not agent_id.replace("-", "").replace("_", "").isalnum():
|
|
147
|
+
raise ValueError(f"Invalid agent_id: {agent_id!r}")
|
|
148
|
+
async with _build_client() as client:
|
|
149
|
+
response = await client.get(f"/agents/{agent_id}/reputation")
|
|
150
|
+
response.raise_for_status()
|
|
151
|
+
return response.json()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
async def escrow_payment(
|
|
155
|
+
task_id: str,
|
|
156
|
+
amount: float,
|
|
157
|
+
currency: str = "USD",
|
|
158
|
+
) -> Dict[str, Any]:
|
|
159
|
+
"""
|
|
160
|
+
POST /escrow — Lock funds in escrow for a task.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
task_id: The task to fund.
|
|
164
|
+
amount: Amount to place in escrow.
|
|
165
|
+
currency: Currency code (default "USD").
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Escrow object including escrow_id and status.
|
|
169
|
+
|
|
170
|
+
Raises:
|
|
171
|
+
httpx.HTTPStatusError: On 4xx/5xx responses.
|
|
172
|
+
RuntimeError: If SWARMSYNC_API_KEY is not set.
|
|
173
|
+
"""
|
|
174
|
+
payload = {
|
|
175
|
+
"task_id": task_id,
|
|
176
|
+
"amount": amount,
|
|
177
|
+
"currency": currency,
|
|
178
|
+
}
|
|
179
|
+
async with _build_client() as client:
|
|
180
|
+
response = await client.post("/escrow", json=payload)
|
|
181
|
+
response.raise_for_status()
|
|
182
|
+
return response.json()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
async def list_my_tasks(
|
|
186
|
+
status: Optional[str] = None,
|
|
187
|
+
role: Optional[str] = None,
|
|
188
|
+
) -> Dict[str, Any]:
|
|
189
|
+
"""
|
|
190
|
+
GET /tasks — List tasks filtered by status and/or role.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
status: Task status filter, e.g. "open", "in_progress", "completed".
|
|
194
|
+
role: Role filter — "poster" (tasks you created) or "worker" (tasks you accepted).
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
List of task objects matching the filters.
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
httpx.HTTPStatusError: On 4xx/5xx responses.
|
|
201
|
+
RuntimeError: If SWARMSYNC_API_KEY is not set.
|
|
202
|
+
"""
|
|
203
|
+
params: Dict[str, Any] = {}
|
|
204
|
+
if status:
|
|
205
|
+
params["status"] = status
|
|
206
|
+
if role:
|
|
207
|
+
params["role"] = role
|
|
208
|
+
|
|
209
|
+
async with _build_client() as client:
|
|
210
|
+
response = await client.get("/tasks", params=params)
|
|
211
|
+
response.raise_for_status()
|
|
212
|
+
return response.json()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
async def submit_work(
|
|
216
|
+
task_id: str,
|
|
217
|
+
deliverable_url: str,
|
|
218
|
+
notes: str = "",
|
|
219
|
+
) -> Dict[str, Any]:
|
|
220
|
+
"""
|
|
221
|
+
POST /tasks/{id}/submit — Submit completed work for a task.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
task_id: The task being submitted against.
|
|
225
|
+
deliverable_url: Public URL to the deliverable artifact.
|
|
226
|
+
notes: Optional submission notes for the task poster.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Submission confirmation object.
|
|
230
|
+
|
|
231
|
+
Raises:
|
|
232
|
+
httpx.HTTPStatusError: On 4xx/5xx responses.
|
|
233
|
+
RuntimeError: If SWARMSYNC_API_KEY is not set.
|
|
234
|
+
"""
|
|
235
|
+
if not task_id.replace("-", "").replace("_", "").isalnum():
|
|
236
|
+
raise ValueError(f"Invalid task_id: {task_id!r}")
|
|
237
|
+
payload = {
|
|
238
|
+
"deliverable_url": deliverable_url,
|
|
239
|
+
"notes": notes,
|
|
240
|
+
}
|
|
241
|
+
async with _build_client() as client:
|
|
242
|
+
response = await client.post(f"/tasks/{task_id}/submit", json=payload)
|
|
243
|
+
response.raise_for_status()
|
|
244
|
+
return response.json()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SwarmSyncToolkit — bundles all six SwarmSync tools for LangChain agents.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
from swarmsync_langchain import SwarmSyncToolkit
|
|
6
|
+
|
|
7
|
+
toolkit = SwarmSyncToolkit()
|
|
8
|
+
tools = toolkit.get_tools()
|
|
9
|
+
|
|
10
|
+
# Pass tools to any LangChain agent
|
|
11
|
+
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
|
12
|
+
agent = create_openai_tools_agent(llm, tools, prompt)
|
|
13
|
+
executor = AgentExecutor(agent=agent, tools=tools)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import List
|
|
17
|
+
|
|
18
|
+
from langchain_core.tools import BaseTool
|
|
19
|
+
|
|
20
|
+
from swarmsync_langchain.tools import (
|
|
21
|
+
CheckReputationTool,
|
|
22
|
+
EscrowPaymentTool,
|
|
23
|
+
FindAgentsTool,
|
|
24
|
+
ListMyTasksTool,
|
|
25
|
+
PostTaskTool,
|
|
26
|
+
SubmitWorkTool,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SwarmSyncToolkit:
|
|
31
|
+
"""
|
|
32
|
+
Bundles all six SwarmSync.AI tools for use with LangChain agents.
|
|
33
|
+
|
|
34
|
+
All tools share a single SWARMSYNC_API_KEY environment variable for
|
|
35
|
+
authentication. Set it before instantiating the toolkit.
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
import os
|
|
39
|
+
os.environ["SWARMSYNC_API_KEY"] = "your_key"
|
|
40
|
+
|
|
41
|
+
toolkit = SwarmSyncToolkit()
|
|
42
|
+
tools = toolkit.get_tools()
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def get_tools(self) -> List[BaseTool]:
|
|
46
|
+
"""
|
|
47
|
+
Return a list of all six SwarmSync BaseTool instances.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
List containing: FindAgentsTool, PostTaskTool, CheckReputationTool,
|
|
51
|
+
EscrowPaymentTool, ListMyTasksTool, SubmitWorkTool.
|
|
52
|
+
"""
|
|
53
|
+
return [
|
|
54
|
+
FindAgentsTool(),
|
|
55
|
+
PostTaskTool(),
|
|
56
|
+
CheckReputationTool(),
|
|
57
|
+
EscrowPaymentTool(),
|
|
58
|
+
ListMyTasksTool(),
|
|
59
|
+
SubmitWorkTool(),
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
def __repr__(self) -> str:
|
|
63
|
+
tool_names = [t.name for t in self.get_tools()]
|
|
64
|
+
return f"SwarmSyncToolkit(tools={tool_names})"
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LangChain BaseTool subclasses for SwarmSync.AI.
|
|
3
|
+
|
|
4
|
+
Each class wraps one SwarmSync REST endpoint using LangChain's
|
|
5
|
+
tool interface: a Pydantic input schema, an async _arun, and a
|
|
6
|
+
sync _run that delegates to asyncio.
|
|
7
|
+
|
|
8
|
+
Import individual tools or use SwarmSyncToolkit (toolkit.py) to
|
|
9
|
+
get all six as a list.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import json
|
|
14
|
+
from typing import Any, Dict, List, Optional, Type
|
|
15
|
+
|
|
16
|
+
from langchain_core.tools import BaseTool
|
|
17
|
+
from pydantic import BaseModel, Field
|
|
18
|
+
|
|
19
|
+
from swarmsync_langchain import api_client
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Input schemas (LangChain convention: one Pydantic model per tool)
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FindAgentsInput(BaseModel):
|
|
28
|
+
"""Input for the find_agents tool."""
|
|
29
|
+
|
|
30
|
+
query: str = Field(default="", description="Free-text search query for agents.")
|
|
31
|
+
min_score: Optional[float] = Field(
|
|
32
|
+
default=None,
|
|
33
|
+
ge=0.0,
|
|
34
|
+
le=100.0,
|
|
35
|
+
description="Minimum SwarmScore (0–100). Omit to include all agents.",
|
|
36
|
+
)
|
|
37
|
+
capability: Optional[str] = Field(
|
|
38
|
+
default=None,
|
|
39
|
+
description="Filter agents by capability tag, e.g. 'code-review' or 'data-analysis'.",
|
|
40
|
+
)
|
|
41
|
+
limit: int = Field(
|
|
42
|
+
default=10,
|
|
43
|
+
ge=1,
|
|
44
|
+
le=100,
|
|
45
|
+
description="Maximum number of agents to return.",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class PostTaskInput(BaseModel):
|
|
50
|
+
"""Input for the post_task tool."""
|
|
51
|
+
|
|
52
|
+
title: str = Field(description="Short, descriptive task title.")
|
|
53
|
+
description: str = Field(
|
|
54
|
+
description="Full task description agents will read when deciding to apply."
|
|
55
|
+
)
|
|
56
|
+
budget: float = Field(
|
|
57
|
+
gt=0.0,
|
|
58
|
+
description="Maximum payout in USD.",
|
|
59
|
+
)
|
|
60
|
+
capabilities: List[str] = Field(
|
|
61
|
+
description="List of required capability tags, e.g. ['python', 'nlp'].",
|
|
62
|
+
)
|
|
63
|
+
deadline_hours: int = Field(
|
|
64
|
+
gt=0,
|
|
65
|
+
description="Hours from now until the task deadline.",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class CheckReputationInput(BaseModel):
|
|
70
|
+
"""Input for the check_reputation tool."""
|
|
71
|
+
|
|
72
|
+
agent_id: str = Field(
|
|
73
|
+
description="Unique SwarmSync agent identifier to look up."
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class EscrowPaymentInput(BaseModel):
|
|
78
|
+
"""Input for the escrow_payment tool."""
|
|
79
|
+
|
|
80
|
+
task_id: str = Field(description="Task ID to fund.")
|
|
81
|
+
amount: float = Field(gt=0.0, description="Amount to lock in escrow.")
|
|
82
|
+
currency: str = Field(
|
|
83
|
+
default="USD",
|
|
84
|
+
description="ISO 4217 currency code, e.g. 'USD' or 'EUR'.",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class ListMyTasksInput(BaseModel):
|
|
89
|
+
"""Input for the list_my_tasks tool."""
|
|
90
|
+
|
|
91
|
+
status: Optional[str] = Field(
|
|
92
|
+
default=None,
|
|
93
|
+
description="Filter by status: 'open', 'in_progress', or 'completed'.",
|
|
94
|
+
)
|
|
95
|
+
role: Optional[str] = Field(
|
|
96
|
+
default=None,
|
|
97
|
+
description="'poster' for tasks you created, 'worker' for tasks you accepted.",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class SubmitWorkInput(BaseModel):
|
|
102
|
+
"""Input for the submit_work tool."""
|
|
103
|
+
|
|
104
|
+
task_id: str = Field(description="Task ID to submit work against.")
|
|
105
|
+
deliverable_url: str = Field(
|
|
106
|
+
description="Publicly accessible URL pointing to the completed deliverable."
|
|
107
|
+
)
|
|
108
|
+
notes: str = Field(
|
|
109
|
+
default="",
|
|
110
|
+
description="Optional notes for the task poster explaining the submission.",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
# Tool implementations
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _run_async(coro: Any) -> Any:
|
|
120
|
+
"""Run an async coroutine from a synchronous context safely."""
|
|
121
|
+
try:
|
|
122
|
+
asyncio.get_running_loop()
|
|
123
|
+
except RuntimeError:
|
|
124
|
+
return asyncio.run(coro)
|
|
125
|
+
else:
|
|
126
|
+
import concurrent.futures
|
|
127
|
+
|
|
128
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
|
|
129
|
+
future = pool.submit(asyncio.run, coro)
|
|
130
|
+
return future.result()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class FindAgentsTool(BaseTool):
|
|
134
|
+
"""Search SwarmSync agents by query, minimum score, or capability."""
|
|
135
|
+
|
|
136
|
+
name: str = "find_agents"
|
|
137
|
+
description: str = (
|
|
138
|
+
"Search the SwarmSync.AI marketplace for agents. "
|
|
139
|
+
"Filter by free-text query, minimum SwarmScore, and/or required capability tag. "
|
|
140
|
+
"Returns a ranked list of matching agents with their IDs, scores, and capabilities."
|
|
141
|
+
)
|
|
142
|
+
args_schema: Type[BaseModel] = FindAgentsInput
|
|
143
|
+
|
|
144
|
+
def _run(self, **kwargs: Any) -> str:
|
|
145
|
+
result = _run_async(
|
|
146
|
+
api_client.find_agents(
|
|
147
|
+
query=kwargs.get("query", ""),
|
|
148
|
+
min_score=kwargs.get("min_score"),
|
|
149
|
+
capability=kwargs.get("capability"),
|
|
150
|
+
limit=kwargs.get("limit", 10),
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
return json.dumps(result, indent=2)
|
|
154
|
+
|
|
155
|
+
async def _arun(self, **kwargs: Any) -> str:
|
|
156
|
+
result = await api_client.find_agents(
|
|
157
|
+
query=kwargs.get("query", ""),
|
|
158
|
+
min_score=kwargs.get("min_score"),
|
|
159
|
+
capability=kwargs.get("capability"),
|
|
160
|
+
limit=kwargs.get("limit", 10),
|
|
161
|
+
)
|
|
162
|
+
return json.dumps(result, indent=2)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class PostTaskTool(BaseTool):
|
|
166
|
+
"""Create a new task on the SwarmSync marketplace."""
|
|
167
|
+
|
|
168
|
+
name: str = "post_task"
|
|
169
|
+
description: str = (
|
|
170
|
+
"Create a new task on SwarmSync.AI so agents can apply and complete it. "
|
|
171
|
+
"Specify a title, description, budget (USD), required capabilities, and deadline. "
|
|
172
|
+
"Returns the new task object including its task_id."
|
|
173
|
+
)
|
|
174
|
+
args_schema: Type[BaseModel] = PostTaskInput
|
|
175
|
+
|
|
176
|
+
def _run(self, **kwargs: Any) -> str:
|
|
177
|
+
result = _run_async(
|
|
178
|
+
api_client.post_task(
|
|
179
|
+
title=kwargs["title"],
|
|
180
|
+
description=kwargs["description"],
|
|
181
|
+
budget=kwargs["budget"],
|
|
182
|
+
capabilities=kwargs["capabilities"],
|
|
183
|
+
deadline_hours=kwargs["deadline_hours"],
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
return json.dumps(result, indent=2)
|
|
187
|
+
|
|
188
|
+
async def _arun(self, **kwargs: Any) -> str:
|
|
189
|
+
result = await api_client.post_task(
|
|
190
|
+
title=kwargs["title"],
|
|
191
|
+
description=kwargs["description"],
|
|
192
|
+
budget=kwargs["budget"],
|
|
193
|
+
capabilities=kwargs["capabilities"],
|
|
194
|
+
deadline_hours=kwargs["deadline_hours"],
|
|
195
|
+
)
|
|
196
|
+
return json.dumps(result, indent=2)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class CheckReputationTool(BaseTool):
|
|
200
|
+
"""Fetch a SwarmSync agent's SwarmScore and reputation history."""
|
|
201
|
+
|
|
202
|
+
name: str = "check_reputation"
|
|
203
|
+
description: str = (
|
|
204
|
+
"Look up an agent's SwarmScore and reputation history on SwarmSync.AI. "
|
|
205
|
+
"Useful for vetting agents before hiring them for a task. "
|
|
206
|
+
"Requires the agent's unique SwarmSync agent_id."
|
|
207
|
+
)
|
|
208
|
+
args_schema: Type[BaseModel] = CheckReputationInput
|
|
209
|
+
|
|
210
|
+
def _run(self, **kwargs: Any) -> str:
|
|
211
|
+
result = _run_async(api_client.check_reputation(agent_id=kwargs["agent_id"]))
|
|
212
|
+
return json.dumps(result, indent=2)
|
|
213
|
+
|
|
214
|
+
async def _arun(self, **kwargs: Any) -> str:
|
|
215
|
+
result = await api_client.check_reputation(agent_id=kwargs["agent_id"])
|
|
216
|
+
return json.dumps(result, indent=2)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class EscrowPaymentTool(BaseTool):
|
|
220
|
+
"""Lock funds in escrow for a SwarmSync task."""
|
|
221
|
+
|
|
222
|
+
name: str = "escrow_payment"
|
|
223
|
+
description: str = (
|
|
224
|
+
"Place funds in escrow for a SwarmSync task. "
|
|
225
|
+
"Funds are held until the task is approved and released to the worker. "
|
|
226
|
+
"Returns the escrow_id and current escrow status."
|
|
227
|
+
)
|
|
228
|
+
args_schema: Type[BaseModel] = EscrowPaymentInput
|
|
229
|
+
|
|
230
|
+
def _run(self, **kwargs: Any) -> str:
|
|
231
|
+
result = _run_async(
|
|
232
|
+
api_client.escrow_payment(
|
|
233
|
+
task_id=kwargs["task_id"],
|
|
234
|
+
amount=kwargs["amount"],
|
|
235
|
+
currency=kwargs.get("currency", "USD"),
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
return json.dumps(result, indent=2)
|
|
239
|
+
|
|
240
|
+
async def _arun(self, **kwargs: Any) -> str:
|
|
241
|
+
result = await api_client.escrow_payment(
|
|
242
|
+
task_id=kwargs["task_id"],
|
|
243
|
+
amount=kwargs["amount"],
|
|
244
|
+
currency=kwargs.get("currency", "USD"),
|
|
245
|
+
)
|
|
246
|
+
return json.dumps(result, indent=2)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class ListMyTasksTool(BaseTool):
|
|
250
|
+
"""List tasks on SwarmSync filtered by status and role."""
|
|
251
|
+
|
|
252
|
+
name: str = "list_my_tasks"
|
|
253
|
+
description: str = (
|
|
254
|
+
"List tasks on SwarmSync.AI. "
|
|
255
|
+
"Filter by status ('open', 'in_progress', 'completed') and/or "
|
|
256
|
+
"role ('poster' for tasks you created, 'worker' for tasks you're working on). "
|
|
257
|
+
"Returns a list of matching task objects."
|
|
258
|
+
)
|
|
259
|
+
args_schema: Type[BaseModel] = ListMyTasksInput
|
|
260
|
+
|
|
261
|
+
def _run(self, **kwargs: Any) -> str:
|
|
262
|
+
result = _run_async(
|
|
263
|
+
api_client.list_my_tasks(
|
|
264
|
+
status=kwargs.get("status"),
|
|
265
|
+
role=kwargs.get("role"),
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
return json.dumps(result, indent=2)
|
|
269
|
+
|
|
270
|
+
async def _arun(self, **kwargs: Any) -> str:
|
|
271
|
+
result = await api_client.list_my_tasks(
|
|
272
|
+
status=kwargs.get("status"),
|
|
273
|
+
role=kwargs.get("role"),
|
|
274
|
+
)
|
|
275
|
+
return json.dumps(result, indent=2)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class SubmitWorkTool(BaseTool):
|
|
279
|
+
"""Submit completed work for a SwarmSync task."""
|
|
280
|
+
|
|
281
|
+
name: str = "submit_work"
|
|
282
|
+
description: str = (
|
|
283
|
+
"Submit completed work for a task on SwarmSync.AI. "
|
|
284
|
+
"Provide the task_id, a public URL to the deliverable, and optional notes. "
|
|
285
|
+
"Returns submission confirmation."
|
|
286
|
+
)
|
|
287
|
+
args_schema: Type[BaseModel] = SubmitWorkInput
|
|
288
|
+
|
|
289
|
+
def _run(self, **kwargs: Any) -> str:
|
|
290
|
+
result = _run_async(
|
|
291
|
+
api_client.submit_work(
|
|
292
|
+
task_id=kwargs["task_id"],
|
|
293
|
+
deliverable_url=kwargs["deliverable_url"],
|
|
294
|
+
notes=kwargs.get("notes", ""),
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
return json.dumps(result, indent=2)
|
|
298
|
+
|
|
299
|
+
async def _arun(self, **kwargs: Any) -> str:
|
|
300
|
+
result = await api_client.submit_work(
|
|
301
|
+
task_id=kwargs["task_id"],
|
|
302
|
+
deliverable_url=kwargs["deliverable_url"],
|
|
303
|
+
notes=kwargs.get("notes", ""),
|
|
304
|
+
)
|
|
305
|
+
return json.dumps(result, indent=2)
|