diff --git a/src/providers/deepseek.rs b/src/providers/deepseek.rs index 207f3f53..7028b6ba 100644 --- a/src/providers/deepseek.rs +++ b/src/providers/deepseek.rs @@ -77,10 +77,12 @@ impl super::Provider for DeepSeekProvider { for m in messages { if m["role"] == "assistant" && m.get("tool_calls").is_some() { if m.get("reasoning_content").is_none() || m["reasoning_content"].is_null() { - // DeepSeek R1 requires reasoning_content for tool calls in history. - // If missing (e.g. from client or other model), inject a placeholder. m["reasoning_content"] = serde_json::json!("Thinking..."); } + // DeepSeek R1 often requires content to be a string, not null + if m.get("content").is_none() || m["content"].is_null() { + m["content"] = serde_json::json!(""); + } } } } @@ -100,6 +102,7 @@ impl super::Provider for DeepSeekProvider { let status = response.status(); let error_text = response.text().await.unwrap_or_default(); tracing::error!("DeepSeek API error ({}): {}", status, error_text); + tracing::debug!("DeepSeek Request Body: {}", serde_json::to_string(&body).unwrap_or_default()); return Err(AppError::ProviderError(format!("DeepSeek API error ({}): {}", status, error_text))); } @@ -164,6 +167,10 @@ impl super::Provider for DeepSeekProvider { if m.get("reasoning_content").is_none() || m["reasoning_content"].is_null() { m["reasoning_content"] = serde_json::json!("Thinking..."); } + // DeepSeek R1 often requires content to be a string, not null + if m.get("content").is_none() || m["content"].is_null() { + m["content"] = serde_json::json!(""); + } } } } @@ -218,9 +225,11 @@ impl super::Provider for DeepSeekProvider { match probe_resp { Ok(r) if !r.status().is_success() => { let status = r.status(); - let body = r.text().await.unwrap_or_default(); - tracing::error!("DeepSeek Stream Error Probe ({}): {}", status, body); - Err(AppError::ProviderError(format!("DeepSeek API error ({}): {}", status, body)))?; + let error_body = r.text().await.unwrap_or_default(); + tracing::error!("DeepSeek Stream Error Probe ({}): {}", status, error_body); + // Log the offending request body at debug level (it's large) + tracing::debug!("Offending DeepSeek Request Body: {}", serde_json::to_string(&probe_body).unwrap_or_default()); + Err(AppError::ProviderError(format!("DeepSeek API error ({}): {}", status, error_body)))?; } _ => { Err(AppError::ProviderError(format!("Stream error: {}", e)))?; diff --git a/src/providers/helpers.rs b/src/providers/helpers.rs index 8e68b34e..86759389 100644 --- a/src/providers/helpers.rs +++ b/src/providers/helpers.rs @@ -65,10 +65,10 @@ pub async fn messages_to_openai_json(messages: &[UnifiedMessage]) -> Result