@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.
- package/CHANGELOG.md +6 -0
- package/dist/browser/neurolink.min.js +219 -219
- package/dist/lib/utils/json/coerce.js +40 -9
- package/dist/utils/json/coerce.js +40 -9
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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
|
+
"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": {
|