@juspay/neurolink 9.70.3 → 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.
@@ -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;
@@ -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.3",
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": {