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
+6 -2
View File
@@ -6,7 +6,10 @@ export function addAttachOptions(cmd: Command): Command {
.argument("<id>", "Agent ID (or prefix)");
}
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
import { fetchProjectedTimelineItems } from "../../utils/timeline.js";
import {
fetchProjectedTimelineItems,
LIVE_HISTORY_FETCH_TIMEOUT_MS,
} from "../../utils/timeline.js";
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
import type { AgentTimelineItem } from "@getpaseo/protocol/agent-types";
import type { AgentStreamEventPayload, AgentStreamMessage } from "@getpaseo/protocol/messages";
@@ -121,7 +124,7 @@ export async function runAttachCommand(
}
try {
const fetchResult = await client.fetchAgent(id);
const fetchResult = await client.fetchAgent({ agentId: id });
if (!fetchResult) {
console.error(`Error: No agent found matching: ${id}`);
console.error("Use `paseo ls` to list available agents");
@@ -139,6 +142,7 @@ export async function runAttachCommand(
const timelineItems = await fetchProjectedTimelineItems({
client,
agentId: resolvedId,
timeoutMs: LIVE_HISTORY_FETCH_TIMEOUT_MS,
});
for (const item of timelineItems) {
printTimelineItem(item);
+1 -1
View File
@@ -76,7 +76,7 @@ export async function runDeleteCommand(
return isSameOrDescendantPath(options.cwd!, a.cwd);
});
} else if (id) {
const fetchResult = await client.fetchAgent(id);
const fetchResult = await client.fetchAgent({ agentId: id });
if (!fetchResult) {
const error: CommandError = {
code: "AGENT_NOT_FOUND",
+1 -1
View File
@@ -243,7 +243,7 @@ export async function runInspectCommand(
}
try {
const fetchResult = await client.fetchAgent(agentIdArg);
const fetchResult = await client.fetchAgent({ agentId: agentIdArg });
if (!fetchResult) {
const error: CommandError = {
code: "AGENT_NOT_FOUND",
+15 -4
View File
@@ -1,7 +1,10 @@
import { Command } from "commander";
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
import type { CommandOptions } from "../../output/index.js";
import { fetchProjectedTimelineItems } from "../../utils/timeline.js";
import {
fetchProjectedTimelineItems,
LIVE_HISTORY_FETCH_TIMEOUT_MS,
} from "../../utils/timeline.js";
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
import type { AgentTimelineItem } from "@getpaseo/protocol/agent-types";
import type { AgentStreamMessage } from "@getpaseo/protocol/messages";
@@ -32,8 +35,9 @@ export const NO_ACTIVITY_MESSAGE = "No activity to display.";
export async function fetchAgentTimelineItems(
client: DaemonClient,
agentId: string,
options?: { timeoutMs?: number },
): Promise<AgentTimelineItem[]> {
return fetchProjectedTimelineItems({ client, agentId });
return fetchProjectedTimelineItems({ client, agentId, timeoutMs: options?.timeoutMs });
}
export function formatAgentActivityTranscript(
@@ -107,7 +111,7 @@ export async function runLogsCommand(
}
try {
const fetchResult = await client.fetchAgent(id);
const fetchResult = await client.fetchAgent({ agentId: id });
if (!fetchResult) {
console.error(`Error: No agent found matching: ${id}`);
console.error("Use `paseo ls` to list available agents");
@@ -173,7 +177,14 @@ async function runFollowMode(
const tailCount = parseTailCount(options.tail) ?? DEFAULT_FOLLOW_TAIL;
// First, get existing timeline.
let existingItems = await fetchAgentTimelineItems(client, agentId);
let existingItems: AgentTimelineItem[] = [];
try {
existingItems = await fetchAgentTimelineItems(client, agentId, {
timeoutMs: LIVE_HISTORY_FETCH_TIMEOUT_MS,
});
} catch (error) {
console.warn("Warning: failed to fetch existing timeline", error);
}
// Apply filter to existing items
if (options.filter) {
+1 -1
View File
@@ -65,7 +65,7 @@ export async function runModeCommand(
let client: Awaited<ReturnType<typeof connectToDaemon>> | undefined;
try {
client = await connectToDaemon({ host: options.host });
const fetchResult = await client.fetchAgent(id);
const fetchResult = await client.fetchAgent({ agentId: id });
if (!fetchResult) {
const error: CommandError = {
code: "AGENT_NOT_FOUND",
+1 -1
View File
@@ -83,7 +83,7 @@ export async function runStopCommand(
});
} else if (id) {
// Stop specific agent
const fetchResult = await client.fetchAgent(id);
const fetchResult = await client.fetchAgent({ agentId: id });
if (!fetchResult) {
const error: CommandError = {
code: "AGENT_NOT_FOUND",
+2 -2
View File
@@ -132,7 +132,7 @@ export async function runUpdateCommand(
}
try {
const fetchResult = await client.fetchAgent(agentIdArg);
const fetchResult = await client.fetchAgent({ agentId: agentIdArg });
if (!fetchResult) {
const error: CommandError = {
code: "AGENT_NOT_FOUND",
@@ -148,7 +148,7 @@ export async function runUpdateCommand(
...(Object.keys(labels).length > 0 ? { labels } : {}),
});
const updatedResult = await client.fetchAgent(agentId);
const updatedResult = await client.fetchAgent({ agentId });
if (!updatedResult) {
throw new Error(`Agent not found after update: ${agentId}`);
}
+4 -1
View File
@@ -32,6 +32,7 @@ export interface AgentWaitOptions extends CommandOptions {
}
const WAIT_ACTIVITY_PREVIEW_COUNT = 5;
const WAIT_ACTIVITY_PREVIEW_TIMEOUT_MS = 2_000;
function appendRecentActivity(message: string, transcript: string | null): string {
if (!transcript || transcript.trim().length === 0) {
@@ -46,7 +47,9 @@ async function getRecentActivityTranscript(
agentId: string,
): Promise<string | null> {
try {
const timelineItems = await fetchAgentTimelineItems(client, agentId);
const timelineItems = await fetchAgentTimelineItems(client, agentId, {
timeoutMs: WAIT_ACTIVITY_PREVIEW_TIMEOUT_MS,
});
return formatAgentActivityTranscript(timelineItems, WAIT_ACTIVITY_PREVIEW_COUNT);
} catch {
return null;