From fed05a3207e8ceac3601bd02b91113cbcfe9ca7e Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Sun, 9 Aug 2026 09:51:22 -0300 Subject: [PATCH] fix(types): normalize DuckDuckGo request messages (#9847) Co-authored-by: backryun --- open-sse/executors/duckduckgo-web.ts | 21 +++++++++++++++++---- tests/unit/duckduckgo-web-executor.test.ts | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/open-sse/executors/duckduckgo-web.ts b/open-sse/executors/duckduckgo-web.ts index 72abad4f84..6b7eba2dce 100644 --- a/open-sse/executors/duckduckgo-web.ts +++ b/open-sse/executors/duckduckgo-web.ts @@ -137,8 +137,23 @@ interface DuckDuckGoModelCapabilities { reasoningEffort: string | null; } +type DuckDuckGoRequestMessage = Record & { + role: string; + content: unknown; +}; + let durablePublicKey: JsonWebKey | null = null; +export function normalizeDuckDuckGoMessages(value: unknown): DuckDuckGoRequestMessage[] { + if (!Array.isArray(value)) return []; + return value.flatMap((message) => { + if (!message || typeof message !== "object" || Array.isArray(message)) return []; + const record = message as Record; + if (typeof record.role !== "string") return []; + return [{ ...record, role: record.role, content: record.content }]; + }); +} + function extractDuckDuckGoContent(data: unknown): string { if (!data || typeof data !== "object") return ""; const record = data as Record; @@ -440,14 +455,12 @@ export class DuckDuckGoWebExecutor extends BaseExecutor { const { model, body, stream, signal, upstreamExtraHeaders } = input; const upstreamModel = normalizeDuckDuckGoModel(model); const bodyObj = (body || {}) as Record; - const rawMessages = Array.isArray((body as { messages?: unknown[] } | null)?.messages) - ? ((body as { messages: unknown[] }).messages as Array>) - : []; + const rawMessages = normalizeDuckDuckGoMessages(bodyObj.messages); const { hasTools, requestedTools, effectiveMessages } = prepareToolMessages( bodyObj, rawMessages ); - const messages = effectiveMessages as Array>; + const messages = effectiveMessages; const isStreaming = stream !== false; const upstreamHeaders = upstreamExtraHeaders || {}; diff --git a/tests/unit/duckduckgo-web-executor.test.ts b/tests/unit/duckduckgo-web-executor.test.ts index 0566efa965..5469185cc7 100644 --- a/tests/unit/duckduckgo-web-executor.test.ts +++ b/tests/unit/duckduckgo-web-executor.test.ts @@ -4,6 +4,7 @@ import { FETCH_TIMEOUT_MS } from "../../open-sse/config/constants.ts"; import { DuckDuckGoWebExecutor, DUCKDUCKGO_BASE, + normalizeDuckDuckGoMessages, STATUS_URL, } from "../../open-sse/executors/duckduckgo-web.ts"; @@ -38,6 +39,21 @@ describe("DuckDuckGoWebExecutor", () => { }); describe("execute method validation", () => { + it("normalizes only role-bearing request messages without dropping metadata", () => { + assert.deepEqual( + normalizeDuckDuckGoMessages([ + { role: "user", content: "hello", name: "caller" }, + { role: "assistant", tool_calls: [{ id: "call-1" }] }, + { content: "missing role" }, + null, + ]), + [ + { role: "user", content: "hello", name: "caller" }, + { role: "assistant", content: undefined, tool_calls: [{ id: "call-1" }] }, + ] + ); + }); + it("should reject empty messages array", async () => { const executor = new DuckDuckGoWebExecutor();