Spaces:
Paused
refactor(antigravity): 🔨 remove thinking mode toggling feature
Browse filesThis commit removes the thinking mode toggling functionality that was previously used to handle model switches mid-conversation when tool use loops were incomplete.
- Removed `_detect_incomplete_tool_turn`, `_inject_turn_completion`, and `_handle_thinking_mode_toggle` helper methods
- Removed environment variable configuration for turn completion behavior (`ANTIGRAVITY_AUTO_INJECT_TURN_COMPLETION`, `ANTIGRAVITY_AUTO_SUPPRESS_THINKING`, `ANTIGRAVITY_TURN_COMPLETION_TEXT`)
- Removed thinking mode toggle logic from `acompletion` method
- Added provider prefix to JSON auto-correction warning log for better debugging
The removed feature was designed to automatically handle incomplete tool use loops when switching to Claude models with thinking mode enabled, but was buggy as hell.
|
@@ -199,7 +199,7 @@ def _recursively_parse_json_strings(obj: Any) -> Any:
|
|
| 199 |
cleaned = stripped[:last_bracket+1]
|
| 200 |
parsed = json.loads(cleaned)
|
| 201 |
lib_logger.warning(
|
| 202 |
-
f"Auto-corrected malformed JSON string: "
|
| 203 |
f"truncated {len(stripped) - len(cleaned)} extra chars"
|
| 204 |
)
|
| 205 |
return _recursively_parse_json_strings(parsed)
|
|
@@ -370,11 +370,6 @@ class AntigravityProvider(AntigravityAuthBase, ProviderInterface):
|
|
| 370 |
self._enable_dynamic_models = _env_bool("ANTIGRAVITY_ENABLE_DYNAMIC_MODELS", False)
|
| 371 |
self._enable_gemini3_tool_fix = _env_bool("ANTIGRAVITY_GEMINI3_TOOL_FIX", True)
|
| 372 |
|
| 373 |
-
# Thinking mode toggling behavior
|
| 374 |
-
self._auto_inject_turn_completion = _env_bool("ANTIGRAVITY_AUTO_INJECT_TURN_COMPLETION", True)
|
| 375 |
-
self._auto_suppress_thinking = _env_bool("ANTIGRAVITY_AUTO_SUPPRESS_THINKING", False)
|
| 376 |
-
self._turn_completion_placeholder = os.getenv("ANTIGRAVITY_TURN_COMPLETION_TEXT", "...")
|
| 377 |
-
|
| 378 |
# Gemini 3 tool fix configuration
|
| 379 |
self._gemini3_tool_prefix = os.getenv("ANTIGRAVITY_GEMINI3_TOOL_PREFIX", "gemini3_")
|
| 380 |
self._gemini3_description_prompt = os.getenv(
|
|
@@ -1368,142 +1363,6 @@ class AntigravityProvider(AntigravityAuthBase, ProviderInterface):
|
|
| 1368 |
|
| 1369 |
return [f"antigravity/{m}" for m in AVAILABLE_MODELS]
|
| 1370 |
|
| 1371 |
-
# =========================================================================
|
| 1372 |
-
# THINKING MODE TOGGLING HELPERS
|
| 1373 |
-
# =========================================================================
|
| 1374 |
-
|
| 1375 |
-
def _detect_incomplete_tool_turn(self, messages: List[Dict[str, Any]]) -> Optional[int]:
|
| 1376 |
-
"""
|
| 1377 |
-
Detect if messages end with an incomplete tool use loop.
|
| 1378 |
-
|
| 1379 |
-
An incomplete tool turn is when:
|
| 1380 |
-
- Last message is a tool result
|
| 1381 |
-
- The assistant message that made the tool call hasn't been completed
|
| 1382 |
-
with a final text response
|
| 1383 |
-
|
| 1384 |
-
Returns:
|
| 1385 |
-
Index of the assistant message with tool_calls if incomplete turn detected,
|
| 1386 |
-
None otherwise
|
| 1387 |
-
"""
|
| 1388 |
-
if len(messages) < 2:
|
| 1389 |
-
return None
|
| 1390 |
-
|
| 1391 |
-
# Last message must be tool result
|
| 1392 |
-
if messages[-1].get("role") != "tool":
|
| 1393 |
-
return None
|
| 1394 |
-
|
| 1395 |
-
# Find the assistant message that made the tool call
|
| 1396 |
-
for i in range(len(messages) - 2, -1, -1):
|
| 1397 |
-
msg = messages[i]
|
| 1398 |
-
if msg.get("role") == "assistant":
|
| 1399 |
-
if msg.get("tool_calls"):
|
| 1400 |
-
# Check if turn was completed by a subsequent assistant message
|
| 1401 |
-
for j in range(i + 1, len(messages)):
|
| 1402 |
-
if messages[j].get("role") == "assistant" and not messages[j].get("tool_calls"):
|
| 1403 |
-
return None # Turn completed
|
| 1404 |
-
|
| 1405 |
-
# Incomplete turn found
|
| 1406 |
-
lib_logger.debug(
|
| 1407 |
-
f"Detected incomplete tool turn: assistant message at index {i} "
|
| 1408 |
-
f"has tool_calls, but no completing text response found"
|
| 1409 |
-
)
|
| 1410 |
-
return i
|
| 1411 |
-
else:
|
| 1412 |
-
# Found completing assistant message
|
| 1413 |
-
return None
|
| 1414 |
-
|
| 1415 |
-
return None
|
| 1416 |
-
|
| 1417 |
-
def _inject_turn_completion(
|
| 1418 |
-
self,
|
| 1419 |
-
messages: List[Dict[str, Any]],
|
| 1420 |
-
incomplete_turn_index: int
|
| 1421 |
-
) -> List[Dict[str, Any]]:
|
| 1422 |
-
"""
|
| 1423 |
-
Inject a completing assistant message to close an incomplete tool use turn.
|
| 1424 |
-
|
| 1425 |
-
Args:
|
| 1426 |
-
messages: Original message list
|
| 1427 |
-
incomplete_turn_index: Index of the assistant message with tool_calls
|
| 1428 |
-
|
| 1429 |
-
Returns:
|
| 1430 |
-
Modified message list with injected completion
|
| 1431 |
-
"""
|
| 1432 |
-
completion_msg = {
|
| 1433 |
-
"role": "assistant",
|
| 1434 |
-
"content": self._turn_completion_placeholder
|
| 1435 |
-
}
|
| 1436 |
-
|
| 1437 |
-
# Append to close the turn
|
| 1438 |
-
modified_messages = messages.copy()
|
| 1439 |
-
modified_messages.append(completion_msg)
|
| 1440 |
-
|
| 1441 |
-
lib_logger.info(
|
| 1442 |
-
f"Injected turn-completing assistant message ('{self._turn_completion_placeholder}') "
|
| 1443 |
-
f"to enable thinking mode. Original tool use started at message index {incomplete_turn_index}."
|
| 1444 |
-
)
|
| 1445 |
-
|
| 1446 |
-
return modified_messages
|
| 1447 |
-
|
| 1448 |
-
def _handle_thinking_mode_toggle(
|
| 1449 |
-
self,
|
| 1450 |
-
messages: List[Dict[str, Any]],
|
| 1451 |
-
model: str,
|
| 1452 |
-
reasoning_effort: Optional[str]
|
| 1453 |
-
) -> Tuple[List[Dict[str, Any]], Optional[str]]:
|
| 1454 |
-
"""
|
| 1455 |
-
Handle thinking mode toggling when switching models mid-conversation.
|
| 1456 |
-
|
| 1457 |
-
When switching to Claude with thinking enabled, but the conversation has
|
| 1458 |
-
an incomplete tool use loop from another model, either:
|
| 1459 |
-
1. Inject a completing message to close the turn (if auto_inject enabled)
|
| 1460 |
-
2. Suppress thinking mode (if auto_suppress enabled)
|
| 1461 |
-
3. Let it fail with API error (if both disabled)
|
| 1462 |
-
|
| 1463 |
-
Args:
|
| 1464 |
-
messages: Original message list
|
| 1465 |
-
model: Target model
|
| 1466 |
-
reasoning_effort: Requested reasoning effort level
|
| 1467 |
-
|
| 1468 |
-
Returns:
|
| 1469 |
-
(modified_messages, modified_reasoning_effort)
|
| 1470 |
-
"""
|
| 1471 |
-
# Only applies when trying to enable thinking on Claude
|
| 1472 |
-
if not self._is_claude(model) or not reasoning_effort:
|
| 1473 |
-
return messages, reasoning_effort
|
| 1474 |
-
|
| 1475 |
-
incomplete_turn_index = self._detect_incomplete_tool_turn(messages)
|
| 1476 |
-
if incomplete_turn_index is None:
|
| 1477 |
-
# No incomplete turn - proceed normally
|
| 1478 |
-
return messages, reasoning_effort
|
| 1479 |
-
|
| 1480 |
-
# Strategy 1: Auto-inject turn completion (preferred)
|
| 1481 |
-
if self._auto_inject_turn_completion:
|
| 1482 |
-
lib_logger.info(
|
| 1483 |
-
"Model switch to Claude with thinking detected mid-tool-use-loop. "
|
| 1484 |
-
"Injecting turn completion to enable thinking mode."
|
| 1485 |
-
)
|
| 1486 |
-
modified_messages = self._inject_turn_completion(messages, incomplete_turn_index)
|
| 1487 |
-
return modified_messages, reasoning_effort
|
| 1488 |
-
|
| 1489 |
-
# Strategy 2: Auto-suppress thinking
|
| 1490 |
-
if self._auto_suppress_thinking:
|
| 1491 |
-
lib_logger.warning(
|
| 1492 |
-
f"Model switch to Claude with thinking detected mid-tool-use-loop. "
|
| 1493 |
-
f"Suppressing reasoning_effort={reasoning_effort} to avoid API error. "
|
| 1494 |
-
f"Set ANTIGRAVITY_AUTO_INJECT_TURN_COMPLETION=true to inject completion instead."
|
| 1495 |
-
)
|
| 1496 |
-
return messages, None
|
| 1497 |
-
|
| 1498 |
-
# Strategy 3: Let it fail (user wants to handle it themselves)
|
| 1499 |
-
lib_logger.warning(
|
| 1500 |
-
"Model switch to Claude with thinking detected mid-tool-use-loop. "
|
| 1501 |
-
"Both auto-injection and auto-suppression are disabled. "
|
| 1502 |
-
"Request will likely fail with API error. "
|
| 1503 |
-
f"Enable ANTIGRAVITY_AUTO_INJECT_TURN_COMPLETION or ANTIGRAVITY_AUTO_SUPPRESS_THINKING."
|
| 1504 |
-
)
|
| 1505 |
-
return messages, reasoning_effort
|
| 1506 |
-
|
| 1507 |
async def acompletion(
|
| 1508 |
self,
|
| 1509 |
client: httpx.AsyncClient,
|
|
@@ -1533,13 +1392,6 @@ class AntigravityProvider(AntigravityAuthBase, ProviderInterface):
|
|
| 1533 |
# Create logger
|
| 1534 |
file_logger = AntigravityFileLogger(model, enable_logging)
|
| 1535 |
|
| 1536 |
-
# Handle thinking mode toggling for model switches
|
| 1537 |
-
messages, reasoning_effort = self._handle_thinking_mode_toggle(messages, model, reasoning_effort)
|
| 1538 |
-
if reasoning_effort != kwargs.get("reasoning_effort"):
|
| 1539 |
-
kwargs["reasoning_effort"] = reasoning_effort
|
| 1540 |
-
if messages != kwargs.get("messages"):
|
| 1541 |
-
kwargs["messages"] = messages
|
| 1542 |
-
|
| 1543 |
# Transform messages
|
| 1544 |
system_instruction, gemini_contents = self._transform_messages(messages, model)
|
| 1545 |
gemini_contents = self._fix_tool_response_grouping(gemini_contents)
|
|
|
|
| 199 |
cleaned = stripped[:last_bracket+1]
|
| 200 |
parsed = json.loads(cleaned)
|
| 201 |
lib_logger.warning(
|
| 202 |
+
f"[Antigravity] Auto-corrected malformed JSON string: "
|
| 203 |
f"truncated {len(stripped) - len(cleaned)} extra chars"
|
| 204 |
)
|
| 205 |
return _recursively_parse_json_strings(parsed)
|
|
|
|
| 370 |
self._enable_dynamic_models = _env_bool("ANTIGRAVITY_ENABLE_DYNAMIC_MODELS", False)
|
| 371 |
self._enable_gemini3_tool_fix = _env_bool("ANTIGRAVITY_GEMINI3_TOOL_FIX", True)
|
| 372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
# Gemini 3 tool fix configuration
|
| 374 |
self._gemini3_tool_prefix = os.getenv("ANTIGRAVITY_GEMINI3_TOOL_PREFIX", "gemini3_")
|
| 375 |
self._gemini3_description_prompt = os.getenv(
|
|
|
|
| 1363 |
|
| 1364 |
return [f"antigravity/{m}" for m in AVAILABLE_MODELS]
|
| 1365 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1366 |
async def acompletion(
|
| 1367 |
self,
|
| 1368 |
client: httpx.AsyncClient,
|
|
|
|
| 1392 |
# Create logger
|
| 1393 |
file_logger = AntigravityFileLogger(model, enable_logging)
|
| 1394 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1395 |
# Transform messages
|
| 1396 |
system_instruction, gemini_contents = self._transform_messages(messages, model)
|
| 1397 |
gemini_contents = self._fix_tool_response_grouping(gemini_contents)
|