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:
Taylor Mullen 2025-05-11 13:32:56 -07:00 committed by N. Taylor Mullen
parent 4d5f0dc080
commit 2970f0a06c
2 changed files with 55 additions and 21 deletions

View File

@ -323,6 +323,18 @@ export const useGeminiStream = (
);
setStreamingState(StreamingState.Idle);
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
@ -335,7 +347,6 @@ export const useGeminiStream = (
setStreamingState(StreamingState.Idle);
} catch (error: unknown) {
if (!isNodeError(error) || error.name !== 'AbortError') {
console.error('Error processing stream or executing tool:', error);
addItem(
{
type: 'error',

View File

@ -18,6 +18,8 @@ import {
ToolResultDisplay,
} from '../tools/tools.js';
import { getResponseText } from '../utils/generateContentResponseUtilities.js';
import { reportError } from '../utils/errorReporting.js';
import { getErrorMessage } from '../utils/errors.js';
// --- Types for Server Logic ---
@ -51,6 +53,11 @@ export enum GeminiEventType {
ToolCallResponse = 'tool_call_response',
ToolCallConfirmation = 'tool_call_confirmation',
UserCancelled = 'user_cancelled',
Error = 'error',
}
export interface GeminiErrorEventValue {
message: string;
}
export interface ToolCallRequestInfo {
@ -79,7 +86,8 @@ export type ServerGeminiStreamEvent =
type: GeminiEventType.ToolCallConfirmation;
value: ServerToolCallConfirmationDetails;
}
| { type: GeminiEventType.UserCancelled };
| { type: GeminiEventType.UserCancelled }
| { type: GeminiEventType.Error; value: GeminiErrorEventValue };
// A turn manages the agentic loop turn within the server context.
export class Turn {
@ -108,31 +116,46 @@ export class Turn {
req: PartListUnion,
signal?: AbortSignal,
): 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) {
this.debugResponses.push(resp);
if (signal?.aborted) {
yield { type: GeminiEventType.UserCancelled };
return;
}
for await (const resp of responseStream) {
this.debugResponses.push(resp);
if (signal?.aborted) {
yield { type: GeminiEventType.UserCancelled };
return;
}
const text = getResponseText(resp);
if (text) {
yield { type: GeminiEventType.Content, value: text };
}
const text = getResponseText(resp);
if (text) {
yield { type: GeminiEventType.Content, value: text };
}
if (!resp.functionCalls) {
continue;
}
if (!resp.functionCalls) {
continue;
}
// Handle function calls (requesting tool execution)
for (const fnCall of resp.functionCalls) {
const event = this.handlePendingFunctionCall(fnCall);
if (event) {
yield event;
// Handle function calls (requesting tool execution)
for (const fnCall of resp.functionCalls) {
const event = this.handlePendingFunctionCall(fnCall);
if (event) {
yield event;
}
}
}
} 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