feat: add OpenClaw User-Agent toggle, default off

Add a switch in the OpenClaw provider form to optionally send a browser
User-Agent header. The toggle defaults to off — only providers that
explicitly include headers in their preset or config will have it enabled.

Remove the previous auto-injection logic that force-added User-Agent on
every preset load and new provider creation.
This commit is contained in:
Jason
2026-03-09 10:36:11 +08:00
parent dd971246be
commit cc15d7b1e3
8 changed files with 67 additions and 0 deletions
+2
View File
@@ -100,6 +100,8 @@ pub struct OpenClawProviderConfig {
pub api: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub models: Vec<OpenClawModelEntry>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub headers: HashMap<String, String>,
#[serde(flatten)]
pub extra: HashMap<String, Value>,
}
@@ -42,6 +42,10 @@ interface OpenClawFormFieldsProps {
// Models
models: OpenClawModel[];
onModelsChange: (models: OpenClawModel[]) => void;
// User-Agent
userAgent: boolean;
onUserAgentChange: (checked: boolean) => void;
}
export function OpenClawFormFields({
@@ -58,6 +62,8 @@ export function OpenClawFormFields({
onApiChange,
models,
onModelsChange,
userAgent,
onUserAgentChange,
}: OpenClawFormFieldsProps) {
const { t } = useTranslation();
const [expandedModels, setExpandedModels] = useState<Record<number, boolean>>(
@@ -205,6 +211,21 @@ export function OpenClawFormFields({
partnerPromotionKey={partnerPromotionKey}
/>
{/* User-Agent */}
<div className="flex items-center justify-between">
<div className="space-y-0.5">
<FormLabel>
{t("openclaw.userAgent", { defaultValue: "发送 User-Agent" })}
</FormLabel>
<p className="text-xs text-muted-foreground">
{t("openclaw.userAgentHint", {
defaultValue: "部分供应商需要浏览器 User-Agent 才能正常访问。",
})}
</p>
</div>
<Switch checked={userAgent} onCheckedChange={onUserAgentChange} />
</div>
{/* Models Editor */}
<div className="space-y-3">
<div className="flex items-center justify-between">
@@ -1450,6 +1450,8 @@ export function ProviderForm({
onApiChange={openclawForm.handleOpenclawApiChange}
models={openclawForm.openclawModels}
onModelsChange={openclawForm.handleOpenclawModelsChange}
userAgent={openclawForm.openclawUserAgent}
onUserAgentChange={openclawForm.handleOpenclawUserAgentChange}
/>
)}
@@ -14,6 +14,9 @@ interface UseOpenclawFormStateParams {
getSettingsConfig: () => string;
}
export const OPENCLAW_DEFAULT_USER_AGENT =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0";
export interface OpenclawFormState {
openclawProviderKey: string;
setOpenclawProviderKey: (key: string) => void;
@@ -21,16 +24,19 @@ export interface OpenclawFormState {
openclawApiKey: string;
openclawApi: string;
openclawModels: OpenClawModel[];
openclawUserAgent: boolean;
existingOpenclawKeys: string[];
handleOpenclawBaseUrlChange: (baseUrl: string) => void;
handleOpenclawApiKeyChange: (apiKey: string) => void;
handleOpenclawApiChange: (api: string) => void;
handleOpenclawModelsChange: (models: OpenClawModel[]) => void;
handleOpenclawUserAgentChange: (enabled: boolean) => void;
resetOpenclawState: (config?: {
baseUrl?: string;
apiKey?: string;
api?: string;
models?: OpenClawModel[];
headers?: Record<string, string>;
}) => void;
}
@@ -92,6 +98,16 @@ export function useOpenclawFormState({
return parseOpenclawField<OpenClawModel[]>(initialData, "models", []);
});
const [openclawUserAgent, setOpenclawUserAgent] = useState<boolean>(() => {
if (appId !== "openclaw") return true;
const headers = parseOpenclawField<Record<string, string>>(
initialData,
"headers",
{},
);
return "User-Agent" in headers;
});
const updateOpenclawConfig = useCallback(
(updater: (config: Record<string, any>) => void) => {
try {
@@ -147,18 +163,35 @@ export function useOpenclawFormState({
[updateOpenclawConfig],
);
const handleOpenclawUserAgentChange = useCallback(
(enabled: boolean) => {
setOpenclawUserAgent(enabled);
updateOpenclawConfig((config) => {
if (enabled) {
config.headers = { "User-Agent": OPENCLAW_DEFAULT_USER_AGENT };
} else {
delete config.headers;
}
});
},
[updateOpenclawConfig],
);
const resetOpenclawState = useCallback(
(config?: {
baseUrl?: string;
apiKey?: string;
api?: string;
models?: OpenClawModel[];
headers?: Record<string, string>;
}) => {
setOpenclawProviderKey("");
setOpenclawBaseUrl(config?.baseUrl || "");
setOpenclawApiKey(config?.apiKey || "");
setOpenclawApi(config?.api || "openai-completions");
setOpenclawModels(config?.models || []);
const ua = config?.headers ? "User-Agent" in config.headers : false;
setOpenclawUserAgent(ua);
},
[],
);
@@ -170,11 +203,13 @@ export function useOpenclawFormState({
openclawApiKey,
openclawApi,
openclawModels,
openclawUserAgent,
existingOpenclawKeys,
handleOpenclawBaseUrlChange,
handleOpenclawApiKeyChange,
handleOpenclawApiChange,
handleOpenclawModelsChange,
handleOpenclawUserAgentChange,
resetOpenclawState,
};
}
+2
View File
@@ -1343,6 +1343,8 @@
"cacheWriteCost": "Cache Write Cost ($/M tokens)",
"cacheCostHint": "Cache costs are used to calculate Prompt Caching costs. Leave empty if not using caching.",
"modelsHint": "Configure the models supported by this provider. Model ID is used for API calls, Display Name for the interface.",
"userAgent": "Send User-Agent",
"userAgentHint": "Some providers require a browser User-Agent header to work properly.",
"env": {
"title": "Environment Variables",
"description": "Manage environment variables in openclaw.json (API keys, custom variables, etc.)",
+2
View File
@@ -1343,6 +1343,8 @@
"cacheWriteCost": "キャッシュ書込コスト ($/M トークン)",
"cacheCostHint": "キャッシュコストは Prompt Caching のコスト計算に使用されます。キャッシュを使用しない場合は空欄のままにしてください。",
"modelsHint": "このプロバイダーがサポートするモデルを設定します。モデル ID は API 呼び出しに、表示名はインターフェースに使用されます。",
"userAgent": "User-Agent を送信",
"userAgentHint": "一部のプロバイダーはブラウザの User-Agent ヘッダーが必要です。",
"env": {
"title": "環境変数",
"description": "openclaw.json の環境変数設定を管理(APIキー、カスタム変数など)",
+2
View File
@@ -1343,6 +1343,8 @@
"cacheWriteCost": "缓存写入价格 ($/M tokens)",
"cacheCostHint": "缓存价格用于计算 Prompt Caching 的成本。如不使用缓存可留空。",
"modelsHint": "配置该供应商支持的模型。模型 ID 用于 API 调用,显示名称用于界面展示。",
"userAgent": "发送 User-Agent",
"userAgentHint": "部分供应商需要浏览器 User-Agent 才能正常访问。",
"env": {
"title": "环境变量",
"description": "管理 openclaw.json 中的环境变量配置(API Key、自定义变量等)",
+1
View File
@@ -522,6 +522,7 @@ export interface OpenClawProviderConfig {
apiKey?: string; // API 密钥
api?: string; // API 协议类型(如 "openai-completions"、"anthropic"
models?: OpenClawModel[]; // 可用模型列表
headers?: Record<string, string>; // 自定义请求头(如 User-Agent
}
// OpenClaw agents.defaults 完整配置