From 85b4f45d4a480bfd5b3d24dfa92cfa0d02b6a25f Mon Sep 17 00:00:00 2001 From: Huarch Date: Thu, 30 Apr 2026 13:38:53 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=B7=A5=E5=85=B7=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=8F=82=E6=95=B0=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/chatStream.test.ts | 29 +++++++++++++++++++++++++++++ src/lib/chatStream.ts | 30 ++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/lib/chatStream.test.ts b/src/lib/chatStream.test.ts index a2e5103..6cf3f16 100644 --- a/src/lib/chatStream.test.ts +++ b/src/lib/chatStream.test.ts @@ -97,6 +97,35 @@ describe("streamAgentChat", () => { }); }); + it("parses legacy tool_call arguments when params is empty", async () => { + apiFetch.mockResolvedValue({ + ok: true, + body: makeStream([ + 'event: tool_call\ndata: {"conversationId":"agent-1e75dd01-29e","tool":"locate_features","params":{},"arguments":"{\\"ids\\":[\\"142902\\"],\\"feature_type\\":\\"junction\\"}"}\n\n', + 'event: done\ndata: {"session_id":"agent-1e75dd01-29e"}\n\n', + ]), + }); + + const events: Array<{ + type: string; + sessionId?: string; + tool?: string; + params?: Record; + }> = []; + + await streamAgentChat({ + message: "hi", + onEvent: (event) => events.push(event), + }); + + expect(events[0]).toEqual({ + type: "tool_call", + sessionId: "agent-1e75dd01-29e", + tool: "locate_features", + params: { ids: ["142902"], feature_type: "junction" }, + }); + }); + it("emits error when response is not ok", async () => { apiFetch.mockResolvedValue({ ok: false, diff --git a/src/lib/chatStream.ts b/src/lib/chatStream.ts index 4d2746a..187cd59 100644 --- a/src/lib/chatStream.ts +++ b/src/lib/chatStream.ts @@ -52,6 +52,30 @@ const parseEventBlock = (block: string): { event?: string; data?: string } => { }; }; +const isObjectRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value); + +const resolveToolParams = ( + params: unknown, + argumentsPayload: unknown, +): Record => { + if (isObjectRecord(params) && Object.keys(params).length > 0) { + return params; + } + if (isObjectRecord(argumentsPayload)) { + return argumentsPayload; + } + if (typeof argumentsPayload === "string") { + try { + const parsed = JSON.parse(argumentsPayload) as unknown; + return isObjectRecord(parsed) ? parsed : {}; + } catch { + return {}; + } + } + return isObjectRecord(params) ? params : {}; +}; + export const streamAgentChat = async ({ message, sessionId, @@ -125,11 +149,13 @@ export const streamAgentChat = async ({ try { const parsed = JSON.parse(data) as { session_id?: string; + conversationId?: string; content?: string; message?: string; detail?: string; tool?: string; params?: Record; + arguments?: unknown; id?: string; phase?: string; status?: "running" | "completed" | "error"; @@ -166,9 +192,9 @@ export const streamAgentChat = async ({ } else if (event === "tool_call") { onEvent({ type: "tool_call", - sessionId: parsed.session_id ?? "", + sessionId: parsed.session_id ?? parsed.conversationId ?? "", tool: parsed.tool ?? "", - params: parsed.params ?? {}, + params: resolveToolParams(parsed.params, parsed.arguments), }); } } catch {