Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions crates/coverage-report/src/requests_expected_differences.json
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,74 @@
{ "pattern": "params.reasoning", "reason": "Anthropic rejects enabled thinking when tool_choice forces a specific tool; thinking is intentionally dropped" }
]
},
{
"testCase": "codeInterpreterToolParam",
"source": "Google",
"target": "Anthropic",
"skip": true,
"reason": "Google code_execution tool has no Anthropic equivalent"
},
{
"testCase": "toolChoiceRequiredWithReasoningParam",
"source": "Google",
"target": "Anthropic",
"fields": [
{ "pattern": "params.reasoning", "reason": "Anthropic rejects enabled thinking when tool_choice forces a specific tool; thinking is intentionally dropped" }
]
},
{
"testCase": "toolChoiceRequiredWithReasoningParam",
"source": "Google",
"target": "Responses",
"fields": [
{ "pattern": "messages.length", "reason": "Responses expands Google required-tool reasoning followups into a different message shape" }
]
},
{
"testCase": "responseModalitiesAudioParam",
"source": "Google",
"target": "Anthropic",
"fields": [
{ "pattern": "messages[*].content[*].type", "reason": "Google assistant audio content becomes text fallback in Anthropic" },
{ "pattern": "messages[*].content[*].media_type", "reason": "Google assistant audio content is not preserved in Anthropic" },
{ "pattern": "messages[*].content[*].data", "reason": "Google assistant audio content is not preserved in Anthropic" },
{ "pattern": "messages[*].content[*].text", "reason": "Google assistant audio content becomes text fallback in Anthropic" }
]
},
{
"testCase": "responseModalitiesAudioParam",
"source": "Google",
"target": "ChatCompletions",
"fields": [
{ "pattern": "messages[*].content[*].type", "reason": "Google assistant audio content becomes text fallback in ChatCompletions" },
{ "pattern": "messages[*].content[*].media_type", "reason": "Google assistant audio content is not preserved in ChatCompletions" },
{ "pattern": "messages[*].content[*].data", "reason": "Google assistant audio content is not preserved in ChatCompletions" },
{ "pattern": "messages[*].content[*].text", "reason": "Google assistant audio content becomes text fallback in ChatCompletions" }
]
},
{
"testCase": "urlContextToolParam",
"source": "Google",
"target": "Anthropic",
"skip": true,
"reason": "Google url_context builtin tool has no Anthropic equivalent"
},
{
"testCase": "urlContextToolParam",
"source": "Google",
"target": "Responses",
"fields": [
{ "pattern": "params.tools", "reason": "Google url_context builtin tool has no Responses equivalent" }
]
},
{
"testCase": "urlContextToolParam",
"source": "Google",
"target": "ChatCompletions",
"fields": [
{ "pattern": "params.tools", "reason": "Google url_context builtin tool has no ChatCompletions equivalent" }
]
},
{
"testCase": "parallelToolCallsRequest",
"source": "*",
Expand Down
78 changes: 78 additions & 0 deletions crates/coverage-report/src/responses_expected_differences.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,22 @@
{ "pattern": "messages.length", "reason": "Google assistant image content not supported in Responses" }
]
},
{
"testCase": "speechConfigParam",
"source": "Google",
"target": "Anthropic",
"fields": [
{ "pattern": "messages.length", "reason": "Anthropic does not preserve Google's empty finish-reason-only response candidate as a message" }
]
},
{
"testCase": "speechConfigParam",
"source": "Google",
"target": "ChatCompletions",
"fields": [
{ "pattern": "finish_reason", "reason": "ChatCompletions does not preserve Google's finishReason OTHER exactly" }
]
},
{
"testCase": "webSearchToolParam",
"source": "Anthropic",
Expand All @@ -260,6 +276,30 @@
{ "pattern": "finish_reason", "reason": "Google infers finish_reason from content - presence of tool calls yields ToolCalls" }
]
},
{
"testCase": "codeInterpreterToolParam",
"source": "Google",
"target": "Anthropic",
"fields": [
{ "pattern": "messages[*].content[*].provider_options", "reason": "Google code execution metadata is preserved in provider_options and has no Anthropic equivalent" }
]
},
{
"testCase": "codeInterpreterToolParam",
"source": "Google",
"target": "ChatCompletions",
"fields": [
{ "pattern": "messages[*].content.length", "reason": "ChatCompletions does not preserve Google code execution metadata as separate assistant content parts" }
]
},
{
"testCase": "codeInterpreterToolParam",
"source": "Google",
"target": "Responses",
"fields": [
{ "pattern": "messages.length", "reason": "Responses does not preserve Google code execution metadata as a single assistant message" }
]
},
{
"testCase": "webSearchToolParam",
"source": "Responses",
Expand All @@ -284,6 +324,44 @@
{ "pattern": "messages.length", "reason": "Google reasoning content expands to separate output items in Responses format" }
]
},
{
"testCase": "toolChoiceRequiredWithReasoningParam",
"source": "Google",
"target": "Responses",
"fields": [
{ "pattern": "messages.length", "reason": "Responses expands Google required-tool reasoning into a different output-item shape" }
]
},
{
"testCase": "responseModalitiesAudioParam",
"source": "Google",
"target": "Anthropic",
"fields": [
{ "pattern": "messages[*].content[*].type", "reason": "Google assistant audio content becomes text fallback in Anthropic" },
{ "pattern": "messages[*].content[*].media_type", "reason": "Google assistant audio content is not preserved in Anthropic" },
{ "pattern": "messages[*].content[*].data", "reason": "Google assistant audio content is not preserved in Anthropic" },
{ "pattern": "messages[*].content[*].text", "reason": "Google assistant audio content becomes text fallback in Anthropic" }
]
},
{
"testCase": "responseModalitiesAudioParam",
"source": "Google",
"target": "ChatCompletions",
"fields": [
{ "pattern": "messages[*].content[*].type", "reason": "Google assistant audio content becomes text fallback in ChatCompletions" },
{ "pattern": "messages[*].content[*].media_type", "reason": "Google assistant audio content is not preserved in ChatCompletions" },
{ "pattern": "messages[*].content[*].data", "reason": "Google assistant audio content is not preserved in ChatCompletions" },
{ "pattern": "messages[*].content[*].text", "reason": "Google assistant audio content becomes text fallback in ChatCompletions" }
]
},
{
"testCase": "responseModalitiesAudioParam",
"source": "Google",
"target": "Responses",
"fields": [
{ "pattern": "messages.length", "reason": "Responses does not preserve Google assistant audio content as a single message" }
]
},
{
"testCase": "simpleRequestTruncated",
"source": "Google",
Expand Down
42 changes: 24 additions & 18 deletions crates/lingua/src/providers/google/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,24 +437,30 @@ impl ProviderAdapter for GoogleAdapter {
.map(|r| r.to_provider_string(self.format()).to_string())
.unwrap_or_else(|| "STOP".to_string());

let candidates: Vec<Value> = resp
.messages
.iter()
.enumerate()
.map(|(i, msg)| {
let content = <GoogleContent as TryFromLLM<Message>>::try_from(msg.clone())
.map_err(|e| TransformError::FromUniversalFailed(e.to_string()))?;

let content_value = serde_json::to_value(&content)
.map_err(|e| TransformError::SerializationFailed(e.to_string()))?;

Ok(serde_json::json!({
"index": i,
"content": content_value,
"finishReason": finish_reason
}))
})
.collect::<Result<Vec<_>, TransformError>>()?;
let candidates: Vec<Value> = if resp.messages.is_empty() && resp.finish_reason.is_some() {
vec![serde_json::json!({
"index": 0,
"finishReason": finish_reason
})]
} else {
resp.messages
.iter()
.enumerate()
.map(|(i, msg)| {
let content = <GoogleContent as TryFromLLM<Message>>::try_from(msg.clone())
.map_err(|e| TransformError::FromUniversalFailed(e.to_string()))?;

let content_value = serde_json::to_value(&content)
.map_err(|e| TransformError::SerializationFailed(e.to_string()))?;

Ok(serde_json::json!({
"index": i,
"content": content_value,
"finishReason": finish_reason
}))
})
.collect::<Result<Vec<_>, TransformError>>()?
};

let mut map = serde_json::Map::new();
map.insert("candidates".into(), Value::Array(candidates));
Expand Down
Loading
Loading