Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/core/Cline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3501,14 +3501,15 @@ export class Cline extends EventEmitter<ClineEvents> {
async getEnvironmentDetails(includeFileDetails: boolean = false) {
let details = ""

const { terminalOutputLineLimit } = (await this.providerRef.deref()?.getState()) ?? {}
const { terminalOutputLineLimit, maxWorkspaceFiles } = (await this.providerRef.deref()?.getState()) ?? {}

// It could be useful for cline to know if the user went from one or no file to another between messages, so we always include this context
details += "\n\n# VSCode Visible Files"
const visibleFilePaths = vscode.window.visibleTextEditors
?.map((editor) => editor.document?.uri?.fsPath)
.filter(Boolean)
.map((absolutePath) => path.relative(cwd, absolutePath))
.slice(0, maxWorkspaceFiles ?? 200)

// Filter paths through rooIgnoreController
const allowedVisibleFiles = this.rooIgnoreController
Expand Down Expand Up @@ -3715,7 +3716,8 @@ export class Cline extends EventEmitter<ClineEvents> {
// don't want to immediately access desktop since it would show permission popup
details += "(Desktop files not shown automatically. Use list_files to explore if needed.)"
} else {
const [files, didHitLimit] = await listFiles(cwd, true, 200)
const maxFiles = maxWorkspaceFiles ?? 200
const [files, didHitLimit] = await listFiles(cwd, true, maxFiles)
const { showRooIgnoredFiles } = (await this.providerRef.deref()?.getState()) ?? {}
const result = formatResponse.formatFilesList(
cwd,
Expand Down
8 changes: 8 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.updateGlobalState("maxOpenTabsContext", tabCount)
await this.postStateToWebview()
break
case "maxWorkspaceFiles":
const fileCount = Math.min(Math.max(0, message.value ?? 200), 500)
await this.updateGlobalState("maxWorkspaceFiles", fileCount)
await this.postStateToWebview()
break
case "browserToolEnabled":
await this.updateGlobalState("browserToolEnabled", message.bool ?? true)
await this.postStateToWebview()
Expand Down Expand Up @@ -2297,6 +2302,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
autoApprovalEnabled,
experiments,
maxOpenTabsContext,
maxWorkspaceFiles,
browserToolEnabled,
telemetrySetting,
showRooIgnoredFiles,
Expand Down Expand Up @@ -2359,6 +2365,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
experiments: experiments ?? experimentDefault,
mcpServers: this.mcpHub?.getAllServers() ?? [],
maxOpenTabsContext: maxOpenTabsContext ?? 20,
maxWorkspaceFiles: maxWorkspaceFiles ?? 200,
cwd,
browserToolEnabled: browserToolEnabled ?? true,
telemetrySetting,
Expand Down Expand Up @@ -2516,6 +2523,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
autoApprovalEnabled: stateValues.autoApprovalEnabled ?? false,
customModes,
maxOpenTabsContext: stateValues.maxOpenTabsContext ?? 20,
maxWorkspaceFiles: stateValues.maxWorkspaceFiles ?? 200,
openRouterUseMiddleOutTransform: stateValues.openRouterUseMiddleOutTransform ?? true,
browserToolEnabled: stateValues.browserToolEnabled ?? true,
telemetrySetting: stateValues.telemetrySetting || "unset",
Expand Down
12 changes: 12 additions & 0 deletions src/core/webview/__tests__/ClineProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ describe("ClineProvider", () => {
customModes: [],
experiments: experimentDefault,
maxOpenTabsContext: 20,
maxWorkspaceFiles: 200,
browserToolEnabled: true,
telemetrySetting: "unset",
showRooIgnoredFiles: true,
Expand Down Expand Up @@ -794,6 +795,17 @@ describe("ClineProvider", () => {
expect(state.customModePrompts).toEqual({})
})

test("handles maxWorkspaceFiles message", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]

await messageHandler({ type: "maxWorkspaceFiles", value: 300 })

expect(mockContextProxy.updateGlobalState).toHaveBeenCalledWith("maxWorkspaceFiles", 300)
expect(mockContext.globalState.update).toHaveBeenCalledWith("maxWorkspaceFiles", 300)
expect(mockPostMessage).toHaveBeenCalled()
})

test.only("uses mode-specific custom instructions in Cline initialization", async () => {
// Setup mock state
const modeCustomInstructions = "Code mode instructions"
Expand Down
1 change: 1 addition & 0 deletions src/exports/roo-code.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export type GlobalStateKey =
| "modelMaxTokens"
| "mistralCodestralUrl"
| "maxOpenTabsContext"
| "maxWorkspaceFiles"
| "browserToolEnabled"
| "lmStudioSpeculativeDecodingEnabled"
| "lmStudioDraftModelId"
Expand Down
1 change: 1 addition & 0 deletions src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export interface ExtensionState {
customModes: ModeConfig[]
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled)
maxOpenTabsContext: number // Maximum number of VSCode open tabs to include in context (0-500)
maxWorkspaceFiles: number // Maximum number of files to include in current working directory details (0-500)
cwd?: string // Current working directory
telemetrySetting: TelemetrySetting
telemetryKey?: string
Expand Down
1 change: 1 addition & 0 deletions src/shared/WebviewMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export interface WebviewMessage {
| "checkpointRestore"
| "deleteMcpServer"
| "maxOpenTabsContext"
| "maxWorkspaceFiles"
| "humanRelayResponse"
| "humanRelayCancel"
| "browserToolEnabled"
Expand Down
1 change: 1 addition & 0 deletions src/shared/globalState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export const GLOBAL_STATE_KEYS = [
"telemetrySetting",
"showRooIgnoredFiles",
"remoteBrowserEnabled",
"maxWorkspaceFiles",
] as const

type CheckGlobalStateKeysExhaustiveness =
Expand Down
1 change: 1 addition & 0 deletions webview-ui/src/__mocks__/lucide-react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export const Check = () => React.createElement("div")
export const ChevronsUpDown = () => React.createElement("div")
export const Loader = () => React.createElement("div")
export const X = () => React.createElement("div")
export const Database = (props: any) => React.createElement("span", { "data-testid": "database-icon", ...props })
75 changes: 1 addition & 74 deletions webview-ui/src/components/settings/AdvancedSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,16 @@ import { Section } from "./Section"

type AdvancedSettingsProps = HTMLAttributes<HTMLDivElement> & {
rateLimitSeconds: number
terminalOutputLineLimit?: number
maxOpenTabsContext: number
diffEnabled?: boolean
fuzzyMatchThreshold?: number
showRooIgnoredFiles?: boolean
setCachedStateField: SetCachedStateField<
| "rateLimitSeconds"
| "terminalOutputLineLimit"
| "maxOpenTabsContext"
| "diffEnabled"
| "fuzzyMatchThreshold"
| "showRooIgnoredFiles"
>
setCachedStateField: SetCachedStateField<"rateLimitSeconds" | "diffEnabled" | "fuzzyMatchThreshold">
experiments: Record<ExperimentId, boolean>
setExperimentEnabled: SetExperimentEnabled
}
export const AdvancedSettings = ({
rateLimitSeconds,
terminalOutputLineLimit,
maxOpenTabsContext,
diffEnabled,
fuzzyMatchThreshold,
showRooIgnoredFiles,
setCachedStateField,
experiments,
setExperimentEnabled,
Expand Down Expand Up @@ -71,52 +58,6 @@ export const AdvancedSettings = ({
<p className="text-vscode-descriptionForeground text-sm mt-0">Minimum time between API requests.</p>
</div>

<div>
<div className="flex flex-col gap-2">
<span className="font-medium">Terminal output limit</span>
<div className="flex items-center gap-2">
<input
type="range"
min="100"
max="5000"
step="100"
value={terminalOutputLineLimit ?? 500}
onChange={(e) =>
setCachedStateField("terminalOutputLineLimit", parseInt(e.target.value))
}
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
/>
<span style={{ ...sliderLabelStyle }}>{terminalOutputLineLimit ?? 500}</span>
</div>
</div>
<p className="text-vscode-descriptionForeground text-sm mt-0">
Maximum number of lines to include in terminal output when executing commands. When exceeded
lines will be removed from the middle, saving tokens.
</p>
</div>

<div>
<div className="flex flex-col gap-2">
<span className="font-medium">Open tabs context limit</span>
<div className="flex items-center gap-2">
<input
type="range"
min="0"
max="500"
step="1"
value={maxOpenTabsContext ?? 20}
onChange={(e) => setCachedStateField("maxOpenTabsContext", parseInt(e.target.value))}
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
/>
<span style={{ ...sliderLabelStyle }}>{maxOpenTabsContext ?? 20}</span>
</div>
</div>
<p className="text-vscode-descriptionForeground text-sm mt-0">
Maximum number of VSCode open tabs to include in context. Higher values provide more context but
increase token usage.
</p>
</div>

<div>
<VSCodeCheckbox
checked={diffEnabled}
Expand Down Expand Up @@ -203,20 +144,6 @@ export const AdvancedSettings = ({
</div>
)}
</div>

<div>
<VSCodeCheckbox
checked={showRooIgnoredFiles}
onChange={(e: any) => {
setCachedStateField("showRooIgnoredFiles", e.target.checked)
}}>
<span className="font-medium">Show .rooignore'd files in lists and searches</span>
</VSCodeCheckbox>
<p className="text-vscode-descriptionForeground text-sm mt-0">
When enabled, files matching patterns in .rooignore will be shown in lists with a lock symbol.
When disabled, these files will be completely hidden from file lists and searches.
</p>
</div>
</Section>
</div>
)
Expand Down
129 changes: 129 additions & 0 deletions webview-ui/src/components/settings/ContextManagementSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { HTMLAttributes } from "react"
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
import { Database } from "lucide-react"

import { cn } from "@/lib/utils"

import { SetCachedStateField } from "./types"
import { sliderLabelStyle } from "./styles"
import { SectionHeader } from "./SectionHeader"
import { Section } from "./Section"

type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
terminalOutputLineLimit?: number
maxOpenTabsContext: number
maxWorkspaceFiles: number
showRooIgnoredFiles?: boolean
setCachedStateField: SetCachedStateField<
"terminalOutputLineLimit" | "maxOpenTabsContext" | "maxWorkspaceFiles" | "showRooIgnoredFiles"
>
}

export const ContextManagementSettings = ({
terminalOutputLineLimit,
maxOpenTabsContext,
maxWorkspaceFiles,
showRooIgnoredFiles,
setCachedStateField,
className,
...props
}: ContextManagementSettingsProps) => {
return (
<div className={cn("flex flex-col gap-2", className)} {...props}>
<SectionHeader description="Control what information is included in the AI's context window, affecting token usage and response quality">
<div className="flex items-center gap-2">
<Database className="w-4" />
<div>Context Management</div>
</div>
</SectionHeader>

<Section>
<div>
<div className="flex flex-col gap-2">
<span className="font-medium">Terminal output limit</span>
<div className="flex items-center gap-2">
<input
type="range"
min="100"
max="5000"
step="100"
value={terminalOutputLineLimit ?? 500}
onChange={(e) =>
setCachedStateField("terminalOutputLineLimit", parseInt(e.target.value))
}
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
data-testid="terminal-output-limit-slider"
/>
<span style={{ ...sliderLabelStyle }}>{terminalOutputLineLimit ?? 500}</span>
</div>
</div>
<p className="text-vscode-descriptionForeground text-sm mt-0">
Maximum number of lines to include in terminal output when executing commands. When exceeded
lines will be removed from the middle, saving tokens.
</p>
</div>

<div>
<div className="flex flex-col gap-2">
<span className="font-medium">Open tabs context limit</span>
<div className="flex items-center gap-2">
<input
type="range"
min="0"
max="500"
step="1"
value={maxOpenTabsContext ?? 20}
onChange={(e) => setCachedStateField("maxOpenTabsContext", parseInt(e.target.value))}
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
data-testid="open-tabs-limit-slider"
/>
<span style={{ ...sliderLabelStyle }}>{maxOpenTabsContext ?? 20}</span>
</div>
</div>
<p className="text-vscode-descriptionForeground text-sm mt-0">
Maximum number of VSCode open tabs to include in context. Higher values provide more context but
increase token usage.
</p>
</div>

<div>
<div className="flex flex-col gap-2">
<span className="font-medium">Workspace files context limit</span>
<div className="flex items-center gap-2">
<input
type="range"
min="0"
max="500"
step="1"
value={maxWorkspaceFiles ?? 200}
onChange={(e) => setCachedStateField("maxWorkspaceFiles", parseInt(e.target.value))}
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
data-testid="workspace-files-limit-slider"
/>
<span style={{ ...sliderLabelStyle }}>{maxWorkspaceFiles ?? 200}</span>
</div>
</div>
<p className="text-vscode-descriptionForeground text-sm mt-0">
Maximum number of files to include in current working directory details. Higher values provide
more context but increase token usage.
</p>
</div>

<div>
<VSCodeCheckbox
checked={showRooIgnoredFiles}
onChange={(e: any) => {
setCachedStateField("showRooIgnoredFiles", e.target.checked)
}}
data-testid="show-rooignored-files-checkbox">
<span className="font-medium">Show .rooignore'd files in lists and searches</span>
</VSCodeCheckbox>
<p className="text-vscode-descriptionForeground text-sm mt-0">
When enabled, files matching patterns in .rooignore will be shown in lists with a lock symbol.
When disabled, these files will be completely hidden from file lists and searches.
</p>
</div>
</Section>
</div>
)
}
Loading