Skip to content

Commit d68eeb3

Browse files
committed
fix: add includeVSCodeFileContext setting to control VSCode file context in API calls
- Add new global setting includeVSCodeFileContext (defaults to true) - Update getEnvironmentDetails to conditionally include VSCode file context - Add setting to ExtensionState and webview message handler - Add comprehensive tests for the new functionality This fixes issue #6194 where excessive VSCode file context was causing connection errors with LLMs that have limited context windows.
1 parent 2170c61 commit d68eeb3

File tree

8 files changed

+128
-39
lines changed

8 files changed

+128
-39
lines changed

packages/types/src/global-settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export const globalSettingsSchema = z.object({
101101
maxWorkspaceFiles: z.number().optional(),
102102
showRooIgnoredFiles: z.boolean().optional(),
103103
maxReadFileLine: z.number().optional(),
104+
includeVSCodeFileContext: z.boolean().optional(),
104105

105106
terminalOutputLineLimit: z.number().optional(),
106107
terminalOutputCharacterLimit: z.number().optional(),
@@ -272,6 +273,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
272273
maxWorkspaceFiles: 200,
273274
showRooIgnoredFiles: true,
274275
maxReadFileLine: -1, // -1 to enable full file reading.
276+
includeVSCodeFileContext: true, // Include VSCode file context in all API calls by default
275277

276278
includeDiagnosticMessages: true,
277279
maxDiagnosticMessages: 50,

src/core/environment/__tests__/getEnvironmentDetails.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ describe("getEnvironmentDetails", () => {
7373
terminalOutputLineLimit: 100,
7474
maxWorkspaceFiles: 50,
7575
maxOpenTabsContext: 10,
76+
includeVSCodeFileContext: true,
7677
mode: "code",
7778
customModes: [],
7879
experiments: {},
@@ -361,4 +362,54 @@ describe("getEnvironmentDetails", () => {
361362

362363
await expect(getEnvironmentDetails(mockCline as Task)).resolves.not.toThrow()
363364
})
365+
366+
describe("VSCode file context inclusion", () => {
367+
it("should include VSCode file context when includeVSCodeFileContext is true", async () => {
368+
mockProvider.getState.mockResolvedValue({
369+
...mockState,
370+
includeVSCodeFileContext: true,
371+
})
372+
373+
const result = await getEnvironmentDetails(mockCline as Task, false)
374+
375+
expect(result).toContain("# VSCode Visible Files")
376+
expect(result).toContain("# VSCode Open Tabs")
377+
})
378+
379+
it("should exclude VSCode file context when includeVSCodeFileContext is false and includeFileDetails is false", async () => {
380+
mockProvider.getState.mockResolvedValue({
381+
...mockState,
382+
includeVSCodeFileContext: false,
383+
})
384+
385+
const result = await getEnvironmentDetails(mockCline as Task, false)
386+
387+
expect(result).not.toContain("# VSCode Visible Files")
388+
expect(result).not.toContain("# VSCode Open Tabs")
389+
})
390+
391+
it("should always include VSCode file context when includeFileDetails is true regardless of includeVSCodeFileContext", async () => {
392+
mockProvider.getState.mockResolvedValue({
393+
...mockState,
394+
includeVSCodeFileContext: false,
395+
})
396+
397+
const result = await getEnvironmentDetails(mockCline as Task, true)
398+
399+
expect(result).toContain("# VSCode Visible Files")
400+
expect(result).toContain("# VSCode Open Tabs")
401+
})
402+
403+
it("should default to including VSCode file context when includeVSCodeFileContext is undefined", async () => {
404+
mockProvider.getState.mockResolvedValue({
405+
...mockState,
406+
includeVSCodeFileContext: undefined,
407+
})
408+
409+
const result = await getEnvironmentDetails(mockCline as Task, false)
410+
411+
expect(result).toContain("# VSCode Visible Files")
412+
expect(result).toContain("# VSCode Open Tabs")
413+
})
414+
})
364415
})

src/core/environment/getEnvironmentDetails.ts

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,48 +30,54 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
3030
terminalOutputLineLimit = 500,
3131
terminalOutputCharacterLimit = DEFAULT_TERMINAL_OUTPUT_CHARACTER_LIMIT,
3232
maxWorkspaceFiles = 200,
33+
includeVSCodeFileContext = true,
3334
} = state ?? {}
3435

35-
// It could be useful for cline to know if the user went from one or no
36-
// file to another between messages, so we always include this context.
37-
details += "\n\n# VSCode Visible Files"
38-
39-
const visibleFilePaths = vscode.window.visibleTextEditors
40-
?.map((editor) => editor.document?.uri?.fsPath)
41-
.filter(Boolean)
42-
.map((absolutePath) => path.relative(cline.cwd, absolutePath))
43-
.slice(0, maxWorkspaceFiles)
44-
45-
// Filter paths through rooIgnoreController
46-
const allowedVisibleFiles = cline.rooIgnoreController
47-
? cline.rooIgnoreController.filterPaths(visibleFilePaths)
48-
: visibleFilePaths.map((p) => p.toPosix()).join("\n")
49-
50-
if (allowedVisibleFiles) {
51-
details += `\n${allowedVisibleFiles}`
52-
} else {
53-
details += "\n(No visible files)"
54-
}
36+
// Only include VSCode file context if enabled in settings or if this is the first request
37+
const shouldIncludeVSCodeContext = includeFileDetails || includeVSCodeFileContext
38+
39+
if (shouldIncludeVSCodeContext) {
40+
// It could be useful for cline to know if the user went from one or no
41+
// file to another between messages, so we always include this context.
42+
details += "\n\n# VSCode Visible Files"
43+
44+
const visibleFilePaths = vscode.window.visibleTextEditors
45+
?.map((editor) => editor.document?.uri?.fsPath)
46+
.filter(Boolean)
47+
.map((absolutePath) => path.relative(cline.cwd, absolutePath))
48+
.slice(0, maxWorkspaceFiles)
5549

56-
details += "\n\n# VSCode Open Tabs"
57-
const { maxOpenTabsContext } = state ?? {}
58-
const maxTabs = maxOpenTabsContext ?? 20
59-
const openTabPaths = vscode.window.tabGroups.all
60-
.flatMap((group) => group.tabs)
61-
.map((tab) => (tab.input as vscode.TabInputText)?.uri?.fsPath)
62-
.filter(Boolean)
63-
.map((absolutePath) => path.relative(cline.cwd, absolutePath).toPosix())
64-
.slice(0, maxTabs)
65-
66-
// Filter paths through rooIgnoreController
67-
const allowedOpenTabs = cline.rooIgnoreController
68-
? cline.rooIgnoreController.filterPaths(openTabPaths)
69-
: openTabPaths.map((p) => p.toPosix()).join("\n")
70-
71-
if (allowedOpenTabs) {
72-
details += `\n${allowedOpenTabs}`
73-
} else {
74-
details += "\n(No open tabs)"
50+
// Filter paths through rooIgnoreController
51+
const allowedVisibleFiles = cline.rooIgnoreController
52+
? cline.rooIgnoreController.filterPaths(visibleFilePaths)
53+
: visibleFilePaths.map((p) => p.toPosix()).join("\n")
54+
55+
if (allowedVisibleFiles) {
56+
details += `\n${allowedVisibleFiles}`
57+
} else {
58+
details += "\n(No visible files)"
59+
}
60+
61+
details += "\n\n# VSCode Open Tabs"
62+
const { maxOpenTabsContext } = state ?? {}
63+
const maxTabs = maxOpenTabsContext ?? 20
64+
const openTabPaths = vscode.window.tabGroups.all
65+
.flatMap((group) => group.tabs)
66+
.map((tab) => (tab.input as vscode.TabInputText)?.uri?.fsPath)
67+
.filter(Boolean)
68+
.map((absolutePath) => path.relative(cline.cwd, absolutePath).toPosix())
69+
.slice(0, maxTabs)
70+
71+
// Filter paths through rooIgnoreController
72+
const allowedOpenTabs = cline.rooIgnoreController
73+
? cline.rooIgnoreController.filterPaths(openTabPaths)
74+
: openTabPaths.map((p) => p.toPosix()).join("\n")
75+
76+
if (allowedOpenTabs) {
77+
details += `\n${allowedOpenTabs}`
78+
} else {
79+
details += "\n(No open tabs)"
80+
}
7581
}
7682

7783
// Get task-specific and background terminals.

src/core/webview/ClineProvider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,7 @@ export class ClineProvider
14201420
experiments,
14211421
maxOpenTabsContext,
14221422
maxWorkspaceFiles,
1423+
includeVSCodeFileContext,
14231424
browserToolEnabled,
14241425
telemetrySetting,
14251426
showRooIgnoredFiles,
@@ -1523,6 +1524,7 @@ export class ClineProvider
15231524
mcpServers: this.mcpHub?.getAllServers() ?? [],
15241525
maxOpenTabsContext: maxOpenTabsContext ?? 20,
15251526
maxWorkspaceFiles: maxWorkspaceFiles ?? 200,
1527+
includeVSCodeFileContext: includeVSCodeFileContext ?? true,
15261528
cwd,
15271529
browserToolEnabled: browserToolEnabled ?? true,
15281530
telemetrySetting,
@@ -1697,6 +1699,7 @@ export class ClineProvider
16971699
customModes,
16981700
maxOpenTabsContext: stateValues.maxOpenTabsContext ?? 20,
16991701
maxWorkspaceFiles: stateValues.maxWorkspaceFiles ?? 200,
1702+
includeVSCodeFileContext: stateValues.includeVSCodeFileContext ?? true,
17001703
openRouterUseMiddleOutTransform: stateValues.openRouterUseMiddleOutTransform ?? true,
17011704
browserToolEnabled: stateValues.browserToolEnabled ?? true,
17021705
telemetrySetting: stateValues.telemetrySetting || "unset",

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ describe("ClineProvider", () => {
528528
experiments: experimentDefault,
529529
maxOpenTabsContext: 20,
530530
maxWorkspaceFiles: 200,
531+
includeVSCodeFileContext: true,
531532
browserToolEnabled: true,
532533
telemetrySetting: "unset",
533534
showRooIgnoredFiles: true,
@@ -1079,6 +1080,25 @@ describe("ClineProvider", () => {
10791080
expect(mockPostMessage).toHaveBeenCalled()
10801081
})
10811082

1083+
test("handles includeVSCodeFileContext message", async () => {
1084+
await provider.resolveWebviewView(mockWebviewView)
1085+
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]
1086+
1087+
// Test setting to false
1088+
await messageHandler({ type: "includeVSCodeFileContext", bool: false })
1089+
1090+
expect(updateGlobalStateSpy).toHaveBeenCalledWith("includeVSCodeFileContext", false)
1091+
expect(mockContext.globalState.update).toHaveBeenCalledWith("includeVSCodeFileContext", false)
1092+
expect(mockPostMessage).toHaveBeenCalled()
1093+
1094+
// Test setting to true
1095+
await messageHandler({ type: "includeVSCodeFileContext", bool: true })
1096+
1097+
expect(updateGlobalStateSpy).toHaveBeenCalledWith("includeVSCodeFileContext", true)
1098+
expect(mockContext.globalState.update).toHaveBeenCalledWith("includeVSCodeFileContext", true)
1099+
expect(mockPostMessage).toHaveBeenCalled()
1100+
})
1101+
10821102
test("handles mode-specific custom instructions updates", async () => {
10831103
await provider.resolveWebviewView(mockWebviewView)
10841104
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]

src/core/webview/webviewMessageHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,10 @@ export const webviewMessageHandler = async (
12361236
await updateGlobalState("maxWorkspaceFiles", fileCount)
12371237
await provider.postStateToWebview()
12381238
break
1239+
case "includeVSCodeFileContext":
1240+
await updateGlobalState("includeVSCodeFileContext", message.bool ?? true)
1241+
await provider.postStateToWebview()
1242+
break
12391243
case "alwaysAllowFollowupQuestions":
12401244
await updateGlobalState("alwaysAllowFollowupQuestions", message.bool ?? false)
12411245
await provider.postStateToWebview()

src/shared/ExtensionMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ export type ExtensionState = Pick<
226226
// | "maxOpenTabsContext" // Optional in GlobalSettings, required here.
227227
// | "maxWorkspaceFiles" // Optional in GlobalSettings, required here.
228228
// | "showRooIgnoredFiles" // Optional in GlobalSettings, required here.
229+
// | "includeVSCodeFileContext" // Optional in GlobalSettings, required here.
229230
// | "maxReadFileLine" // Optional in GlobalSettings, required here.
230231
| "maxConcurrentFileReads" // Optional in GlobalSettings, required here.
231232
| "terminalOutputLineLimit"
@@ -277,6 +278,7 @@ export type ExtensionState = Pick<
277278
maxOpenTabsContext: number // Maximum number of VSCode open tabs to include in context (0-500)
278279
maxWorkspaceFiles: number // Maximum number of files to include in current working directory details (0-500)
279280
showRooIgnoredFiles: boolean // Whether to show .rooignore'd files in listings
281+
includeVSCodeFileContext: boolean // Whether to include VSCode file context (visible files and open tabs) in API calls after the first one
280282
maxReadFileLine: number // Maximum number of lines to read from a file before truncating
281283

282284
experiments: Experiments // Map of experiment IDs to their enabled state

src/shared/WebviewMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ export interface WebviewMessage {
151151
| "deleteMcpServer"
152152
| "maxOpenTabsContext"
153153
| "maxWorkspaceFiles"
154+
| "includeVSCodeFileContext"
154155
| "humanRelayResponse"
155156
| "humanRelayCancel"
156157
| "browserToolEnabled"

0 commit comments

Comments
 (0)