@juspay/neurolink 7.54.0 → 8.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.
- package/CHANGELOG.md +34 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.js +2 -2
- package/dist/lib/mcp/mcpClientFactory.js +0 -3
- package/dist/lib/memory/mem0Initializer.d.ts +10 -5
- package/dist/lib/memory/mem0Initializer.js +17 -28
- package/dist/lib/neurolink.d.ts +8 -0
- package/dist/lib/neurolink.js +351 -316
- package/dist/lib/services/server/ai/observability/instrumentation.d.ts +17 -0
- package/dist/lib/services/server/ai/observability/instrumentation.js +54 -5
- package/dist/lib/types/conversation.d.ts +3 -6
- package/dist/lib/types/observability.d.ts +4 -0
- package/dist/lib/types/utilities.d.ts +0 -35
- package/dist/lib/utils/fileDetector.js +3 -3
- package/dist/lib/utils/messageBuilder.js +3 -3
- package/dist/mcp/mcpClientFactory.js +0 -3
- package/dist/memory/mem0Initializer.d.ts +10 -5
- package/dist/memory/mem0Initializer.js +17 -28
- package/dist/neurolink.d.ts +8 -0
- package/dist/neurolink.js +351 -316
- package/dist/services/server/ai/observability/instrumentation.d.ts +17 -0
- package/dist/services/server/ai/observability/instrumentation.js +54 -5
- package/dist/types/conversation.d.ts +3 -6
- package/dist/types/observability.d.ts +4 -0
- package/dist/types/utilities.d.ts +0 -35
- package/dist/utils/fileDetector.js +3 -3
- package/dist/utils/messageBuilder.js +3 -3
- package/package.json +7 -6
|
@@ -55,3 +55,20 @@ export declare function getLangfuseHealthStatus(): {
|
|
|
55
55
|
release: string;
|
|
56
56
|
} | undefined;
|
|
57
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* Set user and session context for Langfuse spans in the current async context
|
|
60
|
+
*
|
|
61
|
+
* Merges the provided context with existing AsyncLocalStorage context. If a callback is provided,
|
|
62
|
+
* the context is scoped to that callback execution. Without a callback, the context applies to
|
|
63
|
+
* the current execution context and its children.
|
|
64
|
+
*
|
|
65
|
+
* Uses AsyncLocalStorage to properly scope context per request, avoiding race conditions
|
|
66
|
+
* in concurrent scenarios.
|
|
67
|
+
*
|
|
68
|
+
* @param context - Object containing optional userId and/or sessionId to merge with existing context
|
|
69
|
+
* @param callback - Optional callback to run within the context scope. If omitted, context applies to current execution
|
|
70
|
+
*/
|
|
71
|
+
export declare function setLangfuseContext(context: {
|
|
72
|
+
userId?: string | null;
|
|
73
|
+
sessionId?: string | null;
|
|
74
|
+
}, callback?: () => void | Promise<void>): Promise<void>;
|
|
@@ -10,13 +10,38 @@ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
|
10
10
|
import { LangfuseSpanProcessor } from "@langfuse/otel";
|
|
11
11
|
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, } from "@opentelemetry/semantic-conventions";
|
|
12
12
|
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
13
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
13
14
|
import { logger } from "../../../../utils/logger.js";
|
|
14
15
|
const LOG_PREFIX = "[OpenTelemetry]";
|
|
16
|
+
const contextStorage = new AsyncLocalStorage();
|
|
15
17
|
let tracerProvider = null;
|
|
16
18
|
let langfuseProcessor = null;
|
|
17
19
|
let isInitialized = false;
|
|
18
20
|
let isCredentialsValid = false;
|
|
19
21
|
let currentConfig = null;
|
|
22
|
+
/**
|
|
23
|
+
* Span processor that enriches spans with user and session context from AsyncLocalStorage
|
|
24
|
+
*/
|
|
25
|
+
class ContextEnricher {
|
|
26
|
+
onStart(span) {
|
|
27
|
+
const context = contextStorage.getStore();
|
|
28
|
+
const userId = context?.userId ?? currentConfig?.userId;
|
|
29
|
+
const sessionId = context?.sessionId ?? currentConfig?.sessionId;
|
|
30
|
+
if (userId) {
|
|
31
|
+
span.setAttribute("user.id", userId);
|
|
32
|
+
}
|
|
33
|
+
if (sessionId) {
|
|
34
|
+
span.setAttribute("session.id", sessionId);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
onEnd() { }
|
|
38
|
+
shutdown() {
|
|
39
|
+
return Promise.resolve();
|
|
40
|
+
}
|
|
41
|
+
forceFlush() {
|
|
42
|
+
return Promise.resolve();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
20
45
|
/**
|
|
21
46
|
* Initialize OpenTelemetry with Langfuse span processor
|
|
22
47
|
*
|
|
@@ -46,7 +71,6 @@ export function initializeOpenTelemetry(config) {
|
|
|
46
71
|
try {
|
|
47
72
|
currentConfig = config;
|
|
48
73
|
isCredentialsValid = true;
|
|
49
|
-
// Create Langfuse span processor with configuration
|
|
50
74
|
langfuseProcessor = new LangfuseSpanProcessor({
|
|
51
75
|
publicKey: config.publicKey,
|
|
52
76
|
secretKey: config.secretKey,
|
|
@@ -54,18 +78,15 @@ export function initializeOpenTelemetry(config) {
|
|
|
54
78
|
environment: config.environment || "dev",
|
|
55
79
|
release: config.release || "v1.0.0",
|
|
56
80
|
});
|
|
57
|
-
// Create resource with service metadata (v2.x API)
|
|
58
81
|
const resource = resourceFromAttributes({
|
|
59
82
|
[ATTR_SERVICE_NAME]: "neurolink",
|
|
60
83
|
[ATTR_SERVICE_VERSION]: config.release || "v1.0.0",
|
|
61
84
|
"deployment.environment": config.environment || "dev",
|
|
62
85
|
});
|
|
63
|
-
// Initialize tracer provider with span processor and resource
|
|
64
86
|
tracerProvider = new NodeTracerProvider({
|
|
65
87
|
resource,
|
|
66
|
-
spanProcessors: [langfuseProcessor],
|
|
88
|
+
spanProcessors: [new ContextEnricher(), langfuseProcessor],
|
|
67
89
|
});
|
|
68
|
-
// Register provider globally so Vercel AI SDK can use it
|
|
69
90
|
tracerProvider.register();
|
|
70
91
|
isInitialized = true;
|
|
71
92
|
logger.info(`${LOG_PREFIX} Initialized with Langfuse span processor`, {
|
|
@@ -168,4 +189,32 @@ export function getLangfuseHealthStatus() {
|
|
|
168
189
|
: undefined,
|
|
169
190
|
};
|
|
170
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Set user and session context for Langfuse spans in the current async context
|
|
194
|
+
*
|
|
195
|
+
* Merges the provided context with existing AsyncLocalStorage context. If a callback is provided,
|
|
196
|
+
* the context is scoped to that callback execution. Without a callback, the context applies to
|
|
197
|
+
* the current execution context and its children.
|
|
198
|
+
*
|
|
199
|
+
* Uses AsyncLocalStorage to properly scope context per request, avoiding race conditions
|
|
200
|
+
* in concurrent scenarios.
|
|
201
|
+
*
|
|
202
|
+
* @param context - Object containing optional userId and/or sessionId to merge with existing context
|
|
203
|
+
* @param callback - Optional callback to run within the context scope. If omitted, context applies to current execution
|
|
204
|
+
*/
|
|
205
|
+
export async function setLangfuseContext(context, callback) {
|
|
206
|
+
const currentContext = contextStorage.getStore() || {};
|
|
207
|
+
const newContext = {
|
|
208
|
+
userId: context.userId !== undefined ? context.userId : currentContext.userId,
|
|
209
|
+
sessionId: context.sessionId !== undefined
|
|
210
|
+
? context.sessionId
|
|
211
|
+
: currentContext.sessionId,
|
|
212
|
+
};
|
|
213
|
+
if (callback) {
|
|
214
|
+
return await contextStorage.run(newContext, callback);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
contextStorage.enterWith(newContext);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
171
220
|
//# sourceMappingURL=instrumentation.js.map
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
* Conversation Memory Types for NeuroLink
|
|
3
3
|
* Provides type-safe conversation storage and context management
|
|
4
4
|
*/
|
|
5
|
-
import type {
|
|
6
|
-
/**
|
|
7
|
-
* Mem0 configuration type matching mem0ai/oss MemoryConfig structure
|
|
8
|
-
*/
|
|
5
|
+
import type { Mem0Config } from "../memory/mem0Initializer.js";
|
|
9
6
|
/**
|
|
10
7
|
* Configuration for conversation memory feature
|
|
11
8
|
*/
|
|
@@ -28,8 +25,8 @@ export type ConversationMemoryConfig = {
|
|
|
28
25
|
summarizationModel?: string;
|
|
29
26
|
/** Enable mem0 integration for conversation memory */
|
|
30
27
|
mem0Enabled?: boolean;
|
|
31
|
-
/** Configuration for mem0 integration */
|
|
32
|
-
mem0Config?:
|
|
28
|
+
/** Configuration for mem0 cloud API integration */
|
|
29
|
+
mem0Config?: Mem0Config;
|
|
33
30
|
/** Redis configuration (optional) - overrides environment variables */
|
|
34
31
|
redisConfig?: RedisStorageConfig;
|
|
35
32
|
};
|
|
@@ -24,6 +24,10 @@ export type LangfuseConfig = {
|
|
|
24
24
|
environment?: string;
|
|
25
25
|
/** Release/version identifier */
|
|
26
26
|
release?: string;
|
|
27
|
+
/** Optional default user id to attach to spans */
|
|
28
|
+
userId?: string;
|
|
29
|
+
/** Optional default session id to attach to spans */
|
|
30
|
+
sessionId?: string;
|
|
27
31
|
};
|
|
28
32
|
/**
|
|
29
33
|
* OpenTelemetry configuration
|
|
@@ -171,38 +171,3 @@ export type EnvVarValidationResult = {
|
|
|
171
171
|
invalidVars: string[];
|
|
172
172
|
warnings: string[];
|
|
173
173
|
};
|
|
174
|
-
/**
|
|
175
|
-
* Interface for mem0 Memory instance methods based on actual mem0ai/oss API
|
|
176
|
-
*/
|
|
177
|
-
export type Mem0Memory = {
|
|
178
|
-
search(query: string, config: {
|
|
179
|
-
userId?: string;
|
|
180
|
-
limit?: number;
|
|
181
|
-
}): Promise<{
|
|
182
|
-
results: Array<{
|
|
183
|
-
memory: string;
|
|
184
|
-
id: string;
|
|
185
|
-
}>;
|
|
186
|
-
}>;
|
|
187
|
-
add(messages: string, config: {
|
|
188
|
-
userId?: string;
|
|
189
|
-
metadata?: Record<string, unknown>;
|
|
190
|
-
}): Promise<{
|
|
191
|
-
results: Array<{
|
|
192
|
-
id: string;
|
|
193
|
-
memory: string;
|
|
194
|
-
}>;
|
|
195
|
-
}>;
|
|
196
|
-
get(memoryId: string): Promise<{
|
|
197
|
-
id: string;
|
|
198
|
-
memory: string;
|
|
199
|
-
} | null>;
|
|
200
|
-
update(memoryId: string, data: string): Promise<{
|
|
201
|
-
message: string;
|
|
202
|
-
}>;
|
|
203
|
-
delete(memoryId: string): Promise<{
|
|
204
|
-
message: string;
|
|
205
|
-
}>;
|
|
206
|
-
history(memoryId: string): Promise<unknown[]>;
|
|
207
|
-
reset(): Promise<void>;
|
|
208
|
-
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Centralized file detection for all multimodal file types
|
|
4
4
|
* Uses multi-strategy approach for reliable type identification
|
|
5
5
|
*/
|
|
6
|
-
import { request } from "undici";
|
|
6
|
+
import { request, getGlobalDispatcher, interceptors } from "undici";
|
|
7
7
|
import { readFile, stat } from "fs/promises";
|
|
8
8
|
import { logger } from "./logger.js";
|
|
9
9
|
import { CSVProcessor } from "./csvProcessor.js";
|
|
@@ -146,10 +146,10 @@ export class FileDetector {
|
|
|
146
146
|
const maxSize = options?.maxSize || 10 * 1024 * 1024;
|
|
147
147
|
const timeout = options?.timeout || 30000;
|
|
148
148
|
const response = await request(url, {
|
|
149
|
+
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
149
150
|
method: "GET",
|
|
150
151
|
headersTimeout: timeout,
|
|
151
152
|
bodyTimeout: timeout,
|
|
152
|
-
maxRedirections: 5,
|
|
153
153
|
});
|
|
154
154
|
if (response.statusCode !== 200) {
|
|
155
155
|
throw new Error(`HTTP ${response.statusCode}`);
|
|
@@ -271,10 +271,10 @@ class MimeTypeStrategy {
|
|
|
271
271
|
}
|
|
272
272
|
try {
|
|
273
273
|
const response = await request(input, {
|
|
274
|
+
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
274
275
|
method: "HEAD",
|
|
275
276
|
headersTimeout: 5000,
|
|
276
277
|
bodyTimeout: 5000,
|
|
277
|
-
maxRedirections: 5,
|
|
278
278
|
});
|
|
279
279
|
const contentType = response.headers["content-type"] || "";
|
|
280
280
|
const type = this.mimeToFileType(contentType);
|
|
@@ -8,7 +8,7 @@ import { ProviderImageAdapter, MultimodalLogger, } from "../adapters/providerIma
|
|
|
8
8
|
import { logger } from "./logger.js";
|
|
9
9
|
import { FileDetector } from "./fileDetector.js";
|
|
10
10
|
import { PDFProcessor } from "./pdfProcessor.js";
|
|
11
|
-
import { request } from "undici";
|
|
11
|
+
import { request, getGlobalDispatcher, interceptors } from "undici";
|
|
12
12
|
import { readFileSync, existsSync } from "fs";
|
|
13
13
|
/**
|
|
14
14
|
* Type guard for validating message roles
|
|
@@ -562,10 +562,10 @@ function isInternetUrl(input) {
|
|
|
562
562
|
async function downloadImageFromUrl(url) {
|
|
563
563
|
try {
|
|
564
564
|
const response = await request(url, {
|
|
565
|
+
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
565
566
|
method: "GET",
|
|
566
567
|
headersTimeout: 10000, // 10 second timeout for headers
|
|
567
|
-
bodyTimeout: 30000, // 30 second timeout for body
|
|
568
|
-
maxRedirections: 5,
|
|
568
|
+
bodyTimeout: 30000, // 30 second timeout for body,
|
|
569
569
|
});
|
|
570
570
|
if (response.statusCode !== 200) {
|
|
571
571
|
throw new Error(`HTTP ${response.statusCode}: Failed to download image from ${url}`);
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Mem0 Memory Initializer
|
|
3
|
-
* Simple initialization logic for mem0ai
|
|
3
|
+
* Simple initialization logic for mem0ai cloud API integration
|
|
4
4
|
*/
|
|
5
|
-
import
|
|
6
|
-
import type { Mem0Memory } from "../types/utilities.js";
|
|
5
|
+
import { MemoryClient } from "mem0ai";
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
7
|
+
* Mem0 cloud API configuration
|
|
9
8
|
*/
|
|
10
|
-
export
|
|
9
|
+
export interface Mem0Config {
|
|
10
|
+
apiKey: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Initialize mem0 memory instance with cloud API
|
|
14
|
+
*/
|
|
15
|
+
export declare function initializeMem0(mem0Config: Mem0Config): Promise<MemoryClient | null>;
|
|
@@ -1,42 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Mem0 Memory Initializer
|
|
3
|
-
* Simple initialization logic for mem0ai
|
|
3
|
+
* Simple initialization logic for mem0ai cloud API integration
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { MemoryClient } from "mem0ai";
|
|
6
6
|
import { logger } from "../utils/logger.js";
|
|
7
7
|
/**
|
|
8
|
-
* Initialize mem0 memory instance with
|
|
8
|
+
* Initialize mem0 memory instance with cloud API
|
|
9
9
|
*/
|
|
10
10
|
export async function initializeMem0(mem0Config) {
|
|
11
|
-
|
|
11
|
+
// Guard: skip initialization if API key is missing
|
|
12
|
+
if (!mem0Config?.apiKey || mem0Config.apiKey.trim() === "") {
|
|
13
|
+
logger.warn("[mem0Initializer] Missing MEM0_API_KEY; skipping mem0 initialization");
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
logger.debug("[mem0Initializer] Starting mem0 cloud API initialization");
|
|
12
17
|
try {
|
|
13
|
-
// Create
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
// Create MemoryClient instance with cloud API
|
|
19
|
+
const client = new MemoryClient({
|
|
20
|
+
apiKey: mem0Config.apiKey,
|
|
21
|
+
});
|
|
22
|
+
logger.info("[mem0Initializer] Mem0 cloud API initialized successfully");
|
|
23
|
+
return client;
|
|
17
24
|
}
|
|
18
25
|
catch (error) {
|
|
19
|
-
logger.warn("[mem0Initializer] Failed to initialize mem0
|
|
26
|
+
logger.warn("[mem0Initializer] Failed to initialize mem0 cloud API; disabling mem0", {
|
|
20
27
|
error: error instanceof Error ? error.message : String(error),
|
|
21
28
|
});
|
|
22
|
-
return
|
|
29
|
+
return null;
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Create fallback memory implementation
|
|
27
|
-
*/
|
|
28
|
-
function createFallbackMemory() {
|
|
29
|
-
return {
|
|
30
|
-
search: async () => ({ results: [] }),
|
|
31
|
-
add: async () => ({ results: [] }),
|
|
32
|
-
get: async () => null,
|
|
33
|
-
update: async () => ({
|
|
34
|
-
message: "Fallback memory does not support updates",
|
|
35
|
-
}),
|
|
36
|
-
delete: async () => ({
|
|
37
|
-
message: "Fallback memory does not support deletion",
|
|
38
|
-
}),
|
|
39
|
-
history: async () => [],
|
|
40
|
-
reset: async () => { },
|
|
41
|
-
};
|
|
42
|
-
}
|
package/dist/neurolink.d.ts
CHANGED
|
@@ -50,6 +50,10 @@ export declare class NeuroLink {
|
|
|
50
50
|
private hitlManager?;
|
|
51
51
|
private mem0Instance?;
|
|
52
52
|
private mem0Config?;
|
|
53
|
+
/**
|
|
54
|
+
* Extract and set Langfuse context from options with proper async scoping
|
|
55
|
+
*/
|
|
56
|
+
private setLangfuseContextFromOptions;
|
|
53
57
|
/**
|
|
54
58
|
* Simple sync config setup for mem0
|
|
55
59
|
*/
|
|
@@ -130,6 +134,10 @@ export declare class NeuroLink {
|
|
|
130
134
|
private initializeHITL;
|
|
131
135
|
/** Format memory context for prompt inclusion */
|
|
132
136
|
private formatMemoryContext;
|
|
137
|
+
/** Extract memory context from search results */
|
|
138
|
+
private extractMemoryContext;
|
|
139
|
+
/** Store conversation turn in mem0 */
|
|
140
|
+
private storeConversationTurn;
|
|
133
141
|
/**
|
|
134
142
|
* Set up HITL event forwarding to main emitter
|
|
135
143
|
*/
|