Skip to content

Commit 78dd743

Browse files
burkehollandroblourens
authored andcommitted
Add core Beast Mode functionality to GPT-4.1/5 agent prompt (#467)
* Add GPT-4.1 agent prompt and enhance tool capabilities Implemented the GPT-4.1 specific agent prompt to improve multi-step task execution and problem-solving. Updated the DefaultAgentPrompt to conditionally render the new GPT41AgentPrompt based on the model family. Enhanced the tool capabilities detection function to streamline tool usage and added a new tool name for managing todo lists. * Add setting for new prompt, tweaks * Cleanup --------- Co-authored-by: Rob Lourens <[email protected]>
1 parent 1449113 commit 78dd743

File tree

8 files changed

+301
-69
lines changed

8 files changed

+301
-69
lines changed

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,6 +2762,14 @@
27622762
"experimental"
27632763
],
27642764
"description": "%github.copilot.config.retryAfterFilteredResponse.enabled%"
2765+
},
2766+
"github.copilot.chat.alternateGptPrompt.enabled": {
2767+
"type": "boolean",
2768+
"default": false,
2769+
"tags": [
2770+
"experimental"
2771+
],
2772+
"description": "%github.copilot.config.alternateGptPrompt.enabled%"
27652773
}
27662774
}
27672775
}

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
"github.copilot.config.byok.ollamaEndpoint": "The endpoint to use for the Ollama when accessed via bring your own key. Defaults to localhost.",
136136
"github.copilot.config.virtualTools.threshold": "This setting defines the tool count over which virtual tools should be used. Virtual tools group similar sets of tools together and they allow the model to activate them on-demand. Certain tool groups will optimistically be pre-activated. We are actively developing this feature and you experience degraded tool calling once the threshold is hit.\n\nMay be set to `0` to disable virtual tools.",
137137
"github.copilot.config.retryAfterFilteredResponse.enabled": "Enables retrying after a filtered response. If enabled, Copilot Chat will retry the request after a content filter blocks the response.",
138+
"github.copilot.config.alternateGptPrompt.enabled": "Enables an experimental alternate prompt for GPT models instead of the default prompt.",
138139
"github.copilot.command.fixTestFailure": "Fix Test Failure",
139140
"copilot.description": "Ask or edit in context",
140141
"copilot.edits.description": "Edit files in your workspace",

src/extension/prompts/node/agent/agentInstructions.tsx

Lines changed: 223 additions & 33 deletions
Large diffs are not rendered by default.

src/extension/prompts/node/agent/agentPrompt.tsx

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { IAlternativeNotebookContentService } from '../../../../platform/noteboo
1818
import { IPromptPathRepresentationService } from '../../../../platform/prompts/common/promptPathRepresentationService';
1919
import { ITabsAndEditorsService } from '../../../../platform/tabs/common/tabsAndEditorsService';
2020
import { ITasksService } from '../../../../platform/tasks/common/tasksService';
21+
import { IExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';
2122
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
2223
import { coalesce } from '../../../../util/vs/base/common/arrays';
2324
import { basename } from '../../../../util/vs/base/common/path';
@@ -44,7 +45,7 @@ import { UserPreferences } from '../panel/preferences';
4445
import { ChatToolCalls } from '../panel/toolCalling';
4546
import { MultirootWorkspaceStructure } from '../panel/workspace/workspaceStructure';
4647
import { AgentConversationHistory } from './agentConversationHistory';
47-
import { DefaultAgentPrompt, SweBenchAgentPrompt } from './agentInstructions';
48+
import { AlternateGPTPrompt, DefaultAgentPrompt, SweBenchAgentPrompt } from './agentInstructions';
4849
import { SummarizedConversationHistory } from './summarizedConversationHistory';
4950

5051
export interface AgentPromptProps extends GenericBasePromptElementProps {
@@ -75,6 +76,7 @@ export class AgentPrompt extends PromptElement<AgentPromptProps> {
7576
props: AgentPromptProps,
7677
@IConfigurationService private readonly configurationService: IConfigurationService,
7778
@IInstantiationService private readonly instantiationService: IInstantiationService,
79+
@IExperimentationService private readonly experimentationService: IExperimentationService,
7880
@IPromptEndpoint private readonly promptEndpoint: IPromptEndpoint,
7981
) {
8082
super(props);
@@ -83,11 +85,17 @@ export class AgentPrompt extends PromptElement<AgentPromptProps> {
8385
async render(state: void, sizing: PromptSizing) {
8486
const instructions = this.configurationService.getConfig(ConfigKey.Internal.SweBenchAgentPrompt) ?
8587
<SweBenchAgentPrompt availableTools={this.props.promptContext.tools?.availableTools} modelFamily={this.props.endpoint.family} codesearchMode={undefined} /> :
86-
<DefaultAgentPrompt
87-
availableTools={this.props.promptContext.tools?.availableTools}
88-
modelFamily={this.props.endpoint.family}
89-
codesearchMode={this.props.codesearchMode}
90-
/>;
88+
this.props.endpoint.family.startsWith('gpt-') && this.configurationService.getExperimentBasedConfig(ConfigKey.EnableAlternateGptPrompt, this.experimentationService) ?
89+
<AlternateGPTPrompt
90+
availableTools={this.props.promptContext.tools?.availableTools}
91+
modelFamily={this.props.endpoint.family}
92+
codesearchMode={this.props.codesearchMode}
93+
/> :
94+
<DefaultAgentPrompt
95+
availableTools={this.props.promptContext.tools?.availableTools}
96+
modelFamily={this.props.endpoint.family}
97+
codesearchMode={this.props.codesearchMode}
98+
/>;
9199

92100
const omitBaseAgentInstructions = this.configurationService.getConfig(ConfigKey.Internal.OmitBaseAgentInstructions);
93101
const baseAgentInstructions = <>
@@ -304,7 +312,7 @@ export class AgentUserMessage extends PromptElement<AgentUserMessageProps> {
304312
<RepoContext />
305313
<Tag name='reminderInstructions'>
306314
{/* Critical reminders that are effective when repeated right next to the user message */}
307-
{getKeepGoingReminder(this.props.endpoint.family)}
315+
<KeepGoingReminder modelFamily={this.props.endpoint.family} />
308316
{getEditingReminder(hasEditFileTool, hasReplaceStringTool, modelNeedsStrongReplaceStringHint(this.props.endpoint))}
309317
<NotebookReminderInstructions chatVariables={this.props.chatVariables} query={this.props.request} />
310318
{getExplanationReminder(this.props.endpoint.family, hasTodoTool)}
@@ -639,26 +647,52 @@ export function getEditingReminder(hasEditFileTool: boolean, hasReplaceStringToo
639647
return lines;
640648
}
641649

642-
/**
643-
* Remind gpt-4.1 to keep going and not stop to ask questions...
644-
*/
645-
export function getKeepGoingReminder(modelFamily: string | undefined) {
646-
return modelFamily === 'gpt-4.1' ?
647-
<>
648-
You are an agent - you must keep going until the user's query is completely resolved, before ending your turn and yielding back to the user. ONLY terminate your turn when you are sure that the problem is solved, or you absolutely cannot continue.<br />
649-
You take action when possible- the user is expecting YOU to take action and go to work for them. Don't ask unnecessary questions about the details if you can simply DO something useful instead.<br />
650-
</>
651-
: modelFamily === 'gpt-5' ?
652-
<>
653-
You are an agent—keep going until the user's query is completely resolved before ending your turn. ONLY stop if solved or genuinely blocked.<br />
654-
Take action when possible; the user expects you to do useful work without unnecessary questions.<br />
655-
After any parallel, read-only context gathering, give a concise progress update and what's next.<br />
656-
Avoid repetition across turns: don't restate unchanged plans or sections (like the todo list) verbatim; provide delta updates or only the parts that changed.<br />
657-
Tool batches: You MUST preface each batch with a one-sentence why/what/outcome preamble.<br />
658-
Progress cadence: After 3 to 5 tool calls, or when you create/edit &gt; ~3 files in a burst, pause and post a compact checkpoint.<br />
659-
Requirements coverage: Read the user's ask in full, extract each requirement into checklist items, and keep them visible. Do not omit a requirement. If something cannot be done with available tools, note why briefly and propose a viable alternative.<br />
660-
</>
661-
: undefined;
650+
export interface IKeepGoingReminderProps extends BasePromptElementProps {
651+
modelFamily: string | undefined;
652+
}
653+
654+
export class KeepGoingReminder extends PromptElement<IKeepGoingReminderProps> {
655+
constructor(
656+
props: IKeepGoingReminderProps,
657+
@IConfigurationService private readonly configurationService: IConfigurationService,
658+
@IExperimentationService private readonly experimentationService: IExperimentationService,
659+
) {
660+
super(props);
661+
}
662+
663+
async render(state: void, sizing: PromptSizing) {
664+
if (this.props.modelFamily === 'gpt-4.1' || this.props.modelFamily === 'gpt-5') {
665+
if (this.configurationService.getExperimentBasedConfig(ConfigKey.EnableAlternateGptPrompt, this.experimentationService)) {
666+
// Extended reminder
667+
return <>
668+
You are an agent - you must keep going until the user's query is completely resolved, before ending your turn and yielding back to the user.<br />
669+
Your thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.<br />
670+
You MUST iterate and keep going until the problem is solved.<br />
671+
You have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me. <br />
672+
Only terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.<br />
673+
Take your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided. <br />
674+
You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.<br />
675+
You are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.<br />
676+
</>;
677+
} else if (this.props.modelFamily === 'gpt-5') {
678+
return <>
679+
You are an agent—keep going until the user's query is completely resolved before ending your turn. ONLY stop if solved or genuinely blocked.<br />
680+
Take action when possible; the user expects you to do useful work without unnecessary questions.<br />
681+
After any parallel, read-only context gathering, give a concise progress update and what's next.<br />
682+
Avoid repetition across turns: don't restate unchanged plans or sections (like the todo list) verbatim; provide delta updates or only the parts that changed.<br />
683+
Tool batches: You MUST preface each batch with a one-sentence why/what/outcome preamble.<br />
684+
Progress cadence: After 3 to 5 tool calls, or when you create/edit &gt; ~3 files in a burst, pause and post a compact checkpoint.<br />
685+
Requirements coverage: Read the user's ask in full, extract each requirement into checklist items, and keep them visible. Do not omit a requirement. If something cannot be done with available tools, note why briefly and propose a viable alternative.<br />
686+
</>;
687+
} else {
688+
// Original reminder
689+
return <>
690+
You are an agent - you must keep going until the user's query is completely resolved, before ending your turn and yielding back to the user. ONLY terminate your turn when you are sure that the problem is solved, or you absolutely cannot continue.<br />
691+
You take action when possible- the user is expecting YOU to take action and go to work for them. Don't ask unnecessary questions about the details if you can simply DO something useful instead.<br />
692+
</>;
693+
}
694+
}
695+
}
662696
}
663697

664698
function getExplanationReminder(modelFamily: string | undefined, hasTodoTool?: boolean) {

src/extension/prompts/node/agent/simpleSummarizedHistoryPrompt.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { truncate } from '../../../../util/vs/base/common/strings';
99
import { IToolCall, IToolCallRound } from '../../../prompt/common/intents';
1010
import { Tag } from '../base/tag';
1111
import { ToolResult } from '../panel/toolCalling';
12-
import { getKeepGoingReminder } from './agentPrompt';
12+
import { KeepGoingReminder } from './agentPrompt';
1313
import { SummarizedAgentHistoryProps } from './summarizedConversationHistory';
1414

1515
/**
@@ -81,11 +81,10 @@ export class SimpleSummarizedHistory extends PromptElement<SummarizedAgentHistor
8181
}
8282

8383
if (entry.round.summary) {
84-
const keepGoingReminder = getKeepGoingReminder(this.props.endpoint.family);
8584
return <ChunkTag name='conversation-summary' priority={priorityOverride}>
8685
{entry.round.summary}
87-
{keepGoingReminder && <Tag name='reminderInstructions'>
88-
{keepGoingReminder}
86+
{this.props.endpoint.family === 'gpt-4.1' && <Tag name='reminderInstructions'>
87+
<KeepGoingReminder modelFamily={this.props.endpoint.family} />
8988
</Tag>}
9089
</ChunkTag>;
9190
}

src/extension/prompts/node/agent/summarizedConversationHistory.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { NotebookSummary } from '../../../tools/node/notebookSummaryTool';
3535
import { renderPromptElement } from '../base/promptRenderer';
3636
import { Tag } from '../base/tag';
3737
import { ChatToolCalls } from '../panel/toolCalling';
38-
import { AgentPrompt, AgentPromptProps, AgentUserMessage, getKeepGoingReminder, getUserMessagePropsFromAgentProps, getUserMessagePropsFromTurn } from './agentPrompt';
38+
import { AgentPrompt, AgentPromptProps, AgentUserMessage, getUserMessagePropsFromAgentProps, getUserMessagePropsFromTurn, KeepGoingReminder } from './agentPrompt';
3939
import { SimpleSummarizedHistory } from './simpleSummarizedHistoryPrompt';
4040

4141
export interface ConversationHistorySummarizationPromptProps extends SummarizedAgentHistoryProps {
@@ -713,13 +713,12 @@ interface SummaryMessageProps extends BasePromptElementProps {
713713

714714
class SummaryMessageElement extends PromptElement<SummaryMessageProps> {
715715
override async render(state: void, sizing: PromptSizing) {
716-
const keepGoingReminder = getKeepGoingReminder(this.props.endpoint.family);
717716
return <UserMessage>
718717
<Tag name='conversation-summary'>
719718
{this.props.summaryText}
720719
</Tag>
721-
{keepGoingReminder && <Tag name='reminderInstructions'>
722-
{keepGoingReminder}
720+
{this.props.endpoint.family === 'gpt-4.1' && <Tag name='reminderInstructions'>
721+
<KeepGoingReminder modelFamily={this.props.endpoint.family} />
723722
</Tag>}
724723
</UserMessage>;
725724
}

src/extension/tools/common/toolNames.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export const enum ToolName {
4444
CreateDirectory = 'create_directory',
4545
RunVscodeCmd = 'run_vscode_command',
4646
GetTaskOutput = 'get_task_output',
47-
47+
CoreManageTodoList = 'manage_todo_list',
4848
CoreRunInTerminal = 'run_in_terminal',
4949
CoreGetTerminalOutput = 'get_terminal_output',
5050
CoreCreateAndRunTask = 'create_and_run_task',

src/platform/configuration/common/configurationService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ export namespace ConfigKey {
767767
export const CustomInstructionsInSystemMessage = defineSetting<boolean>('chat.customInstructionsInSystemMessage', true);
768768

769769
export const EnableRetryAfterFilteredResponse = defineExpSetting<boolean>('chat.enableRetryAfterFilteredResponse', true);
770+
export const EnableAlternateGptPrompt = defineExpSetting<boolean>('chat.alternateGptPrompt.enabled', false);
770771
}
771772

772773
export function getAllConfigKeys(): string[] {

0 commit comments

Comments
 (0)