Add assistant snapshot management to track unsaved changes and enhance debug handling

This commit is contained in:
Xin Wang
2026-02-26 14:13:47 +08:00
parent da83c8ec8a
commit fbbb2e0fee

View File

@@ -106,8 +106,14 @@ export const AssistantsPage: React.FC = () => {
const [copySuccess, setCopySuccess] = useState(false);
const [saveLoading, setSaveLoading] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [persistedAssistantSnapshotById, setPersistedAssistantSnapshotById] = useState<Record<string, string>>({});
const selectedAssistant = assistants.find(a => a.id === selectedId) || null;
const serializeAssistant = (assistant: Assistant) => JSON.stringify(assistant);
const selectedAssistantHasUnsavedChanges = Boolean(
selectedAssistant
&& persistedAssistantSnapshotById[selectedAssistant.id] !== serializeAssistant(selectedAssistant)
);
const filteredAssistants = assistants.filter(a =>
a.name.toLowerCase().includes(searchTerm.toLowerCase())
@@ -131,6 +137,12 @@ export const AssistantsPage: React.FC = () => {
setLlmModels(llmList);
setAsrModels(asrList);
setTools(toolList);
setPersistedAssistantSnapshotById(
assistantList.reduce<Record<string, string>>((acc, item) => {
acc[item.id] = serializeAssistant(item);
return acc;
}, {})
);
if (assistantList.length > 0) {
setSelectedId(assistantList[0].id);
}
@@ -166,6 +178,7 @@ export const AssistantsPage: React.FC = () => {
try {
const created = await createAssistant(newAssistantPayload);
setAssistants((prev) => [created, ...prev]);
setPersistedAssistantSnapshotById((prev) => ({ ...prev, [created.id]: serializeAssistant(created) }));
setSelectedId(created.id);
setActiveTab(TabValue.GLOBAL);
} catch (error) {
@@ -180,6 +193,7 @@ export const AssistantsPage: React.FC = () => {
try {
const updated = await updateAssistantApi(selectedAssistant.id, selectedAssistant);
setAssistants((prev) => prev.map((item) => (item.id === updated.id ? { ...item, ...updated } : item)));
setPersistedAssistantSnapshotById((prev) => ({ ...prev, [updated.id]: serializeAssistant(updated) }));
} catch (error) {
console.error(error);
alert('保存失败,请稍后重试。');
@@ -218,6 +232,11 @@ export const AssistantsPage: React.FC = () => {
try {
await deleteAssistant(deleteId);
setAssistants(prev => prev.filter(a => a.id !== deleteId));
setPersistedAssistantSnapshotById((prev) => {
const next = { ...prev };
delete next[deleteId];
return next;
});
if (selectedId === deleteId) setSelectedId(null);
setDeleteId(null);
} catch (error) {
@@ -240,6 +259,15 @@ export const AssistantsPage: React.FC = () => {
}
};
const handleOpenDebug = () => {
if (!selectedAssistant) return;
if (selectedAssistantHasUnsavedChanges) {
const proceed = window.confirm('当前助手配置尚未保存。是否继续打开调试窗口?');
if (!proceed) return;
}
setDebugOpen(true);
};
const toggleTool = (toolId: string) => {
if (!selectedAssistant) return;
const currentTools = selectedAssistant.tools || [];
@@ -393,7 +421,7 @@ export const AssistantsPage: React.FC = () => {
<div className="flex items-center space-x-2 pt-6">
<Button
variant="secondary"
onClick={() => setDebugOpen(true)}
onClick={handleOpenDebug}
className="border border-primary/20 hover:border-primary/50 text-primary hover:text-primary hover:bg-primary/10 shadow-[0_0_15px_rgba(6,182,212,0.1)]"
>
<Play className="mr-2 h-4 w-4" />