From ed661f21269ec1f5142a580beeef7caa3eab729d Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Wed, 5 Aug 2026 13:53:40 -0300 Subject: [PATCH] fix(tests): align deepseek-web-tools-execute with #9343 tool envelope contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/unit/deepseek-web-tools-execute-2820.test.ts (executor level) was a test-sibling forgotten when #9343 (commit d969555417) hardened tool-call parsing: bare JSON with no explicit / envelope is never promoted to tool_calls anymore (previously it was, whenever a tools[] set was requested — a security gap allowing prose/code-fenced JSON echoed back by the model, or a copy-attack, to trigger real tool execution). Three siblings were updated in the same commit: web-tools-translation.test.ts and web-tools-translation-2820.test.ts (parseToolCallsFromText, the shared translator), and deepseek-web-tools-variants.test.ts (parseDeepSeekToolCalls, deepseek-specific parser) — all inverted their bare-JSON assertions to `toolCalls === null` + `content === text` (preserved verbatim, not stripped). This file calls the executor's execute() (full HTTP round trip through buildToolAwareResult), so it was not touched by that diff and kept asserting the old contract (finish_reason: "tool_calls", content: null). Verified against source (open-sse/executors/deepseek-web.ts buildToolAwareResult): when parseDeepSeekToolCalls returns toolCalls=null, hasCalls is false, so finish_reason is "stop", message.tool_calls is never set, and message.content is the parser's returned content — which for text with no / tag at all is the original string, unchanged (parseToolCallsFromText's early-return branch). The test now asserts exactly that shape, at the same executor level as the rest of the file's tool_calls that make sense at that level as the rest of the file's tool_calls Refs #9343 --- .../deepseek-web-tools-execute-2820.test.ts | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/unit/deepseek-web-tools-execute-2820.test.ts b/tests/unit/deepseek-web-tools-execute-2820.test.ts index 49c01497d1..77854cebd6 100644 --- a/tests/unit/deepseek-web-tools-execute-2820.test.ts +++ b/tests/unit/deepseek-web-tools-execute-2820.test.ts @@ -132,7 +132,9 @@ test("execute (non-stream) parses reply into OpenAI tool_calls", async () assert.equal(choice.finish_reason, "tool_calls"); assert.equal(choice.message.tool_calls.length, 1); assert.equal(choice.message.tool_calls[0].function.name, "get_weather"); - assert.deepEqual(JSON.parse(choice.message.tool_calls[0].function.arguments), { city: "Paris" }); + assert.deepEqual(JSON.parse(choice.message.tool_calls[0].function.arguments), { + city: "Paris", + }); assert.ok( !String(choice.message.content || "").includes(""), "raw tool block stripped from content" @@ -142,8 +144,9 @@ test("execute (non-stream) parses reply into OpenAI tool_calls", async () } }); -test("execute (non-stream) parses bare JSON reply into OpenAI tool_calls", async () => { - const mock = installMock('{"name":"getWeather","arguments":{"city":"Paris"}}'); +test("execute (non-stream) does NOT promote bare JSON reply to tool_calls (#9343)", async () => { + const bareJson = '{"name":"getWeather","arguments":{"city":"Paris"}}'; + const mock = installMock(bareJson); try { const executor = new DeepSeekWebExecutor(); const result = await executor.execute({ @@ -156,11 +159,17 @@ test("execute (non-stream) parses bare JSON reply into OpenAI tool_calls", async assert.ok(result.response.ok); const json = JSON.parse(await result.response.text()); const choice = json.choices[0]; - assert.equal(choice.finish_reason, "tool_calls"); - assert.equal(choice.message.tool_calls.length, 1); - assert.equal(choice.message.tool_calls[0].function.name, "get_weather"); - assert.deepEqual(JSON.parse(choice.message.tool_calls[0].function.arguments), { city: "Paris" }); - assert.equal(choice.message.content, null, "bare JSON tool call is stripped from content"); + assert.equal( + choice.finish_reason, + "stop", + "bare JSON with no envelope must not be promoted to a tool call" + ); + assert.ok(!choice.message.tool_calls, "no tool_calls on a bare JSON reply (#9343)"); + assert.equal( + choice.message.content, + bareJson, + "bare JSON must be preserved verbatim as content, not stripped or promoted" + ); } finally { mock.restore(); }