openserv-agent-sdk
Original:🇺🇸 English
Translated
8 scriptsChecked / no sensitive code detected
Build and deploy autonomous AI agents using the OpenServ SDK (@openserv-labs/sdk). IMPORTANT - Always read the companion skill openserv-client alongside this skill, as both packages are required to build and run agents. openserv-client covers the full Platform API for multi-agent workflows and ERC-8004 on-chain identity. Read reference.md for the full API reference.
7installs
Sourceopenserv-labs/skills
Added on
NPX Install
npx skill4agent add openserv-labs/skills openserv-agent-sdkTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →OpenServ Agent SDK
Build and deploy custom AI agents for the OpenServ platform using TypeScript.
Reference files:
- - Quick reference for common patterns
reference.md - - Common issues and solutions
troubleshooting.md - - Complete code examples
examples/
What's New in v2.3
- Env Var - Set
DISABLE_TUNNELfor production deployments (e.g. Cloud Run).DISABLE_TUNNEL=truestarts only the HTTP server, no WebSocket tunnel.run() - Env Var - Set
FORCE_TUNNELto force tunnel mode even when anFORCE_TUNNEL=trueis configured.endpointUrl - Public Health Check - The route now responds before auth middleware, so the platform health cron can reach it without credentials.
/health - Binary Tunnel Responses - Tunnel responses are sent as binary frames, preserving gzip, images, and other binary payloads transparently.
Earlier in v2.x
- Built-in Tunnel - The function auto-connects to
run()agents-proxy.openserv.ai - No Endpoint URL Needed - Skip in
endpointUrlduring developmentprovision() - Automatic Port Fallback - If your port is busy, the agent finds an available one
- Direct Credential Binding - can bind credentials directly to agent instance via
provision()agent.instance - Method - Manually bind API key and auth token to agent
setCredentials()
Quick Start
Installation
bash
npm install @openserv-labs/sdk @openserv-labs/client zod openaiNote: The SDK requiresas a peer dependency.openai@^5.x
Minimal Agent
See for a complete runnable example.
examples/basic-agent.tsThe pattern is simple:
- Create an with a system prompt
Agent - Add capabilities with
agent.addCapability() - Call to register on the platform (pass
provision()to bind credentials)agent.instance - Call to start
run(agent)
Complete Agent Template
File Structure
my-agent/
├── src/agent.ts
├── .env
├── .gitignore
├── package.json
└── tsconfig.jsonDependencies
bash
npm init -y && npm pkg set type=module
npm i @openserv-labs/sdk @openserv-labs/client dotenv openai zod
npm i -D @types/node tsx typescriptNote: The project must usein"type": "module". Add apackage.jsonscript for local development."dev": "tsx src/agent.ts"
.env
env
OPENAI_API_KEY=your-openai-key
# Auto-populated by provision():
WALLET_PRIVATE_KEY=
OPENSERV_API_KEY=
OPENSERV_AUTH_TOKEN=
PORT=7378
# Production: skip tunnel and run HTTP server only
# DISABLE_TUNNEL=true
# Force tunnel even when endpointUrl is set
# FORCE_TUNNEL=trueCapabilities
Capabilities are functions your agent can execute. Each requires:
- - Unique identifier
name - - What it does (helps AI decide when to use it)
description - - Zod schema defining parameters
schema - - Function returning a string
run
See for basic capabilities.
examples/capability-example.tsUsing Agent Methods
Access in capabilities to use agent methods like , , etc.
thisaddLogToTask()uploadFile()See for logging and file upload patterns.
examples/capability-with-agent-methods.tsAgent Methods
Task Management
typescript
await agent.createTask({ workspaceId, assignee, description, body, input, dependencies })
await agent.updateTaskStatus({ workspaceId, taskId, status: 'in-progress' })
await agent.addLogToTask({ workspaceId, taskId, severity: 'info', type: 'text', body: '...' })
await agent.markTaskAsErrored({ workspaceId, taskId, error: 'Something went wrong' })
const task = await agent.getTaskDetail({ workspaceId, taskId })
const tasks = await agent.getTasks({ workspaceId })File Operations
typescript
const files = await agent.getFiles({ workspaceId })
await agent.uploadFile({ workspaceId, path: 'output.txt', file: 'content', taskIds: [taskId] })
await agent.deleteFile({ workspaceId, fileId })Action Context
The parameter in capabilities is a union type — only exists on the variant. Always narrow with a type guard before accessing :
actiontask'do-task'action.tasktypescript
async run({ args, action }) {
// action.task does NOT exist on all action types — you must narrow first
if (action?.type === 'do-task' && action.task) {
const { workspace, task } = action
workspace.id // Workspace ID
workspace.goal // Workspace goal
task.id // Task ID
task.description // Task description
task.input // Task input
action.me.id // Current agent ID
}
}Do not extract before the type guard — TypeScript will error with .
action?.task?.idProperty 'task' does not exist on type 'ActionSchema'Workflow Name & Goal
The object in requires two important properties:
workflowprovision()- (string) - This becomes the agent name in ERC-8004. Make it polished, punchy, and memorable — this is the public-facing brand name users see. Think product launch, not variable name. Examples:
name,'Crypto Alpha Scanner','AI Video Studio'.'Instant Blog Machine' - (string, required) - A detailed description of what the workflow accomplishes. Must be descriptive and thorough — short or vague goals will cause API calls to fail. Write at least a full sentence explaining the workflow's purpose.
goal
typescript
workflow: {
name: 'Haiku Poetry Generator', // Polished display name — the ERC-8004 agent name users see
goal: 'Transform any theme or emotion into a beautiful traditional 5-7-5 haiku poem using AI',
trigger: triggers.x402({ ... }),
task: { description: 'Generate a haiku about the given topic' }
}Trigger Types
typescript
import { triggers } from '@openserv-labs/client'
triggers.webhook({ waitForCompletion: true, timeout: 600 })
triggers.x402({ name: '...', description: '...', price: '0.01', timeout: 600 })
triggers.cron({ schedule: '0 9 * * *' })
triggers.manual()Important: Always setto at least 600 seconds (10 minutes) for webhook and x402 triggers. Agents often take significant time to process requests — especially when performing research, content generation, or other complex tasks. A low timeout will cause premature failures. For multi-agent pipelines with many sequential steps, consider 900 seconds or more.timeout
Deployment
Local Development
bash
npm run devThe function automatically:
run()- Starts the agent HTTP server (port 7378, with automatic fallback)
- Connects via WebSocket to
agents-proxy.openserv.ai - Routes platform requests to your local machine
No need for ngrok or other tunneling tools - handles this seamlessly. Just call and your local agent is accessible to the platform.
run()run(agent)Production
When deploying to a hosting provider like Cloud Run, set as an environment variable. This makes start only the HTTP server without opening a WebSocket tunnel — the platform reaches your agent directly at its public URL.
DISABLE_TUNNEL=truerun()typescript
await provision({
agent: {
name: 'my-agent',
description: '...',
endpointUrl: 'https://my-agent.example.com' // Required for production
},
workflow: {
name: 'Lightning Service Pro',
goal: 'Describe in detail what this workflow does — be thorough, vague goals cause failures',
trigger: triggers.webhook({ waitForCompletion: true, timeout: 600 }),
task: { description: 'Process incoming requests' }
}
})
// With DISABLE_TUNNEL=true, run() starts only the HTTP server (no tunnel)
await run(agent)ERC-8004: On-Chain Agent Identity
After provisioning, register your agent on-chain for discoverability via the Identity Registry.
Requires ETH on Base. Registration callson the ERC-8004 contract on Base mainnet (chain 8453), which costs gas. The wallet created byregister()starts with a zero balance. Fund it with a small amount of ETH on Base before the first registration attempt. The wallet address is logged during provisioning (provision()).Created new wallet: 0x...
Always wrap in try/catch so a registration failure (e.g. unfunded wallet) doesn't preventfrom starting.run(agent)
Two important patterns:
- Use programmatically (not
dotenv) so you can reloadimport 'dotenv/config'after.envwritesprovision().WALLET_PRIVATE_KEY - Call after
dotenv.config({ override: true })to pick up the freshly written key before ERC-8004 registration.provision()
typescript
import dotenv from 'dotenv'
dotenv.config()
import { Agent, run } from '@openserv-labs/sdk'
import { provision, triggers, PlatformClient } from '@openserv-labs/client'
// ... define agent and capabilities ...
const result = await provision({
agent: { instance: agent, name: 'my-agent', description: '...' },
workflow: {
name: 'My Service',
goal: 'Detailed description of what the workflow does',
trigger: triggers.x402({ name: 'My Service', description: '...', price: '0.01', timeout: 600 }),
task: { description: 'Process requests' },
},
})
// Reload .env to pick up WALLET_PRIVATE_KEY written by provision()
dotenv.config({ override: true })
// Register on-chain (non-blocking — requires funded wallet on Base)
try {
const client = new PlatformClient()
await client.authenticate(process.env.WALLET_PRIVATE_KEY)
const erc8004 = await client.erc8004.registerOnChain({
workflowId: result.workflowId,
privateKey: process.env.WALLET_PRIVATE_KEY!,
name: 'My Service',
description: 'What this agent does',
})
console.log(`Agent ID: ${erc8004.agentId}`) // "8453:42"
console.log(`TX: ${erc8004.blockExplorerUrl}`)
console.log(`Scan: ${erc8004.scanUrl}`) // "https://www.8004scan.io/agents/base/42"
} catch (error) {
console.warn('ERC-8004 registration skipped:', error instanceof Error ? error.message : error)
}
await run(agent)- First run mints a new identity NFT. Re-runs update the URI — agent ID stays the same.
- Never clear the wallet state unless you intentionally want a new agent ID. To update metadata, just re-run.
- Default chain: Base mainnet (8453). Pass /
chainIdfor others.rpcUrl
See openserv-client skill for the full ERC-8004 API reference and troubleshooting.
DO NOT USE
- inside capabilities - Use direct OpenAI calls instead
this.process() - override - The SDK handles task execution automatically
doTask - - Task completion is handled by the Runtime API
this.completeTask()
Updating This Skill
This skill may be outdated. The OpenServ team ships updates regularly—new features, API changes, and bug fixes won't be reflected here until you update. If something isn't working as expected, or you want to make sure you have the latest information, update the skill before proceeding.
bash
# Check if updates are available
npx skills check
# Update all installed skills to latest versions
npx skills updateOr reinstall the OpenServ skills directly:
bash
npx skills add openserv-labs/skillsRelated Skills
- openserv-client - Full Platform Client API reference
- openserv-multi-agent-workflows - Multi-agent collaboration patterns
- openserv-launch - Launch tokens on Base blockchain
- openserv-ideaboard-api - Find ideas and ship agent services on the Ideaboard