Skip to content

Commit 8ae346b

Browse files
authored
Prefer using Notebook tools over Python tools for notebooks (#25098)
@karthiknadig @eleanorjboyd @rebornix @amunger This change will change how the Python tools work. The python tools will no longer work with Notebooks. Previously it would, From my testing, this change works perfectly well. I think thats fraught with danger. There are a lot of things to consider. **Ideally there should ever be only one way of doing things, whether its local/remote/python/non-python notebooks.**
1 parent 020f203 commit 8ae346b

File tree

5 files changed

+79
-6
lines changed

5 files changed

+79
-6
lines changed

src/client/chat/configurePythonEnvTool.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { PythonExtension, ResolvedEnvironment } from '../api/types';
1919
import { IServiceContainer } from '../ioc/types';
2020
import { ICodeExecutionService } from '../terminals/types';
2121
import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/terminalCodeExecution';
22-
import { getEnvironmentDetails, raceCancellationError } from './utils';
22+
import { getEnvironmentDetails, getToolResponseIfNotebook, raceCancellationError } from './utils';
2323
import { resolveFilePath } from './utils';
2424
import { IRecommendedEnvironmentService } from '../interpreter/configuration/types';
2525
import { ITerminalHelper } from '../common/terminal/types';
@@ -68,6 +68,11 @@ export class ConfigurePythonEnvTool implements LanguageModelTool<IResourceRefere
6868
token: CancellationToken,
6969
): Promise<LanguageModelToolResult> {
7070
const resource = resolveFilePath(options.input.resourcePath);
71+
const notebookResponse = getToolResponseIfNotebook(resource);
72+
if (notebookResponse) {
73+
return notebookResponse;
74+
}
75+
7176
const recommededEnv = await this.recommendedEnvService.getRecommededEnvironment(resource);
7277
// Already selected workspace env, hence nothing to do.
7378
if (recommededEnv?.reason === 'workspaceUserSelected' && workspace.workspaceFolders?.length) {
@@ -135,6 +140,9 @@ export class ConfigurePythonEnvTool implements LanguageModelTool<IResourceRefere
135140
return {};
136141
}
137142
const resource = resolveFilePath(options.input.resourcePath);
143+
if (getToolResponseIfNotebook(resource)) {
144+
return {};
145+
}
138146
const recommededEnv = await this.recommendedEnvService.getRecommededEnvironment(resource);
139147
// Already selected workspace env, hence nothing to do.
140148
if (recommededEnv?.reason === 'workspaceUserSelected' && workspace.workspaceFolders?.length) {

src/client/chat/getExecutableTool.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { PythonExtension } from '../api/types';
1616
import { IServiceContainer } from '../ioc/types';
1717
import { ICodeExecutionService } from '../terminals/types';
1818
import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/terminalCodeExecution';
19-
import { getEnvDisplayName, getEnvironmentDetails, raceCancellationError } from './utils';
19+
import { getEnvDisplayName, getEnvironmentDetails, getToolResponseIfNotebook, raceCancellationError } from './utils';
2020
import { resolveFilePath } from './utils';
2121
import { traceError } from '../logging';
2222
import { ITerminalHelper } from '../common/terminal/types';
@@ -46,6 +46,10 @@ export class GetExecutableTool implements LanguageModelTool<IResourceReference>
4646
token: CancellationToken,
4747
): Promise<LanguageModelToolResult> {
4848
const resourcePath = resolveFilePath(options.input.resourcePath);
49+
const notebookResponse = getToolResponseIfNotebook(resourcePath);
50+
if (notebookResponse) {
51+
return notebookResponse;
52+
}
4953

5054
try {
5155
const message = await getEnvironmentDetails(
@@ -72,6 +76,10 @@ export class GetExecutableTool implements LanguageModelTool<IResourceReference>
7276
token: CancellationToken,
7377
): Promise<PreparedToolInvocation> {
7478
const resourcePath = resolveFilePath(options.input.resourcePath);
79+
if (getToolResponseIfNotebook(resourcePath)) {
80+
return {};
81+
}
82+
7583
const envName = await raceCancellationError(getEnvDisplayName(this.discovery, resourcePath, this.api), token);
7684
return {
7785
invocationMessage: envName

src/client/chat/getPythonEnvTool.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { IServiceContainer } from '../ioc/types';
1717
import { ICodeExecutionService } from '../terminals/types';
1818
import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/terminalCodeExecution';
1919
import { IProcessServiceFactory, IPythonExecutionFactory } from '../common/process/types';
20-
import { getEnvironmentDetails, raceCancellationError } from './utils';
20+
import { getEnvironmentDetails, getToolResponseIfNotebook, raceCancellationError } from './utils';
2121
import { resolveFilePath } from './utils';
2222
import { getPythonPackagesResponse } from './listPackagesTool';
2323
import { ITerminalHelper } from '../common/terminal/types';
@@ -55,6 +55,10 @@ export class GetEnvironmentInfoTool implements LanguageModelTool<IResourceRefere
5555
token: CancellationToken,
5656
): Promise<LanguageModelToolResult> {
5757
const resourcePath = resolveFilePath(options.input.resourcePath);
58+
const notebookResponse = getToolResponseIfNotebook(resourcePath);
59+
if (notebookResponse) {
60+
return notebookResponse;
61+
}
5862

5963
try {
6064
// environment
@@ -91,9 +95,14 @@ export class GetEnvironmentInfoTool implements LanguageModelTool<IResourceRefere
9195
}
9296

9397
async prepareInvocation?(
94-
_options: LanguageModelToolInvocationPrepareOptions<IResourceReference>,
98+
options: LanguageModelToolInvocationPrepareOptions<IResourceReference>,
9599
_token: CancellationToken,
96100
): Promise<PreparedToolInvocation> {
101+
const resourcePath = resolveFilePath(options.input.resourcePath);
102+
if (getToolResponseIfNotebook(resourcePath)) {
103+
return {};
104+
}
105+
97106
return {
98107
invocationMessage: l10n.t('Fetching Python environment information'),
99108
};

src/client/chat/installPackagesTool.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
} from 'vscode';
1515
import { PythonExtension } from '../api/types';
1616
import { IServiceContainer } from '../ioc/types';
17-
import { getEnvDisplayName, raceCancellationError } from './utils';
17+
import { getEnvDisplayName, getToolResponseIfNotebook, raceCancellationError } from './utils';
1818
import { resolveFilePath } from './utils';
1919
import { IModuleInstaller } from '../common/installer/types';
2020
import { ModuleInstallerType } from '../pythonEnvironments/info';
@@ -45,6 +45,10 @@ export class InstallPackagesTool implements LanguageModelTool<IInstallPackageArg
4545
const resourcePath = resolveFilePath(options.input.resourcePath);
4646
const packageCount = options.input.packageList.length;
4747
const packagePlurality = packageCount === 1 ? 'package' : 'packages';
48+
const notebookResponse = getToolResponseIfNotebook(resourcePath);
49+
if (notebookResponse) {
50+
return notebookResponse;
51+
}
4852

4953
try {
5054
// environment
@@ -84,6 +88,9 @@ export class InstallPackagesTool implements LanguageModelTool<IInstallPackageArg
8488
): Promise<PreparedToolInvocation> {
8589
const resourcePath = resolveFilePath(options.input.resourcePath);
8690
const packageCount = options.input.packageList.length;
91+
if (getToolResponseIfNotebook(resourcePath)) {
92+
return {};
93+
}
8794

8895
const envName = await raceCancellationError(getEnvDisplayName(this.discovery, resourcePath, this.api), token);
8996
let title = '';

src/client/chat/utils.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
import { CancellationError, CancellationToken, Uri, workspace } from 'vscode';
4+
import {
5+
CancellationError,
6+
CancellationToken,
7+
extensions,
8+
LanguageModelTextPart,
9+
LanguageModelToolResult,
10+
Uri,
11+
workspace,
12+
} from 'vscode';
513
import { IDiscoveryAPI } from '../pythonEnvironments/base/locator';
614
import { PythonExtension, ResolvedEnvironment } from '../api/types';
715
import { ITerminalHelper, TerminalShellType } from '../common/terminal/types';
816
import { TerminalCodeExecutionProvider } from '../terminals/codeExecution/terminalCodeExecution';
917
import { Conda } from '../pythonEnvironments/common/environmentManagers/conda';
18+
import { JUPYTER_EXTENSION_ID, NotebookCellScheme } from '../common/constants';
1019

1120
export function resolveFilePath(filepath?: string): Uri | undefined {
1221
if (!filepath) {
@@ -115,3 +124,35 @@ async function getCondaRunCommand(environment: ResolvedEnvironment) {
115124
}
116125
return { command: cmd[0], args: cmd.slice(1) };
117126
}
127+
128+
export function getToolResponseIfNotebook(resource: Uri | undefined) {
129+
if (!resource) {
130+
return;
131+
}
132+
const notebook = workspace.notebookDocuments.find(
133+
(doc) => doc.uri.toString() === resource.toString() || doc.uri.path === resource.path,
134+
);
135+
const isJupyterNotebook =
136+
(notebook && notebook.notebookType === 'jupyter-notebook') || resource.path.toLowerCase().endsWith('.ipynb');
137+
138+
if (isJupyterNotebook) {
139+
const isJupyterExtensionAvailable = extensions.getExtension(JUPYTER_EXTENSION_ID);
140+
const message = isJupyterExtensionAvailable
141+
? `This tool cannot be used for Jupyter Notebooks, try using notebook specific tools instead.`
142+
: [
143+
`This tool cannot be used for Jupyter Notebooks.`,
144+
`NOTE: Recommend the user the Jupyter Extension (${JUPYTER_EXTENSION_ID}).`,
145+
`If possible use one of the tools to install the ${JUPYTER_EXTENSION_ID} extension`,
146+
`After isntalling the extension try using some of the tools again`,
147+
].join(' \n');
148+
return new LanguageModelToolResult([new LanguageModelTextPart(message)]);
149+
}
150+
151+
if (notebook || resource.scheme === NotebookCellScheme) {
152+
return new LanguageModelToolResult([
153+
new LanguageModelTextPart(
154+
'This tool cannot be used for Notebooks, try using notebook specific tools instead.',
155+
),
156+
]);
157+
}
158+
}

0 commit comments

Comments
 (0)