fix(app): subagents track display + archive flicker

- Bucket finished subagents as `done` instead of `attention`; drop
  "needs attention" segment from the section header — subagents are
  transient and don't carry an unread state worth surfacing.
- Gate the subagents selector on the existing pending-archive query so
  optimistic archives survive authoritative agent snapshots that wipe
  the local `archivedAt`. Last subagent archived now cleanly hides the
  whole track via the existing empty-rows guard.
This commit is contained in:
Mohamed Boudra
2026-05-09 16:28:09 +07:00
parent 34df55a10a
commit 3eda7dd15b
7 changed files with 253 additions and 80 deletions
+125 -40
View File
@@ -5,6 +5,7 @@ import { useSessionStore, type Agent } from "@/stores/session-store";
const SERVER_ID = "server-1";
const AGENT_TIMESTAMP = new Date("2026-03-08T10:00:00.000Z");
const EMPTY_PENDING_ARCHIVE_IDS = new Set<string>();
const AGENT_DEFAULTS: Agent = {
serverId: SERVER_ID,
@@ -71,10 +72,14 @@ describe("selectSubagentsForParent", () => {
}),
]);
const rows = selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent-a",
});
const rows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent-a",
},
EMPTY_PENDING_ARCHIVE_IDS,
);
expect(rows.map((row) => row.id)).toEqual(["child-a"]);
});
@@ -89,10 +94,14 @@ describe("selectSubagentsForParent", () => {
makeAgent({ id: "unrelated" }),
]);
const rows = selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent-a",
});
const rows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent-a",
},
EMPTY_PENDING_ARCHIVE_IDS,
);
expect(rows.map((row) => row.id)).toEqual(["child-a"]);
});
@@ -104,14 +113,22 @@ describe("selectSubagentsForParent", () => {
makeAgent({ id: "grandchild", parentAgentId: "child" }),
]);
const parentRows = selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent",
});
const childRows = selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "child",
});
const parentRows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent",
},
EMPTY_PENDING_ARCHIVE_IDS,
);
const childRows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "child",
},
EMPTY_PENDING_ARCHIVE_IDS,
);
expect(parentRows.map((row) => row.id)).toEqual(["child"]);
expect(childRows.map((row) => row.id)).toEqual(["grandchild"]);
@@ -137,10 +154,14 @@ describe("selectSubagentsForParent", () => {
}),
]);
const rows = selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent",
});
const rows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent",
},
EMPTY_PENDING_ARCHIVE_IDS,
);
expect(rows.map((row) => row.id)).toEqual(["first", "second", "third"]);
});
@@ -162,10 +183,14 @@ describe("selectSubagentsForParent", () => {
}),
]);
const rows = selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent",
});
const rows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent",
},
EMPTY_PENDING_ARCHIVE_IDS,
);
expect(rows).toEqual([
{
@@ -195,16 +220,24 @@ describe("selectSubagentsForParent", () => {
setAgents([makeAgent({ id: "parent-a" }), makeAgent({ id: "parent-b" }), child]);
expect(
selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent-a",
}).map((row) => row.id),
selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent-a",
},
EMPTY_PENDING_ARCHIVE_IDS,
).map((row) => row.id),
).toEqual(["child"]);
expect(
selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent-b",
}).map((row) => row.id),
selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent-b",
},
EMPTY_PENDING_ARCHIVE_IDS,
).map((row) => row.id),
).toEqual([]);
setAgents([
@@ -214,16 +247,68 @@ describe("selectSubagentsForParent", () => {
]);
expect(
selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent-a",
}).map((row) => row.id),
selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent-a",
},
EMPTY_PENDING_ARCHIVE_IDS,
).map((row) => row.id),
).toEqual([]);
expect(
selectSubagentsForParent(useSessionStore.getState(), {
serverId: SERVER_ID,
parentAgentId: "parent-b",
}).map((row) => row.id),
selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent-b",
},
EMPTY_PENDING_ARCHIVE_IDS,
).map((row) => row.id),
).toEqual(["child"]);
});
it("excludes children whose archive is pending", () => {
setAgents([
makeAgent({ id: "parent" }),
makeAgent({ id: "child-a", parentAgentId: "parent" }),
makeAgent({ id: "child-b", parentAgentId: "parent" }),
]);
const rows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent",
},
new Set(["child-b"]),
);
expect(rows.map((row) => row.id)).toEqual(["child-a"]);
});
it("returns the shared empty array when pending archive hides the last child", () => {
setAgents([makeAgent({ id: "parent" }), makeAgent({ id: "child", parentAgentId: "parent" })]);
const rows = selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "parent",
},
new Set(["child"]),
);
expect(rows).toEqual([]);
expect(rows).toBe(
selectSubagentsForParent(
useSessionStore.getState(),
{
serverId: SERVER_ID,
parentAgentId: "missing-parent",
},
EMPTY_PENDING_ARCHIVE_IDS,
),
);
});
});