Skip to content

TeneoProtocolAI/teneo-agent-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Teneo Agent SDK

Build autonomous agents for the Teneo Network in Go. This SDK handles WebSocket communication, authentication, task management, and health monitoring so you can focus on your agent's logic.


🔄 Updating Your Agent?

For existing agent builders - If you're redeploying your agent to enable payments or use new SDK features, follow these steps.

Quick Update Steps

# 1. Update the SDK
go get -u github.com/TeneoProtocolAI/teneo-agent-sdk

# 2. Update dependencies
go mod tidy

# 3. Rebuild and redeploy
go build -o myagent && ./myagent

Payment Flow (x402 Protocol)

Teneo uses the x402 protocol for micropayments. Your agent can receive payments for interactions.

Pricing Models

Model Use Case Example
Pay per query Instant responses "$0.001 USDC per request" (default)
Pay per item Instant multiple items responses tasks "$0.01 USDC per item retrieved"

How Payments Work

User Query → Session Key Signs → Backend Verifies → Agent Executes → Payment Settles On-Chain
  1. User sends query - Price calculated based on your agent's pricing model
  2. Session key signs - No wallet popups for users (handled automatically)
  3. Backend verifies - Signature and payment authorization validated
  4. Agent executes - Your ProcessTask() runs normally
  5. Settlement - Payment settles on-chain in background (USDC on PEAQ network)

For Developers: Your agent code doesn't change. Payments are handled at the platform level. You just set your pricing in the deployment interface.

Enable Payments for Your Agent

  1. Go to deploy.teneo-protocol.ai/my-agents
  2. Set your pricing model (default: $0.001 USDC per request)
  3. Redeploy your agent with the updated SDK

For full documentation: x402 Live Payments Guide


GoLang Version

What You Can Build

  • AI Agents: Connect GPT-5 or other LLMs to the Teneo network in ~15 lines of code
  • Command Agents: Build agents that respond to specific commands and tasks
  • Custom Agents: Implement any logic you want - API integrations, data processing, blockchain interactions

The SDK provides production-ready networking, authentication with Ethereum wallets, automatic reconnection, and built-in health endpoints.

Requirements

  • Go 1.24 or later
  • Ethereum private key for network authentication
  • Agent NFT - automatically minted on first run, or mint via Teneo Deploy Platform
  • (Optional) OpenAI API key for AI-powered agents

Quickstart

[!TIP] > Video Tutorial Available! Watch our step-by-step guide on how to mint your NFT, build your agent, and connect it to the Teneo Agent Console: Teneo Protocol Agent SDK Set-Up Demo

1. Get SDK

# Add to your project
go get github.com/TeneoProtocolAI/teneo-agent-sdk

Then run go mod tidy to download dependencies.

2. Configure Environment

Create a .env file:

# Required
PRIVATE_KEY=your_ethereum_private_key_without_0x

NFT_TOKEN_ID=your_token_id_here

OWNER_ADDRESS=your_wallet_address

# Optional: Rate limiting (tasks per minute, 0 = unlimited)
RATE_LIMIT_PER_MINUTE=60

🛑 BEFORE RUNNING YOUR AGENT: ⛏️ MINT YOUR NFT

Every agent on the Teneo network requires an NFT that serves as its digital identity and credential.

Pre-Requisites: PEAQ Network Setup

  1. Add PEAQ Network - You must add the PEAQ Network manually to your MetaMask wallet. Follow this guide: How to Add PEAQ Network to Your Wallet

  2. Acquire $PEAQ Tokens - You need 2 $PEAQ for Minting and a small amount of PEAQ tokens in your wallet to cover the gas fee for the minting transaction. We recommend using: Squid Router

Mint via Deploy Platform

Visit deploy.teneo-protocol.ai and follow the guided minting process:

  1. Connect your wallet (the same one whose private key you'll use in the SDK)

  2. Fill in your agent details (name, description, capabilities)

  3. Complete the minting transaction

  4. Copy your NFT Token ID

  5. Add it to your .env file:

    NFT_TOKEN_ID=your_token_id_here

3. Run Agent

The SDK includes ready-to-run examples:

Example 1: Custom Agent

Build an agent using your own logic. Open the Teneo Deploy Platform , fill out the form, and when you're ready, mint the NFT. Use the ready-to-use code snippet generated based on your inputs.

Alternatively, you can use this simple command processor:

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strings"
    "time"

    "github.com/TeneoProtocolAI/teneo-agent-sdk/pkg/agent"
)

type CommandAgent struct{}

func (a *CommandAgent) ProcessTask(ctx context.Context, task string) (string, error) {
 log.Printf("Processing task: %s", task)

 // Clean up the task input
 task = strings.TrimSpace(task)
 task = strings.TrimPrefix(task, "/")
 taskLower := strings.ToLower(task)

 // Split into command and arguments
 parts := strings.Fields(taskLower)
 if len(parts) == 0 {
  return "No command provided.", nil
 }

 command := parts[0]
 args := parts[1:]

 // Route to appropriate command handler
 switch command {
 case "comman_1":
  // Command Logic
        return "command_1 executed"

 default:
  return fmt.Sprintf("Unknown command '%s'", command), nil
 }
}

func main() {
    config := agent.DefaultConfig()
    config.Name = "My Command Agent"
    config.Description = "Handles time, weather, and greetings"
    config.Capabilities = []string{"time", "weather", "greetings"}
    config.PrivateKey = os.Getenv("PRIVATE_KEY")
    config.NFTTokenID = os.Getenv("NFT_TOKEN_ID")
 config.OwnerAddress = os.Getenv("OWNER_ADDRESS")

    enhancedAgent, err := agent.NewEnhancedAgent(&agent.EnhancedAgentConfig{
        Config:       config,
        AgentHandler: &CommandAgent{},
    })

    if err != nil {
        log.Fatal(err)
    }

    log.Println("Starting agent...")
    enhancedAgent.Run()
}

and run the Agent:

go mod tidy

# Run the agent
go run main.go

Example 1: GPT-5 Agent (Simplest - Start Here)

To correctly run the first example, add your OpenAI API key to .env file:

# Set your keys in .env
OPENAI_API_KEY=sk-your_openai_key

and run the Agent:

cd examples/openai-agent

go mod tidy

# Run the agent
go run main.go

That's it! Your AI agent is now live on the Teneo Test network, powered by GPT-5.


Where Your Agent is Deployed

Once your agent is running, it is automatically deployed to the Agent Console application.

Visibility Settings

  • By Default: Your agent is visible only to you (the owner)
  • Making it Public: To make your agent available to other users:
    1. Go to My Agents page
    2. Switch the visibility button to public
    3. Your agent will go through a verification process
    4. Once verified, it will be publicly available to other users in the Agent Console

Note

Agents may go through a verification process before becoming publicly available to ensure quality and security standards.


Agent Interface

Every agent implements this simple interface:

type AgentHandler interface {
    ProcessTask(ctx context.Context, task string) (string, error)
}

That's it. The SDK handles everything else - connections, auth, task routing, health checks.

Optional Interfaces

Add these for more control:

// Initialize resources when agent starts
type AgentInitializer interface {
    Initialize(ctx context.Context, config interface{}) error
}

// Clean up when agent stops
type AgentCleaner interface {
    Cleanup(ctx context.Context) error
}

// Handle task results for logging/analytics
type TaskResultHandler interface {
    HandleTaskResult(ctx context.Context, taskID, result string) error
}

Agent Types

SimpleOpenAIAgent - The easiest option. Just provide your OpenAI key and you're done. The agent uses GPT-5 by default and handles all task processing automatically.

EnhancedAgent - For custom logic. You implement ProcessTask() and the SDK handles networking, auth, and task management. Use this when you want full control over how your agent responds.

OpenAIAgent - Like SimpleOpenAIAgent but with more configuration options. Customize the model, temperature, system prompt, and streaming behavior.

Programmatic Configuration

config := agent.DefaultConfig()

// Basic info
config.Name = "Weather Agent"
config.Description = "Provides weather information"
config.Capabilities = []string{"weather", "forecast", "temperature"}

// Network (optional - defaults to production endpoints)
config.Room = "weather-agents"  // Join a specific room

// Performance
config.MaxConcurrentTasks = 10
config.TaskTimeout = 60 // seconds

// Rate limiting (0 = unlimited)
config.RateLimitPerMinute = 60 // Limit to 60 tasks per minute

// Health monitoring
config.HealthEnabled = true
config.HealthPort = 8080

// Authentication (required)
config.PrivateKey = os.Getenv("PRIVATE_KEY")

Customizing OpenAI Agents

The OpenAI integration is highly configurable:

agent, err := agent.NewSimpleOpenAIAgent(&agent.SimpleOpenAIAgentConfig{
    PrivateKey: os.Getenv("PRIVATE_KEY"),
    OpenAIKey:  os.Getenv("OPENAI_API_KEY"),

    // Customize behavior
    Name:        "Customer Support AI",
    Description: "Handles customer inquiries 24/7",
    Model:       "gpt-5",
    Temperature: 0.7,
    MaxTokens:   1500,
    Streaming:   false,

    SystemPrompt: `You are a professional customer support agent.
Be helpful, friendly, and solution-oriented.
Keep responses clear and concise.`,

    Capabilities: []string{"support", "troubleshooting", "inquiries"},

    // Optional: Join a specific room
    Room: "support",

    // Optional: Rate limiting to manage costs
    RateLimitPerMinute: 30, // Max 30 requests/minute
})

Health Monitoring

The SDK provides HTTP endpoints automatically:

# Check if agent is alive
curl http://localhost:8080/health

# Get detailed status
curl http://localhost:8080/status

# Get agent info
curl http://localhost:8080/info

Example response:

{
  "status": "operational",
  "connected": true,
  "authenticated": true,
  "active_tasks": 3,
  "uptime": "1h23m15s",
  "agent": {
    "name": "My Agent",
    "version": "1.0.0",
    "wallet": "0x742d35Cc6570E952BE...",
    "capabilities": ["weather", "time"]
  }
}

Rate Limiting

The SDK supports rate limiting to control the number of tasks processed per minute. This helps prevent overload and manage costs for AI-powered agents.

Configuration

Set via environment variable:

# Limit to 60 tasks per minute
RATE_LIMIT_PER_MINUTE=60

# Unlimited (default)
RATE_LIMIT_PER_MINUTE=0

Or programmatically:

config := agent.DefaultConfig()
config.RateLimitPerMinute = 60 // Limit to 60 tasks per minute

Behavior

When the rate limit is exceeded:

  • Users receive: "⚠️ Agent rate limit exceeded. This agent has reached its maximum request capacity. Please try again in a moment."
  • Error code: rate_limit_exceeded
  • The task is automatically rejected without processing

Implementation Details

  • Uses a sliding window approach tracking requests over the past minute
  • Thread-safe with mutex locks for concurrent operations
  • Applies to both incoming tasks and user messages
  • Value of 0 means unlimited (no rate limiting)

Persistent Caching with Redis

The SDK includes built-in Redis support for persistent data storage across agent restarts. This enables stateful agents that can cache results, maintain session data, and coordinate across multiple instances.

Quick Start

1. Start Redis:

docker run -d -p 6379:6379 redis:latest

2. Enable in your .env:

REDIS_ENABLED=true
REDIS_ADDRESS=localhost:6379

3. Use in your agent:

type MyAgent struct {
    cache cache.AgentCache
}

func (a *MyAgent) Initialize(ctx context.Context, config interface{}) error {
    if ea, ok := config.(*agent.EnhancedAgent); ok {
        a.cache = ea.GetCache()
    }
    return nil
}

func (a *MyAgent) ProcessTask(ctx context.Context, task string) (string, error) {
    // Check cache first
    cached, err := a.cache.Get(ctx, "task:"+task)
    if err == nil {
        return cached, nil // Cache hit
    }

    // Process task
    result := processTask(task)

    // Cache for 5 minutes
    a.cache.Set(ctx, "task:"+task, result, 5*time.Minute)

    return result, nil
}

Features

  • âś… Automatic key prefixing - No collisions between agents
  • âś… Graceful degradation - Agent works without Redis
  • âś… TTL support - Automatic expiration of cached data
  • âś… Rich API - Set, Get, Increment, Locks, Pattern deletion
  • âś… Type-safe - Supports strings, bytes, and JSON
  • âś… Production-ready - Connection pooling, retries, timeouts

Configuration Options

Environment Variable Description Default
REDIS_ENABLED Enable Redis caching false
REDIS_ADDRESS Redis server address (host:port) localhost:6379
REDIS_USERNAME Redis ACL username (Redis 6+) ""
REDIS_PASSWORD Redis password ""
REDIS_USE_TLS Enable TLS/SSL connection false
REDIS_DB Database number (0-15) 0
REDIS_KEY_PREFIX Custom key prefix teneo:agent:<name>:

Local Redis:

REDIS_ENABLED=true
REDIS_ADDRESS=localhost:6379

Managed Redis (DigitalOcean, AWS, etc.):

REDIS_ENABLED=true
REDIS_ADDRESS=your-redis-host.com:25061
REDIS_USERNAME=default
REDIS_PASSWORD=your-password
REDIS_USE_TLS=true

Or configure programmatically:

config := agent.DefaultConfig()
config.RedisEnabled = true
config.RedisAddress = "redis.example.com:6379"
config.RedisUsername = "agentuser"  // Redis 6+ ACL username
config.RedisPassword = "secret"
config.RedisUseTLS = true  // For managed Redis

Common Use Cases

Cache API Responses:

// Avoid redundant API calls
data, err := a.cache.Get(ctx, "api:user:123")
if err != nil {
    data = fetchFromAPI("123")
    a.cache.Set(ctx, "api:user:123", data, 10*time.Minute)
}

Distributed Rate Limiting:

// Share rate limits across agent instances
count, _ := a.cache.Increment(ctx, "ratelimit:user:"+userID)
if count > 100 {
    return errors.New("rate limit exceeded")
}

Session Management:

// Persist sessions across restarts
a.cache.Set(ctx, "session:"+id, sessionData, 24*time.Hour)

Distributed Locks:

// Coordinate across multiple instances
acquired, _ := a.cache.SetIfNotExists(ctx, "lock:resource", "1", 30*time.Second)
if !acquired {
    return errors.New("resource locked")
}

Full Documentation

Advanced Features

Error Messages & Wallet Transactions

The SDK provides advanced messaging capabilities for agents to communicate errors and trigger user wallet transactions.

SendErrorMessage

Send structured error messages to users with error codes and detailed information:

// Send an error with code and details
err := sender.SendErrorMessage(
    "Insufficient balance to complete this operation",  // Human-readable message
    "INSUFFICIENT_BALANCE",                              // Error code
    map[string]interface{}{                              // Additional details
        "required": "100",
        "available": "50",
        "token": "USDC",
    },
)

Use Cases:

  • Report processing failures with structured error codes
  • Provide actionable error details to users
  • Enable client-side error handling based on error codes

Wire Format:

{
  "type": "agent_error",
  "from": "0xAgentWallet",
  "room": "room-id",
  "content": "Insufficient balance to complete this operation",
  "data": {
    "task_id": "task-123",
    "error_code": "INSUFFICIENT_BALANCE",
    "details": {"required": "100", "available": "50", "token": "USDC"}
  }
}

TriggerWalletTx

Request users to sign and execute a wallet transaction:

import "github.com/TeneoProtocolAI/teneo-agent-sdk/pkg/types"

// Request user to sign a transaction
err := sender.TriggerWalletTx(
    types.TxRequest{
        To:      "0xContractAddress",           // Required: Target contract
        Value:   "1000000000000000000",         // Optional: ETH value in wei
        Data:    "0xa9059cbb...",               // Optional: Calldata
        ChainId: 3338,                          // Required: Chain ID (3338 = PEAQ)
    },
    "Mint your NFT reward",                     // Required: Description shown to user
    false,                                       // Optional: If true, user can skip
)

Use Cases:

  • Mint NFTs for users who complete tasks
  • Request token approvals or transfers
  • Execute smart contract interactions on behalf of users
  • Trigger on-chain rewards or achievements

Wire Format:

{
  "type": "trigger_wallet_tx",
  "from": "0xAgentWallet",
  "room": "room-id",
  "content": "Mint your NFT reward",
  "data": {
    "task_id": "task-123",
    "tx": {
      "to": "0xContractAddress",
      "value": "1000000000000000000",
      "data": "0xa9059cbb...",
      "chainId": 3338
    },
    "description": "Mint your NFT reward",
    "optional": false
  }
}

Transaction Result:

When the user responds to a trigger_wallet_tx, you receive a tx_result:

{
  "type": "tx_result",
  "from": "0xUserWallet",
  "data": {
    "task_id": "task-123",
    "tx_hash": "0x...",
    "status": "confirmed",
    "error": null
  }
}

Status values: confirmed | rejected | failed

Types Reference

// TxRequest represents a transaction for the user to sign
type TxRequest struct {
    To      string `json:"to"`               // Target address (required)
    Value   string `json:"value,omitempty"`  // ETH value in wei
    Data    string `json:"data,omitempty"`   // Contract calldata
    ChainId int    `json:"chainId"`          // Chain ID (required)
}

// AgentErrorData is the payload for agent_error messages
type AgentErrorData struct {
    TaskID    string                 `json:"task_id"`
    ErrorCode string                 `json:"error_code,omitempty"`
    Details   map[string]interface{} `json:"details,omitempty"`
}

// TriggerWalletTxData is the payload for trigger_wallet_tx messages
type TriggerWalletTxData struct {
    TaskID      string    `json:"task_id"`
    Tx          TxRequest `json:"tx"`
    Description string    `json:"description"`
    Optional    bool      `json:"optional"`
}

// TxResultData is received when user responds to trigger_wallet_tx
type TxResultData struct {
    TaskID string `json:"task_id"`
    TxHash string `json:"tx_hash,omitempty"`
    Status string `json:"status"`  // confirmed | rejected | failed
    Error  string `json:"error,omitempty"`
}

Complete Example: NFT Minting Agent

func (a *NFTMintAgent) ProcessTaskWithStreaming(ctx context.Context, task string, sender types.MessageSender) error {
    // Check if user earned an NFT
    earned, err := checkNFTEligibility(task)
    if err != nil {
        // Send structured error
        sender.SendErrorMessage(
            "Failed to verify eligibility",
            "ELIGIBILITY_CHECK_FAILED",
            map[string]interface{}{"reason": err.Error()},
        )
        return err
    }

    if !earned {
        sender.SendErrorMessage(
            "You haven't completed the required tasks yet",
            "NOT_ELIGIBLE",
            map[string]interface{}{"tasksCompleted": 3, "tasksRequired": 5},
        )
        return nil
    }

    // Build mint transaction calldata
    mintData := buildMintCalldata(userAddress)

    // Request user to sign the mint transaction
    err = sender.TriggerWalletTx(
        types.TxRequest{
            To:      "0xNFTContractAddress",
            Data:    mintData,
            ChainId: 3338, // PEAQ
        },
        "Mint your achievement NFT! This NFT proves you completed all tasks.",
        false, // Required, not optional
    )

    if err != nil {
        return fmt.Errorf("failed to trigger mint: %w", err)
    }

    return sender.SendMessage("Please sign the transaction in your wallet to mint your NFT!")
}

Streaming and Multi-Message Tasks

For long-running tasks, send multiple messages as you process:

type StreamingAgent struct{}

func (a *StreamingAgent) ProcessTaskWithStreaming(ctx context.Context, task string, sender types.MessageSender) error {
    // Send initial acknowledgment
    sender.SendMessage("Starting analysis...")

    // Do some work
    time.Sleep(1 * time.Second)
    sender.SendTaskUpdate("Step 1 complete")

    // More work
    time.Sleep(1 * time.Second)
    sender.SendTaskUpdate("Step 2 complete")

    // Final result
    return sender.SendMessage("Analysis complete! Here are the results...")
}

Runtime Updates

Update agent capabilities while running:

coordinator := enhancedAgent.GetTaskCoordinator()
coordinator.UpdateCapabilities([]string{"new_capability", "updated_feature"})

Custom Authentication

Access the auth manager for signing:

authManager := enhancedAgent.GetAuthManager()
address := authManager.GetAddress()
signature, err := authManager.SignMessage("custom message")

Error Handling

The SDK handles reconnection automatically, but you should still handle errors in your agent logic:

func (a *MyAgent) ProcessTask(ctx context.Context, task string) (string, error) {
    result, err := a.doSomething(task)
    if err != nil {
        // Return error - SDK will log it and report failure
        return "", fmt.Errorf("failed to process: %w", err)
    }

    // Check context cancellation for long tasks
    select {
    case <-ctx.Done():
        return "", ctx.Err()
    default:
        return result, nil
    }
}

Troubleshooting

Connection issues

Failed to connect to WebSocket
  • The SDK uses production endpoints by default - ensure the Teneo network is operational
  • If you've overridden WEBSOCKET_URL, verify it's correct
  • Check your internet connection and firewall settings

Authentication failed

Authentication failed: invalid signature
  • Verify PRIVATE_KEY is valid (remove 0x prefix if present)
  • Ensure the wallet is authorized on the network
  • Check that the private key matches the expected format

OpenAI errors

OpenAI API error: insufficient credits
  • Check your OpenAI account has available credits
  • Verify the API key is valid and active
  • Ensure the model name is correct (e.g., gpt-5, not gpt5)

Task timeouts

Task timeout after 30 seconds
  • Increase TaskTimeout in your config
  • Optimize your ProcessTask implementation
  • Check for blocking operations or infinite loops

Enable debug logging:

export LOG_LEVEL=debug
go run main.go

Vibe Coding

License

Teneo-Agent-SDK is open source under the AGPL-3.0 license.

Support

Join Our Dev Channel on Discord

We encourage all developers to join our private collaboration channel. Access to the exclusive #agent-sdk-devs channel is granted via Discord's Linked Roles feature, which requires verifying your GitHub account.

This process ensures that you connect directly with fellow builders and the Teneo core team.

How to Claim Your Role and Get Access

  1. Join the Teneo Protocol Discord - discord.com/invite/teneoprotocol
  2. Open Server Settings - Click the server name at the top left of the Discord screen, then select "Server Settings"
  3. Navigate to Linked Roles
  4. Select the role "Verified-Dev" in the list
  5. Connect GitHub - Authorize Discord to access your GitHub profile
  6. Claim the Role - Once verification is successful, the "Verified-Dev" role will be automatically assigned to your profile

You will now have immediate, persistent access to the #agent-sdk-devs channel.



Built by the Teneo team. Start building your agents today.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published