mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-16 04:29:31 +00:00
refactor(rust-bridge): move the route host modules under host/routes (#46786)
* refactor(rust-bridge): move the route host modules under host/routes Each native route's Python half lived in its own `<route>/route_host.py`, apart from the shared host modules Rust also imports by name. They now sit together in `litellm/rust_bridge/host/routes/<route>.py`, with their unit tests moved to the mirrored path. No behavior change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(rust-host): reference messages route alias Co-Authored-By: yujonglee.dev@gmail.com <yujong@berri.ai> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
238597ed49
commit
55c8ec4647
16 changed files with 20 additions and 20 deletions
|
|
@ -23,7 +23,7 @@ fn run_chat_completions(
|
|||
) -> PyResult<Py<PyAny>> {
|
||||
let host = InferenceHost::new(
|
||||
call.view()?,
|
||||
"litellm.rust_bridge.chat_completions.route_host",
|
||||
"litellm.rust_bridge.host.routes.chat_completions",
|
||||
);
|
||||
run_inference::<ChatCompletionsRoute, _>(
|
||||
py,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use crate::{
|
|||
routes::RequestView,
|
||||
};
|
||||
|
||||
const ROUTE_HOST_MODULE: &str = "litellm.rust_bridge.messages.route_host";
|
||||
const ROUTE_HOST_MODULE: &str = "litellm.rust_bridge.host.routes.messages";
|
||||
const REQUEST_ERROR_MARKER: &str = "messages_request_error";
|
||||
|
||||
const BODY_FIELDS: [&str; 22] = [
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ impl OcrPythonHost {
|
|||
_ => "",
|
||||
};
|
||||
let mapped = py
|
||||
.import("litellm.rust_bridge.ocr.route_host")
|
||||
.import("litellm.rust_bridge.host.routes.ocr")
|
||||
.and_then(|module| module.getattr("map_failure"))
|
||||
.and_then(|map| map.call1((error.value(py), self.view.request(py)?, provider)))
|
||||
.and_then(|mapped| mapped.extract::<Py<PyBaseException>>().map_err(PyErr::from));
|
||||
|
|
@ -115,7 +115,7 @@ impl PythonBinding for OcrPythonHost {
|
|||
py: Python<'_>,
|
||||
response: LiteLLMOcrResponse,
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
public_response(py, "litellm.rust_bridge.ocr.route_host", &response)
|
||||
public_response(py, "litellm.rust_bridge.host.routes.ocr", &response)
|
||||
}
|
||||
|
||||
fn encode_stream_head(
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use super::{
|
|||
};
|
||||
use crate::errors::RustBridgeDeclined;
|
||||
|
||||
const ROUTE_HOST_MODULE: &str = "litellm.rust_bridge.responses.route_host";
|
||||
const ROUTE_HOST_MODULE: &str = "litellm.rust_bridge.host.routes.responses";
|
||||
|
||||
fn run_responses(py: Python<'_>, call: NativeCall<'_>, asynchronous: bool) -> PyResult<Py<PyAny>> {
|
||||
let resolved = call.resolved()?;
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@ Python state Rust needs but does not own, behind one module per question. Rust i
|
|||
- The module path and function signature are a contract. The Rust side pins the path in a `const MODULE` in the crate that asks (`python-bridge/src/routes/messages/host.rs`, `python-bridge/src/secrets/`, `callbacks-legacy-python/src/python.rs`); change both sides together and keep `tests/unit/rust_bridge/host/` green
|
||||
- Inputs and outputs use values and frozen snapshots. Retain caller-owned clients and caches as opaque references when identity is required; Rust never discovers them through module globals
|
||||
- Moving a question into Rust means replacing the function body with a native call, not adding a second resolver. The Python signature stays
|
||||
- A `*/route_host.py` module is not this: it projects one route's kwargs and maps that route's failures. Shared questions belong here
|
||||
- `routes/<route>.py` holds the questions one route asks, under the same function names on every route (`response`, `map_failure`, `connection_defaults`), so Rust names only the module. A question two routes ask goes in a top-level module here instead
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@ Call each path directly with an explicit decision instead. The Python path is th
|
|||
|
||||
Rollout policy itself, meaning which rule matches and what `LITELLM_RUST` changes, belongs in `test_catalog.py`, `test_configuration.py` and `test_dispatch.py`, tested against rules the test builds rather than the shipped `catalog.RULES`
|
||||
|
||||
Before adding a test here, ask whether it checks something Rust cannot. A `route_host.py` module is the Python half of a native route: it projects Python-only state (the cost map, `litellm.*` settings, request kwargs) into the plain values the Rust side consumes, and maps native failures back onto public exceptions. Those projections are what belongs here, because a wrong key or an ignored provider prefix ships the wrong value to Rust and no Rust test sees it. `messages/test_route_host.py` shows the shape. Behavior that lives in Rust (a request transform given its inputs, header assembly, stream relay) is tested in the crate, and the route end to end is tested against a recording server in `tests/test_litellm_rust/`. A test that only re-checks a Python helper the route host happens to call is a duplicate of that helper's own test and should not be added
|
||||
Before adding a test here, ask whether it checks something Rust cannot. A `host/routes/<route>.py` module is the Python half of a native route: it projects Python-only state (the cost map, `litellm.*` settings, request kwargs) into the plain values the Rust side consumes, and maps native failures back onto public exceptions. Those projections are what belongs here, because a wrong key or an ignored provider prefix ships the wrong value to Rust and no Rust test sees it. `host/routes/test_messages.py` shows the shape. Behavior that lives in Rust (a request transform given its inputs, header assembly, stream relay) is tested in the crate, and the route end to end is tested against a recording server in `tests/test_litellm_rust/`. A test that only re-checks a Python helper the route host happens to call is a duplicate of that helper's own test and should not be added
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from typing import Final
|
|||
import pytest
|
||||
|
||||
import litellm
|
||||
from litellm.rust_bridge.chat_completions.route_host import connection_defaults, response
|
||||
from litellm.rust_bridge.host.routes.chat_completions import connection_defaults, response
|
||||
from litellm.types.utils import ModelResponse
|
||||
|
||||
|
||||
|
|
@ -5,8 +5,8 @@ import pytest
|
|||
|
||||
import litellm
|
||||
from litellm.constants import DEFAULT_REQUEST_TIMEOUT_SECONDS
|
||||
from litellm.rust_bridge.messages import route_host
|
||||
from litellm.rust_bridge.messages.route_host import response
|
||||
from litellm.rust_bridge.host.routes import messages as messages_host
|
||||
from litellm.rust_bridge.host.routes.messages import response
|
||||
|
||||
|
||||
def test_response_is_a_detached_public_messages_dict() -> None:
|
||||
|
|
@ -36,7 +36,7 @@ def test_settings_project_caller_configuration_without_resolving_a_model(monkeyp
|
|||
monkeypatch.setattr(litellm, "request_timeout", 1800)
|
||||
monkeypatch.setattr(litellm, "request_timeout_explicitly_set", True)
|
||||
|
||||
projected: Final = route_host.settings({"drop_params": "true", "additional_drop_params": ["metadata.user_id"]})
|
||||
projected: Final = messages_host.settings({"drop_params": "true", "additional_drop_params": ["metadata.user_id"]})
|
||||
|
||||
assert projected == {
|
||||
"drop_params": True,
|
||||
|
|
@ -60,7 +60,7 @@ def test_request_timeout_carries_only_a_configured_global_timeout(
|
|||
monkeypatch.setattr(litellm, "request_timeout", timeout)
|
||||
monkeypatch.setattr(litellm, "request_timeout_explicitly_set", explicitly_set)
|
||||
|
||||
assert route_host.settings({})["request_timeout"] == expected
|
||||
assert messages_host.settings({})["request_timeout"] == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
@ -78,7 +78,7 @@ def test_drop_params_merges_the_global_flag_with_the_request(
|
|||
) -> None:
|
||||
monkeypatch.setattr(litellm, "drop_params", global_flag)
|
||||
|
||||
assert route_host.settings(kwargs)["drop_params"] is expected
|
||||
assert messages_host.settings(kwargs)["drop_params"] is expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
@ -90,7 +90,7 @@ def test_drop_params_merges_the_global_flag_with_the_request(
|
|||
],
|
||||
)
|
||||
def test_additional_drop_params_keep_only_string_paths(configured: object, expected: tuple[str, ...]) -> None:
|
||||
settings: Final = route_host.settings({"additional_drop_params": configured})
|
||||
settings: Final = messages_host.settings({"additional_drop_params": configured})
|
||||
|
||||
assert settings["additional_drop_params"] == expected
|
||||
|
||||
|
|
@ -117,19 +117,19 @@ def test_native_request_rejections_map_to_the_public_400() -> None:
|
|||
rejected: Final = ValueError("claude-sonnet-5 does not support top_k=5")
|
||||
rejected.messages_request_error = True # pyright: ignore[reportAttributeAccessIssue] # marker the native host sets
|
||||
|
||||
mapped: Final = route_host.map_failure(rejected, request.resolved, "anthropic")
|
||||
mapped: Final = messages_host.map_failure(rejected, request.resolved, "anthropic")
|
||||
|
||||
assert isinstance(mapped, litellm.BadRequestError)
|
||||
assert mapped.status_code == 400
|
||||
assert "does not support top_k=5" in mapped.message
|
||||
assert mapped.model == "claude-sonnet-5"
|
||||
assert not isinstance(
|
||||
route_host.map_failure(ValueError("plain"), request.resolved, "anthropic"), litellm.BadRequestError
|
||||
messages_host.map_failure(ValueError("plain"), request.resolved, "anthropic"), litellm.BadRequestError
|
||||
)
|
||||
|
||||
|
||||
def test_stream_hidden_params_projects_upstream_headers_the_way_the_python_handler_does() -> None:
|
||||
hidden: Final = route_host.stream_hidden_params(
|
||||
hidden: Final = messages_host.stream_hidden_params(
|
||||
(("request-id", "req_upstream_123"), ("x-ratelimit-remaining-requests", "41"))
|
||||
)
|
||||
|
||||
|
|
@ -3,8 +3,8 @@ from typing import Final
|
|||
import pytest
|
||||
|
||||
import litellm
|
||||
from litellm.rust_bridge.ocr.route_host import UpstreamFailure, map_failure
|
||||
from litellm.rust_bridge.ocr.route_host import response as build_ocr_response
|
||||
from litellm.rust_bridge.host.routes.ocr import UpstreamFailure, map_failure
|
||||
from litellm.rust_bridge.host.routes.ocr import response as build_ocr_response
|
||||
from litellm.rust_bridge.public_call import NativeCall
|
||||
|
||||
REQUEST: Final = NativeCall(
|
||||
|
|
@ -5,7 +5,7 @@ import pytest
|
|||
from pydantic import ValidationError
|
||||
|
||||
import litellm
|
||||
from litellm.rust_bridge.responses.route_host import connection_defaults, map_failure, response
|
||||
from litellm.rust_bridge.host.routes.responses import connection_defaults, map_failure, response
|
||||
from litellm.types.llms.openai import ResponsesAPIResponse
|
||||
|
||||
|
||||
Loading…
Add table
Reference in a new issue