forked from microsoft/vscode-python
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgetPythonEnvTool.ts
More file actions
131 lines (123 loc) · 5.41 KB
/
getPythonEnvTool.ts
File metadata and controls
131 lines (123 loc) · 5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {
CancellationToken,
l10n,
LanguageModelTextPart,
LanguageModelTool,
LanguageModelToolInvocationOptions,
LanguageModelToolInvocationPrepareOptions,
LanguageModelToolResult,
PreparedToolInvocation,
Uri,
} from 'vscode';
import { PythonExtension } from '../api/types';
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,
getEnvTypeForTelemetry,
getToolResponseIfNotebook,
IResourceReference,
raceCancellationError,
} from './utils';
import { getPythonPackagesResponse } from './listPackagesTool';
import { ITerminalHelper } from '../common/terminal/types';
import { getEnvExtApi, useEnvExtension } from '../envExt/api.internal';
import { ErrorWithTelemetrySafeReason } from '../common/errors/errorUtils';
import { BaseTool } from './baseTool';
export class GetEnvironmentInfoTool extends BaseTool<IResourceReference>
implements LanguageModelTool<IResourceReference> {
private readonly terminalExecutionService: TerminalCodeExecutionProvider;
private readonly pythonExecFactory: IPythonExecutionFactory;
private readonly processServiceFactory: IProcessServiceFactory;
private readonly terminalHelper: ITerminalHelper;
public static readonly toolName = 'get_python_environment_details';
constructor(
private readonly api: PythonExtension['environments'],
private readonly serviceContainer: IServiceContainer,
) {
super(GetEnvironmentInfoTool.toolName);
this.terminalExecutionService = this.serviceContainer.get<TerminalCodeExecutionProvider>(
ICodeExecutionService,
'standard',
);
this.pythonExecFactory = this.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory);
this.processServiceFactory = this.serviceContainer.get<IProcessServiceFactory>(IProcessServiceFactory);
this.terminalHelper = this.serviceContainer.get<ITerminalHelper>(ITerminalHelper);
}
async invokeImpl(
_options: LanguageModelToolInvocationOptions<IResourceReference>,
resourcePath: Uri | undefined,
token: CancellationToken,
): Promise<LanguageModelToolResult> {
const notebookResponse = getToolResponseIfNotebook(resourcePath);
if (notebookResponse) {
return notebookResponse;
}
// environment
const envPath = this.api.getActiveEnvironmentPath(resourcePath);
const environment = await raceCancellationError(this.api.resolveEnvironment(envPath), token);
if (!environment || !environment.version) {
throw new ErrorWithTelemetrySafeReason(
'No environment found for the provided resource path: ' + resourcePath?.fsPath,
'noEnvFound',
);
}
this.extraTelemetryProperties.envType = getEnvTypeForTelemetry(environment);
let packages = '';
let responsePackageCount = 0;
if (useEnvExtension()) {
const api = await getEnvExtApi();
const env = await api.getEnvironment(resourcePath);
const pkgs = env ? await api.getPackages(env) : [];
if (pkgs && pkgs.length > 0) {
responsePackageCount = pkgs.length;
// Installed Python packages, each in the format <name> or <name> (<version>). The version may be omitted if unknown. Returns an empty array if no packages are installed.
const response = [
'Below is a list of the Python packages, each in the format <name> or <name> (<version>). The version may be omitted if unknown: ',
];
pkgs.forEach((pkg) => {
const version = pkg.version;
response.push(version ? `- ${pkg.name} (${version})` : `- ${pkg.name}`);
});
packages = response.join('\n');
}
}
if (!packages) {
packages = await getPythonPackagesResponse(
environment,
this.pythonExecFactory,
this.processServiceFactory,
resourcePath,
token,
);
// Count lines starting with '- ' to get the number of packages
responsePackageCount = (packages.match(/^- /gm) || []).length;
}
this.extraTelemetryProperties.responsePackageCount = String(responsePackageCount);
const message = await getEnvironmentDetails(
resourcePath,
this.api,
this.terminalExecutionService,
this.terminalHelper,
packages,
token,
);
return new LanguageModelToolResult([new LanguageModelTextPart(message)]);
}
async prepareInvocationImpl(
_options: LanguageModelToolInvocationPrepareOptions<IResourceReference>,
resourcePath: Uri | undefined,
_token: CancellationToken,
): Promise<PreparedToolInvocation> {
if (getToolResponseIfNotebook(resourcePath)) {
return {};
}
return {
invocationMessage: l10n.t('Fetching Python environment information'),
};
}
}