fix(gemini): align thought_signature logic with Gemini API requirements
- Extract thought_signature from the Part level during response parsing. - Provide thought_signature as a sibling to functionCall during request assembly. - This fully resolves the 'Unknown name thoughtSignature at function_call' error.
This commit is contained in:
@@ -57,6 +57,8 @@ struct GeminiPart {
|
|||||||
function_response: Option<GeminiFunctionResponse>,
|
function_response: Option<GeminiFunctionResponse>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
thought: Option<String>,
|
thought: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
thought_signature: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -70,8 +72,6 @@ struct GeminiInlineData {
|
|||||||
struct GeminiFunctionCall {
|
struct GeminiFunctionCall {
|
||||||
name: String,
|
name: String,
|
||||||
args: Value,
|
args: Value,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
thought_signature: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -231,6 +231,7 @@ impl GeminiProvider {
|
|||||||
function_call: None,
|
function_call: None,
|
||||||
function_response: None,
|
function_response: None,
|
||||||
thought: None,
|
thought: None,
|
||||||
|
thought_signature: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,6 +271,7 @@ impl GeminiProvider {
|
|||||||
response: response_value,
|
response: response_value,
|
||||||
}),
|
}),
|
||||||
thought: None,
|
thought: None,
|
||||||
|
thought_signature: None,
|
||||||
});
|
});
|
||||||
} else if msg.role == "assistant" {
|
} else if msg.role == "assistant" {
|
||||||
// Assistant messages: handle text, thought (reasoning), and tool_calls
|
// Assistant messages: handle text, thought (reasoning), and tool_calls
|
||||||
@@ -282,6 +284,7 @@ impl GeminiProvider {
|
|||||||
function_call: None,
|
function_call: None,
|
||||||
function_response: None,
|
function_response: None,
|
||||||
thought: None,
|
thought: None,
|
||||||
|
thought_signature: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,6 +299,7 @@ impl GeminiProvider {
|
|||||||
function_call: None,
|
function_call: None,
|
||||||
function_response: None,
|
function_response: None,
|
||||||
thought: Some(reasoning.clone()),
|
thought: Some(reasoning.clone()),
|
||||||
|
thought_signature: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,10 +322,10 @@ impl GeminiProvider {
|
|||||||
function_call: Some(GeminiFunctionCall {
|
function_call: Some(GeminiFunctionCall {
|
||||||
name: tc.function.name.clone(),
|
name: tc.function.name.clone(),
|
||||||
args,
|
args,
|
||||||
thought_signature,
|
|
||||||
}),
|
}),
|
||||||
function_response: None,
|
function_response: None,
|
||||||
thought: None,
|
thought: None,
|
||||||
|
thought_signature,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,6 +341,7 @@ impl GeminiProvider {
|
|||||||
function_call: None,
|
function_call: None,
|
||||||
function_response: None,
|
function_response: None,
|
||||||
thought: None,
|
thought: None,
|
||||||
|
thought_signature: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,6 +360,7 @@ impl GeminiProvider {
|
|||||||
function_call: None,
|
function_call: None,
|
||||||
function_response: None,
|
function_response: None,
|
||||||
thought: None,
|
thought: None,
|
||||||
|
thought_signature: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,6 +396,7 @@ impl GeminiProvider {
|
|||||||
function_call: None,
|
function_call: None,
|
||||||
function_response: None,
|
function_response: None,
|
||||||
thought: None,
|
thought: None,
|
||||||
|
thought_signature: None,
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -516,10 +523,11 @@ impl GeminiProvider {
|
|||||||
fn extract_tool_calls(parts: &[GeminiPart]) -> Option<Vec<ToolCall>> {
|
fn extract_tool_calls(parts: &[GeminiPart]) -> Option<Vec<ToolCall>> {
|
||||||
let calls: Vec<ToolCall> = parts
|
let calls: Vec<ToolCall> = parts
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|p| p.function_call.as_ref())
|
.filter(|p| p.function_call.is_some())
|
||||||
.map(|fc| {
|
.map(|p| {
|
||||||
// CAPTURE: Use thought_signature as the ID if available
|
let fc = p.function_call.as_ref().unwrap();
|
||||||
let id = fc.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple()));
|
// CAPTURE: Use thought_signature from Part as the ID if available
|
||||||
|
let id = p.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple()));
|
||||||
|
|
||||||
ToolCall {
|
ToolCall {
|
||||||
id,
|
id,
|
||||||
@@ -539,11 +547,12 @@ impl GeminiProvider {
|
|||||||
fn extract_tool_call_deltas(parts: &[GeminiPart]) -> Option<Vec<ToolCallDelta>> {
|
fn extract_tool_call_deltas(parts: &[GeminiPart]) -> Option<Vec<ToolCallDelta>> {
|
||||||
let deltas: Vec<ToolCallDelta> = parts
|
let deltas: Vec<ToolCallDelta> = parts
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|p| p.function_call.as_ref())
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, fc)| {
|
.filter(|(_, p)| p.function_call.is_some())
|
||||||
// CAPTURE: Use thought_signature as the ID if available
|
.map(|(i, p)| {
|
||||||
let id = fc.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple()));
|
let fc = p.function_call.as_ref().unwrap();
|
||||||
|
// CAPTURE: Use thought_signature from Part as the ID if available
|
||||||
|
let id = p.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple()));
|
||||||
|
|
||||||
ToolCallDelta {
|
ToolCallDelta {
|
||||||
index: i as u32,
|
index: i as u32,
|
||||||
|
|||||||
Reference in New Issue
Block a user