Preview
Preview Feature — This feature is currently in preview and under active development. APIs and functionality may change. We recommend testing thoroughly before using in production.
Getting Started with Agents
This guide walks you through building your first AI agent in Ductape.
Prerequisites
Before you begin, make sure you have:
- A Ductape account and workspace
- A product created in your workspace
- An API key for an LLM provider (Anthropic or OpenAI)
- The Ductape SDK installed in your project
Step 1: Install the SDK
npm install @ductape/sdk
Step 2: Initialize the SDK
import Ductape from '@ductape/sdk';
const ductape = new Ductape({
user_id: 'your-user-id',
workspace_id: 'your-workspace-id',
private_key: 'your-private-key',
});
Step 3: Set Up Your LLM Model
Before creating an agent, set up a model configuration. This keeps API keys secure and centralized:
// Create a model configuration (do this once)
await ductape.model.create({
product: 'my-product',
tag: 'claude-sonnet',
name: 'Claude Sonnet',
provider: 'anthropic',
model: 'claude-sonnet-4-20250514',
temperature: 0.7,
envs: [
{
slug: 'dev',
apiKey: process.env.ANTHROPIC_API_KEY, // Encrypted automatically
},
],
});
Step 4: Define Your First Agent
Create a simple assistant agent that references the model by tag:
const agent = await ductape.agents.define({
product: 'my-product',
tag: 'simple-assistant',
name: 'Simple Assistant',
model: 'claude-sonnet', // Reference the model tag
systemPrompt: `You are a helpful assistant.
Answer questions clearly and concisely.
If you don't know something, say so.`,
tools: [], // No tools for now
});
Alternative: Inline Model Config
You can also define the model inline (useful for development):
const agent = await ductape.agents.define({
product: 'my-product',
tag: 'simple-assistant',
name: 'Simple Assistant',
model: {
provider: 'anthropic',
model: 'claude-sonnet-4-20250514',
temperature: 0.7,
apiKey: process.env.ANTHROPIC_API_KEY,
},
systemPrompt: `...`,
tools: [],
});
Step 5: Run the Agent
const result = await ductape.agents.run({
product: 'my-product',
env: 'dev',
tag: 'simple-assistant',
input: 'What is the capital of France?',
});
console.log('Response:', result.output);
// Response: The capital of France is Paris.
Step 6: Add Tools
Make your agent more capable with tools:
const agent = await ductape.agents.define({
product: 'my-product',
tag: 'calculator-agent',
name: 'Calculator Agent',
model: {
provider: 'anthropic',
model: 'claude-sonnet-4-20250514',
},
systemPrompt: `You are a helpful assistant that can perform calculations.
Use the calculator tool when you need to compute mathematical expressions.`,
tools: [
{
tag: 'calculate',
description: 'Perform a mathematical calculation',
parameters: {
expression: {
type: 'string',
description: 'Mathematical expression to evaluate (e.g., "2 + 2", "sqrt(16)")',
required: true,
},
},
handler: async (ctx, params) => {
try {
// Simple eval for demo - use a proper math library in production
const result = Function(`"use strict"; return (${params.expression})`)();
return { result, expression: params.expression };
} catch (error) {
return { error: 'Invalid expression' };
}
},
},
],
});
// Test it
const result = await ductape.agents.run({
product: 'my-product',
env: 'dev',
tag: 'calculator-agent',
input: 'What is 15% of 250?',
});
console.log('Response:', result.output);
// Response: 15% of 250 is 37.5
console.log('Tool calls:', result.toolCalls);
// Tool calls: [{ tool: 'calculate', input: { expression: '250 * 0.15' }, output: { result: 37.5 } }]
Step 7: Connect to Ductape Resources
Access databases, APIs, and other resources:
const agent = await ductape.agents.define({
product: 'my-product',
tag: 'data-agent',
name: 'Data Agent',
model: {
provider: 'anthropic',
model: 'claude-sonnet-4-20250514',
},
systemPrompt: `You are a data assistant.
You can look up user information and recent orders.
Always verify the user exists before looking up their orders.`,
tools: [
{
tag: 'get-user',
description: 'Get user information by email or ID',
parameters: {
email: { type: 'string', description: 'User email address' },
userId: { type: 'string', description: 'User ID' },
},
handler: async (ctx, params) => {
return ctx.database.query({
database: 'users-db',
event: 'find-user',
params: { email: params.email, id: params.userId },
});
},
},
{
tag: 'get-orders',
description: 'Get recent orders for a user',
parameters: {
userId: {
type: 'string',
description: 'User ID to get orders for',
required: true,
},
limit: {
type: 'number',
description: 'Maximum number of orders to return',
default: 5,
},
},
handler: async (ctx, params) => {
return ctx.database.query({
database: 'orders-db',
event: 'find-orders',
params: {
userId: params.userId,
limit: params.limit || 5,
},
});
},
},
],
});
Complete Example
Here's a full example of a customer support agent:
import Ductape from '@ductape/sdk';
async function main() {
const ductape = new Ductape({
user_id: 'your-user-id',
workspace_id: 'your-workspace-id',
private_key: 'your-private-key',
});
// Define a customer support agent
const agent = await ductape.agents.define({
product: 'my-product',
tag: 'support-agent',
name: 'Customer Support Agent',
model: {
provider: 'anthropic',
model: 'claude-sonnet-4-20250514',
temperature: 0.5,
maxTokens: 2048,
},
systemPrompt: `You are a customer support agent for an e-commerce store.
Your responsibilities:
- Help customers with order inquiries
- Look up order status and shipping information
- Process returns and refunds (with approval)
- Answer product questions
Always be polite, helpful, and professional.
If you can't help with something, explain why and suggest alternatives.`,
tools: [
{
tag: 'lookup-order',
description: 'Look up order details by order number',
parameters: {
orderNumber: {
type: 'string',
description: 'Order number (e.g., ORD-12345)',
required: true,
},
},
handler: async (ctx, params) => {
const result = await ctx.database.query({
database: 'orders-db',
event: 'find-order',
params: { orderNumber: params.orderNumber },
});
if (!result) {
return { found: false, message: 'Order not found' };
}
return {
found: true,
order: {
number: result.orderNumber,
status: result.status,
items: result.items,
total: result.total,
shippingAddress: result.shippingAddress,
trackingNumber: result.trackingNumber,
estimatedDelivery: result.estimatedDelivery,
},
};
},
},
{
tag: 'check-tracking',
description: 'Get real-time tracking information for a shipment',
parameters: {
trackingNumber: {
type: 'string',
description: 'Shipping tracking number',
required: true,
},
},
handler: async (ctx, params) => {
return ctx.action.run({
app: 'shipping-api',
event: 'track-package',
input: { body: { tracking: params.trackingNumber } },
});
},
},
{
tag: 'initiate-return',
description: 'Start a return process for an order item',
parameters: {
orderNumber: {
type: 'string',
description: 'Order number',
required: true,
},
itemId: {
type: 'string',
description: 'Item ID to return',
required: true,
},
reason: {
type: 'string',
description: 'Reason for return',
required: true,
},
},
requiresConfirmation: true, // Needs approval
handler: async (ctx, params) => {
// Create return request
const returnRequest = await ctx.database.insert({
database: 'returns-db',
event: 'create-return',
data: {
orderNumber: params.orderNumber,
itemId: params.itemId,
reason: params.reason,
status: 'pending',
},
});
// Send confirmation email
await ctx.notification.email({
notification: 'transactional',
event: 'return-initiated',
recipients: [ctx.input.customerEmail],
subject: { orderNumber: params.orderNumber },
template: {
returnId: returnRequest.id,
orderNumber: params.orderNumber,
},
});
return { success: true, returnId: returnRequest.id };
},
},
],
memory: {
shortTerm: {
maxMessages: 20,
truncationStrategy: 'summarize',
},
},
termination: {
maxIterations: 10,
maxTokens: 10000,
timeout: 120000, // 2 minutes
},
humanInLoop: {
enabled: true,
alwaysRequireApproval: ['initiate-return'],
approvalTimeout: 60000, // 1 minute
},
});
// Run the agent
const result = await ductape.agents.run({
product: 'my-product',
env: 'dev',
tag: 'support-agent',
input: 'Hi, I need to check on my order ORD-12345. When will it arrive?',
sessionId: 'customer-session-abc',
});
console.log('Agent response:', result.output);
console.log('Status:', result.status);
console.log('Iterations:', result.iterations);
console.log('Token usage:', result.tokenUsage);
}
main().catch(console.error);
Environment Configuration
Configure different models per environment:
const agent = await ductape.agents.define({
product: 'my-product',
tag: 'configurable-agent',
name: 'Configurable Agent',
model: {
provider: 'anthropic',
model: 'claude-sonnet-4-20250514', // Default model
},
systemPrompt: '...',
tools: [...],
envs: [
{
slug: 'dev',
active: true,
model: {
provider: 'anthropic',
model: 'claude-3-haiku-20240307', // Faster, cheaper for dev
temperature: 0.9, // More creative for testing
},
},
{
slug: 'prd',
active: true,
model: {
provider: 'anthropic',
model: 'claude-sonnet-4-20250514', // Best quality for production
temperature: 0.5, // More consistent
},
},
],
});
Streaming Responses
Get real-time updates as the agent works:
const result = await ductape.agents.run({
product: 'my-product',
env: 'dev',
tag: 'support-agent',
input: 'Check order ORD-12345',
streaming: {
enabled: true,
onEvent: (event) => {
switch (event.type) {
case 'thinking_start':
console.log('Agent is thinking...');
break;
case 'message_delta':
process.stdout.write(event.data.content);
break;
case 'tool_start':
console.log(`Calling tool: ${event.data.tool}`);
break;
case 'tool_end':
console.log(`Tool result: ${JSON.stringify(event.data.result)}`);
break;
case 'agent_complete':
console.log('\nDone!');
break;
}
},
},
});
Next Steps
- Models - Configure and manage LLM models
- Tools - Learn more about creating tools
- Memory - Configure short and long-term memory
- Human-in-the-Loop - Add approval workflows
- Examples - Real-world agent patterns