mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
feat: add compact prompt mode for local LLMs
- Add compactPromptMode boolean setting to ProviderSettings type - Implement compact prompt generation in SYSTEM_PROMPT function - Add UI toggle in LM Studio and Ollama provider settings - Create reusable CompactPromptControl component - Add translation strings for the new feature - Include comprehensive tests for compact prompt functionality This feature addresses issue #7550 by providing a minimal prompt option that reduces context size and improves response times for local LLMs that have slower token generation speeds.
This commit is contained in:
parent
c7d7ad8197
commit
576864bdff
8 changed files with 319 additions and 1 deletions
|
|
@ -103,6 +103,7 @@ const baseProviderSettingsSchema = z.object({
|
|||
modelTemperature: z.number().nullish(),
|
||||
rateLimitSeconds: z.number().optional(),
|
||||
consecutiveMistakeLimit: z.number().min(0).optional(),
|
||||
compactPromptMode: z.boolean().optional(),
|
||||
|
||||
// Model reasoning.
|
||||
enableReasoningEffort: z.boolean().optional(),
|
||||
|
|
|
|||
|
|
@ -672,6 +672,194 @@ describe("SYSTEM_PROMPT", () => {
|
|||
expect(prompt).toContain("## update_todo_list")
|
||||
})
|
||||
|
||||
describe("Compact Prompt Mode", () => {
|
||||
it("should generate a compact prompt when compactPromptMode is true", async () => {
|
||||
const prompt = await SYSTEM_PROMPT(
|
||||
mockContext,
|
||||
"/test/path",
|
||||
false, // supportsComputerUse
|
||||
undefined, // mcpHub
|
||||
undefined, // diffStrategy
|
||||
undefined, // browserViewportSize
|
||||
defaultModeSlug, // mode
|
||||
undefined, // customModePrompts
|
||||
undefined, // customModes
|
||||
undefined, // globalCustomInstructions
|
||||
undefined, // diffEnabled
|
||||
experiments,
|
||||
true, // enableMcpServerCreation
|
||||
undefined, // language
|
||||
undefined, // rooIgnoreInstructions
|
||||
undefined, // partialReadsEnabled
|
||||
undefined, // settings
|
||||
undefined, // todoList
|
||||
undefined, // modelId
|
||||
true, // compactPromptMode
|
||||
)
|
||||
|
||||
// Compact prompt should be significantly shorter
|
||||
const normalPrompt = await SYSTEM_PROMPT(
|
||||
mockContext,
|
||||
"/test/path",
|
||||
false, // supportsComputerUse
|
||||
undefined, // mcpHub
|
||||
undefined, // diffStrategy
|
||||
undefined, // browserViewportSize
|
||||
defaultModeSlug, // mode
|
||||
undefined, // customModePrompts
|
||||
undefined, // customModes
|
||||
undefined, // globalCustomInstructions
|
||||
undefined, // diffEnabled
|
||||
experiments,
|
||||
true, // enableMcpServerCreation
|
||||
undefined, // language
|
||||
undefined, // rooIgnoreInstructions
|
||||
undefined, // partialReadsEnabled
|
||||
undefined, // settings
|
||||
undefined, // todoList
|
||||
undefined, // modelId
|
||||
false, // compactPromptMode
|
||||
)
|
||||
|
||||
// Compact prompt should be shorter
|
||||
expect(prompt.length).toBeLessThan(normalPrompt.length)
|
||||
|
||||
// Should still contain essential sections
|
||||
expect(prompt).toContain("You are Roo")
|
||||
expect(prompt).toContain("## read_file")
|
||||
expect(prompt).toContain("## write_to_file")
|
||||
expect(prompt).toContain("## list_files")
|
||||
expect(prompt).toContain("## search_files")
|
||||
|
||||
// Should NOT contain non-essential sections
|
||||
expect(prompt).not.toContain("MCP")
|
||||
expect(prompt).not.toContain("browser")
|
||||
expect(prompt).not.toContain("CAPABILITIES")
|
||||
expect(prompt).not.toContain("MODES")
|
||||
expect(prompt).not.toContain("execute_command") // Execute command is not included in compact mode for architect mode
|
||||
})
|
||||
|
||||
it("should generate a normal prompt when compactPromptMode is false", async () => {
|
||||
const prompt = await SYSTEM_PROMPT(
|
||||
mockContext,
|
||||
"/test/path",
|
||||
false, // supportsComputerUse
|
||||
undefined, // mcpHub
|
||||
undefined, // diffStrategy
|
||||
undefined, // browserViewportSize
|
||||
defaultModeSlug, // mode
|
||||
undefined, // customModePrompts
|
||||
undefined, // customModes
|
||||
undefined, // globalCustomInstructions
|
||||
undefined, // diffEnabled
|
||||
experiments,
|
||||
true, // enableMcpServerCreation
|
||||
undefined, // language
|
||||
undefined, // rooIgnoreInstructions
|
||||
undefined, // partialReadsEnabled
|
||||
undefined, // settings
|
||||
undefined, // todoList
|
||||
undefined, // modelId
|
||||
false, // compactPromptMode
|
||||
)
|
||||
|
||||
// Normal prompt should contain all sections
|
||||
expect(prompt).toContain("CAPABILITIES")
|
||||
expect(prompt).toContain("MODES")
|
||||
expect(prompt).toContain("RULES")
|
||||
expect(prompt).toContain("SYSTEM INFORMATION")
|
||||
expect(prompt).toContain("OBJECTIVE")
|
||||
})
|
||||
|
||||
it("should generate a normal prompt when compactPromptMode is undefined", async () => {
|
||||
const prompt = await SYSTEM_PROMPT(
|
||||
mockContext,
|
||||
"/test/path",
|
||||
false, // supportsComputerUse
|
||||
undefined, // mcpHub
|
||||
undefined, // diffStrategy
|
||||
undefined, // browserViewportSize
|
||||
defaultModeSlug, // mode
|
||||
undefined, // customModePrompts
|
||||
undefined, // customModes
|
||||
undefined, // globalCustomInstructions
|
||||
undefined, // diffEnabled
|
||||
experiments,
|
||||
true, // enableMcpServerCreation
|
||||
undefined, // language
|
||||
undefined, // rooIgnoreInstructions
|
||||
undefined, // partialReadsEnabled
|
||||
undefined, // settings
|
||||
undefined, // todoList
|
||||
undefined, // modelId
|
||||
undefined, // compactPromptMode
|
||||
)
|
||||
|
||||
// Should generate normal prompt by default
|
||||
expect(prompt).toContain("CAPABILITIES")
|
||||
expect(prompt).toContain("MODES")
|
||||
expect(prompt).toContain("RULES")
|
||||
expect(prompt).toContain("SYSTEM INFORMATION")
|
||||
expect(prompt).toContain("OBJECTIVE")
|
||||
})
|
||||
|
||||
it("should not include diff tool in compact mode even when diffEnabled is true", async () => {
|
||||
const prompt = await SYSTEM_PROMPT(
|
||||
mockContext,
|
||||
"/test/path",
|
||||
false, // supportsComputerUse
|
||||
undefined, // mcpHub
|
||||
new MultiSearchReplaceDiffStrategy(), // diffStrategy
|
||||
undefined, // browserViewportSize
|
||||
defaultModeSlug, // mode
|
||||
undefined, // customModePrompts
|
||||
undefined, // customModes
|
||||
undefined, // globalCustomInstructions
|
||||
true, // diffEnabled
|
||||
experiments,
|
||||
true, // enableMcpServerCreation
|
||||
undefined, // language
|
||||
undefined, // rooIgnoreInstructions
|
||||
undefined, // partialReadsEnabled
|
||||
undefined, // settings
|
||||
undefined, // todoList
|
||||
undefined, // modelId
|
||||
true, // compactPromptMode
|
||||
)
|
||||
|
||||
// Compact mode doesn't include diff tool to keep prompt minimal
|
||||
expect(prompt).not.toContain("apply_diff")
|
||||
})
|
||||
|
||||
it("should maintain custom instructions in compact mode", async () => {
|
||||
const prompt = await SYSTEM_PROMPT(
|
||||
mockContext,
|
||||
"/test/path",
|
||||
false, // supportsComputerUse
|
||||
undefined, // mcpHub
|
||||
undefined, // diffStrategy
|
||||
undefined, // browserViewportSize
|
||||
defaultModeSlug, // mode
|
||||
undefined, // customModePrompts
|
||||
undefined, // customModes
|
||||
"Test global instructions", // globalCustomInstructions
|
||||
undefined, // diffEnabled
|
||||
experiments,
|
||||
true, // enableMcpServerCreation
|
||||
undefined, // language
|
||||
undefined, // rooIgnoreInstructions
|
||||
undefined, // partialReadsEnabled
|
||||
undefined, // settings
|
||||
undefined, // todoList
|
||||
undefined, // modelId
|
||||
true, // compactPromptMode
|
||||
)
|
||||
|
||||
// Should still include custom instructions
|
||||
expect(prompt).toContain("Test global instructions")
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ export const SYSTEM_PROMPT = async (
|
|||
settings?: SystemPromptSettings,
|
||||
todoList?: TodoItem[],
|
||||
modelId?: string,
|
||||
compactPromptMode?: boolean,
|
||||
): Promise<string> => {
|
||||
if (!context) {
|
||||
throw new Error("Extension context is required for generating system prompt")
|
||||
|
|
@ -202,6 +203,62 @@ ${fileCustomSystemPrompt}
|
|||
${customInstructions}`
|
||||
}
|
||||
|
||||
// If compact prompt mode is enabled, generate a minimal prompt
|
||||
if (compactPromptMode) {
|
||||
const { roleDefinition, baseInstructions } = getModeSelection(mode, promptComponent, customModes)
|
||||
const codeIndexManager = CodeIndexManager.getInstance(context, cwd)
|
||||
|
||||
// Generate a compact prompt with only essential sections
|
||||
const compactPrompt = `${roleDefinition}
|
||||
|
||||
====
|
||||
|
||||
TOOL USE
|
||||
|
||||
You have access to tools that are executed upon user approval. Use one tool per message.
|
||||
|
||||
# Tools
|
||||
|
||||
${getToolDescriptionsForMode(
|
||||
mode,
|
||||
cwd,
|
||||
false, // Disable computer use for compact mode
|
||||
codeIndexManager,
|
||||
undefined, // No diff strategy in compact mode
|
||||
undefined, // No browser viewport
|
||||
undefined, // No MCP in compact mode
|
||||
customModes,
|
||||
experiments,
|
||||
partialReadsEnabled,
|
||||
settings,
|
||||
false, // No MCP server creation
|
||||
modelId,
|
||||
)}
|
||||
|
||||
====
|
||||
|
||||
RULES
|
||||
|
||||
- Project directory: ${cwd.toPosix()}
|
||||
- Use tools efficiently to accomplish tasks
|
||||
- Wait for user response after each tool use
|
||||
- Be concise and direct in responses
|
||||
|
||||
====
|
||||
|
||||
OBJECTIVE
|
||||
|
||||
Complete the user's task efficiently using available tools.
|
||||
|
||||
${await addCustomInstructions(baseInstructions, globalCustomInstructions || "", cwd, mode, {
|
||||
language: language ?? formatLanguage(vscode.env.language),
|
||||
rooIgnoreInstructions,
|
||||
settings,
|
||||
})}`
|
||||
|
||||
return compactPrompt
|
||||
}
|
||||
|
||||
// If diff is disabled, don't pass the diffStrategy
|
||||
const effectiveDiffStrategy = diffEnabled ? diffStrategy : undefined
|
||||
|
||||
|
|
|
|||
|
|
@ -2242,6 +2242,11 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
apiConfiguration,
|
||||
} = state ?? {}
|
||||
|
||||
// Check if we should use compact prompt mode for local LLM providers
|
||||
const isLocalLLMProvider =
|
||||
this.apiConfiguration.apiProvider === "lmstudio" || this.apiConfiguration.apiProvider === "ollama"
|
||||
const shouldUseCompactPrompt = isLocalLLMProvider && this.apiConfiguration.compactPromptMode
|
||||
|
||||
return await (async () => {
|
||||
const provider = this.providerRef.deref()
|
||||
|
||||
|
|
@ -2276,6 +2281,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
},
|
||||
undefined, // todoList
|
||||
this.api.getModel().id,
|
||||
shouldUseCompactPrompt,
|
||||
)
|
||||
})()
|
||||
}
|
||||
|
|
|
|||
44
webview-ui/src/components/settings/CompactPromptControl.tsx
Normal file
44
webview-ui/src/components/settings/CompactPromptControl.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import React from "react"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
|
||||
interface CompactPromptControlProps {
|
||||
compactPromptMode?: boolean
|
||||
onChange: (value: boolean) => void
|
||||
providerName?: string
|
||||
}
|
||||
|
||||
export const CompactPromptControl: React.FC<CompactPromptControlProps> = ({
|
||||
compactPromptMode = false,
|
||||
onChange,
|
||||
providerName,
|
||||
}) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
// Determine the correct translation key prefix based on provider
|
||||
const translationPrefix = providerName === "LM Studio" ? "providers.lmStudio" : "providers.ollama"
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label htmlFor="compact-prompt-mode" className="font-medium">
|
||||
{t(`settings:${translationPrefix}.compactPrompt.title`)}
|
||||
</label>
|
||||
<input
|
||||
id="compact-prompt-mode"
|
||||
type="checkbox"
|
||||
checked={compactPromptMode}
|
||||
onChange={(e) => onChange(e.target.checked)}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-sm text-vscode-descriptionForeground">
|
||||
{t(`settings:${translationPrefix}.compactPrompt.description`)}
|
||||
</p>
|
||||
{providerName && (
|
||||
<p className="text-xs text-vscode-descriptionForeground italic">
|
||||
{t(`settings:${translationPrefix}.compactPrompt.providerNote`, { provider: providerName })}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import { vscode } from "@src/utils/vscode"
|
|||
|
||||
import { inputEventTransform } from "../transforms"
|
||||
import { ModelRecord } from "@roo/api"
|
||||
import { CompactPromptControl } from "../CompactPromptControl"
|
||||
|
||||
type LMStudioProps = {
|
||||
apiConfiguration: ProviderSettings
|
||||
|
|
@ -207,6 +208,11 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
|
|||
)}
|
||||
</>
|
||||
)}
|
||||
<CompactPromptControl
|
||||
compactPromptMode={apiConfiguration?.compactPromptMode}
|
||||
onChange={(value) => setApiConfigurationField("compactPromptMode", value)}
|
||||
providerName="LM Studio"
|
||||
/>
|
||||
<div className="text-sm text-vscode-descriptionForeground">
|
||||
<Trans
|
||||
i18nKey="settings:providers.lmStudio.description"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { useRouterModels } from "@src/components/ui/hooks/useRouterModels"
|
|||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
import { inputEventTransform } from "../transforms"
|
||||
import { CompactPromptControl } from "../CompactPromptControl"
|
||||
|
||||
type OllamaProps = {
|
||||
apiConfiguration: ProviderSettings
|
||||
|
|
@ -118,6 +119,11 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro
|
|||
))}
|
||||
</VSCodeRadioGroup>
|
||||
)}
|
||||
<CompactPromptControl
|
||||
compactPromptMode={apiConfiguration?.compactPromptMode}
|
||||
onChange={(value) => setApiConfigurationField("compactPromptMode", value)}
|
||||
providerName="Ollama"
|
||||
/>
|
||||
<div className="text-sm text-vscode-descriptionForeground">
|
||||
{t("settings:providers.ollama.description")}
|
||||
<span className="text-vscode-errorForeground ml-1">{t("settings:providers.ollama.warning")}</span>
|
||||
|
|
|
|||
|
|
@ -368,7 +368,12 @@
|
|||
"draftModelDesc": "Draft model must be from the same model family for speculative decoding to work correctly.",
|
||||
"selectDraftModel": "Select Draft Model",
|
||||
"noModelsFound": "No draft models found. Please ensure LM Studio is running with Server Mode enabled.",
|
||||
"description": "LM Studio allows you to run models locally on your computer. For instructions on how to get started, see their <a>quickstart guide</a>. You will also need to start LM Studio's <b>local server</b> feature to use it with this extension. <span>Note:</span> Roo Code uses complex prompts and works best with Claude models. Less capable models may not work as expected."
|
||||
"description": "LM Studio allows you to run models locally on your computer. For instructions on how to get started, see their <a>quickstart guide</a>. You will also need to start LM Studio's <b>local server</b> feature to use it with this extension. <span>Note:</span> Roo Code uses complex prompts and works best with Claude models. Less capable models may not work as expected.",
|
||||
"compactPrompt": {
|
||||
"title": "Compact Prompt Mode",
|
||||
"description": "Reduces the system prompt size for faster response times with local LLMs. This removes non-essential sections while keeping core functionality.",
|
||||
"providerNote": "Recommended for {{provider}} to prevent timeouts with slower local models"
|
||||
}
|
||||
},
|
||||
"ollama": {
|
||||
"baseUrl": "Base URL (optional)",
|
||||
|
|
@ -376,6 +381,11 @@
|
|||
"description": "Ollama allows you to run models locally on your computer. For instructions on how to get started, see their quickstart guide.",
|
||||
"warning": "Note: Roo Code uses complex prompts and works best with Claude models. Less capable models may not work as expected."
|
||||
},
|
||||
"compactPrompt": {
|
||||
"title": "Compact Prompt Mode",
|
||||
"description": "Reduces the system prompt size for faster response times with local LLMs. This removes non-essential sections while keeping core functionality.",
|
||||
"providerNote": "Recommended for {{provider}} to prevent timeouts with slower local models"
|
||||
},
|
||||
"unboundApiKey": "Unbound API Key",
|
||||
"getUnboundApiKey": "Get Unbound API Key",
|
||||
"unboundRefreshModelsSuccess": "Models list updated! You can now select from the latest models.",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue