perf(app): reduce startup websocket work
Make provider catalogs compact and content-addressed so repeat launches can reuse the persisted snapshot instead of transferring it again. Remove eager global catalog loading and the stopped-agent defensive tail fetch, while keeping sequence-gap and reconnect recovery as the correctness paths. Add an opt-in production-ID Android profiling build for local startup traces.
This commit is contained in:
@@ -3,6 +3,8 @@ import { beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
|
||||
import type { ProviderSnapshotEntry } from "@getpaseo/protocol/agent-types";
|
||||
import { compactProviderSnapshot } from "@getpaseo/protocol/provider-snapshot-codec";
|
||||
import type { CachedProviderSnapshot, ProviderSnapshotCache } from "@/data/provider-snapshot-cache";
|
||||
import { draftAgentCommandsQueryKey } from "@/hooks/agent-commands-query";
|
||||
import { applyProvidersSnapshotUpdate, type ProvidersSnapshotUpdate } from "@/data/push-router";
|
||||
import {
|
||||
@@ -79,6 +81,21 @@ function codexEntry(
|
||||
const readyCodexModel = { provider: "codex", id: "gpt-5.4", label: "GPT-5.4" } as const;
|
||||
const serverId = "server-1";
|
||||
|
||||
function createCache(initial: CachedProviderSnapshot | null = null): ProviderSnapshotCache & {
|
||||
writes: Parameters<ProviderSnapshotCache["write"]>[0][];
|
||||
} {
|
||||
const writes: Parameters<ProviderSnapshotCache["write"]>[0][] = [];
|
||||
return {
|
||||
writes,
|
||||
async read() {
|
||||
return initial;
|
||||
},
|
||||
async write(input) {
|
||||
writes.push(input);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("providersSnapshotQueryKey", () => {
|
||||
it("uses separate keys for home and workspace scopes", () => {
|
||||
expect(providersSnapshotQueryKey(serverId)).toEqual(["providersSnapshot", serverId, "home"]);
|
||||
@@ -95,7 +112,7 @@ describe("fetchProvidersSnapshot", () => {
|
||||
it("sends no cwd for the home scope", async () => {
|
||||
const client = createClient({ snapshots: [providersSnapshot([])] });
|
||||
|
||||
await fetchProvidersSnapshot({ client, cwd: null });
|
||||
await fetchProvidersSnapshot({ client, serverId, cwd: null, cache: createCache() });
|
||||
|
||||
expect(client.getCalls).toEqual([{}]);
|
||||
});
|
||||
@@ -103,10 +120,78 @@ describe("fetchProvidersSnapshot", () => {
|
||||
it("sends the workspace cwd for the workspace scope", async () => {
|
||||
const client = createClient({ snapshots: [providersSnapshot([])] });
|
||||
|
||||
await fetchProvidersSnapshot({ client, cwd: "/repo-a" });
|
||||
await fetchProvidersSnapshot({
|
||||
client,
|
||||
serverId,
|
||||
cwd: "/repo-a",
|
||||
cache: createCache(),
|
||||
});
|
||||
|
||||
expect(client.getCalls).toEqual([{ cwd: "/repo-a" }]);
|
||||
});
|
||||
|
||||
it("reuses a cached snapshot when the daemon reports its hash unchanged", async () => {
|
||||
const entries = [codexEntry("ready", [readyCodexModel])];
|
||||
const compactSnapshot = compactProviderSnapshot(entries);
|
||||
const cache = createCache({
|
||||
version: 1,
|
||||
hash: "snapshot-hash",
|
||||
generatedAt: "2026-01-01T00:00:00.000Z",
|
||||
compactSnapshot,
|
||||
entries,
|
||||
});
|
||||
const client = createClient({
|
||||
snapshots: [
|
||||
{
|
||||
entries: [],
|
||||
snapshotHash: "snapshot-hash",
|
||||
notModified: true,
|
||||
generatedAt: "2026-01-02T00:00:00.000Z",
|
||||
requestId: "snapshot-2",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const snapshot = await fetchProvidersSnapshot({
|
||||
client,
|
||||
serverId,
|
||||
cwd: "/repo-a",
|
||||
cache,
|
||||
});
|
||||
|
||||
expect(client.getCalls).toEqual([{ cwd: "/repo-a", ifNoneMatch: "snapshot-hash" }]);
|
||||
expect(snapshot.entries).toBe(entries);
|
||||
expect(cache.writes).toEqual([]);
|
||||
});
|
||||
|
||||
it("persists a changed compact snapshot for the next launch", async () => {
|
||||
const entries = [codexEntry("ready", [readyCodexModel])];
|
||||
const compactSnapshot = compactProviderSnapshot(entries);
|
||||
const cache = createCache();
|
||||
const client = createClient({
|
||||
snapshots: [
|
||||
{
|
||||
entries,
|
||||
compactSnapshot,
|
||||
snapshotHash: "next-hash",
|
||||
generatedAt: "2026-01-02T00:00:00.000Z",
|
||||
requestId: "snapshot-2",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await fetchProvidersSnapshot({ client, serverId, cwd: "/repo-a", cache });
|
||||
|
||||
expect(cache.writes).toEqual([
|
||||
{
|
||||
serverId,
|
||||
cwd: "/repo-a",
|
||||
hash: "next-hash",
|
||||
generatedAt: "2026-01-02T00:00:00.000Z",
|
||||
compactSnapshot,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("refreshAndApplyProvidersSnapshot", () => {
|
||||
@@ -127,6 +212,7 @@ describe("refreshAndApplyProvidersSnapshot", () => {
|
||||
serverId,
|
||||
cwd: null,
|
||||
providers: ["codex"],
|
||||
cache: createCache(),
|
||||
});
|
||||
|
||||
expect(client.refreshCalls).toEqual([{ providers: ["codex"] }]);
|
||||
@@ -147,6 +233,7 @@ describe("refreshAndApplyProvidersSnapshot", () => {
|
||||
serverId,
|
||||
cwd: "/repo-a",
|
||||
providers: ["codex"],
|
||||
cache: createCache(),
|
||||
});
|
||||
|
||||
expect(client.refreshCalls).toEqual([{ cwd: "/repo-a", providers: ["codex"] }]);
|
||||
@@ -166,6 +253,7 @@ describe("refreshAndApplyProvidersSnapshot", () => {
|
||||
queryClient,
|
||||
serverId,
|
||||
cwd: null,
|
||||
cache: createCache(),
|
||||
});
|
||||
|
||||
expect(
|
||||
@@ -186,6 +274,7 @@ describe("refreshAndApplyProvidersSnapshot", () => {
|
||||
queryClient,
|
||||
serverId,
|
||||
cwd: "/repo-a",
|
||||
cache: createCache(),
|
||||
});
|
||||
|
||||
expect(queryClient.getQueryState(providersSnapshotQueryKey(serverId))?.isInvalidated).toBe(
|
||||
@@ -209,6 +298,7 @@ describe("refreshAndApplyProvidersSnapshot", () => {
|
||||
queryClient,
|
||||
serverId,
|
||||
cwd: "/repo-a",
|
||||
cache: createCache(),
|
||||
});
|
||||
|
||||
expect(queryClient.getQueryState(commandsKey)?.isInvalidated).toBe(true);
|
||||
@@ -266,6 +356,27 @@ describe("applyProvidersSnapshotUpdate", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("persists compact push updates", () => {
|
||||
const entries = [codexEntry("ready", [readyCodexModel])];
|
||||
const compactSnapshot = compactProviderSnapshot(entries);
|
||||
const cache = createCache();
|
||||
const message = updateMessage(entries, "/repo-a");
|
||||
message.payload.compactSnapshot = compactSnapshot;
|
||||
message.payload.snapshotHash = "push-hash";
|
||||
|
||||
applyProvidersSnapshotUpdate({ serverId, queryClient, message, cache });
|
||||
|
||||
expect(cache.writes).toEqual([
|
||||
{
|
||||
serverId,
|
||||
cwd: "/repo-a",
|
||||
hash: "push-hash",
|
||||
generatedAt: "2026-01-01T00:00:01.000Z",
|
||||
compactSnapshot,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("applies Windows daemon updates to app-normalized workspace paths", () => {
|
||||
const workspaceCwd = "C:/Users/Ezekiel Bulver/project";
|
||||
const daemonCwd = "C:\\Users\\Ezekiel Bulver\\project";
|
||||
|
||||
@@ -8,6 +8,11 @@ import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-
|
||||
import { useSessionStore } from "@/stores/session-store";
|
||||
import { useReplicaQuery } from "@/data/query";
|
||||
import { queryClient as singletonQueryClient } from "@/data/query-client";
|
||||
import {
|
||||
providerSnapshotCache,
|
||||
ProviderSnapshotCacheMissError,
|
||||
type ProviderSnapshotCache,
|
||||
} from "@/data/provider-snapshot-cache";
|
||||
import { agentCommandsQueryRoot } from "@/hooks/agent-commands-query";
|
||||
import {
|
||||
isProvidersSnapshotHomeScope,
|
||||
@@ -29,9 +34,31 @@ export type ProvidersSnapshotClient = Pick<
|
||||
|
||||
export async function fetchProvidersSnapshot(input: {
|
||||
client: ProvidersSnapshotClient;
|
||||
serverId: string;
|
||||
cwd: string | null;
|
||||
cache?: ProviderSnapshotCache;
|
||||
}): Promise<GetProvidersSnapshotResult> {
|
||||
return input.client.getProvidersSnapshot(providersSnapshotRequestOptions({ cwd: input.cwd }));
|
||||
const cache = input.cache ?? providerSnapshotCache;
|
||||
const cached = await cache.read(input.serverId, input.cwd);
|
||||
const snapshot = await input.client.getProvidersSnapshot(
|
||||
providersSnapshotRequestOptions({ cwd: input.cwd, ifNoneMatch: cached?.hash }),
|
||||
);
|
||||
if (snapshot.notModified) {
|
||||
if (!cached) {
|
||||
throw new ProviderSnapshotCacheMissError();
|
||||
}
|
||||
return { ...snapshot, entries: cached.entries };
|
||||
}
|
||||
if (snapshot.compactSnapshot && snapshot.snapshotHash) {
|
||||
await cache.write({
|
||||
serverId: input.serverId,
|
||||
cwd: input.cwd,
|
||||
hash: snapshot.snapshotHash,
|
||||
generatedAt: snapshot.generatedAt,
|
||||
compactSnapshot: snapshot.compactSnapshot,
|
||||
});
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
export async function refreshAndApplyProvidersSnapshot(input: {
|
||||
@@ -40,11 +67,17 @@ export async function refreshAndApplyProvidersSnapshot(input: {
|
||||
serverId: string;
|
||||
cwd: string | null;
|
||||
providers?: AgentProvider[];
|
||||
cache?: ProviderSnapshotCache;
|
||||
}): Promise<RefreshProvidersSnapshotResult> {
|
||||
const refreshResult = await input.client.refreshProvidersSnapshot(
|
||||
providersSnapshotRequestOptions({ cwd: input.cwd, providers: input.providers }),
|
||||
);
|
||||
const snapshot = await fetchProvidersSnapshot({ client: input.client, cwd: input.cwd });
|
||||
const snapshot = await fetchProvidersSnapshot({
|
||||
client: input.client,
|
||||
serverId: input.serverId,
|
||||
cwd: input.cwd,
|
||||
cache: input.cache,
|
||||
});
|
||||
input.queryClient.setQueryData(providersSnapshotQueryKey(input.serverId, input.cwd), snapshot);
|
||||
void input.queryClient.invalidateQueries({
|
||||
queryKey: agentCommandsQueryRoot(input.serverId),
|
||||
@@ -113,10 +146,10 @@ export function useProvidersSnapshot(
|
||||
enabled: Boolean(enabled && supportsSnapshot && serverId && client && isConnected),
|
||||
pushEvent: "providers_snapshot_update",
|
||||
queryFn: async () => {
|
||||
if (!client) {
|
||||
if (!client || !serverId) {
|
||||
throw new Error(t("workspace.terminal.hostDisconnected"));
|
||||
}
|
||||
return fetchProvidersSnapshot({ client, cwd });
|
||||
return fetchProvidersSnapshot({ client, serverId, cwd });
|
||||
},
|
||||
});
|
||||
|
||||
@@ -180,6 +213,6 @@ export function prefetchProvidersSnapshot(
|
||||
void singletonQueryClient.prefetchQuery({
|
||||
queryKey,
|
||||
staleTime: Infinity,
|
||||
queryFn: () => fetchProvidersSnapshot({ client, cwd }),
|
||||
queryFn: () => fetchProvidersSnapshot({ client, serverId, cwd }),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user