Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion apps/ade-cli/src/tuiClient/__tests__/multiChatLayout.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
import { describe, expect, it } from "vitest";
import { canRenderMultiChatGrid, computeTileRects, focusedSessionIdForMultiView } from "../multiChatLayout";
import {
canRenderMultiChatGrid,
computeTileRects,
focusedSessionIdForMultiView,
resolveOpenChatSessionIds,
} from "../multiChatLayout";

describe("resolveOpenChatSessionIds", () => {
const multiView = {
tiles: [
{ sessionId: "tile-a", laneId: "lane-1" },
{ sessionId: "tile-b", laneId: "lane-1" },
],
focusedIndex: 0,
};

it("streams tile sessions when the grid is visible", () => {
expect(resolveOpenChatSessionIds({
gridViewActive: true,
multiView,
activeSessionId: "other-chat",
})).toEqual(new Set(["tile-a", "tile-b"]));
});

it("streams only the active chat when a resumable grid is hidden", () => {
expect(resolveOpenChatSessionIds({
gridViewActive: false,
multiView,
activeSessionId: "solo-chat",
})).toEqual(new Set(["solo-chat"]));
});

it("streams the active chat when no grid exists", () => {
expect(resolveOpenChatSessionIds({
gridViewActive: false,
multiView: null,
activeSessionId: "solo-chat",
})).toEqual(new Set(["solo-chat"]));
});
});

describe("multi chat layout", () => {
it("computes the locked 1-6 tile patterns inside the available area", () => {
Expand Down
12 changes: 6 additions & 6 deletions apps/ade-cli/src/tuiClient/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ import {
} from "./hitTestRegistry";
import {
focusedSessionIdForMultiView,
resolveOpenChatSessionIds,
type MultiViewState,
type MultiViewTile,
} from "./multiChatLayout";
Expand Down Expand Up @@ -5870,12 +5871,11 @@ export function AdeCodeApp({ project, forceEmbedded, requireSocket, socketPath }
useEffect(() => {
if (!connection) return;
const unsubscribe = connection.onChatEvent((envelope) => {
const currentMultiView = multiViewRef.current;
const openSessionIds = new Set(
currentMultiView
? currentMultiView.tiles.map((tile) => tile.sessionId)
: [activeSessionIdRef.current].filter((value): value is string => Boolean(value)),
);
const openSessionIds = resolveOpenChatSessionIds({
gridViewActive: gridViewActiveRef.current,
multiView: multiViewRef.current,
activeSessionId: activeSessionIdRef.current,
});
if (!openSessionIds.has(envelope.sessionId)) {
// Event for a session we're not displaying — refresh summaries (cheap,
// dedup-guarded). Only the open-session token stream below is coalesced.
Expand Down
12 changes: 12 additions & 0 deletions apps/ade-cli/src/tuiClient/multiChatLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,15 @@ export function focusedSessionIdForMultiView(multiView: MultiViewState | null):
if (!multiView) return null;
return multiView.tiles[multiView.focusedIndex]?.sessionId ?? null;
}

/** Session ids that should receive live chat event streaming (not summary-only refresh). */
export function resolveOpenChatSessionIds(args: {
gridViewActive: boolean;
multiView: MultiViewState | null;
activeSessionId: string | null;
}): Set<string> {
if (args.gridViewActive && args.multiView) {
return new Set(args.multiView.tiles.map((tile) => tile.sessionId));
}
return args.activeSessionId ? new Set([args.activeSessionId]) : new Set();
}
Loading