feat: Integrate centralized error reporting for API interactions
Implements robust error handling for Gemini API calls, integrating with the centralized error reporting system. - API errors are now caught and reported to dedicated log files, providing detailed diagnostics without cluttering the user interface. - A concise error message is surfaced to the user in the UI, indicating an API issue. - Ensures any pending UI updates are processed before an API error is displayed. This change improves our ability to diagnose API-related problems by capturing rich error context centrally, while maintaining a clean user experience. Signed-off-by: Gemini <YourFriendlyNeighborhoodAI@example.com>
This commit is contained in:
parent
4d5f0dc080
commit
2970f0a06c
|
@ -323,6 +323,18 @@ export const useGeminiStream = (
|
||||||
);
|
);
|
||||||
setStreamingState(StreamingState.Idle);
|
setStreamingState(StreamingState.Idle);
|
||||||
return; // Stop processing the stream
|
return; // Stop processing the stream
|
||||||
|
} else if (event.type === ServerGeminiEventType.Error) {
|
||||||
|
// Flush out existing pending history item.
|
||||||
|
if (pendingHistoryItemRef.current) {
|
||||||
|
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
||||||
|
setPendingHistoryItem(null);
|
||||||
|
}
|
||||||
|
addItem(
|
||||||
|
{ type: 'error', text: `[API Error: ${event.value.message}]` },
|
||||||
|
userMessageTimestamp,
|
||||||
|
);
|
||||||
|
setStreamingState(StreamingState.Idle);
|
||||||
|
// Allow stream to end naturally
|
||||||
}
|
}
|
||||||
} // End stream loop
|
} // End stream loop
|
||||||
|
|
||||||
|
@ -335,7 +347,6 @@ export const useGeminiStream = (
|
||||||
setStreamingState(StreamingState.Idle);
|
setStreamingState(StreamingState.Idle);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (!isNodeError(error) || error.name !== 'AbortError') {
|
if (!isNodeError(error) || error.name !== 'AbortError') {
|
||||||
console.error('Error processing stream or executing tool:', error);
|
|
||||||
addItem(
|
addItem(
|
||||||
{
|
{
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
|
|
@ -18,6 +18,8 @@ import {
|
||||||
ToolResultDisplay,
|
ToolResultDisplay,
|
||||||
} from '../tools/tools.js';
|
} from '../tools/tools.js';
|
||||||
import { getResponseText } from '../utils/generateContentResponseUtilities.js';
|
import { getResponseText } from '../utils/generateContentResponseUtilities.js';
|
||||||
|
import { reportError } from '../utils/errorReporting.js';
|
||||||
|
import { getErrorMessage } from '../utils/errors.js';
|
||||||
|
|
||||||
// --- Types for Server Logic ---
|
// --- Types for Server Logic ---
|
||||||
|
|
||||||
|
@ -51,6 +53,11 @@ export enum GeminiEventType {
|
||||||
ToolCallResponse = 'tool_call_response',
|
ToolCallResponse = 'tool_call_response',
|
||||||
ToolCallConfirmation = 'tool_call_confirmation',
|
ToolCallConfirmation = 'tool_call_confirmation',
|
||||||
UserCancelled = 'user_cancelled',
|
UserCancelled = 'user_cancelled',
|
||||||
|
Error = 'error',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeminiErrorEventValue {
|
||||||
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToolCallRequestInfo {
|
export interface ToolCallRequestInfo {
|
||||||
|
@ -79,7 +86,8 @@ export type ServerGeminiStreamEvent =
|
||||||
type: GeminiEventType.ToolCallConfirmation;
|
type: GeminiEventType.ToolCallConfirmation;
|
||||||
value: ServerToolCallConfirmationDetails;
|
value: ServerToolCallConfirmationDetails;
|
||||||
}
|
}
|
||||||
| { type: GeminiEventType.UserCancelled };
|
| { type: GeminiEventType.UserCancelled }
|
||||||
|
| { type: GeminiEventType.Error; value: GeminiErrorEventValue };
|
||||||
|
|
||||||
// A turn manages the agentic loop turn within the server context.
|
// A turn manages the agentic loop turn within the server context.
|
||||||
export class Turn {
|
export class Turn {
|
||||||
|
@ -108,7 +116,10 @@ export class Turn {
|
||||||
req: PartListUnion,
|
req: PartListUnion,
|
||||||
signal?: AbortSignal,
|
signal?: AbortSignal,
|
||||||
): AsyncGenerator<ServerGeminiStreamEvent> {
|
): AsyncGenerator<ServerGeminiStreamEvent> {
|
||||||
const responseStream = await this.chat.sendMessageStream({ message: req });
|
try {
|
||||||
|
const responseStream = await this.chat.sendMessageStream({
|
||||||
|
message: req,
|
||||||
|
});
|
||||||
|
|
||||||
for await (const resp of responseStream) {
|
for await (const resp of responseStream) {
|
||||||
this.debugResponses.push(resp);
|
this.debugResponses.push(resp);
|
||||||
|
@ -134,6 +145,18 @@ export class Turn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const contextForReport = [...this.chat.getHistory(/*curated*/ true), req];
|
||||||
|
await reportError(
|
||||||
|
error,
|
||||||
|
'Error when talking to Gemini API',
|
||||||
|
contextForReport,
|
||||||
|
'Turn.run-sendMessageStream',
|
||||||
|
);
|
||||||
|
const errorMessage = getErrorMessage(error);
|
||||||
|
yield { type: GeminiEventType.Error, value: { message: errorMessage } };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Execute pending tool calls
|
// Execute pending tool calls
|
||||||
const toolPromises = this.pendingToolCalls.map(
|
const toolPromises = this.pendingToolCalls.map(
|
||||||
|
|
Loading…
Reference in New Issue