// Pure JSONL stream translation (HuggingChat NDJSON -> OpenAI SSE). Verbatim from huggingchat.ts. export function sseChunk(data: unknown): string { return `data: ${JSON.stringify(data)}\n\n`; } export function parseJsonlLine(line: string): { token?: string; done?: boolean; error?: string; text?: string; } { try { const event = JSON.parse(line); if (event.type === "stream" && typeof event.token === "string") { const token = event.token.replace(/\0/g, ""); if (token) return { token }; } if (event.type === "finalAnswer" && typeof event.text === "string") { return { text: event.text, done: true }; } if (event.type === "status") { if (event.status === "error") { return { error: event.message || "HuggingChat generation error" }; } if (event.status === "finished") { return { done: true }; } } } catch { // Skip non-JSON lines } return {}; } export async function* streamJsonlToOpenAi( body: ReadableStream, model: string, id: string, created: number, signal?: AbortSignal | null ): AsyncGenerator { const reader = body.getReader(); const decoder = new TextDecoder(); let buffer = ""; let emittedRole = false; let fullText = ""; let finished = false; try { while (true) { if (signal?.aborted) break; const { value, done } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; const parsed = parseJsonlLine(trimmed); if (parsed.error) { yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: {}, finish_reason: "stop" }], }); yield "data: [DONE]\n\n"; finished = true; return; } if (parsed.token) { if (!emittedRole) { emittedRole = true; yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: { role: "assistant" }, finish_reason: null }], }); } fullText += parsed.token; yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: { content: parsed.token }, finish_reason: null }], }); } if (parsed.text) { const remaining = parsed.text.slice(fullText.length); if (remaining) { if (!emittedRole) { emittedRole = true; yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: { role: "assistant" }, finish_reason: null }], }); } yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: { content: remaining }, finish_reason: null }], }); } finished = true; break; } if (parsed.done) { finished = true; break; } } if (finished) break; } if (!finished && buffer.trim()) { const parsed = parseJsonlLine(buffer.trim()); if (parsed.token && !signal?.aborted) { if (!emittedRole) { emittedRole = true; yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: { role: "assistant" }, finish_reason: null }], }); } yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: { content: parsed.token }, finish_reason: null }], }); } } } finally { reader.releaseLock(); } if (!signal?.aborted) { yield sseChunk({ id, object: "chat.completion.chunk", created, model, choices: [{ index: 0, delta: {}, finish_reason: "stop" }], }); yield "data: [DONE]\n\n"; } } export async function readJsonlResponse( body: ReadableStream, signal?: AbortSignal | null ): Promise { const reader = body.getReader(); const decoder = new TextDecoder(); let buffer = ""; let fullText = ""; try { while (true) { if (signal?.aborted) break; const { value, done } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; const parsed = parseJsonlLine(trimmed); if (parsed.token) fullText += parsed.token; if (parsed.text) return parsed.text; if (parsed.error) throw new Error(parsed.error); } } if (buffer.trim()) { const parsed = parseJsonlLine(buffer.trim()); if (parsed.text) return parsed.text; if (parsed.token) fullText += parsed.token; } } finally { reader.releaseLock(); } return fullText; }