2026-02-05 15:57:52 +08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from src.api.handlers.base.utils import get_format_converter_registry
|
2026-02-16 11:00:48 +08:00
|
|
|
from src.core.api_format.conversion.thinking_cache import signature_cache
|
2026-02-06 16:37:06 +08:00
|
|
|
from src.services.provider.adapters.antigravity.constants import DUMMY_THOUGHT_SIGNATURE
|
2026-02-05 15:57:52 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def _reset_sig_cache() -> None:
|
|
|
|
|
# Module-global cache; tests must isolate state.
|
2026-02-06 16:37:06 +08:00
|
|
|
signature_cache.clear()
|
2026-02-05 15:57:52 +08:00
|
|
|
|
|
|
|
|
|
2026-02-06 16:37:06 +08:00
|
|
|
def test_antigravity_converts_claude_thinking_block_to_gemini_thought_part_prefers_payload_sig() -> (
|
|
|
|
|
None
|
|
|
|
|
):
|
2026-02-05 15:57:52 +08:00
|
|
|
_reset_sig_cache()
|
|
|
|
|
|
|
|
|
|
req = {
|
|
|
|
|
"model": "gemini-3-pro",
|
|
|
|
|
"max_tokens": 64,
|
|
|
|
|
"thinking": {"type": "enabled", "budget_tokens": 1000},
|
|
|
|
|
"messages": [
|
|
|
|
|
{"role": "user", "content": [{"type": "text", "text": "hi"}]},
|
|
|
|
|
{
|
|
|
|
|
"role": "assistant",
|
|
|
|
|
"content": [
|
|
|
|
|
{"type": "thinking", "thinking": "t1", "signature": "sig-1"},
|
|
|
|
|
{"type": "text", "text": "ok"},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registry = get_format_converter_registry()
|
2026-02-07 02:59:02 +08:00
|
|
|
out = registry.convert_request(req, "claude:chat", "gemini:chat", target_variant="antigravity")
|
2026-02-05 15:57:52 +08:00
|
|
|
|
|
|
|
|
assert isinstance(out.get("contents"), list)
|
|
|
|
|
model_turn = out["contents"][1]
|
|
|
|
|
assert model_turn["role"] == "model"
|
|
|
|
|
parts = model_turn["parts"]
|
|
|
|
|
assert parts[0]["thought"] is True
|
|
|
|
|
assert parts[0]["text"] == "t1"
|
|
|
|
|
assert parts[0]["thoughtSignature"] == "sig-1"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_antigravity_uses_dummy_signature_for_gemini_when_missing() -> None:
|
|
|
|
|
_reset_sig_cache()
|
|
|
|
|
|
|
|
|
|
req = {
|
|
|
|
|
"model": "gemini-3-pro",
|
|
|
|
|
"max_tokens": 64,
|
|
|
|
|
"thinking": {"type": "enabled", "budget_tokens": 1000},
|
|
|
|
|
"messages": [
|
|
|
|
|
{"role": "user", "content": [{"type": "text", "text": "hi"}]},
|
|
|
|
|
{
|
|
|
|
|
"role": "assistant",
|
|
|
|
|
"content": [
|
|
|
|
|
{"type": "thinking", "thinking": "t2"},
|
|
|
|
|
{"type": "text", "text": "ok"},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registry = get_format_converter_registry()
|
2026-02-07 02:59:02 +08:00
|
|
|
out = registry.convert_request(req, "claude:chat", "gemini:chat", target_variant="antigravity")
|
2026-02-05 15:57:52 +08:00
|
|
|
|
|
|
|
|
parts = out["contents"][1]["parts"]
|
|
|
|
|
assert parts[0]["thought"] is True
|
|
|
|
|
assert parts[0]["text"] == "t2"
|
|
|
|
|
assert parts[0]["thoughtSignature"] == DUMMY_THOUGHT_SIGNATURE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_antigravity_drops_unsigned_thinking_for_non_gemini_models() -> None:
|
|
|
|
|
_reset_sig_cache()
|
|
|
|
|
|
|
|
|
|
req = {
|
|
|
|
|
"model": "claude-sonnet-4-5",
|
|
|
|
|
"max_tokens": 64,
|
|
|
|
|
"thinking": {"type": "enabled", "budget_tokens": 1000},
|
|
|
|
|
"messages": [
|
|
|
|
|
{"role": "user", "content": [{"type": "text", "text": "hi"}]},
|
|
|
|
|
{
|
|
|
|
|
"role": "assistant",
|
|
|
|
|
"content": [
|
|
|
|
|
{"type": "thinking", "thinking": "t3"},
|
|
|
|
|
{"type": "text", "text": "ok"},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registry = get_format_converter_registry()
|
2026-02-07 02:59:02 +08:00
|
|
|
out = registry.convert_request(req, "claude:chat", "gemini:chat", target_variant="antigravity")
|
2026-02-05 15:57:52 +08:00
|
|
|
|
|
|
|
|
parts = out["contents"][1]["parts"]
|
|
|
|
|
assert all(p.get("thought") is not True for p in parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_antigravity_inserts_dummy_thought_for_last_assistant_when_thinking_enabled() -> None:
|
|
|
|
|
_reset_sig_cache()
|
|
|
|
|
|
|
|
|
|
req = {
|
|
|
|
|
"model": "gemini-3-pro",
|
|
|
|
|
"max_tokens": 64,
|
|
|
|
|
"thinking": {"type": "enabled", "budget_tokens": 1000},
|
|
|
|
|
"messages": [
|
|
|
|
|
{"role": "user", "content": [{"type": "text", "text": "hi"}]},
|
|
|
|
|
{"role": "assistant", "content": [{"type": "text", "text": "prefill"}]},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registry = get_format_converter_registry()
|
2026-02-07 02:59:02 +08:00
|
|
|
out = registry.convert_request(req, "claude:chat", "gemini:chat", target_variant="antigravity")
|
2026-02-05 15:57:52 +08:00
|
|
|
|
|
|
|
|
parts = out["contents"][1]["parts"]
|
|
|
|
|
assert parts[0]["thought"] is True
|
|
|
|
|
assert parts[0]["thoughtSignature"] == DUMMY_THOUGHT_SIGNATURE
|
|
|
|
|
assert parts[1]["text"] == "prefill"
|