import { FORMATS } from "../translator/formats.js"; // Parse SSE data line export function parseSSELine(line) { if (!line || line.charCodeAt(0) !== 100) return null; // 'd' = 100 const data = line.slice(5).trim(); if (data === "[DONE]") return { done: true }; try { return JSON.parse(data); } catch (error) { if (data.length > 0 && data.length < 1000) { console.log(`[WARN] Failed to parse SSE line (${data.length} chars): ${data.substring(0, 100)}...`); } return null; } } // Check if chunk has valuable content (not empty) export function hasValuableContent(chunk, format) { // OpenAI format if (format === FORMATS.OPENAI && chunk.choices?.[0]?.delta) { const delta = chunk.choices[0].delta; return delta.content && delta.content !== "" || delta.reasoning_content && delta.reasoning_content !== "" || delta.tool_calls && delta.tool_calls.length > 0 || chunk.choices[0].finish_reason || delta.role; } // Claude format if (format === FORMATS.CLAUDE) { const isContentBlockDelta = chunk.type === "content_block_delta"; const hasText = chunk.delta?.text && chunk.delta.text !== ""; const hasThinking = chunk.delta?.thinking && chunk.delta.thinking !== ""; const hasInputJson = chunk.delta?.partial_json && chunk.delta.partial_json !== ""; if (isContentBlockDelta && !hasText && !hasThinking && !hasInputJson) { return false; } return true; } return true; // Other formats: keep all chunks } // Fix invalid id (generic or too short) export function fixInvalidId(parsed) { if (parsed.id && (parsed.id === "chat" || parsed.id === "completion" || parsed.id.length < 8)) { const fallbackId = parsed.extend_fields?.requestId || parsed.extend_fields?.traceId || Date.now().toString(36); parsed.id = `chatcmpl-${fallbackId}`; return true; } return false; } // Format output as SSE export function formatSSE(data, sourceFormat) { if (data === null || data === undefined) return "data: null\n\n"; if (data && data.done) return "data: [DONE]\n\n"; // OpenAI Responses API format if (data && data.event && data.data) { return `event: ${data.event}\ndata: ${JSON.stringify(data.data)}\n\n`; } // Claude format if (sourceFormat === FORMATS.CLAUDE && data && data.type) { if (data.usage && typeof data.usage === 'object' && data.usage.perf_metrics === null) { const { perf_metrics, ...usageWithoutPerf } = data.usage; data = { ...data, usage: usageWithoutPerf }; } return `event: ${data.type}\ndata: ${JSON.stringify(data)}\n\n`; } // Remove null perf_metrics if (data?.usage && typeof data.usage === 'object' && data.usage.perf_metrics === null) { const { perf_metrics, ...usageWithoutPerf } = data.usage; data = { ...data, usage: usageWithoutPerf }; } return `data: ${JSON.stringify(data)}\n\n`; }