Initial commit: NetMesh smart ops platform with 3D topology, inspection reports, RCA and AI ops assistant
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
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
This commit is contained in:
185
components/settings/tabs/ai/RcaPromptSettings.tsx
Normal file
185
components/settings/tabs/ai/RcaPromptSettings.tsx
Normal file
@@ -0,0 +1,185 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user