fix(gemini): resolve 400 errors by strictly adhering to JSON schema
- Remove from as it is rejected by the API inside . - Ensure is always a JSON object (google.protobuf.Struct), wrapping non-object tool results in . - Update extraction logic to only look for in sibling fields.
This commit is contained in:
@@ -74,8 +74,6 @@ struct GeminiInlineData {
|
||||
struct GeminiFunctionCall {
|
||||
name: String,
|
||||
args: Value,
|
||||
#[serde(skip_serializing_if = "Option::is_none", rename = "thought_signature")]
|
||||
thought_signature: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -264,8 +262,15 @@ impl GeminiProvider {
|
||||
.unwrap_or_default();
|
||||
|
||||
let name = msg.name.clone().or_else(|| msg.tool_call_id.clone()).unwrap_or_else(|| "unknown_function".to_string());
|
||||
let response_value = serde_json::from_str::<Value>(&text_content)
|
||||
|
||||
// Gemini API requires 'response' to be a JSON object (google.protobuf.Struct).
|
||||
// If it is an array or primitive, wrap it in an object.
|
||||
let mut response_value = serde_json::from_str::<Value>(&text_content)
|
||||
.unwrap_or_else(|_| serde_json::json!({ "result": text_content }));
|
||||
|
||||
if !response_value.is_object() {
|
||||
response_value = serde_json::json!({ "result": response_value });
|
||||
}
|
||||
|
||||
parts.push(GeminiPart {
|
||||
text: None,
|
||||
@@ -328,7 +333,6 @@ impl GeminiProvider {
|
||||
function_call: Some(GeminiFunctionCall {
|
||||
name: tc.function.name.clone(),
|
||||
args,
|
||||
thought_signature: thought_signature.clone(),
|
||||
}),
|
||||
function_response: None,
|
||||
thought: None,
|
||||
@@ -537,10 +541,9 @@ impl GeminiProvider {
|
||||
.filter(|p| p.function_call.is_some())
|
||||
.map(|p| {
|
||||
let fc = p.function_call.as_ref().unwrap();
|
||||
// CAPTURE: Try extracting thought_signature from multiple possible locations
|
||||
// CAPTURE: Try extracting thought_signature from sibling fields
|
||||
let id = p.thought_signature_camel.clone()
|
||||
.or_else(|| p.thought_signature_snake.clone())
|
||||
.or_else(|| fc.thought_signature.clone())
|
||||
.unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple()));
|
||||
|
||||
ToolCall {
|
||||
@@ -886,10 +889,9 @@ impl super::Provider for GeminiProvider {
|
||||
if let Some(fc) = &p.function_call {
|
||||
let tool_call_idx = p_idx as u32;
|
||||
|
||||
// Attempt to find a signature in any possible field
|
||||
// Attempt to find a signature in sibling fields
|
||||
let signature = p.thought_signature_camel.clone()
|
||||
.or_else(|| p.thought_signature_snake.clone())
|
||||
.or_else(|| fc.thought_signature.clone());
|
||||
.or_else(|| p.thought_signature_snake.clone());
|
||||
|
||||
// Ensure the ID remains stable for this tool call index.
|
||||
// If we found a real signature now, we update it; otherwise use the existing or new random ID.
|
||||
|
||||
Reference in New Issue
Block a user