Files
SenMeshNet/components/settings/tabs/ai/RcaPromptSettings.tsx
zhaolei 2f9f8da48e
Some checks failed
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
Initial commit: NetMesh smart ops platform with 3D topology, inspection reports, RCA and AI ops assistant
2026-10-15 13:53:04 +08:00

186 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 { Brain, RotateCcw, Save } from "lucide-react";
import React, { useEffect, useState } from "react";
import { Button } from "../../../ui/button";
import { SettingCard, SettingsSection } from "../../settings-ui";
import {
DEFAULT_PHASE1_SYSTEM,
DEFAULT_PHASE2_SYSTEM,
} from "../../../../infrastructure/ai/rcaAgent/rcaRunner";
const STORAGE_KEY = "netcatty_rca_prompts_v1";
interface RcaPromptsConfig {
phase1?: string;
phase2?: string;
}
function loadConfig(): RcaPromptsConfig {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) return JSON.parse(raw);
} catch (_) {}
return {};
}
function saveConfig(cfg: RcaPromptsConfig) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(cfg));
}
export const RcaPromptSettings: React.FC = () => {
const defaults = {
phase1: DEFAULT_PHASE1_SYSTEM,
phase2: DEFAULT_PHASE2_SYSTEM,
};
const [phase1, setPhase1] = useState("");
const [phase2, setPhase2] = useState("");
const [savedVersion, setSavedVersion] = useState<{ p1: string; p2: string }>({ p1: "", p2: "" });
// 加载 localStorage 中的自定义值(无则空字符串,表示"使用默认")
useEffect(() => {
const cfg = loadConfig();
const p1 = cfg.phase1 ?? "";
const p2 = cfg.phase2 ?? "";
setPhase1(p1);
setPhase2(p2);
setSavedVersion({ p1, p2 });
}, []);
const dirty = phase1 !== savedVersion.p1 || phase2 !== savedVersion.p2;
const phase1IsDefault = !phase1.trim();
const phase2IsDefault = !phase2.trim();
const handleSave = () => {
const cfg: RcaPromptsConfig = {
phase1: phase1.trim() ? phase1 : undefined,
phase2: phase2.trim() ? phase2 : undefined,
};
saveConfig(cfg);
setSavedVersion({ p1: phase1, p2: phase2 });
};
const handleResetAll = () => {
setPhase1("");
setPhase2("");
};
return (
<SettingsSection
anchorId="ai-rca-prompts"
title="RCA 智能诊断提示词"
>
<p className="text-sm text-muted-foreground mb-4">
自定义 AI 根因分析(RCA)的系统提示词。留空表示使用内置默认值。
Phase 1 是诊断命令规划,Phase 2 是根因综合分析。
</p>
<SettingCard divided={false}>
<div className="flex items-center justify-between gap-3 mb-4">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Brain size={16} />
<span>自定义提示词会覆盖内置默认值,点击"恢复默认"可清空编辑内容。</span>
</div>
<div className="flex items-center gap-2">
<Button
variant="ghost"
size="sm"
onClick={handleResetAll}
disabled={phase1IsDefault && phase2IsDefault}
>
<RotateCcw size={14} className="mr-1" />
全部恢复默认
</Button>
<Button size="sm" onClick={handleSave} disabled={!dirty}>
<Save size={14} className="mr-1" />
保存
</Button>
</div>
</div>
{/* Phase 1 */}
<div className="space-y-2 mb-5">
<div className="flex items-center justify-between">
<label className="text-sm font-medium">
Phase 1 — 诊断规划 Agent
<span className="ml-2 text-xs text-muted-foreground font-normal">
(AI 根据告警规划要执行的诊断命令)
</span>
</label>
<div className="flex items-center gap-2 text-xs">
{phase1IsDefault ? (
<span className="text-green-600 dark:text-green-400">使用默认</span>
) : (
<span className="text-amber-600 dark:text-amber-400">已自定义</span>
)}
{!phase1IsDefault && (
<Button
variant="ghost"
size="sm"
className="h-7 px-2 text-xs"
onClick={() => setPhase1("")}
>
<RotateCcw size={12} className="mr-1" /> 恢复默认
</Button>
)}
</div>
</div>
<textarea
value={phase1}
onChange={(e) => setPhase1(e.target.value)}
placeholder={defaults.phase1}
className="w-full h-56 rounded-md border border-input bg-background px-3 py-2 text-sm font-mono resize-y focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
spellCheck={false}
/>
{phase1IsDefault && (
<details className="text-xs text-muted-foreground">
<summary className="cursor-pointer hover:text-foreground">预览内置默认提示词</summary>
<pre className="mt-2 p-3 bg-muted/50 rounded text-xs whitespace-pre-wrap max-h-48 overflow-auto font-mono leading-relaxed">{defaults.phase1}</pre>
</details>
)}
</div>
{/* Phase 2 */}
<div className="space-y-2">
<div className="flex items-center justify-between">
<label className="text-sm font-medium">
Phase 2 — 根因综合 Agent
<span className="ml-2 text-xs text-muted-foreground font-normal">
(AI 综合告警 + metrics + 命令输出,生成根因 + 建议)
</span>
</label>
<div className="flex items-center gap-2 text-xs">
{phase2IsDefault ? (
<span className="text-green-600 dark:text-green-400">使用默认</span>
) : (
<span className="text-amber-600 dark:text-amber-400">已自定义</span>
)}
{!phase2IsDefault && (
<Button
variant="ghost"
size="sm"
className="h-7 px-2 text-xs"
onClick={() => setPhase2("")}
>
<RotateCcw size={12} className="mr-1" /> 恢复默认
</Button>
)}
</div>
</div>
<textarea
value={phase2}
onChange={(e) => setPhase2(e.target.value)}
placeholder={defaults.phase2}
className="w-full h-56 rounded-md border border-input bg-background px-3 py-2 text-sm font-mono resize-y focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
spellCheck={false}
/>
{phase2IsDefault && (
<details className="text-xs text-muted-foreground">
<summary className="cursor-pointer hover:text-foreground">预览内置默认提示词</summary>
<pre className="mt-2 p-3 bg-muted/50 rounded text-xs whitespace-pre-wrap max-h-48 overflow-auto font-mono leading-relaxed">{defaults.phase2}</pre>
</details>
)}
</div>
</SettingCard>
</SettingsSection>
);
};