1414
1515
1616class DeleteCellTool (BaseTool ):
17- """Tool to delete a specific cell from a notebook."""
17+ """Tool to delete specific cells from a notebook."""
1818
1919 def _get_cell_source (self , cell : Any ) -> str :
2020 """Get the cell source from the cell"""
@@ -28,102 +28,98 @@ async def _delete_cell_ydoc(
2828 self ,
2929 serverapp : Any ,
3030 notebook_path : str ,
31- cell_index : int
32- ) -> dict :
31+ cell_indices : list [ int ]
32+ ) -> list :
3333 """Delete cell using YDoc (collaborative editing mode).
3434
3535 Args:
3636 serverapp: Jupyter ServerApp instance
3737 notebook_path: Path to the notebook
38- cell_index: Index of cell to delete
38+ cell_indices: List of indices of cells to delete
3939
4040 Returns:
4141 NotebookNode
4242 """
4343 nb = await get_notebook_model (serverapp , notebook_path )
4444 if nb :
45- if cell_index >= len (nb ):
45+ if max ( cell_indices ) >= len (nb ):
4646 raise ValueError (
47- f"Cell index { cell_index } is out of range. Notebook has { len (nb )} cells."
47+ f"Cell index { max ( cell_indices ) } is out of range. Notebook has { len (nb )} cells."
4848 )
4949
50- cell = nb .delete_cell (cell_index )
51- return {
52- "index" : cell_index ,
53- "cell_type" : cell .cell_type ,
54- "source" : self ._get_cell_source (cell ),
55- }
50+ cells = nb .delete_many_cells (cell_indices )
51+ return cells
5652 else :
5753 # YDoc not available, use file operations
58- return await self ._delete_cell_file (notebook_path , cell_index )
54+ return await self ._delete_cell_file (notebook_path , cell_indices )
5955
6056 async def _delete_cell_file (
6157 self ,
6258 notebook_path : str ,
63- cell_index : int
64- ) -> dict :
59+ cell_indices : list [ int ]
60+ ) -> list :
6561 """Delete cell using file operations (non-collaborative mode).
6662
6763 Args:
6864 notebook_path: Absolute path to the notebook
69- cell_index: Index of cell to delete
65+ cell_indices: List of indices of cells to delete
7066
7167 Returns:
72- Success message
68+ List of deleted cells
7369 """
7470 # Read notebook file as version 4 for consistency
7571 with open (notebook_path , "r" , encoding = "utf-8" ) as f :
7672 notebook = nbformat .read (f , as_version = 4 )
7773
7874 clean_notebook_outputs (notebook )
7975
80- if cell_index >= len (notebook .cells ):
76+ if max ( cell_indices ) >= len (notebook .cells ):
8177 raise ValueError (
82- f"Cell index { cell_index } is out of range. Notebook has { len (notebook .cells )} cells."
78+ f"Cell index { max ( cell_indices ) } is out of range. Notebook has { len (notebook .cells )} cells."
8379 )
8480
85- cell = notebook .cells [cell_index ]
86- result = {
87- "index" : cell_index ,
88- "cell_type" : cell .cell_type ,
89- "source" : self ._get_cell_source (cell ),
90- }
81+ deleted_cells = []
82+ for cell_index in cell_indices :
83+ cell = notebook .cells [cell_index ]
84+ result = {
85+ "index" : cell_index ,
86+ "cell_type" : cell .cell_type ,
87+ "source" : self ._get_cell_source (cell ),
88+ }
89+ deleted_cells .append (result )
9190
9291 # Delete the cell
93- notebook .cells .pop (cell_index )
92+ for cell_index in sorted (cell_indices , reverse = True ):
93+ notebook .cells .pop (cell_index )
9494
9595 # Write back to file
9696 with open (notebook_path , "w" , encoding = "utf-8" ) as f :
9797 nbformat .write (notebook , f )
9898
99- return result
99+ return deleted_cells
100100
101101 async def _delete_cell_websocket (
102102 self ,
103103 notebook_manager : NotebookManager ,
104- cell_index : int
105- ) -> dict :
104+ cell_indices : list [ int ]
105+ ) -> list :
106106 """Delete cell using WebSocket connection (MCP_SERVER mode).
107107
108108 Args:
109109 notebook_manager: Notebook manager instance
110- cell_index: Index of cell to delete
110+ cell_indices: List of indices of cells to delete
111111
112112 Returns:
113- Success message
113+ List of deleted cell information
114114 """
115115 async with notebook_manager .get_current_connection () as notebook :
116- if cell_index >= len (notebook ):
116+ if max ( cell_indices ) >= len (notebook ):
117117 raise ValueError (
118- f"Cell index { cell_index } is out of range. Notebook has { len (notebook )} cells."
118+ f"Cell index { max ( cell_indices ) } is out of range. Notebook has { len (notebook )} cells."
119119 )
120120
121- cell = notebook .delete_cell (cell_index )
122- return {
123- "index" : cell_index ,
124- "cell_type" : cell .cell_type ,
125- "source" : self ._get_cell_source (cell ),
126- }
121+ cells = notebook .delete_many_cells (cell_indices )
122+ return cells
127123
128124 async def execute (
129125 self ,
@@ -135,7 +131,8 @@ async def execute(
135131 kernel_spec_manager : Optional [Any ] = None ,
136132 notebook_manager : Optional [NotebookManager ] = None ,
137133 # Tool-specific parameters
138- cell_index : int = None ,
134+ cell_indices : list [int ] = None ,
135+ include_source : bool = True ,
139136 ** kwargs
140137 ) -> str :
141138 """Execute the delete_cell tool.
@@ -181,17 +178,22 @@ async def execute(
181178
182179 if serverapp :
183180 # Try YDoc approach first
184- cell_info = await self ._delete_cell_ydoc (serverapp , notebook_path , cell_index )
181+ cells = await self ._delete_cell_ydoc (serverapp , notebook_path , cell_indices )
185182 else :
186183 # Fall back to file operations
187- cell_info = await self ._delete_cell_file (notebook_path , cell_index )
184+ cells = await self ._delete_cell_file (notebook_path , cell_indices )
188185
189186 elif mode == ServerMode .MCP_SERVER and notebook_manager is not None :
190187 # MCP_SERVER mode: Use WebSocket connection
191- cell_info = await self ._delete_cell_websocket (notebook_manager , cell_index )
188+ cells = await self ._delete_cell_websocket (notebook_manager , cell_indices )
192189 else :
193190 raise ValueError (f"Invalid mode or missing required clients: mode={ mode } " )
194191
195- info_list = [f"Cell { cell_info ['index' ]} ({ cell_info ['cell_type' ]} ) deleted successfully." ]
196- info_list .append (f"deleted cell source:\n { cell_info ['source' ]} " )
192+ info_list = []
193+ for cell_index , cell_info in zip (cell_indices , cells ):
194+ info_list .append (f"Cell { cell_index } ({ cell_info ['cell_type' ]} ) deleted successfully." )
195+ if include_source :
196+ info_list .append (f"deleted cell source:\n { cell_info ['source' ]} " )
197+ info_list .append ("\n ---\n " )
198+
197199 return "\n " .join (info_list )
0 commit comments