v1.3.5-upstream8.0.35 - 2026-10-28
Summary
/v1/messages turns that keep the reserved DeferredToolPlaceholder but no longer declare a ToolSearch function are now forwarded instead of being rejected locally with 422 deferred bridge requires an active client ToolSearch declaration.
- Routes configured with
client-search: disabled now reject every turn that declares ToolSearch, even when the bridge would forward the body unchanged.
- Compatibility: no configuration change is required. Requests that previously failed now complete with the surviving declarations, while discovery history that cannot be replayed and forced tool choices naming a dropped declaration still fail with
422.
Upstream alignment
- Upstream release:
v8.0.35
- Previous baseline:
v8.0.35
- Intake record: absorbed.md
- Ported: None. This release ports no new upstream work; it is built on the
v8.0.35 baseline, so the tag keeps the previous suffix.
- Skipped: The exclusions recorded for the
v8.0.35 intake remain in force: the separate upstream apply_patch pipeline and its tests, synthesized fetch entries and visibility changes, and catalog or prompt snapshots.
Breaking changes
Added
Changed
- A placeholder-only turn now degrades: the reserved placeholder and the deferred declarations that no discovery result activated are dropped, and
defer_loading is stripped before the non-Anthropic translator runs.
client-search: disabled now rejects every turn that declares ToolSearch, including one the bridge would have forwarded unchanged. This matches the Responses pipeline, which triggers on the declared client search contract, and the documented meaning of the policy.
Fixed
- A Claude Code turn that carries
DeferredToolPlaceholder with defer_loading: true and no ToolSearch declaration no longer fails in a few milliseconds with 422 unsupported_protocol. Such a turn is forwarded with its remaining declarations, so an eager conversation that still advertises deferred support completes.
- A forced
tool_choice that names a dropped declaration is still rejected with 422 forced tool is not active after discovery, and a history containing a search call or a tool_reference result without an active ToolSearch declaration is still rejected with 422 deferred history requires an active client ToolSearch declaration.
- The degrade decision is structural: caller text and tool arguments are never read as discovery, while escaped spellings, duplicate JSON members and lossy Unicode are still inspected and refused by the existing checks.
Security
Validation
- Regression gate PASS on the release candidate with Go 1.26.4:
gofmt, go vet ./..., go test ./... -count=1 (102 packages) and a server build.
- Red-green: restoring the unconditional guard fails four unit subtests, two executor-level cases and two route-policy cases.
- Live end-to-end with a locally built binary, a temporary configuration and a fake OpenAI-compatible upstream on isolated loopback ports:
main before the fix answered 422 in 1.5 ms without contacting the upstream; this candidate answered 200 in 1.9 ms and the upstream received Glob, Grep and Read only, without the placeholder or defer_loading.
- Coverage limit: these checks use synthetic requests and a deterministic fake upstream, not a live provider or a real Claude Code client session; server-executed declarations and multi-provider routing were not exercised.
Known issues
- Discovery history without an active
ToolSearch declaration is rejected rather than rewritten, because dropping the search round can leave later calls to tools that are no longer declared; such a turn must declare ToolSearch again.
- A
tool_result that mixes tool_reference with text, image or error blocks remains unsupported and is rejected with 422, because no contract preserves every component.
- Anthropic server-executed declarations such as
tool_search_tool_regex_20251119 are forwarded as ordinary functions and are not executed by the gateway.
Release assets
CLIProxyAPI_<version>_linux_<arch>.tar.gz is the default Linux build. It supports dynamic library plugins and targets a GLIBC 2.17 baseline.
CLIProxyAPI_<version>_linux_<arch>_no-plugin.tar.gz is 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.gz is the FreeBSD arm64 build. It is built without CGO and does not support dynamic library plugins.
Full changelog
Compare v1.3.4-upstream8.0.35...v1.3.5-upstream8.0.35