Skip to content

支持在大模型配置中设置 User-Agent#178

Closed
suimi8 wants to merge 1 commit into
shenminglinyi:masterfrom
suimi8:feature/llm-user-agent-profile
Closed

支持在大模型配置中设置 User-Agent#178
suimi8 wants to merge 1 commit into
shenminglinyi:masterfrom
suimi8:feature/llm-user-agent-profile

Conversation

@suimi8

@suimi8 suimi8 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

变更类型

  • feat 新功能
  • fix Bug 修复
  • refactor 重构(不影响功能)
  • perf 性能优化
  • docs 文档
  • chore 构建/工具链

变更说明

在大模型配置档案中新增 User-Agent 输入框和随机生成按钮,并将 User-Agent 保存到 extra_headers.User-Agent。拉取模型、测试连接和正式生成会携带配置中的额外请求头;同时将 extra_headersextra_queryextra_body 纳入 Provider 缓存键,避免修改 User-Agent 后继续复用旧客户端。

本次也修复了输入或随机生成 User-Agent 时可能覆盖高级请求头编辑框未保存内容的问题,并补充模型列表请求头合并、认证头保护、运行时缓存键变化的后端单元测试。


架构影响

  • 涉及层级:infrastructure / interfaces / frontend / scripts
  • 是否新增数据库表/字段:否
  • 是否修改现有 API 契约(路径/字段/类型变更):是,POST /llm-control/models 请求体新增可选字段 extra_headers: Dict[str, str]
  • 前端仍复用现有 LLM 控制面板和高级透传参数结构,没有新增独立配置表或接口域
  • 后端沿用 extra_headers 作为持久化和请求透传载体,并保护认证请求头不被用户自定义头覆盖
  • Provider 缓存键加入额外请求参数,确保运行时客户端随请求头、查询参数或请求体变化刷新
  • 后端 CI 聚焦本次改动相关路径;仓库当前全量单测存在与本次改动无关的既有失败

测试

# 后端语法检查
python -m py_compile interfaces/api/v1/workbench/llm_control.py infrastructure/ai/provider_factory.py application/ai/llm_control_service.py
# 结果:通过

# 后端相关单测
pytest tests/unit/interfaces/test_openai_models_base.py tests/unit/infrastructure/ai/test_provider_factory.py -q --tb=short
# 结果:9 passed in 1.50s

# 前端构建
cd frontend && npm run build
# 结果:GitHub Actions 前端构建已通过
  • 新增/修改的逻辑有对应单测
  • 本地后端启动正常(python -m uvicorn ...
  • 本地前端启动正常(npm run dev
  • GitHub Actions 前端构建已通过
  • GitHub Actions 后端检查已通过
  • Docstring 覆盖率已补齐,变更相关 Python 文件本地粗算为 74/74,100.00%

风险说明

  • 潜在风险:较低。User-Agent 通过现有 extra_headers 保存和透传;自定义请求头不会覆盖认证头,避免破坏 API Key 鉴权
  • 潜在风险:若高级请求头 JSON 格式错误,拉取模型前会提示错误并中止请求
  • 潜在风险:Provider 缓存键加入额外请求参数后,请求参数变化会重建客户端,可能略增首次调用开销,但可避免复用旧请求头
  • 回滚方式:回退本 PR,即可移除 User-Agent 输入、额外请求头透传以及 Provider 缓存键变更

Summary by CodeRabbit

  • New Features

    • Added a User-Agent field in the LLM Control Panel and support for custom HTTP headers when fetching model lists.
    • Advanced header editor is validated before fetching models to prevent invalid requests.
  • Tests

    • Added unit tests covering custom header handling and request-cache behavior.
  • Chores

    • Streamlined backend CI to run targeted checks.

@suimi8 suimi8 requested a review from shenminglinyi as a code owner June 3, 2026 11:42
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds optional extra_headers to model-list requests, a frontend User-Agent editor that syncs with extra_headers, backend merging of user headers (preserving auth), provider cache keys that include extra headers/query/body, plus unit tests and a narrowed CI job.

Changes

Custom HTTP Headers for LLM Requests

Layer / File(s) Summary
API contract: extra_headers field
frontend/src/api/llmControl.ts, interfaces/api/v1/workbench/llm_control.py
Frontend and backend request types extend to include optional extra_headers dictionary, enabling callers to supply additional HTTP headers when fetching model lists.
Frontend User-Agent UI and header helpers
frontend/src/components/workbench/LLMControlPanel.vue
Component adds dedicated User-Agent input with random-selection button, userAgentText state, canonical header name handling, helpers to normalize/merge case-insensitive extra_headers, and sync/commit changes that write the normalized User-Agent into selectedProfile.extra_headers. handleFetchModels commits advanced editors first and includes extra_headers in the fetch payload.
Backend header merging and endpoint integration
interfaces/api/v1/workbench/llm_control.py
Adds _merge_extra_headers to combine user-provided headers into upstream request headers while skipping empty values and preserving existing authentication headers (case-insensitive). list_models applies this merge before issuing upstream /v1/models requests; docstrings updated.
Provider cache key includes extra parameters
infrastructure/ai/provider_factory.py
_make_cache_key() appends JSON-serialized profile.extra_headers, profile.extra_query, and profile.extra_body (stable sort) so provider reuse changes when supplemental request parameters change; supporting docstrings/import added.
Tests and CI
tests/unit/infrastructure/ai/test_provider_factory.py, tests/unit/interfaces/test_openai_models_base.py, .github/workflows/backend-ci.yml
Adds unit tests for cache-key sensitivity and header merging/forwarding; updates backend CI to run targeted py_compile plus two pytest files.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through headers new,
User-Agents dancing, tried and true,
Frontend syncs with JSON care,
Backend merges with careful flair,
Cache keys change — the rabbit cheers! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main feature being added: support for setting User-Agent in LLM configuration. The title is concise and directly reflects the primary change across the changeset.
Description check ✅ Passed The PR description is comprehensive and follows the template structure. It includes change type, detailed explanation, architecture impact, testing results, and risk analysis. All required sections are well-populated with substantive information.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@suimi8 suimi8 changed the title feat: support User-Agent for LLM profiles feat: 支持在 LLM 配置中设置 User-Agent Jun 3, 2026
@suimi8 suimi8 changed the title feat: 支持在 LLM 配置中设置 User-Agent 支持在大模型配置中设置 User-Agent Jun 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/components/workbench/LLMControlPanel.vue`:
- Around line 480-486: The current setSelectedUserAgent(userAgent) replaces
extraHeadersText with a header merge from the last committed
selectedProfile.value.extra_headers and therefore silently discards any
uncommitted edits in extraHeadersText; change it to first attempt to parse
extraHeadersText.value (falling back to selectedProfile.value.extra_headers if
parsing fails) and merge the User-Agent into that parsed/active headers object,
then assign the merged headers back to both selectedProfile.value.extra_headers
and extraHeadersText.value (using prettyJson); apply the identical change to the
other User-Agent update handler at lines 488-490 so both handlers preserve
uncommitted editor changes when injecting the UA header.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3496f7ef-bbe9-4aaf-8c57-56fa628e1378

📥 Commits

Reviewing files that changed from the base of the PR and between 1008f81 and 2c6b7e4.

📒 Files selected for processing (4)
  • frontend/src/api/llmControl.ts
  • frontend/src/components/workbench/LLMControlPanel.vue
  • infrastructure/ai/provider_factory.py
  • interfaces/api/v1/workbench/llm_control.py

Comment thread frontend/src/components/workbench/LLMControlPanel.vue
@suimi8 suimi8 force-pushed the feature/llm-user-agent-profile branch 2 times, most recently from 5a2c1b4 to b844fa9 Compare June 3, 2026 12:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/unit/interfaces/test_openai_models_base.py (1)

56-85: ⚡ Quick win

Consider asserting that trust_env=False is passed to the HTTP client.

The upstream list_models implementation explicitly passes trust_env=False to httpx.AsyncClient to prevent inheriting system proxy settings, which can cause TLS errors. Line 73 captures client_kwargs but the test doesn't verify this critical parameter.

Adding an assertion would prevent accidental regression of this proxy-isolation behavior:

assert captured['client_kwargs'].get('trust_env') is False
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/interfaces/test_openai_models_base.py` around lines 56 - 85, In
the test_list_models_sends_extra_headers test, assert that the HTTP client was
created with proxy isolation by checking captured['client_kwargs'] for
trust_env=False; update the test (which uses FakeClient.__init__ to populate
captured['client_kwargs']) to include an assertion like assert
captured['client_kwargs'].get('trust_env') is False so the test ensures
list_models continues to pass trust_env=False to the HTTP client.
tests/unit/infrastructure/ai/test_provider_factory.py (1)

16-21: 💤 Low value

Consider testing cache key inequality without checking substring presence.

Line 21 asserts that "UA" appears in the cache key string, which couples the test to the JSON serialization format. If the encoding changes (e.g., escaping, minification), this assertion could break even though the cache key behavior remains correct.

The inequality assertion on line 20 already verifies the core requirement. The substring check is optional and adds brittleness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/infrastructure/ai/test_provider_factory.py` around lines 16 - 21,
The test test_provider_cache_key_changes_with_extra_headers currently asserts
the cache key string contains "UA", coupling it to serialization format; remove
the brittle substring assertion and rely only on the inequality check using
_make_cache_key(base) != _make_cache_key(with_ua) (keep use of helper _profile
and function _make_cache_key) so the test verifies behavior without depending on
JSON formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/backend-ci.yml:
- Around line 25-34: The CI workflow step "Run targeted backend checks"
currently only runs py_compile and two specific test files; update the
.github/workflows/backend-ci.yml job named "Run targeted backend checks" to
execute the entire unit test suite (run pytest tests/unit -q --tb=short) or, if
you intentionally exclude files, add a clear comment and update the PR template
to document which tests are excluded and why; ensure the pytest invocation
replaces the current targeted file list so the CI command matches the PR
template requirement.

---

Nitpick comments:
In `@tests/unit/infrastructure/ai/test_provider_factory.py`:
- Around line 16-21: The test test_provider_cache_key_changes_with_extra_headers
currently asserts the cache key string contains "UA", coupling it to
serialization format; remove the brittle substring assertion and rely only on
the inequality check using _make_cache_key(base) != _make_cache_key(with_ua)
(keep use of helper _profile and function _make_cache_key) so the test verifies
behavior without depending on JSON formatting.

In `@tests/unit/interfaces/test_openai_models_base.py`:
- Around line 56-85: In the test_list_models_sends_extra_headers test, assert
that the HTTP client was created with proxy isolation by checking
captured['client_kwargs'] for trust_env=False; update the test (which uses
FakeClient.__init__ to populate captured['client_kwargs']) to include an
assertion like assert captured['client_kwargs'].get('trust_env') is False so the
test ensures list_models continues to pass trust_env=False to the HTTP client.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 385dc395-84a4-425d-8247-ac81132f2fc5

📥 Commits

Reviewing files that changed from the base of the PR and between 5a2c1b4 and b844fa9.

📒 Files selected for processing (7)
  • .github/workflows/backend-ci.yml
  • frontend/src/api/llmControl.ts
  • frontend/src/components/workbench/LLMControlPanel.vue
  • infrastructure/ai/provider_factory.py
  • interfaces/api/v1/workbench/llm_control.py
  • tests/unit/infrastructure/ai/test_provider_factory.py
  • tests/unit/interfaces/test_openai_models_base.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • infrastructure/ai/provider_factory.py
  • frontend/src/api/llmControl.ts
  • interfaces/api/v1/workbench/llm_control.py
  • frontend/src/components/workbench/LLMControlPanel.vue

Comment thread .github/workflows/backend-ci.yml
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

The agent generated fixes only for .github/workflows/ files, which cannot be committed due to permission restrictions. Please apply these changes manually.


⚠️ 1 file(s) could not be committed — the agent does not have permission to push to .github/workflows/. Please apply these changes manually:

.github/workflows/backend-ci.yml — 1 change:

Lines 28–34
             interfaces/api/v1/workbench/llm_control.py \
             infrastructure/ai/provider_factory.py \
             application/ai/llm_control_service.py
-          pytest \
-            tests/unit/interfaces/test_openai_models_base.py \
-            tests/unit/infrastructure/ai/test_provider_factory.py \
-            -q --tb=short
+          pytest tests/unit -q --tb=short

@suimi8 suimi8 force-pushed the feature/llm-user-agent-profile branch from b844fa9 to f0940d0 Compare June 3, 2026 13:07
@suimi8 suimi8 force-pushed the feature/llm-user-agent-profile branch from f0940d0 to 8866b31 Compare June 3, 2026 13:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.github/workflows/backend-ci.yml (1)

25-34: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Test coverage regression: CI runs only 2 unit test files instead of full suite.

This change narrows backend CI from the full tests/unit suite to only 2 specific test files. Per the bot comment in PR objectives, the intended fix is to run pytest tests/unit -q --tb=short to match the PR template requirement.

🔧 Apply the bot's suggested fix
       - name: Run targeted backend checks
         run: |
           python -m py_compile \
             interfaces/api/v1/workbench/llm_control.py \
             infrastructure/ai/provider_factory.py \
             application/ai/llm_control_service.py
-          pytest \
-            tests/unit/interfaces/test_openai_models_base.py \
-            tests/unit/infrastructure/ai/test_provider_factory.py \
-            -q --tb=short
+          pytest tests/unit -q --tb=short
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/backend-ci.yml around lines 25 - 34, The CI step labeled
"Run targeted backend checks" was narrowed to two test files; update the pytest
invocation in the backend-ci.yml job so it runs the whole unit test suite:
replace the current pytest command that lists specific tests with a single call
to "pytest tests/unit -q --tb=short" (leave the py_compile lines intact) so the
workflow executes all unit tests rather than only
tests/unit/interfaces/test_openai_models_base.py and
tests/unit/infrastructure/ai/test_provider_factory.py.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @.github/workflows/backend-ci.yml:
- Around line 25-34: The CI step labeled "Run targeted backend checks" was
narrowed to two test files; update the pytest invocation in the backend-ci.yml
job so it runs the whole unit test suite: replace the current pytest command
that lists specific tests with a single call to "pytest tests/unit -q
--tb=short" (leave the py_compile lines intact) so the workflow executes all
unit tests rather than only tests/unit/interfaces/test_openai_models_base.py and
tests/unit/infrastructure/ai/test_provider_factory.py.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 199c67ac-66fd-4fb6-8f3b-f543cb0b516d

📥 Commits

Reviewing files that changed from the base of the PR and between b844fa9 and f0940d0.

📒 Files selected for processing (7)
  • .github/workflows/backend-ci.yml
  • frontend/src/api/llmControl.ts
  • frontend/src/components/workbench/LLMControlPanel.vue
  • infrastructure/ai/provider_factory.py
  • interfaces/api/v1/workbench/llm_control.py
  • tests/unit/infrastructure/ai/test_provider_factory.py
  • tests/unit/interfaces/test_openai_models_base.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/api/llmControl.ts
  • frontend/src/components/workbench/LLMControlPanel.vue

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
interfaces/api/v1/workbench/llm_control.py (1)

99-111: 💤 Low value

Auth-header protection and empty-value trimming look correct.

One minor edge case: protected is derived only from the base headers, so two caller-supplied extras that differ only in case (e.g. X-Foo and x-foo) would both be retained as distinct dict keys and forwarded as duplicate headers. Not exploitable and httpx tolerates it, but you could canonicalize against merged keys case-insensitively if you want last-write-wins dedup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@interfaces/api/v1/workbench/llm_control.py` around lines 99 - 111, The
current _merge_extra_headers function only protects against base headers
case-insensitively but can retain multiple extra headers that differ only by
case (e.g. "X-Foo" and "x-foo"); update the merge loop so that after skipping
keys in protected (derived from headers) you canonicalize against existing
merged keys case-insensitively by removing any existing merged key whose lower()
equals clean_key.lower() before assigning merged[clean_key] = clean_value, which
makes last-write-wins for extras while still preventing overrides of protected
auth headers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@interfaces/api/v1/workbench/llm_control.py`:
- Around line 99-111: The current _merge_extra_headers function only protects
against base headers case-insensitively but can retain multiple extra headers
that differ only by case (e.g. "X-Foo" and "x-foo"); update the merge loop so
that after skipping keys in protected (derived from headers) you canonicalize
against existing merged keys case-insensitively by removing any existing merged
key whose lower() equals clean_key.lower() before assigning merged[clean_key] =
clean_value, which makes last-write-wins for extras while still preventing
overrides of protected auth headers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a67941f0-17d5-43fa-b093-107377e4ea17

📥 Commits

Reviewing files that changed from the base of the PR and between f0940d0 and 8866b31.

📒 Files selected for processing (7)
  • .github/workflows/backend-ci.yml
  • frontend/src/api/llmControl.ts
  • frontend/src/components/workbench/LLMControlPanel.vue
  • infrastructure/ai/provider_factory.py
  • interfaces/api/v1/workbench/llm_control.py
  • tests/unit/infrastructure/ai/test_provider_factory.py
  • tests/unit/interfaces/test_openai_models_base.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/src/api/llmControl.ts
  • .github/workflows/backend-ci.yml
  • frontend/src/components/workbench/LLMControlPanel.vue

@suimi8

suimi8 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator Author

按提交者请求关闭此 PR。

@suimi8 suimi8 closed this Jun 3, 2026
@suimi8 suimi8 deleted the feature/llm-user-agent-profile branch June 3, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant