@juspay/neurolink 9.22.1 → 9.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [9.22.3](https://github.com/juspay/neurolink/compare/v9.22.2...v9.22.3) (2026-03-12)
2
+
3
+ ### Bug Fixes
4
+
5
+ - **(landing):** improve mobile accessibility and touch targets ([98f3f53](https://github.com/juspay/neurolink/commit/98f3f53d9d815d84486194aae8ebd41879009e5d))
6
+
7
+ ## [9.22.2](https://github.com/juspay/neurolink/compare/v9.22.1...v9.22.2) (2026-03-12)
8
+
9
+ ### Bug Fixes
10
+
11
+ - **(observability):** prevent duplicate Langfuse traces from streaming by restricting trace attributes to root spans ([ddac782](https://github.com/juspay/neurolink/commit/ddac78229f7ed42a1d332c23e0a5e6d80418dd6a))
12
+
1
13
  ## [9.22.1](https://github.com/juspay/neurolink/compare/v9.22.0...v9.22.1) (2026-03-12)
2
14
 
3
15
  ### Bug Fixes
@@ -19,6 +19,7 @@ import { recordProviderPerformanceFromMetrics } from "../evaluationProviders.js"
19
19
  import { modelConfig } from "../modelConfiguration.js";
20
20
  import { TelemetryService } from "../../telemetry/telemetryService.js";
21
21
  import { calculateCost, hasPricing } from "../../utils/pricing.js";
22
+ import { getLangfuseContext } from "../../services/server/ai/observability/instrumentation.js";
22
23
  /**
23
24
  * TelemetryHandler class - Handles analytics and telemetry for AI providers
24
25
  */
@@ -143,8 +144,9 @@ export class TelemetryHandler {
143
144
  return undefined;
144
145
  }
145
146
  const context = options.context;
146
- const traceName = context?.traceName;
147
- const userId = context?.userId;
147
+ const langfuseContext = getLangfuseContext();
148
+ const traceName = context?.traceName ?? langfuseContext?.traceName;
149
+ const userId = context?.userId ?? langfuseContext?.userId;
148
150
  const functionId = traceName ? traceName : userId ? userId : "guest";
149
151
  const metadata = {
150
152
  ...(context?.metadata || {}),
@@ -168,7 +170,7 @@ export class TelemetryHandler {
168
170
  isEnabled: true,
169
171
  functionId,
170
172
  metadata,
171
- recordInputs: process.env.NEUROLINK_RECORD_INPUTS?.toLowerCase() === "true",
173
+ recordInputs: process.env.NEUROLINK_RECORD_INPUTS?.toLowerCase() !== "false",
172
174
  recordOutputs: true,
173
175
  };
174
176
  }
@@ -19,6 +19,7 @@ import { recordProviderPerformanceFromMetrics } from "../evaluationProviders.js"
19
19
  import { modelConfig } from "../modelConfiguration.js";
20
20
  import { TelemetryService } from "../../telemetry/telemetryService.js";
21
21
  import { calculateCost, hasPricing } from "../../utils/pricing.js";
22
+ import { getLangfuseContext } from "../../services/server/ai/observability/instrumentation.js";
22
23
  /**
23
24
  * TelemetryHandler class - Handles analytics and telemetry for AI providers
24
25
  */
@@ -143,8 +144,9 @@ export class TelemetryHandler {
143
144
  return undefined;
144
145
  }
145
146
  const context = options.context;
146
- const traceName = context?.traceName;
147
- const userId = context?.userId;
147
+ const langfuseContext = getLangfuseContext();
148
+ const traceName = context?.traceName ?? langfuseContext?.traceName;
149
+ const userId = context?.userId ?? langfuseContext?.userId;
148
150
  const functionId = traceName ? traceName : userId ? userId : "guest";
149
151
  const metadata = {
150
152
  ...(context?.metadata || {}),
@@ -168,7 +170,7 @@ export class TelemetryHandler {
168
170
  isEnabled: true,
169
171
  functionId,
170
172
  metadata,
171
- recordInputs: process.env.NEUROLINK_RECORD_INPUTS?.toLowerCase() === "true",
173
+ recordInputs: process.env.NEUROLINK_RECORD_INPUTS?.toLowerCase() !== "false",
172
174
  recordOutputs: true,
173
175
  };
174
176
  }
@@ -81,7 +81,7 @@ class ContextEnricher {
81
81
  * operations here so we can update the trace name in onEnd().
82
82
  */
83
83
  detectedOperations = new Map();
84
- onStart(span) {
84
+ onStart(span, parentContext) {
85
85
  const context = contextStorage.getStore();
86
86
  const userId = context?.userId ?? currentConfig?.userId ?? "guest";
87
87
  const sessionId = context?.sessionId ?? currentConfig?.sessionId;
@@ -140,10 +140,10 @@ class ContextEnricher {
140
140
  if (context?.requestId) {
141
141
  span.setAttribute("request.id", context.requestId);
142
142
  }
143
- // Set trace name for Langfuse (using proper Langfuse attribute)
144
- if (traceName) {
143
+ const isRootSpan = !trace.getSpan(parentContext);
144
+ if (traceName && isRootSpan) {
145
145
  span.setAttribute("langfuse.trace.name", traceName);
146
- span.setAttribute("trace.name", traceName); // Keep for compatibility
146
+ span.setAttribute("trace.name", traceName);
147
147
  }
148
148
  // Set operation name as separate attribute for filtering/analytics
149
149
  if (operationName) {
@@ -158,14 +158,16 @@ class ContextEnricher {
158
158
  if (typeof value === "string" ||
159
159
  typeof value === "number" ||
160
160
  typeof value === "boolean") {
161
- span.setAttribute(`metadata.${key}`, value);
161
+ if (metadata && isRootSpan) {
162
+ span.setAttribute("langfuse.trace.metadata", JSON.stringify(metadata));
163
+ }
162
164
  }
163
165
  else if (Array.isArray(value) &&
164
166
  value.every((v) => typeof v === "string" ||
165
167
  typeof v === "number" ||
166
168
  typeof v === "boolean")) {
167
169
  // OTEL supports homogeneous arrays of primitives
168
- span.setAttribute(`metadata.${key}`, value);
170
+ span.setAttribute(`metadata.${key}`, JSON.stringify(value));
169
171
  }
170
172
  else {
171
173
  // Fall back to JSON string for complex types
@@ -18,29 +18,29 @@ declare const MODEL_CONFIGS: {
18
18
  };
19
19
  readonly fallback: {
20
20
  readonly provider: "vertex";
21
- readonly model: "gemini-2.5-pro";
21
+ readonly model: "claude-haiku-4-5@20251001";
22
22
  readonly capabilities: readonly ["speed", "general", "basic-reasoning"];
23
23
  readonly avgResponseTime: 1200;
24
24
  readonly costPerToken: 0.0002;
25
- readonly reasoning: "Vertex AI Gemini Pro fallback";
25
+ readonly reasoning: "Vertex AI Claude Haiku fallback";
26
26
  };
27
27
  };
28
28
  readonly reasoning: {
29
29
  readonly primary: {
30
30
  readonly provider: "vertex";
31
- readonly model: "claude-sonnet-4@20250514";
31
+ readonly model: "claude-sonnet-4-5@20250929";
32
32
  readonly capabilities: readonly ["reasoning", "analysis", "complex-logic", "code", "creativity"];
33
33
  readonly avgResponseTime: 3000;
34
34
  readonly costPerToken: 0.003;
35
- readonly reasoning: "Advanced reasoning and analysis via Claude Sonnet 4 on Vertex AI";
35
+ readonly reasoning: "Advanced reasoning and analysis via Claude Sonnet 4-5 on Vertex AI";
36
36
  };
37
37
  readonly fallback: {
38
38
  readonly provider: "vertex";
39
- readonly model: "claude-opus-4@20250514";
39
+ readonly model: "claude-opus-4-5@20251101";
40
40
  readonly capabilities: readonly ["reasoning", "analysis", "complex-logic", "code", "creativity", "agentic"];
41
41
  readonly avgResponseTime: 4000;
42
42
  readonly costPerToken: 0.005;
43
- readonly reasoning: "Claude Opus 4 fallback on Vertex AI for most complex tasks";
43
+ readonly reasoning: "Claude Opus 4-5 fallback on Vertex AI for most complex tasks";
44
44
  };
45
45
  };
46
46
  };
@@ -22,23 +22,23 @@ const MODEL_CONFIGS = {
22
22
  provider: "vertex",
23
23
  model: "gemini-2.5-flash",
24
24
  capabilities: ["speed", "general", "code", "basic-reasoning"],
25
- avgResponseTime: 800, // ms
25
+ avgResponseTime: 800,
26
26
  costPerToken: 0.0001,
27
27
  reasoning: "Optimized for speed and efficiency via Vertex AI",
28
28
  },
29
29
  fallback: {
30
30
  provider: "vertex",
31
- model: "gemini-2.5-pro",
31
+ model: "claude-haiku-4-5@20251001",
32
32
  capabilities: ["speed", "general", "basic-reasoning"],
33
33
  avgResponseTime: 1200,
34
34
  costPerToken: 0.0002,
35
- reasoning: "Vertex AI Gemini Pro fallback",
35
+ reasoning: "Vertex AI Claude Haiku fallback",
36
36
  },
37
37
  },
38
38
  reasoning: {
39
39
  primary: {
40
40
  provider: "vertex",
41
- model: "claude-sonnet-4@20250514",
41
+ model: "claude-sonnet-4-5@20250929",
42
42
  capabilities: [
43
43
  "reasoning",
44
44
  "analysis",
@@ -46,13 +46,13 @@ const MODEL_CONFIGS = {
46
46
  "code",
47
47
  "creativity",
48
48
  ],
49
- avgResponseTime: 3000, // ms
49
+ avgResponseTime: 3000,
50
50
  costPerToken: 0.003,
51
- reasoning: "Advanced reasoning and analysis via Claude Sonnet 4 on Vertex AI",
51
+ reasoning: "Advanced reasoning and analysis via Claude Sonnet 4-5 on Vertex AI",
52
52
  },
53
53
  fallback: {
54
54
  provider: "vertex",
55
- model: "claude-opus-4@20250514",
55
+ model: "claude-opus-4-5@20251101",
56
56
  capabilities: [
57
57
  "reasoning",
58
58
  "analysis",
@@ -63,7 +63,7 @@ const MODEL_CONFIGS = {
63
63
  ],
64
64
  avgResponseTime: 4000,
65
65
  costPerToken: 0.005,
66
- reasoning: "Claude Opus 4 fallback on Vertex AI for most complex tasks",
66
+ reasoning: "Claude Opus 4-5 fallback on Vertex AI for most complex tasks",
67
67
  },
68
68
  },
69
69
  };
@@ -81,7 +81,7 @@ class ContextEnricher {
81
81
  * operations here so we can update the trace name in onEnd().
82
82
  */
83
83
  detectedOperations = new Map();
84
- onStart(span) {
84
+ onStart(span, parentContext) {
85
85
  const context = contextStorage.getStore();
86
86
  const userId = context?.userId ?? currentConfig?.userId ?? "guest";
87
87
  const sessionId = context?.sessionId ?? currentConfig?.sessionId;
@@ -140,10 +140,10 @@ class ContextEnricher {
140
140
  if (context?.requestId) {
141
141
  span.setAttribute("request.id", context.requestId);
142
142
  }
143
- // Set trace name for Langfuse (using proper Langfuse attribute)
144
- if (traceName) {
143
+ const isRootSpan = !trace.getSpan(parentContext);
144
+ if (traceName && isRootSpan) {
145
145
  span.setAttribute("langfuse.trace.name", traceName);
146
- span.setAttribute("trace.name", traceName); // Keep for compatibility
146
+ span.setAttribute("trace.name", traceName);
147
147
  }
148
148
  // Set operation name as separate attribute for filtering/analytics
149
149
  if (operationName) {
@@ -158,14 +158,16 @@ class ContextEnricher {
158
158
  if (typeof value === "string" ||
159
159
  typeof value === "number" ||
160
160
  typeof value === "boolean") {
161
- span.setAttribute(`metadata.${key}`, value);
161
+ if (metadata && isRootSpan) {
162
+ span.setAttribute("langfuse.trace.metadata", JSON.stringify(metadata));
163
+ }
162
164
  }
163
165
  else if (Array.isArray(value) &&
164
166
  value.every((v) => typeof v === "string" ||
165
167
  typeof v === "number" ||
166
168
  typeof v === "boolean")) {
167
169
  // OTEL supports homogeneous arrays of primitives
168
- span.setAttribute(`metadata.${key}`, value);
170
+ span.setAttribute(`metadata.${key}`, JSON.stringify(value));
169
171
  }
170
172
  else {
171
173
  // Fall back to JSON string for complex types
@@ -18,29 +18,29 @@ declare const MODEL_CONFIGS: {
18
18
  };
19
19
  readonly fallback: {
20
20
  readonly provider: "vertex";
21
- readonly model: "gemini-2.5-pro";
21
+ readonly model: "claude-haiku-4-5@20251001";
22
22
  readonly capabilities: readonly ["speed", "general", "basic-reasoning"];
23
23
  readonly avgResponseTime: 1200;
24
24
  readonly costPerToken: 0.0002;
25
- readonly reasoning: "Vertex AI Gemini Pro fallback";
25
+ readonly reasoning: "Vertex AI Claude Haiku fallback";
26
26
  };
27
27
  };
28
28
  readonly reasoning: {
29
29
  readonly primary: {
30
30
  readonly provider: "vertex";
31
- readonly model: "claude-sonnet-4@20250514";
31
+ readonly model: "claude-sonnet-4-5@20250929";
32
32
  readonly capabilities: readonly ["reasoning", "analysis", "complex-logic", "code", "creativity"];
33
33
  readonly avgResponseTime: 3000;
34
34
  readonly costPerToken: 0.003;
35
- readonly reasoning: "Advanced reasoning and analysis via Claude Sonnet 4 on Vertex AI";
35
+ readonly reasoning: "Advanced reasoning and analysis via Claude Sonnet 4-5 on Vertex AI";
36
36
  };
37
37
  readonly fallback: {
38
38
  readonly provider: "vertex";
39
- readonly model: "claude-opus-4@20250514";
39
+ readonly model: "claude-opus-4-5@20251101";
40
40
  readonly capabilities: readonly ["reasoning", "analysis", "complex-logic", "code", "creativity", "agentic"];
41
41
  readonly avgResponseTime: 4000;
42
42
  readonly costPerToken: 0.005;
43
- readonly reasoning: "Claude Opus 4 fallback on Vertex AI for most complex tasks";
43
+ readonly reasoning: "Claude Opus 4-5 fallback on Vertex AI for most complex tasks";
44
44
  };
45
45
  };
46
46
  };
@@ -22,23 +22,23 @@ const MODEL_CONFIGS = {
22
22
  provider: "vertex",
23
23
  model: "gemini-2.5-flash",
24
24
  capabilities: ["speed", "general", "code", "basic-reasoning"],
25
- avgResponseTime: 800, // ms
25
+ avgResponseTime: 800,
26
26
  costPerToken: 0.0001,
27
27
  reasoning: "Optimized for speed and efficiency via Vertex AI",
28
28
  },
29
29
  fallback: {
30
30
  provider: "vertex",
31
- model: "gemini-2.5-pro",
31
+ model: "claude-haiku-4-5@20251001",
32
32
  capabilities: ["speed", "general", "basic-reasoning"],
33
33
  avgResponseTime: 1200,
34
34
  costPerToken: 0.0002,
35
- reasoning: "Vertex AI Gemini Pro fallback",
35
+ reasoning: "Vertex AI Claude Haiku fallback",
36
36
  },
37
37
  },
38
38
  reasoning: {
39
39
  primary: {
40
40
  provider: "vertex",
41
- model: "claude-sonnet-4@20250514",
41
+ model: "claude-sonnet-4-5@20250929",
42
42
  capabilities: [
43
43
  "reasoning",
44
44
  "analysis",
@@ -46,13 +46,13 @@ const MODEL_CONFIGS = {
46
46
  "code",
47
47
  "creativity",
48
48
  ],
49
- avgResponseTime: 3000, // ms
49
+ avgResponseTime: 3000,
50
50
  costPerToken: 0.003,
51
- reasoning: "Advanced reasoning and analysis via Claude Sonnet 4 on Vertex AI",
51
+ reasoning: "Advanced reasoning and analysis via Claude Sonnet 4-5 on Vertex AI",
52
52
  },
53
53
  fallback: {
54
54
  provider: "vertex",
55
- model: "claude-opus-4@20250514",
55
+ model: "claude-opus-4-5@20251101",
56
56
  capabilities: [
57
57
  "reasoning",
58
58
  "analysis",
@@ -63,7 +63,7 @@ const MODEL_CONFIGS = {
63
63
  ],
64
64
  avgResponseTime: 4000,
65
65
  costPerToken: 0.005,
66
- reasoning: "Claude Opus 4 fallback on Vertex AI for most complex tasks",
66
+ reasoning: "Claude Opus 4-5 fallback on Vertex AI for most complex tasks",
67
67
  },
68
68
  },
69
69
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "9.22.1",
3
+ "version": "9.22.3",
4
4
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 13 providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
5
5
  "author": {
6
6
  "name": "Juspay Technologies",