From 2be57c0838a379bc9c23a5c57a46a890384ee68f Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Thu, 11 Jun 2026 00:49:36 +0700 Subject: [PATCH] fix: handle surfsense stream format correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surfsense sends data: {"type":"text-delta","delta":"text"} — use raw.delta (not raw.content) and filter events by type. Skip non-text events (thinking steps, start, etc) to produce clean Anthropic SSE. Co-Authored-By: Claude Fable 5 --- src/lib/ai-proxy.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/ai-proxy.ts b/src/lib/ai-proxy.ts index 768f85d..41cc6c3 100644 --- a/src/lib/ai-proxy.ts +++ b/src/lib/ai-proxy.ts @@ -76,11 +76,13 @@ export const MODEL_ROUTES: Record = { messages: req.messages, }), adaptStreamLine: (line) => { - // surfsense returns lines like: data: {"content":"Hello","done":false} if (!line.startsWith("data: ")) return null; try { const raw = JSON.parse(line.slice(6)); - if (raw.done) return "data: [DONE]"; + if (raw.type === "finish" || raw.done) return "data: [DONE]"; + if (raw.type !== "text-delta") return null; + const text = raw.delta ?? raw.content ?? ""; + if (!text) return null; return `data: ${JSON.stringify({ id: `chatcmpl-${Date.now()}`, object: "chat.completion.chunk", @@ -89,7 +91,7 @@ export const MODEL_ROUTES: Record = { choices: [ { index: 0, - delta: { content: raw.content ?? "" }, + delta: { content: text }, finish_reason: null, }, ],