Next.js Edge Runtime中使用assistant-ui调用自定义API时抛出“Stream ended with an incomplete line”错误
Next.js Edge Runtime中使用assistant-ui调用自定义API时抛出“Stream ended with an incomplete line”错误
你碰到的这个问题其实是assistant-ui内置的SSE(Server-Sent Events)解析器对响应格式要求非常严格导致的。结合你的代码来看,主要有两个核心问题:
问题根源
- JSON中的换行符破坏了SSE格式:你的Python后端返回的
sql_query包含换行符,直接用JSON.stringify序列化后,这些换行符会保留在字符串里,导致生成的SSEdata字段变成了多行内容。而SSE规范要求每个data事件必须是单行文本,解析器看到中途换行的内容就会判定为“不完整的行”。 - 虽然后续加了
\n\n,但序列化后的JSON本身包含换行,导致实际输出的SSE块不符合解析要求。
解决步骤
1. 处理JSON字符串中的换行符
在序列化消息对象之前,先把内容里的换行符转义或者替换,确保整个data字段是单行的。
2. 严格遵循SSE格式输出
确保每个data事件的内容后面必须紧跟\n\n,而且整个data行没有额外的换行。
下面是修改后的route.ts代码,已经修复了这些问题:
// app/api/chat/route.ts export const runtime = 'edge'; export const maxDuration = 60; export async function POST(req: Request) { const requestBody = await req.json(); console.log('🔍 Request body:', JSON.stringify(requestBody, null, 2)); const { messages } = requestBody; const userMessage = messages?.[messages.length - 1]?.content[0].text; console.log('📩 User message:', userMessage); if (!userMessage) { return new Response(JSON.stringify({ error: 'No message provided' }), { status: 400, headers: { 'Content-Type': 'application/json' }, }); } try { console.log('🚀 Sending to backend...'); const res = await fetch( 'http://localhost:8000/sessions/id/messages', // Simplified ID for example { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: userMessage }), }, ); const data = await res.json(); console.log('📦 Backend response:', JSON.stringify(data, null, 2)); // 转义SQL查询中的换行符,确保JSON序列化后是单行,同时保留渲染时的换行效果 const formattedSql = data.sql_query ? data.sql_query.replace(/\n/g, '\\n') : ''; const formattedContent = data.sql_query ? `\`\`\`sql\n${formattedSql}\n\`\`\`` : (data.content ?? 'No response from AI agent.'); console.log('✨ Formatted content:', formattedContent); const encoder = new TextEncoder(); const stream = new ReadableStream({ async start(controller) { const messageChunk = { id: Date.now().toString(), // Unique ID role: 'assistant', content: [{ type: 'text', text: formattedContent }], }; // 序列化后再次检查并转义换行符,确保输出的SSE data是单行 const serializedMessage = JSON.stringify(messageChunk).replace(/\n/g, '\\n'); controller.enqueue(encoder.encode(`data: ${serializedMessage}\n\n`)); controller.close(); }, }); return new Response(stream, { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive', }, }); } catch (error) { console.error('Failed to fetch from agent backend:', error); return new Response( JSON.stringify({ error: 'Failed to fetch from agent backend' }), { status: 500, headers: { 'Content-Type': 'application/json' }, }, ); } }
额外说明
我这里把SQL里的换行符转义为\\n,这样既保证了SSE的data字段是完整单行,前端的Markdown组件解析时又能把转义后的换行符还原成正常的换行,不会影响SQL代码的显示格式。
另外要注意,assistant-ui的ThreadPrimitive默认是基于流式响应设计的,所以即使你只有完整的单条消息,也必须用标准SSE格式返回,不能直接返回JSON响应,否则组件会无法正确处理。
内容来源于stack exchange
相关产品推荐
相关产品推荐

