Files
agent-bounty-protocol/apps/web/src/lib/a2a-growth.ts
OG T 5abf6be991
All checks were successful
CI and Production Smoke / smoke (push) Successful in 11s
feat: expose A2A agent integration catalog
2026-06-11 14:40:02 +08:00

163 lines
6.0 KiB
TypeScript

import { isIP } from "node:net";
import { A2A_AGENT_INTEGRATIONS, TELEGRAM_CONTROL_PLANE_ROLES } from "@/lib/a2a-agent-integrations";
export const VIBEWORK_SITE_URL = (
process.env.VIBEWORK_SITE_URL ||
process.env.NEXT_PUBLIC_VIBEWORK_SITE_URL ||
"https://vibework.wooo.work"
).replace(/\/$/, "");
export const AGENT_GATEWAY_URL = (
process.env.AGENT_GATEWAY_URL ||
process.env.NEXT_PUBLIC_SITE_URL ||
"https://agent.wooo.work"
).replace(/\/$/, "");
export const TREASURY_USDC_ADDRESS = (process.env.VIBEWORK_TREASURY_USDC_ADDRESS || "").trim();
export const TREASURY_WALLET_LABEL = (process.env.VIBEWORK_TREASURY_WALLET_LABEL || "USDC Treasury").trim();
export const TREASURY_USDC_NETWORK = (process.env.VIBEWORK_TREASURY_USDC_NETWORK || "").trim();
export const PROPOSAL_PACKAGES = [
{
id: "scout",
name: "Scout Intake",
feeCents: 2900,
label: "$29",
description: "需求整理、初步 scope triage、referral attribution.",
deliverable: "適合先確認需求是否可交給 AI Agent 處理。",
reviewWindow: "標準 review queue",
},
{
id: "growth",
name: "Growth Routing",
feeCents: 9900,
label: "$99",
description: "優先 scoping、任務包裝、agent routing 與 attribution.",
deliverable: "適合已有明確預算、希望快速轉成 bounty 或專案的人。",
reviewWindow: "priority review",
},
{
id: "priority",
name: "Priority Bounty Launch",
feeCents: 19900,
label: "$199",
description: "fast-track review、bounty conversion、agent broadcast prep.",
deliverable: "適合急件、跨系統整合、需要平台協助拆任務的需求。",
reviewWindow: "fast-track review",
},
] as const;
export type ProposalPackageId = (typeof PROPOSAL_PACKAGES)[number]["id"];
export function sanitizeAgentId(value: string | null | undefined) {
const normalized = (value || "")
.trim()
.toLowerCase()
.replace(/[^a-z0-9._:-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "");
return normalized.slice(0, 80);
}
export function getProposalPackage(id: string | null | undefined) {
return PROPOSAL_PACKAGES.find((item) => item.id === id) || PROPOSAL_PACKAGES[1];
}
export function buildDemandProposalUrl(params: {
referralAgent?: string | null;
campaign?: string | null;
source?: string | null;
}) {
const url = new URL("/propose", VIBEWORK_SITE_URL);
const referralAgent = sanitizeAgentId(params.referralAgent);
if (referralAgent) url.searchParams.set("ref_agent", referralAgent);
if (params.campaign) url.searchParams.set("campaign", params.campaign);
if (params.source) url.searchParams.set("source", params.source);
return url.toString();
}
export function buildAgentGrowthKit(params: {
agentId: string;
campaign?: string | null;
source?: string | null;
}) {
const agentId = sanitizeAgentId(params.agentId);
const proposalUrl = buildDemandProposalUrl({
referralAgent: agentId,
campaign: params.campaign || "a2a-agent-referral",
source: params.source || "external-agent",
});
return {
agent_id: agentId,
referral_url: proposalUrl,
landing_domain: VIBEWORK_SITE_URL,
gateway_api: AGENT_GATEWAY_URL,
incentive: {
referral_fee: "10% of collected proposal routing fees, tracked as pending affiliate ledger after paid conversion.",
qualification: "Agent must pass platform review before payout.",
},
external_agent_pitch: [
"Find humans or teams with software, automation, data, or AI workflow needs.",
`Send them to ${proposalUrl}`,
"Ask them to describe the outcome, budget, stack, and acceptance criteria.",
"After payment, VibeWork turns the proposal into a scoped bounty or review queue item.",
],
demand_proposer_pitch:
"Submit a paid AI-agent-ready proposal. VibeWork scopes it, routes it to approved agents, and tracks delivery evidence.",
copy_blocks: {
short_post:
`Need AI agents to ship a small software task? Submit it here: ${proposalUrl}`,
dm:
`I can route your software/automation request into VibeWork's AI-agent bounty network. Start with a paid proposal intake: ${proposalUrl}`,
agent_instruction:
`When you meet a human demand proposer, do not collect sensitive credentials. Send them to ${proposalUrl} and let VibeWork handle paid intake, scoping, and routing.`,
},
api_next_steps: {
register_agent_card: `${AGENT_GATEWAY_URL}/api/mcp/agent_card`,
inspect_open_tasks: `${AGENT_GATEWAY_URL}/api/open-tasks`,
submit_bid: `${AGENT_GATEWAY_URL}/api/mcp/submit_bid`,
integration_catalog: `${AGENT_GATEWAY_URL}/api/a2a/integrations?agent_id=${encodeURIComponent(agentId)}`,
},
telegram_control_plane: {
group: "VibeAIAgent",
roles: TELEGRAM_CONTROL_PLANE_ROLES.map((role) => ({
id: role.id,
name: role.name,
job: role.job,
})),
rule: "Use Telegram for coordination, alerts, onboarding, and learning feedback; do not post secrets or full customer credentials.",
},
recommended_external_agent_lanes: A2A_AGENT_INTEGRATIONS.slice(0, 8).map((integration) => ({
id: integration.id,
name: integration.name,
status: integration.status,
role: integration.primaryRole,
monetization_lane: integration.monetizationLane,
})),
};
}
export function isSafeOutboundUrl(value: string) {
try {
const url = new URL(value);
if (url.protocol !== "https:") return false;
const host = url.hostname.toLowerCase();
if (["localhost", "127.0.0.1", "::1"].includes(host)) return false;
if (host.endsWith(".local")) return false;
if (isIP(host) === 4) {
if (host.startsWith("10.") || host.startsWith("127.") || host.startsWith("192.168.")) return false;
if (host.startsWith("172.")) {
const second = Number(host.split(".")[1]);
return !(second >= 16 && second <= 31);
}
}
if (isIP(host) === 6 && (host.startsWith("fc") || host.startsWith("fd") || host.startsWith("fe80"))) {
return false;
}
return true;
} catch {
return false;
}
}