Tool Usage in Reaktors
The @operaide/ai library provides powerful utilities for integrating AI tool calling capabilities into your Reaktors. This guide explains how to use the tool integration aktors to enhance your AI interactions with function calling features.
Overview
Tool calling allows AI models to invoke functions during a conversation, enabling the AI to perform tasks like retrieving data, executing commands, or accessing external systems. The @operaide/ai library offers two main approaches for integrating tools into your Reaktors:
- Using
aktorTool: For wrapping standalone tools created with thetoolfunction from theaipackage - Using
aktorToTool: For converting existing aktors into tools accessible to AI models
Core Tool Integration Aktors
- aktorToolSet: Creates a toolset by combining multiple tools for use with AI models
- aktorTool: Wraps standalone tools for integration with the aktor framework
- aktorToTool: Converts existing aktors into tools that can be used with AI models
When to Use aktorTool vs. aktorToTool
Use aktorTool when:
- You have an existing standalone tool created with the
toolfunction - You're building a simple tool that doesn't need to interact with other aktors
- You want to directly define the tool's behavior without using the aktor pattern
Use aktorToTool when:
- You want to expose existing aktor functionality as a tool
- Your tool needs to interact with other aktors or access dependencies
- You want to maintain separation between the tool interface and the underlying implementation
- You need to reuse existing aktor logic as a tool
Using aktorTool for Standalone Tools
The aktorTool function wraps a standalone tool created with the tool function from the ai package, making it compatible with the aktor framework.
Example: Weather Tool
This example demonstrates how to create a simple weather tool and integrate it into a Reaktor:
import { aktorConst, aktorSetting, registerReaktorDefinition } from '@operaide/aktor';
import { aktorAICall, aktorAISettingProviderModel, aktorMessagesFromSystemAndUser, aktorToolSet, aktorTool } from '@operaide/ai';
import { z } from 'zod';
import { tool } from 'ai';
import type { LlmOptions } from '@operaide/ai';
// Create a standalone weather tool
const weatherAiTool = tool({
description: 'Get the weather in a location',
parameters: z.object({
location: z.string().describe('The location to get the weather for'),
}),
execute: async ({ location }) => {
console.log(`[Tool Call]: Getting weather for ${location}`);
return {
location,
temperature: 72 + Math.floor(Math.random() * 21) - 10,
};
},
});
registerReaktorDefinition({
reaktorDefinitionId: 'weather-tool-calling',
label: 'Weather Tool Calling Example',
description: 'Demonstrates tool calling with a weather tool',
createReaktor(params) {
// Wrap the standalone tool with aktorTool
const weatherTool = aktorTool(weatherAiTool);
// Create a toolset with the weather tool
const toolBox = aktorToolSet({ weatherTool });
// Set up the AI call with the toolset
const ai = aktorAICall({
messages: aktorMessagesFromSystemAndUser({
user: params.message,
system: aktorSetting(z.string(), 'You are a helpful assistant.', 'System Message'),
}),
providerModel: aktorAISettingProviderModel(),
tools: toolBox,
llmOptions: aktorConst<LlmOptions>({
max_steps: 5,
}),
});
return ai;
},
inputSchema: z.object({
message: z.string().openapi({ example: 'What is the weather in Berlin?' }),
}),
outputSchema: z.string(),
});
Using aktorToTool for Aktor-Based Tools
The aktorToTool function converts an existing aktor into a tool that can be used with AI models, allowing you to expose aktor functionality as tools.
Example: Memory Database Tools
This example demonstrates how to convert database aktors into tools for persisting and retrieving memories:
import { aktorConst, aktorSetting, registerReaktorDefinition } from '@operaide/aktor';
import { z } from 'zod';
import type { LlmOptions } from '@operaide/ai';
import {
aktorAICall,
aktorAISettingProviderModel,
aktorMessagesFromSystemAndUser,
aktorToolSet,
aktorToTool,
} from '@operaide/ai';
import { aktorDatabase } from '@operaide/database';
import { aktorGetMemories, aktorInitMemories, aktorSaveMemory } from '../aktors/memory-db-aktors';
registerReaktorDefinition({
reaktorDefinitionId: 'memory-tool-calling',
label: 'Memory Database Tool Calling',
description: 'Demonstrates tool calling with memory database operations',
createReaktor(params) {
// Set up database
const databaseId = aktorSetting(z.string(), 'your-database-id', 'Database ID');
const db = aktorDatabase({ id: databaseId });
const initializedDb = aktorInitMemories({ client: db });
// Convert saveMemory aktor to a tool
const saveMemoryTool = aktorToTool({
aktor: aktorSaveMemory,
description: 'Persist a fact, thought, information or idea',
parameters: z.object({
memory: z.string().describe('the content to persist'),
}),
dependencies: {
client: initializedDb,
},
});
// Convert getMemories aktor to a tool
const retrieveMemoryTool = aktorToTool({
aktor: aktorGetMemories,
description: 'Retrieve previously persisted facts, thoughts, information or ideas',
parameters: z.object({}),
dependencies: {
client: initializedDb,
},
});
// Create a toolset with both tools
const toolBox = aktorToolSet({ saveMemoryTool, retrieveMemoryTool });
// Set up the AI call with the toolset
const ai = aktorAICall({
messages: aktorMessagesFromSystemAndUser({
user: params.message,
system: aktorSetting(z.string(), 'You are a helpful assistant.', 'System Message'),
}),
providerModel: aktorAISettingProviderModel(),
tools: toolBox,
llmOptions: aktorConst<LlmOptions>({
max_steps: 5,
}),
});
return ai;
},
inputSchema: z.object({
message: z.string().openapi({ example: 'What is my favorite color?' }),
}),
outputSchema: z.string(),
});
The aktorToTool Configuration
When using aktorToTool, you need to provide a configuration object with the following properties:
- aktor: The aktor factory function to convert to a tool
- description: A description of the tool for the AI model
- parameters: A Zod schema defining the parameters the AI model can provide
- dependencies: External parameters resolved outside the AI call (provided as Aktors)
Parameter Schema
The parameters property defines the schema for parameters that will be provided by the AI model. Use .describe() on each field to provide clear descriptions that help the AI understand how to use the tool:
parameters: z.object({
query: z.string().describe('Search query for finding information'),
limit: z.number().optional().describe('Maximum number of results to return'),
}),
Dependencies
The dependencies property specifies external parameters that will be resolved outside the AI call. These are typically other aktors that the tool depends on:
dependencies: {
database: dbClient,
logger: loggerAktor,
},
Creating a Toolset
Use aktorToolSet to combine multiple tools into a single toolset that can be passed to aktorAICall:
const toolBox = aktorToolSet({
weatherTool, // From aktorTool
saveMemoryTool, // From aktorToTool
retrieveMemoryTool, // From aktorToTool
});
Integrating Tools with AI Calls
To enable AI tool calling, pass the toolset to aktorAICall using the tools parameter:
const ai = aktorAICall({
messages: aktorMessagesFromSystemAndUser({
user: userMessage,
system: systemPrompt,
}),
providerModel: aktorAISettingProviderModel(),
tools: toolBox,
llmOptions: aktorConst<LlmOptions>({
max_steps: 5, // Maximum number of tool calling steps
}),
});
Best Practices
-
Descriptive Tool Names: Use clear, descriptive names for your tools to help the AI understand their purpose
-
Detailed Descriptions: Provide detailed descriptions for tools and parameters to guide the AI's usage
-
Parameter Descriptions: Use
.describe()on all Zod schema fields to clarify parameter purposes -
Error Handling: Implement proper error handling in your tool execution logic
-
Tool Granularity: Create focused tools that do one thing well rather than complex multi-purpose tools
-
Testing: Test your tools independently before integrating them into Reaktors
-
Limit Tool Steps: Set reasonable limits for
max_stepsto prevent excessive tool calling
Advanced Tool Patterns
Combining Tool Types
You can mix both aktorTool and aktorToTool in the same Reaktor:
const toolBox = aktorToolSet({
weatherTool: aktorTool(weatherAiTool),
saveMemoryTool: aktorToTool({ ... }),
retrieveMemoryTool: aktorToTool({ ... }),
});
Conclusion
Tool integration in Reaktors provides a powerful way to extend AI capabilities with custom functionality. By understanding when to use aktorTool versus aktorToTool, you can create flexible, maintainable, and powerful AI-powered applications.
Remember:
- Use
aktorToolfor standalone tools that don't need aktor integration - Use
aktorToToolto expose existing aktor functionality as tools - Combine tools into a toolset with
aktorToolSet - Provide the toolset to
aktorAICallto enable AI tool calling