fix(FN-2177): exclude terminal AI sessions from background list
- Limit background session inclusion to active statuses (generating and awaiting_input) - Remove sessions from local state when SSE updates deliver complete or error terminal statuses - Update useBackgroundSessions tests to assert terminal sessions are filtered out and removed on SSE updates - Adjust session count expectations to reflect active-only tracking
This commit is contained in:
@@ -74,8 +74,6 @@ describe("useBackgroundSessions", () => {
|
||||
await waitFor(() => {
|
||||
expect(result.current.sessions.map((session) => session.id).sort()).toEqual([
|
||||
"s-awaiting",
|
||||
"s-complete",
|
||||
"s-error",
|
||||
"s-generating",
|
||||
]);
|
||||
});
|
||||
@@ -147,6 +145,97 @@ describe("useBackgroundSessions", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("removes session when SSE delivers complete status", async () => {
|
||||
const { result } = renderHook(() => useBackgroundSessions());
|
||||
|
||||
await waitFor(() => {
|
||||
expect(MockEventSource.instances.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
const eventSource = MockEventSource.instances[0]!;
|
||||
|
||||
act(() => {
|
||||
eventSource._emit(
|
||||
"ai_session:updated",
|
||||
makeSession({
|
||||
id: "terminal-complete",
|
||||
type: "planning",
|
||||
status: "generating",
|
||||
updatedAt: "2026-04-08T00:00:01.000Z",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.generating).toBe(1);
|
||||
expect(result.current.sessions.map((session) => session.id)).toEqual(["terminal-complete"]);
|
||||
expect(result.current.planningSessions.map((session) => session.id)).toEqual(["terminal-complete"]);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
eventSource._emit(
|
||||
"ai_session:updated",
|
||||
makeSession({
|
||||
id: "terminal-complete",
|
||||
type: "planning",
|
||||
status: "complete",
|
||||
updatedAt: "2026-04-08T00:00:02.000Z",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.sessions).toEqual([]);
|
||||
expect(result.current.planningSessions).toEqual([]);
|
||||
expect(result.current.generating).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it("removes session when SSE delivers error status", async () => {
|
||||
const { result } = renderHook(() => useBackgroundSessions());
|
||||
|
||||
await waitFor(() => {
|
||||
expect(MockEventSource.instances.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
const eventSource = MockEventSource.instances[0]!;
|
||||
|
||||
act(() => {
|
||||
eventSource._emit(
|
||||
"ai_session:updated",
|
||||
makeSession({
|
||||
id: "terminal-error",
|
||||
type: "planning",
|
||||
status: "generating",
|
||||
updatedAt: "2026-04-08T00:00:01.000Z",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.sessions.map((session) => session.id)).toEqual(["terminal-error"]);
|
||||
expect(result.current.planningSessions.map((session) => session.id)).toEqual(["terminal-error"]);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
eventSource._emit(
|
||||
"ai_session:updated",
|
||||
makeSession({
|
||||
id: "terminal-error",
|
||||
type: "planning",
|
||||
status: "error",
|
||||
updatedAt: "2026-04-08T00:00:02.000Z",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.sessions).toEqual([]);
|
||||
expect(result.current.planningSessions).toEqual([]);
|
||||
expect(result.current.generating).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it("removes sessions when ai_session:deleted SSE event arrives", async () => {
|
||||
mockFetchAiSessions.mockResolvedValueOnce([
|
||||
makeSession({ id: "delete-me", status: "awaiting_input" }),
|
||||
@@ -259,8 +348,11 @@ describe("useBackgroundSessions", () => {
|
||||
await waitFor(() => {
|
||||
expect(result.current.generating).toBe(1);
|
||||
expect(result.current.needsInput).toBe(1);
|
||||
expect(result.current.planningSessions.map((session) => session.id).sort()).toEqual([
|
||||
"count-error-plan",
|
||||
expect(result.current.planningSessions.map((session) => session.id)).toEqual([
|
||||
"count-generating",
|
||||
]);
|
||||
expect(result.current.sessions.map((session) => session.id).sort()).toEqual([
|
||||
"count-awaiting",
|
||||
"count-generating",
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -28,12 +28,7 @@ function parseTimestamp(updatedAt: string | undefined): number {
|
||||
}
|
||||
|
||||
function shouldIncludeSession(session: AiSessionSummary): boolean {
|
||||
return (
|
||||
session.status === "generating" ||
|
||||
session.status === "awaiting_input" ||
|
||||
session.status === "complete" ||
|
||||
session.status === "error"
|
||||
);
|
||||
return session.status === "generating" || session.status === "awaiting_input";
|
||||
}
|
||||
|
||||
export function useBackgroundSessions(projectId?: string): UseBackgroundSessionsResult {
|
||||
@@ -152,7 +147,11 @@ export function useBackgroundSessions(projectId?: string): UseBackgroundSessions
|
||||
|
||||
sessionTimestampsRef.current.set(updated.id, eventTimestamp);
|
||||
|
||||
const idx = prev.findIndex((s) => s.id === updated.id);
|
||||
if (updated.status === "complete" || updated.status === "error") {
|
||||
return prev.filter((session) => session.id !== updated.id);
|
||||
}
|
||||
|
||||
const idx = prev.findIndex((session) => session.id === updated.id);
|
||||
if (idx >= 0) {
|
||||
const next = [...prev];
|
||||
next[idx] = updated;
|
||||
|
||||
Reference in New Issue
Block a user