v1.1.3
[1.1.3] — 2026-06-15
Streaming-correctness release. Brings the streaming routing path (RouteStream) to parity with non-streaming Route: the post-request plugin pipeline, the per-provider circuit breaker, and least-latency / cost-optimized ordering now all apply to stream: true traffic. Also tightens fallback retry semantics and async-context propagation. No public API breaks. Fixes every issue labelled release-1.1.3: #135, #136, #137, and #138, plus enhancement #181.
Fixed
- Streaming requests skipped the post-request plugin pipeline (issue #135, PR #201):
RouteStreamran onlybefore_requestplugins, soafter_request(response-cache store, request-logger) andon_errorplugins never fired for streaming traffic and a cacheSkiphit was discarded with the provider called anyway. The full plugin lifecycle now runs for streams:RunAfterfires once the stream drains — with the response reconstructed from streamed chunks so the response-cache can store it —RunOnErrorfires on resolution / provider / stream / after-plugin failures, and a cache hit short-circuits the provider into a single streamed chunk. @Rachit-Gandhi - Circuit breaker was a no-op for streaming-first traffic (issue #136, PR #199): the streaming path never recorded breaker outcomes, so mid-stream provider failures did not count and the breaker never opened. Stream success is now recorded at stream completion and failures (both at startup and mid-stream) count toward the breaker; open-circuit streaming targets are skipped during resolution so fallback advances instead of returning circuit-open. @Rachit-Gandhi
- Fallback strategy retried cancellations and open circuits (issue #137, PR #198):
shouldRetryreturned true for any error without a parseable HTTP status code, socontext.Canceled/context.DeadlineExceededandcircuitbreaker.ErrCircuitOpenre-attempted already-cancelled requests and burned the whole retry budget against an open circuit. These sentinels are now non-retryable, and the retry loop checksctx.Err()before each attempt. - Streaming ignored least-latency / cost-optimized ordering (issue #138, PR #198):
streamingTargetOrderLockedhad no case for these modes and silently fell through to declaration order. Streaming now orders targets by observed p50 latency (exploring unsampled targets first) and by catalog model cost, mirroring the non-streaming path, and records successful stream latency samples so least-latency converges for streaming-only traffic.
Changed
- Circuit-breaker failure accounting (issue #136, PR #199): caller-side cancellation and client deadlines no longer trip the breaker, while provider-side timeouts that surface as
context.DeadlineExceededwhile the request context is still live are counted as failures. Applies to bothRouteandRouteStream. - Detached background goroutines preserve trace context (issue #181, PR #202): async event hooks and the streaming observability completion event now run under
context.WithoutCancel(ctx)instead of the already-cancelled request context /context.Background(), so fire-and-forget work (DB writes, outbound calls) is no longer dead-on-arrival and recorded events stay linked to the originating trace. MCP background initialization parents its 60s timeout on the gateway shutdown context soClose()cancels in-flight handshakes instead of letting them linger.
Notes
- Under
cost-optimizedrouting withunpriced_strategy: skip, the streaming path keeps unpriced providers as a last-resort fallback (and errors only when no candidate is priced), whereas the non-streaming path never selects an unpriced provider. This is intentional for the streaming fallback chain. - All public
release-1.1.3issues — #135, #136, #137, #138 — and enhancement #181 are closed by this release.
Contributors
Thanks to everyone who shipped this release:
- feat: release v1.1.3 — streaming-correctness (#198) — @MitulShah1 @Rachit-Gandhi
Full changelog: https://github.com/ferro-labs/ai-gateway/blob/v1.1.3/CHANGELOG.md