@robota-sdk/agent-plugin 3.0.0-beta.65 → 3.0.0-beta.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -0
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/package.json +4 -2
- package/src/conversation-history/conversation-history-helpers.ts +2 -0
- package/src/conversation-history/conversation-history-plugin.ts +8 -6
- package/src/conversation-history/storages/database-storage.ts +2 -1
- package/src/conversation-history/storages/file-storage.ts +2 -1
- package/src/error-handling/error-handling-helpers.ts +1 -0
- package/src/error-handling/error-handling-plugin.ts +15 -14
- package/src/execution-analytics/execution-analytics-plugin.ts +18 -7
- package/src/limits/limits-helpers.ts +2 -1
- package/src/limits/limits-plugin.ts +10 -8
- package/src/limits/validation.ts +1 -0
- package/src/logging/logging-helpers.ts +2 -0
- package/src/logging/logging-plugin.ts +10 -9
- package/src/logging/storages/console-storage.ts +4 -2
- package/src/logging/storages/file-storage.ts +4 -2
- package/src/logging/storages/remote-storage.ts +4 -2
- package/src/performance/collectors/system-metrics-collector.ts +2 -1
- package/src/performance/performance-helpers.ts +2 -0
- package/src/performance/performance-plugin.ts +9 -7
- package/src/performance/storages/memory-storage.ts +5 -1
- package/src/usage/storages/file-storage.ts +3 -1
- package/src/usage/storages/memory-storage.ts +2 -1
- package/src/usage/storages/remote-storage.ts +3 -1
- package/src/usage/storages/silent-storage.ts +2 -1
- package/src/usage/usage-plugin-helpers.ts +1 -0
- package/src/usage/usage-plugin.ts +9 -7
- package/src/webhook/http-client.ts +1 -0
- package/src/webhook/transformer.ts +6 -6
- package/src/webhook/types.ts +7 -4
- package/src/webhook/webhook-helpers.ts +1 -0
- package/src/webhook/webhook-plugin.ts +2 -1
- package/src/webhook/webhook-queue.ts +2 -1
package/dist/node/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["DEFAULT_MAX_RETRIES","DEFAULT_MAX_ENTRIES","DEFAULT_PERFORMANCE_THRESHOLD_MS","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","DEFAULT_MAX_ENTRIES","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","DEFAULT_AGGREGATION_INTERVAL_MS"],"sources":["../../src/conversation-history/storages/memory-storage.ts","../../src/conversation-history/storages/file-storage.ts","../../src/conversation-history/storages/database-storage.ts","../../src/conversation-history/conversation-history-helpers.ts","../../src/conversation-history/conversation-history-plugin.ts","../../src/error-handling/context-adapter.ts","../../src/error-handling/error-handling-helpers.ts","../../src/error-handling/error-handling-plugin.ts","../../src/execution-analytics/analytics-aggregation.ts","../../src/execution-analytics/execution-analytics-helpers.ts","../../src/execution-analytics/execution-analytics-plugin.ts","../../src/limits/validation.ts","../../src/limits/limits-helpers.ts","../../src/limits/limits-plugin.ts","../../src/logging/formatters.ts","../../src/logging/storages/console-storage.ts","../../src/logging/storages/file-storage.ts","../../src/logging/storages/remote-storage.ts","../../src/logging/storages/silent-storage.ts","../../src/logging/logging-helpers.ts","../../src/logging/logging-plugin.ts","../../src/performance/collectors/system-metrics-collector.ts","../../src/performance/storages/memory-storage.ts","../../src/performance/performance-helpers.ts","../../src/performance/performance-plugin.ts","../../src/usage/aggregate-usage-stats.ts","../../src/usage/storages/memory-storage.ts","../../src/usage/storages/file-storage.ts","../../src/usage/storages/remote-storage.ts","../../src/usage/storages/silent-storage.ts","../../src/usage/usage-plugin-helpers.ts","../../src/usage/usage-plugin.ts","../../src/webhook/transformer.ts","../../src/webhook/http-client.ts","../../src/webhook/webhook-helpers.ts","../../src/webhook/webhook-queue.ts","../../src/webhook/webhook-plugin.ts"],"sourcesContent":["import type { IHistoryStorage, IConversationHistoryEntry } from '../types';\n\n/**\n * Memory storage implementation\n */\nexport class MemoryHistoryStorage implements IHistoryStorage {\n private conversations = new Map<string, IConversationHistoryEntry>();\n private maxConversations: number;\n\n constructor(maxConversations: number = 100) {\n this.maxConversations = maxConversations;\n }\n\n async save(conversationId: string, entry: IConversationHistoryEntry): Promise<void> {\n // Remove oldest conversation if limit exceeded\n if (\n this.conversations.size >= this.maxConversations &&\n !this.conversations.has(conversationId)\n ) {\n const oldestId = this.conversations.keys().next().value;\n if (oldestId) {\n this.conversations.delete(oldestId);\n }\n }\n\n this.conversations.set(conversationId, { ...entry });\n }\n\n async load(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n return this.conversations.get(conversationId);\n }\n\n async list(): Promise<string[]> {\n return Array.from(this.conversations.keys());\n }\n\n async delete(conversationId: string): Promise<boolean> {\n return this.conversations.delete(conversationId);\n }\n\n async clear(): Promise<void> {\n this.conversations.clear();\n }\n}\n","import type { IHistoryStorage, IConversationHistoryEntry } from '../types';\nimport { createLogger, type ILogger, StorageError } from '@robota-sdk/agent-core';\n\n/**\n * File storage implementation\n */\nexport class FileHistoryStorage implements IHistoryStorage {\n private filePath: string;\n private logger: ILogger;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n this.logger = createLogger('FileHistoryStorage');\n }\n\n async save(conversationId: string, _entry: IConversationHistoryEntry): Promise<void> {\n try {\n // File operations would be implemented here\n // This is a placeholder for actual file system operations\n this.logger.warn('File storage not fully implemented yet', {\n conversationId,\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to save conversation to file', {\n conversationId,\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async load(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n conversationId,\n filePath: this.filePath,\n });\n return undefined;\n } catch (error) {\n throw new StorageError('Failed to load conversation from file', {\n conversationId,\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async list(): Promise<string[]> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n filePath: this.filePath,\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to list conversations from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async delete(conversationId: string): Promise<boolean> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n conversationId,\n filePath: this.filePath,\n });\n return false;\n } catch (error) {\n throw new StorageError('Failed to delete conversation from file', {\n conversationId,\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to clear conversations from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n","import type { IHistoryStorage, IConversationHistoryEntry } from '../types';\nimport { createLogger, type ILogger, StorageError } from '@robota-sdk/agent-core';\n\n/**\n * Database storage implementation\n */\nexport class DatabaseHistoryStorage implements IHistoryStorage {\n private connectionString: string;\n private logger: ILogger;\n\n constructor(connectionString: string) {\n this.connectionString = connectionString;\n this.logger = createLogger('DatabaseHistoryStorage');\n }\n\n async save(conversationId: string, _entry: IConversationHistoryEntry): Promise<void> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n conversationId,\n connectionString: this.maskConnectionString(),\n });\n } catch (error) {\n throw new StorageError('Failed to save conversation to database', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async load(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n conversationId,\n connectionString: this.maskConnectionString(),\n });\n return undefined;\n } catch (error) {\n throw new StorageError('Failed to load conversation from database', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async list(): Promise<string[]> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n connectionString: this.maskConnectionString(),\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to list conversations from database', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async delete(conversationId: string): Promise<boolean> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n conversationId,\n connectionString: this.maskConnectionString(),\n });\n return false;\n } catch (error) {\n throw new StorageError('Failed to delete conversation from database', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n connectionString: this.maskConnectionString(),\n });\n } catch (error) {\n throw new StorageError('Failed to clear conversations from database', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Mask sensitive information in connection string for logging\n */\n private maskConnectionString(): string {\n return this.connectionString.replace(/(:\\/\\/[^:]+:)[^@]+(@)/, '$1***$2');\n }\n}\n","/**\n * Conversation History Plugin - Validation and storage factory helpers.\n *\n * Extracted from conversation-history-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError, PluginError, type ILogger } from '@robota-sdk/agent-core';\nimport { MemoryHistoryStorage, FileHistoryStorage, DatabaseHistoryStorage } from './storages/index';\nimport type {\n IConversationHistoryPluginOptions,\n IHistoryStorage,\n IConversationHistoryEntry,\n} from './types';\n\n/** Validate ConversationHistoryPlugin constructor options. @internal */\nexport function validateConversationHistoryOptions(\n options: IConversationHistoryPluginOptions,\n): void {\n if (!options.storage) {\n throw new ConfigurationError('Storage strategy is required');\n }\n\n if (!['memory', 'file', 'database'].includes(options.storage)) {\n throw new ConfigurationError('Invalid storage strategy', {\n validStrategies: ['memory', 'file', 'database'],\n provided: options.storage,\n });\n }\n\n if (options.storage === 'file' && !options.filePath) {\n throw new ConfigurationError('File path is required for file storage strategy');\n }\n\n if (options.storage === 'database' && !options.connectionString) {\n throw new ConfigurationError('Connection string is required for database storage strategy');\n }\n\n if (options.maxConversations !== undefined && options.maxConversations <= 0) {\n throw new ConfigurationError('Max conversations must be positive');\n }\n\n if (options.maxMessagesPerConversation !== undefined && options.maxMessagesPerConversation <= 0) {\n throw new ConfigurationError('Max messages per conversation must be positive');\n }\n}\n\n/**\n * Load a conversation entry from storage with error wrapping. @internal\n */\nexport async function loadConversationEntry(\n storage: IHistoryStorage,\n conversationId: string,\n pluginName: string,\n logger: ILogger,\n): Promise<IConversationHistoryEntry | undefined> {\n try {\n const entry = await storage.load(conversationId);\n logger.debug('Loaded conversation', {\n conversationId,\n found: !!entry,\n messageCount: entry?.messages.length ?? 0,\n });\n return entry;\n } catch (error) {\n throw new PluginError('Failed to load conversation', pluginName, {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\n/**\n * Flush all pending conversation saves to storage, logging individual failures. @internal\n */\nexport async function savePendingConversations(\n storage: IHistoryStorage,\n pendingSaves: Set<string>,\n pluginName: string,\n logger: ILogger,\n): Promise<void> {\n if (pendingSaves.size === 0) return;\n\n const conversationIds = Array.from(pendingSaves);\n logger.debug('Saving pending conversations', { count: conversationIds.length });\n\n for (const conversationId of conversationIds) {\n try {\n const entry = await storage.load(conversationId);\n if (entry) {\n await storage.save(conversationId, entry);\n }\n pendingSaves.delete(conversationId);\n } catch (error) {\n logger.error('Failed to save pending conversation', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n\n/** Create IHistoryStorage instance for the given strategy. @internal */\nexport function createHistoryStorage(\n strategy: string,\n maxConversations: number,\n filePath: string,\n connectionString: string,\n): IHistoryStorage {\n switch (strategy) {\n case 'memory':\n return new MemoryHistoryStorage(maxConversations);\n case 'file':\n return new FileHistoryStorage(filePath);\n case 'database':\n return new DatabaseHistoryStorage(connectionString);\n default:\n throw new ConfigurationError('Unknown storage strategy', { strategy });\n }\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n type TUniversalMessage,\n createLogger,\n type ILogger,\n PluginError,\n type TTimerId,\n startPeriodicTask,\n stopPeriodicTask,\n} from '@robota-sdk/agent-core';\nimport {\n IConversationHistoryPluginOptions,\n IConversationHistoryPluginStats,\n IConversationHistoryEntry,\n IHistoryStorage,\n} from './types';\nimport {\n validateConversationHistoryOptions,\n createHistoryStorage,\n loadConversationEntry,\n savePendingConversations,\n} from './conversation-history-helpers';\n\nconst DEFAULT_MAX_CONVERSATIONS = 100;\nconst DEFAULT_MAX_MESSAGES = 1000;\nconst DEFAULT_SAVE_INTERVAL_MS = 30000;\n\n/**\n * Persists conversation history using configurable storage backends.\n *\n * Supports memory, file, and database storage strategies. Messages are\n * automatically trimmed to {@link IConversationHistoryPluginOptions.maxMessagesPerConversation | maxMessagesPerConversation}.\n * When {@link IConversationHistoryPluginOptions.autoSave | autoSave} is\n * disabled, changes are batched and flushed on a timer.\n *\n * @extends AbstractPlugin\n * @see IHistoryStorage - storage backend contract\n * @see IConversationHistoryPluginOptions - configuration options\n *\n * @example\n * ```ts\n * const plugin = new ConversationHistoryPlugin({\n * storage: 'memory',\n * maxMessagesPerConversation: 500,\n * });\n * await plugin.startConversation('conv-1');\n * await plugin.addMessage({ role: 'user', content: 'Hello' });\n * ```\n */\nexport class ConversationHistoryPlugin extends AbstractPlugin<\n IConversationHistoryPluginOptions,\n IConversationHistoryPluginStats\n> {\n name = 'ConversationHistoryPlugin';\n version = '1.0.0';\n\n private storage: IHistoryStorage;\n private pluginOptions: Required<IConversationHistoryPluginOptions>;\n private logger: ILogger;\n private currentConversationId?: string;\n private batchSaveTimer?: TTimerId;\n private pendingSaves = new Set<string>();\n\n constructor(options: IConversationHistoryPluginOptions) {\n super();\n this.logger = createLogger('ConversationHistoryPlugin');\n\n // Set plugin classification\n this.category = PluginCategory.STORAGE;\n this.priority = PluginPriority.HIGH;\n\n // Validate options\n validateConversationHistoryOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n storage: options.storage,\n maxConversations: options.maxConversations ?? DEFAULT_MAX_CONVERSATIONS,\n maxMessagesPerConversation: options.maxMessagesPerConversation ?? DEFAULT_MAX_MESSAGES,\n filePath: options.filePath ?? './conversations.json',\n connectionString: options.connectionString ?? '',\n autoSave: options.autoSave ?? true,\n saveInterval: options.saveInterval ?? DEFAULT_SAVE_INTERVAL_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.STORAGE,\n priority: options.priority ?? PluginPriority.HIGH,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n\n // Initialize storage\n this.storage = createHistoryStorage(\n this.pluginOptions.storage,\n this.pluginOptions.maxConversations,\n this.pluginOptions.filePath,\n this.pluginOptions.connectionString,\n );\n\n // Setup batch saving if not auto-saving\n if (!this.pluginOptions.autoSave) {\n this.setupBatchSaving();\n }\n\n this.logger.info('ConversationHistoryPlugin initialized', {\n storage: this.pluginOptions.storage,\n maxConversations: this.pluginOptions.maxConversations,\n autoSave: this.pluginOptions.autoSave,\n });\n }\n\n /**\n * Creates a new conversation entry and persists it (or queues for batch save).\n * @throws PluginError if the storage write fails\n */\n async startConversation(conversationId: string): Promise<void> {\n try {\n this.currentConversationId = conversationId;\n\n const entry: IConversationHistoryEntry = {\n conversationId,\n messages: [],\n startTime: new Date(),\n lastUpdated: new Date(),\n metadata: {},\n };\n\n // Always persist the initial entry so subsequent loads can find it.\n // autoSave=false only means we track the id for deferred external flush via savePending.\n await this.storage.save(conversationId, entry);\n if (!this.pluginOptions.autoSave) {\n this.pendingSaves.add(conversationId);\n }\n\n this.logger.debug('Started new conversation', { conversationId });\n } catch (error) {\n throw new PluginError('Failed to start conversation', this.name, {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Appends a message to the active conversation, trimming to the maximum\n * message limit if exceeded.\n * @throws PluginError if no conversation is active or the storage write fails\n */\n async addMessage(message: TUniversalMessage): Promise<void> {\n if (!this.currentConversationId) {\n throw new PluginError('No active conversation', this.name);\n }\n\n try {\n const entry = (await this.storage.load(this.currentConversationId)) || {\n conversationId: this.currentConversationId,\n messages: [],\n startTime: new Date(),\n lastUpdated: new Date(),\n metadata: {},\n };\n\n // Add message and trim if necessary\n entry.messages.push(message);\n if (entry.messages.length > this.pluginOptions.maxMessagesPerConversation) {\n entry.messages = entry.messages.slice(-this.pluginOptions.maxMessagesPerConversation);\n }\n entry.lastUpdated = new Date();\n\n // Always persist the updated entry. autoSave=false tracks it as pending\n // for deferred external flush via savePending.\n await this.storage.save(this.currentConversationId, entry);\n if (!this.pluginOptions.autoSave) {\n this.pendingSaves.add(this.currentConversationId);\n }\n\n this.logger.debug('Added message to conversation', {\n conversationId: this.currentConversationId,\n messageRole: message.role,\n messageLength: message.content?.length ?? 0,\n });\n } catch (error) {\n throw new PluginError('Failed to add message to conversation', this.name, {\n conversationId: this.currentConversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Load conversation history\n */\n async loadConversation(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n return loadConversationEntry(this.storage, conversationId, this.name, this.logger);\n }\n\n /**\n * Get conversation history as messages\n */\n async getHistory(conversationId: string): Promise<TUniversalMessage[]> {\n const entry = await this.loadConversation(conversationId);\n return entry?.messages ?? [];\n }\n\n /**\n * List all conversation IDs\n */\n async listConversations(): Promise<string[]> {\n try {\n return await this.storage.list();\n } catch (error) {\n throw new PluginError('Failed to list conversations', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Delete a conversation\n */\n async deleteConversation(conversationId: string): Promise<boolean> {\n try {\n const deleted = await this.storage.delete(conversationId);\n this.pendingSaves.delete(conversationId);\n this.logger.debug('Deleted conversation', { conversationId, deleted });\n return deleted;\n } catch (error) {\n throw new PluginError('Failed to delete conversation', this.name, {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Clear all conversations\n */\n async clearAllConversations(): Promise<void> {\n try {\n await this.storage.clear();\n this.pendingSaves.clear();\n this.logger.info('Cleared all conversations');\n } catch (error) {\n throw new PluginError('Failed to clear conversations', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Persists all conversations queued since the last save (batch mode only).\n * Individual save failures are logged but do not abort the remaining saves.\n */\n async savePending(): Promise<void> {\n await savePendingConversations(this.storage, this.pendingSaves, this.name, this.logger);\n }\n\n /**\n * Stops the batch-save timer and flushes any pending conversation saves.\n */\n async destroy(): Promise<void> {\n try {\n stopPeriodicTask(this.batchSaveTimer);\n this.batchSaveTimer = undefined;\n\n // Save any pending conversations\n await this.savePending();\n\n this.logger.info('ConversationHistoryPlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Setup batch saving timer\n */\n private setupBatchSaving(): void {\n this.batchSaveTimer = startPeriodicTask(\n this.logger,\n {\n name: 'ConversationHistoryPlugin.savePending',\n intervalMs: this.pluginOptions.saveInterval,\n },\n async () => {\n await this.savePending();\n },\n );\n }\n}\n","/**\n * ErrorHandling Plugin - Context adapter utilities for Facade pattern\n *\n * REASON: TypeScript exactOptionalPropertyTypes strict mode requires special handling for optional properties\n * ALTERNATIVES_CONSIDERED: Bracket notation (rejected by TS), type assertions (rejected), interface modification (breaks compatibility), union types (causes dependencies), removing context (loses debugging)\n * TODO: Consider unified error context type system across all plugins\n */\n\nimport type { IErrorHandlingContextData, IErrorContextAdapter } from './types';\nimport type { TErrorContextData } from '@robota-sdk/agent-core';\n\n/**\n * Convert IErrorHandlingContextData to ErrorContextData-compatible format for PluginError\n * REASON: Simple object spread with known properties to avoid index signature conflicts\n * ALTERNATIVES_CONSIDERED: Complex type adapters (unnecessary), Object.assign (verbose), bracket notation (rejected by TS), type assertions (reduces safety)\n * TODO: Consider unified error context type system across all plugins\n */\nexport function toErrorContext(context: IErrorHandlingContextData): IErrorContextAdapter {\n return {\n ...(context.executionId && { executionId: context.executionId }),\n ...(context.sessionId && { sessionId: context.sessionId }),\n ...(context.userId && { userId: context.userId }),\n ...(context.attempt !== undefined && { attempt: context.attempt }),\n ...(context.originalError && { originalError: context.originalError }),\n };\n}\n\n/**\n * Safe context extraction for PluginError with nested context structure\n *\n * REASON: PluginError context needs flexible data structure for debugging information\n * ALTERNATIVES_CONSIDERED:\n * 1. Strict primitive types (loses debugging information)\n * 2. Interface definitions (too rigid for error contexts)\n * 3. Union types (becomes unwieldy for error data)\n * 4. Generic constraints (too complex for error handling)\n * 5. Type assertions (decreases type safety)\n * TODO: Consider standardized error context interface if patterns emerge\n */\nexport function createPluginErrorContext(\n context: IErrorHandlingContextData,\n additionalData?: TErrorContextData,\n): TErrorContextData {\n return {\n ...toErrorContext(context),\n ...(additionalData && { ...additionalData }),\n };\n}\n","/**\n * Error Handling Plugin - Validation and strategy handler helpers.\n *\n * Extracted from error-handling-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError } from '@robota-sdk/agent-core';\nimport type { IErrorHandlingPluginOptions } from './types';\n\n/** Validate ErrorHandlingPlugin constructor options. @internal */\nexport function validateErrorHandlingOptions(options: IErrorHandlingPluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Error handling strategy is required');\n }\n\n if (!['simple', 'circuit-breaker', 'exponential-backoff', 'silent'].includes(options.strategy)) {\n throw new ConfigurationError('Invalid error handling strategy', {\n validStrategies: ['simple', 'circuit-breaker', 'exponential-backoff', 'silent'],\n provided: options.strategy,\n });\n }\n\n if (options.maxRetries !== undefined && options.maxRetries < 0) {\n throw new ConfigurationError('Max retries must be non-negative');\n }\n\n if (options.retryDelay !== undefined && options.retryDelay <= 0) {\n throw new ConfigurationError('Retry delay must be positive');\n }\n}\n\n/** Resolve retry delay based on strategy and attempt number. @internal */\nexport function resolveRetryDelay(strategy: string, baseDelay: number, attempt: number): number {\n return strategy === 'exponential-backoff' ? baseDelay * Math.pow(2, attempt - 1) : baseDelay;\n}\n\n/** Resolve true if the circuit breaker timeout has not yet elapsed. @internal */\nexport function isCircuitBreakerStillOpen(\n circuitBreakerOpen: boolean,\n lastFailureTime: number,\n circuitBreakerTimeout: number,\n): { open: boolean; shouldReset: boolean } {\n if (!circuitBreakerOpen) return { open: false, shouldReset: false };\n const timeoutPassed = Date.now() - lastFailureTime > circuitBreakerTimeout;\n if (timeoutPassed) return { open: false, shouldReset: true };\n return { open: true, shouldReset: false };\n}\n\n/** Sleep for a given number of milliseconds. @internal */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n PluginError,\n} from '@robota-sdk/agent-core';\n\n// Import from Facade pattern modules for type safety\nimport type {\n IErrorHandlingContextData,\n IErrorHandlingPluginOptions,\n IErrorHandlingPluginStats,\n} from './types';\nimport { toErrorContext, createPluginErrorContext } from './context-adapter';\nimport {\n validateErrorHandlingOptions,\n resolveRetryDelay,\n isCircuitBreakerStillOpen,\n sleep,\n} from './error-handling-helpers';\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_DELAY_MS = 1000;\nconst DEFAULT_FAILURE_THRESHOLD = 5;\nconst DEFAULT_CIRCUIT_BREAKER_TIMEOUT_MS = 60000;\n\n/**\n * Provides configurable error recovery using one of four strategies:\n * simple logging, circuit breaker, exponential backoff, or silent.\n *\n * The circuit breaker opens after\n * {@link IErrorHandlingPluginOptions.failureThreshold | failureThreshold}\n * consecutive failures and automatically resets after\n * {@link IErrorHandlingPluginOptions.circuitBreakerTimeout | circuitBreakerTimeout} ms.\n * An optional custom error handler can be injected for application-specific\n * recovery logic.\n *\n * @extends AbstractPlugin\n * @see IErrorHandlingPluginOptions - configuration options\n * @see IErrorHandlingContextData - error context contract\n *\n * @example\n * ```ts\n * const plugin = new ErrorHandlingPlugin({\n * strategy: 'circuit-breaker',\n * failureThreshold: 5,\n * circuitBreakerTimeout: 60000,\n * });\n * const result = await plugin.executeWithRetry(() => fetchData());\n * ```\n */\nexport class ErrorHandlingPlugin extends AbstractPlugin<\n IErrorHandlingPluginOptions,\n IErrorHandlingPluginStats\n> {\n name = 'ErrorHandlingPlugin';\n version = '1.0.0';\n\n private pluginOptions: Required<Omit<IErrorHandlingPluginOptions, 'customErrorHandler'>> & {\n customErrorHandler?: (error: Error, context: IErrorHandlingContextData) => Promise<void>;\n };\n private logger: ILogger;\n private failureCount = 0;\n private circuitBreakerOpen = false;\n private lastFailureTime = 0;\n\n constructor(options: IErrorHandlingPluginOptions) {\n super();\n this.logger = createLogger('ErrorHandlingPlugin');\n\n // Validate options\n validateErrorHandlingOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n retryDelay: options.retryDelay ?? DEFAULT_RETRY_DELAY_MS,\n logErrors: options.logErrors ?? true,\n failureThreshold: options.failureThreshold ?? DEFAULT_FAILURE_THRESHOLD,\n circuitBreakerTimeout: options.circuitBreakerTimeout ?? DEFAULT_CIRCUIT_BREAKER_TIMEOUT_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.ERROR_HANDLING,\n priority: options.priority ?? PluginPriority.HIGH,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n ...(options.customErrorHandler && { customErrorHandler: options.customErrorHandler }),\n };\n\n this.logger.info('ErrorHandlingPlugin initialized', {\n strategy: this.pluginOptions.strategy,\n maxRetries: this.pluginOptions.maxRetries,\n failureThreshold: this.pluginOptions.failureThreshold,\n });\n }\n\n /**\n * Dispatches the error to the active strategy handler. If a custom error\n * handler is configured, it takes precedence over strategy-specific handling.\n */\n async handleError(error: Error, context: IErrorHandlingContextData = {}): Promise<void> {\n if (this.pluginOptions.logErrors) {\n this.logger.error('Error occurred', {\n error: error.message,\n stack: error.stack,\n context: context,\n });\n }\n\n // Custom error handler takes precedence\n if (this.pluginOptions.customErrorHandler) {\n try {\n await this.pluginOptions.customErrorHandler(error, context);\n return;\n } catch (handlerError) {\n this.logger.error('Custom error handler failed', {\n handlerError: handlerError instanceof Error ? handlerError.message : String(handlerError),\n });\n }\n }\n\n // Apply strategy-specific handling\n switch (this.pluginOptions.strategy) {\n case 'circuit-breaker':\n await this.handleCircuitBreaker(error, context);\n break;\n case 'exponential-backoff':\n await this.handleExponentialBackoff(error, context);\n break;\n case 'simple':\n await this.handleSimple(error, context);\n break;\n case 'silent':\n // Silent mode - do nothing\n break;\n }\n }\n\n /**\n * Executes a function with automatic retries up to\n * {@link IErrorHandlingPluginOptions.maxRetries | maxRetries}. The delay\n * between retries follows the configured strategy (fixed for simple /\n * circuit-breaker, doubling for exponential-backoff).\n *\n * @throws PluginError after all retry attempts are exhausted\n */\n async executeWithRetry<T>(\n fn: () => Promise<T>,\n context: IErrorHandlingContextData = {},\n ): Promise<T> {\n let lastError: Error | undefined;\n let attempt = 0;\n\n while (attempt <= this.pluginOptions.maxRetries) {\n try {\n // Check circuit breaker\n if (this.pluginOptions.strategy === 'circuit-breaker') {\n const cbState = isCircuitBreakerStillOpen(\n this.circuitBreakerOpen,\n this.lastFailureTime,\n this.pluginOptions.circuitBreakerTimeout,\n );\n if (cbState.shouldReset) {\n this.circuitBreakerOpen = false;\n this.failureCount = 0;\n this.logger.info('Circuit breaker timeout passed, attempting to close');\n }\n if (cbState.open) {\n throw new PluginError('Circuit breaker is open', this.name, toErrorContext(context));\n }\n }\n\n const result = await fn();\n\n // Reset failure count on success\n if (attempt > 0) {\n this.failureCount = 0;\n this.circuitBreakerOpen = false;\n this.logger.info('Operation succeeded after retry', {\n attempt: attempt,\n context: context,\n });\n }\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n attempt++;\n\n if (attempt <= this.pluginOptions.maxRetries) {\n await this.handleError(lastError, { ...context, attempt });\n\n // Calculate delay\n const delay = resolveRetryDelay(\n this.pluginOptions.strategy,\n this.pluginOptions.retryDelay,\n attempt,\n );\n\n this.logger.debug('Retrying operation', {\n attempt: attempt,\n delay: delay,\n context: context,\n });\n await sleep(delay);\n } else {\n await this.handleError(lastError, { ...context, finalAttempt: true });\n }\n }\n }\n\n throw new PluginError(\n `Operation failed after ${this.pluginOptions.maxRetries} retries`,\n this.name,\n createPluginErrorContext(context, {\n originalError: lastError?.message || 'Unknown error',\n }),\n );\n }\n\n /**\n * Resets the circuit breaker to closed state, clearing failure count and\n * last failure timestamp.\n */\n resetCircuitBreaker(): void {\n this.failureCount = 0;\n this.circuitBreakerOpen = false;\n this.lastFailureTime = 0;\n this.logger.info('Circuit breaker reset');\n }\n\n /**\n * Get error handling statistics\n */\n override getStats(): IErrorHandlingPluginStats {\n const base = super.getStats();\n return {\n ...base,\n failureCount: this.failureCount,\n circuitBreakerOpen: this.circuitBreakerOpen,\n lastFailureTime: this.lastFailureTime,\n totalRetries: 0, // TODO: Track total retries\n successfulRecoveries: 0, // TODO: Track successful recoveries\n };\n }\n\n /**\n * Cleanup resources\n */\n async destroy(): Promise<void> {\n this.logger.info('ErrorHandlingPlugin destroyed');\n }\n\n private async handleSimple(error: Error, context: IErrorHandlingContextData): Promise<void> {\n // Simple logging - no additional logic\n this.logger.debug('Simple error handling applied', {\n error: error.message,\n context: context,\n });\n }\n\n private async handleCircuitBreaker(\n _error: Error,\n context: IErrorHandlingContextData,\n ): Promise<void> {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.failureCount >= this.pluginOptions.failureThreshold) {\n this.circuitBreakerOpen = true;\n this.logger.warn('Circuit breaker opened', {\n failureCount: this.failureCount,\n threshold: this.pluginOptions.failureThreshold,\n context: context,\n });\n }\n }\n\n private async handleExponentialBackoff(\n _error: Error,\n context: IErrorHandlingContextData,\n ): Promise<void> {\n this.failureCount++;\n this.logger.debug('Exponential backoff error handling applied', {\n error: _error.message,\n failureCount: this.failureCount,\n context: context,\n });\n }\n}\n","/**\n * Stats aggregation logic for ExecutionAnalyticsPlugin.\n *\n * Extracted from execution-analytics-plugin.ts to keep each file under 300 lines.\n * @internal\n */\nimport type { IExecutionStats, IAggregatedExecutionStats } from './types';\n\n/** Compute aggregated analytics across recorded executions. @internal */\nexport function aggregateExecutionStats(\n stats: IExecutionStats[],\n timeRange?: { start: Date; end: Date },\n): IAggregatedExecutionStats {\n if (stats.length === 0) {\n return {\n totalExecutions: 0,\n successfulExecutions: 0,\n failedExecutions: 0,\n successRate: 0,\n averageDuration: 0,\n totalDuration: 0,\n operationStats: {},\n errorStats: {},\n timeRange: timeRange || { start: new Date(), end: new Date() },\n };\n }\n\n const totalExecutions = stats.length;\n const successfulExecutions = stats.filter((s) => s.success).length;\n const failedExecutions = totalExecutions - successfulExecutions;\n const totalDuration = stats.reduce((sum, s) => sum + s.duration, 0);\n const averageDuration = totalDuration / totalExecutions;\n\n const operationStats: Record<\n string,\n {\n count: number;\n successCount: number;\n failureCount: number;\n totalDuration: number;\n averageDuration: number;\n }\n > = {};\n\n for (const stat of stats) {\n if (!operationStats[stat.operation]) {\n operationStats[stat.operation] = {\n count: 0,\n successCount: 0,\n failureCount: 0,\n totalDuration: 0,\n averageDuration: 0,\n };\n }\n const opStat = operationStats[stat.operation];\n if (opStat) {\n opStat.count++;\n opStat.totalDuration += stat.duration;\n if (stat.success) opStat.successCount++;\n else opStat.failureCount++;\n }\n }\n for (const op in operationStats) {\n const opStat = operationStats[op];\n if (opStat && opStat.count > 0) opStat.averageDuration = opStat.totalDuration / opStat.count;\n }\n\n const errorStats: Record<string, number> = {};\n for (const stat of stats.filter((s) => !s.success && s.error)) {\n const errorType = stat.error!.type;\n errorStats[errorType] = (errorStats[errorType] || 0) + 1;\n }\n\n return {\n totalExecutions,\n successfulExecutions,\n failedExecutions,\n successRate: totalExecutions > 0 ? successfulExecutions / totalExecutions : 0,\n averageDuration,\n totalDuration,\n operationStats,\n errorStats,\n timeRange: timeRange || {\n start: stats[0]?.startTime || new Date(),\n end: stats[stats.length - 1]?.endTime || new Date(),\n },\n };\n}\n","/**\n * Execution Analytics Plugin - Validation and utility helpers.\n *\n * Extracted from execution-analytics-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport type { IExecutionAnalyticsOptions, IExecutionStats } from './types';\n\n/**\n * Validate and sanitize ExecutionAnalyticsPlugin options in-place.\n * Invalid numeric values are reset to safe defaults. @internal\n */\nexport function validateExecutionAnalyticsOptions(\n options: IExecutionAnalyticsOptions,\n pluginOptions: { maxEntries: number; performanceThreshold: number },\n): void {\n if (options.maxEntries !== undefined && options.maxEntries < 1) {\n pluginOptions.maxEntries = 1000;\n }\n if (options.performanceThreshold !== undefined && options.performanceThreshold < 0) {\n pluginOptions.performanceThreshold = 5000;\n }\n}\n\n/** Generate a unique execution ID with an optional prefix. @internal */\nexport function generateExecutionId(prefix: string, counter: number): string {\n return `${prefix}-${Date.now()}-${counter}`;\n}\n\n/**\n * Build an IExecutionStats record for an error event. @internal\n */\nexport function buildErrorExecutionStats(\n executionId: string,\n executionData: { startTime: number; operation: string },\n error: Error,\n trackErrors: boolean,\n context?: { action?: string; tool?: string; attempt?: number },\n): IExecutionStats {\n const duration = Date.now() - executionData.startTime;\n const errorInfo = trackErrors\n ? {\n message: error.message,\n ...(error.stack && { stack: error.stack }),\n type: error.constructor.name,\n }\n : undefined;\n return {\n executionId,\n operation: executionData.operation,\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success: false,\n ...(errorInfo && { error: errorInfo }),\n metadata: {\n errorSource: 'onError-hook',\n contextType: context ? typeof context : 'none',\n hasContext: !!context,\n },\n };\n}\n\n/** Find the first active execution matching the given operation (and optionally the input). @internal */\nexport function findActiveExecution(\n activeExecutions: Map<string, { startTime: number; operation: string; input?: string }>,\n operation: string,\n input?: string,\n):\n | {\n executionId: string;\n executionData: { startTime: number; operation: string; input?: string };\n }\n | undefined {\n for (const [executionId, executionData] of activeExecutions.entries()) {\n if (executionData.operation === operation) {\n if (operation === 'run' && input && executionData.input !== input) continue;\n return { executionId, executionData };\n }\n }\n return undefined;\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n type IPluginErrorContext,\n createLogger,\n type ILogger,\n type IRunOptions,\n type TUniversalMessage,\n isAssistantMessage,\n type TToolParameters,\n type IToolExecutionResult,\n} from '@robota-sdk/agent-core';\nimport type {\n IExecutionStats,\n IAggregatedExecutionStats,\n IExecutionAnalyticsOptions,\n IExecutionAnalyticsPluginStats,\n} from './types';\nimport { aggregateExecutionStats } from './analytics-aggregation';\nimport {\n validateExecutionAnalyticsOptions,\n generateExecutionId,\n findActiveExecution,\n buildErrorExecutionStats,\n} from './execution-analytics-helpers';\n\nconst DEFAULT_MAX_ENTRIES = 1000;\nconst DEFAULT_PERFORMANCE_THRESHOLD_MS = 5000;\nconst PREVIEW_LENGTH = 100;\n\n/**\n * Tracks timing and success/failure of agent runs, provider calls, and tool executions.\n * @extends AbstractPlugin\n */\nexport class ExecutionAnalyticsPlugin extends AbstractPlugin<\n IExecutionAnalyticsOptions,\n IExecutionAnalyticsPluginStats\n> {\n name = 'ExecutionAnalyticsPlugin';\n version = '1.0.0';\n\n private pluginOptions: Required<IExecutionAnalyticsOptions>;\n private logger: ILogger;\n private activeExecutions: Map<string, { startTime: number; operation: string; input?: string }> =\n new Map();\n private executionHistory: IExecutionStats[] = [];\n private executionCounter = 0;\n private initialized = false;\n\n constructor(options: IExecutionAnalyticsOptions = {}) {\n super();\n this.category = PluginCategory.MONITORING;\n this.priority = PluginPriority.NORMAL;\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n maxEntries: options.maxEntries || DEFAULT_MAX_ENTRIES,\n trackErrors: options.trackErrors ?? true,\n performanceThreshold: options.performanceThreshold || DEFAULT_PERFORMANCE_THRESHOLD_MS,\n enableWarnings: options.enableWarnings ?? true,\n category: options.category ?? PluginCategory.MONITORING,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n validateExecutionAnalyticsOptions(options, this.pluginOptions);\n this.logger = createLogger('ExecutionAnalyticsPlugin');\n this.beforeRun = this.beforeRun.bind(this);\n this.afterRun = this.afterRun.bind(this);\n this.beforeProviderCall = this.beforeProviderCall.bind(this);\n this.afterProviderCall = this.afterProviderCall.bind(this);\n this.initialized = true;\n }\n\n override beforeRun = async (input: string, _options?: IRunOptions): Promise<void> => {\n this.activeExecutions.set(generateExecutionId('exec', ++this.executionCounter), {\n startTime: Date.now(),\n operation: 'run',\n input: input.substring(0, PREVIEW_LENGTH),\n });\n };\n\n override afterRun = async (\n input: string,\n response: string,\n options?: IRunOptions,\n ): Promise<void> => {\n const execution = findActiveExecution(this.activeExecutions, 'run', input);\n if (!execution) return;\n const { executionId, executionData } = execution;\n const duration = Date.now() - executionData.startTime;\n this.recordStats({\n executionId,\n operation: 'run',\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success: true,\n metadata: {\n inputLength: input.length,\n responseLength: response.length,\n hasOptions: !!options,\n modelName: String(options?.metadata?.['model'] || 'unknown'),\n },\n });\n this.activeExecutions.delete(executionId);\n if (this.pluginOptions.enableWarnings && duration > this.pluginOptions.performanceThreshold) {\n this.logger.warn('Slow run execution detected', {\n executionId,\n duration,\n threshold: this.pluginOptions.performanceThreshold,\n });\n }\n };\n\n override beforeProviderCall = async (messages: TUniversalMessage[]): Promise<void> => {\n this.activeExecutions.set(generateExecutionId('provider', ++this.executionCounter), {\n startTime: Date.now(),\n operation: 'provider-call',\n input: messages[0]?.content || 'N/A',\n });\n };\n\n override afterProviderCall = async (\n messages: TUniversalMessage[],\n response: TUniversalMessage,\n ): Promise<void> => {\n const execution = findActiveExecution(\n this.activeExecutions,\n 'provider-call',\n messages[0]?.content || '',\n );\n if (!execution) return;\n const { executionId, executionData } = execution;\n const duration = Date.now() - executionData.startTime;\n this.recordStats({\n executionId,\n operation: 'provider-call',\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success: true,\n metadata: {\n inputLength: messages[0]?.content?.length || 0,\n responseLength: response.content?.length || 0,\n hasToolCalls: !!(\n isAssistantMessage(response) &&\n response.toolCalls &&\n response.toolCalls.length > 0\n ),\n toolCallCount:\n isAssistantMessage(response) && response.toolCalls ? response.toolCalls.length : 0,\n },\n });\n this.activeExecutions.delete(executionId);\n if (this.pluginOptions.enableWarnings && duration > this.pluginOptions.performanceThreshold) {\n this.logger.warn('Slow provider call detected', {\n executionId,\n duration,\n threshold: this.pluginOptions.performanceThreshold,\n });\n }\n };\n\n override async beforeToolCall(toolName: string, _parameters: TToolParameters): Promise<void> {\n this.activeExecutions.set(generateExecutionId('tool', ++this.executionCounter), {\n startTime: Date.now(),\n operation: 'tool-call',\n input: toolName,\n });\n }\n\n override async afterToolCall(\n toolName: string,\n parameters: TToolParameters,\n result: IToolExecutionResult,\n ): Promise<void> {\n const execution = findActiveExecution(this.activeExecutions, 'tool-call', toolName);\n if (!execution) return;\n const { executionId, executionData } = execution;\n const duration = Date.now() - executionData.startTime;\n const success = !result?.error;\n const errorInfo =\n result?.error && this.pluginOptions.trackErrors\n ? { message: String(result.error), type: 'ToolExecutionError' }\n : undefined;\n this.recordStats({\n executionId,\n operation: 'tool-call',\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success,\n ...(errorInfo && { error: errorInfo }),\n metadata: {\n toolName,\n parameterCount: Object.keys(parameters).length,\n resultType: typeof result,\n hasError: !!result?.error,\n },\n });\n this.activeExecutions.delete(executionId);\n }\n\n override async onError(error: Error, context?: IPluginErrorContext): Promise<void> {\n const activeExecution = Array.from(this.activeExecutions.entries())[0];\n if (activeExecution) {\n const [executionId, executionData] = activeExecution;\n this.recordStats(\n buildErrorExecutionStats(\n executionId,\n executionData,\n error,\n this.pluginOptions.trackErrors,\n context,\n ),\n );\n this.activeExecutions.delete(executionId);\n }\n }\n\n getExecutionStats(operation?: string, timeRange?: { start: Date; end: Date }): IExecutionStats[] {\n let filtered = this.executionHistory;\n if (operation) filtered = filtered.filter((stat) => stat.operation === operation);\n if (timeRange)\n filtered = filtered.filter(\n (stat) => stat.startTime >= timeRange.start && stat.startTime <= timeRange.end,\n );\n return [...filtered];\n }\n\n getAggregatedStats(timeRange?: { start: Date; end: Date }): IAggregatedExecutionStats {\n return aggregateExecutionStats(this.getExecutionStats(undefined, timeRange), timeRange);\n }\n\n clearStats(): void {\n this.executionHistory = [];\n this.activeExecutions.clear();\n this.executionCounter = 0;\n }\n\n getActiveExecutions(): Array<{ executionId: string; operation: string; duration: number }> {\n const now = Date.now();\n return Array.from(this.activeExecutions.entries()).map(([executionId, data]) => ({\n executionId,\n operation: data.operation,\n duration: now - data.startTime,\n }));\n }\n\n getPluginStats(): {\n totalRecorded: number;\n activeExecutions: number;\n memoryUsage: number;\n oldestRecord?: Date;\n newestRecord?: Date;\n } {\n const oldest = this.executionHistory[0];\n const newest = this.executionHistory[this.executionHistory.length - 1];\n return {\n totalRecorded: this.executionHistory.length,\n activeExecutions: this.activeExecutions.size,\n memoryUsage: this.executionHistory.length + this.activeExecutions.size,\n ...(oldest && { oldestRecord: oldest.startTime }),\n ...(newest && { newestRecord: newest.endTime }),\n };\n }\n\n async destroy(): Promise<void> {\n this.clearStats();\n }\n getExecutionData(): IExecutionStats[] {\n return [...this.executionHistory];\n }\n getAnalyticsStats(): IAggregatedExecutionStats {\n return this.getAggregatedStats();\n }\n clearExecutionData(): void {\n this.clearStats();\n }\n\n override getStatus() {\n return {\n name: this.name,\n version: this.version,\n enabled: this.enabled,\n initialized: this.initialized,\n category: this.category,\n priority: this.priority,\n subscribedEventsCount: this.subscribedEvents.length,\n hasEventEmitter: !!this.eventEmitter,\n };\n }\n\n override getStats(): IExecutionAnalyticsPluginStats {\n const newest = this.executionHistory[this.executionHistory.length - 1];\n const oldest = this.executionHistory[0];\n return {\n enabled: this.enabled,\n calls: this.executionHistory.length,\n errors: this.executionHistory.filter((e) => !e.success).length,\n ...(newest?.endTime && { lastActivity: newest.endTime }),\n totalRecorded: this.executionHistory.length,\n activeExecutions: this.activeExecutions.size,\n memoryUsage: this.executionHistory.length + this.activeExecutions.size,\n ...(oldest && { oldestRecord: oldest.startTime }),\n ...(newest && { newestRecord: newest.endTime }),\n };\n }\n\n private recordStats(stats: IExecutionStats): void {\n this.executionHistory.push(stats);\n if (this.executionHistory.length > this.pluginOptions.maxEntries) this.executionHistory.shift();\n }\n}\n","/**\n * Validation logic for LimitsPlugin options.\n *\n * Extracted from limits-plugin.ts to keep each file under 300 lines.\n * @internal\n */\nimport { PluginError, type ILogger } from '@robota-sdk/agent-core';\nimport type { ILimitsPluginOptions } from './types';\n\n/** Validate LimitsPlugin options. @internal */\nexport function validateLimitsOptions(\n options: ILimitsPluginOptions,\n pluginName: string,\n logger: ILogger,\n): void {\n if (options.strategy === 'none') {\n logger.info('LimitsPlugin configured with \"none\" strategy - no rate limiting will be applied');\n return;\n }\n\n if (!options.strategy) {\n throw new PluginError(\n 'Strategy must be specified for limits plugin. Use \"none\" to disable rate limiting, or choose from: token-bucket, sliding-window, fixed-window',\n pluginName,\n { availableStrategies: ['none', 'token-bucket', 'sliding-window', 'fixed-window'] },\n );\n }\n\n const validStrategies = ['none', 'token-bucket', 'sliding-window', 'fixed-window'];\n if (!validStrategies.includes(options.strategy)) {\n throw new PluginError(\n `Invalid strategy \"${options.strategy}\". Must be one of: ${validStrategies.join(', ')}`,\n pluginName,\n { provided: options.strategy, validStrategies },\n );\n }\n\n if (options.strategy === 'token-bucket') {\n if (options.bucketSize !== undefined && options.bucketSize <= 0)\n throw new PluginError('Bucket size must be positive for token-bucket strategy', pluginName, {\n strategy: options.strategy,\n bucketSize: options.bucketSize,\n });\n if (options.refillRate !== undefined && options.refillRate < 0)\n throw new PluginError(\n 'Refill rate must be non-negative for token-bucket strategy',\n pluginName,\n { strategy: options.strategy, refillRate: options.refillRate },\n );\n }\n\n if (['sliding-window', 'fixed-window'].includes(options.strategy)) {\n if (options.timeWindow !== undefined && options.timeWindow <= 0)\n throw new PluginError(\n `Time window must be positive for ${options.strategy} strategy`,\n pluginName,\n { strategy: options.strategy, timeWindow: options.timeWindow },\n );\n }\n\n if (options.maxRequests !== undefined && options.maxRequests < 0)\n throw new PluginError('Max requests must be non-negative', pluginName, {\n strategy: options.strategy,\n maxRequests: options.maxRequests,\n });\n if (options.maxTokens !== undefined && options.maxTokens < 0)\n throw new PluginError('Max tokens must be non-negative', pluginName, {\n strategy: options.strategy,\n maxTokens: options.maxTokens,\n });\n if (options.maxCost !== undefined && options.maxCost < 0)\n throw new PluginError('Max cost must be non-negative', pluginName, {\n strategy: options.strategy,\n maxCost: options.maxCost,\n });\n if (options.tokenCostPer1000 !== undefined && options.tokenCostPer1000 < 0)\n throw new PluginError('Token cost per 1000 must be non-negative', pluginName, {\n strategy: options.strategy,\n tokenCostPer1000: options.tokenCostPer1000,\n });\n}\n","/**\n * Limits Plugin - Rate limit check, cost calculation, and utility helpers.\n *\n * Extracted from limits-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { PluginError } from '@robota-sdk/agent-core';\nimport type { TUniversalMessage } from '@robota-sdk/agent-core';\nimport type { ILimitWindow, ITokenBucket } from './types';\n\nconst COST_DECIMAL_PLACES = 4;\nconst CHARS_PER_TOKEN = 4;\nconst TOKEN_ESTIMATE_BUFFER = 100;\nconst TOKENS_PER_COST_UNIT = 1000;\nconst MS_PER_SECOND = 1000;\n\n/** Model-specific cost table (per 1000 tokens). @internal */\nconst MODEL_COSTS: Record<string, number> = {\n 'gpt-4': 0.03,\n 'gpt-4-turbo': 0.01,\n 'gpt-3.5-turbo': 0.002,\n 'claude-3-opus': 0.015,\n 'claude-3-sonnet': 0.003,\n 'claude-3-haiku': 0.00025,\n};\n\n/** Default cost calculator: uses model-specific rates or falls back to tokenCostPer1000. @internal */\nexport function defaultCostCalculator(\n tokens: number,\n model: string,\n tokenCostPer1000: number,\n): number {\n return (tokens / TOKENS_PER_COST_UNIT) * (MODEL_COSTS[model] ?? tokenCostPer1000);\n}\n\n/** Estimate token count from message content lengths. @internal */\nexport function estimateTokensFromMessages(messages: TUniversalMessage[]): number {\n return (\n Math.ceil(messages.reduce((t, m) => t + (m.content?.length || 0), 0) / CHARS_PER_TOKEN) +\n TOKEN_ESTIMATE_BUFFER\n );\n}\n\n/** Check and update token-bucket state. Throws PluginError if any limit is exceeded. @internal */\nexport function checkTokenBucket(\n bucket: ITokenBucket,\n now: number,\n estimatedTokens: number,\n estimatedCost: number,\n options: {\n bucketSize: number;\n refillRate: number;\n timeWindow: number;\n maxRequests: number;\n maxCost: number;\n },\n pluginName: string,\n): void {\n const timePassed = (now - bucket.lastRefill) / MS_PER_SECOND;\n bucket.tokens = Math.min(options.bucketSize, bucket.tokens + timePassed * options.refillRate);\n bucket.lastRefill = now;\n\n if (bucket.tokens < estimatedTokens) {\n throw new PluginError(\n `Token bucket depleted. Available: ${Math.floor(bucket.tokens)}, Required: ${estimatedTokens}`,\n pluginName,\n { availableTokens: bucket.tokens, requiredTokens: estimatedTokens },\n );\n }\n\n if (now - bucket.windowStart >= options.timeWindow) {\n bucket.requests = 0;\n bucket.cost = 0;\n bucket.windowStart = now;\n }\n\n if (bucket.requests >= options.maxRequests) {\n throw new PluginError(`Request limit exceeded. Max: ${options.maxRequests}`, pluginName, {\n currentRequests: bucket.requests,\n maxRequests: options.maxRequests,\n });\n }\n\n if (bucket.cost + estimatedCost > options.maxCost) {\n throw new PluginError(\n `Cost limit exceeded. Current: $${bucket.cost.toFixed(COST_DECIMAL_PLACES)}, Estimated: $${estimatedCost.toFixed(COST_DECIMAL_PLACES)}, Max: $${options.maxCost}`,\n pluginName,\n { currentCost: bucket.cost, estimatedCost, maxCost: options.maxCost },\n );\n }\n\n bucket.tokens -= estimatedTokens;\n bucket.requests++;\n}\n\n/** Check and update sliding-window state. Throws PluginError if any limit is exceeded. @internal */\nexport function checkSlidingWindow(\n window: ILimitWindow,\n now: number,\n estimatedTokens: number,\n estimatedCost: number,\n options: {\n timeWindow: number;\n maxTokens: number;\n maxRequests: number;\n maxCost: number;\n },\n pluginName: string,\n): void {\n if (now - window.windowStart < options.timeWindow) {\n if (window.tokens + estimatedTokens > options.maxTokens) {\n throw new PluginError(\n `Token limit exceeded in sliding window. Current: ${window.tokens}, Estimated: ${estimatedTokens}, Max: ${options.maxTokens}`,\n pluginName,\n { currentTokens: window.tokens, estimatedTokens, maxTokens: options.maxTokens },\n );\n }\n if (window.count >= options.maxRequests) {\n throw new PluginError(\n `Request limit exceeded in sliding window. Current: ${window.count}, Max: ${options.maxRequests}`,\n pluginName,\n { currentRequests: window.count, maxRequests: options.maxRequests },\n );\n }\n if (window.cost + estimatedCost > options.maxCost) {\n throw new PluginError(\n `Cost limit exceeded in sliding window. Current: $${window.cost.toFixed(COST_DECIMAL_PLACES)}, Estimated: $${estimatedCost.toFixed(COST_DECIMAL_PLACES)}, Max: $${options.maxCost}`,\n pluginName,\n { currentCost: window.cost, estimatedCost, maxCost: options.maxCost },\n );\n }\n } else {\n window.count = 0;\n window.tokens = 0;\n window.cost = 0;\n window.windowStart = now;\n }\n window.count++;\n}\n\n/** Check and update fixed-window state. Throws PluginError if any limit is exceeded. @internal */\nexport function checkFixedWindow(\n window: ILimitWindow,\n now: number,\n estimatedTokens: number,\n estimatedCost: number,\n options: {\n timeWindow: number;\n maxTokens: number;\n maxRequests: number;\n maxCost: number;\n },\n pluginName: string,\n): void {\n if (now - window.windowStart >= options.timeWindow) {\n window.count = 0;\n window.tokens = 0;\n window.cost = 0;\n window.windowStart = now;\n }\n\n if (window.tokens + estimatedTokens > options.maxTokens) {\n throw new PluginError(\n `Token limit exceeded in fixed window. Current: ${window.tokens}, Estimated: ${estimatedTokens}, Max: ${options.maxTokens}`,\n pluginName,\n { currentTokens: window.tokens, estimatedTokens, maxTokens: options.maxTokens },\n );\n }\n if (window.count >= options.maxRequests) {\n throw new PluginError(\n `Request limit exceeded in fixed window. Current: ${window.count}, Max: ${options.maxRequests}`,\n pluginName,\n { currentRequests: window.count, maxRequests: options.maxRequests },\n );\n }\n if (window.cost + estimatedCost > options.maxCost) {\n throw new PluginError(\n `Cost limit exceeded in fixed window. Current: $${window.cost.toFixed(COST_DECIMAL_PLACES)}, Estimated: $${estimatedCost.toFixed(COST_DECIMAL_PLACES)}, Max: $${options.maxCost}`,\n pluginName,\n { currentCost: window.cost, estimatedCost, maxCost: options.maxCost },\n );\n }\n window.count++;\n}\n","import {\n AbstractPlugin,\n type IPluginExecutionContext,\n type IPluginExecutionResult,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n type TUniversalMessage,\n} from '@robota-sdk/agent-core';\nimport type {\n TLimitsStrategy,\n ILimitsPluginOptions,\n TPluginLimitsStatusData,\n ILimitWindow,\n ITokenBucket,\n} from './types';\nimport { validateLimitsOptions } from './validation';\nimport {\n defaultCostCalculator,\n estimateTokensFromMessages,\n checkTokenBucket,\n checkSlidingWindow,\n checkFixedWindow,\n} from './limits-helpers';\n\nconst DEFAULT_MAX_TOKENS = 100000;\nconst DEFAULT_MAX_REQUESTS = 1000;\nconst DEFAULT_TIME_WINDOW_MS = 3600000;\nconst DEFAULT_MAX_COST = 10.0;\nconst DEFAULT_TOKEN_COST_PER_1000 = 0.002;\nconst DEFAULT_REFILL_RATE = 100;\nconst DEFAULT_BUCKET_SIZE = 10000;\n\nexport type { TLimitsStrategy, ILimitsPluginOptions, TPluginLimitsStatusData };\n\nexport interface ILimitsPluginExecutionContext extends IPluginExecutionContext {\n config?: { model?: string; maxTokens?: number; temperature?: number };\n conversationId?: string;\n}\n\nexport interface ILimitsPluginExecutionResult {\n tokensUsed?: number;\n cost?: number;\n success?: boolean;\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Enforces rate limiting on token usage, request frequency, and cost.\n * @extends AbstractPlugin\n */\nexport class LimitsPlugin extends AbstractPlugin<ILimitsPluginOptions> {\n name = 'LimitsPlugin';\n version = '1.0.0';\n private pluginOptions: Required<ILimitsPluginOptions>;\n private logger: ILogger;\n private windows = new Map<string, ILimitWindow>();\n private buckets = new Map<string, ITokenBucket>();\n\n constructor(options: ILimitsPluginOptions) {\n super();\n this.logger = createLogger('LimitsPlugin');\n validateLimitsOptions(options, this.name, this.logger);\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n maxTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,\n maxRequests: options.maxRequests ?? DEFAULT_MAX_REQUESTS,\n timeWindow: options.timeWindow ?? DEFAULT_TIME_WINDOW_MS,\n maxCost: options.maxCost ?? DEFAULT_MAX_COST,\n tokenCostPer1000: options.tokenCostPer1000 ?? DEFAULT_TOKEN_COST_PER_1000,\n refillRate: options.refillRate ?? DEFAULT_REFILL_RATE,\n bucketSize: options.bucketSize ?? DEFAULT_BUCKET_SIZE,\n costCalculator:\n options.costCalculator ??\n ((tokens: number, model: string) =>\n defaultCostCalculator(tokens, model, this.pluginOptions.tokenCostPer1000)),\n category: options.category ?? PluginCategory.LIMITS,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n }\n\n override async beforeExecution(context: IPluginExecutionContext): Promise<void> {\n if (this.pluginOptions.strategy === 'none') return;\n const key = this.getKey(context);\n const now = Date.now();\n const est = estimateTokensFromMessages(context.messages ?? []);\n const estCost = this.pluginOptions.costCalculator(est, this.resolveModelName(context));\n\n switch (this.pluginOptions.strategy) {\n case 'token-bucket':\n checkTokenBucket(this.getBucket(key), now, est, estCost, this.pluginOptions, this.name);\n break;\n case 'sliding-window':\n checkSlidingWindow(this.getWindow(key), now, est, estCost, this.pluginOptions, this.name);\n break;\n case 'fixed-window':\n checkFixedWindow(this.getWindow(key), now, est, estCost, this.pluginOptions, this.name);\n break;\n }\n }\n\n override async afterExecution(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n if (this.pluginOptions.strategy === 'none') return;\n const key = this.getKey(context);\n const tokensUsed = result?.tokensUsed || 0;\n const cost = this.pluginOptions.costCalculator(tokensUsed, this.resolveModelName(context));\n switch (this.pluginOptions.strategy) {\n case 'token-bucket':\n this.getBucket(key).cost += cost;\n break;\n case 'sliding-window':\n case 'fixed-window': {\n const w = this.getWindow(key);\n w.tokens += tokensUsed;\n w.cost += cost;\n break;\n }\n }\n }\n\n private getBucket(key: string): ITokenBucket {\n if (!this.buckets.has(key))\n this.buckets.set(key, {\n tokens: this.pluginOptions.bucketSize,\n lastRefill: Date.now(),\n requests: 0,\n cost: 0,\n windowStart: Date.now(),\n });\n return this.buckets.get(key)!;\n }\n\n private getWindow(key: string): ILimitWindow {\n if (!this.windows.has(key))\n this.windows.set(key, { count: 0, tokens: 0, cost: 0, windowStart: Date.now() });\n return this.windows.get(key)!;\n }\n\n private getKey(context: ILimitsPluginExecutionContext): string {\n return context.userId || context.sessionId || context.executionId || 'default';\n }\n\n private resolveModelName(context: IPluginExecutionContext): string {\n const m = context.config?.model;\n return typeof m === 'string' && m.length > 0 ? m : 'unknown';\n }\n\n getLimitsStatus(key?: string): TPluginLimitsStatusData {\n if (key) {\n const bucket = this.buckets.get(key);\n const window = this.windows.get(key);\n return {\n strategy: this.pluginOptions.strategy,\n key,\n bucket: bucket\n ? {\n availableTokens: Math.floor(bucket.tokens),\n requests: bucket.requests,\n cost: bucket.cost,\n }\n : null,\n window: window\n ? {\n count: window.count,\n tokens: window.tokens,\n cost: window.cost,\n windowStart: window.windowStart,\n }\n : null,\n };\n }\n return {\n strategy: this.pluginOptions.strategy,\n totalKeys: this.buckets.size + this.windows.size,\n bucketKeys: Array.from(this.buckets.keys()),\n windowKeys: Array.from(this.windows.keys()),\n };\n }\n\n resetLimits(key?: string): void {\n if (key) {\n this.buckets.delete(key);\n this.windows.delete(key);\n } else {\n this.buckets.clear();\n this.windows.clear();\n }\n }\n}\n","import type { ILogEntry, ILogFormatter } from './types';\n\nconst LEVEL_PAD_WIDTH = 5;\n\n/**\n * Default console formatter\n */\nexport class ConsoleLogFormatter implements ILogFormatter {\n format(entry: ILogEntry): string {\n const timestamp = entry.timestamp.toISOString();\n const level = entry.level.toUpperCase().padStart(LEVEL_PAD_WIDTH);\n const contextStr = entry.context ? ` | ${JSON.stringify(entry.context)}` : '';\n const metadataStr = entry.metadata ? ` | ${JSON.stringify(entry.metadata)}` : '';\n return `[${timestamp}] ${level} | ${entry.message}${contextStr}${metadataStr}`;\n }\n}\n\n/**\n * JSON formatter for file/remote logging\n */\nexport class JsonLogFormatter implements ILogFormatter {\n format(entry: ILogEntry): string {\n return JSON.stringify({\n ...entry,\n timestamp: entry.timestamp.toISOString(),\n });\n }\n}\n","import type { ILogEntry, ILogStorage, ILogFormatter, TLogLevel } from '../types';\nimport { ConsoleLogFormatter } from '../formatters';\nimport { SilentLogger, type ILogger } from '@robota-sdk/agent-core';\n\n/**\n * Console log storage\n */\nexport class ConsoleLogStorage implements ILogStorage {\n private formatter: ILogFormatter;\n private logger: ILogger;\n\n constructor(formatter?: ILogFormatter, logger?: ILogger) {\n this.formatter = formatter || new ConsoleLogFormatter();\n this.logger = logger || SilentLogger;\n }\n\n async write(entry: ILogEntry): Promise<void> {\n const formatted = this.formatter.format(entry);\n\n const level: TLogLevel = entry.level;\n switch (level) {\n case 'debug':\n this.logger.debug(formatted);\n break;\n case 'info':\n this.logger.info(formatted);\n break;\n case 'warn':\n this.logger.warn(formatted);\n break;\n case 'error':\n this.logger.error(formatted);\n break;\n }\n }\n\n async flush(): Promise<void> {\n // Console doesn't need flushing\n }\n\n async close(): Promise<void> {\n // Console doesn't need closing\n }\n}\n","import type { ILogEntry, ILogStorage, ILogFormatter } from '../types';\nimport { JsonLogFormatter } from '../formatters';\nimport { createLogger, type ILogger, PluginError } from '@robota-sdk/agent-core';\n\n/**\n * File log storage (placeholder implementation)\n */\nexport class FileLogStorage implements ILogStorage {\n private filePath: string;\n private formatter: ILogFormatter;\n private logger: ILogger;\n\n constructor(filePath: string, formatter?: ILogFormatter) {\n this.filePath = filePath;\n this.formatter = formatter || new JsonLogFormatter();\n this.logger = createLogger('FileLogStorage');\n }\n\n async write(entry: ILogEntry): Promise<void> {\n try {\n // File writing would be implemented here\n // This is a placeholder for actual file system operations\n this.logger.warn('File logging not fully implemented yet', {\n filePath: this.filePath,\n entry: this.formatter.format(entry),\n });\n } catch (error) {\n throw new PluginError('Failed to write log to file', 'LoggingPlugin', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n // File flushing would be implemented here\n this.logger.warn('File flush not fully implemented yet');\n }\n\n async close(): Promise<void> {\n // File closing would be implemented here\n this.logger.warn('File close not fully implemented yet');\n }\n}\n","import type { ILogEntry, ILogStorage, ILogFormatter } from '../types';\nimport { JsonLogFormatter } from '../formatters';\nimport {\n createLogger,\n type ILogger,\n PluginError,\n type TTimerId,\n startPeriodicTask,\n stopPeriodicTask,\n} from '@robota-sdk/agent-core';\n\n/**\n * Remote log storage with batching\n */\nexport class RemoteLogStorage implements ILogStorage {\n private url: string;\n private formatter: ILogFormatter;\n private batchSize: number;\n private flushInterval: number;\n private pendingLogs: ILogEntry[] = [];\n private flushTimer: TTimerId | undefined;\n private logger: ILogger;\n\n constructor(url: string, _options: { timeout?: number } = {}) {\n this.url = url;\n this.formatter = new JsonLogFormatter();\n this.batchSize = 10;\n this.flushInterval = 5000;\n this.logger = createLogger('RemoteLogStorage');\n\n // Start flush timer\n this.flushTimer = startPeriodicTask(\n this.logger,\n { name: 'RemoteLogStorage.flush', intervalMs: this.flushInterval },\n async () => {\n await this.flush();\n },\n );\n }\n\n async write(entry: ILogEntry): Promise<void> {\n this.pendingLogs.push(entry);\n\n if (this.pendingLogs.length >= this.batchSize) {\n await this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.pendingLogs.length === 0) return;\n\n const logsToSend = [...this.pendingLogs];\n this.pendingLogs = [];\n\n try {\n // Remote sending would be implemented here\n // This is a placeholder for actual HTTP requests\n this.logger.warn('Remote logging not fully implemented yet', {\n url: this.url,\n logCount: logsToSend.length,\n logs: logsToSend.map((log) => this.formatter.format(log)),\n });\n } catch (error) {\n throw new PluginError('Failed to send logs to remote endpoint', 'LoggingPlugin', {\n url: this.url,\n logCount: logsToSend.length,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async close(): Promise<void> {\n stopPeriodicTask(this.flushTimer);\n this.flushTimer = undefined;\n\n await this.flush();\n }\n}\n","import type { ILogEntry, ILogStorage } from '../types';\n\n/**\n * Silent log storage (no-op)\n */\nexport class SilentLogStorage implements ILogStorage {\n async write(_entry: ILogEntry): Promise<void> {\n // Silent mode - do nothing\n }\n\n async flush(): Promise<void> {\n // Silent mode - do nothing\n }\n\n async close(): Promise<void> {\n // Silent mode - do nothing\n }\n}\n","/**\n * Logging Plugin - Validation and storage factory helpers.\n *\n * Extracted from logging-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError, EVENT_EMITTER_EVENTS } from '@robota-sdk/agent-core';\nimport {\n ConsoleLogStorage,\n FileLogStorage,\n RemoteLogStorage,\n SilentLogStorage,\n} from './storages/index';\nimport type { ILoggingPluginOptions, ILogStorage, TLogLevel, ILogEntry } from './types';\n\n/** Validate LoggingPlugin constructor options. @internal */\nexport function validateLoggingOptions(options: ILoggingPluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Logging strategy is required');\n }\n\n if (!['console', 'file', 'remote', 'silent'].includes(options.strategy)) {\n throw new ConfigurationError('Invalid logging strategy', {\n validStrategies: ['console', 'file', 'remote', 'silent'],\n provided: options.strategy,\n });\n }\n\n if (options.level && !['debug', 'info', 'warn', 'error'].includes(options.level)) {\n throw new ConfigurationError('Invalid log level', {\n validLevels: ['debug', 'info', 'warn', 'error'],\n provided: options.level,\n });\n }\n\n if (options.strategy === 'file' && !options.filePath) {\n throw new ConfigurationError('File path is required for file logging strategy');\n }\n\n if (options.strategy === 'remote' && !options.remoteEndpoint) {\n throw new ConfigurationError('Remote endpoint is required for remote logging strategy');\n }\n\n if (options.maxLogs !== undefined && options.maxLogs <= 0) {\n throw new ConfigurationError('Max logs must be positive');\n }\n\n if (options.batchSize !== undefined && options.batchSize <= 0) {\n throw new ConfigurationError('Batch size must be positive');\n }\n\n if (options.flushInterval !== undefined && options.flushInterval <= 0) {\n throw new ConfigurationError('Flush interval must be positive');\n }\n}\n\n/** Create ILogStorage instance for the given strategy. @internal */\nexport function createLoggingStorage(\n strategy: string,\n filePath: string,\n remoteEndpoint: string,\n flushInterval: number,\n formatter?: ILoggingPluginOptions['formatter'],\n): ILogStorage {\n switch (strategy) {\n case 'console':\n return new ConsoleLogStorage(formatter);\n case 'file':\n return new FileLogStorage(filePath, formatter);\n case 'remote':\n return new RemoteLogStorage(remoteEndpoint, { timeout: flushInterval });\n case 'silent':\n return new SilentLogStorage();\n default:\n throw new ConfigurationError('Unknown logging strategy', { strategy });\n }\n}\n\n/** Event name → log descriptor mapping for module lifecycle events. @internal */\nexport const LOGGING_MODULE_EVENT_MAP: ReadonlyMap<\n string,\n { level: TLogLevel; message: string; operation: string }\n> = new Map([\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_START,\n {\n level: 'info',\n message: 'Module initialization started',\n operation: 'module_initialize_start',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n {\n level: 'info',\n message: 'Module initialization completed',\n operation: 'module_initialize_complete',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n {\n level: 'error',\n message: 'Module initialization failed',\n operation: 'module_initialize_error',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_START,\n { level: 'debug', message: 'Module execution started', operation: 'module_execution_start' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n {\n level: 'debug',\n message: 'Module execution completed',\n operation: 'module_execution_complete',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n { level: 'error', message: 'Module execution failed', operation: 'module_execution_error' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_START,\n { level: 'debug', message: 'Module disposal started', operation: 'module_dispose_start' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n { level: 'info', message: 'Module disposal completed', operation: 'module_dispose_complete' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n { level: 'error', message: 'Module disposal failed', operation: 'module_dispose_error' },\n ],\n]);\n\n/** Safely extract module data fields from untyped event payload. @internal */\nexport function extractLoggingModuleData(data: unknown): {\n moduleName: string;\n moduleType: string;\n duration?: number;\n success?: boolean;\n} {\n const record = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n return {\n moduleName: typeof record['moduleName'] === 'string' ? record['moduleName'] : 'unknown',\n moduleType: typeof record['moduleType'] === 'string' ? record['moduleType'] : 'unknown',\n ...(typeof record['duration'] === 'number' && { duration: record['duration'] }),\n ...(typeof record['success'] === 'boolean' && { success: record['success'] }),\n };\n}\n\n/** Narrow interface for the log methods needed by convenience helpers. @internal */\nexport interface ILogWriter {\n info(\n message: string,\n context?: Record<string, string | number | boolean | Date | undefined>,\n metadata?: ILogEntry['metadata'],\n ): Promise<void>;\n log(\n level: TLogLevel,\n message: string,\n context?: Record<string, string | number | boolean | Date | undefined>,\n metadata?: ILogEntry['metadata'],\n ): Promise<void>;\n}\n\nconst PREVIEW_LENGTH_HELPER = 100;\n\n/** Log execution start with truncated user input. @internal */\nexport async function logExecutionStartHelper(\n writer: ILogWriter,\n executionId: string,\n userInput: string,\n metadata?: ILogEntry['metadata'],\n): Promise<void> {\n await writer.info(\n 'Execution started',\n { userInput: userInput.substring(0, PREVIEW_LENGTH_HELPER) },\n { executionId, operation: 'execution_start', ...metadata },\n );\n}\n\n/** Log execution completion with duration. @internal */\nexport async function logExecutionCompleteHelper(\n writer: ILogWriter,\n executionId: string,\n duration: number,\n metadata?: ILogEntry['metadata'],\n): Promise<void> {\n await writer.info(\n 'Execution completed',\n { duration },\n {\n executionId,\n operation: 'execution_complete',\n ...(duration !== undefined && { duration }),\n ...metadata,\n },\n );\n}\n\n/** Log a tool execution result at info (success) or error (failure) level. @internal */\nexport async function logToolExecutionHelper(\n writer: ILogWriter,\n toolName: string,\n executionId: string,\n duration?: number,\n success?: boolean,\n metadata?: ILogEntry['metadata'],\n): Promise<void> {\n const message = success ? 'Tool executed successfully' : 'Tool execution failed';\n const level: TLogLevel = success ? 'info' : 'error';\n const logMetadata = {\n executionId,\n operation: 'tool_execution',\n ...(duration !== undefined && { duration }),\n ...(metadata && typeof metadata === 'object' ? metadata : {}),\n } as ILogEntry['metadata'];\n await writer.log(level, message, { toolName, success: success ?? false }, logMetadata);\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n SilentLogger,\n PluginError,\n type IEventEmitterEventData,\n type TEventName,\n} from '@robota-sdk/agent-core';\n\nimport {\n TLogLevel,\n ILogEntry,\n ILoggingContextData,\n ILoggingPluginOptions,\n ILoggingPluginStats,\n ILogStorage,\n ILogFormatter,\n} from './types';\nimport {\n validateLoggingOptions,\n createLoggingStorage,\n extractLoggingModuleData,\n LOGGING_MODULE_EVENT_MAP,\n logExecutionStartHelper,\n logExecutionCompleteHelper,\n logToolExecutionHelper,\n} from './logging-helpers';\n\nexport type { ILoggingContextData } from './types';\n\nconst DEFAULT_MAX_LOGS = 10000;\nconst DEFAULT_BATCH_SIZE = 100;\nconst DEFAULT_FLUSH_INTERVAL_MS = 30000;\n\n/** Logs agent operations using configurable storage backends (console/file/remote/silent). */\nexport class LoggingPlugin extends AbstractPlugin<ILoggingPluginOptions, ILoggingPluginStats> {\n name = 'LoggingPlugin';\n version = '1.0.0';\n\n private storage: ILogStorage;\n private pluginOptions: Required<Omit<ILoggingPluginOptions, 'formatter' | 'logger'>> & {\n formatter?: ILogFormatter;\n logger?: ILogger;\n };\n private logger: ILogger;\n private simpleLogger: ILogger;\n private logLevels: TLogLevel[] = ['debug', 'info', 'warn', 'error'];\n\n constructor(options: ILoggingPluginOptions) {\n super();\n this.logger = createLogger('LoggingPlugin');\n this.simpleLogger = options.logger || SilentLogger;\n\n // Set plugin classification\n this.category = PluginCategory.LOGGING;\n this.priority = PluginPriority.HIGH;\n\n // Validate options\n validateLoggingOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n level: options.level ?? 'info',\n filePath: options.filePath ?? './agent.log',\n remoteEndpoint: options.remoteEndpoint ?? '',\n remoteHeaders: options.remoteHeaders ?? {},\n maxLogs: options.maxLogs ?? DEFAULT_MAX_LOGS,\n includeStackTrace: options.includeStackTrace ?? true,\n ...(options.formatter && { formatter: options.formatter }),\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.LOGGING,\n priority: options.priority ?? PluginPriority.HIGH,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n\n // Initialize storage\n this.storage = createLoggingStorage(\n this.pluginOptions.strategy,\n this.pluginOptions.filePath,\n this.pluginOptions.remoteEndpoint,\n this.pluginOptions.flushInterval,\n this.pluginOptions.formatter,\n );\n\n this.logger.info('LoggingPlugin initialized', {\n strategy: this.pluginOptions.strategy,\n level: this.pluginOptions.level,\n maxLogs: this.pluginOptions.maxLogs,\n });\n }\n\n /**\n * Routes module lifecycle events (initialize, execute, dispose) to the\n * appropriate log level. Errors are logged but never re-thrown.\n */\n override async onModuleEvent(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n ): Promise<void> {\n try {\n const descriptor = LOGGING_MODULE_EVENT_MAP.get(eventName);\n if (!descriptor) return;\n\n const { moduleName, moduleType, duration, success } = extractLoggingModuleData(\n eventData.data,\n );\n const context: ILoggingContextData = { moduleName, moduleType };\n if (duration !== undefined) context.duration = duration;\n if (success !== undefined) context.success = success;\n\n const metadata: ILogEntry['metadata'] = { operation: descriptor.operation };\n if (eventData.executionId) metadata.executionId = eventData.executionId;\n if (duration !== undefined) metadata.duration = duration;\n\n const isErrorEvent = descriptor.level === 'error';\n if (isErrorEvent) {\n await this.error(descriptor.message, eventData.error, context, metadata);\n } else {\n await this.log(descriptor.level, descriptor.message, context, metadata);\n }\n } catch (error) {\n this.simpleLogger.error(\n `LoggingPlugin failed to handle module event ${eventName}:`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /**\n * Writes a log entry to the configured storage if the level meets the\n * current threshold. Logging failures are swallowed to prevent cascading errors.\n */\n async log(\n level: TLogLevel,\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n if (!this.shouldLog(level)) {\n return;\n }\n\n try {\n const entry: ILogEntry = {\n timestamp: new Date(),\n level,\n message,\n ...(context && { context }),\n ...(metadata && { metadata }),\n };\n\n await this.storage.write(entry);\n } catch (error) {\n // Don't throw errors from logging to avoid infinite loops\n this.simpleLogger.error(\n 'Logging failed:',\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /** Log debug message */\n async debug(\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await this.log('debug', message, context, metadata);\n }\n\n /** Log info message */\n async info(\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await this.log('info', message, context, metadata);\n }\n\n /** Log warning message */\n async warn(\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await this.log('warn', message, context, metadata);\n }\n\n /**\n * Log error message\n */\n async error(\n message: string,\n error?: Error,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n const errorContext = {\n ...context,\n ...(error && this.pluginOptions.includeStackTrace\n ? {\n errorMessage: error.message,\n errorStack: error.stack,\n }\n : {}),\n };\n\n await this.log('error', message, errorContext, metadata);\n }\n\n /**\n * Logs the start of an agent execution, truncating user input to 100 characters.\n */\n async logExecutionStart(\n executionId: string,\n userInput: string,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await logExecutionStartHelper(this, executionId, userInput, metadata);\n }\n\n /**\n * Logs the completion of an agent execution with its duration.\n */\n async logExecutionComplete(\n executionId: string,\n duration: number,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await logExecutionCompleteHelper(this, executionId, duration, metadata);\n }\n\n /**\n * Logs a tool execution result at info (success) or error (failure) level.\n */\n async logToolExecution(\n toolName: string,\n executionId: string,\n duration?: number,\n success?: boolean,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await logToolExecutionHelper(this, toolName, executionId, duration, success, metadata);\n }\n\n /**\n * Flushes any buffered log entries to the underlying storage.\n * @throws PluginError if the flush operation fails\n */\n async flush(): Promise<void> {\n try {\n await this.storage.flush();\n } catch (error) {\n throw new PluginError('Failed to flush logs', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Closes the underlying storage and releases resources.\n */\n async destroy(): Promise<void> {\n try {\n await this.storage.close();\n this.logger.info('LoggingPlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /** Check if message should be logged based on level */\n private shouldLog(level: TLogLevel): boolean {\n const currentLevelIndex = this.logLevels.indexOf(this.pluginOptions.level);\n const messageLevelIndex = this.logLevels.indexOf(level);\n return messageLevelIndex >= currentLevelIndex;\n }\n}\n","import { type ISystemMetricsCollector, type IPerformanceMetrics } from '../types';\nimport { createLogger, type ILogger } from '@robota-sdk/agent-core';\n\n/**\n * Node.js system metrics collector\n */\nexport class NodeSystemMetricsCollector implements ISystemMetricsCollector {\n private logger: ILogger;\n\n constructor() {\n this.logger = createLogger('NodeSystemMetricsCollector');\n }\n\n async getMemoryUsage(): Promise<IPerformanceMetrics['memoryUsage']> {\n try {\n const memoryUsage = process.memoryUsage();\n\n // Note: This is a basic implementation for Node.js\n // In production, you might want to use more sophisticated system monitoring libraries\n return {\n used: memoryUsage.rss,\n free: 0, // Not directly available in Node.js without additional libraries\n total: memoryUsage.rss + memoryUsage.external,\n heap: {\n used: memoryUsage.heapUsed,\n total: memoryUsage.heapTotal,\n },\n };\n } catch (error) {\n this.logger.warn('Failed to get memory usage', {\n error: error instanceof Error ? error.message : String(error),\n });\n return undefined;\n }\n }\n\n async getCPUUsage(): Promise<IPerformanceMetrics['cpuUsage']> {\n try {\n const cpuUsage = process.cpuUsage();\n\n // Note: This is a basic implementation for Node.js\n // For more accurate CPU percentage, you'd need to measure over time intervals\n return {\n user: cpuUsage.user,\n system: cpuUsage.system,\n percent: 0, // Would need time-based calculation for actual percentage\n };\n } catch (error) {\n this.logger.warn('Failed to get CPU usage', {\n error: error instanceof Error ? error.message : String(error),\n });\n return undefined;\n }\n }\n\n async getNetworkStats(): Promise<IPerformanceMetrics['networkStats']> {\n try {\n // Note: Network stats are not directly available in Node.js without additional monitoring\n // This would typically require integrating with system monitoring tools or libraries\n this.logger.warn('Network stats monitoring not fully implemented yet');\n return undefined;\n } catch (error) {\n this.logger.warn('Failed to get network stats', {\n error: error instanceof Error ? error.message : String(error),\n });\n return undefined;\n }\n }\n}\n","import { IPerformanceStorage, IPerformanceMetrics, IAggregatedPerformanceStats } from '../types';\n\nexport class MemoryPerformanceStorage implements IPerformanceStorage {\n private entries: IPerformanceMetrics[] = [];\n private maxEntries: number;\n\n constructor(maxEntries: number = 5000) {\n this.maxEntries = maxEntries;\n }\n\n async save(entry: IPerformanceMetrics): Promise<void> {\n if (this.entries.length >= this.maxEntries) {\n this.entries = this.entries.slice(-this.maxEntries + 1);\n }\n this.entries.push({ ...entry });\n }\n\n async getMetrics(\n operation?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IPerformanceMetrics[]> {\n let filtered = [...this.entries];\n if (operation) {\n filtered = filtered.filter((entry) => entry.operation === operation);\n }\n if (timeRange) {\n filtered = filtered.filter(\n (entry) => entry.timestamp >= timeRange.start && entry.timestamp <= timeRange.end,\n );\n }\n return filtered;\n }\n\n async getAggregatedStats(timeRange?: {\n start: Date;\n end: Date;\n }): Promise<IAggregatedPerformanceStats> {\n const metrics = await this.getMetrics(undefined, timeRange);\n\n if (metrics.length === 0) {\n return {\n totalOperations: 0,\n averageDuration: 0,\n minDuration: 0,\n maxDuration: 0,\n successRate: 0,\n errorRate: 0,\n operationStats: {},\n timeRangeStats: {\n startTime: timeRange?.start || new Date(),\n endTime: timeRange?.end || new Date(),\n period: 'empty',\n },\n };\n }\n\n const durations = metrics.map((m) => m.duration);\n const successCount = metrics.filter((m) => m.success).length;\n const errorCount = metrics.reduce((sum, m) => sum + m.errorCount, 0);\n\n return {\n totalOperations: metrics.length,\n averageDuration: durations.reduce((sum, d) => sum + d, 0) / durations.length,\n minDuration: Math.min(...durations),\n maxDuration: Math.max(...durations),\n successRate: successCount / metrics.length,\n errorRate: errorCount / metrics.length,\n operationStats: {},\n timeRangeStats: {\n startTime: timeRange?.start || metrics[0]?.timestamp || new Date(),\n endTime: timeRange?.end || metrics[metrics.length - 1]?.timestamp || new Date(),\n period: 'memory',\n },\n };\n }\n\n async clear(): Promise<void> {\n this.entries = [];\n }\n\n async flush(): Promise<void> {\n // Memory storage doesn't need flushing\n }\n\n async close(): Promise<void> {\n // Memory storage doesn't need closing\n }\n}\n","/**\n * Performance Plugin - Validation, storage factory, and module data extraction helpers.\n *\n * Extracted from performance-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError, EVENT_EMITTER_EVENTS } from '@robota-sdk/agent-core';\nimport { MemoryPerformanceStorage } from './storages/index';\nimport type { IPerformancePluginOptions, IPerformanceStorage } from './types';\n\n/** Validate PerformancePlugin constructor options. @internal */\nexport function validatePerformanceOptions(options: IPerformancePluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Performance monitoring strategy is required');\n }\n\n if (!['memory', 'file', 'prometheus', 'remote', 'silent'].includes(options.strategy)) {\n throw new ConfigurationError('Invalid performance monitoring strategy', {\n validStrategies: ['memory', 'file', 'prometheus', 'remote', 'silent'],\n provided: options.strategy,\n });\n }\n}\n\n/** Create IPerformanceStorage instance for the given strategy. @internal */\nexport function createPerformanceStorage(\n strategy: string,\n maxEntries: number,\n): IPerformanceStorage {\n switch (strategy) {\n case 'memory':\n return new MemoryPerformanceStorage(maxEntries);\n default:\n throw new ConfigurationError('Performance monitoring strategy is not implemented', {\n provided: strategy,\n });\n }\n}\n\n/** Event name → performance metrics descriptor mapping. @internal */\nexport const PERFORMANCE_MODULE_EVENT_MAP: ReadonlyMap<\n string,\n { operation: string; phase: string; isError: boolean }\n> = new Map([\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n { operation: 'module_initialization', phase: 'initialization', isError: false },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n { operation: 'module_initialization', phase: 'initialization', isError: true },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n { operation: 'module_execution', phase: 'execution', isError: false },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n { operation: 'module_execution', phase: 'execution', isError: true },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n { operation: 'module_disposal', phase: 'disposal', isError: false },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n { operation: 'module_disposal', phase: 'disposal', isError: true },\n ],\n]);\n\n/** Safely extract module data fields from untyped event payload. @internal */\nexport function extractPerformanceModuleData(data: unknown): {\n moduleName: string;\n moduleType: string;\n duration?: number;\n success?: boolean;\n} {\n const record = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n return {\n moduleName: typeof record['moduleName'] === 'string' ? record['moduleName'] : 'unknown',\n moduleType: typeof record['moduleType'] === 'string' ? record['moduleType'] : 'unknown',\n ...(typeof record['duration'] === 'number' && { duration: record['duration'] }),\n ...(typeof record['success'] === 'boolean' && { success: record['success'] }),\n };\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n PluginError,\n type IEventEmitterEventData,\n type TEventName,\n} from '@robota-sdk/agent-core';\nimport {\n IPerformanceMetrics,\n IAggregatedPerformanceStats,\n IPerformancePluginOptions,\n IPerformancePluginStats,\n IPerformanceStorage,\n ISystemMetricsCollector,\n} from './types';\nimport { NodeSystemMetricsCollector } from './collectors/system-metrics-collector';\nimport {\n validatePerformanceOptions,\n createPerformanceStorage,\n extractPerformanceModuleData,\n PERFORMANCE_MODULE_EVENT_MAP,\n} from './performance-helpers';\n\nconst DEFAULT_MAX_ENTRIES = 5000;\nconst DEFAULT_BATCH_SIZE = 100;\nconst DEFAULT_FLUSH_INTERVAL_MS = 30000;\nconst DEFAULT_AGGREGATION_INTERVAL_MS = 60000;\nconst DEFAULT_PERFORMANCE_THRESHOLD_MS = 1000;\n\n/**\n * Collects application and system performance metrics during agent execution.\n *\n * Optionally monitors memory, CPU, and network via\n * {@link ISystemMetricsCollector}. Logs a warning when an operation exceeds\n * the configured {@link IPerformancePluginOptions.performanceThreshold | performanceThreshold}.\n * Currently only the `memory` storage strategy is implemented.\n *\n * Lifecycle hooks used: {@link AbstractPlugin.onModuleEvent | onModuleEvent}\n *\n * @extends AbstractPlugin\n * @see IPerformanceStorage - storage backend contract\n * @see ISystemMetricsCollector - system metrics collection contract\n * @see IPerformancePluginOptions - configuration options\n *\n * @example\n * ```ts\n * const plugin = new PerformancePlugin({\n * strategy: 'memory',\n * monitorMemory: true,\n * performanceThreshold: 2000,\n * });\n * await plugin.recordMetrics({ operation: 'run', duration: 1500, success: true, errorCount: 0 });\n * ```\n */\nexport class PerformancePlugin extends AbstractPlugin<\n IPerformancePluginOptions,\n IPerformancePluginStats\n> {\n name = 'PerformancePlugin';\n version = '1.0.0';\n\n private storage: IPerformanceStorage;\n private metricsCollector: ISystemMetricsCollector;\n private pluginOptions: Required<IPerformancePluginOptions>;\n private logger: ILogger;\n\n constructor(options: IPerformancePluginOptions) {\n super();\n this.logger = createLogger('PerformancePlugin');\n\n // Set plugin classification\n this.category = PluginCategory.MONITORING;\n this.priority = PluginPriority.NORMAL;\n\n // Validate options\n validatePerformanceOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n filePath: options.filePath ?? './performance-metrics.json',\n remoteEndpoint: options.remoteEndpoint ?? '',\n prometheusEndpoint: options.prometheusEndpoint ?? '/metrics',\n remoteHeaders: options.remoteHeaders ?? {},\n maxEntries: options.maxEntries ?? DEFAULT_MAX_ENTRIES,\n monitorMemory: options.monitorMemory ?? true,\n monitorCPU: options.monitorCPU ?? true,\n monitorNetwork: options.monitorNetwork ?? false,\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL_MS,\n aggregateStats: options.aggregateStats ?? true,\n aggregationInterval: options.aggregationInterval ?? DEFAULT_AGGREGATION_INTERVAL_MS,\n performanceThreshold: options.performanceThreshold ?? DEFAULT_PERFORMANCE_THRESHOLD_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.MONITORING,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n\n // Initialize storage and metrics collector\n this.storage = createPerformanceStorage(\n this.pluginOptions.strategy,\n this.pluginOptions.maxEntries,\n );\n this.metricsCollector = new NodeSystemMetricsCollector();\n\n this.logger.info('PerformancePlugin initialized', {\n strategy: this.pluginOptions.strategy,\n monitorMemory: this.pluginOptions.monitorMemory,\n monitorCPU: this.pluginOptions.monitorCPU,\n performanceThreshold: this.pluginOptions.performanceThreshold,\n });\n }\n\n /**\n * Records performance metrics from module lifecycle events\n * (initialization, execution, disposal) including duration and error counts.\n */\n override async onModuleEvent(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n ): Promise<void> {\n try {\n const descriptor = PERFORMANCE_MODULE_EVENT_MAP.get(eventName);\n if (!descriptor) return;\n\n const { moduleName, moduleType, duration, success } = extractPerformanceModuleData(\n eventData.data,\n );\n if (duration === undefined) return;\n\n await this.recordMetrics({\n operation: descriptor.operation,\n duration,\n success: descriptor.isError ? false : (success ?? true),\n errorCount: descriptor.isError ? 1 : 0,\n ...(eventData.executionId && { executionId: eventData.executionId }),\n metadata: {\n moduleName,\n moduleType,\n phase: descriptor.phase,\n ...(descriptor.isError && { error: eventData.error?.message || 'unknown error' }),\n },\n });\n } catch (_error) {\n // Swallow to avoid breaking module event processing\n }\n }\n\n /**\n * Records performance metrics, enriching them with system metrics (memory,\n * CPU, network) when the corresponding monitoring options are enabled.\n * @throws PluginError if the storage write fails\n */\n async recordMetrics(\n metrics: Omit<IPerformanceMetrics, 'timestamp' | 'memoryUsage' | 'cpuUsage' | 'networkStats'>,\n ): Promise<void> {\n try {\n const memoryUsage = this.pluginOptions.monitorMemory\n ? await this.metricsCollector.getMemoryUsage()\n : undefined;\n const cpuUsage = this.pluginOptions.monitorCPU\n ? await this.metricsCollector.getCPUUsage()\n : undefined;\n const networkStats = this.pluginOptions.monitorNetwork\n ? await this.metricsCollector.getNetworkStats()\n : undefined;\n\n const entry: IPerformanceMetrics = {\n ...metrics,\n timestamp: new Date(),\n ...(memoryUsage && { memoryUsage }),\n ...(cpuUsage && { cpuUsage }),\n ...(networkStats && { networkStats }),\n };\n\n await this.storage.save(entry);\n\n // Log warning if performance threshold exceeded\n if (entry.duration > this.pluginOptions.performanceThreshold) {\n this.logger.warn('Performance threshold exceeded', {\n operation: entry.operation,\n duration: entry.duration,\n threshold: this.pluginOptions.performanceThreshold,\n executionId: entry.executionId,\n });\n }\n\n this.logger.debug('Performance metrics recorded', {\n operation: entry.operation,\n duration: entry.duration,\n success: entry.success,\n memoryUsed: entry.memoryUsage?.heap.used,\n });\n } catch (error) {\n throw new PluginError('Failed to record performance metrics', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Retrieves recorded metrics, optionally filtered by operation name and time range.\n * @throws PluginError if the storage read fails\n */\n async getMetrics(\n operation?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IPerformanceMetrics[]> {\n try {\n return await this.storage.getMetrics(operation, timeRange);\n } catch (error) {\n throw new PluginError('Failed to get performance metrics', this.name, {\n operation: operation || 'all',\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get aggregated performance statistics\n */\n async getAggregatedStats(timeRange?: {\n start: Date;\n end: Date;\n }): Promise<IAggregatedPerformanceStats> {\n try {\n return await this.storage.getAggregatedStats(timeRange);\n } catch (error) {\n throw new PluginError('Failed to get aggregated performance stats', this.name, {\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Clear all performance metrics\n */\n async clearMetrics(): Promise<void> {\n try {\n await this.storage.clear();\n this.logger.info('Performance metrics cleared');\n } catch (error) {\n throw new PluginError('Failed to clear performance metrics', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Closes the underlying storage and releases resources.\n */\n async destroy(): Promise<void> {\n try {\n await this.storage.close();\n this.logger.info('PerformancePlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n","import type { IAggregatedUsageStats, IUsageStats } from './types';\n\nconst MS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst MS_PER_HOUR = MS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR;\nconst HOURS_PER_DAY = 24;\nconst HOURS_PER_WEEK = 168;\n\ninterface IUsageTimeRange {\n start: Date;\n end: Date;\n}\n\nfunction determineUsagePeriod(timeRange: IUsageTimeRange | undefined): string {\n if (!timeRange) return 'all';\n\n const diff = timeRange.end.getTime() - timeRange.start.getTime();\n const hours = diff / MS_PER_HOUR;\n\n if (hours <= 1) return 'hour';\n if (hours <= HOURS_PER_DAY) return 'day';\n if (hours <= HOURS_PER_WEEK) return 'week';\n return 'month';\n}\n\nfunction resolveTimeRangeStats(\n stats: readonly IUsageStats[],\n timeRange: IUsageTimeRange | undefined,\n): { startTime: Date; endTime: Date; period: string } {\n if (timeRange) {\n return {\n startTime: timeRange.start,\n endTime: timeRange.end,\n period: determineUsagePeriod(timeRange),\n };\n }\n\n if (stats.length > 0) {\n const first = stats[0]?.timestamp;\n const last = stats[stats.length - 1]?.timestamp;\n const now = new Date();\n return {\n startTime: first ?? now,\n endTime: last ?? now,\n period: determineUsagePeriod(undefined),\n };\n }\n\n const now = new Date();\n return {\n startTime: now,\n endTime: now,\n period: determineUsagePeriod(undefined),\n };\n}\n\n/**\n * Aggregate usage statistics into a single summary object.\n * This is a shared SSOT utility (composition over inheritance).\n */\nexport function aggregateUsageStats(\n stats: readonly IUsageStats[],\n timeRange?: IUsageTimeRange,\n): IAggregatedUsageStats {\n const timeRangeStats = resolveTimeRangeStats(stats, timeRange);\n\n const aggregated: IAggregatedUsageStats = {\n totalRequests: stats.length,\n totalTokens: stats.reduce((sum, entry) => sum + entry.tokensUsed.total, 0),\n totalCost: stats.reduce((sum, entry) => sum + (entry.cost?.total ?? 0), 0),\n totalDuration: stats.reduce((sum, entry) => sum + entry.duration, 0),\n successRate:\n stats.length > 0 ? stats.filter((entry) => entry.success).length / stats.length : 0,\n providerStats: {},\n modelStats: {},\n toolStats: {},\n timeRangeStats,\n };\n\n // Aggregate by provider\n for (const entry of stats) {\n if (!aggregated.providerStats[entry.provider]) {\n aggregated.providerStats[entry.provider] = {\n requests: 0,\n tokens: 0,\n cost: 0,\n duration: 0,\n };\n }\n const providerStat = aggregated.providerStats[entry.provider];\n if (providerStat) {\n providerStat.requests += entry.requestCount;\n providerStat.tokens += entry.tokensUsed.total;\n providerStat.cost += entry.cost?.total ?? 0;\n providerStat.duration += entry.duration;\n }\n }\n\n // Aggregate by model\n for (const entry of stats) {\n if (!aggregated.modelStats[entry.model]) {\n aggregated.modelStats[entry.model] = {\n requests: 0,\n tokens: 0,\n cost: 0,\n duration: 0,\n };\n }\n const modelStat = aggregated.modelStats[entry.model];\n if (modelStat) {\n modelStat.requests += entry.requestCount;\n modelStat.tokens += entry.tokensUsed.total;\n modelStat.cost += entry.cost?.total ?? 0;\n modelStat.duration += entry.duration;\n }\n }\n\n // Aggregate by tools\n for (const entry of stats) {\n const toolsUsed = entry.toolsUsed;\n if (!toolsUsed) continue;\n\n for (const tool of toolsUsed) {\n if (!aggregated.toolStats[tool]) {\n aggregated.toolStats[tool] = {\n usageCount: 0,\n successCount: 0,\n totalDuration: 0,\n };\n }\n const toolStat = aggregated.toolStats[tool];\n toolStat.usageCount += 1;\n if (entry.success) {\n toolStat.successCount += 1;\n }\n toolStat.totalDuration += entry.duration;\n }\n }\n\n return aggregated;\n}\n","import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\nimport { aggregateUsageStats } from '../aggregate-usage-stats';\n\n/**\n * Memory storage implementation for usage statistics\n */\nexport class MemoryUsageStorage implements IUsageStorage {\n private entries: IUsageStats[] = [];\n private maxEntries: number;\n\n constructor(maxEntries: number = 10000) {\n this.maxEntries = maxEntries;\n }\n\n async save(entry: IUsageStats): Promise<void> {\n // Remove oldest entries if limit exceeded\n if (this.entries.length >= this.maxEntries) {\n this.entries = this.entries.slice(-this.maxEntries + 1);\n }\n\n this.entries.push({ ...entry });\n }\n\n async getStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n let filtered = [...this.entries];\n\n if (conversationId) {\n filtered = filtered.filter((entry) => entry.conversationId === conversationId);\n }\n\n if (timeRange) {\n filtered = filtered.filter(\n (entry) => entry.timestamp >= timeRange.start && entry.timestamp <= timeRange.end,\n );\n }\n\n return filtered;\n }\n\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n const stats = await this.getStats(undefined, timeRange);\n return aggregateUsageStats(stats, timeRange);\n }\n\n async clear(): Promise<void> {\n this.entries = [];\n }\n\n async flush(): Promise<void> {\n // Memory storage doesn't need flushing\n }\n\n async close(): Promise<void> {\n // Memory storage doesn't need closing\n }\n\n // Aggregation logic intentionally lives in ../aggregate-usage-stats.ts (SSOT utility).\n}\n","import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\nimport { createLogger, type ILogger, StorageError } from '@robota-sdk/agent-core';\nimport { aggregateUsageStats } from '../aggregate-usage-stats';\n\n/**\n * File storage implementation for usage statistics\n */\nexport class FileUsageStorage implements IUsageStorage {\n private filePath: string;\n private logger: ILogger;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n this.logger = createLogger('FileUsageStorage');\n }\n\n async save(entry: IUsageStats): Promise<void> {\n try {\n // File operations would be implemented here\n // This is a placeholder for actual file system operations\n this.logger.warn('File usage storage not fully implemented yet', {\n filePath: this.filePath,\n entry: {\n timestamp: entry.timestamp.toISOString(),\n provider: entry.provider,\n model: entry.model,\n tokens: entry.tokensUsed.total,\n cost: entry.cost?.total,\n success: entry.success,\n },\n });\n } catch (error) {\n throw new StorageError('Failed to save usage stats to file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async getStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n try {\n // File operations would be implemented here\n this.logger.warn('File usage storage not fully implemented yet', {\n filePath: this.filePath,\n conversationId,\n timeRange,\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to load usage stats from file', {\n filePath: this.filePath,\n conversationId: conversationId || 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n try {\n const stats = await this.getStats(undefined, timeRange);\n return aggregateUsageStats(stats, timeRange);\n } catch (error) {\n throw new StorageError('Failed to get aggregated usage stats from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // File operations would be implemented here\n this.logger.warn('File usage storage not fully implemented yet', {\n filePath: this.filePath,\n operation: 'clear',\n });\n } catch (error) {\n throw new StorageError('Failed to clear usage stats from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n try {\n // File flushing would be implemented here\n this.logger.warn('File usage storage flush not fully implemented yet', {\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to flush usage stats to file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async close(): Promise<void> {\n try {\n // File closing would be implemented here\n this.logger.warn('File usage storage close not fully implemented yet', {\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to close usage stats file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n","import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\nimport {\n createLogger,\n type ILogger,\n StorageError,\n type TTimerId,\n startPeriodicTask,\n stopPeriodicTask,\n} from '@robota-sdk/agent-core';\nimport { aggregateUsageStats } from '../aggregate-usage-stats';\n\nconst SAMPLE_SIZE = 3;\n\n/**\n * Remote storage implementation for usage statistics with batching\n */\nexport class RemoteUsageStorage implements IUsageStorage {\n private apiUrl: string;\n private batchSize: number;\n private flushInterval: number;\n private batch: IUsageStats[] = [];\n private timer?: TTimerId;\n private logger: ILogger;\n\n constructor(\n apiUrl: string,\n _apiKey: string,\n _timeout: number,\n _headers: Record<string, string> = {},\n batchSize: number = 50,\n flushInterval: number = 60000, // 1 minute\n ) {\n this.apiUrl = apiUrl;\n this.batchSize = batchSize;\n this.flushInterval = flushInterval;\n this.logger = createLogger('RemoteUsageStorage');\n\n this.timer = startPeriodicTask(\n this.logger,\n { name: 'RemoteUsageStorage.flush', intervalMs: this.flushInterval },\n async () => {\n await this.flush();\n },\n );\n }\n\n async save(entry: IUsageStats): Promise<void> {\n this.batch.push(entry);\n\n if (this.batch.length >= this.batchSize) {\n await this.flush();\n }\n }\n\n async getStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n try {\n // Remote API call would be implemented here\n this.logger.warn('Remote usage storage not fully implemented yet', {\n endpoint: this.apiUrl,\n operation: 'getStats',\n conversationId,\n timeRange,\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to get usage stats from remote endpoint', {\n endpoint: this.apiUrl,\n conversationId: conversationId || 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n try {\n const stats = await this.getStats(undefined, timeRange);\n return aggregateUsageStats(stats, timeRange);\n } catch (error) {\n throw new StorageError('Failed to get aggregated usage stats from remote endpoint', {\n endpoint: this.apiUrl,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // Remote API call would be implemented here\n this.logger.warn('Remote usage storage not fully implemented yet', {\n endpoint: this.apiUrl,\n operation: 'clear',\n });\n } catch (error) {\n throw new StorageError('Failed to clear usage stats from remote endpoint', {\n endpoint: this.apiUrl,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n if (this.batch.length === 0) return;\n\n const statsToSend = [...this.batch];\n this.batch = [];\n\n try {\n // Remote API call would be implemented here\n // This is a placeholder for actual HTTP requests\n this.logger.warn('Remote usage storage not fully implemented yet', {\n endpoint: this.apiUrl,\n operation: 'flush',\n batchSize: statsToSend.length,\n sample: statsToSend.slice(0, SAMPLE_SIZE).map((stat) => ({\n timestamp: stat.timestamp.toISOString(),\n provider: stat.provider,\n model: stat.model,\n tokens: stat.tokensUsed.total,\n cost: stat.cost?.total,\n success: stat.success,\n })),\n });\n } catch (error) {\n // Re-add failed batch to the beginning of current batch\n this.batch = [...statsToSend, ...this.batch];\n throw new StorageError('Failed to send usage stats to remote endpoint', {\n endpoint: this.apiUrl,\n batchSize: statsToSend.length,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async close(): Promise<void> {\n stopPeriodicTask(this.timer);\n this.timer = undefined;\n\n await this.flush();\n }\n}\n","import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\nimport { aggregateUsageStats } from '../aggregate-usage-stats';\n\n/**\n * Silent storage implementation for usage statistics (no-op)\n */\nexport class SilentUsageStorage implements IUsageStorage {\n async save(_entry: IUsageStats): Promise<void> {\n // Silent mode - do nothing\n }\n\n async getStats(\n _conversationId?: string,\n _timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n // Silent mode - return empty array\n return [];\n }\n\n async getAggregatedStats(_timeRange?: {\n start: Date;\n end: Date;\n }): Promise<IAggregatedUsageStats> {\n return aggregateUsageStats([], _timeRange);\n }\n\n async clear(): Promise<void> {\n // Silent mode - do nothing\n }\n\n async flush(): Promise<void> {\n // Silent mode - do nothing\n }\n\n async close(): Promise<void> {\n // Silent mode - do nothing\n }\n}\n","import {\n PluginCategory,\n PluginPriority,\n ConfigurationError,\n type TEventName,\n EVENT_EMITTER_EVENTS,\n} from '@robota-sdk/agent-core';\nimport type { IUsagePluginOptions } from './types';\n\nconst DEFAULT_MAX_ENTRIES = 10000;\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_FLUSH_INTERVAL_MS = 60000;\nconst DEFAULT_AGGREGATION_INTERVAL_MS = 300000;\n\nexport type TResolvedUsageOptions = Required<Omit<IUsagePluginOptions, 'costRates'>> & {\n costRates?: Record<string, { input: number; output: number }>;\n};\n\nexport function resolvePluginOptions(options: IUsagePluginOptions): TResolvedUsageOptions {\n return {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n filePath: options.filePath ?? './usage-stats.json',\n remoteEndpoint: options.remoteEndpoint ?? '',\n remoteHeaders: options.remoteHeaders ?? {},\n maxEntries: options.maxEntries ?? DEFAULT_MAX_ENTRIES,\n trackCosts: options.trackCosts ?? true,\n ...(options.costRates && { costRates: options.costRates }),\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL_MS,\n aggregateStats: options.aggregateStats ?? true,\n aggregationInterval: options.aggregationInterval ?? DEFAULT_AGGREGATION_INTERVAL_MS,\n category: options.category ?? PluginCategory.MONITORING,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n}\n\nexport function calculateCost(\n costRates: Record<string, { input: number; output: number }> | undefined,\n model: string,\n tokens: { input: number; output: number },\n): { input: number; output: number; total: number } | undefined {\n if (!costRates || !costRates[model]) return undefined;\n const rates = costRates[model];\n const inputCost = tokens.input * rates.input;\n const outputCost = tokens.output * rates.output;\n return { input: inputCost, output: outputCost, total: inputCost + outputCost };\n}\n\nconst VALID_STRATEGIES = ['memory', 'file', 'remote', 'silent'] as const;\n\nexport function validateUsageOptions(options: IUsagePluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Usage tracking strategy is required');\n }\n if (!(VALID_STRATEGIES as readonly string[]).includes(options.strategy)) {\n throw new ConfigurationError('Invalid usage tracking strategy', {\n validStrategies: [...VALID_STRATEGIES],\n provided: options.strategy,\n });\n }\n if (options.strategy === 'file' && !options.filePath) {\n throw new ConfigurationError('File path is required for file usage tracking strategy');\n }\n if (options.strategy === 'remote' && !options.remoteEndpoint) {\n throw new ConfigurationError('Remote endpoint is required for remote usage tracking strategy');\n }\n if (options.maxEntries !== undefined && options.maxEntries <= 0) {\n throw new ConfigurationError('Max entries must be positive');\n }\n if (options.batchSize !== undefined && options.batchSize <= 0) {\n throw new ConfigurationError('Batch size must be positive');\n }\n if (options.flushInterval !== undefined && options.flushInterval <= 0) {\n throw new ConfigurationError('Flush interval must be positive');\n }\n if (options.aggregationInterval !== undefined && options.aggregationInterval <= 0) {\n throw new ConfigurationError('Aggregation interval must be positive');\n }\n}\n\nconst MODULE_SUCCESS_EVENTS = new Set<TEventName>([\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n]);\n\nconst MODULE_ERROR_EVENTS = new Set<TEventName>([\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n]);\n\nexport function isModuleSuccessEvent(eventName: TEventName): boolean {\n return MODULE_SUCCESS_EVENTS.has(eventName);\n}\n\nexport function isModuleErrorEvent(eventName: TEventName): boolean {\n return MODULE_ERROR_EVENTS.has(eventName);\n}\n\nexport function extractStringField(data: unknown, field: string): string {\n if (data && typeof data === 'object' && field in data) {\n const value = (data as Record<string, unknown>)[field];\n if (typeof value === 'string') return value;\n }\n return 'unknown';\n}\n\nexport function resolveOperation(eventName: TEventName): string {\n if (eventName.includes('initialize')) return 'initialization';\n if (eventName.includes('execution')) return 'execution';\n return 'disposal';\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n PluginError,\n ConfigurationError,\n type IEventEmitterEventData,\n type TEventName,\n type TTimerId,\n startPeriodicTask,\n} from '@robota-sdk/agent-core';\nimport {\n IUsageStats,\n IAggregatedUsageStats,\n IUsagePluginOptions,\n IUsagePluginStats,\n IUsageStorage,\n} from './types';\nimport {\n MemoryUsageStorage,\n FileUsageStorage,\n RemoteUsageStorage,\n SilentUsageStorage,\n} from './storages/index';\nimport {\n type TResolvedUsageOptions,\n resolvePluginOptions,\n validateUsageOptions,\n calculateCost,\n isModuleSuccessEvent,\n isModuleErrorEvent,\n extractStringField,\n resolveOperation,\n} from './usage-plugin-helpers';\n\nconst DEFAULT_REMOTE_TIMEOUT_MS = 30000;\n\n/**\n * Tracks token usage, request counts, and costs across agent executions.\n *\n * Supports memory, file, remote, and silent storage strategies. When\n * {@link IUsagePluginOptions.trackCosts | trackCosts} is enabled, per-model\n * cost rates are applied automatically. Periodic aggregation can be enabled\n * via {@link IUsagePluginOptions.aggregateStats | aggregateStats}.\n *\n * Lifecycle hooks used: {@link AbstractPlugin.onModuleEvent | onModuleEvent}\n *\n * @extends AbstractPlugin\n * @see IUsageStorage - storage backend contract\n * @see IUsagePluginOptions - configuration options\n *\n * @example\n * ```ts\n * const plugin = new UsagePlugin({\n * strategy: 'memory',\n * trackCosts: true,\n * costRates: { 'gpt-4': { input: 0.03, output: 0.06 } },\n * });\n * await plugin.recordUsage({ provider: 'openai', model: 'gpt-4', ... });\n * ```\n */\nexport class UsagePlugin extends AbstractPlugin<IUsagePluginOptions, IUsagePluginStats> {\n name = 'UsagePlugin';\n version = '1.0.0';\n\n private storage: IUsageStorage;\n private pluginOptions: TResolvedUsageOptions;\n private logger: ILogger;\n private aggregationTimer?: TTimerId;\n\n constructor(options: IUsagePluginOptions) {\n super();\n this.logger = createLogger('UsagePlugin');\n this.category = PluginCategory.MONITORING;\n this.priority = PluginPriority.NORMAL;\n\n validateUsageOptions(options);\n this.pluginOptions = resolvePluginOptions(options);\n this.storage = this.createStorage();\n\n if (this.pluginOptions.aggregateStats) {\n this.setupAggregation();\n }\n\n this.logger.info('UsagePlugin initialized', {\n strategy: this.pluginOptions.strategy,\n trackCosts: this.pluginOptions.trackCosts,\n maxEntries: this.pluginOptions.maxEntries,\n });\n }\n\n /**\n * Records usage statistics from module lifecycle events (completion and\n * error events). Duration-bearing events are recorded with zero token\n * counts as module events do not involve LLM calls.\n */\n override async onModuleEvent(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n ): Promise<void> {\n try {\n const isSuccess = isModuleSuccessEvent(eventName);\n const isError = isModuleErrorEvent(eventName);\n if (!isSuccess && !isError) return;\n\n const moduleData = eventData.data;\n if (!moduleData || !('duration' in moduleData) || typeof moduleData.duration !== 'number')\n return;\n\n await this.recordModuleUsage(eventName, eventData, moduleData.duration, isSuccess);\n } catch {\n // Swallow to avoid breaking module event processing\n }\n }\n\n private async recordModuleUsage(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n duration: number,\n success: boolean,\n ): Promise<void> {\n const moduleData = eventData.data;\n const moduleName = extractStringField(moduleData, 'moduleName');\n const moduleType = extractStringField(moduleData, 'moduleType');\n const operation = resolveOperation(eventName);\n\n const metadata: Record<string, string> = { moduleName, moduleType, operation };\n if (!success) {\n metadata['error'] = eventData.error?.message || 'unknown error';\n }\n\n await this.recordUsage({\n provider: 'module',\n model: moduleType,\n tokensUsed: { input: 0, output: 0, total: 0 },\n requestCount: 1,\n duration,\n success,\n ...(eventData.executionId && { executionId: eventData.executionId }),\n ...(eventData.sessionId && { conversationId: eventData.sessionId }),\n metadata,\n });\n }\n\n /**\n * Records a usage entry, calculating cost if cost tracking is enabled and\n * a rate is configured for the model.\n * @throws PluginError if the storage write fails\n */\n async recordUsage(usage: Omit<IUsageStats, 'timestamp' | 'cost'>): Promise<void> {\n try {\n const cost = this.pluginOptions.trackCosts\n ? calculateCost(this.pluginOptions.costRates, usage.model, usage.tokensUsed)\n : undefined;\n\n const entry: IUsageStats = {\n ...usage,\n timestamp: new Date(),\n ...(cost && { cost }),\n };\n\n await this.storage.save(entry);\n\n this.logger.debug('Usage recorded', {\n provider: entry.provider,\n model: entry.model,\n tokens: entry.tokensUsed.total,\n cost: entry.cost?.total,\n success: entry.success,\n });\n } catch (error) {\n throw new PluginError('Failed to record usage', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Retrieves usage entries, optionally filtered by conversation and time range.\n * @throws PluginError if the storage read fails\n */\n async getUsageStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n try {\n return await this.storage.getStats(conversationId, timeRange);\n } catch (error) {\n throw new PluginError('Failed to get usage stats', this.name, {\n conversationId: conversationId || 'all',\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns aggregated totals (requests, tokens, cost, success rate) across\n * all recorded usage entries within the optional time range.\n * @throws PluginError if the storage aggregation fails\n */\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n try {\n return await this.storage.getAggregatedStats(timeRange);\n } catch (error) {\n throw new PluginError('Failed to get aggregated usage stats', this.name, {\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clearStats(): Promise<void> {\n try {\n await this.storage.clear();\n this.logger.info('Usage statistics cleared');\n } catch (error) {\n throw new PluginError('Failed to clear usage stats', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n try {\n await this.storage.flush();\n } catch (error) {\n throw new PluginError('Failed to flush usage stats', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Stops the aggregation timer and closes the underlying storage.\n */\n async destroy(): Promise<void> {\n try {\n if (this.aggregationTimer) {\n clearInterval(this.aggregationTimer);\n }\n await this.storage.close();\n this.logger.info('UsagePlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n private createStorage(): IUsageStorage {\n switch (this.pluginOptions.strategy) {\n case 'memory':\n return new MemoryUsageStorage(this.pluginOptions.maxEntries);\n case 'file':\n return new FileUsageStorage(this.pluginOptions.filePath);\n case 'remote':\n return new RemoteUsageStorage(\n this.pluginOptions.remoteEndpoint!,\n '',\n DEFAULT_REMOTE_TIMEOUT_MS,\n this.pluginOptions.remoteHeaders || {},\n this.pluginOptions.batchSize,\n this.pluginOptions.flushInterval,\n );\n case 'silent':\n return new SilentUsageStorage();\n default:\n throw new ConfigurationError('Unknown usage tracking strategy', {\n strategy: this.pluginOptions.strategy,\n });\n }\n }\n\n private setupAggregation(): void {\n this.aggregationTimer = startPeriodicTask(\n this.logger,\n { name: 'UsagePlugin.aggregate', intervalMs: this.pluginOptions.aggregationInterval },\n async () => {\n const stats = await this.getAggregatedStats();\n this.logger.debug('Periodic usage aggregation', {\n totalRequests: stats.totalRequests,\n totalTokens: stats.totalTokens,\n totalCost: stats.totalCost,\n successRate: stats.successRate,\n });\n },\n );\n }\n}\n","/**\n * Webhook data transformation utilities\n * Converts base plugin types to webhook-specific types safely\n */\n\nimport type {\n IPluginExecutionContext,\n IPluginExecutionResult,\n TLoggerData,\n TUniversalValue,\n} from '@robota-sdk/agent-core';\nimport type {\n IWebhookExecutionContext,\n IWebhookExecutionResult,\n IWebhookEventData,\n IWebhookExecutionData,\n IWebhookConversationData,\n IWebhookToolData,\n IWebhookErrorData,\n IWebhookToolCallData,\n TWebhookEventName,\n} from './types';\n\n/**\n * Webhook data transformer utility class\n */\nexport class WebhookTransformer {\n /**\n * Convert IPluginExecutionContext to WebhookExecutionContext\n */\n static contextToWebhook(context: IPluginExecutionContext): IWebhookExecutionContext {\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n };\n }\n\n /**\n * Convert IPluginExecutionResult to WebhookExecutionResult\n */\n static resultToWebhook(result: IPluginExecutionResult): IWebhookExecutionResult {\n return {\n response: result.response,\n content: result.content,\n duration: result.duration,\n tokensUsed: result.tokensUsed,\n toolsExecuted: result.toolsExecuted,\n success: result.success,\n usage: result.usage,\n toolCalls: result.toolCalls,\n error: result.error,\n };\n }\n\n /**\n * Create execution event data\n */\n static createExecutionData(\n context: IWebhookExecutionContext,\n result: IWebhookExecutionResult,\n ): IWebhookEventData {\n const executionData: IWebhookExecutionData = {\n response: result.response || undefined,\n duration: result.duration || undefined,\n tokensUsed: result.tokensUsed || undefined,\n toolsExecuted: result.toolsExecuted || undefined,\n success: result.success !== undefined ? result.success : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n result: executionData,\n };\n }\n\n /**\n * Create conversation event data\n */\n static createConversationData(\n context: IWebhookExecutionContext,\n result: IWebhookExecutionResult,\n ): IWebhookEventData {\n const toolCalls: IWebhookToolCallData[] =\n result.toolCalls?.map((call) => ({\n id: call.id || '',\n name: call.name || '',\n arguments: JSON.stringify(call.arguments || {}),\n result: String(call.result || ''),\n })) || [];\n\n const conversationData: IWebhookConversationData = {\n response: result.content || result.response || undefined,\n tokensUsed: result.usage?.totalTokens || result.tokensUsed || undefined,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n conversation: conversationData,\n };\n }\n\n /**\n * Create tool execution event data\n *\n * REASON: Tool result structure varies by tool type and provider, needs flexible handling for webhook processing\n * ALTERNATIVES_CONSIDERED:\n * 1. Strict tool result interfaces (breaks tool compatibility)\n * 2. Union types (insufficient for dynamic tool results)\n * 3. Generic constraints (too complex for webhook processing)\n * 4. Interface definitions (too rigid for varied tool results)\n * 5. Type assertions (decreases type safety)\n * TODO: Consider standardized tool result interface across tools\n */\n static createToolData(\n context: IWebhookExecutionContext,\n toolResult: TLoggerData,\n ): IWebhookEventData {\n // Safely extract tool data from result\n const toolName = this.safeGetProperty(toolResult, 'toolName') || 'unknown';\n const toolId =\n this.safeGetProperty(toolResult, 'toolId') ||\n this.safeGetProperty(toolResult, 'executionId') ||\n 'unknown';\n const hasError = this.safeGetProperty(toolResult, 'error');\n const duration = this.safeGetProperty(toolResult, 'duration');\n const result = this.safeGetProperty(toolResult, 'result');\n\n const toolData: IWebhookToolData = {\n name: String(toolName),\n id: String(toolId),\n success: !hasError,\n duration: typeof duration === 'number' ? duration : undefined,\n result: hasError ? undefined : String(result || ''),\n error: hasError\n ? hasError instanceof Error\n ? hasError.message\n : String(hasError)\n : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n tool: toolData,\n };\n }\n\n /**\n * Create error event data\n */\n static createErrorData(context: IWebhookExecutionContext, error: Error): IWebhookEventData {\n const errorData: IWebhookErrorData = {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n type: error instanceof Error ? error.constructor.name : 'Unknown',\n context: context\n ? {\n executionId: context.executionId || '',\n sessionId: context.sessionId || '',\n userId: context.userId || '',\n }\n : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n error: errorData,\n };\n }\n\n /**\n * Safely get property from object (handles index signature issues)\n *\n * REASON: Safe property access for webhook data transformation needs flexible input/output types\n * ALTERNATIVES_CONSIDERED:\n * 1. Strict object types (breaks dynamic property access)\n * 2. Union types (insufficient for property extraction)\n * 3. Generic constraints (too complex for simple property access)\n * 4. Interface definitions (too rigid for dynamic objects)\n * 5. Type assertions (decreases type safety)\n * TODO: Consider typed property access if patterns emerge\n */\n private static safeGetProperty(obj: TLoggerData, key: string): TUniversalValue | Date | Error {\n if (!obj || typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return undefined;\n }\n return obj[key];\n }\n\n /**\n * Default payload transformer for webhook events\n */\n static defaultPayloadTransformer(\n _event: TWebhookEventName,\n data: IWebhookEventData,\n ): IWebhookEventData {\n // Simply return the data as-is for the default transformer\n return data;\n }\n}\n","/**\n * Webhook HTTP client for sending webhook requests\n * Handles retries, timeouts, and error scenarios\n */\n\nimport jsSHA from 'jssha';\nimport type { IWebhookRequest } from './types';\nimport type { ILogger } from '@robota-sdk/agent-core';\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BACKOFF_BASE_MS = 1000;\nconst MAX_BACKOFF_MS = 10000;\n\n/**\n * HTTP client for webhook requests\n */\nexport class WebhookHttpClient {\n private logger: ILogger;\n\n constructor(logger: ILogger) {\n this.logger = logger;\n }\n\n /**\n * Send a single webhook request with retries\n */\n async sendRequest(request: IWebhookRequest): Promise<void> {\n const { endpoint, payload, attempt } = request;\n const timeout = endpoint.timeout ?? DEFAULT_TIMEOUT_MS;\n const maxRetries = endpoint.retries ?? DEFAULT_MAX_RETRIES;\n\n try {\n // Prepare request body\n const body = JSON.stringify(payload);\n\n // Prepare headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'User-Agent': 'robota-webhook/1.0.0',\n ...endpoint.headers,\n };\n\n // Add signature if secret is provided\n if (endpoint.secret) {\n const signature = this.generateSignature(body, endpoint.secret);\n headers['X-Webhook-Signature'] = signature;\n }\n\n // Make HTTP request\n const response = await this.makeHttpRequest(endpoint.url, {\n method: 'POST',\n headers,\n body,\n timeout,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n this.logger.debug('Webhook sent successfully', {\n url: endpoint.url,\n event: payload.event,\n attempt,\n status: response.status,\n });\n } catch (error) {\n this.logger.error('Webhook request failed', {\n url: endpoint.url,\n event: payload.event,\n attempt,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // Retry if we haven't exceeded max attempts\n if (attempt < maxRetries) {\n const retryRequest: IWebhookRequest = {\n ...request,\n attempt: attempt + 1,\n };\n\n // Exponential backoff\n const delay = Math.min(BACKOFF_BASE_MS * Math.pow(2, attempt - 1), MAX_BACKOFF_MS);\n await this.delay(delay);\n\n return this.sendRequest(retryRequest);\n }\n\n // Max retries exceeded\n throw error;\n }\n }\n\n /**\n * Generate HMAC signature for webhook security using jsSHA (browser compatible)\n */\n private generateSignature(body: string, secret: string): string {\n const shaObj = new jsSHA('SHA-256', 'TEXT', {\n hmacKey: { value: secret, format: 'TEXT' },\n });\n shaObj.update(body);\n return shaObj.getHash('HEX').toLowerCase();\n }\n\n /**\n * Make HTTP request with timeout support\n */\n private async makeHttpRequest(\n url: string,\n options: {\n method: string;\n headers: Record<string, string>;\n body: string;\n timeout: number;\n },\n ): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), options.timeout);\n\n try {\n const response = await fetch(url, {\n method: options.method,\n headers: options.headers,\n body: options.body,\n signal: controller.signal,\n });\n\n return response;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Delay utility for retry backoff\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * Webhook Plugin - Validation helpers and event constants.\n *\n * Extracted from webhook-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { PluginError, EXECUTION_EVENTS, EXECUTION_EVENT_PREFIX } from '@robota-sdk/agent-core';\nimport type { TWebhookEventName, IWebhookEndpoint } from './types';\n\n/** Local execution event names used by WebhookPlugin. @internal */\nexport const WEBHOOK_EXEC_EVENTS = {\n START: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.START}` as TWebhookEventName,\n COMPLETE: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.COMPLETE}` as TWebhookEventName,\n ERROR: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.ERROR}` as TWebhookEventName,\n} as const;\n\nexport const WEBHOOK_CONV_EVENTS = {\n COMPLETE: 'conversation.complete' as TWebhookEventName,\n} as const;\nexport const WEBHOOK_TOOL_EVENTS = { EXECUTED: 'tool.executed' as TWebhookEventName } as const;\nexport const WEBHOOK_ERROR_EVENTS = { OCCURRED: 'error.occurred' as TWebhookEventName } as const;\n\n/**\n * Validate all configured webhook endpoints. Throws PluginError for any\n * invalid URL or unsupported event name. @internal\n */\nexport function validateWebhookEndpoints(\n endpoints: IWebhookEndpoint[],\n pluginName: string,\n validEvents: TWebhookEventName[],\n): void {\n for (const endpoint of endpoints) {\n if (!endpoint.url) {\n throw new PluginError(`Webhook endpoint URL is required`, pluginName);\n }\n\n let parsed: URL;\n try {\n parsed = new URL(endpoint.url);\n } catch {\n throw new PluginError(`Invalid webhook URL: ${endpoint.url}`, pluginName);\n }\n\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new PluginError(\n `Webhook endpoint URL must use http or https: ${endpoint.url}`,\n pluginName,\n );\n }\n\n if (endpoint.events) {\n for (const event of endpoint.events) {\n if (!validEvents.includes(event)) {\n throw new PluginError(`Invalid webhook event: ${event}`, pluginName);\n }\n }\n }\n }\n}\n","/**\n * Webhook Plugin - Queue and batch management.\n *\n * Extracted from webhook-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { type ILogger, type TTimerId } from '@robota-sdk/agent-core';\nimport type {\n TWebhookEventName,\n IWebhookPayload,\n IWebhookEndpoint,\n IWebhookRequest,\n} from './types';\nimport { WebhookHttpClient } from './http-client';\n\n/** Manages the async request queue, batch queue, and concurrency for WebhookPlugin. @internal */\nexport class WebhookQueueManager {\n private requestQueue: IWebhookRequest[] = [];\n private batchQueue: IWebhookPayload[] = [];\n private batchTimer?: TTimerId;\n activeConcurrency = 0;\n totalSentCount = 0;\n totalErrorCount = 0;\n totalResponseTime = 0;\n\n constructor(\n private readonly logger: ILogger,\n private readonly httpClient: WebhookHttpClient,\n private readonly maxConcurrency: number,\n ) {}\n\n get queueLength(): number {\n return this.requestQueue.length;\n }\n\n get batchQueueLength(): number {\n return this.batchQueue.length;\n }\n\n setupBatching(\n flushInterval: number,\n getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[],\n ): void {\n this.batchTimer = setInterval(() => {\n this.drainBatch(getEndpoints);\n }, flushInterval);\n }\n\n async enqueueBatch(\n payload: IWebhookPayload,\n maxSize: number,\n getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[],\n ): Promise<void> {\n this.batchQueue.push(payload);\n if (this.batchQueue.length >= maxSize) {\n await this.drainBatch(getEndpoints);\n }\n }\n\n async sendToEndpoints(\n payload: IWebhookPayload,\n getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[],\n async_: boolean = true,\n ): Promise<void> {\n const endpoints = getEndpoints(payload.event);\n if (endpoints.length === 0) return;\n\n const requests: IWebhookRequest[] = endpoints.map((endpoint) => ({\n endpoint,\n payload,\n attempt: 1,\n timestamp: new Date(),\n }));\n\n if (async_) {\n this.requestQueue.push(...requests);\n this.processQueue();\n } else {\n await Promise.allSettled(\n requests.map((req) => {\n const startTime = Date.now();\n return this.httpClient\n .sendRequest(req)\n .then(() => {\n this.totalSentCount++;\n this.totalResponseTime += Date.now() - startTime;\n })\n .catch((error: unknown) => {\n this.totalErrorCount++;\n throw error;\n });\n }),\n );\n }\n }\n\n private processQueue(): void {\n while (this.requestQueue.length > 0 && this.activeConcurrency < this.maxConcurrency) {\n const request = this.requestQueue.shift();\n if (!request) break;\n\n this.activeConcurrency++;\n const startTime = Date.now();\n this.httpClient\n .sendRequest(request)\n .then(() => {\n this.totalSentCount++;\n this.totalResponseTime += Date.now() - startTime;\n })\n .catch((error: unknown) => {\n this.totalErrorCount++;\n const message = error instanceof Error ? error.message : String(error);\n this.logger.error('Webhook request failed', {\n endpoint: request.endpoint.url,\n event: request.payload.event,\n error: message,\n });\n })\n .finally(() => {\n this.activeConcurrency--;\n if (this.requestQueue.length > 0) this.processQueue();\n });\n }\n }\n\n async drainBatch(getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[]): Promise<void> {\n if (this.batchQueue.length === 0) return;\n const payloads = [...this.batchQueue];\n this.batchQueue = [];\n this.logger.debug('Flushing webhook batch', { payloadCount: payloads.length });\n for (const payload of payloads) {\n await this.sendToEndpoints(payload, getEndpoints);\n }\n }\n\n clearQueues(): void {\n this.requestQueue = [];\n this.batchQueue = [];\n }\n\n stopBatchTimer(): void {\n if (this.batchTimer) {\n clearInterval(this.batchTimer);\n this.batchTimer = undefined;\n }\n }\n}\n","/**\n * Webhook Plugin - Facade Pattern Implementation\n * Coordinates webhook functionality through clean, separated components\n */\n\nimport {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n type IPluginExecutionContext,\n type IPluginExecutionResult,\n type IPluginErrorContext,\n createLogger,\n type ILogger,\n PluginError,\n} from '@robota-sdk/agent-core';\n\nimport { WebhookTransformer } from './transformer';\nimport { WebhookHttpClient } from './http-client';\nimport {\n validateWebhookEndpoints,\n WEBHOOK_EXEC_EVENTS,\n WEBHOOK_CONV_EVENTS,\n WEBHOOK_TOOL_EVENTS,\n WEBHOOK_ERROR_EVENTS,\n} from './webhook-helpers';\nimport { WebhookQueueManager } from './webhook-queue';\nimport type {\n TWebhookEventName,\n IWebhookEventData,\n TWebhookMetadata,\n IWebhookPayload,\n IWebhookEndpoint,\n IWebhookPluginOptions,\n IWebhookPluginStats,\n} from './types';\n\n/**\n * Sends HTTP webhook notifications for agent execution lifecycle events.\n *\n * Routes events to configured {@link IWebhookEndpoint | endpoints} with\n * optional event filtering per endpoint. Supports asynchronous delivery with\n * configurable concurrency, automatic retries via {@link WebhookHttpClient},\n * and optional payload batching.\n *\n * Lifecycle hooks used: {@link AbstractPlugin.afterExecution | afterExecution},\n * {@link AbstractPlugin.afterConversation | afterConversation},\n * {@link AbstractPlugin.afterToolExecution | afterToolExecution},\n * {@link AbstractPlugin.onError | onError}\n *\n * @extends AbstractPlugin\n * @see IWebhookPluginOptions - configuration options\n * @see WebhookTransformer - payload transformation utilities\n * @see WebhookHttpClient - HTTP delivery client\n *\n * @example\n * ```ts\n * const plugin = new WebhookPlugin({\n * endpoints: [{ url: 'https://example.com/hook' }],\n * async: true,\n * maxConcurrency: 3,\n * });\n * ```\n */\nexport class WebhookPlugin extends AbstractPlugin<IWebhookPluginOptions, IWebhookPluginStats> {\n name = 'WebhookPlugin';\n version = '1.0.0';\n\n private pluginOptions: Required<IWebhookPluginOptions>;\n private logger: ILogger;\n private queue: WebhookQueueManager;\n\n constructor(options: IWebhookPluginOptions) {\n super();\n\n // Set plugin classification\n this.category = PluginCategory.NOTIFICATION;\n this.priority = PluginPriority.LOW;\n\n // Validate required options\n if (!options.endpoints || options.endpoints.length === 0) {\n throw new PluginError('At least one webhook endpoint is required', this.name);\n }\n\n // Set default options\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n events: [\n WEBHOOK_EXEC_EVENTS.COMPLETE,\n WEBHOOK_CONV_EVENTS.COMPLETE,\n WEBHOOK_TOOL_EVENTS.EXECUTED,\n WEBHOOK_ERROR_EVENTS.OCCURRED,\n ],\n defaultTimeout: 5000,\n defaultRetries: 3,\n async: true,\n maxConcurrency: 3,\n batching: {\n enabled: false,\n maxSize: 10,\n flushInterval: 5000,\n },\n payloadTransformer: WebhookTransformer.defaultPayloadTransformer,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.NOTIFICATION,\n priority: options.priority ?? PluginPriority.LOW,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n ...options,\n };\n\n this.logger = createLogger(`${this.name}`);\n const httpClient = new WebhookHttpClient(this.logger);\n this.queue = new WebhookQueueManager(\n this.logger,\n httpClient,\n this.pluginOptions.maxConcurrency,\n );\n\n validateWebhookEndpoints(this.pluginOptions.endpoints, this.name, [\n WEBHOOK_EXEC_EVENTS.START,\n WEBHOOK_EXEC_EVENTS.COMPLETE,\n WEBHOOK_EXEC_EVENTS.ERROR,\n WEBHOOK_CONV_EVENTS.COMPLETE,\n WEBHOOK_TOOL_EVENTS.EXECUTED,\n WEBHOOK_ERROR_EVENTS.OCCURRED,\n 'custom',\n ]);\n\n if (this.pluginOptions.batching.enabled) {\n this.queue.setupBatching(\n this.pluginOptions.batching.flushInterval,\n this.getEndpointsForEvent.bind(this),\n );\n }\n\n this.logger.info('WebhookPlugin initialized', {\n endpointCount: this.pluginOptions.endpoints.length,\n events: this.pluginOptions.events,\n batching: this.pluginOptions.batching.enabled,\n });\n }\n\n /**\n * Sends an execution-complete webhook after the agent finishes processing.\n */\n override async afterExecution(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n const webhookContext = WebhookTransformer.contextToWebhook(context);\n const webhookResult = WebhookTransformer.resultToWebhook(result);\n const eventData = WebhookTransformer.createExecutionData(webhookContext, webhookResult);\n await this.sendWebhook(WEBHOOK_EXEC_EVENTS.COMPLETE, eventData);\n }\n\n /**\n * Sends a conversation-complete webhook after a conversation round finishes.\n */\n override async afterConversation(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n const webhookContext = WebhookTransformer.contextToWebhook(context);\n const webhookResult = WebhookTransformer.resultToWebhook(result);\n const eventData = WebhookTransformer.createConversationData(webhookContext, webhookResult);\n await this.sendWebhook(WEBHOOK_CONV_EVENTS.COMPLETE, eventData);\n }\n\n /**\n * Sends a tool-executed webhook for each tool call in the result set.\n */\n override async afterToolExecution(\n context: IPluginExecutionContext,\n toolResults: IPluginExecutionResult,\n ): Promise<void> {\n const webhookContext = WebhookTransformer.contextToWebhook(context);\n if (toolResults.toolCalls && toolResults.toolCalls.length > 0) {\n for (const toolCall of toolResults.toolCalls) {\n const toolData = {\n toolName: toolCall.name || '',\n toolId: toolCall.id || '',\n result: toolCall.result,\n success: toolCall.result !== null,\n duration: toolResults.duration,\n };\n const eventData = WebhookTransformer.createToolData(webhookContext, toolData);\n await this.sendWebhook(WEBHOOK_TOOL_EVENTS.EXECUTED, eventData);\n }\n }\n }\n\n /**\n * Sends both an error-occurred and execution-error webhook on failure.\n */\n override async onError(error: Error, context?: IPluginErrorContext): Promise<void> {\n const webhookContext = context\n ? { executionId: context.executionId, sessionId: context.sessionId, userId: context.userId }\n : { executionId: undefined, sessionId: undefined, userId: undefined };\n const errorEventData = WebhookTransformer.createErrorData(webhookContext, error);\n await this.sendWebhook(WEBHOOK_ERROR_EVENTS.OCCURRED, errorEventData);\n await this.sendWebhook(WEBHOOK_EXEC_EVENTS.ERROR, errorEventData);\n }\n\n /**\n * Builds a webhook payload and delivers it to all matching endpoints. When\n * batching is enabled, payloads are queued and flushed at the configured interval.\n */\n async sendWebhook(\n event: TWebhookEventName,\n data: IWebhookEventData,\n metadata?: TWebhookMetadata,\n ): Promise<void> {\n if (!this.pluginOptions.events.includes(event)) return;\n\n const payload: IWebhookPayload = {\n event,\n timestamp: new Date().toISOString(),\n data: this.pluginOptions.payloadTransformer(event, data),\n ...(metadata && { metadata }),\n };\n if (data.executionId) payload.executionId = data.executionId;\n if (data.sessionId) payload.sessionId = data.sessionId;\n if (data.userId) payload.userId = data.userId;\n\n this.logger.debug('Sending webhook', {\n event,\n endpointCount: this.getEndpointsForEvent(event).length,\n });\n\n if (this.pluginOptions.batching.enabled) {\n await this.queue.enqueueBatch(\n payload,\n this.pluginOptions.batching.maxSize,\n this.getEndpointsForEvent.bind(this),\n );\n } else {\n await this.queue.sendToEndpoints(\n payload,\n this.getEndpointsForEvent.bind(this),\n this.pluginOptions.async,\n );\n }\n }\n\n /**\n * Sends a webhook with the `custom` event type.\n */\n async sendCustomWebhook(data: IWebhookEventData, metadata?: TWebhookMetadata): Promise<void> {\n await this.sendWebhook('custom', data, metadata);\n }\n\n /**\n * Get webhook plugin statistics\n */\n override getStats(): IWebhookPluginStats {\n const base = super.getStats();\n return {\n ...base,\n endpointCount: this.pluginOptions.endpoints.length,\n queueLength: this.queue.queueLength,\n batchQueueLength: this.queue.batchQueueLength,\n activeConcurrency: this.queue.activeConcurrency,\n supportedEvents: this.pluginOptions.events,\n totalSent: this.queue.totalSentCount,\n totalErrors: this.queue.totalErrorCount,\n averageResponseTime:\n this.queue.totalSentCount > 0\n ? this.queue.totalResponseTime / this.queue.totalSentCount\n : 0,\n };\n }\n\n /**\n * Clear webhook queue\n */\n clearQueue(): void {\n this.queue.clearQueues();\n this.logger.info('Webhook queues cleared');\n }\n\n /**\n * Flushes pending batches, clears request queues, and stops the batch timer.\n */\n async destroy(): Promise<void> {\n this.queue.stopBatchTimer();\n await this.queue.drainBatch(this.getEndpointsForEvent.bind(this));\n this.clearQueue();\n this.logger.info('WebhookPlugin destroyed');\n }\n\n private getEndpointsForEvent(event: TWebhookEventName): IWebhookEndpoint[] {\n return this.pluginOptions.endpoints.filter((endpoint) => {\n if (!endpoint.events || endpoint.events.length === 0) return true;\n return endpoint.events.includes(event);\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["DEFAULT_MAX_RETRIES","DEFAULT_MAX_ENTRIES","DEFAULT_PERFORMANCE_THRESHOLD_MS","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","DEFAULT_MAX_ENTRIES","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","DEFAULT_AGGREGATION_INTERVAL_MS"],"sources":["../../src/conversation-history/storages/memory-storage.ts","../../src/conversation-history/storages/file-storage.ts","../../src/conversation-history/storages/database-storage.ts","../../src/conversation-history/conversation-history-helpers.ts","../../src/conversation-history/conversation-history-plugin.ts","../../src/error-handling/context-adapter.ts","../../src/error-handling/error-handling-helpers.ts","../../src/error-handling/error-handling-plugin.ts","../../src/execution-analytics/analytics-aggregation.ts","../../src/execution-analytics/execution-analytics-helpers.ts","../../src/execution-analytics/execution-analytics-plugin.ts","../../src/limits/limits-helpers.ts","../../src/limits/validation.ts","../../src/limits/limits-plugin.ts","../../src/logging/formatters.ts","../../src/logging/storages/console-storage.ts","../../src/logging/storages/file-storage.ts","../../src/logging/storages/remote-storage.ts","../../src/logging/storages/silent-storage.ts","../../src/logging/logging-helpers.ts","../../src/logging/logging-plugin.ts","../../src/performance/collectors/system-metrics-collector.ts","../../src/performance/storages/memory-storage.ts","../../src/performance/performance-helpers.ts","../../src/performance/performance-plugin.ts","../../src/usage/aggregate-usage-stats.ts","../../src/usage/storages/memory-storage.ts","../../src/usage/storages/file-storage.ts","../../src/usage/storages/remote-storage.ts","../../src/usage/storages/silent-storage.ts","../../src/usage/usage-plugin-helpers.ts","../../src/usage/usage-plugin.ts","../../src/webhook/http-client.ts","../../src/webhook/transformer.ts","../../src/webhook/webhook-helpers.ts","../../src/webhook/webhook-queue.ts","../../src/webhook/webhook-plugin.ts"],"sourcesContent":["import type { IHistoryStorage, IConversationHistoryEntry } from '../types';\n\n/**\n * Memory storage implementation\n */\nexport class MemoryHistoryStorage implements IHistoryStorage {\n private conversations = new Map<string, IConversationHistoryEntry>();\n private maxConversations: number;\n\n constructor(maxConversations: number = 100) {\n this.maxConversations = maxConversations;\n }\n\n async save(conversationId: string, entry: IConversationHistoryEntry): Promise<void> {\n // Remove oldest conversation if limit exceeded\n if (\n this.conversations.size >= this.maxConversations &&\n !this.conversations.has(conversationId)\n ) {\n const oldestId = this.conversations.keys().next().value;\n if (oldestId) {\n this.conversations.delete(oldestId);\n }\n }\n\n this.conversations.set(conversationId, { ...entry });\n }\n\n async load(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n return this.conversations.get(conversationId);\n }\n\n async list(): Promise<string[]> {\n return Array.from(this.conversations.keys());\n }\n\n async delete(conversationId: string): Promise<boolean> {\n return this.conversations.delete(conversationId);\n }\n\n async clear(): Promise<void> {\n this.conversations.clear();\n }\n}\n","import { createLogger, type ILogger, StorageError } from '@robota-sdk/agent-core';\n\nimport type { IHistoryStorage, IConversationHistoryEntry } from '../types';\n\n/**\n * File storage implementation\n */\nexport class FileHistoryStorage implements IHistoryStorage {\n private filePath: string;\n private logger: ILogger;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n this.logger = createLogger('FileHistoryStorage');\n }\n\n async save(conversationId: string, _entry: IConversationHistoryEntry): Promise<void> {\n try {\n // File operations would be implemented here\n // This is a placeholder for actual file system operations\n this.logger.warn('File storage not fully implemented yet', {\n conversationId,\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to save conversation to file', {\n conversationId,\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async load(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n conversationId,\n filePath: this.filePath,\n });\n return undefined;\n } catch (error) {\n throw new StorageError('Failed to load conversation from file', {\n conversationId,\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async list(): Promise<string[]> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n filePath: this.filePath,\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to list conversations from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async delete(conversationId: string): Promise<boolean> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n conversationId,\n filePath: this.filePath,\n });\n return false;\n } catch (error) {\n throw new StorageError('Failed to delete conversation from file', {\n conversationId,\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // File operations would be implemented here\n this.logger.warn('File storage not fully implemented yet', {\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to clear conversations from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n","import { createLogger, type ILogger, StorageError } from '@robota-sdk/agent-core';\n\nimport type { IHistoryStorage, IConversationHistoryEntry } from '../types';\n\n/**\n * Database storage implementation\n */\nexport class DatabaseHistoryStorage implements IHistoryStorage {\n private connectionString: string;\n private logger: ILogger;\n\n constructor(connectionString: string) {\n this.connectionString = connectionString;\n this.logger = createLogger('DatabaseHistoryStorage');\n }\n\n async save(conversationId: string, _entry: IConversationHistoryEntry): Promise<void> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n conversationId,\n connectionString: this.maskConnectionString(),\n });\n } catch (error) {\n throw new StorageError('Failed to save conversation to database', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async load(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n conversationId,\n connectionString: this.maskConnectionString(),\n });\n return undefined;\n } catch (error) {\n throw new StorageError('Failed to load conversation from database', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async list(): Promise<string[]> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n connectionString: this.maskConnectionString(),\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to list conversations from database', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async delete(conversationId: string): Promise<boolean> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n conversationId,\n connectionString: this.maskConnectionString(),\n });\n return false;\n } catch (error) {\n throw new StorageError('Failed to delete conversation from database', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // Database operations would be implemented here\n this.logger.warn('Database storage not fully implemented yet', {\n connectionString: this.maskConnectionString(),\n });\n } catch (error) {\n throw new StorageError('Failed to clear conversations from database', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Mask sensitive information in connection string for logging\n */\n private maskConnectionString(): string {\n return this.connectionString.replace(/(:\\/\\/[^:]+:)[^@]+(@)/, '$1***$2');\n }\n}\n","/**\n * Conversation History Plugin - Validation and storage factory helpers.\n *\n * Extracted from conversation-history-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError, PluginError, type ILogger } from '@robota-sdk/agent-core';\n\nimport { MemoryHistoryStorage, FileHistoryStorage, DatabaseHistoryStorage } from './storages/index';\n\nimport type {\n IConversationHistoryPluginOptions,\n IHistoryStorage,\n IConversationHistoryEntry,\n} from './types';\n\n/** Validate ConversationHistoryPlugin constructor options. @internal */\nexport function validateConversationHistoryOptions(\n options: IConversationHistoryPluginOptions,\n): void {\n if (!options.storage) {\n throw new ConfigurationError('Storage strategy is required');\n }\n\n if (!['memory', 'file', 'database'].includes(options.storage)) {\n throw new ConfigurationError('Invalid storage strategy', {\n validStrategies: ['memory', 'file', 'database'],\n provided: options.storage,\n });\n }\n\n if (options.storage === 'file' && !options.filePath) {\n throw new ConfigurationError('File path is required for file storage strategy');\n }\n\n if (options.storage === 'database' && !options.connectionString) {\n throw new ConfigurationError('Connection string is required for database storage strategy');\n }\n\n if (options.maxConversations !== undefined && options.maxConversations <= 0) {\n throw new ConfigurationError('Max conversations must be positive');\n }\n\n if (options.maxMessagesPerConversation !== undefined && options.maxMessagesPerConversation <= 0) {\n throw new ConfigurationError('Max messages per conversation must be positive');\n }\n}\n\n/**\n * Load a conversation entry from storage with error wrapping. @internal\n */\nexport async function loadConversationEntry(\n storage: IHistoryStorage,\n conversationId: string,\n pluginName: string,\n logger: ILogger,\n): Promise<IConversationHistoryEntry | undefined> {\n try {\n const entry = await storage.load(conversationId);\n logger.debug('Loaded conversation', {\n conversationId,\n found: !!entry,\n messageCount: entry?.messages.length ?? 0,\n });\n return entry;\n } catch (error) {\n throw new PluginError('Failed to load conversation', pluginName, {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\n/**\n * Flush all pending conversation saves to storage, logging individual failures. @internal\n */\nexport async function savePendingConversations(\n storage: IHistoryStorage,\n pendingSaves: Set<string>,\n pluginName: string,\n logger: ILogger,\n): Promise<void> {\n if (pendingSaves.size === 0) return;\n\n const conversationIds = Array.from(pendingSaves);\n logger.debug('Saving pending conversations', { count: conversationIds.length });\n\n for (const conversationId of conversationIds) {\n try {\n const entry = await storage.load(conversationId);\n if (entry) {\n await storage.save(conversationId, entry);\n }\n pendingSaves.delete(conversationId);\n } catch (error) {\n logger.error('Failed to save pending conversation', {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n\n/** Create IHistoryStorage instance for the given strategy. @internal */\nexport function createHistoryStorage(\n strategy: string,\n maxConversations: number,\n filePath: string,\n connectionString: string,\n): IHistoryStorage {\n switch (strategy) {\n case 'memory':\n return new MemoryHistoryStorage(maxConversations);\n case 'file':\n return new FileHistoryStorage(filePath);\n case 'database':\n return new DatabaseHistoryStorage(connectionString);\n default:\n throw new ConfigurationError('Unknown storage strategy', { strategy });\n }\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n type TUniversalMessage,\n createLogger,\n type ILogger,\n PluginError,\n type TTimerId,\n startPeriodicTask,\n stopPeriodicTask,\n} from '@robota-sdk/agent-core';\n\nimport {\n validateConversationHistoryOptions,\n createHistoryStorage,\n loadConversationEntry,\n savePendingConversations,\n} from './conversation-history-helpers';\n\nimport type {\n IConversationHistoryPluginOptions,\n IConversationHistoryPluginStats,\n IConversationHistoryEntry,\n IHistoryStorage,\n} from './types';\n\nconst DEFAULT_MAX_CONVERSATIONS = 100;\nconst DEFAULT_MAX_MESSAGES = 1000;\nconst DEFAULT_SAVE_INTERVAL_MS = 30000;\n\n/**\n * Persists conversation history using configurable storage backends.\n *\n * Supports memory, file, and database storage strategies. Messages are\n * automatically trimmed to {@link IConversationHistoryPluginOptions.maxMessagesPerConversation | maxMessagesPerConversation}.\n * When {@link IConversationHistoryPluginOptions.autoSave | autoSave} is\n * disabled, changes are batched and flushed on a timer.\n *\n * @extends AbstractPlugin\n * @see IHistoryStorage - storage backend contract\n * @see IConversationHistoryPluginOptions - configuration options\n *\n * @example\n * ```ts\n * const plugin = new ConversationHistoryPlugin({\n * storage: 'memory',\n * maxMessagesPerConversation: 500,\n * });\n * await plugin.startConversation('conv-1');\n * await plugin.addMessage({ role: 'user', content: 'Hello' });\n * ```\n */\nexport class ConversationHistoryPlugin extends AbstractPlugin<\n IConversationHistoryPluginOptions,\n IConversationHistoryPluginStats\n> {\n name = 'ConversationHistoryPlugin';\n version = '1.0.0';\n\n private storage: IHistoryStorage;\n private pluginOptions: Required<IConversationHistoryPluginOptions>;\n private logger: ILogger;\n private currentConversationId?: string;\n private batchSaveTimer?: TTimerId;\n private pendingSaves = new Set<string>();\n\n constructor(options: IConversationHistoryPluginOptions) {\n super();\n this.logger = createLogger('ConversationHistoryPlugin');\n\n // Set plugin classification\n this.category = PluginCategory.STORAGE;\n this.priority = PluginPriority.HIGH;\n\n // Validate options\n validateConversationHistoryOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n storage: options.storage,\n maxConversations: options.maxConversations ?? DEFAULT_MAX_CONVERSATIONS,\n maxMessagesPerConversation: options.maxMessagesPerConversation ?? DEFAULT_MAX_MESSAGES,\n filePath: options.filePath ?? './conversations.json',\n connectionString: options.connectionString ?? '',\n autoSave: options.autoSave ?? true,\n saveInterval: options.saveInterval ?? DEFAULT_SAVE_INTERVAL_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.STORAGE,\n priority: options.priority ?? PluginPriority.HIGH,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n\n // Initialize storage\n this.storage = createHistoryStorage(\n this.pluginOptions.storage,\n this.pluginOptions.maxConversations,\n this.pluginOptions.filePath,\n this.pluginOptions.connectionString,\n );\n\n // Setup batch saving if not auto-saving\n if (!this.pluginOptions.autoSave) {\n this.setupBatchSaving();\n }\n\n this.logger.info('ConversationHistoryPlugin initialized', {\n storage: this.pluginOptions.storage,\n maxConversations: this.pluginOptions.maxConversations,\n autoSave: this.pluginOptions.autoSave,\n });\n }\n\n /**\n * Creates a new conversation entry and persists it (or queues for batch save).\n * @throws PluginError if the storage write fails\n */\n async startConversation(conversationId: string): Promise<void> {\n try {\n this.currentConversationId = conversationId;\n\n const entry: IConversationHistoryEntry = {\n conversationId,\n messages: [],\n startTime: new Date(),\n lastUpdated: new Date(),\n metadata: {},\n };\n\n // Always persist the initial entry so subsequent loads can find it.\n // autoSave=false only means we track the id for deferred external flush via savePending.\n await this.storage.save(conversationId, entry);\n if (!this.pluginOptions.autoSave) {\n this.pendingSaves.add(conversationId);\n }\n\n this.logger.debug('Started new conversation', { conversationId });\n } catch (error) {\n throw new PluginError('Failed to start conversation', this.name, {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Appends a message to the active conversation, trimming to the maximum\n * message limit if exceeded.\n * @throws PluginError if no conversation is active or the storage write fails\n */\n async addMessage(message: TUniversalMessage): Promise<void> {\n if (!this.currentConversationId) {\n throw new PluginError('No active conversation', this.name);\n }\n\n try {\n const entry = (await this.storage.load(this.currentConversationId)) || {\n conversationId: this.currentConversationId,\n messages: [],\n startTime: new Date(),\n lastUpdated: new Date(),\n metadata: {},\n };\n\n // Add message and trim if necessary\n entry.messages.push(message);\n if (entry.messages.length > this.pluginOptions.maxMessagesPerConversation) {\n entry.messages = entry.messages.slice(-this.pluginOptions.maxMessagesPerConversation);\n }\n entry.lastUpdated = new Date();\n\n // Always persist the updated entry. autoSave=false tracks it as pending\n // for deferred external flush via savePending.\n await this.storage.save(this.currentConversationId, entry);\n if (!this.pluginOptions.autoSave) {\n this.pendingSaves.add(this.currentConversationId);\n }\n\n this.logger.debug('Added message to conversation', {\n conversationId: this.currentConversationId,\n messageRole: message.role,\n messageLength: message.content?.length ?? 0,\n });\n } catch (error) {\n throw new PluginError('Failed to add message to conversation', this.name, {\n conversationId: this.currentConversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Load conversation history\n */\n async loadConversation(conversationId: string): Promise<IConversationHistoryEntry | undefined> {\n return loadConversationEntry(this.storage, conversationId, this.name, this.logger);\n }\n\n /**\n * Get conversation history as messages\n */\n async getHistory(conversationId: string): Promise<TUniversalMessage[]> {\n const entry = await this.loadConversation(conversationId);\n return entry?.messages ?? [];\n }\n\n /**\n * List all conversation IDs\n */\n async listConversations(): Promise<string[]> {\n try {\n return await this.storage.list();\n } catch (error) {\n throw new PluginError('Failed to list conversations', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Delete a conversation\n */\n async deleteConversation(conversationId: string): Promise<boolean> {\n try {\n const deleted = await this.storage.delete(conversationId);\n this.pendingSaves.delete(conversationId);\n this.logger.debug('Deleted conversation', { conversationId, deleted });\n return deleted;\n } catch (error) {\n throw new PluginError('Failed to delete conversation', this.name, {\n conversationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Clear all conversations\n */\n async clearAllConversations(): Promise<void> {\n try {\n await this.storage.clear();\n this.pendingSaves.clear();\n this.logger.info('Cleared all conversations');\n } catch (error) {\n throw new PluginError('Failed to clear conversations', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Persists all conversations queued since the last save (batch mode only).\n * Individual save failures are logged but do not abort the remaining saves.\n */\n async savePending(): Promise<void> {\n await savePendingConversations(this.storage, this.pendingSaves, this.name, this.logger);\n }\n\n /**\n * Stops the batch-save timer and flushes any pending conversation saves.\n */\n async destroy(): Promise<void> {\n try {\n stopPeriodicTask(this.batchSaveTimer);\n this.batchSaveTimer = undefined;\n\n // Save any pending conversations\n await this.savePending();\n\n this.logger.info('ConversationHistoryPlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Setup batch saving timer\n */\n private setupBatchSaving(): void {\n this.batchSaveTimer = startPeriodicTask(\n this.logger,\n {\n name: 'ConversationHistoryPlugin.savePending',\n intervalMs: this.pluginOptions.saveInterval,\n },\n async () => {\n await this.savePending();\n },\n );\n }\n}\n","/**\n * ErrorHandling Plugin - Context adapter utilities for Facade pattern\n *\n * REASON: TypeScript exactOptionalPropertyTypes strict mode requires special handling for optional properties\n * ALTERNATIVES_CONSIDERED: Bracket notation (rejected by TS), type assertions (rejected), interface modification (breaks compatibility), union types (causes dependencies), removing context (loses debugging)\n * TODO: Consider unified error context type system across all plugins\n */\n\nimport type { IErrorHandlingContextData, IErrorContextAdapter } from './types';\nimport type { TErrorContextData } from '@robota-sdk/agent-core';\n\n/**\n * Convert IErrorHandlingContextData to ErrorContextData-compatible format for PluginError\n * REASON: Simple object spread with known properties to avoid index signature conflicts\n * ALTERNATIVES_CONSIDERED: Complex type adapters (unnecessary), Object.assign (verbose), bracket notation (rejected by TS), type assertions (reduces safety)\n * TODO: Consider unified error context type system across all plugins\n */\nexport function toErrorContext(context: IErrorHandlingContextData): IErrorContextAdapter {\n return {\n ...(context.executionId && { executionId: context.executionId }),\n ...(context.sessionId && { sessionId: context.sessionId }),\n ...(context.userId && { userId: context.userId }),\n ...(context.attempt !== undefined && { attempt: context.attempt }),\n ...(context.originalError && { originalError: context.originalError }),\n };\n}\n\n/**\n * Safe context extraction for PluginError with nested context structure\n *\n * REASON: PluginError context needs flexible data structure for debugging information\n * ALTERNATIVES_CONSIDERED:\n * 1. Strict primitive types (loses debugging information)\n * 2. Interface definitions (too rigid for error contexts)\n * 3. Union types (becomes unwieldy for error data)\n * 4. Generic constraints (too complex for error handling)\n * 5. Type assertions (decreases type safety)\n * TODO: Consider standardized error context interface if patterns emerge\n */\nexport function createPluginErrorContext(\n context: IErrorHandlingContextData,\n additionalData?: TErrorContextData,\n): TErrorContextData {\n return {\n ...toErrorContext(context),\n ...(additionalData && { ...additionalData }),\n };\n}\n","/**\n * Error Handling Plugin - Validation and strategy handler helpers.\n *\n * Extracted from error-handling-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError } from '@robota-sdk/agent-core';\n\nimport type { IErrorHandlingPluginOptions } from './types';\n\n/** Validate ErrorHandlingPlugin constructor options. @internal */\nexport function validateErrorHandlingOptions(options: IErrorHandlingPluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Error handling strategy is required');\n }\n\n if (!['simple', 'circuit-breaker', 'exponential-backoff', 'silent'].includes(options.strategy)) {\n throw new ConfigurationError('Invalid error handling strategy', {\n validStrategies: ['simple', 'circuit-breaker', 'exponential-backoff', 'silent'],\n provided: options.strategy,\n });\n }\n\n if (options.maxRetries !== undefined && options.maxRetries < 0) {\n throw new ConfigurationError('Max retries must be non-negative');\n }\n\n if (options.retryDelay !== undefined && options.retryDelay <= 0) {\n throw new ConfigurationError('Retry delay must be positive');\n }\n}\n\n/** Resolve retry delay based on strategy and attempt number. @internal */\nexport function resolveRetryDelay(strategy: string, baseDelay: number, attempt: number): number {\n return strategy === 'exponential-backoff' ? baseDelay * Math.pow(2, attempt - 1) : baseDelay;\n}\n\n/** Resolve true if the circuit breaker timeout has not yet elapsed. @internal */\nexport function isCircuitBreakerStillOpen(\n circuitBreakerOpen: boolean,\n lastFailureTime: number,\n circuitBreakerTimeout: number,\n): { open: boolean; shouldReset: boolean } {\n if (!circuitBreakerOpen) return { open: false, shouldReset: false };\n const timeoutPassed = Date.now() - lastFailureTime > circuitBreakerTimeout;\n if (timeoutPassed) return { open: false, shouldReset: true };\n return { open: true, shouldReset: false };\n}\n\n/** Sleep for a given number of milliseconds. @internal */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n PluginError,\n} from '@robota-sdk/agent-core';\n\n// Import from Facade pattern modules for type safety\nimport { toErrorContext, createPluginErrorContext } from './context-adapter';\nimport {\n validateErrorHandlingOptions,\n resolveRetryDelay,\n isCircuitBreakerStillOpen,\n sleep,\n} from './error-handling-helpers';\n\nimport type {\n IErrorHandlingContextData,\n IErrorHandlingPluginOptions,\n IErrorHandlingPluginStats,\n} from './types';\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_DELAY_MS = 1000;\nconst DEFAULT_FAILURE_THRESHOLD = 5;\nconst DEFAULT_CIRCUIT_BREAKER_TIMEOUT_MS = 60000;\n\n/**\n * Provides configurable error recovery using one of four strategies:\n * simple logging, circuit breaker, exponential backoff, or silent.\n *\n * The circuit breaker opens after\n * {@link IErrorHandlingPluginOptions.failureThreshold | failureThreshold}\n * consecutive failures and automatically resets after\n * {@link IErrorHandlingPluginOptions.circuitBreakerTimeout | circuitBreakerTimeout} ms.\n * An optional custom error handler can be injected for application-specific\n * recovery logic.\n *\n * @extends AbstractPlugin\n * @see IErrorHandlingPluginOptions - configuration options\n * @see IErrorHandlingContextData - error context contract\n *\n * @example\n * ```ts\n * const plugin = new ErrorHandlingPlugin({\n * strategy: 'circuit-breaker',\n * failureThreshold: 5,\n * circuitBreakerTimeout: 60000,\n * });\n * const result = await plugin.executeWithRetry(() => fetchData());\n * ```\n */\nexport class ErrorHandlingPlugin extends AbstractPlugin<\n IErrorHandlingPluginOptions,\n IErrorHandlingPluginStats\n> {\n name = 'ErrorHandlingPlugin';\n version = '1.0.0';\n\n private pluginOptions: Required<Omit<IErrorHandlingPluginOptions, 'customErrorHandler'>> & {\n customErrorHandler?: (error: Error, context: IErrorHandlingContextData) => Promise<void>;\n };\n private logger: ILogger;\n private failureCount = 0;\n private circuitBreakerOpen = false;\n private lastFailureTime = 0;\n\n constructor(options: IErrorHandlingPluginOptions) {\n super();\n this.logger = createLogger('ErrorHandlingPlugin');\n\n // Validate options\n validateErrorHandlingOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n retryDelay: options.retryDelay ?? DEFAULT_RETRY_DELAY_MS,\n logErrors: options.logErrors ?? true,\n failureThreshold: options.failureThreshold ?? DEFAULT_FAILURE_THRESHOLD,\n circuitBreakerTimeout: options.circuitBreakerTimeout ?? DEFAULT_CIRCUIT_BREAKER_TIMEOUT_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.ERROR_HANDLING,\n priority: options.priority ?? PluginPriority.HIGH,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n ...(options.customErrorHandler && { customErrorHandler: options.customErrorHandler }),\n };\n\n this.logger.info('ErrorHandlingPlugin initialized', {\n strategy: this.pluginOptions.strategy,\n maxRetries: this.pluginOptions.maxRetries,\n failureThreshold: this.pluginOptions.failureThreshold,\n });\n }\n\n /**\n * Dispatches the error to the active strategy handler. If a custom error\n * handler is configured, it takes precedence over strategy-specific handling.\n */\n async handleError(error: Error, context: IErrorHandlingContextData = {}): Promise<void> {\n if (this.pluginOptions.logErrors) {\n this.logger.error('Error occurred', {\n error: error.message,\n stack: error.stack,\n context,\n });\n }\n\n // Custom error handler takes precedence\n if (this.pluginOptions.customErrorHandler) {\n try {\n await this.pluginOptions.customErrorHandler(error, context);\n return;\n } catch (handlerError) {\n this.logger.error('Custom error handler failed', {\n handlerError: handlerError instanceof Error ? handlerError.message : String(handlerError),\n });\n }\n }\n\n // Apply strategy-specific handling\n switch (this.pluginOptions.strategy) {\n case 'circuit-breaker':\n await this.handleCircuitBreaker(error, context);\n break;\n case 'exponential-backoff':\n await this.handleExponentialBackoff(error, context);\n break;\n case 'simple':\n await this.handleSimple(error, context);\n break;\n case 'silent':\n // Silent mode - do nothing\n break;\n }\n }\n\n /**\n * Executes a function with automatic retries up to\n * {@link IErrorHandlingPluginOptions.maxRetries | maxRetries}. The delay\n * between retries follows the configured strategy (fixed for simple /\n * circuit-breaker, doubling for exponential-backoff).\n *\n * @throws PluginError after all retry attempts are exhausted\n */\n async executeWithRetry<T>(\n fn: () => Promise<T>,\n context: IErrorHandlingContextData = {},\n ): Promise<T> {\n let lastError: Error | undefined;\n let attempt = 0;\n\n while (attempt <= this.pluginOptions.maxRetries) {\n try {\n // Check circuit breaker\n if (this.pluginOptions.strategy === 'circuit-breaker') {\n const cbState = isCircuitBreakerStillOpen(\n this.circuitBreakerOpen,\n this.lastFailureTime,\n this.pluginOptions.circuitBreakerTimeout,\n );\n if (cbState.shouldReset) {\n this.circuitBreakerOpen = false;\n this.failureCount = 0;\n this.logger.info('Circuit breaker timeout passed, attempting to close');\n }\n if (cbState.open) {\n throw new PluginError('Circuit breaker is open', this.name, toErrorContext(context));\n }\n }\n\n const result = await fn();\n\n // Reset failure count on success\n if (attempt > 0) {\n this.failureCount = 0;\n this.circuitBreakerOpen = false;\n this.logger.info('Operation succeeded after retry', {\n attempt,\n context,\n });\n }\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n attempt++;\n\n if (attempt <= this.pluginOptions.maxRetries) {\n await this.handleError(lastError, { ...context, attempt });\n\n // Calculate delay\n const delay = resolveRetryDelay(\n this.pluginOptions.strategy,\n this.pluginOptions.retryDelay,\n attempt,\n );\n\n this.logger.debug('Retrying operation', {\n attempt,\n delay,\n context,\n });\n await sleep(delay);\n } else {\n await this.handleError(lastError, { ...context, finalAttempt: true });\n }\n }\n }\n\n throw new PluginError(\n `Operation failed after ${this.pluginOptions.maxRetries} retries`,\n this.name,\n createPluginErrorContext(context, {\n originalError: lastError?.message || 'Unknown error',\n }),\n );\n }\n\n /**\n * Resets the circuit breaker to closed state, clearing failure count and\n * last failure timestamp.\n */\n resetCircuitBreaker(): void {\n this.failureCount = 0;\n this.circuitBreakerOpen = false;\n this.lastFailureTime = 0;\n this.logger.info('Circuit breaker reset');\n }\n\n /**\n * Get error handling statistics\n */\n override getStats(): IErrorHandlingPluginStats {\n const base = super.getStats();\n return {\n ...base,\n failureCount: this.failureCount,\n circuitBreakerOpen: this.circuitBreakerOpen,\n lastFailureTime: this.lastFailureTime,\n totalRetries: 0, // TODO: Track total retries\n successfulRecoveries: 0, // TODO: Track successful recoveries\n };\n }\n\n /**\n * Cleanup resources\n */\n async destroy(): Promise<void> {\n this.logger.info('ErrorHandlingPlugin destroyed');\n }\n\n private async handleSimple(error: Error, context: IErrorHandlingContextData): Promise<void> {\n // Simple logging - no additional logic\n this.logger.debug('Simple error handling applied', {\n error: error.message,\n context,\n });\n }\n\n private async handleCircuitBreaker(\n _error: Error,\n context: IErrorHandlingContextData,\n ): Promise<void> {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.failureCount >= this.pluginOptions.failureThreshold) {\n this.circuitBreakerOpen = true;\n this.logger.warn('Circuit breaker opened', {\n failureCount: this.failureCount,\n threshold: this.pluginOptions.failureThreshold,\n context,\n });\n }\n }\n\n private async handleExponentialBackoff(\n _error: Error,\n context: IErrorHandlingContextData,\n ): Promise<void> {\n this.failureCount++;\n this.logger.debug('Exponential backoff error handling applied', {\n error: _error.message,\n failureCount: this.failureCount,\n context,\n });\n }\n}\n","/**\n * Stats aggregation logic for ExecutionAnalyticsPlugin.\n *\n * Extracted from execution-analytics-plugin.ts to keep each file under 300 lines.\n * @internal\n */\nimport type { IExecutionStats, IAggregatedExecutionStats } from './types';\n\n/** Compute aggregated analytics across recorded executions. @internal */\nexport function aggregateExecutionStats(\n stats: IExecutionStats[],\n timeRange?: { start: Date; end: Date },\n): IAggregatedExecutionStats {\n if (stats.length === 0) {\n return {\n totalExecutions: 0,\n successfulExecutions: 0,\n failedExecutions: 0,\n successRate: 0,\n averageDuration: 0,\n totalDuration: 0,\n operationStats: {},\n errorStats: {},\n timeRange: timeRange || { start: new Date(), end: new Date() },\n };\n }\n\n const totalExecutions = stats.length;\n const successfulExecutions = stats.filter((s) => s.success).length;\n const failedExecutions = totalExecutions - successfulExecutions;\n const totalDuration = stats.reduce((sum, s) => sum + s.duration, 0);\n const averageDuration = totalDuration / totalExecutions;\n\n const operationStats: Record<\n string,\n {\n count: number;\n successCount: number;\n failureCount: number;\n totalDuration: number;\n averageDuration: number;\n }\n > = {};\n\n for (const stat of stats) {\n if (!operationStats[stat.operation]) {\n operationStats[stat.operation] = {\n count: 0,\n successCount: 0,\n failureCount: 0,\n totalDuration: 0,\n averageDuration: 0,\n };\n }\n const opStat = operationStats[stat.operation];\n if (opStat) {\n opStat.count++;\n opStat.totalDuration += stat.duration;\n if (stat.success) opStat.successCount++;\n else opStat.failureCount++;\n }\n }\n for (const op in operationStats) {\n const opStat = operationStats[op];\n if (opStat && opStat.count > 0) opStat.averageDuration = opStat.totalDuration / opStat.count;\n }\n\n const errorStats: Record<string, number> = {};\n for (const stat of stats.filter((s) => !s.success && s.error)) {\n const errorType = stat.error!.type;\n errorStats[errorType] = (errorStats[errorType] || 0) + 1;\n }\n\n return {\n totalExecutions,\n successfulExecutions,\n failedExecutions,\n successRate: totalExecutions > 0 ? successfulExecutions / totalExecutions : 0,\n averageDuration,\n totalDuration,\n operationStats,\n errorStats,\n timeRange: timeRange || {\n start: stats[0]?.startTime || new Date(),\n end: stats[stats.length - 1]?.endTime || new Date(),\n },\n };\n}\n","/**\n * Execution Analytics Plugin - Validation and utility helpers.\n *\n * Extracted from execution-analytics-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport type { IExecutionAnalyticsOptions, IExecutionStats } from './types';\n\n/**\n * Validate and sanitize ExecutionAnalyticsPlugin options in-place.\n * Invalid numeric values are reset to safe defaults. @internal\n */\nexport function validateExecutionAnalyticsOptions(\n options: IExecutionAnalyticsOptions,\n pluginOptions: { maxEntries: number; performanceThreshold: number },\n): void {\n if (options.maxEntries !== undefined && options.maxEntries < 1) {\n pluginOptions.maxEntries = 1000;\n }\n if (options.performanceThreshold !== undefined && options.performanceThreshold < 0) {\n pluginOptions.performanceThreshold = 5000;\n }\n}\n\n/** Generate a unique execution ID with an optional prefix. @internal */\nexport function generateExecutionId(prefix: string, counter: number): string {\n return `${prefix}-${Date.now()}-${counter}`;\n}\n\n/**\n * Build an IExecutionStats record for an error event. @internal\n */\nexport function buildErrorExecutionStats(\n executionId: string,\n executionData: { startTime: number; operation: string },\n error: Error,\n trackErrors: boolean,\n context?: { action?: string; tool?: string; attempt?: number },\n): IExecutionStats {\n const duration = Date.now() - executionData.startTime;\n const errorInfo = trackErrors\n ? {\n message: error.message,\n ...(error.stack && { stack: error.stack }),\n type: error.constructor.name,\n }\n : undefined;\n return {\n executionId,\n operation: executionData.operation,\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success: false,\n ...(errorInfo && { error: errorInfo }),\n metadata: {\n errorSource: 'onError-hook',\n contextType: context ? typeof context : 'none',\n hasContext: !!context,\n },\n };\n}\n\n/** Find the first active execution matching the given operation (and optionally the input). @internal */\nexport function findActiveExecution(\n activeExecutions: Map<string, { startTime: number; operation: string; input?: string }>,\n operation: string,\n input?: string,\n):\n | {\n executionId: string;\n executionData: { startTime: number; operation: string; input?: string };\n }\n | undefined {\n for (const [executionId, executionData] of activeExecutions.entries()) {\n if (executionData.operation === operation) {\n if (operation === 'run' && input && executionData.input !== input) continue;\n return { executionId, executionData };\n }\n }\n return undefined;\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n type IPluginErrorContext,\n createLogger,\n type ILogger,\n type IRunOptions,\n type TUniversalMessage,\n isAssistantMessage,\n type TToolParameters,\n type IToolExecutionResult,\n} from '@robota-sdk/agent-core';\n\nimport { aggregateExecutionStats } from './analytics-aggregation';\nimport {\n validateExecutionAnalyticsOptions,\n generateExecutionId,\n findActiveExecution,\n buildErrorExecutionStats,\n} from './execution-analytics-helpers';\n\nimport type {\n IExecutionStats,\n IAggregatedExecutionStats,\n IExecutionAnalyticsOptions,\n IExecutionAnalyticsPluginStats,\n} from './types';\n\nconst DEFAULT_MAX_ENTRIES = 1000;\nconst DEFAULT_PERFORMANCE_THRESHOLD_MS = 5000;\nconst PREVIEW_LENGTH = 100;\n\n/**\n * Tracks timing and success/failure of agent runs, provider calls, and tool executions.\n * @extends AbstractPlugin\n */\nexport class ExecutionAnalyticsPlugin extends AbstractPlugin<\n IExecutionAnalyticsOptions,\n IExecutionAnalyticsPluginStats\n> {\n name = 'ExecutionAnalyticsPlugin';\n version = '1.0.0';\n\n private pluginOptions: Required<IExecutionAnalyticsOptions>;\n private logger: ILogger;\n private activeExecutions: Map<string, { startTime: number; operation: string; input?: string }> =\n new Map();\n private executionHistory: IExecutionStats[] = [];\n private executionCounter = 0;\n private initialized = false;\n\n constructor(options: IExecutionAnalyticsOptions = {}) {\n super();\n this.category = PluginCategory.MONITORING;\n this.priority = PluginPriority.NORMAL;\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n maxEntries: options.maxEntries || DEFAULT_MAX_ENTRIES,\n trackErrors: options.trackErrors ?? true,\n performanceThreshold: options.performanceThreshold || DEFAULT_PERFORMANCE_THRESHOLD_MS,\n enableWarnings: options.enableWarnings ?? true,\n category: options.category ?? PluginCategory.MONITORING,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n validateExecutionAnalyticsOptions(options, this.pluginOptions);\n this.logger = createLogger('ExecutionAnalyticsPlugin');\n this.beforeRun = this.beforeRun.bind(this);\n this.afterRun = this.afterRun.bind(this);\n this.beforeProviderCall = this.beforeProviderCall.bind(this);\n this.afterProviderCall = this.afterProviderCall.bind(this);\n this.initialized = true;\n }\n\n override beforeRun = async (input: string, _options?: IRunOptions): Promise<void> => {\n this.activeExecutions.set(generateExecutionId('exec', ++this.executionCounter), {\n startTime: Date.now(),\n operation: 'run',\n input: input.substring(0, PREVIEW_LENGTH),\n });\n };\n\n override afterRun = async (\n input: string,\n response: string,\n options?: IRunOptions,\n ): Promise<void> => {\n const execution = findActiveExecution(this.activeExecutions, 'run', input);\n if (!execution) return;\n const { executionId, executionData } = execution;\n const duration = Date.now() - executionData.startTime;\n this.recordStats({\n executionId,\n operation: 'run',\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success: true,\n metadata: {\n inputLength: input.length,\n responseLength: response.length,\n hasOptions: !!options,\n modelName: String(options?.metadata?.['model'] || 'unknown'),\n },\n });\n this.activeExecutions.delete(executionId);\n if (this.pluginOptions.enableWarnings && duration > this.pluginOptions.performanceThreshold) {\n this.logger.warn('Slow run execution detected', {\n executionId,\n duration,\n threshold: this.pluginOptions.performanceThreshold,\n });\n }\n };\n\n override beforeProviderCall = async (messages: TUniversalMessage[]): Promise<void> => {\n this.activeExecutions.set(generateExecutionId('provider', ++this.executionCounter), {\n startTime: Date.now(),\n operation: 'provider-call',\n input: messages[0]?.content || 'N/A',\n });\n };\n\n override afterProviderCall = async (\n messages: TUniversalMessage[],\n response: TUniversalMessage,\n ): Promise<void> => {\n const execution = findActiveExecution(\n this.activeExecutions,\n 'provider-call',\n messages[0]?.content || '',\n );\n if (!execution) return;\n const { executionId, executionData } = execution;\n const duration = Date.now() - executionData.startTime;\n this.recordStats({\n executionId,\n operation: 'provider-call',\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success: true,\n metadata: {\n inputLength: messages[0]?.content?.length || 0,\n responseLength: response.content?.length || 0,\n hasToolCalls: !!(\n isAssistantMessage(response) &&\n response.toolCalls &&\n response.toolCalls.length > 0\n ),\n toolCallCount:\n isAssistantMessage(response) && response.toolCalls ? response.toolCalls.length : 0,\n },\n });\n this.activeExecutions.delete(executionId);\n if (this.pluginOptions.enableWarnings && duration > this.pluginOptions.performanceThreshold) {\n this.logger.warn('Slow provider call detected', {\n executionId,\n duration,\n threshold: this.pluginOptions.performanceThreshold,\n });\n }\n };\n\n override async beforeToolCall(toolName: string, _parameters: TToolParameters): Promise<void> {\n this.activeExecutions.set(generateExecutionId('tool', ++this.executionCounter), {\n startTime: Date.now(),\n operation: 'tool-call',\n input: toolName,\n });\n }\n\n override async afterToolCall(\n toolName: string,\n parameters: TToolParameters,\n result: IToolExecutionResult,\n ): Promise<void> {\n const execution = findActiveExecution(this.activeExecutions, 'tool-call', toolName);\n if (!execution) return;\n const { executionId, executionData } = execution;\n const duration = Date.now() - executionData.startTime;\n const success = !result?.error;\n const errorInfo =\n result?.error && this.pluginOptions.trackErrors\n ? { message: String(result.error), type: 'ToolExecutionError' }\n : undefined;\n this.recordStats({\n executionId,\n operation: 'tool-call',\n startTime: new Date(executionData.startTime),\n endTime: new Date(),\n duration,\n success,\n ...(errorInfo && { error: errorInfo }),\n metadata: {\n toolName,\n parameterCount: Object.keys(parameters).length,\n resultType: typeof result,\n hasError: !!result?.error,\n },\n });\n this.activeExecutions.delete(executionId);\n }\n\n override async onError(error: Error, context?: IPluginErrorContext): Promise<void> {\n const activeExecution = Array.from(this.activeExecutions.entries())[0];\n if (activeExecution) {\n const [executionId, executionData] = activeExecution;\n this.recordStats(\n buildErrorExecutionStats(\n executionId,\n executionData,\n error,\n this.pluginOptions.trackErrors,\n context,\n ),\n );\n this.activeExecutions.delete(executionId);\n }\n }\n\n getExecutionStats(operation?: string, timeRange?: { start: Date; end: Date }): IExecutionStats[] {\n let filtered = this.executionHistory;\n if (operation) filtered = filtered.filter((stat) => stat.operation === operation);\n if (timeRange)\n filtered = filtered.filter(\n (stat) => stat.startTime >= timeRange.start && stat.startTime <= timeRange.end,\n );\n return [...filtered];\n }\n\n getAggregatedStats(timeRange?: { start: Date; end: Date }): IAggregatedExecutionStats {\n return aggregateExecutionStats(this.getExecutionStats(undefined, timeRange), timeRange);\n }\n\n clearStats(): void {\n this.executionHistory = [];\n this.activeExecutions.clear();\n this.executionCounter = 0;\n }\n\n getActiveExecutions(): Array<{ executionId: string; operation: string; duration: number }> {\n const now = Date.now();\n return Array.from(this.activeExecutions.entries()).map(([executionId, data]) => ({\n executionId,\n operation: data.operation,\n duration: now - data.startTime,\n }));\n }\n\n getPluginStats(): {\n totalRecorded: number;\n activeExecutions: number;\n memoryUsage: number;\n oldestRecord?: Date;\n newestRecord?: Date;\n } {\n const oldest = this.executionHistory[0];\n const newest = this.executionHistory[this.executionHistory.length - 1];\n return {\n totalRecorded: this.executionHistory.length,\n activeExecutions: this.activeExecutions.size,\n memoryUsage: this.executionHistory.length + this.activeExecutions.size,\n ...(oldest && { oldestRecord: oldest.startTime }),\n ...(newest && { newestRecord: newest.endTime }),\n };\n }\n\n async destroy(): Promise<void> {\n this.clearStats();\n }\n getExecutionData(): IExecutionStats[] {\n return [...this.executionHistory];\n }\n getAnalyticsStats(): IAggregatedExecutionStats {\n return this.getAggregatedStats();\n }\n clearExecutionData(): void {\n this.clearStats();\n }\n\n override getStatus(): {\n name: string;\n version: string;\n enabled: boolean;\n initialized: boolean;\n category: PluginCategory;\n priority: number;\n subscribedEventsCount: number;\n hasEventEmitter: boolean;\n } {\n return {\n name: this.name,\n version: this.version,\n enabled: this.enabled,\n initialized: this.initialized,\n category: this.category,\n priority: this.priority,\n subscribedEventsCount: this.subscribedEvents.length,\n hasEventEmitter: !!this.eventEmitter,\n };\n }\n\n override getStats(): IExecutionAnalyticsPluginStats {\n const newest = this.executionHistory[this.executionHistory.length - 1];\n const oldest = this.executionHistory[0];\n return {\n enabled: this.enabled,\n calls: this.executionHistory.length,\n errors: this.executionHistory.filter((e) => !e.success).length,\n ...(newest?.endTime && { lastActivity: newest.endTime }),\n totalRecorded: this.executionHistory.length,\n activeExecutions: this.activeExecutions.size,\n memoryUsage: this.executionHistory.length + this.activeExecutions.size,\n ...(oldest && { oldestRecord: oldest.startTime }),\n ...(newest && { newestRecord: newest.endTime }),\n };\n }\n\n private recordStats(stats: IExecutionStats): void {\n this.executionHistory.push(stats);\n if (this.executionHistory.length > this.pluginOptions.maxEntries) this.executionHistory.shift();\n }\n}\n","/**\n * Limits Plugin - Rate limit check, cost calculation, and utility helpers.\n *\n * Extracted from limits-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { PluginError } from '@robota-sdk/agent-core';\n\nimport type { ILimitWindow, ITokenBucket } from './types';\nimport type { TUniversalMessage } from '@robota-sdk/agent-core';\n\nconst COST_DECIMAL_PLACES = 4;\nconst CHARS_PER_TOKEN = 4;\nconst TOKEN_ESTIMATE_BUFFER = 100;\nconst TOKENS_PER_COST_UNIT = 1000;\nconst MS_PER_SECOND = 1000;\n\n/** Model-specific cost table (per 1000 tokens). @internal */\nconst MODEL_COSTS: Record<string, number> = {\n 'gpt-4': 0.03,\n 'gpt-4-turbo': 0.01,\n 'gpt-3.5-turbo': 0.002,\n 'claude-3-opus': 0.015,\n 'claude-3-sonnet': 0.003,\n 'claude-3-haiku': 0.00025,\n};\n\n/** Default cost calculator: uses model-specific rates or falls back to tokenCostPer1000. @internal */\nexport function defaultCostCalculator(\n tokens: number,\n model: string,\n tokenCostPer1000: number,\n): number {\n return (tokens / TOKENS_PER_COST_UNIT) * (MODEL_COSTS[model] ?? tokenCostPer1000);\n}\n\n/** Estimate token count from message content lengths. @internal */\nexport function estimateTokensFromMessages(messages: TUniversalMessage[]): number {\n return (\n Math.ceil(messages.reduce((t, m) => t + (m.content?.length || 0), 0) / CHARS_PER_TOKEN) +\n TOKEN_ESTIMATE_BUFFER\n );\n}\n\n/** Check and update token-bucket state. Throws PluginError if any limit is exceeded. @internal */\nexport function checkTokenBucket(\n bucket: ITokenBucket,\n now: number,\n estimatedTokens: number,\n estimatedCost: number,\n options: {\n bucketSize: number;\n refillRate: number;\n timeWindow: number;\n maxRequests: number;\n maxCost: number;\n },\n pluginName: string,\n): void {\n const timePassed = (now - bucket.lastRefill) / MS_PER_SECOND;\n bucket.tokens = Math.min(options.bucketSize, bucket.tokens + timePassed * options.refillRate);\n bucket.lastRefill = now;\n\n if (bucket.tokens < estimatedTokens) {\n throw new PluginError(\n `Token bucket depleted. Available: ${Math.floor(bucket.tokens)}, Required: ${estimatedTokens}`,\n pluginName,\n { availableTokens: bucket.tokens, requiredTokens: estimatedTokens },\n );\n }\n\n if (now - bucket.windowStart >= options.timeWindow) {\n bucket.requests = 0;\n bucket.cost = 0;\n bucket.windowStart = now;\n }\n\n if (bucket.requests >= options.maxRequests) {\n throw new PluginError(`Request limit exceeded. Max: ${options.maxRequests}`, pluginName, {\n currentRequests: bucket.requests,\n maxRequests: options.maxRequests,\n });\n }\n\n if (bucket.cost + estimatedCost > options.maxCost) {\n throw new PluginError(\n `Cost limit exceeded. Current: $${bucket.cost.toFixed(COST_DECIMAL_PLACES)}, Estimated: $${estimatedCost.toFixed(COST_DECIMAL_PLACES)}, Max: $${options.maxCost}`,\n pluginName,\n { currentCost: bucket.cost, estimatedCost, maxCost: options.maxCost },\n );\n }\n\n bucket.tokens -= estimatedTokens;\n bucket.requests++;\n}\n\n/** Check and update sliding-window state. Throws PluginError if any limit is exceeded. @internal */\nexport function checkSlidingWindow(\n window: ILimitWindow,\n now: number,\n estimatedTokens: number,\n estimatedCost: number,\n options: {\n timeWindow: number;\n maxTokens: number;\n maxRequests: number;\n maxCost: number;\n },\n pluginName: string,\n): void {\n if (now - window.windowStart < options.timeWindow) {\n if (window.tokens + estimatedTokens > options.maxTokens) {\n throw new PluginError(\n `Token limit exceeded in sliding window. Current: ${window.tokens}, Estimated: ${estimatedTokens}, Max: ${options.maxTokens}`,\n pluginName,\n { currentTokens: window.tokens, estimatedTokens, maxTokens: options.maxTokens },\n );\n }\n if (window.count >= options.maxRequests) {\n throw new PluginError(\n `Request limit exceeded in sliding window. Current: ${window.count}, Max: ${options.maxRequests}`,\n pluginName,\n { currentRequests: window.count, maxRequests: options.maxRequests },\n );\n }\n if (window.cost + estimatedCost > options.maxCost) {\n throw new PluginError(\n `Cost limit exceeded in sliding window. Current: $${window.cost.toFixed(COST_DECIMAL_PLACES)}, Estimated: $${estimatedCost.toFixed(COST_DECIMAL_PLACES)}, Max: $${options.maxCost}`,\n pluginName,\n { currentCost: window.cost, estimatedCost, maxCost: options.maxCost },\n );\n }\n } else {\n window.count = 0;\n window.tokens = 0;\n window.cost = 0;\n window.windowStart = now;\n }\n window.count++;\n}\n\n/** Check and update fixed-window state. Throws PluginError if any limit is exceeded. @internal */\nexport function checkFixedWindow(\n window: ILimitWindow,\n now: number,\n estimatedTokens: number,\n estimatedCost: number,\n options: {\n timeWindow: number;\n maxTokens: number;\n maxRequests: number;\n maxCost: number;\n },\n pluginName: string,\n): void {\n if (now - window.windowStart >= options.timeWindow) {\n window.count = 0;\n window.tokens = 0;\n window.cost = 0;\n window.windowStart = now;\n }\n\n if (window.tokens + estimatedTokens > options.maxTokens) {\n throw new PluginError(\n `Token limit exceeded in fixed window. Current: ${window.tokens}, Estimated: ${estimatedTokens}, Max: ${options.maxTokens}`,\n pluginName,\n { currentTokens: window.tokens, estimatedTokens, maxTokens: options.maxTokens },\n );\n }\n if (window.count >= options.maxRequests) {\n throw new PluginError(\n `Request limit exceeded in fixed window. Current: ${window.count}, Max: ${options.maxRequests}`,\n pluginName,\n { currentRequests: window.count, maxRequests: options.maxRequests },\n );\n }\n if (window.cost + estimatedCost > options.maxCost) {\n throw new PluginError(\n `Cost limit exceeded in fixed window. Current: $${window.cost.toFixed(COST_DECIMAL_PLACES)}, Estimated: $${estimatedCost.toFixed(COST_DECIMAL_PLACES)}, Max: $${options.maxCost}`,\n pluginName,\n { currentCost: window.cost, estimatedCost, maxCost: options.maxCost },\n );\n }\n window.count++;\n}\n","/**\n * Validation logic for LimitsPlugin options.\n *\n * Extracted from limits-plugin.ts to keep each file under 300 lines.\n * @internal\n */\nimport { PluginError, type ILogger } from '@robota-sdk/agent-core';\n\nimport type { ILimitsPluginOptions } from './types';\n\n/** Validate LimitsPlugin options. @internal */\nexport function validateLimitsOptions(\n options: ILimitsPluginOptions,\n pluginName: string,\n logger: ILogger,\n): void {\n if (options.strategy === 'none') {\n logger.info('LimitsPlugin configured with \"none\" strategy - no rate limiting will be applied');\n return;\n }\n\n if (!options.strategy) {\n throw new PluginError(\n 'Strategy must be specified for limits plugin. Use \"none\" to disable rate limiting, or choose from: token-bucket, sliding-window, fixed-window',\n pluginName,\n { availableStrategies: ['none', 'token-bucket', 'sliding-window', 'fixed-window'] },\n );\n }\n\n const validStrategies = ['none', 'token-bucket', 'sliding-window', 'fixed-window'];\n if (!validStrategies.includes(options.strategy)) {\n throw new PluginError(\n `Invalid strategy \"${options.strategy}\". Must be one of: ${validStrategies.join(', ')}`,\n pluginName,\n { provided: options.strategy, validStrategies },\n );\n }\n\n if (options.strategy === 'token-bucket') {\n if (options.bucketSize !== undefined && options.bucketSize <= 0)\n throw new PluginError('Bucket size must be positive for token-bucket strategy', pluginName, {\n strategy: options.strategy,\n bucketSize: options.bucketSize,\n });\n if (options.refillRate !== undefined && options.refillRate < 0)\n throw new PluginError(\n 'Refill rate must be non-negative for token-bucket strategy',\n pluginName,\n { strategy: options.strategy, refillRate: options.refillRate },\n );\n }\n\n if (['sliding-window', 'fixed-window'].includes(options.strategy)) {\n if (options.timeWindow !== undefined && options.timeWindow <= 0)\n throw new PluginError(\n `Time window must be positive for ${options.strategy} strategy`,\n pluginName,\n { strategy: options.strategy, timeWindow: options.timeWindow },\n );\n }\n\n if (options.maxRequests !== undefined && options.maxRequests < 0)\n throw new PluginError('Max requests must be non-negative', pluginName, {\n strategy: options.strategy,\n maxRequests: options.maxRequests,\n });\n if (options.maxTokens !== undefined && options.maxTokens < 0)\n throw new PluginError('Max tokens must be non-negative', pluginName, {\n strategy: options.strategy,\n maxTokens: options.maxTokens,\n });\n if (options.maxCost !== undefined && options.maxCost < 0)\n throw new PluginError('Max cost must be non-negative', pluginName, {\n strategy: options.strategy,\n maxCost: options.maxCost,\n });\n if (options.tokenCostPer1000 !== undefined && options.tokenCostPer1000 < 0)\n throw new PluginError('Token cost per 1000 must be non-negative', pluginName, {\n strategy: options.strategy,\n tokenCostPer1000: options.tokenCostPer1000,\n });\n}\n","import {\n AbstractPlugin,\n type IPluginExecutionContext,\n type IPluginExecutionResult,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n type TUniversalMessage,\n} from '@robota-sdk/agent-core';\n\nimport {\n defaultCostCalculator,\n estimateTokensFromMessages,\n checkTokenBucket,\n checkSlidingWindow,\n checkFixedWindow,\n} from './limits-helpers';\nimport { validateLimitsOptions } from './validation';\n\nimport type {\n TLimitsStrategy,\n ILimitsPluginOptions,\n TPluginLimitsStatusData,\n ILimitWindow,\n ITokenBucket,\n} from './types';\n\nconst DEFAULT_MAX_TOKENS = 100000;\nconst DEFAULT_MAX_REQUESTS = 1000;\nconst DEFAULT_TIME_WINDOW_MS = 3600000;\nconst DEFAULT_MAX_COST = 10.0;\nconst DEFAULT_TOKEN_COST_PER_1000 = 0.002;\nconst DEFAULT_REFILL_RATE = 100;\nconst DEFAULT_BUCKET_SIZE = 10000;\n\nexport type { TLimitsStrategy, ILimitsPluginOptions, TPluginLimitsStatusData };\n\nexport interface ILimitsPluginExecutionContext extends IPluginExecutionContext {\n config?: { model?: string; maxTokens?: number; temperature?: number };\n conversationId?: string;\n}\n\nexport interface ILimitsPluginExecutionResult {\n tokensUsed?: number;\n cost?: number;\n success?: boolean;\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Enforces rate limiting on token usage, request frequency, and cost.\n * @extends AbstractPlugin\n */\nexport class LimitsPlugin extends AbstractPlugin<ILimitsPluginOptions> {\n name = 'LimitsPlugin';\n version = '1.0.0';\n private pluginOptions: Required<ILimitsPluginOptions>;\n private logger: ILogger;\n private windows = new Map<string, ILimitWindow>();\n private buckets = new Map<string, ITokenBucket>();\n\n constructor(options: ILimitsPluginOptions) {\n super();\n this.logger = createLogger('LimitsPlugin');\n validateLimitsOptions(options, this.name, this.logger);\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n maxTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,\n maxRequests: options.maxRequests ?? DEFAULT_MAX_REQUESTS,\n timeWindow: options.timeWindow ?? DEFAULT_TIME_WINDOW_MS,\n maxCost: options.maxCost ?? DEFAULT_MAX_COST,\n tokenCostPer1000: options.tokenCostPer1000 ?? DEFAULT_TOKEN_COST_PER_1000,\n refillRate: options.refillRate ?? DEFAULT_REFILL_RATE,\n bucketSize: options.bucketSize ?? DEFAULT_BUCKET_SIZE,\n costCalculator:\n options.costCalculator ??\n ((tokens: number, model: string) =>\n defaultCostCalculator(tokens, model, this.pluginOptions.tokenCostPer1000)),\n category: options.category ?? PluginCategory.LIMITS,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n }\n\n override async beforeExecution(context: IPluginExecutionContext): Promise<void> {\n if (this.pluginOptions.strategy === 'none') return;\n const key = this.getKey(context);\n const now = Date.now();\n const est = estimateTokensFromMessages(context.messages ?? []);\n const estCost = this.pluginOptions.costCalculator(est, this.resolveModelName(context));\n\n switch (this.pluginOptions.strategy) {\n case 'token-bucket':\n checkTokenBucket(this.getBucket(key), now, est, estCost, this.pluginOptions, this.name);\n break;\n case 'sliding-window':\n checkSlidingWindow(this.getWindow(key), now, est, estCost, this.pluginOptions, this.name);\n break;\n case 'fixed-window':\n checkFixedWindow(this.getWindow(key), now, est, estCost, this.pluginOptions, this.name);\n break;\n }\n }\n\n override async afterExecution(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n if (this.pluginOptions.strategy === 'none') return;\n const key = this.getKey(context);\n const tokensUsed = result?.tokensUsed || 0;\n const cost = this.pluginOptions.costCalculator(tokensUsed, this.resolveModelName(context));\n switch (this.pluginOptions.strategy) {\n case 'token-bucket':\n this.getBucket(key).cost += cost;\n break;\n case 'sliding-window':\n case 'fixed-window': {\n const w = this.getWindow(key);\n w.tokens += tokensUsed;\n w.cost += cost;\n break;\n }\n }\n }\n\n private getBucket(key: string): ITokenBucket {\n if (!this.buckets.has(key))\n this.buckets.set(key, {\n tokens: this.pluginOptions.bucketSize,\n lastRefill: Date.now(),\n requests: 0,\n cost: 0,\n windowStart: Date.now(),\n });\n return this.buckets.get(key)!;\n }\n\n private getWindow(key: string): ILimitWindow {\n if (!this.windows.has(key))\n this.windows.set(key, { count: 0, tokens: 0, cost: 0, windowStart: Date.now() });\n return this.windows.get(key)!;\n }\n\n private getKey(context: ILimitsPluginExecutionContext): string {\n return context.userId || context.sessionId || context.executionId || 'default';\n }\n\n private resolveModelName(context: IPluginExecutionContext): string {\n const m = context.config?.model;\n return typeof m === 'string' && m.length > 0 ? m : 'unknown';\n }\n\n getLimitsStatus(key?: string): TPluginLimitsStatusData {\n if (key) {\n const bucket = this.buckets.get(key);\n const window = this.windows.get(key);\n return {\n strategy: this.pluginOptions.strategy,\n key,\n bucket: bucket\n ? {\n availableTokens: Math.floor(bucket.tokens),\n requests: bucket.requests,\n cost: bucket.cost,\n }\n : null,\n window: window\n ? {\n count: window.count,\n tokens: window.tokens,\n cost: window.cost,\n windowStart: window.windowStart,\n }\n : null,\n };\n }\n return {\n strategy: this.pluginOptions.strategy,\n totalKeys: this.buckets.size + this.windows.size,\n bucketKeys: Array.from(this.buckets.keys()),\n windowKeys: Array.from(this.windows.keys()),\n };\n }\n\n resetLimits(key?: string): void {\n if (key) {\n this.buckets.delete(key);\n this.windows.delete(key);\n } else {\n this.buckets.clear();\n this.windows.clear();\n }\n }\n}\n","import type { ILogEntry, ILogFormatter } from './types';\n\nconst LEVEL_PAD_WIDTH = 5;\n\n/**\n * Default console formatter\n */\nexport class ConsoleLogFormatter implements ILogFormatter {\n format(entry: ILogEntry): string {\n const timestamp = entry.timestamp.toISOString();\n const level = entry.level.toUpperCase().padStart(LEVEL_PAD_WIDTH);\n const contextStr = entry.context ? ` | ${JSON.stringify(entry.context)}` : '';\n const metadataStr = entry.metadata ? ` | ${JSON.stringify(entry.metadata)}` : '';\n return `[${timestamp}] ${level} | ${entry.message}${contextStr}${metadataStr}`;\n }\n}\n\n/**\n * JSON formatter for file/remote logging\n */\nexport class JsonLogFormatter implements ILogFormatter {\n format(entry: ILogEntry): string {\n return JSON.stringify({\n ...entry,\n timestamp: entry.timestamp.toISOString(),\n });\n }\n}\n","import { SilentLogger, type ILogger } from '@robota-sdk/agent-core';\n\nimport { ConsoleLogFormatter } from '../formatters';\n\nimport type { ILogEntry, ILogStorage, ILogFormatter, TLogLevel } from '../types';\n\n/**\n * Console log storage\n */\nexport class ConsoleLogStorage implements ILogStorage {\n private formatter: ILogFormatter;\n private logger: ILogger;\n\n constructor(formatter?: ILogFormatter, logger?: ILogger) {\n this.formatter = formatter || new ConsoleLogFormatter();\n this.logger = logger || SilentLogger;\n }\n\n async write(entry: ILogEntry): Promise<void> {\n const formatted = this.formatter.format(entry);\n\n const level: TLogLevel = entry.level;\n switch (level) {\n case 'debug':\n this.logger.debug(formatted);\n break;\n case 'info':\n this.logger.info(formatted);\n break;\n case 'warn':\n this.logger.warn(formatted);\n break;\n case 'error':\n this.logger.error(formatted);\n break;\n }\n }\n\n async flush(): Promise<void> {\n // Console doesn't need flushing\n }\n\n async close(): Promise<void> {\n // Console doesn't need closing\n }\n}\n","import { createLogger, type ILogger, PluginError } from '@robota-sdk/agent-core';\n\nimport { JsonLogFormatter } from '../formatters';\n\nimport type { ILogEntry, ILogStorage, ILogFormatter } from '../types';\n\n/**\n * File log storage (placeholder implementation)\n */\nexport class FileLogStorage implements ILogStorage {\n private filePath: string;\n private formatter: ILogFormatter;\n private logger: ILogger;\n\n constructor(filePath: string, formatter?: ILogFormatter) {\n this.filePath = filePath;\n this.formatter = formatter || new JsonLogFormatter();\n this.logger = createLogger('FileLogStorage');\n }\n\n async write(entry: ILogEntry): Promise<void> {\n try {\n // File writing would be implemented here\n // This is a placeholder for actual file system operations\n this.logger.warn('File logging not fully implemented yet', {\n filePath: this.filePath,\n entry: this.formatter.format(entry),\n });\n } catch (error) {\n throw new PluginError('Failed to write log to file', 'LoggingPlugin', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n // File flushing would be implemented here\n this.logger.warn('File flush not fully implemented yet');\n }\n\n async close(): Promise<void> {\n // File closing would be implemented here\n this.logger.warn('File close not fully implemented yet');\n }\n}\n","import {\n createLogger,\n type ILogger,\n PluginError,\n type TTimerId,\n startPeriodicTask,\n stopPeriodicTask,\n} from '@robota-sdk/agent-core';\n\nimport { JsonLogFormatter } from '../formatters';\n\nimport type { ILogEntry, ILogStorage, ILogFormatter } from '../types';\n\n/**\n * Remote log storage with batching\n */\nexport class RemoteLogStorage implements ILogStorage {\n private url: string;\n private formatter: ILogFormatter;\n private batchSize: number;\n private flushInterval: number;\n private pendingLogs: ILogEntry[] = [];\n private flushTimer: TTimerId | undefined;\n private logger: ILogger;\n\n constructor(url: string, _options: { timeout?: number } = {}) {\n this.url = url;\n this.formatter = new JsonLogFormatter();\n this.batchSize = 10;\n this.flushInterval = 5000;\n this.logger = createLogger('RemoteLogStorage');\n\n // Start flush timer\n this.flushTimer = startPeriodicTask(\n this.logger,\n { name: 'RemoteLogStorage.flush', intervalMs: this.flushInterval },\n async () => {\n await this.flush();\n },\n );\n }\n\n async write(entry: ILogEntry): Promise<void> {\n this.pendingLogs.push(entry);\n\n if (this.pendingLogs.length >= this.batchSize) {\n await this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.pendingLogs.length === 0) return;\n\n const logsToSend = [...this.pendingLogs];\n this.pendingLogs = [];\n\n try {\n // Remote sending would be implemented here\n // This is a placeholder for actual HTTP requests\n this.logger.warn('Remote logging not fully implemented yet', {\n url: this.url,\n logCount: logsToSend.length,\n logs: logsToSend.map((log) => this.formatter.format(log)),\n });\n } catch (error) {\n throw new PluginError('Failed to send logs to remote endpoint', 'LoggingPlugin', {\n url: this.url,\n logCount: logsToSend.length,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async close(): Promise<void> {\n stopPeriodicTask(this.flushTimer);\n this.flushTimer = undefined;\n\n await this.flush();\n }\n}\n","import type { ILogEntry, ILogStorage } from '../types';\n\n/**\n * Silent log storage (no-op)\n */\nexport class SilentLogStorage implements ILogStorage {\n async write(_entry: ILogEntry): Promise<void> {\n // Silent mode - do nothing\n }\n\n async flush(): Promise<void> {\n // Silent mode - do nothing\n }\n\n async close(): Promise<void> {\n // Silent mode - do nothing\n }\n}\n","/**\n * Logging Plugin - Validation and storage factory helpers.\n *\n * Extracted from logging-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError, EVENT_EMITTER_EVENTS } from '@robota-sdk/agent-core';\n\nimport {\n ConsoleLogStorage,\n FileLogStorage,\n RemoteLogStorage,\n SilentLogStorage,\n} from './storages/index';\n\nimport type { ILoggingPluginOptions, ILogStorage, TLogLevel, ILogEntry } from './types';\n\n/** Validate LoggingPlugin constructor options. @internal */\nexport function validateLoggingOptions(options: ILoggingPluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Logging strategy is required');\n }\n\n if (!['console', 'file', 'remote', 'silent'].includes(options.strategy)) {\n throw new ConfigurationError('Invalid logging strategy', {\n validStrategies: ['console', 'file', 'remote', 'silent'],\n provided: options.strategy,\n });\n }\n\n if (options.level && !['debug', 'info', 'warn', 'error'].includes(options.level)) {\n throw new ConfigurationError('Invalid log level', {\n validLevels: ['debug', 'info', 'warn', 'error'],\n provided: options.level,\n });\n }\n\n if (options.strategy === 'file' && !options.filePath) {\n throw new ConfigurationError('File path is required for file logging strategy');\n }\n\n if (options.strategy === 'remote' && !options.remoteEndpoint) {\n throw new ConfigurationError('Remote endpoint is required for remote logging strategy');\n }\n\n if (options.maxLogs !== undefined && options.maxLogs <= 0) {\n throw new ConfigurationError('Max logs must be positive');\n }\n\n if (options.batchSize !== undefined && options.batchSize <= 0) {\n throw new ConfigurationError('Batch size must be positive');\n }\n\n if (options.flushInterval !== undefined && options.flushInterval <= 0) {\n throw new ConfigurationError('Flush interval must be positive');\n }\n}\n\n/** Create ILogStorage instance for the given strategy. @internal */\nexport function createLoggingStorage(\n strategy: string,\n filePath: string,\n remoteEndpoint: string,\n flushInterval: number,\n formatter?: ILoggingPluginOptions['formatter'],\n): ILogStorage {\n switch (strategy) {\n case 'console':\n return new ConsoleLogStorage(formatter);\n case 'file':\n return new FileLogStorage(filePath, formatter);\n case 'remote':\n return new RemoteLogStorage(remoteEndpoint, { timeout: flushInterval });\n case 'silent':\n return new SilentLogStorage();\n default:\n throw new ConfigurationError('Unknown logging strategy', { strategy });\n }\n}\n\n/** Event name → log descriptor mapping for module lifecycle events. @internal */\nexport const LOGGING_MODULE_EVENT_MAP: ReadonlyMap<\n string,\n { level: TLogLevel; message: string; operation: string }\n> = new Map([\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_START,\n {\n level: 'info',\n message: 'Module initialization started',\n operation: 'module_initialize_start',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n {\n level: 'info',\n message: 'Module initialization completed',\n operation: 'module_initialize_complete',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n {\n level: 'error',\n message: 'Module initialization failed',\n operation: 'module_initialize_error',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_START,\n { level: 'debug', message: 'Module execution started', operation: 'module_execution_start' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n {\n level: 'debug',\n message: 'Module execution completed',\n operation: 'module_execution_complete',\n },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n { level: 'error', message: 'Module execution failed', operation: 'module_execution_error' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_START,\n { level: 'debug', message: 'Module disposal started', operation: 'module_dispose_start' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n { level: 'info', message: 'Module disposal completed', operation: 'module_dispose_complete' },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n { level: 'error', message: 'Module disposal failed', operation: 'module_dispose_error' },\n ],\n]);\n\n/** Safely extract module data fields from untyped event payload. @internal */\nexport function extractLoggingModuleData(data: unknown): {\n moduleName: string;\n moduleType: string;\n duration?: number;\n success?: boolean;\n} {\n const record = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n return {\n moduleName: typeof record['moduleName'] === 'string' ? record['moduleName'] : 'unknown',\n moduleType: typeof record['moduleType'] === 'string' ? record['moduleType'] : 'unknown',\n ...(typeof record['duration'] === 'number' && { duration: record['duration'] }),\n ...(typeof record['success'] === 'boolean' && { success: record['success'] }),\n };\n}\n\n/** Narrow interface for the log methods needed by convenience helpers. @internal */\nexport interface ILogWriter {\n info(\n message: string,\n context?: Record<string, string | number | boolean | Date | undefined>,\n metadata?: ILogEntry['metadata'],\n ): Promise<void>;\n log(\n level: TLogLevel,\n message: string,\n context?: Record<string, string | number | boolean | Date | undefined>,\n metadata?: ILogEntry['metadata'],\n ): Promise<void>;\n}\n\nconst PREVIEW_LENGTH_HELPER = 100;\n\n/** Log execution start with truncated user input. @internal */\nexport async function logExecutionStartHelper(\n writer: ILogWriter,\n executionId: string,\n userInput: string,\n metadata?: ILogEntry['metadata'],\n): Promise<void> {\n await writer.info(\n 'Execution started',\n { userInput: userInput.substring(0, PREVIEW_LENGTH_HELPER) },\n { executionId, operation: 'execution_start', ...metadata },\n );\n}\n\n/** Log execution completion with duration. @internal */\nexport async function logExecutionCompleteHelper(\n writer: ILogWriter,\n executionId: string,\n duration: number,\n metadata?: ILogEntry['metadata'],\n): Promise<void> {\n await writer.info(\n 'Execution completed',\n { duration },\n {\n executionId,\n operation: 'execution_complete',\n ...(duration !== undefined && { duration }),\n ...metadata,\n },\n );\n}\n\n/** Log a tool execution result at info (success) or error (failure) level. @internal */\nexport async function logToolExecutionHelper(\n writer: ILogWriter,\n toolName: string,\n executionId: string,\n duration?: number,\n success?: boolean,\n metadata?: ILogEntry['metadata'],\n): Promise<void> {\n const message = success ? 'Tool executed successfully' : 'Tool execution failed';\n const level: TLogLevel = success ? 'info' : 'error';\n const logMetadata = {\n executionId,\n operation: 'tool_execution',\n ...(duration !== undefined && { duration }),\n ...(metadata && typeof metadata === 'object' ? metadata : {}),\n } as ILogEntry['metadata'];\n await writer.log(level, message, { toolName, success: success ?? false }, logMetadata);\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n SilentLogger,\n PluginError,\n type IEventEmitterEventData,\n type TEventName,\n} from '@robota-sdk/agent-core';\n\nimport {\n validateLoggingOptions,\n createLoggingStorage,\n extractLoggingModuleData,\n LOGGING_MODULE_EVENT_MAP,\n logExecutionStartHelper,\n logExecutionCompleteHelper,\n logToolExecutionHelper,\n} from './logging-helpers';\n\nimport type {\n TLogLevel,\n ILogEntry,\n ILoggingContextData,\n ILoggingPluginOptions,\n ILoggingPluginStats,\n ILogStorage,\n ILogFormatter,\n} from './types';\n\nexport type { ILoggingContextData } from './types';\n\nconst DEFAULT_MAX_LOGS = 10000;\nconst DEFAULT_BATCH_SIZE = 100;\nconst DEFAULT_FLUSH_INTERVAL_MS = 30000;\n\n/** Logs agent operations using configurable storage backends (console/file/remote/silent). */\nexport class LoggingPlugin extends AbstractPlugin<ILoggingPluginOptions, ILoggingPluginStats> {\n name = 'LoggingPlugin';\n version = '1.0.0';\n\n private storage: ILogStorage;\n private pluginOptions: Required<Omit<ILoggingPluginOptions, 'formatter' | 'logger'>> & {\n formatter?: ILogFormatter;\n logger?: ILogger;\n };\n private logger: ILogger;\n private simpleLogger: ILogger;\n private logLevels: TLogLevel[] = ['debug', 'info', 'warn', 'error'];\n\n constructor(options: ILoggingPluginOptions) {\n super();\n this.logger = createLogger('LoggingPlugin');\n this.simpleLogger = options.logger || SilentLogger;\n\n // Set plugin classification\n this.category = PluginCategory.LOGGING;\n this.priority = PluginPriority.HIGH;\n\n // Validate options\n validateLoggingOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n level: options.level ?? 'info',\n filePath: options.filePath ?? './agent.log',\n remoteEndpoint: options.remoteEndpoint ?? '',\n remoteHeaders: options.remoteHeaders ?? {},\n maxLogs: options.maxLogs ?? DEFAULT_MAX_LOGS,\n includeStackTrace: options.includeStackTrace ?? true,\n ...(options.formatter && { formatter: options.formatter }),\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.LOGGING,\n priority: options.priority ?? PluginPriority.HIGH,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n\n // Initialize storage\n this.storage = createLoggingStorage(\n this.pluginOptions.strategy,\n this.pluginOptions.filePath,\n this.pluginOptions.remoteEndpoint,\n this.pluginOptions.flushInterval,\n this.pluginOptions.formatter,\n );\n\n this.logger.info('LoggingPlugin initialized', {\n strategy: this.pluginOptions.strategy,\n level: this.pluginOptions.level,\n maxLogs: this.pluginOptions.maxLogs,\n });\n }\n\n /**\n * Routes module lifecycle events (initialize, execute, dispose) to the\n * appropriate log level. Errors are logged but never re-thrown.\n */\n override async onModuleEvent(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n ): Promise<void> {\n try {\n const descriptor = LOGGING_MODULE_EVENT_MAP.get(eventName);\n if (!descriptor) return;\n\n const { moduleName, moduleType, duration, success } = extractLoggingModuleData(\n eventData.data,\n );\n const context: ILoggingContextData = { moduleName, moduleType };\n if (duration !== undefined) context.duration = duration;\n if (success !== undefined) context.success = success;\n\n const metadata: ILogEntry['metadata'] = { operation: descriptor.operation };\n if (eventData.executionId) metadata.executionId = eventData.executionId;\n if (duration !== undefined) metadata.duration = duration;\n\n const isErrorEvent = descriptor.level === 'error';\n if (isErrorEvent) {\n await this.error(descriptor.message, eventData.error, context, metadata);\n } else {\n await this.log(descriptor.level, descriptor.message, context, metadata);\n }\n } catch (error) {\n this.simpleLogger.error(\n `LoggingPlugin failed to handle module event ${eventName}:`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /**\n * Writes a log entry to the configured storage if the level meets the\n * current threshold. Logging failures are swallowed to prevent cascading errors.\n */\n async log(\n level: TLogLevel,\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n if (!this.shouldLog(level)) {\n return;\n }\n\n try {\n const entry: ILogEntry = {\n timestamp: new Date(),\n level,\n message,\n ...(context && { context }),\n ...(metadata && { metadata }),\n };\n\n await this.storage.write(entry);\n } catch (error) {\n // Don't throw errors from logging to avoid infinite loops\n this.simpleLogger.error(\n 'Logging failed:',\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /** Log debug message */\n async debug(\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await this.log('debug', message, context, metadata);\n }\n\n /** Log info message */\n async info(\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await this.log('info', message, context, metadata);\n }\n\n /** Log warning message */\n async warn(\n message: string,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await this.log('warn', message, context, metadata);\n }\n\n /**\n * Log error message\n */\n async error(\n message: string,\n error?: Error,\n context?: ILoggingContextData,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n const errorContext = {\n ...context,\n ...(error && this.pluginOptions.includeStackTrace\n ? {\n errorMessage: error.message,\n errorStack: error.stack,\n }\n : {}),\n };\n\n await this.log('error', message, errorContext, metadata);\n }\n\n /**\n * Logs the start of an agent execution, truncating user input to 100 characters.\n */\n async logExecutionStart(\n executionId: string,\n userInput: string,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await logExecutionStartHelper(this, executionId, userInput, metadata);\n }\n\n /**\n * Logs the completion of an agent execution with its duration.\n */\n async logExecutionComplete(\n executionId: string,\n duration: number,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await logExecutionCompleteHelper(this, executionId, duration, metadata);\n }\n\n /**\n * Logs a tool execution result at info (success) or error (failure) level.\n */\n async logToolExecution(\n toolName: string,\n executionId: string,\n duration?: number,\n success?: boolean,\n metadata?: ILogEntry['metadata'],\n ): Promise<void> {\n await logToolExecutionHelper(this, toolName, executionId, duration, success, metadata);\n }\n\n /**\n * Flushes any buffered log entries to the underlying storage.\n * @throws PluginError if the flush operation fails\n */\n async flush(): Promise<void> {\n try {\n await this.storage.flush();\n } catch (error) {\n throw new PluginError('Failed to flush logs', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Closes the underlying storage and releases resources.\n */\n async destroy(): Promise<void> {\n try {\n await this.storage.close();\n this.logger.info('LoggingPlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /** Check if message should be logged based on level */\n private shouldLog(level: TLogLevel): boolean {\n const currentLevelIndex = this.logLevels.indexOf(this.pluginOptions.level);\n const messageLevelIndex = this.logLevels.indexOf(level);\n return messageLevelIndex >= currentLevelIndex;\n }\n}\n","import { createLogger, type ILogger } from '@robota-sdk/agent-core';\n\nimport { type ISystemMetricsCollector, type IPerformanceMetrics } from '../types';\n\n/**\n * Node.js system metrics collector\n */\nexport class NodeSystemMetricsCollector implements ISystemMetricsCollector {\n private logger: ILogger;\n\n constructor() {\n this.logger = createLogger('NodeSystemMetricsCollector');\n }\n\n async getMemoryUsage(): Promise<IPerformanceMetrics['memoryUsage']> {\n try {\n const memoryUsage = process.memoryUsage();\n\n // Note: This is a basic implementation for Node.js\n // In production, you might want to use more sophisticated system monitoring libraries\n return {\n used: memoryUsage.rss,\n free: 0, // Not directly available in Node.js without additional libraries\n total: memoryUsage.rss + memoryUsage.external,\n heap: {\n used: memoryUsage.heapUsed,\n total: memoryUsage.heapTotal,\n },\n };\n } catch (error) {\n this.logger.warn('Failed to get memory usage', {\n error: error instanceof Error ? error.message : String(error),\n });\n return undefined;\n }\n }\n\n async getCPUUsage(): Promise<IPerformanceMetrics['cpuUsage']> {\n try {\n const cpuUsage = process.cpuUsage();\n\n // Note: This is a basic implementation for Node.js\n // For more accurate CPU percentage, you'd need to measure over time intervals\n return {\n user: cpuUsage.user,\n system: cpuUsage.system,\n percent: 0, // Would need time-based calculation for actual percentage\n };\n } catch (error) {\n this.logger.warn('Failed to get CPU usage', {\n error: error instanceof Error ? error.message : String(error),\n });\n return undefined;\n }\n }\n\n async getNetworkStats(): Promise<IPerformanceMetrics['networkStats']> {\n try {\n // Note: Network stats are not directly available in Node.js without additional monitoring\n // This would typically require integrating with system monitoring tools or libraries\n this.logger.warn('Network stats monitoring not fully implemented yet');\n return undefined;\n } catch (error) {\n this.logger.warn('Failed to get network stats', {\n error: error instanceof Error ? error.message : String(error),\n });\n return undefined;\n }\n }\n}\n","import type {\n IPerformanceStorage,\n IPerformanceMetrics,\n IAggregatedPerformanceStats,\n} from '../types';\n\nexport class MemoryPerformanceStorage implements IPerformanceStorage {\n private entries: IPerformanceMetrics[] = [];\n private maxEntries: number;\n\n constructor(maxEntries: number = 5000) {\n this.maxEntries = maxEntries;\n }\n\n async save(entry: IPerformanceMetrics): Promise<void> {\n if (this.entries.length >= this.maxEntries) {\n this.entries = this.entries.slice(-this.maxEntries + 1);\n }\n this.entries.push({ ...entry });\n }\n\n async getMetrics(\n operation?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IPerformanceMetrics[]> {\n let filtered = [...this.entries];\n if (operation) {\n filtered = filtered.filter((entry) => entry.operation === operation);\n }\n if (timeRange) {\n filtered = filtered.filter(\n (entry) => entry.timestamp >= timeRange.start && entry.timestamp <= timeRange.end,\n );\n }\n return filtered;\n }\n\n async getAggregatedStats(timeRange?: {\n start: Date;\n end: Date;\n }): Promise<IAggregatedPerformanceStats> {\n const metrics = await this.getMetrics(undefined, timeRange);\n\n if (metrics.length === 0) {\n return {\n totalOperations: 0,\n averageDuration: 0,\n minDuration: 0,\n maxDuration: 0,\n successRate: 0,\n errorRate: 0,\n operationStats: {},\n timeRangeStats: {\n startTime: timeRange?.start || new Date(),\n endTime: timeRange?.end || new Date(),\n period: 'empty',\n },\n };\n }\n\n const durations = metrics.map((m) => m.duration);\n const successCount = metrics.filter((m) => m.success).length;\n const errorCount = metrics.reduce((sum, m) => sum + m.errorCount, 0);\n\n return {\n totalOperations: metrics.length,\n averageDuration: durations.reduce((sum, d) => sum + d, 0) / durations.length,\n minDuration: Math.min(...durations),\n maxDuration: Math.max(...durations),\n successRate: successCount / metrics.length,\n errorRate: errorCount / metrics.length,\n operationStats: {},\n timeRangeStats: {\n startTime: timeRange?.start || metrics[0]?.timestamp || new Date(),\n endTime: timeRange?.end || metrics[metrics.length - 1]?.timestamp || new Date(),\n period: 'memory',\n },\n };\n }\n\n async clear(): Promise<void> {\n this.entries = [];\n }\n\n async flush(): Promise<void> {\n // Memory storage doesn't need flushing\n }\n\n async close(): Promise<void> {\n // Memory storage doesn't need closing\n }\n}\n","/**\n * Performance Plugin - Validation, storage factory, and module data extraction helpers.\n *\n * Extracted from performance-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { ConfigurationError, EVENT_EMITTER_EVENTS } from '@robota-sdk/agent-core';\n\nimport { MemoryPerformanceStorage } from './storages/index';\n\nimport type { IPerformancePluginOptions, IPerformanceStorage } from './types';\n\n/** Validate PerformancePlugin constructor options. @internal */\nexport function validatePerformanceOptions(options: IPerformancePluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Performance monitoring strategy is required');\n }\n\n if (!['memory', 'file', 'prometheus', 'remote', 'silent'].includes(options.strategy)) {\n throw new ConfigurationError('Invalid performance monitoring strategy', {\n validStrategies: ['memory', 'file', 'prometheus', 'remote', 'silent'],\n provided: options.strategy,\n });\n }\n}\n\n/** Create IPerformanceStorage instance for the given strategy. @internal */\nexport function createPerformanceStorage(\n strategy: string,\n maxEntries: number,\n): IPerformanceStorage {\n switch (strategy) {\n case 'memory':\n return new MemoryPerformanceStorage(maxEntries);\n default:\n throw new ConfigurationError('Performance monitoring strategy is not implemented', {\n provided: strategy,\n });\n }\n}\n\n/** Event name → performance metrics descriptor mapping. @internal */\nexport const PERFORMANCE_MODULE_EVENT_MAP: ReadonlyMap<\n string,\n { operation: string; phase: string; isError: boolean }\n> = new Map([\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n { operation: 'module_initialization', phase: 'initialization', isError: false },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n { operation: 'module_initialization', phase: 'initialization', isError: true },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n { operation: 'module_execution', phase: 'execution', isError: false },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n { operation: 'module_execution', phase: 'execution', isError: true },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n { operation: 'module_disposal', phase: 'disposal', isError: false },\n ],\n [\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n { operation: 'module_disposal', phase: 'disposal', isError: true },\n ],\n]);\n\n/** Safely extract module data fields from untyped event payload. @internal */\nexport function extractPerformanceModuleData(data: unknown): {\n moduleName: string;\n moduleType: string;\n duration?: number;\n success?: boolean;\n} {\n const record = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n return {\n moduleName: typeof record['moduleName'] === 'string' ? record['moduleName'] : 'unknown',\n moduleType: typeof record['moduleType'] === 'string' ? record['moduleType'] : 'unknown',\n ...(typeof record['duration'] === 'number' && { duration: record['duration'] }),\n ...(typeof record['success'] === 'boolean' && { success: record['success'] }),\n };\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n PluginError,\n type IEventEmitterEventData,\n type TEventName,\n} from '@robota-sdk/agent-core';\n\nimport { NodeSystemMetricsCollector } from './collectors/system-metrics-collector';\nimport {\n validatePerformanceOptions,\n createPerformanceStorage,\n extractPerformanceModuleData,\n PERFORMANCE_MODULE_EVENT_MAP,\n} from './performance-helpers';\n\nimport type {\n IPerformanceMetrics,\n IAggregatedPerformanceStats,\n IPerformancePluginOptions,\n IPerformancePluginStats,\n IPerformanceStorage,\n ISystemMetricsCollector,\n} from './types';\n\nconst DEFAULT_MAX_ENTRIES = 5000;\nconst DEFAULT_BATCH_SIZE = 100;\nconst DEFAULT_FLUSH_INTERVAL_MS = 30000;\nconst DEFAULT_AGGREGATION_INTERVAL_MS = 60000;\nconst DEFAULT_PERFORMANCE_THRESHOLD_MS = 1000;\n\n/**\n * Collects application and system performance metrics during agent execution.\n *\n * Optionally monitors memory, CPU, and network via\n * {@link ISystemMetricsCollector}. Logs a warning when an operation exceeds\n * the configured {@link IPerformancePluginOptions.performanceThreshold | performanceThreshold}.\n * Currently only the `memory` storage strategy is implemented.\n *\n * Lifecycle hooks used: {@link AbstractPlugin.onModuleEvent | onModuleEvent}\n *\n * @extends AbstractPlugin\n * @see IPerformanceStorage - storage backend contract\n * @see ISystemMetricsCollector - system metrics collection contract\n * @see IPerformancePluginOptions - configuration options\n *\n * @example\n * ```ts\n * const plugin = new PerformancePlugin({\n * strategy: 'memory',\n * monitorMemory: true,\n * performanceThreshold: 2000,\n * });\n * await plugin.recordMetrics({ operation: 'run', duration: 1500, success: true, errorCount: 0 });\n * ```\n */\nexport class PerformancePlugin extends AbstractPlugin<\n IPerformancePluginOptions,\n IPerformancePluginStats\n> {\n name = 'PerformancePlugin';\n version = '1.0.0';\n\n private storage: IPerformanceStorage;\n private metricsCollector: ISystemMetricsCollector;\n private pluginOptions: Required<IPerformancePluginOptions>;\n private logger: ILogger;\n\n constructor(options: IPerformancePluginOptions) {\n super();\n this.logger = createLogger('PerformancePlugin');\n\n // Set plugin classification\n this.category = PluginCategory.MONITORING;\n this.priority = PluginPriority.NORMAL;\n\n // Validate options\n validatePerformanceOptions(options);\n\n // Set defaults\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n filePath: options.filePath ?? './performance-metrics.json',\n remoteEndpoint: options.remoteEndpoint ?? '',\n prometheusEndpoint: options.prometheusEndpoint ?? '/metrics',\n remoteHeaders: options.remoteHeaders ?? {},\n maxEntries: options.maxEntries ?? DEFAULT_MAX_ENTRIES,\n monitorMemory: options.monitorMemory ?? true,\n monitorCPU: options.monitorCPU ?? true,\n monitorNetwork: options.monitorNetwork ?? false,\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL_MS,\n aggregateStats: options.aggregateStats ?? true,\n aggregationInterval: options.aggregationInterval ?? DEFAULT_AGGREGATION_INTERVAL_MS,\n performanceThreshold: options.performanceThreshold ?? DEFAULT_PERFORMANCE_THRESHOLD_MS,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.MONITORING,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n\n // Initialize storage and metrics collector\n this.storage = createPerformanceStorage(\n this.pluginOptions.strategy,\n this.pluginOptions.maxEntries,\n );\n this.metricsCollector = new NodeSystemMetricsCollector();\n\n this.logger.info('PerformancePlugin initialized', {\n strategy: this.pluginOptions.strategy,\n monitorMemory: this.pluginOptions.monitorMemory,\n monitorCPU: this.pluginOptions.monitorCPU,\n performanceThreshold: this.pluginOptions.performanceThreshold,\n });\n }\n\n /**\n * Records performance metrics from module lifecycle events\n * (initialization, execution, disposal) including duration and error counts.\n */\n override async onModuleEvent(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n ): Promise<void> {\n try {\n const descriptor = PERFORMANCE_MODULE_EVENT_MAP.get(eventName);\n if (!descriptor) return;\n\n const { moduleName, moduleType, duration, success } = extractPerformanceModuleData(\n eventData.data,\n );\n if (duration === undefined) return;\n\n await this.recordMetrics({\n operation: descriptor.operation,\n duration,\n success: descriptor.isError ? false : (success ?? true),\n errorCount: descriptor.isError ? 1 : 0,\n ...(eventData.executionId && { executionId: eventData.executionId }),\n metadata: {\n moduleName,\n moduleType,\n phase: descriptor.phase,\n ...(descriptor.isError && { error: eventData.error?.message || 'unknown error' }),\n },\n });\n } catch (_error) {\n // Swallow to avoid breaking module event processing\n }\n }\n\n /**\n * Records performance metrics, enriching them with system metrics (memory,\n * CPU, network) when the corresponding monitoring options are enabled.\n * @throws PluginError if the storage write fails\n */\n async recordMetrics(\n metrics: Omit<IPerformanceMetrics, 'timestamp' | 'memoryUsage' | 'cpuUsage' | 'networkStats'>,\n ): Promise<void> {\n try {\n const memoryUsage = this.pluginOptions.monitorMemory\n ? await this.metricsCollector.getMemoryUsage()\n : undefined;\n const cpuUsage = this.pluginOptions.monitorCPU\n ? await this.metricsCollector.getCPUUsage()\n : undefined;\n const networkStats = this.pluginOptions.monitorNetwork\n ? await this.metricsCollector.getNetworkStats()\n : undefined;\n\n const entry: IPerformanceMetrics = {\n ...metrics,\n timestamp: new Date(),\n ...(memoryUsage && { memoryUsage }),\n ...(cpuUsage && { cpuUsage }),\n ...(networkStats && { networkStats }),\n };\n\n await this.storage.save(entry);\n\n // Log warning if performance threshold exceeded\n if (entry.duration > this.pluginOptions.performanceThreshold) {\n this.logger.warn('Performance threshold exceeded', {\n operation: entry.operation,\n duration: entry.duration,\n threshold: this.pluginOptions.performanceThreshold,\n executionId: entry.executionId,\n });\n }\n\n this.logger.debug('Performance metrics recorded', {\n operation: entry.operation,\n duration: entry.duration,\n success: entry.success,\n memoryUsed: entry.memoryUsage?.heap.used,\n });\n } catch (error) {\n throw new PluginError('Failed to record performance metrics', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Retrieves recorded metrics, optionally filtered by operation name and time range.\n * @throws PluginError if the storage read fails\n */\n async getMetrics(\n operation?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IPerformanceMetrics[]> {\n try {\n return await this.storage.getMetrics(operation, timeRange);\n } catch (error) {\n throw new PluginError('Failed to get performance metrics', this.name, {\n operation: operation || 'all',\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get aggregated performance statistics\n */\n async getAggregatedStats(timeRange?: {\n start: Date;\n end: Date;\n }): Promise<IAggregatedPerformanceStats> {\n try {\n return await this.storage.getAggregatedStats(timeRange);\n } catch (error) {\n throw new PluginError('Failed to get aggregated performance stats', this.name, {\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Clear all performance metrics\n */\n async clearMetrics(): Promise<void> {\n try {\n await this.storage.clear();\n this.logger.info('Performance metrics cleared');\n } catch (error) {\n throw new PluginError('Failed to clear performance metrics', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Closes the underlying storage and releases resources.\n */\n async destroy(): Promise<void> {\n try {\n await this.storage.close();\n this.logger.info('PerformancePlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n","import type { IAggregatedUsageStats, IUsageStats } from './types';\n\nconst MS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst MS_PER_HOUR = MS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR;\nconst HOURS_PER_DAY = 24;\nconst HOURS_PER_WEEK = 168;\n\ninterface IUsageTimeRange {\n start: Date;\n end: Date;\n}\n\nfunction determineUsagePeriod(timeRange: IUsageTimeRange | undefined): string {\n if (!timeRange) return 'all';\n\n const diff = timeRange.end.getTime() - timeRange.start.getTime();\n const hours = diff / MS_PER_HOUR;\n\n if (hours <= 1) return 'hour';\n if (hours <= HOURS_PER_DAY) return 'day';\n if (hours <= HOURS_PER_WEEK) return 'week';\n return 'month';\n}\n\nfunction resolveTimeRangeStats(\n stats: readonly IUsageStats[],\n timeRange: IUsageTimeRange | undefined,\n): { startTime: Date; endTime: Date; period: string } {\n if (timeRange) {\n return {\n startTime: timeRange.start,\n endTime: timeRange.end,\n period: determineUsagePeriod(timeRange),\n };\n }\n\n if (stats.length > 0) {\n const first = stats[0]?.timestamp;\n const last = stats[stats.length - 1]?.timestamp;\n const now = new Date();\n return {\n startTime: first ?? now,\n endTime: last ?? now,\n period: determineUsagePeriod(undefined),\n };\n }\n\n const now = new Date();\n return {\n startTime: now,\n endTime: now,\n period: determineUsagePeriod(undefined),\n };\n}\n\n/**\n * Aggregate usage statistics into a single summary object.\n * This is a shared SSOT utility (composition over inheritance).\n */\nexport function aggregateUsageStats(\n stats: readonly IUsageStats[],\n timeRange?: IUsageTimeRange,\n): IAggregatedUsageStats {\n const timeRangeStats = resolveTimeRangeStats(stats, timeRange);\n\n const aggregated: IAggregatedUsageStats = {\n totalRequests: stats.length,\n totalTokens: stats.reduce((sum, entry) => sum + entry.tokensUsed.total, 0),\n totalCost: stats.reduce((sum, entry) => sum + (entry.cost?.total ?? 0), 0),\n totalDuration: stats.reduce((sum, entry) => sum + entry.duration, 0),\n successRate:\n stats.length > 0 ? stats.filter((entry) => entry.success).length / stats.length : 0,\n providerStats: {},\n modelStats: {},\n toolStats: {},\n timeRangeStats,\n };\n\n // Aggregate by provider\n for (const entry of stats) {\n if (!aggregated.providerStats[entry.provider]) {\n aggregated.providerStats[entry.provider] = {\n requests: 0,\n tokens: 0,\n cost: 0,\n duration: 0,\n };\n }\n const providerStat = aggregated.providerStats[entry.provider];\n if (providerStat) {\n providerStat.requests += entry.requestCount;\n providerStat.tokens += entry.tokensUsed.total;\n providerStat.cost += entry.cost?.total ?? 0;\n providerStat.duration += entry.duration;\n }\n }\n\n // Aggregate by model\n for (const entry of stats) {\n if (!aggregated.modelStats[entry.model]) {\n aggregated.modelStats[entry.model] = {\n requests: 0,\n tokens: 0,\n cost: 0,\n duration: 0,\n };\n }\n const modelStat = aggregated.modelStats[entry.model];\n if (modelStat) {\n modelStat.requests += entry.requestCount;\n modelStat.tokens += entry.tokensUsed.total;\n modelStat.cost += entry.cost?.total ?? 0;\n modelStat.duration += entry.duration;\n }\n }\n\n // Aggregate by tools\n for (const entry of stats) {\n const toolsUsed = entry.toolsUsed;\n if (!toolsUsed) continue;\n\n for (const tool of toolsUsed) {\n if (!aggregated.toolStats[tool]) {\n aggregated.toolStats[tool] = {\n usageCount: 0,\n successCount: 0,\n totalDuration: 0,\n };\n }\n const toolStat = aggregated.toolStats[tool];\n toolStat.usageCount += 1;\n if (entry.success) {\n toolStat.successCount += 1;\n }\n toolStat.totalDuration += entry.duration;\n }\n }\n\n return aggregated;\n}\n","import { aggregateUsageStats } from '../aggregate-usage-stats';\n\nimport type { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\n\n/**\n * Memory storage implementation for usage statistics\n */\nexport class MemoryUsageStorage implements IUsageStorage {\n private entries: IUsageStats[] = [];\n private maxEntries: number;\n\n constructor(maxEntries: number = 10000) {\n this.maxEntries = maxEntries;\n }\n\n async save(entry: IUsageStats): Promise<void> {\n // Remove oldest entries if limit exceeded\n if (this.entries.length >= this.maxEntries) {\n this.entries = this.entries.slice(-this.maxEntries + 1);\n }\n\n this.entries.push({ ...entry });\n }\n\n async getStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n let filtered = [...this.entries];\n\n if (conversationId) {\n filtered = filtered.filter((entry) => entry.conversationId === conversationId);\n }\n\n if (timeRange) {\n filtered = filtered.filter(\n (entry) => entry.timestamp >= timeRange.start && entry.timestamp <= timeRange.end,\n );\n }\n\n return filtered;\n }\n\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n const stats = await this.getStats(undefined, timeRange);\n return aggregateUsageStats(stats, timeRange);\n }\n\n async clear(): Promise<void> {\n this.entries = [];\n }\n\n async flush(): Promise<void> {\n // Memory storage doesn't need flushing\n }\n\n async close(): Promise<void> {\n // Memory storage doesn't need closing\n }\n\n // Aggregation logic intentionally lives in ../aggregate-usage-stats.ts (SSOT utility).\n}\n","import { createLogger, type ILogger, StorageError } from '@robota-sdk/agent-core';\n\nimport { aggregateUsageStats } from '../aggregate-usage-stats';\n\nimport type { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\n\n/**\n * File storage implementation for usage statistics\n */\nexport class FileUsageStorage implements IUsageStorage {\n private filePath: string;\n private logger: ILogger;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n this.logger = createLogger('FileUsageStorage');\n }\n\n async save(entry: IUsageStats): Promise<void> {\n try {\n // File operations would be implemented here\n // This is a placeholder for actual file system operations\n this.logger.warn('File usage storage not fully implemented yet', {\n filePath: this.filePath,\n entry: {\n timestamp: entry.timestamp.toISOString(),\n provider: entry.provider,\n model: entry.model,\n tokens: entry.tokensUsed.total,\n cost: entry.cost?.total,\n success: entry.success,\n },\n });\n } catch (error) {\n throw new StorageError('Failed to save usage stats to file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async getStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n try {\n // File operations would be implemented here\n this.logger.warn('File usage storage not fully implemented yet', {\n filePath: this.filePath,\n conversationId,\n timeRange,\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to load usage stats from file', {\n filePath: this.filePath,\n conversationId: conversationId || 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n try {\n const stats = await this.getStats(undefined, timeRange);\n return aggregateUsageStats(stats, timeRange);\n } catch (error) {\n throw new StorageError('Failed to get aggregated usage stats from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // File operations would be implemented here\n this.logger.warn('File usage storage not fully implemented yet', {\n filePath: this.filePath,\n operation: 'clear',\n });\n } catch (error) {\n throw new StorageError('Failed to clear usage stats from file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n try {\n // File flushing would be implemented here\n this.logger.warn('File usage storage flush not fully implemented yet', {\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to flush usage stats to file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async close(): Promise<void> {\n try {\n // File closing would be implemented here\n this.logger.warn('File usage storage close not fully implemented yet', {\n filePath: this.filePath,\n });\n } catch (error) {\n throw new StorageError('Failed to close usage stats file', {\n filePath: this.filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n","import {\n createLogger,\n type ILogger,\n StorageError,\n type TTimerId,\n startPeriodicTask,\n stopPeriodicTask,\n} from '@robota-sdk/agent-core';\n\nimport { aggregateUsageStats } from '../aggregate-usage-stats';\n\nimport type { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\n\nconst SAMPLE_SIZE = 3;\n\n/**\n * Remote storage implementation for usage statistics with batching\n */\nexport class RemoteUsageStorage implements IUsageStorage {\n private apiUrl: string;\n private batchSize: number;\n private flushInterval: number;\n private batch: IUsageStats[] = [];\n private timer?: TTimerId;\n private logger: ILogger;\n\n constructor(\n apiUrl: string,\n _apiKey: string,\n _timeout: number,\n _headers: Record<string, string> = {},\n batchSize: number = 50,\n flushInterval: number = 60000, // 1 minute\n ) {\n this.apiUrl = apiUrl;\n this.batchSize = batchSize;\n this.flushInterval = flushInterval;\n this.logger = createLogger('RemoteUsageStorage');\n\n this.timer = startPeriodicTask(\n this.logger,\n { name: 'RemoteUsageStorage.flush', intervalMs: this.flushInterval },\n async () => {\n await this.flush();\n },\n );\n }\n\n async save(entry: IUsageStats): Promise<void> {\n this.batch.push(entry);\n\n if (this.batch.length >= this.batchSize) {\n await this.flush();\n }\n }\n\n async getStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n try {\n // Remote API call would be implemented here\n this.logger.warn('Remote usage storage not fully implemented yet', {\n endpoint: this.apiUrl,\n operation: 'getStats',\n conversationId,\n timeRange,\n });\n return [];\n } catch (error) {\n throw new StorageError('Failed to get usage stats from remote endpoint', {\n endpoint: this.apiUrl,\n conversationId: conversationId || 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n try {\n const stats = await this.getStats(undefined, timeRange);\n return aggregateUsageStats(stats, timeRange);\n } catch (error) {\n throw new StorageError('Failed to get aggregated usage stats from remote endpoint', {\n endpoint: this.apiUrl,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clear(): Promise<void> {\n try {\n // Remote API call would be implemented here\n this.logger.warn('Remote usage storage not fully implemented yet', {\n endpoint: this.apiUrl,\n operation: 'clear',\n });\n } catch (error) {\n throw new StorageError('Failed to clear usage stats from remote endpoint', {\n endpoint: this.apiUrl,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n if (this.batch.length === 0) return;\n\n const statsToSend = [...this.batch];\n this.batch = [];\n\n try {\n // Remote API call would be implemented here\n // This is a placeholder for actual HTTP requests\n this.logger.warn('Remote usage storage not fully implemented yet', {\n endpoint: this.apiUrl,\n operation: 'flush',\n batchSize: statsToSend.length,\n sample: statsToSend.slice(0, SAMPLE_SIZE).map((stat) => ({\n timestamp: stat.timestamp.toISOString(),\n provider: stat.provider,\n model: stat.model,\n tokens: stat.tokensUsed.total,\n cost: stat.cost?.total,\n success: stat.success,\n })),\n });\n } catch (error) {\n // Re-add failed batch to the beginning of current batch\n this.batch = [...statsToSend, ...this.batch];\n throw new StorageError('Failed to send usage stats to remote endpoint', {\n endpoint: this.apiUrl,\n batchSize: statsToSend.length,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async close(): Promise<void> {\n stopPeriodicTask(this.timer);\n this.timer = undefined;\n\n await this.flush();\n }\n}\n","import { aggregateUsageStats } from '../aggregate-usage-stats';\n\nimport type { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';\n\n/**\n * Silent storage implementation for usage statistics (no-op)\n */\nexport class SilentUsageStorage implements IUsageStorage {\n async save(_entry: IUsageStats): Promise<void> {\n // Silent mode - do nothing\n }\n\n async getStats(\n _conversationId?: string,\n _timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n // Silent mode - return empty array\n return [];\n }\n\n async getAggregatedStats(_timeRange?: {\n start: Date;\n end: Date;\n }): Promise<IAggregatedUsageStats> {\n return aggregateUsageStats([], _timeRange);\n }\n\n async clear(): Promise<void> {\n // Silent mode - do nothing\n }\n\n async flush(): Promise<void> {\n // Silent mode - do nothing\n }\n\n async close(): Promise<void> {\n // Silent mode - do nothing\n }\n}\n","import {\n PluginCategory,\n PluginPriority,\n ConfigurationError,\n type TEventName,\n EVENT_EMITTER_EVENTS,\n} from '@robota-sdk/agent-core';\n\nimport type { IUsagePluginOptions } from './types';\n\nconst DEFAULT_MAX_ENTRIES = 10000;\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_FLUSH_INTERVAL_MS = 60000;\nconst DEFAULT_AGGREGATION_INTERVAL_MS = 300000;\n\nexport type TResolvedUsageOptions = Required<Omit<IUsagePluginOptions, 'costRates'>> & {\n costRates?: Record<string, { input: number; output: number }>;\n};\n\nexport function resolvePluginOptions(options: IUsagePluginOptions): TResolvedUsageOptions {\n return {\n enabled: options.enabled ?? true,\n strategy: options.strategy,\n filePath: options.filePath ?? './usage-stats.json',\n remoteEndpoint: options.remoteEndpoint ?? '',\n remoteHeaders: options.remoteHeaders ?? {},\n maxEntries: options.maxEntries ?? DEFAULT_MAX_ENTRIES,\n trackCosts: options.trackCosts ?? true,\n ...(options.costRates && { costRates: options.costRates }),\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL_MS,\n aggregateStats: options.aggregateStats ?? true,\n aggregationInterval: options.aggregationInterval ?? DEFAULT_AGGREGATION_INTERVAL_MS,\n category: options.category ?? PluginCategory.MONITORING,\n priority: options.priority ?? PluginPriority.NORMAL,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n };\n}\n\nexport function calculateCost(\n costRates: Record<string, { input: number; output: number }> | undefined,\n model: string,\n tokens: { input: number; output: number },\n): { input: number; output: number; total: number } | undefined {\n if (!costRates || !costRates[model]) return undefined;\n const rates = costRates[model];\n const inputCost = tokens.input * rates.input;\n const outputCost = tokens.output * rates.output;\n return { input: inputCost, output: outputCost, total: inputCost + outputCost };\n}\n\nconst VALID_STRATEGIES = ['memory', 'file', 'remote', 'silent'] as const;\n\nexport function validateUsageOptions(options: IUsagePluginOptions): void {\n if (!options.strategy) {\n throw new ConfigurationError('Usage tracking strategy is required');\n }\n if (!(VALID_STRATEGIES as readonly string[]).includes(options.strategy)) {\n throw new ConfigurationError('Invalid usage tracking strategy', {\n validStrategies: [...VALID_STRATEGIES],\n provided: options.strategy,\n });\n }\n if (options.strategy === 'file' && !options.filePath) {\n throw new ConfigurationError('File path is required for file usage tracking strategy');\n }\n if (options.strategy === 'remote' && !options.remoteEndpoint) {\n throw new ConfigurationError('Remote endpoint is required for remote usage tracking strategy');\n }\n if (options.maxEntries !== undefined && options.maxEntries <= 0) {\n throw new ConfigurationError('Max entries must be positive');\n }\n if (options.batchSize !== undefined && options.batchSize <= 0) {\n throw new ConfigurationError('Batch size must be positive');\n }\n if (options.flushInterval !== undefined && options.flushInterval <= 0) {\n throw new ConfigurationError('Flush interval must be positive');\n }\n if (options.aggregationInterval !== undefined && options.aggregationInterval <= 0) {\n throw new ConfigurationError('Aggregation interval must be positive');\n }\n}\n\nconst MODULE_SUCCESS_EVENTS = new Set<TEventName>([\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_COMPLETE,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_COMPLETE,\n]);\n\nconst MODULE_ERROR_EVENTS = new Set<TEventName>([\n EVENT_EMITTER_EVENTS.MODULE_INITIALIZE_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_EXECUTION_ERROR,\n EVENT_EMITTER_EVENTS.MODULE_DISPOSE_ERROR,\n]);\n\nexport function isModuleSuccessEvent(eventName: TEventName): boolean {\n return MODULE_SUCCESS_EVENTS.has(eventName);\n}\n\nexport function isModuleErrorEvent(eventName: TEventName): boolean {\n return MODULE_ERROR_EVENTS.has(eventName);\n}\n\nexport function extractStringField(data: unknown, field: string): string {\n if (data && typeof data === 'object' && field in data) {\n const value = (data as Record<string, unknown>)[field];\n if (typeof value === 'string') return value;\n }\n return 'unknown';\n}\n\nexport function resolveOperation(eventName: TEventName): string {\n if (eventName.includes('initialize')) return 'initialization';\n if (eventName.includes('execution')) return 'execution';\n return 'disposal';\n}\n","import {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n createLogger,\n type ILogger,\n PluginError,\n ConfigurationError,\n type IEventEmitterEventData,\n type TEventName,\n type TTimerId,\n startPeriodicTask,\n} from '@robota-sdk/agent-core';\n\nimport {\n MemoryUsageStorage,\n FileUsageStorage,\n RemoteUsageStorage,\n SilentUsageStorage,\n} from './storages/index';\nimport {\n type TResolvedUsageOptions,\n resolvePluginOptions,\n validateUsageOptions,\n calculateCost,\n isModuleSuccessEvent,\n isModuleErrorEvent,\n extractStringField,\n resolveOperation,\n} from './usage-plugin-helpers';\n\nimport type {\n IUsageStats,\n IAggregatedUsageStats,\n IUsagePluginOptions,\n IUsagePluginStats,\n IUsageStorage,\n} from './types';\n\nconst DEFAULT_REMOTE_TIMEOUT_MS = 30000;\n\n/**\n * Tracks token usage, request counts, and costs across agent executions.\n *\n * Supports memory, file, remote, and silent storage strategies. When\n * {@link IUsagePluginOptions.trackCosts | trackCosts} is enabled, per-model\n * cost rates are applied automatically. Periodic aggregation can be enabled\n * via {@link IUsagePluginOptions.aggregateStats | aggregateStats}.\n *\n * Lifecycle hooks used: {@link AbstractPlugin.onModuleEvent | onModuleEvent}\n *\n * @extends AbstractPlugin\n * @see IUsageStorage - storage backend contract\n * @see IUsagePluginOptions - configuration options\n *\n * @example\n * ```ts\n * const plugin = new UsagePlugin({\n * strategy: 'memory',\n * trackCosts: true,\n * costRates: { 'gpt-4': { input: 0.03, output: 0.06 } },\n * });\n * await plugin.recordUsage({ provider: 'openai', model: 'gpt-4', ... });\n * ```\n */\nexport class UsagePlugin extends AbstractPlugin<IUsagePluginOptions, IUsagePluginStats> {\n name = 'UsagePlugin';\n version = '1.0.0';\n\n private storage: IUsageStorage;\n private pluginOptions: TResolvedUsageOptions;\n private logger: ILogger;\n private aggregationTimer?: TTimerId;\n\n constructor(options: IUsagePluginOptions) {\n super();\n this.logger = createLogger('UsagePlugin');\n this.category = PluginCategory.MONITORING;\n this.priority = PluginPriority.NORMAL;\n\n validateUsageOptions(options);\n this.pluginOptions = resolvePluginOptions(options);\n this.storage = this.createStorage();\n\n if (this.pluginOptions.aggregateStats) {\n this.setupAggregation();\n }\n\n this.logger.info('UsagePlugin initialized', {\n strategy: this.pluginOptions.strategy,\n trackCosts: this.pluginOptions.trackCosts,\n maxEntries: this.pluginOptions.maxEntries,\n });\n }\n\n /**\n * Records usage statistics from module lifecycle events (completion and\n * error events). Duration-bearing events are recorded with zero token\n * counts as module events do not involve LLM calls.\n */\n override async onModuleEvent(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n ): Promise<void> {\n try {\n const isSuccess = isModuleSuccessEvent(eventName);\n const isError = isModuleErrorEvent(eventName);\n if (!isSuccess && !isError) return;\n\n const moduleData = eventData.data;\n if (!moduleData || !('duration' in moduleData) || typeof moduleData.duration !== 'number')\n return;\n\n await this.recordModuleUsage(eventName, eventData, moduleData.duration, isSuccess);\n } catch {\n // Swallow to avoid breaking module event processing\n }\n }\n\n private async recordModuleUsage(\n eventName: TEventName,\n eventData: IEventEmitterEventData,\n duration: number,\n success: boolean,\n ): Promise<void> {\n const moduleData = eventData.data;\n const moduleName = extractStringField(moduleData, 'moduleName');\n const moduleType = extractStringField(moduleData, 'moduleType');\n const operation = resolveOperation(eventName);\n\n const metadata: Record<string, string> = { moduleName, moduleType, operation };\n if (!success) {\n metadata['error'] = eventData.error?.message || 'unknown error';\n }\n\n await this.recordUsage({\n provider: 'module',\n model: moduleType,\n tokensUsed: { input: 0, output: 0, total: 0 },\n requestCount: 1,\n duration,\n success,\n ...(eventData.executionId && { executionId: eventData.executionId }),\n ...(eventData.sessionId && { conversationId: eventData.sessionId }),\n metadata,\n });\n }\n\n /**\n * Records a usage entry, calculating cost if cost tracking is enabled and\n * a rate is configured for the model.\n * @throws PluginError if the storage write fails\n */\n async recordUsage(usage: Omit<IUsageStats, 'timestamp' | 'cost'>): Promise<void> {\n try {\n const cost = this.pluginOptions.trackCosts\n ? calculateCost(this.pluginOptions.costRates, usage.model, usage.tokensUsed)\n : undefined;\n\n const entry: IUsageStats = {\n ...usage,\n timestamp: new Date(),\n ...(cost && { cost }),\n };\n\n await this.storage.save(entry);\n\n this.logger.debug('Usage recorded', {\n provider: entry.provider,\n model: entry.model,\n tokens: entry.tokensUsed.total,\n cost: entry.cost?.total,\n success: entry.success,\n });\n } catch (error) {\n throw new PluginError('Failed to record usage', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Retrieves usage entries, optionally filtered by conversation and time range.\n * @throws PluginError if the storage read fails\n */\n async getUsageStats(\n conversationId?: string,\n timeRange?: { start: Date; end: Date },\n ): Promise<IUsageStats[]> {\n try {\n return await this.storage.getStats(conversationId, timeRange);\n } catch (error) {\n throw new PluginError('Failed to get usage stats', this.name, {\n conversationId: conversationId || 'all',\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns aggregated totals (requests, tokens, cost, success rate) across\n * all recorded usage entries within the optional time range.\n * @throws PluginError if the storage aggregation fails\n */\n async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {\n try {\n return await this.storage.getAggregatedStats(timeRange);\n } catch (error) {\n throw new PluginError('Failed to get aggregated usage stats', this.name, {\n timeRange: timeRange\n ? `${timeRange.start.toISOString()}-${timeRange.end.toISOString()}`\n : 'all',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async clearStats(): Promise<void> {\n try {\n await this.storage.clear();\n this.logger.info('Usage statistics cleared');\n } catch (error) {\n throw new PluginError('Failed to clear usage stats', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async flush(): Promise<void> {\n try {\n await this.storage.flush();\n } catch (error) {\n throw new PluginError('Failed to flush usage stats', this.name, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Stops the aggregation timer and closes the underlying storage.\n */\n async destroy(): Promise<void> {\n try {\n if (this.aggregationTimer) {\n clearInterval(this.aggregationTimer);\n }\n await this.storage.close();\n this.logger.info('UsagePlugin destroyed');\n } catch (error) {\n this.logger.error('Error during plugin cleanup', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n private createStorage(): IUsageStorage {\n switch (this.pluginOptions.strategy) {\n case 'memory':\n return new MemoryUsageStorage(this.pluginOptions.maxEntries);\n case 'file':\n return new FileUsageStorage(this.pluginOptions.filePath);\n case 'remote':\n return new RemoteUsageStorage(\n this.pluginOptions.remoteEndpoint!,\n '',\n DEFAULT_REMOTE_TIMEOUT_MS,\n this.pluginOptions.remoteHeaders || {},\n this.pluginOptions.batchSize,\n this.pluginOptions.flushInterval,\n );\n case 'silent':\n return new SilentUsageStorage();\n default:\n throw new ConfigurationError('Unknown usage tracking strategy', {\n strategy: this.pluginOptions.strategy,\n });\n }\n }\n\n private setupAggregation(): void {\n this.aggregationTimer = startPeriodicTask(\n this.logger,\n { name: 'UsagePlugin.aggregate', intervalMs: this.pluginOptions.aggregationInterval },\n async () => {\n const stats = await this.getAggregatedStats();\n this.logger.debug('Periodic usage aggregation', {\n totalRequests: stats.totalRequests,\n totalTokens: stats.totalTokens,\n totalCost: stats.totalCost,\n successRate: stats.successRate,\n });\n },\n );\n }\n}\n","/**\n * Webhook HTTP client for sending webhook requests\n * Handles retries, timeouts, and error scenarios\n */\n\nimport jsSHA from 'jssha';\n\nimport type { IWebhookRequest } from './types';\nimport type { ILogger } from '@robota-sdk/agent-core';\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BACKOFF_BASE_MS = 1000;\nconst MAX_BACKOFF_MS = 10000;\n\n/**\n * HTTP client for webhook requests\n */\nexport class WebhookHttpClient {\n private logger: ILogger;\n\n constructor(logger: ILogger) {\n this.logger = logger;\n }\n\n /**\n * Send a single webhook request with retries\n */\n async sendRequest(request: IWebhookRequest): Promise<void> {\n const { endpoint, payload, attempt } = request;\n const timeout = endpoint.timeout ?? DEFAULT_TIMEOUT_MS;\n const maxRetries = endpoint.retries ?? DEFAULT_MAX_RETRIES;\n\n try {\n // Prepare request body\n const body = JSON.stringify(payload);\n\n // Prepare headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'User-Agent': 'robota-webhook/1.0.0',\n ...endpoint.headers,\n };\n\n // Add signature if secret is provided\n if (endpoint.secret) {\n const signature = this.generateSignature(body, endpoint.secret);\n headers['X-Webhook-Signature'] = signature;\n }\n\n // Make HTTP request\n const response = await this.makeHttpRequest(endpoint.url, {\n method: 'POST',\n headers,\n body,\n timeout,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n this.logger.debug('Webhook sent successfully', {\n url: endpoint.url,\n event: payload.event,\n attempt,\n status: response.status,\n });\n } catch (error) {\n this.logger.error('Webhook request failed', {\n url: endpoint.url,\n event: payload.event,\n attempt,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // Retry if we haven't exceeded max attempts\n if (attempt < maxRetries) {\n const retryRequest: IWebhookRequest = {\n ...request,\n attempt: attempt + 1,\n };\n\n // Exponential backoff\n const delay = Math.min(BACKOFF_BASE_MS * Math.pow(2, attempt - 1), MAX_BACKOFF_MS);\n await this.delay(delay);\n\n return this.sendRequest(retryRequest);\n }\n\n // Max retries exceeded\n throw error;\n }\n }\n\n /**\n * Generate HMAC signature for webhook security using jsSHA (browser compatible)\n */\n private generateSignature(body: string, secret: string): string {\n const shaObj = new jsSHA('SHA-256', 'TEXT', {\n hmacKey: { value: secret, format: 'TEXT' },\n });\n shaObj.update(body);\n return shaObj.getHash('HEX').toLowerCase();\n }\n\n /**\n * Make HTTP request with timeout support\n */\n private async makeHttpRequest(\n url: string,\n options: {\n method: string;\n headers: Record<string, string>;\n body: string;\n timeout: number;\n },\n ): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), options.timeout);\n\n try {\n const response = await fetch(url, {\n method: options.method,\n headers: options.headers,\n body: options.body,\n signal: controller.signal,\n });\n\n return response;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Delay utility for retry backoff\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * Webhook data transformation utilities\n * Converts base plugin types to webhook-specific types safely\n */\n\nimport type {\n IWebhookExecutionContext,\n IWebhookExecutionResult,\n IWebhookEventData,\n IWebhookExecutionData,\n IWebhookConversationData,\n IWebhookToolData,\n IWebhookErrorData,\n IWebhookToolCallData,\n TWebhookEventName,\n} from './types';\nimport type {\n IPluginExecutionContext,\n IPluginExecutionResult,\n TLoggerData,\n TUniversalValue,\n} from '@robota-sdk/agent-core';\n\n/**\n * Webhook data transformer utility class\n */\nexport class WebhookTransformer {\n /**\n * Convert IPluginExecutionContext to WebhookExecutionContext\n */\n static contextToWebhook(context: IPluginExecutionContext): IWebhookExecutionContext {\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n };\n }\n\n /**\n * Convert IPluginExecutionResult to WebhookExecutionResult\n */\n static resultToWebhook(result: IPluginExecutionResult): IWebhookExecutionResult {\n return {\n response: result.response,\n content: result.content,\n duration: result.duration,\n tokensUsed: result.tokensUsed,\n toolsExecuted: result.toolsExecuted,\n success: result.success,\n usage: result.usage,\n toolCalls: result.toolCalls,\n error: result.error,\n };\n }\n\n /**\n * Create execution event data\n */\n static createExecutionData(\n context: IWebhookExecutionContext,\n result: IWebhookExecutionResult,\n ): IWebhookEventData {\n const executionData: IWebhookExecutionData = {\n response: result.response || undefined,\n duration: result.duration || undefined,\n tokensUsed: result.tokensUsed || undefined,\n toolsExecuted: result.toolsExecuted || undefined,\n success: result.success !== undefined ? result.success : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n result: executionData,\n };\n }\n\n /**\n * Create conversation event data\n */\n static createConversationData(\n context: IWebhookExecutionContext,\n result: IWebhookExecutionResult,\n ): IWebhookEventData {\n const toolCalls: IWebhookToolCallData[] =\n result.toolCalls?.map((call) => ({\n id: call.id || '',\n name: call.name || '',\n arguments: JSON.stringify(call.arguments || {}),\n result: String(call.result || ''),\n })) || [];\n\n const conversationData: IWebhookConversationData = {\n response: result.content || result.response || undefined,\n tokensUsed: result.usage?.totalTokens || result.tokensUsed || undefined,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n conversation: conversationData,\n };\n }\n\n /**\n * Create tool execution event data\n *\n * REASON: Tool result structure varies by tool type and provider, needs flexible handling for webhook processing\n * ALTERNATIVES_CONSIDERED:\n * 1. Strict tool result interfaces (breaks tool compatibility)\n * 2. Union types (insufficient for dynamic tool results)\n * 3. Generic constraints (too complex for webhook processing)\n * 4. Interface definitions (too rigid for varied tool results)\n * 5. Type assertions (decreases type safety)\n * TODO: Consider standardized tool result interface across tools\n */\n static createToolData(\n context: IWebhookExecutionContext,\n toolResult: TLoggerData,\n ): IWebhookEventData {\n // Safely extract tool data from result\n const toolName = this.safeGetProperty(toolResult, 'toolName') || 'unknown';\n const toolId =\n this.safeGetProperty(toolResult, 'toolId') ||\n this.safeGetProperty(toolResult, 'executionId') ||\n 'unknown';\n const hasError = this.safeGetProperty(toolResult, 'error');\n const duration = this.safeGetProperty(toolResult, 'duration');\n const result = this.safeGetProperty(toolResult, 'result');\n\n const toolData: IWebhookToolData = {\n name: String(toolName),\n id: String(toolId),\n success: !hasError,\n duration: typeof duration === 'number' ? duration : undefined,\n result: hasError ? undefined : String(result || ''),\n error: hasError\n ? hasError instanceof Error\n ? hasError.message\n : String(hasError)\n : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n tool: toolData,\n };\n }\n\n /**\n * Create error event data\n */\n static createErrorData(context: IWebhookExecutionContext, error: Error): IWebhookEventData {\n const errorData: IWebhookErrorData = {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n type: error instanceof Error ? error.constructor.name : 'Unknown',\n context: context\n ? {\n executionId: context.executionId || '',\n sessionId: context.sessionId || '',\n userId: context.userId || '',\n }\n : undefined,\n };\n\n return {\n executionId: context.executionId,\n sessionId: context.sessionId,\n userId: context.userId,\n error: errorData,\n };\n }\n\n /**\n * Safely get property from object (handles index signature issues)\n *\n * REASON: Safe property access for webhook data transformation needs flexible input/output types\n * ALTERNATIVES_CONSIDERED:\n * 1. Strict object types (breaks dynamic property access)\n * 2. Union types (insufficient for property extraction)\n * 3. Generic constraints (too complex for simple property access)\n * 4. Interface definitions (too rigid for dynamic objects)\n * 5. Type assertions (decreases type safety)\n * TODO: Consider typed property access if patterns emerge\n */\n private static safeGetProperty(obj: TLoggerData, key: string): TUniversalValue | Date | Error {\n if (!obj || typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return undefined;\n }\n return obj[key];\n }\n\n /**\n * Default payload transformer for webhook events\n */\n static defaultPayloadTransformer(\n _event: TWebhookEventName,\n data: IWebhookEventData,\n ): IWebhookEventData {\n // Simply return the data as-is for the default transformer\n return data;\n }\n}\n","/**\n * Webhook Plugin - Validation helpers and event constants.\n *\n * Extracted from webhook-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { PluginError, EXECUTION_EVENTS, EXECUTION_EVENT_PREFIX } from '@robota-sdk/agent-core';\n\nimport type { TWebhookEventName, IWebhookEndpoint } from './types';\n\n/** Local execution event names used by WebhookPlugin. @internal */\nexport const WEBHOOK_EXEC_EVENTS = {\n START: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.START}` as TWebhookEventName,\n COMPLETE: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.COMPLETE}` as TWebhookEventName,\n ERROR: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.ERROR}` as TWebhookEventName,\n} as const;\n\nexport const WEBHOOK_CONV_EVENTS = {\n COMPLETE: 'conversation.complete' as TWebhookEventName,\n} as const;\nexport const WEBHOOK_TOOL_EVENTS = { EXECUTED: 'tool.executed' as TWebhookEventName } as const;\nexport const WEBHOOK_ERROR_EVENTS = { OCCURRED: 'error.occurred' as TWebhookEventName } as const;\n\n/**\n * Validate all configured webhook endpoints. Throws PluginError for any\n * invalid URL or unsupported event name. @internal\n */\nexport function validateWebhookEndpoints(\n endpoints: IWebhookEndpoint[],\n pluginName: string,\n validEvents: TWebhookEventName[],\n): void {\n for (const endpoint of endpoints) {\n if (!endpoint.url) {\n throw new PluginError(`Webhook endpoint URL is required`, pluginName);\n }\n\n let parsed: URL;\n try {\n parsed = new URL(endpoint.url);\n } catch {\n throw new PluginError(`Invalid webhook URL: ${endpoint.url}`, pluginName);\n }\n\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new PluginError(\n `Webhook endpoint URL must use http or https: ${endpoint.url}`,\n pluginName,\n );\n }\n\n if (endpoint.events) {\n for (const event of endpoint.events) {\n if (!validEvents.includes(event)) {\n throw new PluginError(`Invalid webhook event: ${event}`, pluginName);\n }\n }\n }\n }\n}\n","/**\n * Webhook Plugin - Queue and batch management.\n *\n * Extracted from webhook-plugin.ts to keep each file under 300 lines.\n * @internal\n */\n\nimport { type ILogger, type TTimerId } from '@robota-sdk/agent-core';\n\nimport type { WebhookHttpClient } from './http-client';\nimport type {\n TWebhookEventName,\n IWebhookPayload,\n IWebhookEndpoint,\n IWebhookRequest,\n} from './types';\n\n/** Manages the async request queue, batch queue, and concurrency for WebhookPlugin. @internal */\nexport class WebhookQueueManager {\n private requestQueue: IWebhookRequest[] = [];\n private batchQueue: IWebhookPayload[] = [];\n private batchTimer?: TTimerId;\n activeConcurrency = 0;\n totalSentCount = 0;\n totalErrorCount = 0;\n totalResponseTime = 0;\n\n constructor(\n private readonly logger: ILogger,\n private readonly httpClient: WebhookHttpClient,\n private readonly maxConcurrency: number,\n ) {}\n\n get queueLength(): number {\n return this.requestQueue.length;\n }\n\n get batchQueueLength(): number {\n return this.batchQueue.length;\n }\n\n setupBatching(\n flushInterval: number,\n getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[],\n ): void {\n this.batchTimer = setInterval(() => {\n this.drainBatch(getEndpoints);\n }, flushInterval);\n }\n\n async enqueueBatch(\n payload: IWebhookPayload,\n maxSize: number,\n getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[],\n ): Promise<void> {\n this.batchQueue.push(payload);\n if (this.batchQueue.length >= maxSize) {\n await this.drainBatch(getEndpoints);\n }\n }\n\n async sendToEndpoints(\n payload: IWebhookPayload,\n getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[],\n async_: boolean = true,\n ): Promise<void> {\n const endpoints = getEndpoints(payload.event);\n if (endpoints.length === 0) return;\n\n const requests: IWebhookRequest[] = endpoints.map((endpoint) => ({\n endpoint,\n payload,\n attempt: 1,\n timestamp: new Date(),\n }));\n\n if (async_) {\n this.requestQueue.push(...requests);\n this.processQueue();\n } else {\n await Promise.allSettled(\n requests.map((req) => {\n const startTime = Date.now();\n return this.httpClient\n .sendRequest(req)\n .then(() => {\n this.totalSentCount++;\n this.totalResponseTime += Date.now() - startTime;\n })\n .catch((error: unknown) => {\n this.totalErrorCount++;\n throw error;\n });\n }),\n );\n }\n }\n\n private processQueue(): void {\n while (this.requestQueue.length > 0 && this.activeConcurrency < this.maxConcurrency) {\n const request = this.requestQueue.shift();\n if (!request) break;\n\n this.activeConcurrency++;\n const startTime = Date.now();\n this.httpClient\n .sendRequest(request)\n .then(() => {\n this.totalSentCount++;\n this.totalResponseTime += Date.now() - startTime;\n })\n .catch((error: unknown) => {\n this.totalErrorCount++;\n const message = error instanceof Error ? error.message : String(error);\n this.logger.error('Webhook request failed', {\n endpoint: request.endpoint.url,\n event: request.payload.event,\n error: message,\n });\n })\n .finally(() => {\n this.activeConcurrency--;\n if (this.requestQueue.length > 0) this.processQueue();\n });\n }\n }\n\n async drainBatch(getEndpoints: (event: TWebhookEventName) => IWebhookEndpoint[]): Promise<void> {\n if (this.batchQueue.length === 0) return;\n const payloads = [...this.batchQueue];\n this.batchQueue = [];\n this.logger.debug('Flushing webhook batch', { payloadCount: payloads.length });\n for (const payload of payloads) {\n await this.sendToEndpoints(payload, getEndpoints);\n }\n }\n\n clearQueues(): void {\n this.requestQueue = [];\n this.batchQueue = [];\n }\n\n stopBatchTimer(): void {\n if (this.batchTimer) {\n clearInterval(this.batchTimer);\n this.batchTimer = undefined;\n }\n }\n}\n","/**\n * Webhook Plugin - Facade Pattern Implementation\n * Coordinates webhook functionality through clean, separated components\n */\n\nimport {\n AbstractPlugin,\n PluginCategory,\n PluginPriority,\n type IPluginExecutionContext,\n type IPluginExecutionResult,\n type IPluginErrorContext,\n createLogger,\n type ILogger,\n PluginError,\n} from '@robota-sdk/agent-core';\n\nimport { WebhookHttpClient } from './http-client';\nimport { WebhookTransformer } from './transformer';\nimport {\n validateWebhookEndpoints,\n WEBHOOK_EXEC_EVENTS,\n WEBHOOK_CONV_EVENTS,\n WEBHOOK_TOOL_EVENTS,\n WEBHOOK_ERROR_EVENTS,\n} from './webhook-helpers';\nimport { WebhookQueueManager } from './webhook-queue';\n\nimport type {\n TWebhookEventName,\n IWebhookEventData,\n TWebhookMetadata,\n IWebhookPayload,\n IWebhookEndpoint,\n IWebhookPluginOptions,\n IWebhookPluginStats,\n} from './types';\n\n/**\n * Sends HTTP webhook notifications for agent execution lifecycle events.\n *\n * Routes events to configured {@link IWebhookEndpoint | endpoints} with\n * optional event filtering per endpoint. Supports asynchronous delivery with\n * configurable concurrency, automatic retries via {@link WebhookHttpClient},\n * and optional payload batching.\n *\n * Lifecycle hooks used: {@link AbstractPlugin.afterExecution | afterExecution},\n * {@link AbstractPlugin.afterConversation | afterConversation},\n * {@link AbstractPlugin.afterToolExecution | afterToolExecution},\n * {@link AbstractPlugin.onError | onError}\n *\n * @extends AbstractPlugin\n * @see IWebhookPluginOptions - configuration options\n * @see WebhookTransformer - payload transformation utilities\n * @see WebhookHttpClient - HTTP delivery client\n *\n * @example\n * ```ts\n * const plugin = new WebhookPlugin({\n * endpoints: [{ url: 'https://example.com/hook' }],\n * async: true,\n * maxConcurrency: 3,\n * });\n * ```\n */\nexport class WebhookPlugin extends AbstractPlugin<IWebhookPluginOptions, IWebhookPluginStats> {\n name = 'WebhookPlugin';\n version = '1.0.0';\n\n private pluginOptions: Required<IWebhookPluginOptions>;\n private logger: ILogger;\n private queue: WebhookQueueManager;\n\n constructor(options: IWebhookPluginOptions) {\n super();\n\n // Set plugin classification\n this.category = PluginCategory.NOTIFICATION;\n this.priority = PluginPriority.LOW;\n\n // Validate required options\n if (!options.endpoints || options.endpoints.length === 0) {\n throw new PluginError('At least one webhook endpoint is required', this.name);\n }\n\n // Set default options\n this.pluginOptions = {\n enabled: options.enabled ?? true,\n events: [\n WEBHOOK_EXEC_EVENTS.COMPLETE,\n WEBHOOK_CONV_EVENTS.COMPLETE,\n WEBHOOK_TOOL_EVENTS.EXECUTED,\n WEBHOOK_ERROR_EVENTS.OCCURRED,\n ],\n defaultTimeout: 5000,\n defaultRetries: 3,\n async: true,\n maxConcurrency: 3,\n batching: {\n enabled: false,\n maxSize: 10,\n flushInterval: 5000,\n },\n payloadTransformer: WebhookTransformer.defaultPayloadTransformer,\n // Add plugin options defaults\n category: options.category ?? PluginCategory.NOTIFICATION,\n priority: options.priority ?? PluginPriority.LOW,\n moduleEvents: options.moduleEvents ?? [],\n subscribeToAllModuleEvents: options.subscribeToAllModuleEvents ?? false,\n ...options,\n };\n\n this.logger = createLogger(`${this.name}`);\n const httpClient = new WebhookHttpClient(this.logger);\n this.queue = new WebhookQueueManager(\n this.logger,\n httpClient,\n this.pluginOptions.maxConcurrency,\n );\n\n validateWebhookEndpoints(this.pluginOptions.endpoints, this.name, [\n WEBHOOK_EXEC_EVENTS.START,\n WEBHOOK_EXEC_EVENTS.COMPLETE,\n WEBHOOK_EXEC_EVENTS.ERROR,\n WEBHOOK_CONV_EVENTS.COMPLETE,\n WEBHOOK_TOOL_EVENTS.EXECUTED,\n WEBHOOK_ERROR_EVENTS.OCCURRED,\n 'custom',\n ]);\n\n if (this.pluginOptions.batching.enabled) {\n this.queue.setupBatching(\n this.pluginOptions.batching.flushInterval,\n this.getEndpointsForEvent.bind(this),\n );\n }\n\n this.logger.info('WebhookPlugin initialized', {\n endpointCount: this.pluginOptions.endpoints.length,\n events: this.pluginOptions.events,\n batching: this.pluginOptions.batching.enabled,\n });\n }\n\n /**\n * Sends an execution-complete webhook after the agent finishes processing.\n */\n override async afterExecution(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n const webhookContext = WebhookTransformer.contextToWebhook(context);\n const webhookResult = WebhookTransformer.resultToWebhook(result);\n const eventData = WebhookTransformer.createExecutionData(webhookContext, webhookResult);\n await this.sendWebhook(WEBHOOK_EXEC_EVENTS.COMPLETE, eventData);\n }\n\n /**\n * Sends a conversation-complete webhook after a conversation round finishes.\n */\n override async afterConversation(\n context: IPluginExecutionContext,\n result: IPluginExecutionResult,\n ): Promise<void> {\n const webhookContext = WebhookTransformer.contextToWebhook(context);\n const webhookResult = WebhookTransformer.resultToWebhook(result);\n const eventData = WebhookTransformer.createConversationData(webhookContext, webhookResult);\n await this.sendWebhook(WEBHOOK_CONV_EVENTS.COMPLETE, eventData);\n }\n\n /**\n * Sends a tool-executed webhook for each tool call in the result set.\n */\n override async afterToolExecution(\n context: IPluginExecutionContext,\n toolResults: IPluginExecutionResult,\n ): Promise<void> {\n const webhookContext = WebhookTransformer.contextToWebhook(context);\n if (toolResults.toolCalls && toolResults.toolCalls.length > 0) {\n for (const toolCall of toolResults.toolCalls) {\n const toolData = {\n toolName: toolCall.name || '',\n toolId: toolCall.id || '',\n result: toolCall.result,\n success: toolCall.result !== null,\n duration: toolResults.duration,\n };\n const eventData = WebhookTransformer.createToolData(webhookContext, toolData);\n await this.sendWebhook(WEBHOOK_TOOL_EVENTS.EXECUTED, eventData);\n }\n }\n }\n\n /**\n * Sends both an error-occurred and execution-error webhook on failure.\n */\n override async onError(error: Error, context?: IPluginErrorContext): Promise<void> {\n const webhookContext = context\n ? { executionId: context.executionId, sessionId: context.sessionId, userId: context.userId }\n : { executionId: undefined, sessionId: undefined, userId: undefined };\n const errorEventData = WebhookTransformer.createErrorData(webhookContext, error);\n await this.sendWebhook(WEBHOOK_ERROR_EVENTS.OCCURRED, errorEventData);\n await this.sendWebhook(WEBHOOK_EXEC_EVENTS.ERROR, errorEventData);\n }\n\n /**\n * Builds a webhook payload and delivers it to all matching endpoints. When\n * batching is enabled, payloads are queued and flushed at the configured interval.\n */\n async sendWebhook(\n event: TWebhookEventName,\n data: IWebhookEventData,\n metadata?: TWebhookMetadata,\n ): Promise<void> {\n if (!this.pluginOptions.events.includes(event)) return;\n\n const payload: IWebhookPayload = {\n event,\n timestamp: new Date().toISOString(),\n data: this.pluginOptions.payloadTransformer(event, data),\n ...(metadata && { metadata }),\n };\n if (data.executionId) payload.executionId = data.executionId;\n if (data.sessionId) payload.sessionId = data.sessionId;\n if (data.userId) payload.userId = data.userId;\n\n this.logger.debug('Sending webhook', {\n event,\n endpointCount: this.getEndpointsForEvent(event).length,\n });\n\n if (this.pluginOptions.batching.enabled) {\n await this.queue.enqueueBatch(\n payload,\n this.pluginOptions.batching.maxSize,\n this.getEndpointsForEvent.bind(this),\n );\n } else {\n await this.queue.sendToEndpoints(\n payload,\n this.getEndpointsForEvent.bind(this),\n this.pluginOptions.async,\n );\n }\n }\n\n /**\n * Sends a webhook with the `custom` event type.\n */\n async sendCustomWebhook(data: IWebhookEventData, metadata?: TWebhookMetadata): Promise<void> {\n await this.sendWebhook('custom', data, metadata);\n }\n\n /**\n * Get webhook plugin statistics\n */\n override getStats(): IWebhookPluginStats {\n const base = super.getStats();\n return {\n ...base,\n endpointCount: this.pluginOptions.endpoints.length,\n queueLength: this.queue.queueLength,\n batchQueueLength: this.queue.batchQueueLength,\n activeConcurrency: this.queue.activeConcurrency,\n supportedEvents: this.pluginOptions.events,\n totalSent: this.queue.totalSentCount,\n totalErrors: this.queue.totalErrorCount,\n averageResponseTime:\n this.queue.totalSentCount > 0\n ? this.queue.totalResponseTime / this.queue.totalSentCount\n : 0,\n };\n }\n\n /**\n * Clear webhook queue\n */\n clearQueue(): void {\n this.queue.clearQueues();\n this.logger.info('Webhook queues cleared');\n }\n\n /**\n * Flushes pending batches, clears request queues, and stops the batch timer.\n */\n async destroy(): Promise<void> {\n this.queue.stopBatchTimer();\n await this.queue.drainBatch(this.getEndpointsForEvent.bind(this));\n this.clearQueue();\n this.logger.info('WebhookPlugin destroyed');\n }\n\n private getEndpointsForEvent(event: TWebhookEventName): IWebhookEndpoint[] {\n return this.pluginOptions.endpoints.filter((endpoint) => {\n if (!endpoint.events || endpoint.events.length === 0) return true;\n return endpoint.events.includes(event);\n });\n }\n}\n"],"mappings":"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"}
|