Skip to content

fix(genai): correct Anthropic SSE event-type filtering and text path …#1606

Open
Irfan-del-droid wants to merge 1 commit intofoss42:mainfrom
Irfan-del-droid:fix-anthropic-sse-parsing
Open

fix(genai): correct Anthropic SSE event-type filtering and text path …#1606
Irfan-del-droid wants to merge 1 commit intofoss42:mainfrom
Irfan-del-droid:fix-anthropic-sse-parsing

Conversation

@Irfan-del-droid
Copy link
Copy Markdown

Summary

Fixes #1592 — Anthropic streaming was silently broken in two ways:

  1. AnthropicModel.streamOutputFormatter returned x['text'] which is
    always null. The actual text lives at x['delta']['text'].
  2. streamGenAIRequest ignored SSE event: field lines entirely and
    forwarded every data: line to the formatter — including ping,
    message_start, content_block_start, etc. — causing null noise
    in the output stream.

Changes

📦 Files Changed — packages/genai/

lib/models/model_provider.dart

  • Added optional {String? eventType} parameter to streamOutputFormatter

lib/models/ai_request_model.dart

  • Updated getFormattedStreamOutput to accept and forward eventType

lib/utils/ai_request_utils.dart

  • Track SSE event: type across chunk boundaries using lastEventType
  • Pass eventType to getFormattedStreamOutput
  • Reset lastEventType on empty lines (SSE block boundaries)
  • Handle \r\n line endings with trimRight()
  • Suppress null / empty formatter results before sink.add

lib/interface/model_providers/anthropic.dart ⭐ Core fix

  • Added two guard constants: _kContentBlockDelta, _kTextDelta
  • Fast-path: skip payload inspection if eventType is not content_block_delta
  • Check x['type'] as fallback when eventType is absent
  • Validate delta is a Map
  • Check delta['type'] == 'text_delta' before extracting text
  • Fix extraction path: x['text']x['delta']['text']
  • Return null for all non-text events (ping, message_start, etc.)

lib/interface/model_providers/openai.dart

  • Signature alignment: added {String? eventType} (unused, no logic change)

lib/interface/model_providers/gemini.dart

  • Signature alignment: added {String? eventType} (unused, no logic change)

lib/interface/model_providers/azureopenai.dart

  • Signature alignment: added {String? eventType} (unused, no logic change)

test/genai_test.dart

  • Removed two dead unused imports from empty placeholder file

test/streaming/anthropic_stream_formatter_test.dart

  • 35 new unit tests across 7 groups:
    • Valid content_block_delta events
    • Ignored events via SSE event: fast-path
    • Ignored events via payload type field
    • Malformed / edge-case payloads
    • Multi-chunk sequential streaming simulation
    • Fast-path vs payload-check consistency
    • Full JSON encode → decode → format round-trip

Root pubspec.yaml

  • Added missing flutter_driver: sdk: flutter dev dependency
  • Fixes integrationDriver being undefined in test_driver/integration_test.dart

Root Cause

Anthropic's SSE wire format emits multiple event types per response:

…extraction

- Track SSE event: type across chunks in streamGenAIRequest
- Pass eventType through getFormattedStreamOutput -> streamOutputFormatter
- Fix AnthropicModel.streamOutputFormatter: check payload type and
  extract text from x['delta']['text'] instead of x['text']
- Suppress null/empty formatter outputs before sink.add
- Align streamOutputFormatter signature across all providers
- Add flutter_driver dev dependency for integration_test driver

Fixes foss42#1592
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Anthropic streaming response parsing broken due to incorrect SSE event type handling and data path extraction

1 participant