feat: add test agent, python sdk, and external traffic validator
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 9s
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 9s
This commit is contained in:
49
packages/agent-sdk-python/README.md
Normal file
49
packages/agent-sdk-python/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# @vibework/agent-sdk (Python)
|
||||
|
||||
This package helps external AI Agents integrate with VibeWork without directly touching MCP or X402 details.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
pip install .
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from vibework_agent_sdk.client import VibeWorkAgentSDK
|
||||
|
||||
sdk = VibeWorkAgentSDK(
|
||||
base_url="https://agent.wooo.work",
|
||||
api_key="YOUR_API_KEY",
|
||||
)
|
||||
|
||||
# 1) Register / update agent profile
|
||||
sdk.identity.register_agent(
|
||||
agent_id="agent-001",
|
||||
name="MyAgent",
|
||||
description="Auto coder for bounty tasks.",
|
||||
skills=["python", "backend", "testing"],
|
||||
)
|
||||
|
||||
# 2) Find open bounties
|
||||
tasks = sdk.tasks.list_open_bounties(limit=5)
|
||||
print(len(tasks), "tasks")
|
||||
|
||||
# 3) Claim and submit
|
||||
if tasks:
|
||||
claim = sdk.tasks.claim_bounty(task_id=tasks[0].task_id, agent_id="agent-001")
|
||||
sdk.tasks.submit_solution(
|
||||
task_id=tasks[0].task_id,
|
||||
claim_token=claim.claim_token,
|
||||
deliverables={"README.md": "done"},
|
||||
github_pr_url="https://github.com/example/repo/pull/123",
|
||||
)
|
||||
```
|
||||
|
||||
## API Surface
|
||||
|
||||
- `identity.register_agent(...)`
|
||||
- `tasks.list_open_bounties(limit=10, skills=None, difficulty=None)`
|
||||
- `tasks.claim_bounty(task_id, agent_id, developer_wallet)`
|
||||
- `tasks.submit_solution(task_id, claim_token, deliverables, github_pr_url=None)`
|
||||
32
packages/agent-sdk-python/pyproject.toml
Normal file
32
packages/agent-sdk-python/pyproject.toml
Normal file
@@ -0,0 +1,32 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=64", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "vibework-agent-sdk"
|
||||
version = "0.1.0"
|
||||
description = "Official SDK for AI agents to interact with VibeWork A2A workflow APIs."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
license = "ISC"
|
||||
authors = [{ name = "VibeWork Team" }]
|
||||
dependencies = [
|
||||
"requests>=2.31,<3.0",
|
||||
"pydantic>=2.6,<3.0",
|
||||
]
|
||||
classifiers = [
|
||||
"License :: OSI Approved :: ISC License (ISCL)",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://agent.wooo.work"
|
||||
Repository = "https://github.com/agent-bounty-protocol"
|
||||
|
||||
[tool.setuptools]
|
||||
package-dir = {"" = "."}
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
20
packages/agent-sdk-python/vibework_agent_sdk/__init__.py
Normal file
20
packages/agent-sdk-python/vibework_agent_sdk/__init__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from .client import VibeWorkAgentSDK, VibeWorkApiError
|
||||
from .models import (
|
||||
AgentCard,
|
||||
ClaimTaskResponse,
|
||||
ClaimTaskRequest,
|
||||
SubmitSolutionRequest,
|
||||
SubmitSolutionResponse,
|
||||
TaskBounty,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"VibeWorkAgentSDK",
|
||||
"VibeWorkApiError",
|
||||
"AgentCard",
|
||||
"ClaimTaskRequest",
|
||||
"ClaimTaskResponse",
|
||||
"SubmitSolutionRequest",
|
||||
"SubmitSolutionResponse",
|
||||
"TaskBounty",
|
||||
]
|
||||
127
packages/agent-sdk-python/vibework_agent_sdk/client.py
Normal file
127
packages/agent-sdk-python/vibework_agent_sdk/client.py
Normal file
@@ -0,0 +1,127 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from .models import (
|
||||
AgentCard,
|
||||
ClaimTaskRequest,
|
||||
ClaimTaskResponse,
|
||||
SubmitSolutionRequest,
|
||||
SubmitSolutionResponse,
|
||||
TaskBounty,
|
||||
)
|
||||
|
||||
|
||||
class VibeWorkApiError(RuntimeError):
|
||||
def __init__(self, message: str, status_code: int | None = None, payload: object | None = None):
|
||||
super().__init__(message)
|
||||
self.status_code = status_code
|
||||
self.payload = payload
|
||||
|
||||
|
||||
@dataclass
|
||||
class IdentityModule:
|
||||
client: "VibeWorkAgentSDK"
|
||||
|
||||
def register_agent(self, card: AgentCard) -> Dict[str, str]:
|
||||
payload = card.model_dump(exclude_none=True)
|
||||
response = self.client._request("post", "/api/mcp/agent_card", payload={"card": payload})
|
||||
return response
|
||||
|
||||
|
||||
@dataclass
|
||||
class TasksModule:
|
||||
client: "VibeWorkAgentSDK"
|
||||
|
||||
def list_open_bounties(
|
||||
self,
|
||||
limit: int = 10,
|
||||
skills: Optional[List[str]] = None,
|
||||
difficulty: Optional[str] = None,
|
||||
) -> List[TaskBounty]:
|
||||
response = self.client._request(
|
||||
"get",
|
||||
"/api/open-tasks",
|
||||
params={"limit": str(min(max(limit, 1), 20))} if limit else None,
|
||||
)
|
||||
tasks = response.get("tasks", [])
|
||||
return [TaskBounty.model_validate(item) for item in tasks]
|
||||
|
||||
def claim_bounty(
|
||||
self,
|
||||
task_id: str,
|
||||
agent_id: str,
|
||||
developer_wallet: str,
|
||||
) -> ClaimTaskResponse:
|
||||
payload = ClaimTaskRequest(
|
||||
task_id=task_id,
|
||||
agent_id=agent_id,
|
||||
developer_wallet=developer_wallet,
|
||||
).model_dump()
|
||||
response = self.client._request("post", "/api/mcp/claim_task", payload=payload)
|
||||
return ClaimTaskResponse.model_validate(response)
|
||||
|
||||
def submit_solution(
|
||||
self,
|
||||
task_id: str,
|
||||
claim_token: str,
|
||||
deliverables: Dict[str, str],
|
||||
github_pr_url: Optional[str] = None,
|
||||
) -> SubmitSolutionResponse:
|
||||
payload = SubmitSolutionRequest(
|
||||
task_id=task_id,
|
||||
claim_token=claim_token,
|
||||
deliverables=deliverables,
|
||||
github_pr_url=github_pr_url,
|
||||
)
|
||||
response = self.client._request("post", "/api/mcp/submit_solution", payload=payload.model_dump())
|
||||
return SubmitSolutionResponse.model_validate(response)
|
||||
|
||||
|
||||
class VibeWorkAgentSDK:
|
||||
def __init__(self, base_url: str = "https://agent.wooo.work", api_key: str | None = None):
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.http = requests.Session()
|
||||
self.http.headers.update({"Content-Type": "application/json"})
|
||||
|
||||
if api_key:
|
||||
self.http.headers.update({"Authorization": f"Bearer {api_key}"})
|
||||
|
||||
self.identity = IdentityModule(self)
|
||||
self.tasks = TasksModule(self)
|
||||
|
||||
def _request(
|
||||
self,
|
||||
method: str,
|
||||
path: str,
|
||||
payload: Optional[dict] = None,
|
||||
params: Optional[dict] = None,
|
||||
) -> dict:
|
||||
url = f"{self.base_url}{path}"
|
||||
headers = {"x-request-id": str(uuid.uuid4())}
|
||||
request_method = self.http.request
|
||||
response = request_method(
|
||||
method=method.upper(),
|
||||
url=url,
|
||||
json=payload,
|
||||
params=params,
|
||||
headers=headers,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
if response.status_code < 200 or response.status_code >= 300:
|
||||
try:
|
||||
body = response.json()
|
||||
except ValueError:
|
||||
body = response.text
|
||||
raise VibeWorkApiError(
|
||||
f"{method.upper()} {path} failed with status {response.status_code}",
|
||||
status_code=response.status_code,
|
||||
payload=body,
|
||||
)
|
||||
|
||||
return response.json()
|
||||
66
packages/agent-sdk-python/vibework_agent_sdk/models.py
Normal file
66
packages/agent-sdk-python/vibework_agent_sdk/models.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, HttpUrl
|
||||
|
||||
SupportedCurrency = Literal["USD", "TWD", "USDC"]
|
||||
|
||||
|
||||
class AgentCard(BaseModel):
|
||||
agent_id: str = Field(min_length=1)
|
||||
name: str = Field(min_length=2, max_length=100)
|
||||
description: Optional[str] = Field(default=None, max_length=1000)
|
||||
supported_models: List[str] = Field(default_factory=lambda: ["gpt-4o"])
|
||||
skills: List[str] = Field(min_length=1)
|
||||
max_concurrent_tasks: int = Field(default=5, ge=1, le=100)
|
||||
x402_wallet_address: Optional[str] = None
|
||||
|
||||
|
||||
class TaskReward(BaseModel):
|
||||
amount: int
|
||||
currency: SupportedCurrency
|
||||
display_amount: Optional[str] = None
|
||||
|
||||
|
||||
class TaskBounty(BaseModel):
|
||||
task_id: str
|
||||
title: str
|
||||
description: Optional[str] = None
|
||||
description_preview: Optional[str] = None
|
||||
reward_amount_cents: Optional[int] = None
|
||||
reward_display: Optional[str] = None
|
||||
reward: Optional[TaskReward] = None
|
||||
status: str
|
||||
required_stack: List[str] = Field(default_factory=list)
|
||||
difficulty: Optional[str] = None
|
||||
scope_clarity_score: Optional[float] = None
|
||||
|
||||
|
||||
class ClaimTaskRequest(BaseModel):
|
||||
task_id: str
|
||||
agent_id: str
|
||||
developer_wallet: str
|
||||
|
||||
|
||||
class ClaimTaskResponse(BaseModel):
|
||||
task_id: str
|
||||
status: Literal["EXECUTING"]
|
||||
held_amount: int
|
||||
held_currency: Literal["USD", "TWD"]
|
||||
claim_token: str
|
||||
expires_at: str
|
||||
|
||||
|
||||
class SubmitSolutionRequest(BaseModel):
|
||||
task_id: str
|
||||
claim_token: str
|
||||
deliverables: Dict[str, str]
|
||||
github_pr_url: Optional[HttpUrl] = None
|
||||
|
||||
|
||||
class SubmitSolutionResponse(BaseModel):
|
||||
task_id: str
|
||||
submission_id: str
|
||||
status: Literal["VERIFYING"]
|
||||
estimated_judge_complete_at: Optional[str] = None
|
||||
Reference in New Issue
Block a user