* test(rust): encode anthropic response serialization shape as rstest cases Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(rust): shape Anthropic Messages requests natively The Rust Messages route only relayed the body. It now runs the request shaping the Python handler does for the direct Anthropic provider: history sanitizers (empty blocks, tool ids, replayed web search results, provider_specific_fields, encrypted reasoning, advisor blocks), reasoning_effort and adaptive/legacy thinking translation against the model's capability flags, the sampling and speed gates under drop_params, the metadata allowlist, additional_drop_params, reasoning auto summary, OAuth and ANTHROPIC_AUTH_TOKEN credentials, provider_specific_header merging and anthropic-beta injection. Capability flags and LiteLLM settings reach Rust through route_host.shaping(). A request the route rejects before the call now maps to BadRequestError instead of APIConnectionError Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(rust): port Anthropic Messages shaping tests and pin comment contracts as cases Every Python unit test that exercises the ported shaping for the direct Anthropic provider now has a named rstest counterpart, and every comment that stated a behavior contract is deleted in favor of a case that pins it. Measured with cargo-mutants over the touched files, all viable mutants are caught Porting the tests surfaced parity gaps, fixed here to match Python: every casing of a forwarded anthropic-beta header is merged, replayed web search results are rewritten from their own block (an empty result keeps its slot and a server_tool_use with a non-string query stays), an empty output_config.effort falls back to medium, speed and reasoning effort errors quote values the way Python does, additional_drop_params apply after metadata validation and the auto summary and never touch model or messages, and a non-string metadata.user_id is rejected before the call * fix(rust): resolve Messages credentials through the secret source and scope headers by resolved provider The native Messages route read ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN and the base URL straight from the process environment, so a key or base held in a configured secret manager was never found. Each provider config now declares its secret names and the route resolves them through the same SecretSource the OCR route uses, with the Python bridge passing in litellm's configured manager provider_specific_header entries were scoped by the explicit custom_llm_provider only, falling back to anthropic, so an azure_ai/ model lost its azure_ai scoped headers. Scoping now happens in the route after the provider is resolved from the model, as Python's handler does The Azure config now adds the same anthropic-beta feature headers Python's Azure route adds, and the metadata allowlist, reasoning auto summary and history sanitizers move from the core route into the llms crate, mirroring their home in Python's messages handler * test(rust): escape the dot in the metadata.user_id match pattern * refactor(rust-bridge): project Messages capabilities without mutable dicts The capability flags and effort tiers were built as dict comprehensions, which the type-discipline gate counts as mutable construction, and the asdict call carried a mutable-ok suppression that suppressed nothing. The flags are now passed one by one and the effort tiers are a frozen dataclass, which asdict projects to the same map the native side reads --------- Co-authored-by: Yujong Lee <yujong@berri.ai> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| benches | ||
| src | ||
| tests | ||
| AGENTS.md | ||
| build.rs | ||
| Cargo.toml | ||
| README.md | ||
Native OCR uses litellm_secrets::source::SecretSource. Built-in secret managers resolve to retained Rust backends. Custom Python managers and overrides keep the callback path. Readable managers still require the Rust secret-manager binding to be enabled
The shared proxy initializer captures native configuration without loading the extension or doing native I/O. _SecretManagerRuntime.from_client constructs a backend on first use and keeps its handle on the Python client. The secret-manager dispatcher selects Python or Rust through catalog.py. Native reads call that handle; Rust routes extract the backend directly. Configuration changes replace the handle, while calls already bound to the previous backend keep using it. Handles cannot be reused after fork. Directly constructed LiteLLM managers are adapted on first native use. Manually supplied SDK clients keep their Python behavior because their credentials cannot be inferred safely. Provider implementations contain no bridge registration
Retention describes ownership and lifetime. callbacks-legacy-python::PublicCall owns Python references for one call to preserve identity. A native cache or secret-manager handle owns shared Rust state across calls to preserve connection pools and caches. Both use existing Py<T> and shared Rust ownership, with execution and GIL transitions handled by litellm-host-python
Cache and secret-manager catalog entries remain Python-only, including when LITELLM_RUST=1. This wiring does not change rollout policy
OCR provider requests use the shared litellm-http pool. AWS and Google secret-manager SDK clients keep their SDK transports, which do not yet inherit the pool's proxy, TLS, certificate, timeout, or observability configuration. Preserve those SDK transports and configure them equivalently instead of forcing them through reqwest