feat: add external demand campaign kit
All checks were successful
CI and Production Smoke / smoke (push) Successful in 7s
All checks were successful
CI and Production Smoke / smoke (push) Successful in 7s
This commit is contained in:
@@ -11,6 +11,7 @@ export async function GET() {
|
||||
mcp: "https://agent.wooo.work/api/mcp/discover",
|
||||
rpc: "https://agent.wooo.work/api/a2a/rpc",
|
||||
onboarding: "https://agent.wooo.work/api/a2a/onboarding?agent_id={agent_id}®ister=true",
|
||||
demand_campaign_kit: "https://agent.wooo.work/api/a2a/campaigns/demand?agent_id={agent_id}®ister=true",
|
||||
growth_kit: "https://agent.wooo.work/api/a2a/growth/kit?agent_id={agent_id}®ister=true",
|
||||
referral_status: "https://agent.wooo.work/api/a2a/referrals/status?agent_id={agent_id}",
|
||||
integration_catalog: "https://agent.wooo.work/api/a2a/integrations?agent_id={agent_id}",
|
||||
@@ -26,6 +27,7 @@ export async function GET() {
|
||||
capabilities: [
|
||||
"Task_Delegation",
|
||||
"Demand_Referral",
|
||||
"Demand_Campaign_Kit",
|
||||
"External_Agent_Onboarding",
|
||||
"Dispute_Arbitration",
|
||||
"ICO_Launchpad"
|
||||
|
||||
@@ -30,6 +30,17 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
/api/a2a/campaigns/demand:
|
||||
get:
|
||||
operationId: getA2ADemandCampaignKit
|
||||
summary: Get external-agent demand campaign kit
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
/api/a2a/growth/kit:
|
||||
get:
|
||||
operationId: getA2AGrowthKit
|
||||
|
||||
88
apps/web/src/app/api/a2a/campaigns/demand/route.ts
Normal file
88
apps/web/src/app/api/a2a/campaigns/demand/route.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { buildAgentDemandCampaignKit, sanitizeAgentId } from "@/lib/a2a-growth";
|
||||
import { logA2aTrafficEvent } from "@/lib/a2a-traffic";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const agentId = sanitizeAgentId(searchParams.get("agent_id"));
|
||||
const campaign = sanitizeAgentId(searchParams.get("campaign")) || "a2a-agent-referral";
|
||||
const channel = sanitizeAgentId(searchParams.get("channel")) || "";
|
||||
const source = sanitizeAgentId(searchParams.get("source")) || channel || "campaign-kit";
|
||||
const shouldRegister = searchParams.get("register") === "true";
|
||||
|
||||
if (!agentId) {
|
||||
return NextResponse.json({ error: "agent_id is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
if (shouldRegister) {
|
||||
await prisma.agentProfile.upsert({
|
||||
where: { agent_id: agentId },
|
||||
update: {
|
||||
discovery_source: "A2A_DEMAND_CAMPAIGN_KIT",
|
||||
},
|
||||
create: {
|
||||
agent_id: agentId,
|
||||
type: "SCOUT",
|
||||
status: "PENDING",
|
||||
discovery_source: "A2A_DEMAND_CAMPAIGN_KIT",
|
||||
capabilities: {
|
||||
growth_referral: true,
|
||||
demand_campaign_kit: true,
|
||||
campaign,
|
||||
source,
|
||||
channel: channel || null,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const kit = buildAgentDemandCampaignKit({
|
||||
agentId,
|
||||
campaign,
|
||||
source,
|
||||
channel: channel || source,
|
||||
});
|
||||
|
||||
await prisma.auditEvent.create({
|
||||
data: {
|
||||
actorType: "AGENT",
|
||||
actorId: agentId,
|
||||
action: "A2A_DEMAND_CAMPAIGN_KIT_ISSUED",
|
||||
entityType: "SYSTEM",
|
||||
entityId: "a2a-demand-campaign-kit",
|
||||
metadata: {
|
||||
campaign,
|
||||
source,
|
||||
channel: channel || null,
|
||||
registered_pending_agent: shouldRegister,
|
||||
landing_url: kit.landing_url,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await logA2aTrafficEvent({
|
||||
headers: request.headers,
|
||||
fallbackAgentId: agentId,
|
||||
action: "EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED",
|
||||
surface: "a2a/campaigns/demand",
|
||||
entityId: "a2a-demand-campaign-kit",
|
||||
reason: "external_agent_demand_campaign_kit_issued",
|
||||
metadata: {
|
||||
campaign,
|
||||
source,
|
||||
channel: channel || null,
|
||||
registered_pending_agent: shouldRegister,
|
||||
landing_url: kit.landing_url,
|
||||
response_status: 200,
|
||||
response_summary: "a2a_demand_campaign_kit_issued",
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
kit,
|
||||
});
|
||||
}
|
||||
@@ -33,6 +33,7 @@ function buildEndpointTemplates(agentId: string | null) {
|
||||
|
||||
return {
|
||||
onboarding: `${AGENT_GATEWAY_URL}/api/a2a/onboarding?agent_id=${encodedAgentId}®ister=true`,
|
||||
demand_campaign_kit: `${AGENT_GATEWAY_URL}/api/a2a/campaigns/demand?agent_id=${encodedAgentId}®ister=true`,
|
||||
integration_catalog: `${AGENT_GATEWAY_URL}/api/a2a/integrations?agent_id=${encodedAgentId}`,
|
||||
growth_kit: `${AGENT_GATEWAY_URL}/api/a2a/growth/kit?agent_id=${encodedAgentId}®ister=true`,
|
||||
referral_status: `${AGENT_GATEWAY_URL}/api/a2a/referrals/status?agent_id=${encodedAgentId}`,
|
||||
@@ -160,18 +161,24 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
id: "publish-campaign",
|
||||
action: "Fetch the demand campaign kit and publish only approved copy blocks in a relevant channel.",
|
||||
endpoint: endpoints.demand_campaign_kit,
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
id: "refer-demand",
|
||||
action: "Send human demand proposers to the attributed paid proposal URL. Do not collect payment or credentials yourself.",
|
||||
endpoint: growthKit?.referral_url || endpoints.paid_proposal,
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
step: 4,
|
||||
id: "track",
|
||||
action: "Check sanitized referral funnel and pending affiliate ledger status.",
|
||||
endpoint: endpoints.referral_status,
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
step: 5,
|
||||
id: "execute",
|
||||
action: "Use open tasks and MCP/A2A routes only after agent review, wallet binding, and task authorization.",
|
||||
endpoint: endpoints.open_tasks,
|
||||
|
||||
@@ -6,6 +6,8 @@ import { buildDemandProposalUrl, sanitizeAgentId } from "@/lib/a2a-growth";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
const TRACKED_REFERRAL_ACTIONS = [
|
||||
"EXTERNAL_A2A_ONBOARDING_VIEW",
|
||||
"EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED",
|
||||
"EXTERNAL_A2A_GROWTH_KIT_ISSUED",
|
||||
"EXTERNAL_DEMAND_PROPOSAL_VIEW",
|
||||
"EXTERNAL_DEMAND_PROPOSAL_INTAKE_CREATED",
|
||||
@@ -215,6 +217,8 @@ export async function GET(request: NextRequest) {
|
||||
payment_truth: "Paid conversion is counted only after Stripe webhook or verified USDC wallet receipt.",
|
||||
},
|
||||
traffic_funnel: {
|
||||
onboarding_events: actionCounts.EXTERNAL_A2A_ONBOARDING_VIEW || 0,
|
||||
demand_campaign_kit_events: actionCounts.EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED || 0,
|
||||
growth_kit_events: actionCounts.EXTERNAL_A2A_GROWTH_KIT_ISSUED || 0,
|
||||
proposal_view_events: actionCounts.EXTERNAL_DEMAND_PROPOSAL_VIEW || 0,
|
||||
proposal_created_events: actionCounts.EXTERNAL_DEMAND_PROPOSAL_INTAKE_CREATED || 0,
|
||||
|
||||
@@ -253,6 +253,8 @@ export async function GET(request: Request) {
|
||||
mcp_command: MCP_BOOTSTRAP_COMMAND,
|
||||
api_base_url: MCP_API_BASE_URL,
|
||||
demand_proposal_url: `${VIBEWORK_SITE_URL}/propose`,
|
||||
agent_onboarding_url: `${AGENT_GATEWAY_URL}/api/a2a/onboarding?agent_id=<YOUR_AGENT_ID>®ister=true`,
|
||||
demand_campaign_kit_url: `${AGENT_GATEWAY_URL}/api/a2a/campaigns/demand?agent_id=<YOUR_AGENT_ID>®ister=true`,
|
||||
agent_growth_kit_url: `${AGENT_GATEWAY_URL}/api/a2a/growth/kit?agent_id=<YOUR_AGENT_ID>®ister=true`,
|
||||
referral_url_template: `${VIBEWORK_SITE_URL}/propose?ref_agent=<YOUR_AGENT_ID>&source=external-agent&campaign=a2a-agent-referral`,
|
||||
auth_policy: "Protected MCP mutation endpoints require an approved bearer token.",
|
||||
@@ -266,8 +268,9 @@ export async function GET(request: Request) {
|
||||
required_steps: [
|
||||
"1) 先用 curl 或 MCP 列出任務",
|
||||
"2) 註冊 agent card 並等待白名單核准",
|
||||
"3) 用 growth kit 將外部需求方導到 VibeWork paid intake",
|
||||
"4) 核准後再依平台規則 bid/claim/submit",
|
||||
"3) 用 onboarding 與 demand campaign kit 取得核准文案與 referral URL",
|
||||
"4) 將外部需求方導到 VibeWork paid intake",
|
||||
"5) 核准後再依平台規則 bid/claim/submit",
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -504,6 +504,8 @@ export async function GET(request: NextRequest) {
|
||||
const discoveryEvents =
|
||||
(actionSummary["EXTERNAL_LIST_OPEN_TASKS"] || 0) +
|
||||
(actionSummary["EXTERNAL_LIST_OPEN_TASKS_MCP"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_ONBOARDING_VIEW"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_INTEGRATION_CATALOG_VIEW"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_GROWTH_KIT_ISSUED"] || 0);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ const EVENT_LABELS: Record<string, string> = {
|
||||
EXTERNAL_LIST_OPEN_TASKS: "外部公開流量頁讀取 open tasks",
|
||||
EXTERNAL_A2A_ONBOARDING_VIEW: "外部 Agent 讀取 onboarding contract",
|
||||
PUBLIC_A2A_ONBOARDING_VIEW: "公開 A2A onboarding 被讀取",
|
||||
EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED: "外部 Agent 領取需求 campaign kit",
|
||||
EXTERNAL_A2A_INTEGRATION_CATALOG_VIEW: "外部 Agent 讀取 A2A 整合目錄",
|
||||
EXTERNAL_A2A_GROWTH_KIT_ISSUED: "外部 Agent 領取 growth kit",
|
||||
EXTERNAL_A2A_REFERRAL_STATUS_VIEW: "外部 Agent 查詢 referral 狀態",
|
||||
@@ -388,6 +389,8 @@ async function getTrafficSummary(minutes: number) {
|
||||
const discoveryEvents =
|
||||
(actionSummary["EXTERNAL_LIST_OPEN_TASKS"] || 0) +
|
||||
(actionSummary["EXTERNAL_LIST_OPEN_TASKS_MCP"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_ONBOARDING_VIEW"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_INTEGRATION_CATALOG_VIEW"] || 0) +
|
||||
(actionSummary["EXTERNAL_A2A_GROWTH_KIT_ISSUED"] || 0);
|
||||
const proposalViewEvents = actionSummary["EXTERNAL_DEMAND_PROPOSAL_VIEW"] || 0;
|
||||
|
||||
Reference in New Issue
Block a user