返回 DeepSeek-Reasonix
ToolRecoveryPanel.tsx
根目录 / desktop / frontend / src / components / ToolRecoveryPanel.tsx
1 import { ErrorMessage } from "./ErrorMessage";
2 import { useEffect, useRef, useState } from "react";
3 import { app } from "../lib/bridge";
4 import { useT } from "../lib/i18n";
5 import type { ToolRecoveryBindings, ToolRecoverySnapshot } from "../lib/toolRecovery";
6 import "./ToolRecoveryPanel.css";
7
8 export function ToolRecoveryPanel({ tabId, sessionKey, running, refreshKey, bindings = app }: {
9 tabId: string; sessionKey: string; running: boolean; refreshKey: number;
10 bindings?: ToolRecoveryBindings;
11 }) {
12 const t = useT();
13 const generation = useRef(0);
14 const [snapshot, setSnapshot] = useState<ToolRecoverySnapshot | null>(null);
15 const [error, setError] = useState("");
16 useEffect(() => {
17 const own = ++generation.current;
18 setSnapshot(null); setError("");
19 if (!running && bindings.GetToolRecoveryForTab) {
20 void bindings.GetToolRecoveryForTab(tabId).then(next => {
21 if (generation.current === own) setSnapshot(next);
22 }).catch(err => { if (generation.current === own) setError(String(err)); });
23 }
24 return () => { generation.current++; };
25 }, [bindings, tabId, sessionKey, running, refreshKey]);
26
27 if (!snapshot?.calls.length && !error) return null;
28 return <section className="notice-line notice-line--warn tool-recovery-panel" aria-label={t("toolRecovery.title")}>
29 <details open>
30 <summary className="notice-line__title">{t("toolRecovery.title")}</summary>
31 <div className="notice-line__text">
32 {error && <p role="alert"><ErrorMessage error={error} /></p>}
33 {!!snapshot?.calls.length && <p>{t("toolRecovery.retired")}</p>}
34 {(snapshot?.calls ?? []).map(call => <div key={call.identity.attempt_id}>
35 <p>{call.identity.canonical_tool} · {t("toolRecovery.unknown")}</p>
36 <details><summary>{t("toolRecovery.details")}</summary>
37 <p>{call.identity.resource_scope}</p>
38 <p>{call.identity.argument_digest}</p>
39 {call.arguments !== undefined && <pre>{JSON.stringify(call.arguments, null, 2)}</pre>}
40 </details>
41 </div>)}
42 </div>
43 </details>
44 </section>;
45 }
46
46 lines Plain Text