XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

fix: Update thought signature handling and improve tool call processing in Antigravity and GeminiCLI providers

0217ca24
hlohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

7 个文件 +45 -28
Modified g4f/Provider/needs_auth/Antigravity.py +13 -7
@@ -992,9 +992,10 @@ class AntigravityProvider:
992 992 "name": tool_call["function"]["name"],
993 993 "args": json.loads(tool_call["function"]["arguments"]),
994 994 }
995 # Restore thought_signature required by Gemini thinking models
996 if "thought_signature" in tool_call:
997 func_call["thoughtSignature"] = tool_call["thought_signature"]
995 # Restore thoughtSignature for Gemini thinking models when available
996 thought_sig = tool_call.get("extra_content", {}).get("google", {}).get("thought_signature")
997 if thought_sig:
998 func_call["thoughtSignature"] = thought_sig
998 999 parts.append({"functionCall": func_call})
999 1000
1000 1001 # Handle string content
@@ -1256,7 +1257,7 @@ class AntigravityProvider:
1256 1257
1257 1258 # Function calls from Gemini
1258 1259 elif "functionCall" in part:
1259 tool_calls.append(part["functionCall"])
1260 tool_calls.append(part)
1260 1261
1261 1262 # Text content
1262 1263 elif "text" in part:
@@ -1275,7 +1276,8 @@ class AntigravityProvider:
1275 1276 if tool_calls:
1276 1277 # Convert Gemini tool calls to OpenAI format
1277 1278 openai_tool_calls = []
1278 for i, tc in enumerate(tool_calls):
1279 for i, part in enumerate(tool_calls):
1280 tc = part["functionCall"]
1279 1281 tool_call_obj = {
1280 1282 "id": f"call_{i}_{tc.get('name', 'unknown')}",
1281 1283 "type": "function",
@@ -1285,8 +1287,12 @@ class AntigravityProvider:
1285 1287 }
1286 1288 }
1287 1289 # Preserve thought_signature for thinking models (Gemini 2.5+)
1288 if "thoughtSignature" in tc:
1289 tool_call_obj["thought_signature"] = tc["thoughtSignature"]
1290 if "thoughtSignature" in part:
1291 tool_call_obj["extra_content"] = {
1292 "google": {
1293 "thought_signature": tc["thought_signature"]
1294 }
1295 }
1290 1296 openai_tool_calls.append(tool_call_obj)
1291 1297 yield ToolCalls(openai_tool_calls)
1292 1298
Modified g4f/Provider/needs_auth/GeminiCLI.py +24 -14
@@ -572,36 +572,40 @@ class GeminiCLIProvider():
572 572
573 573 # Handle tool role (OpenAI style)
574 574 if msg["role"] == "tool":
575 tool_result = msg.get("content", "")
575 576 parts = [
576 577 {
577 578 "functionResponse": {
578 579 "name": msg.get("tool_call_id", "unknown_function"),
579 580 "response": {
580 581 "result": (
581 msg["content"]
582 if isinstance(msg["content"], str)
583 else json.dumps(msg["content"])
582 tool_result
583 if isinstance(tool_result, str)
584 else json.dumps(tool_result)
584 585 )
585 586 },
586 587 }
587 588 }
588 ],
589 ]
589 590
590 591 # Handle assistant messages with tool calls
591 592 elif msg["role"] == "assistant" and msg.get("tool_calls"):
592 593 parts = []
593 if isinstance(msg["content"], str) and msg["content"].strip():
594 parts.append({"text": msg["content"]})
595 for tool_call in msg["tool_calls"]:
594 content = msg.get("content")
595 if isinstance(content, str) and content.strip():
596 parts.append({"text": content})
597 for idx, tool_call in enumerate(msg["tool_calls"]):
596 598 if tool_call.get("type") == "function":
597 599 func_call = {
598 600 "name": tool_call["function"]["name"],
599 601 "args": json.loads(tool_call["function"]["arguments"]),
600 602 }
601 603 # Restore thought_signature required by Gemini thinking models
602 if "thought_signature" in tool_call:
603 func_call["thoughtSignature"] = tool_call["thought_signature"]
604 parts.append({"functionCall": func_call})
604 thought_sig = tool_call.get("extra_content", {}).get("google", {}).get("thought_signature", "skip_thought_signature_validator")
605 if idx == 0: # Only add skip_thought_signature_validator for the first tool call if no signature is present
606 parts.append({"functionCall": func_call, "thoughtSignature": thought_sig})
607 else:
608 parts.append({"functionCall": func_call})
605 609
606 610 # Handle string content
607 611 elif isinstance(msg["content"], str):
@@ -609,6 +613,7 @@ class GeminiCLIProvider():
609 613
610 614 # Handle array content (possibly multimodal)
611 615 elif isinstance(msg["content"], list):
616 parts = []
612 617 for content in msg["content"]:
613 618 ctype = content.get("type")
614 619 if ctype == "text":
@@ -822,7 +827,7 @@ class GeminiCLIProvider():
822 827
823 828 # Function calls from Gemini
824 829 elif "functionCall" in part:
825 tool_calls.append(part["functionCall"])
830 tool_calls.append(part)
826 831
827 832 # Text content
828 833 elif "text" in part:
@@ -843,7 +848,8 @@ class GeminiCLIProvider():
843 848 if tool_calls:
844 849 # Convert Gemini tool calls to OpenAI format
845 850 openai_tool_calls = []
846 for i, tc in enumerate(tool_calls):
851 for i, part in enumerate(tool_calls):
852 tc = part["functionCall"]
847 853 tool_call_obj = {
848 854 "id": f"call_{i}_{tc.get('name', 'unknown')}",
849 855 "type": "function",
@@ -853,8 +859,12 @@ class GeminiCLIProvider():
853 859 }
854 860 }
855 861 # Preserve thought_signature for thinking models (Gemini 2.5+)
856 if "thoughtSignature" in tc:
857 tool_call_obj["thought_signature"] = tc["thoughtSignature"]
862 if "thoughtSignature" in part:
863 tool_call_obj["extra_content"] = {
864 "google": {
865 "thought_signature": part["thoughtSignature"]
866 }
867 }
858 868 openai_tool_calls.append(tool_call_obj)
859 869 yield ToolCalls(openai_tool_calls)
860 870 if usage_metadata:
Modified g4f/client/stubs.py +1 -0
@@ -70,6 +70,7 @@ class ToolCallModel(BaseModel):
70 70 id: str
71 71 type: str
72 72 function: ToolFunctionModel
73 extra_content: Optional[dict] = None
73 74
74 75 @classmethod
75 76 def model_construct(cls, function=None, index=0, **kwargs):
Modified g4f/config.py +3 -3
@@ -15,12 +15,12 @@ def get_config_dir() -> Path:
15 15 elif sys.platform == "darwin":
16 16 return Path.home() / "Library" / "Application Support"
17 17 return Path.home() / ".config"
18 config_dir = Path.home() / ".config"
18 config_dir = Path.home() / ".g4f"
19 19 if not config_dir.exists():
20 20 config_dir = get_fallback_config_dir()
21 21 if not config_dir.exists():
22 22 config_dir = Path.home() / ".g4f"
23 config_dir.mkdir(parents=True, exist_ok=True)
23 config_dir = config_dir / "g4f"
24 24 return config_dir
25 25
26 26 DEFAULT_PORT = 1337
@@ -28,7 +28,7 @@ DEFAULT_TIMEOUT = 600
28 28 DEFAULT_STREAM_TIMEOUT = 30
29 29
30 30 PACKAGE_NAME = "g4f"
31 CONFIG_DIR = get_config_dir() / PACKAGE_NAME
31 CONFIG_DIR = get_config_dir()
32 32 COOKIES_DIR = CONFIG_DIR / "cookies"
33 33 CUSTOM_COOKIES_DIR = "./har_and_cookies"
34 34 ORGANIZATION = "gpt4free"
Modified g4f/cookies.py +1 -1
@@ -226,7 +226,7 @@ def read_cookie_files(dir_path: Optional[str] = None, domains_filter: Optional[L
226 226 from dotenv import load_dotenv
227 227 env_path = os.path.join(dir_path, ".env")
228 228 load_dotenv(env_path, override=True)
229 debug.log(f"Read cookies: Loaded env vars from {env_path}")
229 debug.log(f"Loaded env vars from {env_path}: {os.path.exists(env_path)}")
230 230 except ImportError:
231 231 debug.error("Warning: 'python-dotenv' is not installed. Env vars not loaded.")
232 232
Modified g4f/providers/base_provider.py +2 -2
@@ -296,11 +296,11 @@ class AsyncGeneratorProvider(AbstractProvider):
296 296 """Get the quota information for the API key."""
297 297 if cls.quota_url is None:
298 298 raise NotImplementedError(f"{cls.__name__} does not implement get_quota method")
299 if not api_key:
299 if not api_key and cls.needs_auth:
300 300 raise MissingAuthError("API key is required.")
301 301 headers = {
302 302 "authorization": f"Bearer {api_key}"
303 }
303 } if api_key else {}
304 304 async with ClientSession() as session:
305 305 async with session.get(cls.quota_url, headers=headers) as response:
306 306 await raise_for_status(response)
Modified scripts/setup-openclaw.sh +1 -1
@@ -35,7 +35,7 @@ models:
35 35 providers:
36 36 - provider: "GeminiCLI"
37 37 model: "gemini-3-flash-preview"
38 condition: "quota.models.gemini-3-flash-preview.remaining > 0 and error_count < 3"
38 condition: "quota.models.gemini-3-flash-preview.remainingFraction > 0 and error_count < 3"
39 39 - provider: "Antigravity"
40 40 model: "gemini-3-flash"
41 41 condition: "quota.models.gemini-3-flash.quotaInfo.remainingFraction > 0 and error_count < 3"