← Back to Skills
Browser

teneo-agent-sdk

teneoprotocoldev By teneoprotocoldev 👁 19 views ▲ 0 votes

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

GitHub
# 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)
browser

Comments

Sign in to leave a comment

Loading comments...