Files
openteam/server/internal/proxy/sse_fix_test.go
T
Sakurasan 79545aa48e fix: 兼容上游 SSE data: 后无空格格式,流式记账不再 0 消耗
火山方舟等上游流式返回 data:{...}(data: 后无空格),原解析只认
'data: '(带空格),导致 content 文本与 usage 全部漏解析:
- sseContentText 抽成 sseDataPayload,统一处理 data: 前缀
  (支持带/不带空格 + event:+data: 多行块)
- scanUsage 复用 sseDataPayload
- convert/stream.go parseLine 也支持 data:{ 无空格
- 新增回归测试覆盖无空格/带空格/多行块三种形态
2026-08-27 01:24:30 +08:00

49 lines
2.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package proxy
import (
"encoding/json"
"testing"
)
// 复现线上火山方舟 qwen 流:data:{...} 无空格(省略 data: 后的空格)。
func TestSSEDataPayloadNoSpace(t *testing.T) {
lines := []string{
`data:{"message":{"model":"qwen3.8-flash","id":"msg_1","role":"assistant","type":"message","content":[],"usage":{"input_tokens":31626,"output_tokens":0}},"type":"message_start"}`,
`data:{"delta":{"type":"text_delta","text":"你好"},"type":"content_block_delta","index":0}`,
`data:{"delta":{"type":"text_delta","text":"!"},"type":"content_block_delta","index":0}`,
`data:{"delta":{"stop_reason":"end_turn"},"type":"message_delta","usage":{"cache_creation":{"ephemeral_5m_input_tokens":33065},"output_tokens":8,"cache_creation_input_tokens":33065,"input_tokens":8,"cache_read_input_tokens":0}}`,
}
var out string
for _, l := range lines {
out += sseContentText([]byte(l))
}
if out != "你好!" {
t.Fatalf("outputText=%q, want %q", out, "你好!")
}
// message_delta 的 delta.usage 应能提取(output_tokens=8)
u := scanUsage([]byte(lines[3]))
if u == nil {
t.Fatal("scanUsage returned nil for message_delta with usage")
}
var sh usageShape
if err := json.Unmarshal(u, &sh); err != nil {
t.Fatalf("unmarshal usage: %v", err)
}
if sh.OutputTokens != 8 {
t.Fatalf("output_tokens=%d, want 8", sh.OutputTokens)
}
}
// 兼容带空格的单 data: 行(标准 SSE)与 event:+data: 多行块。
func TestSSEDataPayloadSpacedAndMultiLine(t *testing.T) {
// 标准:data: {...}
if got := sseContentText([]byte(`data: {"delta":{"type":"text_delta","text":"hi"},"type":"content_block_delta","index":0}`)); got != "hi" {
t.Fatalf("spaced single line: got %q, want hi", got)
}
// 多行块:event: message_delta\ndata: {...}
block := []byte("event: message_delta\ndata: {\"delta\":{\"type\":\"text_delta\",\"text\":\"yo\"},\"type\":\"content_block_delta\",\"index\":0}\n")
if got := sseContentText(block); got != "yo" {
t.Fatalf("multiline block: got %q, want yo", got)
}
}