Default client RPC waits to 60 seconds (#1789)

* fix(client): wait longer for session responses

* fix(client): default RPC waits to sixty seconds

* fix(app): preserve detached stream scroll on delayed history

Code drift: longer client RPC waits let delayed timeline responses arrive after a user scroll-away, so web stream anchoring must not reattach on transient scroll-top resets.

Restore the 15s connect deadline and leave app initialization slack above the default 60s session RPC wait.

* fix(client): keep helper waits within caller deadlines

Review fix: the 60s default session RPC wait leaked into wait previews and waitForAgentUpsert helper fetches. Bound those helper RPCs to the caller deadline or a short best-effort preview timeout, and allow small scroll ranges to reattach at bottom.

* fix(client): respect caller timeout budgets

* fix(cli): keep diagnostic probes responsive

* Refactor daemon client request options

* Preserve daemon client legacy overloads
This commit is contained in:
Mohamed Boudra
2026-06-29 17:23:18 +02:00
committed by GitHub
parent 57800a0f17
commit b613bea9f6
58 changed files with 1234 additions and 281 deletions
@@ -5,6 +5,7 @@ import { getInitDeferred, getInitKey, resolveInitDeferred } from "@/utils/agent-
import {
createSetAgentInitializing,
ensureAgentIsInitialized,
refreshAgentInitializationTimeout,
refreshAgent,
} from "./use-agent-initialization";
@@ -80,7 +81,7 @@ describe("ensureAgentIsInitialized", () => {
expect(getInitDeferred(getInitKey(serverId, agentId))?.requestDirection).toBe("tail");
});
it("times out initialization after 30 seconds", async () => {
it("times out initialization after 65 seconds", async () => {
vi.useFakeTimers();
const client = makeClient();
useSessionStore.getState().initializeSession(serverId, client as never);
@@ -92,18 +93,50 @@ describe("ensureAgentIsInitialized", () => {
setAgentInitializing: bindSetAgentInitializing(),
});
vi.advanceTimersByTime(29_999);
vi.advanceTimersByTime(64_999);
expect(getInitDeferred(getInitKey(serverId, agentId))).toBeDefined();
vi.advanceTimersByTime(1);
await expect(promise).rejects.toThrow("History sync timed out after 30s");
await expect(promise).rejects.toThrow("History sync timed out after 65s");
expect(getInitDeferred(getInitKey(serverId, agentId))).toBeUndefined();
expect(useSessionStore.getState().sessions[serverId]?.initializingAgents.get(agentId)).toBe(
false,
);
vi.useRealTimers();
});
it("refreshes the initialization timeout after paged catch-up progress", async () => {
vi.useFakeTimers();
const client = makeClient();
useSessionStore.getState().initializeSession(serverId, client as never);
const setAgentInitializing = bindSetAgentInitializing();
const key = getInitKey(serverId, agentId);
const promise = ensureAgentIsInitialized({
serverId,
agentId,
client: client as never,
setAgentInitializing,
});
vi.advanceTimersByTime(64_999);
refreshAgentInitializationTimeout({ key, agentId, setAgentInitializing });
vi.advanceTimersByTime(1);
expect(getInitDeferred(key)).toBeDefined();
const rejection = expect(promise).rejects.toThrow("History sync timed out after 65s");
vi.advanceTimersByTime(64_998);
expect(getInitDeferred(key)).toBeDefined();
vi.advanceTimersByTime(1);
await rejection;
expect(getInitDeferred(key)).toBeUndefined();
vi.useRealTimers();
});
});
describe("refreshAgent", () => {