@@ -59,7 +59,9 @@ export function createManageTodoListToolData(writeOnly: boolean): IToolData {
5959 }
6060 } ;
6161
62- const requiredFields = [ 'todoList' ] ;
62+ // Only require the full todoList when operating in write-only mode.
63+ // In read/write mode, the write path validates todoList at runtime, so it's not schema-required.
64+ const requiredFields = writeOnly ? [ 'todoList' ] : [ ] as string [ ] ;
6365
6466 if ( ! writeOnly ) {
6567 baseProperties . operation = {
@@ -231,9 +233,25 @@ export class ManageTodoListTool extends Disposable implements IToolImpl {
231233 status : parsedTodo . status
232234 } ) ) ;
233235
236+ const existingTodos = this . chatTodoListService . getTodos ( chatSessionId ) ;
237+ const changes = this . calculateTodoChanges ( existingTodos , todoList ) ;
238+
234239 this . chatTodoListService . setTodos ( chatSessionId , todoList ) ;
235240 const statusCounts = this . calculateStatusCounts ( todoList ) ;
236241
242+ // Build warnings
243+ const warnings : string [ ] = [ ] ;
244+ if ( todoList . length < 3 ) {
245+ warnings . push ( 'Warning: Small todo list (<3 items). This task might not need a todo list.' ) ;
246+ }
247+ else if ( todoList . length > 10 ) {
248+ warnings . push ( 'Warning: Large todo list (>10 items). Consider keeping the list focused and actionable.' ) ;
249+ }
250+
251+ if ( changes > 3 ) {
252+ warnings . push ( 'Warning: Did you mean to update so many todos at the same time? Consider working on them one by one.' ) ;
253+ }
254+
237255 this . telemetryService . publicLog2 < TodoListToolInvokedEvent , TodoListToolInvokedClassification > (
238256 'todoListToolInvoked' ,
239257 {
@@ -248,7 +266,7 @@ export class ManageTodoListTool extends Disposable implements IToolImpl {
248266 return {
249267 content : [ {
250268 kind : 'text' ,
251- value : ' Successfully wrote todo list'
269+ value : ` Successfully wrote todo list${ warnings . length ? '\n\n' + warnings . join ( '\n' ) : '' } `
252270 } ]
253271 } ;
254272 }
@@ -288,6 +306,24 @@ export class ManageTodoListTool extends Disposable implements IToolImpl {
288306 return lines . join ( '\n' ) ;
289307 } ) . join ( '\n' ) ;
290308 }
309+
310+ private calculateTodoChanges ( oldList : IChatTodo [ ] , newList : IChatTodo [ ] ) : number {
311+ // Assume arrays are equivalent in order; compare index-by-index
312+ let modified = 0 ;
313+ const minLen = Math . min ( oldList . length , newList . length ) ;
314+ for ( let i = 0 ; i < minLen ; i ++ ) {
315+ const o = oldList [ i ] ;
316+ const n = newList [ i ] ;
317+ if ( o . title !== n . title || ( o . description ?? '' ) !== ( n . description ?? '' ) || o . status !== n . status ) {
318+ modified ++ ;
319+ }
320+ }
321+
322+ const added = Math . max ( 0 , newList . length - oldList . length ) ;
323+ const removed = Math . max ( 0 , oldList . length - newList . length ) ;
324+ const totalChanges = added + removed + modified ;
325+ return totalChanges ;
326+ }
291327}
292328
293329type TodoListToolInvokedEvent = {
0 commit comments