feat: add lite mode for smaller context in local models

- Add liteMode option to SystemPromptSettings type
- Create condensed tool descriptions for lite mode
- Add lite mode handling to system prompt sections (rules, capabilities)
- Reduce system prompt from ~14k to ~4k tokens when lite mode enabled
- Add UI checkbox in Context Management settings for lite mode
- Optimized for local models with limited context windows (32k, 64k)

Addresses #9351
This commit is contained in:
Roo Code 2025-11-18 12:00:56 +00:00
parent f7c2e8d164
commit 9bdc8440f1
9 changed files with 282 additions and 20 deletions

View file

@ -16,6 +16,18 @@ export function getCapabilitiesSection(
codeIndexManager?: CodeIndexManager,
settings?: SystemPromptSettings,
): string {
// Return simplified capabilities for lite mode
if (settings?.liteMode) {
return `====
CAPABILITIES
- CLI commands, file operations (list/read/write), search, definitions
- Project structure in environment_details
- Each command runs in new terminal
${mcpHub ? "- MCP servers provide additional tools\n" : ""}`
}
// Get available tools from relevant groups
const availableEditTools = getAvailableToolsInGroup(
"edit",

View file

@ -86,6 +86,20 @@ export function getRulesSection(
codeIndexManager?: CodeIndexManager,
settings?: SystemPromptSettings,
): string {
// Return simplified rules for lite mode
if (settings?.liteMode) {
return `====
RULES
- Base directory: ${cwd.toPosix()}
- Use relative paths from base directory
- Read files before editing
- Wait for user confirmation after each tool use
- Use attempt_completion to present final results
- Be direct and technical, not conversational`
}
const isCodebaseSearchAvailable =
codeIndexManager &&
codeIndexManager.isFeatureEnabled &&
@ -132,6 +146,7 @@ export function getRulesSection(
// Determine whether to use XML tool references based on protocol
const effectiveProtocol = getEffectiveProtocol(settings?.toolProtocol)
// Full rules for regular mode
return `====
RULES

View file

@ -28,10 +28,38 @@ import { getRunSlashCommandDescription } from "./run-slash-command"
import { getGenerateImageDescription } from "./generate-image"
import { CodeIndexManager } from "../../../services/code-index/manager"
// Import lite descriptions
import {
getLiteReadFileDescription,
getLiteWriteToFileDescription,
getLiteSearchFilesDescription,
getLiteListFilesDescription,
getLiteExecuteCommandDescription,
getLiteInsertContentDescription,
getLiteListCodeDefinitionNamesDescription,
getLiteAskFollowupQuestionDescription,
getLiteAttemptCompletionDescription,
getLiteBrowserActionDescription,
getLiteSwitchModeDescription,
getLiteNewTaskDescription,
getLiteUpdateTodoListDescription,
getLiteFetchInstructionsDescription,
getLiteApplyDiffDescription,
getLiteCodebaseSearchDescription,
getLiteUseMcpToolDescription,
getLiteAccessMcpResourceDescription,
getLiteGenerateImageDescription,
getLiteRunSlashCommandDescription,
} from "./lite-descriptions"
// Map of tool names to their description functions
const toolDescriptionMap: Record<string, (args: ToolArgs) => string | undefined> = {
execute_command: (args) => getExecuteCommandDescription(args),
execute_command: (args) => {
if (args.settings?.liteMode) return getLiteExecuteCommandDescription()
return getExecuteCommandDescription(args)
},
read_file: (args) => {
if (args.settings?.liteMode) return getLiteReadFileDescription(args)
// Check if the current model should use the simplified read_file tool
const modelId = args.settings?.modelId
if (modelId && shouldUseSingleFileRead(modelId)) {
@ -39,25 +67,80 @@ const toolDescriptionMap: Record<string, (args: ToolArgs) => string | undefined>
}
return getReadFileDescription(args)
},
fetch_instructions: (args) => getFetchInstructionsDescription(args.settings?.enableMcpServerCreation),
write_to_file: (args) => getWriteToFileDescription(args),
search_files: (args) => getSearchFilesDescription(args),
list_files: (args) => getListFilesDescription(args),
list_code_definition_names: (args) => getListCodeDefinitionNamesDescription(args),
browser_action: (args) => getBrowserActionDescription(args),
ask_followup_question: () => getAskFollowupQuestionDescription(),
attempt_completion: (args) => getAttemptCompletionDescription(args),
use_mcp_tool: (args) => getUseMcpToolDescription(args),
access_mcp_resource: (args) => getAccessMcpResourceDescription(args),
codebase_search: (args) => getCodebaseSearchDescription(args),
switch_mode: () => getSwitchModeDescription(),
new_task: (args) => getNewTaskDescription(args),
insert_content: (args) => getInsertContentDescription(args),
apply_diff: (args) =>
args.diffStrategy ? args.diffStrategy.getToolDescription({ cwd: args.cwd, toolOptions: args.toolOptions }) : "",
update_todo_list: (args) => getUpdateTodoListDescription(args),
run_slash_command: () => getRunSlashCommandDescription(),
generate_image: (args) => getGenerateImageDescription(args),
fetch_instructions: (args) => {
if (args.settings?.liteMode) return getLiteFetchInstructionsDescription()
return getFetchInstructionsDescription(args.settings?.enableMcpServerCreation)
},
write_to_file: (args) => {
if (args.settings?.liteMode) return getLiteWriteToFileDescription()
return getWriteToFileDescription(args)
},
search_files: (args) => {
if (args.settings?.liteMode) return getLiteSearchFilesDescription()
return getSearchFilesDescription(args)
},
list_files: (args) => {
if (args.settings?.liteMode) return getLiteListFilesDescription()
return getListFilesDescription(args)
},
list_code_definition_names: (args) => {
if (args.settings?.liteMode) return getLiteListCodeDefinitionNamesDescription()
return getListCodeDefinitionNamesDescription(args)
},
browser_action: (args) => {
if (args.settings?.liteMode) return getLiteBrowserActionDescription()
return getBrowserActionDescription(args)
},
ask_followup_question: (args) => {
if (args.settings?.liteMode) return getLiteAskFollowupQuestionDescription()
return getAskFollowupQuestionDescription()
},
attempt_completion: (args) => {
if (args.settings?.liteMode) return getLiteAttemptCompletionDescription()
return getAttemptCompletionDescription(args)
},
use_mcp_tool: (args) => {
if (args.settings?.liteMode) return getLiteUseMcpToolDescription()
return getUseMcpToolDescription(args)
},
access_mcp_resource: (args) => {
if (args.settings?.liteMode) return getLiteAccessMcpResourceDescription()
return getAccessMcpResourceDescription(args)
},
codebase_search: (args) => {
if (args.settings?.liteMode) return getLiteCodebaseSearchDescription()
return getCodebaseSearchDescription(args)
},
switch_mode: (args) => {
if (args.settings?.liteMode) return getLiteSwitchModeDescription()
return getSwitchModeDescription()
},
new_task: (args) => {
if (args.settings?.liteMode) return getLiteNewTaskDescription()
return getNewTaskDescription(args)
},
insert_content: (args) => {
if (args.settings?.liteMode) return getLiteInsertContentDescription()
return getInsertContentDescription(args)
},
apply_diff: (args) => {
if (args.settings?.liteMode) return getLiteApplyDiffDescription(args.diffStrategy)
return args.diffStrategy
? args.diffStrategy.getToolDescription({ cwd: args.cwd, toolOptions: args.toolOptions })
: ""
},
update_todo_list: (args) => {
if (args.settings?.liteMode) return getLiteUpdateTodoListDescription()
return getUpdateTodoListDescription(args)
},
run_slash_command: (args) => {
if (args.settings?.liteMode) return getLiteRunSlashCommandDescription()
return getRunSlashCommandDescription()
},
generate_image: (args) => {
if (args.settings?.liteMode) return getLiteGenerateImageDescription()
return getGenerateImageDescription(args)
},
}
export function getToolDescriptionsForMode(

View file

@ -0,0 +1,127 @@
import { ToolArgs } from "./types"
import { DiffStrategy } from "../../../shared/tools"
/**
* Returns a compact tool description without examples for lite mode
*/
export function getLiteReadFileDescription(args: ToolArgs): string {
const maxReads = args.settings?.maxConcurrentFileReads ?? 5
return `## read_file
Read file contents (max ${maxReads} files/request). Line-numbered output.
Params: path (required), line_range (optional)`
}
export function getLiteWriteToFileDescription(): string {
return `## write_to_file
Create/overwrite file with content.
Params: path, content, line_count (required)`
}
export function getLiteSearchFilesDescription(): string {
return `## search_files
Regex search in directory.
Params: path, regex (required), file_pattern (optional)`
}
export function getLiteListFilesDescription(): string {
return `## list_files
List directory contents.
Params: path (required), recursive (optional)`
}
export function getLiteExecuteCommandDescription(): string {
return `## execute_command
Execute CLI command.
Params: command (required), cwd (optional)`
}
export function getLiteInsertContentDescription(): string {
return `## insert_content
Insert lines at specific position.
Params: path, line, content (required)`
}
export function getLiteListCodeDefinitionNamesDescription(): string {
return `## list_code_definition_names
List code definitions (classes, functions, etc).
Params: path (required)`
}
export function getLiteAskFollowupQuestionDescription(): string {
return `## ask_followup_question
Ask user for clarification.
Params: question, follow_up with 2-4 suggest tags`
}
export function getLiteAttemptCompletionDescription(): string {
return `## attempt_completion
Present final result after task completion.
Params: result (required)`
}
export function getLiteBrowserActionDescription(): string {
return `## browser_action
Browser interaction: screenshot, click, type, scroll.
Params: action (required), coordinate/text/direction/amount based on action`
}
export function getLiteSwitchModeDescription(): string {
return `## switch_mode
Switch to different mode.
Params: mode_slug (required), reason (optional)`
}
export function getLiteNewTaskDescription(): string {
return `## new_task
Create new task in specified mode.
Params: mode, message (required)`
}
export function getLiteUpdateTodoListDescription(): string {
return `## update_todo_list
Update TODO checklist.
Format: [ ] pending, [x] completed, [-] in progress`
}
export function getLiteFetchInstructionsDescription(): string {
return `## fetch_instructions
Get task instructions.
Params: task (required) - create_mcp_server or create_mode`
}
export function getLiteApplyDiffDescription(diffStrategy?: DiffStrategy): string {
if (!diffStrategy) return ""
return `## apply_diff
Apply targeted edits to existing file.
Params: path, diff (SEARCH/REPLACE blocks with :start_line:)`
}
export function getLiteCodebaseSearchDescription(): string {
return `## codebase_search
Semantic search for relevant code.
Params: query (required)`
}
export function getLiteUseMcpToolDescription(): string {
return `## use_mcp_tool
Use MCP server tool.
Params: server_name, tool_name, arguments (required)`
}
export function getLiteAccessMcpResourceDescription(): string {
return `## access_mcp_resource
Access MCP server resource.
Params: server_name, uri (required), arguments (optional)`
}
export function getLiteGenerateImageDescription(): string {
return `## generate_image
Generate image using AI.
Params: prompt (required), size (optional)`
}
export function getLiteRunSlashCommandDescription(): string {
return `## run_slash_command
Run a VS Code slash command.
Params: command, args (required)`
}

View file

@ -10,4 +10,5 @@ export interface SystemPromptSettings {
useAgentRules: boolean
newTaskRequireTodos: boolean
toolProtocol?: ToolProtocol
liteMode?: boolean
}

View file

@ -349,6 +349,7 @@ export type ExtensionState = Pick<
remoteControlEnabled: boolean
taskSyncEnabled: boolean
featureRoomoteControlEnabled: boolean
liteMode?: boolean
}
export interface ClineSayTool {

View file

@ -30,6 +30,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
includeCurrentTime?: boolean
includeCurrentCost?: boolean
maxGitStatusFiles?: number
liteMode?: boolean
setCachedStateField: SetCachedStateField<
| "autoCondenseContext"
| "autoCondenseContextPercent"
@ -47,6 +48,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
| "includeCurrentTime"
| "includeCurrentCost"
| "maxGitStatusFiles"
| "liteMode"
>
}
@ -69,6 +71,7 @@ export const ContextManagementSettings = ({
includeCurrentTime,
includeCurrentCost,
maxGitStatusFiles,
liteMode,
className,
...props
}: ContextManagementSettingsProps) => {
@ -411,6 +414,20 @@ export const ContextManagementSettings = ({
{t("settings:contextManagement.includeCurrentCost.description")}
</div>
</div>
<div>
<VSCodeCheckbox
checked={liteMode}
onChange={(e: any) => setCachedStateField("liteMode", e.target.checked)}
data-testid="lite-mode-checkbox">
<label className="block font-medium mb-1">
{t("settings:contextManagement.liteMode.label")}
</label>
</VSCodeCheckbox>
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-3">
{t("settings:contextManagement.liteMode.description")}
</div>
</div>
</Section>
<Section className="pt-2">
<VSCodeCheckbox

View file

@ -204,6 +204,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
includeCurrentTime,
includeCurrentCost,
maxGitStatusFiles,
liteMode,
} = cachedState
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
@ -767,6 +768,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
includeCurrentTime={includeCurrentTime}
includeCurrentCost={includeCurrentCost}
maxGitStatusFiles={maxGitStatusFiles}
liteMode={liteMode}
setCachedStateField={setCachedStateField}
/>
)}

View file

@ -165,6 +165,8 @@ export interface ExtensionStateContextType extends ExtensionState {
setIncludeCurrentTime: (value: boolean) => void
includeCurrentCost?: boolean
setIncludeCurrentCost: (value: boolean) => void
liteMode?: boolean
setLiteMode: (value: boolean) => void
}
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@ -596,6 +598,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setIncludeCurrentTime,
includeCurrentCost,
setIncludeCurrentCost,
liteMode: state.liteMode,
setLiteMode: (value) => setState((prevState) => ({ ...prevState, liteMode: value })),
}
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>