From 153e8e72f9e296963559e8651f799e4ee699dbb6 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 21 May 2025 06:45:17 +1000 Subject: [PATCH] Handle cases when failing to resolve env --- src/client/chat/configurePythonEnvTool.ts | 99 +++++++++++++---------- src/client/chat/getExecutableTool.ts | 10 ++- src/client/chat/getPythonEnvTool.ts | 9 ++- src/client/chat/installPackagesTool.ts | 12 ++- src/client/chat/utils.ts | 30 ++++++- 5 files changed, 110 insertions(+), 50 deletions(-) diff --git a/src/client/chat/configurePythonEnvTool.ts b/src/client/chat/configurePythonEnvTool.ts index 1a22fed83140..aef2272f357c 100644 --- a/src/client/chat/configurePythonEnvTool.ts +++ b/src/client/chat/configurePythonEnvTool.ts @@ -19,7 +19,7 @@ import { PythonExtension, ResolvedEnvironment } from '../api/types'; import { IServiceContainer } from '../ioc/types'; import { ICodeExecutionService } from '../terminals/types'; import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/terminalCodeExecution'; -import { getEnvironmentDetails, raceCancellationError } from './utils'; +import { getEnvironmentDetails, NoEnvironmentError, raceCancellationError } from './utils'; import { resolveFilePath } from './utils'; import { IRecommendedEnvironmentService } from '../interpreter/configuration/types'; import { ITerminalHelper } from '../common/terminal/types'; @@ -67,33 +67,51 @@ export class ConfigurePythonEnvTool implements LanguageModelTool, token: CancellationToken, ): Promise { - const resource = resolveFilePath(options.input.resourcePath); - const recommededEnv = await this.recommendedEnvService.getRecommededEnvironment(resource); - // Already selected workspace env, hence nothing to do. - if (recommededEnv?.reason === 'workspaceUserSelected' && workspace.workspaceFolders?.length) { - return await getEnvDetailsForResponse( - recommededEnv.environment, - this.api, - this.terminalExecutionService, - this.terminalHelper, - resource, - token, - ); - } - // No workspace folders, and the user selected a global environment. - if (recommededEnv?.reason === 'globalUserSelected' && !workspace.workspaceFolders?.length) { - return await getEnvDetailsForResponse( - recommededEnv.environment, - this.api, - this.terminalExecutionService, - this.terminalHelper, - resource, - token, - ); - } + try { + const resource = resolveFilePath(options.input.resourcePath); + const recommededEnv = await this.recommendedEnvService.getRecommededEnvironment(resource); + // Already selected workspace env, hence nothing to do. + if (recommededEnv?.reason === 'workspaceUserSelected' && workspace.workspaceFolders?.length) { + return await getEnvDetailsForResponse( + recommededEnv.environment, + this.api, + this.terminalExecutionService, + this.terminalHelper, + resource, + token, + ); + } + // No workspace folders, and the user selected a global environment. + if (recommededEnv?.reason === 'globalUserSelected' && !workspace.workspaceFolders?.length) { + return await getEnvDetailsForResponse( + recommededEnv.environment, + this.api, + this.terminalExecutionService, + this.terminalHelper, + resource, + token, + ); + } - if (!workspace.workspaceFolders?.length) { - const selected = await Promise.resolve(commands.executeCommand(Commands.Set_Interpreter)); + if (!workspace.workspaceFolders?.length) { + const selected = await Promise.resolve(commands.executeCommand(Commands.Set_Interpreter)); + const env = await this.api.resolveEnvironment(this.api.getActiveEnvironmentPath(resource)); + if (selected && env) { + return await getEnvDetailsForResponse( + env, + this.api, + this.terminalExecutionService, + this.terminalHelper, + resource, + token, + ); + } + return new LanguageModelToolResult([ + new LanguageModelTextPart('User did not select a Python environment.'), + ]); + } + + const selected = await showCreateAndSelectEnvironmentQuickPick(resource, this.serviceContainer); const env = await this.api.resolveEnvironment(this.api.getActiveEnvironmentPath(resource)); if (selected && env) { return await getEnvDetailsForResponse( @@ -106,25 +124,18 @@ export class ConfigurePythonEnvTool implements LanguageModelTool ); return new LanguageModelToolResult([new LanguageModelTextPart(message)]); } catch (error) { + if (error instanceof NoEnvironmentError) { + return new LanguageModelToolResult([ + new LanguageModelTextPart( + 'Failed to configure a Python Environment, as the environment could not be found.', + ), + ]); + } + if (error instanceof CancellationError) { throw error; } diff --git a/src/client/chat/getPythonEnvTool.ts b/src/client/chat/getPythonEnvTool.ts index 11af29f18be7..8f0a5349a117 100644 --- a/src/client/chat/getPythonEnvTool.ts +++ b/src/client/chat/getPythonEnvTool.ts @@ -17,7 +17,7 @@ import { IServiceContainer } from '../ioc/types'; import { ICodeExecutionService } from '../terminals/types'; import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/terminalCodeExecution'; import { IProcessServiceFactory, IPythonExecutionFactory } from '../common/process/types'; -import { getEnvironmentDetails, raceCancellationError } from './utils'; +import { getEnvironmentDetails, NoEnvironmentError, raceCancellationError } from './utils'; import { resolveFilePath } from './utils'; import { getPythonPackagesResponse } from './listPackagesTool'; import { ITerminalHelper } from '../common/terminal/types'; @@ -82,6 +82,13 @@ export class GetEnvironmentInfoTool implements LanguageModelTool(IModuleInstaller); @@ -70,6 +70,14 @@ export class InstallPackagesTool implements LanguageModelTool doc.uri.fsPath === uri.fsPath) + ) { + throw new Error('This tool does not support Notebooks, use a relevant tool instead.'); + } +}