Documentation Index
Fetch the complete documentation index at: https://docs.relaycore.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The RelayAgent class enables AI agents to:
- Discover services with reputation-based filtering
- Execute paid operations with automatic x402 payment
- Build workflows with fallbacks and retries
- Track outcomes for learning and optimization
Design Philosophy: Decision abstraction, not CRUD. Agents focus on what to do, not how to do it.
Installation
npm install @relaycore/sdk ethers
Quick Start
import { RelayAgent } from '@relaycore/sdk';
import { ethers } from 'ethers';
// Initialize agent
const agent = new RelayAgent({
wallet: new ethers.Wallet(privateKey, provider),
apiKey: 'rc_test_...',
network: 'cronos-testnet',
apiUrl: 'https://api.relaycore.xyz'
});
// Discover services
const services = await agent.discoverServices({
category: 'trading',
constraints: {
minReputation: 90,
maxPrice: '1000000', // 1 USDC
maxLatency: 5000
}
});
// Execute service with automatic payment
const result = await agent.execute(services[0].id, {
pair: 'BTC-USD',
side: 'long',
leverage: 10,
sizeUsd: 1000
});
console.log(result.data); // Quote data
console.log(result.payment); // { id, txHash, amount }
Core Methods
constructor(config: AgentConfig)
Initialize the agent with wallet and configuration.
Parameters:
interface AgentConfig {
wallet: ethers.Signer | string; // Wallet for signing payments
apiKey: string; // RelayCore API key
network?: Network; // 'cronos-testnet' | 'cronos-mainnet'
apiUrl?: string; // API endpoint (default: production)
}
Example:
const agent = new RelayAgent({
wallet: signer,
apiKey: process.env.RELAYCORE_API_KEY,
network: 'cronos-testnet'
});
discoverServices(criteria: ServiceCriteria): Promise<SelectedService[]>
Find services matching criteria with reputation-based scoring.
Parameters:
interface ServiceCriteria {
category?: string; // e.g., 'trading', 'data', 'oracle'
inputType?: string; // Expected input format
outputType?: string; // Expected output format
tags?: string[]; // Service tags
capabilities?: string[]; // Required capabilities
constraints?: TrustPolicy; // Trust constraints
}
interface TrustPolicy {
minReputation?: number; // Minimum reputation score (0-100)
maxLatency?: number; // Maximum latency in ms
maxPrice?: number; // Maximum price in base units
verifiedOnly?: boolean; // Only verified services
preferredProviders?: string[]; // Preferred provider addresses
blacklistedProviders?: string[]; // Excluded provider addresses
}
Returns:
interface SelectedService {
id: string;
name: string;
endpoint: string;
price: string; // In base units
provider: string; // Provider address
reputation: number; // Score 0-100
latency: number; // Avg latency in ms
selectionReason: string; // Why this service was selected
scoreBreakdown: {
reputation: number;
latency: number;
price: number;
total: number;
};
}
Example:
const services = await agent.discoverServices({
category: 'oracle',
tags: ['pyth', 'price-feed'],
constraints: {
minReputation: 85,
maxLatency: 3000,
maxPrice: '500000' // 0.5 USDC
}
});
// Services are sorted by composite score
console.log(services[0].selectionReason);
// "Highest composite score: reputation (95), low latency (1200ms), competitive price (0.3 USDC)"
Scoring Algorithm:
compositeScore = (reputation * 0.5) + (latencyScore * 0.3) + (priceScore * 0.2)
where:
latencyScore = max(0, 100 - (latency / 100))
priceScore = max(0, 100 - (price / maxPrice * 100))
Execute a service with automatic x402 payment handling.
Parameters:
serviceId: Service identifier from discoverServices
input: Service-specific input data
Returns:
interface ExecutionResult<T> {
success: boolean;
data?: T; // Service response
error?: ExecutionError; // Error if failed
payment?: {
id: string; // Payment ID
txHash: string; // Transaction hash
amount: string; // Amount paid (base units)
};
metrics: {
totalMs: number; // Total execution time
paymentMs?: number; // Payment settlement time
serviceMs?: number; // Service execution time
};
}
Example:
const result = await agent.execute<QuoteData>('service_abc123', {
pair: 'ETH-USD',
side: 'short',
leverage: 5,
sizeUsd: 500
});
if (result.success) {
console.log('Quote:', result.data);
console.log('Paid:', result.payment.amount, 'via', result.payment.txHash);
console.log('Execution time:', result.metrics.totalMs, 'ms');
} else {
console.error('Error:', result.error.message);
if (result.error.retryable) {
console.log('Retry after:', result.error.retryAfterMs, 'ms');
}
}
Payment Flow:
- Agent calls service endpoint
- If 402 response: generate EIP-3009 signature
- Settle payment via Facilitator
- Retry request with payment ID
- Return service response
executeWorkflow<T>(steps: WorkflowStep[]): Promise<WorkflowResult<T>>
Execute multi-step workflow with fallbacks and retries.
Parameters:
interface WorkflowStep<TInput, TOutput> {
name: string;
service?: SelectedService; // Pre-selected service
serviceId?: string; // Service ID to use
criteria?: ServiceCriteria; // Discover service dynamically
transform?: (input: TInput) => TOutput | Promise<TOutput>;
timeout?: number; // Step timeout in ms
retries?: number; // Retry attempts
fallback?: WorkflowStep<TInput, TOutput>; // Fallback step
onSuccess?: (result: TOutput) => void | Promise<void>;
onFailure?: (error: ExecutionError) => void | Promise<void>;
}
Returns:
interface WorkflowResult<T> {
success: boolean;
data?: T;
stepResults: Array<{
stepName: string;
success: boolean;
data?: unknown;
error?: ExecutionError;
durationMs: number;
}>;
totalMs: number;
completedSteps: number;
failedSteps: number;
}
Example:
const workflow = await agent.executeWorkflow([
{
name: 'get_price',
criteria: { category: 'oracle', tags: ['pyth'] },
timeout: 5000,
retries: 2
},
{
name: 'get_quote',
serviceId: 'perpai_service',
transform: (priceData) => ({
pair: 'BTC-USD',
entryPrice: priceData.price,
leverage: 10
}),
fallback: {
name: 'get_quote_backup',
criteria: { category: 'trading', minReputation: 80 }
}
},
{
name: 'execute_trade',
serviceId: 'dex_router',
onSuccess: async (result) => {
console.log('Trade executed:', result.txHash);
},
onFailure: async (error) => {
console.error('Trade failed:', error.message);
}
}
]);
console.log('Workflow completed:', workflow.success);
console.log('Steps:', workflow.completedSteps, '/', workflow.stepResults.length);
getMemory(): AgentMemory
Access execution history and statistics for learning.
Returns:
interface AgentMemory {
totalCalls: number;
successRate: number;
avgLatency: number;
record(outcome: OutcomeRecord): void;
getHistory(serviceId?: string): OutcomeRecord[];
getStats(): { totalCalls: number; successRate: number; avgLatency: number };
clear(): void;
}
interface OutcomeRecord {
timestamp: Date;
serviceId: string;
success: boolean;
latencyMs: number;
paymentAmount?: string;
error?: ExecutionError;
}
Example:
const memory = agent.getMemory();
// Get overall stats
console.log('Success rate:', memory.successRate, '%');
console.log('Avg latency:', memory.avgLatency, 'ms');
// Get history for specific service
const serviceHistory = memory.getHistory('service_abc123');
console.log('Service calls:', serviceHistory.length);
console.log('Service success rate:',
serviceHistory.filter(r => r.success).length / serviceHistory.length * 100
);
// Record custom outcome
memory.record({
timestamp: new Date(),
serviceId: 'custom_service',
success: true,
latencyMs: 1200,
paymentAmount: '10000'
});
Error Handling
Error Codes
enum ErrorCode {
INSUFFICIENT_BALANCE = 'INSUFFICIENT_BALANCE',
PAYMENT_FAILED = 'PAYMENT_FAILED',
SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',
SERVICE_TIMEOUT = 'SERVICE_TIMEOUT',
SERVICE_ERROR = 'SERVICE_ERROR',
INVALID_INPUT = 'INVALID_INPUT',
INVALID_OUTPUT = 'INVALID_OUTPUT',
NETWORK_ERROR = 'NETWORK_ERROR',
UNAUTHORIZED = 'UNAUTHORIZED',
RATE_LIMITED = 'RATE_LIMITED',
UNKNOWN = 'UNKNOWN'
}
Error Structure
interface ExecutionError {
code: ErrorCode;
message: string;
retryable: boolean;
retryAfterMs?: number;
details?: unknown;
}
Handling Errors
const result = await agent.execute(serviceId, input);
if (!result.success) {
switch (result.error.code) {
case 'INSUFFICIENT_BALANCE':
console.log('Fund wallet with USDC');
break;
case 'SERVICE_TIMEOUT':
if (result.error.retryable) {
await new Promise(r => setTimeout(r, result.error.retryAfterMs));
// Retry execution
}
break;
case 'RATE_LIMITED':
console.log('Wait', result.error.retryAfterMs, 'ms before retry');
break;
default:
console.error('Unhandled error:', result.error.message);
}
}
Advanced Usage
Custom Trust Policy
const conservativePolicy: TrustPolicy = {
minReputation: 95,
maxLatency: 2000,
maxPrice: '500000',
verifiedOnly: true,
preferredProviders: [
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
'0x1234567890abcdef1234567890abcdef12345678'
]
};
const services = await agent.discoverServices({
category: 'oracle',
constraints: conservativePolicy
});
Workflow with Conditional Logic
const workflow = await agent.executeWorkflow([
{
name: 'check_balance',
serviceId: 'balance_checker',
onSuccess: async (balance) => {
if (balance.usdc < 100) {
throw new Error('Insufficient balance for workflow');
}
}
},
{
name: 'get_market_data',
criteria: { category: 'data', tags: ['real-time'] },
transform: (data) => ({
shouldTrade: data.volatility < 0.05,
marketData: data
})
},
{
name: 'execute_trade',
serviceId: 'dex_router',
// Only executes if previous step returned shouldTrade: true
transform: (prev) => prev.shouldTrade ? prev.marketData : null
}
]);
Memory-Based Service Selection
const memory = agent.getMemory();
// Prefer services with good historical performance
const services = await agent.discoverServices({
category: 'trading',
constraints: {
minReputation: 85,
preferredProviders: memory.getHistory()
.filter(r => r.success && r.latencyMs < 2000)
.map(r => r.serviceId)
.slice(0, 3) // Top 3 performers
}
});
Best Practices
1. Always Handle Errors
try {
const result = await agent.execute(serviceId, input);
if (!result.success) {
// Handle error
}
} catch (error) {
// Handle exception
}
2. Use Workflows for Complex Operations
// ❌ Bad: Manual orchestration
const price = await agent.execute('oracle', {});
const quote = await agent.execute('trading', { price });
const trade = await agent.execute('dex', { quote });
// ✅ Good: Workflow with automatic error handling
const result = await agent.executeWorkflow([
{ name: 'get_price', serviceId: 'oracle' },
{ name: 'get_quote', serviceId: 'trading', transform: (price) => ({ price }) },
{ name: 'execute_trade', serviceId: 'dex', retries: 2 }
]);
3. Track Outcomes for Learning
const result = await agent.execute(serviceId, input);
agent.getMemory().record({
timestamp: new Date(),
serviceId,
success: result.success,
latencyMs: result.metrics.totalMs,
paymentAmount: result.payment?.amount
});
4. Use Trust Policies
// Define once, reuse everywhere
const productionPolicy: TrustPolicy = {
minReputation: 90,
maxLatency: 5000,
verifiedOnly: true
};
const services = await agent.discoverServices({
category: 'any',
constraints: productionPolicy
});
Next Steps
Service SDK
Build and monetize services
Session Management
Use session budgets for efficiency
Error Handling
Robust error handling patterns
First Payment Guide
Complete tutorial with code