mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-10 09:14:45 +08:00
* fix(web): handle incomplete JSON in MCP tool call arguments (#528) When using stream_mode=["messages", "updates"] with MCP tools, tool call arguments arrive in chunks that may be incomplete JSON (missing closing braces). This caused JSON.parse() to throw errors in the frontend. Changes: - Add safeParseToolArgs() function using best-effort-json-parser to gracefully handle incomplete JSON from streaming - Replace direct JSON.parse() with safe parser in mergeMessage() - Add comprehensive tests for tool call argument parsing scenarios * Address the code review comments
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { parse as bestEffortParse } from "best-effort-json-parser";
|
||||
|
||||
import type {
|
||||
ChatEvent,
|
||||
InterruptEvent,
|
||||
@@ -13,6 +15,34 @@ import { deepClone } from "../utils/deep-clone";
|
||||
|
||||
import type { Message } from "./types";
|
||||
|
||||
/**
|
||||
* Safely parse JSON from streamed tool call argument chunks.
|
||||
* Uses best-effort-json-parser to handle incomplete JSON from streaming.
|
||||
* This addresses issue #528 where MCP tool call arguments may be incomplete
|
||||
* when using stream_mode="messages".
|
||||
*/
|
||||
function safeParseToolArgs(argsString: string): Record<string, unknown> {
|
||||
try {
|
||||
// First try standard JSON.parse for complete JSON
|
||||
return JSON.parse(argsString) as Record<string, unknown>;
|
||||
} catch {
|
||||
// If standard parsing fails, use best-effort parser for incomplete JSON
|
||||
try {
|
||||
const result = bestEffortParse(argsString);
|
||||
// Ensure we return an object
|
||||
if (result && typeof result === "object" && !Array.isArray(result)) {
|
||||
return result as Record<string, unknown>;
|
||||
}
|
||||
// If parsing returns something unexpected, wrap in an object
|
||||
return { _parsed: result };
|
||||
} catch {
|
||||
// If all parsing fails, return empty object
|
||||
console.warn("Failed to parse tool call arguments:", argsString);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function mergeMessage(message: Message, event: ChatEvent) {
|
||||
if (event.type === "message_chunk") {
|
||||
mergeTextMessage(message, event);
|
||||
@@ -29,7 +59,7 @@ export function mergeMessage(message: Message, event: ChatEvent) {
|
||||
if (message.toolCalls) {
|
||||
message.toolCalls.forEach((toolCall) => {
|
||||
if (toolCall.argsChunks?.length) {
|
||||
toolCall.args = JSON.parse(toolCall.argsChunks.join(""));
|
||||
toolCall.args = safeParseToolArgs(toolCall.argsChunks.join(""));
|
||||
delete toolCall.argsChunks;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user