@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,689 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console, curly */
3
+ /**
4
+ * NeuroLink CLI Telemetry Commands
5
+ *
6
+ * Commands for managing telemetry and observability exporters:
7
+ * - status: Show exporter status
8
+ * - configure: Configure an exporter
9
+ * - list-exporters: List configured exporters
10
+ * - flush: Flush pending spans
11
+ * - stats: Show token/cost stats
12
+ */
13
+ import chalk from "chalk";
14
+ import ora from "ora";
15
+ import { logger } from "../../lib/utils/logger.js";
16
+ import { NeuroLink } from "../../lib/neurolink.js";
17
+ import { flushOpenTelemetry } from "../../lib/services/server/ai/observability/instrumentation.js";
18
+ import { formatRow, formatCost } from "../utils/formatters.js";
19
+ /**
20
+ * Available exporter names
21
+ */
22
+ const AVAILABLE_EXPORTERS = [
23
+ "langfuse",
24
+ "langsmith",
25
+ "otel",
26
+ "datadog",
27
+ "sentry",
28
+ "braintrust",
29
+ "arize",
30
+ "posthog",
31
+ "laminar",
32
+ ];
33
+ /**
34
+ * Telemetry Command Factory
35
+ */
36
+ export class TelemetryCommandFactory {
37
+ /**
38
+ * Create the telemetry command group
39
+ */
40
+ static createTelemetryCommands() {
41
+ return {
42
+ command: "telemetry <subcommand>",
43
+ aliases: ["tel"],
44
+ describe: "Telemetry and exporter management",
45
+ builder: (yargs) => {
46
+ return yargs
47
+ .command(TelemetryCommandFactory.createStatusCommand())
48
+ .command(TelemetryCommandFactory.createConfigureCommand())
49
+ .command(TelemetryCommandFactory.createListExportersCommand())
50
+ .command(TelemetryCommandFactory.createFlushCommand())
51
+ .command(TelemetryCommandFactory.createStatsCommand())
52
+ .demandCommand(1, "Please specify a subcommand")
53
+ .strict();
54
+ },
55
+ handler: () => {
56
+ // This handler is not called directly due to demandCommand
57
+ },
58
+ };
59
+ }
60
+ /**
61
+ * Create the status subcommand
62
+ */
63
+ static createStatusCommand() {
64
+ return {
65
+ command: "status",
66
+ describe: "Show exporter status and health",
67
+ builder: (yargs) => {
68
+ return yargs
69
+ .option("format", {
70
+ alias: "f",
71
+ type: "string",
72
+ choices: ["text", "json", "table"],
73
+ default: "text",
74
+ describe: "Output format",
75
+ })
76
+ .option("quiet", {
77
+ alias: "q",
78
+ type: "boolean",
79
+ default: false,
80
+ describe: "Minimal output",
81
+ });
82
+ },
83
+ handler: async (args) => {
84
+ const spinner = args.quiet
85
+ ? null
86
+ : ora("Checking exporter status...").start();
87
+ try {
88
+ const neurolink = new NeuroLink();
89
+ const status = neurolink.getTelemetryStatus();
90
+ if (spinner)
91
+ spinner.succeed("Status retrieved");
92
+ if (args.format === "json") {
93
+ console.log(JSON.stringify(status, null, 2));
94
+ }
95
+ else {
96
+ console.log("");
97
+ console.log(chalk.bold.cyan("=== Telemetry Status ==="));
98
+ console.log("");
99
+ // Telemetry enabled status
100
+ const enabledIcon = status.enabled
101
+ ? chalk.green("ENABLED")
102
+ : chalk.red("DISABLED");
103
+ console.log(formatRow("Telemetry:", enabledIcon));
104
+ // OpenTelemetry status
105
+ if (status.openTelemetry) {
106
+ console.log("");
107
+ console.log(chalk.bold("OpenTelemetry:"));
108
+ const otelStatus = status.openTelemetry.enabled
109
+ ? chalk.green("Active")
110
+ : chalk.gray("Inactive");
111
+ console.log(formatRow(" Status:", otelStatus));
112
+ if (status.openTelemetry.endpoint) {
113
+ console.log(formatRow(" Endpoint:", status.openTelemetry.endpoint));
114
+ }
115
+ if (status.openTelemetry.serviceName) {
116
+ console.log(formatRow(" Service:", status.openTelemetry.serviceName));
117
+ }
118
+ }
119
+ // Langfuse status
120
+ if (status.langfuse) {
121
+ console.log("");
122
+ console.log(chalk.bold("Langfuse:"));
123
+ const lfStatus = status.langfuse.enabled
124
+ ? chalk.green("Active")
125
+ : chalk.gray("Inactive");
126
+ console.log(formatRow(" Status:", lfStatus));
127
+ if (status.langfuse.baseUrl) {
128
+ console.log(formatRow(" URL:", status.langfuse.baseUrl));
129
+ }
130
+ if (status.langfuse.environment) {
131
+ console.log(formatRow(" Environment:", status.langfuse.environment));
132
+ }
133
+ }
134
+ // Exporters health summary
135
+ if (status.exporters && status.exporters.length > 0) {
136
+ console.log("");
137
+ console.log(chalk.bold("Exporter Health:"));
138
+ for (const exporter of status.exporters) {
139
+ const healthIcon = exporter.healthy
140
+ ? chalk.green("[OK]")
141
+ : chalk.red("[ERROR]");
142
+ const pendingInfo = exporter.pendingSpans
143
+ ? chalk.gray(` (${exporter.pendingSpans} pending)`)
144
+ : "";
145
+ console.log(` ${healthIcon} ${exporter.name}${pendingInfo}`);
146
+ if (exporter.errors && exporter.errors.length > 0) {
147
+ for (const error of exporter.errors.slice(0, 2)) {
148
+ console.log(chalk.red(` Error: ${error}`));
149
+ }
150
+ }
151
+ }
152
+ }
153
+ else {
154
+ console.log("");
155
+ console.log(chalk.gray("No exporters configured."));
156
+ }
157
+ console.log("");
158
+ }
159
+ }
160
+ catch (error) {
161
+ if (spinner)
162
+ spinner.fail("Failed to get status");
163
+ logger.error("Error:", error instanceof Error ? error.message : String(error));
164
+ process.exit(1);
165
+ }
166
+ },
167
+ };
168
+ }
169
+ /**
170
+ * Create the configure subcommand
171
+ */
172
+ static createConfigureCommand() {
173
+ return {
174
+ command: "configure",
175
+ describe: "Configure an exporter with JSON settings",
176
+ builder: (yargs) => {
177
+ return yargs
178
+ .option("exporter", {
179
+ alias: "e",
180
+ type: "string",
181
+ demandOption: true,
182
+ choices: AVAILABLE_EXPORTERS,
183
+ describe: "Exporter name to configure",
184
+ })
185
+ .option("config", {
186
+ alias: "c",
187
+ type: "string",
188
+ demandOption: true,
189
+ describe: "JSON configuration string",
190
+ })
191
+ .option("format", {
192
+ alias: "f",
193
+ type: "string",
194
+ choices: ["text", "json", "table"],
195
+ default: "text",
196
+ describe: "Output format",
197
+ })
198
+ .option("quiet", {
199
+ alias: "q",
200
+ type: "boolean",
201
+ default: false,
202
+ describe: "Minimal output",
203
+ });
204
+ },
205
+ handler: async (args) => {
206
+ const spinner = args.quiet
207
+ ? null
208
+ : ora(`Configuring ${args.exporter} exporter...`).start();
209
+ try {
210
+ // Parse the JSON config
211
+ let config;
212
+ try {
213
+ config = JSON.parse(args.config);
214
+ }
215
+ catch {
216
+ if (spinner)
217
+ spinner.fail("Invalid JSON configuration");
218
+ console.log(chalk.red("Error: Configuration must be valid JSON"));
219
+ console.log("");
220
+ console.log("Example:");
221
+ console.log(chalk.gray(` neurolink telemetry configure --exporter langfuse --config '{"publicKey":"pk-...", "secretKey":"sk-..."}'`));
222
+ process.exit(1);
223
+ }
224
+ // Validate required fields based on exporter type
225
+ const validationResult = validateExporterConfig(args.exporter, config);
226
+ if (!validationResult.valid) {
227
+ if (spinner)
228
+ spinner.fail("Configuration validation failed");
229
+ console.log(chalk.red(`Error: ${validationResult.error}`));
230
+ console.log("");
231
+ console.log(chalk.yellow(`Required fields for ${args.exporter}:`));
232
+ for (const field of validationResult.requiredFields ?? []) {
233
+ console.log(chalk.gray(` - ${field}`));
234
+ }
235
+ process.exit(1);
236
+ }
237
+ // Currently, exporter configuration is done via environment variables
238
+ // or SDK initialization. This command provides guidance on how to configure.
239
+ if (spinner)
240
+ spinner.succeed(`${args.exporter} configuration validated`);
241
+ if (args.format === "json") {
242
+ console.log(JSON.stringify({
243
+ exporter: args.exporter,
244
+ config: config,
245
+ valid: true,
246
+ message: "Configuration validated. Set environment variables or use SDK initialization.",
247
+ }, null, 2));
248
+ }
249
+ else {
250
+ console.log("");
251
+ console.log(chalk.bold.cyan(`=== ${args.exporter} Configuration ===`));
252
+ console.log("");
253
+ console.log(chalk.green("Configuration validated successfully!"));
254
+ console.log("");
255
+ console.log(chalk.bold("To apply this configuration:"));
256
+ console.log("");
257
+ // Show environment variable instructions
258
+ const envVars = getExporterEnvVars(args.exporter);
259
+ console.log(chalk.yellow("Option 1: Set environment variables"));
260
+ for (const [key, description] of Object.entries(envVars)) {
261
+ console.log(chalk.gray(` export ${key}="<${description}>"`));
262
+ }
263
+ console.log("");
264
+ console.log(chalk.yellow("Option 2: SDK initialization"));
265
+ console.log(chalk.gray(` const neurolink = new NeuroLink({`));
266
+ console.log(chalk.gray(` observability: {`));
267
+ console.log(chalk.gray(` ${args.exporter}: ${JSON.stringify(config, null, 6).split("\n").join("\n ")}`));
268
+ console.log(chalk.gray(` }`));
269
+ console.log(chalk.gray(` });`));
270
+ console.log("");
271
+ }
272
+ }
273
+ catch (error) {
274
+ if (spinner)
275
+ spinner.fail("Failed to configure exporter");
276
+ logger.error("Error:", error instanceof Error ? error.message : String(error));
277
+ process.exit(1);
278
+ }
279
+ },
280
+ };
281
+ }
282
+ /**
283
+ * Create the list-exporters subcommand
284
+ */
285
+ static createListExportersCommand() {
286
+ return {
287
+ command: "list-exporters",
288
+ aliases: ["list", "ls"],
289
+ describe: "List all available and configured exporters",
290
+ builder: (yargs) => {
291
+ return yargs
292
+ .option("format", {
293
+ alias: "f",
294
+ type: "string",
295
+ choices: ["text", "json", "table"],
296
+ default: "text",
297
+ describe: "Output format",
298
+ })
299
+ .option("quiet", {
300
+ alias: "q",
301
+ type: "boolean",
302
+ default: false,
303
+ describe: "Minimal output",
304
+ });
305
+ },
306
+ handler: async (args) => {
307
+ const spinner = args.quiet ? null : ora("Listing exporters...").start();
308
+ try {
309
+ const neurolink = new NeuroLink();
310
+ const status = neurolink.getTelemetryStatus();
311
+ if (spinner)
312
+ spinner.succeed("Exporters listed");
313
+ const configuredExporters = status.exporters ?? [];
314
+ const configuredNames = new Set(configuredExporters.map((e) => e.name.toLowerCase()));
315
+ if (args.format === "json") {
316
+ console.log(JSON.stringify({
317
+ available: AVAILABLE_EXPORTERS,
318
+ configured: configuredExporters,
319
+ }, null, 2));
320
+ }
321
+ else {
322
+ console.log("");
323
+ console.log(chalk.bold.cyan("=== Available Exporters ==="));
324
+ console.log("");
325
+ for (const exporter of AVAILABLE_EXPORTERS) {
326
+ const isConfigured = configuredNames.has(exporter);
327
+ const configuredExporter = configuredExporters.find((e) => e.name.toLowerCase() === exporter);
328
+ const statusIcon = isConfigured
329
+ ? configuredExporter?.healthy
330
+ ? chalk.green("[ACTIVE]")
331
+ : chalk.yellow("[CONFIGURED]")
332
+ : chalk.gray("[AVAILABLE]");
333
+ const description = getExporterDescription(exporter);
334
+ console.log(`${statusIcon} ${chalk.bold(exporter)}`);
335
+ console.log(chalk.gray(` ${description}`));
336
+ if (isConfigured && configuredExporter) {
337
+ if (configuredExporter.pendingSpans) {
338
+ console.log(chalk.gray(` Pending spans: ${configuredExporter.pendingSpans}`));
339
+ }
340
+ if (configuredExporter.lastExportTime) {
341
+ const lastExport = new Date(configuredExporter.lastExportTime);
342
+ console.log(chalk.gray(` Last export: ${lastExport.toISOString()}`));
343
+ }
344
+ }
345
+ console.log("");
346
+ }
347
+ console.log(chalk.bold("Configuration Help:"));
348
+ console.log(chalk.gray(" Use 'neurolink telemetry configure --exporter <name> --config <json>' to configure an exporter"));
349
+ console.log("");
350
+ }
351
+ }
352
+ catch (error) {
353
+ if (spinner)
354
+ spinner.fail("Failed to list exporters");
355
+ logger.error("Error:", error instanceof Error ? error.message : String(error));
356
+ process.exit(1);
357
+ }
358
+ },
359
+ };
360
+ }
361
+ /**
362
+ * Create the flush subcommand
363
+ */
364
+ static createFlushCommand() {
365
+ return {
366
+ command: "flush",
367
+ describe: "Flush all pending spans to exporters",
368
+ builder: (yargs) => {
369
+ return yargs
370
+ .option("timeout", {
371
+ alias: "t",
372
+ type: "number",
373
+ default: 30000,
374
+ describe: "Timeout in milliseconds",
375
+ })
376
+ .option("format", {
377
+ alias: "f",
378
+ type: "string",
379
+ choices: ["text", "json", "table"],
380
+ default: "text",
381
+ describe: "Output format",
382
+ })
383
+ .option("quiet", {
384
+ alias: "q",
385
+ type: "boolean",
386
+ default: false,
387
+ describe: "Minimal output",
388
+ });
389
+ },
390
+ handler: async (args) => {
391
+ const spinner = args.quiet
392
+ ? null
393
+ : ora("Flushing pending spans...").start();
394
+ try {
395
+ const neurolink = new NeuroLink();
396
+ const statusBefore = neurolink.getTelemetryStatus();
397
+ // Count pending spans before flush
398
+ const pendingBefore = statusBefore.exporters?.reduce((sum, e) => sum + (e.pendingSpans ?? 0), 0) ?? 0;
399
+ // Create a timeout promise
400
+ const timeoutPromise = new Promise((_, reject) => {
401
+ setTimeout(() => reject(new Error("Flush operation timed out")), args.timeout ?? 30000);
402
+ });
403
+ // Flush OpenTelemetry spans
404
+ const flushPromise = flushOpenTelemetry();
405
+ // Race between flush and timeout
406
+ await Promise.race([flushPromise, timeoutPromise]);
407
+ // Get status after flush
408
+ const statusAfter = neurolink.getTelemetryStatus();
409
+ const pendingAfter = statusAfter.exporters?.reduce((sum, e) => sum + (e.pendingSpans ?? 0), 0) ?? 0;
410
+ const flushedCount = Math.max(0, pendingBefore - pendingAfter);
411
+ if (spinner)
412
+ spinner.succeed("Flush completed");
413
+ if (args.format === "json") {
414
+ console.log(JSON.stringify({
415
+ success: true,
416
+ pendingBefore,
417
+ pendingAfter,
418
+ flushed: flushedCount,
419
+ }, null, 2));
420
+ }
421
+ else {
422
+ console.log("");
423
+ console.log(chalk.bold.cyan("=== Flush Complete ==="));
424
+ console.log("");
425
+ console.log(formatRow("Spans before:", pendingBefore.toString()));
426
+ console.log(formatRow("Spans after:", pendingAfter.toString()));
427
+ console.log(formatRow("Flushed:", chalk.green(flushedCount.toString())));
428
+ console.log("");
429
+ }
430
+ }
431
+ catch (error) {
432
+ if (spinner)
433
+ spinner.fail("Failed to flush spans");
434
+ logger.error("Error:", error instanceof Error ? error.message : String(error));
435
+ process.exit(1);
436
+ }
437
+ },
438
+ };
439
+ }
440
+ /**
441
+ * Create the stats subcommand
442
+ */
443
+ static createStatsCommand() {
444
+ return {
445
+ command: "stats",
446
+ describe: "Show token usage and cost statistics",
447
+ builder: (yargs) => {
448
+ return yargs
449
+ .option("format", {
450
+ alias: "f",
451
+ type: "string",
452
+ choices: ["text", "json", "table"],
453
+ default: "text",
454
+ describe: "Output format",
455
+ })
456
+ .option("detailed", {
457
+ alias: "d",
458
+ type: "boolean",
459
+ default: false,
460
+ describe: "Show detailed statistics",
461
+ })
462
+ .option("by-model", {
463
+ alias: "m",
464
+ type: "boolean",
465
+ default: true,
466
+ describe: "Show breakdown by model",
467
+ })
468
+ .option("by-provider", {
469
+ alias: "p",
470
+ type: "boolean",
471
+ default: true,
472
+ describe: "Show breakdown by provider",
473
+ })
474
+ .option("quiet", {
475
+ alias: "q",
476
+ type: "boolean",
477
+ default: false,
478
+ describe: "Minimal output",
479
+ });
480
+ },
481
+ handler: async (args) => {
482
+ const spinner = args.quiet
483
+ ? null
484
+ : ora("Gathering statistics...").start();
485
+ try {
486
+ const neurolink = new NeuroLink();
487
+ const metrics = neurolink.getMetrics();
488
+ if (spinner)
489
+ spinner.succeed("Statistics retrieved");
490
+ if (args.format === "json") {
491
+ console.log(JSON.stringify({
492
+ tokens: {
493
+ input: metrics.tokens.totalInputTokens,
494
+ output: metrics.tokens.totalOutputTokens,
495
+ total: metrics.tokens.totalTokens,
496
+ cacheRead: metrics.tokens.cacheReadTokens,
497
+ reasoning: metrics.tokens.reasoningTokens,
498
+ },
499
+ cost: {
500
+ total: metrics.totalCost,
501
+ byProvider: metrics.costByProvider,
502
+ byModel: metrics.costByModel,
503
+ },
504
+ requests: {
505
+ total: metrics.totalSpans,
506
+ successful: metrics.successfulSpans,
507
+ failed: metrics.failedSpans,
508
+ successRate: metrics.successRate,
509
+ },
510
+ latency: metrics.latency,
511
+ }, null, 2));
512
+ }
513
+ else {
514
+ console.log("");
515
+ console.log(chalk.bold.cyan("=== Token & Cost Statistics ==="));
516
+ console.log("");
517
+ // Token usage
518
+ console.log(chalk.bold("Token Usage:"));
519
+ console.log(formatRow(" Input tokens:", metrics.tokens.totalInputTokens.toLocaleString()));
520
+ console.log(formatRow(" Output tokens:", metrics.tokens.totalOutputTokens.toLocaleString()));
521
+ console.log(formatRow(" Total tokens:", metrics.tokens.totalTokens.toLocaleString()));
522
+ if (args.detailed) {
523
+ if (metrics.tokens.cacheReadTokens > 0) {
524
+ console.log(formatRow(" Cache read:", metrics.tokens.cacheReadTokens.toLocaleString()));
525
+ }
526
+ if (metrics.tokens.reasoningTokens > 0) {
527
+ console.log(formatRow(" Reasoning:", metrics.tokens.reasoningTokens.toLocaleString()));
528
+ }
529
+ }
530
+ // Cost summary
531
+ console.log("");
532
+ console.log(chalk.bold("Cost Summary:"));
533
+ console.log(formatRow(" Total cost:", formatCost(metrics.totalCost ?? 0)));
534
+ // Cost by provider
535
+ if (args.byProvider !== false &&
536
+ metrics.costByProvider &&
537
+ metrics.costByProvider.length > 0) {
538
+ console.log("");
539
+ console.log(chalk.bold("Cost by Provider:"));
540
+ const sortedProviders = [...metrics.costByProvider].sort((a, b) => b.totalCost - a.totalCost);
541
+ for (const provider of sortedProviders) {
542
+ console.log(` ${chalk.cyan(provider.provider.padEnd(15))} ${formatCost(provider.totalCost)}`);
543
+ console.log(chalk.gray(` ${provider.requestCount} requests, avg ${formatCost(provider.avgCostPerRequest)}/req`));
544
+ }
545
+ }
546
+ // Cost by model
547
+ if (args.byModel !== false &&
548
+ metrics.costByModel &&
549
+ metrics.costByModel.length > 0) {
550
+ console.log("");
551
+ console.log(chalk.bold("Cost by Model:"));
552
+ const sortedModels = [...metrics.costByModel].sort((a, b) => b.totalCost - a.totalCost);
553
+ for (const model of sortedModels) {
554
+ console.log(` ${chalk.cyan(model.model)}`);
555
+ console.log(` Cost: ${formatCost(model.totalCost)}`);
556
+ console.log(chalk.gray(` ${model.requestCount} requests, avg ${formatCost(model.avgCostPerRequest)}/req`));
557
+ if (args.detailed) {
558
+ console.log(chalk.gray(` ${model.inputTokens.toLocaleString()} input, ${model.outputTokens.toLocaleString()} output tokens`));
559
+ }
560
+ }
561
+ }
562
+ // Request statistics
563
+ console.log("");
564
+ console.log(chalk.bold("Request Statistics:"));
565
+ console.log(formatRow(" Total requests:", metrics.totalSpans.toLocaleString()));
566
+ console.log(formatRow(" Successful:", metrics.successfulSpans.toLocaleString()));
567
+ console.log(formatRow(" Failed:", metrics.failedSpans.toLocaleString()));
568
+ console.log(formatRow(" Success rate:", `${(metrics.successRate * 100).toFixed(2)}%`));
569
+ // Latency (if detailed)
570
+ if (args.detailed && metrics.latency.count > 0) {
571
+ console.log("");
572
+ console.log(chalk.bold("Latency (ms):"));
573
+ console.log(formatRow(" P50:", metrics.latency.p50.toFixed(2)));
574
+ console.log(formatRow(" P95:", metrics.latency.p95.toFixed(2)));
575
+ console.log(formatRow(" P99:", metrics.latency.p99.toFixed(2)));
576
+ }
577
+ // Tracking duration
578
+ if (metrics.trackingDurationMs) {
579
+ const durationSec = metrics.trackingDurationMs / 1000;
580
+ const throughput = metrics.totalSpans > 0 ? metrics.totalSpans / durationSec : 0;
581
+ console.log("");
582
+ console.log(chalk.gray(`Tracking: ${durationSec.toFixed(1)}s (${throughput.toFixed(2)} req/s)`));
583
+ }
584
+ console.log("");
585
+ }
586
+ }
587
+ catch (error) {
588
+ if (spinner)
589
+ spinner.fail("Failed to get statistics");
590
+ logger.error("Error:", error instanceof Error ? error.message : String(error));
591
+ process.exit(1);
592
+ }
593
+ },
594
+ };
595
+ }
596
+ }
597
+ /**
598
+ * Validate exporter configuration
599
+ */
600
+ function validateExporterConfig(exporter, config) {
601
+ const requiredFieldsMap = {
602
+ langfuse: ["publicKey", "secretKey"],
603
+ langsmith: ["apiKey"],
604
+ otel: ["endpoint"],
605
+ datadog: ["apiKey"],
606
+ sentry: ["dsn"],
607
+ braintrust: ["apiKey", "projectName"],
608
+ arize: ["spaceKey", "apiKey"],
609
+ posthog: ["apiKey"],
610
+ laminar: ["apiKey"],
611
+ };
612
+ const requiredFields = requiredFieldsMap[exporter];
613
+ const missingFields = requiredFields.filter((field) => !(field in config) || !config[field]);
614
+ if (missingFields.length > 0) {
615
+ return {
616
+ valid: false,
617
+ error: `Missing required fields: ${missingFields.join(", ")}`,
618
+ requiredFields,
619
+ };
620
+ }
621
+ return { valid: true };
622
+ }
623
+ /**
624
+ * Get environment variable names for an exporter
625
+ */
626
+ function getExporterEnvVars(exporter) {
627
+ const envVarsMap = {
628
+ langfuse: {
629
+ LANGFUSE_PUBLIC_KEY: "your-public-key",
630
+ LANGFUSE_SECRET_KEY: "your-secret-key",
631
+ LANGFUSE_BASEURL: "https://cloud.langfuse.com (optional)",
632
+ },
633
+ langsmith: {
634
+ LANGCHAIN_API_KEY: "your-api-key",
635
+ LANGCHAIN_PROJECT: "your-project-name (optional)",
636
+ LANGCHAIN_ENDPOINT: "https://api.smith.langchain.com (optional)",
637
+ },
638
+ otel: {
639
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
640
+ OTEL_SERVICE_NAME: "your-service-name",
641
+ OTEL_EXPORTER_OTLP_PROTOCOL: "http (or grpc)",
642
+ },
643
+ datadog: {
644
+ DD_API_KEY: "your-api-key",
645
+ DD_SITE: "datadoghq.com (or regional site)",
646
+ DD_SERVICE: "your-service-name",
647
+ },
648
+ sentry: {
649
+ SENTRY_DSN: "your-dsn-url",
650
+ SENTRY_TRACES_SAMPLE_RATE: "1.0 (optional)",
651
+ SENTRY_RELEASE: "your-release-version (optional)",
652
+ },
653
+ braintrust: {
654
+ BRAINTRUST_API_KEY: "your-api-key",
655
+ BRAINTRUST_PROJECT: "your-project-name",
656
+ },
657
+ arize: {
658
+ ARIZE_SPACE_KEY: "your-space-key",
659
+ ARIZE_API_KEY: "your-api-key",
660
+ },
661
+ posthog: {
662
+ POSTHOG_API_KEY: "your-api-key",
663
+ POSTHOG_HOST: "https://app.posthog.com (optional)",
664
+ },
665
+ laminar: {
666
+ LAMINAR_API_KEY: "your-api-key",
667
+ LAMINAR_BASE_URL: "https://api.laminar.run (optional)",
668
+ },
669
+ };
670
+ return envVarsMap[exporter];
671
+ }
672
+ /**
673
+ * Get description for an exporter
674
+ */
675
+ function getExporterDescription(exporter) {
676
+ const descriptions = {
677
+ langfuse: "Open-source LLM observability platform with traces and analytics",
678
+ langsmith: "LangChain's platform for LLM application debugging and monitoring",
679
+ otel: "OpenTelemetry Protocol (OTLP) for distributed tracing",
680
+ datadog: "APM and infrastructure monitoring platform",
681
+ sentry: "Error tracking and performance monitoring",
682
+ braintrust: "AI evaluation and experimentation platform",
683
+ arize: "ML observability platform for model monitoring",
684
+ posthog: "Product analytics with LLM event tracking",
685
+ laminar: "LLM application monitoring and debugging",
686
+ };
687
+ return descriptions[exporter];
688
+ }
689
+ //# sourceMappingURL=telemetry.js.map