@juspay/neurolink 9.22.1 → 9.22.2
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 +6 -0
- package/dist/core/modules/TelemetryHandler.js +5 -3
- package/dist/lib/core/modules/TelemetryHandler.js +5 -3
- package/dist/lib/services/server/ai/observability/instrumentation.js +8 -6
- package/dist/lib/utils/modelRouter.d.ts +6 -6
- package/dist/lib/utils/modelRouter.js +8 -8
- package/dist/services/server/ai/observability/instrumentation.js +8 -6
- package/dist/utils/modelRouter.d.ts +6 -6
- package/dist/utils/modelRouter.js +8 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [9.22.2](https://github.com/juspay/neurolink/compare/v9.22.1...v9.22.2) (2026-03-12)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **(observability):** prevent duplicate Langfuse traces from streaming by restricting trace attributes to root spans ([ddac782](https://github.com/juspay/neurolink/commit/ddac78229f7ed42a1d332c23e0a5e6d80418dd6a))
|
|
6
|
+
|
|
1
7
|
## [9.22.1](https://github.com/juspay/neurolink/compare/v9.22.0...v9.22.1) (2026-03-12)
|
|
2
8
|
|
|
3
9
|
### 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
|
|
147
|
-
const
|
|
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()
|
|
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
|
|
147
|
-
const
|
|
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()
|
|
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
|
-
|
|
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);
|
|
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
|
-
|
|
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: "
|
|
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
|
|
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@
|
|
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@
|
|
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,
|
|
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: "
|
|
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
|
|
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@
|
|
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,
|
|
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@
|
|
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
|
-
|
|
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);
|
|
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
|
-
|
|
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: "
|
|
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
|
|
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@
|
|
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@
|
|
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,
|
|
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: "
|
|
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
|
|
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@
|
|
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,
|
|
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@
|
|
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.
|
|
3
|
+
"version": "9.22.2",
|
|
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",
|