Skip to content
This repository was archived by the owner on May 20, 2026. It is now read-only.

Commit 0eaf799

Browse files
authored
Clear tools if there aren't any tools in the request (#4601)
1 parent 18c897b commit 0eaf799

2 files changed

Lines changed: 113 additions & 2 deletions

File tree

src/extension/chatSessions/vscode-node/copilotCLIChatSessionsContribution.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1754,7 +1754,10 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
17541754
if (agentInRequest) {
17551755
const customAgent = await this.copilotCLIAgents.resolveAgent(agentInRequest);
17561756
if (customAgent) {
1757-
customAgent.tools = (request.modeInstructions2.toolReferences || []).map(t => t.name);
1757+
const tools = (request.modeInstructions2.toolReferences || []).map(t => t.name);
1758+
if (tools.length > 0) {
1759+
customAgent.tools = tools;
1760+
}
17581761
return customAgent;
17591762
}
17601763
}

src/extension/chatSessions/vscode-node/test/copilotCLIChatSessionParticipant.spec.ts

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { Attachment, SessionOptions } from '@github/copilot/sdk';
6+
import { Attachment, SessionOptions, SweCustomAgent } from '@github/copilot/sdk';
77
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
88
import * as vscode from 'vscode';
99
import { Uri } from 'vscode';
@@ -1861,4 +1861,112 @@ describe('CopilotCLIChatSessionParticipant.handleRequest', () => {
18611861
);
18621862
});
18631863
});
1864+
1865+
describe('agent tool references via modeInstructions2', () => {
1866+
class MockCopilotCLIAgentsWithCustomAgent extends NullCopilotCLIAgents {
1867+
constructor(private readonly agentTools: string[] | null) {
1868+
super();
1869+
}
1870+
override resolveAgent(agentId: string): Promise<SweCustomAgent | undefined> {
1871+
if (agentId === 'custom-agent') {
1872+
return Promise.resolve({
1873+
name: 'custom-agent',
1874+
displayName: 'Custom Agent',
1875+
description: 'A test agent',
1876+
tools: this.agentTools,
1877+
prompt: async () => 'System prompt',
1878+
disableModelInvocation: false,
1879+
});
1880+
}
1881+
return Promise.resolve(undefined);
1882+
}
1883+
}
1884+
1885+
function makeParticipantWithAgents(agents: MockCopilotCLIAgentsWithCustomAgent): CopilotCLIChatSessionParticipant {
1886+
const nullDelegationService = new class extends mock<IChatDelegationSummaryService>() {
1887+
override async summarize(_context: vscode.ChatContext, _token: vscode.CancellationToken): Promise<string | undefined> {
1888+
return undefined;
1889+
}
1890+
}();
1891+
return new CopilotCLIChatSessionParticipant(
1892+
contentProvider,
1893+
promptResolver,
1894+
itemProvider,
1895+
cloudProvider,
1896+
repositoryTracker,
1897+
git,
1898+
models as unknown as ICopilotCLIModels,
1899+
agents,
1900+
sessionService,
1901+
worktree,
1902+
worktreeCheckpointService,
1903+
workspaceFolderService,
1904+
telemetry,
1905+
logService,
1906+
new PromptsServiceImpl(new NullWorkspaceService()),
1907+
nullDelegationService,
1908+
folderRepositoryManager,
1909+
configurationService,
1910+
sdk,
1911+
new MockChatSessionMetadataStore(),
1912+
customSessionTitleService,
1913+
new (mock<IOctoKitService>())(),
1914+
);
1915+
}
1916+
1917+
it('preserves agent tools when modeInstructions2 has no tool references', async () => {
1918+
const agentParticipant = makeParticipantWithAgents(new MockCopilotCLIAgentsWithCustomAgent(['original-tool']));
1919+
const createSessionSpy = vi.spyOn(sessionService, 'createSession');
1920+
1921+
const request = new TestChatRequest('Do something');
1922+
(request as any).modeInstructions2 = { name: 'custom-agent', content: 'agent content' };
1923+
const context = createChatContext('temp-new', true);
1924+
const stream = new MockChatResponseStream();
1925+
const token = disposables.add(new CancellationTokenSource()).token;
1926+
1927+
await agentParticipant.createHandler()(request, context, stream, token);
1928+
1929+
expect(createSessionSpy).toHaveBeenCalled();
1930+
const { agent } = createSessionSpy.mock.calls[0][0];
1931+
expect(agent?.tools).toEqual(['original-tool']);
1932+
});
1933+
1934+
it('overrides agent tools when modeInstructions2 provides tool references', async () => {
1935+
const agentParticipant = makeParticipantWithAgents(new MockCopilotCLIAgentsWithCustomAgent(['original-tool']));
1936+
const createSessionSpy = vi.spyOn(sessionService, 'createSession');
1937+
1938+
const request = new TestChatRequest('Do something');
1939+
(request as any).modeInstructions2 = {
1940+
name: 'custom-agent',
1941+
content: 'agent content',
1942+
toolReferences: [{ name: 'override-tool-1' }, { name: 'override-tool-2' }],
1943+
};
1944+
const context = createChatContext('temp-new', true);
1945+
const stream = new MockChatResponseStream();
1946+
const token = disposables.add(new CancellationTokenSource()).token;
1947+
1948+
await agentParticipant.createHandler()(request, context, stream, token);
1949+
1950+
expect(createSessionSpy).toHaveBeenCalled();
1951+
const { agent } = createSessionSpy.mock.calls[0][0];
1952+
expect(agent?.tools).toEqual(['override-tool-1', 'override-tool-2']);
1953+
});
1954+
1955+
it('preserves null tools when modeInstructions2 has no tool references', async () => {
1956+
const agentParticipant = makeParticipantWithAgents(new MockCopilotCLIAgentsWithCustomAgent(null));
1957+
const createSessionSpy = vi.spyOn(sessionService, 'createSession');
1958+
1959+
const request = new TestChatRequest('Do something');
1960+
(request as any).modeInstructions2 = { name: 'custom-agent', content: 'agent content' };
1961+
const context = createChatContext('temp-new', true);
1962+
const stream = new MockChatResponseStream();
1963+
const token = disposables.add(new CancellationTokenSource()).token;
1964+
1965+
await agentParticipant.createHandler()(request, context, stream, token);
1966+
1967+
expect(createSessionSpy).toHaveBeenCalled();
1968+
const { agent } = createSessionSpy.mock.calls[0][0];
1969+
expect(agent?.tools).toBeNull();
1970+
});
1971+
});
18641972
});

0 commit comments

Comments
 (0)