feat(webui): show forked history boundary

This commit is contained in:
Xubin Ren
2026-06-10 04:26:06 +08:00
parent 73d4b1cb2f
commit 26a58282d4
21 changed files with 242 additions and 121 deletions
+19 -3
View File
@@ -20,7 +20,7 @@ export function useSessions(): {
error: string | null;
refresh: () => Promise<void>;
createChat: (workspaceScope?: WorkspaceScopePayload | null) => Promise<string>;
forkChat: (sourceChatId: string, beforeUserIndex: number) => Promise<string>;
forkChat: (sourceChatId: string, beforeUserIndex: number, title?: string) => Promise<string>;
deleteChat: (key: string) => Promise<void>;
} {
const { client, token } = useClient();
@@ -92,8 +92,9 @@ export function useSessions(): {
const forkChat = useCallback(async (
sourceChatId: string,
beforeUserIndex: number,
title?: string,
): Promise<string> => {
const chatId = await client.forkChat(sourceChatId, beforeUserIndex);
const chatId = await client.forkChat(sourceChatId, beforeUserIndex, title);
const key = `websocket:${chatId}`;
optimisticKeysRef.current.add(key);
setSessions((prev) => [
@@ -103,7 +104,7 @@ export function useSessions(): {
chatId,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
title: "",
title: title ?? "",
preview: "",
workspaceScope: null,
},
@@ -131,6 +132,7 @@ export function useSessionHistory(key: string | null): {
error: string | null;
refresh: () => void;
version: number;
forkBoundaryMessageCount: number | null;
/** ``true`` when the replayed transcript ends with a trace row (turn still in flight). */
hasPendingToolCalls: boolean;
} {
@@ -145,6 +147,7 @@ export function useSessionHistory(key: string | null): {
loading: boolean;
error: string | null;
hasPendingToolCalls: boolean;
forkBoundaryMessageCount: number | null;
version: number;
}>({
key: null,
@@ -152,6 +155,7 @@ export function useSessionHistory(key: string | null): {
loading: false,
error: null,
hasPendingToolCalls: false,
forkBoundaryMessageCount: null,
version: 0,
});
@@ -163,6 +167,7 @@ export function useSessionHistory(key: string | null): {
loading: false,
error: null,
hasPendingToolCalls: false,
forkBoundaryMessageCount: null,
version: 0,
});
return;
@@ -178,6 +183,7 @@ export function useSessionHistory(key: string | null): {
loading: true,
error: null,
hasPendingToolCalls: false,
forkBoundaryMessageCount: null,
version: 0,
});
(async () => {
@@ -191,6 +197,7 @@ export function useSessionHistory(key: string | null): {
loading: false,
error: null,
hasPendingToolCalls: false,
forkBoundaryMessageCount: null,
version: prev.key === key ? prev.version + 1 : 1,
}));
return;
@@ -202,12 +209,16 @@ export function useSessionHistory(key: string | null): {
}));
const last = ui[ui.length - 1];
const hasPending = last?.kind === "trace";
const forkBoundary = typeof body.fork_boundary_message_count === "number"
? Math.max(0, Math.min(body.fork_boundary_message_count, ui.length))
: null;
setState((prev) => ({
key,
messages: ui,
loading: false,
error: null,
hasPendingToolCalls: hasPending,
forkBoundaryMessageCount: forkBoundary,
version: prev.key === key ? prev.version + 1 : 1,
}));
} catch (e) {
@@ -219,6 +230,7 @@ export function useSessionHistory(key: string | null): {
loading: false,
error: null,
hasPendingToolCalls: false,
forkBoundaryMessageCount: null,
version: prev.key === key ? prev.version + 1 : 1,
}));
} else {
@@ -228,6 +240,7 @@ export function useSessionHistory(key: string | null): {
loading: false,
error: (e as Error).message,
hasPendingToolCalls: false,
forkBoundaryMessageCount: null,
version: prev.key === key ? prev.version : 0,
}));
}
@@ -245,6 +258,7 @@ export function useSessionHistory(key: string | null): {
error: null,
refresh,
version: 0,
forkBoundaryMessageCount: null,
hasPendingToolCalls: false,
};
}
@@ -258,6 +272,7 @@ export function useSessionHistory(key: string | null): {
error: null,
refresh,
version: 0,
forkBoundaryMessageCount: null,
hasPendingToolCalls: false,
};
}
@@ -268,6 +283,7 @@ export function useSessionHistory(key: string | null): {
error: state.error,
refresh,
version: state.version,
forkBoundaryMessageCount: state.forkBoundaryMessageCount,
hasPendingToolCalls: state.hasPendingToolCalls,
};
}