mirror of
https://github.com/whit3rabbit/anyllm-proxy.git
synced 2026-09-22 08:00:51 +00:00
Large admin-ui refactor (Performative component system, sidebar nav,
provider/route tabs) plus backend module restructuring.
Admin UI contract fixes (this session):
- Fix Models page crash: useBackends unwraps {backends:[...]}; align
ModelEntry to {model_name, deployments} and ModelsResponse.strategy;
fix add-model body to {model_name, actual_model, backend_name}.
- Fix Backends/Providers health rendering: source per-backend status and
latency from the uptime endpoint (health_checks); narrow Backend type to
the real get_backends shape.
- Route + sidebar-link the previously-unrouted Backends tab.
Verified: cargo test (exit 0), clippy -D warnings (exit 0), fmt --check,
admin-ui tsc + vite build all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.4 KiB
2.4 KiB
anyllm_client
Async HTTP client for talking to Anthropic-style backends: retry policy, SSRF protection, SSE streaming, rate limiting.
See root ../../CLAUDE.md for workspace-wide commands and conventions.
Test
cargo test -p anyllm_client
Features
default = ["ssrf-protection", "native-tls"].- At least one TLS backend (
native-tlsorrustls) must be enabled or the crate fails to compile with an actionable error (seelib.rs). ssrf-protectiongates the URL/IP filtering inhttp.rs.
Layout
retry.rs—send_with_retry_policyis the canonical retry loop for the whole workspace. The proxy'sbackend/mod.rs::send_with_retrydelegates here.http.rs—build_http_client, SSRF filtering, header assembly.sse.rs+streaming.rs—run_sse_taskis the shared SSE frame reader.anthropic_client.rs— delegates toretry::send_with_retry_policy(no hand-rolled loop).rate_limit.rs,tools.rs,error.rs.
Gotchas
reqwest::Error::is_timeout()fires on read timeouts too. A read timeout means the POST was already processed. Onlyis_connect()is safe to retry on POST.retry_transport_errorsgates onis_connect()only by design — do NOT addis_timeout().- Two retry loops exist (this crate's canonical
retry.rsand proxy'sbedrock_client.rs). A backoff/classification change must hit both or they diverge silently.anthropic_client.rsdelegates toretry.rs, so it tracks automatically. 2u64.pow(attempt)overflows at attempt >= 64.backoff_delaycaps withattempt.min(62). Any new backoff formula needs the same guard.- Backoff jitter is deterministic (upper bound, not random) to keep tests predictable.
Ipv4Addr::is_broadcast()matches only255.255.255.255, not directed broadcasts like10.0.0.255. Those slip through SSRF filters whenallow_private=true.extra_headersVec +HeaderMap::insert= last writer wins. Push builder-level headers to the END of the Vec so they overwrite caller duplicates. Index 0 loses.- Header
&strslices: when building&[(&str, &str)]from aHeaderMap, collect ownedStringlocals first; the borrow checker rejects inline.to_str(). - Avoid
.clone()before serialization when only one field changes. Useserde_json::to_value(req)+ patch —MessageCreateRequestclone is O(content size).