feat: add overrideSystemPrompt option for custom modes

When overrideSystemPrompt is true on a ModeConfig, the system prompt
uses only the roleDefinition as its body, skipping all standard
sections (CAPABILITIES, TOOL USE, MODES, SKILLS, RULES, SYSTEM INFO,
OBJECTIVE, MARKDOWN RULES). Custom instructions from .roo/rules-*
files and global settings are still appended.

This gives power users full control over the system prompt for
specialized workflows while maintaining backward compatibility --
the flag defaults to false/undefined so existing modes are unaffected.

Closes #11793
This commit is contained in:
Roo Code 2026-02-28 07:30:18 +00:00
parent 193053110b
commit d1f7b65d60
3 changed files with 156 additions and 0 deletions

View file

@ -102,6 +102,7 @@ export const modeConfigSchema = z.object({
customInstructions: z.string().optional(),
groups: groupEntryArraySchema,
source: z.enum(["global", "project"]).optional(),
overrideSystemPrompt: z.boolean().optional(),
})
export type ModeConfig = z.infer<typeof modeConfigSchema>

View file

@ -575,6 +575,144 @@ describe("SYSTEM_PROMPT", () => {
expect(prompt).toContain("OBJECTIVE")
})
describe("overrideSystemPrompt", () => {
it("should use only roleDefinition + custom instructions when overrideSystemPrompt is true", async () => {
const customModes: ModeConfig[] = [
{
slug: "custom-override",
name: "Custom Override",
roleDefinition: "You are a fully custom assistant with complete override.",
customInstructions: "Follow these custom mode instructions.",
groups: ["read", "edit"],
overrideSystemPrompt: true,
},
]
const prompt = await SYSTEM_PROMPT(
mockContext,
"/test/path",
false,
undefined, // mcpHub
undefined, // diffStrategy
"custom-override" as Mode,
undefined, // customModePrompts
customModes,
"Global instructions here", // globalCustomInstructions
experiments,
undefined, // language
undefined, // rooIgnoreInstructions
)
// Should contain the roleDefinition
expect(prompt).toContain("You are a fully custom assistant with complete override.")
// Should NOT contain standard sections
expect(prompt).not.toContain("CAPABILITIES")
expect(prompt).not.toContain("TOOL USE")
expect(prompt).not.toContain("MODES")
expect(prompt).not.toContain("SYSTEM INFORMATION")
expect(prompt).not.toContain("OBJECTIVE")
expect(prompt).not.toContain("MARKDOWN RULES")
})
it("should still include custom instructions when overrideSystemPrompt is true", async () => {
const customModes: ModeConfig[] = [
{
slug: "custom-override-instructions",
name: "Custom Override With Instructions",
roleDefinition: "You are a specialized assistant.",
customInstructions: "Mode-specific instructions here.",
groups: ["read"],
overrideSystemPrompt: true,
},
]
const prompt = await SYSTEM_PROMPT(
mockContext,
"/test/path",
false,
undefined, // mcpHub
undefined, // diffStrategy
"custom-override-instructions" as Mode,
undefined, // customModePrompts
customModes,
"Global custom instructions.", // globalCustomInstructions
experiments,
undefined, // language
undefined, // rooIgnoreInstructions
)
// Should contain custom instructions section
expect(prompt).toContain("USER'S CUSTOM INSTRUCTIONS")
expect(prompt).toContain("Mode-specific instructions here.")
})
it("should behave normally when overrideSystemPrompt is false", async () => {
const customModes: ModeConfig[] = [
{
slug: "custom-normal",
name: "Custom Normal",
roleDefinition: "You are a normal custom assistant.",
groups: ["read", "edit"],
overrideSystemPrompt: false,
},
]
const prompt = await SYSTEM_PROMPT(
mockContext,
"/test/path",
false,
undefined, // mcpHub
undefined, // diffStrategy
"custom-normal" as Mode,
undefined, // customModePrompts
customModes,
undefined, // globalCustomInstructions
experiments,
undefined, // language
undefined, // rooIgnoreInstructions
)
// Should contain standard sections
expect(prompt).toContain("CAPABILITIES")
expect(prompt).toContain("TOOL USE")
expect(prompt).toContain("SYSTEM INFORMATION")
expect(prompt).toContain("OBJECTIVE")
})
it("should behave normally when overrideSystemPrompt is not set", async () => {
const customModes: ModeConfig[] = [
{
slug: "custom-unset",
name: "Custom Unset",
roleDefinition: "You are a custom assistant without override flag.",
groups: ["read"],
},
]
const prompt = await SYSTEM_PROMPT(
mockContext,
"/test/path",
false,
undefined, // mcpHub
undefined, // diffStrategy
"custom-unset" as Mode,
undefined, // customModePrompts
customModes,
undefined, // globalCustomInstructions
experiments,
undefined, // language
undefined, // rooIgnoreInstructions
)
// Should contain standard sections (default behavior)
expect(prompt).toContain("CAPABILITIES")
expect(prompt).toContain("TOOL USE")
expect(prompt).toContain("SYSTEM INFORMATION")
expect(prompt).toContain("OBJECTIVE")
})
})
afterAll(() => {
vi.restoreAllMocks()
})

View file

@ -64,6 +64,23 @@ async function generatePrompt(
const modeConfig = getModeBySlug(mode, customModeConfigs) || modes.find((m) => m.slug === mode) || modes[0]
const { roleDefinition, baseInstructions } = getModeSelection(mode, promptComponent, customModeConfigs)
// When overrideSystemPrompt is true, use roleDefinition as the entire system prompt
// body, only appending custom instructions. All standard sections are skipped.
if (modeConfig.overrideSystemPrompt) {
const customInstructionsSection = await addCustomInstructions(
baseInstructions,
globalCustomInstructions || "",
cwd,
mode,
{
language: language ?? formatLanguage(vscode.env.language),
rooIgnoreInstructions,
settings,
},
)
return `${roleDefinition}${customInstructionsSection}`
}
// Check if MCP functionality should be included
const hasMcpGroup = modeConfig.groups.some((groupEntry) => getGroupName(groupEntry) === "mcp")
const hasMcpServers = mcpHub && mcpHub.getServers().length > 0