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 = { 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); });