fix: preserve investigation execution history by round
This commit is contained in:
@@ -27,6 +27,7 @@ export type AgentSessionRuntime = {
|
||||
topicId?: string | null;
|
||||
purpose: AgentSessionPurpose;
|
||||
taskId?: string;
|
||||
taskExecutionHistory?: { taskId: string; runId: string; sessionId: string };
|
||||
draft: string;
|
||||
reference?: AnswerUiSelection;
|
||||
taskDiscussion?: { context: AgentTaskDiscussionContext; reportGeneration?: number | null };
|
||||
|
||||
@@ -200,7 +200,12 @@ export function useWorkbenchAgent({
|
||||
}
|
||||
}
|
||||
}, [resources, scopeKey, scopeClient, selectedModel, approvalMode]);
|
||||
const interactionRequests = useInteractionRequests(scopeClient, scopeKey, sessionId, continueInteraction);
|
||||
const interactionRequests = useInteractionRequests(
|
||||
scopeClient,
|
||||
scopeKey,
|
||||
sessionPurpose === "task_execution" ? null : sessionId,
|
||||
continueInteraction
|
||||
);
|
||||
const refreshInteractionRequests = interactionRequests.refresh;
|
||||
|
||||
|
||||
@@ -510,7 +515,9 @@ export function useWorkbenchAgent({
|
||||
|
||||
const streaming = runtimeRunning(runtime);
|
||||
const { data: pendingInputs = [], mutate: refreshPendingInputs } = useSWR(
|
||||
sessionId ? ["agent", "response-inputs", getAccessToken, scopeKey, sessionId] : null,
|
||||
sessionId && sessionPurpose !== "task_execution"
|
||||
? ["agent", "response-inputs", getAccessToken, scopeKey, sessionId]
|
||||
: null,
|
||||
() => clientRef.current.listResponseInputs(sessionId!),
|
||||
{ refreshInterval: streaming ? 1000 : 0, shouldRetryOnError: false }
|
||||
);
|
||||
@@ -776,6 +783,118 @@ export function useWorkbenchAgent({
|
||||
return id;
|
||||
}, [activateRuntime, getAccessToken, getProjectId, projectScopeKey, resources]);
|
||||
|
||||
const openTaskExecutionHistory = useCallback(async (taskId: string, runId: string, executionSessionId: string) => {
|
||||
const normalizedTaskId = taskId.trim();
|
||||
const normalizedRunId = runId.trim();
|
||||
const normalizedSessionId = executionSessionId.trim();
|
||||
if (!normalizedTaskId || !normalizedRunId || !normalizedSessionId) {
|
||||
throw new Error("调查任务缺少可用的执行记录标识。");
|
||||
}
|
||||
const projectClient = createAgentApiClient(undefined, {
|
||||
getAccessToken: getWorkbenchTokenProvider(getAccessToken),
|
||||
getProjectId
|
||||
});
|
||||
const loaded = await projectClient.loadTaskExecutionSession(
|
||||
normalizedTaskId,
|
||||
normalizedRunId,
|
||||
normalizedSessionId,
|
||||
AbortSignal.timeout(15_000)
|
||||
);
|
||||
if (!loaded) throw new Error("调查执行记录不存在或尚未持久化。");
|
||||
let target = agentRuntimes(resources).find((entry) =>
|
||||
entry.scope === projectScopeKey && entry.sessionId === loaded.sessionId
|
||||
);
|
||||
if (!target) {
|
||||
target = createAgentRuntime(
|
||||
resources,
|
||||
projectScopeKey,
|
||||
projectClient,
|
||||
createWorkbenchAgentTransport(projectClient, getAccessToken, getProjectId),
|
||||
loaded
|
||||
);
|
||||
} else {
|
||||
target.client = projectClient;
|
||||
target.chat.messages = toAgentUiMessages(loaded.messages);
|
||||
target.title = loaded.title;
|
||||
target.purpose = "task_execution";
|
||||
target.taskId = normalizedTaskId;
|
||||
target.loadedAt = Date.now();
|
||||
target.updatedAt = loaded.updatedAt;
|
||||
target.runStatus = loaded.runStatus;
|
||||
target.error = undefined;
|
||||
}
|
||||
target.taskDiscussion = undefined;
|
||||
target.taskExecutionHistory = {
|
||||
taskId: normalizedTaskId,
|
||||
runId: normalizedRunId,
|
||||
sessionId: normalizedSessionId
|
||||
};
|
||||
target.draft = "";
|
||||
activateRuntime(target);
|
||||
setStatusLabel(loaded.runStatus === "running" ? "调查执行记录自动同步中" : "调查执行记录已打开");
|
||||
return loaded.sessionId;
|
||||
}, [activateRuntime, getAccessToken, getProjectId, projectScopeKey, resources]);
|
||||
|
||||
useEffect(() => {
|
||||
const target = runtimeRef.current;
|
||||
const binding = target?.taskExecutionHistory;
|
||||
if (sessionPurpose !== "task_execution" || !target || !binding || target.sessionId !== binding.sessionId) return;
|
||||
let stopped = false;
|
||||
let refreshing = false;
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
const controller = new AbortController();
|
||||
const schedule = (delay = 2_000) => {
|
||||
if (!stopped) timer = setTimeout(() => void refresh(), delay);
|
||||
};
|
||||
const refresh = async () => {
|
||||
if (stopped || refreshing || resources.activeAgent !== target || target.purpose !== "task_execution") return;
|
||||
refreshing = true;
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = undefined;
|
||||
}
|
||||
try {
|
||||
const loaded = await target.client.loadTaskExecutionSession(
|
||||
binding.taskId,
|
||||
binding.runId,
|
||||
binding.sessionId,
|
||||
controller.signal
|
||||
);
|
||||
if (!loaded || stopped || resources.activeAgent !== target || target.purpose !== "task_execution") {
|
||||
refreshing = false;
|
||||
return;
|
||||
}
|
||||
target.chat.messages = mergeHistoryMessages(target.chat.messages, toAgentUiMessages(loaded.messages));
|
||||
target.title = loaded.title;
|
||||
target.updatedAt = loaded.updatedAt;
|
||||
target.loadedAt = Date.now();
|
||||
target.runStatus = loaded.runStatus;
|
||||
target.connectionError = undefined;
|
||||
setSessionTitle(loaded.title);
|
||||
setStatusLabel(loaded.runStatus === "running" ? "调查执行记录自动同步中" : "调查执行记录已同步");
|
||||
resources.notify();
|
||||
refreshing = false;
|
||||
if (loaded.runStatus === "running" || loaded.isStreaming) schedule();
|
||||
} catch (error) {
|
||||
refreshing = false;
|
||||
if (controller.signal.aborted || stopped) return;
|
||||
target.connectionError = error instanceof Error ? error.message : "调查执行记录同步失败";
|
||||
setStatusLabel("调查执行记录同步中断,正在重试");
|
||||
resources.notify();
|
||||
schedule(4_000);
|
||||
}
|
||||
};
|
||||
const refreshOnFocus = () => void refresh();
|
||||
window.addEventListener("focus", refreshOnFocus);
|
||||
schedule();
|
||||
return () => {
|
||||
stopped = true;
|
||||
controller.abort();
|
||||
if (timer) clearTimeout(timer);
|
||||
window.removeEventListener("focus", refreshOnFocus);
|
||||
};
|
||||
}, [resources, sessionId, sessionPurpose]);
|
||||
|
||||
const renameHistorySession = useCallback(
|
||||
async (nextSessionId: string, title: string) => {
|
||||
const normalizedTitle = title.trim();
|
||||
@@ -890,6 +1009,42 @@ export function useWorkbenchAgent({
|
||||
if (!normalizedPrompt) {
|
||||
return;
|
||||
}
|
||||
let activeSessionId = sessionIdRef.current;
|
||||
if (runtimeRef.current?.purpose === "task_execution") {
|
||||
const target = runtimeRef.current;
|
||||
const binding = target.taskExecutionHistory;
|
||||
if (!binding) throw new Error("调查执行记录缺少调试分支信息,请重新打开后再试。");
|
||||
setStatusLabel("正在创建调查调试分支");
|
||||
try {
|
||||
const branch = await target.client.createTaskExecutionDebugSession(
|
||||
binding.taskId,
|
||||
binding.runId,
|
||||
binding.sessionId
|
||||
);
|
||||
const loaded = await target.client.loadSession(branch.session_id, {
|
||||
messageLimit: 40,
|
||||
signal: AbortSignal.timeout(15_000)
|
||||
});
|
||||
if (!loaded) throw new Error("调查调试分支创建后无法读取。");
|
||||
if (runtimeRef.current !== target) throw new Error("当前 Agent 会话已切换,请在新会话中重新发送。");
|
||||
target.sessionId = loaded.sessionId;
|
||||
target.title = loaded.title;
|
||||
target.purpose = "task_collaboration";
|
||||
target.taskId = binding.taskId;
|
||||
target.taskExecutionHistory = undefined;
|
||||
target.chat.messages = mergeHistoryMessages(target.chat.messages, toAgentUiMessages(loaded.messages));
|
||||
target.messagePage = loaded.messagePage;
|
||||
target.loadedAt = Date.now();
|
||||
target.updatedAt = loaded.updatedAt;
|
||||
target.runStatus = loaded.runStatus;
|
||||
activeSessionId = loaded.sessionId;
|
||||
activateRuntime(target);
|
||||
setStatusLabel("调查调试会话已创建");
|
||||
} catch (error) {
|
||||
showMapNotice({ tone: "error", title: "调查调试会话创建失败", message: error instanceof Error ? error.message : "请稍后重试。" });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (streaming || interactionRequests.awaitingInput) {
|
||||
const owningRuntime = runtimeRef.current;
|
||||
@@ -925,8 +1080,8 @@ export function useWorkbenchAgent({
|
||||
{ text: normalizedPrompt },
|
||||
{
|
||||
body: {
|
||||
session_id: sessionIdRef.current ?? undefined,
|
||||
topic_id: !sessionIdRef.current ? runtimeRef.current?.topicId ?? undefined : undefined,
|
||||
session_id: activeSessionId ?? undefined,
|
||||
topic_id: !activeSessionId ? runtimeRef.current?.topicId ?? undefined : undefined,
|
||||
model: selectedModel || undefined,
|
||||
approval_mode: approvalMode,
|
||||
capabilities: frontendActionEnabledRef.current ? ["frontend-action@1", "host-question@1"] : ["host-question@1"],
|
||||
@@ -935,7 +1090,7 @@ export function useWorkbenchAgent({
|
||||
}
|
||||
);
|
||||
},
|
||||
[approvalMode, chat, inputDelivery, interactionRequests.awaitingInput, refreshInteractionRequests, refreshPendingInputs, selectedModel, streaming, taskDiscussion]
|
||||
[activateRuntime, approvalMode, chat, inputDelivery, interactionRequests.awaitingInput, refreshInteractionRequests, refreshPendingInputs, selectedModel, streaming, taskDiscussion]
|
||||
);
|
||||
|
||||
const triggerEvent = useCallback(async (trigger: AgentEventTriggerContext, prompt: string) => {
|
||||
@@ -1060,6 +1215,7 @@ export function useWorkbenchAgent({
|
||||
startNewSession,
|
||||
loadHistorySession,
|
||||
openTaskCollaboration,
|
||||
openTaskExecutionHistory,
|
||||
renameHistorySession,
|
||||
deleteHistorySession,
|
||||
sessionHistory,
|
||||
|
||||
Reference in New Issue
Block a user