From 6acf337a47a8cb20166e8317340cbb364682420b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=B5=B7?= <7836246@qq.com> Date: Thu, 5 Mar 2026 17:51:30 +0800 Subject: [PATCH] fix: add tolerant json parsing to support unescaped newlines in tools --- src/converter.ts | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/converter.ts b/src/converter.ts index a28c85b..49f22d2 100644 --- a/src/converter.ts +++ b/src/converter.ts @@ -291,6 +291,41 @@ function extractToolResultText(block: AnthropicContentBlock): string { // ==================== 响应解析 ==================== +function tolerantParse(jsonStr: string): any { + try { + return JSON.parse(jsonStr); + } catch (e) { + let inString = false; + let escaped = false; + let fixed = ''; + for (let i = 0; i < jsonStr.length; i++) { + const char = jsonStr[i]; + if (char === '\\' && !escaped) { + escaped = true; + fixed += char; + } else if (char === '"' && !escaped) { + inString = !inString; + fixed += char; + escaped = false; + } else { + if (inString && (char === '\n' || char === '\r')) { + fixed += char === '\n' ? '\\n' : '\\r'; + } else if (inString && char === '\t') { + fixed += '\\t'; + } else { + fixed += char; + } + escaped = false; + } + } + + // Remove trailing commas + fixed = fixed.replace(/,\s*([}\]])/g, '$1'); + + return JSON.parse(fixed); + } +} + export function parseToolCalls(responseText: string): { toolCalls: ParsedToolCall[]; cleanText: string; @@ -304,7 +339,7 @@ export function parseToolCalls(responseText: string): { while ((match = fullBlockRegex.exec(responseText)) !== null) { let isToolCall = false; try { - const parsed = JSON.parse(match[1]); + const parsed = tolerantParse(match[1]); // check for tool or name if (parsed.tool || parsed.name) { toolCalls.push({ @@ -315,6 +350,7 @@ export function parseToolCalls(responseText: string): { } } catch (e) { // Ignored, not a valid json tool call + console.error('[Converter] tolerantParse 失败:', e); } if (isToolCall) {