2025-10-16 17:40:25 +08:00
|
|
|
|
import { useState, useCallback, useRef, useEffect } from "react";
|
2025-10-18 16:52:02 +08:00
|
|
|
|
import {
|
|
|
|
|
|
extractCodexBaseUrl,
|
|
|
|
|
|
setCodexBaseUrl as setCodexBaseUrlInConfig,
|
|
|
|
|
|
} from "@/utils/providerConfigUtils";
|
2025-10-16 17:40:25 +08:00
|
|
|
|
import type { ProviderCategory } from "@/types";
|
|
|
|
|
|
|
|
|
|
|
|
interface UseBaseUrlStateProps {
|
|
|
|
|
|
appType: "claude" | "codex";
|
|
|
|
|
|
category: ProviderCategory | undefined;
|
|
|
|
|
|
settingsConfig: string;
|
|
|
|
|
|
codexConfig?: string;
|
|
|
|
|
|
onSettingsConfigChange: (config: string) => void;
|
|
|
|
|
|
onCodexConfigChange?: (config: string) => void;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 管理 Base URL 状态
|
|
|
|
|
|
* 支持 Claude (JSON) 和 Codex (TOML) 两种格式
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function useBaseUrlState({
|
|
|
|
|
|
appType,
|
|
|
|
|
|
category,
|
|
|
|
|
|
settingsConfig,
|
|
|
|
|
|
codexConfig,
|
|
|
|
|
|
onSettingsConfigChange,
|
|
|
|
|
|
onCodexConfigChange,
|
|
|
|
|
|
}: UseBaseUrlStateProps) {
|
|
|
|
|
|
const [baseUrl, setBaseUrl] = useState("");
|
|
|
|
|
|
const [codexBaseUrl, setCodexBaseUrl] = useState("");
|
|
|
|
|
|
const isUpdatingRef = useRef(false);
|
|
|
|
|
|
|
|
|
|
|
|
// 从配置同步到 state(Claude)
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (appType !== "claude") return;
|
|
|
|
|
|
if (category !== "third_party" && category !== "custom") return;
|
|
|
|
|
|
if (isUpdatingRef.current) return;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const config = JSON.parse(settingsConfig || "{}");
|
|
|
|
|
|
const envUrl: unknown = config?.env?.ANTHROPIC_BASE_URL;
|
|
|
|
|
|
if (typeof envUrl === "string" && envUrl && envUrl !== baseUrl) {
|
|
|
|
|
|
setBaseUrl(envUrl.trim());
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
// ignore
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [appType, category, settingsConfig, baseUrl]);
|
|
|
|
|
|
|
|
|
|
|
|
// 从配置同步到 state(Codex)
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (appType !== "codex") return;
|
|
|
|
|
|
if (category !== "third_party" && category !== "custom") return;
|
|
|
|
|
|
if (isUpdatingRef.current) return;
|
|
|
|
|
|
if (!codexConfig) return;
|
|
|
|
|
|
|
|
|
|
|
|
const extracted = extractCodexBaseUrl(codexConfig) || "";
|
|
|
|
|
|
if (extracted !== codexBaseUrl) {
|
|
|
|
|
|
setCodexBaseUrl(extracted);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [appType, category, codexConfig, codexBaseUrl]);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理 Claude Base URL 变化
|
|
|
|
|
|
const handleClaudeBaseUrlChange = useCallback(
|
|
|
|
|
|
(url: string) => {
|
|
|
|
|
|
const sanitized = url.trim().replace(/\/+$/, "");
|
|
|
|
|
|
setBaseUrl(sanitized);
|
|
|
|
|
|
isUpdatingRef.current = true;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const config = JSON.parse(settingsConfig || "{}");
|
|
|
|
|
|
if (!config.env) {
|
|
|
|
|
|
config.env = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
config.env.ANTHROPIC_BASE_URL = sanitized;
|
|
|
|
|
|
onSettingsConfigChange(JSON.stringify(config, null, 2));
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
// ignore
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
isUpdatingRef.current = false;
|
|
|
|
|
|
}, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
[settingsConfig, onSettingsConfigChange],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理 Codex Base URL 变化
|
|
|
|
|
|
const handleCodexBaseUrlChange = useCallback(
|
|
|
|
|
|
(url: string) => {
|
|
|
|
|
|
const sanitized = url.trim().replace(/\/+$/, "");
|
|
|
|
|
|
setCodexBaseUrl(sanitized);
|
|
|
|
|
|
|
|
|
|
|
|
if (!sanitized || !onCodexConfigChange) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
isUpdatingRef.current = true;
|
2025-10-18 16:52:02 +08:00
|
|
|
|
const updatedConfig = setCodexBaseUrlInConfig(
|
|
|
|
|
|
codexConfig || "",
|
|
|
|
|
|
sanitized,
|
|
|
|
|
|
);
|
2025-10-16 17:40:25 +08:00
|
|
|
|
onCodexConfigChange(updatedConfig);
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
isUpdatingRef.current = false;
|
|
|
|
|
|
}, 0);
|
|
|
|
|
|
},
|
|
|
|
|
|
[codexConfig, onCodexConfigChange],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
baseUrl,
|
|
|
|
|
|
setBaseUrl,
|
|
|
|
|
|
codexBaseUrl,
|
|
|
|
|
|
setCodexBaseUrl,
|
|
|
|
|
|
handleClaudeBaseUrlChange,
|
|
|
|
|
|
handleCodexBaseUrlChange,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|