UNPKG

oneie

Version:

Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.

894 lines (786 loc) 24.6 kB
--- title: Integration Examples dimension: connections category: integration-examples.md tags: agent, ai, backend, ontology, protocol related_dimensions: events, groups, things scope: global created: 2025-11-03 updated: 2025-11-03 version: 1.0.0 ai_context: | This document is part of the connections dimension in the integration-examples.md category. Location: one/connections/integration-examples.md Purpose: Documents external integration examples Related dimensions: events, groups, things For AI agents: Read this to understand integration examples. --- # External Integration Examples **Purpose:** Reference implementations for integrating ONE Platform with external systems **Status:** Template patterns (implement when needed) **Last Updated:** 2025-10-25 --- ## Overview This document provides copy-paste patterns for common external integrations. All patterns follow the 6-dimension ontology and use protocol metadata where applicable. **Integration Categories:** 1. **Protocol-Based** - A2A, ACP, AP2, X402, AG-UI 2. **External Agents** - ElizaOS, ChatGPT plugins, custom agents 3. **External Workflows** - n8n, Zapier, Make automation 4. **External APIs** - Third-party services (Stripe, OpenAI, etc.) --- ## Pattern 1: A2A Protocol - Delegate Task to External Agent **Use Case:** ONE agent delegates a task to an external ElizaOS agent ```typescript // backend/convex/mutations/protocols/a2a.ts import { mutation } from "../../_generated/server"; import { v } from "convex/values"; /** * Delegate task to external agent via A2A protocol * * Creates: * - external_agent entity (if doesn't exist) * - delegated connection (oneAgent → externalAgent) * - task_event with protocol: "a2a" */ export const delegateTask = mutation({ args: { groupId: v.id("groups"), oneAgentId: v.id("entities"), externalPlatform: v.string(), // "elizaos", "chatgpt", etc. externalAgentId: v.string(), task: v.string(), parameters: v.any() }, handler: async (ctx, args) => { // 1. Get or create external_agent entity let externalAgent = await ctx.db .query("entities") .withIndex("group_type", q => q.eq("groupId", args.groupId).eq("type", "external_agent") ) .filter(q => q.and( q.eq(q.field("properties.platform"), args.externalPlatform), q.eq(q.field("properties.agentId"), args.externalAgentId) ) ) .first(); if (!externalAgent) { const externalAgentEntityId = await ctx.db.insert("entities", { groupId: args.groupId, type: "external_agent", name: `${args.externalPlatform} Agent (${args.externalAgentId})`, properties: { platform: args.externalPlatform, agentId: args.externalAgentId, protocol: "a2a", capabilities: [], // To be filled later status: "active" }, status: "active", createdAt: Date.now(), updatedAt: Date.now() }); externalAgent = await ctx.db.get(externalAgentEntityId); } if (!externalAgent) { throw new Error("Failed to create external agent entity"); } // 2. Create delegated connection const connectionId = await ctx.db.insert("connections", { groupId: args.groupId, fromEntityId: args.oneAgentId, toEntityId: externalAgent._id, relationshipType: "delegated", metadata: { protocol: "a2a", task: args.task, parameters: args.parameters, status: "pending", delegatedAt: Date.now() }, createdAt: Date.now() }); // 3. Log task_event await ctx.db.insert("events", { groupId: args.groupId, type: "task_event", actorId: args.oneAgentId, targetId: externalAgent._id, timestamp: Date.now(), metadata: { action: "delegated", protocol: "a2a", task: args.task, connectionId: connectionId, parameters: args.parameters } }); // 4. Call external agent API try { const response = await fetch( `https://agent.${args.externalPlatform}.com/api/tasks`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${process.env[`${args.externalPlatform.toUpperCase()}_API_KEY`]}` }, body: JSON.stringify({ task: args.task, parameters: args.parameters, callbackUrl: `${process.env.CONVEX_SITE_URL}/api/a2a/callback` }) } ); if (!response.ok) { throw new Error(`External agent API error: ${response.statusText}`); } const result = await response.json(); // Update connection with external task ID await ctx.db.patch(connectionId, { metadata: { ...externalAgent.properties, externalTaskId: result.taskId, status: "in_progress" } }); return { success: true, connectionId, externalTaskId: result.taskId }; } catch (error) { // Log failure event await ctx.db.insert("events", { groupId: args.groupId, type: "task_event", actorId: args.oneAgentId, targetId: externalAgent._id, timestamp: Date.now(), metadata: { action: "delegation_failed", protocol: "a2a", error: error instanceof Error ? error.message : "Unknown error" } }); throw error; } } }); /** * Handle A2A callback from external agent * * Called by external agent when task is complete */ export const handleCallback = mutation({ args: { connectionId: v.id("connections"), status: v.union(v.literal("completed"), v.literal("failed")), result: v.any() }, handler: async (ctx, args) => { const connection = await ctx.db.get(args.connectionId); if (!connection) { throw new Error("Connection not found"); } // Update connection status await ctx.db.patch(args.connectionId, { metadata: { ...connection.metadata, status: args.status, result: args.result, completedAt: Date.now() } }); // Log completion event await ctx.db.insert("events", { groupId: connection.groupId, type: "task_event", actorId: connection.toEntityId, targetId: connection.fromEntityId, timestamp: Date.now(), metadata: { action: args.status === "completed" ? "task_completed" : "task_failed", protocol: "a2a", connectionId: args.connectionId, result: args.result } }); return { success: true }; } }); ``` **Frontend Usage:** ```tsx // web/src/components/agents/TaskDelegation.tsx import { useMutation } from "convex/react"; import { api } from "@/convex/_generated/api"; import { Button } from "@/components/ui/button"; export function TaskDelegation({ agentId, groupId }) { const delegateTask = useMutation(api.mutations.protocols.a2a.delegateTask); const handleDelegate = async () => { const result = await delegateTask({ groupId, oneAgentId: agentId, externalPlatform: "elizaos", externalAgentId: "agent_research_123", task: "research_market_trends", parameters: { industry: "fitness", timeframe: "last_30_days", sources: ["google_trends", "social_media"] } }); console.log("Task delegated:", result); }; return ( <Button onClick={handleDelegate}> Delegate Research Task to ElizaOS </Button> ); } ``` --- ## Pattern 2: ACP Protocol - Agent-Initiated Purchase **Use Case:** External agent (ChatGPT, Claude) purchases a product ```typescript // backend/convex/mutations/protocols/acp.ts import { mutation } from "../../_generated/server"; import { v } from "convex/values"; /** * Handle agent purchase via ACP protocol * * Creates: * - external_agent entity (if doesn't exist) * - transacted connection (agent → product) * - commerce_event with protocol: "acp" */ export const handleAgentPurchase = mutation({ args: { productId: v.id("entities"), agentPlatform: v.string(), // "chatgpt", "claude", etc. agentUserId: v.string(), paymentMethod: v.string(), paymentDetails: v.any() }, handler: async (ctx, args) => { // 1. Get product (must be type: "product") const product = await ctx.db.get(args.productId); if (!product || product.type !== "product") { throw new Error("Invalid product"); } // 2. Get or create external_agent entity let agentThing = await ctx.db .query("entities") .withIndex("group_type", q => q.eq("groupId", product.groupId).eq("type", "external_agent") ) .filter(q => q.and( q.eq(q.field("properties.platform"), args.agentPlatform), q.eq(q.field("properties.userId"), args.agentUserId) ) ) .first(); if (!agentThing) { const agentEntityId = await ctx.db.insert("entities", { groupId: product.groupId, type: "external_agent", name: `${args.agentPlatform} Agent (${args.agentUserId})`, properties: { platform: args.agentPlatform, userId: args.agentUserId, protocol: "acp" }, status: "active", createdAt: Date.now(), updatedAt: Date.now() }); agentThing = await ctx.db.get(agentEntityId); } if (!agentThing) { throw new Error("Failed to create agent entity"); } // 3. Log commerce event (purchase initiated) const eventId = await ctx.db.insert("events", { groupId: product.groupId, type: "commerce_event", actorId: agentThing._id, targetId: product._id, timestamp: Date.now(), metadata: { protocol: "acp", eventType: "purchase_initiated", agentPlatform: args.agentPlatform, productId: args.productId, amount: product.properties.price, currency: product.properties.currency || "USD" } }); // 4. Process payment (integrate with Stripe, etc.) try { const paymentResult = await processPayment({ amount: product.properties.price, currency: product.properties.currency || "USD", method: args.paymentMethod, details: args.paymentDetails }); // 5. Create transacted connection await ctx.db.insert("connections", { groupId: product.groupId, fromEntityId: agentThing._id, toEntityId: product._id, relationshipType: "transacted", metadata: { protocol: "acp", transactionType: "purchase", amount: product.properties.price, currency: product.properties.currency || "USD", paymentId: paymentResult.id, status: "completed" }, createdAt: Date.now() }); // 6. Log completion event await ctx.db.insert("events", { groupId: product.groupId, type: "commerce_event", actorId: agentThing._id, targetId: product._id, timestamp: Date.now(), metadata: { protocol: "acp", eventType: "purchase_completed", paymentId: paymentResult.id, transactionId: paymentResult.transactionId } }); return { success: true, transactionId: paymentResult.transactionId, paymentId: paymentResult.id }; } catch (error) { // Log failure event await ctx.db.insert("events", { groupId: product.groupId, type: "commerce_event", actorId: agentThing._id, targetId: product._id, timestamp: Date.now(), metadata: { protocol: "acp", eventType: "purchase_failed", error: error instanceof Error ? error.message : "Unknown error" } }); throw error; } } }); // Helper function (integrate with your payment provider) async function processPayment(args: { amount: number; currency: string; method: string; details: any; }) { // Stripe integration example // const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); // const paymentIntent = await stripe.paymentIntents.create({ ... }); // return { id: paymentIntent.id, transactionId: paymentIntent.id }; return { id: `pay_${Date.now()}`, transactionId: `txn_${Date.now()}` }; } ``` **REST API Endpoint (when Hono is implemented):** ```typescript // backend/convex/http.ts (Hono) app.post("/api/protocols/acp/purchase", async (c) => { const body = await c.req.json(); const result = await c.env.ctx.runMutation( api.mutations.protocols.acp.handleAgentPurchase, { productId: body.productId, agentPlatform: body.agentPlatform, agentUserId: body.agentUserId, paymentMethod: body.paymentMethod, paymentDetails: body.paymentDetails } ); return c.json(result); }); ``` --- ## Pattern 3: X402 Protocol - HTTP Micropayments **Use Case:** Verify blockchain payment before granting API access ```typescript // backend/convex/mutations/protocols/x402.ts import { mutation } from "../../_generated/server"; import { v } from "convex/values"; /** * Verify X402 payment and grant API access * * Creates: * - payment_event with protocol: "x402" * - transacted connection (user → resource) */ export const verifyPayment = mutation({ args: { groupId: v.id("groups"), userId: v.id("entities"), resourceId: v.id("entities"), payment: v.object({ scheme: v.union(v.literal("permit"), v.literal("transfer")), network: v.string(), // "base", "ethereum", etc. amount: v.string(), signature: v.string(), permitData: v.optional(v.any()) }) }, handler: async (ctx, args) => { // 1. Log payment request event const requestEventId = await ctx.db.insert("events", { groupId: args.groupId, type: "payment_event", actorId: args.userId, targetId: args.resourceId, timestamp: Date.now(), metadata: { protocol: "x402", status: "requested", scheme: args.payment.scheme, network: args.payment.network, amount: args.payment.amount } }); // 2. Verify payment on blockchain try { const isValid = await verifyX402Payment(args.payment); if (!isValid) { throw new Error("Invalid X402 payment signature"); } // 3. Log payment verified event await ctx.db.insert("events", { groupId: args.groupId, type: "payment_event", actorId: args.userId, targetId: args.resourceId, timestamp: Date.now(), metadata: { protocol: "x402", status: "verified", requestEventId: requestEventId, transactionHash: args.payment.signature } }); // 4. Create transacted connection await ctx.db.insert("connections", { groupId: args.groupId, fromEntityId: args.userId, toEntityId: args.resourceId, relationshipType: "transacted", metadata: { protocol: "x402", transactionType: "micropayment", amount: args.payment.amount, network: args.payment.network, transactionHash: args.payment.signature }, createdAt: Date.now() }); // 5. Grant access (return API token or execute request) return { accessGranted: true, token: generateApiToken(), expiresIn: 3600 // 1 hour }; } catch (error) { // Log failure event await ctx.db.insert("events", { groupId: args.groupId, type: "payment_event", actorId: args.userId, targetId: args.resourceId, timestamp: Date.now(), metadata: { protocol: "x402", status: "verification_failed", error: error instanceof Error ? error.message : "Unknown error" } }); throw error; } } }); // Helper functions async function verifyX402Payment(payment: any): Promise<boolean> { // Implement blockchain verification logic // Example: Verify permit signature with viem/ethers return true; // Placeholder } function generateApiToken(): string { // Generate temporary API token return `token_${Date.now()}_${Math.random().toString(36).slice(2)}`; } ``` --- ## Pattern 4: External Workflow Integration (n8n, Zapier) **Use Case:** Trigger n8n workflow when event occurs ```typescript // backend/convex/mutations/integrations/n8n.ts import { mutation } from "../../_generated/server"; import { v } from "convex/values"; /** * Trigger n8n workflow * * Creates: * - external_workflow entity (if doesn't exist) * - workflow_triggered event */ export const triggerWorkflow = mutation({ args: { groupId: v.id("groups"), workflowName: v.string(), webhookUrl: v.string(), payload: v.any() }, handler: async (ctx, args) => { // 1. Get or create external_workflow entity let workflow = await ctx.db .query("entities") .withIndex("group_type", q => q.eq("groupId", args.groupId).eq("type", "external_workflow") ) .filter(q => q.eq(q.field("name"), args.workflowName)) .first(); if (!workflow) { const workflowId = await ctx.db.insert("entities", { groupId: args.groupId, type: "external_workflow", name: args.workflowName, properties: { platform: "n8n", webhookUrl: args.webhookUrl }, status: "active", createdAt: Date.now(), updatedAt: Date.now() }); workflow = await ctx.db.get(workflowId); } if (!workflow) { throw new Error("Failed to create workflow entity"); } // 2. Trigger webhook try { const response = await fetch(args.webhookUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(args.payload) }); if (!response.ok) { throw new Error(`Webhook failed: ${response.statusText}`); } // 3. Log workflow_triggered event await ctx.db.insert("events", { groupId: args.groupId, type: "workflow_event", actorId: workflow._id, timestamp: Date.now(), metadata: { action: "triggered", workflow: args.workflowName, platform: "n8n", payload: args.payload, status: "success" } }); return { success: true }; } catch (error) { // Log failure event await ctx.db.insert("events", { groupId: args.groupId, type: "workflow_event", actorId: workflow._id, timestamp: Date.now(), metadata: { action: "trigger_failed", workflow: args.workflowName, error: error instanceof Error ? error.message : "Unknown error" } }); throw error; } } }); ``` --- ## Pattern 5: External API Integration (Stripe, OpenAI) **Use Case:** Call external API service (Stripe payment processing) ```typescript // backend/convex/mutations/integrations/stripe.ts import { mutation } from "../../_generated/server"; import { v } from "convex/values"; /** * Process payment via Stripe * * Creates: * - transacted connection (user → product) * - payment_event */ export const processPayment = mutation({ args: { groupId: v.id("groups"), userId: v.id("entities"), productId: v.id("entities"), amount: v.number(), currency: v.string(), paymentMethodId: v.string() }, handler: async (ctx, args) => { // Get product const product = await ctx.db.get(args.productId); if (!product) { throw new Error("Product not found"); } // Log payment initiated await ctx.db.insert("events", { groupId: args.groupId, type: "payment_event", actorId: args.userId, targetId: args.productId, timestamp: Date.now(), metadata: { action: "initiated", provider: "stripe", amount: args.amount, currency: args.currency } }); try { // Call Stripe API const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); const paymentIntent = await stripe.paymentIntents.create({ amount: Math.round(args.amount * 100), // Convert to cents currency: args.currency, payment_method: args.paymentMethodId, confirm: true }); // Create transacted connection await ctx.db.insert("connections", { groupId: args.groupId, fromEntityId: args.userId, toEntityId: args.productId, relationshipType: "transacted", metadata: { provider: "stripe", paymentIntentId: paymentIntent.id, amount: args.amount, currency: args.currency, status: paymentIntent.status }, createdAt: Date.now() }); // Log success event await ctx.db.insert("events", { groupId: args.groupId, type: "payment_event", actorId: args.userId, targetId: args.productId, timestamp: Date.now(), metadata: { action: "completed", provider: "stripe", paymentIntentId: paymentIntent.id, amount: args.amount, currency: args.currency } }); return { success: true, paymentIntentId: paymentIntent.id, status: paymentIntent.status }; } catch (error) { // Log failure event await ctx.db.insert("events", { groupId: args.groupId, type: "payment_event", actorId: args.userId, targetId: args.productId, timestamp: Date.now(), metadata: { action: "failed", provider: "stripe", error: error instanceof Error ? error.message : "Unknown error" } }); throw error; } } }); ``` --- ## Integration Testing Pattern ```typescript // web/test/integration/external-api.test.ts import { describe, it, expect } from "vitest"; import { ConvexHttpClient } from "convex/browser"; import { api } from "../../../backend/convex/_generated/api"; const convex = new ConvexHttpClient(process.env.PUBLIC_CONVEX_URL!); describe("External Integration: A2A Protocol", () => { it("should delegate task to external agent", async () => { const result = await convex.mutation( api.mutations.protocols.a2a.delegateTask, { groupId: testGroupId, oneAgentId: testAgentId, externalPlatform: "elizaos", externalAgentId: "agent_research_123", task: "research_market_trends", parameters: { industry: "fitness", timeframe: "last_30_days" } } ); expect(result.success).toBe(true); expect(result.connectionId).toBeDefined(); expect(result.externalTaskId).toBeDefined(); }); it("should log protocol metadata in events", async () => { const events = await convex.query(api.queries.events.list, { groupId: testGroupId }); const a2aEvent = events.find(e => e.metadata?.protocol === "a2a" && e.metadata?.action === "delegated" ); expect(a2aEvent).toBeDefined(); expect(a2aEvent?.metadata?.task).toBe("research_market_trends"); }); }); ``` --- ## Key Principles 1. **Always create entities** - External systems represented as things (external_agent, external_workflow, external_connection) 2. **Use protocol metadata** - Store protocol identifier in metadata.protocol field 3. **Log all events** - Track every integration action with proper event types 4. **Handle errors gracefully** - Log failure events, implement retries 5. **Multi-tenant isolation** - All integrations scoped to groupId 6. **Test end-to-end** - Verify complete flows including external API calls --- **Next Steps:** 1. Implement Hono REST API layer (when external API needed) 2. Add protocol-specific endpoints (A2A, ACP, X402, AP2) 3. Create SDKs for external developers 4. Write comprehensive integration tests 5. Document API patterns for partners **See Also:** - `/Users/toc/Server/ONE/one/connections/integration-phase2.md` - Integration layer documentation - `/Users/toc/Server/ONE/one/connections/protocols.md` - Protocol specifications - `/Users/toc/Server/ONE/one/knowledge/specifications.md` - Protocol integration patterns