Skip to main content
Chappie streams responses from the ChatGPT/Codex backend using one of two transports: a WebSocket connection to the Codex WebSocket endpoint, or HTTP Server-Sent Events (SSE). By default Chappie prefers WebSocket for lower first-token latency and switches to HTTP/SSE automatically if WebSocket cannot recover. You can override this behaviour through ChappieStreamingTransportPolicy.

How the default transport works

With the default policy, Chappie opens a WebSocket connection for each streaming request. If the connection drops mid-stream, Chappie attempts to reconnect up to 5 times. If all reconnection attempts fail, Chappie falls back to HTTP/SSE for the remainder of that session. When a reconnect succeeds and the server replays previously delivered text, Chappie suppresses the replayed prefix so your UI does not receive duplicate tokens. If the replayed content diverges from what was already delivered — meaning the server sends different text for an already-emitted prefix — Chappie stops the stream and throws ChappieClientError.streamingTransportReplayDiverged rather than corrupting your conversation output.

Available transport policies

ChappieStreamingTransportPolicy exposes two ready-made static values:
PolicyprefersWebSocketmaxWebSocketReconnectionAttemptsfallsBackToHTTPSSE
.defaulttrue5true
.httpSSEOnlyfalse0true
You can also construct a custom policy using the memberwise initialiser:
public init(
    prefersWebSocket: Bool = true,
    maxWebSocketReconnectionAttempts: Int = 5,
    fallsBackToHTTPSSE: Bool = true
)

Forcing HTTP/SSE-only transport

Pass .httpSSEOnly when you need deterministic, WebSocket-free transport:
let client = Chappie.client(
    streamingTransportPolicy: .httpSSEOnly
)
Via a shared ChappieConfiguration:
let config = ChappieConfiguration(
    streamingTransportPolicy: .httpSSEOnly
)

let authSession = Chappie.authSession(configuration: config)
let client = Chappie.client(configuration: config)
The default WebSocket transport typically delivers the first streaming token with lower latency than HTTP/SSE. Switch to .httpSSEOnly only when WebSocket is unavailable or you need simpler transport semantics for testing.

When to use .httpSSEOnly

Use HTTP/SSE-only transport in these situations:
  • Environments with WebSocket restrictions — corporate networks, certain VPN configurations, or enterprise MDM policies that block WebSocket upgrades.
  • Automated testing — HTTP/SSE removes WebSocket reconnection state from the equation, making test behaviour more predictable.
  • Debugging transport issues — isolating whether a problem is WebSocket-specific by confirming the same request works over SSE.

Handling streamingTransportReplayDiverged

ChappieClientError.streamingTransportReplayDiverged means a WebSocket reconnect returned text that contradicts what your UI already displayed. The associated string value contains the partial text that was emitted before the divergence was detected. When you catch this error, re-render the conversation from scratch or show the user an error prompt asking them to retry:
do {
    for try await event in client.stream("Draft a reply.") {
        switch event {
        case .textDelta(let delta):
            appendText(delta)
        case .completed:
            break
        default:
            break
        }
    }
} catch ChappieClientError.streamingTransportReplayDiverged(let partialText) {
    // The partial text shown so far may be inconsistent.
    // Clear the in-progress message and prompt the user to retry.
    clearInProgressMessage()
    showRetryPrompt()
    print("Diverged after: \(partialText)")
}
If you see streamingTransportReplayDiverged frequently in production, switch to .httpSSEOnly as a mitigation while you investigate whether a proxy or network policy is corrupting WebSocket reconnection payloads.