Skip to content

Commit dee11c7

Browse files
committed
feat: enhance DeepSeek response handling for WebSearch tool
1 parent f3dbe02 commit dee11c7

2 files changed

Lines changed: 51 additions & 40 deletions

File tree

packages/core/src/tests/web-search-handler.test.ts

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ test("WebSearch matches rate limit errors case-sensitively", async () => {
217217
assert.deepEqual(rateLimitedTools, []);
218218
});
219219

220-
test("WebSearch uses DeepSeek Responses API with the required model", async () => {
220+
test("WebSearch accepts a completed DeepSeek response with partial web search failures", async () => {
221221
const workspace = createTempWorkspace();
222222
const starts: Array<{ id: string | number; command: string }> = [];
223223
const exits: Array<string | number> = [];
@@ -252,7 +252,10 @@ test("WebSearch uses DeepSeek Responses API with the required model", async () =
252252
responseRequests.push(request);
253253
return {
254254
status: "completed",
255-
output: [{ type: "web_search_call", status: "completed" }],
255+
output: [
256+
{ type: "web_search_call", status: "completed" },
257+
{ type: "web_search_call", status: "failed" },
258+
],
256259
output_text: "Node.js 24 is the latest release.",
257260
};
258261
},
@@ -288,13 +291,55 @@ test("WebSearch uses DeepSeek Responses API with the required model", async () =
288291
assert.deepEqual(exits, [starts[0].id]);
289292
});
290293

291-
test("WebSearch rejects invalid DeepSeek web search responses", async () => {
294+
test("WebSearch treats an incomplete empty DeepSeek response as a successful empty result", async () => {
295+
const workspace = createTempWorkspace();
296+
const fakeClient = {
297+
chat: {
298+
completions: {
299+
create: async () => ({
300+
choices: [
301+
{
302+
message: {
303+
content: '{"dominant_language":"en","reason":"English sources are more useful."}',
304+
},
305+
},
306+
],
307+
}),
308+
},
309+
},
310+
responses: {
311+
create: async () => ({
312+
status: "incomplete",
313+
output: [],
314+
output_text: " ",
315+
}),
316+
},
317+
} as unknown as OpenAI;
318+
319+
const result = await handleWebSearchTool(
320+
{ query: "latest node release" },
321+
createContext(workspace, {
322+
client: fakeClient,
323+
baseURL: "https://api.deepseek.com",
324+
})
325+
);
326+
327+
assert.equal(result.ok, true);
328+
assert.equal(result.output, "No web search results were returned.");
329+
});
330+
331+
test("WebSearch rejects DeepSeek request and provider failures", async () => {
292332
const responseCases = [
293333
{
294334
response: null,
295335
requestError: new Error("network unavailable"),
296336
error: "WebSearch default mode failed: network unavailable",
297337
},
338+
{
339+
response: null,
340+
requestError: new Error("429 rate limit exceeded"),
341+
error: "WebSearch default mode failed: 429 rate limit exceeded",
342+
},
298343
{
299344
response: {
300345
status: "failed",
@@ -303,30 +348,6 @@ test("WebSearch rejects invalid DeepSeek web search responses", async () => {
303348
},
304349
error: "WebSearch default mode failed: DeepSeek Responses API returned status failed.",
305350
},
306-
{
307-
response: {
308-
status: "completed",
309-
output: [],
310-
output_text: "An answer without a search call.",
311-
},
312-
error: "WebSearch default mode failed: DeepSeek Responses API did not perform a web search.",
313-
},
314-
{
315-
response: {
316-
status: "completed",
317-
output: [{ type: "web_search_call", status: "failed" }],
318-
output_text: "An answer from an incomplete search.",
319-
},
320-
error: "WebSearch default mode failed: DeepSeek Responses API returned an incomplete web search call.",
321-
},
322-
{
323-
response: {
324-
status: "completed",
325-
output: [{ type: "web_search_call", status: "completed" }],
326-
output_text: " ",
327-
},
328-
error: "WebSearch default mode failed: The DeepSeek web search response was empty.",
329-
},
330351
];
331352

332353
for (const responseCase of responseCases) {

packages/core/src/tools/web-search-handler.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const WEB_SEARCH_TOOL_ACTIVITY_PREFIX = "WebSearch:";
99
const DEFAULT_WEB_SEARCH_API_URL = "https://deepcode.vegamo.cn/api/plugin/web-search";
1010
const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
1111
const DEEPSEEK_WEB_SEARCH_MODEL = "deepseek-v4-flash";
12+
const EMPTY_DEEPSEEK_WEB_SEARCH_OUTPUT = "No web search results were returned.";
1213

1314
type SearchLanguage = "en" | "zh";
1415

@@ -399,23 +400,12 @@ async function runDeepSeekWebSearchRequest(
399400
tool_choice: "required",
400401
});
401402

402-
if (response.status !== "completed") {
403+
if (response.status === "failed") {
403404
throw new Error(`DeepSeek Responses API returned status ${response.status}.`);
404405
}
405406

406-
const searchCalls = response.output.filter((item) => item.type === "web_search_call");
407-
if (searchCalls.length === 0) {
408-
throw new Error("DeepSeek Responses API did not perform a web search.");
409-
}
410-
if (searchCalls.some((call) => call.status !== "completed")) {
411-
throw new Error("DeepSeek Responses API returned an incomplete web search call.");
412-
}
413-
414407
const output = response.output_text.trim();
415-
if (!output) {
416-
throw new Error("The DeepSeek web search response was empty.");
417-
}
418-
return output;
408+
return output || EMPTY_DEEPSEEK_WEB_SEARCH_OUTPUT;
419409
} finally {
420410
context.onProcessExit?.(activityId);
421411
}

0 commit comments

Comments
 (0)