From 1bcd2c33a937bab803c5d46b5962c3db79624197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=87=83=E7=83=A7=E5=86=9B=E5=9B=A2=E5=9B=A2=E6=94=AF?= =?UTF-8?q?=E9=83=A8=E4=B9=A6=E8=AE=B0?= <94532689+konodiodaaaaa1@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:22:23 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=20Gemini=20?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=A3=B0=E6=98=8E=E9=98=B6=E6=AE=B5=E4=B8=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=9A=84=20examples=20=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add function to remove 'examples' field from Gemini tool list. --- .../core/provider/sources/openai_source.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index b19f3460dd..1607888997 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -527,6 +527,18 @@ async def _query(self, payloads: dict, tools: ToolSet | None) -> LLMResponse: omit_empty_parameter_field=omit_empty_param_field, ) if tool_list: + # 清洗Gemini中的examples字段 + if "gemini" in model: + def remove_examples(schema): + if isinstance(schema, dict): + schema.pop("examples", None) + for val in schema.values(): + remove_examples(val) + elif isinstance(schema, list): + for item in schema: + remove_examples(item) + + remove_examples(tool_list) payloads["tools"] = tool_list payloads["tool_choice"] = payloads.get("tool_choice", "auto") @@ -599,6 +611,18 @@ async def _query_stream( omit_empty_parameter_field=omit_empty_param_field, ) if tool_list: + # 清洗Gemini中的examples字段 + if "gemini" in model: + def remove_examples(schema): + if isinstance(schema, dict): + schema.pop("examples", None) + for val in schema.values(): + remove_examples(val) + elif isinstance(schema, list): + for item in schema: + remove_examples(item) + + remove_examples(tool_list) payloads["tools"] = tool_list payloads["tool_choice"] = payloads.get("tool_choice", "auto") From 0802f00485c9934f8069b5a7605697e58dab22ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=87=83=E7=83=A7=E5=86=9B=E5=9B=A2=E5=9B=A2=E6=94=AF?= =?UTF-8?q?=E9=83=A8=E4=B9=A6=E8=AE=B0?= <94532689+konodiodaaaaa1@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:39:56 +0800 Subject: [PATCH 2/2] Refactor Gemini tool list cleaning logic Refactored the tool list cleaning process for Gemini models by introducing a new static method to remove 'examples' fields from JSON Schema. --- .../core/provider/sources/openai_source.py | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index 1607888997..e3ad9aaa70 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -181,6 +181,15 @@ def _is_invalid_attachment_error(self, error: Exception) -> bool: return True return False + @staticmethod + def _clean_gemini_tool_list(schema: Any) -> Any: + """非破坏性地递归移除 JSON Schema 中的 examples 字段,以适配 Gemini。""" + if isinstance(schema, dict): + return {k: ProviderOpenAIOfficial._clean_gemini_tool_list(v) for k, v in schema.items() if k != "examples"} + if isinstance(schema, list): + return [ProviderOpenAIOfficial._clean_gemini_tool_list(i) for i in schema] + return schema + @classmethod def _encode_image_file_to_data_url( cls, @@ -528,17 +537,9 @@ async def _query(self, payloads: dict, tools: ToolSet | None) -> LLMResponse: ) if tool_list: # 清洗Gemini中的examples字段 - if "gemini" in model: - def remove_examples(schema): - if isinstance(schema, dict): - schema.pop("examples", None) - for val in schema.values(): - remove_examples(val) - elif isinstance(schema, list): - for item in schema: - remove_examples(item) - - remove_examples(tool_list) + model_basename = model.split("/")[-1] if "/" in model else model + if model_basename.startswith("gemini"): + tool_list = self._clean_gemini_tool_list(tool_list) payloads["tools"] = tool_list payloads["tool_choice"] = payloads.get("tool_choice", "auto") @@ -612,17 +613,9 @@ async def _query_stream( ) if tool_list: # 清洗Gemini中的examples字段 - if "gemini" in model: - def remove_examples(schema): - if isinstance(schema, dict): - schema.pop("examples", None) - for val in schema.values(): - remove_examples(val) - elif isinstance(schema, list): - for item in schema: - remove_examples(item) - - remove_examples(tool_list) + model_basename = model.split("/")[-1] if "/" in model else model + if model_basename.startswith("gemini"): + tool_list = self._clean_gemini_tool_list(tool_list) payloads["tools"] = tool_list payloads["tool_choice"] = payloads.get("tool_choice", "auto")