Skip to content

Commit 7500871

Browse files
authored
Merge branch 'microsoft:main' into tgrue-openai/support-activated-env-w-workspacefile
2 parents 922de2c + 5070566 commit 7500871

19 files changed

+460
-256
lines changed

build/azure-pipeline.stable.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ extends:
128128
project: 'Monaco'
129129
definition: 593
130130
buildVersionToDownload: 'latestFromBranch'
131-
branchName: 'refs/heads/release/2025.4'
131+
branchName: 'refs/heads/release/2025.8'
132132
targetPath: '$(Build.SourcesDirectory)/python-env-tools/bin'
133133
artifactName: 'bin-$(buildTarget)'
134134
itemPattern: |

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "python",
33
"displayName": "Python",
44
"description": "Python language support with extension access points for IntelliSense (Pylance), Debugging (Python Debugger), linting, formatting, refactoring, unit tests, and more.",
5-
"version": "2025.7.0-dev",
5+
"version": "2025.9.0-dev",
66
"featureFlags": {
77
"usingNewInterpreterStorage": true
88
},
@@ -1474,9 +1474,10 @@
14741474
"displayName": "Get Python Environment Info",
14751475
"userDescription": "%python.languageModelTools.get_python_environment_details.userDescription%",
14761476
"modelDescription": "This tool will retrieve the details of the Python Environment for the specified file or workspace. The details returned include the 1. Type of Environment (conda, venv, etec), 2. Version of Python, 3. List of all installed packages with their versions. ALWAYS call configure_python_environment before using this tool.",
1477-
"toolReferenceName": "pythonGetEnvironmentInfo",
1477+
"toolReferenceName": "getPythonEnvironmentInfo",
14781478
"tags": [
14791479
"python",
1480+
"python environment",
14801481
"extension_installed_by_tool",
14811482
"enable_other_tool_configure_python_environment"
14821483
],
@@ -1491,17 +1492,17 @@
14911492
}
14921493
},
14931494
"required": []
1494-
},
1495-
"when": "!pythonEnvExtensionInstalled"
1495+
}
14961496
},
14971497
{
14981498
"name": "get_python_executable_details",
14991499
"displayName": "Get Python Executable",
15001500
"userDescription": "%python.languageModelTools.get_python_executable_details.userDescription%",
15011501
"modelDescription": "This tool will retrieve the details of the Python Environment for the specified file or workspace. ALWAYS use this tool before executing any Python command in the terminal. This tool returns the details of how to construct the fully qualified path and or command including details such as arguments required to run Python in a terminal. Note: Instead of executing `python --version` or `python -c 'import sys; print(sys.executable)'`, use this tool to get the Python executable path to replace the `python` command. E.g. instead of using `python -c 'import sys; print(sys.executable)'`, use this tool to build the command `conda run -n <env_name> -c 'import sys; print(sys.executable)'`. ALWAYS call configure_python_environment before using this tool.",
1502-
"toolReferenceName": "pythonExecutableCommand",
1502+
"toolReferenceName": "getPythonExecutableCommand",
15031503
"tags": [
15041504
"python",
1505+
"python environment",
15051506
"extension_installed_by_tool",
15061507
"enable_other_tool_configure_python_environment"
15071508
],
@@ -1516,17 +1517,17 @@
15161517
}
15171518
},
15181519
"required": []
1519-
},
1520-
"when": "!pythonEnvExtensionInstalled"
1520+
}
15211521
},
15221522
{
15231523
"name": "install_python_packages",
15241524
"displayName": "Install Python Package",
15251525
"userDescription": "%python.languageModelTools.install_python_packages.userDescription%",
15261526
"modelDescription": "Installs Python packages in the given workspace. Use this tool to install packages in the user's chosen environment. ALWAYS call configure_python_environment before using this tool.",
1527-
"toolReferenceName": "pythonInstallPackage",
1527+
"toolReferenceName": "installPythonPackage",
15281528
"tags": [
15291529
"python",
1530+
"python environment",
15301531
"install python package",
15311532
"extension_installed_by_tool",
15321533
"enable_other_tool_configure_python_environment"
@@ -1551,8 +1552,7 @@
15511552
"required": [
15521553
"packageList"
15531554
]
1554-
},
1555-
"when": "!pythonEnvExtensionInstalled"
1555+
}
15561556
},
15571557
{
15581558
"name": "configure_python_environment",
@@ -1562,6 +1562,7 @@
15621562
"toolReferenceName": "configurePythonEnvironment",
15631563
"tags": [
15641564
"python",
1565+
"python environment",
15651566
"extension_installed_by_tool"
15661567
],
15671568
"icon": "$(gear)",
@@ -1575,8 +1576,7 @@
15751576
}
15761577
},
15771578
"required": []
1578-
},
1579-
"when": "!pythonEnvExtensionInstalled"
1579+
}
15801580
},
15811581
{
15821582
"name": "create_virtual_environment",

src/client/chat/configurePythonEnvTool.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/termin
1919
import {
2020
getEnvDetailsForResponse,
2121
getToolResponseIfNotebook,
22+
getUntrustedWorkspaceResponse,
2223
IResourceReference,
2324
isCancellationError,
2425
raceCancellationError,
@@ -28,7 +29,6 @@ import { ITerminalHelper } from '../common/terminal/types';
2829
import { IRecommendedEnvironmentService } from '../interpreter/configuration/types';
2930
import { CreateVirtualEnvTool } from './createVirtualEnvTool';
3031
import { ISelectPythonEnvToolArguments, SelectPythonEnvTool } from './selectEnvTool';
31-
import { useEnvExtension } from '../envExt/api.internal';
3232

3333
export class ConfigurePythonEnvTool implements LanguageModelTool<IResourceReference> {
3434
private readonly terminalExecutionService: TerminalCodeExecutionProvider;
@@ -54,6 +54,9 @@ export class ConfigurePythonEnvTool implements LanguageModelTool<IResourceRefere
5454
options: LanguageModelToolInvocationOptions<IResourceReference>,
5555
token: CancellationToken,
5656
): Promise<LanguageModelToolResult> {
57+
if (!workspace.isTrusted) {
58+
return getUntrustedWorkspaceResponse();
59+
}
5760
const resource = resolveFilePath(options.input.resourcePath);
5861
const notebookResponse = getToolResponseIfNotebook(resource);
5962
if (notebookResponse) {
@@ -78,10 +81,7 @@ export class ConfigurePythonEnvTool implements LanguageModelTool<IResourceRefere
7881

7982
if (await this.createEnvTool.shouldCreateNewVirtualEnv(resource, token)) {
8083
try {
81-
// If the Python Env extension is available, then use that.
82-
// create_quick_virtual_environment
83-
const toolName = useEnvExtension() ? 'create_quick_virtual_environment' : CreateVirtualEnvTool.toolName;
84-
return await lm.invokeTool(toolName, options, token);
84+
return await lm.invokeTool(CreateVirtualEnvTool.toolName, options, token);
8585
} catch (ex) {
8686
if (isCancellationError(ex)) {
8787
const input: ISelectPythonEnvToolArguments = {

src/client/chat/createVirtualEnvTool.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import {
55
CancellationError,
66
CancellationToken,
7+
commands,
78
l10n,
89
LanguageModelTool,
910
LanguageModelToolInvocationOptions,
@@ -21,6 +22,7 @@ import {
2122
doesWorkspaceHaveVenvOrCondaEnv,
2223
getDisplayVersion,
2324
getEnvDetailsForResponse,
25+
getUntrustedWorkspaceResponse,
2426
IResourceReference,
2527
isCancellationError,
2628
raceCancellationError,
@@ -39,6 +41,9 @@ import { isStableVersion } from '../pythonEnvironments/info/pythonVersion';
3941
import { createVirtualEnvironment } from '../pythonEnvironments/creation/createEnvApi';
4042
import { traceError, traceVerbose, traceWarn } from '../logging';
4143
import { StopWatch } from '../common/utils/stopWatch';
44+
import { useEnvExtension } from '../envExt/api.internal';
45+
import { PythonEnvironment } from '../envExt/types';
46+
import { hideEnvCreation } from '../pythonEnvironments/creation/provider/hideEnvCreation';
4247

4348
interface ICreateVirtualEnvToolParams extends IResourceReference {
4449
packageList?: string[]; // Added only becausewe have ability to create a virtual env with list of packages same tool within the in Python Env extension.
@@ -66,9 +71,12 @@ export class CreateVirtualEnvTool implements LanguageModelTool<ICreateVirtualEnv
6671
}
6772

6873
async invoke(
69-
options: LanguageModelToolInvocationOptions<IResourceReference>,
74+
options: LanguageModelToolInvocationOptions<ICreateVirtualEnvToolParams>,
7075
token: CancellationToken,
7176
): Promise<LanguageModelToolResult> {
77+
if (!workspace.isTrusted) {
78+
return getUntrustedWorkspaceResponse();
79+
}
7280
const resource = resolveFilePath(options.input.resourcePath);
7381
let info = await this.getPreferredEnvForCreation(resource);
7482
if (!info) {
@@ -79,18 +87,31 @@ export class CreateVirtualEnvTool implements LanguageModelTool<ICreateVirtualEnv
7987
const interpreterPathService = this.serviceContainer.get<IInterpreterPathService>(IInterpreterPathService);
8088
const disposables = new DisposableStore();
8189
try {
90+
disposables.add(hideEnvCreation());
8291
const interpreterChanged = new Promise<void>((resolve) => {
8392
disposables.add(interpreterPathService.onDidChange(() => resolve()));
8493
});
8594

86-
const created = await raceCancellationError(
87-
createVirtualEnvironment({
88-
interpreter: preferredGlobalPythonEnv.id,
89-
workspaceFolder,
90-
}),
91-
token,
92-
);
93-
if (!created?.path) {
95+
let createdEnvPath: string | undefined = undefined;
96+
if (useEnvExtension()) {
97+
const result: PythonEnvironment | undefined = await commands.executeCommand('python-envs.createAny', {
98+
quickCreate: true,
99+
additionalPackages: options.input.packageList || [],
100+
uri: workspaceFolder.uri,
101+
selectEnvironment: true,
102+
});
103+
createdEnvPath = result?.environmentPath.fsPath;
104+
} else {
105+
const created = await raceCancellationError(
106+
createVirtualEnvironment({
107+
interpreter: preferredGlobalPythonEnv.id,
108+
workspaceFolder,
109+
}),
110+
token,
111+
);
112+
createdEnvPath = created?.path;
113+
}
114+
if (!createdEnvPath) {
94115
traceWarn(`${CreateVirtualEnvTool.toolName} tool not invoked, virtual env not created.`);
95116
throw new CancellationError();
96117
}
@@ -102,7 +123,7 @@ export class CreateVirtualEnvTool implements LanguageModelTool<ICreateVirtualEnv
102123
const stopWatch = new StopWatch();
103124
let env: ResolvedEnvironment | undefined;
104125
while (stopWatch.elapsedTime < 5_000 || !env) {
105-
env = await this.api.resolveEnvironment(created.path);
126+
env = await this.api.resolveEnvironment(createdEnvPath);
106127
if (env) {
107128
break;
108129
} else {
@@ -150,7 +171,7 @@ export class CreateVirtualEnvTool implements LanguageModelTool<ICreateVirtualEnv
150171
}
151172

152173
async prepareInvocation?(
153-
options: LanguageModelToolInvocationPrepareOptions<IResourceReference>,
174+
options: LanguageModelToolInvocationPrepareOptions<ICreateVirtualEnvToolParams>,
154175
token: CancellationToken,
155176
): Promise<PreparedToolInvocation> {
156177
const resource = resolveFilePath(options.input.resourcePath);

src/client/chat/getExecutableTool.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
LanguageModelToolInvocationPrepareOptions,
1111
LanguageModelToolResult,
1212
PreparedToolInvocation,
13+
workspace,
1314
} from 'vscode';
1415
import { PythonExtension } from '../api/types';
1516
import { IServiceContainer } from '../ioc/types';
@@ -19,6 +20,7 @@ import {
1920
getEnvDisplayName,
2021
getEnvironmentDetails,
2122
getToolResponseIfNotebook,
23+
getUntrustedWorkspaceResponse,
2224
IResourceReference,
2325
raceCancellationError,
2426
} from './utils';
@@ -45,6 +47,10 @@ export class GetExecutableTool implements LanguageModelTool<IResourceReference>
4547
options: LanguageModelToolInvocationOptions<IResourceReference>,
4648
token: CancellationToken,
4749
): Promise<LanguageModelToolResult> {
50+
if (!workspace.isTrusted) {
51+
return getUntrustedWorkspaceResponse();
52+
}
53+
4854
const resourcePath = resolveFilePath(options.input.resourcePath);
4955
const notebookResponse = getToolResponseIfNotebook(resourcePath);
5056
if (notebookResponse) {

src/client/chat/getPythonEnvTool.ts

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,24 @@ import {
1010
LanguageModelToolInvocationPrepareOptions,
1111
LanguageModelToolResult,
1212
PreparedToolInvocation,
13+
workspace,
1314
} from 'vscode';
1415
import { PythonExtension } from '../api/types';
1516
import { IServiceContainer } from '../ioc/types';
1617
import { ICodeExecutionService } from '../terminals/types';
1718
import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/terminalCodeExecution';
1819
import { IProcessServiceFactory, IPythonExecutionFactory } from '../common/process/types';
19-
import { getEnvironmentDetails, getToolResponseIfNotebook, IResourceReference, raceCancellationError } from './utils';
20+
import {
21+
getEnvironmentDetails,
22+
getToolResponseIfNotebook,
23+
getUntrustedWorkspaceResponse,
24+
IResourceReference,
25+
raceCancellationError,
26+
} from './utils';
2027
import { resolveFilePath } from './utils';
2128
import { getPythonPackagesResponse } from './listPackagesTool';
2229
import { ITerminalHelper } from '../common/terminal/types';
30+
import { getEnvExtApi, useEnvExtension } from '../envExt/api.internal';
2331

2432
export class GetEnvironmentInfoTool implements LanguageModelTool<IResourceReference> {
2533
private readonly terminalExecutionService: TerminalCodeExecutionProvider;
@@ -44,6 +52,10 @@ export class GetEnvironmentInfoTool implements LanguageModelTool<IResourceRefere
4452
options: LanguageModelToolInvocationOptions<IResourceReference>,
4553
token: CancellationToken,
4654
): Promise<LanguageModelToolResult> {
55+
if (!workspace.isTrusted) {
56+
return getUntrustedWorkspaceResponse();
57+
}
58+
4759
const resourcePath = resolveFilePath(options.input.resourcePath);
4860
const notebookResponse = getToolResponseIfNotebook(resourcePath);
4961
if (notebookResponse) {
@@ -56,14 +68,33 @@ export class GetEnvironmentInfoTool implements LanguageModelTool<IResourceRefere
5668
if (!environment || !environment.version) {
5769
throw new Error('No environment found for the provided resource path: ' + resourcePath?.fsPath);
5870
}
59-
const packages = await getPythonPackagesResponse(
60-
environment,
61-
this.pythonExecFactory,
62-
this.processServiceFactory,
63-
resourcePath,
64-
token,
65-
);
6671

72+
let packages = '';
73+
if (useEnvExtension()) {
74+
const api = await getEnvExtApi();
75+
const env = await api.getEnvironment(resourcePath);
76+
const pkgs = env ? await api.getPackages(env) : [];
77+
if (pkgs && pkgs.length > 0) {
78+
// 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.
79+
const response = [
80+
'Below is a list of the Python packages, each in the format <name> or <name> (<version>). The version may be omitted if unknown: ',
81+
];
82+
pkgs.forEach((pkg) => {
83+
const version = pkg.version;
84+
response.push(version ? `- ${pkg.name} (${version})` : `- ${pkg.name}`);
85+
});
86+
packages = response.join('\n');
87+
}
88+
}
89+
if (!packages) {
90+
packages = await getPythonPackagesResponse(
91+
environment,
92+
this.pythonExecFactory,
93+
this.processServiceFactory,
94+
resourcePath,
95+
token,
96+
);
97+
}
6798
const message = await getEnvironmentDetails(
6899
resourcePath,
69100
this.api,

0 commit comments

Comments
 (0)