@juspay/neurolink 8.5.0 → 8.6.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 (58) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/adapters/providerImageAdapter.d.ts +4 -2
  3. package/dist/adapters/providerImageAdapter.js +72 -11
  4. package/dist/config/conversationMemory.d.ts +6 -0
  5. package/dist/config/conversationMemory.js +14 -0
  6. package/dist/constants/enums.d.ts +23 -3
  7. package/dist/constants/enums.js +30 -4
  8. package/dist/constants/tokens.d.ts +27 -12
  9. package/dist/constants/tokens.js +46 -12
  10. package/dist/core/baseProvider.js +6 -2
  11. package/dist/core/modules/GenerationHandler.js +20 -5
  12. package/dist/core/modules/MessageBuilder.js +4 -0
  13. package/dist/core/modules/TelemetryHandler.js +6 -1
  14. package/dist/lib/adapters/providerImageAdapter.d.ts +4 -2
  15. package/dist/lib/adapters/providerImageAdapter.js +72 -11
  16. package/dist/lib/config/conversationMemory.d.ts +6 -0
  17. package/dist/lib/config/conversationMemory.js +14 -0
  18. package/dist/lib/constants/enums.d.ts +23 -3
  19. package/dist/lib/constants/enums.js +30 -4
  20. package/dist/lib/constants/tokens.d.ts +27 -12
  21. package/dist/lib/constants/tokens.js +46 -12
  22. package/dist/lib/core/baseProvider.js +6 -2
  23. package/dist/lib/core/modules/GenerationHandler.js +20 -5
  24. package/dist/lib/core/modules/MessageBuilder.js +4 -0
  25. package/dist/lib/core/modules/TelemetryHandler.js +6 -1
  26. package/dist/lib/middleware/builtin/guardrails.js +7 -0
  27. package/dist/lib/models/modelRegistry.js +93 -0
  28. package/dist/lib/neurolink.js +75 -5
  29. package/dist/lib/providers/googleAiStudio.d.ts +27 -0
  30. package/dist/lib/providers/googleAiStudio.js +27 -0
  31. package/dist/lib/providers/googleVertex.d.ts +35 -0
  32. package/dist/lib/providers/googleVertex.js +38 -0
  33. package/dist/lib/telemetry/telemetryService.d.ts +1 -1
  34. package/dist/lib/telemetry/telemetryService.js +4 -4
  35. package/dist/lib/types/common.d.ts +5 -0
  36. package/dist/lib/types/content.d.ts +1 -1
  37. package/dist/lib/types/generateTypes.d.ts +68 -2
  38. package/dist/lib/types/multimodal.d.ts +38 -1
  39. package/dist/lib/types/streamTypes.d.ts +21 -2
  40. package/dist/lib/utils/messageBuilder.js +70 -8
  41. package/dist/lib/utils/multimodalOptionsBuilder.d.ts +1 -1
  42. package/dist/middleware/builtin/guardrails.js +7 -0
  43. package/dist/models/modelRegistry.js +93 -0
  44. package/dist/neurolink.js +75 -5
  45. package/dist/providers/googleAiStudio.d.ts +27 -0
  46. package/dist/providers/googleAiStudio.js +27 -0
  47. package/dist/providers/googleVertex.d.ts +35 -0
  48. package/dist/providers/googleVertex.js +38 -0
  49. package/dist/telemetry/telemetryService.d.ts +1 -1
  50. package/dist/telemetry/telemetryService.js +4 -4
  51. package/dist/types/common.d.ts +5 -0
  52. package/dist/types/content.d.ts +1 -1
  53. package/dist/types/generateTypes.d.ts +68 -2
  54. package/dist/types/multimodal.d.ts +38 -1
  55. package/dist/types/streamTypes.d.ts +21 -2
  56. package/dist/utils/messageBuilder.js +70 -8
  57. package/dist/utils/multimodalOptionsBuilder.d.ts +1 -1
  58. package/package.json +1 -1
@@ -6,7 +6,7 @@ import type { EvaluationData } from "./evaluation.js";
6
6
  import type { ChatMessage, ConversationMemoryConfig } from "./conversation.js";
7
7
  import type { MiddlewareFactoryOptions } from "./middlewareTypes.js";
8
8
  import type { JsonValue } from "./common.js";
9
- import type { Content } from "./content.js";
9
+ import type { Content, ImageWithAltText } from "./content.js";
10
10
  /**
11
11
  * Generate function options type - Primary method for content generation
12
12
  * Supports multimodal content while maintaining backward compatibility
@@ -14,7 +14,24 @@ import type { Content } from "./content.js";
14
14
  export type GenerateOptions = {
15
15
  input: {
16
16
  text: string;
17
- images?: Array<Buffer | string>;
17
+ /**
18
+ * Images to include in the request.
19
+ * Supports simple image data (Buffer, string) or objects with alt text for accessibility.
20
+ *
21
+ * @example Simple usage
22
+ * ```typescript
23
+ * images: [imageBuffer, "https://example.com/image.jpg"]
24
+ * ```
25
+ *
26
+ * @example With alt text for accessibility
27
+ * ```typescript
28
+ * images: [
29
+ * { data: imageBuffer, altText: "Product screenshot showing main dashboard" },
30
+ * { data: "https://example.com/chart.png", altText: "Sales chart for Q3 2024" }
31
+ * ]
32
+ * ```
33
+ */
34
+ images?: Array<Buffer | string | ImageWithAltText>;
18
35
  csvFiles?: Array<Buffer | string>;
19
36
  pdfFiles?: Array<Buffer | string>;
20
37
  files?: Array<Buffer | string>;
@@ -34,9 +51,58 @@ export type GenerateOptions = {
34
51
  temperature?: number;
35
52
  maxTokens?: number;
36
53
  systemPrompt?: string;
54
+ /**
55
+ * Zod schema for structured output validation
56
+ *
57
+ * @important Google Gemini Limitation
58
+ * Google Vertex AI and Google AI Studio cannot combine function calling with
59
+ * structured output. You MUST use `disableTools: true` when using schemas with
60
+ * Google providers.
61
+ *
62
+ * Error without disableTools: "Function calling with a response mime type:
63
+ * 'application/json' is unsupported"
64
+ *
65
+ * This is a documented Google API limitation, not a NeuroLink bug.
66
+ * All frameworks (LangChain, Vercel AI SDK, Agno, Instructor) use this approach.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * // ✅ Correct for Google providers
71
+ * const result = await neurolink.generate({
72
+ * schema: MySchema,
73
+ * provider: "vertex",
74
+ * disableTools: true // Required for Google
75
+ * });
76
+ *
77
+ * // ✅ No restriction for other providers
78
+ * const result = await neurolink.generate({
79
+ * schema: MySchema,
80
+ * provider: "openai" // Works without disableTools
81
+ * });
82
+ * ```
83
+ *
84
+ * @see https://ai.google.dev/gemini-api/docs/function-calling
85
+ */
37
86
  schema?: ValidationSchema;
38
87
  tools?: Record<string, Tool>;
39
88
  timeout?: number | string;
89
+ /**
90
+ * Disable tool execution (including built-in tools)
91
+ *
92
+ * @required For Google Gemini providers when using schemas
93
+ * Google Vertex AI and Google AI Studio require this flag when using
94
+ * structured output (schemas) due to Google API limitations.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * // Required for Google providers with schemas
99
+ * await neurolink.generate({
100
+ * schema: MySchema,
101
+ * provider: "vertex",
102
+ * disableTools: true
103
+ * });
104
+ * ```
105
+ */
40
106
  disableTools?: boolean;
41
107
  enableEvaluation?: boolean;
42
108
  enableAnalytics?: boolean;
@@ -52,6 +52,8 @@ export type TextContent = {
52
52
  export type ImageContent = {
53
53
  type: "image";
54
54
  data: Buffer | string;
55
+ /** Alternative text for accessibility (screen readers, SEO) */
56
+ altText?: string;
55
57
  mediaType?: "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/bmp" | "image/tiff";
56
58
  metadata?: {
57
59
  description?: string;
@@ -164,13 +166,48 @@ export type VideoContent = {
164
166
  * Covers text, images, documents, and multimedia
165
167
  */
166
168
  export type Content = TextContent | ImageContent | CSVContent | PDFContent | AudioContent | VideoContent;
169
+ /**
170
+ * Image data with optional alt text for accessibility
171
+ * Use this when you need to provide alt text for screen readers and SEO
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const imageWithAlt: ImageWithAltText = {
176
+ * data: imageBuffer,
177
+ * altText: "A dashboard showing quarterly sales trends"
178
+ * };
179
+ * ```
180
+ */
181
+ export type ImageWithAltText = {
182
+ /** Image data as Buffer, base64 string, URL, or data URI */
183
+ data: Buffer | string;
184
+ /** Alternative text for accessibility (screen readers, SEO) */
185
+ altText?: string;
186
+ };
167
187
  /**
168
188
  * Multimodal input type for options that may contain images or content arrays
169
189
  * This is the primary interface for users to provide multimodal content
170
190
  */
171
191
  export type MultimodalInput = {
172
192
  text: string;
173
- images?: Array<Buffer | string>;
193
+ /**
194
+ * Images to include in the request.
195
+ * Can be simple image data (Buffer, string) or objects with alt text for accessibility.
196
+ *
197
+ * @example Simple usage
198
+ * ```typescript
199
+ * images: [imageBuffer, "https://example.com/image.jpg"]
200
+ * ```
201
+ *
202
+ * @example With alt text for accessibility
203
+ * ```typescript
204
+ * images: [
205
+ * { data: imageBuffer, altText: "Product screenshot showing main dashboard" },
206
+ * { data: "https://example.com/chart.png", altText: "Sales chart for Q3 2024" }
207
+ * ]
208
+ * ```
209
+ */
210
+ images?: Array<Buffer | string | ImageWithAltText>;
174
211
  content?: Content[];
175
212
  csvFiles?: Array<Buffer | string>;
176
213
  pdfFiles?: Array<Buffer | string>;
@@ -1,7 +1,7 @@
1
1
  import type { Tool } from "ai";
2
2
  import type { ValidationSchema, StandardRecord } from "./typeAliases.js";
3
3
  import type { AIModelProviderConfig } from "./providers.js";
4
- import type { Content } from "./content.js";
4
+ import type { Content, ImageWithAltText } from "./content.js";
5
5
  import type { AnalyticsData, ToolExecutionEvent, ToolExecutionSummary } from "../types/index.js";
6
6
  import { AIProviderName } from "../constants/enums.js";
7
7
  import type { TokenUsage } from "./analytics.js";
@@ -125,7 +125,24 @@ export type StreamOptions = {
125
125
  input: {
126
126
  text: string;
127
127
  audio?: AudioInputSpec;
128
- images?: Array<Buffer | string>;
128
+ /**
129
+ * Images to include in the request.
130
+ * Supports simple image data (Buffer, string) or objects with alt text for accessibility.
131
+ *
132
+ * @example Simple usage
133
+ * ```typescript
134
+ * images: [imageBuffer, "https://example.com/image.jpg"]
135
+ * ```
136
+ *
137
+ * @example With alt text for accessibility
138
+ * ```typescript
139
+ * images: [
140
+ * { data: imageBuffer, altText: "Product screenshot showing main dashboard" },
141
+ * { data: "https://example.com/chart.png", altText: "Sales chart for Q3 2024" }
142
+ * ]
143
+ * ```
144
+ */
145
+ images?: Array<Buffer | string | ImageWithAltText>;
129
146
  csvFiles?: Array<Buffer | string>;
130
147
  pdfFiles?: Array<Buffer | string>;
131
148
  files?: Array<Buffer | string>;
@@ -211,6 +228,8 @@ export type StreamResult = {
211
228
  totalToolExecutions?: number;
212
229
  toolExecutionTime?: number;
213
230
  hasToolErrors?: boolean;
231
+ guardrailsBlocked?: boolean;
232
+ error?: string;
214
233
  };
215
234
  analytics?: AnalyticsData | Promise<AnalyticsData>;
216
235
  evaluation?: EvaluationData | Promise<EvaluationData>;
@@ -3,13 +3,37 @@
3
3
  * Centralized logic for building message arrays from TextGenerationOptions
4
4
  * Enhanced with multimodal support for images
5
5
  */
6
- import { CONVERSATION_INSTRUCTIONS } from "../config/conversationMemory.js";
6
+ import { CONVERSATION_INSTRUCTIONS, STRUCTURED_OUTPUT_INSTRUCTIONS, } from "../config/conversationMemory.js";
7
7
  import { ProviderImageAdapter, MultimodalLogger, } from "../adapters/providerImageAdapter.js";
8
8
  import { logger } from "./logger.js";
9
9
  import { FileDetector } from "./fileDetector.js";
10
10
  import { PDFProcessor } from "./pdfProcessor.js";
11
11
  import { request, getGlobalDispatcher, interceptors } from "undici";
12
12
  import { readFileSync, existsSync } from "fs";
13
+ /**
14
+ * Type guard to check if an image input has alt text
15
+ */
16
+ function isImageWithAltText(image) {
17
+ return (typeof image === "object" && !Buffer.isBuffer(image) && "data" in image);
18
+ }
19
+ /**
20
+ * Extract image data from an image input (handles both simple and alt text formats)
21
+ */
22
+ function extractImageData(image) {
23
+ if (isImageWithAltText(image)) {
24
+ return image.data;
25
+ }
26
+ return image;
27
+ }
28
+ /**
29
+ * Extract alt text from an image input if available
30
+ */
31
+ function extractAltText(image) {
32
+ if (isImageWithAltText(image)) {
33
+ return image.altText;
34
+ }
35
+ return undefined;
36
+ }
13
37
  /**
14
38
  * Type guard for validating message roles
15
39
  */
@@ -199,6 +223,15 @@ function formatCSVMetadata(metadata) {
199
223
  }
200
224
  return parts.length > 0 ? `**Metadata**: ${parts.join(" | ")}` : "";
201
225
  }
226
+ /**
227
+ * Check if structured output mode should be enabled
228
+ * Structured output is used when a schema is provided with json/structured format
229
+ */
230
+ function shouldUseStructuredOutput(options) {
231
+ return (!!options.schema &&
232
+ (options.output?.format === "json" ||
233
+ options.output?.format === "structured"));
234
+ }
202
235
  /**
203
236
  * Build a properly formatted message array for AI providers
204
237
  * Combines system prompt, conversation history, and current user prompt
@@ -215,6 +248,10 @@ export async function buildMessagesArray(options) {
215
248
  if (hasConversationHistory) {
216
249
  systemPrompt = `${systemPrompt.trim()}${CONVERSATION_INSTRUCTIONS}`;
217
250
  }
251
+ // Add structured output instructions when schema is provided with json/structured format
252
+ if (shouldUseStructuredOutput(options)) {
253
+ systemPrompt = `${systemPrompt.trim()}${STRUCTURED_OUTPUT_INSTRUCTIONS}`;
254
+ }
218
255
  // Add system message if we have one
219
256
  if (systemPrompt.trim()) {
220
257
  messages.push({
@@ -473,6 +510,10 @@ export async function buildMultimodalMessagesArray(options, provider, model) {
473
510
  if (hasConversationHistory) {
474
511
  systemPrompt = `${systemPrompt.trim()}${CONVERSATION_INSTRUCTIONS}`;
475
512
  }
513
+ // Add structured output instructions when schema is provided with json/structured format
514
+ if (shouldUseStructuredOutput(options)) {
515
+ systemPrompt = `${systemPrompt.trim()}${STRUCTURED_OUTPUT_INSTRUCTIONS}`;
516
+ }
476
517
  // Add file handling guidance when multimodal files are present
477
518
  const hasCSVFiles = (options.input.csvFiles && options.input.csvFiles.length > 0) ||
478
519
  (options.input.files &&
@@ -622,28 +663,47 @@ async function downloadImageFromUrl(url) {
622
663
  * - URLs: Downloaded and converted to base64 for Vercel AI SDK compatibility
623
664
  * - Local files: Converted to base64 for Vercel AI SDK compatibility
624
665
  * - Buffers/Data URIs: Processed normally
666
+ * - Supports alt text for accessibility (included as context in text parts)
625
667
  */
626
668
  async function convertSimpleImagesToProviderFormat(text, images, provider, _model) {
627
669
  // For Vercel AI SDK, we need to return the content in the standard format
628
670
  // The Vercel AI SDK will handle provider-specific formatting internally
671
+ // IMPORTANT: Generate alt text descriptions BEFORE URL downloading to maintain correct image numbering
672
+ // This ensures image numbers match the original order provided by users, even if some URLs fail to download
673
+ const altTextDescriptions = images
674
+ .map((image, idx) => {
675
+ const altText = extractAltText(image);
676
+ return altText ? `[Image ${idx + 1}: ${altText}]` : null;
677
+ })
678
+ .filter(Boolean);
679
+ // Build enhanced text with alt text context for accessibility
680
+ // NOTE: Alt text is appended to the user's prompt as contextual information because most AI providers
681
+ // don't have native alt text fields in their APIs. This approach ensures accessibility metadata
682
+ // is preserved and helps AI models better understand image content.
683
+ const enhancedText = altTextDescriptions.length > 0
684
+ ? `${text}\n\nImage descriptions for context: ${altTextDescriptions.join(" ")}`
685
+ : text;
629
686
  // Smart auto-detection: separate URLs from actual image data
687
+ // Also track alt text for each image
630
688
  const urlImages = [];
631
689
  const actualImages = [];
632
690
  images.forEach((image, _index) => {
633
- if (typeof image === "string" && isInternetUrl(image)) {
691
+ const imageData = extractImageData(image);
692
+ const altText = extractAltText(image);
693
+ if (typeof imageData === "string" && isInternetUrl(imageData)) {
634
694
  // Internet URL - will be downloaded and converted to base64
635
- urlImages.push(image);
695
+ urlImages.push({ url: imageData, altText });
636
696
  }
637
697
  else {
638
698
  // Actual image data (file path, Buffer, data URI) - process for Vercel AI SDK
639
- actualImages.push(image);
699
+ actualImages.push({ data: imageData, altText });
640
700
  }
641
701
  });
642
702
  // Download URL images and add to actual images
643
- for (const url of urlImages) {
703
+ for (const { url, altText } of urlImages) {
644
704
  try {
645
705
  const downloadedDataUri = await downloadImageFromUrl(url);
646
- actualImages.push(downloadedDataUri);
706
+ actualImages.push({ data: downloadedDataUri, altText });
647
707
  }
648
708
  catch (error) {
649
709
  MultimodalLogger.logError("URL_DOWNLOAD_FAILED_SKIPPING", error, { url });
@@ -651,9 +711,11 @@ async function convertSimpleImagesToProviderFormat(text, images, provider, _mode
651
711
  logger.warn(`Failed to download image from ${url}, skipping: ${error instanceof Error ? error.message : String(error)}`);
652
712
  }
653
713
  }
654
- const content = [{ type: "text", text }];
714
+ const content = [
715
+ { type: "text", text: enhancedText },
716
+ ];
655
717
  // Process all images (including downloaded URLs) for Vercel AI SDK
656
- actualImages.forEach((image, index) => {
718
+ actualImages.forEach(({ data: image }, index) => {
657
719
  try {
658
720
  // Vercel AI SDK expects { type: 'image', image: Buffer | string, mimeType?: string }
659
721
  // For Vertex AI, we need to include mimeType
@@ -44,7 +44,7 @@ import type { StreamOptions } from "../types/streamTypes.js";
44
44
  export declare function buildMultimodalOptions(options: StreamOptions, providerName: string, modelName: string): {
45
45
  input: {
46
46
  text: string;
47
- images: (string | Buffer<ArrayBufferLike>)[] | undefined;
47
+ images: (string | Buffer<ArrayBufferLike> | import("../types/multimodal.js").ImageWithAltText)[] | undefined;
48
48
  content: import("../types/multimodal.js").Content[] | undefined;
49
49
  files: (string | Buffer<ArrayBufferLike>)[] | undefined;
50
50
  csvFiles: (string | Buffer<ArrayBufferLike>)[] | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "8.5.0",
3
+ "version": "8.6.0",
4
4
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 9 major providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
5
5
  "author": {
6
6
  "name": "Juspay Technologies",