Files
OG T 752a4a45d7
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 8s
feat: Enhance login page UI with delayed redirect instead of transparent 307
2026-06-08 18:37:35 +08:00

273 lines
9.1 KiB
TypeScript

import {
VibeWorkAgentSDK,
ClaimTaskResponse,
QueryAgentMemoryRequest,
SubmitSolutionRequest,
TaskBounty,
} from '@vibework/agent-sdk';
import 'dotenv/config';
type A2AAction = 'query-memory' | 'create-sub-task' | 'peer-review' | 'help-signal' | 'rent-resource';
interface A2AConfig {
enabled: boolean;
sequence: A2AAction[];
maxActionsPerCycle: number;
helpErrorMessage: string;
peerReviewSnippet: string;
rentDurationMinutes: number;
}
function resolveEnv(name: string, fallback: string): string {
return process.env[name]?.trim() || fallback;
}
function parseIntEnv(name: string, fallback: number): number {
const raw = process.env[name]?.trim();
if (!raw) {
return fallback;
}
const parsed = Number(raw);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
function parseA2ASequence(value: string, fallback: A2AAction[]): A2AAction[] {
const aliases: Record<string, A2AAction> = {
memory: 'query-memory',
'query-memory': 'query-memory',
query: 'query-memory',
'create-sub-task': 'create-sub-task',
subtask: 'create-sub-task',
'peer-review': 'peer-review',
review: 'peer-review',
'help-signal': 'help-signal',
help: 'help-signal',
rent: 'rent-resource',
'rent-resource': 'rent-resource',
};
const parsed: A2AAction[] = [];
for (const token of value.split(',').map((item) => item.trim().toLowerCase()).filter(Boolean)) {
const action = aliases[token];
if (action && !parsed.includes(action)) {
parsed.push(action);
}
}
return parsed.length ? parsed : fallback;
}
function getA2AConfig(): A2AConfig {
const defaultSequence: A2AAction[] = ['query-memory', 'create-sub-task', 'peer-review', 'rent-resource'];
const enabled = resolveEnv('VIBEWORK_A2A_ENABLED', 'true').toLowerCase() === 'true';
const sequence = parseA2ASequence(process.env.VIBEWORK_A2A_SEQUENCE || '', defaultSequence);
return {
enabled,
sequence,
maxActionsPerCycle: parseIntEnv('VIBEWORK_A2A_MAX_ACTIONS_PER_CYCLE', 1),
helpErrorMessage: resolveEnv(
'VIBEWORK_A2A_HELP_ERROR',
'Stuck while reproducing external failure case'
),
peerReviewSnippet: resolveEnv(
'VIBEWORK_A2A_REVIEW_SNIPPET',
'function demo() { return "ok"; }'
),
rentDurationMinutes: parseIntEnv('VIBEWORK_A2A_RENT_MINUTES', 5),
};
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function runA2AProbe(
sdk: VibeWorkAgentSDK,
agentId: string,
targetTask: TaskBounty,
claimResult: ClaimTaskResponse,
config: A2AConfig,
cycle: number,
) {
const actions = config.sequence.slice(0, config.maxActionsPerCycle);
if (!actions.length) {
console.log('🕊️ A2A sequence is empty, skip probe.');
return;
}
for (const action of actions) {
if (action === 'query-memory') {
const request: QueryAgentMemoryRequest = {
query: `open_task_lookup ${targetTask.title}`,
error_code: 'A2A_TEST_DRILL',
};
const memory = await sdk.a2a.queryAgentMemory(request);
console.log(`🧠 Memory probe: ${memory.results.length} results`);
continue;
}
if (action === 'create-sub-task') {
if (claimResult.held_amount <= 1) {
console.log('⚠️ Skip create-sub-task: held_amount too small.');
continue;
}
const rewardAmount = Math.min(
claimResult.held_amount - 1,
Math.max(1, Math.floor(claimResult.held_amount / 10))
);
const created = await sdk.a2a.createSubTask({
parent_task_id: targetTask.task_id,
claim_token: claimResult.claim_token,
title: `[A2A Drill][${cycle}] ${targetTask.title.slice(0, 20)}`,
description:
'Automated helper sub-task generated by test agent for A2A communication verification.',
reward_amount: rewardAmount,
acceptance_criteria: {
validation_mode: 'AST_PARSING',
test_file_content: `// A2A helper stub\nexport const a2aTask = () => "${targetTask.task_id}";`,
rules: [
{
assertion: 'helper_export_exists',
expected: true,
description: 'helper function should exist',
},
],
},
});
console.log(`🧩 Sub-task created: ${created.sub_task_id} (${created.status})`);
continue;
}
if (action === 'peer-review') {
const review = await sdk.a2a.requestPeerReview({
parent_task_id: targetTask.task_id,
claim_token: claimResult.claim_token,
code_snippet: config.peerReviewSnippet,
review_instructions: `Run a quick static review for task ${targetTask.task_id}.`,
});
console.log(`🧾 Peer-review task created: ${review.review_task_id}, cost=${review.cost}`);
continue;
}
if (action === 'help-signal') {
const sos = await sdk.a2a.broadcastHelpSignal({
parent_task_id: targetTask.task_id,
claim_token: claimResult.claim_token,
error_message: config.helpErrorMessage,
contextual_code: `function fallback() { return 'retry later'; } // cycle=${cycle}`,
});
console.log(`🆘 Help signal emitted: ${sos.sos_task_id} (${sos.status})`);
continue;
}
if (action === 'rent-resource') {
const rent = await sdk.a2a.rentApiResource({
agent_id: agentId,
resource_type: 'GPT_4O',
duration_minutes: config.rentDurationMinutes,
});
console.log(`📦 Rent resource result: ${rent.status} - ${rent.message}`);
}
}
}
async function main() {
console.log('🤖 Starting VibeWork Test Agent...');
const baseUrl = resolveEnv('VIBEWORK_API_URL', 'https://agent.wooo.work');
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 agentName = resolveEnv('VIBEWORK_AGENT_NAME', 'HunterBot-Test');
const githubPrUrl = resolveEnv(
'VIBEWORK_PR_URL',
'https://github.com/agent-bounty-protocol/pr/123'
);
const iterationLimit = parseIntEnv('VIBEWORK_MAX_ITERATIONS', 1);
const sleepMs = parseIntEnv('VIBEWORK_SIMULATE_WORK_MS', 3000);
const a2aConfig = getA2AConfig();
const sdk = new VibeWorkAgentSDK({
baseUrl,
apiKey,
agentId,
agentName,
});
try {
console.log('📝 Registering Agent Identity...');
const registerResult = await sdk.identity.registerAgent({
agent_id: agentId,
name: agentName,
description:
'A test agent built with @vibework/agent-sdk to run A2A drill traffic and verify MCP interoperability.',
supported_models: ['gpt-4o'],
skills: ['typescript', 'javascript', 'react', 'testing', 'a2a'],
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 through MCP...`);
const openBountiesResp = await sdk.a2a.listOpenBounties(8);
const openBounties = openBountiesResp.tasks as TaskBounty[];
console.log(`🎯 Found ${openBounties.length} open bounties (stockout=${openBountiesResp.stockout_warning})`);
if (!openBounties.length) {
console.log('😴 No MCP-open tasks, run visibility heartbeat only.');
const heartbeat = await sdk.a2a.queryAgentMemory({
query: `open-tasks empty cycle=${iteration}`,
error_code: 'EMPTY_BOARD_DRILL',
});
console.log(`📡 Visibility heartbeat: memory hits ${heartbeat.results.length}`);
await sleep(1500);
continue;
}
const targetTask = openBounties[0];
console.log(
`📌 Target: [${targetTask.task_id}] ${targetTask.title} (Reward: ${
targetTask.reward?.display_amount ?? targetTask.reward_display ?? 'n/a'
})`
);
const claimResult = 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 sleep(sleepMs);
if (a2aConfig.enabled) {
await runA2AProbe(sdk, agentId, targetTask, claimResult, a2aConfig, iteration);
} else {
console.log('🔒 A2A drill disabled, skipping external MCP interactions.');
}
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);
});