Repository navigation
v1.3.4-upstream8.0.35
·
3 commits
to main
since this release
v1.3.4-upstream8.0.35 - 2026-10-24
Summary
- Add an opt-in
requests.streaming.bootstrap-timeoutthat bounds one streaming attempt's request-to-first-frame wait, so an upstream that accepts a request and never writes a frame is retried within the existingbootstrap-retriesbudget or rejected with504instead of holding the client's response open indefinitely. - Include the three upstream repairs merged after
v1.3.3-upstream8.0.35: Codex multi-line SSE event assembly, Interactions fallback item IDs, and the model-template fallback. - Compatibility: the new option defaults to
0(unbounded), so an existing configuration behaves exactly as before until an operator opts in; no credential, provider or protocol behaviour changes.
Upstream alignment
- Upstream release:
v8.0.35 - Previous baseline:
v8.0.35 - Intake record: absorbed.md
- Ported: The three repairs already recorded in the intake ledger: upstream
7795de19ca80940adeafe45ebe7c5dbfc4931cc5(Codex HTTP execute and stream paths assemble multi-line SSE data events with the upstream scanner and its raw-line budget accounting), upstreamb0db5448e8f8cce9b58e5d02eab23d32d4ec5dca(Interactions fallback item IDs become per-response UUID-prefixed) and upstreame240bd84321c55b96b226d43fa557c9a8be55a00(Codex and multi-agent templates fall back to the first valid model template whengpt-5.5is absent, still preferring it when present). The bootstrap timeout is fork-local and ports no upstream work. - Skipped: The exclusions recorded for those ports remain in force: the separate upstream
apply_patchpipeline and its tests, synthesized fetch entries and visibility changes, and catalog or prompt snapshots. Broader upstream feature and concurrency chains reviewed in the intake decisions remain excluded.
Breaking changes
- None.
requests.streaming.bootstrap-timeoutis new and defaults to0, which keeps the previous unbounded bootstrap wait; only an explicit positive value changes runtime behaviour.
Added
requests.streaming.bootstrap-timeoutbounds how long one streaming attempt may wait for its first upstream frame. It accepts a duration (90s,1m30s) or whole seconds (90); an empty value and0,none,off,never,unlimited,disabledor an unparsable value mean unbounded, which is also the default.- When the bound expires, the attempt is cancelled and either retried within
requests.streaming.bootstrap-retriesor answered with504and the messageupstream produced no frame within bootstrap timeout <duration>, written before any SSE byte is sent.
Changed
- A streaming attempt that produced no client-visible frame now releases its derived context and its deadline timer, while an attempt that delivered a frame keeps its context for the rest of the stream.
- Retries consumed by the bootstrap deadline share the same counter as retries triggered by an upstream error, so
bootstrap-retriesremains the single budget, and the Home dispatcher still forces zero retries.
Fixed
- A silent upstream no longer holds the streaming chat completions endpoints open with zero bytes until the client times out. In an observed incident the gateway held the request for exactly 300 s, its keep-alive ticker could not run because SSE headers are committed only after the first upstream chunk, and the failure surfaced only as a client-side idle timeout. With
bootstrap-timeoutconfigured the gateway abandons the attempt, retries it when the budget allows, and otherwise answers504before the client's own deadline. - Codex streaming and buffered responses assemble multi-line SSE
data:events with the upstream scanner instead of dropping them, while the raw bootstrap budgets, replay, responses-tools and cancellation paths are retained. - Interactions fallback item IDs are scoped to each response, so two responses no longer collide on the same fallback ID; supplied IDs and namespaced custom tools keep their existing handling.
- Codex and multi-agent templates fall back to the first valid model template when
gpt-5.5is absent, instead of rejecting the catalog entry;gpt-5.5is still preferred when present.
Security
- None. The option adds no endpoint, reads no new credential and logs no request content.
Validation
- Regression gate PASS on the release candidate with Go 1.26.0:
gofmt, the tracked catalog validation,go vet ./...,go test ./... -count=1and a server build. - Focused evidence for the bootstrap timeout:
gofmtclean on both Go 1.26.0 and Go 1.27.2,go vet ./...clean, and new tests covering a deadline-abandoned attempt retried to success,504when the retry budget is exhausted, a silent upstream consuming exactly one retry, the configuration parsing table and the accessor. - Measured end-to-end evidence with a locally built binary on isolated ports (
127.0.0.1:18317-18319) against a local upstream that accepts a request and never writes a byte: the default configuration stayed silent with no bytes for 8 s;bootstrap-timeout: 3swithbootstrap-retries: 1answered504in 6.00 s after exactly two upstream requests; and an upstream that stalled once and then served returned HTTP200with real SSE content in 3.0 s. - The three ported repairs carry their own recorded evidence in the intake ledger: behavioural replay fails on the baseline and passes on the candidate, package tests and the server build pass, and each commit received an independent read-only review.
- Coverage limit: the end-to-end checks use a deterministic local upstream, not a live provider or a desktop client; multi-provider performance was not measured.
Known issues
- Plugin-executor routes (
streamWithPluginExecutor) do not use this bootstrap path, so a routed plugin executor can still stay silent during bootstrap. - Silence after the first frame remains unbounded by design: the option intentionally bounds only the wait for the first frame and does not replace a general stream idle timeout.
- One initial unrelated Antigravity credits assertion was recorded during the ported-repair validation and is preserved in the intake evidence; its cause was not established and no stage was waived.
Release assets
CLIProxyAPI_<version>_linux_<arch>.tar.gzis the default Linux build. It supports dynamic library plugins and targets a GLIBC 2.17 baseline.CLIProxyAPI_<version>_linux_<arch>_no-plugin.tar.gzis the portable Linux build for musl-based or older systems such as OpenWrt. It does not support dynamic library plugins.CLIProxyAPI_<version>_freebsd_aarch64_no-plugin.tar.gzis the FreeBSD arm64 build. It is built without CGO and does not support dynamic library plugins.