@jupyterlite/ai 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -214
- package/lib/agent.d.ts +58 -66
- package/lib/agent.js +274 -300
- package/lib/approval-buttons.d.ts +19 -82
- package/lib/approval-buttons.js +36 -289
- package/lib/chat-model-registry.d.ts +6 -0
- package/lib/chat-model-registry.js +4 -1
- package/lib/chat-model.d.ts +19 -54
- package/lib/chat-model.js +243 -303
- package/lib/components/clear-button.d.ts +6 -1
- package/lib/components/clear-button.js +8 -3
- package/lib/components/completion-status.d.ts +5 -0
- package/lib/components/completion-status.js +5 -4
- package/lib/components/model-select.d.ts +6 -1
- package/lib/components/model-select.js +9 -8
- package/lib/components/stop-button.d.ts +6 -1
- package/lib/components/stop-button.js +8 -3
- package/lib/components/token-usage-display.d.ts +5 -0
- package/lib/components/token-usage-display.js +2 -2
- package/lib/components/tool-select.d.ts +6 -1
- package/lib/components/tool-select.js +6 -5
- package/lib/index.js +62 -38
- package/lib/models/settings-model.d.ts +1 -1
- package/lib/providers/built-in-providers.js +38 -19
- package/lib/providers/models.d.ts +3 -3
- package/lib/providers/provider-registry.d.ts +3 -4
- package/lib/providers/provider-registry.js +1 -4
- package/lib/tokens.d.ts +5 -6
- package/lib/tools/commands.d.ts +2 -1
- package/lib/tools/commands.js +37 -46
- package/lib/tools/file.js +49 -73
- package/lib/tools/notebook.js +370 -445
- package/lib/widgets/ai-settings.d.ts +6 -0
- package/lib/widgets/ai-settings.js +72 -71
- package/lib/widgets/main-area-chat.d.ts +2 -0
- package/lib/widgets/main-area-chat.js +5 -2
- package/lib/widgets/provider-config-dialog.d.ts +2 -0
- package/lib/widgets/provider-config-dialog.js +34 -34
- package/package.json +12 -12
- package/src/agent.ts +342 -361
- package/src/approval-buttons.ts +43 -389
- package/src/chat-model-registry.ts +9 -1
- package/src/chat-model.ts +355 -370
- package/src/completion/completion-provider.ts +2 -3
- package/src/components/clear-button.tsx +16 -3
- package/src/components/completion-status.tsx +18 -4
- package/src/components/model-select.tsx +21 -8
- package/src/components/stop-button.tsx +16 -3
- package/src/components/token-usage-display.tsx +14 -2
- package/src/components/tool-select.tsx +23 -5
- package/src/index.ts +80 -36
- package/src/models/settings-model.ts +1 -1
- package/src/providers/built-in-providers.ts +38 -19
- package/src/providers/models.ts +3 -3
- package/src/providers/provider-registry.ts +4 -8
- package/src/tokens.ts +5 -6
- package/src/tools/commands.ts +39 -50
- package/src/tools/file.ts +49 -75
- package/src/tools/notebook.ts +451 -510
- package/src/widgets/ai-settings.tsx +153 -84
- package/src/widgets/main-area-chat.ts +8 -2
- package/src/widgets/provider-config-dialog.tsx +54 -41
- package/style/base.css +13 -73
- package/lib/mcp/browser.d.ts +0 -68
- package/lib/mcp/browser.js +0 -138
- package/src/mcp/browser.ts +0 -220
package/src/tools/notebook.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CodeCell,
|
|
3
|
+
CodeCellModel,
|
|
4
|
+
ICodeCellModel,
|
|
5
|
+
MarkdownCell
|
|
6
|
+
} from '@jupyterlab/cells';
|
|
2
7
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
3
8
|
import { DocumentWidget } from '@jupyterlab/docregistry';
|
|
4
9
|
import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
|
|
5
10
|
import { KernelSpec } from '@jupyterlab/services';
|
|
6
11
|
|
|
7
|
-
import { tool } from '
|
|
12
|
+
import { tool } from 'ai';
|
|
8
13
|
|
|
9
14
|
import { z } from 'zod';
|
|
10
15
|
|
|
@@ -91,10 +96,10 @@ export function createNotebookCreationTool(
|
|
|
91
96
|
kernelSpecManager: KernelSpec.IManager
|
|
92
97
|
): ITool {
|
|
93
98
|
return tool({
|
|
94
|
-
|
|
99
|
+
title: 'Create Notebook',
|
|
95
100
|
description:
|
|
96
101
|
'Create a new Jupyter notebook with a kernel for the specified programming language',
|
|
97
|
-
|
|
102
|
+
inputSchema: z.object({
|
|
98
103
|
language: z
|
|
99
104
|
.string()
|
|
100
105
|
.optional()
|
|
@@ -121,49 +126,48 @@ export function createNotebookCreationTool(
|
|
|
121
126
|
const { name } = input;
|
|
122
127
|
|
|
123
128
|
if (!name) {
|
|
124
|
-
|
|
129
|
+
return {
|
|
130
|
+
success: false,
|
|
131
|
+
error: 'A name must be provided to create a notebook'
|
|
132
|
+
};
|
|
125
133
|
}
|
|
126
134
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const fileName = name.endsWith('.ipynb') ? name : `${name}.ipynb`;
|
|
130
|
-
|
|
131
|
-
// Create untitled notebook first
|
|
132
|
-
const notebookModel = await docManager.newUntitled({
|
|
133
|
-
type: 'notebook'
|
|
134
|
-
});
|
|
135
|
+
// TODO: handle cwd / path?
|
|
136
|
+
const fileName = name.endsWith('.ipynb') ? name : `${name}.ipynb`;
|
|
135
137
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const notebook = docManager.createNew(fileName, 'default', {
|
|
141
|
-
name: kernel
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
if (!(notebook instanceof DocumentWidget)) {
|
|
145
|
-
throw new Error('Failed to create notebook widget');
|
|
146
|
-
}
|
|
138
|
+
// Create untitled notebook first
|
|
139
|
+
const notebookModel = await docManager.newUntitled({
|
|
140
|
+
type: 'notebook'
|
|
141
|
+
});
|
|
147
142
|
|
|
148
|
-
|
|
149
|
-
|
|
143
|
+
// Rename to desired filename
|
|
144
|
+
await docManager.services.contents.rename(notebookModel.path, fileName);
|
|
150
145
|
|
|
151
|
-
|
|
146
|
+
// Create widget with specific kernel
|
|
147
|
+
const notebook = docManager.createNew(fileName, 'default', {
|
|
148
|
+
name: kernel
|
|
149
|
+
});
|
|
152
150
|
|
|
153
|
-
|
|
154
|
-
success: true,
|
|
155
|
-
message: `Successfully created notebook ${fileName} with ${kernel} kernel${input.language ? ` for ${input.language}` : ''}`,
|
|
156
|
-
notebookPath: fileName,
|
|
157
|
-
notebookName: fileName,
|
|
158
|
-
kernel,
|
|
159
|
-
language: input.language
|
|
160
|
-
};
|
|
161
|
-
} catch (error) {
|
|
151
|
+
if (!(notebook instanceof DocumentWidget)) {
|
|
162
152
|
return {
|
|
163
153
|
success: false,
|
|
164
|
-
error:
|
|
154
|
+
error: 'Failed to create notebook widget'
|
|
165
155
|
};
|
|
166
156
|
}
|
|
157
|
+
|
|
158
|
+
await notebook.context.ready;
|
|
159
|
+
await notebook.context.save();
|
|
160
|
+
|
|
161
|
+
docManager.openOrReveal(fileName);
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
success: true,
|
|
165
|
+
message: `Successfully created notebook ${fileName} with ${kernel} kernel${input.language ? ` for ${input.language}` : ''}`,
|
|
166
|
+
notebookPath: fileName,
|
|
167
|
+
notebookName: fileName,
|
|
168
|
+
kernel,
|
|
169
|
+
language: input.language
|
|
170
|
+
};
|
|
167
171
|
}
|
|
168
172
|
});
|
|
169
173
|
}
|
|
@@ -176,9 +180,9 @@ export function createAddCellTool(
|
|
|
176
180
|
notebookTracker?: INotebookTracker
|
|
177
181
|
): ITool {
|
|
178
182
|
return tool({
|
|
179
|
-
|
|
183
|
+
title: 'Add Cell',
|
|
180
184
|
description: 'Add a cell to the current notebook with optional content',
|
|
181
|
-
|
|
185
|
+
inputSchema: z.object({
|
|
182
186
|
notebookPath: z
|
|
183
187
|
.string()
|
|
184
188
|
.optional()
|
|
@@ -201,83 +205,76 @@ export function createAddCellTool(
|
|
|
201
205
|
.default('below')
|
|
202
206
|
.describe('Position relative to current cell')
|
|
203
207
|
}),
|
|
204
|
-
async
|
|
208
|
+
execute: async ({
|
|
205
209
|
notebookPath,
|
|
206
210
|
content,
|
|
207
211
|
cellType = 'code',
|
|
208
212
|
position = 'below'
|
|
209
|
-
}) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
213
|
+
}) => {
|
|
214
|
+
const currentWidget = await getNotebookWidget(
|
|
215
|
+
notebookPath,
|
|
216
|
+
docManager,
|
|
217
|
+
notebookTracker
|
|
218
|
+
);
|
|
219
|
+
if (!currentWidget) {
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: notebookPath
|
|
223
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
224
|
+
: 'No active notebook and no notebook path provided'
|
|
225
|
+
};
|
|
226
|
+
}
|
|
224
227
|
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
const notebook = currentWidget.content;
|
|
229
|
+
const model = notebook.model;
|
|
227
230
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
if (!model) {
|
|
232
|
+
return {
|
|
233
|
+
success: false,
|
|
234
|
+
error: 'No notebook model available'
|
|
235
|
+
};
|
|
236
|
+
}
|
|
234
237
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
238
|
+
// Check if we should replace the first empty cell instead of adding
|
|
239
|
+
const shouldReplaceFirstCell =
|
|
240
|
+
model.cells.length === 1 &&
|
|
241
|
+
model.cells.get(0).sharedModel.getSource().trim() === '';
|
|
239
242
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
243
|
+
if (shouldReplaceFirstCell) {
|
|
244
|
+
// Replace the first empty cell by removing it and adding new one
|
|
245
|
+
model.sharedModel.deleteCell(0);
|
|
246
|
+
}
|
|
244
247
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
// Create the new cell using shared model
|
|
249
|
+
const newCellData = {
|
|
250
|
+
cell_type: cellType,
|
|
251
|
+
source: content || '',
|
|
252
|
+
metadata: cellType === 'code' ? { trusted: true } : {}
|
|
253
|
+
};
|
|
251
254
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
255
|
+
model.sharedModel.addCell(newCellData);
|
|
256
|
+
|
|
257
|
+
// Execute markdown cells after creation to render them
|
|
258
|
+
if (cellType === 'markdown' && content) {
|
|
259
|
+
const cellIndex = model.cells.length - 1;
|
|
260
|
+
const cellWidget = notebook.widgets[cellIndex];
|
|
261
|
+
if (cellWidget && cellWidget instanceof MarkdownCell) {
|
|
262
|
+
try {
|
|
263
|
+
await cellWidget.ready;
|
|
264
|
+
cellWidget.rendered = true;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.warn('Failed to render markdown cell:', error);
|
|
265
267
|
}
|
|
266
268
|
}
|
|
267
|
-
|
|
268
|
-
return {
|
|
269
|
-
success: true,
|
|
270
|
-
message: `${cellType} cell added successfully`,
|
|
271
|
-
content: content || '',
|
|
272
|
-
cellType,
|
|
273
|
-
position
|
|
274
|
-
};
|
|
275
|
-
} catch (error) {
|
|
276
|
-
return {
|
|
277
|
-
success: false,
|
|
278
|
-
error: `Failed to add ${cellType} cell: ${(error as Error).message}`
|
|
279
|
-
};
|
|
280
269
|
}
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
success: true,
|
|
273
|
+
message: `${cellType} cell added successfully`,
|
|
274
|
+
content: content || '',
|
|
275
|
+
cellType,
|
|
276
|
+
position
|
|
277
|
+
};
|
|
281
278
|
}
|
|
282
279
|
});
|
|
283
280
|
}
|
|
@@ -290,10 +287,10 @@ export function createGetNotebookInfoTool(
|
|
|
290
287
|
notebookTracker?: INotebookTracker
|
|
291
288
|
): ITool {
|
|
292
289
|
return tool({
|
|
293
|
-
|
|
290
|
+
title: 'Get Notebook Info',
|
|
294
291
|
description:
|
|
295
292
|
'Get information about a notebook including number of cells and active cell index',
|
|
296
|
-
|
|
293
|
+
inputSchema: z.object({
|
|
297
294
|
notebookPath: z
|
|
298
295
|
.string()
|
|
299
296
|
.optional()
|
|
@@ -305,51 +302,44 @@ export function createGetNotebookInfoTool(
|
|
|
305
302
|
execute: async (input: { notebookPath?: string | null }) => {
|
|
306
303
|
const { notebookPath } = input;
|
|
307
304
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (!currentWidget) {
|
|
315
|
-
return JSON.stringify({
|
|
316
|
-
success: false,
|
|
317
|
-
error: notebookPath
|
|
318
|
-
? `Failed to open notebook at path: ${notebookPath}`
|
|
319
|
-
: 'No active notebook and no notebook path provided'
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const notebook = currentWidget.content;
|
|
324
|
-
const model = notebook.model;
|
|
325
|
-
|
|
326
|
-
if (!model) {
|
|
327
|
-
return JSON.stringify({
|
|
328
|
-
success: false,
|
|
329
|
-
error: 'No notebook model available'
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const cellCount = model.cells.length;
|
|
334
|
-
const activeCellIndex = notebook.activeCellIndex;
|
|
335
|
-
const activeCell = notebook.activeCell;
|
|
336
|
-
const activeCellType = activeCell?.model.type || 'unknown';
|
|
337
|
-
|
|
305
|
+
const currentWidget = await getNotebookWidget(
|
|
306
|
+
notebookPath,
|
|
307
|
+
docManager,
|
|
308
|
+
notebookTracker
|
|
309
|
+
);
|
|
310
|
+
if (!currentWidget) {
|
|
338
311
|
return JSON.stringify({
|
|
339
|
-
success:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
activeCellIndex,
|
|
344
|
-
activeCellType,
|
|
345
|
-
isDirty: model.dirty
|
|
312
|
+
success: false,
|
|
313
|
+
error: notebookPath
|
|
314
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
315
|
+
: 'No active notebook and no notebook path provided'
|
|
346
316
|
});
|
|
347
|
-
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const notebook = currentWidget.content;
|
|
320
|
+
const model = notebook.model;
|
|
321
|
+
|
|
322
|
+
if (!model) {
|
|
348
323
|
return JSON.stringify({
|
|
349
324
|
success: false,
|
|
350
|
-
error:
|
|
325
|
+
error: 'No notebook model available'
|
|
351
326
|
});
|
|
352
327
|
}
|
|
328
|
+
|
|
329
|
+
const cellCount = model.cells.length;
|
|
330
|
+
const activeCellIndex = notebook.activeCellIndex;
|
|
331
|
+
const activeCell = notebook.activeCell;
|
|
332
|
+
const activeCellType = activeCell?.model.type || 'unknown';
|
|
333
|
+
|
|
334
|
+
return JSON.stringify({
|
|
335
|
+
success: true,
|
|
336
|
+
notebookName: currentWidget.title.label,
|
|
337
|
+
notebookPath: currentWidget.context.path,
|
|
338
|
+
cellCount,
|
|
339
|
+
activeCellIndex,
|
|
340
|
+
activeCellType,
|
|
341
|
+
isDirty: model.dirty
|
|
342
|
+
});
|
|
353
343
|
}
|
|
354
344
|
});
|
|
355
345
|
}
|
|
@@ -362,10 +352,10 @@ export function createGetCellInfoTool(
|
|
|
362
352
|
notebookTracker?: INotebookTracker
|
|
363
353
|
): ITool {
|
|
364
354
|
return tool({
|
|
365
|
-
|
|
355
|
+
title: 'Get Cell Info',
|
|
366
356
|
description:
|
|
367
357
|
'Get information about a specific cell including its type, source content, and outputs',
|
|
368
|
-
|
|
358
|
+
inputSchema: z.object({
|
|
369
359
|
notebookPath: z
|
|
370
360
|
.string()
|
|
371
361
|
.optional()
|
|
@@ -387,70 +377,64 @@ export function createGetCellInfoTool(
|
|
|
387
377
|
}) => {
|
|
388
378
|
const { notebookPath } = input;
|
|
389
379
|
let { cellIndex } = input;
|
|
390
|
-
try {
|
|
391
|
-
const currentWidget = await getNotebookWidget(
|
|
392
|
-
notebookPath,
|
|
393
|
-
docManager,
|
|
394
|
-
notebookTracker
|
|
395
|
-
);
|
|
396
|
-
if (!currentWidget) {
|
|
397
|
-
return JSON.stringify({
|
|
398
|
-
success: false,
|
|
399
|
-
error: notebookPath
|
|
400
|
-
? `Failed to open notebook at path: ${notebookPath}`
|
|
401
|
-
: 'No active notebook and no notebook path provided'
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const notebook = currentWidget.content;
|
|
406
|
-
const model = notebook.model;
|
|
407
|
-
|
|
408
|
-
if (!model) {
|
|
409
|
-
return JSON.stringify({
|
|
410
|
-
success: false,
|
|
411
|
-
error: 'No notebook model available'
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
380
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const sharedModel = cell.sharedModel;
|
|
429
|
-
const source = sharedModel.getSource();
|
|
381
|
+
const currentWidget = await getNotebookWidget(
|
|
382
|
+
notebookPath,
|
|
383
|
+
docManager,
|
|
384
|
+
notebookTracker
|
|
385
|
+
);
|
|
386
|
+
if (!currentWidget) {
|
|
387
|
+
return JSON.stringify({
|
|
388
|
+
success: false,
|
|
389
|
+
error: notebookPath
|
|
390
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
391
|
+
: 'No active notebook and no notebook path provided'
|
|
392
|
+
});
|
|
393
|
+
}
|
|
430
394
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (cellType === 'code') {
|
|
434
|
-
const rawOutputs = sharedModel.toJSON().outputs;
|
|
435
|
-
outputs = Array.isArray(rawOutputs) ? rawOutputs : [];
|
|
436
|
-
}
|
|
395
|
+
const notebook = currentWidget.content;
|
|
396
|
+
const model = notebook.model;
|
|
437
397
|
|
|
398
|
+
if (!model) {
|
|
438
399
|
return JSON.stringify({
|
|
439
|
-
success:
|
|
440
|
-
|
|
441
|
-
cellIndex,
|
|
442
|
-
cellType,
|
|
443
|
-
source,
|
|
444
|
-
outputs,
|
|
445
|
-
executionCount:
|
|
446
|
-
cellType === 'code' ? (cell as any).executionCount : null
|
|
400
|
+
success: false,
|
|
401
|
+
error: 'No notebook model available'
|
|
447
402
|
});
|
|
448
|
-
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (cellIndex === undefined || cellIndex === null) {
|
|
406
|
+
cellIndex = notebook.activeCellIndex;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (cellIndex < 0 || cellIndex >= model.cells.length) {
|
|
449
410
|
return JSON.stringify({
|
|
450
411
|
success: false,
|
|
451
|
-
error: `
|
|
412
|
+
error: `Invalid cell index: ${cellIndex}. Notebook has ${model.cells.length} cells.`
|
|
452
413
|
});
|
|
453
414
|
}
|
|
415
|
+
|
|
416
|
+
const cell = model.cells.get(cellIndex);
|
|
417
|
+
const cellType = cell.type;
|
|
418
|
+
const sharedModel = cell.sharedModel;
|
|
419
|
+
const source = sharedModel.getSource();
|
|
420
|
+
|
|
421
|
+
// Get outputs for code cells
|
|
422
|
+
let outputs: any[] = [];
|
|
423
|
+
if (cellType === 'code') {
|
|
424
|
+
const rawOutputs = sharedModel.toJSON().outputs;
|
|
425
|
+
outputs = Array.isArray(rawOutputs) ? rawOutputs : [];
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return JSON.stringify({
|
|
429
|
+
success: true,
|
|
430
|
+
cellId: cell.id,
|
|
431
|
+
cellIndex,
|
|
432
|
+
cellType,
|
|
433
|
+
source,
|
|
434
|
+
outputs,
|
|
435
|
+
executionCount:
|
|
436
|
+
cellType === 'code' ? (cell as CodeCellModel).executionCount : null
|
|
437
|
+
});
|
|
454
438
|
}
|
|
455
439
|
});
|
|
456
440
|
}
|
|
@@ -464,10 +448,10 @@ export function createSetCellContentTool(
|
|
|
464
448
|
diffManager?: IDiffManager
|
|
465
449
|
): ITool {
|
|
466
450
|
return tool({
|
|
467
|
-
|
|
451
|
+
title: 'Set Cell Content',
|
|
468
452
|
description:
|
|
469
453
|
'Set the content of a specific cell and return both the previous and new content',
|
|
470
|
-
|
|
454
|
+
inputSchema: z.object({
|
|
471
455
|
notebookPath: z
|
|
472
456
|
.string()
|
|
473
457
|
.optional()
|
|
@@ -499,120 +483,113 @@ export function createSetCellContentTool(
|
|
|
499
483
|
}) => {
|
|
500
484
|
const { notebookPath, cellId, cellIndex, content } = input;
|
|
501
485
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
486
|
+
const notebookWidget = await getNotebookWidget(
|
|
487
|
+
notebookPath,
|
|
488
|
+
docManager,
|
|
489
|
+
notebookTracker
|
|
490
|
+
);
|
|
491
|
+
if (!notebookWidget) {
|
|
492
|
+
return JSON.stringify({
|
|
493
|
+
success: false,
|
|
494
|
+
error: notebookPath
|
|
495
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
496
|
+
: 'No active notebook and no notebook path provided'
|
|
497
|
+
});
|
|
498
|
+
}
|
|
516
499
|
|
|
517
|
-
|
|
518
|
-
|
|
500
|
+
const notebook = notebookWidget.content;
|
|
501
|
+
const targetNotebookPath = notebookWidget.context.path;
|
|
519
502
|
|
|
520
|
-
|
|
503
|
+
const model = notebook.model;
|
|
521
504
|
|
|
522
|
-
|
|
505
|
+
if (!model) {
|
|
506
|
+
return JSON.stringify({
|
|
507
|
+
success: false,
|
|
508
|
+
error: 'No notebook model available'
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Determine target cell index
|
|
513
|
+
let targetCellIndex: number;
|
|
514
|
+
if (cellId !== undefined && cellId !== null) {
|
|
515
|
+
// Find cell by ID
|
|
516
|
+
targetCellIndex = -1;
|
|
517
|
+
for (let i = 0; i < model.cells.length; i++) {
|
|
518
|
+
if (model.cells.get(i).id === cellId) {
|
|
519
|
+
targetCellIndex = i;
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (targetCellIndex === -1) {
|
|
523
524
|
return JSON.stringify({
|
|
524
525
|
success: false,
|
|
525
|
-
error: '
|
|
526
|
+
error: `Cell with ID '${cellId}' not found in notebook`
|
|
526
527
|
});
|
|
527
528
|
}
|
|
528
|
-
|
|
529
|
-
//
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (model.cells.get(i).id === cellId) {
|
|
536
|
-
targetCellIndex = i;
|
|
537
|
-
break;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
if (targetCellIndex === -1) {
|
|
541
|
-
return JSON.stringify({
|
|
542
|
-
success: false,
|
|
543
|
-
error: `Cell with ID '${cellId}' not found in notebook`
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
} else if (cellIndex !== undefined && cellIndex !== null) {
|
|
547
|
-
// Use provided cell index
|
|
548
|
-
if (cellIndex < 0 || cellIndex >= model.cells.length) {
|
|
549
|
-
return JSON.stringify({
|
|
550
|
-
success: false,
|
|
551
|
-
error: `Invalid cell index: ${cellIndex}. Notebook has ${model.cells.length} cells.`
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
targetCellIndex = cellIndex;
|
|
555
|
-
} else {
|
|
556
|
-
// Use active cell
|
|
557
|
-
targetCellIndex = notebook.activeCellIndex;
|
|
558
|
-
if (targetCellIndex === -1 || targetCellIndex >= model.cells.length) {
|
|
559
|
-
return JSON.stringify({
|
|
560
|
-
success: false,
|
|
561
|
-
error: 'No active cell or invalid active cell index'
|
|
562
|
-
});
|
|
563
|
-
}
|
|
529
|
+
} else if (cellIndex !== undefined && cellIndex !== null) {
|
|
530
|
+
// Use provided cell index
|
|
531
|
+
if (cellIndex < 0 || cellIndex >= model.cells.length) {
|
|
532
|
+
return JSON.stringify({
|
|
533
|
+
success: false,
|
|
534
|
+
error: `Invalid cell index: ${cellIndex}. Notebook has ${model.cells.length} cells.`
|
|
535
|
+
});
|
|
564
536
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
537
|
+
targetCellIndex = cellIndex;
|
|
538
|
+
} else {
|
|
539
|
+
// Use active cell
|
|
540
|
+
targetCellIndex = notebook.activeCellIndex;
|
|
541
|
+
if (targetCellIndex === -1 || targetCellIndex >= model.cells.length) {
|
|
569
542
|
return JSON.stringify({
|
|
570
543
|
success: false,
|
|
571
|
-
error:
|
|
544
|
+
error: 'No active cell or invalid active cell index'
|
|
572
545
|
});
|
|
573
546
|
}
|
|
547
|
+
}
|
|
574
548
|
|
|
575
|
-
|
|
549
|
+
// Get the target cell
|
|
550
|
+
const targetCell = model.cells.get(targetCellIndex);
|
|
551
|
+
if (!targetCell) {
|
|
552
|
+
return JSON.stringify({
|
|
553
|
+
success: false,
|
|
554
|
+
error: `Cell at index ${targetCellIndex} not found`
|
|
555
|
+
});
|
|
556
|
+
}
|
|
576
557
|
|
|
577
|
-
|
|
578
|
-
const previousContent = sharedModel.getSource();
|
|
579
|
-
const previousCellType = targetCell.type;
|
|
580
|
-
const retrievedCellId = targetCell.id;
|
|
558
|
+
const sharedModel = targetCell.sharedModel;
|
|
581
559
|
|
|
582
|
-
|
|
560
|
+
// Get previous content and type
|
|
561
|
+
const previousContent = sharedModel.getSource();
|
|
562
|
+
const previousCellType = targetCell.type;
|
|
563
|
+
const retrievedCellId = targetCell.id;
|
|
583
564
|
|
|
584
|
-
|
|
585
|
-
if (diffManager) {
|
|
586
|
-
await diffManager.showCellDiff({
|
|
587
|
-
original: previousContent,
|
|
588
|
-
modified: content,
|
|
589
|
-
cellId: retrievedCellId,
|
|
590
|
-
notebookPath: targetNotebookPath
|
|
591
|
-
});
|
|
592
|
-
}
|
|
565
|
+
sharedModel.setSource(content);
|
|
593
566
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
: cellIndex !== undefined && cellIndex !== null
|
|
600
|
-
? `Cell ${targetCellIndex} content replaced successfully`
|
|
601
|
-
: 'Active cell content replaced successfully',
|
|
602
|
-
notebookPath: targetNotebookPath,
|
|
567
|
+
// Show the cell diff using the diff manager if available
|
|
568
|
+
if (diffManager) {
|
|
569
|
+
await diffManager.showCellDiff({
|
|
570
|
+
original: previousContent,
|
|
571
|
+
modified: content,
|
|
603
572
|
cellId: retrievedCellId,
|
|
604
|
-
|
|
605
|
-
previousContent,
|
|
606
|
-
previousCellType,
|
|
607
|
-
newContent: content,
|
|
608
|
-
wasActiveCell: cellId === undefined && cellIndex === undefined
|
|
609
|
-
});
|
|
610
|
-
} catch (error) {
|
|
611
|
-
return JSON.stringify({
|
|
612
|
-
success: false,
|
|
613
|
-
error: `Failed to replace cell content: ${(error as Error).message}`
|
|
573
|
+
notebookPath: targetNotebookPath
|
|
614
574
|
});
|
|
615
575
|
}
|
|
576
|
+
|
|
577
|
+
return JSON.stringify({
|
|
578
|
+
success: true,
|
|
579
|
+
message:
|
|
580
|
+
cellId !== undefined && cellId !== null
|
|
581
|
+
? `Cell with ID '${cellId}' content replaced successfully`
|
|
582
|
+
: cellIndex !== undefined && cellIndex !== null
|
|
583
|
+
? `Cell ${targetCellIndex} content replaced successfully`
|
|
584
|
+
: 'Active cell content replaced successfully',
|
|
585
|
+
notebookPath: targetNotebookPath,
|
|
586
|
+
cellId: retrievedCellId,
|
|
587
|
+
cellIndex: targetCellIndex,
|
|
588
|
+
previousContent,
|
|
589
|
+
previousCellType,
|
|
590
|
+
newContent: content,
|
|
591
|
+
wasActiveCell: cellId === undefined && cellIndex === undefined
|
|
592
|
+
});
|
|
616
593
|
}
|
|
617
594
|
});
|
|
618
595
|
}
|
|
@@ -625,9 +602,9 @@ export function createRunCellTool(
|
|
|
625
602
|
notebookTracker?: INotebookTracker
|
|
626
603
|
): ITool {
|
|
627
604
|
return tool({
|
|
628
|
-
|
|
605
|
+
title: 'Run Cell',
|
|
629
606
|
description: 'Run a specific cell in the notebook by index',
|
|
630
|
-
|
|
607
|
+
inputSchema: z.object({
|
|
631
608
|
notebookPath: z
|
|
632
609
|
.string()
|
|
633
610
|
.optional()
|
|
@@ -649,85 +626,70 @@ export function createRunCellTool(
|
|
|
649
626
|
}) => {
|
|
650
627
|
const { notebookPath, cellIndex, recordTiming = true } = input;
|
|
651
628
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
const notebook = currentWidget.content;
|
|
668
|
-
const model = notebook.model;
|
|
629
|
+
const currentWidget = await getNotebookWidget(
|
|
630
|
+
notebookPath,
|
|
631
|
+
docManager,
|
|
632
|
+
notebookTracker
|
|
633
|
+
);
|
|
634
|
+
if (!currentWidget) {
|
|
635
|
+
return JSON.stringify({
|
|
636
|
+
success: false,
|
|
637
|
+
error: notebookPath
|
|
638
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
639
|
+
: 'No active notebook and no notebook path provided'
|
|
640
|
+
});
|
|
641
|
+
}
|
|
669
642
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
success: false,
|
|
673
|
-
error: 'No notebook model available'
|
|
674
|
-
});
|
|
675
|
-
}
|
|
643
|
+
const notebook = currentWidget.content;
|
|
644
|
+
const model = notebook.model;
|
|
676
645
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
646
|
+
if (!model) {
|
|
647
|
+
return JSON.stringify({
|
|
648
|
+
success: false,
|
|
649
|
+
error: 'No notebook model available'
|
|
650
|
+
});
|
|
651
|
+
}
|
|
683
652
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
});
|
|
691
|
-
}
|
|
653
|
+
if (cellIndex < 0 || cellIndex >= model.cells.length) {
|
|
654
|
+
return JSON.stringify({
|
|
655
|
+
success: false,
|
|
656
|
+
error: `Invalid cell index: ${cellIndex}. Notebook has ${model.cells.length} cells.`
|
|
657
|
+
});
|
|
658
|
+
}
|
|
692
659
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
// Use direct CodeCell.execute() method
|
|
697
|
-
const sessionCtx = currentWidget.sessionContext;
|
|
698
|
-
await CodeCell.execute(cellWidget, sessionCtx, {
|
|
699
|
-
recordTiming,
|
|
700
|
-
deletedCells: model.deletedCells
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
const codeModel = cellWidget.model as ICodeCellModel;
|
|
704
|
-
return JSON.stringify({
|
|
705
|
-
success: true,
|
|
706
|
-
message: `Cell ${cellIndex} executed successfully`,
|
|
707
|
-
cellIndex,
|
|
708
|
-
executionCount: codeModel.executionCount,
|
|
709
|
-
hasOutput: codeModel.outputs.length > 0
|
|
710
|
-
});
|
|
711
|
-
} else {
|
|
712
|
-
// For non-code cells, just return success
|
|
713
|
-
return JSON.stringify({
|
|
714
|
-
success: true,
|
|
715
|
-
message: `Cell ${cellIndex} is not a code cell, no execution needed`,
|
|
716
|
-
cellIndex,
|
|
717
|
-
cellType: cellWidget.model.type
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
} catch (error) {
|
|
721
|
-
return JSON.stringify({
|
|
722
|
-
success: false,
|
|
723
|
-
error: `Failed to execute cell: ${(error as Error).message}`,
|
|
724
|
-
cellIndex
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
} catch (error) {
|
|
660
|
+
// Get the target cell widget
|
|
661
|
+
const cellWidget = notebook.widgets[cellIndex];
|
|
662
|
+
if (!cellWidget) {
|
|
728
663
|
return JSON.stringify({
|
|
729
664
|
success: false,
|
|
730
|
-
error: `
|
|
665
|
+
error: `Cell widget at index ${cellIndex} not found`
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Execute using shared model approach (non-disruptive)
|
|
670
|
+
if (cellWidget instanceof CodeCell) {
|
|
671
|
+
// Use direct CodeCell.execute() method
|
|
672
|
+
const sessionCtx = currentWidget.sessionContext;
|
|
673
|
+
await CodeCell.execute(cellWidget, sessionCtx, {
|
|
674
|
+
recordTiming,
|
|
675
|
+
deletedCells: model.deletedCells
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
const codeModel = cellWidget.model as ICodeCellModel;
|
|
679
|
+
return JSON.stringify({
|
|
680
|
+
success: true,
|
|
681
|
+
message: `Cell ${cellIndex} executed successfully`,
|
|
682
|
+
cellIndex,
|
|
683
|
+
executionCount: codeModel.executionCount,
|
|
684
|
+
hasOutput: codeModel.outputs.length > 0
|
|
685
|
+
});
|
|
686
|
+
} else {
|
|
687
|
+
// For non-code cells, just return success
|
|
688
|
+
return JSON.stringify({
|
|
689
|
+
success: true,
|
|
690
|
+
message: `Cell ${cellIndex} is not a code cell, no execution needed`,
|
|
691
|
+
cellIndex,
|
|
692
|
+
cellType: cellWidget.model.type
|
|
731
693
|
});
|
|
732
694
|
}
|
|
733
695
|
}
|
|
@@ -742,9 +704,9 @@ export function createDeleteCellTool(
|
|
|
742
704
|
notebookTracker?: INotebookTracker
|
|
743
705
|
): ITool {
|
|
744
706
|
return tool({
|
|
745
|
-
|
|
707
|
+
title: 'Delete Cell',
|
|
746
708
|
description: 'Delete a specific cell from the notebook by index',
|
|
747
|
-
|
|
709
|
+
inputSchema: z.object({
|
|
748
710
|
notebookPath: z
|
|
749
711
|
.string()
|
|
750
712
|
.optional()
|
|
@@ -760,62 +722,55 @@ export function createDeleteCellTool(
|
|
|
760
722
|
}) => {
|
|
761
723
|
const { notebookPath, cellIndex } = input;
|
|
762
724
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
const notebook = currentWidget.content;
|
|
779
|
-
const model = notebook.model;
|
|
780
|
-
|
|
781
|
-
if (!model) {
|
|
782
|
-
return JSON.stringify({
|
|
783
|
-
success: false,
|
|
784
|
-
error: 'No notebook model available'
|
|
785
|
-
});
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
if (cellIndex < 0 || cellIndex >= model.cells.length) {
|
|
789
|
-
return JSON.stringify({
|
|
790
|
-
success: false,
|
|
791
|
-
error: `Invalid cell index: ${cellIndex}. Notebook has ${model.cells.length} cells.`
|
|
792
|
-
});
|
|
793
|
-
}
|
|
725
|
+
const currentWidget = await getNotebookWidget(
|
|
726
|
+
notebookPath,
|
|
727
|
+
docManager,
|
|
728
|
+
notebookTracker
|
|
729
|
+
);
|
|
730
|
+
if (!currentWidget) {
|
|
731
|
+
return JSON.stringify({
|
|
732
|
+
success: false,
|
|
733
|
+
error: notebookPath
|
|
734
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
735
|
+
: 'No active notebook and no notebook path provided'
|
|
736
|
+
});
|
|
737
|
+
}
|
|
794
738
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (!targetCell) {
|
|
798
|
-
return JSON.stringify({
|
|
799
|
-
success: false,
|
|
800
|
-
error: `Cell at index ${cellIndex} not found`
|
|
801
|
-
});
|
|
802
|
-
}
|
|
739
|
+
const notebook = currentWidget.content;
|
|
740
|
+
const model = notebook.model;
|
|
803
741
|
|
|
804
|
-
|
|
805
|
-
|
|
742
|
+
if (!model) {
|
|
743
|
+
return JSON.stringify({
|
|
744
|
+
success: false,
|
|
745
|
+
error: 'No notebook model available'
|
|
746
|
+
});
|
|
747
|
+
}
|
|
806
748
|
|
|
749
|
+
if (cellIndex < 0 || cellIndex >= model.cells.length) {
|
|
807
750
|
return JSON.stringify({
|
|
808
|
-
success:
|
|
809
|
-
|
|
810
|
-
cellIndex,
|
|
811
|
-
remainingCells: model.cells.length
|
|
751
|
+
success: false,
|
|
752
|
+
error: `Invalid cell index: ${cellIndex}. Notebook has ${model.cells.length} cells.`
|
|
812
753
|
});
|
|
813
|
-
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// Validate cell exists
|
|
757
|
+
const targetCell = model.cells.get(cellIndex);
|
|
758
|
+
if (!targetCell) {
|
|
814
759
|
return JSON.stringify({
|
|
815
760
|
success: false,
|
|
816
|
-
error: `
|
|
761
|
+
error: `Cell at index ${cellIndex} not found`
|
|
817
762
|
});
|
|
818
763
|
}
|
|
764
|
+
|
|
765
|
+
// Delete cell using shared model (non-disruptive)
|
|
766
|
+
model.sharedModel.deleteCell(cellIndex);
|
|
767
|
+
|
|
768
|
+
return JSON.stringify({
|
|
769
|
+
success: true,
|
|
770
|
+
message: `Cell ${cellIndex} deleted successfully`,
|
|
771
|
+
cellIndex,
|
|
772
|
+
remainingCells: model.cells.length
|
|
773
|
+
});
|
|
819
774
|
}
|
|
820
775
|
});
|
|
821
776
|
}
|
|
@@ -828,10 +783,10 @@ export function createExecuteActiveCellTool(
|
|
|
828
783
|
notebookTracker?: INotebookTracker
|
|
829
784
|
): ITool {
|
|
830
785
|
return tool({
|
|
831
|
-
|
|
786
|
+
title: 'Execute Active Cell',
|
|
832
787
|
description:
|
|
833
788
|
'Execute the currently active cell in the notebook without disrupting user focus',
|
|
834
|
-
|
|
789
|
+
inputSchema: z.object({
|
|
835
790
|
notebookPath: z
|
|
836
791
|
.string()
|
|
837
792
|
.optional()
|
|
@@ -856,76 +811,69 @@ export function createExecuteActiveCellTool(
|
|
|
856
811
|
}) => {
|
|
857
812
|
const { notebookPath, code, recordTiming = true } = input;
|
|
858
813
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
const notebook = currentWidget.content;
|
|
875
|
-
const model = notebook.model;
|
|
876
|
-
const activeCellIndex = notebook.activeCellIndex;
|
|
877
|
-
|
|
878
|
-
if (!model || activeCellIndex === -1) {
|
|
879
|
-
return JSON.stringify({
|
|
880
|
-
success: false,
|
|
881
|
-
error: 'No notebook model or active cell available'
|
|
882
|
-
});
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
const activeCell = model.cells.get(activeCellIndex);
|
|
886
|
-
if (!activeCell) {
|
|
887
|
-
return JSON.stringify({
|
|
888
|
-
success: false,
|
|
889
|
-
error: 'Active cell not found'
|
|
890
|
-
});
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
// Set code content if provided
|
|
894
|
-
if (code) {
|
|
895
|
-
activeCell.sharedModel.setSource(code);
|
|
896
|
-
}
|
|
814
|
+
const currentWidget = await getNotebookWidget(
|
|
815
|
+
notebookPath,
|
|
816
|
+
docManager,
|
|
817
|
+
notebookTracker
|
|
818
|
+
);
|
|
819
|
+
if (!currentWidget) {
|
|
820
|
+
return JSON.stringify({
|
|
821
|
+
success: false,
|
|
822
|
+
error: notebookPath
|
|
823
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
824
|
+
: 'No active notebook and no notebook path provided'
|
|
825
|
+
});
|
|
826
|
+
}
|
|
897
827
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
return JSON.stringify({
|
|
902
|
-
success: false,
|
|
903
|
-
error: 'Active cell is not a code cell'
|
|
904
|
-
});
|
|
905
|
-
}
|
|
828
|
+
const notebook = currentWidget.content;
|
|
829
|
+
const model = notebook.model;
|
|
830
|
+
const activeCellIndex = notebook.activeCellIndex;
|
|
906
831
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
deletedCells: model.deletedCells
|
|
832
|
+
if (!model || activeCellIndex === -1) {
|
|
833
|
+
return JSON.stringify({
|
|
834
|
+
success: false,
|
|
835
|
+
error: 'No notebook model or active cell available'
|
|
912
836
|
});
|
|
837
|
+
}
|
|
913
838
|
|
|
914
|
-
|
|
839
|
+
const activeCell = model.cells.get(activeCellIndex);
|
|
840
|
+
if (!activeCell) {
|
|
915
841
|
return JSON.stringify({
|
|
916
|
-
success:
|
|
917
|
-
|
|
918
|
-
cellIndex: activeCellIndex,
|
|
919
|
-
executionCount: codeModel.executionCount,
|
|
920
|
-
hasOutput: codeModel.outputs.length > 0,
|
|
921
|
-
code: code || activeCell.sharedModel.getSource()
|
|
842
|
+
success: false,
|
|
843
|
+
error: 'Active cell not found'
|
|
922
844
|
});
|
|
923
|
-
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Set code content if provided
|
|
848
|
+
if (code) {
|
|
849
|
+
activeCell.sharedModel.setSource(code);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Get the cell widget for execution
|
|
853
|
+
const cellWidget = notebook.widgets[activeCellIndex];
|
|
854
|
+
if (!cellWidget || !(cellWidget instanceof CodeCell)) {
|
|
924
855
|
return JSON.stringify({
|
|
925
856
|
success: false,
|
|
926
|
-
error:
|
|
857
|
+
error: 'Active cell is not a code cell'
|
|
927
858
|
});
|
|
928
859
|
}
|
|
860
|
+
|
|
861
|
+
// Execute using shared model approach (non-disruptive)
|
|
862
|
+
const sessionCtx = currentWidget.sessionContext;
|
|
863
|
+
await CodeCell.execute(cellWidget, sessionCtx, {
|
|
864
|
+
recordTiming,
|
|
865
|
+
deletedCells: model.deletedCells
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
const codeModel = cellWidget.model as ICodeCellModel;
|
|
869
|
+
return JSON.stringify({
|
|
870
|
+
success: true,
|
|
871
|
+
message: 'Code executed successfully in active cell',
|
|
872
|
+
cellIndex: activeCellIndex,
|
|
873
|
+
executionCount: codeModel.executionCount,
|
|
874
|
+
hasOutput: codeModel.outputs.length > 0,
|
|
875
|
+
code: code || activeCell.sharedModel.getSource()
|
|
876
|
+
});
|
|
929
877
|
}
|
|
930
878
|
});
|
|
931
879
|
}
|
|
@@ -938,9 +886,9 @@ export function createSaveNotebookTool(
|
|
|
938
886
|
notebookTracker?: INotebookTracker
|
|
939
887
|
): ITool {
|
|
940
888
|
return tool({
|
|
941
|
-
|
|
889
|
+
title: 'Save Notebook',
|
|
942
890
|
description: 'Save a specific notebook to disk',
|
|
943
|
-
|
|
891
|
+
inputSchema: z.object({
|
|
944
892
|
notebookPath: z
|
|
945
893
|
.string()
|
|
946
894
|
.optional()
|
|
@@ -952,35 +900,28 @@ export function createSaveNotebookTool(
|
|
|
952
900
|
execute: async (input: { notebookPath?: string | null }) => {
|
|
953
901
|
const { notebookPath } = input;
|
|
954
902
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
if (!currentWidget) {
|
|
962
|
-
return JSON.stringify({
|
|
963
|
-
success: false,
|
|
964
|
-
error: notebookPath
|
|
965
|
-
? `Failed to open notebook at path: ${notebookPath}`
|
|
966
|
-
: 'No active notebook and no notebook path provided'
|
|
967
|
-
});
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
await currentWidget.context.save();
|
|
971
|
-
|
|
972
|
-
return JSON.stringify({
|
|
973
|
-
success: true,
|
|
974
|
-
message: 'Notebook saved successfully',
|
|
975
|
-
notebookName: currentWidget.title.label,
|
|
976
|
-
notebookPath: currentWidget.context.path
|
|
977
|
-
});
|
|
978
|
-
} catch (error) {
|
|
903
|
+
const currentWidget = await getNotebookWidget(
|
|
904
|
+
notebookPath,
|
|
905
|
+
docManager,
|
|
906
|
+
notebookTracker
|
|
907
|
+
);
|
|
908
|
+
if (!currentWidget) {
|
|
979
909
|
return JSON.stringify({
|
|
980
910
|
success: false,
|
|
981
|
-
error:
|
|
911
|
+
error: notebookPath
|
|
912
|
+
? `Failed to open notebook at path: ${notebookPath}`
|
|
913
|
+
: 'No active notebook and no notebook path provided'
|
|
982
914
|
});
|
|
983
915
|
}
|
|
916
|
+
|
|
917
|
+
await currentWidget.context.save();
|
|
918
|
+
|
|
919
|
+
return JSON.stringify({
|
|
920
|
+
success: true,
|
|
921
|
+
message: 'Notebook saved successfully',
|
|
922
|
+
notebookName: currentWidget.title.label,
|
|
923
|
+
notebookPath: currentWidget.context.path
|
|
924
|
+
});
|
|
984
925
|
}
|
|
985
926
|
});
|
|
986
927
|
}
|