Building Custom Plugins in Astreus

Custom plugins extend Astreus agents with specialized tools and capabilities. By creating plugins, you give your agents the ability to interact with APIs, databases, and external services beyond their base reasoning abilities.

## Understanding the Plugin Architecture

Astreus uses three core TypeScript interfaces for plugin development. ToolDefinition specifies individual tools, Plugin packages multiple tools together, and Agent.registerPlugin() makes them available to your agent. This modular approach lets you build focused capabilities and combine them as needed.

## Defining a Tool

Every tool needs four components: a unique name, a description explaining its purpose, a parameters schema, and an async handler function. The description is critical because it helps the agent decide when to use the tool.

```typescript
const weatherTool: ToolDefinition = {
name: 'get_weather',
description: 'Get current weather for a location',
parameters: {
location: {
name: 'location',
type: 'string',
description: 'City name',
required: true
},
units: {
name: 'units',
type: 'string',
description: 'Temperature units',
enum: ['celsius', 'fahrenheit']
}
},
handler: async (params) => {
try {
const weather = {
temperature: 22,
conditions: 'sunny',
location: params.location
};
return {
success: true,
data: weather
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
};
```

The parameters object defines each input with its type, description, and whether it's required. Optional parameters can include enums to constrain valid values.

## Creating a Plugin

Plugins bundle related tools into a cohesive package. Each plugin has a name, version, description, and an array of tools.

```typescript
const weatherPlugin: Plugin = {
name: 'weather',
version: '1.0.0',
description: 'Provides weather information for locations',
tools: [weatherTool]
};
```

This structure makes plugins easy to version, distribute, and maintain. You can add multiple tools to a single plugin for related functionality.

## Registering Plugins with Your Agent

Once you've defined your plugin, register it with your agent using Agent.registerPlugin(). The agent automatically discovers and uses registered tools when responding to user queries.

```typescript
const agent = await Agent.create({
name: 'WeatherAgent',
model: 'gpt-4o'
});

await agent.registerPlugin(weatherPlugin);

const response = await agent.ask("What's the weather like in Tokyo?");
```

Registration happens asynchronously, so use await to ensure the plugin is ready before the agent handles requests. After registration, the agent intelligently determines when to invoke your tools based on user input.

## Error Handling Best Practices

Handlers should return structured responses indicating success or failure. This lets the agent explain problems clearly to users instead of throwing exceptions.

```typescript
handler: async (params) => {
try {
const result = await externalAPI.call(params);
return {
success: true,
data: result
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
```

Structured responses maintain the conversation flow even when services fail. The agent can acknowledge the error and suggest alternatives.

## Getting Started

You can start with the complete example repository or install the Astreus package directly. The example includes a working weather plugin you can modify and extend.

```bash
git clone https://github.com/astreus-ai/custom-plugins
cd custom-plugins
npm install
npm run dev
```

Alternatively, add Astreus to an existing project:

```bash
npm install @astreus-ai/astreus
```

Both approaches give you the same capabilities. The example repository provides a starting point with configuration already in place.

## Environment Configuration

Astreus requires two environment variables: an OpenAI API key for the language model and a database URL for persistent storage.

```bash
OPENAI_API_KEY=sk-your-openai-api-key-here
DB_URL=sqlite://./astreus.db
```

The database URL uses SQLite by default, but you can configure other databases as needed. These variables should be in a .env file at your project root.

## How Agents Use Tools

When a user asks a question, the agent analyzes registered tools to determine which ones might help. It examines tool descriptions and parameter schemas, then decides whether to invoke a tool. If appropriate, the agent extracts parameters from the user's query, calls the handler, and incorporates the results into its response.

This happens automatically without explicit prompting. You don't need to tell the agent when to use tools or how to parse parameters. The language model handles the reasoning based on your tool definitions.

## Building Complex Plugins

Plugins can include multiple tools for comprehensive functionality. A weather plugin might provide current conditions, forecasts, and historical data.

```typescript
const advancedWeatherPlugin: Plugin = {
name: 'weather_advanced',
version: '2.0.0',
description: 'Comprehensive weather information',
tools: [
getCurrentWeather,
getWeatherForecast,
getWeatherHistory
]
};
```

Each tool serves a distinct purpose, letting the agent choose the most appropriate one for each query. This modular design keeps individual tools focused and maintainable.

## Type Safety with TypeScript

Astreus provides full TypeScript support for type-safe plugin development. The interfaces ensure your tools are correctly structured and catch errors at compile time.

```typescript
import { ToolDefinition, Plugin } from '@astreus-ai/astreus';

const myTool: ToolDefinition = {
name: 'my_tool',
description: 'Does something useful',
parameters: {
input: {
name: 'input',
type: 'string',
description: 'Input value to process',
required: true
}
},
handler: async (params) => {
// TypeScript knows params.input is a string
return { success: true, data: params.input };
}
};
```

Type checking prevents common mistakes and makes your code more maintainable. Your IDE provides autocomplete and inline documentation for the Astreus API.

## Testing Your Plugins

Start by testing individual tool handlers with known inputs. Verify they return expected results and handle errors gracefully.

```typescript
const result = await weatherTool.handler({ location: 'Tokyo' });
console.log(result); // Should return weather data
```

Then test the complete agent interaction by asking questions that should trigger your tools. Observe whether the agent invokes the correct tools and uses the results appropriately.

## Beyond Weather: Real-World Applications

The plugin architecture supports diverse use cases. Create plugins for database queries, file operations, mathematical computations, image processing, or business-specific APIs.

```typescript
const databaseTool: ToolDefinition = {
name: 'query_database',
description: 'Execute SQL queries on the database',
parameters: {
query: {
name: 'query',
type: 'string',
description: 'SQL query to execute',
required: true
}
},
handler: async (params) => {
try {
const results = await db.query(params.query);
return { success: true, data: results };
} catch (error) {
return { success: false, error: error.message };
}
}
};
```

Each plugin transforms your agent from a conversational interface into an automation engine capable of real-world actions.

## Official Resources

The complete implementation and additional examples are available in the official repository at https://github.com/astreus-ai/custom-plugins. This includes working code you can clone, modify, and deploy.

## Key Principles

Successful plugin development requires clear tool descriptions that help the agent understand when to use them. Write focused tools that do one thing well, handle errors gracefully with structured responses, and use TypeScript for type safety. Test thoroughly with various inputs and edge cases.

With well-designed plugins, you extend your agent's capabilities beyond conversation into meaningful interaction with the real world.

This experiment is written for Astreus v0.5.37. Please ensure you are using a compatible version.