fix(deepseek): even stricter R1 history compliance and error logging
- Ensure ALL assistant messages in history have reasoning_content and string content. - Use a single space as a professional minimal placeholder for missing reasoning. - Log full offending request bodies at ERROR level for detailed debugging.
This commit is contained in:
@@ -72,15 +72,16 @@ impl super::Provider for DeepSeekProvider {
|
|||||||
obj.remove("logprobs");
|
obj.remove("logprobs");
|
||||||
obj.remove("top_logprobs");
|
obj.remove("top_logprobs");
|
||||||
|
|
||||||
// ENSURE: assistant messages with tool_calls must have reasoning_content
|
// ENSURE: EVERY assistant message must have reasoning_content and valid content
|
||||||
if let Some(messages) = obj.get_mut("messages").and_then(|m| m.as_array_mut()) {
|
if let Some(messages) = obj.get_mut("messages").and_then(|m| m.as_array_mut()) {
|
||||||
for m in messages {
|
for m in messages {
|
||||||
if m["role"] == "assistant" && m.get("tool_calls").is_some() {
|
if m["role"].as_str() == Some("assistant") {
|
||||||
|
// DeepSeek R1 requires reasoning_content for consistency in history.
|
||||||
if m.get("reasoning_content").is_none() || m["reasoning_content"].is_null() {
|
if m.get("reasoning_content").is_none() || m["reasoning_content"].is_null() {
|
||||||
m["reasoning_content"] = serde_json::json!("Thinking...");
|
m["reasoning_content"] = serde_json::json!(" ");
|
||||||
}
|
}
|
||||||
// DeepSeek R1 often requires content to be a string, not null
|
// DeepSeek R1 often requires content to be a string, not null/array
|
||||||
if m.get("content").is_none() || m["content"].is_null() {
|
if m.get("content").is_none() || m["content"].is_null() || m["content"].is_array() {
|
||||||
m["content"] = serde_json::json!("");
|
m["content"] = serde_json::json!("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,7 +103,7 @@ impl super::Provider for DeepSeekProvider {
|
|||||||
let status = response.status();
|
let status = response.status();
|
||||||
let error_text = response.text().await.unwrap_or_default();
|
let error_text = response.text().await.unwrap_or_default();
|
||||||
tracing::error!("DeepSeek API error ({}): {}", status, error_text);
|
tracing::error!("DeepSeek API error ({}): {}", status, error_text);
|
||||||
tracing::debug!("DeepSeek Request Body: {}", serde_json::to_string(&body).unwrap_or_default());
|
tracing::error!("Offending DeepSeek Request Body: {}", serde_json::to_string(&body).unwrap_or_default());
|
||||||
return Err(AppError::ProviderError(format!("DeepSeek API error ({}): {}", status, error_text)));
|
return Err(AppError::ProviderError(format!("DeepSeek API error ({}): {}", status, error_text)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,15 +161,16 @@ impl super::Provider for DeepSeekProvider {
|
|||||||
obj.remove("logprobs");
|
obj.remove("logprobs");
|
||||||
obj.remove("top_logprobs");
|
obj.remove("top_logprobs");
|
||||||
|
|
||||||
// ENSURE: assistant messages with tool_calls must have reasoning_content
|
// ENSURE: EVERY assistant message must have reasoning_content and valid content
|
||||||
if let Some(messages) = obj.get_mut("messages").and_then(|m| m.as_array_mut()) {
|
if let Some(messages) = obj.get_mut("messages").and_then(|m| m.as_array_mut()) {
|
||||||
for m in messages {
|
for m in messages {
|
||||||
if m["role"] == "assistant" && m.get("tool_calls").is_some() {
|
if m["role"].as_str() == Some("assistant") {
|
||||||
|
// DeepSeek R1 requires reasoning_content for consistency in history.
|
||||||
if m.get("reasoning_content").is_none() || m["reasoning_content"].is_null() {
|
if m.get("reasoning_content").is_none() || m["reasoning_content"].is_null() {
|
||||||
m["reasoning_content"] = serde_json::json!("Thinking...");
|
m["reasoning_content"] = serde_json::json!(" ");
|
||||||
}
|
}
|
||||||
// DeepSeek R1 often requires content to be a string, not null
|
// DeepSeek R1 often requires content to be a string, not null/array
|
||||||
if m.get("content").is_none() || m["content"].is_null() {
|
if m.get("content").is_none() || m["content"].is_null() || m["content"].is_array() {
|
||||||
m["content"] = serde_json::json!("");
|
m["content"] = serde_json::json!("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,8 +229,8 @@ impl super::Provider for DeepSeekProvider {
|
|||||||
let status = r.status();
|
let status = r.status();
|
||||||
let error_body = r.text().await.unwrap_or_default();
|
let error_body = r.text().await.unwrap_or_default();
|
||||||
tracing::error!("DeepSeek Stream Error Probe ({}): {}", status, error_body);
|
tracing::error!("DeepSeek Stream Error Probe ({}): {}", status, error_body);
|
||||||
// Log the offending request body at debug level (it's large)
|
// Log the offending request body at ERROR level so it shows up in standard logs
|
||||||
tracing::debug!("Offending DeepSeek Request Body: {}", serde_json::to_string(&probe_body).unwrap_or_default());
|
tracing::error!("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!("DeepSeek API error ({}): {}", status, error_body)))?;
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user