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:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -33,5 +33,9 @@ build
|
|||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
|
|
||||||
|
# Python
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
|
||||||
# E2B / MCP specific
|
# E2B / MCP specific
|
||||||
.e2b
|
.e2b
|
||||||
|
|||||||
88
apps/test-agent/index.ts
Normal file
88
apps/test-agent/index.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { VibeWorkAgentSDK } from '@vibework/agent-sdk';
|
||||||
|
import { ClaimTaskResponse, SubmitSolutionRequest, TaskBounty } from '@vibework/agent-sdk';
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
function resolveEnv(name: string, fallback: string): string {
|
||||||
|
return process.env[name]?.trim() || fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log("🤖 Starting VibeWork Test Agent...");
|
||||||
|
|
||||||
|
const baseUrl = resolveEnv('VIBEWORK_API_URL', 'http://localhost:3000');
|
||||||
|
const apiKey = process.env.VIBEWORK_API_KEY;
|
||||||
|
const agentId = resolveEnv('VIBEWORK_AGENT_ID', 'test-hunter-bot-001');
|
||||||
|
const wallet = resolveEnv('VIBEWORK_AGENT_WALLET', '0x1234567890abcdef1234567890abcdef12345678');
|
||||||
|
const githubPrUrl = resolveEnv(
|
||||||
|
'VIBEWORK_PR_URL',
|
||||||
|
'https://github.com/agent-bounty-protocol/pr/123'
|
||||||
|
);
|
||||||
|
const iterationLimit = Number(process.env.VIBEWORK_MAX_ITERATIONS ?? '1');
|
||||||
|
const sleepMs = Number(process.env.VIBEWORK_SIMULATE_WORK_MS ?? '3000');
|
||||||
|
|
||||||
|
const sdk = new VibeWorkAgentSDK({
|
||||||
|
baseUrl,
|
||||||
|
apiKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log("📝 Registering Agent Identity...");
|
||||||
|
const registerResult = await sdk.identity.registerAgent({
|
||||||
|
agent_id: agentId,
|
||||||
|
name: resolveEnv("VIBEWORK_AGENT_NAME", "HunterBot-Test"),
|
||||||
|
description:
|
||||||
|
"A test agent built with @vibework/agent-sdk to hunt for bounties autonomously.",
|
||||||
|
supported_models: ["gpt-4o"],
|
||||||
|
skills: ["typescript", "javascript", "react", "testing"],
|
||||||
|
max_concurrent_tasks: 3,
|
||||||
|
x402_wallet_address: wallet,
|
||||||
|
});
|
||||||
|
console.log(`✅ Registered successfully: ${registerResult.message}`);
|
||||||
|
|
||||||
|
let iteration = 0;
|
||||||
|
while (iteration < iterationLimit) {
|
||||||
|
iteration += 1;
|
||||||
|
console.log(`\n[Cycle ${iteration}] 🔍 Scanning for open bounties...`);
|
||||||
|
const openBounties = await sdk.tasks.listOpenBounties(5);
|
||||||
|
console.log(`🎯 Found ${openBounties.length} open bounties.`);
|
||||||
|
|
||||||
|
if (!openBounties.length) {
|
||||||
|
console.log("😴 No open bounties found. Exit.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetTask = openBounties[0] as TaskBounty;
|
||||||
|
console.log(
|
||||||
|
`📌 Target: [${targetTask.task_id}] ${targetTask.title} (Reward: ${
|
||||||
|
targetTask.reward?.display_amount ?? targetTask.reward_display ?? 'n/a'
|
||||||
|
})`
|
||||||
|
);
|
||||||
|
|
||||||
|
const claimResult: ClaimTaskResponse = await sdk.tasks.claimBounty(targetTask.task_id, agentId, wallet);
|
||||||
|
console.log(`✅ Bounty claimed. Claim token prefix: ${claimResult.claim_token.slice(0, 10)}...`);
|
||||||
|
|
||||||
|
console.log(`⏳ Working on task ${targetTask.task_id}...`);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, sleepMs));
|
||||||
|
|
||||||
|
const submitPayload: SubmitSolutionRequest = {
|
||||||
|
task_id: targetTask.task_id,
|
||||||
|
claim_token: claimResult.claim_token,
|
||||||
|
deliverables: {
|
||||||
|
'README.md': 'Completed the task from the automated test agent.',
|
||||||
|
'solution.diff': 'noop',
|
||||||
|
},
|
||||||
|
github_pr_url: githubPrUrl,
|
||||||
|
};
|
||||||
|
const submitResult = await sdk.tasks.submitWork(submitPayload);
|
||||||
|
console.log(`🎉 Submit done. Status: ${submitResult.status}, submission_id=${submitResult.submission_id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("🤖 Agent cycles complete.");
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("❌ Agent encountered an error:", err?.response?.data || err.message || err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
23
apps/test-agent/package.json
Normal file
23
apps/test-agent/package.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "test-agent",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "tsx index.ts",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"packageManager": "pnpm@10.32.1",
|
||||||
|
"dependencies": {
|
||||||
|
"@vibework/agent-sdk": "workspace:*",
|
||||||
|
"dotenv": "^17.4.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^25.9.2",
|
||||||
|
"tsx": "^4.22.4",
|
||||||
|
"typescript": "^6.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { VibeWorkClient } from '../client';
|
import { VibeWorkClient } from '../client';
|
||||||
import { AgentProfile } from '../types';
|
import { AgentCard, RegisterAgentResponse } from '../types';
|
||||||
|
|
||||||
export class IdentityModule {
|
export class IdentityModule {
|
||||||
private client: VibeWorkClient;
|
private client: VibeWorkClient;
|
||||||
@@ -11,23 +11,8 @@ export class IdentityModule {
|
|||||||
/**
|
/**
|
||||||
* Register or update an Agent Card
|
* Register or update an Agent Card
|
||||||
*/
|
*/
|
||||||
async registerAgent(card: {
|
async registerAgent(card: AgentCard): Promise<RegisterAgentResponse> {
|
||||||
agent_id: string;
|
const response = await this.client.http.post<{ status: string; message: string }>('/api/mcp/agent_card', { card });
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
model_provider?: string;
|
|
||||||
capabilities: string[];
|
|
||||||
x402_wallet_address?: string;
|
|
||||||
}): Promise<AgentProfile> {
|
|
||||||
const response = await this.client.http.post('/api/mcp/agent_card', card);
|
|
||||||
return response.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an Agent Profile by ID
|
|
||||||
*/
|
|
||||||
async getProfile(agentId: string): Promise<AgentProfile> {
|
|
||||||
const response = await this.client.http.get(`/api/mcp/agent_card?agent_id=${agentId}`);
|
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { VibeWorkClient } from '../client';
|
import { VibeWorkClient } from '../client';
|
||||||
import { TaskBounty, PagedResponse } from '../types';
|
import { ClaimTaskRequest, ClaimTaskResponse, SubmitSolutionRequest, SubmitSolutionResponse, TaskBounty } from '../types';
|
||||||
|
|
||||||
export class TasksModule {
|
export class TasksModule {
|
||||||
private client: VibeWorkClient;
|
private client: VibeWorkClient;
|
||||||
@@ -11,33 +11,29 @@ export class TasksModule {
|
|||||||
/**
|
/**
|
||||||
* List all open bounties in the IntentPool
|
* List all open bounties in the IntentPool
|
||||||
*/
|
*/
|
||||||
async listOpenBounties(): Promise<PagedResponse<TaskBounty>> {
|
async listOpenBounties(limit = 10): Promise<TaskBounty[]> {
|
||||||
const response = await this.client.http.get('/api/open-tasks');
|
const response = await this.client.http.get<{ tasks: TaskBounty[] }>('/api/open-tasks');
|
||||||
return {
|
return response.data.tasks.slice(0, limit);
|
||||||
data: response.data,
|
|
||||||
total: response.data.length
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Claim a bounty task
|
* Claim a bounty task
|
||||||
*/
|
*/
|
||||||
async claimBounty(taskId: string, agentId: string): Promise<TaskBounty> {
|
async claimBounty(taskId: string, agentId: string, developerWallet: string = "0x0000000000000000000000000000000000000000"): Promise<ClaimTaskResponse> {
|
||||||
const response = await this.client.http.post(`/api/mcp/claim_task`, {
|
const request: ClaimTaskRequest = {
|
||||||
taskId,
|
task_id: taskId,
|
||||||
agentId
|
agent_id: agentId,
|
||||||
});
|
developer_wallet: developerWallet
|
||||||
|
};
|
||||||
|
const response = await this.client.http.post<ClaimTaskResponse>('/api/mcp/claim_task', request);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit work for a bounty
|
* Submit work for a bounty
|
||||||
*/
|
*/
|
||||||
async submitWork(taskId: string, pullRequestUrl: string): Promise<TaskBounty> {
|
async submitWork(options: SubmitSolutionRequest): Promise<SubmitSolutionResponse> {
|
||||||
const response = await this.client.http.post(`/api/mcp/submit_work`, {
|
const response = await this.client.http.post<SubmitSolutionResponse>('/api/mcp/submit_solution', options);
|
||||||
taskId,
|
|
||||||
pullRequestUrl
|
|
||||||
});
|
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,82 @@ export interface PagedResponse<T> {
|
|||||||
total: number;
|
total: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TaskReward {
|
||||||
|
amount: number;
|
||||||
|
currency: 'USD' | 'TWD' | 'USDC';
|
||||||
|
display_amount?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TaskBounty {
|
export interface TaskBounty {
|
||||||
id: string;
|
task_id: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description?: string;
|
||||||
reward_amount: number;
|
description_preview?: string;
|
||||||
reward_currency: string;
|
reward_amount_cents?: number;
|
||||||
status: 'OPEN' | 'ASSIGNED' | 'IN_REVIEW' | 'COMPLETED' | 'CANCELLED';
|
reward_display?: string;
|
||||||
requirements: string[];
|
reward?: TaskReward;
|
||||||
|
status:
|
||||||
|
| 'DRAFT'
|
||||||
|
| 'OPEN'
|
||||||
|
| 'EXECUTING'
|
||||||
|
| 'VERIFYING'
|
||||||
|
| 'COMPLETED'
|
||||||
|
| 'FAILED'
|
||||||
|
| 'FAILED_RETRYABLE'
|
||||||
|
| 'CANCELLED'
|
||||||
|
| 'DISPUTED'
|
||||||
|
| 'REFUND_PENDING'
|
||||||
|
| 'PAYOUT_READY'
|
||||||
|
| 'PAYOUT_SETTLED'
|
||||||
|
| 'ARCHIVED'
|
||||||
|
| 'IN_REVIEW';
|
||||||
|
required_stack: string[];
|
||||||
|
difficulty?: string;
|
||||||
|
scope_clarity_score?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AgentCard {
|
||||||
|
agent_id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
supported_models?: string[];
|
||||||
|
skills: string[];
|
||||||
|
max_concurrent_tasks?: number;
|
||||||
|
x402_wallet_address?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegisterAgentResponse {
|
||||||
|
status: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClaimTaskRequest {
|
||||||
|
task_id: string;
|
||||||
|
agent_id: string;
|
||||||
|
developer_wallet: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClaimTaskResponse {
|
||||||
|
task_id: string;
|
||||||
|
status: 'EXECUTING';
|
||||||
|
held_amount: number;
|
||||||
|
held_currency: 'USD' | 'TWD';
|
||||||
|
claim_token: string;
|
||||||
|
expires_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubmitSolutionRequest {
|
||||||
|
task_id: string;
|
||||||
|
claim_token: string;
|
||||||
|
deliverables: Record<string, string>;
|
||||||
|
github_pr_url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubmitSolutionResponse {
|
||||||
|
task_id: string;
|
||||||
|
submission_id: string;
|
||||||
|
status: 'VERIFYING';
|
||||||
|
estimated_judge_complete_at?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentProfile {
|
export interface AgentProfile {
|
||||||
|
|||||||
928
pnpm-lock.yaml
generated
928
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,16 @@
|
|||||||
# This script simulates an external AI agent discovering the network via the Beta Promo token.
|
# This script simulates an external AI agent discovering the network via the Beta Promo token.
|
||||||
|
|
||||||
API_URL=${1:-"https://agent.wooo.work"}
|
API_URL=${1:-"https://agent.wooo.work"}
|
||||||
API_KEY="vw_beta_promo_2026"
|
API_KEY="${MCP_API_KEY:-vw_beta_promo_2026}"
|
||||||
AGENT_ID="test_agent_$(date +%s)"
|
AGENT_ID="${MCP_AGENT_ID:-test_agent_$(date +%s)}"
|
||||||
|
DEVELOPER_WALLET="${MCP_DEVELOPER_WALLET:-acct_demoagent001}"
|
||||||
|
SUBMIT="${MCP_DO_SUBMIT:-0}"
|
||||||
|
SUBMIT_DELAY_MS="${MCP_SUBMIT_DELAY_MS:-1500}"
|
||||||
|
|
||||||
echo "🚀 Simulating External AI Agent connecting to $API_URL"
|
echo "🚀 Simulating External AI Agent connecting to $API_URL"
|
||||||
echo "🔑 Using Public Beta Token: $API_KEY"
|
echo "🔑 Using Public Beta Token: $API_KEY"
|
||||||
echo "🤖 Agent ID: $AGENT_ID"
|
echo "🤖 Agent ID: $AGENT_ID"
|
||||||
|
echo "💳 Wallet: $DEVELOPER_WALLET"
|
||||||
echo "---------------------------------------------------"
|
echo "---------------------------------------------------"
|
||||||
|
|
||||||
# 1. Fetch Open Tasks
|
# 1. Fetch Open Tasks
|
||||||
@@ -48,10 +52,12 @@ CLAIM_RESPONSE=$(curl -s -X POST "$API_URL/api/mcp/claim_task" \
|
|||||||
-d '{
|
-d '{
|
||||||
"task_id": "'"$TASK_ID"'",
|
"task_id": "'"$TASK_ID"'",
|
||||||
"agent_id": "'"$AGENT_ID"'",
|
"agent_id": "'"$AGENT_ID"'",
|
||||||
"developer_wallet": "0xTestWalletExternalAgent999"
|
"developer_wallet": "'"$DEVELOPER_WALLET"'"
|
||||||
}')
|
}')
|
||||||
|
|
||||||
CLAIM_STATUS=$(echo $CLAIM_RESPONSE | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
|
CLAIM_TOKEN=$(echo $CLAIM_RESPONSE | grep -o '"claim_token":"[^"]*"' | cut -d'"' -f4)
|
||||||
|
CLAIM_STATUS=$(echo $CLAIM_RESPONSE | grep -o '"status":"[^"]*"' | head -n 1 | cut -d'"' -f4)
|
||||||
|
TASK_LOCK_STATUS=$(echo $CLAIM_RESPONSE | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
|
||||||
ERROR_MSG=$(echo $CLAIM_RESPONSE | grep -o '"error":"[^"]*"' | cut -d'"' -f4)
|
ERROR_MSG=$(echo $CLAIM_RESPONSE | grep -o '"error":"[^"]*"' | cut -d'"' -f4)
|
||||||
|
|
||||||
if [ -n "$ERROR_MSG" ]; then
|
if [ -n "$ERROR_MSG" ]; then
|
||||||
@@ -59,7 +65,51 @@ if [ -n "$ERROR_MSG" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✅ Task claimed successfully! Status: $CLAIM_STATUS"
|
if [ -n "$ERROR_MSG" ] || [ -z "$CLAIM_TOKEN" ]; then
|
||||||
|
echo "❌ Claim failed. Status=$CLAIM_STATUS Error=$ERROR_MSG"
|
||||||
|
echo "📄 Response: $CLAIM_RESPONSE"
|
||||||
|
if [ "$SUBMIT" = "1" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Task claimed successfully! Status: $CLAIM_STATUS, token=$CLAIM_TOKEN"
|
||||||
|
|
||||||
|
if [ "$SUBMIT" = "1" ]; then
|
||||||
|
if [ -z "$CLAIM_TOKEN" ]; then
|
||||||
|
echo "❌ Skip submit: claim_token missing."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "👉 3. Submitting Solution (submit_solution)..."
|
||||||
|
if [ "$SUBMIT_DELAY_MS" -gt 0 ]; then
|
||||||
|
sleep_time=$(echo "$SUBMIT_DELAY_MS" | awk 'BEGIN{FS=1} {printf "%f", $1/1000}')
|
||||||
|
sleep "$sleep_time"
|
||||||
|
fi
|
||||||
|
SUBMIT_RESPONSE=$(curl -s -X POST "$API_URL/api/mcp/submit_solution" \
|
||||||
|
-H "Authorization: Bearer $API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "x-agent-id: $AGENT_ID" \
|
||||||
|
-d '{
|
||||||
|
"task_id": "'"$TASK_ID"'",
|
||||||
|
"claim_token": "'"$CLAIM_TOKEN"'",
|
||||||
|
"deliverables": {
|
||||||
|
"README.md": "Automated verification from external test agent."
|
||||||
|
},
|
||||||
|
"github_pr_url": "https://github.com/example/agent-task-demo/pull/999"
|
||||||
|
}')
|
||||||
|
|
||||||
|
SUBMIT_STATUS=$(echo $SUBMIT_RESPONSE | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
|
||||||
|
SUBMIT_ERROR=$(echo $SUBMIT_RESPONSE | grep -o '"error":"[^"]*"' | cut -d'"' -f4)
|
||||||
|
|
||||||
|
if [ -n "$SUBMIT_ERROR" ]; then
|
||||||
|
echo "❌ Failed to submit solution: $SUBMIT_ERROR"
|
||||||
|
echo $SUBMIT_RESPONSE
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Solution submitted successfully. Status: $SUBMIT_STATUS"
|
||||||
|
fi
|
||||||
|
|
||||||
# We won't submit solution because we don't have the real sandbox context.
|
|
||||||
echo "🎉 Test pipeline passed!"
|
echo "🎉 Test pipeline passed!"
|
||||||
|
|||||||
Reference in New Issue
Block a user