feat(provider-form): custom User-Agent presets dropdown in advanced settings

Polish the provider-level User-Agent override UI on the Claude and Codex forms.

- Add a shared CustomUserAgentField (label + input + preset dropdown + live
  validation) so both forms stay in sync.
- Provide curated UA presets (Claude Code / Kilo Code families that pass
  coding-plan UA whitelists per #3671); the first is Claude Code's real
  `claude-cli/x (external, cli)` format. Whitelists gate on the name prefix,
  not the version, so static values stay valid across upgrades.
- Expose presets via a dropdown to the right of the input (z-[200] so it
  renders above the dialog layers) instead of inline chips.
- Move the field into the existing advanced/reasoning collapsibles.
- userAgent.ts mirrors the backend byte rule (reject only control chars;
  non-ASCII is allowed) for a non-blocking inline hint.
- i18n for all four locales (zh/en/ja/zh-TW).
This commit is contained in:
Jason
2026-06-10 16:39:26 +08:00
parent 8b925c2f2f
commit 596019505f
11 changed files with 212 additions and 56 deletions
+16
View File
@@ -0,0 +1,16 @@
/**
* 自定义 User-Agent 合法性校验。
*
* 与后端 `parse_custom_user_agent`(基于 `http::HeaderValue::from_str`)口径严格一致:
* HeaderValue 按**字节**判定合法性,规则为 `b >= 32 && b != 127 || b == '\t'`。也就是说:
* - 制表符(\t)、可见 ASCII0x200x7E)、以及任意非 ASCII 字符(UTF-8 字节均 ≥ 0x80)都合法;
* - 仅控制字符非法:除 \t 外的 0x00–0x1F(含换行)与 0x7FDEL)。
*
* 空串(trim 后为空)视为"未设置",合法。
*/
export function isValidUserAgentHeader(value: string): boolean {
const trimmed = value.trim();
if (trimmed === "") return true;
// eslint-disable-next-line no-control-regex
return !/[\x00-\x08\x0a-\x1f\x7f]/.test(trimmed);
}