fix(FN-714): increase Claude provider timeout to 75s and improve error diagnostics

- Increase Claude fetch timeout from 10s to 75s to accommodate retries and CLI fallback
- Include response body snippet in HTTP error messages for better debugging
- Improve Claude CLI timeout error message with actionable guidance
- Export withTimeout and CLAUDE_FETCH_TIMEOUT_MS for testability
- Add comprehensive tests for withTimeout, timeout constant, and error diagnostics
This commit is contained in:
gsxdsm
2026-04-02 18:40:24 -07:00
parent 91fabbce74
commit bce6ca94c2
2 changed files with 114 additions and 5 deletions

View File

@@ -440,7 +440,7 @@ async function fetchClaudeUsageViaCli(): Promise<ProviderUsage> {
if (clean.includes("Current session") || clean.includes("% left") || clean.includes("% used")) {
resolve(buf);
} else {
reject(new Error("Claude CLI timed out after 60 seconds. The Claude CLI may be slow to start or authenticate."));
reject(new Error("Claude CLI timed out after 60s — got output but no usage data. Try running `claude /usage` manually."));
}
}, 60000);
@@ -704,7 +704,8 @@ async function fetchClaudeUsage(): Promise<ProviderUsage> {
// Any other non-200 status — fail immediately (not transient)
if (res.status !== 200) {
usage.status = "error";
usage.error = `HTTP ${res.status}`;
const bodySnippet = res.body ? res.body.slice(0, 100).replace(/\n/g, " ") : "";
usage.error = bodySnippet ? `HTTP ${res.status}: ${bodySnippet}` : `HTTP ${res.status}`;
return usage;
}
@@ -1231,11 +1232,18 @@ async function fetchZaiUsage(): Promise<ProviderUsage> {
/** Max time to wait for any individual provider fetch (ms) */
const PROVIDER_FETCH_TIMEOUT_MS = 10_000; // 10 seconds
/**
* Extended timeout for Claude provider fetch (ms).
* Claude's flow can include up to 3 API retries with exponential backoff (~7s)
* plus a 60-second CLI fallback via PTY, so the default 10s is insufficient.
*/
export const CLAUDE_FETCH_TIMEOUT_MS = 75_000; // 75 seconds
/**
* Wrap a provider fetch with a timeout. Returns the provider result or an
* error provider if the fetch takes longer than PROVIDER_FETCH_TIMEOUT_MS.
*/
function withTimeout(
export function withTimeout(
providerPromise: Promise<ProviderUsage>,
providerName: string,
timeoutMs: number = PROVIDER_FETCH_TIMEOUT_MS,
@@ -1246,7 +1254,7 @@ function withTimeout(
name: providerName,
icon: "⏱️",
status: "error",
error: "Timed out",
error: `Timed out after ${Math.round(timeoutMs / 1000)}s`,
windows: [],
});
}, timeoutMs);
@@ -1277,7 +1285,7 @@ export async function fetchAllProviderUsage(_authStorage?: AuthStorageLike): Pro
// Fetch all providers in parallel with per-provider timeout
const results = await Promise.allSettled([
withTimeout(fetchClaudeUsage(), "Claude"),
withTimeout(fetchClaudeUsage(), "Claude", CLAUDE_FETCH_TIMEOUT_MS),
withTimeout(fetchCodexUsage(), "Codex"),
withTimeout(fetchGeminiUsage(), "Gemini"),
withTimeout(fetchMinimaxUsage(), "Minimax"),