fix(deepseek): more aggressive R1 fix and detailed error logging
Some checks failed
CI / Check (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Formatting (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Release Build (push) Has been cancelled

- Ensure assistant tool calls always have content: "" instead of null.
- Add debug-level logging of the full request body when DeepSeek returns 400.
- Improved R1 placeholder injection to include content sanitation.
This commit is contained in:
2026-03-05 19:11:46 +00:00
parent 1ddb5277e9
commit 6a324c08c7
2 changed files with 18 additions and 9 deletions

View File

@@ -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)))?;