litellm/litellm-rust/crates/callbacks-legacy-python/AGENTS.md
Yujong Lee df84fef96e refactor(rust): rename legacy callback adapter crate
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-19 23:06:26 +00:00

3.2 KiB

  • Target invariants, not completion claims
  • Keep this crate the legacy @client wrapper as the native call sees it, and nothing else: the Logging contract (function_setup, the deployment hooks, pre_call/post_call, the sync and async success and failure fan-out, the deferred proxy release, the argument sharing those callbacks rely on) plus the kwargs rewrites the wrapper makes on the way in (credential-name inheritance, the budget and retry-count limits)
    • The driver in litellm-host-python, the routes and core see one PythonLifecycle; they never learn which Python objects consume a call
  • Rust drives the call; every litellm Python internal it still borrows is a variant of LegacyPython, grouped by subsystem (Wrapper, Logging, DeploymentHooks)
    • The enum only shrinks: when Rust owns a subsystem, delete its group rather than adding a Rust path beside it
    • Calling a user's own callback directly is permanent Python surface and gets its own type outside LegacyPython
    • PublicCall is the caller's call as Logging sees it: the positional arguments, the keyword view as the legacy path rewrites it (setup, deployment hook, prepare) and the bound request object whose attributes back keywords the caller omitted; routes hand it over through run_legacy_call and keep no copy
  • setup reuses a Logging the caller passed as litellm_logging_obj (the proxy and Router are the live cases) and otherwise builds one through function_setup, as @client does
    • Either way every phase calls the same Logging method the Python path calls; which callbacks run is Logging's decision, never this crate's
  • Callbacks receive the caller's own objects and may mutate them; this crate alone carries that obligation
    • Retain complete boundary arguments, opaque unknown values, aliases, omitted/default distinctions and deliberate copies; preserve the established deployment-hook kwargs view
    • Before pre_call, re-alias every body key whose value equals the caller's argument to the caller's own object; this crate compares the two itself, and the argument is resolved by litellm_host_python::lookup
    • Retain independently captured body/header roots from pre_call to post_call; in-place mutation reaches the wire, envelope field replacement is visible to later callbacks only
    • A later kind of callback host (WASM, in-process Rust) has none of these obligations, so they stay out of litellm-host, litellm-host-python and the bridge; the only fact that crosses from the route is the prepared keyword view
  • Success and failure handlers receive the exact selected public response or exception; logging projections, redaction and snapshots keep their own copy contracts
    • Ordinary failure-handler errors cannot suppress the other eligible family or replace the mapped provider error; a cancellation ends the call with no further dispatch
    • Dispatch errors never replay provider work or trigger the opposite outcome; the proxy's acceptance or rejection releases deferred success at most once
    • Delivery follows the registry, not the callable's type: direct, awaited, executor-submitted, logging-worker and deferred paths stay distinct
  • Traverse every retained Python edge; close is idempotent and restores the correlation context once