Skip to content

Responses-family stream parsers silently drop the terminal event and unparented text deltas #995

Description

@Adolanium

Two silent data-loss bugs in the OpenAI Responses-family stream parsers in packages/ai.

1. Codex parseSSE drops a trailing unterminated event

packages/ai/src/providers/openai-codex-responses.ts, parseSSE (~535-586). Events are only extracted when a blank-line delimiter arrives inside the read loop. If a server closes the connection right after the final data: line without a trailing blank line, the terminal response.completed event is dropped and the final usage and stop reason are lost. The Anthropic provider's iterateSseMessages already handles this by draining the decoder and flushing the remaining buffer, the Codex one does not. CRLF line endings are also not normalized.

2. output_text.delta is silently dropped when content_part.added never arrives

packages/ai/src/providers/openai-responses-shared.ts (~376-392, same pattern for refusal.delta at ~393-409). The delta handler only appends when a matching content part already exists, and silently continues otherwise. Responses-compatible endpoints that are not fully spec-compliant (Azure, OpenRouter, various proxies) can stream response.output_text.delta without a preceding response.content_part.added, and the assistant text just vanishes with no error.

Fix for both: flush the decoder and any remaining buffered event after the read loop, normalize line endings, and lazily create the missing content part before appending a delta.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions