Custom Agents
Build your own agents for specialized use cases.
Overview
While reference agents cover common use cases, you can build custom agents for specialized needs. Custom agents use the same SDK and infrastructure but with your own logic and capabilities.
Start with a reference agent when possible and customize from there. Build from scratch only when your use case is significantly different.
Project Setup
Create a new agent project:
# Create new agent project
$ mkdir my-custom-agent && cd my-custom-agent
$ pnpm init
# Install SDK and dependencies
$ pnpm add @hyperfold/actions-sdk
$ pnpm add -D typescript @types/node
# Initialize TypeScript
$ npx tsc --init
# Create project structure
$ mkdir -p src/{handlers,tools,utils}
$ touch src/index.ts src/agent.ts
Agent Structure
Basic structure of a custom agent:
import {
HyperfoldAgent,
OnACPEvent,
OnSchedule,
OnEndpoint,
getProduct,
calculateDynamicPrice,
sendEmail,
} from '@hyperfold/actions-sdk';
@HyperfoldAgent({
name: 'my-custom-agent',
type: 'custom',
model: {
provider: 'openai',
model: 'gpt-4o',
temperature: 0.7,
},
systemPrompt: `
You are a specialized agent for [your use case].
[Your custom instructions here]
`,
capabilities: ['custom_capability'],
integrations: {
catalog: 'default',
payments: 'stripe',
},
})
export class MyCustomAgent {
@OnACPEvent('custom_action')
async handleCustomAction(data: CustomActionData) {
return { success: true, result: data };
}
@OnSchedule('0 9 * * *')
async dailyTask() {
await this.processDaily();
}
@OnEndpoint('/custom/webhook')
async handleWebhook(request: Request) {
const payload = request.body;
await this.processWebhook(payload);
return { received: true };
}
private async processDaily() {
// Your daily processing logic
}
private async processWebhook(payload: any) {
// Your webhook processing logic
}
}
// src/index.ts
export { MyCustomAgent } from './agent';
Local Testing
Test your agent locally before deployment:
import { TestRunner } from '@hyperfold/actions-sdk/testing';
import { MyCustomAgent } from './agent';
const runner = new TestRunner(MyCustomAgent);
async function test() {
const result = await runner.invoke('custom_action', {
data: { test: true },
});
console.log('Custom action result:', result);
const quoteResult = await runner.invoke('quote', {
productId: 'prod_test',
offer: 100,
context: {
customer_id: 'cust_test',
loyalty_tier: 'gold',
},
});
console.log('Quote result:', quoteResult);
}
test();
$ npx ts-node src/test.ts
# Or use the CLI simulator
$ hyperfold sim local ./src/agent.ts
> [Local] Starting local agent simulation...
> [Ready] Agent loaded. Type messages to interact.
You: Test my custom action
Agent: [Executing custom_action handler...]
Agent: Custom action completed successfully.
Deployment
Deploy your custom agent:
# Build the agent
$ pnpm build
# Deploy to Hyperfold
$ hyperfold agent deploy ./dist
> [Scan] Found agent: my-custom-agent
> [Build] Packaging agent code...
> [Push] Uploading to Container Registry...
> [Deploy] Creating Cloud Run service...
> [Config] Setting up Firestore collections...
✓ Agent deployed successfully!
Name: my-custom-agent
URL: https://my-custom-agent-xyz.run.app
Status: active
# Deploy with environment variables
$ hyperfold agent deploy ./dist \
--set-env="API_KEY=xxx" \
--set-env="FEATURE_FLAG=true"
# Deploy to specific environment
$ hyperfold agent deploy ./dist --env=production
# Verify deployment
$ hyperfold agent get my-custom-agent
Dockerfile
The SDK auto-generates a Dockerfile, but you can customize it:
# Dockerfile (auto-generated, customize if needed)
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
COPY pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
CMD ["node", "dist/index.js"]
Examples
Example custom agents for common use cases:
// Example 1: Subscription Management Agent
@HyperfoldAgent({
name: 'subscription-agent',
type: 'custom',
capabilities: ['subscribe', 'manage_subscription'],
})
export class SubscriptionAgent {
@OnACPEvent('subscribe')
async handleSubscribe(productId: string, plan: string, context: BuyerContext) {
const product = await getProduct(productId);
const subscription = await this.stripe.subscriptions.create({
customer: context.stripe_customer_id,
items: [{ price: product.stripe_price_id }],
});
return {
status: 'subscribed',
subscription_id: subscription.id,
next_billing: subscription.current_period_end,
};
}
@OnSchedule('0 0 * * *')
async processRenewals() {
const expiringToday = await this.getExpiringSubscriptions();
for (const sub of expiringToday) {
await this.sendRenewalReminder(sub);
}
}
}
// Example 2: Inventory Alert Agent
@HyperfoldAgent({
name: 'inventory-alert-agent',
type: 'custom',
})
export class InventoryAlertAgent {
@OnSchedule('*/15 * * * *')
async checkInventoryLevels() {
const lowStock = await this.catalog.findLowStock({ threshold: 10 });
if (lowStock.length > 0) {
await this.sendSlackAlert({
channel: '#inventory-alerts',
message: `⚠️ Low stock alert: ${lowStock.length} products below threshold`,
products: lowStock,
});
}
}
@OnEndpoint('/reorder', { method: 'POST' })
async triggerReorder(request: Request) {
const { product_id, quantity } = request.body;
await this.createPurchaseOrder(product_id, quantity);
return { status: 'reorder_created' };
}
}
// Example 3: Customer Success Agent
@HyperfoldAgent({
name: 'customer-success-agent',
type: 'custom',
})
export class CustomerSuccessAgent {
@OnEvent('order.delivered')
async followUpAfterDelivery(order: Order) {
await this.scheduleTask({
delay: '3d',
action: 'send_feedback_request',
data: { order_id: order.id, customer_id: order.customer_id },
});
}
@OnSchedule('0 10 * * 1')
async weeklyCustomerOutreach() {
const dormant = await this.findDormantCustomers({ days: 30 });
for (const customer of dormant) {
const recommendations = await this.recommender.getPersonalized(customer.id);
await this.sendReEngagementEmail(customer, recommendations);
}
}
}
Need help? Check the Cookbook for complete agent implementation examples.