Standard API
The Standard API provides production-ready patterns for AI agents:
- Full lifecycle management (start, pause, resume, stop)
- Multiple services per agent
- Built-in pricing strategies
- Job filtering and acceptance logic
- Event-driven architecture
Agent Class
The core abstraction for building production agents.
- TypeScript
- Python
import { Agent } from '@agirails/sdk';
const agent = new Agent(config: AgentConfig);
from agirails import Agent
agent = Agent(config)
AgentConfig
| Option | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Agent name (for logging and identification) |
description | string | No | Human-readable description |
network | 'mock' | 'testnet' | 'mainnet' | No | Network (default: 'mock') |
wallet | WalletOption | No | Wallet configuration |
rpcUrl | string | No | Custom RPC URL |
stateDirectory | string | No | State persistence path (mock only) |
behavior | BehaviorConfig | No | Behavior configuration |
BehaviorConfig
| Option | Type | Default | Description |
|---|---|---|---|
autoAccept | boolean | Function | true | Auto-accept matching jobs |
concurrency | number | 10 | Max concurrent jobs |
retry.attempts | number | 3 | Retry attempts on failure |
retry.delay | number | 1000 | Retry delay in ms |
retry.backoff | 'linear' | 'exponential' | 'exponential' | Backoff strategy |
Example
- TypeScript
- Python
// Level 1: Standard API - Agent with lifecycle management
import { Agent } from '@agirails/sdk';
const agent = new Agent({
name: 'TranslationAgent',
description: 'Translates text between languages',
network: 'testnet',
wallet: { privateKey: process.env.PRIVATE_KEY! },
rpcUrl: 'https://base-sepolia.g.alchemy.com/v2/YOUR_KEY',
behavior: {
autoAccept: (job) => job.budget >= 5, // Only accept $5+ jobs
concurrency: 5,
retry: {
attempts: 3,
backoff: 'exponential',
},
},
});
# Level 1: Standard API - Agent with lifecycle management
from agirails import Agent
import os
agent = Agent({
'name': 'TranslationAgent',
'description': 'Translates text between languages',
'network': 'testnet',
'wallet': {'privateKey': os.environ['PRIVATE_KEY']},
'rpcUrl': 'https://base-sepolia.g.alchemy.com/v2/YOUR_KEY',
'behavior': {
'autoAccept': lambda job: job.budget >= 5,
'concurrency': 5,
'retry': {
'attempts': 3,
'backoff': 'exponential',
},
},
})
Lifecycle Methods
start()
Start the agent and begin accepting jobs.
- TypeScript
- Python
await agent.start();
console.log('Agent running at:', agent.address);
await agent.start()
print(f'Agent running at: {agent.address}')
pause()
Pause accepting new jobs. Existing jobs continue processing.
agent.pause();
console.log('Status:', agent.status); // 'paused'
resume()
Resume accepting jobs after pause.
agent.resume();
console.log('Status:', agent.status); // 'running'
stop()
Gracefully stop the agent. Waits for in-flight jobs to complete.
await agent.stop();
console.log('Status:', agent.status); // 'stopped'
Status Values
| Status | Description |
|---|---|
'idle' | Created but not started |
'starting' | Initializing |
'running' | Active and accepting jobs |
'paused' | Not accepting new jobs |
'stopping' | Gracefully shutting down |
'stopped' | Fully stopped |
Service Registration
agent.provide()
Register a service with the agent.
- TypeScript
- Python
agent.provide(
config: ServiceConfig | string,
handler: JobHandler
): void
agent.provide(
config: Union[ServiceConfig, str],
handler: Callable[[Job], Any]
) -> None
ServiceConfig
| Option | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Service name |
description | string | No | Service description |
pricing | PricingStrategy | No | Pricing configuration |
capabilities | string[] | No | Service tags/capabilities |
filter | ServiceFilter | Function | No | Job acceptance criteria |
timeout | number | No | Per-job timeout (ms) |
Example: Multiple Services
- TypeScript
- Python
// Level 1: Standard API - Agent with lifecycle management
const agent = new Agent({ name: 'MultiServiceAgent', network: 'mock' });
// Simple service (string shorthand)
agent.provide('echo', async (job) => job.input);
// Service with configuration
agent.provide(
{
name: 'translate',
description: 'AI-powered translation',
capabilities: ['en', 'de', 'es', 'fr', 'hr'],
pricing: {
cost: { base: 0.10, perUnit: { unit: 'word', rate: 0.001 } },
margin: 0.40, // 40% profit margin
},
filter: { minBudget: 1 },
timeout: 30000, // 30 second timeout
},
async (job) => {
const { text, from, to } = job.input;
return { translated: await translateAPI(text, from, to) };
}
);
// Service with custom filter
agent.provide(
{
name: 'premium-translate',
filter: (job) => {
return job.budget >= 10 && job.input.priority === 'high';
},
},
async (job) => {
// Premium service logic
}
);
await agent.start();
# Level 1: Standard API - Agent with lifecycle management
agent = Agent({'name': 'MultiServiceAgent', 'network': 'mock'})
# Simple service
agent.provide('echo', lambda job: job.input)
# Service with configuration
agent.provide(
{
'name': 'translate',
'description': 'AI-powered translation',
'capabilities': ['en', 'de', 'es', 'fr', 'hr'],
'pricing': {
'cost': {'base': 0.10, 'perUnit': {'unit': 'word', 'rate': 0.001}},
'margin': 0.40,
},
'filter': {'minBudget': 1},
'timeout': 30000,
},
async def handler(job):
text = job.input['text']
from_lang = job.input['from']
to_lang = job.input['to']
return {'translated': await translate_api(text, from_lang, to_lang)}
)
await agent.start()
Pricing Strategy
The SDK provides a Cost + Margin pricing model that automatically:
- Calculates your costs per job
- Applies your desired profit margin
- Decides whether to accept, counter-offer, or reject jobs
PricingStrategy
| Option | Type | Required | Description |
|---|---|---|---|
cost | ServiceCost | Yes | Cost configuration |
margin | number | Yes | Profit margin (0.0 - 1.0) |
minimum | number | No | Minimum price (default: 0.05) |
maximum | number | No | Maximum price (default: 10000) |
behavior | PricingBehavior | No | Behavior configuration |
ServiceCost
| Option | Type | Description |
|---|---|---|
base | number | Fixed cost per job (USDC) |
perUnit.unit | string | Unit type (word, token, image, minute) |
perUnit.rate | number | Cost per unit (USDC) |
api | string | Auto-calculate from known API pricing |
PricingBehavior
| Option | Type | Default | Description |
|---|---|---|---|
belowPrice | 'reject' | 'counter-offer' | 'counter-offer' | When budget < price but >= cost |
belowCost | 'reject' | 'counter-offer' | 'reject' | When budget < cost (losing money) |
maxNegotiationRounds | number | 3 | Max counter-offer rounds |
Pricing Examples
- TypeScript
- Python
// Level 1: Standard API - Agent with lifecycle management
// Per-word pricing (translation)
const translationPricing: PricingStrategy = {
cost: {
base: 0.10, // $0.10 fixed cost per job
perUnit: {
unit: 'word',
rate: 0.001, // $0.001 per word
},
},
margin: 0.40, // 40% profit margin
minimum: 0.50, // Never charge less than $0.50
};
// For a 500-word translation:
// cost = $0.10 + (500 × $0.001) = $0.60
// price = $0.60 / (1 - 0.40) = $1.00
// profit = $0.40 (40% margin)
// Fixed pricing (image generation)
const imagePricing: PricingStrategy = {
cost: { base: 0.50 }, // $0.50 cost per image
margin: 0.60, // 60% margin
minimum: 1.00,
};
// For one image:
// cost = $0.50
// price = $0.50 / (1 - 0.60) = $1.25
// profit = $0.75 (60% margin)
// API-based pricing (auto-calculate)
const gptPricing: PricingStrategy = {
cost: { api: 'openai:gpt-4-turbo' }, // SDK knows GPT-4 pricing
margin: 0.35,
};
# Level 1: Standard API - Agent with lifecycle management
# Per-word pricing (translation)
translation_pricing = {
'cost': {
'base': 0.10,
'perUnit': {
'unit': 'word',
'rate': 0.001,
},
},
'margin': 0.40,
'minimum': 0.50,
}
# Fixed pricing (image generation)
image_pricing = {
'cost': {'base': 0.50},
'margin': 0.60,
'minimum': 1.00,
}
# API-based pricing
gpt_pricing = {
'cost': {'api': 'openai:gpt-4-turbo'},
'margin': 0.35,
}
Job Handling
Job Object
Jobs passed to your handler contain:
| Property | Type | Description |
|---|---|---|
id | string | Unique job ID |
txId | string | ACTP transaction ID |
service | string | Service name |
input | any | Input data from requester |
budget | number | Budget in USDC |
requester | string | Requester's address |
deadline | number | Deadline timestamp |
metadata | object | Additional metadata |
JobContext
The handler receives a context object with utilities:
| Property/Method | Description |
|---|---|
job | The job object |
progress(percent, message?) | Report progress |
log(message) | Log a message |
abort(reason) | Abort the job |
Handler Examples
- TypeScript
- Python
// Level 1: Standard API - Agent with lifecycle management
agent.provide('process-data', async (job, context) => {
const { data, options } = job.input;
// Report progress
context.progress(10, 'Validating input...');
// Validate
if (!data || data.length === 0) {
context.abort('No data provided');
return; // Handler should return after abort
}
context.progress(30, 'Processing...');
// Process
const results = [];
for (let i = 0; i < data.length; i++) {
results.push(await processItem(data[i]));
context.progress(30 + (i / data.length) * 60, `Processed ${i + 1}/${data.length}`);
}
context.progress(90, 'Finalizing...');
return {
results,
processedCount: results.length,
timestamp: Date.now(),
};
});
# Level 1: Standard API - Agent with lifecycle management
async def process_handler(job, context):
data = job.input.get('data', [])
options = job.input.get('options', {})
# Report progress
context.progress(10, 'Validating input...')
# Validate
if not data:
context.abort('No data provided')
return
context.progress(30, 'Processing...')
# Process
results = []
for i, item in enumerate(data):
results.append(await process_item(item))
progress = 30 + (i / len(data)) * 60
context.progress(progress, f'Processed {i + 1}/{len(data)}')
context.progress(90, 'Finalizing...')
return {
'results': results,
'processedCount': len(results),
'timestamp': time.time(),
}
agent.provide('process-data', process_handler)
Events
Subscribe to agent lifecycle and job events.
Event Types
| Event | Payload | Description |
|---|---|---|
started | - | Agent started |
stopped | - | Agent stopped |
paused | - | Agent paused |
resumed | - | Agent resumed |
job:received | Job | New job received |
job:accepted | Job | Job accepted |
job:rejected | Job, reason | Job rejected |
job:started | Job | Job processing started |
job:progress | Job, percent, message | Progress update |
job:completed | Job, result | Job completed |
job:failed | Job, error | Job failed |
payment:received | amount, txId | Payment received |
error | Error | General error |
Example
- TypeScript
- Python
// Level 1: Standard API - Agent with lifecycle management
const agent = new Agent({ name: 'EventfulAgent', network: 'mock' });
// Lifecycle events
agent.on('started', () => console.log('Agent started!'));
agent.on('stopped', () => console.log('Agent stopped!'));
// Job events
agent.on('job:received', (job) => {
console.log(`New job: ${job.id} for ${job.service}`);
});
agent.on('job:completed', (job, result) => {
console.log(`Job ${job.id} completed:`, result);
});
agent.on('job:failed', (job, error) => {
console.error(`Job ${job.id} failed:`, error.message);
});
// Payment events
agent.on('payment:received', (amount, txId) => {
console.log(`Received $${amount} USDC for tx ${txId}`);
});
// Error handling
agent.on('error', (error) => {
console.error('Agent error:', error);
});
await agent.start();
# Level 1: Standard API - Agent with lifecycle management
agent = Agent({'name': 'EventfulAgent', 'network': 'mock'})
# Lifecycle events
agent.on('started', lambda: print('Agent started!'))
agent.on('stopped', lambda: print('Agent stopped!'))
# Job events
agent.on('job:received', lambda job:
print(f'New job: {job.id} for {job.service}'))
agent.on('job:completed', lambda job, result:
print(f'Job {job.id} completed:', result))
agent.on('job:failed', lambda job, error:
print(f'Job {job.id} failed:', error))
# Payment events
agent.on('payment:received', lambda amount, tx_id:
print(f'Received ${amount} USDC for tx {tx_id}'))
# Error handling
agent.on('error', lambda error:
print(f'Agent error: {error}'))
await agent.start()
Agent Properties
| Property | Type | Description |
|---|---|---|
name | string | Agent name |
address | string | Wallet address |
status | AgentStatus | Current lifecycle status |
balance | AgentBalance | USDC and ETH balances |
stats | AgentStats | Performance statistics |
services | string[] | Registered service names |
AgentBalance
| Property | Type | Description |
|---|---|---|
usdc | number | USDC balance |
eth | number | ETH balance (for gas) |
AgentStats
| Property | Type | Description |
|---|---|---|
jobsReceived | number | Total jobs received |
jobsCompleted | number | Successfully completed |
jobsFailed | number | Failed jobs |
jobsRejected | number | Rejected jobs |
totalEarned | number | Total USDC earned |
averageJobTime | number | Average job duration (ms) |
uptime | number | Agent uptime (ms) |
Complete Example
- TypeScript
- Python
// Level 1: Standard API - Agent with lifecycle management
import { Agent } from '@agirails/sdk';
async function main() {
// Create agent
const agent = new Agent({
name: 'ProductionAgent',
network: 'mock',
behavior: {
concurrency: 5,
retry: { attempts: 3, backoff: 'exponential' },
},
});
// Register services
agent.provide(
{
name: 'echo',
pricing: { cost: { base: 0.05 }, margin: 0.20 },
},
async (job) => job.input
);
agent.provide(
{
name: 'summarize',
pricing: {
cost: { base: 0.10, perUnit: { unit: 'word', rate: 0.0005 } },
margin: 0.35,
},
filter: { minBudget: 1 },
},
async (job, context) => {
context.progress(50, 'Summarizing...');
return { summary: await summarizeText(job.input.text) };
}
);
// Event handlers
agent.on('payment:received', (amount) => {
console.log(`+$${amount.toFixed(2)} USDC`);
});
agent.on('error', console.error);
// Start
await agent.start();
console.log(`Agent running at ${agent.address}`);
console.log(`Services: ${agent.services.join(', ')}`);
// Keep running (in production, handle signals)
process.on('SIGINT', async () => {
console.log('Shutting down...');
await agent.stop();
console.log('Stats:', agent.stats);
process.exit(0);
});
}
main().catch(console.error);
# Level 1: Standard API - Agent with lifecycle management
import asyncio
import signal
from agirails import Agent
async def main():
# Create agent
agent = Agent({
'name': 'ProductionAgent',
'network': 'mock',
'behavior': {
'concurrency': 5,
'retry': {'attempts': 3, 'backoff': 'exponential'},
},
})
# Register services
agent.provide(
{'name': 'echo', 'pricing': {'cost': {'base': 0.05}, 'margin': 0.20}},
lambda job: job.input
)
async def summarize_handler(job, context):
context.progress(50, 'Summarizing...')
return {'summary': await summarize_text(job.input['text'])}
agent.provide(
{
'name': 'summarize',
'pricing': {
'cost': {'base': 0.10, 'perUnit': {'unit': 'word', 'rate': 0.0005}},
'margin': 0.35,
},
'filter': {'minBudget': 1},
},
summarize_handler
)
# Event handlers
agent.on('payment:received', lambda amount:
print(f'+${amount:.2f} USDC'))
agent.on('error', print)
# Start
await agent.start()
print(f'Agent running at {agent.address}')
print(f'Services: {", ".join(agent.services)}')
# Handle shutdown
def shutdown():
asyncio.create_task(agent.stop())
print('Stats:', agent.stats)
signal.signal(signal.SIGINT, lambda *_: shutdown())
# Keep running
while agent.status != 'stopped':
await asyncio.sleep(1)
asyncio.run(main())
When to Use Standard API
Use Standard API when:
- Building production agents
- Need lifecycle management
- Want built-in pricing strategies
- Managing multiple services
- Need event-driven architecture
Use Basic API when:
- Prototyping or learning
- Simple one-off payments
- Quick integrations
Use Advanced API when:
- Need full protocol control
- Building custom integrations
- Direct escrow/attestation access
Next Steps
- Advanced API - Full protocol control
- Examples - Working examples
- Quick Start - End-to-end tutorial