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);
|
||||
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',
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue