feat(app): restore recent chat while reconnecting (#2206)

Keep a small non-authoritative view of the last focused chat so the app can paint it before the daemon finishes revalidation. Bound persistence to one focused agent per host and evict whole host entries to limit storage and serialization work.
This commit is contained in:
Mohamed Boudra
2026-07-19 03:08:46 +08:00
committed by GitHub
parent 2185779d6c
commit 5ea311f243
9 changed files with 875 additions and 20 deletions
@@ -190,6 +190,25 @@ describe("deriveAgentScreenViewState", () => {
expect(sync.ui).toBe("silent");
});
it("keeps hydrated history visible while reconnect revalidation and visibility catch-up overlap", () => {
const memory = createBaseMemory({
hasRenderedReady: true,
lastReadyAgent: createAgent("agent-1"),
});
const input: AgentScreenMachineInput = {
...createBaseInput(),
hasHydratedHistoryBefore: true,
needsAuthoritativeSync: true,
visibilityCatchUpStatus: "pending",
};
const result = deriveAgentScreenViewState({ input, memory });
const ready = expectReadyState(result.state);
const sync = expectCatchingUpSync(ready);
expect(sync.ui).toBe("silent");
});
it("covers already-hydrated history while a newly visible agent catches up", () => {
const memory = createBaseMemory({
hasRenderedReady: true,
@@ -150,9 +150,11 @@ function resolveCatchingUpUi(args: {
hasOptimisticCreateContinuity: boolean;
isVisibilityCatchUpPending: boolean;
hasHydratedHistoryBefore: boolean;
needsAuthoritativeSync: boolean;
hadInitialSyncFailure: boolean;
}): "overlay" | "silent" {
if (args.hasOptimisticCreateContinuity) return "silent";
if (args.hasHydratedHistoryBefore && args.needsAuthoritativeSync) return "silent";
if (args.isVisibilityCatchUpPending) return "overlay";
if (args.hasHydratedHistoryBefore) return "silent";
if (args.hadInitialSyncFailure) return "silent";
@@ -184,6 +186,7 @@ function resolveAgentScreenSync(args: {
hasOptimisticCreateContinuity: hasOptimisticCreateContinuity(input),
isVisibilityCatchUpPending: input.visibilityCatchUpStatus === "pending",
hasHydratedHistoryBefore: input.hasHydratedHistoryBefore,
needsAuthoritativeSync: input.needsAuthoritativeSync,
hadInitialSyncFailure,
}),
};