diff --git a/apps/aether-gateway/src/execution_runtime/transport.rs b/apps/aether-gateway/src/execution_runtime/transport.rs index 5cfeb3cf4..c5c52ae26 100644 --- a/apps/aether-gateway/src/execution_runtime/transport.rs +++ b/apps/aether-gateway/src/execution_runtime/transport.rs @@ -9737,7 +9737,10 @@ mod tests { headers: BTreeMap::from([("content-type".into(), "application/json".into())]), content_type: Some("application/json".into()), content_encoding: Some(encoding.into()), - body: RequestBody::from_json(json!({"model": "gpt-4.1"})), + body: RequestBody::from_json(json!({ + "model": "gpt-4.1", + "service_tier": "ultrafast" + })), stream: false, client_api_format: "openai:chat".into(), provider_api_format: "openai:chat".into(), @@ -9758,7 +9761,7 @@ mod tests { result.body.and_then(|body| body.json_body), Some(json!({ "content_encoding": encoding, - "body": {"model": "gpt-4.1"}, + "body": {"model": "gpt-4.1", "service_tier": "ultrafast"}, })) ); } diff --git a/apps/aether-gateway/src/tests/ai_execute/stream_cli/direct.rs b/apps/aether-gateway/src/tests/ai_execute/stream_cli/direct.rs index 8ad2bb958..f4224aced 100644 --- a/apps/aether-gateway/src/tests/ai_execute/stream_cli/direct.rs +++ b/apps/aether-gateway/src/tests/ai_execute/stream_cli/direct.rs @@ -38,6 +38,7 @@ async fn gateway_executes_codex_cli_stream_via_local_decision_gate_after_oauth_r trace_id: String, url: String, model: String, + service_tier: String, content_encoding: String, stream: bool, accept: String, @@ -383,6 +384,13 @@ async fn gateway_executes_codex_cli_stream_via_local_decision_gate_after_oauth_r .and_then(|value| value.as_str()) .unwrap_or_default() .to_string(), + service_tier: payload + .get("body") + .and_then(|value| value.get("json_body")) + .and_then(|value| value.get("service_tier")) + .and_then(|value| value.as_str()) + .unwrap_or_default() + .to_string(), content_encoding: payload .get("content_encoding") .and_then(|value| value.as_str()) @@ -605,7 +613,7 @@ async fn gateway_executes_codex_cli_stream_via_local_decision_gate_after_oauth_r ) .header(TRACE_ID_HEADER, "trace-codex-cli-stream-local-123") .body( - r#"{"model":"gpt-5.6-sol","instructions":"Use the configured tools.","input":[{"type":"message","role":"user","content":[{"type":"input_text","text":"compact"}]},{"type":"compaction_trigger"}],"tools":[{"type":"function","name":"lookup","parameters":{"type":"object"}}],"context_management":[{"type":"compaction","compact_threshold":128000}],"parallel_tool_calls":true,"prompt_cache_key":"thread-codex-stream-local-123","client_metadata":{"session_id":"session-codex-stream-local-123","thread_id":"thread-codex-stream-local-123"},"stream":true}"#, + r#"{"model":"gpt-5.6-sol","service_tier":"ultrafast","instructions":"Use the configured tools.","input":[{"type":"message","role":"user","content":[{"type":"input_text","text":"compact"}]},{"type":"compaction_trigger"}],"tools":[{"type":"function","name":"lookup","parameters":{"type":"object"}}],"context_management":[{"type":"compaction","compact_threshold":128000}],"parallel_tool_calls":true,"prompt_cache_key":"thread-codex-stream-local-123","client_metadata":{"session_id":"session-codex-stream-local-123","thread_id":"thread-codex-stream-local-123"},"stream":true}"#, ) .send() .await @@ -716,6 +724,7 @@ async fn gateway_executes_codex_cli_stream_via_local_decision_gate_after_oauth_r "https://chatgpt.com/backend-api/codex/responses" ); assert_eq!(seen_execution_runtime_request.model, "gpt-5.6-sol"); + assert_eq!(seen_execution_runtime_request.service_tier, "ultrafast"); assert_eq!(seen_execution_runtime_request.content_encoding, "zstd"); assert!(seen_execution_runtime_request.stream); assert_eq!(seen_execution_runtime_request.accept, "text/event-stream"); diff --git a/crates/aether-ai/formats/src/formats/openai/request_contract.rs b/crates/aether-ai/formats/src/formats/openai/request_contract.rs index 771f8a184..8805cd279 100644 --- a/crates/aether-ai/formats/src/formats/openai/request_contract.rs +++ b/crates/aether-ai/formats/src/formats/openai/request_contract.rs @@ -229,7 +229,7 @@ fn validate_final_openai_provider_request_contract( #[cfg(test)] mod tests { - use serde_json::json; + use serde_json::{json, Value}; use super::{ finalize_openai_provider_request, @@ -587,6 +587,61 @@ mod tests { } } + #[test] + fn codex_finalization_preserves_explicit_service_tiers() { + let capabilities = CodexResponsesModelCapabilities { + use_responses_lite: false, + supports_reasoning_summary_parameter: false, + default_reasoning_effort: None, + default_reasoning_summary: None, + supported_reasoning_efforts: Vec::new(), + supports_parallel_tool_calls: true, + support_verbosity: false, + default_verbosity: None, + supported_service_tiers: vec!["priority".to_string()], + }; + for source_api_format in ["openai:responses", "openai:chat"] { + for provider_api_format in ["openai:responses", "openai:responses:compact"] { + for model_capabilities in [None, Some(&capabilities)] { + for service_tier in [ + Some("ultrafast"), + Some("priority"), + Some("default"), + Some("auto"), + Some("flex"), + Some("future-tier"), + None, + ] { + let mut body = json!({"model": "gpt-5.6-sol", "input": []}); + if let Some(service_tier) = service_tier { + body["service_tier"] = json!(service_tier); + } + finalize_openai_provider_request_with_codex_model_capabilities( + &mut body, + OpenAiProviderRequestFinalization { + source_api_format, + provider_api_format, + provider_type: "codex", + provider_model: "gpt-5.6-sol", + source_model: "gpt-5.6-sol", + body_rules: None, + upstream_is_stream: true, + require_body_stream_field: true, + }, + model_capabilities, + ) + .expect("explicit service tiers should be validated by the upstream"); + assert_eq!( + body.get("service_tier").and_then(Value::as_str), + service_tier, + "{source_api_format} -> {provider_api_format}", + ); + } + } + } + } + } + #[test] fn dynamic_codex_card_preserves_default_effort_and_keeps_mode_model_specific() { let finalization = OpenAiProviderRequestFinalization { diff --git a/crates/aether-ai/formats/src/formats/openai/responses/codex.rs b/crates/aether-ai/formats/src/formats/openai/responses/codex.rs index 919b7f659..9af15f2d5 100644 --- a/crates/aether-ai/formats/src/formats/openai/responses/codex.rs +++ b/crates/aether-ai/formats/src/formats/openai/responses/codex.rs @@ -91,12 +91,6 @@ impl CodexResponsesModelCapabilities { .iter() .any(|candidate| candidate == effort.trim()) } - - fn supports_service_tier(&self, service_tier: &str) -> bool { - self.supported_service_tiers - .iter() - .any(|candidate| candidate == service_tier) - } } fn codex_namespaced_model_suffix(model: &str) -> Option<&str> { @@ -1214,18 +1208,6 @@ fn apply_codex_model_request_capabilities( } } } - - if !body_rules_handle_path(body_rules, "service_tier") { - let service_tier = body_object - .get("service_tier") - .and_then(Value::as_str) - .map(str::to_string); - if !service_tier.as_deref().is_some_and(|service_tier| { - service_tier != "default" && capabilities.supports_service_tier(service_tier) - }) { - body_object.remove("service_tier"); - } - } } fn ensure_codex_reasoning_defaults( @@ -2654,7 +2636,7 @@ mod tests { assert_eq!(body["reasoning"]["effort"], "high"); assert_eq!(body["include"], json!(["reasoning.encrypted_content"])); assert_eq!(body["parallel_tool_calls"], false); - assert!(body.get("service_tier").is_none()); + assert_eq!(body["service_tier"], "priority"); assert!(body["text"].get("verbosity").is_none()); assert_eq!(body["text"]["format"]["type"], "json_schema"); diff --git a/frontend/src/features/usage/components/UsageModelDisplay.vue b/frontend/src/features/usage/components/UsageModelDisplay.vue index 123d3094f..7c316b5dd 100644 --- a/frontend/src/features/usage/components/UsageModelDisplay.vue +++ b/frontend/src/features/usage/components/UsageModelDisplay.vue @@ -8,8 +8,8 @@ : undefined" >