Skip to content

feat(provider): Integrate OpenAI Responses API with native web search support.#5953

Open
outlook84 wants to merge 7 commits intoAstrBotDevs:masterfrom
outlook84:fix/openai-responses-streaming-tools
Open

feat(provider): Integrate OpenAI Responses API with native web search support.#5953
outlook84 wants to merge 7 commits intoAstrBotDevs:masterfrom
outlook84:fix/openai-responses-streaming-tools

Conversation

@outlook84
Copy link

@outlook84 outlook84 commented Mar 9, 2026

支持 OpenAI 新版 Responses API 和网页搜索原生工具。

Modifications / 改动点

核心改动文件有 5 个:

  • astrbot/core/provider/sources/openai_source.py
  • astrbot/core/config/default.py
  • dashboard/src/i18n/locales/zh-CN/features/config-metadata.json
  • dashboard/src/i18n/locales/en-US/features/config-metadata.json
  • tests/test_openai_source.py

它实现的功能可以概括成三块:

  1. OpenAI Provider 增加 Responses API 支持
    在 openai_source.py 里新增了 use_responses_api 开关,并在请求路径上区分:

    • 传统 /v1/chat/completions
    • 新的 /v1/responses
  2. 支持 OpenAI 原生工具
    增加了一个能力开关:

    • oa_native_web_search

    启用后会强制走 Responses API,并使用 OpenAI 原生工具,而不是 AstrBot 原本的函数工具链。

  3. 配置项和测试补齐

    • 在 default.py 给 provider 模板加了这几个新配置项
    • 在中英文 config-metadata.json / config-metadata.json 补了 WebUI 文案
    • 在 test_openai_source.py 增加了对应行为测试
  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

firefox_fMOisMtHsn firefox_z2iGJvvQM9

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

在基于 OpenAI 的 provider 栈中新增对 Responses API 的支持,并将其接入现有的查询/流式处理管线,包括在聊天消息格式与 Responses 输入/输出之间进行转换。

新功能:

  • 引入一个可配置开关,使 OpenAI Responses API 能与现有的 chat completions 端点并行使用。
  • 增加对 OpenAI 原生 Web 搜索和代码解释器工具的支持,通过 provider 配置开关启用,并映射到 Responses 的 tools 接口中。

增强内容:

  • 为兼容 OpenAI 的后端扩展 provider 模板,增加用于选择使用 Responses API 和原生工具的新标志位。
  • 改进 token 使用量统计,通过处理 Responses API 的使用字段,并区分缓存与非缓存的输入 tokens。

测试:

  • 新增单元测试,覆盖 Responses 负载构造、原生工具优先于函数工具的策略、Responses 补全结果解析、无效工具参数的错误处理,以及流式分片行为。
Original summary in English

Summary by Sourcery

Add Responses API support to the OpenAI-based provider stack and wire it into the existing query/streaming pipeline, including conversion between chat-style messages and Responses inputs/outputs.

New Features:

  • Introduce a configurable switch to use the OpenAI Responses API alongside the existing chat completions endpoint.
  • Add support for OpenAI native web search and code interpreter tools, enabled via provider configuration flags and mapped into the Responses tools interface.

Enhancements:

  • Extend provider templates for OpenAI-compatible backends with new flags for selecting Responses API and native tool usage.
  • Improve token usage tracking by handling Responses API usage fields and distinguishing cached vs non-cached input tokens.

Tests:

  • Add unit tests covering Responses payload construction, native tool precedence over function tools, Responses completion parsing, error handling for invalid tool arguments, and streaming chunk behavior.

Summary by Sourcery

为 OpenAI 兼容的提供方栈添加 OpenAI Responses API 支持,并在启用时通过该 API 路由查询/流,包括原生网页搜索工具以及更新后的用量追踪。

新功能:

  • 引入一个可配置的开关,用于在基于 OpenAI 的提供方之间切换 chat completions/v1/responses API。
  • 添加一个提供方选项以启用 OpenAI 原生网页搜索工具,在启用时强制使用 Responses API,并绕过 AstrBot 的函数工具。

增强:

  • 扩展 OpenAI 兼容的提供方模板,增加共享默认值以及新的与 Responses 相关的配置字段。
  • 将对话式消息、工具以及多媒体内容转换为适用于 Responses API 的输入/输出格式,并分别追踪缓存输入与非缓存输入的 tokens 用量。

测试:

  • 添加单元测试,覆盖 Responses 请求负载的构造、原生工具优先于函数工具的优先级逻辑、Responses 补全结果的解析与错误处理、用量提取以及流式分块行为。
Original summary in English

Summary by Sourcery

Add OpenAI Responses API support to the OpenAI-compatible provider stack and route queries/streams through it when enabled, including native web search tooling and updated usage tracking.

New Features:

  • Introduce a configurable flag to switch OpenAI-based providers between chat completions and the /v1/responses API.
  • Add a provider option to enable OpenAI native web search tools, forcing use of the Responses API and bypassing AstrBot function tools.

Enhancements:

  • Extend OpenAI-compatible provider templates with shared defaults and new Responses-related configuration fields.
  • Convert chat-style messages, tools, and multimedia content into Responses API input/output formats and track token usage with cached vs non-cached inputs.

Tests:

  • Add unit tests covering Responses payload construction, native tool precedence over function tools, Responses completion parsing and error handling, usage extraction, and streaming chunk behavior.

@auto-assign auto-assign bot requested review from LIghtJUNction and anka-afk March 9, 2026 13:33
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Mar 9, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the OpenAI provider by integrating the latest Responses API, which unlocks powerful native tools like web search and code interpreter. The changes include core logic for API interaction, message conversion, and tool handling, alongside necessary configuration updates and UI localizations. This enhancement allows users to tap into advanced OpenAI capabilities directly, offering more robust and integrated functionality.

Highlights

  • OpenAI Responses API Integration: Implemented support for OpenAI's new Responses API, allowing the system to utilize the /v1/responses endpoint instead of /v1/chat/completions when enabled.
  • Native Web Search and Code Interpreter Support: Added functionality to leverage OpenAI's native web search and code interpreter tools, which are exclusively available through the Responses API. Enabling these tools will override AstrBot's custom function toolchain.
  • New Configuration Options: Introduced new boolean configuration parameters (use_responses_api, oa_native_web_search, oa_native_code_interpreter) across various chat provider templates to control the new features.
  • User Interface Updates: Updated the English and Chinese UI metadata to include descriptions and hints for the newly added configuration options, ensuring clarity for users.
  • Comprehensive Testing: Added new unit tests to validate the correct construction of Responses API payloads, the behavior of native tools, and the parsing of Responses API completions, including streaming responses.
Changelog
  • astrbot/core/config/default.py
    • Added 'use_responses_api', 'oa_native_web_search', and 'oa_native_code_interpreter' boolean fields to all chat provider templates, defaulting to False.
    • Updated the configuration metadata structure to include descriptions and hints for the new fields.
  • astrbot/core/provider/sources/openai_source.py
    • Imported new types from openai.types.responses for Responses API handling.
    • Added a static helper method _as_bool to robustly convert various input types to boolean.
    • Modified the __init__ method to store responses_default_params and initialize use_responses_api based on provider configuration.
    • Implemented _get_openai_native_tools, _openai_native_tools_enabled, and _should_use_responses_api methods to manage native tool activation and Responses API usage.
    • Updated _query and _query_stream methods to conditionally call _query_responses or _query_stream_responses based on configuration.
    • Refactored parameter handling in _query and _query_stream to use chat_default_params for traditional chat completions.
    • Added _convert_openai_tools_to_responses to transform AstrBot's tool format to OpenAI Responses API format.
    • Implemented _normalize_message_content_to_list and _convert_message_parts_to_responses_content for robust message content conversion.
    • Developed _convert_openai_messages_to_responses_input to map OpenAI chat messages to the Responses API input format, handling various roles and content types.
    • Created _build_responses_payload to construct the request payload for the Responses API, including native tools and custom extra body parameters.
    • Added _query_responses for non-streaming Responses API calls and _query_stream_responses for streaming Responses API calls, handling events and final response parsing.
    • Implemented _extract_responses_usage to parse token usage from Responses API responses.
    • Developed _parse_responses_completion to extract text, reasoning, and tool calls from the Responses API response object.
  • dashboard/src/i18n/locales/en-US/features/config-metadata.json
    • Added English descriptions and hints for 'use_responses_api', 'oa_native_web_search', and 'oa_native_code_interpreter' in the configuration metadata.
  • dashboard/src/i18n/locales/zh-CN/features/config-metadata.json
    • Added Chinese descriptions and hints for 'use_responses_api', 'oa_native_web_search', and 'oa_native_code_interpreter' in the configuration metadata.
  • tests/test_openai_source.py
    • Imported OpenAIResponse from openai.types.responses for testing.
    • Added test_build_responses_payload_converts_messages_and_tools to verify correct payload construction for the Responses API, including message and tool conversion.
    • Added test_native_tools_force_responses_mode_and_override_function_tools to confirm native tools enable Responses API mode and take precedence over AstrBot's function tools.
    • Added test_parse_responses_completion_extracts_text_reasoning_and_tool_calls to test parsing of text, reasoning, and tool calls from a Responses API completion.
    • Added test_parse_responses_completion_raises_on_invalid_tool_arguments to ensure an exception is raised for malformed tool arguments in Responses API.
    • Added test_query_stream_responses_yields_distinct_text_and_reasoning_chunks to verify correct handling and yielding of streaming text and reasoning chunks from the Responses API.
Activity
  • The pull request was created by outlook84 to integrate OpenAI's Responses API and native tools.
  • Screenshots were provided by the author to demonstrate the new functionality and UI changes.
  • The author confirmed that this is not a breaking change.
  • The author verified that the changes are well-tested and provided evidence.
  • The author confirmed that no new dependencies were introduced, or if so, they were properly added.
  • The author confirmed that no malicious code was introduced.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@dosubot dosubot bot added the area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. label Mar 9, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/openai_source.py" line_range="691-692" />
<code_context>
             output=completion_tokens,
         )

+    def _extract_responses_usage(self, usage: ResponseUsage) -> TokenUsage:
+        cached = usage.input_tokens_details.cached_tokens or 0
+        input_tokens = usage.input_tokens or 0
+        output_tokens = usage.output_tokens or 0
</code_context>
<issue_to_address>
**issue (bug_risk):** 当提取 Responses API 的 token 使用情况时,如果 `usage.input_tokens_details` 为 None,可能会引发 AttributeError。

在 `_extract_responses_usage` 中,`cached = usage.input_tokens_details.cached_tokens or 0` 假设 `input_tokens_details` 一定有值。但某些 Responses API 的负载中,`input_tokens_details` 可能为 `None` 或被省略,这会导致 AttributeError。建议在访问前进行保护,例如:

```python
details = getattr(usage, "input_tokens_details", None) or {}
cached = getattr(details, "cached_tokens", 0) or 0
```

或者在读取 `cached_tokens` 之前显式判断是否为 `None`。
</issue_to_address>

Sourcery 对开源项目免费 —— 如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进评审质量。
Original comment in English

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/openai_source.py" line_range="691-692" />
<code_context>
             output=completion_tokens,
         )

+    def _extract_responses_usage(self, usage: ResponseUsage) -> TokenUsage:
+        cached = usage.input_tokens_details.cached_tokens or 0
+        input_tokens = usage.input_tokens or 0
+        output_tokens = usage.output_tokens or 0
</code_context>
<issue_to_address>
**issue (bug_risk):** Potential AttributeError if usage.input_tokens_details is None when extracting Responses API token usage.

In `_extract_responses_usage`, `cached = usage.input_tokens_details.cached_tokens or 0` assumes `input_tokens_details` is always set. Some Responses API payloads may have `input_tokens_details` as `None` or omit it, which would raise an AttributeError. Consider guarding the access, e.g.:

```python
details = getattr(usage, "input_tokens_details", None) or {}
cached = getattr(details, "cached_tokens", 0) or 0
```

or equivalently check for `None` before reading `cached_tokens`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

本次 PR 集成了 OpenAI 最新的 Responses API,并增加了对原生网页搜索和代码解释器工具的支持。openai_source.py 中的核心逻辑改动结构清晰,妥善地处理了新的 API 端点、消息格式以及流式和非流式请求。新功能也同步更新到了配置和 UI 中。新增的测试用例很全面,覆盖了多种场景。

我有几点建议可以提高代码的可维护性和一致性。具体来说,我指出了默认配置文件中的代码重复问题,一个改进响应解析逻辑中类型检查的方法,以及新测试代码中的一个风格问题。

总体而言,这是一次很棒的功能增强。

Comment on lines +1084 to +1086
"use_responses_api": False,
"oa_native_web_search": False,
"oa_native_code_interpreter": False,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这三个新的配置项在此文件中为几乎所有 OpenAI 兼容的 provider 重复添加(约20次),导致了严重的代码重复,使未来的修改变得困难。为了提高可维护性,建议将这些选项定义在一个公共字典中,然后合并到每个 provider 的配置中。这将集中管理默认值,使配置更易于维护。例如:

OPENAI_COMPATIBLE_DEFAULTS = {
    "use_responses_api": False,
    "oa_native_web_search": False,
    "oa_native_code_interpreter": False,
}

# 在定义 provider 配置时
"OpenAI": {
    ...,
    **OPENAI_COMPATIBLE_DEFAULTS,
    "custom_headers": {},
},

此建议适用于此文件中所有类似的代码块。

Comment on lines +901 to +916
else:
item_type = getattr(item, "type", "")
if item_type == "function_call" and tools is not None:
try:
args = json.loads(item.arguments)
except json.JSONDecodeError:
logger.error(
"Responses API function_call arguments is not valid JSON: %s",
item.arguments,
)
raise Exception(
f"Responses API function_call arguments is not valid JSON: {item.arguments}"
)
tool_args.append(args)
tool_names.append(item.name)
tool_ids.append(item.call_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

为了与其他响应项类型(如 ResponseOutputMessage)的处理方式保持一致,并增强类型安全性,建议使用 isinstance 来检查 FunctionCall 类型。

这需要在文件顶部添加以下导入:

from openai.types.responses.function_call import FunctionCall
            elif isinstance(item, FunctionCall) and tools is not None:
                try:
                    args = json.loads(item.arguments)
                except json.JSONDecodeError:
                    logger.error(
                        "Responses API function_call arguments is not valid JSON: %s",
                        item.arguments,
                    )
                    raise Exception(
                        f"Responses API function_call arguments is not valid JSON: {item.arguments}"
                    )
                tool_args.append(args)
                tool_names.append(item.name)
                tool_ids.append(item.call_id)

Comment on lines +267 to +269
import asyncio

asyncio.run(provider.terminate())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

根据 PEP 8 风格指南,导入语句应放在文件的顶部。在 finally 块中导入 asyncio 是不常规的做法,并且会使模块的依赖关系不够清晰。请将 import asyncio 移动到文件的顶部。此评论同样适用于 test_native_tools_force_responses_mode_and_override_function_tools 测试函数中的导入。

Suggested change
import asyncio
asyncio.run(provider.terminate())
asyncio.run(provider.terminate())
References
  1. According to PEP 8, import statements should be placed at the top of the file, after any module docstrings and before any module-level global variables and constants. (link)

@outlook84
Copy link
Author

代码执行器输出渲染效果不行,明天修一下。

@outlook84 outlook84 marked this pull request as draft March 9, 2026 23:35
@outlook84 outlook84 changed the title feat(provider): Integrate OpenAI Responses API with native web search and code interpreter support. feat(provider): Integrate OpenAI Responses API with native web search support. Mar 10, 2026
@outlook84
Copy link
Author

展示代码执行器涉及的代码太多了,暂时放弃。

@outlook84 outlook84 marked this pull request as ready for review March 10, 2026 05:48
@auto-assign auto-assign bot requested a review from Raven95676 March 10, 2026 05:48
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出了一些总体反馈:

  • 新增的 Responses 专用转换逻辑(尤其是 _convert_openai_messages_to_responses_input_build_responses_payload)现在已经变得相当庞大且复杂;可以考虑将其拆分成更小、更聚焦的辅助函数,或者在角色/工具映射规则附近添加简短的行内注释,以便未来修改时更安全、更易于理解。
  • _query_stream_responses 中,你只处理了 response.output_text.deltaresponse.reasoning_text.delta 事件,其余的都延后到最终的 response.completed 再处理;如果预期 API 会返回流式的 function/tool-call 事件,那么可能值得在这里按增量进行处理,或者明确说明:工具调用只会在流结束后才可用。
  • _as_bool 这个辅助函数是一个普适的配置解析器;如果其他 provider 或配置路径也需要类似的行为,可以考虑把这个工具函数集中放到一个共享模块中,以避免在真值字符串解析上的微妙不一致。
供 AI 代理使用的提示
Please address the comments from this code review:

## Overall Comments
- The new Responses-specific conversion logic (especially `_convert_openai_messages_to_responses_input` and `_build_responses_payload`) has grown quite large and intricate; consider breaking it into smaller, focused helpers or adding brief inline comments around the role/tool mapping rules to make future changes safer and easier to reason about.
- In `_query_stream_responses` you only handle `response.output_text.delta` and `response.reasoning_text.delta` events and defer everything else to the final `response.completed`; if streaming function/tool-call events are expected from the API, it may be worth either handling them incrementally here or explicitly documenting that tool calls are only available once the stream completes.
- The `_as_bool` helper is a generally useful configuration parser; if other providers or config paths need similar behavior, consider centralizing this utility in a shared module to avoid subtle inconsistencies in how truthy string values are interpreted.

Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English

Hey - I've left some high level feedback:

  • The new Responses-specific conversion logic (especially _convert_openai_messages_to_responses_input and _build_responses_payload) has grown quite large and intricate; consider breaking it into smaller, focused helpers or adding brief inline comments around the role/tool mapping rules to make future changes safer and easier to reason about.
  • In _query_stream_responses you only handle response.output_text.delta and response.reasoning_text.delta events and defer everything else to the final response.completed; if streaming function/tool-call events are expected from the API, it may be worth either handling them incrementally here or explicitly documenting that tool calls are only available once the stream completes.
  • The _as_bool helper is a generally useful configuration parser; if other providers or config paths need similar behavior, consider centralizing this utility in a shared module to avoid subtle inconsistencies in how truthy string values are interpreted.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new Responses-specific conversion logic (especially `_convert_openai_messages_to_responses_input` and `_build_responses_payload`) has grown quite large and intricate; consider breaking it into smaller, focused helpers or adding brief inline comments around the role/tool mapping rules to make future changes safer and easier to reason about.
- In `_query_stream_responses` you only handle `response.output_text.delta` and `response.reasoning_text.delta` events and defer everything else to the final `response.completed`; if streaming function/tool-call events are expected from the API, it may be worth either handling them incrementally here or explicitly documenting that tool calls are only available once the stream completes.
- The `_as_bool` helper is a generally useful configuration parser; if other providers or config paths need similar behavior, consider centralizing this utility in a shared module to avoid subtle inconsistencies in how truthy string values are interpreted.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@outlook84 outlook84 force-pushed the fix/openai-responses-streaming-tools branch from 81f2cc1 to ea53bf9 Compare March 10, 2026 11:13
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant