Skip to main content

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:
register-agent.ts
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 Metadata

Update agent name, description, or metadata URI:
update-agent.ts
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:
batch-fetch-agents.ts
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:
verify-agent.ts
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
  }
}
Each agentId must be unique per owner. Use a different ID or update the existing agent.
Standard agents require ~0.02 SOL rent. Ensure your wallet has enough SOL:
solana balance --url devnet
solana airdrop 2 --url devnet
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