Skip to content

Commit 3ff59a8

Browse files
CopilotDonJayamanne
andcommitted
Add robust error handling and execution order validation
Co-authored-by: DonJayamanne <[email protected]>
1 parent 1380ec8 commit 3ff59a8

File tree

2 files changed

+76
-15
lines changed

2 files changed

+76
-15
lines changed

src/standalone/chat/installPackageTool.node.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,20 @@ export class InstallPackagesTool extends BaseTool<IInstallPackageParams> impleme
3434
// Track cell execution for all notebooks
3535
this.disposables.push(
3636
vscode.workspace.onDidChangeNotebookDocument((e) => {
37-
for (const change of e.cellChanges) {
38-
const cell = change.cell;
39-
if (
40-
cell.kind === vscode.NotebookCellKind.Code &&
41-
typeof cell.executionSummary?.executionOrder === 'number'
42-
) {
43-
this.executedNotebooks.add(e.notebook);
37+
try {
38+
for (const change of e.cellChanges) {
39+
const cell = change.cell;
40+
if (
41+
cell.kind === vscode.NotebookCellKind.Code &&
42+
typeof cell.executionSummary?.executionOrder === 'number' &&
43+
cell.executionSummary.executionOrder > 0
44+
) {
45+
this.executedNotebooks.add(e.notebook);
46+
break; // Once we find one executed cell, no need to check others
47+
}
4448
}
49+
} catch (error) {
50+
console.warn('Error processing notebook document change:', error);
4551
}
4652
})
4753
);
@@ -53,19 +59,31 @@ export class InstallPackagesTool extends BaseTool<IInstallPackageParams> impleme
5359
}
5460

5561
private initializeExecutedNotebooks(): void {
56-
// Check all currently open notebooks for executed cells
57-
for (const notebook of vscode.workspace.notebookDocuments) {
58-
if (this.hasAnyExecutedCells(notebook)) {
59-
this.executedNotebooks.add(notebook);
62+
try {
63+
// Check all currently open notebooks for executed cells
64+
for (const notebook of vscode.workspace.notebookDocuments) {
65+
if (this.hasAnyExecutedCells(notebook)) {
66+
this.executedNotebooks.add(notebook);
67+
}
6068
}
69+
} catch (error) {
70+
// If there's an error during initialization, log it but don't fail
71+
console.warn('Error initializing executed notebooks:', error);
6172
}
6273
}
6374

6475
private hasAnyExecutedCells(notebook: vscode.NotebookDocument): boolean {
65-
return notebook.getCells().some(cell =>
66-
cell.kind === vscode.NotebookCellKind.Code &&
67-
typeof cell.executionSummary?.executionOrder === 'number'
68-
);
76+
try {
77+
return notebook.getCells().some(cell =>
78+
cell.kind === vscode.NotebookCellKind.Code &&
79+
typeof cell.executionSummary?.executionOrder === 'number' &&
80+
cell.executionSummary.executionOrder > 0
81+
);
82+
} catch (error) {
83+
// If there's an error accessing cells, assume no execution
84+
console.warn('Error checking executed cells:', error);
85+
return false;
86+
}
6987
}
7088

7189
private hasExecutedCells(notebook: vscode.NotebookDocument): boolean {

src/standalone/chat/installPackageTool.node.unit.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,26 @@ suite('InstallPackagesTool Unit Tests', () => {
8989
assert.isTrue(hasExecuted, 'Should return true for notebook with executed cells');
9090
});
9191

92+
test('Should not detect cells with execution order 0', () => {
93+
// Setup notebook with cell that has execution order 0 (not executed)
94+
const mockNonExecutedCell = {
95+
kind: vscode.NotebookCellKind.Code,
96+
executionSummary: { executionOrder: 0 }
97+
} as vscode.NotebookCell;
98+
99+
mockCells.push(mockNonExecutedCell);
100+
101+
installPackagesTool = new InstallPackagesTool(
102+
instance(kernelProvider),
103+
instance(controllerRegistration),
104+
instance(installationManager)
105+
);
106+
107+
// hasExecutedCells should return false for cell with execution order 0
108+
const hasExecuted = (installPackagesTool as any).hasExecutedCells(mockNotebook);
109+
assert.isFalse(hasExecuted, 'Should return false for cell with execution order 0');
110+
});
111+
92112
test('Should track cell execution via event listener', () => {
93113
let onDidChangeCallback: (e: vscode.NotebookDocumentChangeEvent) => void;
94114

@@ -170,6 +190,29 @@ suite('InstallPackagesTool Unit Tests', () => {
170190
assert.isFalse((installPackagesTool as any).hasExecutedCells(mockNotebook));
171191
});
172192

193+
test('Should handle errors gracefully during initialization', () => {
194+
// Setup notebook that throws error when getCells is called
195+
const mockErrorNotebook = {
196+
uri: vscode.Uri.file('/test/error-notebook.ipynb'),
197+
getCells: sinon.stub().throws(new Error('Test error'))
198+
} as any;
199+
200+
mockWorkspace.notebookDocuments = [mockErrorNotebook];
201+
202+
// Should not throw error during initialization
203+
assert.doesNotThrow(() => {
204+
installPackagesTool = new InstallPackagesTool(
205+
instance(kernelProvider),
206+
instance(controllerRegistration),
207+
instance(installationManager)
208+
);
209+
}, 'Should handle initialization errors gracefully');
210+
211+
// Should return false for error case
212+
const hasExecuted = (installPackagesTool as any).hasExecutedCells(mockErrorNotebook);
213+
assert.isFalse(hasExecuted, 'Should return false when error occurs');
214+
});
215+
173216
test('Should dispose of event listeners properly', () => {
174217
const disposeSpy = sinon.spy();
175218
(mockWorkspace.onDidChangeNotebookDocument as sinon.SinonStub).returns({ dispose: disposeSpy });

0 commit comments

Comments
 (0)