From ed5d722f418b117c5d65a4f44d0e453259ebe6aa Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sun, 12 Jul 2026 08:33:15 -0700 Subject: [PATCH 1/4] bump --- crates/braintrust-llm-router/src/router.rs | 3 ++- crates/braintrust-llm-router/tests/router.rs | 6 +++--- crates/lingua/src/processing/transform.rs | 20 ++++++++------------ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/crates/braintrust-llm-router/src/router.rs b/crates/braintrust-llm-router/src/router.rs index 95aaeeee..d30af84e 100644 --- a/crates/braintrust-llm-router/src/router.rs +++ b/crates/braintrust-llm-router/src/router.rs @@ -829,7 +829,8 @@ impl Router { Error::NoProvider(catalog_format) })?; let provider_formats = provider.provider_formats(); - let format = if provider_formats.contains(&ProviderFormat::Responses) + let format = if output_format == ProviderFormat::ChatCompletions + && provider_formats.contains(&ProviderFormat::Responses) && spec.requires_responses_api() { ProviderFormat::Responses diff --git a/crates/braintrust-llm-router/tests/router.rs b/crates/braintrust-llm-router/tests/router.rs index 9cd46ac3..cd1af4a8 100644 --- a/crates/braintrust-llm-router/tests/router.rs +++ b/crates/braintrust-llm-router/tests/router.rs @@ -885,7 +885,7 @@ async fn reasoning_effort_with_tools_upgrades_format_to_responses() { } #[tokio::test] -async fn responses_required_model_uses_responses_for_anthropic_messages_output() { +async fn responses_required_model_does_not_force_responses_for_anthropic_messages_output() { let mut catalog = ModelCatalog::empty(); catalog.insert( "gpt-5.5".into(), @@ -931,8 +931,8 @@ async fn responses_required_model_uses_responses_for_anthropic_messages_output() ); assert_eq!( metadata.provider_format, - ProviderFormat::Responses, - "gpt-5.5 should use Responses transport even when the caller uses /v1/messages" + ProviderFormat::ChatCompletions, + "Responses transport override should only apply to chat completions output" ); } diff --git a/crates/lingua/src/processing/transform.rs b/crates/lingua/src/processing/transform.rs index 7d09912e..0c840726 100644 --- a/crates/lingua/src/processing/transform.rs +++ b/crates/lingua/src/processing/transform.rs @@ -868,10 +868,7 @@ fn request_model_needs_forced_translation( override_model: Option<&str>, target: ProviderFormat, ) -> bool { - if !matches!( - target, - ProviderFormat::ChatCompletions | ProviderFormat::Responses - ) { + if target != ProviderFormat::ChatCompletions { return false; } @@ -883,8 +880,7 @@ fn request_model_needs_forced_translation( return true; } - target == ProviderFormat::ChatCompletions - && request_model.is_some_and(is_models_prefixed_gemini_model) + request_model.is_some_and(is_models_prefixed_gemini_model) && override_model.is_some_and(is_bare_gemini_model) } @@ -2126,7 +2122,7 @@ mod tests { #[test] #[cfg(feature = "openai")] - fn test_reasoning_responses_model_forces_translation() { + fn test_reasoning_responses_model_passthrough() { let payload = json!({ "model": "gpt-5.1-mini", "input": [{"role": "user", "content": "Hello"}], @@ -2137,12 +2133,12 @@ mod tests { let result = transform_request(input, ProviderFormat::Responses, None).unwrap(); assert!( - !result.is_passthrough(), - "Reasoning Responses models should force translation" + result.is_passthrough(), + "Responses requests should not force same-format translation" ); let output: Value = crate::serde_json::from_slice(result.as_bytes()).unwrap(); - assert!(output.get("top_p").is_none(), "Should not have top_p"); + assert_eq!(output.get("top_p").and_then(Value::as_f64), Some(0.9)); } #[test] @@ -2169,8 +2165,8 @@ mod tests { let result = transform_request(input, ProviderFormat::Responses, None).unwrap(); assert!( - !result.is_passthrough(), - "Reasoning Responses models should force translation" + result.is_passthrough(), + "Responses requests should not force same-format translation" ); let output: Value = crate::serde_json::from_slice(result.as_bytes()).unwrap(); From be73aabfc7eb61e64226e4ce827c3eb6f199bdb4 Mon Sep 17 00:00:00 2001 From: Ken Jiang Date: Mon, 13 Jul 2026 17:16:54 -0400 Subject: [PATCH 2/4] we should always upgrade to responses --- crates/braintrust-llm-router/src/router.rs | 3 +-- crates/braintrust-llm-router/tests/router.rs | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/braintrust-llm-router/src/router.rs b/crates/braintrust-llm-router/src/router.rs index d30af84e..95aaeeee 100644 --- a/crates/braintrust-llm-router/src/router.rs +++ b/crates/braintrust-llm-router/src/router.rs @@ -829,8 +829,7 @@ impl Router { Error::NoProvider(catalog_format) })?; let provider_formats = provider.provider_formats(); - let format = if output_format == ProviderFormat::ChatCompletions - && provider_formats.contains(&ProviderFormat::Responses) + let format = if provider_formats.contains(&ProviderFormat::Responses) && spec.requires_responses_api() { ProviderFormat::Responses diff --git a/crates/braintrust-llm-router/tests/router.rs b/crates/braintrust-llm-router/tests/router.rs index cd1af4a8..9cd46ac3 100644 --- a/crates/braintrust-llm-router/tests/router.rs +++ b/crates/braintrust-llm-router/tests/router.rs @@ -885,7 +885,7 @@ async fn reasoning_effort_with_tools_upgrades_format_to_responses() { } #[tokio::test] -async fn responses_required_model_does_not_force_responses_for_anthropic_messages_output() { +async fn responses_required_model_uses_responses_for_anthropic_messages_output() { let mut catalog = ModelCatalog::empty(); catalog.insert( "gpt-5.5".into(), @@ -931,8 +931,8 @@ async fn responses_required_model_does_not_force_responses_for_anthropic_message ); assert_eq!( metadata.provider_format, - ProviderFormat::ChatCompletions, - "Responses transport override should only apply to chat completions output" + ProviderFormat::Responses, + "gpt-5.5 should use Responses transport even when the caller uses /v1/messages" ); } From 2157b999f705aed49af2c4a566a9e94cb4151cdc Mon Sep 17 00:00:00 2001 From: Ken Jiang Date: Mon, 13 Jul 2026 17:27:13 -0400 Subject: [PATCH 3/4] add lingua_passthrough to router metadata --- crates/braintrust-llm-router/src/router.rs | 33 +++++++++++++++----- crates/braintrust-llm-router/tests/router.rs | 8 ++--- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/crates/braintrust-llm-router/src/router.rs b/crates/braintrust-llm-router/src/router.rs index 95aaeeee..d7daf31a 100644 --- a/crates/braintrust-llm-router/src/router.rs +++ b/crates/braintrust-llm-router/src/router.rs @@ -172,6 +172,9 @@ pub struct RouterMetadata { /// that was detected. pub detected_input_format: ProviderFormat, + /// Whether Lingua forwarded the request body without transforming it. + pub lingua_passthrough: bool, + /// The alias of the provider that was used to execute the request. pub provider_alias: String, @@ -228,22 +231,28 @@ async fn prepare_provider_request( format: ProviderFormat, stream: bool, options: RequestPreparationOptions, -) -> Result<(Bytes, Option, ProviderFormat)> { +) -> Result<(Bytes, Option, ProviderFormat, bool)> { if requires_bedrock_request_preparation(format) { let bytes = prepare_bedrock_request(body, spec, format).await?; - return Ok((bytes, Some(format), format)); + return Ok((bytes, Some(format), format, false)); } let model_override = options.rewrite_body_model.then_some(spec.model.as_str()); - let (transformed, detected_format, actual_format, maybe_rewrite_model) = + let (transformed, detected_format, actual_format, maybe_rewrite_model, lingua_passthrough) = match lingua::transform_request(body.clone(), format, model_override) { - Ok(TransformResult::PassThrough(bytes)) => (bytes, None, format, true), + Ok(TransformResult::PassThrough(bytes)) => (bytes, None, format, true, true), Ok(TransformResult::Transformed { bytes, source_format, actual_target_format, - }) => (bytes, Some(source_format), actual_target_format, false), - Err(TransformError::UnsupportedTargetFormat(_)) => (body, None, format, true), + }) => ( + bytes, + Some(source_format), + actual_target_format, + false, + false, + ), + Err(TransformError::UnsupportedTargetFormat(_)) => (body, None, format, true, false), Err(err) => return Err(err.into()), }; @@ -260,9 +269,15 @@ async fn prepare_provider_request( enable_streaming_payload(transformed, actual_format), detected_format, actual_format, + lingua_passthrough, )) } else { - Ok((transformed, detected_format, actual_format)) + Ok(( + transformed, + detected_format, + actual_format, + lingua_passthrough, + )) } } @@ -293,7 +308,7 @@ impl Router { stream: bool, options: RequestPreparationOptions, ) -> Result<(PreparedRequestInner, RouterMetadata)> { - let (payload, detected_format, actual_format) = + let (payload, detected_format, actual_format, lingua_passthrough) = prepare_provider_request(body, route.spec.as_ref(), route.format, stream, options) .await?; Ok(( @@ -308,6 +323,7 @@ impl Router { }, RouterMetadata { detected_input_format: detected_format.unwrap_or(route.format), + lingua_passthrough, provider_alias: route.provider_alias.clone(), provider_format: actual_format, }, @@ -1948,6 +1964,7 @@ mod tests { metadata.detected_input_format, ProviderFormat::ChatCompletions ); + assert!(!metadata.lingua_passthrough); assert_eq!(metadata.provider_format, ProviderFormat::Google); assert_eq!(request.inner.format, ProviderFormat::Google); assert_ne!(request.inner.payload, body); diff --git a/crates/braintrust-llm-router/tests/router.rs b/crates/braintrust-llm-router/tests/router.rs index 9cd46ac3..f160dc3d 100644 --- a/crates/braintrust-llm-router/tests/router.rs +++ b/crates/braintrust-llm-router/tests/router.rs @@ -152,10 +152,10 @@ async fn router_routes_to_stub_provider() { ] })); - let (request, _metadata) = - create_request(&router, body, model, ProviderFormat::ChatCompletions) - .await - .expect("create request"); + let (request, metadata) = create_request(&router, body, model, ProviderFormat::ChatCompletions) + .await + .expect("create request"); + assert!(metadata.lingua_passthrough); let bytes: Bytes = router .complete(request, &ClientHeaders::default()) .await From 6120782f2dae908ce304a4675fc2d5426e81fc07 Mon Sep 17 00:00:00 2001 From: Ken Jiang Date: Mon, 13 Jul 2026 17:35:09 -0400 Subject: [PATCH 4/4] fixxxx --- crates/braintrust-llm-router/src/router.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/braintrust-llm-router/src/router.rs b/crates/braintrust-llm-router/src/router.rs index d7daf31a..ad3914af 100644 --- a/crates/braintrust-llm-router/src/router.rs +++ b/crates/braintrust-llm-router/src/router.rs @@ -252,7 +252,7 @@ async fn prepare_provider_request( false, false, ), - Err(TransformError::UnsupportedTargetFormat(_)) => (body, None, format, true, false), + Err(TransformError::UnsupportedTargetFormat(_)) => (body, None, format, true, true), Err(err) => return Err(err.into()), }; @@ -1530,7 +1530,7 @@ mod tests { ); let spec = openai_spec("gpt-5-mini", ModelFlavor::Chat); - let (payload, _, _) = prepare_provider_request( + let (payload, _, _, _) = prepare_provider_request( body, &spec, ProviderFormat::ChatCompletions, @@ -1553,7 +1553,7 @@ mod tests { ); let spec = openai_spec("gpt-5-mini", ModelFlavor::Chat); - let (payload, _, _) = prepare_provider_request( + let (payload, _, _, _) = prepare_provider_request( body, &spec, ProviderFormat::ChatCompletions, @@ -1591,7 +1591,7 @@ mod tests { available_providers: vec!["vertex".to_string()], }; - let (payload, _, actual_format) = prepare_provider_request( + let (payload, _, actual_format, _) = prepare_provider_request( body, &spec, ProviderFormat::VertexAnthropic, @@ -1631,7 +1631,7 @@ mod tests { available_providers: vec!["google".to_string()], }; - let (payload, _, actual_format) = prepare_provider_request( + let (payload, _, actual_format, _) = prepare_provider_request( body, &spec, ProviderFormat::Google, @@ -1658,7 +1658,7 @@ mod tests { ); let spec = openai_spec("gpt-4o", ModelFlavor::Chat); - let (payload, _, actual_format) = prepare_provider_request( + let (payload, _, actual_format, _) = prepare_provider_request( body, &spec, ProviderFormat::ChatCompletions, @@ -1684,7 +1684,7 @@ mod tests { ); let spec = openai_spec("gpt-4o", ModelFlavor::Chat); - let (payload, _, actual_format) = prepare_provider_request( + let (payload, _, actual_format, _) = prepare_provider_request( body, &spec, ProviderFormat::ChatCompletions, @@ -1712,7 +1712,7 @@ mod tests { ); let spec = openai_spec("gpt-4o", ModelFlavor::Chat); - let (payload, detected_format, actual_format) = prepare_provider_request( + let (payload, detected_format, actual_format, _) = prepare_provider_request( body, &spec, ProviderFormat::ChatCompletions, @@ -1760,7 +1760,7 @@ mod tests { ); let spec = openai_spec("gpt-5.4-mini", ModelFlavor::Chat); - let (_, _, actual_format) = prepare_provider_request( + let (_, _, actual_format, _) = prepare_provider_request( body, &spec, ProviderFormat::ChatCompletions,