Executors
Executors are the actions that your AI agent can perform. They are the tools in your agent's toolbox that process and enhance the context chain.
Understanding Executors​
An executor is a function that:
- Has a clear name and description
- Extracts needed data from the context chain
- Can modify or enhance the context
- Returns structured results
Here's a basic executor:
// Snippet from inside a plugin, this is not a full implementation
this.executors = [
{
name: "generate_image",
description: "Generate an image based on a text prompt",
fn: async (context: AgentContext): Promise<PluginResult> => {
try {
// Extract prompt from context using getObject
const promptResponse = await this.runtime.operations.getObject(
PromptResponseSchema,
generatePromptTemplate(context.contextChain),
{ temperature: 0.7 }
);
const prompt = promptResponse.prompt;
const urls = await this.service.getImage(prompt);
return {
success: true,
data: {
urls,
helpfulInstruction:
"IMPORTANT: You MUST use the exact URLs provided in the urls array above."
}
};
} catch (error) {
return {
success: false,
error:
error instanceof Error ? error.message : "Unknown error occurred"
};
}
}
}
];
Executor Components​
Name and Description​
{
name: "generate_image",
description: "Generate an image based on a text prompt"
}
The name and description are crucial because:
- They help the AI understand the executor's purpose
- They provide context for data extraction
- They guide the AI in choosing the right tool
Data Extraction​
Instead of accepting parameters directly, executors use getObject
to extract needed data from the context chain. Here's how it works:
// 1. Define your schema with descriptions
const PromptResponseSchema = z.object({
prompt: z.string().describe("The prompt for the image generation model")
});
// 2. Create a prompt string that guides the AI in extracting data
const promptResponse = await this.runtime.operations.getObject(
PromptResponseSchema,
`Generate a prompt for an image generation model based on the context chain.
Look for relevant information in the most recent context items.
Here is the context chain with the user's message and previous operations:
${JSON.stringify(context.contextChain, null, 2)}`,
{
temperature: 0.7 // Higher temperature for more creative prompts
}
);
This approach:
- Uses schema descriptions to guide the AI
- Provides clear instructions in the prompt string
- Ensures type safety through Zod validation
- Handles missing or ambiguous data gracefully
Context Management​
Executors can read from and enhance the context chain:
execute: async (context: AgentContext): Promise<PluginResult> => {
const promptResponse = await this.runtime.operations.getObject(
PromptResponseSchema,
generatePromptTemplate(context.contextChain),
{ temperature: 0.7 }
);
const prompt = promptResponse.prompt;
const urls = await this.service.getImage(prompt);
return {
success: true,
data: {
urls,
helpfulInstruction:
"IMPORTANT: You MUST use the exact URLs provided in the urls array above. DO NOT use placeholders like [generated-image-url]. Instead, copy and paste the complete URL from the urls array into your response. The user can access these URLs directly. Other plugins can also access these URLs."
}
};
};
Results​
You can add hardcoded strings to the data
field of the PluginResult
object.
Adding metadata such as helpfulInstruction
is particularly important as it co-locates data with guidance for the model:
return {
success: true,
data: {
urls,
helpfulInstruction:
"IMPORTANT: You MUST use the exact URLs provided in the urls array above. DO NOT use placeholders like [generated-image-url]. Instead, copy and paste the complete URL from the urls array into your response. The user can access these URLs directly. Other plugins can also access these URLs."
}
};
This approach:
- Ensures the model understands how to use the data correctly
- Prevents common mistakes (like using placeholders)
- Provides context about data accessibility and usage
- Guides the model in maintaining data integrity
You can think of helpful instructions as programmer-written notes that help the model understand and use the data appropriately in its responses.
Schema Definition​
Use Zod schemas with clear descriptions:
const PromptResponseSchema = z.object({
prompt: z.string().describe("The prompt for the image generation model")
});
Clear Documentation​
Document your executor's context requirements:
export class ImageGenerationPlugin extends Plugin {
constructor({ useMultiModal = false }: { useMultiModal?: boolean } = {}) {
super({
id: "plugin-image-generation",
requiredCapabilities: [imageGenerationCapability.id]
// other configurations ...
});
this.executors = [
{
name: "generate_image",
description:
"Generate an image based on a text prompt. Information from the context chain will be used to assist in the generation.",
fn: async (task: AgentTask) => {
// Implementation
return { success: true, data: { urls: [] } };
}
}
];
}
}
Real-World Example​
Here's a complete example of an image generation plugin:
export class SearchPlugin extends Plugin {
private service: PerplexityService;
constructor(config: SearchPluginConfig) {
super({
id: "plugin-search",
name: "Search",
description: "Search the web for information",
...
});
this.service = new PerplexityService(config.apiKey);
this.executors = [
{
name: "search",
description: async () =>
(
await this.runtime.templates.render(`${this.id}/search_description`)
).trim(),
fn: this.search.bind(this)
}
];
}
private async search(task: AgentTask): Promise<PluginResult> {
const queryPrompt = await this.runtime.templates.render(
`${this.id}/query`,
{
context: JSON.stringify(task, null, 2)
}
);
const params = await this.runtime.getObject(
PerplexityQueryResponseSchema,
queryPrompt
);
const query = params.query;
const result = await this.service.query(query);
return {
success: true,
data: {
content: result.content,
citations: result.citations
}
};
}
}
- Learn about Triggers for handling events
- Explore getObject for data extraction
- Check out Plugin Philosophy for architectural overview
- Read about Model Providers for model integration