fix: support response parts with extra fields like thoughtSignature
Some checks failed
Rust / build (push) Has been cancelled
Some checks failed
Rust / build (push) Has been cancelled
Implement custom Deserialize for Part to tolerate additional response fields (such as thoughtSignature or thought) returned by thinking models.
This commit is contained in:
@@ -83,7 +83,7 @@ impl FromStr for Role {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum Part {
|
pub enum Part {
|
||||||
Text(String),
|
Text(String),
|
||||||
@@ -100,3 +100,66 @@ pub enum Part {
|
|||||||
args: HashMap<String, String>,
|
args: HashMap<String, String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct PartHelper {
|
||||||
|
text: Option<String>,
|
||||||
|
inline_data: Option<InlineDataHelper>,
|
||||||
|
file_data: Option<FileDataHelper>,
|
||||||
|
function_call: Option<FunctionCallHelper>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct InlineDataHelper {
|
||||||
|
mime_type: String,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct FileDataHelper {
|
||||||
|
mime_type: String,
|
||||||
|
file_uri: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct FunctionCallHelper {
|
||||||
|
name: String,
|
||||||
|
args: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Part {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let helper = PartHelper::deserialize(deserializer)?;
|
||||||
|
if let Some(text) = helper.text {
|
||||||
|
return Ok(Part::Text(text));
|
||||||
|
}
|
||||||
|
if let Some(inline_data) = helper.inline_data {
|
||||||
|
return Ok(Part::InlineData {
|
||||||
|
mime_type: inline_data.mime_type,
|
||||||
|
data: inline_data.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(file_data) = helper.file_data {
|
||||||
|
return Ok(Part::FileData {
|
||||||
|
mime_type: file_data.mime_type,
|
||||||
|
file_uri: file_data.file_uri,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(function_call) = helper.function_call {
|
||||||
|
return Ok(Part::FunctionCall {
|
||||||
|
name: function_call.name,
|
||||||
|
args: function_call.args,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(serde::de::Error::custom(
|
||||||
|
"Part does not contain any recognizable variant",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -531,4 +531,34 @@ mod tests {
|
|||||||
}"#;
|
}"#;
|
||||||
serde_json::from_str::<GenerateContentResponse>(input).unwrap();
|
serde_json::from_str::<GenerateContentResponse>(input).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_response_with_thought_signature() {
|
||||||
|
let input = r#"{
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"role": "model",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"text": "Hello world",
|
||||||
|
"thoughtSignature": "AY89a1+twFsQ+oYDReN5PU76yp0ciDinNh3MgyCbe/BLvyh93lje7qHOCJuNxaPULnqmgvKvtuQnjyf2wwD20Dl2rWnxbdZZAeqhRJEdvKOc4LQ="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"finishReason": "STOP"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"usageMetadata": {
|
||||||
|
"promptTokenCount": 877,
|
||||||
|
"candidatesTokenCount": 547,
|
||||||
|
"totalTokenCount": 1424,
|
||||||
|
"trafficType": "ON_DEMAND"
|
||||||
|
},
|
||||||
|
"modelVersion": "gemini-3.5-flash-lite",
|
||||||
|
"createTime": "2026-09-06T10:36:16.330983Z",
|
||||||
|
"responseId": "IEKdaueZFKyrz_IPp8Sc4QQ"
|
||||||
|
}"#;
|
||||||
|
serde_json::from_str::<GenerateContentResponse>(input).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user