Extensibility
AITOS is designed with extensibility at its core, allowing developers to add new capabilities through modules and organize agent configurations with blueprints. This page explains how to extend AITOS functionality and follow the development standards.
Modules
Modules are the primary way to add new capabilities to an AITOS agent. Each module encapsulates a specific functionality that can be enabled on an agent instance.
Module Structure
A typical AITOS module consists of:
- Setup Function: The entry point that enables the module on an agent
- Event Listeners: Functions that respond to specific events
- Task Definitions: Logic to be executed in response to events
- Resource Cleanup: Functions to properly release resources when the module is disabled
Creating a Custom Module
Here’s a step-by-step guide to creating a custom module:
- Create a Module Directory:
Create a new directory under src/modules/ with your module name:
src/modules/myCustomModule/- Create the Main Module File:
Create an index.ts file with your module’s main code:
import { Agent } from "@/src/agent";
import { AgentEvent } from "@/src/agent/core/EventTypes";
// Module configuration options
interface MyModuleOptions {
interval: number;
detailed?: boolean;
}
/**
* Enable the custom module on an agent
*/
export function enableMyCustomModule(agent: Agent, options: MyModuleOptions) {
const { interval, detailed = false } = options;
// Set up interval for periodic tasks
const intervalId = setInterval(() => {
if (detailed) {
console.log("Running periodic task...");
}
// Emit an event from this module
agent.sensing.emitEvent({
type: "MY_MODULE_PERIODIC_EVENT",
description: "Periodic event from custom module",
payload: { timestamp: Date.now() },
timestamp: Date.now(),
});
}, interval);
// Set up event listeners
const offCustomEventListener = agent.sensing.registerListener((evt: AgentEvent) => {
if (evt.type === "CUSTOM_REQUEST_EVENT") {
if (detailed) {
console.log("Received custom request event. Creating task...");
}
// Create a task in response to the event
agent.taskManager.createTask({
type: "CUSTOM_TASK",
description: "Process custom request",
payload: evt.payload,
callback: async (payload) => {
try {
// Task implementation
const result = await processCustomRequest(payload);
// Emit a success event
agent.sensing.emitEvent({
type: "CUSTOM_TASK_COMPLETED",
description: "Custom task completed successfully",
payload: { result },
timestamp: Date.now(),
});
return result;
} catch (error) {
// Emit an error event
agent.sensing.emitEvent({
type: "CUSTOM_TASK_FAILED",
description: "Custom task failed",
payload: { error },
timestamp: Date.now(),
});
throw error;
}
},
});
}
});
// Implementation of custom processing function
async function processCustomRequest(payload: any) {
// Your implementation here
return { processed: true, data: payload };
}
// Return a cleanup function to disable the module
return function disableMyCustomModule() {
clearInterval(intervalId);
offCustomEventListener();
};
}- Export Module from Directory:
Create or update a barrel export in your module directory:
// src/modules/myCustomModule/index.ts
export * from './myCustomModule';- Register in Module Index:
Add your module to the main modules index for easy importing:
// src/modules/index.ts
export * from './core';
export * from './myCustomModule';
// Other module exports...Using Your Module
Once created, you can enable your module on any agent:
import { Agent } from "@/src/agent";
import { enableMyCustomModule } from "@/src/modules/myCustomModule";
const agent = new Agent({ agentId: "custom-module-agent" });
// Enable the custom module
const disableMyModule = enableMyCustomModule(agent, {
interval: 5000, // Run every 5 seconds
detailed: true // Enable detailed logging
});
// Later, disable the module if needed
disableMyModule();Blueprints
Blueprints provide a way to bundle multiple modules and configurations together for reuse. They define a template for agent setup that can be applied to any agent instance.
Blueprint Structure
A blueprint is essentially a function that:
- Takes an agent instance
- Enables multiple modules with specific configurations
- Returns a cleanup function that disables all modules
Creating a Custom Blueprint
Here’s how to create a custom blueprint:
- Create a Blueprint File:
// src/blueprints/MyCustomBlueprint.ts
import { Agent } from "@/src/agent";
import { enableMyCustomModule } from "@/src/modules/myCustomModule";
import { enableNetworkModule } from "@/src/modules/network";
export function MyCustomBlueprint(agent: Agent) {
// Enable required modules
const disableMyModule = enableMyCustomModule(agent, {
interval: 10000,
detailed: false,
});
const disableNetworkModule = enableNetworkModule(agent, {
endpoints: ["https://api.example.com/v1"],
timeoutMs: 5000,
});
// Return a composite cleanup function
return function disableMyCustomBlueprint() {
disableMyModule();
disableNetworkModule();
};
}- Export from Blueprints Directory:
// src/blueprints/index.ts
export * from './BasicBlueprint';
export * from './MyCustomBlueprint';
// Other blueprint exports...Using Your Blueprint
Apply your custom blueprint to an agent:
import { Agent } from "@/src/agent";
import { MyCustomBlueprint } from "@/src/blueprints";
const agent = new Agent({
agentId: "blueprint-agent",
blueprint: MyCustomBlueprint,
});
// The agent now has all capabilities defined in the blueprintBest Practices
- Single Responsibility: Each module should focus on a specific capability
- Resource Cleanup: Always return a cleanup function that removes all listeners and intervals
- Event Naming: Use consistent naming patterns for events (e.g.,
MODULE_ACTION_EVENT) - Configuration: Make modules configurable through options
- Error Handling: Include proper error handling in task callbacks
- Documentation: Document the events your module emits and listens for
Next Steps
- Learn about Multi-Agent Communication
- Explore Code Examples demonstrating module and blueprint usage