@juspay/neurolink 12.59.0 → 13.0.1

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 (146) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/dist/auth/anthropicOAuth.js +3 -3
  3. package/dist/auth/middleware/AuthMiddleware.d.ts +1 -1
  4. package/dist/auth/sessionManager.js +4 -4
  5. package/dist/auth/tokenStore.js +4 -4
  6. package/dist/browser/neurolink.min.js +474 -473
  7. package/dist/cli/commands/observability.d.ts +1 -6
  8. package/dist/cli/commands/observability.js +0 -106
  9. package/dist/cli/commands/proxy.js +9 -18
  10. package/dist/cli/commands/telemetry.d.ts +3 -13
  11. package/dist/cli/commands/telemetry.js +7 -354
  12. package/dist/cli/loop/session.js +1 -1
  13. package/dist/client/httpClient.js +1 -1
  14. package/dist/client/sseClient.js +1 -1
  15. package/dist/client/streamingClient.js +2 -2
  16. package/dist/client/wsClient.js +1 -1
  17. package/dist/constants/langfuse.d.ts +25 -0
  18. package/dist/constants/langfuse.js +38 -0
  19. package/dist/constants/telemetry.d.ts +20 -0
  20. package/dist/constants/telemetry.js +34 -0
  21. package/dist/core/baseProvider.d.ts +2 -1
  22. package/dist/core/baseProvider.js +4 -11
  23. package/dist/core/conversationMemoryManager.js +5 -8
  24. package/dist/core/factory.js +1 -1
  25. package/dist/core/geminiLoopAdapter.d.ts +8 -1
  26. package/dist/core/geminiLoopAdapter.js +25 -1
  27. package/dist/core/loopEngine.js +69 -40
  28. package/dist/core/modules/MessageBuilder.js +2 -2
  29. package/dist/core/modules/StreamHandler.js +2 -2
  30. package/dist/core/modules/TelemetryHandler.d.ts +2 -18
  31. package/dist/core/modules/TelemetryHandler.js +1 -66
  32. package/dist/core/modules/ToolsManager.js +40 -31
  33. package/dist/core/nativeGenerateLoop.js +78 -8
  34. package/dist/core/redisConversationMemoryManager.js +8 -15
  35. package/dist/core/toolExecutionGuards.js +1 -13
  36. package/dist/index.d.ts +5 -12
  37. package/dist/index.js +5 -37
  38. package/dist/mcp/batching/requestBatcher.js +1 -1
  39. package/dist/mcp/externalServerManager.js +3 -21
  40. package/dist/mcp/toolDiscoveryService.js +4 -16
  41. package/dist/mcp/toolRegistry.js +2 -5
  42. package/dist/memory/memoryRetrievalTools.js +1 -1
  43. package/dist/neurolink.d.ts +16 -27
  44. package/dist/neurolink.js +788 -792
  45. package/dist/observability/exporterSpanProcessor.d.ts +50 -0
  46. package/dist/observability/exporterSpanProcessor.js +181 -0
  47. package/dist/observability/exporters/langfuseExporter.d.ts +13 -34
  48. package/dist/observability/exporters/langfuseExporter.js +101 -154
  49. package/dist/observability/index.d.ts +1 -0
  50. package/dist/observability/index.js +1 -0
  51. package/dist/observability/langfuseMasking.d.ts +8 -0
  52. package/dist/observability/langfuseMasking.js +47 -0
  53. package/dist/observability/otlpEncoding.d.ts +20 -0
  54. package/dist/observability/otlpEncoding.js +85 -0
  55. package/dist/providers/amazonBedrock/client.js +142 -176
  56. package/dist/providers/amazonBedrock/loopAdapter.js +14 -1
  57. package/dist/providers/amazonSagemaker.js +118 -80
  58. package/dist/providers/anthropic/client.js +3 -52
  59. package/dist/providers/anthropic/loopAdapter.js +24 -1
  60. package/dist/providers/anthropic/rateLimitCapture.js +9 -12
  61. package/dist/providers/googleAiStudio/client.d.ts +4 -5
  62. package/dist/providers/googleAiStudio/client.js +38 -40
  63. package/dist/providers/googleVertex/client.d.ts +2 -7
  64. package/dist/providers/googleVertex/client.js +282 -378
  65. package/dist/providers/googleVertex/constants.js +2 -2
  66. package/dist/providers/litellm/client.d.ts +2 -9
  67. package/dist/providers/litellm/client.js +1 -63
  68. package/dist/providers/openAI/client.d.ts +1 -8
  69. package/dist/providers/openAI/client.js +0 -65
  70. package/dist/providers/openaiChatCompletionsBase.d.ts +1 -0
  71. package/dist/providers/openaiChatCompletionsBase.js +61 -4
  72. package/dist/providers/replicate.js +22 -4
  73. package/dist/proxy/codexUsage.js +7 -0
  74. package/dist/proxy/proxyFetch.js +19 -25
  75. package/dist/proxy/proxyTracer.d.ts +14 -7
  76. package/dist/proxy/proxyTracer.js +129 -83
  77. package/dist/proxy/proxyTranslationEngine.js +0 -1
  78. package/dist/proxy/requestLogger.d.ts +1 -1
  79. package/dist/proxy/requestLogger.js +39 -45
  80. package/dist/server/middleware/auth.d.ts +5 -1
  81. package/dist/server/middleware/auth.js +10 -3
  82. package/dist/server/middleware/common.js +1 -1
  83. package/dist/server/routes/agentRoutes.js +4 -4
  84. package/dist/server/routes/claudeProxyRoutes.js +99 -196
  85. package/dist/server/routes/codexProxyRoutes.js +621 -591
  86. package/dist/server/routes/healthRoutes.js +6 -6
  87. package/dist/server/routes/mcpRoutes.js +7 -7
  88. package/dist/server/routes/memoryRoutes.js +7 -7
  89. package/dist/server/routes/openApiRoutes.js +3 -3
  90. package/dist/server/routes/toolRoutes.js +5 -5
  91. package/dist/server/routes/transcribeRoutes.js +1 -1
  92. package/dist/server/utils/validation.d.ts +3 -3
  93. package/dist/services/server/ai/observability/instrumentation.d.ts +34 -201
  94. package/dist/services/server/ai/observability/instrumentation.js +220 -1267
  95. package/dist/services/server/ai/observability/langfuseSetup.d.ts +14 -0
  96. package/dist/services/server/ai/observability/langfuseSetup.js +55 -0
  97. package/dist/services/server/ai/observability/otlpSetup.d.ts +16 -0
  98. package/dist/services/server/ai/observability/otlpSetup.js +58 -0
  99. package/dist/session/globalSessionState.js +0 -11
  100. package/dist/telemetry/attributes.d.ts +23 -46
  101. package/dist/telemetry/attributes.js +76 -162
  102. package/dist/telemetry/chatMessages.d.ts +13 -0
  103. package/dist/telemetry/chatMessages.js +59 -0
  104. package/dist/telemetry/index.d.ts +5 -19
  105. package/dist/telemetry/index.js +5 -26
  106. package/dist/telemetry/observation.d.ts +37 -0
  107. package/dist/telemetry/observation.js +112 -0
  108. package/dist/telemetry/observationNames.d.ts +18 -0
  109. package/dist/telemetry/observationNames.js +24 -0
  110. package/dist/telemetry/spanSanitizer.d.ts +39 -0
  111. package/dist/telemetry/spanSanitizer.js +92 -0
  112. package/dist/telemetry/spanSerialization.d.ts +13 -0
  113. package/dist/telemetry/spanSerialization.js +46 -0
  114. package/dist/telemetry/tracers.d.ts +37 -18
  115. package/dist/telemetry/tracers.js +97 -19
  116. package/dist/telemetry/withSpan.d.ts +47 -25
  117. package/dist/telemetry/withSpan.js +158 -71
  118. package/dist/types/cli.d.ts +0 -11
  119. package/dist/types/decision.d.ts +3 -0
  120. package/dist/types/exporter.d.ts +54 -0
  121. package/dist/types/exporter.js +0 -4
  122. package/dist/types/generate.d.ts +4 -1
  123. package/dist/types/isolatedAgent.d.ts +5 -4
  124. package/dist/types/loopEngine.d.ts +18 -28
  125. package/dist/types/observability.d.ts +127 -160
  126. package/dist/types/providers.d.ts +15 -0
  127. package/dist/types/proxy.d.ts +41 -2
  128. package/dist/types/server.d.ts +9 -5
  129. package/dist/utils/anthropicTraceSanitizer.d.ts +2 -2
  130. package/dist/utils/anthropicTraceSanitizer.js +3 -1
  131. package/dist/utils/conversationMemory.js +4 -4
  132. package/dist/utils/fileDetector.js +1 -1
  133. package/dist/utils/messageBuilder.js +1 -1
  134. package/dist/utils/noOutputSentinel.d.ts +4 -16
  135. package/dist/utils/noOutputSentinel.js +12 -28
  136. package/dist/utils/providerRetry.js +4 -4
  137. package/dist/voice/livekit/brain.js +1 -1
  138. package/dist/voice/livekit/realtimeMemory.d.ts +1 -1
  139. package/dist/voice/livekit/realtimeMemory.js +66 -1
  140. package/dist/voice/livekit/realtimeVoiceAgent.js +1 -1
  141. package/docs-site/static/search-index.json +42 -64
  142. package/package.json +5 -4
  143. package/dist/telemetry/telemetryService.d.ts +0 -79
  144. package/dist/telemetry/telemetryService.js +0 -572
  145. package/dist/utils/observabilityHelpers.d.ts +0 -27
  146. package/dist/utils/observabilityHelpers.js +0 -47
@@ -5,11 +5,10 @@
5
5
  * Commands for monitoring and managing observability features:
6
6
  * - status: Show telemetry status
7
7
  * - metrics: Show metrics summary
8
- * - exporters: List configured exporters
9
8
  * - costs: Show cost breakdown
10
9
  */
11
10
  import type { CommandModule } from "yargs";
12
- import type { ObservabilityStatusArgs as StatusArgs, ObservabilityMetricsArgs as MetricsArgs, ObservabilityExportersArgs as ExportersArgs, ObservabilityCostsArgs as CostsArgs } from "../../types/index.js";
11
+ import type { ObservabilityStatusArgs as StatusArgs, ObservabilityMetricsArgs as MetricsArgs, ObservabilityCostsArgs as CostsArgs } from "../../types/index.js";
13
12
  /**
14
13
  * Observability Command Factory
15
14
  */
@@ -26,10 +25,6 @@ export declare class ObservabilityCommandFactory {
26
25
  * Create the metrics subcommand
27
26
  */
28
27
  static createMetricsCommand(): CommandModule<object, MetricsArgs>;
29
- /**
30
- * Create the exporters subcommand
31
- */
32
- static createExportersCommand(): CommandModule<object, ExportersArgs>;
33
28
  /**
34
29
  * Create the costs subcommand
35
30
  */
@@ -5,7 +5,6 @@
5
5
  * Commands for monitoring and managing observability features:
6
6
  * - status: Show telemetry status
7
7
  * - metrics: Show metrics summary
8
- * - exporters: List configured exporters
9
8
  * - costs: Show cost breakdown
10
9
  */
11
10
  import chalk from "chalk";
@@ -30,7 +29,6 @@ export class ObservabilityCommandFactory {
30
29
  return yargs
31
30
  .command(ObservabilityCommandFactory.createStatusCommand())
32
31
  .command(ObservabilityCommandFactory.createMetricsCommand())
33
- .command(ObservabilityCommandFactory.createExportersCommand())
34
32
  .command(ObservabilityCommandFactory.createCostsCommand())
35
33
  .demandCommand(1, "Please specify a subcommand")
36
34
  .strict();
@@ -118,17 +116,6 @@ export class ObservabilityCommandFactory {
118
116
  logger.always(formatRow(" Service:", status.openTelemetry.serviceName));
119
117
  }
120
118
  }
121
- // Exporters summary
122
- if (status.exporters && status.exporters.length > 0) {
123
- logger.always("");
124
- logger.always(chalk.bold("Active Exporters:"));
125
- for (const exporter of status.exporters) {
126
- const exporterStatus = exporter.healthy
127
- ? chalk.green("Healthy")
128
- : chalk.red("Unhealthy");
129
- logger.always(formatRow(` ${exporter.name}:`, exporterStatus));
130
- }
131
- }
132
119
  logger.always("");
133
120
  }
134
121
  }
@@ -252,99 +239,6 @@ export class ObservabilityCommandFactory {
252
239
  },
253
240
  };
254
241
  }
255
- /**
256
- * Create the exporters subcommand
257
- */
258
- static createExportersCommand() {
259
- return {
260
- command: "exporters",
261
- aliases: ["exp"],
262
- describe: "List configured exporters",
263
- builder: (yargs) => {
264
- return yargs
265
- .option("format", {
266
- alias: "f",
267
- type: "string",
268
- choices: ["text", "json", "table"],
269
- default: "text",
270
- describe: "Output format",
271
- })
272
- .option("quiet", {
273
- alias: "q",
274
- type: "boolean",
275
- default: false,
276
- describe: "Minimal output",
277
- });
278
- },
279
- handler: async (args) => {
280
- const spinner = args.quiet
281
- ? null
282
- : ora("Checking exporters...").start();
283
- try {
284
- const neurolink = new NeuroLink();
285
- const status = neurolink.getTelemetryStatus();
286
- if (spinner) {
287
- spinner.succeed("Exporters retrieved");
288
- }
289
- const exporters = status.exporters ?? [];
290
- if (args.format === "json") {
291
- logger.always(JSON.stringify(exporters, null, 2));
292
- }
293
- else {
294
- logger.always("");
295
- logger.always(chalk.bold.cyan("=== Configured Exporters ==="));
296
- logger.always("");
297
- if (exporters.length === 0) {
298
- logger.always(chalk.gray("No exporters configured."));
299
- logger.always("");
300
- logger.always("Available exporters:");
301
- logger.always(" - Langfuse (langfuse)");
302
- logger.always(" - LangSmith (langsmith)");
303
- logger.always(" - OpenTelemetry (otel)");
304
- logger.always(" - Datadog (datadog)");
305
- logger.always(" - Sentry (sentry)");
306
- logger.always(" - Braintrust (braintrust)");
307
- logger.always(" - Arize (arize)");
308
- logger.always(" - PostHog (posthog)");
309
- logger.always(" - Laminar (laminar)");
310
- }
311
- else {
312
- for (const exporter of exporters) {
313
- const healthIcon = exporter.healthy
314
- ? chalk.green("[OK]")
315
- : chalk.red("[ERROR]");
316
- logger.always(`${healthIcon} ${chalk.bold(exporter.name)}`);
317
- if (exporter.latencyMs !== undefined) {
318
- logger.always(formatRow(" Latency:", `${exporter.latencyMs.toFixed(2)}ms`));
319
- }
320
- if (exporter.pendingSpans !== undefined) {
321
- logger.always(formatRow(" Pending spans:", exporter.pendingSpans.toLocaleString()));
322
- }
323
- if (exporter.lastExportTime) {
324
- const lastExport = new Date(exporter.lastExportTime);
325
- logger.always(formatRow(" Last export:", lastExport.toISOString()));
326
- }
327
- if (exporter.errors && exporter.errors.length > 0) {
328
- logger.always(chalk.yellow(" Errors:"));
329
- for (const error of exporter.errors.slice(0, 3)) {
330
- logger.always(chalk.red(` - ${error}`));
331
- }
332
- }
333
- logger.always("");
334
- }
335
- }
336
- }
337
- }
338
- catch (error) {
339
- if (spinner) {
340
- spinner.fail("Failed to get exporters");
341
- }
342
- logger.error("Error:", error instanceof Error ? error.message : String(error));
343
- process.exit(1);
344
- }
345
- },
346
- };
347
- }
348
242
  /**
349
243
  * Create the costs subcommand
350
244
  */
@@ -8,6 +8,7 @@ import { stripVTControlCharacters } from "node:util";
8
8
  import chalk from "chalk";
9
9
  import ora from "ora";
10
10
  import { buildProxyHealthResponse, createProxyReadinessState, markProxyDrainingForUpdate, markProxyReady, resumeProxyConnections, waitForProxyReadiness, } from "../../proxy/proxyHealth.js";
11
+ import { ensureTelemetry, getLangfuseHealthStatus, } from "../../services/server/ai/observability/instrumentation.js";
11
12
  import { logger } from "../../utils/logger.js";
12
13
  import { applyAllClients, applyClientsOnProxyStart, restoreAllClients, } from "../proxy-clients/registry.js";
13
14
  import { resolveProxyConfigPath } from "../../proxy/proxyConfig.js";
@@ -2350,26 +2351,16 @@ async function initializeProxyOpenTelemetry() {
2350
2351
  ]
2351
2352
  .filter(Boolean)
2352
2353
  .join(",");
2353
- const { initializeOpenTelemetry, isOpenTelemetryInitialized } = await import("../../services/server/ai/observability/instrumentation.js");
2354
- const { buildObservabilityConfigFromEnv } = await import("../../utils/observabilityHelpers.js");
2355
- if (isOpenTelemetryInitialized()) {
2356
- return;
2357
- }
2358
- const observabilityConfig = buildObservabilityConfigFromEnv();
2359
- const langfuseConfig = observabilityConfig?.langfuse;
2360
- const langfuseEnabled = langfuseConfig?.enabled === true;
2361
- await initializeOpenTelemetry({
2362
- enabled: langfuseEnabled,
2363
- publicKey: langfuseConfig?.publicKey || "",
2364
- secretKey: langfuseConfig?.secretKey || "",
2365
- baseUrl: langfuseConfig?.baseUrl,
2366
- environment: "proxy",
2367
- release: PROXY_VERSION,
2368
- userId: "neurolink-proxy",
2369
- autoDetectOperationName: true,
2354
+ const hasLangfuseKeys = Boolean(process.env.LANGFUSE_PUBLIC_KEY && process.env.LANGFUSE_SECRET_KEY);
2355
+ ensureTelemetry({
2356
+ langfuse: hasLangfuseKeys && {
2357
+ environment: process.env.LANGFUSE_TRACING_ENVIRONMENT || "proxy",
2358
+ release: process.env.LANGFUSE_RELEASE || PROXY_VERSION,
2359
+ },
2370
2360
  });
2361
+ const langfuseEnabled = getLangfuseHealthStatus().hasProcessor;
2371
2362
  if (langfuseEnabled) {
2372
- logger.always(`[proxy] Langfuse enabled — exporting to ${langfuseConfig.baseUrl || "https://cloud.langfuse.com"} (environment=proxy)`);
2363
+ logger.always(`[proxy] Langfuse enabled — exporting to ${process.env.LANGFUSE_BASE_URL || "https://cloud.langfuse.com"}`);
2373
2364
  }
2374
2365
  if (otlpEndpoint) {
2375
2366
  logger.always(`[proxy] OTLP exporter enabled — exporting to ${otlpEndpoint} (service.name=neurolink-proxy)`);
@@ -2,15 +2,13 @@
2
2
  /**
3
3
  * NeuroLink CLI Telemetry Commands
4
4
  *
5
- * Commands for managing telemetry and observability exporters:
6
- * - status: Show exporter status
7
- * - configure: Configure an exporter
8
- * - list-exporters: List configured exporters
5
+ * Commands for managing telemetry:
6
+ * - status: Show telemetry status
9
7
  * - flush: Flush pending spans
10
8
  * - stats: Show token/cost stats
11
9
  */
12
10
  import type { CommandModule } from "yargs";
13
- import type { TelemetryStatusArgs as StatusArgs, TelemetryConfigureArgs as ConfigureArgs, TelemetryListExportersArgs as ListExportersArgs, TelemetryFlushArgs as FlushArgs, TelemetryStatsArgs as StatsArgs, TelemetryNativePrepareArgs, TelemetryNativeValidateArgs } from "../../types/index.js";
11
+ import type { TelemetryStatusArgs as StatusArgs, TelemetryFlushArgs as FlushArgs, TelemetryStatsArgs as StatsArgs, TelemetryNativePrepareArgs, TelemetryNativeValidateArgs } from "../../types/index.js";
14
12
  /**
15
13
  * Telemetry Command Factory
16
14
  */
@@ -26,14 +24,6 @@ export declare class TelemetryCommandFactory {
26
24
  * Create the status subcommand
27
25
  */
28
26
  static createStatusCommand(): CommandModule<object, StatusArgs>;
29
- /**
30
- * Create the configure subcommand
31
- */
32
- static createConfigureCommand(): CommandModule<object, ConfigureArgs>;
33
- /**
34
- * Create the list-exporters subcommand
35
- */
36
- static createListExportersCommand(): CommandModule<object, ListExportersArgs>;
37
27
  /**
38
28
  * Create the flush subcommand
39
29
  */
@@ -2,10 +2,8 @@
2
2
  /**
3
3
  * NeuroLink CLI Telemetry Commands
4
4
  *
5
- * Commands for managing telemetry and observability exporters:
6
- * - status: Show exporter status
7
- * - configure: Configure an exporter
8
- * - list-exporters: List configured exporters
5
+ * Commands for managing telemetry:
6
+ * - status: Show telemetry status
9
7
  * - flush: Flush pending spans
10
8
  * - stats: Show token/cost stats
11
9
  */
@@ -17,20 +15,6 @@ import { flushOpenTelemetry } from "../../services/server/ai/observability/instr
17
15
  import { formatRow, formatCost } from "../utils/formatters.js";
18
16
  import { redactUrlCredentials } from "../../utils/logSanitize.js";
19
17
  import { prepareNativeTelemetry, validateNativeTelemetry, } from "../utils/nativeTelemetry.js";
20
- /**
21
- * Available exporter names
22
- */
23
- const AVAILABLE_EXPORTERS = [
24
- "langfuse",
25
- "langsmith",
26
- "otel",
27
- "datadog",
28
- "sentry",
29
- "braintrust",
30
- "arize",
31
- "posthog",
32
- "laminar",
33
- ];
34
18
  /**
35
19
  * Telemetry Command Factory
36
20
  */
@@ -42,12 +26,10 @@ export class TelemetryCommandFactory {
42
26
  return {
43
27
  command: "telemetry <subcommand>",
44
28
  aliases: ["tel"],
45
- describe: "Telemetry and exporter management",
29
+ describe: "Telemetry management",
46
30
  builder: (yargs) => {
47
31
  return yargs
48
32
  .command(TelemetryCommandFactory.createStatusCommand())
49
- .command(TelemetryCommandFactory.createConfigureCommand())
50
- .command(TelemetryCommandFactory.createListExportersCommand())
51
33
  .command(TelemetryCommandFactory.createFlushCommand())
52
34
  .command(TelemetryCommandFactory.createStatsCommand())
53
35
  .command(TelemetryCommandFactory.createNativePrepareCommand())
@@ -176,7 +158,7 @@ export class TelemetryCommandFactory {
176
158
  static createStatusCommand() {
177
159
  return {
178
160
  command: "status",
179
- describe: "Show exporter status and health",
161
+ describe: "Show telemetry status",
180
162
  builder: (yargs) => {
181
163
  return yargs
182
164
  .option("format", {
@@ -196,7 +178,7 @@ export class TelemetryCommandFactory {
196
178
  handler: async (args) => {
197
179
  const spinner = args.quiet
198
180
  ? null
199
- : ora("Checking exporter status...").start();
181
+ : ora("Checking telemetry status...").start();
200
182
  try {
201
183
  const neurolink = new NeuroLink();
202
184
  const status = neurolink.getTelemetryStatus();
@@ -248,29 +230,6 @@ export class TelemetryCommandFactory {
248
230
  logger.always(formatRow(" Environment:", status.langfuse.environment));
249
231
  }
250
232
  }
251
- // Exporters health summary
252
- if (status.exporters && status.exporters.length > 0) {
253
- logger.always("");
254
- logger.always(chalk.bold("Exporter Health:"));
255
- for (const exporter of status.exporters) {
256
- const healthIcon = exporter.healthy
257
- ? chalk.green("[OK]")
258
- : chalk.red("[ERROR]");
259
- const pendingInfo = exporter.pendingSpans
260
- ? chalk.gray(` (${exporter.pendingSpans} pending)`)
261
- : "";
262
- logger.always(` ${healthIcon} ${exporter.name}${pendingInfo}`);
263
- if (exporter.errors && exporter.errors.length > 0) {
264
- for (const error of exporter.errors.slice(0, 2)) {
265
- logger.always(chalk.red(` Error: ${error}`));
266
- }
267
- }
268
- }
269
- }
270
- else {
271
- logger.always("");
272
- logger.always(chalk.gray("No exporters configured."));
273
- }
274
233
  logger.always("");
275
234
  }
276
235
  }
@@ -284,211 +243,13 @@ export class TelemetryCommandFactory {
284
243
  },
285
244
  };
286
245
  }
287
- /**
288
- * Create the configure subcommand
289
- */
290
- static createConfigureCommand() {
291
- return {
292
- command: "configure",
293
- describe: "Configure an exporter with JSON settings",
294
- builder: (yargs) => {
295
- return yargs
296
- .option("exporter", {
297
- alias: "e",
298
- type: "string",
299
- demandOption: true,
300
- choices: AVAILABLE_EXPORTERS,
301
- describe: "Exporter name to configure",
302
- })
303
- .option("config", {
304
- alias: "c",
305
- type: "string",
306
- demandOption: true,
307
- describe: "JSON configuration string",
308
- })
309
- .option("format", {
310
- alias: "f",
311
- type: "string",
312
- choices: ["text", "json", "table"],
313
- default: "text",
314
- describe: "Output format",
315
- })
316
- .option("quiet", {
317
- alias: "q",
318
- type: "boolean",
319
- default: false,
320
- describe: "Minimal output",
321
- });
322
- },
323
- handler: async (args) => {
324
- const spinner = args.quiet
325
- ? null
326
- : ora(`Configuring ${args.exporter} exporter...`).start();
327
- try {
328
- // Parse the JSON config
329
- let config;
330
- try {
331
- config = JSON.parse(args.config);
332
- }
333
- catch {
334
- if (spinner) {
335
- spinner.fail("Invalid JSON configuration");
336
- }
337
- logger.always(chalk.red("Error: Configuration must be valid JSON"));
338
- logger.always("");
339
- logger.always("Example:");
340
- logger.always(chalk.gray(` neurolink telemetry configure --exporter langfuse --config '{"publicKey":"pk-...", "secretKey":"sk-..."}'`));
341
- process.exit(1);
342
- }
343
- // Validate required fields based on exporter type
344
- const validationResult = validateExporterConfig(args.exporter, config);
345
- if (!validationResult.valid) {
346
- if (spinner) {
347
- spinner.fail("Configuration validation failed");
348
- }
349
- logger.always(chalk.red(`Error: ${validationResult.error}`));
350
- logger.always("");
351
- logger.always(chalk.yellow(`Required fields for ${args.exporter}:`));
352
- for (const field of validationResult.requiredFields ?? []) {
353
- logger.always(chalk.gray(` - ${field}`));
354
- }
355
- process.exit(1);
356
- }
357
- // Currently, exporter configuration is done via environment variables
358
- // or SDK initialization. This command provides guidance on how to configure.
359
- if (spinner) {
360
- spinner.succeed(`${args.exporter} configuration validated`);
361
- }
362
- if (args.format === "json") {
363
- logger.always(JSON.stringify({
364
- exporter: args.exporter,
365
- config: config,
366
- valid: true,
367
- message: "Configuration validated. Set environment variables or use SDK initialization.",
368
- }, null, 2));
369
- }
370
- else {
371
- logger.always("");
372
- logger.always(chalk.bold.cyan(`=== ${args.exporter} Configuration ===`));
373
- logger.always("");
374
- logger.always(chalk.green("Configuration validated successfully!"));
375
- logger.always("");
376
- logger.always(chalk.bold("To apply this configuration:"));
377
- logger.always("");
378
- // Show environment variable instructions
379
- const envVars = getExporterEnvVars(args.exporter);
380
- logger.always(chalk.yellow("Option 1: Set environment variables"));
381
- for (const [key, description] of Object.entries(envVars)) {
382
- logger.always(chalk.gray(` export ${key}="<${description}>"`));
383
- }
384
- logger.always("");
385
- logger.always(chalk.yellow("Option 2: SDK initialization"));
386
- logger.always(chalk.gray(` const neurolink = new NeuroLink({`));
387
- logger.always(chalk.gray(` observability: {`));
388
- logger.always(chalk.gray(` ${args.exporter}: ${JSON.stringify(config, null, 6).split("\n").join("\n ")}`));
389
- logger.always(chalk.gray(` }`));
390
- logger.always(chalk.gray(` });`));
391
- logger.always("");
392
- }
393
- }
394
- catch (error) {
395
- if (spinner) {
396
- spinner.fail("Failed to configure exporter");
397
- }
398
- logger.error("Error:", error instanceof Error ? error.message : String(error));
399
- process.exit(1);
400
- }
401
- },
402
- };
403
- }
404
- /**
405
- * Create the list-exporters subcommand
406
- */
407
- static createListExportersCommand() {
408
- return {
409
- command: "list-exporters",
410
- aliases: ["list", "ls"],
411
- describe: "List all available and configured exporters",
412
- builder: (yargs) => {
413
- return yargs
414
- .option("format", {
415
- alias: "f",
416
- type: "string",
417
- choices: ["text", "json", "table"],
418
- default: "text",
419
- describe: "Output format",
420
- })
421
- .option("quiet", {
422
- alias: "q",
423
- type: "boolean",
424
- default: false,
425
- describe: "Minimal output",
426
- });
427
- },
428
- handler: async (args) => {
429
- const spinner = args.quiet ? null : ora("Listing exporters...").start();
430
- try {
431
- const neurolink = new NeuroLink();
432
- const status = neurolink.getTelemetryStatus();
433
- if (spinner) {
434
- spinner.succeed("Exporters listed");
435
- }
436
- const configuredExporters = status.exporters ?? [];
437
- const configuredNames = new Set(configuredExporters.map((e) => e.name.toLowerCase()));
438
- if (args.format === "json") {
439
- logger.always(JSON.stringify({
440
- available: AVAILABLE_EXPORTERS,
441
- configured: configuredExporters,
442
- }, null, 2));
443
- }
444
- else {
445
- logger.always("");
446
- logger.always(chalk.bold.cyan("=== Available Exporters ==="));
447
- logger.always("");
448
- for (const exporter of AVAILABLE_EXPORTERS) {
449
- const isConfigured = configuredNames.has(exporter);
450
- const configuredExporter = configuredExporters.find((e) => e.name.toLowerCase() === exporter);
451
- const statusIcon = isConfigured
452
- ? configuredExporter?.healthy
453
- ? chalk.green("[ACTIVE]")
454
- : chalk.yellow("[CONFIGURED]")
455
- : chalk.gray("[AVAILABLE]");
456
- const description = getExporterDescription(exporter);
457
- logger.always(`${statusIcon} ${chalk.bold(exporter)}`);
458
- logger.always(chalk.gray(` ${description}`));
459
- if (isConfigured && configuredExporter) {
460
- if (configuredExporter.pendingSpans) {
461
- logger.always(chalk.gray(` Pending spans: ${configuredExporter.pendingSpans}`));
462
- }
463
- if (configuredExporter.lastExportTime) {
464
- const lastExport = new Date(configuredExporter.lastExportTime);
465
- logger.always(chalk.gray(` Last export: ${lastExport.toISOString()}`));
466
- }
467
- }
468
- logger.always("");
469
- }
470
- logger.always(chalk.bold("Configuration Help:"));
471
- logger.always(chalk.gray(" Use 'neurolink telemetry configure --exporter <name> --config <json>' to configure an exporter"));
472
- logger.always("");
473
- }
474
- }
475
- catch (error) {
476
- if (spinner) {
477
- spinner.fail("Failed to list exporters");
478
- }
479
- logger.error("Error:", error instanceof Error ? error.message : String(error));
480
- process.exit(1);
481
- }
482
- },
483
- };
484
- }
485
246
  /**
486
247
  * Create the flush subcommand
487
248
  */
488
249
  static createFlushCommand() {
489
250
  return {
490
251
  command: "flush",
491
- describe: "Flush all pending spans to exporters",
252
+ describe: "Flush all pending spans",
492
253
  builder: (yargs) => {
493
254
  return yargs
494
255
  .option("timeout", {
@@ -516,10 +277,6 @@ export class TelemetryCommandFactory {
516
277
  ? null
517
278
  : ora("Flushing pending spans...").start();
518
279
  try {
519
- const neurolink = new NeuroLink();
520
- const statusBefore = neurolink.getTelemetryStatus();
521
- // Count pending spans before flush
522
- const pendingBefore = statusBefore.exporters?.reduce((sum, e) => sum + (e.pendingSpans ?? 0), 0) ?? 0;
523
280
  // Create a timeout promise
524
281
  let flushTimer;
525
282
  const timeoutPromise = new Promise((_, reject) => {
@@ -533,28 +290,16 @@ export class TelemetryCommandFactory {
533
290
  if (flushTimer !== undefined) {
534
291
  clearTimeout(flushTimer);
535
292
  }
536
- // Get status after flush
537
- const statusAfter = neurolink.getTelemetryStatus();
538
- const pendingAfter = statusAfter.exporters?.reduce((sum, e) => sum + (e.pendingSpans ?? 0), 0) ?? 0;
539
- const flushedCount = Math.max(0, pendingBefore - pendingAfter);
540
293
  if (spinner) {
541
294
  spinner.succeed("Flush completed");
542
295
  }
543
296
  if (args.format === "json") {
544
- logger.always(JSON.stringify({
545
- success: true,
546
- pendingBefore,
547
- pendingAfter,
548
- flushed: flushedCount,
549
- }, null, 2));
297
+ logger.always(JSON.stringify({ success: true }, null, 2));
550
298
  }
551
299
  else {
552
300
  logger.always("");
553
301
  logger.always(chalk.bold.cyan("=== Flush Complete ==="));
554
302
  logger.always("");
555
- logger.always(formatRow("Spans before:", pendingBefore.toString()));
556
- logger.always(formatRow("Spans after:", pendingAfter.toString()));
557
- logger.always(formatRow("Flushed:", chalk.green(flushedCount.toString())));
558
303
  logger.always("");
559
304
  }
560
305
  }
@@ -727,96 +472,4 @@ export class TelemetryCommandFactory {
727
472
  };
728
473
  }
729
474
  }
730
- /**
731
- * Validate exporter configuration
732
- */
733
- function validateExporterConfig(exporter, config) {
734
- const requiredFieldsMap = {
735
- langfuse: ["publicKey", "secretKey"],
736
- langsmith: ["apiKey"],
737
- otel: ["endpoint"],
738
- datadog: ["apiKey"],
739
- sentry: ["dsn"],
740
- braintrust: ["apiKey", "projectName"],
741
- arize: ["spaceKey", "apiKey"],
742
- posthog: ["apiKey"],
743
- laminar: ["apiKey"],
744
- };
745
- const requiredFields = requiredFieldsMap[exporter];
746
- const missingFields = requiredFields.filter((field) => !(field in config) || !config[field]);
747
- if (missingFields.length > 0) {
748
- return {
749
- valid: false,
750
- error: `Missing required fields: ${missingFields.join(", ")}`,
751
- requiredFields,
752
- };
753
- }
754
- return { valid: true };
755
- }
756
- /**
757
- * Get environment variable names for an exporter
758
- */
759
- function getExporterEnvVars(exporter) {
760
- const envVarsMap = {
761
- langfuse: {
762
- LANGFUSE_PUBLIC_KEY: "your-public-key",
763
- LANGFUSE_SECRET_KEY: "your-secret-key",
764
- LANGFUSE_BASEURL: "https://cloud.langfuse.com (optional)",
765
- },
766
- langsmith: {
767
- LANGCHAIN_API_KEY: "your-api-key",
768
- LANGCHAIN_PROJECT: "your-project-name (optional)",
769
- LANGCHAIN_ENDPOINT: "https://api.smith.langchain.com (optional)",
770
- },
771
- otel: {
772
- OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
773
- OTEL_SERVICE_NAME: "your-service-name",
774
- OTEL_EXPORTER_OTLP_PROTOCOL: "http (or grpc)",
775
- },
776
- datadog: {
777
- DD_API_KEY: "your-api-key",
778
- DD_SITE: "datadoghq.com (or regional site)",
779
- DD_SERVICE: "your-service-name",
780
- },
781
- sentry: {
782
- SENTRY_DSN: "your-dsn-url",
783
- SENTRY_TRACES_SAMPLE_RATE: "1.0 (optional)",
784
- SENTRY_RELEASE: "your-release-version (optional)",
785
- },
786
- braintrust: {
787
- BRAINTRUST_API_KEY: "your-api-key",
788
- BRAINTRUST_PROJECT: "your-project-name",
789
- },
790
- arize: {
791
- ARIZE_SPACE_KEY: "your-space-key",
792
- ARIZE_API_KEY: "your-api-key",
793
- },
794
- posthog: {
795
- POSTHOG_API_KEY: "your-api-key",
796
- POSTHOG_HOST: "https://app.posthog.com (optional)",
797
- },
798
- laminar: {
799
- LAMINAR_API_KEY: "your-api-key",
800
- LAMINAR_BASE_URL: "https://api.laminar.run (optional)",
801
- },
802
- };
803
- return envVarsMap[exporter];
804
- }
805
- /**
806
- * Get description for an exporter
807
- */
808
- function getExporterDescription(exporter) {
809
- const descriptions = {
810
- langfuse: "Open-source LLM observability platform with traces and analytics",
811
- langsmith: "LangChain's platform for LLM application debugging and monitoring",
812
- otel: "OpenTelemetry Protocol (OTLP) for distributed tracing",
813
- datadog: "APM and infrastructure monitoring platform",
814
- sentry: "Error tracking and performance monitoring",
815
- braintrust: "AI evaluation and experimentation platform",
816
- arize: "ML observability platform for model monitoring",
817
- posthog: "Product analytics with LLM event tracking",
818
- laminar: "LLM application monitoring and debugging",
819
- };
820
- return descriptions[exporter];
821
- }
822
475
  //# sourceMappingURL=telemetry.js.map