Skip to content

Commit ce749f9

Browse files
authored
fix: update presentation logic for ManageTodoListTool invocation (#311455)
Add presentation property to ManageTodoListTool invocation response
1 parent 79612fb commit ce749f9

File tree

2 files changed

+91
-3
lines changed

2 files changed

+91
-3
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import {
1515
IToolResult,
1616
ToolDataSource,
1717
IToolInvocationPreparationContext,
18-
IPreparedToolInvocation
18+
IPreparedToolInvocation,
19+
ToolInvocationPresentation
1920
} from '../languageModelToolsService.js';
2021
import { ILogService } from '../../../../../../platform/log/common/log.js';
2122
import { ITelemetryService } from '../../../../../../platform/telemetry/common/telemetry.js';
@@ -162,6 +163,7 @@ export class ManageTodoListTool extends Disposable implements IToolImpl {
162163

163164
return {
164165
invocationMessage,
166+
presentation: items.length ? undefined : ToolInvocationPresentation.Hidden,
165167
pastTenseMessage: new MarkdownString(message ?? localize('todo.updatedList', "Updated todo list")),
166168
toolSpecificData: {
167169
kind: 'todoList',

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

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import assert from 'assert';
7+
import { CancellationToken } from '../../../../../../../base/common/cancellation.js';
8+
import { Event } from '../../../../../../../base/common/event.js';
9+
import { URI } from '../../../../../../../base/common/uri.js';
710
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js';
8-
import { createManageTodoListToolData } from '../../../../common/tools/builtinTools/manageTodoListTool.js';
9-
import { IToolData } from '../../../../common/tools/languageModelToolsService.js';
11+
import { NullLogService } from '../../../../../../../platform/log/common/log.js';
12+
import { NullTelemetryService } from '../../../../../../../platform/telemetry/common/telemetryUtils.js';
13+
import { createManageTodoListToolData, ManageTodoListTool } from '../../../../common/tools/builtinTools/manageTodoListTool.js';
14+
import { IChatTodo, IChatTodoListService } from '../../../../common/tools/chatTodoListService.js';
15+
import { IToolData, ToolInvocationPresentation } from '../../../../common/tools/languageModelToolsService.js';
1016
import { IJSONSchema } from '../../../../../../../base/common/jsonSchema.js';
1117

1218
suite('ManageTodoListTool Schema', () => {
@@ -59,3 +65,83 @@ suite('ManageTodoListTool Schema', () => {
5965
assert.deepStrictEqual(statusProperty.enum, ['not-started', 'in-progress', 'completed'], 'Status should have correct enum values');
6066
});
6167
});
68+
69+
suite('ManageTodoListTool prepareToolInvocation', () => {
70+
const store = ensureNoDisposablesAreLeakedInTestSuite();
71+
const sessionResource = URI.parse('vscode-chat://session/1');
72+
73+
function createMockTodoListService(todos: IChatTodo[] = []): IChatTodoListService {
74+
return {
75+
_serviceBrand: undefined,
76+
onDidUpdateTodos: Event.None,
77+
getTodos: () => todos,
78+
setTodos: () => { },
79+
migrateTodos: () => { },
80+
};
81+
}
82+
83+
function createTool(todos: IChatTodo[] = []): ManageTodoListTool {
84+
return store.add(new ManageTodoListTool(
85+
createMockTodoListService(todos),
86+
new NullLogService(),
87+
NullTelemetryService,
88+
));
89+
}
90+
91+
test('presentation is Hidden when todoList param is empty', async () => {
92+
const tool = createTool();
93+
const result = await tool.prepareToolInvocation({
94+
parameters: { todoList: [] },
95+
toolCallId: 'call-1',
96+
chatSessionResource: sessionResource,
97+
}, CancellationToken.None);
98+
99+
assert.strictEqual(result?.presentation, ToolInvocationPresentation.Hidden);
100+
});
101+
102+
test('presentation is undefined when todoList param has items', async () => {
103+
const tool = createTool();
104+
const result = await tool.prepareToolInvocation({
105+
parameters: {
106+
todoList: [{ id: 1, title: 'Task 1', status: 'not-started' }],
107+
},
108+
toolCallId: 'call-1',
109+
chatSessionResource: sessionResource,
110+
}, CancellationToken.None);
111+
112+
assert.strictEqual(result?.presentation, undefined);
113+
});
114+
115+
test('presentation is Hidden for read operation with no existing todos', async () => {
116+
const tool = createTool([]);
117+
const result = await tool.prepareToolInvocation({
118+
parameters: { operation: 'read' },
119+
toolCallId: 'call-1',
120+
chatSessionResource: sessionResource,
121+
}, CancellationToken.None);
122+
123+
assert.strictEqual(result?.presentation, ToolInvocationPresentation.Hidden);
124+
});
125+
126+
test('presentation is undefined for read operation with existing todos', async () => {
127+
const tool = createTool([{ id: 1, title: 'Existing', status: 'in-progress' }]);
128+
const result = await tool.prepareToolInvocation({
129+
parameters: { operation: 'read' },
130+
toolCallId: 'call-1',
131+
chatSessionResource: sessionResource,
132+
}, CancellationToken.None);
133+
134+
assert.strictEqual(result?.presentation, undefined);
135+
});
136+
137+
test('returns undefined when no chatSessionResource is provided', async () => {
138+
const tool = createTool();
139+
const result = await tool.prepareToolInvocation({
140+
parameters: { todoList: [{ id: 1, title: 'Task', status: 'not-started' }] },
141+
toolCallId: 'call-1',
142+
chatSessionResource: undefined,
143+
}, CancellationToken.None);
144+
145+
assert.strictEqual(result, undefined);
146+
});
147+
});

0 commit comments

Comments
 (0)