diff --git a/lib/crates/fabro-llm/src/cli.rs b/lib/crates/fabro-llm/src/cli.rs index ffd605bdc..edb435f7f 100644 --- a/lib/crates/fabro-llm/src/cli.rs +++ b/lib/crates/fabro-llm/src/cli.rs @@ -882,7 +882,10 @@ fn validate_deep_result( ) -> (cli_table::Color, String) { // Check tool use: need at least 2 steps (tool call + follow-up) if result.steps.len() < 2 { - return (Color::Red, "deep: fail (model did not call tool)".to_string()); + return ( + Color::Red, + "deep: fail (model did not call tool)".to_string(), + ); } // Check that step 0 had tool results (tool was executed) @@ -1042,11 +1045,8 @@ async fn test_one_model(info: &ModelInfo, deep: bool) -> (Color, String) { match build_deep_test_params(info) { None => (Color::Yellow, "deep: skipped (no tool support)".to_string()), Some(params) => { - let result = tokio::time::timeout( - Duration::from_secs(90), - generate::generate(params), - ) - .await; + let result = + tokio::time::timeout(Duration::from_secs(90), generate::generate(params)).await; match result { Ok(Ok(ref gen_result)) => validate_deep_result(gen_result, info), Ok(Err(e)) => (Color::Red, format!("deep: error: {e}")), @@ -1094,16 +1094,15 @@ async fn test_models( let test_kind = if deep { "Deep testing" } else { "Testing" }; let pb = indicatif::ProgressBar::new(models_to_test.len() as u64); pb.set_style( - indicatif::ProgressStyle::with_template( - &format!("{{spinner:.green}} {test_kind} {{pos}}/{{len}} models {{wide_bar}} {{eta}}"), - ) + indicatif::ProgressStyle::with_template(&format!( + "{{spinner:.green}} {test_kind} {{pos}}/{{len}} models {{wide_bar}} {{eta}}" + )) .unwrap(), ); pb.enable_steady_tick(Duration::from_millis(100)); // Build (original_index, model_info) pairs, then shuffle for provider spread - let mut indexed: Vec<(usize, &ModelInfo)> = - models_to_test.iter().enumerate().collect(); + let mut indexed: Vec<(usize, &ModelInfo)> = models_to_test.iter().enumerate().collect(); indexed.shuffle(&mut rand::thread_rng()); // Run tests concurrently, 6 at a time diff --git a/lib/crates/fabro-llm/src/providers/openai.rs b/lib/crates/fabro-llm/src/providers/openai.rs index ff1eb60e2..95c5bffad 100644 --- a/lib/crates/fabro-llm/src/providers/openai.rs +++ b/lib/crates/fabro-llm/src/providers/openai.rs @@ -138,6 +138,8 @@ struct ApiRequest { #[serde(skip_serializing_if = "Option::is_none")] metadata: Option>, store: bool, + #[serde(skip_serializing_if = "Vec::is_empty")] + include: Vec, #[serde(skip_serializing_if = "std::ops::Not::not")] stream: bool, } @@ -391,6 +393,12 @@ fn build_api_request(request: &Request, stream: bool, codex_mode: bool) -> ApiRe .as_ref() .and_then(translate_response_format); + let include = if reasoning.is_some() { + vec!["reasoning.encrypted_content".to_string()] + } else { + Vec::new() + }; + let instructions = if codex_mode { Some(instructions.unwrap_or_default()) } else { @@ -414,7 +422,12 @@ fn build_api_request(request: &Request, stream: bool, codex_mode: bool) -> ApiRe text, stop: request.stop_sequences.clone(), metadata: request.metadata.clone(), - store: true, + // store: false is required for non-Azure OpenAI endpoints. Reasoning + // items still round-trip correctly because we request encrypted_content + // via the `include` field, which embeds them in the response payload + // rather than relying on server-side storage. + store: false, + include, stream, } }