Remove AI config approval flow

This commit is contained in:
npc0-hue
2026-09-22 15:33:32 +08:00
parent 20008b4043
commit a8b5d483a3
54 changed files with 364 additions and 875 deletions
+26 -51
View File
@@ -53,6 +53,7 @@ export function ServerDetailPage(props: PageComponentProps) {
const [confirm, setConfirm] = useState<null | { title: string; description: string; danger?: boolean; run: () => Promise<void> }>(null);
const [confirmBusy, setConfirmBusy] = useState(false);
const [terminalOpen, setTerminalOpen] = useState(false);
const [terminalJobId, setTerminalJobId] = useState<string | null>(null);
const [configEditorOpen, setConfigEditorOpen] = useState(false);
const defaultSectionResolvedRef = useRef(false);
@@ -214,7 +215,7 @@ export function ServerDetailPage(props: PageComponentProps) {
className="icon-command"
disabled={!canManageServers}
title={canManageServers ? "打开终端" : "当前账号没有管理权限"}
onClick={() => setTerminalOpen(true)}
onClick={() => { setTerminalJobId(null); setTerminalOpen(true); }}
>
<Terminal size={15} />
<span></span>
@@ -275,8 +276,8 @@ export function ServerDetailPage(props: PageComponentProps) {
/>
)}
{section === "files" && <ServerFilesSection instance={instance.data} session={session} operations={operations} />}
{section === "llm" && <LlmSection serverId={serverId} instance={instance.data} session={session} operations={operations} />}
<ServerManagementTerminalDrawer open={terminalOpen} serverId={instance.data.id} serverName={instance.data.name} onClose={() => setTerminalOpen(false)} />
{section === "llm" && <LlmSection serverId={serverId} session={session} operations={operations} onOpenTerminal={(jobId) => { setTerminalJobId(jobId ?? null); setTerminalOpen(true); }} />}
<ServerManagementTerminalDrawer open={terminalOpen} serverId={instance.data.id} serverName={instance.data.name} jobId={terminalJobId ?? undefined} onClose={() => { setTerminalOpen(false); setTerminalJobId(null); }} />
{configEditorOpen && <ServerConfigEditor instance={instance.data} operations={operations} requester={session.displayName} onClose={() => setConfigEditorOpen(false)} />}
</>
)}
@@ -941,17 +942,15 @@ function formatDateTime(value?: string): string {
interface LlmSectionProps {
serverId: string;
instance: ServerInstanceResponse;
session: PageComponentProps["session"];
operations: PageComponentProps["operations"];
onOpenTerminal: (jobId?: string) => void;
}
function LlmSection({ serverId, instance, session, operations }: LlmSectionProps) {
function LlmSection({ serverId, session, operations, onOpenTerminal }: LlmSectionProps) {
const [prompt, setPrompt] = useState("");
const [suggestion, setSuggestion] = useState<LlmSuggestionView | null>(null);
const [confirming, setConfirming] = useState(false);
const [busy, setBusy] = useState(false);
const [approvalBusy, setApprovalBusy] = useState(false);
const [suggestionError, setSuggestionError] = useState("");
async function requestSuggestion(event: FormEvent<HTMLFormElement>) {
@@ -968,13 +967,19 @@ function LlmSection({ serverId, instance, session, operations }: LlmSectionProps
throw new Error(response.error?.message ?? "AI 提供商未返回可用建议");
}
const recommendation = response.configRecommendation;
const execution = response.configExecution;
if (execution?.job) {
const operationId = operations.begin({ intent: "AI 直接写入配置", targetKind: "llm", targetId: serverId, requester: session.displayName });
operations.succeed(operationId, "AI 建议已直接派发,写入任务 " + execution.job.id + " 已进入队列", execution.job);
onOpenTerminal(execution.job.id);
}
setSuggestion({
serverInstanceId: serverId,
source: "api",
recommendation: response.recommendation ?? "Platform 已返回配置建议。",
diffId: recommendation?.diffId,
expiresAt: recommendation?.expiresAt,
diffSummary: recommendation?.diffSummary
diffSummary: recommendation?.diffSummary,
executionStatus: execution?.status,
job: execution?.job
});
} catch (caught) {
setSuggestionError(caught instanceof Error ? caught.message : "AI 建议请求失败");
@@ -983,27 +988,7 @@ function LlmSection({ serverId, instance, session, operations }: LlmSectionProps
}
}
async function applySuggestion() {
if (!suggestion?.diffId || approvalBusy) {
return;
}
const operationId = operations.begin({ intent: "应用 AI 配置建议", targetKind: "llm", targetId: serverId, requester: session.displayName });
setApprovalBusy(true);
try {
const approved = await platformApiClient.approveAIConfigDiff(suggestion.diffId, `web:ai.config.approve:${suggestion.diffId}`);
const job = approved.dispatch.job;
operations.succeed(operationId, `AI 建议已确认,写入任务 ${job.id} 已派发`, job);
setSuggestion(null);
setConfirming(false);
} catch (error) {
operations.fail(operationId, error instanceof Error ? error.message : "写入任务派发失败", operationId);
setConfirming(false);
} finally {
setApprovalBusy(false);
}
}
const llmOperation = operations.operations.find((operation) => operation.intent === "应用 AI 配置建议" && operation.targetId === serverId);
const llmOperation = operations.operations.find((operation) => operation.intent === "AI 直接写入配置" && operation.targetId === serverId);
return (
<article className="console-panel" aria-label="llm configuration assistance">
@@ -1014,7 +999,7 @@ function LlmSection({ serverId, instance, session, operations }: LlmSectionProps
<span className="page-status"> {serverId}</span>
</div>
<p style={{ margin: "0 0 12px", color: "var(--ink-soft)", fontSize: 13.5 }}>
AI <strong></strong> AI
AI AI
</p>
{llmOperation && (
<div style={{ marginBottom: 10 }}>
@@ -1053,37 +1038,27 @@ function LlmSection({ serverId, instance, session, operations }: LlmSectionProps
<span className="page-status"> AI Provider</span>
</div>
<p style={{ margin: 0, color: "var(--ink-soft)", fontSize: 14 }}>{suggestion.recommendation}</p>
{suggestion.diffId ? (
{suggestion.job ? (
<>
<div className="console-record">
<div className="console-record-head"><strong>Reviewable AI diff</strong><span className="status-pill status-active">pending</span></div>
<div className="console-record-meta"><span>Diff {suggestion.diffId}</span>{suggestion.expiresAt && <span> {new Date(suggestion.expiresAt).toLocaleString()}</span>}</div>
<span className="provider-id">{suggestion.diffSummary ?? "平台已保存可审查配置差异;批准后才会派发写入任务。"}</span>
<div className="console-record-head"><strong>AI </strong><span className="status-pill status-active">{suggestion.executionStatus ?? "queued"}</span></div>
<div className="console-record-meta"><span>Job {suggestion.job.id}</span><span>{suggestion.job.capability}</span><span>{suggestion.job.targetKey}</span></div>
<span className="provider-id">{suggestion.diffSummary ?? "AI 建议已直接进入 config.write 队列,日志正在实时输出。"}</span>
</div>
<div className="confirm-actions">
<button type="button" onClick={() => setSuggestion(null)}>
<button type="button" onClick={() => onOpenTerminal(suggestion.job?.id)}>
</button>
<button type="button" className="confirm-primary" onClick={() => setConfirming(true)}>
AI
<button type="button" className="confirm-primary" onClick={() => setSuggestion(null)}>
</button>
</div>
</>
) : (
<span className="provider-id"></span>
<span className="provider-id"></span>
)}
</div>
)}
<ConfirmDialog
open={confirming}
title="确认应用 AI 配置建议"
description={`即将向服务器 ${instance.name}${serverId})派发配置写入任务。写入内容以上方差异为准。`}
confirmLabel="确认写入"
busy={approvalBusy || llmOperation?.status === "pending"}
onCancel={() => setConfirming(false)}
onConfirm={() => void applySuggestion()}
/>
</article>
);
}