Success, failure and request callbacks on the native OCR path no longer go
through Logging.pre_call, post_call, success_handler or failure_handler.
Core's DispatchCursor selects each target and leaf method; the bridge
invokes it directly or through one labeled leaf in
litellm.rust_bridge.leaves. Delivery follows the family: request and sync
failure run inline, deployment hooks and async failure are awaited by
drive(), sync success runs as one grouped WorkerJob on the executor, async
success is a coroutine enqueued on the logging worker with the deferred gate
held natively in DeferredSuccess.
PrepareLogging (cost, standard payload, redaction) runs inside the dispatch
delivery and never fails the request; Finalize keeps only public response
metadata. Dedup markers stay on the shared logging object and are read as
an eligibility fact. Caller-supplied Logging instances take a separate
compat path that calls their own handlers.
Tests prove the two-pass hook order, per-target hook containment, hook
result replacement, marker write and honour, best-effort preparation, and a
positive run with every legacy orchestration entry point patched to raise.
Native OCR setup no longer calls utils.function_setup. The bridge reads
registration facts (coroutine-ness, CustomLogger, known names, existing list
membership) and core's plan_registration decides every public registry
mutation, which the bridge writes back through litellm.rust_bridge.setup.
The Logging object is built by a narrow Python factory with the same
constructor arguments. Caller-supplied Logging instances keep identity and
skip registration.
A differential test asserts registry side effects equal function_setup for
nine registration shapes; mutating the planner fails four of them.
Adds CallbackId, Delivery, CallbackInvocation, CallbackFamily, LoggedMarker,
DispatchCursor, plan_success and plan_failure to call_lifecycle. Core now
owns target ordering, get_combined_callback_list dedup, the two-pass success
shape, marker placement, per-family delivery and error policy, and the
sync/async success dispatch plan. No host wiring yet.
The request crossed the boundary four times: Python bind_request into a
dataclass, Rust re-reading each field back with its own precedence rules,
a BridgeOcrRequest copy, then the core request. The dataclass was retained
for the whole call only so map_failure could read model and kwargs at the
end.
Add a route-agnostic Signature binder that reproduces Python's positional
and keyword binding rules and TypeError messages, and project straight
from the bound arguments into the core request. This removes the Python
LiteLLMOcrRequest dataclass, bind_request, PythonOcrInput, BridgeOcrRequest,
and the retained boundary_request, document, api_key and callback_inputs
Python objects. api_key for pre_call now comes from core's resolved
connection, matching the legacy handler, and core no longer carries
retained_fields or retains_document since the bridge stopped re-aliasing.
The bridge kept a Rust-side shadow of Logging's callback registries and
elided pre_call/post_call/success_handler when it thought nothing was
listening. That forked the logging contract and hid a bug: with callbacks
present, the during-call hook re-inserted the caller's original document
and unmapped optional params over the provider-transformed body.
Call the real Logging handlers unconditionally, like the Python wrapper
does, and hand callbacks a fresh dict built from core's composed body
instead of re-aliasing caller objects into it.