UNPKG

@meshailabs/sdk

Version:

MeshAI SDK for JavaScript/TypeScript - Universal AI Agent Orchestration

942 lines (935 loc) 28 kB
// src/types.ts var TaskStatus = /* @__PURE__ */ ((TaskStatus2) => { TaskStatus2["PENDING"] = "pending"; TaskStatus2["ROUTING"] = "routing"; TaskStatus2["EXECUTING"] = "executing"; TaskStatus2["COMPLETED"] = "completed"; TaskStatus2["FAILED"] = "failed"; TaskStatus2["CANCELLED"] = "cancelled"; return TaskStatus2; })(TaskStatus || {}); var AgentStatus = /* @__PURE__ */ ((AgentStatus2) => { AgentStatus2["ACTIVE"] = "active"; AgentStatus2["INACTIVE"] = "inactive"; AgentStatus2["ERROR"] = "error"; return AgentStatus2; })(AgentStatus || {}); var RoutingStrategy = /* @__PURE__ */ ((RoutingStrategy3) => { RoutingStrategy3["ROUND_ROBIN"] = "round_robin"; RoutingStrategy3["CAPABILITY_MATCH"] = "capability_match"; RoutingStrategy3["LEAST_LOADED"] = "least_loaded"; RoutingStrategy3["PERFORMANCE_BASED"] = "performance_based"; RoutingStrategy3["STICKY_SESSION"] = "sticky_session"; RoutingStrategy3["COST_OPTIMIZED"] = "cost_optimized"; RoutingStrategy3["GEOGRAPHIC"] = "geographic"; return RoutingStrategy3; })(RoutingStrategy || {}); // src/config.ts var MeshConfig = class _MeshConfig { constructor(options = {}) { this.apiKey = options.apiKey || process.env.MESHAI_API_KEY || ""; if (!this.apiKey) { console.warn("MeshAI SDK: No API key provided. Set MESHAI_API_KEY environment variable or pass apiKey in config."); } this.registryUrl = options.registryUrl || process.env.MESHAI_REGISTRY_URL || "https://api.meshai.dev/registry"; this.runtimeUrl = options.runtimeUrl || process.env.MESHAI_RUNTIME_URL || "https://api.meshai.dev/runtime"; this.timeout = options.timeout || 3e4; this.maxRetries = options.maxRetries || 3; this.retryDelay = options.retryDelay || 1e3; this.connectionPoolSize = options.connectionPoolSize || 10; this.maxConcurrentTasks = options.maxConcurrentTasks || 100; this.circuitBreakerEnabled = options.circuitBreakerEnabled !== false; this.circuitBreakerThreshold = options.circuitBreakerThreshold || 5; this.circuitBreakerResetTimeout = options.circuitBreakerResetTimeout || 6e4; this.defaultRoutingStrategy = options.defaultRoutingStrategy || "capability_match" /* CAPABILITY_MATCH */; this.metricsEnabled = options.metricsEnabled !== false; this.logLevel = options.logLevel || "info"; this.customHeaders = options.customHeaders || {}; this.validateSsl = options.validateSsl !== false; } /** * Get headers for API requests */ getHeaders() { const headers = { "Content-Type": "application/json", "Accept": "application/json", "User-Agent": "MeshAI-SDK-JS/0.1.0", ...this.customHeaders }; if (this.apiKey) { headers["X-API-Key"] = this.apiKey; } return headers; } /** * Validate configuration */ validate() { if (!this.apiKey) { throw new Error("API key is required for MeshAI SDK"); } if (!this.registryUrl) { throw new Error("Registry URL is required"); } if (!this.runtimeUrl) { throw new Error("Runtime URL is required"); } if (this.timeout <= 0) { throw new Error("Timeout must be greater than 0"); } if (this.maxRetries < 0) { throw new Error("Max retries must be non-negative"); } } /** * Create a copy of the config with overrides */ withOverrides(overrides) { return new _MeshConfig({ apiKey: overrides.apiKey ?? this.apiKey, registryUrl: overrides.registryUrl ?? this.registryUrl, runtimeUrl: overrides.runtimeUrl ?? this.runtimeUrl, timeout: overrides.timeout ?? this.timeout, maxRetries: overrides.maxRetries ?? this.maxRetries, retryDelay: overrides.retryDelay ?? this.retryDelay, connectionPoolSize: overrides.connectionPoolSize ?? this.connectionPoolSize, maxConcurrentTasks: overrides.maxConcurrentTasks ?? this.maxConcurrentTasks, circuitBreakerEnabled: overrides.circuitBreakerEnabled ?? this.circuitBreakerEnabled, circuitBreakerThreshold: overrides.circuitBreakerThreshold ?? this.circuitBreakerThreshold, circuitBreakerResetTimeout: overrides.circuitBreakerResetTimeout ?? this.circuitBreakerResetTimeout, defaultRoutingStrategy: overrides.defaultRoutingStrategy ?? this.defaultRoutingStrategy, metricsEnabled: overrides.metricsEnabled ?? this.metricsEnabled, logLevel: overrides.logLevel ?? this.logLevel, customHeaders: { ...this.customHeaders, ...overrides.customHeaders }, validateSsl: overrides.validateSsl ?? this.validateSsl }); } }; // src/clients/registry.ts import axios from "axios"; // src/errors.ts var MeshError = class _MeshError extends Error { constructor(message, code, statusCode, details) { super(message); this.name = "MeshError"; this.code = code; this.statusCode = statusCode; this.details = details; Object.setPrototypeOf(this, _MeshError.prototype); } }; var AuthenticationError = class _AuthenticationError extends MeshError { constructor(message = "Authentication failed", details) { super(message, "AUTHENTICATION_ERROR", 401, details); this.name = "AuthenticationError"; Object.setPrototypeOf(this, _AuthenticationError.prototype); } }; var AuthorizationError = class _AuthorizationError extends MeshError { constructor(message = "Authorization failed", details) { super(message, "AUTHORIZATION_ERROR", 403, details); this.name = "AuthorizationError"; Object.setPrototypeOf(this, _AuthorizationError.prototype); } }; var ValidationError = class _ValidationError extends MeshError { constructor(message, details) { super(message, "VALIDATION_ERROR", 400, details); this.name = "ValidationError"; Object.setPrototypeOf(this, _ValidationError.prototype); } }; var NotFoundError = class _NotFoundError extends MeshError { constructor(resource, identifier) { const message = identifier ? `${resource} with identifier '${identifier}' not found` : `${resource} not found`; super(message, "NOT_FOUND", 404); this.name = "NotFoundError"; Object.setPrototypeOf(this, _NotFoundError.prototype); } }; var TimeoutError = class _TimeoutError extends MeshError { constructor(message = "Operation timed out", timeoutSeconds) { super(message, "TIMEOUT_ERROR", 408, { timeoutSeconds }); this.name = "TimeoutError"; Object.setPrototypeOf(this, _TimeoutError.prototype); } }; var RateLimitError = class _RateLimitError extends MeshError { constructor(message = "Rate limit exceeded", retryAfter) { super(message, "RATE_LIMIT_ERROR", 429, { retryAfter }); this.name = "RateLimitError"; this.retryAfter = retryAfter; Object.setPrototypeOf(this, _RateLimitError.prototype); } }; var NetworkError = class _NetworkError extends MeshError { constructor(message = "Network error occurred", details) { super(message, "NETWORK_ERROR", 0, details); this.name = "NetworkError"; Object.setPrototypeOf(this, _NetworkError.prototype); } }; var AgentError = class _AgentError extends MeshError { constructor(message, agentId, details) { super(message, "AGENT_ERROR", 500, { ...details, agentId }); this.name = "AgentError"; this.agentId = agentId; Object.setPrototypeOf(this, _AgentError.prototype); } }; var TaskExecutionError = class _TaskExecutionError extends MeshError { constructor(message, taskId, agentId, details) { super(message, "TASK_EXECUTION_ERROR", 500, { ...details, taskId, agentId }); this.name = "TaskExecutionError"; this.taskId = taskId; this.agentId = agentId; Object.setPrototypeOf(this, _TaskExecutionError.prototype); } }; // src/clients/registry.ts var RegistryClient = class { constructor(config) { this.config = config; this.client = axios.create({ baseURL: config.registryUrl, timeout: config.timeout, headers: config.getHeaders(), validateStatus: (status) => status < 500 }); this.setupInterceptors(); } setupInterceptors() { this.client.interceptors.response.use( (response) => response, async (error) => { if (error.response) { const status = error.response.status; const data = error.response.data; switch (status) { case 401: throw new AuthenticationError(data?.message || "Invalid API key"); case 404: throw new NotFoundError("Resource", data?.resource); case 429: const retryAfter = error.response.headers["retry-after"]; throw new RateLimitError(data?.message, retryAfter ? parseInt(retryAfter) : void 0); case 400: throw new ValidationError(data?.message || "Invalid request", data?.errors); default: throw new MeshError( data?.message || error.message, data?.code, status, data ); } } else if (error.request) { throw new NetworkError("No response received from server", { request: error.config?.url }); } else { throw new MeshError(error.message); } } ); } /** * Register a new agent with MeshAI */ async registerAgent(registration) { try { const response = await this.client.post("/agents", registration); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to register agent", "REGISTRATION_ERROR"); } } /** * Update an existing agent */ async updateAgent(agentId, updates) { try { const response = await this.client.put(`/agents/${agentId}`, updates); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to update agent", "UPDATE_ERROR"); } } /** * Deregister an agent */ async deregisterAgent(agentId) { try { await this.client.delete(`/agents/${agentId}`); } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to deregister agent", "DEREGISTRATION_ERROR"); } } /** * Get agent information by ID */ async getAgent(agentId) { try { const response = await this.client.get(`/agents/${agentId}`); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new NotFoundError("Agent", agentId); } } /** * List all registered agents */ async listAgents(limit, offset) { try { const params = {}; if (limit !== void 0) params.limit = limit; if (offset !== void 0) params.offset = offset; const response = await this.client.get("/agents", { params }); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to list agents", "LIST_ERROR"); } } /** * Discover agents based on capabilities and requirements */ async discoverAgents(query) { try { const response = await this.client.post("/agents/discover", query); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to discover agents", "DISCOVERY_ERROR"); } } /** * Check health of a specific agent */ async checkAgentHealth(agentId) { try { const response = await this.client.get(`/agents/${agentId}/health`); return { ...response.data, lastCheck: new Date(response.data.lastCheck) }; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to check agent health", "HEALTH_CHECK_ERROR"); } } /** * Get agent metrics and statistics */ async getAgentMetrics(agentId) { try { const response = await this.client.get(`/agents/${agentId}/metrics`); return { ...response.data, lastExecuted: response.data.lastExecuted ? new Date(response.data.lastExecuted) : void 0 }; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to get agent metrics", "METRICS_ERROR"); } } /** * Update agent status */ async updateAgentStatus(agentId, status) { try { await this.client.patch(`/agents/${agentId}/status`, { status }); } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to update agent status", "STATUS_UPDATE_ERROR"); } } /** * Heartbeat to maintain agent registration */ async sendHeartbeat(agentId) { try { await this.client.post(`/agents/${agentId}/heartbeat`); } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to send heartbeat", "HEARTBEAT_ERROR"); } } /** * Get system-wide statistics */ async getSystemStats() { try { const response = await this.client.get("/stats"); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to get system stats", "STATS_ERROR"); } } }; // src/clients/runtime.ts import axios2 from "axios"; import WebSocket from "ws"; var RuntimeClient = class { constructor(config) { this.config = config; this.taskCallbacks = /* @__PURE__ */ new Map(); this.progressCallbacks = /* @__PURE__ */ new Map(); this.client = axios2.create({ baseURL: config.runtimeUrl, timeout: config.timeout, headers: config.getHeaders(), validateStatus: (status) => status < 500 }); this.setupInterceptors(); } setupInterceptors() { this.client.interceptors.response.use( (response) => response, async (error) => { if (error.response) { const status = error.response.status; const data = error.response.data; switch (status) { case 401: throw new AuthenticationError(data?.message || "Invalid API key"); case 400: throw new ValidationError(data?.message || "Invalid request", data?.errors); case 408: throw new TimeoutError(data?.message || "Task execution timed out"); default: throw new TaskExecutionError( data?.message || error.message, data?.taskId, data?.agentId, data ); } } else if (error.request) { throw new NetworkError("No response received from runtime", { request: error.config?.url }); } else { throw new MeshError(error.message); } } ); } /** * Execute a task through MeshAI runtime */ async execute(task, options = {}) { if (!task.routingStrategy) { task.routingStrategy = this.config.defaultRoutingStrategy; } try { if (options.async) { const response = await this.client.post("/tasks/async", task); const taskId = response.data.taskId; if (options.callback || options.onProgress) { this.setupWebSocketMonitoring(taskId, options.callback, options.onProgress); } return { taskId, status: "pending" /* PENDING */, startedAt: /* @__PURE__ */ new Date() }; } else { const response = await this.client.post("/tasks", task); return response.data; } } catch (error) { if (error instanceof MeshError) throw error; throw new TaskExecutionError( "Failed to execute task", task.taskId, void 0, { error: error instanceof Error ? error.message : error } ); } } /** * Execute task with specific agent */ async executeWithAgent(agentId, task, options = {}) { try { const response = await this.client.post( `/tasks/agent/${agentId}`, task ); if (options.callback) { options.callback(response.data); } return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new TaskExecutionError( "Failed to execute task with specific agent", task.taskId, agentId ); } } /** * Execute batch of tasks */ async executeBatch(tasks) { try { const response = await this.client.post("/tasks/batch", { tasks }); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new TaskExecutionError("Failed to execute batch tasks"); } } /** * Get task status */ async getTaskStatus(taskId) { try { const response = await this.client.get(`/tasks/${taskId}`); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new TaskExecutionError("Failed to get task status", taskId); } } /** * Cancel a running task */ async cancelTask(taskId) { try { await this.client.post(`/tasks/${taskId}/cancel`); } catch (error) { if (error instanceof MeshError) throw error; throw new TaskExecutionError("Failed to cancel task", taskId); } } /** * Retry a failed task */ async retryTask(taskId) { try { const response = await this.client.post(`/tasks/${taskId}/retry`); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new TaskExecutionError("Failed to retry task", taskId); } } /** * Get task history for a conversation */ async getTaskHistory(conversationId) { try { const response = await this.client.get( `/conversations/${conversationId}/tasks` ); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to get task history", "HISTORY_ERROR"); } } /** * Get conversation context */ async getConversationContext(conversationId) { try { const response = await this.client.get( `/conversations/${conversationId}/context` ); return response.data; } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to get conversation context", "CONTEXT_ERROR"); } } /** * Update conversation context */ async updateConversationContext(conversationId, updates) { try { await this.client.patch( `/conversations/${conversationId}/context`, updates ); } catch (error) { if (error instanceof MeshError) throw error; throw new MeshError("Failed to update conversation context", "CONTEXT_UPDATE_ERROR"); } } /** * Setup WebSocket monitoring for async tasks */ setupWebSocketMonitoring(taskId, callback, onProgress) { if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) { this.connectWebSocket(); } if (callback) { this.taskCallbacks.set(taskId, callback); } if (onProgress) { this.progressCallbacks.set(taskId, onProgress); } if (this.websocket && this.websocket.readyState === WebSocket.OPEN) { this.websocket.send(JSON.stringify({ type: "subscribe", taskId })); } } /** * Connect to WebSocket for real-time updates */ connectWebSocket() { const wsUrl = this.config.runtimeUrl.replace(/^http/, "ws") + "/ws"; const headers = this.config.getHeaders(); this.websocket = new WebSocket(wsUrl, { headers }); this.websocket.on("open", () => { console.log("WebSocket connected to MeshAI runtime"); }); this.websocket.on("message", (data) => { try { const message = JSON.parse(data.toString()); this.handleWebSocketMessage(message); } catch (error) { console.error("Failed to parse WebSocket message:", error); } }); this.websocket.on("close", () => { console.log("WebSocket disconnected from MeshAI runtime"); setTimeout(() => { if (this.taskCallbacks.size > 0 || this.progressCallbacks.size > 0) { this.connectWebSocket(); } }, 5e3); }); this.websocket.on("error", (error) => { console.error("WebSocket error:", error); }); } /** * Handle WebSocket messages */ handleWebSocketMessage(message) { const { type, taskId, data } = message; switch (type) { case "task_update": const progressCallback = this.progressCallbacks.get(taskId); if (progressCallback) { progressCallback(data.status, data.details); } break; case "task_complete": const callback = this.taskCallbacks.get(taskId); if (callback) { callback(data); this.taskCallbacks.delete(taskId); this.progressCallbacks.delete(taskId); } break; case "task_error": const errorCallback = this.taskCallbacks.get(taskId); if (errorCallback) { errorCallback({ taskId, status: "failed" /* FAILED */, error: data.error }); this.taskCallbacks.delete(taskId); this.progressCallbacks.delete(taskId); } break; } } /** * Disconnect WebSocket */ disconnect() { if (this.websocket) { this.websocket.close(); this.websocket = void 0; } this.taskCallbacks.clear(); this.progressCallbacks.clear(); } }; // src/client.ts var MeshClient = class _MeshClient { constructor(options = {}) { this.initialized = false; this.config = new MeshConfig(options); this.registry = new RegistryClient(this.config); this.runtime = new RuntimeClient(this.config); } /** * Initialize the client and validate configuration */ async initialize() { if (this.initialized) return; try { this.config.validate(); await Promise.all([ this.registry.getSystemStats() // Add runtime health check when available ]); this.initialized = true; } catch (error) { throw new MeshError( "Failed to initialize MeshAI client", "INITIALIZATION_ERROR", void 0, { error: error instanceof Error ? error.message : error } ); } } /** * Register an agent with MeshAI */ async registerAgent(registration) { await this.ensureInitialized(); return this.registry.registerAgent(registration); } /** * Execute a task using intelligent routing */ async execute(task, options = {}) { await this.ensureInitialized(); return this.runtime.execute(task, options); } /** * Execute a task with a specific agent */ async executeWithAgent(agentId, task, options = {}) { await this.ensureInitialized(); return this.runtime.executeWithAgent(agentId, task, options); } /** * Discover agents based on capabilities */ async discoverAgents(query) { await this.ensureInitialized(); return this.registry.discoverAgents(query); } /** * Get agent by ID */ async getAgent(agentId) { await this.ensureInitialized(); return this.registry.getAgent(agentId); } /** * List all available agents */ async listAgents(limit, offset) { await this.ensureInitialized(); return this.registry.listAgents(limit, offset); } /** * Update agent information */ async updateAgent(agentId, updates) { await this.ensureInitialized(); return this.registry.updateAgent(agentId, updates); } /** * Deregister an agent */ async deregisterAgent(agentId) { await this.ensureInitialized(); return this.registry.deregisterAgent(agentId); } /** * Check agent health */ async checkAgentHealth(agentId) { await this.ensureInitialized(); return this.registry.checkAgentHealth(agentId); } /** * Get task status */ async getTaskStatus(taskId) { await this.ensureInitialized(); return this.runtime.getTaskStatus(taskId); } /** * Cancel a running task */ async cancelTask(taskId) { await this.ensureInitialized(); return this.runtime.cancelTask(taskId); } /** * Retry a failed task */ async retryTask(taskId) { await this.ensureInitialized(); return this.runtime.retryTask(taskId); } /** * Execute batch of tasks */ async executeBatch(tasks) { await this.ensureInitialized(); return this.runtime.executeBatch(tasks); } /** * Get conversation context */ async getConversationContext(conversationId) { await this.ensureInitialized(); return this.runtime.getConversationContext(conversationId); } /** * Update conversation context */ async updateConversationContext(conversationId, updates) { await this.ensureInitialized(); return this.runtime.updateConversationContext(conversationId, updates); } /** * Get task history for a conversation */ async getTaskHistory(conversationId) { await this.ensureInitialized(); return this.runtime.getTaskHistory(conversationId); } /** * Get system statistics */ async getSystemStats() { await this.ensureInitialized(); return this.registry.getSystemStats(); } /** * Get agent metrics */ async getAgentMetrics(agentId) { await this.ensureInitialized(); return this.registry.getAgentMetrics(agentId); } /** * Update agent status */ async updateAgentStatus(agentId, status) { await this.ensureInitialized(); return this.registry.updateAgentStatus(agentId, status); } /** * Send heartbeat to maintain agent registration */ async sendHeartbeat(agentId) { await this.ensureInitialized(); return this.registry.sendHeartbeat(agentId); } /** * Create a task with default configuration */ createTask(input, options = {}) { return { taskType: options.taskType || "general", input, parameters: options.parameters, context: options.context, requiredCapabilities: options.requiredCapabilities, preferredFramework: options.preferredFramework, routingStrategy: options.routingStrategy || this.config.defaultRoutingStrategy, timeoutSeconds: options.timeoutSeconds, maxRetries: options.maxRetries, preserveContext: options.preserveContext, conversationId: options.conversationId, sourceAgent: options.sourceAgent, correlationId: options.correlationId }; } /** * Quick execute - simplified task execution */ async quickExecute(input, capabilities) { const task = this.createTask(input, { requiredCapabilities: capabilities }); return this.execute(task); } /** * Disconnect and cleanup resources */ disconnect() { this.runtime.disconnect(); this.initialized = false; } /** * Ensure client is initialized */ async ensureInitialized() { if (!this.initialized) { await this.initialize(); } } /** * Create a new MeshClient instance */ static create(options = {}) { return new _MeshClient(options); } /** * Create and initialize a MeshClient */ static async createAndInitialize(options = {}) { const client = new _MeshClient(options); await client.initialize(); return client; } }; export { AgentError, AgentStatus, AuthenticationError, AuthorizationError, MeshClient, MeshConfig, MeshError, NetworkError, NotFoundError, RateLimitError, RegistryClient, RoutingStrategy, RuntimeClient, TaskExecutionError, TaskStatus, TimeoutError, ValidationError };