Bot orchestration SDK for building autonomous agent systems with tool execution, health monitoring, and observability built-in.
npm install @egintegrations/bot-sdkBot orchestration SDK for building autonomous agent systems. Provides a complete framework for tool execution, health monitoring, observability, and idempotency out of the box.
- Tool Management: Register and execute tools with automatic validation
- Observability: Built-in logging, metrics, and distributed tracing
- Health Checks: Configurable health and readiness endpoints
- Idempotency: Optional idempotent tool execution with pluggable storage
- Error Handling: Comprehensive error types and handling
- Express Integration: Production-ready Express server with middleware
- TypeScript: Full type safety with comprehensive interfaces
``bash`
npm install @egintegrations/bot-sdk express zod
`bash`
npm install express zod
The SDK automatically includes:
- @egintegrations/core-utils - Error handling, retry logic, idempotency@egintegrations/observability
- - Logging, metrics, telemetry
`typescript
import { BotSDK, Tool } from '@egintegrations/bot-sdk';
// Define your tools
const tools: Tool[] = [
{
name: 'get_weather',
description: 'Get current weather for a location',
parameters: [
{
name: 'location',
type: 'string',
description: 'City name',
required: true,
},
],
handler: async (params, correlationId) => {
// Your tool logic here
return { temperature: 72, condition: 'sunny' };
},
},
];
// Create and start bot
const bot = new BotSDK({
name: 'weather-bot',
version: '1.0.0',
port: 3000,
tools,
});
await bot.start();
console.log('Bot is running on port 3000');
`
Main SDK class for creating and managing bots.
`typescript`
const bot = new BotSDK(config: BotSDKConfig);
#### Configuration
`typescript`
interface BotSDKConfig {
name: string; // Bot name
version: string; // Bot version
port?: number; // HTTP port (default: 3000)
metricsPort?: number; // Metrics port (default: 9090)
enableTracing?: boolean; // Enable OpenTelemetry (default: true)
tools: Tool[]; // Array of tools
idempotencyStore?: IdempotencyStore; // Optional idempotency storage
idempotencyTTL?: number; // Idempotency TTL in ms (default: 1 hour)
healthChecks?: HealthCheck[]; // Custom health checks
readinessChecks?: HealthCheck[]; // Custom readiness checks
}
#### Methods
`typescript
// Start the bot server
await bot.start(): Promise
// Stop the bot server
await bot.stop(): Promise
// Get Express app for custom routes
bot.getApp(): Express
// Get tool handler for runtime tool management
bot.getToolHandler(): ToolHandler
`
`typescript
interface Tool {
name: string;
description: string;
parameters: ToolParameter[];
handler: (params: Record
}
interface ToolParameter {
name: string;
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
description: string;
required: boolean;
default?: any;
}
`
Implement this interface to provide custom idempotency storage:
`typescript`
interface IdempotencyStore {
get(key: string): Promise
set(key: string, value: any, ttlMs: number): Promise
delete(key: string): Promise
}
Example with Redis:
`typescript
import { createClient } from 'redis';
class RedisIdempotencyStore implements IdempotencyStore {
private client = createClient();
async get(key: string) {
const value = await this.client.get(key);
return value ? JSON.parse(value) : null;
}
async set(key: string, value: any, ttlMs: number) {
await this.client.setEx(key, Math.floor(ttlMs / 1000), JSON.stringify(value));
}
async delete(key: string) {
await this.client.del(key);
}
}
`
Add custom health and readiness checks:
`typescript`
const bot = new BotSDK({
name: 'my-bot',
version: '1.0.0',
tools,
healthChecks: [
{
name: 'database',
check: async () => {
try {
await db.ping();
return true;
} catch {
return false;
}
},
},
],
readinessChecks: [
{
name: 'api',
check: async () => {
try {
await fetch('https://api.example.com/health');
return true;
} catch {
return false;
}
},
},
],
});
The SDK automatically creates these endpoints:
GET /healthz
`Response:
`json
{
"status": "healthy",
"timestamp": "2024-01-20T10:30:00Z",
"uptime": 3600.5
}
`$3
`
GET /readyz
`Response:
`json
{
"status": "ready",
"timestamp": "2024-01-20T10:30:00Z",
"checks": {
"database": true,
"api": true
}
}
`$3
`
GET /tools
`Response:
`json
{
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": [
{
"name": "location",
"type": "string",
"description": "City name",
"required": true
}
]
}
]
}
`$3
`
POST /tools/:toolName
Content-Type: application/json
X-Correlation-ID: req-12345 (optional)
X-Idempotency-Key: unique-key (optional){
"parameters": {
"location": "San Francisco"
}
}
`Response:
`json
{
"success": true,
"result": {
"temperature": 72,
"condition": "sunny"
}
}
`$3
`
GET :9090/metrics
`Returns Prometheus-formatted metrics.
Complete Example
`typescript
import { BotSDK, Tool, IdempotencyStore } from '@egintegrations/bot-sdk';
import { createClient } from 'redis';// Redis idempotency store
class RedisStore implements IdempotencyStore {
private client = createClient();
constructor() {
this.client.connect();
}
async get(key: string) {
const value = await this.client.get(key);
return value ? JSON.parse(value) : null;
}
async set(key: string, value: any, ttlMs: number) {
await this.client.setEx(key, Math.floor(ttlMs / 1000), JSON.stringify(value));
}
async delete(key: string) {
await this.client.del(key);
}
}
// Define tools
const tools: Tool[] = [
{
name: 'calculate',
description: 'Perform arithmetic calculation',
parameters: [
{ name: 'operation', type: 'string', description: 'add, subtract, multiply, divide', required: true },
{ name: 'a', type: 'number', description: 'First number', required: true },
{ name: 'b', type: 'number', description: 'Second number', required: true },
],
handler: async (params, correlationId) => {
const { operation, a, b } = params;
switch (operation) {
case 'add': return { result: a + b };
case 'subtract': return { result: a - b };
case 'multiply': return { result: a * b };
case 'divide': return { result: a / b };
default: throw new Error('Invalid operation');
}
},
},
{
name: 'get_time',
description: 'Get current time',
parameters: [],
handler: async () => {
return { time: new Date().toISOString() };
},
},
];
// Create bot
const bot = new BotSDK({
name: 'calculator-bot',
version: '1.0.0',
port: 3000,
metricsPort: 9090,
enableTracing: true,
tools,
idempotencyStore: new RedisStore(),
healthChecks: [
{
name: 'redis',
check: async () => {
// Check Redis connection
return true;
},
},
],
});
// Add custom routes
const app = bot.getApp();
app.get('/custom', (req, res) => {
res.json({ message: 'Custom endpoint' });
});
// Start bot
await bot.start();
console.log('Calculator bot started on port 3000');
// Graceful shutdown
process.on('SIGTERM', async () => {
await bot.stop();
process.exit(0);
});
`Observability
The SDK includes built-in observability:
$3
Uses Winston for structured logging:
`typescript
import { logger, createChildLogger } from '@egintegrations/bot-sdk';// Main logger
logger.info('Application started');
// Child logger with correlation ID
const childLogger = createChildLogger('request-123');
childLogger.info('Processing request');
`$3
Prometheus metrics automatically collected:
-
http_requests_total - Total HTTP requests
- http_request_duration_seconds - Request duration histogram
- tool_executions_total - Total tool executions
- tool_execution_duration_seconds - Tool execution duration
- idempotency_hits_total - Idempotency cache hits
- idempotency_misses_total - Idempotency cache misses
- error_total - Total errors by type$3
OpenTelemetry distributed tracing enabled by default. Configure with environment variables:
`bash
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=my-bot
`Error Handling
The SDK provides comprehensive error types:
`typescript
import { BotError, ToolExecutionError, ValidationError } from '@egintegrations/bot-sdk';// Tool errors are automatically caught and formatted
throw new ToolExecutionError('Failed to execute tool', originalError);
// Validation errors for parameter validation
throw new ValidationError('Invalid parameters');
// Generic bot errors with status codes
throw new BotError('Not found', 404, 'NOT_FOUND');
`Runtime Tool Management
Add or remove tools at runtime:
`typescript
const toolHandler = bot.getToolHandler();// Register new tool
toolHandler.registerTool({
name: 'new_tool',
description: 'A new tool',
parameters: [],
handler: async () => ({ result: 'success' }),
});
// Unregister tool
toolHandler.unregisterTool('old_tool');
// List all tools
const tools = toolHandler.listTools();
`Source Project
Extracted from egi-botnet:
- BotSDK:
packages/bot-sdk-node/src/bot-sdk.ts
- ToolHandler: packages/bot-sdk-node/src/tool-handler.ts
- Health endpoints: packages/bot-sdk-node/src/endpoints.ts`Refactored with:
- Dependency injection for idempotency storage
- Integration with published @egintegrations packages
- Configurable health and readiness checks
- Improved error handling and observability
MIT
See the main egi-comp-library repository for contribution guidelines.