Skip to content

Commit e9d8794

Browse files
authored
feat(CopilotCLI): support reasoning effort (#308951)
* feat(CopilotCLI): support reasoning effort * Enable reasoning effort for Copilot CLI
1 parent 05d42a2 commit e9d8794

File tree

3 files changed

+34
-16
lines changed

3 files changed

+34
-16
lines changed

extensions/copilot/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4582,7 +4582,7 @@
45824582
},
45834583
"github.copilot.chat.cli.thinkingEffort.enabled": {
45844584
"type": "boolean",
4585-
"default": false,
4585+
"default": true,
45864586
"markdownDescription": "%github.copilot.config.cli.thinkingEffort.enabled%",
45874587
"tags": [
45884588
"advanced"

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

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import { emptyWorkspaceInfo, getWorkingDirectory, isIsolationEnabled, IWorkspace
4444
import { ICustomSessionTitleService } from '../copilotcli/common/customSessionTitleService';
4545
import { IChatDelegationSummaryService } from '../copilotcli/common/delegationSummaryService';
4646
import { getCopilotCLISessionDir } from '../copilotcli/node/cliHelpers';
47-
import { ICopilotCLIAgents, ICopilotCLIModels, ICopilotCLISDK, isWelcomeView } from '../copilotcli/node/copilotCli';
47+
import { COPILOT_CLI_REASONING_EFFORT_PROPERTY, ICopilotCLIAgents, ICopilotCLIModels, ICopilotCLISDK, isWelcomeView } from '../copilotcli/node/copilotCli';
4848
import { CopilotCLIPromptResolver } from '../copilotcli/node/copilotcliPromptResolver';
4949
import { builtinSlashSCommands, CopilotCLICommand, copilotCLICommands, ICopilotCLISession } from '../copilotcli/node/copilotcliSession';
5050
import { ICopilotCLISessionItem, ICopilotCLISessionService } from '../copilotcli/node/copilotcliSessionService';
@@ -447,6 +447,10 @@ function isIsolationOptionFeatureEnabled(configurationService: IConfigurationSer
447447
return configurationService.getConfig(ConfigKey.Advanced.CLIIsolationOption);
448448
}
449449

450+
function isReasoningEffortFeatureEnabled(configurationService: IConfigurationService): boolean {
451+
return configurationService.getConfig(ConfigKey.Advanced.CLIThinkingEffortEnabled);
452+
}
453+
450454
export class CopilotCLIChatSessionContentProvider extends Disposable implements vscode.ChatSessionContentProvider {
451455
private readonly _onDidChangeChatSessionOptions = this._register(new Emitter<vscode.ChatSessionOptionChangeEvent>());
452456
readonly onDidChangeChatSessionOptions = this._onDidChangeChatSessionOptions.event;
@@ -1349,23 +1353,23 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
13491353
// This is a request that was created in createCLISessionAndSubmitRequest with attachments already resolved.
13501354
const { prompt, attachments } = contextForRequest;
13511355
this.contextForRequest.delete(session.object.sessionId);
1352-
await session.object.handleRequest(request, { prompt }, attachments, model ? { model } : undefined, authInfo, token);
1356+
await session.object.handleRequest(request, { prompt }, attachments, model, authInfo, token);
13531357
await this.commitWorktreeChangesIfNeeded(request, session.object, token);
13541358
} else if (request.command && !request.prompt && !isUntitled) {
13551359
const input = (copilotCLICommands as readonly string[]).includes(request.command)
13561360
? { command: request.command as CopilotCLICommand, prompt: '' }
13571361
: { prompt: `/${request.command}` };
1358-
await session.object.handleRequest(request, input, [], model ? { model } : undefined, authInfo, token);
1362+
await session.object.handleRequest(request, input, [], model, authInfo, token);
13591363
await this.commitWorktreeChangesIfNeeded(request, session.object, token);
13601364
} else if (request.prompt && Object.values(builtinSlashSCommands).some(command => request.prompt.startsWith(command))) {
13611365
// Sessions app built-in slash commands
13621366
const { prompt, attachments } = await this.promptResolver.resolvePrompt(request, undefined, [], session.object.workspace, [], token);
1363-
await session.object.handleRequest(request, { prompt }, attachments, model ? { model } : undefined, authInfo, token);
1367+
await session.object.handleRequest(request, { prompt }, attachments, model, authInfo, token);
13641368
await this.commitWorktreeChangesIfNeeded(request, session.object, token);
13651369
} else {
13661370
// Construct the full prompt with references to be sent to CLI.
13671371
const { prompt, attachments } = await this.promptResolver.resolvePrompt(request, undefined, [], session.object.workspace, [], token);
1368-
await session.object.handleRequest(request, { prompt }, attachments, model ? { model } : undefined, authInfo, token);
1372+
await session.object.handleRequest(request, { prompt }, attachments, model, authInfo, token);
13691373
await this.commitWorktreeChangesIfNeeded(request, session.object, token);
13701374
}
13711375

@@ -1671,7 +1675,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
16711675
}
16721676
}
16731677

1674-
private async getOrCreateSession(request: vscode.ChatRequest, chatSessionContext: vscode.ChatSessionContext, stream: vscode.ChatResponseStream, options: { model: string | undefined; agent: SweCustomAgent | undefined }, disposables: DisposableStore, token: vscode.CancellationToken): Promise<{ session: IReference<ICopilotCLISession> | undefined; trusted: boolean }> {
1678+
private async getOrCreateSession(request: vscode.ChatRequest, chatSessionContext: vscode.ChatSessionContext, stream: vscode.ChatResponseStream, options: { model: { model: string; reasoningEffort?: string } | undefined; agent: SweCustomAgent | undefined }, disposables: DisposableStore, token: vscode.CancellationToken): Promise<{ session: IReference<ICopilotCLISession> | undefined; trusted: boolean }> {
16751679
const { resource } = chatSessionContext.chatSessionItem;
16761680
const existingSessionId = this.sessionItemProvider.untitledSessionIdMapping.get(SessionIdForCLI.parse(resource));
16771681
const id = existingSessionId ?? SessionIdForCLI.parse(resource);
@@ -1689,8 +1693,8 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
16891693
const debugTargetSessionIds = extractDebugTargetSessionIds(request.references);
16901694
const mcpServerMappings = buildMcpServerMappings(request.tools);
16911695
const session = isNewSession ?
1692-
await this.sessionService.createSession({ model, workspace: workspaceInfo, agent, debugTargetSessionIds, mcpServerMappings }, token) :
1693-
await this.sessionService.getSession({ sessionId: id, model, workspace: workspaceInfo, agent, debugTargetSessionIds, mcpServerMappings }, token);
1696+
await this.sessionService.createSession({ model: model?.model, reasoningEffort: model?.reasoningEffort, workspace: workspaceInfo, agent, debugTargetSessionIds, mcpServerMappings }, token) :
1697+
await this.sessionService.getSession({ sessionId: id, model: model?.model, reasoningEffort: model?.reasoningEffort, workspace: workspaceInfo, agent, debugTargetSessionIds, mcpServerMappings }, token);
16941698
this.sessionItemProvider.notifySessionsChange();
16951699
// TODO @DonJayamanne We need to refresh to add this new session, but we need a label.
16961700
// So when creating a session we need a dummy label (or an initial prompt).
@@ -1718,15 +1722,29 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
17181722
return { session, trusted };
17191723
}
17201724

1721-
private async getModelId(request: vscode.ChatRequest | undefined, token: vscode.CancellationToken): Promise<string | undefined> {
1725+
private async getModelId(request: vscode.ChatRequest | undefined, token: vscode.CancellationToken): Promise<{ model: string; reasoningEffort?: string } | undefined> {
17221726
const promptFile = request ? await this.getPromptInfoFromRequest(request, token) : undefined;
17231727
const model = promptFile?.header?.model ? await getModelFromPromptFile(promptFile.header.model, this.copilotCLIModels) : undefined;
1724-
if (model || token.isCancellationRequested) {
1725-
return model;
1728+
if (token.isCancellationRequested) {
1729+
return undefined;
1730+
}
1731+
if (model) {
1732+
return { model };
17261733
}
17271734
// Get model from request.
17281735
const preferredModelInRequest = request?.model?.id ? await this.copilotCLIModels.resolveModel(request.model.id) : undefined;
1729-
return preferredModelInRequest ?? await this.copilotCLIModels.getDefaultModel();
1736+
if (preferredModelInRequest) {
1737+
const reasoningEffort = isReasoningEffortFeatureEnabled(this.configurationService) ? request?.modelConfiguration?.[COPILOT_CLI_REASONING_EFFORT_PROPERTY] : undefined;
1738+
return {
1739+
model: preferredModelInRequest,
1740+
reasoningEffort: typeof reasoningEffort === 'string' && reasoningEffort ? reasoningEffort : undefined
1741+
};
1742+
}
1743+
const defaultModel = await this.copilotCLIModels.getDefaultModel();
1744+
if (!defaultModel) {
1745+
return undefined;
1746+
}
1747+
return { model: defaultModel };
17301748
}
17311749

17321750
private async handleDelegationToCloud(session: ICopilotCLISession, request: vscode.ChatRequest, context: vscode.ChatContext, stream: vscode.ChatResponseStream, token: vscode.CancellationToken) {
@@ -1835,7 +1853,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
18351853
const { prompt, attachments, references } = await this.promptResolver.resolvePrompt(request, await requestPromptPromise, (otherReferences || []).concat([]), workspaceInfo, [], token);
18361854

18371855
const mcpServerMappings = buildMcpServerMappings(request.tools);
1838-
const session = await this.sessionService.createSession({ workspace: workspaceInfo, agent, model, mcpServerMappings }, token);
1856+
const session = await this.sessionService.createSession({ workspace: workspaceInfo, agent, model: model?.model, reasoningEffort: model?.reasoningEffort, mcpServerMappings }, token);
18391857
const modeInstructions = this.createModeInstructions(request);
18401858
this.chatSessionMetadataStore.updateRequestDetails(session.object.sessionId, [{ vscodeRequestId: request.id, agentId: agent?.name ?? '', modeInstructions }]).catch(ex => this.logService.error(ex, 'Failed to update request details'));
18411859
if (summary) {
@@ -1869,7 +1887,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
18691887
// The caller is most likely a chat editor or the like.
18701888
// Now that we've delegated it to a session, we can get out of here.
18711889
// Else if the request takes say 10 minutes, the caller would be blocked for that long.
1872-
session.object.handleRequest(request, { prompt }, attachments, model ? { model } : undefined, authInfo, token)
1890+
session.object.handleRequest(request, { prompt }, attachments, model, authInfo, token)
18731891
.then(() => this.commitWorktreeChangesIfNeeded(request, session.object, token))
18741892
.catch(error => {
18751893
this.logService.error(`Failed to handle CLI session request: ${error}`);

extensions/copilot/src/platform/configuration/common/configurationService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ export namespace ConfigKey {
618618
export const CLIIsolationOption = defineSetting<boolean>('chat.cli.isolationOption.enabled', ConfigType.Simple, true);
619619
export const CLIAutoCommitEnabled = defineSetting<boolean>('chat.cli.autoCommit.enabled', ConfigType.Simple, true);
620620
export const CLISessionController = defineSetting<boolean>('chat.cli.sessionController.enabled', ConfigType.Simple, false);
621-
export const CLIThinkingEffortEnabled = defineSetting<boolean>('chat.cli.thinkingEffort.enabled', ConfigType.Simple, false);
621+
export const CLIThinkingEffortEnabled = defineSetting<boolean>('chat.cli.thinkingEffort.enabled', ConfigType.Simple, true);
622622
export const CLISessionControllerForSessionsApp = defineSetting<boolean>('chat.cli.sessionControllerForSessionsApp.enabled', ConfigType.Simple, false);
623623
export const CLITerminalLinks = defineSetting<boolean>('chat.cli.terminalLinks.enabled', ConfigType.Simple, true);
624624
export const RequestLoggerMaxEntries = defineAndMigrateSetting<number>('chat.advanced.debug.requestLogger.maxEntries', 'chat.debug.requestLogger.maxEntries', 100);

0 commit comments

Comments
 (0)