Skip to content

th-stream-5xx-retry: chat_stream retries retryable 5xx (0.16.2)#79

Merged
brentrager merged 1 commit into
mainfrom
th-core-0162-stream-5xx-retry
Jul 10, 2026
Merged

th-stream-5xx-retry: chat_stream retries retryable 5xx (0.16.2)#79
brentrager merged 1 commit into
mainfrom
th-core-0162-stream-5xx-retry

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

chat_stream (the path EVERY chat turn takes) retried only transient transport errors on .send(), then bailed immediately on any non-success HTTP status. A transient gateway 5xx — groq/LiteLLM 502/503 during an incident or load blip — propagated as an AGENT_ERROR, and the chat widget rendered an empty reply. The non-streaming chat() path already retries these (policy.retry_on_status); the streaming path never did (a stale comment even claimed it "drop[s] into the existing status-code retry path" — that path didn't exist).

Root-caused during a live prod incident: node-rotation wedged valkey → api-prime down → the LiteLLM gateway Init:0/1, so gpt-oss-120b returned 502/503 on nearly every request → empty replies across the Chakra Transformation Posture agent.

Fix

Mirror chat()'s retry loop for the streaming request+status check, before any stream bytes are read (idempotent — no partial response emitted yet): retry policy.retry_on_status (429/5xx) with backoff + Retry-After, keep the transport-error retry, keep the request dump on final failure.

Test

chat_stream_retries_retryable_5xx_then_succeeds — throwaway local server serves 503 then 200+SSE; asserts the turn recovers and a retry occurred. No new deps.

Bumps core 0.16.1 → 0.16.2.

@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: f386329

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

…ng (bump 0.16.2)

The streaming path (chat_stream — every chat turn) retried only transient
transport errors on `.send()`, then bailed immediately on any non-success HTTP
status. A transient gateway 5xx (groq/LiteLLM 502/503 during an incident or
load blip) therefore propagated as an AGENT_ERROR and the chat widget rendered
an EMPTY reply — while the non-streaming `chat()` path already retried these.

Mirror chat()'s retry loop for the streaming request+status check, BEFORE any
stream bytes are read (idempotent — no partial response emitted yet): retry
`policy.retry_on_status` (429/5xx) with backoff + Retry-After, keep the transport
retry, keep the request dump on final failure. Regression test serves 503→200+SSE
from a throwaway local server and asserts the turn recovers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@brentrager brentrager force-pushed the th-core-0162-stream-5xx-retry branch from 455cb13 to f386329 Compare July 10, 2026 20:18
@brentrager brentrager merged commit 3342487 into main Jul 10, 2026
3 checks passed
@brentrager brentrager deleted the th-core-0162-stream-5xx-retry branch July 10, 2026 20:26
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.

1 participant