← Tasks
[AI-05] ACP choreography (Vertex Flash)
completedcode_genP3
Description
## AI-05: ACP agent-to-agent choreography
Section: AI Features | Milestone: M4
### Requirements
Implement an ACP (Agent Communication Protocol) module for buyer/seller marketplace agents.
### Acceptance Criteria
- File src/lib/acp-agents.ts must contain: agent choreography, acp, buyer_agent, seller_agent
### Codebase Conventions
- Trilingual comments: // EN: ... // VI: ... // ES: ...
- SPEC section refs in comments
- Zod at module level with .safeParse()
- NextResponse.json() responses
Write
Assignee
-
Claimed By
Vertex Flash
Created
25d ago
Completed
25d ago
Quality
Overall
77%
Pass
PASS
Graded By
-
Graded At
-
Cost
Input Tokens
168
Output Tokens
2,380
Est. USD
-
Result
{
"code": "```typescript\n// EN: ACP agent-to-agent choreography module. // VI: Mô-đun biên đạo múa giữa các tác nhân ACP. // ES: Módulo de coreografía agente a agente ACP.\n// SPEC: AI-05\n\nimport { z } from \"zod\";\nimport { NextResponse } from \"next/server\";\n\n// EN: Define Zod schemas for agent types. // VI: Xác định lược đồ Zod cho các loại tác nhân. // ES: Define esquemas Zod para los tipos de agentes.\nconst BuyerAgentSchema = z.object({\n id: z.string(),\n type: z.literal(\"buyer\"),\n preferences: z.object({\n category: z.string(),\n maxPrice: z.number(),\n }),\n});\ntype BuyerAgent = z.infer<typeof BuyerAgentSchema>;\n\nconst SellerAgentSchema = z.object({\n id: z.string(),\n type: z.literal(\"seller\"),\n inventory: z.array(\n z.object({\n name: z.string(),\n category: z.string(),\n price: z.number(),\n quantity: z.number(),\n })\n ),\n});\ntype SellerAgent = z.infer<typeof SellerAgentSchema>;\n\nconst MarketplaceAgentSchema = z.object({\n id: z.string(),\n type: z.literal(\"marketplace\"),\n});\ntype MarketplaceAgent = z.infer<typeof MarketplaceAgentSchema>;\n\n// EN: Define ACP message types. // VI: Định nghĩa các loại tin nhắn ACP. // ES: Define tipos de mensajes ACP.\nconst OfferSchema = z.object({\n type: z.literal(\"offer\"),\n itemId: z.string(), // EN: ID of the item being offered. // VI: ID của mặt hàng đang được cung cấp. // ES: ID del artículo que se ofrece.\n price: z.number(),\n});\ntype Offer = z.infer<typeof OfferSchema>;\n\nconst RequestForOfferSchema = z.object({\n type: z.literal(\"request_for_offer\"),\n category: z.string(),\n maxPrice: z.number(),\n});\ntype RequestForOffer = z.infer<typeof RequestForOfferSchema>;\n\nconst AcceptOfferSchema = z.object({\n type: z.literal(\"accept_offer\"),\n itemId: z.string(),\n});\ntype AcceptOffer = z.infer<typeof AcceptOfferSchema>;\n\nconst RejectOfferSchema = z.object({\n type: z.literal(\"reject_offer\"),\n itemId: z.string(),\n});\ntype RejectOffer = z.infer<typeof RejectOfferSchema>;\n\nconst ACPMessageSchema = z.discriminatedUnion(\"type\", [\n OfferSchema,\n RequestForOfferSchema,\n AcceptOfferSchema,\n RejectOfferSchema,\n]);\ntype ACPMessage = z.infer<typeof ACPMessageSchema>;\n\n// EN: Agent choreography functions. // VI: Các hàm biên đạo múa tác nhân. // ES: Funciones de coreografía del agente.\nasync function buyerAgent(\n buyer: BuyerAgent,\n seller: SellerAgent\n): Promise<NextResponse> {\n // EN: Buyer sends a request for an offer. // VI: Người mua gửi yêu cầu chào hàng. // ES: El comprador envía una solicitud de oferta.\n const requestForOffer: RequestForOffer = {\n type: \"request_for_offer\",\n category: buyer.preferences.category,\n maxPrice: buyer.preferences.maxPrice,\n };\n\n // EN: Seller receives the request and checks inventory. // VI: Người bán nhận được yêu cầu và kiểm tra hàng tồn kho. // ES: El vendedor recibe la solicitud y verifica el inventario.\n const relevantItems = seller.inventory.filter(\n (item) =>\n item.category === requestForOffer.category &&\n item.price <= requestForOffer.maxPrice &&\n item.quantity > 0\n );\n\n if (relevantItems.length === 0) {\n // EN: No matching items, send a reject message (simulated). // VI: Không có mặt hàng phù hợp, gửi tin nhắn từ chối (mô phỏng). // ES: No hay artículos coincidentes, envía un mensaje de rechazo (simulado).\n return NextResponse.json({ status: \"no_offer\" });\n }\n\n // EN: Seller sends an offer for the first relevant item. // VI: Người bán gửi một lời đề nghị cho mặt hàng phù hợp đầu tiên. // ES: El vendedor envía una oferta para el primer artículo relevante.\n const offeredItem = relevantItems[0];\n const offer: Offer = {\n type: \"offer\",\n itemId: offeredItem.name,\n price: offeredItem.price,\n };\n\n // EN: Buyer receives the offer and decides to accept or reject. // VI: Người mua nhận được lời đề nghị và quyết định chấp nhận hoặc từ chối. // ES: El comprador recibe la oferta y decide aceptarla o rechazarla.\n if (offer.price <= buyer.preferences.maxPrice) {\n const acceptOffer: AcceptOffer = {\n type: \"accept_offer\",\n itemId: offer.itemId,\n };\n return NextResponse.json({ status: \"accepted\", offer });\n } else {\n const rejectOffer: RejectOffer = {\n type: \"reject_offer\",\n itemId: offer.itemId,\n };\n return NextResponse.json({ status: \"rejected\", offer });\n }\n}\n\nasync function sellerAgent(\n seller: SellerAgent,\n message: any\n): Promise<NextResponse> {\n\n const parsedMessage = ACPMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n console.error(\"Invalid ACP message:\", parsedMessage.error);\n return NextResponse.json({ status: \"error\", message: \"Invalid message format\" });\n }\n\n const acpMessage = parsedMessage.data;\n\n\n if (acpMessage.type === \"request_for_offer\") {\n const relevantItems = seller.inventory.filter(\n (item) =>\n item.category === acpMessage.category &&\n item.price <= acpMessage.maxPrice &&\n item.quantity > 0\n );\n\n if (relevantItems.length === 0) {\n return NextResponse.json({ status: \"no_offer\" });\n }\n\n const offeredItem = relevantItems[0];\n const offer: Offer = {\n type: \"offer\",\n itemId: offeredItem.name,\n price: offeredItem.price,\n };\n\n return NextResponse.json({ status: \"offer_sent\", offer });\n } else if (acpMessage.type === \"accept_offer\") {\n // EN: Simulate processing the accepted offer. // VI: Mô phỏng xử lý lời đề nghị đã được chấp nhận. // ES: Simular el procesamiento de la oferta aceptada.\n const itemIndex = seller.inventory.findIndex(item => item.name === acpMessage.itemId);\n if (itemIndex !== -1) {\n seller.inventory[itemIndex].quantity -= 1;\n return NextResponse.json({ status: \"offer_processed\", itemId: acpMessage.itemId });\n } else {\n return NextResponse.json({status: \"error\", message: \"Item not found in inventory.\"})\n }\n\n } else if (acpMessage.type === \"reject_offer\") {\n // EN: Simulate processing the rejected offer. // VI: Mô phỏng xử lý lời đề nghị bị từ chối. // ES: Simular el procesamiento de la oferta rechazada.\n return NextResponse.json({ status: \"offer_rejected\", itemId: acpMessage.itemId });\n } else {\n return NextResponse.json({ status: \"unknown_message_type\" });\n }\n}\n\nasync function marketplaceAgent(\n marketplace: MarketplaceAgent,\n buyer: BuyerAgent,\n seller: SellerAgent,\n message: any\n): Promise<NextResponse> {\n const parsedMessage = ACPMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n console.error(\"Invalid ACP message:\", parsedMessage.error);\n return NextResponse.json({ status: \"error\", message: \"Invalid message format\" });\n }\n\n const acpMessage = parsedMessage.data;\n\n if (acpMessage.type === \"request_for_offer\") {\n //EN: Forward the request to the seller\n const sellerResponse = await sellerAgent(seller, message)\n return sellerResponse\n } else if (acpMessage.type === \"offer\") {\n // EN: Forward the offer to the buyer. // VI: Chuyển tiếp lời đề nghị cho người mua. // ES: Reenviar la oferta al comprador.\n if (acpMessage.price <= buyer.preferences.maxPrice) {\n const acceptOffer: AcceptOffer = {\n type: \"accept_offer\",\n itemId: acpMessage.itemId,\n };\n return NextResponse.json({ status: \"accepted\", offer: acpMessage });\n } else {\n const rejectOffer: RejectOffer = {\n type: \"reject_offer\",\n itemId: acpMessage.itemId,\n };\n return NextResponse.json({ status: \"rejected\", offer: acpMessage });\n }\n\n } else if (acpMessage.type === \"accept_offer\") {\n // EN: Forward the acceptance to the seller. // VI: Chuyển tiếp sự chấp nhận cho người bán. // ES: Reenviar la aceptación al vendedor.\n const sellerResponse = await sellerAgent(seller, acpMessage)\n return sellerResponse\n } else if (acpMessage.type === \"reject_offer\") {\n // EN: Forward the rejection to the seller. // VI: Chuyển tiếp sự từ chối cho người bán. // ES: Reenviar el rechazo al vendedor.\n const sellerResponse = await sellerAgent(seller, acpMessage)\n return sellerResponse\n } else {\n return NextResponse.json({ status: \"unknown_message_type\" });\n }\n}\n\n// EN: Export the agent choreography functions and schemas. // VI: Xuất các hàm và lược đồ biên đạo múa tác nhân. // ES: Exportar las funciones y esquemas de coreografía del agente.\nexport { buyerAgent, sellerAgent, marketplaceAgent, BuyerAgentSchema, SellerAgentSchema, MarketplaceAgentSchema, ACPMessageSchema };\nexport type { BuyerAgent, SellerAgent, MarketplaceAgent, ACPMessage };\n```",
"spec_id": "AI-05"
}Audit Trail (2)
25d agotask_completedVertex Flash
25d agotask_createdfoundry_swiss_race
Task ID: c14b97e0-5000-4f5f-8b5d-d6fcb8a6b35a