Continue to work through 429/500s.

- The root of this issue was actually a genai SDK bug that was fixed here: https://critique.corp.google.com/cl/753255997
- Upgrade to latest genai SDK for latest bug fixes (including the above)
- Removed specific 429 handling for uncaught rejections.

Fixes https://b.corp.google.com/issues/413760164
This commit is contained in:
Taylor Mullen
2025-05-07 16:31:43 -07:00
committed by N. Taylor Mullen
parent 95ab38e8d6
commit 43c707b4e8
4 changed files with 24 additions and 56 deletions

View File

@@ -86,27 +86,6 @@ async function main() {
// --- Global Unhandled Rejection Handler ---
process.on('unhandledRejection', (reason, _promise) => {
// Check if this is the known 429 ClientError that sometimes escapes
// this is a workaround for a specific issue with the way we are calling gemini
// where a 429 error is thrown but not caught, causing an unhandled rejection
// TODO(adh): Remove this when the race condition is fixed
const isKnownEscaped429 =
reason instanceof Error &&
reason.name === 'ClientError' &&
reason.message.includes('got status: 429');
if (isKnownEscaped429) {
// Log it differently and DON'T exit, as it's likely already handled visually
console.warn('-----------------------------------------');
console.warn(
'WORKAROUND: Suppressed known escaped 429 Unhandled Rejection.',
);
console.warn('-----------------------------------------');
console.warn('Reason:', reason);
return;
// No process.exit(1); Don't exit.
}
// Log other unexpected unhandled rejections as critical errors
console.error('=========================================');
console.error('CRITICAL: Unhandled Promise Rejection!');

View File

@@ -19,7 +19,7 @@
"dist"
],
"dependencies": {
"@google/genai": "^0.10.0",
"@google/genai": "^0.13.0",
"@modelcontextprotocol/sdk": "^1.11.0",
"diff": "^7.0.0",
"dotenv": "^16.4.7",

View File

@@ -133,39 +133,28 @@ export class GeminiClient {
): AsyncGenerator<ServerGeminiStreamEvent> {
let turns = 0;
const availableTools = this.config.getToolRegistry().getAllTools();
try {
while (turns < this.MAX_TURNS) {
turns++;
const turn = new Turn(chat, availableTools);
const resultStream = turn.run(request, signal);
for await (const event of resultStream) {
yield event;
}
while (turns < this.MAX_TURNS) {
turns++;
const turn = new Turn(chat, availableTools);
const resultStream = turn.run(request, signal);
for await (const event of resultStream) {
yield event;
}
const confirmations = turn.getConfirmationDetails();
if (confirmations.length > 0) {
break;
}
const confirmations = turn.getConfirmationDetails();
if (confirmations.length > 0) {
break;
}
// What do we do when we have both function responses and confirmations?
const fnResponses = turn.getFunctionResponses();
if (fnResponses.length === 0) {
break; // user's turn to respond
}
request = fnResponses;
// What do we do when we have both function responses and confirmations?
const fnResponses = turn.getFunctionResponses();
if (fnResponses.length === 0) {
break; // user's turn to respond
}
if (turns >= this.MAX_TURNS) {
console.warn(
'sendMessageStream: Reached maximum tool call turns limit.',
);
}
} catch (error: unknown) {
if (error instanceof Error && error.name === 'AbortError') {
console.log('Gemini stream request aborted by user.');
throw error;
}
console.error(`Error during Gemini stream or tool interaction:`, error);
throw error;
request = fnResponses;
}
if (turns >= this.MAX_TURNS) {
console.warn('sendMessageStream: Reached maximum tool call turns limit.');
}
}