@juspay/neurolink 9.24.0 → 9.25.0

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 (215) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/adapters/tts/googleTTSHandler.js +26 -1
  3. package/dist/adapters/video/vertexVideoHandler.js +23 -17
  4. package/dist/cli/commands/config.d.ts +3 -3
  5. package/dist/cli/commands/observability.d.ts +53 -0
  6. package/dist/cli/commands/observability.js +453 -0
  7. package/dist/cli/commands/telemetry.d.ts +63 -0
  8. package/dist/cli/commands/telemetry.js +689 -0
  9. package/dist/cli/factories/commandFactory.js +29 -15
  10. package/dist/cli/parser.js +6 -9
  11. package/dist/cli/utils/formatters.d.ts +13 -0
  12. package/dist/cli/utils/formatters.js +23 -0
  13. package/dist/constants/contextWindows.js +6 -0
  14. package/dist/constants/enums.d.ts +6 -0
  15. package/dist/constants/enums.js +8 -2
  16. package/dist/context/budgetChecker.js +75 -48
  17. package/dist/context/contextCompactor.js +135 -127
  18. package/dist/core/baseProvider.d.ts +5 -0
  19. package/dist/core/baseProvider.js +158 -102
  20. package/dist/core/conversationMemoryInitializer.js +7 -4
  21. package/dist/core/conversationMemoryManager.d.ts +2 -0
  22. package/dist/core/conversationMemoryManager.js +6 -2
  23. package/dist/core/modules/GenerationHandler.d.ts +2 -2
  24. package/dist/core/modules/GenerationHandler.js +12 -12
  25. package/dist/evaluation/ragasEvaluator.js +39 -19
  26. package/dist/evaluation/scoring.js +46 -20
  27. package/dist/features/ppt/presentationOrchestrator.js +23 -0
  28. package/dist/features/ppt/slideGenerator.js +13 -0
  29. package/dist/features/ppt/slideRenderers.d.ts +1 -1
  30. package/dist/features/ppt/slideRenderers.js +6 -4
  31. package/dist/features/ppt/slideTypeInference.d.ts +1 -1
  32. package/dist/features/ppt/slideTypeInference.js +75 -73
  33. package/dist/files/fileTools.d.ts +6 -6
  34. package/dist/index.d.ts +46 -12
  35. package/dist/index.js +79 -17
  36. package/dist/lib/adapters/tts/googleTTSHandler.js +26 -1
  37. package/dist/lib/adapters/video/vertexVideoHandler.js +23 -17
  38. package/dist/lib/constants/contextWindows.js +6 -0
  39. package/dist/lib/constants/enums.d.ts +6 -0
  40. package/dist/lib/constants/enums.js +8 -2
  41. package/dist/lib/context/budgetChecker.js +75 -48
  42. package/dist/lib/context/contextCompactor.js +135 -127
  43. package/dist/lib/core/baseProvider.d.ts +5 -0
  44. package/dist/lib/core/baseProvider.js +158 -102
  45. package/dist/lib/core/conversationMemoryInitializer.js +7 -4
  46. package/dist/lib/core/conversationMemoryManager.d.ts +2 -0
  47. package/dist/lib/core/conversationMemoryManager.js +6 -2
  48. package/dist/lib/core/modules/GenerationHandler.d.ts +2 -2
  49. package/dist/lib/core/modules/GenerationHandler.js +12 -12
  50. package/dist/lib/evaluation/ragasEvaluator.js +39 -19
  51. package/dist/lib/evaluation/scoring.js +46 -20
  52. package/dist/lib/features/ppt/presentationOrchestrator.js +23 -0
  53. package/dist/lib/features/ppt/slideGenerator.js +13 -0
  54. package/dist/lib/features/ppt/slideRenderers.d.ts +1 -1
  55. package/dist/lib/features/ppt/slideRenderers.js +6 -4
  56. package/dist/lib/features/ppt/slideTypeInference.d.ts +1 -1
  57. package/dist/lib/features/ppt/slideTypeInference.js +75 -73
  58. package/dist/lib/files/fileTools.d.ts +6 -6
  59. package/dist/lib/index.d.ts +46 -12
  60. package/dist/lib/index.js +79 -17
  61. package/dist/lib/mcp/httpRateLimiter.js +39 -12
  62. package/dist/lib/mcp/httpRetryHandler.js +22 -1
  63. package/dist/lib/mcp/mcpClientFactory.js +13 -15
  64. package/dist/lib/memory/memoryRetrievalTools.js +22 -0
  65. package/dist/lib/neurolink.d.ts +64 -72
  66. package/dist/lib/neurolink.js +984 -566
  67. package/dist/lib/observability/exporterRegistry.d.ts +152 -0
  68. package/dist/lib/observability/exporterRegistry.js +414 -0
  69. package/dist/lib/observability/exporters/arizeExporter.d.ts +32 -0
  70. package/dist/lib/observability/exporters/arizeExporter.js +139 -0
  71. package/dist/lib/observability/exporters/baseExporter.d.ts +117 -0
  72. package/dist/lib/observability/exporters/baseExporter.js +191 -0
  73. package/dist/lib/observability/exporters/braintrustExporter.d.ts +30 -0
  74. package/dist/lib/observability/exporters/braintrustExporter.js +155 -0
  75. package/dist/lib/observability/exporters/datadogExporter.d.ts +37 -0
  76. package/dist/lib/observability/exporters/datadogExporter.js +197 -0
  77. package/dist/lib/observability/exporters/index.d.ts +13 -0
  78. package/dist/lib/observability/exporters/index.js +14 -0
  79. package/dist/lib/observability/exporters/laminarExporter.d.ts +48 -0
  80. package/dist/lib/observability/exporters/laminarExporter.js +303 -0
  81. package/dist/lib/observability/exporters/langfuseExporter.d.ts +47 -0
  82. package/dist/lib/observability/exporters/langfuseExporter.js +200 -0
  83. package/dist/lib/observability/exporters/langsmithExporter.d.ts +26 -0
  84. package/dist/lib/observability/exporters/langsmithExporter.js +124 -0
  85. package/dist/lib/observability/exporters/otelExporter.d.ts +39 -0
  86. package/dist/lib/observability/exporters/otelExporter.js +165 -0
  87. package/dist/lib/observability/exporters/posthogExporter.d.ts +48 -0
  88. package/dist/lib/observability/exporters/posthogExporter.js +288 -0
  89. package/dist/lib/observability/exporters/sentryExporter.d.ts +32 -0
  90. package/dist/lib/observability/exporters/sentryExporter.js +166 -0
  91. package/dist/lib/observability/index.d.ts +25 -0
  92. package/dist/lib/observability/index.js +32 -0
  93. package/dist/lib/observability/metricsAggregator.d.ts +260 -0
  94. package/dist/lib/observability/metricsAggregator.js +553 -0
  95. package/dist/lib/observability/otelBridge.d.ts +49 -0
  96. package/dist/lib/observability/otelBridge.js +132 -0
  97. package/dist/lib/observability/retryPolicy.d.ts +192 -0
  98. package/dist/lib/observability/retryPolicy.js +384 -0
  99. package/dist/lib/observability/sampling/index.d.ts +4 -0
  100. package/dist/lib/observability/sampling/index.js +5 -0
  101. package/dist/lib/observability/sampling/samplers.d.ts +116 -0
  102. package/dist/lib/observability/sampling/samplers.js +217 -0
  103. package/dist/lib/observability/spanProcessor.d.ts +129 -0
  104. package/dist/lib/observability/spanProcessor.js +288 -0
  105. package/dist/lib/observability/tokenTracker.d.ts +156 -0
  106. package/dist/lib/observability/tokenTracker.js +414 -0
  107. package/dist/lib/observability/types/exporterTypes.d.ts +250 -0
  108. package/dist/lib/observability/types/exporterTypes.js +6 -0
  109. package/dist/lib/observability/types/index.d.ts +6 -0
  110. package/dist/lib/observability/types/index.js +5 -0
  111. package/dist/lib/observability/types/spanTypes.d.ts +244 -0
  112. package/dist/lib/observability/types/spanTypes.js +93 -0
  113. package/dist/lib/observability/utils/index.d.ts +4 -0
  114. package/dist/lib/observability/utils/index.js +5 -0
  115. package/dist/lib/observability/utils/spanSerializer.d.ts +115 -0
  116. package/dist/lib/observability/utils/spanSerializer.js +287 -0
  117. package/dist/lib/providers/amazonSagemaker.d.ts +5 -4
  118. package/dist/lib/providers/amazonSagemaker.js +3 -4
  119. package/dist/lib/providers/googleVertex.d.ts +7 -0
  120. package/dist/lib/providers/googleVertex.js +80 -2
  121. package/dist/lib/rag/pipeline/RAGPipeline.d.ts +0 -5
  122. package/dist/lib/rag/pipeline/RAGPipeline.js +122 -87
  123. package/dist/lib/rag/ragIntegration.js +30 -0
  124. package/dist/lib/rag/retrieval/hybridSearch.js +22 -0
  125. package/dist/lib/server/abstract/baseServerAdapter.js +51 -19
  126. package/dist/lib/server/middleware/common.js +44 -12
  127. package/dist/lib/services/server/ai/observability/instrumentation.d.ts +2 -2
  128. package/dist/lib/services/server/ai/observability/instrumentation.js +10 -5
  129. package/dist/lib/types/conversationMemoryInterface.d.ts +2 -0
  130. package/dist/lib/types/modelTypes.d.ts +18 -18
  131. package/dist/lib/types/providers.d.ts +5 -0
  132. package/dist/lib/utils/pricing.js +25 -1
  133. package/dist/lib/utils/ttsProcessor.js +74 -59
  134. package/dist/lib/workflow/config.d.ts +36 -36
  135. package/dist/lib/workflow/core/ensembleExecutor.js +10 -0
  136. package/dist/lib/workflow/core/judgeScorer.js +20 -2
  137. package/dist/lib/workflow/core/workflowRunner.js +34 -1
  138. package/dist/mcp/httpRateLimiter.js +39 -12
  139. package/dist/mcp/httpRetryHandler.js +22 -1
  140. package/dist/mcp/mcpClientFactory.js +13 -15
  141. package/dist/memory/memoryRetrievalTools.js +22 -0
  142. package/dist/neurolink.d.ts +64 -72
  143. package/dist/neurolink.js +984 -566
  144. package/dist/observability/FEATURE-STATUS.md +269 -0
  145. package/dist/observability/exporterRegistry.d.ts +152 -0
  146. package/dist/observability/exporterRegistry.js +413 -0
  147. package/dist/observability/exporters/arizeExporter.d.ts +32 -0
  148. package/dist/observability/exporters/arizeExporter.js +138 -0
  149. package/dist/observability/exporters/baseExporter.d.ts +117 -0
  150. package/dist/observability/exporters/baseExporter.js +190 -0
  151. package/dist/observability/exporters/braintrustExporter.d.ts +30 -0
  152. package/dist/observability/exporters/braintrustExporter.js +154 -0
  153. package/dist/observability/exporters/datadogExporter.d.ts +37 -0
  154. package/dist/observability/exporters/datadogExporter.js +196 -0
  155. package/dist/observability/exporters/index.d.ts +13 -0
  156. package/dist/observability/exporters/index.js +13 -0
  157. package/dist/observability/exporters/laminarExporter.d.ts +48 -0
  158. package/dist/observability/exporters/laminarExporter.js +302 -0
  159. package/dist/observability/exporters/langfuseExporter.d.ts +47 -0
  160. package/dist/observability/exporters/langfuseExporter.js +199 -0
  161. package/dist/observability/exporters/langsmithExporter.d.ts +26 -0
  162. package/dist/observability/exporters/langsmithExporter.js +123 -0
  163. package/dist/observability/exporters/otelExporter.d.ts +39 -0
  164. package/dist/observability/exporters/otelExporter.js +164 -0
  165. package/dist/observability/exporters/posthogExporter.d.ts +48 -0
  166. package/dist/observability/exporters/posthogExporter.js +287 -0
  167. package/dist/observability/exporters/sentryExporter.d.ts +32 -0
  168. package/dist/observability/exporters/sentryExporter.js +165 -0
  169. package/dist/observability/index.d.ts +25 -0
  170. package/dist/observability/index.js +31 -0
  171. package/dist/observability/metricsAggregator.d.ts +260 -0
  172. package/dist/observability/metricsAggregator.js +552 -0
  173. package/dist/observability/otelBridge.d.ts +49 -0
  174. package/dist/observability/otelBridge.js +131 -0
  175. package/dist/observability/retryPolicy.d.ts +192 -0
  176. package/dist/observability/retryPolicy.js +383 -0
  177. package/dist/observability/sampling/index.d.ts +4 -0
  178. package/dist/observability/sampling/index.js +4 -0
  179. package/dist/observability/sampling/samplers.d.ts +116 -0
  180. package/dist/observability/sampling/samplers.js +216 -0
  181. package/dist/observability/spanProcessor.d.ts +129 -0
  182. package/dist/observability/spanProcessor.js +287 -0
  183. package/dist/observability/tokenTracker.d.ts +156 -0
  184. package/dist/observability/tokenTracker.js +413 -0
  185. package/dist/observability/types/exporterTypes.d.ts +250 -0
  186. package/dist/observability/types/exporterTypes.js +5 -0
  187. package/dist/observability/types/index.d.ts +6 -0
  188. package/dist/observability/types/index.js +4 -0
  189. package/dist/observability/types/spanTypes.d.ts +244 -0
  190. package/dist/observability/types/spanTypes.js +92 -0
  191. package/dist/observability/utils/index.d.ts +4 -0
  192. package/dist/observability/utils/index.js +4 -0
  193. package/dist/observability/utils/spanSerializer.d.ts +115 -0
  194. package/dist/observability/utils/spanSerializer.js +286 -0
  195. package/dist/providers/amazonSagemaker.d.ts +5 -4
  196. package/dist/providers/amazonSagemaker.js +3 -4
  197. package/dist/providers/googleVertex.d.ts +7 -0
  198. package/dist/providers/googleVertex.js +80 -2
  199. package/dist/rag/pipeline/RAGPipeline.d.ts +0 -5
  200. package/dist/rag/pipeline/RAGPipeline.js +122 -87
  201. package/dist/rag/ragIntegration.js +30 -0
  202. package/dist/rag/retrieval/hybridSearch.js +22 -0
  203. package/dist/server/abstract/baseServerAdapter.js +51 -19
  204. package/dist/server/middleware/common.js +44 -12
  205. package/dist/services/server/ai/observability/instrumentation.d.ts +2 -2
  206. package/dist/services/server/ai/observability/instrumentation.js +10 -5
  207. package/dist/types/conversationMemoryInterface.d.ts +2 -0
  208. package/dist/types/providers.d.ts +5 -0
  209. package/dist/utils/pricing.js +25 -1
  210. package/dist/utils/ttsProcessor.js +74 -59
  211. package/dist/workflow/config.d.ts +52 -52
  212. package/dist/workflow/core/ensembleExecutor.js +10 -0
  213. package/dist/workflow/core/judgeScorer.js +20 -2
  214. package/dist/workflow/core/workflowRunner.js +34 -1
  215. package/package.json +1 -1
@@ -0,0 +1,553 @@
1
+ /**
2
+ * Metrics Aggregator
3
+ * Comprehensive metrics aggregation with latency percentiles, token usage, and cost tracking
4
+ */
5
+ import { TokenTracker } from "./tokenTracker.js";
6
+ /**
7
+ * Metrics Aggregator for comprehensive telemetry analysis
8
+ * Provides latency percentiles, token aggregation, and cost tracking
9
+ */
10
+ export class MetricsAggregator {
11
+ spans = [];
12
+ latencyValues = [];
13
+ tokenTracker;
14
+ timeWindows = new Map();
15
+ config;
16
+ spansByType = new Map();
17
+ costByProvider = new Map();
18
+ costByModel = new Map();
19
+ successCount = 0;
20
+ failureCount = 0;
21
+ firstSpanTime;
22
+ lastSpanTime;
23
+ constructor(config = {}) {
24
+ this.config = {
25
+ maxSpansRetained: config.maxSpansRetained ?? 10000,
26
+ enableTimeWindows: config.enableTimeWindows ?? true,
27
+ timeWindowMs: config.timeWindowMs ?? 60000, // 1 minute default
28
+ maxTimeWindows: config.maxTimeWindows ?? 60, // 1 hour of 1-minute windows
29
+ };
30
+ this.tokenTracker = new TokenTracker();
31
+ }
32
+ /**
33
+ * Record a span for metrics aggregation
34
+ */
35
+ recordSpan(span) {
36
+ // Enforce maximum spans limit
37
+ if (this.spans.length >= this.config.maxSpansRetained) {
38
+ this.spans.shift(); // Remove oldest span
39
+ // Note: We keep aggregated metrics, only raw spans are trimmed
40
+ }
41
+ this.spans.push(span);
42
+ // Update timestamps
43
+ const spanTime = new Date(span.startTime);
44
+ if (!this.firstSpanTime || spanTime < this.firstSpanTime) {
45
+ this.firstSpanTime = spanTime;
46
+ }
47
+ if (!this.lastSpanTime || spanTime > this.lastSpanTime) {
48
+ this.lastSpanTime = spanTime;
49
+ }
50
+ // Track latency if duration is available
51
+ if (span.durationMs !== undefined) {
52
+ this.latencyValues.push(span.durationMs);
53
+ }
54
+ // Track success/failure
55
+ if (span.status === 2) {
56
+ // SpanStatus.ERROR = 2
57
+ this.failureCount++;
58
+ }
59
+ else {
60
+ this.successCount++;
61
+ }
62
+ // Track by span type
63
+ const currentCount = this.spansByType.get(span.type) ?? 0;
64
+ this.spansByType.set(span.type, currentCount + 1);
65
+ // Track tokens via TokenTracker
66
+ this.tokenTracker.trackSpan(span);
67
+ // Track cost by provider and model
68
+ this.trackCosts(span);
69
+ // Update time window if enabled
70
+ if (this.config.enableTimeWindows) {
71
+ this.updateTimeWindow(span);
72
+ }
73
+ }
74
+ /**
75
+ * Track cost aggregations from a span
76
+ */
77
+ trackCosts(span) {
78
+ const attrs = span.attributes;
79
+ const provider = attrs["ai.provider"];
80
+ const model = attrs["ai.model"];
81
+ const inputCost = attrs["ai.cost.input"] ?? 0;
82
+ const outputCost = attrs["ai.cost.output"] ?? 0;
83
+ const totalCost = attrs["ai.cost.total"] ?? inputCost + outputCost;
84
+ const inputTokens = attrs["ai.tokens.input"] ?? 0;
85
+ const outputTokens = attrs["ai.tokens.output"] ?? 0;
86
+ // Update provider costs
87
+ if (provider) {
88
+ const existing = this.costByProvider.get(provider) ?? {
89
+ provider,
90
+ totalCost: 0,
91
+ requestCount: 0,
92
+ avgCostPerRequest: 0,
93
+ inputCost: 0,
94
+ outputCost: 0,
95
+ };
96
+ existing.totalCost += totalCost;
97
+ existing.requestCount += 1;
98
+ existing.avgCostPerRequest = existing.totalCost / existing.requestCount;
99
+ existing.inputCost += inputCost;
100
+ existing.outputCost += outputCost;
101
+ this.costByProvider.set(provider, existing);
102
+ }
103
+ // Update model costs
104
+ if (model) {
105
+ const existing = this.costByModel.get(model) ?? {
106
+ model,
107
+ provider: provider ?? "unknown",
108
+ totalCost: 0,
109
+ requestCount: 0,
110
+ avgCostPerRequest: 0,
111
+ inputTokens: 0,
112
+ outputTokens: 0,
113
+ inputCost: 0,
114
+ outputCost: 0,
115
+ };
116
+ existing.totalCost += totalCost;
117
+ existing.requestCount += 1;
118
+ existing.avgCostPerRequest = existing.totalCost / existing.requestCount;
119
+ existing.inputTokens += inputTokens;
120
+ existing.outputTokens += outputTokens;
121
+ existing.inputCost += inputCost;
122
+ existing.outputCost += outputCost;
123
+ this.costByModel.set(model, existing);
124
+ }
125
+ }
126
+ /**
127
+ * Update time window statistics
128
+ */
129
+ updateTimeWindow(span) {
130
+ const spanTime = new Date(span.startTime).getTime();
131
+ const windowKey = Math.floor(spanTime / this.config.timeWindowMs) *
132
+ this.config.timeWindowMs;
133
+ // Enforce maximum time windows
134
+ if (this.timeWindows.size >= this.config.maxTimeWindows &&
135
+ !this.timeWindows.has(windowKey)) {
136
+ // Remove oldest window
137
+ const oldestKey = Math.min(...Array.from(this.timeWindows.keys()));
138
+ this.timeWindows.delete(oldestKey);
139
+ }
140
+ let window = this.timeWindows.get(windowKey);
141
+ if (!window) {
142
+ window = this.createEmptyTimeWindow(windowKey);
143
+ this.timeWindows.set(windowKey, window);
144
+ }
145
+ // Update window stats
146
+ window.requestCount++;
147
+ if (span.status === 2) {
148
+ window.errorCount++;
149
+ }
150
+ window.successRate =
151
+ (window.requestCount - window.errorCount) / window.requestCount;
152
+ window.throughput = window.requestCount / (window.windowDurationMs / 1000);
153
+ // Update window end time
154
+ const spanEndTime = new Date(span.endTime ?? span.startTime);
155
+ if (spanEndTime > window.windowEnd) {
156
+ window.windowEnd = spanEndTime;
157
+ }
158
+ }
159
+ /**
160
+ * Create an empty time window
161
+ */
162
+ createEmptyTimeWindow(windowKey) {
163
+ return {
164
+ windowStart: new Date(windowKey),
165
+ windowEnd: new Date(windowKey + this.config.timeWindowMs),
166
+ windowDurationMs: this.config.timeWindowMs,
167
+ requestCount: 0,
168
+ errorCount: 0,
169
+ successRate: 1,
170
+ throughput: 0,
171
+ latency: this.createEmptyLatencyStats(),
172
+ tokens: {
173
+ totalInputTokens: 0,
174
+ totalOutputTokens: 0,
175
+ totalTokens: 0,
176
+ cacheReadTokens: 0,
177
+ cacheCreationTokens: 0,
178
+ reasoningTokens: 0,
179
+ totalCost: 0,
180
+ byProvider: new Map(),
181
+ byModel: new Map(),
182
+ bySpanType: new Map(),
183
+ },
184
+ costByProvider: new Map(),
185
+ costByModel: new Map(),
186
+ };
187
+ }
188
+ /**
189
+ * Create empty latency stats
190
+ */
191
+ createEmptyLatencyStats() {
192
+ return {
193
+ min: 0,
194
+ max: 0,
195
+ mean: 0,
196
+ median: 0,
197
+ p50: 0,
198
+ p75: 0,
199
+ p90: 0,
200
+ p95: 0,
201
+ p99: 0,
202
+ stdDev: 0,
203
+ count: 0,
204
+ };
205
+ }
206
+ /**
207
+ * Calculate latency percentile from sorted array
208
+ */
209
+ calculatePercentile(sortedValues, percentile) {
210
+ if (sortedValues.length === 0) {
211
+ return 0;
212
+ }
213
+ const index = Math.ceil((percentile / 100) * sortedValues.length) - 1;
214
+ return sortedValues[Math.max(0, index)] ?? 0;
215
+ }
216
+ /**
217
+ * Calculate standard deviation
218
+ */
219
+ calculateStdDev(values, mean) {
220
+ if (values.length < 2) {
221
+ return 0;
222
+ }
223
+ const squaredDiffs = values.map((v) => (v - mean) ** 2);
224
+ const avgSquaredDiff = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;
225
+ return Math.sqrt(avgSquaredDiff);
226
+ }
227
+ /**
228
+ * Get comprehensive latency statistics
229
+ */
230
+ getLatencyStats() {
231
+ if (this.latencyValues.length === 0) {
232
+ return this.createEmptyLatencyStats();
233
+ }
234
+ const sorted = [...this.latencyValues].sort((a, b) => a - b);
235
+ const sum = sorted.reduce((a, b) => a + b, 0);
236
+ const mean = sum / sorted.length;
237
+ return {
238
+ min: sorted[0] ?? 0,
239
+ max: sorted[sorted.length - 1] ?? 0,
240
+ mean,
241
+ median: this.calculatePercentile(sorted, 50),
242
+ p50: this.calculatePercentile(sorted, 50),
243
+ p75: this.calculatePercentile(sorted, 75),
244
+ p90: this.calculatePercentile(sorted, 90),
245
+ p95: this.calculatePercentile(sorted, 95),
246
+ p99: this.calculatePercentile(sorted, 99),
247
+ stdDev: this.calculateStdDev(sorted, mean),
248
+ count: sorted.length,
249
+ };
250
+ }
251
+ /**
252
+ * Get token usage statistics
253
+ */
254
+ getTokenStats() {
255
+ return this.tokenTracker.getStats();
256
+ }
257
+ /**
258
+ * Get cost breakdown by provider
259
+ */
260
+ getCostByProvider() {
261
+ return Array.from(this.costByProvider.values());
262
+ }
263
+ /**
264
+ * Get cost breakdown by model
265
+ */
266
+ getCostByModel() {
267
+ return Array.from(this.costByModel.values());
268
+ }
269
+ /**
270
+ * Get total cost across all providers
271
+ */
272
+ getTotalCost() {
273
+ let total = 0;
274
+ const providerStatsArray = Array.from(this.costByProvider.values());
275
+ for (const stats of providerStatsArray) {
276
+ total += stats.totalCost;
277
+ }
278
+ return total;
279
+ }
280
+ /**
281
+ * Get time window statistics
282
+ */
283
+ getTimeWindows() {
284
+ return Array.from(this.timeWindows.values()).sort((a, b) => a.windowStart.getTime() - b.windowStart.getTime());
285
+ }
286
+ /**
287
+ * Get statistics for a specific time range
288
+ */
289
+ getStatsForTimeRange(startTime, endTime) {
290
+ const relevantSpans = this.spans.filter((span) => {
291
+ const spanTime = new Date(span.startTime);
292
+ return spanTime >= startTime && spanTime <= endTime;
293
+ });
294
+ // Create a temporary aggregator for this time range
295
+ const tempAggregator = new MetricsAggregator({
296
+ enableTimeWindows: false,
297
+ });
298
+ for (const span of relevantSpans) {
299
+ tempAggregator.recordSpan(span);
300
+ }
301
+ const summary = tempAggregator.getSummary();
302
+ const durationMs = endTime.getTime() - startTime.getTime();
303
+ return {
304
+ windowStart: startTime,
305
+ windowEnd: endTime,
306
+ windowDurationMs: durationMs,
307
+ requestCount: summary.totalSpans,
308
+ errorCount: summary.failedSpans,
309
+ successRate: summary.successRate,
310
+ throughput: summary.totalSpans / (durationMs / 1000),
311
+ latency: summary.latency,
312
+ tokens: summary.tokens,
313
+ costByProvider: new Map(summary.costByProvider.map((p) => [p.provider, p])),
314
+ costByModel: new Map(summary.costByModel.map((m) => [m.model, m])),
315
+ };
316
+ }
317
+ /**
318
+ * Record a latency measurement for an operation
319
+ * Use this for standalone latency tracking without a full span
320
+ */
321
+ recordLatency(operation, latencyMs) {
322
+ this.latencyValues.push(latencyMs);
323
+ // Track by operation type (similar to span type)
324
+ const currentCount = this.spansByType.get(operation) ?? 0;
325
+ this.spansByType.set(operation, currentCount + 1);
326
+ // Update timestamps
327
+ const now = new Date();
328
+ if (!this.firstSpanTime) {
329
+ this.firstSpanTime = now;
330
+ }
331
+ this.lastSpanTime = now;
332
+ // Increment success count (standalone latency records are assumed successful)
333
+ this.successCount++;
334
+ }
335
+ /**
336
+ * Get comprehensive metrics summary (alias for getSummary)
337
+ */
338
+ getMetrics() {
339
+ return this.getSummary();
340
+ }
341
+ /**
342
+ * Get comprehensive metrics summary
343
+ */
344
+ getSummary() {
345
+ const totalSpans = this.successCount + this.failureCount;
346
+ return {
347
+ totalSpans,
348
+ successfulSpans: this.successCount,
349
+ failedSpans: this.failureCount,
350
+ successRate: totalSpans > 0 ? this.successCount / totalSpans : 1,
351
+ latency: this.getLatencyStats(),
352
+ tokens: this.getTokenStats(),
353
+ costByProvider: this.getCostByProvider(),
354
+ costByModel: this.getCostByModel(),
355
+ totalCost: this.getTotalCost(),
356
+ spansByType: Object.fromEntries(this.spansByType),
357
+ firstSpanTime: this.firstSpanTime,
358
+ lastSpanTime: this.lastSpanTime,
359
+ trackingDurationMs: this.firstSpanTime && this.lastSpanTime
360
+ ? this.lastSpanTime.getTime() - this.firstSpanTime.getTime()
361
+ : undefined,
362
+ };
363
+ }
364
+ /**
365
+ * Get all recorded spans (returns a copy)
366
+ */
367
+ getSpans() {
368
+ return [...this.spans];
369
+ }
370
+ /**
371
+ * Get spans grouped by traceId as hierarchical trace views
372
+ */
373
+ getTraces() {
374
+ const traceMap = new Map();
375
+ for (const span of this.spans) {
376
+ const existing = traceMap.get(span.traceId) || [];
377
+ existing.push(span);
378
+ traceMap.set(span.traceId, existing);
379
+ }
380
+ const traces = [];
381
+ for (const [traceId, spans] of traceMap) {
382
+ // Root span is the one with no parentSpanId, or first span if all have parents
383
+ const rootSpan = spans.find((s) => !s.parentSpanId) || spans[0];
384
+ const childSpans = spans.filter((s) => s !== rootSpan);
385
+ // Calculate total duration
386
+ let totalDurationMs = 0;
387
+ for (const s of spans) {
388
+ if (s.durationMs) {
389
+ totalDurationMs = Math.max(totalDurationMs, s.durationMs);
390
+ }
391
+ }
392
+ // Determine status
393
+ const hasError = spans.some((s) => s.status === 2); // SpanStatus.ERROR
394
+ const allOk = spans.every((s) => s.status === 1); // SpanStatus.OK
395
+ const status = hasError
396
+ ? "error"
397
+ : allOk
398
+ ? "ok"
399
+ : "partial";
400
+ traces.push({
401
+ traceId,
402
+ rootSpan,
403
+ childSpans,
404
+ totalDurationMs,
405
+ spanCount: spans.length,
406
+ status,
407
+ });
408
+ }
409
+ return traces;
410
+ }
411
+ /**
412
+ * Get the underlying token tracker for custom pricing configuration
413
+ */
414
+ getTokenTracker() {
415
+ return this.tokenTracker;
416
+ }
417
+ /**
418
+ * Reset all metrics
419
+ */
420
+ reset() {
421
+ this.spans = [];
422
+ this.latencyValues = [];
423
+ this.tokenTracker.reset();
424
+ this.timeWindows.clear();
425
+ this.spansByType.clear();
426
+ this.costByProvider.clear();
427
+ this.costByModel.clear();
428
+ this.successCount = 0;
429
+ this.failureCount = 0;
430
+ this.firstSpanTime = undefined;
431
+ this.lastSpanTime = undefined;
432
+ }
433
+ /**
434
+ * Export metrics as JSON
435
+ */
436
+ toJSON() {
437
+ const summary = this.getSummary();
438
+ return {
439
+ totalSpans: summary.totalSpans,
440
+ successfulSpans: summary.successfulSpans,
441
+ failedSpans: summary.failedSpans,
442
+ successRate: summary.successRate,
443
+ latency: summary.latency,
444
+ tokens: this.tokenTracker.toJSON(),
445
+ costByProvider: summary.costByProvider,
446
+ costByModel: summary.costByModel,
447
+ totalCost: summary.totalCost,
448
+ spansByType: summary.spansByType,
449
+ firstSpanTime: summary.firstSpanTime?.toISOString(),
450
+ lastSpanTime: summary.lastSpanTime?.toISOString(),
451
+ trackingDurationMs: summary.trackingDurationMs,
452
+ timeWindows: this.config.enableTimeWindows
453
+ ? this.getTimeWindows().map((w) => ({
454
+ windowStart: w.windowStart.toISOString(),
455
+ windowEnd: w.windowEnd.toISOString(),
456
+ requestCount: w.requestCount,
457
+ errorCount: w.errorCount,
458
+ successRate: w.successRate,
459
+ throughput: w.throughput,
460
+ }))
461
+ : undefined,
462
+ };
463
+ }
464
+ /**
465
+ * Format cost as currency string
466
+ */
467
+ formatCost(cost, currency = "USD") {
468
+ return new Intl.NumberFormat("en-US", {
469
+ style: "currency",
470
+ currency,
471
+ minimumFractionDigits: 4,
472
+ }).format(cost);
473
+ }
474
+ /**
475
+ * Get a formatted summary string
476
+ */
477
+ getFormattedSummary() {
478
+ const summary = this.getSummary();
479
+ const latency = summary.latency;
480
+ const lines = [
481
+ "=== Metrics Summary ===",
482
+ "",
483
+ "Request Statistics:",
484
+ ` Total requests: ${summary.totalSpans.toLocaleString()}`,
485
+ ` Successful: ${summary.successfulSpans.toLocaleString()}`,
486
+ ` Failed: ${summary.failedSpans.toLocaleString()}`,
487
+ ` Success rate: ${(summary.successRate * 100).toFixed(2)}%`,
488
+ "",
489
+ "Latency (ms):",
490
+ ` Min: ${latency.min.toFixed(2)}`,
491
+ ` Max: ${latency.max.toFixed(2)}`,
492
+ ` Mean: ${latency.mean.toFixed(2)}`,
493
+ ` P50: ${latency.p50.toFixed(2)}`,
494
+ ` P95: ${latency.p95.toFixed(2)}`,
495
+ ` P99: ${latency.p99.toFixed(2)}`,
496
+ "",
497
+ "Token Usage:",
498
+ ` Input tokens: ${summary.tokens.totalInputTokens.toLocaleString()}`,
499
+ ` Output tokens: ${summary.tokens.totalOutputTokens.toLocaleString()}`,
500
+ ` Total tokens: ${summary.tokens.totalTokens.toLocaleString()}`,
501
+ "",
502
+ "Cost:",
503
+ ` Total: ${this.formatCost(summary.totalCost)}`,
504
+ ];
505
+ // Add cost by provider
506
+ if (summary.costByProvider.length > 0) {
507
+ lines.push("");
508
+ lines.push("Cost by Provider:");
509
+ for (const providerCost of summary.costByProvider) {
510
+ lines.push(` ${providerCost.provider}: ${this.formatCost(providerCost.totalCost)} (${providerCost.requestCount} requests)`);
511
+ }
512
+ }
513
+ // Add cost by model
514
+ if (summary.costByModel.length > 0) {
515
+ lines.push("");
516
+ lines.push("Cost by Model:");
517
+ for (const modelCost of summary.costByModel) {
518
+ lines.push(` ${modelCost.model}: ${this.formatCost(modelCost.totalCost)} (${modelCost.requestCount} requests)`);
519
+ }
520
+ }
521
+ // Add tracking duration
522
+ if (summary.trackingDurationMs) {
523
+ const durationSec = summary.trackingDurationMs / 1000;
524
+ const throughput = summary.totalSpans / durationSec;
525
+ lines.push("");
526
+ lines.push(`Tracking duration: ${durationSec.toFixed(1)}s (${throughput.toFixed(2)} req/s)`);
527
+ }
528
+ return lines.join("\n");
529
+ }
530
+ }
531
+ /**
532
+ * Global metrics aggregator instance (singleton pattern from main)
533
+ */
534
+ let globalMetricsAggregator = null;
535
+ /**
536
+ * Get the global metrics aggregator instance
537
+ */
538
+ export function getMetricsAggregator() {
539
+ if (!globalMetricsAggregator) {
540
+ globalMetricsAggregator = new MetricsAggregator();
541
+ }
542
+ return globalMetricsAggregator;
543
+ }
544
+ /**
545
+ * Reset the global metrics aggregator (for testing)
546
+ */
547
+ export function resetMetricsAggregator() {
548
+ if (globalMetricsAggregator) {
549
+ globalMetricsAggregator.reset();
550
+ }
551
+ globalMetricsAggregator = null;
552
+ }
553
+ //# sourceMappingURL=metricsAggregator.js.map
@@ -0,0 +1,49 @@
1
+ /**
2
+ * OpenTelemetry Bridge
3
+ * Bidirectional context propagation between NeuroLink and OpenTelemetry
4
+ */
5
+ import { type SpanContext } from "@opentelemetry/api";
6
+ import type { SpanData } from "./types/spanTypes.js";
7
+ import { type SpanType } from "./types/spanTypes.js";
8
+ /**
9
+ * Bridge for bidirectional context propagation between
10
+ * NeuroLink's observability system and OpenTelemetry
11
+ */
12
+ export declare class OtelBridge {
13
+ private readonly tracer;
14
+ /**
15
+ * Extract trace context from incoming request headers
16
+ */
17
+ extractContext(headers: Record<string, string>): SpanContext | null;
18
+ /**
19
+ * Inject trace context into outgoing request headers
20
+ */
21
+ injectContext(headers: Record<string, string>): Record<string, string>;
22
+ /**
23
+ * Create a NeuroLink span from OpenTelemetry context
24
+ */
25
+ createSpanFromOtelContext(spanContext: SpanContext, type: SpanType, name: string): SpanData;
26
+ /**
27
+ * Wrap a function with OpenTelemetry tracing that also creates NeuroLink spans
28
+ */
29
+ wrapWithTracing<T>(name: string, type: SpanType, fn: (span: SpanData) => Promise<T>, onSpanEnd?: (span: SpanData) => void): Promise<T>;
30
+ /**
31
+ * Convert NeuroLink span to OpenTelemetry span and export
32
+ */
33
+ exportToOtel(span: SpanData): void;
34
+ /**
35
+ * Get current trace context for correlation
36
+ */
37
+ getCurrentTraceContext(): {
38
+ traceId: string;
39
+ spanId: string;
40
+ } | null;
41
+ /**
42
+ * Filter attributes to only include OTel-compatible types
43
+ */
44
+ private filterAttributes;
45
+ /**
46
+ * Filter event attributes
47
+ */
48
+ private filterEventAttributes;
49
+ }