Skip to content

Commit 7165d7f

Browse files
authored
Merge pull request #1650 from RooVetGit/context_management
Context management
2 parents 7dcd105 + 9bbbaf2 commit 7165d7f

File tree

14 files changed

+253
-79
lines changed

14 files changed

+253
-79
lines changed

src/core/Cline.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,14 +3501,15 @@ export class Cline extends EventEmitter<ClineEvents> {
35013501
async getEnvironmentDetails(includeFileDetails: boolean = false) {
35023502
let details = ""
35033503

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

35063506
// 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
35073507
details += "\n\n# VSCode Visible Files"
35083508
const visibleFilePaths = vscode.window.visibleTextEditors
35093509
?.map((editor) => editor.document?.uri?.fsPath)
35103510
.filter(Boolean)
35113511
.map((absolutePath) => path.relative(cwd, absolutePath))
3512+
.slice(0, maxWorkspaceFiles ?? 200)
35123513

35133514
// Filter paths through rooIgnoreController
35143515
const allowedVisibleFiles = this.rooIgnoreController
@@ -3715,7 +3716,8 @@ export class Cline extends EventEmitter<ClineEvents> {
37153716
// don't want to immediately access desktop since it would show permission popup
37163717
details += "(Desktop files not shown automatically. Use list_files to explore if needed.)"
37173718
} else {
3718-
const [files, didHitLimit] = await listFiles(cwd, true, 200)
3719+
const maxFiles = maxWorkspaceFiles ?? 200
3720+
const [files, didHitLimit] = await listFiles(cwd, true, maxFiles)
37193721
const { showRooIgnoredFiles } = (await this.providerRef.deref()?.getState()) ?? {}
37203722
const result = formatResponse.formatFilesList(
37213723
cwd,

src/core/webview/ClineProvider.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
15181518
await this.updateGlobalState("maxOpenTabsContext", tabCount)
15191519
await this.postStateToWebview()
15201520
break
1521+
case "maxWorkspaceFiles":
1522+
const fileCount = Math.min(Math.max(0, message.value ?? 200), 500)
1523+
await this.updateGlobalState("maxWorkspaceFiles", fileCount)
1524+
await this.postStateToWebview()
1525+
break
15211526
case "browserToolEnabled":
15221527
await this.updateGlobalState("browserToolEnabled", message.bool ?? true)
15231528
await this.postStateToWebview()
@@ -2297,6 +2302,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
22972302
autoApprovalEnabled,
22982303
experiments,
22992304
maxOpenTabsContext,
2305+
maxWorkspaceFiles,
23002306
browserToolEnabled,
23012307
telemetrySetting,
23022308
showRooIgnoredFiles,
@@ -2359,6 +2365,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
23592365
experiments: experiments ?? experimentDefault,
23602366
mcpServers: this.mcpHub?.getAllServers() ?? [],
23612367
maxOpenTabsContext: maxOpenTabsContext ?? 20,
2368+
maxWorkspaceFiles: maxWorkspaceFiles ?? 200,
23622369
cwd,
23632370
browserToolEnabled: browserToolEnabled ?? true,
23642371
telemetrySetting,
@@ -2516,6 +2523,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
25162523
autoApprovalEnabled: stateValues.autoApprovalEnabled ?? false,
25172524
customModes,
25182525
maxOpenTabsContext: stateValues.maxOpenTabsContext ?? 20,
2526+
maxWorkspaceFiles: stateValues.maxWorkspaceFiles ?? 200,
25192527
openRouterUseMiddleOutTransform: stateValues.openRouterUseMiddleOutTransform ?? true,
25202528
browserToolEnabled: stateValues.browserToolEnabled ?? true,
25212529
telemetrySetting: stateValues.telemetrySetting || "unset",

src/core/webview/__tests__/ClineProvider.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ describe("ClineProvider", () => {
448448
customModes: [],
449449
experiments: experimentDefault,
450450
maxOpenTabsContext: 20,
451+
maxWorkspaceFiles: 200,
451452
browserToolEnabled: true,
452453
telemetrySetting: "unset",
453454
showRooIgnoredFiles: true,
@@ -794,6 +795,17 @@ describe("ClineProvider", () => {
794795
expect(state.customModePrompts).toEqual({})
795796
})
796797

798+
test("handles maxWorkspaceFiles message", async () => {
799+
await provider.resolveWebviewView(mockWebviewView)
800+
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
801+
802+
await messageHandler({ type: "maxWorkspaceFiles", value: 300 })
803+
804+
expect(mockContextProxy.updateGlobalState).toHaveBeenCalledWith("maxWorkspaceFiles", 300)
805+
expect(mockContext.globalState.update).toHaveBeenCalledWith("maxWorkspaceFiles", 300)
806+
expect(mockPostMessage).toHaveBeenCalled()
807+
})
808+
797809
test.only("uses mode-specific custom instructions in Cline initialization", async () => {
798810
// Setup mock state
799811
const modeCustomInstructions = "Code mode instructions"

src/exports/roo-code.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ export type GlobalStateKey =
211211
| "modelMaxTokens"
212212
| "mistralCodestralUrl"
213213
| "maxOpenTabsContext"
214+
| "maxWorkspaceFiles"
214215
| "browserToolEnabled"
215216
| "lmStudioSpeculativeDecodingEnabled"
216217
| "lmStudioDraftModelId"

src/shared/ExtensionMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ export interface ExtensionState {
147147
customModes: ModeConfig[]
148148
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled)
149149
maxOpenTabsContext: number // Maximum number of VSCode open tabs to include in context (0-500)
150+
maxWorkspaceFiles: number // Maximum number of files to include in current working directory details (0-500)
150151
cwd?: string // Current working directory
151152
telemetrySetting: TelemetrySetting
152153
telemetryKey?: string

src/shared/WebviewMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export interface WebviewMessage {
9797
| "checkpointRestore"
9898
| "deleteMcpServer"
9999
| "maxOpenTabsContext"
100+
| "maxWorkspaceFiles"
100101
| "humanRelayResponse"
101102
| "humanRelayCancel"
102103
| "browserToolEnabled"

src/shared/globalState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export const GLOBAL_STATE_KEYS = [
116116
"telemetrySetting",
117117
"showRooIgnoredFiles",
118118
"remoteBrowserEnabled",
119+
"maxWorkspaceFiles",
119120
] as const
120121

121122
type CheckGlobalStateKeysExhaustiveness =

webview-ui/src/__mocks__/lucide-react.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export const Check = () => React.createElement("div")
44
export const ChevronsUpDown = () => React.createElement("div")
55
export const Loader = () => React.createElement("div")
66
export const X = () => React.createElement("div")
7+
export const Database = (props: any) => React.createElement("span", { "data-testid": "database-icon", ...props })

webview-ui/src/components/settings/AdvancedSettings.tsx

Lines changed: 1 addition & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,16 @@ import { Section } from "./Section"
1313

1414
type AdvancedSettingsProps = HTMLAttributes<HTMLDivElement> & {
1515
rateLimitSeconds: number
16-
terminalOutputLineLimit?: number
17-
maxOpenTabsContext: number
1816
diffEnabled?: boolean
1917
fuzzyMatchThreshold?: number
20-
showRooIgnoredFiles?: boolean
21-
setCachedStateField: SetCachedStateField<
22-
| "rateLimitSeconds"
23-
| "terminalOutputLineLimit"
24-
| "maxOpenTabsContext"
25-
| "diffEnabled"
26-
| "fuzzyMatchThreshold"
27-
| "showRooIgnoredFiles"
28-
>
18+
setCachedStateField: SetCachedStateField<"rateLimitSeconds" | "diffEnabled" | "fuzzyMatchThreshold">
2919
experiments: Record<ExperimentId, boolean>
3020
setExperimentEnabled: SetExperimentEnabled
3121
}
3222
export const AdvancedSettings = ({
3323
rateLimitSeconds,
34-
terminalOutputLineLimit,
35-
maxOpenTabsContext,
3624
diffEnabled,
3725
fuzzyMatchThreshold,
38-
showRooIgnoredFiles,
3926
setCachedStateField,
4027
experiments,
4128
setExperimentEnabled,
@@ -71,52 +58,6 @@ export const AdvancedSettings = ({
7158
<p className="text-vscode-descriptionForeground text-sm mt-0">Minimum time between API requests.</p>
7259
</div>
7360

74-
<div>
75-
<div className="flex flex-col gap-2">
76-
<span className="font-medium">Terminal output limit</span>
77-
<div className="flex items-center gap-2">
78-
<input
79-
type="range"
80-
min="100"
81-
max="5000"
82-
step="100"
83-
value={terminalOutputLineLimit ?? 500}
84-
onChange={(e) =>
85-
setCachedStateField("terminalOutputLineLimit", parseInt(e.target.value))
86-
}
87-
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
88-
/>
89-
<span style={{ ...sliderLabelStyle }}>{terminalOutputLineLimit ?? 500}</span>
90-
</div>
91-
</div>
92-
<p className="text-vscode-descriptionForeground text-sm mt-0">
93-
Maximum number of lines to include in terminal output when executing commands. When exceeded
94-
lines will be removed from the middle, saving tokens.
95-
</p>
96-
</div>
97-
98-
<div>
99-
<div className="flex flex-col gap-2">
100-
<span className="font-medium">Open tabs context limit</span>
101-
<div className="flex items-center gap-2">
102-
<input
103-
type="range"
104-
min="0"
105-
max="500"
106-
step="1"
107-
value={maxOpenTabsContext ?? 20}
108-
onChange={(e) => setCachedStateField("maxOpenTabsContext", parseInt(e.target.value))}
109-
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
110-
/>
111-
<span style={{ ...sliderLabelStyle }}>{maxOpenTabsContext ?? 20}</span>
112-
</div>
113-
</div>
114-
<p className="text-vscode-descriptionForeground text-sm mt-0">
115-
Maximum number of VSCode open tabs to include in context. Higher values provide more context but
116-
increase token usage.
117-
</p>
118-
</div>
119-
12061
<div>
12162
<VSCodeCheckbox
12263
checked={diffEnabled}
@@ -203,20 +144,6 @@ export const AdvancedSettings = ({
203144
</div>
204145
)}
205146
</div>
206-
207-
<div>
208-
<VSCodeCheckbox
209-
checked={showRooIgnoredFiles}
210-
onChange={(e: any) => {
211-
setCachedStateField("showRooIgnoredFiles", e.target.checked)
212-
}}>
213-
<span className="font-medium">Show .rooignore'd files in lists and searches</span>
214-
</VSCodeCheckbox>
215-
<p className="text-vscode-descriptionForeground text-sm mt-0">
216-
When enabled, files matching patterns in .rooignore will be shown in lists with a lock symbol.
217-
When disabled, these files will be completely hidden from file lists and searches.
218-
</p>
219-
</div>
220147
</Section>
221148
</div>
222149
)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { HTMLAttributes } from "react"
2+
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
3+
import { Database } from "lucide-react"
4+
5+
import { cn } from "@/lib/utils"
6+
7+
import { SetCachedStateField } from "./types"
8+
import { sliderLabelStyle } from "./styles"
9+
import { SectionHeader } from "./SectionHeader"
10+
import { Section } from "./Section"
11+
12+
type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
13+
terminalOutputLineLimit?: number
14+
maxOpenTabsContext: number
15+
maxWorkspaceFiles: number
16+
showRooIgnoredFiles?: boolean
17+
setCachedStateField: SetCachedStateField<
18+
"terminalOutputLineLimit" | "maxOpenTabsContext" | "maxWorkspaceFiles" | "showRooIgnoredFiles"
19+
>
20+
}
21+
22+
export const ContextManagementSettings = ({
23+
terminalOutputLineLimit,
24+
maxOpenTabsContext,
25+
maxWorkspaceFiles,
26+
showRooIgnoredFiles,
27+
setCachedStateField,
28+
className,
29+
...props
30+
}: ContextManagementSettingsProps) => {
31+
return (
32+
<div className={cn("flex flex-col gap-2", className)} {...props}>
33+
<SectionHeader description="Control what information is included in the AI's context window, affecting token usage and response quality">
34+
<div className="flex items-center gap-2">
35+
<Database className="w-4" />
36+
<div>Context Management</div>
37+
</div>
38+
</SectionHeader>
39+
40+
<Section>
41+
<div>
42+
<div className="flex flex-col gap-2">
43+
<span className="font-medium">Terminal output limit</span>
44+
<div className="flex items-center gap-2">
45+
<input
46+
type="range"
47+
min="100"
48+
max="5000"
49+
step="100"
50+
value={terminalOutputLineLimit ?? 500}
51+
onChange={(e) =>
52+
setCachedStateField("terminalOutputLineLimit", parseInt(e.target.value))
53+
}
54+
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
55+
data-testid="terminal-output-limit-slider"
56+
/>
57+
<span style={{ ...sliderLabelStyle }}>{terminalOutputLineLimit ?? 500}</span>
58+
</div>
59+
</div>
60+
<p className="text-vscode-descriptionForeground text-sm mt-0">
61+
Maximum number of lines to include in terminal output when executing commands. When exceeded
62+
lines will be removed from the middle, saving tokens.
63+
</p>
64+
</div>
65+
66+
<div>
67+
<div className="flex flex-col gap-2">
68+
<span className="font-medium">Open tabs context limit</span>
69+
<div className="flex items-center gap-2">
70+
<input
71+
type="range"
72+
min="0"
73+
max="500"
74+
step="1"
75+
value={maxOpenTabsContext ?? 20}
76+
onChange={(e) => setCachedStateField("maxOpenTabsContext", parseInt(e.target.value))}
77+
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
78+
data-testid="open-tabs-limit-slider"
79+
/>
80+
<span style={{ ...sliderLabelStyle }}>{maxOpenTabsContext ?? 20}</span>
81+
</div>
82+
</div>
83+
<p className="text-vscode-descriptionForeground text-sm mt-0">
84+
Maximum number of VSCode open tabs to include in context. Higher values provide more context but
85+
increase token usage.
86+
</p>
87+
</div>
88+
89+
<div>
90+
<div className="flex flex-col gap-2">
91+
<span className="font-medium">Workspace files context limit</span>
92+
<div className="flex items-center gap-2">
93+
<input
94+
type="range"
95+
min="0"
96+
max="500"
97+
step="1"
98+
value={maxWorkspaceFiles ?? 200}
99+
onChange={(e) => setCachedStateField("maxWorkspaceFiles", parseInt(e.target.value))}
100+
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
101+
data-testid="workspace-files-limit-slider"
102+
/>
103+
<span style={{ ...sliderLabelStyle }}>{maxWorkspaceFiles ?? 200}</span>
104+
</div>
105+
</div>
106+
<p className="text-vscode-descriptionForeground text-sm mt-0">
107+
Maximum number of files to include in current working directory details. Higher values provide
108+
more context but increase token usage.
109+
</p>
110+
</div>
111+
112+
<div>
113+
<VSCodeCheckbox
114+
checked={showRooIgnoredFiles}
115+
onChange={(e: any) => {
116+
setCachedStateField("showRooIgnoredFiles", e.target.checked)
117+
}}
118+
data-testid="show-rooignored-files-checkbox">
119+
<span className="font-medium">Show .rooignore'd files in lists and searches</span>
120+
</VSCodeCheckbox>
121+
<p className="text-vscode-descriptionForeground text-sm mt-0">
122+
When enabled, files matching patterns in .rooignore will be shown in lists with a lock symbol.
123+
When disabled, these files will be completely hidden from file lists and searches.
124+
</p>
125+
</div>
126+
</Section>
127+
</div>
128+
)
129+
}

0 commit comments

Comments
 (0)