feat: add MiMo reasoning_content support for Claude Code proxy (#2990)

* feat: add MiMo reasoning_content support for Claude Code proxy

MiMo requires reasoning_content to be passed back in multi-turn
conversations with tool calls. Add "mimo" and "xiaomimimo" to the
preserve_reasoning_content whitelist so thinking blocks are converted
to reasoning_content when proxying Claude Code → MiMo.

Also handle redacted_thinking blocks (encrypted by Claude Code across
turns) by injecting a placeholder to prevent MiMo 400 errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: support MiMo reasoning histories

- Fix the PR CI clippy failure for redacted thinking handling.
- Preserve MiMo reasoning content on the OpenAI Chat proxy path.
- Normalize Claude Desktop Anthropic thinking history for MiMo local routes.
- Reject unsupported Claude Desktop direct model remaps.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
zhangyapu1
2026-05-26 22:55:36 +08:00
committed by GitHub
parent 48473a5ca3
commit 707a5593e5
3 changed files with 333 additions and 1 deletions
@@ -438,6 +438,14 @@ fn convert_message_to_openai(
}
}
}
"redacted_thinking" if preserve_reasoning_content => {
// Claude Code encrypts historical thinking into redacted_thinking blocks.
// MiMo/DeepSeek require non-empty reasoning_content on assistant tool-call
// messages, so inject a minimal placeholder when the real content is
// unavailable. Skip when preserve_reasoning_content is off (generic
// OpenAI-compatible path).
reasoning_parts.push("[redacted thinking]".to_string());
}
_ => {}
}
}
@@ -950,6 +958,26 @@ mod tests {
assert_eq!(msg["tool_calls"][0]["id"], "call_123");
}
#[test]
fn test_anthropic_to_openai_tool_use_uses_redacted_thinking_placeholder() {
let input = json!({
"model": "mimo-v2.5-pro",
"max_tokens": 1024,
"messages": [{
"role": "assistant",
"content": [
{"type": "redacted_thinking", "data": "opaque"},
{"type": "tool_use", "id": "call_123", "name": "get_weather", "input": {"location": "Tokyo"}}
]
}]
});
let result = anthropic_to_openai_with_reasoning_content(input, true).unwrap();
let msg = &result["messages"][0];
assert_eq!(msg["reasoning_content"], "[redacted thinking]");
assert_eq!(msg["tool_calls"][0]["id"], "call_123");
}
#[test]
fn test_anthropic_to_openai_does_not_emit_reasoning_content_by_default() {
let input = json!({