@juspay/neurolink 9.70.2 → 9.70.4

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.
@@ -14,6 +14,7 @@ import { FileDetector } from "../utils/fileDetector.js";
14
14
  import { processUnifiedFilesArray } from "../utils/messageBuilder.js";
15
15
  import { logger } from "../utils/logger.js";
16
16
  import { hasRestrictedOutputLimit, RESTRICTED_OUTPUT_TOKEN_LIMIT, toVertexAnthropicModelId, } from "../utils/modelDetection.js";
17
+ import { detectImageMimeType } from "../utils/imageDetection.js";
17
18
  import { resolveClaudeMaxTokens } from "../utils/tokenLimits.js";
18
19
  import { validateApiKey, createVertexProjectConfig, createGoogleAuthConfig, } from "../utils/providerConfig.js";
19
20
  import { convertZodToJsonSchema, inlineJsonSchema, ensureNestedSchemaTypes, } from "../utils/schemaConversion.js";
@@ -948,10 +949,17 @@ export class GoogleVertexProvider extends BaseProvider {
948
949
  else {
949
950
  // Assume base64 string
950
951
  imageBuffer = Buffer.from(image, "base64");
952
+ // Sniff the real format from magic bytes — bare base64 carries no
953
+ // mime hint, and leaving the image/jpeg default makes Anthropic
954
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
955
+ mimeType = this.detectImageType(imageBuffer);
951
956
  }
952
957
  }
953
958
  else {
954
959
  imageBuffer = image;
960
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
961
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
962
+ mimeType = this.detectImageType(imageBuffer);
955
963
  }
956
964
  const base64Data = imageBuffer.toString("base64");
957
965
  userParts.push({
@@ -1567,10 +1575,17 @@ export class GoogleVertexProvider extends BaseProvider {
1567
1575
  else {
1568
1576
  // Assume base64 string
1569
1577
  imageBuffer = Buffer.from(image, "base64");
1578
+ // Sniff the real format from magic bytes — bare base64 carries no
1579
+ // mime hint, and leaving the image/jpeg default makes Anthropic
1580
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
1581
+ mimeType = this.detectImageType(imageBuffer);
1570
1582
  }
1571
1583
  }
1572
1584
  else {
1573
1585
  imageBuffer = image;
1586
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
1587
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
1588
+ mimeType = this.detectImageType(imageBuffer);
1574
1589
  }
1575
1590
  const base64Data = imageBuffer.toString("base64");
1576
1591
  userParts.push({
@@ -2184,10 +2199,17 @@ export class GoogleVertexProvider extends BaseProvider {
2184
2199
  else {
2185
2200
  // Assume base64 string
2186
2201
  imageBuffer = Buffer.from(image, "base64");
2202
+ // Sniff the real format from magic bytes — bare base64 carries no
2203
+ // mime hint, and leaving the image/jpeg default makes Anthropic
2204
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
2205
+ mimeType = this.detectImageType(imageBuffer);
2187
2206
  }
2188
2207
  }
2189
2208
  else {
2190
2209
  imageBuffer = image;
2210
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
2211
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
2212
+ mimeType = this.detectImageType(imageBuffer);
2191
2213
  }
2192
2214
  const base64Data = imageBuffer.toString("base64");
2193
2215
  userContentParts.push({
@@ -2713,10 +2735,17 @@ export class GoogleVertexProvider extends BaseProvider {
2713
2735
  else {
2714
2736
  // Assume base64 string
2715
2737
  imageBuffer = Buffer.from(image, "base64");
2738
+ // Sniff the real format from magic bytes — bare base64 carries no
2739
+ // mime hint, and leaving the image/jpeg default makes Anthropic
2740
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
2741
+ mimeType = this.detectImageType(imageBuffer);
2716
2742
  }
2717
2743
  }
2718
2744
  else {
2719
2745
  imageBuffer = image;
2746
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
2747
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
2748
+ mimeType = this.detectImageType(imageBuffer);
2720
2749
  }
2721
2750
  const base64Data = imageBuffer.toString("base64");
2722
2751
  userContentParts.push({
@@ -4142,42 +4171,7 @@ export class GoogleVertexProvider extends BaseProvider {
4142
4171
  * Detect image MIME type from buffer
4143
4172
  */
4144
4173
  detectImageType(buffer) {
4145
- // Check PNG signature
4146
- if (buffer.length >= 8 &&
4147
- buffer[0] === 0x89 &&
4148
- buffer[1] === 0x50 &&
4149
- buffer[2] === 0x4e &&
4150
- buffer[3] === 0x47) {
4151
- return "image/png";
4152
- }
4153
- // Check JPEG signature
4154
- if (buffer.length >= 3 &&
4155
- buffer[0] === 0xff &&
4156
- buffer[1] === 0xd8 &&
4157
- buffer[2] === 0xff) {
4158
- return "image/jpeg";
4159
- }
4160
- // Check WebP signature
4161
- if (buffer.length >= 12 &&
4162
- buffer[0] === 0x52 &&
4163
- buffer[1] === 0x49 &&
4164
- buffer[2] === 0x46 &&
4165
- buffer[3] === 0x46 &&
4166
- buffer[8] === 0x57 &&
4167
- buffer[9] === 0x45 &&
4168
- buffer[10] === 0x42 &&
4169
- buffer[11] === 0x50) {
4170
- return "image/webp";
4171
- }
4172
- // Check GIF signature
4173
- if (buffer.length >= 6 &&
4174
- buffer[0] === 0x47 &&
4175
- buffer[1] === 0x49 &&
4176
- buffer[2] === 0x46) {
4177
- return "image/gif";
4178
- }
4179
- // Default to PNG if unknown
4180
- return "image/png";
4174
+ return detectImageMimeType(buffer);
4181
4175
  }
4182
4176
  /**
4183
4177
  * Estimate token count from text (simple character-based estimation)
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Image format detection from magic bytes.
3
+ *
4
+ * The native Vertex+Anthropic image block needs the correct `mimeType` for
5
+ * each inline image. Buffer and bare-base64 inputs (e.g. Slack / REST uploads)
6
+ * carry no mime hint, so the format must be sniffed from the leading bytes —
7
+ * otherwise a wrong default (historically `image/jpeg`) makes Anthropic reject
8
+ * PNG/GIF/WebP with a media-type mismatch 400.
9
+ */
10
+ /**
11
+ * Detect an image's MIME type from its magic bytes. Returns `image/png` for
12
+ * buffers that match no known signature (the safest neutral default for the
13
+ * Vertex image path).
14
+ */
15
+ export declare function detectImageMimeType(buffer: Buffer): string;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Image format detection from magic bytes.
3
+ *
4
+ * The native Vertex+Anthropic image block needs the correct `mimeType` for
5
+ * each inline image. Buffer and bare-base64 inputs (e.g. Slack / REST uploads)
6
+ * carry no mime hint, so the format must be sniffed from the leading bytes —
7
+ * otherwise a wrong default (historically `image/jpeg`) makes Anthropic reject
8
+ * PNG/GIF/WebP with a media-type mismatch 400.
9
+ */
10
+ /**
11
+ * Detect an image's MIME type from its magic bytes. Returns `image/png` for
12
+ * buffers that match no known signature (the safest neutral default for the
13
+ * Vertex image path).
14
+ */
15
+ export function detectImageMimeType(buffer) {
16
+ // PNG: 89 50 4E 47
17
+ if (buffer.length >= 8 &&
18
+ buffer[0] === 0x89 &&
19
+ buffer[1] === 0x50 &&
20
+ buffer[2] === 0x4e &&
21
+ buffer[3] === 0x47) {
22
+ return "image/png";
23
+ }
24
+ // JPEG: FF D8 FF
25
+ if (buffer.length >= 3 &&
26
+ buffer[0] === 0xff &&
27
+ buffer[1] === 0xd8 &&
28
+ buffer[2] === 0xff) {
29
+ return "image/jpeg";
30
+ }
31
+ // WebP: "RIFF"...."WEBP"
32
+ if (buffer.length >= 12 &&
33
+ buffer[0] === 0x52 &&
34
+ buffer[1] === 0x49 &&
35
+ buffer[2] === 0x46 &&
36
+ buffer[3] === 0x46 &&
37
+ buffer[8] === 0x57 &&
38
+ buffer[9] === 0x45 &&
39
+ buffer[10] === 0x42 &&
40
+ buffer[11] === 0x50) {
41
+ return "image/webp";
42
+ }
43
+ // GIF: "GIF"
44
+ if (buffer.length >= 6 &&
45
+ buffer[0] === 0x47 &&
46
+ buffer[1] === 0x49 &&
47
+ buffer[2] === 0x46) {
48
+ return "image/gif";
49
+ }
50
+ // Unknown — neutral default.
51
+ return "image/png";
52
+ }
53
+ //# sourceMappingURL=imageDetection.js.map
@@ -93,8 +93,32 @@ export function coerceJsonToSchema(text, schema) {
93
93
  if (firstOpen >= 0) {
94
94
  candidates.push({ text: text.slice(firstOpen), truncated: true });
95
95
  }
96
+ // JSON-string-literal wrapper: some providers double-encode and return the
97
+ // object as a JSON *string* (e.g. `"{\"k\":1}"`). Unwrap one layer and add
98
+ // the inner text's balanced spans as candidates so the object is recovered.
99
+ const literal = text.trim();
100
+ if (literal.length > 1 && literal.startsWith('"') && literal.endsWith('"')) {
101
+ try {
102
+ const inner = JSON.parse(literal);
103
+ if (typeof inner === "string") {
104
+ let innerFrom = 0;
105
+ for (;;) {
106
+ const innerSpan = nextBalancedJsonSpan(inner, innerFrom);
107
+ if (!innerSpan) {
108
+ break;
109
+ }
110
+ candidates.push({ text: innerSpan.span, truncated: false });
111
+ innerFrom = innerSpan.end;
112
+ }
113
+ }
114
+ }
115
+ catch {
116
+ // not a string literal — ignore
117
+ }
118
+ }
96
119
  let firstValid;
97
- let schemaMatch;
120
+ const schemaValid = [];
121
+ const hasSchema = !!(schema && hasSafeParse(schema));
98
122
  const seen = new Set();
99
123
  for (const candidate of candidates) {
100
124
  if (seen.has(candidate.text)) {
@@ -115,18 +139,25 @@ export function coerceJsonToSchema(text, schema) {
115
139
  if (firstValid === undefined) {
116
140
  firstValid = record;
117
141
  }
118
- if (schema && hasSafeParse(schema)) {
119
- const safeParseable = schema;
120
- if (safeParseable.safeParse(outcome.value).success) {
121
- schemaMatch = record;
122
- break;
123
- }
124
- }
125
- else {
142
+ if (!hasSchema) {
126
143
  // No Zod schema to discriminate — first parseable object wins.
127
144
  break;
128
145
  }
146
+ const safeParseable = schema;
147
+ if (safeParseable.safeParse(outcome.value).success) {
148
+ schemaValid.push(record);
149
+ }
129
150
  }
151
+ // Among schema-valid candidates prefer the MOST COMPLETE one. With nullable
152
+ // fields a lean object (e.g. `{summary, attachment: null}`) validates
153
+ // alongside the full object, so breaking on the first match would drop the
154
+ // richer payload (the classic preamble-then-real-answer case). Pick the
155
+ // candidate whose serialized form carries the most content.
156
+ const schemaMatch = schemaValid.length > 0
157
+ ? schemaValid.reduce((best, cur) => JSON.stringify(cur.value).length > JSON.stringify(best.value).length
158
+ ? cur
159
+ : best)
160
+ : undefined;
130
161
  const chosen = schemaMatch ?? firstValid;
131
162
  if (chosen === undefined) {
132
163
  return null;
@@ -14,6 +14,7 @@ import { FileDetector } from "../utils/fileDetector.js";
14
14
  import { processUnifiedFilesArray } from "../utils/messageBuilder.js";
15
15
  import { logger } from "../utils/logger.js";
16
16
  import { hasRestrictedOutputLimit, RESTRICTED_OUTPUT_TOKEN_LIMIT, toVertexAnthropicModelId, } from "../utils/modelDetection.js";
17
+ import { detectImageMimeType } from "../utils/imageDetection.js";
17
18
  import { resolveClaudeMaxTokens } from "../utils/tokenLimits.js";
18
19
  import { validateApiKey, createVertexProjectConfig, createGoogleAuthConfig, } from "../utils/providerConfig.js";
19
20
  import { convertZodToJsonSchema, inlineJsonSchema, ensureNestedSchemaTypes, } from "../utils/schemaConversion.js";
@@ -948,10 +949,17 @@ export class GoogleVertexProvider extends BaseProvider {
948
949
  else {
949
950
  // Assume base64 string
950
951
  imageBuffer = Buffer.from(image, "base64");
952
+ // Sniff the real format from magic bytes — bare base64 carries no
953
+ // mime hint, and leaving the image/jpeg default makes Anthropic
954
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
955
+ mimeType = this.detectImageType(imageBuffer);
951
956
  }
952
957
  }
953
958
  else {
954
959
  imageBuffer = image;
960
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
961
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
962
+ mimeType = this.detectImageType(imageBuffer);
955
963
  }
956
964
  const base64Data = imageBuffer.toString("base64");
957
965
  userParts.push({
@@ -1567,10 +1575,17 @@ export class GoogleVertexProvider extends BaseProvider {
1567
1575
  else {
1568
1576
  // Assume base64 string
1569
1577
  imageBuffer = Buffer.from(image, "base64");
1578
+ // Sniff the real format from magic bytes — bare base64 carries no
1579
+ // mime hint, and leaving the image/jpeg default makes Anthropic
1580
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
1581
+ mimeType = this.detectImageType(imageBuffer);
1570
1582
  }
1571
1583
  }
1572
1584
  else {
1573
1585
  imageBuffer = image;
1586
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
1587
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
1588
+ mimeType = this.detectImageType(imageBuffer);
1574
1589
  }
1575
1590
  const base64Data = imageBuffer.toString("base64");
1576
1591
  userParts.push({
@@ -2184,10 +2199,17 @@ export class GoogleVertexProvider extends BaseProvider {
2184
2199
  else {
2185
2200
  // Assume base64 string
2186
2201
  imageBuffer = Buffer.from(image, "base64");
2202
+ // Sniff the real format from magic bytes — bare base64 carries no
2203
+ // mime hint, and leaving the image/jpeg default makes Anthropic
2204
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
2205
+ mimeType = this.detectImageType(imageBuffer);
2187
2206
  }
2188
2207
  }
2189
2208
  else {
2190
2209
  imageBuffer = image;
2210
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
2211
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
2212
+ mimeType = this.detectImageType(imageBuffer);
2191
2213
  }
2192
2214
  const base64Data = imageBuffer.toString("base64");
2193
2215
  userContentParts.push({
@@ -2713,10 +2735,17 @@ export class GoogleVertexProvider extends BaseProvider {
2713
2735
  else {
2714
2736
  // Assume base64 string
2715
2737
  imageBuffer = Buffer.from(image, "base64");
2738
+ // Sniff the real format from magic bytes — bare base64 carries no
2739
+ // mime hint, and leaving the image/jpeg default makes Anthropic
2740
+ // reject PNG/GIF/WebP with a media-type mismatch 400.
2741
+ mimeType = this.detectImageType(imageBuffer);
2716
2742
  }
2717
2743
  }
2718
2744
  else {
2719
2745
  imageBuffer = image;
2746
+ // Buffer input (e.g. Slack/REST uploads) carries no mime hint; sniff
2747
+ // it instead of defaulting to image/jpeg (mislabels PNG -> 400).
2748
+ mimeType = this.detectImageType(imageBuffer);
2720
2749
  }
2721
2750
  const base64Data = imageBuffer.toString("base64");
2722
2751
  userContentParts.push({
@@ -4142,42 +4171,7 @@ export class GoogleVertexProvider extends BaseProvider {
4142
4171
  * Detect image MIME type from buffer
4143
4172
  */
4144
4173
  detectImageType(buffer) {
4145
- // Check PNG signature
4146
- if (buffer.length >= 8 &&
4147
- buffer[0] === 0x89 &&
4148
- buffer[1] === 0x50 &&
4149
- buffer[2] === 0x4e &&
4150
- buffer[3] === 0x47) {
4151
- return "image/png";
4152
- }
4153
- // Check JPEG signature
4154
- if (buffer.length >= 3 &&
4155
- buffer[0] === 0xff &&
4156
- buffer[1] === 0xd8 &&
4157
- buffer[2] === 0xff) {
4158
- return "image/jpeg";
4159
- }
4160
- // Check WebP signature
4161
- if (buffer.length >= 12 &&
4162
- buffer[0] === 0x52 &&
4163
- buffer[1] === 0x49 &&
4164
- buffer[2] === 0x46 &&
4165
- buffer[3] === 0x46 &&
4166
- buffer[8] === 0x57 &&
4167
- buffer[9] === 0x45 &&
4168
- buffer[10] === 0x42 &&
4169
- buffer[11] === 0x50) {
4170
- return "image/webp";
4171
- }
4172
- // Check GIF signature
4173
- if (buffer.length >= 6 &&
4174
- buffer[0] === 0x47 &&
4175
- buffer[1] === 0x49 &&
4176
- buffer[2] === 0x46) {
4177
- return "image/gif";
4178
- }
4179
- // Default to PNG if unknown
4180
- return "image/png";
4174
+ return detectImageMimeType(buffer);
4181
4175
  }
4182
4176
  /**
4183
4177
  * Estimate token count from text (simple character-based estimation)
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Image format detection from magic bytes.
3
+ *
4
+ * The native Vertex+Anthropic image block needs the correct `mimeType` for
5
+ * each inline image. Buffer and bare-base64 inputs (e.g. Slack / REST uploads)
6
+ * carry no mime hint, so the format must be sniffed from the leading bytes —
7
+ * otherwise a wrong default (historically `image/jpeg`) makes Anthropic reject
8
+ * PNG/GIF/WebP with a media-type mismatch 400.
9
+ */
10
+ /**
11
+ * Detect an image's MIME type from its magic bytes. Returns `image/png` for
12
+ * buffers that match no known signature (the safest neutral default for the
13
+ * Vertex image path).
14
+ */
15
+ export declare function detectImageMimeType(buffer: Buffer): string;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Image format detection from magic bytes.
3
+ *
4
+ * The native Vertex+Anthropic image block needs the correct `mimeType` for
5
+ * each inline image. Buffer and bare-base64 inputs (e.g. Slack / REST uploads)
6
+ * carry no mime hint, so the format must be sniffed from the leading bytes —
7
+ * otherwise a wrong default (historically `image/jpeg`) makes Anthropic reject
8
+ * PNG/GIF/WebP with a media-type mismatch 400.
9
+ */
10
+ /**
11
+ * Detect an image's MIME type from its magic bytes. Returns `image/png` for
12
+ * buffers that match no known signature (the safest neutral default for the
13
+ * Vertex image path).
14
+ */
15
+ export function detectImageMimeType(buffer) {
16
+ // PNG: 89 50 4E 47
17
+ if (buffer.length >= 8 &&
18
+ buffer[0] === 0x89 &&
19
+ buffer[1] === 0x50 &&
20
+ buffer[2] === 0x4e &&
21
+ buffer[3] === 0x47) {
22
+ return "image/png";
23
+ }
24
+ // JPEG: FF D8 FF
25
+ if (buffer.length >= 3 &&
26
+ buffer[0] === 0xff &&
27
+ buffer[1] === 0xd8 &&
28
+ buffer[2] === 0xff) {
29
+ return "image/jpeg";
30
+ }
31
+ // WebP: "RIFF"...."WEBP"
32
+ if (buffer.length >= 12 &&
33
+ buffer[0] === 0x52 &&
34
+ buffer[1] === 0x49 &&
35
+ buffer[2] === 0x46 &&
36
+ buffer[3] === 0x46 &&
37
+ buffer[8] === 0x57 &&
38
+ buffer[9] === 0x45 &&
39
+ buffer[10] === 0x42 &&
40
+ buffer[11] === 0x50) {
41
+ return "image/webp";
42
+ }
43
+ // GIF: "GIF"
44
+ if (buffer.length >= 6 &&
45
+ buffer[0] === 0x47 &&
46
+ buffer[1] === 0x49 &&
47
+ buffer[2] === 0x46) {
48
+ return "image/gif";
49
+ }
50
+ // Unknown — neutral default.
51
+ return "image/png";
52
+ }
@@ -93,8 +93,32 @@ export function coerceJsonToSchema(text, schema) {
93
93
  if (firstOpen >= 0) {
94
94
  candidates.push({ text: text.slice(firstOpen), truncated: true });
95
95
  }
96
+ // JSON-string-literal wrapper: some providers double-encode and return the
97
+ // object as a JSON *string* (e.g. `"{\"k\":1}"`). Unwrap one layer and add
98
+ // the inner text's balanced spans as candidates so the object is recovered.
99
+ const literal = text.trim();
100
+ if (literal.length > 1 && literal.startsWith('"') && literal.endsWith('"')) {
101
+ try {
102
+ const inner = JSON.parse(literal);
103
+ if (typeof inner === "string") {
104
+ let innerFrom = 0;
105
+ for (;;) {
106
+ const innerSpan = nextBalancedJsonSpan(inner, innerFrom);
107
+ if (!innerSpan) {
108
+ break;
109
+ }
110
+ candidates.push({ text: innerSpan.span, truncated: false });
111
+ innerFrom = innerSpan.end;
112
+ }
113
+ }
114
+ }
115
+ catch {
116
+ // not a string literal — ignore
117
+ }
118
+ }
96
119
  let firstValid;
97
- let schemaMatch;
120
+ const schemaValid = [];
121
+ const hasSchema = !!(schema && hasSafeParse(schema));
98
122
  const seen = new Set();
99
123
  for (const candidate of candidates) {
100
124
  if (seen.has(candidate.text)) {
@@ -115,18 +139,25 @@ export function coerceJsonToSchema(text, schema) {
115
139
  if (firstValid === undefined) {
116
140
  firstValid = record;
117
141
  }
118
- if (schema && hasSafeParse(schema)) {
119
- const safeParseable = schema;
120
- if (safeParseable.safeParse(outcome.value).success) {
121
- schemaMatch = record;
122
- break;
123
- }
124
- }
125
- else {
142
+ if (!hasSchema) {
126
143
  // No Zod schema to discriminate — first parseable object wins.
127
144
  break;
128
145
  }
146
+ const safeParseable = schema;
147
+ if (safeParseable.safeParse(outcome.value).success) {
148
+ schemaValid.push(record);
149
+ }
129
150
  }
151
+ // Among schema-valid candidates prefer the MOST COMPLETE one. With nullable
152
+ // fields a lean object (e.g. `{summary, attachment: null}`) validates
153
+ // alongside the full object, so breaking on the first match would drop the
154
+ // richer payload (the classic preamble-then-real-answer case). Pick the
155
+ // candidate whose serialized form carries the most content.
156
+ const schemaMatch = schemaValid.length > 0
157
+ ? schemaValid.reduce((best, cur) => JSON.stringify(cur.value).length > JSON.stringify(best.value).length
158
+ ? cur
159
+ : best)
160
+ : undefined;
130
161
  const chosen = schemaMatch ?? firstValid;
131
162
  if (chosen === undefined) {
132
163
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "9.70.2",
3
+ "version": "9.70.4",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applications with 21+ providers: OpenAI, Anthropic, Google AI Studio, Google Vertex, AWS Bedrock, Azure OpenAI, Mistral, LiteLLM, SageMaker, Hugging Face, Ollama, OpenAI-compatible, OpenRouter, DeepSeek, NVIDIA NIM, LM Studio, llama.cpp, plus voice (OpenAI TTS, ElevenLabs, Deepgram, Azure Speech).",
6
6
  "author": {
@@ -453,7 +453,7 @@
453
453
  "@vitest/coverage-v8": "^4.1.0",
454
454
  "concurrently": "^9.2.1",
455
455
  "conventional-changelog-conventionalcommits": "^9.1.0",
456
- "esbuild": "^0.27.4",
456
+ "esbuild": "^0.28.1",
457
457
  "eslint": "^10.0.2",
458
458
  "husky": "^9.1.7",
459
459
  "js-yaml": "^4.1.1",
@@ -465,7 +465,7 @@
465
465
  "react": "^19.2.4",
466
466
  "react-dom": "^19.2.4",
467
467
  "semantic-release": "^25.0.3",
468
- "shell-quote": "^1.8.3",
468
+ "shell-quote": "^1.8.4",
469
469
  "svelte": "^5.55.7",
470
470
  "svelte-check": "^4.4.4",
471
471
  "ts-morph": "^24.0.0",