From cf9b6ec1f617defbea94b70407d6ad2f839934c2 Mon Sep 17 00:00:00 2001 From: Shreya Keshive Date: Tue, 16 Sep 2025 18:38:17 -0400 Subject: [PATCH] fix(ide): increase IDE open / close tool timeouts (#8587) --- packages/core/src/ide/constants.ts | 1 + packages/core/src/ide/ide-client.ts | 89 +++++++++---------- .../vscode-ide-companion/src/ide-server.ts | 2 +- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/packages/core/src/ide/constants.ts b/packages/core/src/ide/constants.ts index 573b9aec03..2844a5d859 100644 --- a/packages/core/src/ide/constants.ts +++ b/packages/core/src/ide/constants.ts @@ -7,3 +7,4 @@ export const GEMINI_CLI_COMPANION_EXTENSION_NAME = 'Gemini CLI Companion'; export const IDE_MAX_OPEN_FILES = 10; export const IDE_MAX_SELECTED_TEXT_LENGTH = 16384; // 16 KiB limit +export const IDE_REQUEST_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes diff --git a/packages/core/src/ide/ide-client.ts b/packages/core/src/ide/ide-client.ts index abd774687d..09e259c024 100644 --- a/packages/core/src/ide/ide-client.ts +++ b/packages/core/src/ide/ide-client.ts @@ -23,6 +23,7 @@ import * as os from 'node:os'; import * as path from 'node:path'; import { EnvHttpProxyAgent } from 'undici'; import { ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js'; +import { IDE_REQUEST_TIMEOUT_MS } from './constants.js'; const logger = { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -238,31 +239,29 @@ export class IdeClient { } this.diffResponses.set(filePath, resolve); this.client - .callTool({ - name: `openDiff`, - arguments: { - filePath, - newContent, + .request( + { + method: 'tools/call', + params: { + name: `openDiff`, + arguments: { + filePath, + newContent, + }, + }, }, - }) - .then((result) => { - const parsedResult = CallToolResultSchema.safeParse(result); - if (!parsedResult.success) { - const err = new Error('Failed to parse tool result from IDE'); - logger.debug(err, parsedResult.error); - this.diffResponses.delete(filePath); - reject(err); - return; - } - - if (parsedResult.data.isError) { - const textPart = parsedResult.data.content.find( + CallToolResultSchema, + { timeout: IDE_REQUEST_TIMEOUT_MS }, + ) + .then((parsedResultData) => { + if (parsedResultData.isError) { + const textPart = parsedResultData.content.find( (part) => part.type === 'text', ); const errorMessage = textPart?.text ?? `Tool 'openDiff' reported an error.`; logger.debug( - `callTool for ${filePath} failed with isError:`, + `Request for openDiff ${filePath} failed with isError:`, errorMessage, ); this.diffResponses.delete(filePath); @@ -270,7 +269,7 @@ export class IdeClient { } }) .catch((err) => { - logger.debug(`callTool for ${filePath} failed:`, err); + logger.debug(`Request for openDiff ${filePath} failed:`, err); this.diffResponses.delete(filePath); reject(err); }); @@ -314,43 +313,42 @@ export class IdeClient { options?: { suppressNotification?: boolean }, ): Promise { try { - const result = await this.client?.callTool({ - name: `closeDiff`, - arguments: { - filePath, - suppressNotification: options?.suppressNotification, + if (!this.client) { + return undefined; + } + const resultData = await this.client.request( + { + method: 'tools/call', + params: { + name: `closeDiff`, + arguments: { + filePath, + suppressNotification: options?.suppressNotification, + }, + }, }, - }); + CallToolResultSchema, + { timeout: IDE_REQUEST_TIMEOUT_MS }, + ); - if (!result) { + if (!resultData) { return undefined; } - const parsedResult = CallToolResultSchema.safeParse(result); - if (!parsedResult.success) { - logger.debug( - `Failed to parse tool result from IDE for closeDiff:`, - parsedResult.error, - ); - return undefined; - } - - if (parsedResult.data.isError) { - const textPart = parsedResult.data.content.find( + if (resultData.isError) { + const textPart = resultData.content.find( (part) => part.type === 'text', ); const errorMessage = textPart?.text ?? `Tool 'closeDiff' reported an error.`; logger.debug( - `callTool for closeDiff ${filePath} failed with isError:`, + `Request for closeDiff ${filePath} failed with isError:`, errorMessage, ); return undefined; } - const textPart = parsedResult.data.content.find( - (part) => part.type === 'text', - ); + const textPart = resultData.content.find((part) => part.type === 'text'); if (textPart?.text) { try { @@ -369,7 +367,7 @@ export class IdeClient { } } } catch (err) { - logger.debug(`callTool for closeDiff ${filePath} failed:`, err); + logger.debug(`Request for closeDiff ${filePath} failed:`, err); } return undefined; } @@ -706,16 +704,17 @@ export class IdeClient { }, ); this.client.onerror = (_error) => { + const errorMessage = _error instanceof Error ? _error.message : `_error`; this.setState( IDEConnectionStatus.Disconnected, - `IDE connection error. The connection was lost unexpectedly. Please try reconnecting by running /ide enable`, + `IDE connection error. The connection was lost unexpectedly. Please try reconnecting by running /ide enable\n${errorMessage}`, true, ); }; this.client.onclose = () => { this.setState( IDEConnectionStatus.Disconnected, - `IDE connection error. The connection was lost unexpectedly. Please try reconnecting by running /ide enable`, + `IDE connection closed. To reconnect, run /ide enable.`, true, ); }; diff --git a/packages/vscode-ide-companion/src/ide-server.ts b/packages/vscode-ide-companion/src/ide-server.ts index 883012d1d3..c1bb85d3fe 100644 --- a/packages/vscode-ide-companion/src/ide-server.ts +++ b/packages/vscode-ide-companion/src/ide-server.ts @@ -191,7 +191,7 @@ export class IDEServer { ); clearInterval(keepAlive); } - }, 60000); // 60 sec + }, 30000); // 30 sec transport.onclose = () => { clearInterval(keepAlive);