Revert the timeline optimistic and pagination rework (#2596)

* Add npm release track invariant and beta dist-tag procedure

* Revert "Keep older chat history and image previews stable (#2490)"

The timeline optimistic/pagination rework needs more work than main releases can wait for. Reverted together with #2484; both are reapplied on integration/timeline-optimistic-rework.

* Revert "Stop completed turns from appearing stuck (#2484)"

See the #2490 revert. #2490 built on this submission-authority change, so the two revert and reapply as a pair.
This commit is contained in:
Mohamed Boudra
2026-07-29 13:35:43 +02:00
committed by GitHub
parent ab24070075
commit acb8506d1f
81 changed files with 1721 additions and 7893 deletions
@@ -111,47 +111,6 @@ describe("ensureAgentIsInitialized", () => {
expect(getInitDeferred(getInitKey(serverId, agentId))?.requestDirection).toBe("tail");
});
it("requests a bounded projected tail after restoring painted replica items", () => {
const client = new FakeDaemonClient();
const runtime = new FakeTimelineRuntime();
useSessionStore.getState().restoreSessionReplica(serverId, {
agents: new Map(),
workspaces: new Map(),
emptyProjects: new Map(),
timeline: {
agentId,
items: [
{
kind: "assistant_message",
id: "painted-item",
text: "Painted before hydration",
timestamp: new Date("2026-07-27T10:00:00.000Z"),
},
],
},
});
void ensureAgentIsInitialized({
serverId,
agentId,
client: client as never,
runtime,
setAgentInitializing: bindSetAgentInitializing(),
});
expect(runtime.requests).toEqual([
{
serverId,
agentId,
request: {
direction: "tail",
limit: TIMELINE_FETCH_PAGE_SIZE,
projection: "projected",
},
},
]);
});
it("times out initialization after 65 seconds", async () => {
vi.useFakeTimers();
const client = new FakeDaemonClient();
@@ -1,7 +1,7 @@
import { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
import { selectAgentTimelineState, useSessionStore } from "@/stores/session-store";
import { useSessionStore } from "@/stores/session-store";
import {
createInitDeferred,
getInitDeferred,
@@ -52,9 +52,8 @@ export function ensureAgentIsInitialized(input: EnsureAgentIsInitializedInput):
}
const session = useSessionStore.getState().sessions[serverId];
const timeline = selectAgentTimelineState(session, agentId);
const cursor = timeline.status === "synced" ? (timeline.range ?? undefined) : undefined;
const hasAuthoritativeHistory = timeline.status === "synced";
const cursor = session?.agentTimelineCursor.get(agentId);
const hasAuthoritativeHistory = session?.agentAuthoritativeHistoryApplied.get(agentId) === true;
const timelineRequest = planInitialAgentTimelineSync({ cursor, hasAuthoritativeHistory });
const deferred = createInitDeferred(key, timelineRequest.direction);
@@ -84,7 +84,7 @@ describe("loadOlderAgentHistory", () => {
const client = createClient();
const inFlight = createInFlight();
const started = await loadOlderAgentHistory(agentId, {
await loadOlderAgentHistory(agentId, {
client,
cursor: undefined,
hasOlder: true,
@@ -94,14 +94,13 @@ describe("loadOlderAgentHistory", () => {
expect(client.calls).toEqual([]);
expect(inFlight.values).toEqual([false]);
expect(started).toBe(false);
});
it("no-ops when the daemon says no older history exists", async () => {
const client = createClient();
const inFlight = createInFlight();
const started = await loadOlderAgentHistory(agentId, {
await loadOlderAgentHistory(agentId, {
client,
cursor: someCursor,
hasOlder: false,
@@ -111,14 +110,13 @@ describe("loadOlderAgentHistory", () => {
expect(client.calls).toEqual([]);
expect(inFlight.values).toEqual([false]);
expect(started).toBe(false);
});
it("no-ops when a request is already in flight", async () => {
const client = createClient();
const inFlight = createInFlight(true);
const started = await loadOlderAgentHistory(agentId, {
await loadOlderAgentHistory(agentId, {
client,
cursor: someCursor,
hasOlder: true,
@@ -128,14 +126,13 @@ describe("loadOlderAgentHistory", () => {
expect(client.calls).toEqual([]);
expect(inFlight.values).toEqual([true]);
expect(started).toBe(true);
});
it("requests the page before the current start cursor and clears in-flight on success", async () => {
const client = createClient();
const inFlight = createInFlight();
const started = await loadOlderAgentHistory(agentId, {
await loadOlderAgentHistory(agentId, {
client,
cursor: someCursor,
hasOlder: true,
@@ -155,7 +152,6 @@ describe("loadOlderAgentHistory", () => {
},
]);
expect(inFlight.values).toEqual([false, true, false]);
expect(started).toBe(true);
});
it("shows a panel toast, warns, and clears in-flight on failure", async () => {
@@ -2,11 +2,7 @@ import { useCallback } from "react";
import { useTranslation } from "react-i18next";
import type { ToastApi } from "@/components/toast-host";
import { i18n } from "@/i18n/i18next";
import {
selectAgentTimelineState,
useSessionStore,
type AgentTimelineCursorState,
} from "@/stores/session-store";
import { useSessionStore, type AgentTimelineCursorState } from "@/stores/session-store";
import { planTimelineOlderFetch } from "@/timeline/timeline-sync-plan";
import { getHostRuntimeStore } from "@/runtime/host-runtime";
@@ -40,14 +36,11 @@ export interface LoadOlderAgentHistoryDeps {
export async function loadOlderAgentHistory(
agentId: string,
deps: LoadOlderAgentHistoryDeps,
): Promise<boolean> {
): Promise<void> {
const { client, cursor, hasOlder, isLoadingOlder, setInFlight, toast, logger, failedMessage } =
deps;
if (isLoadingOlder) {
return true;
}
if (!client || !cursor || !hasOlder) {
return false;
if (!client || !cursor || !hasOlder || isLoadingOlder) {
return;
}
setInFlight(true);
@@ -65,7 +58,6 @@ export async function loadOlderAgentHistory(
} finally {
setInFlight(false);
}
return true;
}
export function useLoadOlderAgentHistory({
@@ -78,17 +70,15 @@ export function useLoadOlderAgentHistory({
toast?: ToastApi | null;
}) {
const { t } = useTranslation();
const hasOlder = useSessionStore((state) => {
const timeline = selectAgentTimelineState(state.sessions[serverId], agentId);
return timeline.status === "synced" && timeline.older === "available";
});
const hasOlder =
useSessionStore((state) => state.sessions[serverId]?.agentTimelineHasOlder.get(agentId)) ===
true;
const isLoadingOlder =
useSessionStore((state) =>
state.sessions[serverId]?.agentTimelineOlderFetchInFlight.get(agentId),
) === true;
const progressKey = useSessionStore((state) => {
const timeline = selectAgentTimelineState(state.sessions[serverId], agentId);
const cursor = timeline.status === "synced" ? timeline.range : null;
const cursor = state.sessions[serverId]?.agentTimelineCursor.get(agentId);
return cursor ? `${cursor.epoch}:${cursor.startSeq}` : null;
});
const setOlderFetchInFlight = useSessionStore(
@@ -109,18 +99,17 @@ export function useLoadOlderAgentHistory({
[agentId, serverId, setOlderFetchInFlight],
);
const loadOlder = useCallback(async (): Promise<boolean> => {
const loadOlder = useCallback(() => {
const session = useSessionStore.getState().sessions[serverId];
const timeline = selectAgentTimelineState(session, agentId);
return await loadOlderAgentHistory(agentId, {
void loadOlderAgentHistory(agentId, {
client: session?.client
? {
fetchAgentTimeline: (timelineAgentId, request) =>
getHostRuntimeStore().fetchAgentTimeline(serverId, timelineAgentId, request),
}
: null,
cursor: timeline.status === "synced" ? (timeline.range ?? undefined) : undefined,
hasOlder: timeline.status === "synced" && timeline.older === "available",
cursor: session?.agentTimelineCursor.get(agentId),
hasOlder: session?.agentTimelineHasOlder.get(agentId) === true,
isLoadingOlder: session?.agentTimelineOlderFetchInFlight.get(agentId) === true,
setInFlight,
toast,