@@ -250,6 +250,8 @@ export interface SerializedNotebookContext {
250250 contextNote : string ;
251251 /** Full wrapped context (if wrapInNotebookContext is true) */
252252 fullContext ?: string ;
253+ /** Whether this serialized context represents a full notebook (true) or a windowed context (false). Undefined when allCellsInfo is not present. */
254+ isFullNotebookContext ?: boolean ;
253255}
254256
255257/**
@@ -272,6 +274,13 @@ export function serializeNotebookContext(
272274 // Get all cells from context (may already be filtered)
273275 const allCells = context . allCells || [ ] ;
274276 const totalCells = context . cellCount ;
277+ const canIncludeFullNotebook = totalCells < MAX_CELLS_FOR_ALL_CELLS_CONTEXT ;
278+
279+ // Helper function to find executed cells (used in multiple places)
280+ const getExecutedCells = ( cells : positron . notebooks . NotebookCell [ ] ) => {
281+ const codeCells = cells . filter ( c => c . type === positron . notebooks . NotebookCellType . Code ) ;
282+ return codeCells . filter ( c => c . executionOrder !== undefined ) ;
283+ } ;
275284
276285 // Determine anchor index for sliding window if not provided
277286 let effectiveAnchorIndex : number ;
@@ -282,8 +291,7 @@ export function serializeNotebookContext(
282291 effectiveAnchorIndex = Math . max ( ...context . selectedCells . map ( cell => cell . index ) ) ;
283292 } else {
284293 // Try to find last executed cell
285- const codeCells = allCells . filter ( c => c . type === positron . notebooks . NotebookCellType . Code ) ;
286- const executedCells = codeCells . filter ( c => c . executionOrder !== undefined ) ;
294+ const executedCells = getExecutedCells ( allCells ) ;
287295 if ( executedCells . length > 0 ) {
288296 effectiveAnchorIndex = Math . max ( ...executedCells . map ( c => c . index ) ) ;
289297 } else {
@@ -295,21 +303,20 @@ export function serializeNotebookContext(
295303 // Apply filtering logic to determine which cells to include
296304 let cellsToInclude : positron . notebooks . NotebookCell [ ] ;
297305
298- if ( totalCells < MAX_CELLS_FOR_ALL_CELLS_CONTEXT ) {
306+ if ( canIncludeFullNotebook ) {
299307 // Small notebooks: include all cells
300308 cellsToInclude = allCells . length > 0 ? allCells : [ ] ;
301309 } else if ( context . selectedCells . length === 0 && allCells . length === 0 ) {
302310 // Large notebooks without selection and no allCells: no cells to include
303311 cellsToInclude = [ ] ;
304312 } else if ( context . selectedCells . length === 0 ) {
305313 // Large notebooks without selection: use sliding window around executed cells
306- const codeCells = allCells . filter ( c => c . type === positron . notebooks . NotebookCellType . Code ) ;
307- const executedCells = codeCells . filter ( c => c . executionOrder !== undefined ) ;
314+ const executedCells = getExecutedCells ( allCells ) ;
308315 if ( executedCells . length > 0 || effectiveAnchorIndex !== 0 ) {
309316 const { startIndex, endIndex } = calculateSlidingWindow ( allCells . length , effectiveAnchorIndex ) ;
310317 cellsToInclude = allCells . slice ( startIndex , endIndex ) ;
311318 } else {
312- // No executed cells, use first 20 cells
319+ // No executed cells, use first MAX_CELLS_FOR_ALL_CELLS_CONTEXT cells
313320 cellsToInclude = allCells . slice ( 0 , MAX_CELLS_FOR_ALL_CELLS_CONTEXT ) ;
314321 }
315322 } else {
@@ -344,8 +351,7 @@ export function serializeNotebookContext(
344351 let allCellsInfo : string | undefined ;
345352 let formattedCells : string | undefined ;
346353 if ( cellsToInclude . length > 0 ) {
347- const isFullNotebook = context . cellCount < 20 ;
348- const description = isFullNotebook
354+ const description = canIncludeFullNotebook
349355 ? 'All cells in notebook (notebook has fewer than 20 cells)'
350356 : 'Context window around selected/recent cells (notebook has 20+ cells)' ;
351357 // Format cells once and reuse
@@ -358,7 +364,7 @@ export function serializeNotebookContext(
358364 // Generate context note XML
359365 let contextNote : string ;
360366 if ( cellsToInclude . length > 0 ) {
361- if ( context . cellCount < 20 ) {
367+ if ( canIncludeFullNotebook ) {
362368 contextNote = xml . node ( 'note' , 'All cells are provided above because this notebook has fewer than 20 cells.' ) ;
363369 } else {
364370 contextNote = xml . node ( 'note' , 'A context window around the selected/recent cells is provided above. Use the GetNotebookCells tool to retrieve additional cells by index when needed.' ) ;
@@ -373,13 +379,13 @@ export function serializeNotebookContext(
373379 cellCountInfo,
374380 selectedCellsInfo,
375381 allCellsInfo,
376- contextNote
382+ contextNote,
383+ isFullNotebookContext : allCellsInfo ? canIncludeFullNotebook : undefined
377384 } ;
378385
379386 // Optionally wrap in notebook-context node
380387 if ( wrapInNotebookContext ) {
381- const isFullNotebook = context . cellCount < 20 ;
382- const contextMode = isFullNotebook
388+ const contextMode = canIncludeFullNotebook
383389 ? 'Full notebook (< 20 cells, all cells provided below)'
384390 : 'Context window around selected/recent cells (notebook has 20+ cells)' ;
385391
@@ -601,9 +607,9 @@ export function serializeNotebookContextAsUserMessage(
601607
602608 // Determine context mode based on whether allCellsInfo exists
603609 if ( context . allCellsInfo ) {
604- // Check if this is a full notebook or windowed context by examining the allCellsInfo
605- const isFullNotebook = context . allCellsInfo . includes ( 'fewer than 20 cells' ) ;
606- const contextMode = isFullNotebook
610+ // Use explicit isFullNotebookContext field instead of parsing XML
611+ const isFullNotebookContext = context . isFullNotebookContext === true ;
612+ const contextMode = isFullNotebookContext
607613 ? 'Full notebook (< 20 cells, all cells provided below)'
608614 : 'Context window around selected/recent cells (notebook has 20+ cells)' ;
609615 parts . push ( xml . node ( 'context-mode' , contextMode ) ) ;
0 commit comments