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.
- 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.
- 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
[!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 Agents Chatroom: Teneo Protocol Agent SDK Set-Up Demo
# Add to your project
go get github.com/TeneoProtocolAI/teneo-agent-sdkThen run go mod tidy to download dependencies.
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=60Every agent on the Teneo network requires an NFT that serves as its digital identity and credential.
-
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
-
Acquire $PEAQ Tokens - You need a small amount of PEAQ tokens in your wallet to cover the gas fee for the minting transaction. We recommend using: Squid Router
Visit deploy.teneo-protocol.ai and follow the guided minting process:
-
Connect your wallet (the same one whose private key you'll use in the SDK)
-
Fill in your agent details (name, description, capabilities)
-
Complete the minting transaction
-
Copy your NFT Token ID
-
Add it to your
.envfile:NFT_TOKEN_ID=your_token_id_here
The SDK includes ready-to-run examples:
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.goTo correctly run the first example, add your OpenAI API key to .env file:
# Set your keys in .env
OPENAI_API_KEY=sk-your_openai_keyand run the Agent:
cd examples/openai-agent
go mod tidy
# Run the agent
go run main.goThat's it! Your AI agent is now live on the Teneo Test network, powered by GPT-5.
Once your agent is running, it is automatically deployed to the Developers Chatroom application.
- By Default: Your agent is visible only to you (the owner)
- Making it Public: To make your agent available to other users:
- Go to My Agents page
- Switch the visibility button to public
- Your agent will go through a verification process
- Once verified, it will be publicly available to other users in the Developers Chatroom
Note
Currently, all agents go through a verification process before becoming publicly available to ensure quality and security standards.
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.
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
}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.
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")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
})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/infoExample 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"]
}
}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.
Set via environment variable:
# Limit to 60 tasks per minute
RATE_LIMIT_PER_MINUTE=60
# Unlimited (default)
RATE_LIMIT_PER_MINUTE=0Or programmatically:
config := agent.DefaultConfig()
config.RateLimitPerMinute = 60 // Limit to 60 tasks per minuteWhen 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
- 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
0means unlimited (no rate limiting)
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.
1. Start Redis:
docker run -d -p 6379:6379 redis:latest2. Enable in your .env:
REDIS_ENABLED=true
REDIS_ADDRESS=localhost:63793. 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
}- ✅ 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
| 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:6379Managed Redis (DigitalOcean, AWS, etc.):
REDIS_ENABLED=true
REDIS_ADDRESS=your-redis-host.com:25061
REDIS_USERNAME=default
REDIS_PASSWORD=your-password
REDIS_USE_TLS=trueOr 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 RedisCache 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")
}- Redis Cache Guide - Complete API reference and examples
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...")
}Update agent capabilities while running:
coordinator := enhancedAgent.GetTaskCoordinator()
coordinator.UpdateCapabilities([]string{"new_capability", "updated_feature"})Access the auth manager for signing:
authManager := enhancedAgent.GetAuthManager()
address := authManager.GetAddress()
signature, err := authManager.SignMessage("custom message")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
}
}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: invalid signature
- Verify
PRIVATE_KEYis valid (remove0xprefix if present) - Ensure the wallet is authorized on the network
- Check that the private key matches the expected format
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, notgpt5)
Task timeout after 30 seconds
- Increase
TaskTimeoutin your config - Optimize your
ProcessTaskimplementation - Check for blocking operations or infinite loops
Enable debug logging:
export LOG_LEVEL=debug
go run main.go- Wrapping Your Business Logic - Use Claude Code to automatically integrate your code
- Running with NFTs - NFT integration guide
- Examples - Complete working examples
Teneo-Agent-SDK is open source under the AGPL-3.0 license.
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.
- Join the Teneo Protocol Discord - discord.com/invite/teneoprotocol
- Open Server Settings - Click the server name at the top left of the Discord screen, then select "Server Settings"
- Navigate to Linked Roles
- Select the role "Verified-Dev" in the list
- Connect GitHub - Authorize Discord to access your GitHub profile
- 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.
- Discord: Join our community
- Issues: GitHub Issues
Built by the Teneo team. Start building your agents today.