Back to Skills
    🦞

    teneo-agent-sdk

    The Teneo SDK (`@teneo-protocol/sdk`) enables

    By @teneoprotocoldev
    View on GitHub
    SKILL.md
    # Teneo SDK Skill
    
    ## Overview
    
    The Teneo SDK (`@teneo-protocol/sdk`) enables connection to AI agents on the Teneo Protocol platform. It provides:
    
    - WebSocket-based real-time communication with AI agents
    - Wallet-based authentication using Ethereum private keys
    - Room management (private/public rooms, agent invitations)
    - x402 micropayment protocol for paid agent interactions
    - Multi-chain payment support (Base, Peaq, Avalanche)
    
    ## Installation
    
    ```bash
    npm install @teneo-protocol/sdk
    # or
    pnpm add @teneo-protocol/sdk
    ```
    
    ## Core Concepts
    
    ### Rooms
    Rooms are communication channels where users interact with AI agents:
    - **Private rooms**: Auto-available after authentication, no subscription needed
    - **Public rooms**: Require explicit subscription via `subscribeToRoom()`
    - Room ownership determines ability to invite agents
    
    ### Agents
    AI agents are identified by their `@handle` (e.g., `@x-agent-enterprise-v2`). Agents can be:
    - Discovered via `listAgents()` or `searchAgents()`
    - Invited to private rooms by room owners
    - Some require x402 payments for each interaction
    
    ### x402 Payment Protocol
    Micropayments for agent interactions using USDC on supported chains:
    - **Base** (chain ID: 8453) - Recommended for low fees
    - **Peaq** (chain ID: 3338)
    - **Avalanche** (chain ID: 43114)
    
    Payment amounts are typically $0.01 - $0.10 per request.
    
    ## Authentication & Connection
    
    ```typescript
    import { TeneoSDK } from "@teneo-protocol/sdk";
    
    const sdk = new TeneoSDK({
      wsUrl: "wss://backend.developer.chatroom.teneo-protocol.ai/ws",
      privateKey: "0x...", // Ethereum private key
      logLevel: "silent", // or "debug", "info", "warn", "error"
      maxReconnectAttempts: 30,
    
      // Payment configuration (required for paid agents)
      paymentNetwork: "eip155:8453", // Base network in CAIP-2 format
      paymentAsset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // Base USDC
    });
    
    // Connect (handles WebSocket + wallet signature auth)
    await sdk.connect();
    
    // Get authenticated wallet address
    const authState = sdk.getAuthState();
    console.log(`Authenticated as: ${authState.walletAddress}`);
    
    // Check connection status
    if (sdk.isConnected) {
      console.log("Connected!");
    }
    
    // Disconnect when done
    sdk.disconnect();
    ```
    
    ### Payment Network Configuration
    
    Use CAIP-2 format for `paymentNetwork`:
    
    | Network | CAIP-2 ID | Chain ID | USDC Contract |
    |---------|-----------|----------|---------------|
    | Base | `eip155:8453` | 8453 | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
    | Peaq | `eip155:3338` | 3338 | `0xbbA60da06c2c5424f03f7434542280FCAd453d10` |
    | Avalanche | `eip155:43114` | 43114 | `0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E` |
    
    ## Room Management
    
    ### Discovering Rooms
    
    ```typescript
    // Get all rooms available to this wallet (sync - cached after connect)
    const rooms = sdk.getRooms();
    
    for (const room of rooms) {
      console.log(`Room: ${room.name} [${room.id}]`);
      console.log(`  Public: ${room.is_public}`);
      console.log(`  Owner: ${room.is_owner}`);
    }
    ```
    
    ### Subscribing to Rooms
    
    ```typescript
    // Private rooms: auto-available after auth, no subscription needed
    // Public rooms: require explicit subscription
    
    const publicRoom = rooms.find(r => r.is_public);
    if (publicRoom) {
      await sdk.subscribeToRoom(publicRoom.id);
    }
    
    // Check subscribed rooms
    const subscribedRooms = sdk.getSubscribedRooms();
    console.log(`Subscribed to: ${subscribedRooms.join(", ")}`);
    ```
    
    ## Agent Discovery & Invitation
    
    ### Finding Available Agents
    
    ```typescript
    // List all available agents on the platform
    const agents = await sdk.listAgents();
    
    for (const agent of agents) {
      console.log(`Agent: ${agent.name} (@${agent.handle})`);
      console.log(`  ID: ${agent.agent_id}`);
      console.log(`  Description: ${agent.description}`);
      console.log(`  Price: ${agent.price_per_request || 0}`);
    }
    
    // Search for agents by name or keyword
    const results = await sdk.searchAgents("twitter");
    console.log(`Found ${results.length} agents matching "twitter"`);
    ```
    
    ### Listing Agents in a Room
    
    ```typescript
    // Get agents currently in a specific room
    const roomAgents = await sdk.listRoomAgents(roomId);
    
    for (const agent of roomAgents) {
      console.log(`  - ${agent.name} (${agent.agent_id})`);
    }
    ```
    
    ### Inviting Agents to Rooms
    
    Only room owners can invite agents:
    
    ```typescript
    // First, find the agent you want to invite
    const agents = await sdk.listAgents();
    const xAgent = agents.find(a => a.handle === "x-agent-enterprise-v2");
    
    if (xAgent) {
      // Add agent to your room by their agent_id
      await sdk.addAgentToRoom(roomId, xAgent.agent_id);
      console.log(`Invited ${xAgent.name} to room`);
    }
    
    // Or invite directly by known agent ID
    await sdk.addAgentToRoom(roomId, "x-agent-enterprise-v2");
    ```
    
    ### Ensuring Required Agents Are in Room
    
    ```typescript
    async function ensureAgentsInRoom(
      sdk: TeneoSDK,
      roomId: string,
      requiredAgentIds: string[]
    ): Promise<void> {
      // Get agents currently in the room
      const roomAgents = await sdk.listRoomAgents(roomId);
      const existingIds = new Set(roomAgents.map(a => a.agent_id?.toLowerCase()));
    
      // Find missing agents
      const missing = requiredAgentIds.filter(
        id => !existingIds.has(id.toLowerCase())
      );
    
      // Invite missing agents
      for (const agentId of missing) {
        try {
          await sdk.addAgentToRoom(roomId, agentId);
          console.log(`Invited agent "${agentId}" to room`);
        } catch (err: any) {
          console.warn(`Failed to invite "${agentId}": ${err.message}`);
        }
      }
    }
    
    // Usage
    await ensureAgentsInRoom(sdk, roomId, [
      "x-agent-enterprise-v2",
      "another-agent-id",
    ]);
    ```
    
    ## Sending Messages to Agents
    
    ### Basic Message
    
    ```typescript
    const response = await sdk.sendMessage("@x-agent-enterprise-v2 user @elonmusk", {
      waitForResponse: true,
      timeout: 60000, // 60 seconds
      format: "both", // Get both raw content and humanized version
    });
    
    console.log(response.humanized || response.content);
    ```
    
    ### Message with Room Context
    
    ```typescript
    const response = await sdk.sendMessage("@x-agent-enterprise-v2 post_stats 123456", {
      waitForResponse: true,
      timeout: 60000,
      format: "both",
      room: "room-id-here", // Specify target room
    });
    ```
    
    ### Common Agent Commands
    
    ```typescript
    // X/Twitter agent - Get user profile stats
    "@x-agent-enterprise-v2 user @username"
    
    // X/Twitter agent - Get post/tweet stats
    "@x-agent-enterprise-v2 post_stats 1234567890123456789"
    ```
    
    ## Event Handling
    
    ### Agent Responses
    
    ```typescript
    sdk.on("agent:response", (data) => {
      console.log(`Agent: ${data.agentName || data.agentId}`);
      console.log(`Success: ${data.success}`);
      console.log(`Content: ${data.humanized || data.content}`);
    
      if (data.error) {
        console.error(`Error: ${data.error}`);
      }
    });
    ```
    
    ### Payment Detection
    
    x402 payments are reflected in agent responses. Parse the response to detect payment amounts:
    
    ```typescript
    sdk.on("agent:response", (data) => {
      const content = data.humanized || data.content || "";
    
      // Common patterns for payment detection
      const patterns = [
        /x402 Payment \$([0-9.]+)/i,
        /Payment[:\s]+\$([0-9.]+)/i,
        /charged \$([0-9.]+)/i,
        /\$([0-9.]+)\s*(?:USDC|usdc)/i,
      ];
    
      for (const pattern of patterns) {
        const match = content.match(pattern);
        if (match) {
          const usdAmount = parseFloat(match[1]);
          console.log(`Payment: ${usdAmount} USDC`);
          break;
        }
      }
    });
    ```
    
    ### Connection Events
    
    ```typescript
    sdk.on("connection:open", () => {
      console.log("WebSocket connected");
    });
    
    sdk.on("disconnect", () => {
      console.log("Disconnected");
    });
    
    sdk.on("ready", () => {
      console.log("SDK ready for messages");
    });
    
    sdk.on("error", (err) => {
      // Handle rate limiting
      const rateLimitMatch = err.message.match(/Please wait (\d+)ms/);
      if (rateLimitMatch) {
        const waitMs = parseInt(rateLimitMatch[1], 10);
        console.log(`Rate limited, wait ${waitMs}ms`);
        return;
      }
    
      // Handle auth failures
      if (err.message.includes("Invalid challenge") ||
          err.message.includes("authentication failed")) {
        console.log("Authentication failed, reconnecting...");
        return;
      }
    
      console.error(`SDK Error: ${err.message}`);
    });
    ```
    
    ## Complete Example: Base Network Agent Interaction
    
    ```typescript
    import "dotenv/config";
    import { TeneoSDK } from "@teneo-protocol/sdk";
    
    // Configuration
    const BASE_USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
    const BASE_NETWORK = "eip155:8453";
    
    async function main() {
      // Initialize SDK with Base payment config
      const sdk = new TeneoSDK({
        wsUrl: "wss://backend.developer.chatroom.teneo-protocol.ai/ws",
        privateKey: process.env.PRIVATE_KEY!,
        logLevel: "info",
        maxReconnectAttempts: 10,
        paymentNetwork: BASE_NETWORK,
        paymentAsset: BASE_USDC,
      });
    
      // Track payments
      let totalSpent = 0;
    
      sdk.on("agent:response", (data) => {
        const content = data.humanized || data.content || "";
    
        // Detect x402 payment
        const match = content.match(/\$([0-9.]+)/);
        if (match) {
          const amount = parseFloat(match[1]);
          if (amount > 0 && amount < 1) { // Sanity check
            totalSpent += amount;
            console.log(`Payment: ${amount} | Total: ${totalSpent.toFixed(4)}`);
          }
        }
      });
    
      // Connect with retry logic
      for (let attempt = 1; attempt <= 5; attempt++) {
        try {
          await sdk.connect();
          console.log("Connected!");
          break;
        } catch (err: any) {
          // Handle rate limiting
          const rateLimitMatch = err.message?.match(/Please wait (\d+)ms/);
          if (rateLimitMatch) {
            const waitMs = parseInt(rateLimitMatch[1], 10) + 100;
            console.log(`Rate limited, waiting ${waitMs}ms...`);
            await sleep(waitMs);
            continue;
          }
          throw err;
        }
      }
    
      // Get wallet address
      const authState = sdk.getAuthState();
      console.log(`Wallet: ${authState.walletAddress}`);
    
      // Find a room (prefer private rooms)
      const rooms = sdk.getRooms();
      let selectedRoom = rooms.find(r => !r.is_public) || rooms[0];
    
      if (selectedRoom?.is_public) {
        await 
    
    ... (truncated)