Prevent Android chats from freezing or going blank (#1989)
* fix(app): stabilize streamed chat rendering Use deterministic Markdown AST keys and preserve unique row identities when an assistant message resumes after a tool. Keep native gesture and plan-card children correctly keyed to avoid unsupported Fabric reconciliation paths. * fix(app): stabilize retained native panels Keep retained workspace roots in a stable native order and make active panels present in the selection commit. Hidden panels now stop expensive subscriptions and animations without losing mounted state. * fix(app): harden retained panel activity
This commit is contained in:
@@ -92,8 +92,22 @@ describe("workspace agent activity index", () => {
|
||||
|
||||
expect(index).toEqual(
|
||||
new Map([
|
||||
["workspace-a", { status: "needs_input", enteredAt: new Date("2026-06-01T10:01:00.000Z") }],
|
||||
["workspace-b", { status: "attention", enteredAt: new Date("2026-06-01T10:02:00.000Z") }],
|
||||
[
|
||||
"workspace-a",
|
||||
{
|
||||
agentId: "permission",
|
||||
status: "needs_input",
|
||||
enteredAt: new Date("2026-06-01T10:01:00.000Z"),
|
||||
},
|
||||
],
|
||||
[
|
||||
"workspace-b",
|
||||
{
|
||||
agentId: "attention",
|
||||
status: "attention",
|
||||
enteredAt: new Date("2026-06-01T10:02:00.000Z"),
|
||||
},
|
||||
],
|
||||
]),
|
||||
);
|
||||
});
|
||||
@@ -135,8 +149,82 @@ describe("workspace agent activity index", () => {
|
||||
);
|
||||
|
||||
expect(index.get("workspace-a")).toEqual({
|
||||
agentId: "root",
|
||||
status: "running",
|
||||
enteredAt: new Date("2026-06-01T10:00:00.000Z"),
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves the activity index while the same agent remains in the same status", () => {
|
||||
const previous = buildWorkspaceAgentActivityIndex(
|
||||
new Map([
|
||||
[
|
||||
"root",
|
||||
agent({
|
||||
id: "root",
|
||||
workspaceId: "workspace-a",
|
||||
status: "running",
|
||||
updatedAt: "2026-06-01T10:00:00.000Z",
|
||||
}),
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
const next = buildWorkspaceAgentActivityIndex(
|
||||
new Map([
|
||||
[
|
||||
"root",
|
||||
agent({
|
||||
id: "root",
|
||||
workspaceId: "workspace-a",
|
||||
status: "running",
|
||||
updatedAt: "2026-06-01T10:05:00.000Z",
|
||||
}),
|
||||
],
|
||||
]),
|
||||
previous,
|
||||
);
|
||||
|
||||
expect(next).toBe(previous);
|
||||
expect(next.get("workspace-a")?.enteredAt).toEqual(new Date("2026-06-01T10:00:00.000Z"));
|
||||
});
|
||||
|
||||
it("records a new entry time when an agent changes status", () => {
|
||||
const previous = buildWorkspaceAgentActivityIndex(
|
||||
new Map([
|
||||
[
|
||||
"root",
|
||||
agent({
|
||||
id: "root",
|
||||
workspaceId: "workspace-a",
|
||||
status: "running",
|
||||
updatedAt: "2026-06-01T10:00:00.000Z",
|
||||
}),
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
const next = buildWorkspaceAgentActivityIndex(
|
||||
new Map([
|
||||
[
|
||||
"root",
|
||||
agent({
|
||||
id: "root",
|
||||
workspaceId: "workspace-a",
|
||||
status: "idle",
|
||||
updatedAt: "2026-06-01T10:05:00.000Z",
|
||||
pendingPermissionCount: 1,
|
||||
}),
|
||||
],
|
||||
]),
|
||||
previous,
|
||||
);
|
||||
|
||||
expect(next).not.toBe(previous);
|
||||
expect(next.get("workspace-a")).toEqual({
|
||||
agentId: "root",
|
||||
status: "needs_input",
|
||||
enteredAt: new Date("2026-06-01T10:05:00.000Z"),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user