diff --git a/src/lib/anthropic-proxy.ts b/src/lib/anthropic-proxy.ts
index 722364b..f22a1ec 100644
--- a/src/lib/anthropic-proxy.ts
+++ b/src/lib/anthropic-proxy.ts
@@ -280,6 +280,14 @@ function accumulateSSEText(sseBody: string): string {
const parsed = JSON.parse(raw);
if (parsed.type === "text-delta" && parsed.delta) {
accumulated += parsed.delta;
+ continue;
+ }
+ // Handle OpenAI-format SSE with reasoning_content
+ const delta = parsed.choices?.[0]?.delta;
+ if (delta?.reasoning_content) {
+ accumulated += `${delta.reasoning_content}`;
+ } else if (delta?.content) {
+ accumulated += delta.content;
}
} catch {
// skip unparseable lines
@@ -295,6 +303,9 @@ function accumulateSSEText(sseBody: string): string {
* - Claude Code format: { "type": "text-delta", "delta": "..." }
* - OpenAI format: { "choices": [{ "delta": { "content": "..." } }] }
* - Generic JSON: { "content": "..." } or { "text": "..." }
+ *
+ * Also handles reasoning_content (e.g., DeepSeek model output) by wrapping
+ * it in tags so it is preserved in the Anthropic stream output.
*/
function extractTextFromSSE(parsed: any): string | null {
if (parsed == null) return null;
@@ -308,9 +319,21 @@ function extractTextFromSSE(parsed: any): string | null {
}
}
- const openai = parsed.choices?.[0]?.delta?.content ??
- parsed.choices?.[0]?.text;
- if (openai) return openai;
+ const delta = parsed.choices?.[0]?.delta;
+ const reasoningDelta = delta?.reasoning_content;
+ const contentDelta = delta?.content;
+ const textFallback = parsed.choices?.[0]?.text;
+
+ // When the delta has reasoning_content but no content, wrap in tags
+ if (reasoningDelta && !contentDelta) {
+ return `${reasoningDelta}`;
+ }
+ // When both exist, prepend thinking and follow with text content
+ if (reasoningDelta && contentDelta) {
+ return `${reasoningDelta}${contentDelta}`;
+ }
+ if (contentDelta) return contentDelta;
+ if (textFallback) return textFallback;
if (typeof parsed.content === "string") return parsed.content;
if (typeof parsed.text === "string") return parsed.text;
@@ -909,6 +932,13 @@ export async function handleAnthropicMessages(
parsed = { content: text };
}
+ // Apply backend adaptResponse if available (handles double-nested responses
+ // from providers like opencode.ai that wrap the real response as a JSON
+ // string inside choices[0].message.content).
+ if (config.adaptResponse && typeof parsed === "object" && parsed !== null) {
+ parsed = config.adaptResponse(parsed, req as any) ?? parsed;
+ }
+
const adapted = backendToAnthropicResponse(parsed, req.model);
return new Response(JSON.stringify(adapted), {
status: 200,