diff --git a/src/protocols/spec.rs b/src/protocols/spec.rs index 3ed54dc8..30d5fb97 100644 --- a/src/protocols/spec.rs +++ b/src/protocols/spec.rs @@ -517,7 +517,7 @@ pub struct ChatCompletionRequest { #[serde(skip_serializing_if = "Option::is_none")] pub echo: Option, - /// Reasoning effort level for reasoning models (low, medium, high) + /// Reasoning effort level supported by OpenAI-compatible vLLM servers. #[serde(skip_serializing_if = "Option::is_none")] pub reasoning_effort: Option, @@ -855,9 +855,14 @@ fn default_reasoning_effort() -> Option { #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum ReasoningEffort { + None, + Minimal, Low, Medium, High, + #[serde(rename = "xhigh")] + XHigh, + Max, } // ============= Input/Output Items ============= diff --git a/tests/test_openai_routing.rs b/tests/test_openai_routing.rs index f8c2b9e9..d9b7424f 100644 --- a/tests/test_openai_routing.rs +++ b/tests/test_openai_routing.rs @@ -471,3 +471,24 @@ async fn test_openai_router_chat_with_reasoning_fields() { // Verify it's a valid chat completion response assert_eq!(chat_response["object"], "chat.completion"); } + +#[test] +fn reasoning_effort_accepts_current_vllm_values() { + for value in ["none", "minimal", "low", "medium", "high", "xhigh", "max"] { + let request: vllm_router_rs::protocols::spec::ChatCompletionRequest = + serde_json::from_value(serde_json::json!({ + "model": "test-model", + "messages": [{"role": "user", "content": "hello"}], + "reasoning_effort": value + })) + .unwrap(); + assert_eq!( + serde_json::to_value(request).unwrap()["reasoning_effort"], + value + ); + + let reasoning: vllm_router_rs::protocols::spec::ResponseReasoningParam = + serde_json::from_value(serde_json::json!({"effort": value})).unwrap(); + assert_eq!(serde_json::to_value(reasoning).unwrap()["effort"], value); + } +}