diff --git a/apps/desktop/src/view/pages/settings-window/components/AgentXProfilesConfig.tsx b/apps/desktop/src/view/pages/settings-window/components/AgentXProfilesConfig.tsx
new file mode 100644
index 00000000..d0a20b49
--- /dev/null
+++ b/apps/desktop/src/view/pages/settings-window/components/AgentXProfilesConfig.tsx
@@ -0,0 +1,226 @@
+import { useState, useEffect } from "react"
+import { useTranslation } from "react-i18next"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogFooter,
+} from "@/components/ui/dialog"
+import { CheckCircle2, XCircle, Loader2, Plus, Pencil, Trash2, Check } from "lucide-react"
+import { toast } from "sonner"
+
+interface AgentXProfile {
+ id: string
+ name: string
+ apiKey: string
+ baseUrl: string
+ model: string
+}
+
+const EMPTY_FORM = {
+ name: "",
+ apiKey: "",
+ baseUrl: "https://api.anthropic.com",
+ model: "claude-sonnet-4-20250514",
+}
+
+export function AgentXProfilesConfig() {
+ const { t } = useTranslation()
+ const [profiles, setProfiles] = useState
([])
+ const [activeProfileId, setActiveProfileId] = useState()
+ const [dialogOpen, setDialogOpen] = useState(false)
+ const [editingId, setEditingId] = useState(null)
+ const [form, setForm] = useState(EMPTY_FORM)
+ const [isTesting, setIsTesting] = useState(false)
+ const [isSaving, setIsSaving] = useState(false)
+ const [connectionStatus, setConnectionStatus] = useState<"idle" | "success" | "error">("idle")
+
+ useEffect(() => { loadProfiles() }, [])
+
+ const loadProfiles = async () => {
+ const config = await window.electronAPI?.agentx.getConfig()
+ if (config) {
+ setProfiles((config as any).profiles ?? [])
+ setActiveProfileId((config as any).activeProfileId)
+ }
+ }
+
+ const openAdd = () => {
+ setEditingId(null)
+ setForm(EMPTY_FORM)
+ setConnectionStatus("idle")
+ setDialogOpen(true)
+ }
+
+ const openEdit = (p: AgentXProfile) => {
+ setEditingId(p.id)
+ setForm({ name: p.name, apiKey: p.apiKey, baseUrl: p.baseUrl, model: p.model })
+ setConnectionStatus("idle")
+ setDialogOpen(true)
+ }
+
+ const handleActivate = async (id: string) => {
+ const config = await window.electronAPI?.agentx.getConfig()
+ await window.electronAPI?.agentx.updateConfig({ ...(config as any), activeProfileId: id })
+ setActiveProfileId(id)
+ toast.success(t("settings.agentx.profiles.activated"))
+ }
+
+ const handleDelete = async (id: string) => {
+ const config = await window.electronAPI?.agentx.getConfig()
+ const newProfiles = ((config as any).profiles ?? []).filter((p: AgentXProfile) => p.id !== id)
+ const newActiveId = (config as any).activeProfileId === id ? newProfiles[0]?.id : (config as any).activeProfileId
+ await window.electronAPI?.agentx.updateConfig({ ...(config as any), profiles: newProfiles, activeProfileId: newActiveId })
+ setProfiles(newProfiles)
+ setActiveProfileId(newActiveId)
+ toast.success(t("settings.agentx.profiles.deleted"))
+ }
+
+ const handleTest = async () => {
+ setIsTesting(true)
+ setConnectionStatus("idle")
+ try {
+ const result = await window.electronAPI?.agentx.testConnection({
+ apiKey: form.apiKey,
+ baseUrl: form.baseUrl,
+ model: form.model,
+ })
+ setConnectionStatus(result?.success ? "success" : "error")
+ if (!result?.success) toast.error(result?.error ?? t("settings.agentx.testFailed"))
+ } catch {
+ setConnectionStatus("error")
+ } finally {
+ setIsTesting(false)
+ }
+ }
+
+ const handleSave = async () => {
+ if (!form.name || !form.apiKey) return
+ setIsSaving(true)
+ try {
+ const config = await window.electronAPI?.agentx.getConfig()
+ const existing: AgentXProfile[] = (config as any).profiles ?? []
+ let newProfiles: AgentXProfile[]
+ let newActiveId = (config as any).activeProfileId as string | undefined
+
+ if (editingId) {
+ newProfiles = existing.map(p => p.id === editingId ? { ...p, ...form } : p)
+ } else {
+ const newProfile: AgentXProfile = { id: crypto.randomUUID(), ...form }
+ newProfiles = [...existing, newProfile]
+ if (!newActiveId) newActiveId = newProfile.id
+ }
+
+ await window.electronAPI?.agentx.updateConfig({ ...(config as any), profiles: newProfiles, activeProfileId: newActiveId })
+ setProfiles(newProfiles)
+ setActiveProfileId(newActiveId)
+ setDialogOpen(false)
+ toast.success(t("settings.agentx.profiles.saved"))
+ } finally {
+ setIsSaving(false)
+ }
+ }
+
+ return (
+
+ {profiles.length === 0 ? (
+
{t("settings.agentx.profiles.empty")}
+ ) : (
+ profiles.map(profile => (
+
+
+
+ {profile.name}
+ {profile.id === activeProfileId && (
+
+ {t("settings.agentx.profiles.active")}
+
+ )}
+
+
{profile.baseUrl} · {profile.model}
+
+
+ {profile.id !== activeProfileId && (
+
+ )}
+
+
+
+
+ ))
+ )}
+
+
+
+
+
+ )
+}
diff --git a/apps/desktop/src/view/pages/settings-window/index.tsx b/apps/desktop/src/view/pages/settings-window/index.tsx
index 22fd0fac..6731ea38 100644
--- a/apps/desktop/src/view/pages/settings-window/index.tsx
+++ b/apps/desktop/src/view/pages/settings-window/index.tsx
@@ -21,7 +21,8 @@ import { LanguageSelector } from "./components/LanguageSelector"
import { MCPConfig } from "./components/MCPConfig"
import { SkillsConfig } from "./components/SkillsConfig"
import { WebAccessConfig } from "./components/WebAccessConfig"
-import { Loader2, CheckCircle2, XCircle, Settings, Bot, RefreshCw, Wifi } from "lucide-react"
+import { AgentXProfilesConfig } from "./components/AgentXProfilesConfig"
+import { Loader2, Settings, Bot, RefreshCw, Wifi, AlertTriangle } from "lucide-react"
interface ServerConfig {
host: string
@@ -30,12 +31,6 @@ interface ServerConfig {
enableV2: boolean
}
-interface AgentXConfig {
- apiKey: string
- baseUrl: string
- model: string
-}
-
interface StatusMessage {
type: "success" | "error" | null
message: string
@@ -50,16 +45,8 @@ function SettingsWindow() {
debug: false,
enableV2: true
})
- const [agentXConfig, setAgentXConfig] = useState({
- apiKey: "",
- baseUrl: "https://api.anthropic.com",
- model: "claude-sonnet-4-20250514"
- })
const [statusMessage, setStatusMessage] = useState({ type: null, message: "" })
const [isLoading, setIsLoading] = useState(false)
- const [isTestingConnection, setIsTestingConnection] = useState(false)
- const [connectionStatus, setConnectionStatus] = useState<"idle" | "success" | "error">("idle")
- const [isSavingAgentX, setIsSavingAgentX] = useState(false)
const [isCheckingUpdate, setIsCheckingUpdate] = useState(false)
const [showRestartDialog, setShowRestartDialog] = useState(false)
@@ -88,11 +75,6 @@ function SettingsWindow() {
if (config) {
setServerConfig(config)
}
-
- const agentxConfig = await window.electronAPI?.agentx.getConfig()
- if (agentxConfig) {
- setAgentXConfig(agentxConfig)
- }
} catch (error) {
console.error("Failed to load settings:", error)
showMessage("error", t("messages.loadError"))
@@ -171,47 +153,6 @@ function SettingsWindow() {
}
}
- const handleAgentXConfigChange = (field: keyof AgentXConfig, value: string) => {
- setAgentXConfig(prev => ({ ...prev, [field]: value }))
- setConnectionStatus("idle")
- }
-
- const handleTestConnection = async () => {
- setIsTestingConnection(true)
- setConnectionStatus("idle")
- try {
- const result = await window.electronAPI?.agentx.testConnection(agentXConfig)
- if (result?.success) {
- setConnectionStatus("success")
- showMessage("success", t("settings.agentx.testSuccess"))
- } else {
- setConnectionStatus("error")
- showMessage("error", result?.error || t("settings.agentx.testFailed"))
- }
- } catch (error) {
- setConnectionStatus("error")
- showMessage("error", String(error))
- } finally {
- setIsTestingConnection(false)
- }
- }
-
- const handleSaveAgentXConfig = async () => {
- setIsSavingAgentX(true)
- try {
- const result = await window.electronAPI?.agentx.updateConfig(agentXConfig)
- if (result?.success) {
- showMessage("success", t("settings.agentx.saveSuccess"))
- } else {
- showMessage("error", result?.error || t("settings.agentx.saveFailed"))
- }
- } catch (error) {
- showMessage("error", String(error))
- } finally {
- setIsSavingAgentX(false)
- }
- }
-
const handleCheckUpdate = async () => {
setIsCheckingUpdate(true)
try {
@@ -367,72 +308,28 @@ function SettingsWindow() {
{t("settings.agentx.title")}
{t("settings.agentx.description")}
-
-
-
-
handleAgentXConfigChange("apiKey", e.target.value)}
- />
-
{t("settings.agentx.apiKey.description")}
-
-
-
-
-
handleAgentXConfigChange("baseUrl", e.target.value)}
- />
-
{t("settings.agentx.baseUrl.description")}
-
-
-
-
-
handleAgentXConfigChange("model", e.target.value)}
- />
-
{t("settings.agentx.model.description")}
-
+
+
+
-
-
-
- {connectionStatus === "success" && (
-
- )}
- {connectionStatus === "error" && (
-
- )}
+ {/* Windows Git requirement warning */}
+ {window.electronAPI?.platform === "win32" && (
+
-
+ )}
{/* MCP 配置 */}