fix(web): restore sessions from conversation detail authority

This commit is contained in:
lyon
2026-06-17 08:25:49 +08:00
parent 55946aac65
commit 221eb0c02d
+49 -19
View File
@@ -153,29 +153,23 @@ export const useWorkbenchStore = defineStore("workbench", () => {
workspace.value = optimisticWorkspaceSelection(current, conversation, tabProjectId);
void refreshSessionStatusById(sessionIdFromConversation(conversation));
loading.value = true;
const [response, detailResponse] = await Promise.all([
api.workbench.selectConversation(current.workspaceId, { projectId: tabProjectId, conversationId: conversation.conversationId, sessionId: conversation.sessionId, threadId: conversation.threadId, updatedByClient: "cloud-web-vue" }),
api.workbench.conversation(conversation.conversationId, { projectId: tabProjectId })
]);
const persistPromise = api.workbench.selectConversation(current.workspaceId, { projectId: tabProjectId, conversationId: conversation.conversationId, sessionId: conversation.sessionId, threadId: conversation.threadId, updatedByClient: "cloud-web-vue" });
const detailResponse = await api.workbench.conversation(conversation.conversationId, { projectId: tabProjectId });
const response = await persistPromise;
loading.value = false;
clearSwitchingConversation(conversation.conversationId);
if (!isCurrentWorkspaceSelection(requestEpoch, conversation.conversationId)) return;
if (response.ok) {
const selectedConversation = detailResponse.ok ? detailResponse.data?.conversation ?? null : null;
if (!selectedConversation) error.value = detailResponse.error ?? "conversation unavailable";
const selectedProjectId = conversationProjectId(selectedConversation ?? conversation, tabProjectId);
workspace.value = workspaceWithSelectedConversation(response.data?.workspace ?? current, selectedConversation ?? conversation, selectedProjectId);
messages.value = restoreMessagesTraceAuthority(messagesFromSelectedConversation(selectedConversation, conversation.conversationId, null, []), messages.value);
if (selectedConversation) conversations.value = mergeConversationIntoList(conversations.value, selectedConversation);
void hydrateTurnStatusAuthority(messages.value);
void hydrateTerminalMessageDiagnostics();
void hydrateTraceEvents(messages.value);
reattachRestoredActiveTrace();
currentRequest.value = null;
await refreshSelectedSessionStatus(selectedConversation ?? conversation);
const selectedConversation = detailResponse.ok ? detailResponse.data?.conversation ?? null : null;
if (selectedConversation) {
const selectedProjectId = conversationProjectId(selectedConversation, tabProjectId);
applySelectedConversationDetail(selectedConversation, response.ok ? response.data?.workspace ?? current : workspace.value ?? current, selectedProjectId, null, messages.value);
error.value = null;
void persistSelectedConversation(selectedConversation, selectedProjectId, response);
await refreshSelectedSessionStatus(selectedConversation);
await refreshConversations(conversation.conversationId);
return;
}
error.value = detailResponse.error ?? "conversation unavailable";
if (response.status === 404 && await retrySelectConversationWithFreshWorkspace(conversation, tabProjectId, requestEpoch)) return;
error.value = response.error ?? "session switch failed";
}
@@ -203,9 +197,14 @@ export const useWorkbenchStore = defineStore("workbench", () => {
error.value = response.error ?? "session URL not found";
return false;
}
const selectedProjectId = conversationProjectId(conversation, activeProjectId.value);
applySelectedConversationDetail(conversation, current, selectedProjectId, null, messages.value);
clearSwitchingConversation(normalized);
error.value = null;
void refreshSessionStatusById(sessionIdFromConversation(conversation));
await selectConversation(conversation);
return activeConversationId.value === normalized;
void persistSelectedConversation(conversation, selectedProjectId);
void refreshConversations(normalized);
return activeConversationId.value === normalized && messages.value.length > 0;
}
async function deleteCurrentSession(): Promise<void> {
@@ -685,6 +684,37 @@ export const useWorkbenchStore = defineStore("workbench", () => {
if (switchingConversationId.value === conversationId) switchingConversationId.value = null;
}
function applySelectedConversationDetail(conversation: ConversationRecord, baseWorkspace: WorkspaceRecord | null, selectedProjectId: string, previousConversationId: string | null, previousMessages: ChatMessage[]): void {
workspace.value = workspaceWithSelectedConversation(baseWorkspace, conversation, selectedProjectId);
messages.value = restoreMessagesTraceAuthority(messagesFromSelectedConversation(conversation, conversation.conversationId, previousConversationId, previousMessages), previousMessages);
conversations.value = mergeConversationIntoList(conversations.value, conversation);
conversationsReady.value = true;
currentRequest.value = null;
void hydrateTurnStatusAuthority(messages.value);
void hydrateTerminalMessageDiagnostics();
void hydrateTraceEvents(messages.value);
reattachRestoredActiveTrace();
}
async function persistSelectedConversation(conversation: ConversationRecord, selectedProjectId: string, existingResponse?: ApiResult<{ workspace?: WorkspaceRecord }>): Promise<void> {
const conversationId = conversation.conversationId;
let response = existingResponse ?? null;
if (!response) {
const workspaceId = workspace.value?.workspaceId;
if (!workspaceId) return;
response = await api.workbench.selectConversation(workspaceId, { projectId: selectedProjectId, conversationId, sessionId: conversation.sessionId, threadId: conversation.threadId, updatedByClient: "cloud-web-vue" });
}
if (!response.ok && response.status === 404) {
const fresh = await api.workbench.workspace(selectedProjectId);
const freshWorkspace = fresh.data?.workspace;
if (fresh.ok && freshWorkspace?.workspaceId && activeConversationId.value === conversationId) {
response = await api.workbench.selectConversation(freshWorkspace.workspaceId, { projectId: selectedProjectId, conversationId, sessionId: conversation.sessionId, threadId: conversation.threadId, updatedByClient: "cloud-web-vue-retry" });
}
}
if (!response.ok || !response.data?.workspace || activeConversationId.value !== conversationId) return;
workspace.value = workspaceWithSelectedConversation(response.data.workspace, conversation, selectedProjectId);
}
async function retrySelectConversationWithFreshWorkspace(conversation: ConversationRecord, tabProjectId: string, requestEpoch: number): Promise<boolean> {
const fresh = await api.workbench.workspace(tabProjectId);
if (!isCurrentWorkspaceSelection(requestEpoch, conversation.conversationId)) return true;