Spaces:
Paused
Paused
Mirrowel commited on
Commit Β·
3ff0b2d
1
Parent(s): 5c4d30a
fix(tools): π inject dummy parameter for tools with empty schemas
Browse filesGemini/Antigravity API fails to emit functionCall when tool schemas have empty properties {}. This commit adds a workaround by injecting a dummy optional parameter "_" into empty tool schemas to ensure function calls are properly emitted.
- Add dummy parameter injection in both antigravity_provider and gemini_cli_provider
- Apply workaround to both schema transformation paths and default empty schema cases
- Update docstring for _apply_claude_tool_transform to clarify its purpose
- Improve inline comments for error body reading logic
src/rotator_library/providers/antigravity_provider.py
CHANGED
|
@@ -2450,9 +2450,23 @@ class AntigravityProvider(AntigravityAuthBase, ProviderInterface):
|
|
| 2450 |
schema.pop("$schema", None)
|
| 2451 |
schema.pop("strict", None)
|
| 2452 |
schema = _normalize_type_arrays(schema)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2453 |
func_decl["parametersJsonSchema"] = schema
|
| 2454 |
else:
|
| 2455 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2456 |
|
| 2457 |
gemini_tools.append({"functionDeclarations": [func_decl]})
|
| 2458 |
|
|
@@ -2577,7 +2591,11 @@ class AntigravityProvider(AntigravityAuthBase, ProviderInterface):
|
|
| 2577 |
return antigravity_payload
|
| 2578 |
|
| 2579 |
def _apply_claude_tool_transform(self, payload: Dict[str, Any]) -> None:
|
| 2580 |
-
"""Apply Claude-specific tool schema transformations.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2581 |
tools = payload["request"].get("tools", [])
|
| 2582 |
for tool in tools:
|
| 2583 |
for func_decl in tool.get("functionDeclarations", []):
|
|
@@ -3219,8 +3237,8 @@ class AntigravityProvider(AntigravityAuthBase, ProviderInterface):
|
|
| 3219 |
"POST", url, headers=headers, json=payload, timeout=600.0
|
| 3220 |
) as response:
|
| 3221 |
if response.status_code >= 400:
|
| 3222 |
-
# Read error body
|
| 3223 |
-
#
|
| 3224 |
try:
|
| 3225 |
await response.aread()
|
| 3226 |
# lib_logger.error(
|
|
|
|
| 2450 |
schema.pop("$schema", None)
|
| 2451 |
schema.pop("strict", None)
|
| 2452 |
schema = _normalize_type_arrays(schema)
|
| 2453 |
+
|
| 2454 |
+
# Workaround: Antigravity/Gemini fails to emit functionCall
|
| 2455 |
+
# when tool has empty properties {}. Inject a dummy optional
|
| 2456 |
+
# parameter to ensure the tool call is emitted.
|
| 2457 |
+
props = schema.get("properties", {})
|
| 2458 |
+
if not props:
|
| 2459 |
+
schema["properties"] = {
|
| 2460 |
+
"_": {"type": "string", "description": "Unused"}
|
| 2461 |
+
}
|
| 2462 |
+
|
| 2463 |
func_decl["parametersJsonSchema"] = schema
|
| 2464 |
else:
|
| 2465 |
+
# No parameters provided - use default with dummy param
|
| 2466 |
+
func_decl["parametersJsonSchema"] = {
|
| 2467 |
+
"type": "object",
|
| 2468 |
+
"properties": {"_": {"type": "string", "description": "Unused"}},
|
| 2469 |
+
}
|
| 2470 |
|
| 2471 |
gemini_tools.append({"functionDeclarations": [func_decl]})
|
| 2472 |
|
|
|
|
| 2591 |
return antigravity_payload
|
| 2592 |
|
| 2593 |
def _apply_claude_tool_transform(self, payload: Dict[str, Any]) -> None:
|
| 2594 |
+
"""Apply Claude-specific tool schema transformations.
|
| 2595 |
+
|
| 2596 |
+
Converts parametersJsonSchema to parameters and applies Claude-specific
|
| 2597 |
+
schema cleaning (removes unsupported JSON Schema fields).
|
| 2598 |
+
"""
|
| 2599 |
tools = payload["request"].get("tools", [])
|
| 2600 |
for tool in tools:
|
| 2601 |
for func_decl in tool.get("functionDeclarations", []):
|
|
|
|
| 3237 |
"POST", url, headers=headers, json=payload, timeout=600.0
|
| 3238 |
) as response:
|
| 3239 |
if response.status_code >= 400:
|
| 3240 |
+
# Read error body so it's available in response.text for logging
|
| 3241 |
+
# The actual logging happens in failure_logger via _extract_response_body
|
| 3242 |
try:
|
| 3243 |
await response.aread()
|
| 3244 |
# lib_logger.error(
|
src/rotator_library/providers/gemini_cli_provider.py
CHANGED
|
@@ -1256,13 +1256,22 @@ class GeminiCliProvider(GeminiAuthBase, ProviderInterface):
|
|
| 1256 |
schema = self._gemini_cli_transform_schema(
|
| 1257 |
new_function["parameters"]
|
| 1258 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1259 |
new_function["parametersJsonSchema"] = schema
|
| 1260 |
del new_function["parameters"]
|
| 1261 |
elif "parametersJsonSchema" not in new_function:
|
| 1262 |
-
# Set default
|
| 1263 |
new_function["parametersJsonSchema"] = {
|
| 1264 |
"type": "object",
|
| 1265 |
-
"properties": {
|
|
|
|
|
|
|
| 1266 |
}
|
| 1267 |
|
| 1268 |
# Gemini 3 specific transformations
|
|
|
|
| 1256 |
schema = self._gemini_cli_transform_schema(
|
| 1257 |
new_function["parameters"]
|
| 1258 |
)
|
| 1259 |
+
# Workaround: Gemini fails to emit functionCall for tools
|
| 1260 |
+
# with empty properties {}. Inject a dummy optional param.
|
| 1261 |
+
props = schema.get("properties", {})
|
| 1262 |
+
if not props:
|
| 1263 |
+
schema["properties"] = {
|
| 1264 |
+
"_": {"type": "string", "description": "Unused"}
|
| 1265 |
+
}
|
| 1266 |
new_function["parametersJsonSchema"] = schema
|
| 1267 |
del new_function["parameters"]
|
| 1268 |
elif "parametersJsonSchema" not in new_function:
|
| 1269 |
+
# Set default schema with dummy param if neither exists
|
| 1270 |
new_function["parametersJsonSchema"] = {
|
| 1271 |
"type": "object",
|
| 1272 |
+
"properties": {
|
| 1273 |
+
"_": {"type": "string", "description": "Unused"}
|
| 1274 |
+
},
|
| 1275 |
}
|
| 1276 |
|
| 1277 |
# Gemini 3 specific transformations
|