Skip to content

Commit a6f8e82

Browse files
authored
update todo list validation and add warnings for size and bulk updates (microsoft#264386)
1 parent 4f77078 commit a6f8e82

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

src/vs/workbench/contrib/chat/browser/chatContentParts/chatTodoListWidget.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export class ChatTodoListWidget extends Disposable {
118118
}
119119

120120
const todoList = this.chatTodoListService.getTodos(sessionId);
121-
if (todoList.length > 0) {
121+
if (todoList.length > 2) {
122122
this.renderTodoList(todoList);
123123
this.domNode.style.display = 'block';
124124
} else {

src/vs/workbench/contrib/chat/common/tools/manageTodoListTool.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

293329
type TodoListToolInvokedEvent = {

0 commit comments

Comments
 (0)