Octopus
Writing Functions
Every AI Function must export an execute(input) function. The function receives a plain JavaScript object as input and must return a JSON-serialisable value. This page covers the required structure, common patterns, and error handling.
Required Structure
// Minimum required structure
function execute(input) {
// Process input
// Return a JSON-serialisable value
return { result: "ok" };
}
// Arrow function style also works
const execute = (input) => {
return { result: "ok" };
};
Example: Leave Day Calculator
function execute(input) {
const startDate = new Date(input.startDate);
const endDate = new Date(input.endDate);
const entitlement= parseInt(input.annualEntitlement) || 20;
const usedDays = parseInt(input.usedDays) || 0;
// Calculate working days between dates (Mon-Fri only)
let requestedDays = 0;
let current = new Date(startDate);
while (current <= endDate) {
const day = current.getDay();
if (day !== 0 && day !== 6) requestedDays++; // Skip Sunday=0, Saturday=6
current.setDate(current.getDate() + 1);
}
const remaining = entitlement - usedDays;
const canApprove = requestedDays <= remaining;
return {
requestedDays: requestedDays,
remainingBefore: remaining,
remainingAfter: canApprove ? remaining - requestedDays : remaining,
canApprove: canApprove,
message: canApprove
? `Leave request for ${requestedDays} days approved. ${remaining - requestedDays} days remaining.`
: `Insufficient leave balance. Requested ${requestedDays} days but only ${remaining} remaining.`
};
}
Example: JSON Transformer
// Transform a raw API response into a clean summary
function execute(input) {
const items = input.items || [];
// Filter, map, and sort
const summary = items
.filter(item => item.status === "active")
.map(item => ({
id: item.id,
name: item.name,
quantity: item.inventory?.quantity ?? 0,
category: item.metadata?.category ?? "Uncategorized"
}))
.sort((a, b) => b.quantity - a.quantity)
.slice(0, 10); // Top 10 by quantity
return {
totalActive: items.filter(i => i.status === "active").length,
topItems: summary,
generatedAt: new Date().toISOString()
};
}
Error Handling Pattern
function execute(input) {
// Validate required inputs
if (!input.employeeId) {
return { error: "missing_field", message: "employeeId is required" };
}
try {
// Main logic
const result = processEmployee(input.employeeId);
return { success: true, data: result };
} catch (err) {
// Return structured error — don't throw (unhandled throws become runtime errors)
return {
error: "execution_error",
message: err.message || "An unexpected error occurred"
};
}
}
// Helper function defined at module level
function processEmployee(id) {
// ... logic ...
return { id: id, processed: true };
}
Common Pitfalls
| Pitfall | Problem | Fix |
|---|---|---|
| Missing return statement | Function returns undefined — serialised as null | Always return an explicit value |
| Circular references in return value | JSON serialisation fails | Return only plain objects with no circular refs |
Using Date.now() for determinism | Non-deterministic output makes testing difficult | Accept date inputs explicitly if needed |
| Infinite loops | Function hits timeout (5s) and is killed | Always use bounded loops; test edge cases |
| Large return objects | Result injected into LLM context — large objects waste tokens | Return only what the LLM needs |