opt(chat): Enhance error handling for chat.send timeouts and improve logging in gateway RPC calls (#788)

This commit is contained in:
Haze
2026-04-07 17:07:57 +08:00
committed by GitHub
Unverified
parent c3a735a49c
commit 97d29ab23c
3 changed files with 30 additions and 7 deletions

View File

@@ -1152,6 +1152,7 @@ function registerGatewayHandlers(
const result = await gatewayManager.rpc(method, params, timeoutMs);
return { success: true, result };
} catch (error) {
logger.warn(`[gateway:rpc] ${method} failed (timeoutMs=${timeoutMs ?? 30000}): ${String(error)}`);
return { success: false, error: String(error) };
}
});

View File

@@ -956,6 +956,15 @@ function upsertToolStatuses(current: ToolStatus[], updates: ToolStatus[]): ToolS
return next;
}
/**
* Only treat an explicit chat.send ack timeout as recoverable.
* Gateway stopped / Gateway not connected are hard failures that
* should still terminate the send immediately.
*/
function isRecoverableChatSendTimeout(error: string): boolean {
return error.includes('RPC timeout: chat.send');
}
function collectToolUpdates(message: unknown, eventState: string): ToolStatus[] {
const updates: ToolStatus[] = [];
const toolResultUpdate = extractToolResultUpdate(message, eventState);
@@ -1675,14 +1684,26 @@ export const useChatStore = create<ChatState>((set, get) => ({
console.log(`[sendMessage] RPC result: success=${result.success}, runId=${result.result?.runId || 'none'}`);
if (!result.success) {
clearHistoryPoll();
set({ error: result.error || 'Failed to send message', sending: false });
const errorMsg = result.error || 'Failed to send message';
if (isRecoverableChatSendTimeout(errorMsg)) {
console.warn(`[sendMessage] Recoverable chat.send timeout, keeping poll alive: ${errorMsg}`);
set({ error: errorMsg });
} else {
clearHistoryPoll();
set({ error: errorMsg, sending: false });
}
} else if (result.result?.runId) {
set({ activeRunId: result.result.runId });
}
} catch (err) {
clearHistoryPoll();
set({ error: String(err), sending: false });
const errStr = String(err);
if (isRecoverableChatSendTimeout(errStr)) {
console.warn(`[sendMessage] Recoverable chat.send timeout, keeping poll alive: ${errStr}`);
set({ error: errStr });
} else {
clearHistoryPoll();
set({ error: errStr, sending: false });
}
}
},
@@ -1761,11 +1782,11 @@ export const useChatStore = create<ChatState>((set, get) => ({
break;
}
case 'delta': {
// If we're receiving new deltas, the Gateway has recovered from any
// prior error — cancel the error finalization timer and clear the
// stale error banner so the user sees the live stream again.
// Clear any stale error (including RPC timeout) when new data arrives.
if (_errorRecoveryTimer) {
clearErrorRecoveryTimer();
}
if (get().error) {
set({ error: null });
}
const updates = collectToolUpdates(event.message, resolvedState);

View File

@@ -177,6 +177,7 @@ function handleGatewayNotification(notification: { method?: string; params?: Rec
activeRunId: null,
pendingFinal: false,
lastUserMessageAt: null,
error: null,
});
}
})