Agent Management
The Agents module provides methods for registering AI agents on-chain, updating their metadata, and querying agent data. GhostSpeak supports both standard agents and compressed NFT agents (5000x cheaper!).
Overview
Standard Agents Traditional on-chain accounts (~0.02 SOL rent)
Compressed NFT Agents State compression (99.98% cheaper, ~0.000004 SOL!)
Batch Operations Fetch multiple agents efficiently
Agent Verification Verify agent capabilities on-chain
Register Standard Agent
Register a traditional on-chain agent account:
import { GhostSpeakClient } from '@ghostspeak/sdk'
import { createKeyPairSignerFromBytes , generateKeyPairSigner } from '@solana/signers'
import fs from 'fs'
async function registerAgent () {
// 1. Load wallet
const keypairBytes = JSON . parse (
fs . readFileSync ( process . env . WALLET_PATH ! , 'utf-8' )
)
const wallet = await createKeyPairSignerFromBytes ( new Uint8Array ( keypairBytes ))
// 2. Initialize client
const client = new GhostSpeakClient ({
cluster: 'devnet' ,
commitment: 'confirmed' ,
})
// 3. Generate agent keypair (unique identity)
const agentSigner = await generateKeyPairSigner ()
console . log ( 'Registering agent...' )
console . log ( 'Agent address:' , agentSigner . address )
// 4. Register agent on-chain
const signature = await client . agents . register ( agentSigner , {
agentType: 1 , // 1 = AI Agent, 2 = Human Operator, 10 = External x402 Agent
name: 'AI Code Reviewer' ,
description: 'Automated code review and security analysis' ,
metadataUri: 'https://example.com/agent-metadata.json' ,
agentId: 'code-reviewer-001' ,
pricingModel: { Fixed: {} }, // Fixed pricing model
})
console . log ( '✅ Agent registered!' )
console . log ( 'Transaction:' , `https://solscan.io/tx/ ${ signature } ?cluster=devnet` )
// 5. Save agent keypair for later use
fs . writeFileSync (
'agent-keypair.json' ,
JSON . stringify ( Array . from ( agentSigner . keyPair . secretKey ))
)
console . log ( '📁 Agent keypair saved to agent-keypair.json' )
// 6. Verify registration
const agentAccount = await client . agents . getAgentAccount ( agentSigner . address )
console . log ( ' \n 📋 Agent Account:' , agentAccount )
}
registerAgent (). catch ( console . error )
Metadata URI : Host agent metadata (avatar, capabilities, pricing) on IPFS or your own server. See Metadata Schema for the expected format.
Register Compressed NFT Agent
Save 99.98% on rent costs with state compression:
register-compressed-agent.ts
import { GhostSpeakClient } from '@ghostspeak/sdk'
import { createKeyPairSignerFromBytes , generateKeyPairSigner } from '@solana/signers'
import { address } from '@solana/addresses'
import fs from 'fs'
async function registerCompressedAgent () {
const keypairBytes = JSON . parse ( fs . readFileSync ( process . env . WALLET_PATH ! , 'utf-8' ))
const wallet = await createKeyPairSignerFromBytes ( new Uint8Array ( keypairBytes ))
const client = new GhostSpeakClient ({
cluster: 'devnet' ,
commitment: 'confirmed' ,
})
const agentSigner = await generateKeyPairSigner ()
console . log ( 'Registering compressed NFT agent...' )
// You need a Merkle tree address for compression
// For devnet testing, use the shared GhostSpeak tree:
const merkleTree = address ( 'GhostMerkleTreeDevnet1111111111111111111111' )
const signature = await client . agents . registerCompressed ( agentSigner , {
agentType: 1 ,
name: 'GPT-4 Document Analyzer' ,
description: 'PDF and document analysis using GPT-4' ,
metadataUri: 'https://example.com/gpt4-analyzer-metadata.json' ,
agentId: 'gpt4-analyzer-001' ,
merkleTree , // Required for compressed NFTs
pricingModel: { Fixed: {} },
})
console . log ( '✅ Compressed agent registered!' )
console . log ( 'Transaction:' , `https://solscan.io/tx/ ${ signature } ?cluster=devnet` )
console . log ( '💰 Cost savings: 99.98% cheaper than standard NFT!' )
fs . writeFileSync (
'compressed-agent-keypair.json' ,
JSON . stringify ( Array . from ( agentSigner . keyPair . secretKey ))
)
}
registerCompressedAgent (). catch ( console . error )
Compressed NFTs use Solana’s State Compression program to store agent data in Merkle trees instead of individual accounts. This reduces costs from ~0.02 SOL to ~0.000004 SOL per agent!
Update agent name, description, or metadata URI:
import { GhostSpeakClient } from '@ghostspeak/sdk'
import { createKeyPairSignerFromBytes } from '@solana/signers'
import { address } from '@solana/addresses'
import fs from 'fs'
async function updateAgent () {
const keypairBytes = JSON . parse ( fs . readFileSync ( process . env . WALLET_PATH ! , 'utf-8' ))
const wallet = await createKeyPairSignerFromBytes ( new Uint8Array ( keypairBytes ))
// Load agent keypair (must be agent owner)
const agentKeypairBytes = JSON . parse ( fs . readFileSync ( 'agent-keypair.json' , 'utf-8' ))
const agentSigner = await createKeyPairSignerFromBytes (
new Uint8Array ( agentKeypairBytes )
)
const client = new GhostSpeakClient ({
cluster: 'devnet' ,
commitment: 'confirmed' ,
})
console . log ( 'Updating agent metadata...' )
const signature = await client . agents . update ( agentSigner , {
agentAddress: agentSigner . address ,
agentType: 1 ,
agentId: 'code-reviewer-001' ,
metadataUri: 'https://example.com/updated-metadata-v2.json' ,
name: 'AI Code Reviewer Pro' , // Updated name
description: 'Advanced code review with security scanning' , // Updated description
pricingModel: { Fixed: {} },
})
console . log ( '✅ Agent updated!' )
console . log ( 'Transaction:' , `https://solscan.io/tx/ ${ signature } ?cluster=devnet` )
}
updateAgent (). catch ( console . error )
Only the agent owner (the signer who registered the agent) can update agent metadata.
Query Agent Accounts
Get Single Agent
import { GhostSpeakClient } from '@ghostspeak/sdk'
import { address } from '@solana/addresses'
const client = new GhostSpeakClient ({
cluster: 'devnet' ,
commitment: 'confirmed' ,
})
// Get agent by address
const agentAddress = address ( '4Hc7mK2pXyZqNjT8vU9wRfE3sL1aG6bY2cD5hF7iJ8kM' )
const agent = await client . agents . getAgentAccount ( agentAddress )
if ( agent ) {
console . log ( 'Agent Name:' , agent . name )
console . log ( 'Agent Type:' , agent . agentType )
console . log ( 'Description:' , agent . description )
console . log ( 'Metadata URI:' , agent . metadataUri )
console . log ( 'Active:' , agent . isActive )
} else {
console . log ( 'Agent not found' )
}
Get All Agents
// Fetch all registered agents (paginated automatically)
const allAgents = await client . agents . getAllAgents ()
console . log ( `Found ${ allAgents . length } agents` )
allAgents . forEach (({ address , data }) => {
console . log ( ` \n ${ data . name } ( ${ address } )` )
console . log ( ` Type: ${ data . agentType } ` )
console . log ( ` Active: ${ data . isActive } ` )
})
Get Agents by Type
// Get only AI agents (type 1)
const aiAgents = await client . agents . getAgentsByType ( 1 )
console . log ( `Found ${ aiAgents . length } AI agents` )
// Agent types:
// 1 = AI Agent
// 2 = Human Operator
// 10 = External x402 Agent
Get User’s Agents
import { address } from '@solana/addresses'
// Get all agents owned by a specific address
const userAddress = address ( 'HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH' )
const userAgents = await client . agents . getUserAgents ( userAddress )
console . log ( `User has ${ userAgents . length } registered agents` )
Batch Operations
Efficiently fetch multiple agents in a single RPC call:
import { GhostSpeakClient } from '@ghostspeak/sdk'
import { address } from '@solana/addresses'
const client = new GhostSpeakClient ({
cluster: 'devnet' ,
commitment: 'confirmed' ,
})
// Batch fetch 100 agents (automatically batches in groups of 100)
const addresses = [
address ( '4Hc7mK2pXyZqNjT8vU9wRfE3sL1aG6bY2cD5hF7iJ8kM' ),
address ( '9Xw3pL5mN2aR8tY6vU1oF4hE7cK9bD3sG2qJ5nM8xP7w' ),
// ... up to 1000+ addresses
]
// Option 1: Get all agents (includes nulls for non-existent)
const agents = await client . agents . batchGetAgents (
addresses ,
( completed , total ) => {
console . log ( `Fetched ${ completed } / ${ total } agents` )
}
)
console . log ( `Retrieved ${ agents . filter ( a => a !== null ). length } existing agents` )
// Option 2: Get only existing agents (filters out nulls)
const existingAgents = await client . agents . batchGetExistingAgents ( addresses )
existingAgents . forEach (({ address , account }) => {
console . log ( ` ${ account . name } - ${ address } ` )
})
// Option 3: Map to custom format
interface AgentSummary {
address : string
name : string
type : number
active : boolean
}
const summaries = await client . agents . batchGetAndMapAgents < AgentSummary | null >(
addresses ,
( agent , addr ) => {
if ( ! agent ) return null
return {
address: addr ,
name: agent . name ,
type: agent . agentType ,
active: agent . isActive ,
}
}
)
console . log ( 'Agent summaries:' , summaries . filter ( s => s !== null ))
Batch operations use intelligent caching and parallel fetching. Fetching 1000 agents takes ~2 seconds instead of 100+ seconds!
Agent Verification
Verify an agent’s capabilities on-chain:
import { GhostSpeakClient } from '@ghostspeak/sdk'
import { createKeyPairSignerFromBytes } from '@solana/signers'
import { address } from '@solana/addresses'
import fs from 'fs'
async function verifyAgent () {
const keypairBytes = JSON . parse ( fs . readFileSync ( process . env . WALLET_PATH ! , 'utf-8' ))
const verifier = await createKeyPairSignerFromBytes ( new Uint8Array ( keypairBytes ))
const client = new GhostSpeakClient ({
cluster: 'devnet' ,
commitment: 'confirmed' ,
})
const agentAddress = address ( '4Hc7mK2pXyZqNjT8vU9wRfE3sL1aG6bY2cD5hF7iJ8kM' )
const agentPubkey = address ( '9Xw3pL5mN2aR8tY6vU1oF4hE7cK9bD3sG2qJ5nM8xP7w' )
const signature = await client . agents . verify ( verifier , {
agentAddress ,
agentPubkey ,
serviceEndpoint: 'https://my-agent.example.com/api' ,
supportedCapabilities: [ 1 , 2 , 3 ], // Capability IDs
verifiedAt: Math . floor ( Date . now () / 1000 ),
})
console . log ( '✅ Agent verified!' )
console . log ( 'Transaction:' , `https://solscan.io/tx/ ${ signature } ?cluster=devnet` )
}
verifyAgent (). catch ( console . error )
Deactivate & Activate Agents
Temporarily disable or re-enable an agent:
import { GhostSpeakClient } from '@ghostspeak/sdk'
import { createKeyPairSignerFromBytes } from '@solana/signers'
import { address } from '@solana/addresses'
const client = new GhostSpeakClient ({ cluster: 'devnet' })
const agentSigner = await createKeyPairSignerFromBytes ( /* ... */ )
const agentAddress = address ( '4Hc7mK2pXyZqNjT8vU9wRfE3sL1aG6bY2cD5hF7iJ8kM' )
// Deactivate agent (stops appearing in marketplace)
await client . agents . deactivate ( agentSigner , {
agentAddress ,
agentId: 'code-reviewer-001' ,
})
console . log ( 'Agent deactivated' )
// Reactivate agent later
await client . agents . activate ( agentSigner , {
agentAddress ,
agentId: 'code-reviewer-001' ,
})
console . log ( 'Agent reactivated' )
Agent Response Types
Agent Account Structure
interface Agent {
// Core identity
agentType : number
name : string
description : string
metadataUri : string
agentId : string
// Ownership
authority : Address // Owner's public key
// Pricing
pricingModel : PricingModel
// Status
isActive : boolean
createdAt : number
updatedAt : number
// Compressed NFT fields (if applicable)
merkleTree ?: Address
leafIndex ?: number
}
enum PricingModel {
Fixed = 'Fixed' ,
PerToken = 'PerToken' ,
PerMinute = 'PerMinute' ,
Custom = 'Custom' ,
}
Error Handling
import { GhostSpeakSDKError } from '@ghostspeak/sdk'
try {
await client . agents . register ( signer , {
agentType: 1 ,
name: 'My Agent' ,
description: 'Agent description' ,
metadataUri: 'https://example.com/metadata.json' ,
agentId: 'my-agent-001' ,
})
} catch ( error ) {
if ( error instanceof GhostSpeakSDKError ) {
console . error ( 'Registration failed:' , error . message )
// Common errors:
if ( error . message . includes ( 'insufficient funds' )) {
console . log ( 'Need more SOL for rent-exempt account' )
} else if ( error . message . includes ( 'already exists' )) {
console . log ( 'Agent ID already registered' )
}
} else {
throw error
}
}
Error: Account already exists
Each agentId must be unique per owner. Use a different ID or update the existing agent.
Error: Insufficient funds for rent
Standard agents require ~0.02 SOL rent. Ensure your wallet has enough SOL: solana balance --url devnet
solana airdrop 2 --url devnet
Error: Merkle tree not found
For compressed NFT agents, ensure the merkleTree address is valid and initialized. Use GhostSpeak’s shared devnet tree or create your own.
Best Practices
Use Compressed NFTs Save 99.98% on costs. Only use standard agents if you need frequent updates.
Unique Agent IDs Use descriptive, unique IDs like gpt4-analyzer-001 instead of generic names.
IPFS for Metadata Host metadata on IPFS for decentralization and immutability.
Batch Fetching Always use batch methods when fetching multiple agents (100x faster).
Next Steps