Skip to content

Commit d44cec6

Browse files
committed
fix: improve json parsing resilience and disable gemini thinking
- add jsonrepair fallback for truncated LLM output - disable gemini built-in thinking mode (thinkingBudget: 0) - increase token limits for errorAnalyzer, queryRewriter, serpCluster - switch production default to gemini-2.5-flash-lite - fix normalizeHostName to handle wildcard patterns
1 parent 579fd95 commit d44cec6

6 files changed

Lines changed: 91 additions & 25 deletions

File tree

config.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,19 @@
3838
},
3939
"evaluator": {
4040
"temperature": 0.6,
41-
"maxTokens": 200
41+
"maxTokens": 1000
42+
},
43+
"errorAnalyzer": {
44+
"maxTokens": 4000
4245
},
43-
"errorAnalyzer": {},
4446
"queryRewriter": {
45-
"temperature": 0.1
47+
"temperature": 0.1,
48+
"maxTokens": 4000
4649
},
4750
"researchPlanner": {},
48-
"serpCluster": {},
51+
"serpCluster": {
52+
"maxTokens": 4000
53+
},
4954
"agent": {
5055
"temperature": 0.7
5156
},

jina-ai/config.json

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,35 @@
3434
"models": {
3535
"gemini": {
3636
"default": {
37-
"model": "gemini-2.5-flash",
37+
"model": "gemini-2.5-flash-lite",
3838
"temperature": 0.6,
3939
"maxTokens": 8000
4040
},
4141
"tools": {
4242
"coder": {
43-
"maxTokens": 2000,
44-
"model": "gemini-2.5-flash-lite"
43+
"maxTokens": 2000
4544
},
4645
"researchPlanner": {},
4746
"evaluator": {
4847
"maxTokens": 2000
4948
},
50-
"serpCluster": {},
49+
"serpCluster": {
50+
"maxTokens": 4000
51+
},
5152
"errorAnalyzer": {
52-
"maxTokens": 1000
53+
"maxTokens": 4000
5354
},
5455
"queryRewriter": {
55-
"maxTokens": 2000
56+
"maxTokens": 4000
57+
},
58+
"agent": {
59+
"model": "gemini-2.5-flash"
60+
},
61+
"agentBeastMode": {
62+
"model": "gemini-2.5-flash"
5663
},
57-
"agent": {},
58-
"agentBeastMode": {},
5964
"fallback": {
60-
"maxTokens": 8000,
61-
"model": "gemini-2.5-flash-lite"
65+
"maxTokens": 8000
6266
},
6367
"finalizer": {},
6468
"reducer": {

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"express-validator": "^7.2.1",
4141
"hjson": "^3.2.2",
4242
"jsdom": "^26.0.0",
43+
"jsonrepair": "^3.13.1",
4344
"node-fetch": "^3.3.2",
4445
"sharp": "^0.34.2",
4546
"undici": "^7.3.0",

src/utils/safe-generator.ts

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import {
88
} from "ai";
99
import { TokenTracker } from "./token-tracker";
1010
import { getModel, ToolName, getToolConfig } from "../config";
11-
import Hjson from 'hjson'; // Import Hjson library
11+
import Hjson from 'hjson';
1212
import { logError, logDebug, logWarning } from '../logging';
1313

14+
// Dynamic import for ESM module
15+
const getJsonRepair = async () => {
16+
const { jsonrepair } = await import('jsonrepair');
17+
return jsonrepair;
18+
};
19+
1420
interface GenerateObjectResult<T> {
1521
object: T;
1622
usage: LanguageModelUsage;
@@ -154,6 +160,13 @@ export class ObjectGeneratorSafe {
154160
messages,
155161
maxTokens: getToolConfig(model).maxTokens,
156162
temperature: getToolConfig(model).temperature,
163+
providerOptions: {
164+
google: {
165+
thinkingConfig: {
166+
thinkingBudget: 0 // Disable Gemini's built-in thinking to avoid conflict with our schema's think field
167+
}
168+
}
169+
}
157170
});
158171

159172
this.tokenTracker.trackUsage(model, result.usage);
@@ -200,6 +213,13 @@ export class ObjectGeneratorSafe {
200213
schema: distilledSchema,
201214
prompt: `Following the given JSON schema, extract the field from below: \n\n ${failedOutput}`,
202215
temperature: getToolConfig('fallback').temperature,
216+
providerOptions: {
217+
google: {
218+
thinkingConfig: {
219+
thinkingBudget: 0
220+
}
221+
}
222+
}
203223
});
204224

205225
this.tokenTracker.trackUsage('fallback', fallbackResult.usage); // Track against fallback model
@@ -224,26 +244,40 @@ export class ObjectGeneratorSafe {
224244
private async handleGenerateObjectError<T>(error: unknown): Promise<GenerateObjectResult<T>> {
225245
if (NoObjectGeneratedError.isInstance(error)) {
226246
logWarning('Object not generated according to schema, fallback to manual parsing', { error });
247+
const rawText = (error as any).text;
248+
249+
// 1. First try standard JSON parsing
227250
try {
228-
// First try standard JSON parsing
229-
const partialResponse = JSON.parse((error as any).text);
251+
const partialResponse = JSON.parse(rawText);
230252
logDebug('JSON parse success!');
231253
return {
232254
object: partialResponse as T,
233255
usage: (error as any).usage
234256
};
235-
} catch (parseError) {
236-
// Use Hjson to parse the error response for more lenient parsing
257+
} catch (jsonError) {
258+
// 2. Try jsonrepair to fix truncated/malformed JSON
237259
try {
238-
const hjsonResponse = Hjson.parse((error as any).text);
239-
logDebug('Hjson parse success!');
260+
const jsonrepair = await getJsonRepair();
261+
const repairedJson = jsonrepair(rawText);
262+
const repairedResponse = JSON.parse(repairedJson);
263+
logDebug('jsonrepair parse success!');
240264
return {
241-
object: hjsonResponse as T,
265+
object: repairedResponse as T,
242266
usage: (error as any).usage
243267
};
244-
} catch (hjsonError) {
245-
logError('Both JSON and Hjson parsing failed:', { error: hjsonError });
246-
throw error;
268+
} catch (repairError) {
269+
// 3. Try Hjson for lenient parsing (trailing commas, comments, etc.)
270+
try {
271+
const hjsonResponse = Hjson.parse(rawText);
272+
logDebug('Hjson parse success!');
273+
return {
274+
object: hjsonResponse as T,
275+
usage: (error as any).usage
276+
};
277+
} catch (hjsonError) {
278+
logError('All JSON parsing attempts failed (JSON, jsonrepair, Hjson):', { error: hjsonError });
279+
throw error;
280+
}
247281
}
248282
}
249283
}

src/utils/url-tools.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ const extractUrlParts = (urlStr: string) => {
194194
};
195195

196196
export const normalizeHostName = (hostStr: string) => {
197+
// Handle wildcard patterns like *.medium.com
198+
if (hostStr.startsWith('*.')) {
199+
hostStr = hostStr.slice(2);
200+
}
201+
202+
// If it doesn't look like a URL (no protocol), just clean up the hostname directly
203+
if (!hostStr.includes('://')) {
204+
const cleaned = hostStr.startsWith('www.') ? hostStr.slice(4) : hostStr;
205+
return cleaned.toLowerCase();
206+
}
207+
208+
// Try to parse as URL
197209
const extract = extractUrlParts(hostStr);
198210
const host = extract.hostname;
199211
if (!host) {

0 commit comments

Comments
 (0)