fix: preserve provider schema drift safely

This commit is contained in:
elky
2026-06-03 22:29:24 +08:00
parent da5624c98e
commit 465476985b
7 changed files with 93 additions and 7 deletions
@@ -2785,6 +2785,59 @@ mod tests {
));
}
#[test]
fn same_format_canonical_roundtrip_preserves_future_root_fields() {
let cases = [
(
"openai:chat",
json!({
"model": "gpt-source",
"messages": [{"role": "user", "content": "hello"}],
"future_field": {"enabled": true}
}),
"future_field",
),
(
"openai:responses",
json!({
"model": "gpt-source",
"input": [{"role": "user", "content": "hello"}],
"future_field": {"enabled": true}
}),
"future_field",
),
(
"claude:messages",
json!({
"model": "claude-source",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "hello"}],
"future_field": {"enabled": true}
}),
"future_field",
),
(
"gemini:generate_content",
json!({
"model": "gemini-source",
"contents": [{"role": "user", "parts": [{"text": "hello"}]}],
"futureField": {"enabled": true}
}),
"futureField",
),
];
for (format, body, field) in cases {
let converted = convert_request_pure(format, format, &body)
.unwrap_or_else(|err| panic!("{format} same-format roundtrip failed: {err}"));
assert_eq!(
converted.value.get(field),
body.get(field),
"{format} must preserve unknown provider root fields in canonical roundtrip"
);
}
}
#[test]
fn pure_openai_chat_to_claude_blocks_target_unsupported_generation_field() {
let body = json!({
@@ -4582,9 +4582,29 @@ pub(crate) fn apply_gemini_request_extensions(
if let Some(raw_tool_config) = gemini.get("raw_tool_config").cloned() {
output_object.insert("toolConfig".to_string(), raw_tool_config);
}
for (key, value) in gemini {
if GEMINI_REQUEST_EXTENSION_INTERNAL_KEYS.contains(&key.as_str()) {
continue;
}
output_object
.entry(key.clone())
.or_insert_with(|| value.clone());
}
Some(())
}
const GEMINI_REQUEST_EXTENSION_INTERNAL_KEYS: &[&str] = &[
"builtin_tools",
"cached_content",
"generation_config_extra",
"grounding",
"raw_tool_config",
"raw_tools",
"response_modalities",
"safety_settings",
"thinking_config",
];
fn should_reuse_raw_gemini_tools(gemini: &Map<String, Value>) -> bool {
let Some(google_search) = gemini
.get("grounding")