From e96f194a5977c80905ce0fa9bf2282bb20385ff5 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Sun, 16 Aug 2026 05:05:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E5=99=A8:=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20Responses=20=E6=B5=81=E5=BC=8F=20response.completed?= =?UTF-8?q?=20=E7=BC=BA=20usage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 上游 chat 流 finish_reason 块先于 usage 块, 原实现在 finish 时即发 response.completed 导致 usage 为空; 改为等 usage 块到达(或 [DONE] 兜底)再发, completed 携带 input/output tokens Co-Authored-By: Claude --- server/internal/proxy/convert/stream.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/server/internal/proxy/convert/stream.go b/server/internal/proxy/convert/stream.go index 77a779e..7630af1 100644 --- a/server/internal/proxy/convert/stream.go +++ b/server/internal/proxy/convert/stream.go @@ -412,9 +412,10 @@ func (t *responsesToChat) line(line []byte) []byte { type chatToResponses struct { sseState - model string - usage any - done bool + model string + usage any + finishSeen bool + done bool } func newChatToResponses() *chatToResponses { return &chatToResponses{} } @@ -425,6 +426,7 @@ func (t *chatToResponses) line(line []byte) []byte { return nil } if done { + // 流结束兜底:finish 后 usage 未随块到达时在此补发 completed if !t.done { t.done = true return eventLine("response.completed", map[string]any{ @@ -453,6 +455,9 @@ func (t *chatToResponses) line(line []byte) []byte { finish, _ = c0["finish_reason"].(string) } } + if finish != "" { + t.finishSeen = true + } var out [][]byte if role, _ := delta["role"].(string); role == "assistant" { out = append(out, eventLine("response.created", map[string]any{ @@ -465,7 +470,8 @@ func (t *chatToResponses) line(line []byte) []byte { "type": "response.output_text.delta", "delta": content, "item_id": "msg_1", "output_index": 0, "content_index": 0, })) } - if finish != "" && !t.done { + // 上游 usage 块(choices 为空)通常晚于 finish_reason:此时再发 completed,携带 usage + if _, hasUsage := m["usage"]; hasUsage && t.finishSeen && !t.done { t.done = true out = append(out, eventLine("response.completed", map[string]any{ "type": "response.completed",