diff --git a/backend/internal/pkg/antigravity/stream_transformer.go b/backend/internal/pkg/antigravity/stream_transformer.go index 902646aaab..13471ddddc 100644 --- a/backend/internal/pkg/antigravity/stream_transformer.go +++ b/backend/internal/pkg/antigravity/stream_transformer.go @@ -40,6 +40,7 @@ type StreamingProcessor struct { outputTokens int cacheReadTokens int imageOutputTokens int + hasContent bool } // NewStreamingProcessor 创建流式响应处理器 @@ -175,6 +176,11 @@ func (p *StreamingProcessor) MessageStartSent() bool { return p.messageStartSent } +// HasContent reports whether any substantive text, thinking, or tool calls were emitted. +func (p *StreamingProcessor) HasContent() bool { + return p.hasContent +} + // emitMessageStart 发送 message_start 事件 func (p *StreamingProcessor) emitMessageStart(v1Resp *V1InternalResponse) []byte { if p.messageStartSent { @@ -296,6 +302,7 @@ func (p *StreamingProcessor) processThinking(text, signature string) []byte { } if text != "" { + p.hasContent = true _, _ = result.Write(p.emitDelta("thinking_delta", map[string]any{ "thinking": text, })) @@ -350,6 +357,7 @@ func (p *StreamingProcessor) processText(text, signature string) []byte { })) } + p.hasContent = true _, _ = result.Write(p.emitDelta("text_delta", map[string]any{ "text": text, })) @@ -362,6 +370,7 @@ func (p *StreamingProcessor) processFunctionCall(fc *GeminiFunctionCall, signatu var result bytes.Buffer p.usedTool = true + p.hasContent = true toolID := fc.ID if toolID == "" { diff --git a/backend/internal/service/antigravity_gateway_compat_stream.go b/backend/internal/service/antigravity_gateway_compat_stream.go index 26d30ddb46..1a69bea601 100644 --- a/backend/internal/service/antigravity_gateway_compat_stream.go +++ b/backend/internal/service/antigravity_gateway_compat_stream.go @@ -141,15 +141,18 @@ func (s *antigravityCompatStreamSession) consume(line string) { } func (s *antigravityCompatStreamSession) hasMeaningfulData() bool { - return s.meaningfulData + return s.meaningfulData || s.processor.HasContent() } -func (s *antigravityCompatStreamSession) finish() *antigravityStreamResult { +func (s *antigravityCompatStreamSession) finish() (*antigravityStreamResult, error) { finalEvents, usage := s.processor.Finish() mergeAntigravityCompatUsage(s.usage, usage) s.consumeClaudeEvents(finalEvents) + if !s.hasMeaningfulData() && !s.writer.Disconnected() { + return nil, antigravityCompatEmptyStreamError() + } s.adapter.Finalize(s.writer) - return s.result(s.writer.Disconnected()) + return s.result(s.writer.Disconnected()), nil } func (s *antigravityCompatStreamSession) collectResult(clientDisconnect bool) *antigravityStreamResult { @@ -220,24 +223,18 @@ func isMeaningfulAntigravityCompatEvent(event *apicompat.AnthropicStreamEvent) b if event == nil { return false } - if event.Type == "message_stop" { - return true - } if event.ContentBlock != nil { block := event.ContentBlock return block.Type == "tool_use" || block.Text != "" || block.Thinking != "" || - block.Signature != "" || block.Source != nil } if event.Delta != nil { delta := event.Delta return delta.Text != "" || delta.PartialJSON != "" || - delta.Thinking != "" || - delta.Signature != "" || - delta.StopReason != "" + delta.Thinking != "" } return false } @@ -295,7 +292,7 @@ func (s *AntigravityGatewayService) handleAntigravityCompatStream( if !session.hasMeaningfulData() && !writer.Disconnected() { return nil, antigravityCompatEmptyStreamError() } - return session.finish(), nil + return session.finish() } if event.err != nil { return s.handleAntigravityCompatReadError(c, session, event.err, maxLineSize, prefix)