diff --git a/src/llm/model.rs b/src/llm/model.rs index c24c16459..3cc0b56c4 100644 --- a/src/llm/model.rs +++ b/src/llm/model.rs @@ -9,8 +9,8 @@ use crate::llm::routing::{ use futures::StreamExt as _; use rig::completion::{self, CompletionError, CompletionModel, CompletionRequest, GetTokenUsage}; use rig::message::{ - AssistantContent, DocumentSourceKind, Image, Message, MimeType, Text, ToolCall, ToolFunction, - UserContent, + AssistantContent, DocumentSourceKind, Image, Message, MimeType, ReasoningContent, Text, + ToolCall, ToolFunction, UserContent, }; use rig::one_or_many::OneOrMany; use rig::streaming::{RawStreamingChoice, RawStreamingToolCall, StreamingCompletionResponse}; @@ -1369,6 +1369,8 @@ fn convert_messages_to_openai(messages: &OneOrMany) -> Vec { let mut text_parts = Vec::new(); + let mut reasoning_parts = Vec::new(); + let mut saw_reasoning = false; let mut tool_calls = Vec::new(); for item in content.iter() { @@ -1376,6 +1378,10 @@ fn convert_messages_to_openai(messages: &OneOrMany) -> Vec { text_parts.push(t.text.clone()); } + AssistantContent::Reasoning(reasoning) => { + saw_reasoning = true; + reasoning_parts.extend(collect_reasoning_text_parts(reasoning)); + } AssistantContent::ToolCall(tc) => { // OpenAI expects arguments as a JSON string. // Prefer call_id (set when replaying Responses-API tool calls @@ -1403,6 +1409,11 @@ fn convert_messages_to_openai(messages: &OneOrMany) -> Vec) -> Vec Vec { + reasoning + .content + .iter() + .filter_map(|content| match content { + ReasoningContent::Text { text, .. } => (!text.trim().is_empty()).then(|| text.clone()), + ReasoningContent::Summary(summary) => { + (!summary.trim().is_empty()).then(|| summary.clone()) + } + ReasoningContent::Encrypted(_) | ReasoningContent::Redacted { .. } => None, + #[allow(unreachable_patterns)] + _ => None, + }) + .collect() +} + fn convert_messages_to_openai_responses(messages: &OneOrMany) -> Vec { let mut result = Vec::new(); @@ -1461,6 +1488,9 @@ fn convert_messages_to_openai_responses(messages: &OneOrMany) -> Vec { let mut text_parts = Vec::new(); + let mut reasoning_parts = Vec::new(); + let mut saw_reasoning = false; + let mut function_calls = Vec::new(); for item in content.iter() { match item { @@ -1470,6 +1500,10 @@ fn convert_messages_to_openai_responses(messages: &OneOrMany) -> Vec { + saw_reasoning = true; + reasoning_parts.extend(collect_reasoning_text_parts(reasoning)); + } AssistantContent::ToolCall(tool_call) => { let arguments = serde_json::to_string(&tool_call.function.arguments) .unwrap_or_else(|_| "{}".to_string()); @@ -1478,7 +1512,7 @@ fn convert_messages_to_openai_responses(messages: &OneOrMany) -> Vec) -> Vec