From eea5e4123b48b20fd951116bcb50fedeb87b3ed8 Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 30 Aug 2025 22:08:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(codex):=20=E5=A2=9E=E5=8A=A0=20Codex=20?= =?UTF-8?q?=E9=A2=84=E8=AE=BE=E4=BE=9B=E5=BA=94=E5=95=86=EF=BC=88=E5=AE=98?= =?UTF-8?q?=E6=96=B9=E3=80=81PackyCode=EF=BC=89=EF=BC=9B=E5=9C=A8=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BE=9B=E5=BA=94=E5=95=86=E6=97=B6=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=B8=80=E9=94=AE=E9=A2=84=E8=AE=BE=E4=B8=8E=20API=20Key=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=86=99=E5=85=A5=20auth.json=EF=BC=9BUI=20?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=20Codex=20=E9=A2=84=E8=AE=BE=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E4=B8=8E=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ProviderForm.tsx | 129 ++++++++++++++++++++++++++++- src/config/codexProviderPresets.ts | 31 +++++++ 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/config/codexProviderPresets.ts diff --git a/src/components/ProviderForm.tsx b/src/components/ProviderForm.tsx index a4eb9d2..09867a5 100644 --- a/src/components/ProviderForm.tsx +++ b/src/components/ProviderForm.tsx @@ -10,6 +10,7 @@ import { setApiKeyInConfig, } from "../utils/providerConfigUtils"; import { providerPresets } from "../config/providerPresets"; +import { codexProviderPresets } from "../config/codexProviderPresets"; import "./AddProviderModal.css"; interface ProviderFormProps { @@ -45,6 +46,10 @@ const ProviderForm: React.FC = ({ // Codex 特有的状态 const [codexAuth, setCodexAuth] = useState(""); const [codexConfig, setCodexConfig] = useState(""); + const [codexApiKey, setCodexApiKey] = useState(""); + const [selectedCodexPreset, setSelectedCodexPreset] = useState( + null, + ); // 初始化 Codex 配置 useEffect(() => { @@ -53,6 +58,14 @@ const ProviderForm: React.FC = ({ if (typeof config === "object" && config !== null) { setCodexAuth(JSON.stringify(config.auth || {}, null, 2)); setCodexConfig(config.config || ""); + try { + const auth = config.auth || {}; + if (auth && typeof auth.api_key === "string") { + setCodexApiKey(auth.api_key); + } + } catch { + // ignore + } } } }, [isCodex, initialData]); @@ -186,6 +199,33 @@ const ProviderForm: React.FC = ({ setDisableCoAuthored(hasCoAuthoredDisabled); }; + // Codex: 应用预设 + const applyCodexPreset = ( + preset: (typeof codexProviderPresets)[0], + index: number, + ) => { + const authString = JSON.stringify(preset.auth || {}, null, 2); + setCodexAuth(authString); + setCodexConfig(preset.config || ""); + + setFormData({ + name: preset.name, + websiteUrl: preset.websiteUrl, + settingsConfig: formData.settingsConfig, + }); + + setSelectedCodexPreset(index); + + // 同步 API Key 输入框 + try { + const auth = JSON.parse(authString); + const key = typeof auth.api_key === "string" ? auth.api_key : ""; + setCodexApiKey(key); + } catch { + setCodexApiKey(""); + } + }; + // 处理 API Key 输入并自动更新配置 const handleApiKeyChange = (key: string) => { setApiKey(key); @@ -207,6 +247,18 @@ const ProviderForm: React.FC = ({ setDisableCoAuthored(hasCoAuthoredDisabled); }; + // Codex: 处理 API Key 输入并写回 auth.json + const handleCodexApiKeyChange = (key: string) => { + setCodexApiKey(key); + try { + const auth = JSON.parse(codexAuth || "{}"); + auth.api_key = key.trim(); + setCodexAuth(JSON.stringify(auth, null, 2)); + } catch { + // ignore + } + }; + // 根据当前配置决定是否展示 API Key 输入框 const showApiKey = selectedPreset !== null || hasApiKeyField(formData.settingsConfig); @@ -216,6 +268,21 @@ const ProviderForm: React.FC = ({ selectedPreset !== null && providerPresets[selectedPreset]?.isOfficial === true; + // Codex: 控制显示 API Key 与官方标记 + const getCodexAuthApiKey = (authString: string): string => { + try { + const auth = JSON.parse(authString || "{}"); + return typeof auth.api_key === "string" ? auth.api_key : ""; + } catch { + return ""; + } + }; + const showCodexApiKey = + selectedCodexPreset !== null || getCodexAuthApiKey(codexAuth) !== ""; + const isCodexOfficialPreset = + selectedCodexPreset !== null && + codexProviderPresets[selectedCodexPreset]?.isOfficial === true; + // 初始时从配置中同步 API Key(编辑模式) useEffect(() => { if (initialData) { @@ -289,6 +356,26 @@ const ProviderForm: React.FC = ({ )} + {showPresets && isCodex && ( +
+ +
+ {codexProviderPresets.map((preset, index) => ( + + ))} +
+
+ )} +
= ({
)} + {isCodex && ( +
+ + handleCodexApiKeyChange(e.target.value)} + placeholder={ + isCodexOfficialPreset + ? "官方无需填写 API Key,直接保存即可" + : "只需要填这里,上方 auth.json 会自动填充" + } + disabled={isCodexOfficialPreset} + autoComplete="off" + style={ + isCodexOfficialPreset + ? { + backgroundColor: "#f5f5f5", + cursor: "not-allowed", + color: "#999", + } + : {} + } + /> +
+ )} +
= ({