From 50b1dccff3fb7d2fdded57e94c3b92aac4be11c3 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 31 Oct 2025 21:48:45 +0800 Subject: [PATCH] feat: support xAI Grok Live Search config (#3203) * Add xai_native_search configuration option * Implement xAI compatibility and search injection Add support for xAI integration with search parameters injection. * Refactor xAI handling in openai_source.py Removed the _is_xai method and updated xAI search injection logic. * Fix formatting of condition in default.py * Fix formatting in openai_source.py --- astrbot/core/config/default.py | 7 ++++++ .../core/provider/sources/openai_source.py | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 20e8e228f..b8a7e1853 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -771,6 +771,7 @@ CONFIG_METADATA_2 = { "timeout": 120, "model_config": {"model": "grok-2-latest", "temperature": 0.4}, "custom_extra_body": {}, + "xai_native_search": False, "modalities": ["text", "image", "tool_use"], }, "Anthropic": { @@ -1288,6 +1289,12 @@ CONFIG_METADATA_2 = { }, }, "items": { + "xai_native_search": { + "description": "启用原生搜索功能", + "type": "bool", + "hint": "启用后,将通过 xAI 的 Chat Completions 原生 Live Search 进行联网检索(按需计费)。仅对 xAI 提供商生效。", + "condition": {"provider": "xai"}, + }, "rerank_api_base": { "description": "重排序模型 API Base URL", "type": "string", diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index 09c284acb..361d0a4de 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -68,6 +68,28 @@ class ProviderOpenAIOfficial(Provider): model = model_config.get("model", "unknown") self.set_model(model) + def _maybe_inject_xai_search(self, payloads: dict, **kwargs): + """当开启 xAI 原生搜索时,向请求体注入 Live Search 参数。 + + - 仅在 provider_config.xai_native_search 为 True 时生效 + - 默认注入 {"mode": "auto"} + - 允许通过 kwargs 使用 xai_search_mode 覆盖(on/auto/off) + """ + if not bool(self.provider_config.get("xai_native_search", False)): + return + + mode = kwargs.get("xai_search_mode", "auto") + mode = str(mode).lower() + if mode not in ("auto", "on", "off"): + mode = "auto" + + # off 时不注入,保持与未开启一致 + if mode == "off": + return + + # OpenAI SDK 不识别的字段会在 _query/_query_stream 中放入 extra_body + payloads["search_parameters"] = {"mode": mode} + async def get_models(self): try: models_str = [] @@ -271,6 +293,9 @@ class ProviderOpenAIOfficial(Provider): payloads = {"messages": context_query, **model_config} + # xAI 原生搜索参数(最小侵入地在此处注入) + self._maybe_inject_xai_search(payloads, **kwargs) + return payloads, context_query async def _handle_api_error(