@juspay/neurolink 9.6.0 → 9.7.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.
- package/CHANGELOG.md +6 -0
- package/dist/adapters/video/vertexVideoHandler.js +3 -3
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/loop/optionsSchema.js +4 -0
- package/dist/core/analytics.js +11 -4
- package/dist/core/baseProvider.d.ts +6 -0
- package/dist/core/baseProvider.js +83 -14
- package/dist/core/conversationMemoryManager.d.ts +13 -0
- package/dist/core/conversationMemoryManager.js +28 -0
- package/dist/core/dynamicModels.js +3 -2
- package/dist/core/modules/GenerationHandler.js +2 -0
- package/dist/core/redisConversationMemoryManager.d.ts +11 -0
- package/dist/core/redisConversationMemoryManager.js +26 -9
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/lib/adapters/video/vertexVideoHandler.js +3 -3
- package/dist/lib/core/analytics.js +11 -4
- package/dist/lib/core/baseProvider.d.ts +6 -0
- package/dist/lib/core/baseProvider.js +83 -14
- package/dist/lib/core/conversationMemoryManager.d.ts +13 -0
- package/dist/lib/core/conversationMemoryManager.js +28 -0
- package/dist/lib/core/dynamicModels.js +3 -2
- package/dist/lib/core/modules/GenerationHandler.js +2 -0
- package/dist/lib/core/redisConversationMemoryManager.d.ts +11 -0
- package/dist/lib/core/redisConversationMemoryManager.js +26 -9
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +5 -0
- package/dist/lib/mcp/httpRetryHandler.js +6 -2
- package/dist/lib/neurolink.d.ts +5 -0
- package/dist/lib/neurolink.js +160 -10
- package/dist/lib/processors/base/BaseFileProcessor.js +2 -1
- package/dist/lib/processors/errors/errorHelpers.js +12 -4
- package/dist/lib/providers/amazonBedrock.js +2 -1
- package/dist/lib/providers/anthropic.js +2 -2
- package/dist/lib/providers/anthropicBaseProvider.js +10 -4
- package/dist/lib/providers/azureOpenai.js +14 -25
- package/dist/lib/providers/googleAiStudio.d.ts +0 -34
- package/dist/lib/providers/googleAiStudio.js +124 -315
- package/dist/lib/providers/googleNativeGemini3.d.ts +119 -0
- package/dist/lib/providers/googleNativeGemini3.js +264 -0
- package/dist/lib/providers/googleVertex.d.ts +0 -40
- package/dist/lib/providers/googleVertex.js +150 -317
- package/dist/lib/providers/huggingFace.js +20 -5
- package/dist/lib/providers/litellm.js +6 -4
- package/dist/lib/providers/mistral.js +3 -2
- package/dist/lib/providers/openAI.js +2 -2
- package/dist/lib/providers/openRouter.js +8 -7
- package/dist/lib/providers/openaiCompatible.js +10 -4
- package/dist/lib/rag/resilience/RetryHandler.js +6 -2
- package/dist/lib/services/server/ai/observability/instrumentation.d.ts +24 -2
- package/dist/lib/services/server/ai/observability/instrumentation.js +12 -1
- package/dist/lib/types/generateTypes.d.ts +28 -0
- package/dist/lib/types/ragTypes.d.ts +9 -1
- package/dist/lib/types/streamTypes.d.ts +13 -0
- package/dist/lib/utils/conversationMemory.js +15 -0
- package/dist/lib/utils/errorHandling.d.ts +5 -0
- package/dist/lib/utils/errorHandling.js +19 -0
- package/dist/lib/utils/pricing.d.ts +12 -0
- package/dist/lib/utils/pricing.js +134 -0
- package/dist/lib/utils/redis.d.ts +17 -0
- package/dist/lib/utils/redis.js +105 -0
- package/dist/lib/utils/timeout.d.ts +10 -0
- package/dist/lib/utils/timeout.js +15 -0
- package/dist/mcp/httpRetryHandler.js +6 -2
- package/dist/neurolink.d.ts +5 -0
- package/dist/neurolink.js +160 -10
- package/dist/processors/base/BaseFileProcessor.js +2 -1
- package/dist/processors/errors/errorHelpers.js +12 -4
- package/dist/providers/amazonBedrock.js +2 -1
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/anthropicBaseProvider.js +10 -4
- package/dist/providers/azureOpenai.js +14 -25
- package/dist/providers/googleAiStudio.d.ts +0 -34
- package/dist/providers/googleAiStudio.js +124 -315
- package/dist/providers/googleNativeGemini3.d.ts +119 -0
- package/dist/providers/googleNativeGemini3.js +263 -0
- package/dist/providers/googleVertex.d.ts +0 -40
- package/dist/providers/googleVertex.js +150 -317
- package/dist/providers/huggingFace.js +20 -5
- package/dist/providers/litellm.js +6 -4
- package/dist/providers/mistral.js +3 -2
- package/dist/providers/openAI.js +2 -2
- package/dist/providers/openRouter.js +8 -7
- package/dist/providers/openaiCompatible.js +10 -4
- package/dist/rag/resilience/RetryHandler.js +6 -2
- package/dist/services/server/ai/observability/instrumentation.d.ts +24 -2
- package/dist/services/server/ai/observability/instrumentation.js +12 -1
- package/dist/types/generateTypes.d.ts +28 -0
- package/dist/types/ragTypes.d.ts +9 -1
- package/dist/types/streamTypes.d.ts +13 -0
- package/dist/utils/conversationMemory.js +15 -0
- package/dist/utils/errorHandling.d.ts +5 -0
- package/dist/utils/errorHandling.js +19 -0
- package/dist/utils/pricing.d.ts +12 -0
- package/dist/utils/pricing.js +133 -0
- package/dist/utils/redis.d.ts +17 -0
- package/dist/utils/redis.js +105 -0
- package/dist/utils/timeout.d.ts +10 -0
- package/dist/utils/timeout.js +15 -0
- package/package.json +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { directAgentTools } from "../agent/directTools.js";
|
|
2
2
|
import { IMAGE_GENERATION_MODELS } from "../core/constants.js";
|
|
3
3
|
import { MiddlewareFactory } from "../middleware/factory.js";
|
|
4
|
+
import { isAbortError } from "../utils/errorHandling.js";
|
|
4
5
|
import { logger } from "../utils/logger.js";
|
|
5
|
-
import { createTimeoutController, TimeoutError } from "../utils/timeout.js";
|
|
6
|
+
import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../utils/timeout.js";
|
|
6
7
|
import { shouldDisableBuiltinTools } from "../utils/toolUtils.js";
|
|
7
8
|
import { getKeyCount, getKeysAsString } from "../utils/transformationUtils.js";
|
|
8
9
|
import { TTSProcessor } from "../utils/ttsProcessor.js";
|
|
@@ -101,16 +102,11 @@ export class BaseProvider {
|
|
|
101
102
|
// executeStream() can simply use options.tools (or getAllTools() + options.tools)
|
|
102
103
|
// and get the complete tool set without needing per-provider merge logic.
|
|
103
104
|
if (!options.disableTools && this.supportsTools()) {
|
|
104
|
-
const
|
|
105
|
-
const externalTools = (options.tools || {});
|
|
106
|
-
const mergedTools = { ...baseTools, ...externalTools };
|
|
105
|
+
const mergedTools = await this.getToolsForStream(options);
|
|
107
106
|
options = { ...options, tools: mergedTools };
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
externalToolCount: Object.keys(externalTools).length,
|
|
112
|
-
totalToolCount: Object.keys(mergedTools).length,
|
|
113
|
-
});
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
options = { ...options, tools: {} };
|
|
114
110
|
}
|
|
115
111
|
// CRITICAL FIX: Always prefer real streaming over fake streaming
|
|
116
112
|
// Try real streaming first, use fake streaming only as fallback
|
|
@@ -175,6 +171,13 @@ export class BaseProvider {
|
|
|
175
171
|
toolUsageContext: options.toolUsageContext,
|
|
176
172
|
context: options.context,
|
|
177
173
|
csvOptions: options.csvOptions,
|
|
174
|
+
// Forward abort, tool filtering, and timeout options to prevent
|
|
175
|
+
// silent bypass when falling back from real streaming to fake streaming
|
|
176
|
+
abortSignal: options.abortSignal,
|
|
177
|
+
toolFilter: options.toolFilter,
|
|
178
|
+
excludeTools: options.excludeTools,
|
|
179
|
+
skipToolPromptInjection: options.skipToolPromptInjection,
|
|
180
|
+
timeout: options.timeout,
|
|
178
181
|
};
|
|
179
182
|
logger.debug(`Calling generate for fake streaming`, {
|
|
180
183
|
provider: this.providerName,
|
|
@@ -254,18 +257,62 @@ export class BaseProvider {
|
|
|
254
257
|
throw this.handleProviderError(error);
|
|
255
258
|
}
|
|
256
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* Apply per-call tool filtering (whitelist/blacklist) to a tools record.
|
|
262
|
+
* If toolFilter is set, only tools whose names are in the list are kept.
|
|
263
|
+
* If excludeTools is set, matching tools are removed. excludeTools is applied after toolFilter.
|
|
264
|
+
*/
|
|
265
|
+
applyToolFiltering(tools, options) {
|
|
266
|
+
if ((!options.toolFilter || options.toolFilter.length === 0) &&
|
|
267
|
+
(!options.excludeTools || options.excludeTools.length === 0)) {
|
|
268
|
+
return tools;
|
|
269
|
+
}
|
|
270
|
+
const beforeCount = Object.keys(tools).length;
|
|
271
|
+
let filtered = { ...tools };
|
|
272
|
+
if (options.toolFilter && options.toolFilter.length > 0) {
|
|
273
|
+
const allowSet = new Set(options.toolFilter);
|
|
274
|
+
const result = {};
|
|
275
|
+
for (const [name, tool] of Object.entries(filtered)) {
|
|
276
|
+
if (allowSet.has(name)) {
|
|
277
|
+
result[name] = tool;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
filtered = result;
|
|
281
|
+
}
|
|
282
|
+
if (options.excludeTools && options.excludeTools.length > 0) {
|
|
283
|
+
const denySet = new Set(options.excludeTools);
|
|
284
|
+
for (const name of Object.keys(filtered)) {
|
|
285
|
+
if (denySet.has(name)) {
|
|
286
|
+
delete filtered[name];
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const afterCount = Object.keys(filtered).length;
|
|
291
|
+
if (beforeCount !== afterCount) {
|
|
292
|
+
logger.debug(`Tool filtering applied`, {
|
|
293
|
+
provider: this.providerName,
|
|
294
|
+
beforeCount,
|
|
295
|
+
afterCount,
|
|
296
|
+
toolFilter: options.toolFilter,
|
|
297
|
+
excludeTools: options.excludeTools,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return filtered;
|
|
301
|
+
}
|
|
257
302
|
/**
|
|
258
303
|
* Prepare generation context including tools and model
|
|
259
304
|
*/
|
|
260
305
|
async prepareGenerationContext(options) {
|
|
261
306
|
const shouldUseTools = !options.disableTools && this.supportsTools();
|
|
262
307
|
const baseTools = shouldUseTools ? await this.getAllTools() : {};
|
|
263
|
-
|
|
308
|
+
let tools = shouldUseTools
|
|
264
309
|
? {
|
|
265
310
|
...baseTools,
|
|
266
311
|
...(options.tools || {}),
|
|
267
312
|
}
|
|
268
313
|
: {};
|
|
314
|
+
// Apply per-call tool filtering (whitelist/blacklist)
|
|
315
|
+
tools = this.applyToolFiltering(tools, options);
|
|
269
316
|
logger.debug(`Final tools prepared for AI`, {
|
|
270
317
|
provider: this.providerName,
|
|
271
318
|
directTools: getKeyCount(baseTools),
|
|
@@ -294,7 +341,9 @@ export class BaseProvider {
|
|
|
294
341
|
}
|
|
295
342
|
const baseTools = await this.getAllTools();
|
|
296
343
|
const externalTools = (options.tools || {});
|
|
297
|
-
|
|
344
|
+
let merged = { ...baseTools, ...externalTools };
|
|
345
|
+
// Apply per-call tool filtering (whitelist/blacklist)
|
|
346
|
+
merged = this.applyToolFiltering(merged, options);
|
|
298
347
|
logger.debug(`Tools prepared for streaming`, {
|
|
299
348
|
provider: this.providerName,
|
|
300
349
|
baseToolCount: Object.keys(baseTools).length,
|
|
@@ -424,7 +473,19 @@ export class BaseProvider {
|
|
|
424
473
|
// ===== Normal AI Generation Flow =====
|
|
425
474
|
const { tools, model } = await this.prepareGenerationContext(options);
|
|
426
475
|
const messages = await this.buildMessages(options);
|
|
427
|
-
|
|
476
|
+
// Compose timeout signal with user-provided abort signal (mirrors stream path)
|
|
477
|
+
const timeoutController = createTimeoutController(options.timeout, this.providerName, "generate");
|
|
478
|
+
const composedSignal = composeAbortSignals(options.abortSignal, timeoutController?.controller.signal);
|
|
479
|
+
const composedOptions = composedSignal
|
|
480
|
+
? { ...options, abortSignal: composedSignal }
|
|
481
|
+
: options;
|
|
482
|
+
let generateResult;
|
|
483
|
+
try {
|
|
484
|
+
generateResult = await this.executeGeneration(model, messages, tools, composedOptions);
|
|
485
|
+
}
|
|
486
|
+
finally {
|
|
487
|
+
timeoutController?.cleanup();
|
|
488
|
+
}
|
|
428
489
|
this.analyzeAIResponse(generateResult);
|
|
429
490
|
this.logGenerationComplete(generateResult);
|
|
430
491
|
const responseTime = Date.now() - startTime;
|
|
@@ -471,7 +532,15 @@ export class BaseProvider {
|
|
|
471
532
|
return await this.enhanceResult(enhancedResult, options, startTime);
|
|
472
533
|
}
|
|
473
534
|
catch (error) {
|
|
474
|
-
|
|
535
|
+
// Abort errors are expected when a generation is cancelled — log at info, not error
|
|
536
|
+
if (isAbortError(error)) {
|
|
537
|
+
logger.info(`Generate aborted for ${this.providerName}`, {
|
|
538
|
+
error: error instanceof Error ? error.message : String(error),
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
logger.error(`Generate failed for ${this.providerName}:`, error);
|
|
543
|
+
}
|
|
475
544
|
throw this.handleProviderError(error);
|
|
476
545
|
}
|
|
477
546
|
}
|
|
@@ -18,6 +18,15 @@ export declare class ConversationMemoryManager implements IConversationMemoryMan
|
|
|
18
18
|
* Initialize the memory manager
|
|
19
19
|
*/
|
|
20
20
|
initialize(): Promise<void>;
|
|
21
|
+
/** Whether this memory manager can persist data (always true for in-memory within process) */
|
|
22
|
+
get canPersist(): boolean;
|
|
23
|
+
/** Whether Redis client is configured (always false for in-memory) */
|
|
24
|
+
get isRedisConfigured(): boolean;
|
|
25
|
+
/** Get health status for monitoring */
|
|
26
|
+
getHealthStatus(): {
|
|
27
|
+
initialized: boolean;
|
|
28
|
+
connected: boolean;
|
|
29
|
+
};
|
|
21
30
|
/**
|
|
22
31
|
* Store a conversation turn for a session
|
|
23
32
|
* TOKEN-BASED: Validates message size and triggers summarization based on tokens
|
|
@@ -32,6 +41,10 @@ export declare class ConversationMemoryManager implements IConversationMemoryMan
|
|
|
32
41
|
* Check if summarization is needed based on token count
|
|
33
42
|
*/
|
|
34
43
|
private checkAndSummarize;
|
|
44
|
+
/**
|
|
45
|
+
* Estimate total tokens for a list of messages
|
|
46
|
+
*/
|
|
47
|
+
private estimateTokens;
|
|
35
48
|
/**
|
|
36
49
|
* Build context messages for AI prompt injection (TOKEN-BASED)
|
|
37
50
|
* Returns messages from pointer onwards (or all if no pointer)
|
|
@@ -42,6 +42,21 @@ export class ConversationMemoryManager {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
+
/** Whether this memory manager can persist data (always true for in-memory within process) */
|
|
46
|
+
get canPersist() {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/** Whether Redis client is configured (always false for in-memory) */
|
|
50
|
+
get isRedisConfigured() {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
/** Get health status for monitoring */
|
|
54
|
+
getHealthStatus() {
|
|
55
|
+
return {
|
|
56
|
+
initialized: this.isInitialized,
|
|
57
|
+
connected: false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
45
60
|
/**
|
|
46
61
|
* Store a conversation turn for a session
|
|
47
62
|
* TOKEN-BASED: Validates message size and triggers summarization based on tokens
|
|
@@ -162,6 +177,19 @@ export class ConversationMemoryManager {
|
|
|
162
177
|
this.summarizationInProgress.delete(session.sessionId);
|
|
163
178
|
}
|
|
164
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Estimate total tokens for a list of messages
|
|
182
|
+
*/
|
|
183
|
+
estimateTokens(messages) {
|
|
184
|
+
return messages.reduce((total, msg) => {
|
|
185
|
+
let msgTokens = TokenUtils.estimateTokenCount(msg.content);
|
|
186
|
+
if (msg.events && Array.isArray(msg.events) && msg.events.length > 0) {
|
|
187
|
+
const eventsJson = JSON.stringify(msg.events);
|
|
188
|
+
msgTokens += TokenUtils.estimateTokenCount(eventsJson);
|
|
189
|
+
}
|
|
190
|
+
return total + msgTokens;
|
|
191
|
+
}, 0);
|
|
192
|
+
}
|
|
165
193
|
/**
|
|
166
194
|
* Build context messages for AI prompt injection (TOKEN-BASED)
|
|
167
195
|
* Returns messages from pointer onwards (or all if no pointer)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { isAbortError } from "../utils/errorHandling.js";
|
|
2
3
|
import { logger } from "../utils/logger.js";
|
|
3
4
|
/**
|
|
4
5
|
* Model configuration schema for validation
|
|
@@ -122,7 +123,7 @@ export class DynamicModelProvider {
|
|
|
122
123
|
}
|
|
123
124
|
catch (error) {
|
|
124
125
|
clearTimeout(timeoutId);
|
|
125
|
-
if (error
|
|
126
|
+
if (isAbortError(error)) {
|
|
126
127
|
throw new Error(`Request timeout after ${timeoutMs}ms`);
|
|
127
128
|
}
|
|
128
129
|
throw error;
|
|
@@ -177,7 +178,7 @@ export class DynamicModelProvider {
|
|
|
177
178
|
}
|
|
178
179
|
catch (error) {
|
|
179
180
|
clearTimeout(timeoutId);
|
|
180
|
-
if (error
|
|
181
|
+
if (isAbortError(error)) {
|
|
181
182
|
throw new Error(`Localhost health check timeout - server may not be running`);
|
|
182
183
|
}
|
|
183
184
|
// For connection refused, throw a more specific error
|
|
@@ -53,6 +53,7 @@ export class GenerationHandler {
|
|
|
53
53
|
...(shouldUseTools && { toolChoice: "auto" }),
|
|
54
54
|
temperature: options.temperature,
|
|
55
55
|
maxTokens: options.maxTokens,
|
|
56
|
+
abortSignal: options.abortSignal,
|
|
56
57
|
...(useStructuredOutput &&
|
|
57
58
|
options.schema && {
|
|
58
59
|
experimental_output: Output.object({ schema: options.schema }),
|
|
@@ -272,6 +273,7 @@ export class GenerationHandler {
|
|
|
272
273
|
return {
|
|
273
274
|
content,
|
|
274
275
|
usage,
|
|
276
|
+
finishReason: generateResult.finishReason,
|
|
275
277
|
provider: this.providerName,
|
|
276
278
|
model: this.modelName,
|
|
277
279
|
toolCalls: generateResult.toolCalls
|
|
@@ -34,6 +34,17 @@ export declare class RedisConversationMemoryManager implements IConversationMemo
|
|
|
34
34
|
* Initialize the memory manager with Redis connection
|
|
35
35
|
*/
|
|
36
36
|
initialize(): Promise<void>;
|
|
37
|
+
/** Whether this memory manager can persist data (Redis connected and initialized) */
|
|
38
|
+
get canPersist(): boolean;
|
|
39
|
+
/** Whether Redis client is configured and connected */
|
|
40
|
+
get isRedisConfigured(): boolean;
|
|
41
|
+
/** Get health status for monitoring */
|
|
42
|
+
getHealthStatus(): {
|
|
43
|
+
initialized: boolean;
|
|
44
|
+
connected: boolean;
|
|
45
|
+
host: string;
|
|
46
|
+
keyPrefix: string;
|
|
47
|
+
};
|
|
37
48
|
/**
|
|
38
49
|
* Get session by ID, reconstructing a SessionMemory from Redis storage.
|
|
39
50
|
*/
|
|
@@ -9,7 +9,7 @@ import { NeuroLink } from "../neurolink.js";
|
|
|
9
9
|
import { ConversationMemoryError } from "../types/conversation.js";
|
|
10
10
|
import { buildContextFromPointer, getEffectiveTokenThreshold, } from "../utils/conversationMemory.js";
|
|
11
11
|
import { logger } from "../utils/logger.js";
|
|
12
|
-
import { createRedisClient, deserializeConversation, getNormalizedConfig, getSessionKey, getUserSessionsKey, scanKeys, serializeConversation, } from "../utils/redis.js";
|
|
12
|
+
import { createRedisClient, deserializeConversation, getNormalizedConfig, getPooledRedisClient, getSessionKey, getUserSessionsKey, releasePooledRedisClient, scanKeys, serializeConversation, } from "../utils/redis.js";
|
|
13
13
|
/**
|
|
14
14
|
* Redis-based implementation of the ConversationMemoryManager
|
|
15
15
|
* Uses the same interface but stores data in Redis
|
|
@@ -54,7 +54,7 @@ export class RedisConversationMemoryManager {
|
|
|
54
54
|
keyPrefix: this.redisConfig.keyPrefix,
|
|
55
55
|
ttl: this.redisConfig.ttl,
|
|
56
56
|
});
|
|
57
|
-
this.redisClient = await
|
|
57
|
+
this.redisClient = await getPooledRedisClient(this.redisConfig);
|
|
58
58
|
this.isInitialized = true;
|
|
59
59
|
logger.info("RedisConversationMemoryManager initialized", {
|
|
60
60
|
storage: "redis",
|
|
@@ -82,6 +82,23 @@ export class RedisConversationMemoryManager {
|
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
/** Whether this memory manager can persist data (Redis connected and initialized) */
|
|
86
|
+
get canPersist() {
|
|
87
|
+
return (this.isInitialized && this.redisClient !== null && this.redisClient.isOpen);
|
|
88
|
+
}
|
|
89
|
+
/** Whether Redis client is configured and connected */
|
|
90
|
+
get isRedisConfigured() {
|
|
91
|
+
return this.redisClient !== null && this.redisClient.isOpen;
|
|
92
|
+
}
|
|
93
|
+
/** Get health status for monitoring */
|
|
94
|
+
getHealthStatus() {
|
|
95
|
+
return {
|
|
96
|
+
initialized: this.isInitialized,
|
|
97
|
+
connected: this.redisClient?.isOpen ?? false,
|
|
98
|
+
host: this.redisConfig.host,
|
|
99
|
+
keyPrefix: this.redisConfig.keyPrefix,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
85
102
|
/**
|
|
86
103
|
* Get session by ID, reconstructing a SessionMemory from Redis storage.
|
|
87
104
|
*/
|
|
@@ -671,7 +688,7 @@ export class RedisConversationMemoryManager {
|
|
|
671
688
|
* Uses AI to create a concise, descriptive title (5-8 words)
|
|
672
689
|
*/
|
|
673
690
|
async generateConversationTitle(userMessage) {
|
|
674
|
-
logger.
|
|
691
|
+
logger.info("[RedisConversationMemoryManager] Generating conversation title", {
|
|
675
692
|
userMessageLength: userMessage.length,
|
|
676
693
|
userMessagePreview: userMessage.substring(0, 100),
|
|
677
694
|
});
|
|
@@ -680,12 +697,12 @@ export class RedisConversationMemoryManager {
|
|
|
680
697
|
const titleGenerator = new NeuroLink({
|
|
681
698
|
conversationMemory: { enabled: false },
|
|
682
699
|
});
|
|
683
|
-
const titlePrompt = `Generate a clear, concise, and descriptive title (5–8 words maximum) for a conversation based on the following user message.
|
|
684
|
-
The title must meaningfully reflect the topic or intent of the message.
|
|
685
|
-
Do not output anything unrelated, vague, or generic.
|
|
700
|
+
const titlePrompt = `Generate a clear, concise, and descriptive title (5–8 words maximum) for a conversation based on the following user message.
|
|
701
|
+
The title must meaningfully reflect the topic or intent of the message.
|
|
702
|
+
Do not output anything unrelated, vague, or generic.
|
|
686
703
|
Do not say you cannot create a title. Always return a valid title.
|
|
687
704
|
|
|
688
|
-
User message: "${userMessage}`;
|
|
705
|
+
User message: "${userMessage}"`;
|
|
689
706
|
const result = await titleGenerator.generate({
|
|
690
707
|
input: { text: titlePrompt },
|
|
691
708
|
provider: this.config.summarizationProvider || "vertex",
|
|
@@ -704,7 +721,7 @@ User message: "${userMessage}`;
|
|
|
704
721
|
if (title.length < 3) {
|
|
705
722
|
title = "New Conversation";
|
|
706
723
|
}
|
|
707
|
-
logger.
|
|
724
|
+
logger.info("[RedisConversationMemoryManager] Generated conversation title", {
|
|
708
725
|
originalLength: result.content?.length || 0,
|
|
709
726
|
cleanedTitle: title,
|
|
710
727
|
titleLength: title.length,
|
|
@@ -744,7 +761,7 @@ User message: "${userMessage}`;
|
|
|
744
761
|
*/
|
|
745
762
|
async close() {
|
|
746
763
|
if (this.redisClient) {
|
|
747
|
-
await this.
|
|
764
|
+
await releasePooledRedisClient(this.redisConfig);
|
|
748
765
|
this.redisClient = null;
|
|
749
766
|
this.isInitialized = false;
|
|
750
767
|
logger.info("Redis connection closed");
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -40,12 +40,15 @@ export { validateTool } from "./sdk/toolRegistration.js";
|
|
|
40
40
|
export * from "./types/index.js";
|
|
41
41
|
export type { DynamicModelConfig, ModelRegistry } from "./types/modelTypes.js";
|
|
42
42
|
export { getAvailableProviders, getBestProvider, isValidProvider, } from "./utils/providerUtils.js";
|
|
43
|
+
export { calculateCost, hasPricing } from "./utils/pricing.js";
|
|
44
|
+
export { isAbortError } from "./utils/errorHandling.js";
|
|
43
45
|
import { NeuroLink } from "./neurolink.js";
|
|
44
46
|
export { NeuroLink };
|
|
45
47
|
export type { MCPServerInfo } from "./types/mcpTypes.js";
|
|
46
48
|
export type { LangfuseConfig, LangfuseSpanAttributes, ObservabilityConfig, OpenTelemetryConfig, TraceNameFormat, } from "./types/observability.js";
|
|
47
49
|
export { buildObservabilityConfigFromEnv } from "./utils/observabilityHelpers.js";
|
|
48
50
|
import { createContextEnricher, flushOpenTelemetry, getLangfuseContext, getLangfuseHealthStatus, getLangfuseSpanProcessor, getSpanProcessors, getTracer, getTracerProvider, initializeOpenTelemetry, isOpenTelemetryInitialized, isUsingExternalTracerProvider, setLangfuseContext, shutdownOpenTelemetry } from "./services/server/ai/observability/instrumentation.js";
|
|
51
|
+
export type { LangfuseContext } from "./services/server/ai/observability/instrumentation.js";
|
|
49
52
|
export { initializeOpenTelemetry, shutdownOpenTelemetry, flushOpenTelemetry, getLangfuseHealthStatus, setLangfuseContext, getLangfuseSpanProcessor, getTracerProvider, isOpenTelemetryInitialized, getSpanProcessors, createContextEnricher, isUsingExternalTracerProvider, getLangfuseContext, getTracer, };
|
|
50
53
|
export { clearAnalyticsMetrics, createAnalyticsMiddleware, getAnalyticsMetrics, } from "./middleware/builtin/analytics.js";
|
|
51
54
|
export { MiddlewareFactory } from "./middleware/factory.js";
|
|
@@ -191,6 +194,7 @@ export type { AuthorizationUrlResult, DiscoveredMcp, HTTPRetryConfig, MCPOAuthCo
|
|
|
191
194
|
export type { ExecutionContext, ToolExecutionResult, ToolInfo, } from "./types/tools.js";
|
|
192
195
|
export type { LogLevel } from "./types/utilities.js";
|
|
193
196
|
export { logger } from "./utils/logger.js";
|
|
197
|
+
export { getPoolStats } from "./utils/redis.js";
|
|
194
198
|
export declare function initializeTelemetry(): Promise<boolean>;
|
|
195
199
|
export declare function getTelemetryStatus(): Promise<{
|
|
196
200
|
enabled: boolean;
|
package/dist/lib/index.js
CHANGED
|
@@ -45,6 +45,10 @@ export { validateTool } from "./sdk/toolRegistration.js";
|
|
|
45
45
|
export * from "./types/index.js";
|
|
46
46
|
// Utility exports
|
|
47
47
|
export { getAvailableProviders, getBestProvider, isValidProvider, } from "./utils/providerUtils.js";
|
|
48
|
+
// Pricing utilities
|
|
49
|
+
export { calculateCost, hasPricing } from "./utils/pricing.js";
|
|
50
|
+
// Error utilities
|
|
51
|
+
export { isAbortError } from "./utils/errorHandling.js";
|
|
48
52
|
// Main NeuroLink wrapper class and diagnostic types
|
|
49
53
|
import { NeuroLink } from "./neurolink.js";
|
|
50
54
|
export { NeuroLink };
|
|
@@ -222,6 +226,7 @@ initializeMCPEcosystem, isRetryableHTTPError, isRetryableStatusCode, isTokenExpi
|
|
|
222
226
|
// Circuit Breaker
|
|
223
227
|
MCPCircuitBreaker, mcpLogger, NeuroLinkOAuthProvider, RateLimiterManager, validateServerTools, validateTool as validateMCPTool, withHTTPRetry, } from "./mcp/index.js";
|
|
224
228
|
export { logger } from "./utils/logger.js";
|
|
229
|
+
export { getPoolStats } from "./utils/redis.js";
|
|
225
230
|
// ============================================================================
|
|
226
231
|
// REAL-TIME SERVICES & TELEMETRY - Enterprise Platform Features
|
|
227
232
|
// ============================================================================
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Provides retry logic with exponential backoff and jitter
|
|
5
5
|
* specifically designed for HTTP-based MCP transport connections.
|
|
6
6
|
*/
|
|
7
|
+
import { isAbortError } from "../utils/errorHandling.js";
|
|
7
8
|
import { calculateBackoffDelay } from "../utils/retryHandler.js";
|
|
8
9
|
import { logger } from "../utils/logger.js";
|
|
9
10
|
/**
|
|
@@ -50,11 +51,14 @@ export function isRetryableHTTPError(error, config = DEFAULT_HTTP_RETRY_CONFIG)
|
|
|
50
51
|
return false;
|
|
51
52
|
}
|
|
52
53
|
const errorObj = error;
|
|
54
|
+
// User-initiated aborts are NOT retryable — the caller explicitly cancelled
|
|
55
|
+
if (isAbortError(error)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
53
58
|
// Check for timeout errors
|
|
54
59
|
if (errorObj.name === "TimeoutError" ||
|
|
55
60
|
errorObj.code === "TIMEOUT" ||
|
|
56
|
-
errorObj.code === "ETIMEDOUT"
|
|
57
|
-
errorObj.name === "AbortError") {
|
|
61
|
+
errorObj.code === "ETIMEDOUT") {
|
|
58
62
|
return true;
|
|
59
63
|
}
|
|
60
64
|
// Check for network-related errors
|
package/dist/lib/neurolink.d.ts
CHANGED
|
@@ -527,6 +527,11 @@ export declare class NeuroLink {
|
|
|
527
527
|
/**
|
|
528
528
|
* Create tool-aware system prompt that informs AI about available tools
|
|
529
529
|
*/
|
|
530
|
+
/**
|
|
531
|
+
* Apply per-call tool filtering (whitelist/blacklist) to a ToolInfo array.
|
|
532
|
+
* Used to filter the tool list before building the system prompt.
|
|
533
|
+
*/
|
|
534
|
+
private applyToolInfoFiltering;
|
|
530
535
|
private createToolAwareSystemPrompt;
|
|
531
536
|
/**
|
|
532
537
|
* Execute tools if available through centralized registry
|