mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-04 07:27:51 +00:00
* fix(vertex_ai): drop the caller's anthropic-version header on Claude /v1/messages Vertex reads the API version from the body's anthropic_version and answers 400 when a forwarded anthropic-version header names a different one, which anthropic SDK 2.x always does. Strip the header on the Python and LITELLM_RUST Vertex messages routes. * fix(vertex_ai): carry the caller's anthropic-version into the Claude /v1/messages body Vertex reads the API version from the body alone, so the caller's anthropic-version header now becomes the body's anthropic_version instead of a pinned vertex-2023-10-16. The 2023-01-01 and 2023-06-01 first-party versions keep vertex-2023-10-16, and the header itself is still never sent. Same change on the Python proxy and the Rust gateway. * fix(vertex_ai): follow drop_params for an anthropic-version Vertex does not accept Only versions Vertex accepts in the body (vertex-2023-10-16, 2026-10-21) are carried into anthropic_version. 2023-06-01, 2023-01-01, a blank header, or no header keep vertex-2023-10-16. Any other value drops to vertex-2023-10-16 under drop_params and answers a 400 naming drop_params without it, on the Python proxy and the Rust gateway. * refactor(vertex_ai): return the unsupported anthropic-version error as a value and keep Rust helpers and tests in place * fix(rust gateway): resolve os.environ drop_params and accept the same flag words as Python The gateway read drop_params: os.environ/NAME and words like yes as off, so the drop_params opt-out from the new anthropic-version 400 did not work there * docs(rust router): name Router::from_config in the crate README --------- Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
124 lines
4.3 KiB
Rust
124 lines
4.3 KiB
Rust
use std::time::Duration;
|
|
|
|
use litellm_config::Config;
|
|
use litellm_inference_messages::{MessagesSettings, MessagesShaping};
|
|
use litellm_router::{Deployment, Router};
|
|
use rstest::rstest;
|
|
|
|
#[rstest]
|
|
#[case::minimal("")]
|
|
#[case::configured(
|
|
"api_key: test-key\n api_base: https://provider.example/v1\n custom_llm_provider: test-provider"
|
|
)]
|
|
#[case::secret_reference("api_key: os.environ/ROUTER_TEST_API_KEY")]
|
|
fn configuration_preserves_deployment_parameters(#[case] parameters: &str) {
|
|
let config = Config::from_yaml(&format!(
|
|
"model_list:\n - model_name: public-model\n litellm_params:\n model: provider/model\n {parameters}"
|
|
))
|
|
.unwrap();
|
|
let router = Router::from_config(&config, &|_: &str| None);
|
|
let deployment = router.get(&config.model_list[0].model_name).unwrap();
|
|
let params = &config.model_list[0].litellm_params;
|
|
|
|
assert_eq!(deployment.model, params.model);
|
|
assert_eq!(
|
|
deployment.api_key.as_deref(),
|
|
params.api_key.as_ref().map(|key| key.expose())
|
|
);
|
|
assert_eq!(deployment.api_base, params.api_base);
|
|
assert_eq!(deployment.custom_llm_provider, params.custom_llm_provider);
|
|
assert_eq!(deployment.timeout, Deployment::default().timeout);
|
|
assert_eq!(deployment.shaping, Deployment::default().shaping);
|
|
assert_eq!(deployment.litellm_params, *params);
|
|
}
|
|
|
|
#[rstest]
|
|
fn configuration_types_the_provider_params_of_a_deployment() {
|
|
let config = Config::from_yaml(
|
|
"model_list:
|
|
- model_name: public-model
|
|
litellm_params:
|
|
model: bedrock/anthropic.claude-3
|
|
aws_region_name: eu-central-1
|
|
aws_bedrock_runtime_endpoint: https://runtime.example
|
|
azure_ad_token: ignored-by-every-group",
|
|
)
|
|
.unwrap();
|
|
let router = Router::from_config(&config, &|_: &str| None);
|
|
let params = &router.get("public-model").unwrap().litellm_params;
|
|
|
|
assert_eq!(
|
|
(
|
|
params.aws.aws_region_name.as_deref(),
|
|
params.aws.aws_bedrock_runtime_endpoint.as_deref(),
|
|
params.aws.aws_access_key_id.as_deref(),
|
|
),
|
|
(Some("eu-central-1"), Some("https://runtime.example"), None)
|
|
);
|
|
}
|
|
|
|
#[rstest]
|
|
#[case::first("public-a", Some("provider/a"))]
|
|
#[case::second("public-b", Some("provider/b"))]
|
|
#[case::unknown("missing", None)]
|
|
#[case::provider_name_is_not_an_alias("provider/a", None)]
|
|
#[case::case_sensitive("PUBLIC-A", None)]
|
|
fn lookup_uses_public_names(#[case] name: &str, #[case] expected: Option<&str>) {
|
|
let config = Config::from_yaml(
|
|
"model_list:
|
|
- model_name: public-a
|
|
litellm_params:
|
|
model: provider/a
|
|
- model_name: public-b
|
|
litellm_params:
|
|
model: provider/b",
|
|
)
|
|
.unwrap();
|
|
let router = Router::from_config(&config, &|_: &str| None);
|
|
|
|
assert_eq!(router.get(name).map(|entry| entry.model.as_str()), expected);
|
|
}
|
|
|
|
#[rstest]
|
|
fn empty_configuration_has_no_deployment() {
|
|
let config = Config::from_yaml("model_list: []").unwrap();
|
|
|
|
assert!(
|
|
Router::from_config(&config, &|_: &str| None)
|
|
.get("")
|
|
.is_none()
|
|
);
|
|
assert!(Router::default().get("unknown").is_none());
|
|
}
|
|
|
|
#[rstest]
|
|
fn programmatic_deployments_preserve_overrides_and_last_entry_wins() {
|
|
let deployment = Deployment {
|
|
model: "provider/selected".into(),
|
|
api_key: Some("test-key".into()),
|
|
api_base: Some("https://provider.example/v1".into()),
|
|
custom_llm_provider: Some("test-provider".into()),
|
|
litellm_params: Default::default(),
|
|
timeout: Some(Duration::from_secs(7)),
|
|
shaping: MessagesShaping {
|
|
settings: MessagesSettings {
|
|
drop_params: true,
|
|
additional_drop_params: vec!["metadata.test".into()],
|
|
..MessagesSettings::default()
|
|
},
|
|
..Default::default()
|
|
},
|
|
};
|
|
let router = Router::from_iter([
|
|
("public-model".into(), Deployment::default()),
|
|
("public-model".into(), deployment.clone()),
|
|
]);
|
|
let selected = router.get("public-model").unwrap();
|
|
|
|
assert_eq!(selected.model, deployment.model);
|
|
assert_eq!(selected.api_key, deployment.api_key);
|
|
assert_eq!(selected.api_base, deployment.api_base);
|
|
assert_eq!(selected.custom_llm_provider, deployment.custom_llm_provider);
|
|
assert_eq!(selected.timeout, deployment.timeout);
|
|
assert_eq!(selected.shaping, deployment.shaping);
|
|
}
|