Deploy as Agents
Deploy MDX Functions as autonomous AI agents
Deploy MDX Functions as Agents
Documentation Status: This documentation describes the planned API design for the .do platform. Code examples represent the intended interface and may not reflect the current implementation state. See roadmap for implementation status.
Transform your MDX functions into autonomous AI agents that can execute tasks, make decisions, and interact with users and systems independently.
Overview
When you deploy MDX functions as agents, they become:
- Autonomous - Can operate independently without constant human oversight
- Intelligent - Make decisions based on context and goals
- Reactive - Respond to events and triggers automatically
- Collaborative - Work with other agents and humans
- Persistent - Maintain state and memory across interactions
Creating an Agent from MDX
Basic Agent
Take an MDX function and deploy it as an agent:
---
title: Customer Support Agent
description: Automated customer support assistant
---
export async function handleSupportRequest(request) {
// Analyze the request
const analysis = await $.ai.analyze(request.message, {
intent: true,
sentiment: true,
urgency: true
})
// Route based on urgency
if (analysis.urgency === 'high') {
await $.human.notify({
type: 'urgent_support',
request,
analysis
})
}
// Generate response
const response = await $.ai.generateText({
prompt: 'Provide helpful support response',
context: {
request: request.message,
analysis,
knowledgeBase: await $.db.articles.search(analysis.topic)
}
})
// Send response
await $.email.send.message({
to: request.email,
subject: `Re: ${request.subject}`,
body: response
})
// Track interaction
return await $.db.interactions.create({
type: 'support',
request,
response,
analysis,
timestamp: new Date()
})
}Deploy as an agent:
export const supportAgent = $.agent({
name: 'Customer Support Agent',
description: 'Handles customer support requests automatically',
// Import the MDX function as a capability
capabilities: {
handleSupportRequest,
},
// Define when the agent should act
triggers: [
$.on('support.request.created', (event) => handleSupportRequest(event.request)),
$.on('email.received', (event) => event.subject.includes('support') && handleSupportRequest(event)),
],
// Agent configuration
config: {
model: 'claude-sonnet-4.5',
temperature: 0.7,
maxTokens: 2000,
},
})Agent Capabilities
Decision Making
Agents can make autonomous decisions:
---
title: Content Moderator
description: Automatically moderate user-generated content
---
export async function moderateContent(content) {
// Analyze content
const analysis = await $.ai.moderate(content.text, {
checkFor: ['spam', 'abuse', 'inappropriate', 'harmful']
})
// Make decision
if (analysis.violations.length === 0) {
// Approve automatically
await $.db.content.update(content.id, { status: 'approved' })
return { action: 'approved', automated: true }
}
if (analysis.severity === 'high') {
// Reject automatically
await $.db.content.update(content.id, { status: 'rejected' })
await $.user.notify(content.authorId, {
type: 'content_rejected',
reason: analysis.violations
})
return { action: 'rejected', automated: true, reason: analysis }
}
// Send for human review
await $.human.request({
type: 'content_review',
content,
analysis,
assignee: 'moderation_team'
})
return { action: 'pending_review', automated: false }
}Memory and Context
Agents maintain state across interactions:
---
title: Sales Assistant
description: Personalized sales assistance with context
---
export async function assistCustomer(customerId, message) {
// Retrieve customer context
const context = await $.agent.memory.get(customerId, {
include: ['previous_interactions', 'preferences', 'purchase_history']
})
// Generate personalized response
const response = await $.ai.generateText({
prompt: 'Provide personalized sales assistance',
context: {
customer: context,
message,
catalog: await $.db.products.find({ available: true })
}
})
// Update memory
await $.agent.memory.update(customerId, {
lastInteraction: new Date(),
messages: [...context.messages, { role: 'user', content: message }],
intent: await $.ai.analyze(message, { intent: true })
})
return response
}Multi-Step Workflows
Agents can orchestrate complex workflows:
---
title: Content Publisher
description: Automated content publishing workflow
---
export async function publishContent(contentId) {
const content = await $.db.content.findById(contentId)
// Step 1: Generate SEO metadata
const seo = await $.ai.generate.metadata({
title: content.title,
body: content.body,
type: 'article'
})
// Step 2: Generate images
const images = await $.ai.generateImages({
prompts: extractImageNeeds(content.body),
style: 'professional'
})
// Step 3: Optimize content
const optimized = await $.ai.optimize(content.body, {
for: ['readability', 'seo', 'engagement']
})
// Step 4: Schedule social media
const scheduled = await $.social.schedule.posts([
{
platform: 'twitter',
content: generateTweet(content),
time: 'optimal'
},
{
platform: 'linkedin',
content: generateLinkedInPost(content),
time: 'optimal'
}
])
// Step 5: Publish
await $.db.content.update(contentId, {
status: 'published',
seo,
images,
body: optimized,
publishedAt: new Date(),
socialSchedule: scheduled
})
return { success: true, contentId, scheduled }
}Agent Teams
Combine multiple agents to work together:
export const marketingTeam = $.agent.team({
name: 'Marketing Team',
agents: [
{
role: 'content_creator',
agent: contentCreatorAgent,
responsibilities: ['Generate blog posts', 'Create social content'],
},
{
role: 'seo_optimizer',
agent: seoOptimizerAgent,
responsibilities: ['Optimize for search', 'Generate metadata'],
},
{
role: 'publisher',
agent: publisherAgent,
responsibilities: ['Schedule posts', 'Manage distribution'],
},
],
// Define team workflow
workflow: async (task) => {
// Content creator generates
const content = await contentCreatorAgent.execute(task)
// SEO optimizer enhances
const optimized = await seoOptimizerAgent.execute(content)
// Publisher distributes
const published = await publisherAgent.execute(optimized)
return published
},
})Agent Configuration
Deployment Config
// do.config.ts
export default {
agents: [
{
name: 'support-agent',
source: './agents/support.mdx',
deployment: {
triggers: ['support.request.created', 'email.received'],
schedule: null, // event-driven only
concurrency: 10, // handle 10 requests concurrently
timeout: 300000, // 5 minute timeout
retries: 3,
},
environment: {
AI_MODEL: 'claude-sonnet-4.5',
KNOWLEDGE_BASE_ID: 'kb_123',
NOTIFY_ON_ESCALATION: '[email protected]',
},
},
{
name: 'content-moderator',
source: './agents/moderator.mdx',
deployment: {
triggers: ['content.submitted'],
schedule: '*/5 * * * *', // also check every 5 minutes
concurrency: 50,
timeout: 30000,
},
},
],
}Environment Variables
# .env
AI_MODEL=claude-sonnet-4.5
AI_TEMPERATURE=0.7
AI_MAX_TOKENS=2000
AGENT_MEMORY_STORE=redis://localhost:6379
AGENT_LOG_LEVEL=infoMonitoring and Observability
Agent Dashboard
Monitor agent performance in real-time:
// Access agent metrics
const metrics = await $.agent.metrics.get('support-agent', {
period: 'last_24h',
})
console.log({
requestsHandled: metrics.total,
averageResponseTime: metrics.avgResponseTime,
successRate: metrics.successRate,
escalations: metrics.escalations,
cost: metrics.aiCost,
})Logging and Tracing
// Enable detailed logging
export const agent = $.agent({
name: 'Debug Agent',
capabilities: { myFunction },
config: {
logging: {
level: 'debug',
includeContext: true,
includePrompts: true,
redact: ['email', 'phone', 'ssn'],
},
tracing: {
enabled: true,
sampleRate: 1.0,
},
},
})Best Practices
Error Handling
Always handle errors gracefully:
export async function robustAgentFunction(input) {
try {
const result = await processInput(input)
return { success: true, result }
} catch (error) {
// Log error
await $.log.error('Agent function failed', {
error: error.message,
input,
stack: error.stack
})
// Notify humans if critical
if (error.critical) {
await $.human.notify({
type: 'agent_failure',
error,
input
})
}
return { success: false, error: error.message }
}
}Rate Limiting
Respect API limits and costs:
export const agent = $.agent({
name: 'Rate Limited Agent',
capabilities: { myFunction },
config: {
rateLimit: {
requests: 100,
period: '1m',
},
costLimit: {
amount: 10.0,
period: '1h',
currency: 'USD',
},
},
})Testing
Test agents before deployment:
import { test } from 'vitest'
test('support agent handles request', async () => {
const request = {
email: '[email protected]',
subject: 'Need help',
message: 'How do I reset my password?',
}
const result = await handleSupportRequest(request)
expect(result).toHaveProperty('type', 'support')
expect(result.response).toBeDefined()
})Production Deployment
Deployment Strategy
// Production deployment configuration
export default {
agents: [
{
name: 'production-agent',
source: './agents/support.mdx',
deployment: {
strategy: 'blue-green', // 'blue-green' | 'canary' | 'rolling'
// Blue-green deployment
blueGreen: {
enabled: true,
healthCheckUrl: '/health',
healthCheckInterval: 30000,
switchoverDelay: 60000,
},
// Canary deployment
canary: {
enabled: false,
initialTraffic: 0.05, // 5% traffic to canary
incrementBy: 0.1,
incrementInterval: 300000, // 5 minutes
successThreshold: 0.99,
},
// Rolling deployment
rolling: {
enabled: false,
batchSize: 2,
healthCheckDelay: 10000,
},
},
},
],
}Health Checks
// Health check implementation
export async function healthCheck() {
return {
status: 'healthy',
checks: {
database: await checkDatabase(),
ai: await checkAI(),
memory: await checkMemory(),
},
timestamp: new Date().toISOString(),
}
}
async function checkDatabase() {
try {
await $.db.ping()
return { status: 'healthy', latency: 5 }
} catch (error) {
return { status: 'unhealthy', error: error.message }
}
}
async function checkAI() {
try {
const start = Date.now()
await $.ai.ping()
return { status: 'healthy', latency: Date.now() - start }
} catch (error) {
return { status: 'unhealthy', error: error.message }
}
}
async function checkMemory() {
const usage = process.memoryUsage()
const limit = 1024 * 1024 * 1024 // 1GB
return {
status: usage.heapUsed < limit ? 'healthy' : 'warning',
heapUsed: usage.heapUsed,
heapTotal: usage.heapTotal,
}
}Readiness Probes
export async function readinessCheck() {
// Check if agent is ready to accept traffic
const checks = await Promise.all([
checkModelLoaded(),
checkKnowledgeBaseReady(),
checkMemoryStoreConnected(),
])
const allReady = checks.every(check => check.ready)
return {
ready: allReady,
checks,
}
}
async function checkModelLoaded() {
try {
const loaded = await $.ai.models.check('claude-sonnet-4.5')
return { ready: loaded, service: 'ai-model' }
} catch (error) {
return { ready: false, service: 'ai-model', error: error.message }
}
}Production Monitoring
// Comprehensive monitoring setup
export default {
agents: [
{
name: 'production-agent',
monitoring: {
// Metrics
metrics: {
enabled: true,
interval: 30000, // 30 seconds
metrics: [
'requests_total',
'requests_duration',
'errors_total',
'ai_tokens_used',
'memory_usage',
'cpu_usage',
],
},
// Logging
logging: {
level: 'info', // 'debug' | 'info' | 'warn' | 'error'
structured: true,
includeContext: true,
excludeFields: ['apiKey', 'password'],
destinations: [
{ type: 'console' },
{ type: 'file', path: '/var/log/agents/production.log' },
{ type: 'cloudwatch', logGroup: '/agents/production' },
],
},
// Tracing
tracing: {
enabled: true,
provider: 'opentelemetry',
endpoint: 'https://trace.example.do',
sampleRate: 1.0, // 100% in production
includeHeaders: false,
},
// Alerting
alerts: [
{
name: 'high-error-rate',
condition: 'error_rate > 0.05',
duration: '5m',
severity: 'critical',
notify: ['[email protected]', 'pagerduty'],
actions: ['scale-up', 'notify-on-call'],
},
{
name: 'high-latency',
condition: 'p95_latency > 5000',
duration: '10m',
severity: 'warning',
notify: ['[email protected]'],
},
{
name: 'memory-high',
condition: 'memory_usage > 0.85',
duration: '3m',
severity: 'warning',
notify: ['[email protected]'],
actions: ['scale-up'],
},
],
},
},
],
}CI/CD Pipeline
# .github/workflows/deploy-agent.yml
name: Deploy Agent to Production
on:
push:
branches: [main]
paths:
- 'agents/**'
- '.github/workflows/deploy-agent.yml'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Install dependencies
run: pnpm install
- name: Run tests
run: pnpm test agents/
- name: Type check
run: pnpm typecheck
- name: Lint
run: pnpm lint agents/
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build agent
run: pnpm build:agent
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: agent-build
path: dist/agents/
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment: staging
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: agent-build
- name: Deploy to staging
run: |
pnpm do deploy:agent --env staging
env:
DO_TOKEN: ${{ secrets.DO_STAGING_TOKEN }}
- name: Wait for health check
run: |
for i in {1..30}; do
if curl -f https://staging-agent.example.do/health; then
echo "Health check passed"
exit 0
fi
echo "Waiting for health check... ($i/30)"
sleep 10
done
echo "Health check failed"
exit 1
- name: Run smoke tests
run: pnpm test:e2e --env staging
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: agent-build
- name: Deploy to production (blue-green)
run: |
# Deploy to green environment
pnpm do deploy:agent --env production --slot green
# Wait for green to be healthy
pnpm do wait-healthy --slot green --timeout 300
# Switch traffic to green
pnpm do switch-traffic --from blue --to green
# Monitor for issues
sleep 300
# If no issues, keep green as active
# Otherwise rollback happens automatically
env:
DO_TOKEN: ${{ secrets.DO_PRODUCTION_TOKEN }}
- name: Verify deployment
run: |
curl -f https://agent.example.do/health
pnpm do verify-deployment --env production
- name: Notify Slack
if: always()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Agent deployment ${{ job.status }}: ${{ github.event.head_commit.message }}",
"status": "${{ job.status }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}Rollback Procedures
# Manual rollback commands
# List recent deployments
pnpm do deployments list --agent production-agent
# Output:
# ID VERSION STATUS DEPLOYED_AT TRAFFIC
# dep_123 v1.2.5 active 2024-01-15 10:30:00 100%
# dep_122 v1.2.4 standby 2024-01-14 09:15:00 0%
# dep_121 v1.2.3 archived 2024-01-13 14:22:00 0%
# Rollback to previous version
pnpm do rollback --agent production-agent
# Rollback to specific version
pnpm do rollback --agent production-agent --version v1.2.4
# Automatic rollback on failure
pnpm do deploy:agent --auto-rollback \
--failure-threshold 0.05 \
--monitoring-period 300Automated Rollback Configuration
export default {
agents: [
{
name: 'production-agent',
deployment: {
autoRollback: {
enabled: true,
// Trigger conditions
triggers: [
{
metric: 'error_rate',
threshold: 0.05,
duration: '5m',
},
{
metric: 'p99_latency',
threshold: 10000,
duration: '3m',
},
{
metric: 'health_check_failures',
threshold: 3,
duration: '1m',
},
],
// Rollback behavior
behavior: {
immediate: true,
notifyBefore: true,
retainLogs: true,
createIncident: true,
},
},
},
},
],
}Production Troubleshooting
# View agent logs
pnpm do logs --agent production-agent --tail 100
# Stream live logs
pnpm do logs --agent production-agent --follow
# Filter by level
pnpm do logs --agent production-agent --level error
# View metrics
pnpm do metrics --agent production-agent --period 1h
# Debug mode (temporary)
pnpm do debug enable --agent production-agent --duration 10m
# Check agent status
pnpm do status --agent production-agent
# Output:
# Agent: production-agent
# Status: running
# Version: v1.2.5
# Uptime: 5d 3h 22m
# Requests/min: 145
# Error rate: 0.2%
# P95 latency: 234ms
# Memory: 456MB / 1GB (45%)
# CPU: 12%
# Restart agent
pnpm do restart --agent production-agent
# Scale agent
pnpm do scale --agent production-agent --replicas 5Performance Optimization
// Production performance configuration
export default {
agents: [
{
name: 'production-agent',
performance: {
// Caching
cache: {
enabled: true,
provider: 'redis',
ttl: 3600,
keyPrefix: 'agent:production',
// Cache frequently accessed data
strategies: {
'user-data': { ttl: 300 },
'knowledge-base': { ttl: 86400 },
'model-responses': { ttl: 1800 },
},
},
// Connection pooling
database: {
pool: {
min: 5,
max: 20,
acquireTimeout: 30000,
idleTimeout: 600000,
},
},
// Request batching
batching: {
enabled: true,
maxBatchSize: 50,
maxWaitTime: 100, // ms
},
// Resource limits
limits: {
memory: '1GB',
cpu: '1000m', // 1 CPU core
concurrency: 100,
queueSize: 1000,
},
// Optimization flags
optimize: {
enableJIT: true,
enableV8Flags: ['--max-old-space-size=1024'],
preloadModels: true,
warmupRequests: 10,
},
},
},
],
}Security Hardening
export default {
agents: [
{
name: 'production-agent',
security: {
// Authentication
auth: {
required: true,
methods: ['jwt', 'api-key'],
jwtSecret: process.env.JWT_SECRET,
tokenExpiry: '1h',
},
// Rate limiting
rateLimit: {
windowMs: 60000, // 1 minute
max: 100, // 100 requests per minute
skipSuccessfulRequests: false,
standardHeaders: true,
},
// Input validation
validation: {
enabled: true,
sanitize: true,
maxPayloadSize: '10mb',
allowedOrigins: ['https://app.example.do'],
},
// Secrets management
secrets: {
provider: 'aws-secrets-manager',
autoRotate: true,
rotationInterval: '30d',
},
// Network security
network: {
allowedIPs: ['10.0.0.0/8'],
requireHTTPS: true,
enableCORS: true,
corsOrigins: ['https://app.example.do'],
},
// Audit logging
audit: {
enabled: true,
logLevel: 'all',
includePayload: false,
retention: '90d',
},
},
},
],
}Disaster Recovery
export default {
agents: [
{
name: 'production-agent',
disasterRecovery: {
// Backup strategy
backup: {
enabled: true,
schedule: '0 2 * * *', // Daily at 2 AM
retention: 30, // days
destinations: ['s3://backups/agents'],
},
// Multi-region deployment
regions: ['us-east-1', 'us-west-2', 'eu-west-1'],
failover: {
enabled: true,
automatic: true,
healthCheckInterval: 30000,
failoverThreshold: 3,
},
// Data replication
replication: {
enabled: true,
mode: 'async',
lag: 'max-10s',
},
// Recovery procedures
recovery: {
rto: 300, // Recovery Time Objective: 5 minutes
rpo: 60, // Recovery Point Objective: 1 minute
runbooks: [
'https://docs.example.do/runbooks/agent-recovery',
],
},
},
},
],
}Load Testing
// Load test configuration
import { loadTest } from '@dotdo/testing'
await loadTest({
agent: 'production-agent',
// Test scenarios
scenarios: [
{
name: 'normal-load',
duration: '10m',
vus: 100, // virtual users
rps: 50, // requests per second
},
{
name: 'peak-load',
duration: '5m',
vus: 500,
rps: 250,
},
{
name: 'stress-test',
duration: '2m',
vus: 1000,
rps: 500,
},
],
// Assertions
thresholds: {
'http_req_duration': ['p(95)<500', 'p(99)<1000'],
'http_req_failed': ['rate<0.01'],
'http_reqs': ['rate>45'],
},
// Reporting
reports: {
output: 'test-results/load-test.html',
realtime: true,
webhooks: ['https://metrics.example.do/load-test'],
},
})Related Documentation
-
- Agents Framework - Complete agent capabilities
-
- Functions - Function types and composition
- Workflows - Deploy as workflows
- Services - Deploy as services
- Configuration - Deployment configuration
- Build Process - Build pipeline