@juspay/neurolink 8.3.0 → 8.4.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 (123) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -0
  3. package/dist/adapters/providerImageAdapter.d.ts +1 -1
  4. package/dist/adapters/providerImageAdapter.js +62 -0
  5. package/dist/agent/directTools.d.ts +0 -72
  6. package/dist/agent/directTools.js +3 -74
  7. package/dist/cli/commands/config.d.ts +18 -18
  8. package/dist/cli/factories/commandFactory.js +1 -0
  9. package/dist/constants/enums.d.ts +1 -0
  10. package/dist/constants/enums.js +3 -1
  11. package/dist/constants/tokens.d.ts +3 -0
  12. package/dist/constants/tokens.js +3 -0
  13. package/dist/core/baseProvider.d.ts +56 -53
  14. package/dist/core/baseProvider.js +107 -1095
  15. package/dist/core/constants.d.ts +3 -0
  16. package/dist/core/constants.js +6 -3
  17. package/dist/core/modelConfiguration.js +10 -0
  18. package/dist/core/modules/GenerationHandler.d.ts +63 -0
  19. package/dist/core/modules/GenerationHandler.js +230 -0
  20. package/dist/core/modules/MessageBuilder.d.ts +39 -0
  21. package/dist/core/modules/MessageBuilder.js +179 -0
  22. package/dist/core/modules/StreamHandler.d.ts +52 -0
  23. package/dist/core/modules/StreamHandler.js +103 -0
  24. package/dist/core/modules/TelemetryHandler.d.ts +64 -0
  25. package/dist/core/modules/TelemetryHandler.js +170 -0
  26. package/dist/core/modules/ToolsManager.d.ts +98 -0
  27. package/dist/core/modules/ToolsManager.js +521 -0
  28. package/dist/core/modules/Utilities.d.ts +88 -0
  29. package/dist/core/modules/Utilities.js +329 -0
  30. package/dist/factories/providerRegistry.js +1 -1
  31. package/dist/lib/adapters/providerImageAdapter.d.ts +1 -1
  32. package/dist/lib/adapters/providerImageAdapter.js +62 -0
  33. package/dist/lib/agent/directTools.d.ts +0 -72
  34. package/dist/lib/agent/directTools.js +3 -74
  35. package/dist/lib/constants/enums.d.ts +1 -0
  36. package/dist/lib/constants/enums.js +3 -1
  37. package/dist/lib/constants/tokens.d.ts +3 -0
  38. package/dist/lib/constants/tokens.js +3 -0
  39. package/dist/lib/core/baseProvider.d.ts +56 -53
  40. package/dist/lib/core/baseProvider.js +107 -1095
  41. package/dist/lib/core/constants.d.ts +3 -0
  42. package/dist/lib/core/constants.js +6 -3
  43. package/dist/lib/core/modelConfiguration.js +10 -0
  44. package/dist/lib/core/modules/GenerationHandler.d.ts +63 -0
  45. package/dist/lib/core/modules/GenerationHandler.js +231 -0
  46. package/dist/lib/core/modules/MessageBuilder.d.ts +39 -0
  47. package/dist/lib/core/modules/MessageBuilder.js +180 -0
  48. package/dist/lib/core/modules/StreamHandler.d.ts +52 -0
  49. package/dist/lib/core/modules/StreamHandler.js +104 -0
  50. package/dist/lib/core/modules/TelemetryHandler.d.ts +64 -0
  51. package/dist/lib/core/modules/TelemetryHandler.js +171 -0
  52. package/dist/lib/core/modules/ToolsManager.d.ts +98 -0
  53. package/dist/lib/core/modules/ToolsManager.js +522 -0
  54. package/dist/lib/core/modules/Utilities.d.ts +88 -0
  55. package/dist/lib/core/modules/Utilities.js +330 -0
  56. package/dist/lib/factories/providerRegistry.js +1 -1
  57. package/dist/lib/mcp/servers/agent/directToolsServer.js +0 -1
  58. package/dist/lib/memory/mem0Initializer.d.ts +32 -1
  59. package/dist/lib/memory/mem0Initializer.js +55 -2
  60. package/dist/lib/models/modelRegistry.js +44 -0
  61. package/dist/lib/neurolink.d.ts +1 -1
  62. package/dist/lib/neurolink.js +43 -10
  63. package/dist/lib/providers/amazonBedrock.js +59 -10
  64. package/dist/lib/providers/anthropic.js +2 -30
  65. package/dist/lib/providers/azureOpenai.js +2 -24
  66. package/dist/lib/providers/googleAiStudio.js +2 -24
  67. package/dist/lib/providers/googleVertex.js +2 -45
  68. package/dist/lib/providers/huggingFace.js +3 -31
  69. package/dist/lib/providers/litellm.d.ts +1 -1
  70. package/dist/lib/providers/litellm.js +110 -44
  71. package/dist/lib/providers/mistral.js +5 -32
  72. package/dist/lib/providers/ollama.d.ts +1 -0
  73. package/dist/lib/providers/ollama.js +476 -129
  74. package/dist/lib/providers/openAI.js +2 -28
  75. package/dist/lib/providers/openaiCompatible.js +3 -31
  76. package/dist/lib/types/content.d.ts +16 -113
  77. package/dist/lib/types/content.js +16 -2
  78. package/dist/lib/types/conversation.d.ts +3 -17
  79. package/dist/lib/types/generateTypes.d.ts +2 -2
  80. package/dist/lib/types/index.d.ts +2 -0
  81. package/dist/lib/types/index.js +2 -0
  82. package/dist/lib/types/multimodal.d.ts +282 -0
  83. package/dist/lib/types/multimodal.js +101 -0
  84. package/dist/lib/types/streamTypes.d.ts +2 -2
  85. package/dist/lib/utils/imageProcessor.d.ts +1 -1
  86. package/dist/lib/utils/messageBuilder.js +25 -2
  87. package/dist/lib/utils/multimodalOptionsBuilder.d.ts +1 -1
  88. package/dist/lib/utils/pdfProcessor.d.ts +9 -0
  89. package/dist/lib/utils/pdfProcessor.js +67 -9
  90. package/dist/mcp/servers/agent/directToolsServer.js +0 -1
  91. package/dist/memory/mem0Initializer.d.ts +32 -1
  92. package/dist/memory/mem0Initializer.js +55 -2
  93. package/dist/models/modelRegistry.js +44 -0
  94. package/dist/neurolink.d.ts +1 -1
  95. package/dist/neurolink.js +43 -10
  96. package/dist/providers/amazonBedrock.js +59 -10
  97. package/dist/providers/anthropic.js +2 -30
  98. package/dist/providers/azureOpenai.js +2 -24
  99. package/dist/providers/googleAiStudio.js +2 -24
  100. package/dist/providers/googleVertex.js +2 -45
  101. package/dist/providers/huggingFace.js +3 -31
  102. package/dist/providers/litellm.d.ts +1 -1
  103. package/dist/providers/litellm.js +110 -44
  104. package/dist/providers/mistral.js +5 -32
  105. package/dist/providers/ollama.d.ts +1 -0
  106. package/dist/providers/ollama.js +476 -129
  107. package/dist/providers/openAI.js +2 -28
  108. package/dist/providers/openaiCompatible.js +3 -31
  109. package/dist/types/content.d.ts +16 -113
  110. package/dist/types/content.js +16 -2
  111. package/dist/types/conversation.d.ts +3 -17
  112. package/dist/types/generateTypes.d.ts +2 -2
  113. package/dist/types/index.d.ts +2 -0
  114. package/dist/types/index.js +2 -0
  115. package/dist/types/multimodal.d.ts +282 -0
  116. package/dist/types/multimodal.js +100 -0
  117. package/dist/types/streamTypes.d.ts +2 -2
  118. package/dist/utils/imageProcessor.d.ts +1 -1
  119. package/dist/utils/messageBuilder.js +25 -2
  120. package/dist/utils/multimodalOptionsBuilder.d.ts +1 -1
  121. package/dist/utils/pdfProcessor.d.ts +9 -0
  122. package/dist/utils/pdfProcessor.js +67 -9
  123. package/package.json +5 -2
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Utilities Module
3
+ *
4
+ * Handles validation, normalization, schema conversion, and error handling utilities.
5
+ * Extracted from BaseProvider to follow Single Responsibility Principle.
6
+ *
7
+ * Responsibilities:
8
+ * - Options validation (text generation and stream options)
9
+ * - Options normalization (string to object conversion)
10
+ * - Provider information formatting
11
+ * - Timeout parsing and calculation
12
+ * - Schema utilities (Zod detection, permissive schema creation, OpenAI strict mode fixes)
13
+ * - Tool result conversion
14
+ * - Middleware options extraction
15
+ * - Common error pattern handling
16
+ *
17
+ * @module core/modules/Utilities
18
+ */
19
+ import { z } from "zod";
20
+ import { logger } from "../../utils/logger.js";
21
+ import { getSafeMaxTokens } from "../../utils/tokenLimits.js";
22
+ import { TimeoutError } from "../../utils/timeout.js";
23
+ import { validateStreamOptions as validateStreamOpts, validateTextGenerationOptions, ValidationError, createValidationSummary, } from "../../utils/parameterValidation.js";
24
+ import { STEP_LIMITS } from "../constants.js";
25
+ /**
26
+ * Utilities class - Provides validation, normalization, and utility methods
27
+ */
28
+ export class Utilities {
29
+ providerName;
30
+ modelName;
31
+ defaultTimeout;
32
+ middlewareOptions;
33
+ constructor(providerName, modelName, defaultTimeout = 30000, middlewareOptions) {
34
+ this.providerName = providerName;
35
+ this.modelName = modelName;
36
+ this.defaultTimeout = defaultTimeout;
37
+ this.middlewareOptions = middlewareOptions;
38
+ }
39
+ /**
40
+ * Validate text generation options
41
+ */
42
+ validateOptions(options) {
43
+ const validation = validateTextGenerationOptions(options);
44
+ if (!validation.isValid) {
45
+ const summary = createValidationSummary(validation);
46
+ throw new ValidationError(`Text generation options validation failed: ${summary}`, "options", "VALIDATION_FAILED", validation.suggestions);
47
+ }
48
+ // Log warnings if any
49
+ if (validation.warnings.length > 0) {
50
+ logger.warn("Text generation options validation warnings:", validation.warnings);
51
+ }
52
+ // Additional BaseProvider-specific validation
53
+ if (options.maxSteps !== undefined) {
54
+ if (options.maxSteps < STEP_LIMITS.min ||
55
+ options.maxSteps > STEP_LIMITS.max) {
56
+ throw new ValidationError(`maxSteps must be between ${STEP_LIMITS.min} and ${STEP_LIMITS.max}`, "maxSteps", "OUT_OF_RANGE", [
57
+ `Use a value between ${STEP_LIMITS.min} and ${STEP_LIMITS.max} for optimal performance`,
58
+ ]);
59
+ }
60
+ }
61
+ }
62
+ /**
63
+ * Validate stream options
64
+ */
65
+ validateStreamOptions(options) {
66
+ const validation = validateStreamOpts(options);
67
+ if (!validation.isValid) {
68
+ const summary = createValidationSummary(validation);
69
+ throw new ValidationError(`Stream options validation failed: ${summary}`, "options", "VALIDATION_FAILED", validation.suggestions);
70
+ }
71
+ // Log warnings if any
72
+ if (validation.warnings.length > 0) {
73
+ logger.warn("Stream options validation warnings:", validation.warnings);
74
+ }
75
+ // Additional BaseProvider-specific validation
76
+ if (options.maxSteps !== undefined) {
77
+ if (options.maxSteps < STEP_LIMITS.min ||
78
+ options.maxSteps > STEP_LIMITS.max) {
79
+ throw new ValidationError(`maxSteps must be between ${STEP_LIMITS.min} and ${STEP_LIMITS.max}`, "maxSteps", "OUT_OF_RANGE", [
80
+ `Use a value between ${STEP_LIMITS.min} and ${STEP_LIMITS.max} for optimal performance`,
81
+ ]);
82
+ }
83
+ }
84
+ }
85
+ /**
86
+ * Normalize text generation options from string or object
87
+ */
88
+ normalizeTextOptions(optionsOrPrompt) {
89
+ if (typeof optionsOrPrompt === "string") {
90
+ const safeMaxTokens = getSafeMaxTokens(this.providerName, this.modelName);
91
+ return {
92
+ prompt: optionsOrPrompt,
93
+ provider: this.providerName,
94
+ model: this.modelName,
95
+ maxTokens: safeMaxTokens,
96
+ };
97
+ }
98
+ // Handle both prompt and input.text formats
99
+ const prompt = optionsOrPrompt.prompt || optionsOrPrompt.input?.text || "";
100
+ const modelName = optionsOrPrompt.model || this.modelName;
101
+ const providerName = optionsOrPrompt.provider || this.providerName;
102
+ // Apply safe maxTokens based on provider and model
103
+ const safeMaxTokens = getSafeMaxTokens(providerName, modelName, optionsOrPrompt.maxTokens);
104
+ // CRITICAL FIX: Preserve the entire input object for multimodal support
105
+ // This ensures images and content arrays are not lost during normalization
106
+ const normalizedOptions = {
107
+ ...optionsOrPrompt,
108
+ prompt,
109
+ provider: providerName,
110
+ model: modelName,
111
+ maxTokens: safeMaxTokens,
112
+ };
113
+ // Ensure input object is preserved if it exists (for multimodal support)
114
+ if (optionsOrPrompt.input) {
115
+ normalizedOptions.input = {
116
+ ...optionsOrPrompt.input,
117
+ text: prompt, // Ensure text is consistent
118
+ };
119
+ }
120
+ return normalizedOptions;
121
+ }
122
+ /**
123
+ * Normalize stream options from string or object
124
+ */
125
+ normalizeStreamOptions(optionsOrPrompt) {
126
+ if (typeof optionsOrPrompt === "string") {
127
+ const safeMaxTokens = getSafeMaxTokens(this.providerName, this.modelName);
128
+ return {
129
+ input: { text: optionsOrPrompt },
130
+ provider: this.providerName,
131
+ model: this.modelName,
132
+ maxTokens: safeMaxTokens,
133
+ };
134
+ }
135
+ const modelName = optionsOrPrompt.model || this.modelName;
136
+ const providerName = optionsOrPrompt.provider || this.providerName;
137
+ // Apply safe maxTokens based on provider and model
138
+ const safeMaxTokens = getSafeMaxTokens(providerName, modelName, optionsOrPrompt.maxTokens);
139
+ return {
140
+ ...optionsOrPrompt,
141
+ provider: providerName,
142
+ model: modelName,
143
+ maxTokens: safeMaxTokens,
144
+ };
145
+ }
146
+ /**
147
+ * Get provider information
148
+ */
149
+ getProviderInfo() {
150
+ return {
151
+ provider: this.providerName,
152
+ model: this.modelName,
153
+ };
154
+ }
155
+ /**
156
+ * Get timeout value in milliseconds from options
157
+ * Supports number or string formats (e.g., '30s', '2m', '1h')
158
+ */
159
+ getTimeout(options) {
160
+ if (!options.timeout) {
161
+ return this.defaultTimeout;
162
+ }
163
+ if (typeof options.timeout === "number") {
164
+ return options.timeout;
165
+ }
166
+ // Parse string timeout (e.g., '30s', '2m', '1h')
167
+ const timeoutStr = options.timeout.toLowerCase();
168
+ const value = parseInt(timeoutStr);
169
+ if (timeoutStr.includes("h")) {
170
+ return value * 60 * 60 * 1000;
171
+ }
172
+ else if (timeoutStr.includes("m")) {
173
+ return value * 60 * 1000;
174
+ }
175
+ else if (timeoutStr.includes("s")) {
176
+ return value * 1000;
177
+ }
178
+ return this.defaultTimeout;
179
+ }
180
+ /**
181
+ * Check if a schema is a Zod schema
182
+ */
183
+ isZodSchema(schema) {
184
+ return (typeof schema === "object" &&
185
+ schema !== null &&
186
+ // Most Zod schemas have an internal _def and a parse method
187
+ typeof schema.parse === "function");
188
+ }
189
+ /**
190
+ * Convert tool execution result from MCP format to standard format
191
+ * Handles tool failures gracefully to prevent stream termination
192
+ */
193
+ async convertToolResult(result) {
194
+ // Handle MCP-style results
195
+ if (result && typeof result === "object" && "success" in result) {
196
+ const mcpResult = result;
197
+ if (mcpResult.success) {
198
+ return mcpResult.data;
199
+ }
200
+ else {
201
+ // Instead of throwing, return a structured error result
202
+ // This prevents tool failures from terminating streams
203
+ const errorMsg = typeof mcpResult.error === "string"
204
+ ? mcpResult.error
205
+ : "Tool execution failed";
206
+ // Log the error for debugging but don't throw
207
+ logger.warn(`Tool execution failed: ${errorMsg}`);
208
+ // Return error as structured data that can be processed by the AI
209
+ return {
210
+ isError: true,
211
+ error: errorMsg,
212
+ content: [
213
+ {
214
+ type: "text",
215
+ text: `Tool execution failed: ${errorMsg}`,
216
+ },
217
+ ],
218
+ };
219
+ }
220
+ }
221
+ return result;
222
+ }
223
+ /**
224
+ * Create a permissive Zod schema that accepts all parameters as-is
225
+ */
226
+ createPermissiveZodSchema() {
227
+ // Create a permissive record that accepts any object structure
228
+ // This allows all parameters to pass through without validation issues
229
+ return z.record(z.unknown()).transform((data) => {
230
+ // Return the data as-is to preserve all parameter information
231
+ return data;
232
+ });
233
+ }
234
+ /**
235
+ * Recursively fix JSON Schema for OpenAI strict mode compatibility
236
+ * OpenAI requires additionalProperties: false at ALL levels and preserves required array
237
+ */
238
+ fixSchemaForOpenAIStrictMode(schema) {
239
+ const fixedSchema = JSON.parse(JSON.stringify(schema));
240
+ if (fixedSchema.type === "object" &&
241
+ fixedSchema.properties &&
242
+ typeof fixedSchema.properties === "object") {
243
+ const allPropertyNames = Object.keys(fixedSchema.properties);
244
+ if (!fixedSchema.required || !Array.isArray(fixedSchema.required)) {
245
+ fixedSchema.required = [];
246
+ }
247
+ fixedSchema.additionalProperties = false;
248
+ for (const propName of allPropertyNames) {
249
+ const propValue = fixedSchema.properties[propName];
250
+ if (propValue && typeof propValue === "object") {
251
+ if (propValue.type === "object") {
252
+ fixedSchema.properties[propName] =
253
+ this.fixSchemaForOpenAIStrictMode(propValue);
254
+ }
255
+ else if (propValue.type === "array" &&
256
+ propValue.items &&
257
+ typeof propValue.items === "object") {
258
+ fixedSchema.properties[propName].items =
259
+ this.fixSchemaForOpenAIStrictMode(propValue.items);
260
+ }
261
+ }
262
+ }
263
+ }
264
+ return fixedSchema;
265
+ }
266
+ /**
267
+ * Extract middleware options from generation/stream options
268
+ * This is the single source of truth for deciding if middleware should be applied
269
+ */
270
+ extractMiddlewareOptions(options) {
271
+ // 1. Determine effective middleware config: per-request overrides global.
272
+ const middlewareOpts = options.middleware ??
273
+ this.middlewareOptions;
274
+ if (!middlewareOpts) {
275
+ return null;
276
+ }
277
+ // 2. The middleware property must be an object with configuration.
278
+ if (typeof middlewareOpts !== "object" ||
279
+ middlewareOpts === null ||
280
+ middlewareOpts instanceof Date ||
281
+ middlewareOpts instanceof RegExp) {
282
+ return null;
283
+ }
284
+ // 3. Check if the middleware object has any actual configuration keys.
285
+ const fullOpts = middlewareOpts;
286
+ const hasArray = (arr) => Array.isArray(arr) && arr.length > 0;
287
+ const hasConfig = !!fullOpts.middlewareConfig ||
288
+ hasArray(fullOpts.enabledMiddleware) ||
289
+ hasArray(fullOpts.disabledMiddleware) ||
290
+ !!fullOpts.preset ||
291
+ hasArray(fullOpts.middleware);
292
+ if (!hasConfig) {
293
+ return null;
294
+ }
295
+ // 4. Return the formatted options if configuration is present.
296
+ return {
297
+ ...fullOpts,
298
+ global: {
299
+ collectStats: true,
300
+ continueOnError: true,
301
+ ...(fullOpts.global || {}),
302
+ },
303
+ };
304
+ }
305
+ /**
306
+ * Handle common error patterns across providers
307
+ * Returns transformed error or null if not a common pattern
308
+ */
309
+ handleCommonErrors(error) {
310
+ if (error instanceof TimeoutError) {
311
+ return new Error(`${this.providerName} request timed out after ${error.timeout}ms. Consider increasing timeout or using a lighter model.`);
312
+ }
313
+ const message = error instanceof Error ? error.message : String(error);
314
+ // Common API key errors
315
+ if (message.includes("API_KEY_INVALID") ||
316
+ message.includes("Invalid API key") ||
317
+ message.includes("authentication") ||
318
+ message.includes("unauthorized")) {
319
+ return new Error(`Invalid API key for ${this.providerName}. Please check your API key environment variable.`);
320
+ }
321
+ // Common rate limit errors
322
+ if (message.includes("rate limit") ||
323
+ message.includes("quota") ||
324
+ message.includes("429")) {
325
+ return new Error(`Rate limit exceeded for ${this.providerName}. Please wait before making more requests.`);
326
+ }
327
+ return null; // Not a common error, let provider handle it
328
+ }
329
+ }
330
+ //# sourceMappingURL=Utilities.js.map
@@ -24,7 +24,7 @@ export class ProviderRegistry {
24
24
  ProviderFactory.registerProvider(AIProviderName.GOOGLE_AI, async (modelName, _providerName, sdk) => {
25
25
  const { GoogleAIStudioProvider } = await import("../providers/googleAiStudio.js");
26
26
  return new GoogleAIStudioProvider(modelName, sdk);
27
- }, GoogleAIModels.GEMINI_2_5_FLASH, ["googleAiStudio", "google", "gemini", "google-ai"]);
27
+ }, GoogleAIModels.GEMINI_2_5_FLASH, ["googleAiStudio", "google", "gemini", "google-ai", "google-ai-studio"]);
28
28
  // Register OpenAI provider
29
29
  ProviderFactory.registerProvider(AIProviderName.OPENAI, async (modelName, _providerName, sdk) => {
30
30
  const { OpenAIProvider } = await import("../providers/openAI.js");
@@ -135,7 +135,6 @@ function getToolCategory(toolName) {
135
135
  case "readFile":
136
136
  case "writeFile":
137
137
  case "listDirectory":
138
- case "searchFiles":
139
138
  return "filesystem";
140
139
  case "websearchGrounding":
141
140
  return "search";
@@ -8,8 +8,39 @@ import { MemoryClient } from "mem0ai";
8
8
  */
9
9
  export interface Mem0Config {
10
10
  apiKey: string;
11
+ /**
12
+ * Optional organization ID - if not provided, will be auto-populated from ping() response
13
+ */
14
+ organizationId?: string;
15
+ /**
16
+ * Optional project ID - if not provided, will be auto-populated from ping() response
17
+ */
18
+ projectId?: string;
19
+ /**
20
+ * Whether to update project-level custom instructions during initialization
21
+ * Default: false (don't update project settings)
22
+ *
23
+ * Note: organizationId and projectId are NOT required - they will be auto-populated
24
+ * from the mem0 API via ping() if not provided
25
+ */
26
+ updateProjectSettings?: boolean;
27
+ /**
28
+ * Custom instructions and categories for mem0 extraction behavior
29
+ * Only used if updateProjectSettings is true
30
+ */
31
+ customPrompts?: {
32
+ /**
33
+ * Custom instructions for how mem0 should extract and store memories
34
+ * This applies to ALL memories added to the project
35
+ */
36
+ custom_instructions?: string;
37
+ /**
38
+ * Custom categories for organizing memories
39
+ */
40
+ custom_categories?: Array<Record<string, unknown>>;
41
+ };
11
42
  }
12
43
  /**
13
- * Initialize mem0 memory instance with cloud API
44
+ * Initialize mem0 memory instance with cloud API and optional project settings
14
45
  */
15
46
  export declare function initializeMem0(mem0Config: Mem0Config): Promise<MemoryClient | null>;
@@ -5,7 +5,7 @@
5
5
  import { MemoryClient } from "mem0ai";
6
6
  import { logger } from "../utils/logger.js";
7
7
  /**
8
- * Initialize mem0 memory instance with cloud API
8
+ * Initialize mem0 memory instance with cloud API and optional project settings
9
9
  */
10
10
  export async function initializeMem0(mem0Config) {
11
11
  // Guard: skip initialization if API key is missing
@@ -18,8 +18,61 @@ export async function initializeMem0(mem0Config) {
18
18
  // Create MemoryClient instance with cloud API
19
19
  const client = new MemoryClient({
20
20
  apiKey: mem0Config.apiKey,
21
+ organizationId: mem0Config.organizationId,
22
+ projectId: mem0Config.projectId,
23
+ });
24
+ // Track whether project settings were actually updated (not just requested)
25
+ let projectSettingsUpdated = false;
26
+ // Update project-level settings if requested
27
+ if (mem0Config.updateProjectSettings && mem0Config.customPrompts) {
28
+ // Build update payload - only include fields that are actually provided
29
+ const updatePayload = {};
30
+ if (mem0Config.customPrompts.custom_instructions &&
31
+ mem0Config.customPrompts.custom_instructions.trim() !== "") {
32
+ updatePayload.custom_instructions =
33
+ mem0Config.customPrompts.custom_instructions;
34
+ }
35
+ if (Array.isArray(mem0Config.customPrompts.custom_categories) &&
36
+ mem0Config.customPrompts.custom_categories.length > 0) {
37
+ updatePayload.custom_categories =
38
+ mem0Config.customPrompts.custom_categories;
39
+ }
40
+ // Only proceed if there's something to update
41
+ if (Object.keys(updatePayload).length > 0) {
42
+ try {
43
+ // Note: updateProject() internally calls ping() first, which auto-populates
44
+ // organizationId and projectId from the server, so they're not required
45
+ await client.updateProject(updatePayload);
46
+ projectSettingsUpdated = true; // Only set to true on successful update
47
+ logger.info("[mem0Initializer] Project settings updated successfully", {
48
+ hasInstructions: !!updatePayload.custom_instructions,
49
+ hasCategories: !!updatePayload.custom_categories,
50
+ // Note: These IDs are auto-populated by ping() inside updateProject()
51
+ organizationId: client.organizationId,
52
+ projectId: client.projectId,
53
+ });
54
+ }
55
+ catch (error) {
56
+ logger.warn("[mem0Initializer] Failed to update project settings", {
57
+ error: error instanceof Error ? error.message : String(error),
58
+ hint: "Ensure your MEM0_API_KEY has permission to update project settings",
59
+ });
60
+ // Continue initialization even if project update fails
61
+ // projectSettingsUpdated remains false
62
+ }
63
+ }
64
+ else {
65
+ logger.warn("[mem0Initializer] updateProjectSettings=true but no custom instructions or categories provided - nothing to update");
66
+ }
67
+ }
68
+ else if (mem0Config.updateProjectSettings && !mem0Config.customPrompts) {
69
+ logger.warn("[mem0Initializer] updateProjectSettings=true but customPrompts not provided - nothing to update");
70
+ }
71
+ logger.info("[mem0Initializer] Mem0 cloud API initialized successfully", {
72
+ hasOrgId: !!client.organizationId,
73
+ hasProjectId: !!client.projectId,
74
+ projectSettingsUpdated,
21
75
  });
22
- logger.info("[mem0Initializer] Mem0 cloud API initialized successfully");
23
76
  return client;
24
77
  }
25
78
  catch (error) {
@@ -188,6 +188,50 @@ export const MODEL_REGISTRY = {
188
188
  category: "general",
189
189
  },
190
190
  // Anthropic Models
191
+ [AnthropicModels.CLAUDE_4_5_HAIKU]: {
192
+ id: AnthropicModels.CLAUDE_4_5_HAIKU,
193
+ name: "Claude 4.5 Haiku",
194
+ provider: AIProviderName.ANTHROPIC,
195
+ description: "Latest fast and efficient Claude model with vision support",
196
+ capabilities: {
197
+ vision: true,
198
+ functionCalling: true,
199
+ codeGeneration: true,
200
+ reasoning: true,
201
+ multimodal: true,
202
+ streaming: true,
203
+ jsonMode: false,
204
+ },
205
+ pricing: {
206
+ inputCostPer1K: 0.001,
207
+ outputCostPer1K: 0.005,
208
+ currency: "USD",
209
+ },
210
+ performance: {
211
+ speed: "fast",
212
+ quality: "high",
213
+ accuracy: "high",
214
+ },
215
+ limits: {
216
+ maxContextTokens: 200000,
217
+ maxOutputTokens: 64000,
218
+ maxRequestsPerMinute: 100,
219
+ },
220
+ useCases: {
221
+ coding: 8,
222
+ creative: 8,
223
+ analysis: 8,
224
+ conversation: 9,
225
+ reasoning: 8,
226
+ translation: 8,
227
+ summarization: 9,
228
+ },
229
+ aliases: ["claude-4.5-haiku", "claude-haiku-latest", "haiku-4.5"],
230
+ deprecated: false,
231
+ isLocal: false,
232
+ releaseDate: "2025-10-15",
233
+ category: "general",
234
+ },
191
235
  [AnthropicModels.CLAUDE_3_5_SONNET]: {
192
236
  id: AnthropicModels.CLAUDE_3_5_SONNET,
193
237
  name: "Claude 3.5 Sonnet",
@@ -137,7 +137,7 @@ export declare class NeuroLink {
137
137
  /** Extract memory context from search results */
138
138
  private extractMemoryContext;
139
139
  /** Store conversation turn in mem0 */
140
- private storeConversationTurn;
140
+ private storeMem0ConversationTurn;
141
141
  /**
142
142
  * Set up HITL event forwarding to main emitter
143
143
  */
@@ -402,9 +402,12 @@ Current user's request: ${currentInput}`;
402
402
  .join("\n");
403
403
  }
404
404
  /** Store conversation turn in mem0 */
405
- async storeConversationTurn(mem0, userContent, userId, metadata) {
406
- // Store user message only, reducing latency in mem0
407
- const conversationTurn = [{ role: "user", content: userContent }];
405
+ async storeMem0ConversationTurn(mem0, userContent, aiResponse, userId, metadata) {
406
+ // Store both user message and AI response for better context extraction
407
+ const conversationTurn = [
408
+ { role: "user", content: userContent },
409
+ { role: "assistant", content: aiResponse },
410
+ ];
408
411
  await mem0.add(conversationTurn, {
409
412
  user_id: userId,
410
413
  metadata,
@@ -455,7 +458,7 @@ Current user's request: ${currentInput}`;
455
458
  try {
456
459
  this.externalServerManager = new ExternalServerManager({
457
460
  maxServers: 20,
458
- defaultTimeout: 15000,
461
+ defaultTimeout: 30000, // Increased from 15s to 30s for proxy latency (e.g., LiteLLM)
459
462
  enableAutoRestart: true,
460
463
  enablePerformanceMonitoring: true,
461
464
  }, {
@@ -1366,7 +1369,7 @@ Current user's request: ${currentInput}`;
1366
1369
  try {
1367
1370
  const mem0 = await this.ensureMem0Ready();
1368
1371
  if (mem0) {
1369
- await this.storeConversationTurn(mem0, originalPrompt, options.context?.userId, {
1372
+ await this.storeMem0ConversationTurn(mem0, originalPrompt, generateResult.content, options.context?.userId, {
1370
1373
  timestamp: new Date().toISOString(),
1371
1374
  provider: generateResult.provider,
1372
1375
  model: generateResult.model,
@@ -1963,6 +1966,29 @@ Current user's request: ${currentInput}`;
1963
1966
  // Continue with original options if orchestration fails
1964
1967
  }
1965
1968
  }
1969
+ // 🔧 AUTO-DISABLE TOOLS: For Ollama models that don't support tools (same logic as generate())
1970
+ // This prevents overwhelming smaller models with massive tool descriptions in the system message
1971
+ if ((options.provider === "ollama" ||
1972
+ options.provider?.toLowerCase().includes("ollama")) &&
1973
+ !options.disableTools) {
1974
+ const { ModelConfigurationManager } = await import("./core/modelConfiguration.js");
1975
+ const modelConfig = ModelConfigurationManager.getInstance();
1976
+ const ollamaConfig = modelConfig.getProviderConfiguration("ollama");
1977
+ const toolCapableModels = ollamaConfig?.modelBehavior?.toolCapableModels || [];
1978
+ // Only disable tools if we have explicit evidence the model doesn't support them
1979
+ // If toolCapableModels is empty or model is not specified, don't make assumptions
1980
+ const modelName = options.model;
1981
+ if (toolCapableModels.length > 0 && modelName) {
1982
+ const modelSupportsTools = toolCapableModels.some((capableModel) => modelName.toLowerCase().includes(capableModel.toLowerCase()));
1983
+ if (!modelSupportsTools) {
1984
+ options.disableTools = true;
1985
+ logger.debug("Auto-disabled tools for Ollama model that doesn't support them (stream)", {
1986
+ model: options.model,
1987
+ toolCapableModels: toolCapableModels.slice(0, 3), // Show first 3 for brevity
1988
+ });
1989
+ }
1990
+ }
1991
+ }
1966
1992
  factoryResult = processStreamingFactoryOptions(options);
1967
1993
  enhancedOptions = createCleanStreamOptions(options);
1968
1994
  if (options.input?.text) {
@@ -2014,11 +2040,9 @@ Current user's request: ${currentInput}`;
2014
2040
  try {
2015
2041
  const mem0 = await self.ensureMem0Ready();
2016
2042
  if (mem0) {
2017
- await self.storeConversationTurn(mem0, originalPrompt, enhancedOptions.context?.userId, {
2043
+ await self.storeMem0ConversationTurn(mem0, originalPrompt, accumulatedContent.trim(), enhancedOptions.context?.userId, {
2018
2044
  timestamp: new Date().toISOString(),
2019
2045
  type: "conversation_turn_stream",
2020
- userMessage: originalPrompt,
2021
- aiResponse: accumulatedContent.trim(),
2022
2046
  });
2023
2047
  }
2024
2048
  }
@@ -2091,17 +2115,26 @@ Current user's request: ${currentInput}`;
2091
2115
  customTools: this.getCustomTools(),
2092
2116
  executeTool: this.executeTool.bind(this),
2093
2117
  }, "NeuroLink.createMCPStream");
2118
+ // 🔧 FIX: Get available tools and create tool-aware system prompt
2119
+ // Use SAME pattern as tryMCPGeneration (generate mode)
2120
+ const availableTools = await this.getAllAvailableTools();
2121
+ const enhancedSystemPrompt = this.createToolAwareSystemPrompt(options.systemPrompt, availableTools);
2094
2122
  // Get conversation messages for context
2095
2123
  const conversationMessages = await getConversationMessages(this.conversationMemory, {
2096
2124
  prompt: options.input.text,
2097
2125
  context: options.context,
2098
2126
  });
2099
- // Let provider handle tools and system prompt automatically via Vercel AI SDK
2100
- // This ensures proper tool integration in stream mode
2127
+ // 🔧 FIX: Pass enhanced system prompt to real streaming
2128
+ // Tools will be accessed through the streamText call in executeStream
2101
2129
  const streamResult = await provider.stream({
2102
2130
  ...options,
2131
+ systemPrompt: enhancedSystemPrompt, // Use enhanced prompt with tool descriptions
2103
2132
  conversationMessages,
2104
2133
  });
2134
+ logger.debug("[createMCPStream] Stream created successfully", {
2135
+ provider: providerName,
2136
+ systemPromptPassedLength: enhancedSystemPrompt.length,
2137
+ });
2105
2138
  return { stream: streamResult.stream, provider: providerName };
2106
2139
  }
2107
2140
  /**