From 0135253616ee98d0f6a6e52da7515ff89974630d Mon Sep 17 00:00:00 2001 From: Flavio martil Date: Sun, 2 Aug 2026 15:02:26 -0300 Subject: [PATCH] fix: tag kimi content parts so serde emits the type discriminant --- src/providers/kimi/translate/request.rs | 62 ++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/providers/kimi/translate/request.rs b/src/providers/kimi/translate/request.rs index 229baff..3beefcf 100644 --- a/src/providers/kimi/translate/request.rs +++ b/src/providers/kimi/translate/request.rs @@ -488,7 +488,7 @@ fn push_user_messages(out: &mut Vec, blocks: &[ContentBlock]) { } #[derive(Debug, Clone, Serialize)] -#[serde(untagged)] +#[serde(tag = "type", rename_all = "snake_case")] enum KimiUserContentPart { Text { text: String }, ImageUrl { image_url: KimiImageUrl }, @@ -552,7 +552,7 @@ fn tool_result_content(content: &Value, is_error: Option) -> Value { } #[derive(Debug, Clone, Serialize)] -#[serde(untagged)] +#[serde(tag = "type", rename_all = "snake_case")] enum KimiToolResultPart { Text { text: String }, ImageUrl { image_url: KimiImageUrl }, @@ -841,6 +841,64 @@ mod tests { } } + #[test] + fn user_content_parts_carry_a_type_discriminant() { + let req: MessagesRequest = serde_json::from_value(json!({ + "model": "kimi-for-coding", + "messages": [{ + "role": "user", + "content": [ + {"type": "text", "text": "describe this"}, + {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": "xyz"}} + ] + }] + })) + .unwrap(); + let translated = translate_request(&req, TranslateOptions { session_id: None }).unwrap(); + match &translated.messages[0] { + KimiMessage::User { content, .. } => { + let parts = content.as_array().unwrap(); + assert_eq!(parts[0].get("type").and_then(|v| v.as_str()), Some("text")); + assert_eq!( + parts[1].get("type").and_then(|v| v.as_str()), + Some("image_url") + ); + } + _ => panic!("expected User message"), + } + } + + #[test] + fn tool_result_parts_carry_a_type_discriminant() { + let req: MessagesRequest = serde_json::from_value(json!({ + "model": "kimi-for-coding", + "messages": [{ + "role": "user", + "content": [{ + "type": "tool_result", + "tool_use_id": "toolu_1", + "content": [ + {"type": "text", "text": "caption"}, + {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "abc"}} + ] + }] + }] + })) + .unwrap(); + let translated = translate_request(&req, TranslateOptions { session_id: None }).unwrap(); + match &translated.messages[0] { + KimiMessage::Tool { content, .. } => { + let parts = content.as_array().unwrap(); + assert_eq!(parts[0].get("type").and_then(|v| v.as_str()), Some("text")); + assert_eq!( + parts[1].get("type").and_then(|v| v.as_str()), + Some("image_url") + ); + } + _ => panic!("expected Tool message"), + } + } + #[test] fn translate_text_only_user_collapses_to_string() { let req: MessagesRequest = serde_json::from_value(json!({