@robota-sdk/agent-plugin 3.0.0-beta.64

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.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/dist/node/index.cjs +1 -0
  3. package/dist/node/index.d.ts +1724 -0
  4. package/dist/node/index.d.ts.map +1 -0
  5. package/dist/node/index.js +2 -0
  6. package/dist/node/index.js.map +1 -0
  7. package/package.json +48 -0
  8. package/src/conversation-history/__tests__/conversation-history-plugin.test.ts +221 -0
  9. package/src/conversation-history/__tests__/history-storages.test.ts +115 -0
  10. package/src/conversation-history/conversation-history-helpers.ts +120 -0
  11. package/src/conversation-history/conversation-history-plugin.ts +294 -0
  12. package/src/conversation-history/index.ts +11 -0
  13. package/src/conversation-history/storages/database-storage.ts +96 -0
  14. package/src/conversation-history/storages/file-storage.ts +95 -0
  15. package/src/conversation-history/storages/index.ts +3 -0
  16. package/src/conversation-history/storages/memory-storage.ts +44 -0
  17. package/src/conversation-history/types.ts +64 -0
  18. package/src/error-handling/__tests__/error-handling-plugin.test.ts +201 -0
  19. package/src/error-handling/context-adapter.ts +48 -0
  20. package/src/error-handling/error-handling-helpers.ts +53 -0
  21. package/src/error-handling/error-handling-plugin.ts +293 -0
  22. package/src/error-handling/index.ts +9 -0
  23. package/src/error-handling/types.ts +82 -0
  24. package/src/execution-analytics/__tests__/execution-analytics-plugin.test.ts +224 -0
  25. package/src/execution-analytics/analytics-aggregation.ts +88 -0
  26. package/src/execution-analytics/execution-analytics-helpers.ts +83 -0
  27. package/src/execution-analytics/execution-analytics-plugin.ts +315 -0
  28. package/src/execution-analytics/index.ts +9 -0
  29. package/src/execution-analytics/types.ts +97 -0
  30. package/src/index.ts +8 -0
  31. package/src/limits/__tests__/limits-plugin.test.ts +712 -0
  32. package/src/limits/index.ts +9 -0
  33. package/src/limits/limits-helpers.ts +185 -0
  34. package/src/limits/limits-plugin.ts +196 -0
  35. package/src/limits/types.ts +73 -0
  36. package/src/limits/validation.ts +81 -0
  37. package/src/logging/__tests__/formatters.test.ts +48 -0
  38. package/src/logging/__tests__/logging-plugin.test.ts +464 -0
  39. package/src/logging/__tests__/logging-storages.test.ts +95 -0
  40. package/src/logging/formatters.ts +28 -0
  41. package/src/logging/index.ts +15 -0
  42. package/src/logging/logging-helpers.ts +223 -0
  43. package/src/logging/logging-plugin.ts +288 -0
  44. package/src/logging/storages/console-storage.ts +44 -0
  45. package/src/logging/storages/file-storage.ts +44 -0
  46. package/src/logging/storages/index.ts +4 -0
  47. package/src/logging/storages/remote-storage.ts +78 -0
  48. package/src/logging/storages/silent-storage.ts +18 -0
  49. package/src/logging/types.ts +106 -0
  50. package/src/performance/__tests__/memory-storage.test.ts +86 -0
  51. package/src/performance/__tests__/performance-plugin.test.ts +208 -0
  52. package/src/performance/__tests__/system-metrics-collector.test.ts +33 -0
  53. package/src/performance/collectors/system-metrics-collector.ts +69 -0
  54. package/src/performance/index.ts +12 -0
  55. package/src/performance/performance-helpers.ts +86 -0
  56. package/src/performance/performance-plugin.ts +274 -0
  57. package/src/performance/storages/index.ts +1 -0
  58. package/src/performance/storages/memory-storage.ts +88 -0
  59. package/src/performance/types.ts +160 -0
  60. package/src/usage/__tests__/aggregate-usage-stats.test.ts +136 -0
  61. package/src/usage/__tests__/memory-storage.test.ts +83 -0
  62. package/src/usage/__tests__/silent-storage.test.ts +44 -0
  63. package/src/usage/__tests__/usage-plugin-helpers.test.ts +155 -0
  64. package/src/usage/__tests__/usage-plugin.test.ts +358 -0
  65. package/src/usage/aggregate-usage-stats.ts +142 -0
  66. package/src/usage/index.ts +14 -0
  67. package/src/usage/storages/file-storage.ts +115 -0
  68. package/src/usage/storages/index.ts +4 -0
  69. package/src/usage/storages/memory-storage.ts +61 -0
  70. package/src/usage/storages/remote-storage.ts +143 -0
  71. package/src/usage/storages/silent-storage.ts +38 -0
  72. package/src/usage/types.ts +132 -0
  73. package/src/usage/usage-plugin-helpers.ts +116 -0
  74. package/src/usage/usage-plugin.ts +296 -0
  75. package/src/webhook/__tests__/webhook-plugin.test.ts +560 -0
  76. package/src/webhook/http-client.ts +141 -0
  77. package/src/webhook/index.ts +9 -0
  78. package/src/webhook/transformer.ts +209 -0
  79. package/src/webhook/types.ts +201 -0
  80. package/src/webhook/webhook-helpers.ts +60 -0
  81. package/src/webhook/webhook-plugin.ts +298 -0
  82. package/src/webhook/webhook-queue.ts +148 -0
@@ -0,0 +1,142 @@
1
+ import type { IAggregatedUsageStats, IUsageStats } from './types';
2
+
3
+ const MS_PER_SECOND = 1000;
4
+ const SECONDS_PER_MINUTE = 60;
5
+ const MINUTES_PER_HOUR = 60;
6
+ const MS_PER_HOUR = MS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
7
+ const HOURS_PER_DAY = 24;
8
+ const HOURS_PER_WEEK = 168;
9
+
10
+ interface IUsageTimeRange {
11
+ start: Date;
12
+ end: Date;
13
+ }
14
+
15
+ function determineUsagePeriod(timeRange: IUsageTimeRange | undefined): string {
16
+ if (!timeRange) return 'all';
17
+
18
+ const diff = timeRange.end.getTime() - timeRange.start.getTime();
19
+ const hours = diff / MS_PER_HOUR;
20
+
21
+ if (hours <= 1) return 'hour';
22
+ if (hours <= HOURS_PER_DAY) return 'day';
23
+ if (hours <= HOURS_PER_WEEK) return 'week';
24
+ return 'month';
25
+ }
26
+
27
+ function resolveTimeRangeStats(
28
+ stats: readonly IUsageStats[],
29
+ timeRange: IUsageTimeRange | undefined,
30
+ ): { startTime: Date; endTime: Date; period: string } {
31
+ if (timeRange) {
32
+ return {
33
+ startTime: timeRange.start,
34
+ endTime: timeRange.end,
35
+ period: determineUsagePeriod(timeRange),
36
+ };
37
+ }
38
+
39
+ if (stats.length > 0) {
40
+ const first = stats[0]?.timestamp;
41
+ const last = stats[stats.length - 1]?.timestamp;
42
+ const now = new Date();
43
+ return {
44
+ startTime: first ?? now,
45
+ endTime: last ?? now,
46
+ period: determineUsagePeriod(undefined),
47
+ };
48
+ }
49
+
50
+ const now = new Date();
51
+ return {
52
+ startTime: now,
53
+ endTime: now,
54
+ period: determineUsagePeriod(undefined),
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Aggregate usage statistics into a single summary object.
60
+ * This is a shared SSOT utility (composition over inheritance).
61
+ */
62
+ export function aggregateUsageStats(
63
+ stats: readonly IUsageStats[],
64
+ timeRange?: IUsageTimeRange,
65
+ ): IAggregatedUsageStats {
66
+ const timeRangeStats = resolveTimeRangeStats(stats, timeRange);
67
+
68
+ const aggregated: IAggregatedUsageStats = {
69
+ totalRequests: stats.length,
70
+ totalTokens: stats.reduce((sum, entry) => sum + entry.tokensUsed.total, 0),
71
+ totalCost: stats.reduce((sum, entry) => sum + (entry.cost?.total ?? 0), 0),
72
+ totalDuration: stats.reduce((sum, entry) => sum + entry.duration, 0),
73
+ successRate:
74
+ stats.length > 0 ? stats.filter((entry) => entry.success).length / stats.length : 0,
75
+ providerStats: {},
76
+ modelStats: {},
77
+ toolStats: {},
78
+ timeRangeStats,
79
+ };
80
+
81
+ // Aggregate by provider
82
+ for (const entry of stats) {
83
+ if (!aggregated.providerStats[entry.provider]) {
84
+ aggregated.providerStats[entry.provider] = {
85
+ requests: 0,
86
+ tokens: 0,
87
+ cost: 0,
88
+ duration: 0,
89
+ };
90
+ }
91
+ const providerStat = aggregated.providerStats[entry.provider];
92
+ if (providerStat) {
93
+ providerStat.requests += entry.requestCount;
94
+ providerStat.tokens += entry.tokensUsed.total;
95
+ providerStat.cost += entry.cost?.total ?? 0;
96
+ providerStat.duration += entry.duration;
97
+ }
98
+ }
99
+
100
+ // Aggregate by model
101
+ for (const entry of stats) {
102
+ if (!aggregated.modelStats[entry.model]) {
103
+ aggregated.modelStats[entry.model] = {
104
+ requests: 0,
105
+ tokens: 0,
106
+ cost: 0,
107
+ duration: 0,
108
+ };
109
+ }
110
+ const modelStat = aggregated.modelStats[entry.model];
111
+ if (modelStat) {
112
+ modelStat.requests += entry.requestCount;
113
+ modelStat.tokens += entry.tokensUsed.total;
114
+ modelStat.cost += entry.cost?.total ?? 0;
115
+ modelStat.duration += entry.duration;
116
+ }
117
+ }
118
+
119
+ // Aggregate by tools
120
+ for (const entry of stats) {
121
+ const toolsUsed = entry.toolsUsed;
122
+ if (!toolsUsed) continue;
123
+
124
+ for (const tool of toolsUsed) {
125
+ if (!aggregated.toolStats[tool]) {
126
+ aggregated.toolStats[tool] = {
127
+ usageCount: 0,
128
+ successCount: 0,
129
+ totalDuration: 0,
130
+ };
131
+ }
132
+ const toolStat = aggregated.toolStats[tool];
133
+ toolStat.usageCount += 1;
134
+ if (entry.success) {
135
+ toolStat.successCount += 1;
136
+ }
137
+ toolStat.totalDuration += entry.duration;
138
+ }
139
+ }
140
+
141
+ return aggregated;
142
+ }
@@ -0,0 +1,14 @@
1
+ export { UsagePlugin } from './usage-plugin';
2
+ export { aggregateUsageStats } from './aggregate-usage-stats';
3
+ export { MemoryUsageStorage } from './storages/memory-storage';
4
+ export { FileUsageStorage } from './storages/file-storage';
5
+ export { RemoteUsageStorage } from './storages/remote-storage';
6
+ export { SilentUsageStorage } from './storages/silent-storage';
7
+ export type {
8
+ TUsageTrackingStrategy,
9
+ IUsageStats,
10
+ IAggregatedUsageStats,
11
+ IUsagePluginOptions,
12
+ IUsagePluginStats,
13
+ IUsageStorage,
14
+ } from './types';
@@ -0,0 +1,115 @@
1
+ import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';
2
+ import { createLogger, type ILogger, StorageError } from '@robota-sdk/agent-core';
3
+ import { aggregateUsageStats } from '../aggregate-usage-stats';
4
+
5
+ /**
6
+ * File storage implementation for usage statistics
7
+ */
8
+ export class FileUsageStorage implements IUsageStorage {
9
+ private filePath: string;
10
+ private logger: ILogger;
11
+
12
+ constructor(filePath: string) {
13
+ this.filePath = filePath;
14
+ this.logger = createLogger('FileUsageStorage');
15
+ }
16
+
17
+ async save(entry: IUsageStats): Promise<void> {
18
+ try {
19
+ // File operations would be implemented here
20
+ // This is a placeholder for actual file system operations
21
+ this.logger.warn('File usage storage not fully implemented yet', {
22
+ filePath: this.filePath,
23
+ entry: {
24
+ timestamp: entry.timestamp.toISOString(),
25
+ provider: entry.provider,
26
+ model: entry.model,
27
+ tokens: entry.tokensUsed.total,
28
+ cost: entry.cost?.total,
29
+ success: entry.success,
30
+ },
31
+ });
32
+ } catch (error) {
33
+ throw new StorageError('Failed to save usage stats to file', {
34
+ filePath: this.filePath,
35
+ error: error instanceof Error ? error.message : String(error),
36
+ });
37
+ }
38
+ }
39
+
40
+ async getStats(
41
+ conversationId?: string,
42
+ timeRange?: { start: Date; end: Date },
43
+ ): Promise<IUsageStats[]> {
44
+ try {
45
+ // File operations would be implemented here
46
+ this.logger.warn('File usage storage not fully implemented yet', {
47
+ filePath: this.filePath,
48
+ conversationId,
49
+ timeRange,
50
+ });
51
+ return [];
52
+ } catch (error) {
53
+ throw new StorageError('Failed to load usage stats from file', {
54
+ filePath: this.filePath,
55
+ conversationId: conversationId || 'all',
56
+ error: error instanceof Error ? error.message : String(error),
57
+ });
58
+ }
59
+ }
60
+
61
+ async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {
62
+ try {
63
+ const stats = await this.getStats(undefined, timeRange);
64
+ return aggregateUsageStats(stats, timeRange);
65
+ } catch (error) {
66
+ throw new StorageError('Failed to get aggregated usage stats from file', {
67
+ filePath: this.filePath,
68
+ error: error instanceof Error ? error.message : String(error),
69
+ });
70
+ }
71
+ }
72
+
73
+ async clear(): Promise<void> {
74
+ try {
75
+ // File operations would be implemented here
76
+ this.logger.warn('File usage storage not fully implemented yet', {
77
+ filePath: this.filePath,
78
+ operation: 'clear',
79
+ });
80
+ } catch (error) {
81
+ throw new StorageError('Failed to clear usage stats from file', {
82
+ filePath: this.filePath,
83
+ error: error instanceof Error ? error.message : String(error),
84
+ });
85
+ }
86
+ }
87
+
88
+ async flush(): Promise<void> {
89
+ try {
90
+ // File flushing would be implemented here
91
+ this.logger.warn('File usage storage flush not fully implemented yet', {
92
+ filePath: this.filePath,
93
+ });
94
+ } catch (error) {
95
+ throw new StorageError('Failed to flush usage stats to file', {
96
+ filePath: this.filePath,
97
+ error: error instanceof Error ? error.message : String(error),
98
+ });
99
+ }
100
+ }
101
+
102
+ async close(): Promise<void> {
103
+ try {
104
+ // File closing would be implemented here
105
+ this.logger.warn('File usage storage close not fully implemented yet', {
106
+ filePath: this.filePath,
107
+ });
108
+ } catch (error) {
109
+ throw new StorageError('Failed to close usage stats file', {
110
+ filePath: this.filePath,
111
+ error: error instanceof Error ? error.message : String(error),
112
+ });
113
+ }
114
+ }
115
+ }
@@ -0,0 +1,4 @@
1
+ export { MemoryUsageStorage } from './memory-storage';
2
+ export { FileUsageStorage } from './file-storage';
3
+ export { RemoteUsageStorage } from './remote-storage';
4
+ export { SilentUsageStorage } from './silent-storage';
@@ -0,0 +1,61 @@
1
+ import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';
2
+ import { aggregateUsageStats } from '../aggregate-usage-stats';
3
+
4
+ /**
5
+ * Memory storage implementation for usage statistics
6
+ */
7
+ export class MemoryUsageStorage implements IUsageStorage {
8
+ private entries: IUsageStats[] = [];
9
+ private maxEntries: number;
10
+
11
+ constructor(maxEntries: number = 10000) {
12
+ this.maxEntries = maxEntries;
13
+ }
14
+
15
+ async save(entry: IUsageStats): Promise<void> {
16
+ // Remove oldest entries if limit exceeded
17
+ if (this.entries.length >= this.maxEntries) {
18
+ this.entries = this.entries.slice(-this.maxEntries + 1);
19
+ }
20
+
21
+ this.entries.push({ ...entry });
22
+ }
23
+
24
+ async getStats(
25
+ conversationId?: string,
26
+ timeRange?: { start: Date; end: Date },
27
+ ): Promise<IUsageStats[]> {
28
+ let filtered = [...this.entries];
29
+
30
+ if (conversationId) {
31
+ filtered = filtered.filter((entry) => entry.conversationId === conversationId);
32
+ }
33
+
34
+ if (timeRange) {
35
+ filtered = filtered.filter(
36
+ (entry) => entry.timestamp >= timeRange.start && entry.timestamp <= timeRange.end,
37
+ );
38
+ }
39
+
40
+ return filtered;
41
+ }
42
+
43
+ async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {
44
+ const stats = await this.getStats(undefined, timeRange);
45
+ return aggregateUsageStats(stats, timeRange);
46
+ }
47
+
48
+ async clear(): Promise<void> {
49
+ this.entries = [];
50
+ }
51
+
52
+ async flush(): Promise<void> {
53
+ // Memory storage doesn't need flushing
54
+ }
55
+
56
+ async close(): Promise<void> {
57
+ // Memory storage doesn't need closing
58
+ }
59
+
60
+ // Aggregation logic intentionally lives in ../aggregate-usage-stats.ts (SSOT utility).
61
+ }
@@ -0,0 +1,143 @@
1
+ import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';
2
+ import {
3
+ createLogger,
4
+ type ILogger,
5
+ StorageError,
6
+ type TTimerId,
7
+ startPeriodicTask,
8
+ stopPeriodicTask,
9
+ } from '@robota-sdk/agent-core';
10
+ import { aggregateUsageStats } from '../aggregate-usage-stats';
11
+
12
+ const SAMPLE_SIZE = 3;
13
+
14
+ /**
15
+ * Remote storage implementation for usage statistics with batching
16
+ */
17
+ export class RemoteUsageStorage implements IUsageStorage {
18
+ private apiUrl: string;
19
+ private batchSize: number;
20
+ private flushInterval: number;
21
+ private batch: IUsageStats[] = [];
22
+ private timer?: TTimerId;
23
+ private logger: ILogger;
24
+
25
+ constructor(
26
+ apiUrl: string,
27
+ _apiKey: string,
28
+ _timeout: number,
29
+ _headers: Record<string, string> = {},
30
+ batchSize: number = 50,
31
+ flushInterval: number = 60000, // 1 minute
32
+ ) {
33
+ this.apiUrl = apiUrl;
34
+ this.batchSize = batchSize;
35
+ this.flushInterval = flushInterval;
36
+ this.logger = createLogger('RemoteUsageStorage');
37
+
38
+ this.timer = startPeriodicTask(
39
+ this.logger,
40
+ { name: 'RemoteUsageStorage.flush', intervalMs: this.flushInterval },
41
+ async () => {
42
+ await this.flush();
43
+ },
44
+ );
45
+ }
46
+
47
+ async save(entry: IUsageStats): Promise<void> {
48
+ this.batch.push(entry);
49
+
50
+ if (this.batch.length >= this.batchSize) {
51
+ await this.flush();
52
+ }
53
+ }
54
+
55
+ async getStats(
56
+ conversationId?: string,
57
+ timeRange?: { start: Date; end: Date },
58
+ ): Promise<IUsageStats[]> {
59
+ try {
60
+ // Remote API call would be implemented here
61
+ this.logger.warn('Remote usage storage not fully implemented yet', {
62
+ endpoint: this.apiUrl,
63
+ operation: 'getStats',
64
+ conversationId,
65
+ timeRange,
66
+ });
67
+ return [];
68
+ } catch (error) {
69
+ throw new StorageError('Failed to get usage stats from remote endpoint', {
70
+ endpoint: this.apiUrl,
71
+ conversationId: conversationId || 'all',
72
+ error: error instanceof Error ? error.message : String(error),
73
+ });
74
+ }
75
+ }
76
+
77
+ async getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats> {
78
+ try {
79
+ const stats = await this.getStats(undefined, timeRange);
80
+ return aggregateUsageStats(stats, timeRange);
81
+ } catch (error) {
82
+ throw new StorageError('Failed to get aggregated usage stats from remote endpoint', {
83
+ endpoint: this.apiUrl,
84
+ error: error instanceof Error ? error.message : String(error),
85
+ });
86
+ }
87
+ }
88
+
89
+ async clear(): Promise<void> {
90
+ try {
91
+ // Remote API call would be implemented here
92
+ this.logger.warn('Remote usage storage not fully implemented yet', {
93
+ endpoint: this.apiUrl,
94
+ operation: 'clear',
95
+ });
96
+ } catch (error) {
97
+ throw new StorageError('Failed to clear usage stats from remote endpoint', {
98
+ endpoint: this.apiUrl,
99
+ error: error instanceof Error ? error.message : String(error),
100
+ });
101
+ }
102
+ }
103
+
104
+ async flush(): Promise<void> {
105
+ if (this.batch.length === 0) return;
106
+
107
+ const statsToSend = [...this.batch];
108
+ this.batch = [];
109
+
110
+ try {
111
+ // Remote API call would be implemented here
112
+ // This is a placeholder for actual HTTP requests
113
+ this.logger.warn('Remote usage storage not fully implemented yet', {
114
+ endpoint: this.apiUrl,
115
+ operation: 'flush',
116
+ batchSize: statsToSend.length,
117
+ sample: statsToSend.slice(0, SAMPLE_SIZE).map((stat) => ({
118
+ timestamp: stat.timestamp.toISOString(),
119
+ provider: stat.provider,
120
+ model: stat.model,
121
+ tokens: stat.tokensUsed.total,
122
+ cost: stat.cost?.total,
123
+ success: stat.success,
124
+ })),
125
+ });
126
+ } catch (error) {
127
+ // Re-add failed batch to the beginning of current batch
128
+ this.batch = [...statsToSend, ...this.batch];
129
+ throw new StorageError('Failed to send usage stats to remote endpoint', {
130
+ endpoint: this.apiUrl,
131
+ batchSize: statsToSend.length,
132
+ error: error instanceof Error ? error.message : String(error),
133
+ });
134
+ }
135
+ }
136
+
137
+ async close(): Promise<void> {
138
+ stopPeriodicTask(this.timer);
139
+ this.timer = undefined;
140
+
141
+ await this.flush();
142
+ }
143
+ }
@@ -0,0 +1,38 @@
1
+ import { IUsageStorage, IUsageStats, IAggregatedUsageStats } from '../types';
2
+ import { aggregateUsageStats } from '../aggregate-usage-stats';
3
+
4
+ /**
5
+ * Silent storage implementation for usage statistics (no-op)
6
+ */
7
+ export class SilentUsageStorage implements IUsageStorage {
8
+ async save(_entry: IUsageStats): Promise<void> {
9
+ // Silent mode - do nothing
10
+ }
11
+
12
+ async getStats(
13
+ _conversationId?: string,
14
+ _timeRange?: { start: Date; end: Date },
15
+ ): Promise<IUsageStats[]> {
16
+ // Silent mode - return empty array
17
+ return [];
18
+ }
19
+
20
+ async getAggregatedStats(_timeRange?: {
21
+ start: Date;
22
+ end: Date;
23
+ }): Promise<IAggregatedUsageStats> {
24
+ return aggregateUsageStats([], _timeRange);
25
+ }
26
+
27
+ async clear(): Promise<void> {
28
+ // Silent mode - do nothing
29
+ }
30
+
31
+ async flush(): Promise<void> {
32
+ // Silent mode - do nothing
33
+ }
34
+
35
+ async close(): Promise<void> {
36
+ // Silent mode - do nothing
37
+ }
38
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Usage tracking strategy types
3
+ */
4
+ export type TUsageTrackingStrategy = 'memory' | 'file' | 'remote' | 'silent';
5
+
6
+ /**
7
+ * Usage statistics entry
8
+ */
9
+ export interface IUsageStats {
10
+ conversationId?: string;
11
+ executionId?: string;
12
+ timestamp: Date;
13
+ provider: string;
14
+ model: string;
15
+ tokensUsed: {
16
+ input: number;
17
+ output: number;
18
+ total: number;
19
+ };
20
+ cost?: {
21
+ input: number;
22
+ output: number;
23
+ total: number;
24
+ };
25
+ requestCount: number;
26
+ duration: number; // in milliseconds
27
+ success: boolean;
28
+ toolsUsed?: string[];
29
+ metadata?: Record<string, string | number | boolean | Date>;
30
+ }
31
+
32
+ /**
33
+ * Aggregated usage statistics
34
+ */
35
+ export interface IAggregatedUsageStats {
36
+ totalRequests: number;
37
+ totalTokens: number;
38
+ totalCost: number;
39
+ totalDuration: number;
40
+ successRate: number;
41
+ providerStats: Record<
42
+ string,
43
+ {
44
+ requests: number;
45
+ tokens: number;
46
+ cost: number;
47
+ duration: number;
48
+ }
49
+ >;
50
+ modelStats: Record<
51
+ string,
52
+ {
53
+ requests: number;
54
+ tokens: number;
55
+ cost: number;
56
+ duration: number;
57
+ }
58
+ >;
59
+ toolStats: Record<
60
+ string,
61
+ {
62
+ usageCount: number;
63
+ successCount: number;
64
+ totalDuration: number;
65
+ }
66
+ >;
67
+ timeRangeStats: {
68
+ startTime: Date;
69
+ endTime: Date;
70
+ period: string; // 'hour', 'day', 'week', 'month'
71
+ };
72
+ }
73
+
74
+ import type { IPluginOptions, IPluginStats } from '@robota-sdk/agent-core';
75
+
76
+ /**
77
+ * Configuration options for usage plugin
78
+ */
79
+ export interface IUsagePluginOptions extends IPluginOptions {
80
+ /** Usage tracking strategy to use */
81
+ strategy: TUsageTrackingStrategy;
82
+ /** File path for file strategy */
83
+ filePath?: string;
84
+ /** Remote endpoint for remote strategy */
85
+ remoteEndpoint?: string;
86
+ /** Headers for remote logging */
87
+ remoteHeaders?: Record<string, string>;
88
+ /** Maximum number of usage entries to keep in memory */
89
+ maxEntries?: number;
90
+ /** Whether to track token costs */
91
+ trackCosts?: boolean;
92
+ /** Cost per token rates for different models */
93
+ costRates?: Record<string, { input: number; output: number }>;
94
+ /** Batch size for remote reporting */
95
+ batchSize?: number;
96
+ /** Flush interval for batched reporting in milliseconds */
97
+ flushInterval?: number;
98
+ /** Whether to aggregate statistics */
99
+ aggregateStats?: boolean;
100
+ /** Aggregation interval in milliseconds */
101
+ aggregationInterval?: number;
102
+ }
103
+
104
+ /**
105
+ * Usage storage interface
106
+ */
107
+ export interface IUsageStorage {
108
+ save(entry: IUsageStats): Promise<void>;
109
+ getStats(conversationId?: string, timeRange?: { start: Date; end: Date }): Promise<IUsageStats[]>;
110
+ getAggregatedStats(timeRange?: { start: Date; end: Date }): Promise<IAggregatedUsageStats>;
111
+ clear(): Promise<void>;
112
+ flush(): Promise<void>;
113
+ close(): Promise<void>;
114
+ }
115
+
116
+ /**
117
+ * Usage plugin statistics
118
+ */
119
+ export interface IUsagePluginStats extends IPluginStats {
120
+ /** Total number of usage entries tracked */
121
+ entriesTracked: number;
122
+ /** Total tokens tracked */
123
+ totalTokens: number;
124
+ /** Total cost tracked */
125
+ totalCost: number;
126
+ /** Current tracking strategy */
127
+ strategy: TUsageTrackingStrategy;
128
+ /** Last tracking timestamp */
129
+ lastTrackTime?: Date;
130
+ /** Number of failed tracking attempts */
131
+ failedTracking: number;
132
+ }