@egintegrations/bot-sdk
v0.1.0
Published
Bot orchestration SDK for building autonomous agent systems with tool execution, health monitoring, and observability built-in.
Maintainers
Readme
@egintegrations/bot-sdk
Bot orchestration SDK for building autonomous agent systems. Provides a complete framework for tool execution, health monitoring, observability, and idempotency out of the box.
Features
- 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
Installation
npm install @egintegrations/bot-sdk express zodPeer Dependencies
npm install express zodThe SDK automatically includes:
@egintegrations/core-utils- Error handling, retry logic, idempotency@egintegrations/observability- Logging, metrics, telemetry
Quick Start
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');API Reference
BotSDK
Main SDK class for creating and managing bots.
const bot = new BotSDK(config: BotSDKConfig);Configuration
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
// Start the bot server
await bot.start(): Promise<void>
// Stop the bot server
await bot.stop(): Promise<void>
// Get Express app for custom routes
bot.getApp(): Express
// Get tool handler for runtime tool management
bot.getToolHandler(): ToolHandlerTool Definition
interface Tool {
name: string;
description: string;
parameters: ToolParameter[];
handler: (params: Record<string, any>, correlationId: string) => Promise<any>;
}
interface ToolParameter {
name: string;
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
description: string;
required: boolean;
default?: any;
}Idempotency Store
Implement this interface to provide custom idempotency storage:
interface IdempotencyStore {
get(key: string): Promise<any | null>;
set(key: string, value: any, ttlMs: number): Promise<void>;
delete(key: string): Promise<void>;
}Example with Redis:
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);
}
}Health Checks
Add custom health and readiness checks:
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;
}
},
},
],
});HTTP Endpoints
The SDK automatically creates these endpoints:
Health Endpoint
GET /healthzResponse:
{
"status": "healthy",
"timestamp": "2024-01-20T10:30:00Z",
"uptime": 3600.5
}Readiness Endpoint
GET /readyzResponse:
{
"status": "ready",
"timestamp": "2024-01-20T10:30:00Z",
"checks": {
"database": true,
"api": true
}
}List Tools
GET /toolsResponse:
{
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": [
{
"name": "location",
"type": "string",
"description": "City name",
"required": true
}
]
}
]
}Execute Tool
POST /tools/:toolName
Content-Type: application/json
X-Correlation-ID: req-12345 (optional)
X-Idempotency-Key: unique-key (optional)
{
"parameters": {
"location": "San Francisco"
}
}Response:
{
"success": true,
"result": {
"temperature": 72,
"condition": "sunny"
}
}Metrics Endpoint
GET :9090/metricsReturns Prometheus-formatted metrics.
Complete Example
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:
Logging
Uses Winston for structured logging:
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');Metrics
Prometheus metrics automatically collected:
http_requests_total- Total HTTP requestshttp_request_duration_seconds- Request duration histogramtool_executions_total- Total tool executionstool_execution_duration_seconds- Tool execution durationidempotency_hits_total- Idempotency cache hitsidempotency_misses_total- Idempotency cache misseserror_total- Total errors by type
Tracing
OpenTelemetry distributed tracing enabled by default. Configure with environment variables:
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=my-botError Handling
The SDK provides comprehensive error types:
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:
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
License
MIT
Contributing
See the main egi-comp-library repository for contribution guidelines.
