@juspay/neurolink 9.25.2 → 9.26.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/adapters/providerImageAdapter.d.ts +3 -27
  3. package/dist/adapters/providerImageAdapter.js +9 -199
  4. package/dist/agent/directTools.d.ts +35 -3
  5. package/dist/agent/directTools.js +122 -0
  6. package/dist/cli/commands/config.d.ts +6 -6
  7. package/dist/context/contextCompactor.d.ts +1 -2
  8. package/dist/context/contextCompactor.js +7 -1
  9. package/dist/context/prompts/summarizationPrompt.d.ts +3 -3
  10. package/dist/context/prompts/summarizationPrompt.js +16 -9
  11. package/dist/context/stages/structuredSummarizer.d.ts +2 -2
  12. package/dist/context/stages/structuredSummarizer.js +80 -30
  13. package/dist/lib/adapters/providerImageAdapter.d.ts +3 -27
  14. package/dist/lib/adapters/providerImageAdapter.js +9 -199
  15. package/dist/lib/agent/directTools.d.ts +33 -1
  16. package/dist/lib/agent/directTools.js +122 -0
  17. package/dist/lib/context/contextCompactor.d.ts +1 -2
  18. package/dist/lib/context/contextCompactor.js +7 -1
  19. package/dist/lib/context/prompts/summarizationPrompt.d.ts +3 -3
  20. package/dist/lib/context/prompts/summarizationPrompt.js +16 -9
  21. package/dist/lib/context/stages/structuredSummarizer.d.ts +2 -2
  22. package/dist/lib/context/stages/structuredSummarizer.js +80 -30
  23. package/dist/lib/mcp/servers/agent/directToolsServer.js +2 -0
  24. package/dist/lib/mcp/toolRegistry.d.ts +8 -0
  25. package/dist/lib/mcp/toolRegistry.js +20 -0
  26. package/dist/lib/neurolink.d.ts +10 -0
  27. package/dist/lib/neurolink.js +281 -17
  28. package/dist/lib/providers/googleAiStudio.js +13 -7
  29. package/dist/lib/types/configTypes.d.ts +3 -0
  30. package/dist/lib/types/contextTypes.d.ts +5 -2
  31. package/dist/lib/types/contextTypes.js +8 -8
  32. package/dist/lib/types/generateTypes.d.ts +25 -0
  33. package/dist/lib/types/modelTypes.d.ts +2 -2
  34. package/dist/lib/utils/messageBuilder.js +2 -0
  35. package/dist/lib/utils/modelAliasResolver.d.ts +17 -0
  36. package/dist/lib/utils/modelAliasResolver.js +55 -0
  37. package/dist/lib/utils/pdfProcessor.d.ts +1 -1
  38. package/dist/lib/utils/pdfProcessor.js +7 -7
  39. package/dist/lib/utils/toolUtils.d.ts +8 -0
  40. package/dist/lib/utils/toolUtils.js +15 -0
  41. package/dist/lib/workflow/config.d.ts +24 -24
  42. package/dist/mcp/servers/agent/directToolsServer.js +2 -0
  43. package/dist/mcp/toolRegistry.d.ts +8 -0
  44. package/dist/mcp/toolRegistry.js +20 -0
  45. package/dist/neurolink.d.ts +10 -0
  46. package/dist/neurolink.js +281 -17
  47. package/dist/providers/googleAiStudio.js +13 -7
  48. package/dist/server/utils/validation.d.ts +2 -2
  49. package/dist/types/configTypes.d.ts +3 -0
  50. package/dist/types/contextTypes.d.ts +5 -2
  51. package/dist/types/contextTypes.js +8 -8
  52. package/dist/types/generateTypes.d.ts +25 -0
  53. package/dist/utils/messageBuilder.js +2 -0
  54. package/dist/utils/modelAliasResolver.d.ts +17 -0
  55. package/dist/utils/modelAliasResolver.js +54 -0
  56. package/dist/utils/pdfProcessor.d.ts +1 -1
  57. package/dist/utils/pdfProcessor.js +7 -7
  58. package/dist/utils/toolUtils.d.ts +8 -0
  59. package/dist/utils/toolUtils.js +15 -0
  60. package/dist/workflow/config.d.ts +82 -82
  61. package/package.json +1 -1
@@ -155,12 +155,12 @@ export class ContextFactory {
155
155
  */
156
156
  static processContext(context, config = {}) {
157
157
  const startTime = Date.now();
158
- const finalConfig = { ...this.DEFAULT_CONFIG, ...config };
158
+ const finalConfig = { ...ContextFactory.DEFAULT_CONFIG, ...config };
159
159
  let processedContext = null;
160
160
  const template = "default";
161
161
  let truncated = false;
162
162
  if (finalConfig.includeInPrompt && finalConfig.mode !== "metadata_only") {
163
- processedContext = this.formatContextForPrompt(context, finalConfig);
163
+ processedContext = ContextFactory.formatContextForPrompt(context, finalConfig);
164
164
  // Truncate if necessary
165
165
  if (finalConfig.maxLength &&
166
166
  processedContext.length > finalConfig.maxLength) {
@@ -188,13 +188,13 @@ export class ContextFactory {
188
188
  static formatContextForPrompt(context, config) {
189
189
  switch (config.mode) {
190
190
  case "prompt_prefix":
191
- return this.formatAsPrefix(context);
191
+ return ContextFactory.formatAsPrefix(context);
192
192
  case "prompt_suffix":
193
- return this.formatAsSuffix(context);
193
+ return ContextFactory.formatAsSuffix(context);
194
194
  case "system_prompt":
195
- return this.formatForSystemPrompt(context);
195
+ return ContextFactory.formatForSystemPrompt(context);
196
196
  case "structured_prompt":
197
- return this.formatStructured(context);
197
+ return ContextFactory.formatStructured(context);
198
198
  case "metadata_only":
199
199
  case "none":
200
200
  default:
@@ -304,7 +304,7 @@ export class ContextConverter {
304
304
  legacyContext.authToken ||
305
305
  legacyContext.accessToken,
306
306
  endpoint: legacyContext.apiEndpoint || legacyContext.serviceUrl,
307
- provider: this.inferProvider(legacyContext),
307
+ provider: ContextConverter.inferProvider(legacyContext),
308
308
  },
309
309
  platformConfig: {
310
310
  type: legacyContext.platformType || "generic",
@@ -328,7 +328,7 @@ export class ContextConverter {
328
328
  }
329
329
  : {}),
330
330
  // Include all additional custom data
331
- ...this.extractCustomData(legacyContext),
331
+ ...ContextConverter.extractCustomData(legacyContext),
332
332
  },
333
333
  },
334
334
  metadata: includeMetadata
@@ -548,6 +548,13 @@ export type GenerateResult = {
548
548
  workflowId: string;
549
549
  workflowName: string;
550
550
  };
551
+ retries?: {
552
+ count: number;
553
+ errors: Array<{
554
+ code: string;
555
+ message: string;
556
+ }>;
557
+ };
551
558
  };
552
559
  /**
553
560
  * Unified options for both generation and streaming
@@ -899,6 +906,13 @@ export type TextGenerationResult = {
899
906
  imageOutput?: {
900
907
  base64: string;
901
908
  } | null;
909
+ retries?: {
910
+ count: number;
911
+ errors: Array<{
912
+ code: string;
913
+ message: string;
914
+ }>;
915
+ };
902
916
  };
903
917
  /**
904
918
  * Enhanced result type with optional analytics/evaluation
@@ -907,3 +921,14 @@ export type EnhancedGenerateResult = GenerateResult & {
907
921
  analytics?: AnalyticsData;
908
922
  evaluation?: EvaluationData;
909
923
  };
924
+ /**
925
+ * NL-004: Model alias/deprecation configuration.
926
+ * Allows mapping deprecated model names to their replacements.
927
+ */
928
+ export type ModelAliasConfig = {
929
+ aliases: Record<string, {
930
+ target: string;
931
+ action: "warn" | "redirect" | "block";
932
+ reason?: string;
933
+ }>;
934
+ };
@@ -1182,6 +1182,8 @@ async function downloadImageFromUrl(url) {
1182
1182
  * - Supports alt text for accessibility (included as context in text parts)
1183
1183
  */
1184
1184
  async function convertSimpleImagesToProviderFormat(text, images, provider, _model) {
1185
+ // Validate image count against provider-specific limits before processing
1186
+ ProviderImageAdapter.validateImageCount(images.length, provider, _model);
1185
1187
  // For Vercel AI SDK, we need to return the content in the standard format
1186
1188
  // The Vercel AI SDK will handle provider-specific formatting internally
1187
1189
  // IMPORTANT: Generate alt text descriptions BEFORE URL downloading to maintain correct image numbering
@@ -0,0 +1,17 @@
1
+ /**
2
+ * NL-004: Model alias/deprecation resolver.
3
+ *
4
+ * Resolves model names against an alias configuration map and applies the
5
+ * configured action (warn, redirect, or block).
6
+ */
7
+ import type { ModelAliasConfig } from "../types/generateTypes.js";
8
+ /**
9
+ * Resolve model aliases/deprecations.
10
+ * Checks the model name against the alias map and applies the configured action.
11
+ *
12
+ * @param model - The requested model name (may be undefined).
13
+ * @param config - The alias configuration containing model mappings.
14
+ * @returns The resolved model name (original or redirected).
15
+ * @throws {NeuroLinkError} When the alias action is "block".
16
+ */
17
+ export declare function resolveModel(model: string | undefined, config: ModelAliasConfig | undefined): string | undefined;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * NL-004: Model alias/deprecation resolver.
3
+ *
4
+ * Resolves model names against an alias configuration map and applies the
5
+ * configured action (warn, redirect, or block).
6
+ */
7
+ import { ErrorCategory, ErrorSeverity } from "../constants/enums.js";
8
+ import { NeuroLinkError } from "./errorHandling.js";
9
+ import { logger } from "./logger.js";
10
+ /**
11
+ * Resolve model aliases/deprecations.
12
+ * Checks the model name against the alias map and applies the configured action.
13
+ *
14
+ * @param model - The requested model name (may be undefined).
15
+ * @param config - The alias configuration containing model mappings.
16
+ * @returns The resolved model name (original or redirected).
17
+ * @throws {NeuroLinkError} When the alias action is "block".
18
+ */
19
+ export function resolveModel(model, config) {
20
+ if (!model || !config?.aliases) {
21
+ return model;
22
+ }
23
+ const alias = config.aliases[model];
24
+ if (!alias) {
25
+ return model;
26
+ }
27
+ switch (alias.action) {
28
+ case "block":
29
+ throw new NeuroLinkError({
30
+ code: "MODEL_DEPRECATED",
31
+ message: `Model '${model}' is blocked. ${alias.reason || `Use '${alias.target}' instead.`}`,
32
+ category: ErrorCategory.VALIDATION,
33
+ severity: ErrorSeverity.HIGH,
34
+ retriable: false,
35
+ context: {
36
+ requestedModel: model,
37
+ suggestedModel: alias.target,
38
+ reason: alias.reason,
39
+ },
40
+ });
41
+ case "warn":
42
+ logger.warn(`[ModelAlias] Model '${model}' is deprecated. ${alias.reason || `Redirecting to '${alias.target}'.`}`, {
43
+ requestedModel: model,
44
+ targetModel: alias.target,
45
+ reason: alias.reason,
46
+ });
47
+ return alias.target;
48
+ case "redirect":
49
+ logger.debug(`[ModelAlias] Redirecting model '${model}' to '${alias.target}'`);
50
+ return alias.target;
51
+ default:
52
+ return model;
53
+ }
54
+ }
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * The conversion uses pdf-to-img package (MuPDF-based) for high-quality conversion.
9
9
  */
10
- import type { FileProcessingResult, PDFProviderConfig, PDFProcessorOptions } from "../types/fileTypes.js";
10
+ import type { FileProcessingResult, PDFProcessorOptions, PDFProviderConfig } from "../types/fileTypes.js";
11
11
  /**
12
12
  * Options for PDF to image conversion
13
13
  */
@@ -8,8 +8,8 @@
8
8
  * The conversion uses pdf-to-img package (MuPDF-based) for high-quality conversion.
9
9
  */
10
10
  import { PDF_LIMITS } from "../core/constants.js";
11
- import { logger } from "./logger.js";
12
11
  import { ErrorFactory } from "./errorHandling.js";
12
+ import { logger } from "./logger.js";
13
13
  /**
14
14
  * Provider configurations for PDF handling
15
15
  *
@@ -98,7 +98,7 @@ const PDF_PROVIDER_CONFIGS = {
98
98
  "openai-compatible": {
99
99
  maxSizeMB: 10,
100
100
  maxPages: 100,
101
- supportsNative: true,
101
+ supportsNative: false, // LiteLLM is a proxy — underlying model may not support native PDF; default to safe text extraction
102
102
  requiresCitations: false,
103
103
  apiType: "files-api",
104
104
  },
@@ -133,7 +133,7 @@ export class PDFProcessor {
133
133
  static async process(content, options) {
134
134
  const provider = (options?.provider || "unknown").toLowerCase();
135
135
  const config = PDF_PROVIDER_CONFIGS[provider];
136
- if (!this.isValidPDF(content)) {
136
+ if (!PDFProcessor.isValidPDF(content)) {
137
137
  throw new Error("Invalid PDF file format. File must start with %PDF- header.");
138
138
  }
139
139
  if (!config) {
@@ -149,7 +149,7 @@ export class PDFProcessor {
149
149
  if (sizeMB > config.maxSizeMB) {
150
150
  throw new Error(`PDF size ${sizeMB.toFixed(2)}MB exceeds ${config.maxSizeMB}MB limit for ${provider}`);
151
151
  }
152
- const metadata = this.extractBasicMetadata(content);
152
+ const metadata = PDFProcessor.extractBasicMetadata(content);
153
153
  if (metadata.estimatedPages && metadata.estimatedPages > config.maxPages) {
154
154
  const enforceLimits = options?.enforceLimits !== false;
155
155
  if (enforceLimits) {
@@ -205,7 +205,7 @@ export class PDFProcessor {
205
205
  if (buffer.length < 5) {
206
206
  return false;
207
207
  }
208
- return buffer.subarray(0, 5).equals(this.PDF_SIGNATURE);
208
+ return buffer.subarray(0, 5).equals(PDFProcessor.PDF_SIGNATURE);
209
209
  }
210
210
  static extractBasicMetadata(buffer) {
211
211
  const headerSize = Math.min(10000, buffer.length);
@@ -274,7 +274,7 @@ export class PDFProcessor {
274
274
  "A valid PDF must be at least 5 bytes (PDF header).");
275
275
  }
276
276
  // 2. Validate PDF magic bytes (%PDF-)
277
- if (!this.isValidPDF(pdfBuffer)) {
277
+ if (!PDFProcessor.isValidPDF(pdfBuffer)) {
278
278
  throw new Error("Invalid PDF: File must start with %PDF- header. " +
279
279
  "The provided buffer does not appear to be a valid PDF file.");
280
280
  }
@@ -354,7 +354,7 @@ export class PDFProcessor {
354
354
  static async convertFromPath(pdfPath, options) {
355
355
  const fs = await import("fs/promises");
356
356
  const pdfBuffer = await fs.readFile(pdfPath);
357
- return this.convertToImages(pdfBuffer, options);
357
+ return PDFProcessor.convertToImages(pdfBuffer, options);
358
358
  }
359
359
  /**
360
360
  * Check if PDF to image conversion is available
@@ -24,6 +24,14 @@ export declare function shouldAllowCustomTools(toolConfig?: ToolConfig): boolean
24
24
  * @returns true if MCP tools should be enabled
25
25
  */
26
26
  export declare function shouldEnableMCPTools(toolConfig?: ToolConfig): boolean;
27
+ /**
28
+ * Check if the bash command execution tool should be enabled.
29
+ * This is opt-in only (defaults to false) for security reasons.
30
+ *
31
+ * @param toolConfig - Optional tool configuration (if available from config)
32
+ * @returns true if the bash tool should be enabled
33
+ */
34
+ export declare function shouldEnableBashTool(toolConfig?: ToolConfig): boolean;
27
35
  /**
28
36
  * Get maximum tools per provider
29
37
  * @param toolConfig - Optional tool configuration
@@ -40,6 +40,21 @@ export function shouldEnableMCPTools(toolConfig) {
40
40
  }
41
41
  return process.env.NEUROLINK_DISABLE_MCP_TOOLS !== "true";
42
42
  }
43
+ /**
44
+ * Check if the bash command execution tool should be enabled.
45
+ * This is opt-in only (defaults to false) for security reasons.
46
+ *
47
+ * @param toolConfig - Optional tool configuration (if available from config)
48
+ * @returns true if the bash tool should be enabled
49
+ */
50
+ export function shouldEnableBashTool(toolConfig) {
51
+ // Priority: explicit config > environment variable > default (false)
52
+ if (toolConfig?.enableBashTool !== undefined) {
53
+ return toolConfig.enableBashTool;
54
+ }
55
+ // Single source of truth for environment variable access
56
+ return process.env.NEUROLINK_ENABLE_BASH_TOOL === "true";
57
+ }
43
58
  /**
44
59
  * Get maximum tools per provider
45
60
  * @param toolConfig - Optional tool configuration