Create new context management section in settings

This commit is contained in:
Matt Rubens 2025-03-14 09:45:31 -04:00
parent 7dcd10593a
commit a679c95412
4 changed files with 172 additions and 77 deletions

View file

@ -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,
@ -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}
@ -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>
)

View file

@ -0,0 +1,99 @@
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
showRooIgnoredFiles?: boolean
setCachedStateField: SetCachedStateField<"terminalOutputLineLimit" | "maxOpenTabsContext" | "showRooIgnoredFiles">
}
export const ContextManagementSettings = ({
terminalOutputLineLimit,
maxOpenTabsContext,
showRooIgnoredFiles,
setCachedStateField,
className,
...props
}: ContextManagementSettingsProps) => {
return (
<div className={cn("flex flex-col gap-2", className)} {...props}>
<SectionHeader>
<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"
/>
<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={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>
)
}

View file

@ -11,6 +11,7 @@ import {
AlertTriangle,
} from "lucide-react"
import { Database } from "lucide-react"
import { ExperimentId } from "../../../../src/shared/experiments"
import { TelemetrySetting } from "../../../../src/shared/TelemetrySetting"
import { ApiConfiguration } from "../../../../src/shared/api"
@ -39,6 +40,7 @@ import { AutoApproveSettings } from "./AutoApproveSettings"
import { BrowserSettings } from "./BrowserSettings"
import { CheckpointSettings } from "./CheckpointSettings"
import { NotificationSettings } from "./NotificationSettings"
import { ContextManagementSettings } from "./ContextManagementSettings"
import { AdvancedSettings } from "./AdvancedSettings"
import { SettingsFooter } from "./SettingsFooter"
import { Section } from "./Section"
@ -230,6 +232,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
const browserRef = useRef<HTMLDivElement>(null)
const checkpointRef = useRef<HTMLDivElement>(null)
const notificationsRef = useRef<HTMLDivElement>(null)
const contextRef = useRef<HTMLDivElement>(null)
const advancedRef = useRef<HTMLDivElement>(null)
const experimentalRef = useRef<HTMLDivElement>(null)
@ -242,6 +245,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
{ id: "browser", icon: SquareMousePointer, ref: browserRef },
{ id: "checkpoint", icon: GitBranch, ref: checkpointRef },
{ id: "notifications", icon: Bell, ref: notificationsRef },
{ id: "context", icon: Database, ref: contextRef },
{ id: "advanced", icon: Cog, ref: advancedRef },
{ id: "experimental", icon: FlaskConical, ref: experimentalRef },
],
@ -255,6 +259,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
{ ref: browserRef, id: "browser" },
{ ref: checkpointRef, id: "checkpoint" },
{ ref: notificationsRef, id: "notifications" },
{ ref: contextRef, id: "context" },
{ ref: advancedRef, id: "advanced" },
{ ref: experimentalRef, id: "experimental" },
]
@ -401,14 +406,20 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
/>
</div>
<div ref={contextRef}>
<ContextManagementSettings
terminalOutputLineLimit={terminalOutputLineLimit}
maxOpenTabsContext={maxOpenTabsContext}
showRooIgnoredFiles={showRooIgnoredFiles}
setCachedStateField={setCachedStateField}
/>
</div>
<div ref={advancedRef}>
<AdvancedSettings
rateLimitSeconds={rateLimitSeconds}
terminalOutputLineLimit={terminalOutputLineLimit}
maxOpenTabsContext={maxOpenTabsContext}
diffEnabled={diffEnabled}
fuzzyMatchThreshold={fuzzyMatchThreshold}
showRooIgnoredFiles={showRooIgnoredFiles}
setCachedStateField={setCachedStateField}
setExperimentEnabled={setExperimentEnabled}
experiments={experiments}

View file

@ -0,0 +1,58 @@
import { render, screen, fireEvent } from "@testing-library/react"
import { ContextManagementSettings } from "../ContextManagementSettings"
describe("ContextManagementSettings", () => {
const defaultProps = {
terminalOutputLineLimit: 500,
maxOpenTabsContext: 20,
showRooIgnoredFiles: false,
setCachedStateField: jest.fn(),
}
beforeEach(() => {
jest.clearAllMocks()
})
it("renders all controls", () => {
render(<ContextManagementSettings {...defaultProps} />)
// Terminal output limit
expect(screen.getByText("Terminal output limit")).toBeInTheDocument()
expect(screen.getByRole("slider", { name: /Terminal output limit/i })).toHaveValue("500")
// Open tabs context limit
expect(screen.getByText("Open tabs context limit")).toBeInTheDocument()
expect(screen.getByRole("slider", { name: /Open tabs context limit/i })).toHaveValue("20")
// Show .rooignore'd files
expect(screen.getByText("Show .rooignore'd files in lists and searches")).toBeInTheDocument()
expect(screen.getByRole("checkbox")).not.toBeChecked()
})
it("updates terminal output limit", () => {
render(<ContextManagementSettings {...defaultProps} />)
const slider = screen.getByRole("slider", { name: /Terminal output limit/i })
fireEvent.change(slider, { target: { value: "1000" } })
expect(defaultProps.setCachedStateField).toHaveBeenCalledWith("terminalOutputLineLimit", 1000)
})
it("updates open tabs context limit", () => {
render(<ContextManagementSettings {...defaultProps} />)
const slider = screen.getByRole("slider", { name: /Open tabs context limit/i })
fireEvent.change(slider, { target: { value: "50" } })
expect(defaultProps.setCachedStateField).toHaveBeenCalledWith("maxOpenTabsContext", 50)
})
it("updates show rooignored files setting", () => {
render(<ContextManagementSettings {...defaultProps} />)
const checkbox = screen.getByRole("checkbox")
fireEvent.click(checkbox)
expect(defaultProps.setCachedStateField).toHaveBeenCalledWith("showRooIgnoredFiles", true)
})
})