Files
qiming/qimingclaw/crates/agent-electron-client/src/renderer/components/settings/AgentRunnerSettings.tsx

227 lines
6.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect } from "react";
import {
agentRunnerManager,
AgentRunnerConfig,
AgentRunnerStatus,
} from "../../services/agents/agentRunner";
import { DEFAULT_ANTHROPIC_API_URL } from "@shared/constants";
import { t } from "../../services/core/i18n";
interface AgentRunnerSettingsProps {
isOpen: boolean;
onClose: () => void;
}
function AgentRunnerSettings({ isOpen, onClose }: AgentRunnerSettingsProps) {
const [config, setConfig] = useState<AgentRunnerConfig>(
agentRunnerManager.getConfig(),
);
const [status, setStatus] = useState<AgentRunnerStatus>({ running: false });
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState("");
useEffect(() => {
if (isOpen) {
loadConfig();
checkStatus();
}
}, [isOpen]);
const loadConfig = async () => {
await agentRunnerManager.loadConfig();
setConfig(agentRunnerManager.getConfig());
};
const checkStatus = async () => {
const s = await agentRunnerManager.checkStatus();
setStatus(s);
};
const handleSave = async () => {
agentRunnerManager.setConfig(config);
await agentRunnerManager.saveConfig();
setMessage(t("Claw.AgentRunner.configSaved"));
setTimeout(() => setMessage(""), 2000);
};
const handleStartStop = async () => {
setLoading(true);
setMessage("");
try {
if (status.running) {
const result = await agentRunnerManager.stop();
if (result.success) {
setMessage(t("Claw.AgentRunner.stopped"));
} else {
setMessage(t("Claw.AgentRunner.error", result.error || ""));
}
} else {
const result = await agentRunnerManager.start();
if (result.success) {
setMessage(t("Claw.AgentRunner.started"));
} else {
setMessage(t("Claw.AgentRunner.error", result.error || ""));
}
}
} catch (error) {
setMessage(t("Claw.AgentRunner.error", String(error)));
}
await checkStatus();
setLoading(false);
};
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div
className="modal-content agent-runner-modal"
onClick={(e) => e.stopPropagation()}
>
<div className="modal-header">
<h2>Agent Runner</h2>
<button className="close-btn" onClick={onClose}>
×
</button>
</div>
<div className="agent-runner-section">
<div className="status-panel">
<div
className={`status-indicator ${status.running ? "running" : "stopped"}`}
>
{status.running
? t("Claw.AgentRunner.running")
: t("Claw.AgentRunner.stoppedStatus")}
</div>
{status.pid && <div className="pid">PID: {status.pid}</div>}
</div>
{status.running && (
<div className="url-info">
<div className="url-item">
<span className="label">
{t("Claw.AgentRunner.backendAddress")}:
</span>
<code>{status.backendUrl}</code>
</div>
<div className="url-item">
<span className="label">
{t("Claw.AgentRunner.proxyAddress")}:
</span>
<code>{status.proxyUrl}</code>
</div>
</div>
)}
<button
className={`toggle-agent-btn ${status.running ? "stop" : "start"}`}
onClick={handleStartStop}
disabled={loading}
>
{loading
? "..."
: status.running
? t("Claw.AgentRunner.stop")
: t("Claw.AgentRunner.start")}
</button>
</div>
<div className="agent-runner-section">
<h3>{t("Claw.AgentRunner.config")}</h3>
<div className="form-group">
<label>{t("Claw.AgentRunner.executablePath")}</label>
<input
type="text"
value={config.binPath}
onChange={(e) =>
setConfig({ ...config, binPath: e.target.value })
}
placeholder="qiming-agent-core"
/>
</div>
<div className="form-row">
<div className="form-group">
<label>{t("Claw.AgentRunner.backendPort")}</label>
<input
type="number"
value={config.backendPort}
onChange={(e) =>
setConfig({
...config,
backendPort: parseInt(e.target.value),
})
}
placeholder="60001"
/>
</div>
<div className="form-group">
<label>{t("Claw.AgentRunner.proxyPort")}</label>
<input
type="number"
value={config.proxyPort}
onChange={(e) =>
setConfig({ ...config, proxyPort: parseInt(e.target.value) })
}
placeholder="60002"
/>
</div>
</div>
<div className="form-group">
<label>{t("Claw.AgentRunner.apiKey")}</label>
<input
type="password"
value={config.apiKey}
onChange={(e) => setConfig({ ...config, apiKey: e.target.value })}
placeholder="sk-ant-..."
/>
</div>
<div className="form-group">
<label>{t("Claw.AgentRunner.apiBaseUrl")}</label>
<input
type="text"
value={config.apiBaseUrl}
onChange={(e) =>
setConfig({ ...config, apiBaseUrl: e.target.value })
}
placeholder={DEFAULT_ANTHROPIC_API_URL}
autoComplete="off"
spellCheck={false}
/>
</div>
<div className="form-group">
<label>{t("Claw.AgentRunner.defaultModel")}</label>
<select
value={config.defaultModel}
onChange={(e) =>
setConfig({ ...config, defaultModel: e.target.value })
}
>
<option value="claude-opus-4-20250514">Claude Opus 4</option>
<option value="claude-sonnet-4-20250514">Claude Sonnet 4</option>
<option value="claude-haiku-3-20240307">Claude Haiku 3</option>
</select>
</div>
</div>
{message && <div className="agent-runner-message">{message}</div>}
<div className="modal-footer">
<button className="save-btn" onClick={handleSave}>
{t("Claw.AgentRunner.saveConfig")}
</button>
</div>
</div>
</div>
);
}
export default AgentRunnerSettings;