diff --git a/backend/src/adapters/request/anthropic.ts b/backend/src/adapters/request/anthropic.ts index 10e1e99..7db6ffb 100644 --- a/backend/src/adapters/request/anthropic.ts +++ b/backend/src/adapters/request/anthropic.ts @@ -70,10 +70,12 @@ interface AnthropicRequest { } // ============================================================================= -// Known Fields (for extracting extra body) +// Mapped Fields (fields explicitly extracted by parse(), excluded from extraParams) +// All other fields (e.g. metadata) are passed through via extraParams +// to the upstream provider. // ============================================================================= -const KNOWN_FIELDS = new Set([ +const MAPPED_FIELDS = new Set([ "model", "messages", "system", @@ -85,7 +87,6 @@ const KNOWN_FIELDS = new Set([ "stop_sequences", "tools", "tool_choice", - "metadata", ]); // ============================================================================= @@ -343,7 +344,7 @@ export const anthropicRequestAdapter: RequestAdapter = { let hasExtra = false; for (const [key, value] of Object.entries(body)) { - if (!KNOWN_FIELDS.has(key)) { + if (!MAPPED_FIELDS.has(key)) { extra[key] = value; hasExtra = true; } diff --git a/backend/src/adapters/request/openai-chat.ts b/backend/src/adapters/request/openai-chat.ts index ef6839f..4a5a188 100644 --- a/backend/src/adapters/request/openai-chat.ts +++ b/backend/src/adapters/request/openai-chat.ts @@ -112,30 +112,22 @@ interface OpenAIChatRequest { } // ============================================================================= -// Known Fields (for extracting extra body) +// Mapped Fields (fields explicitly extracted by parse(), excluded from extraParams) +// All other fields (e.g. response_format, presence_penalty, seed, etc.) +// are passed through via extraParams to the upstream provider. // ============================================================================= -const KNOWN_FIELDS = new Set([ +const MAPPED_FIELDS = new Set([ "model", "messages", "max_tokens", "max_completion_tokens", "temperature", "top_p", - "n", "stream", - "stream_options", "stop", "tools", "tool_choice", - "presence_penalty", - "frequency_penalty", - "logit_bias", - "logprobs", - "top_logprobs", - "user", - "seed", - "response_format", ]); // ============================================================================= @@ -340,7 +332,7 @@ export const openaiChatRequestAdapter: RequestAdapter = { let hasExtra = false; for (const [key, value] of Object.entries(body)) { - if (!KNOWN_FIELDS.has(key)) { + if (!MAPPED_FIELDS.has(key)) { extra[key] = value; hasExtra = true; } diff --git a/backend/src/adapters/request/openai-response.ts b/backend/src/adapters/request/openai-response.ts index 296ed7e..777d83f 100644 --- a/backend/src/adapters/request/openai-response.ts +++ b/backend/src/adapters/request/openai-response.ts @@ -109,24 +109,21 @@ interface ResponseApiRequest { } // ============================================================================= -// Known Fields (for extracting extra body) +// Mapped Fields (fields explicitly extracted by parse(), excluded from extraParams) +// All other fields (e.g. modalities, parallel_tool_calls, store, metadata, etc.) +// are passed through via extraParams to the upstream provider. // ============================================================================= -const KNOWN_FIELDS = new Set([ +const MAPPED_FIELDS = new Set([ "model", "input", "instructions", - "modalities", "max_output_tokens", "temperature", "top_p", "stream", "tools", "tool_choice", - "parallel_tool_calls", - "previous_response_id", - "store", - "metadata", ]); // ============================================================================= @@ -298,7 +295,7 @@ export const openaiResponseRequestAdapter: RequestAdapter = let hasExtra = false; for (const [key, value] of Object.entries(body)) { - if (!KNOWN_FIELDS.has(key)) { + if (!MAPPED_FIELDS.has(key)) { extra[key] = value; hasExtra = true; } diff --git a/backend/src/adapters/response/openai-chat.ts b/backend/src/adapters/response/openai-chat.ts index e6a4660..2fa81ea 100644 --- a/backend/src/adapters/response/openai-chat.ts +++ b/backend/src/adapters/response/openai-chat.ts @@ -35,6 +35,7 @@ interface OpenAIChatChoice { interface OpenAIChatMessage { role: "assistant"; content: string | null; + reasoning_content?: string | null; tool_calls?: OpenAIToolCall[]; refusal?: string | null; } @@ -113,9 +114,11 @@ function convertStopReason(stopReason: StopReason): string | null { } /** - * Extract text content from internal content blocks + * Extract text and reasoning content from internal content blocks */ -function extractTextContent(content: InternalContentBlock[]): string { +function extractContent( + content: InternalContentBlock[], +): { text: string; reasoning?: string } { const textParts: string[] = []; const thinkingParts: string[] = []; @@ -127,14 +130,10 @@ function extractTextContent(content: InternalContentBlock[]): string { } } - // Prepend thinking content wrapped in tags if present - let result = ""; - if (thinkingParts.length > 0) { - result += `${thinkingParts.join("")}\n`; - } - result += textParts.join(""); - - return result; + return { + text: textParts.join(""), + reasoning: thinkingParts.length > 0 ? thinkingParts.join("") : undefined, + }; } /** @@ -168,7 +167,8 @@ export const openaiChatResponseAdapter: ResponseAdapter = format: "openai-chat", serialize(response: InternalResponse): OpenAIChatCompletion { - const content = extractTextContent(response.content); + const { text: content, reasoning: reasoningContent } = + extractContent(response.content); const toolCalls = convertToolCalls(response.content); return { @@ -182,6 +182,7 @@ export const openaiChatResponseAdapter: ResponseAdapter = message: { role: "assistant", content: content || null, + ...(reasoningContent !== undefined && { reasoning_content: reasoningContent }), tool_calls: toolCalls, }, finish_reason: convertStopReason(response.stopReason),