From 7ff0b66f4a648595e48f6fbf89c04a028bc22798 Mon Sep 17 00:00:00 2001
From: li
Date: Fri, 27 Feb 2026 00:46:05 +0100
Subject: [PATCH] fix(gemini): strip x-extension fields from tool schemas and
handle empty safety blocks
---
vtcode-core/src/gemini/streaming/processor.rs | 4 ++++
vtcode-core/src/llm/providers/gemini/sanitize.rs | 2 +-
vtcode-core/src/tools/registry/declarations.rs | 14 ++++++++++----
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/vtcode-core/src/gemini/streaming/processor.rs b/vtcode-core/src/gemini/streaming/processor.rs
index 4f2c3cc36..322716c99 100644
--- a/vtcode-core/src/gemini/streaming/processor.rs
+++ b/vtcode-core/src/gemini/streaming/processor.rs
@@ -532,6 +532,10 @@ impl StreamingProcessor {
{
let mut _has_valid_content = false;
+ if candidate.finish_reason.is_some() {
+ _has_valid_content = true;
+ }
+
// Process each part of the content
for part in &candidate.content.parts {
match part {
diff --git a/vtcode-core/src/llm/providers/gemini/sanitize.rs b/vtcode-core/src/llm/providers/gemini/sanitize.rs
index ba4ce4660..c160d0dbc 100644
--- a/vtcode-core/src/llm/providers/gemini/sanitize.rs
+++ b/vtcode-core/src/llm/providers/gemini/sanitize.rs
@@ -33,7 +33,7 @@ pub fn sanitize_function_parameters(parameters: Value) -> Value {
let mut sanitized = Map::new();
for (key, value) in map {
// Skip unsupported fields at this level
- if UNSUPPORTED_FIELDS.contains(&key.as_str()) {
+ if UNSUPPORTED_FIELDS.contains(&key.as_str()) || key.starts_with("x-") {
continue;
}
// Recursively sanitize nested values
diff --git a/vtcode-core/src/tools/registry/declarations.rs b/vtcode-core/src/tools/registry/declarations.rs
index 2c71f65e1..c24813f72 100644
--- a/vtcode-core/src/tools/registry/declarations.rs
+++ b/vtcode-core/src/tools/registry/declarations.rs
@@ -904,22 +904,22 @@ fn annotate_parameters(params: &mut Value, meta: &super::registration::ToolMetad
};
if let Some(permission) = meta.default_permission() {
- map.insert(
+ insert_if_allowed(map,
"x-default-permission".to_string(),
json!(permission_label(&permission)),
);
}
if !meta.aliases().is_empty() {
- map.insert("x-aliases".to_string(), json!(meta.aliases().to_vec()));
+ insert_if_allowed(map, "x-aliases".to_string(), json!(meta.aliases().to_vec()));
}
if let Some(schema) = meta.config_schema() {
- map.insert("x-config-schema".to_string(), schema.clone());
+ insert_if_allowed(map, "x-config-schema".to_string(), schema.clone());
}
if let Some(schema) = meta.state_schema() {
- map.insert("x-state-schema".to_string(), schema.clone());
+ insert_if_allowed(map, "x-state-schema".to_string(), schema.clone());
}
}
@@ -930,3 +930,9 @@ fn permission_label(permission: &ToolPolicy) -> &'static str {
ToolPolicy::Prompt => "prompt",
}
}
+
+fn insert_if_allowed(map: &mut serde_json::Map, key: String, value: Value) {
+ if !key.starts_with("x-") {
+ map.insert(key, value);
+ }
+}