mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-16 09:39:29 +08:00
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:
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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.)",
|
||||
|
||||
@@ -1343,6 +1343,8 @@
|
||||
"cacheWriteCost": "キャッシュ書込コスト ($/M トークン)",
|
||||
"cacheCostHint": "キャッシュコストは Prompt Caching のコスト計算に使用されます。キャッシュを使用しない場合は空欄のままにしてください。",
|
||||
"modelsHint": "このプロバイダーがサポートするモデルを設定します。モデル ID は API 呼び出しに、表示名はインターフェースに使用されます。",
|
||||
"userAgent": "User-Agent を送信",
|
||||
"userAgentHint": "一部のプロバイダーはブラウザの User-Agent ヘッダーが必要です。",
|
||||
"env": {
|
||||
"title": "環境変数",
|
||||
"description": "openclaw.json の環境変数設定を管理(APIキー、カスタム変数など)",
|
||||
|
||||
@@ -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、自定义变量等)",
|
||||
|
||||
@@ -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 完整配置
|
||||
|
||||
Reference in New Issue
Block a user