Actions
Define executable functions that enable your Axiom agent to perform tasks and interact with external systems.
Actions
Actions are the core building blocks that define what your Axiom agent can do. They are typed functions that your agent can execute to perform operations, fetch data, or interact with external systems.
What is an Action?
An Action is a function your agent can call to:
- 🔍 Fetch data from APIs, databases, or external services
- ⚙️ Perform operations like calculations, file processing, or data manipulation
- 🔗 Interact with systems like sending emails, creating tickets, or updating records
- 📊 Process information and return structured results for the LLM to use
Think of actions as your agent's "hands" - they're how it actually accomplishes tasks in the real world.
Actions vs Inputs vs Outputs
Building Block | Purpose | When LLM Uses It | Returns Data |
---|---|---|---|
Actions | Execute functions, get data, perform operations | When it needs information for reasoning | ✅ Yes - LLM uses results |
Inputs | Listen for external events (user messages, webhooks) | Never - inputs trigger the agent | ❌ No - triggers conversation |
Outputs | Communicate results to users | When it wants to respond/notify | ❌ No - final communication step |
Basic Action Structure
import { action } from "@axiomkit/core";
import { z } from "zod";
const myAction = action({
name: "action-name", // Unique identifier
description: "What this action does", // Human-readable description
schema: z.object({ // Input validation schema
param1: z.string(),
param2: z.number().optional(),
}),
handler: async (args, ctx) => { // The actual function
// Your logic here
return { result: "success" };
},
});
Example Actions
1. Weather Lookup Action
import { action } from "@axiomkit/core";
import { z } from "zod";
const getWeather = action({
name: "get-weather",
description: "Get current weather information for a city",
schema: z.object({
city: z.string().describe("The city name to get weather for"),
units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
}),
handler: async (args, ctx) => {
const { city, units } = args;
// Simulate API call
const weatherData = {
city,
temperature: units === "celsius" ? "22°C" : "72°F",
condition: "Sunny",
humidity: "65%",
};
return {
success: true,
data: weatherData,
};
},
});
2. Database Query Action
import { action } from "@axiomkit/core";
import { z } from "zod";
const searchUsers = action({
name: "search-users",
description: "Search for users in the database",
schema: z.object({
query: z.string().describe("Search term for user name or email"),
limit: z.number().min(1).max(100).default(10),
}),
handler: async (args, ctx) => {
const { query, limit } = args;
// Simulate database query
const users = [
{ id: 1, name: "John Doe", email: "john@example.com" },
{ id: 2, name: "Jane Smith", email: "jane@example.com" },
].filter(user =>
user.name.toLowerCase().includes(query.toLowerCase()) ||
user.email.toLowerCase().includes(query.toLowerCase())
).slice(0, limit);
return {
success: true,
users,
total: users.length,
};
},
});
3. File Processing Action
import { action } from "@axiomkit/core";
import { z } from "zod";
import * as fs from "fs/promises";
const processFile = action({
name: "process-file",
description: "Read and process a text file",
schema: z.object({
filePath: z.string().describe("Path to the file to process"),
operation: z.enum(["count-words", "count-lines", "get-content"]),
}),
handler: async (args, ctx) => {
const { filePath, operation } = args;
try {
const content = await fs.readFile(filePath, "utf-8");
let result;
switch (operation) {
case "count-words":
result = content.split(/\s+/).length;
break;
case "count-lines":
result = content.split("\n").length;
break;
case "get-content":
result = content;
break;
}
return {
success: true,
operation,
result,
};
} catch (error) {
return {
success: false,
error: `Failed to process file: ${error.message}`,
};
}
},
});
4. API Integration Action
import { action } from "@axiomkit/core";
import { z } from "zod";
const sendNotification = action({
name: "send-notification",
description: "Send a notification via external service",
schema: z.object({
message: z.string().describe("The notification message"),
recipient: z.string().email().describe("Email address of recipient"),
priority: z.enum(["low", "medium", "high"]).default("medium"),
}),
handler: async (args, ctx) => {
const { message, recipient, priority } = args;
// Simulate API call to notification service
const notificationId = `notif_${Date.now()}`;
// In real implementation, you'd call an actual API
console.log(`Sending ${priority} notification to ${recipient}: ${message}`);
return {
success: true,
notificationId,
status: "sent",
timestamp: new Date().toISOString(),
};
},
});
Adding Actions to Your Context
import { context } from "@axiomkit/core";
import { z } from "zod";
const myContext = context({
type: "my-agent",
schema: z.object({
userId: z.string(),
}),
// Add your actions here
actions: [
getWeather,
searchUsers,
processFile,
sendNotification,
],
// ... rest of your context configuration
});
Action Features
Type Safety
Actions use Zod schemas for complete type safety:
- Input validation happens automatically
- TypeScript types are inferred
- Runtime errors are caught early
Error Handling
const riskyAction = action({
name: "risky-action",
description: "An action that might fail",
schema: z.object({
input: z.string(),
}),
handler: async (args, ctx) => {
try {
// Risky operation
const result = await someRiskyOperation(args.input);
return { success: true, result };
} catch (error) {
return {
success: false,
error: error.message
};
}
},
});
Conditional Execution
const conditionalAction = action({
name: "conditional-action",
description: "Only runs under certain conditions",
schema: z.object({
data: z.string(),
}),
enabled: (ctx) => {
// Only enable if user has permission
return ctx.memory.userRole === "admin";
},
handler: async (args, ctx) => {
// This only runs if enabled() returns true
return { processed: args.data };
},
});
Best Practices
- Clear Descriptions: Write descriptive names and descriptions so the LLM knows when to use each action
- Proper Schemas: Use detailed Zod schemas with descriptions for better LLM understanding
- Error Handling: Always handle errors gracefully and return structured responses
- Type Safety: Leverage TypeScript and Zod for compile-time and runtime safety
- Idempotent Operations: Make actions safe to retry when possible