Skip to content

feat(provider): 在请求头中新增 User-Agent 预设配置#5460

Open
piexian wants to merge 3 commits intoAstrBotDevs:masterfrom
piexian:feat/provider-custom-headers-default
Open

feat(provider): 在请求头中新增 User-Agent 预设配置#5460
piexian wants to merge 3 commits intoAstrBotDevs:masterfrom
piexian:feat/provider-custom-headers-default

Conversation

@piexian
Copy link
Contributor

@piexian piexian commented Feb 25, 2026

主要解决 WebUI 中请求头配置不直观、且并非所有供应商都默认显示 custom_headers 的问题。通过统一展示并提供 User-Agent 等预设字段,降低某些api网站开启 Cloudflare Bot 被误拦截风险。

Modifications / 改动点

  • 修改 astrbot/core/config/default.py

    • custom_headers 增加 template_schema 预设字段:User-AgentAcceptAccept-Language
    • 为所有 provider config_template(chat_completion / agent_runner / speech_to_text / text_to_speech / embedding / rerank)补齐默认 custom_headers: {}
  • 修改 dashboard/src/composables/useProviderSources.ts

    • 加载已有 provider_sourcesproviders 时自动补齐缺失的 custom_headers,保证旧配置在编辑时也能显示该项。
    • 新增模型 provider 时默认写入 custom_headers: {}
  • 修改i18n文案:

    • dashboard/src/i18n/locales/zh-CN/features/config-metadata.json
    • dashboard/src/i18n/locales/en-US/features/config-metadata.json
    • 补充 custom_headers.template_schema 的字段名称与提示信息。
  • This is NOT a breaking change. / 这不是一个破坏性变更。

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

image

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

为所有 provider 配置添加可配置的 HTTP 自定义请求头预设,并确保它们在 Web 界面中可见且有默认值。

新功能:

  • 在 provider 配置中引入自定义 HTTP 请求头的预设模板 schema,包括 User-AgentAcceptAccept-Language
  • 在所有 provider 模板以及新创建的 provider 模型中,将 custom_headers 默认设置为空对象。

增强:

  • 规范已加载的 provider 源和 provider,使其始终包含有效的 custom_headers 对象,以在控制台中保持向后兼容性。

文档:

  • 更新中文和英文配置元数据文本,记录新的 custom_headers 预设字段。
Original summary in English

Summary by Sourcery

Add configurable HTTP custom headers with presets to all provider configurations and ensure they are visible and defaulted in the Web UI.

New Features:

  • Introduce a preset template schema for custom HTTP headers including User-Agent, Accept, and Accept-Language in provider configuration.
  • Default custom_headers to an empty object across all provider templates and newly created provider models.

Enhancements:

  • Normalize loaded provider sources and providers to always include a valid custom_headers object for backward compatibility in the dashboard.

Documentation:

  • Update Chinese and English configuration metadata texts to document the new custom_headers preset fields.

@auto-assign auto-assign bot requested review from Raven95676 and Soulter February 25, 2026 12:32
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 25, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @piexian, 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!

此拉取请求旨在通过在 WebUI 中引入统一且直观的请求头配置,增强用户体验和系统兼容性。通过为所有提供商默认启用自定义请求头,并提供常用字段(如 User-Agent)的预设模板,它解决了现有配置不直观的问题,并有效降低了因缺少特定请求头而导致的潜在服务拦截风险。这些改进确保了无论新旧配置,都能无缝支持高级请求头定制。

Highlights

  • 统一请求头配置: 为所有提供商配置(包括聊天、代理、语音转文本、文本转语音、嵌入和重排序)补齐了默认的 custom_headers: {} 字段,确保所有提供商都能支持自定义请求头。
  • 新增 User-Agent 预设配置: 在 custom_headers 中增加了 template_schema 预设字段,包括 User-AgentAcceptAccept-Language,方便用户直观配置,并降低被 Cloudflare Bot 误拦截的风险。
  • 前端兼容性处理: 修改了前端逻辑,在加载已有 provider_sourcesproviders 时自动补齐缺失的 custom_headers 字段,并确保新增模型提供商时默认写入 custom_headers: {},以保证旧配置的兼容性和新配置的完整性。
  • 国际化支持: 更新了中文和英文的国际化文案,为 custom_headers.template_schema 中的预设字段提供了名称和提示信息。
Changelog
  • astrbot/core/config/default.py
    • 为多个提供商配置添加了默认的 custom_headers 字段。
    • custom_headers 字段定义了 User-AgentAcceptAccept-Language 的模板模式。
  • dashboard/src/composables/useProviderSources.ts
    • 引入了 withDefaultCustomHeaders 函数以确保 custom_headers 字段的正确初始化。
    • 在加载或创建提供商时应用了 withDefaultCustomHeaders 函数,以处理 custom_headers 的默认值和兼容性。
  • dashboard/src/i18n/locales/en-US/features/config-metadata.json
    • 更新了英文本地化文件,为 custom_headers 字段添加了 User-AgentAcceptAccept-Language 的模板模式描述和提示。
  • dashboard/src/i18n/locales/zh-CN/features/config-metadata.json
    • 更新了中文本地化文件,为 custom_headers 字段添加了 User-AgentAcceptAccept-Language 的模板模式描述和提示。
Activity
  • 目前没有检测到人工活动,例如评论或审查。
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 Feb 25, 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 - 我发现了两个问题,并给出了一些整体性的反馈:

  • withDefaultCustomHeaders 中,使用 JSON.parse(JSON.stringify(entry || {})) 进行克隆可能过于笨重,而且会在没有提示的情况下丢弃非 JSON 安全的值;可以考虑直接修改原对象,或者使用更安全的克隆机制,比如在可用的环境下使用 structuredClone
  • 在后端模板和前端(创建 + 规范化)同时为 custom_headers 设置默认值会引入一些冗余;如果可能,建议把默认逻辑集中放在一侧,从而降低两边随着时间推移出现不一致的风险。
面向 AI 代理的提示词
Please address the comments from this code review:

## Overall Comments
- In `withDefaultCustomHeaders`, using `JSON.parse(JSON.stringify(entry || {}))` for cloning may be unnecessarily heavy and can silently strip non-JSON-safe values; consider either mutating the original object directly or using a safer clone mechanism like `structuredClone` (where available).
- Defaulting `custom_headers` on both the backend templates and the frontend (creation + normalization) introduces some redundancy; if possible, centralize the defaulting logic on one side to reduce the risk of the two drifting out of sync over time.

## Individual Comments

### Comment 1
<location path="dashboard/src/composables/useProviderSources.ts" line_range="43-52" />
<code_context>

   const confirmDialog = useConfirmDialog()

+  function withDefaultCustomHeaders<T extends Record<string, any>>(entry: T): T {
+    const normalized = JSON.parse(JSON.stringify(entry || {}))
+    if (
+      !Object.prototype.hasOwnProperty.call(normalized, 'custom_headers') ||
+      typeof normalized.custom_headers !== 'object' ||
+      normalized.custom_headers === null ||
+      Array.isArray(normalized.custom_headers)
+    ) {
+      normalized.custom_headers = {}
+    }
+    return normalized as T
+  }
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid JSON.parse/JSON.stringify for cloning here to prevent data loss and unnecessary overhead.

`JSON.parse(JSON.stringify(entry || {}))` will drop non-JSON-safe values (e.g., `Date`, `undefined`, class instances) and adds unnecessary cost. Since we only need to normalize `custom_headers`, we can shallow-copy and fix that field only:

```ts
function withDefaultCustomHeaders<T extends Record<string, any>>(entry: T): T {
  const normalized = { ...entry } as any
  const headers = normalized.custom_headers
  if (!headers || typeof headers !== 'object' || Array.isArray(headers)) {
    normalized.custom_headers = {}
  }
  return normalized as T
}
```

This avoids data loss, keeps other fields intact, and is cheaper than deep cloning.
</issue_to_address>

### Comment 2
<location path="astrbot/core/config/default.py" line_range="1633-1639" />
<code_context>
                         "type": "dict",
                         "items": {},
                         "hint": "此处添加的键值对将被合并到 OpenAI SDK 的 default_headers 中,用于自定义 HTTP 请求头。值必须为字符串。",
+                        "template_schema": {
+                            "User-Agent": {
+                                "name": "User-Agent",
+                                "description": "User-Agent 请求头",
+                                "hint": "用于覆盖默认客户端标识。",
+                                "type": "string",
+                                "default": "",
+                            },
+                            "Accept": {
+                                "name": "Accept",
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Reconsider defaulting the `Accept` header value to avoid unintentionally overriding SDK or provider defaults.

The `template_schema` sets a default `Accept: application/json`, which can override SDK/provider defaults that may expect different or more flexible values (e.g., streaming, audio, or `*/*`). Consider leaving the default empty so provider defaults apply, and requiring users to set `Accept` only when they intentionally want to override it, reducing subtle content negotiation issues.

```suggestion
                            "Accept": {
                                "name": "Accept",
                                "description": "Accept 请求头",
                                "hint": "声明可接受的响应类型。默认留空以使用 SDK/服务端默认值,仅在需要时显式覆盖(例如指定 application/json)。",
                                "type": "string",
                                "default": "",
                            },
```
</issue_to_address>

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

Hey - I've found 2 issues, and left some high level feedback:

  • In withDefaultCustomHeaders, using JSON.parse(JSON.stringify(entry || {})) for cloning may be unnecessarily heavy and can silently strip non-JSON-safe values; consider either mutating the original object directly or using a safer clone mechanism like structuredClone (where available).
  • Defaulting custom_headers on both the backend templates and the frontend (creation + normalization) introduces some redundancy; if possible, centralize the defaulting logic on one side to reduce the risk of the two drifting out of sync over time.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `withDefaultCustomHeaders`, using `JSON.parse(JSON.stringify(entry || {}))` for cloning may be unnecessarily heavy and can silently strip non-JSON-safe values; consider either mutating the original object directly or using a safer clone mechanism like `structuredClone` (where available).
- Defaulting `custom_headers` on both the backend templates and the frontend (creation + normalization) introduces some redundancy; if possible, centralize the defaulting logic on one side to reduce the risk of the two drifting out of sync over time.

## Individual Comments

### Comment 1
<location path="dashboard/src/composables/useProviderSources.ts" line_range="43-52" />
<code_context>

   const confirmDialog = useConfirmDialog()

+  function withDefaultCustomHeaders<T extends Record<string, any>>(entry: T): T {
+    const normalized = JSON.parse(JSON.stringify(entry || {}))
+    if (
+      !Object.prototype.hasOwnProperty.call(normalized, 'custom_headers') ||
+      typeof normalized.custom_headers !== 'object' ||
+      normalized.custom_headers === null ||
+      Array.isArray(normalized.custom_headers)
+    ) {
+      normalized.custom_headers = {}
+    }
+    return normalized as T
+  }
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid JSON.parse/JSON.stringify for cloning here to prevent data loss and unnecessary overhead.

`JSON.parse(JSON.stringify(entry || {}))` will drop non-JSON-safe values (e.g., `Date`, `undefined`, class instances) and adds unnecessary cost. Since we only need to normalize `custom_headers`, we can shallow-copy and fix that field only:

```ts
function withDefaultCustomHeaders<T extends Record<string, any>>(entry: T): T {
  const normalized = { ...entry } as any
  const headers = normalized.custom_headers
  if (!headers || typeof headers !== 'object' || Array.isArray(headers)) {
    normalized.custom_headers = {}
  }
  return normalized as T
}
```

This avoids data loss, keeps other fields intact, and is cheaper than deep cloning.
</issue_to_address>

### Comment 2
<location path="astrbot/core/config/default.py" line_range="1633-1639" />
<code_context>
                         "type": "dict",
                         "items": {},
                         "hint": "此处添加的键值对将被合并到 OpenAI SDK 的 default_headers 中,用于自定义 HTTP 请求头。值必须为字符串。",
+                        "template_schema": {
+                            "User-Agent": {
+                                "name": "User-Agent",
+                                "description": "User-Agent 请求头",
+                                "hint": "用于覆盖默认客户端标识。",
+                                "type": "string",
+                                "default": "",
+                            },
+                            "Accept": {
+                                "name": "Accept",
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Reconsider defaulting the `Accept` header value to avoid unintentionally overriding SDK or provider defaults.

The `template_schema` sets a default `Accept: application/json`, which can override SDK/provider defaults that may expect different or more flexible values (e.g., streaming, audio, or `*/*`). Consider leaving the default empty so provider defaults apply, and requiring users to set `Accept` only when they intentionally want to override it, reducing subtle content negotiation issues.

```suggestion
                            "Accept": {
                                "name": "Accept",
                                "description": "Accept 请求头",
                                "hint": "声明可接受的响应类型。默认留空以使用 SDK/服务端默认值,仅在需要时显式覆盖(例如指定 application/json)。",
                                "type": "string",
                                "default": "",
                            },
```
</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.

@dosubot
Copy link

dosubot bot commented Feb 25, 2026

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

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 的目标是为 provider 新增 User-Agent 等请求头的预设,以提升易用性并降低被 Cloudflare 等服务拦截的风险。整体实现思路清晰,通过修改后端默认配置、前端数据兼容处理以及补充国际化文案,完整地实现了该功能。代码改动基本符合预期。我有一个关于前端数据处理性能和健壮性的优化建议,请查看具体评论。

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:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant