Skip to content

OpenAI subscription stream failures are fatal after the first model event #19

Description

@danielkov

Problem

An OpenAI subscription response stream can terminate the ACP session after model output has started, even when the underlying failure is a transient response-body interruption. Kit retries the same failure before the first model event, but Kit 0.1.86 treated it as fatal after an event had been emitted.

Version

kit 0.1.86

Environment

  • OS: Darwin 25.5.0
  • Architecture: arm64
  • Surface/host: ACP
  • Provider: openai-subscription

Reproduction

  1. Start an ACP session using openai-subscription.
  2. Begin a model turn and allow at least one ModelTurnEvent to be emitted.
  3. Interrupt the HTTP response body before the provider sends response.completed (for a deterministic test, serve an SSE response with a truncated Content-Length).

The reported session ran for approximately 54 seconds after its last completed tool result before the response stream ended.

Actual behavior

The turn terminates with a fatal provider error and does not persist a completed assistant item:

openai-subscription stream transport failed
(timeout=false, connect=false, request=false, body=false, decode=true)

Sanitized fatal diagnostics:

{
  "stage": "stream",
  "retryable": false,
  "attempt": 1,
  "reqwest": {
    "timeout": false,
    "connect": false,
    "request": false,
    "body": false,
    "decode": true
  },
  "source_chain": [
    { "kind": "hyper" },
    { "kind": "io", "classification": "unexpected_eof" }
  ]
}

Reqwest reports decode=true because Response::bytes_stream() wraps response-body frame failures as decode errors. The low-level cause was unexpected_eof.

Expected behavior

Kit should recover from a transient post-event interruption without assuming that a non-deterministic model will replay the same SSE frames. After ACP v2 is available, Kit can replace the in-progress assistant message with the new authoritative response. Recovery must not duplicate text or reasoning, and tool calls must not execute twice.

Dependencies

  • Blocked by feat(acp): add v2 mid-turn steering #24, which moves Kit's ACP integration to v2. The recovery design depends on ACP v2 message identity and replacement semantics; raw provider-frame replay is not a safe basis for recovery.

Related work

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