Migrating from v0 to v1
Moving from v0? Here's everything you need to update.
v0 support is ending. We recommend migrating to v1 for new features and continued updates.
This guide covers the breaking changes and how to update your agents.
What's New in v1?
No More Manual Agent Registration
In v0, agents had to be created via the CLI (agentuity agent create) to register them with unique IDs in the cloud. In v1, just create a folder in src/agent/ with agent.ts — agents are auto-discovered and registered on deploy. No CLI commands or manual registration required.
Key improvements in v1:
- Auto-Discovery: Create agents by adding folders, no CLI registration needed
- Type-Safe Schemas: Built-in support for Zod, Valibot, ArkType, and StandardSchema libraries
- Advanced Routing: Native WebSocket, SSE, email, cron, and SMS routes
- Bun Runtime: Native S3 storage and SQL database support
- Evaluations & Events: Test agent outputs and monitor lifecycle
Workbench: v0's "DevMode" is being rebranded to "Workbench", to better support agent development both locally and in production. The v0 welcome() function pattern for suggested prompts has been removed as part of this redesign.
Breaking Changes Overview
High Impact Changes
These changes require code modifications in all agents:
- Handler Pattern: Default export functions replaced with
createAgent() - Request/Response: New pattern using direct parameters and return values
- Context Properties:
runIdrenamed tosessionId, new properties added - Package Structure: SDK split into multiple packages (
@agentuity/runtime,@agentuity/core, etc.) - Language Support: v1 is TypeScript-only, optimized for Bun runtime
- Trigger Configuration: Cron schedules, email addresses, and SMS numbers are now configured in code (via
router.cron(),router.email(),router.sms()) rather than in the cloud console UI
Step-by-Step Migration
Step 1: Create a Fresh v1 Project
v1 has a different project structure, so we recommend creating a new project and migrating your agent code.
Install the v1 CLI:
curl -sSL https://v1.agentuity.sh | shCreate a new v1 project:
agentuity createThis sets up the correct project structure with all dependencies. You'll migrate your agent logic into this new project using the patterns in the following steps.
Step 2: Update Agent Handler Pattern
The most significant change is how agents are created and exported.
Basic Agent Handler
v0:
import { AgentHandler } from '@agentuity/sdk';
const handler: AgentHandler = async (request, response, context) => {
const data = await request.data.json();
context.logger.info('Processing request', data);
return response.json({
message: 'Hello from my agent!',
data: data
});
};
export default handler;v1:
// src/agent/my-agent/agent.ts
import { createAgent } from '@agentuity/runtime';
const agent = createAgent('My Agent', {
description: 'A simple agent',
handler: async (ctx, input) => {
ctx.logger.info('Processing request', input);
return {
message: 'Hello from my agent!',
data: input
};
}
});
export default agent;Key Changes:
- Import from
@agentuity/runtimeinstead of@agentuity/sdk - Use
createAgent('Name', { ... })with the name as the first argument - Handler receives
(ctx, input)instead of(request, response, context) - Return values directly instead of using
response.json() - Export the agent (routes are defined separately in
src/api/)
File Structure Change: In v0, agents were typically single files. In v1, agents and routes are separated:
src/agent/my-agent/agent.ts- Contains thecreateAgent()call with your handler logicsrc/api/index.ts- Contains all HTTP routes that import and call agents
Routes import agents and call them via agent.run(input). This separation keeps HTTP routing concerns separate from agent core logic, making agents reusable across different routes.
Agent with Schema Validation
v1 introduces optional schema validation for type safety:
// src/agent/typed-agent/agent.ts
import { createAgent } from '@agentuity/runtime';
import { z } from 'zod';
const agent = createAgent('Typed Agent', {
description: 'An agent with type-safe inputs and outputs',
schema: {
input: z.object({
message: z.string(),
count: z.number().optional()
}),
output: z.object({
response: z.string(),
timestamp: z.number()
})
},
handler: async (ctx, input) => {
// input is fully typed as { message: string, count?: number }
return {
response: `Received: ${input.message}`,
timestamp: Date.now()
};
// Return type is validated automatically
}
});
export default agent;// src/api/index.ts - All routes are consolidated here
import { createRouter } from '@agentuity/runtime';
import typedAgent from '@agent/typed-agent';
const router = createRouter();
// Routes are mounted at /api/* automatically
router.post('/typed-agent', typedAgent.validator(), async (c) => {
const data = c.req.valid('json');
const result = await typedAgent.run(data);
return c.json(result);
});
export default router;Benefits:
- Full TypeScript autocomplete
- Runtime validation of inputs and outputs
- Automatic error handling for invalid data
- Self-documenting API contracts
Step 3: Update Context Usage
The context object has several changes and additions.
Context Property Changes
v0:
const handler: AgentHandler = async (request, response, context) => {
// Access run ID
const id = context.runId;
// Access services
await context.kv.set('cache', 'key', data);
// Access logger
context.logger.info('Message');
};v1:
const agent = createAgent('My Agent', {
handler: async (ctx, input) => {
// runId renamed to sessionId
const id = ctx.sessionId;
// Services work the same way
await ctx.kv.set('cache', 'key', data);
// Logger unchanged
ctx.logger.info('Message');
// NEW: State management
ctx.state.set('myKey', 'myValue');
// NEW: Session and thread objects
ctx.logger.info('Session:', ctx.session);
ctx.logger.info('Thread:', ctx.thread);
return { result: 'done' };
}
});Key Changes:
context.runId→ctx.sessionId- New
ctx.statefor temporary state storage - New
ctx.sessionandctx.threadfor conversation management - Agent-to-agent communication uses imports (see Step 7)
Step 4: Update Request Handling
Request handling is simplified in v1.
Accessing Request Data
v0:
const handler: AgentHandler = async (request, response, context) => {
// Get JSON data
const data = await request.data.json();
// Get text data
const text = await request.data.text();
// Get binary data
const binary = await request.data.binary();
// Get metadata
const userId = request.get('userId');
const trigger = request.trigger;
};v1 (HTTP Routes):
import { createRouter } from '@agentuity/runtime';
const router = createRouter();
router.post('/my-agent', async (c) => {
// Get JSON body directly from Hono context
const data = await c.req.json();
// Get text body
const text = await c.req.text();
// Get headers
const userId = c.req.header('x-user-id');
// Get query params
const param = c.req.query('param');
return { processed: data };
});
export default router;v1 (Agent with Schema):
const agent = createAgent('My Agent', {
schema: {
input: z.object({ message: z.string() })
},
handler: async (ctx, input) => {
// Input is automatically parsed and validated
// No need to call request.data.json()
ctx.logger.info('Input message:', { message: input.message });
return { response: 'ok' };
}
});Step 5: Update Response Handling
Responses are now returned directly instead of using a response builder.
Basic Responses
v0:
const handler: AgentHandler = async (request, response, context) => {
// JSON response
return response.json({ message: 'Hello' });
// Text response
return response.text('Hello');
// Binary response
return response.binary(buffer);
// Empty response
return response.empty();
};v1:
const agent = createAgent('My Agent', {
handler: async (ctx, input) => {
// JSON response - just return an object
return { message: 'Hello' };
// Text response - return a string
return 'Hello';
}
});
// For more control over responses, use routes in src/api/index.ts:
router.get('/hello', async (c) => {
const result = await myAgent.run({ name: 'World' });
return c.json(result); // JSON response
return c.text('Hello'); // Text response
return c.body(buffer); // Binary response
});Key Changes:
- No
responseobject - return values directly from agent handler - Objects are automatically JSON-serialized
- Use Hono context methods in routes for advanced responses
- For typed responses, define output schema
Step 6: Update Service Usage
KV and Vector storage APIs are unchanged.
Object Storage → Bun S3
Object storage has been replaced with Bun's native S3 APIs for better performance and simpler code:
v0/Early v1:
// Store file
await context.objectstore.put('uploads', 'hello.txt', data, {
contentType: 'text/plain',
});
// Get file
const result = await context.objectstore.get('uploads', 'hello.txt');
if (result.exists) {
const text = new TextDecoder().decode(result.data);
}
// Create public URL
const url = await context.objectstore.createPublicURL('uploads', 'file.pdf', {
expiresDuration: 3600000,
});
// Delete file
await context.objectstore.delete('uploads', 'hello.txt');v1 (Bun S3):
import { s3 } from "bun";
// Store file
const file = s3.file("uploads/hello.txt");
await file.write("Hello, World!", { type: "text/plain" });
// Get file
if (await file.exists()) {
const text = await file.text();
}
// Presign URL (synchronous, no network request)
const url = s3.presign("uploads/file.pdf", {
expiresIn: 3600, // seconds, not milliseconds
});
// Delete file
await file.delete();Key Changes:
- Import
s3from"bun"instead of usingctx.objectstore - Use
s3.file(path)to create a lazy file reference presign()takes seconds, not milliseconds, and is synchronous- File operations are methods on the file object:
file.write(),file.text(),file.delete() - Credentials are auto-injected via environment variables
Credential Auto-Injection
Agentuity automatically injects S3 credentials (S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_BUCKET, S3_ENDPOINT) during development and deployment.
Database Support
v1 adds SQL database support via Bun's native SQL APIs:
import { sql } from "bun";
// Query with automatic parameter escaping (prevents SQL injection)
const users = await sql`SELECT * FROM users WHERE active = ${true}`;
// Insert data
await sql`INSERT INTO users (name, email) VALUES (${"Alice"}, ${"alice@example.com"})`;
// Transactions
await sql.begin(async (tx) => {
await tx`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${fromId}`;
await tx`UPDATE accounts SET balance = balance + ${amount} WHERE id = ${toId}`;
});Credential Auto-Injection
Agentuity automatically injects DATABASE_URL during development and deployment.
Step 7: Update Agent-to-Agent Communication
Agent-to-agent communication uses direct imports in v1.
v0:
const handler: AgentHandler = async (request, response, context) => {
// Get agent by ID
const agent = await context.getAgent({ id: 'agent_123' });
// Or by name
const agent = await context.getAgent({
name: 'other-agent',
projectId: 'proj_123'
});
// Run the agent
const result = await agent.run({
data: JSON.stringify({ message: 'Hello' }),
contentType: 'application/json'
});
const output = await result.data.json();
};v1:
// src/agent/coordinator/agent.ts
import { createAgent } from '@agentuity/runtime';
import otherAgent from '@agent/other-agent';
const agent = createAgent('Coordinator', {
handler: async (ctx, input) => {
// Import and call agents directly
const result = await otherAgent.run({
message: 'Hello'
});
// Result is automatically typed if the agent has a schema
ctx.logger.info('Agent response:', { response: result });
return result;
}
});
export default agent;Key Changes:
- Import agents using
import agent from '@agent/agent-name' - Call directly with
agent.run(input) - No need to JSON-stringify data
- Type-safe when using schemas
Other v1 Features
These features are optional but can improve your agents.
Specialized Routes
v1 adds native email and cron routes. See Routes documentation for WebSocket and SSE.
Email:
router.email('support@example.com', async (email, ctx) => {
ctx.logger.info('Email from:', email.fromEmail());
return { status: 'processed' };
});Cron:
router.cron('0 0 * * *', async (ctx) => {
ctx.logger.info('Daily job running');
return { status: 'completed' };
});Evaluations
Test agent outputs automatically with agent.createEval(). See Evaluations.
Event Listeners
Monitor agent lifecycle with agent.addEventListener('started' | 'completed' | 'errored', ...). See Events.
Sessions and Threads
Manage conversational state with ctx.session and ctx.thread. See State Management.
Troubleshooting
Issue 1: "Cannot find module '@agentuity/sdk'"
Cause: You haven't updated your imports from v0 to v1.
Solution: Change all imports from:
import { ... } from '@agentuity/sdk';To:
import { ... } from '@agentuity/runtime';Issue 2: "Property 'runId' does not exist on type 'AgentContext'"
Cause: runId was renamed to sessionId in v1.
Solution: Replace all instances of context.runId with ctx.sessionId.
Issue 3: "Handler is not a function"
Cause: You're not exporting the agent correctly.
Solution: Export the agent from agent.ts and import it in your routes:
// src/agent/my-agent/agent.ts
const agent = createAgent('My Agent', { ... });
export default agent;
// src/api/index.ts
import myAgent from '@agent/my-agent';
router.post('/my-agent', async (c) => {
const result = await myAgent.run(await c.req.json());
return c.json(result);
});Issue 4: "Input validation failed"
Cause: You defined an input schema but the incoming data doesn't match it.
Solution: Check your schema definition and ensure incoming data matches:
const agent = createAgent('My Agent', {
schema: {
input: z.object({
message: z.string(),
// Make optional fields explicit
metadata: z.record(z.unknown()).optional()
})
},
handler: async (ctx, input) => {
// ...
}
});Issue 5: "Cannot find agent" or import errors
Cause: Agent import path is incorrect.
Solution: Use the @agent/ alias to import agents:
// Correct - use @agent/ alias
import myAgent from '@agent/my-agent';
// The alias maps to src/agent/
// So @agent/my-agent resolves to src/agent/my-agent/agent.tsGetting Help
If you encounter issues not covered in this guide:
- Check the Documentation: Visit the API Reference for detailed information
- Review Examples: Browse the Cookbook for working patterns
- Community Support: Join our Discord community for help
- Report Issues: Open an issue on GitHub if you find bugs
Next Steps
After migrating your agents:
- Add Schema Validation: Improve type safety with Schema Validation
- Implement Evaluations: Ensure quality with Evaluations
- Use Advanced Routing: Explore WebSocket, SSE, and other routes
- Add Event Listeners: Monitor your agents with Events & Lifecycle
Need Help?
Join our Community for assistance or just to hang with other humans building agents.
Send us an email at hi@agentuity.com if you'd like to get in touch.
Please Follow us on
If you haven't already, please Signup for your free account now and start building your first agent!