feat: add profile-specific context condensing thresholds (#4456)

Co-authored-by: Daniel Riccio <ricciodaniel98@gmail.com>
Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
This commit is contained in:
SannidhyaSah 2025-06-21 08:32:04 +05:30 committed by GitHub
parent 37ed013157
commit 7392f14e44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 629 additions and 67 deletions

View file

@ -103,6 +103,7 @@ export const globalSettingsSchema = z.object({
customSupportPrompts: customSupportPromptsSchema.optional(),
enhancementApiConfigId: z.string().optional(),
historyPreviewCollapsed: z.boolean().optional(),
profileThresholds: z.record(z.string(), z.number()).optional(),
})
export type GlobalSettings = z.infer<typeof globalSettingsSchema>

View file

@ -8,6 +8,8 @@ import { ApiMessage } from "../task-persistence/apiMessages"
import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning"
export const N_MESSAGES_TO_KEEP = 3
export const MIN_CONDENSE_THRESHOLD = 5 // Minimum percentage of context window to trigger condensing
export const MAX_CONDENSE_THRESHOLD = 100 // Maximum percentage of context window to trigger condensing
const SUMMARY_PROMPT = `\
Your task is to create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions.

View file

@ -19,7 +19,14 @@ import {
// Create a mock ApiHandler for testing
class MockApiHandler extends BaseProvider {
createMessage(): any {
throw new Error("Method not implemented.")
// Mock implementation for testing - returns an async iterable stream
const mockStream = {
async *[Symbol.asyncIterator]() {
yield { type: "text", text: "Mock summary content" }
yield { type: "usage", inputTokens: 100, outputTokens: 50 }
},
}
return mockStream
}
getModel(): { id: string; info: ModelInfo } {
@ -265,6 +272,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
// Check the new return type
@ -304,6 +313,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result).toEqual({
@ -337,6 +348,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
const result2 = await truncateConversationIfNeeded({
@ -349,6 +362,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result1.messages).toEqual(result2.messages)
@ -368,6 +383,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
const result4 = await truncateConversationIfNeeded({
@ -380,6 +397,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result3.messages).toEqual(result4.messages)
@ -414,6 +433,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(resultWithSmall).toEqual({
messages: messagesWithSmallContent,
@ -447,6 +468,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(resultWithLarge.messages).not.toEqual(messagesWithLargeContent) // Should truncate
expect(resultWithLarge.summary).toBe("")
@ -473,6 +496,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(resultWithVeryLarge.messages).not.toEqual(messagesWithVeryLargeContent) // Should truncate
expect(resultWithVeryLarge.summary).toBe("")
@ -509,6 +534,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result).toEqual({
messages: expectedResult,
@ -554,6 +581,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
// Verify summarizeConversation was called with the right parameters
@ -619,6 +648,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
// Verify summarizeConversation was called
@ -664,6 +695,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 50, // This shouldn't matter since autoCondenseContext is false
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
// Verify summarizeConversation was not called
@ -719,6 +752,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 50, // Set threshold to 50% - our tokens are at 60%
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
// Verify summarizeConversation was called with the right parameters
@ -769,6 +804,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 50, // Set threshold to 50% - our tokens are at 40%
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
// Verify summarizeConversation was not called
@ -787,6 +824,212 @@ describe("Sliding Window", () => {
})
})
/**
* Tests for profile-specific thresholds functionality
*/
describe("profile-specific thresholds", () => {
const createModelInfo = (contextWindow: number, maxTokens?: number): ModelInfo => ({
contextWindow,
supportsPromptCache: true,
maxTokens,
})
const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
{ role: "assistant", content: "Fourth message" },
{ role: "user", content: "Fifth message" },
]
/**
* Test that a profile's specific threshold is correctly used instead of the global threshold
* when defined in profileThresholds
*/
it("should use profile-specific threshold when enabled and profile has specific threshold", async () => {
const modelInfo = createModelInfo(100000, 30000)
const profileThresholds = {
"test-profile": 60, // Profile-specific threshold of 60%
}
const currentProfileId = "test-profile"
const contextWindow = modelInfo.contextWindow
// Set tokens to 65% of context window - above profile threshold (60%) but below global default (100%)
const totalTokens = Math.floor(contextWindow * 0.65) // 65000 tokens
// Create messages with very small content in the last one to avoid token overflow
const messagesWithSmallContent = [
...messages.slice(0, -1),
{ ...messages[messages.length - 1], content: "" },
]
// Mock the summarizeConversation function
const mockSummary = "Profile-specific threshold summary"
const mockCost = 0.03
const mockSummarizeResponse: condenseModule.SummarizeResponse = {
messages: [
{ role: "user", content: "First message" },
{ role: "assistant", content: mockSummary, isSummary: true },
{ role: "user", content: "Last message" },
],
summary: mockSummary,
cost: mockCost,
newContextTokens: 100,
}
const summarizeSpy = vi
.spyOn(condenseModule, "summarizeConversation")
.mockResolvedValue(mockSummarizeResponse)
const result = await truncateConversationIfNeeded({
messages: messagesWithSmallContent,
totalTokens,
contextWindow,
maxTokens: modelInfo.maxTokens,
apiHandler: mockApiHandler,
autoCondenseContext: true,
autoCondenseContextPercent: 100, // Global threshold of 100%
systemPrompt: "System prompt",
taskId,
profileThresholds,
currentProfileId,
})
// Should use summarization because 65% > 60% (profile threshold)
expect(summarizeSpy).toHaveBeenCalled()
expect(result).toMatchObject({
messages: mockSummarizeResponse.messages,
summary: mockSummary,
cost: mockCost,
prevContextTokens: totalTokens,
})
// Clean up
summarizeSpy.mockRestore()
})
/**
* Test that when a profile's threshold is set to -1,
* the function correctly falls back to using the global autoCondenseContextPercent
*/
it("should fall back to global threshold when profile threshold is -1", async () => {
const modelInfo = createModelInfo(100000, 30000)
const profileThresholds = {
"test-profile": -1, // Profile threshold set to -1 (use global)
}
const currentProfileId = "test-profile"
const contextWindow = modelInfo.contextWindow
// Set tokens to 80% of context window - above global threshold (75%) but would be below if profile had its own
const totalTokens = Math.floor(contextWindow * 0.8) // 80000 tokens
// Create messages with very small content in the last one to avoid token overflow
const messagesWithSmallContent = [
...messages.slice(0, -1),
{ ...messages[messages.length - 1], content: "" },
]
// Mock the summarizeConversation function
const mockSummary = "Global threshold fallback summary"
const mockCost = 0.04
const mockSummarizeResponse: condenseModule.SummarizeResponse = {
messages: [
{ role: "user", content: "First message" },
{ role: "assistant", content: mockSummary, isSummary: true },
{ role: "user", content: "Last message" },
],
summary: mockSummary,
cost: mockCost,
newContextTokens: 120,
}
const summarizeSpy = vi
.spyOn(condenseModule, "summarizeConversation")
.mockResolvedValue(mockSummarizeResponse)
const result = await truncateConversationIfNeeded({
messages: messagesWithSmallContent,
totalTokens,
contextWindow,
maxTokens: modelInfo.maxTokens,
apiHandler: mockApiHandler,
autoCondenseContext: true,
autoCondenseContextPercent: 75, // Global threshold of 75%
systemPrompt: "System prompt",
taskId,
profileThresholds,
currentProfileId,
})
// Should use summarization because 80% > 75% (global threshold, since profile is -1)
expect(summarizeSpy).toHaveBeenCalled()
expect(result).toMatchObject({
messages: mockSummarizeResponse.messages,
summary: mockSummary,
cost: mockCost,
prevContextTokens: totalTokens,
})
// Clean up
summarizeSpy.mockRestore()
})
/**
* Test that when a profile does not have a specific threshold defined,
* the function correctly falls back to the global default
*/
it("should fall back to global threshold when profile has no specific threshold", async () => {
const modelInfo = createModelInfo(100000, 30000)
const profileThresholds = {
"other-profile": 50, // Different profile has a threshold
}
const currentProfileId = "test-profile" // This profile is not in profileThresholds
const contextWindow = modelInfo.contextWindow
// Calculate allowedTokens: contextWindow * (1 - TOKEN_BUFFER_PERCENTAGE) - reservedTokens
// allowedTokens = 100000 * 0.9 - 30000 = 60000
// Set tokens to be below both the global threshold (80%) and allowedTokens
const totalTokens = 50000 // 50% of context window, well below 60000 allowedTokens and 80% threshold
// Create messages with very small content in the last one to avoid token overflow
const messagesWithSmallContent = [
...messages.slice(0, -1),
{ ...messages[messages.length - 1], content: "" },
]
// Reset any previous mock calls
vi.clearAllMocks()
const summarizeSpy = vi.spyOn(condenseModule, "summarizeConversation")
const result = await truncateConversationIfNeeded({
messages: messagesWithSmallContent,
totalTokens,
contextWindow,
maxTokens: modelInfo.maxTokens,
apiHandler: mockApiHandler,
autoCondenseContext: true,
autoCondenseContextPercent: 80, // Global threshold of 80%
systemPrompt: "System prompt",
taskId,
profileThresholds,
currentProfileId,
})
// Should NOT use summarization because 50% < 80% (global threshold, since profile has no specific threshold)
// and totalTokens (50000) < allowedTokens (60000)
expect(summarizeSpy).not.toHaveBeenCalled()
expect(result).toEqual({
messages: messagesWithSmallContent,
summary: "",
cost: 0,
prevContextTokens: totalTokens,
})
// Clean up
summarizeSpy.mockRestore()
})
})
/**
* Tests for the getMaxTokens function (private but tested through truncateConversationIfNeeded)
*/
@ -829,6 +1072,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result1).toEqual({
messages: messagesWithSmallContent,
@ -848,6 +1093,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result2.messages).not.toEqual(messagesWithSmallContent)
expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction
@ -878,6 +1125,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result1).toEqual({
messages: messagesWithSmallContent,
@ -897,6 +1146,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result2.messages).not.toEqual(messagesWithSmallContent)
expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction
@ -926,6 +1177,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result1.messages).toEqual(messagesWithSmallContent)
@ -940,6 +1193,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result2).not.toEqual(messagesWithSmallContent)
expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction
@ -967,6 +1222,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result1.messages).toEqual(messagesWithSmallContent)
@ -981,6 +1238,8 @@ describe("Sliding Window", () => {
autoCondenseContextPercent: 100,
systemPrompt: "System prompt",
taskId,
profileThresholds: {},
currentProfileId: "default",
})
expect(result2).not.toEqual(messagesWithSmallContent)
expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction

View file

@ -3,7 +3,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
import { TelemetryService } from "@roo-code/telemetry"
import { ApiHandler } from "../../api"
import { summarizeConversation, SummarizeResponse } from "../condense"
import { MAX_CONDENSE_THRESHOLD, MIN_CONDENSE_THRESHOLD, summarizeConversation, SummarizeResponse } from "../condense"
import { ApiMessage } from "../task-persistence/apiMessages"
/**
@ -74,6 +74,8 @@ type TruncateOptions = {
taskId: string
customCondensingPrompt?: string
condensingApiHandler?: ApiHandler
profileThresholds: Record<string, number>
currentProfileId: string
}
type TruncateResponse = SummarizeResponse & { prevContextTokens: number }
@ -97,6 +99,8 @@ export async function truncateConversationIfNeeded({
taskId,
customCondensingPrompt,
condensingApiHandler,
profileThresholds,
currentProfileId,
}: TruncateOptions): Promise<TruncateResponse> {
let error: string | undefined
let cost = 0
@ -117,9 +121,29 @@ export async function truncateConversationIfNeeded({
// Truncate if we're within TOKEN_BUFFER_PERCENTAGE of the context window
const allowedTokens = contextWindow * (1 - TOKEN_BUFFER_PERCENTAGE) - reservedTokens
// Determine the effective threshold to use
let effectiveThreshold = autoCondenseContextPercent
const profileThreshold = profileThresholds[currentProfileId]
if (profileThreshold !== undefined) {
if (profileThreshold === -1) {
// Special case: -1 means inherit from global setting
effectiveThreshold = autoCondenseContextPercent
} else if (profileThreshold >= MIN_CONDENSE_THRESHOLD && profileThreshold <= MAX_CONDENSE_THRESHOLD) {
// Valid custom threshold
effectiveThreshold = profileThreshold
} else {
// Invalid threshold value, fall back to global setting
console.warn(
`Invalid profile threshold ${profileThreshold} for profile "${currentProfileId}". Using global default of ${autoCondenseContextPercent}%`,
)
effectiveThreshold = autoCondenseContextPercent
}
}
// If no specific threshold is found for the profile, fall back to global setting
if (autoCondenseContext) {
const contextPercent = (100 * prevContextTokens) / contextWindow
if (contextPercent >= autoCondenseContextPercent || prevContextTokens > allowedTokens) {
if (contextPercent >= effectiveThreshold || prevContextTokens > allowedTokens) {
// Attempt to intelligently condense the context
const result = await summarizeConversation(
messages,

View file

@ -1643,6 +1643,7 @@ export class Task extends EventEmitter<ClineEvents> {
mode,
autoCondenseContext = true,
autoCondenseContextPercent = 100,
profileThresholds = {},
} = state ?? {}
// Get condensing configuration for automatic triggers
@ -1719,6 +1720,8 @@ export class Task extends EventEmitter<ClineEvents> {
taskId: this.taskId,
customCondensingPrompt,
condensingApiHandler,
profileThresholds,
currentProfileId: state?.currentApiConfigName || "default",
})
if (truncateResult.messages !== this.apiConversationHistory) {
await this.overwriteApiConversationHistory(truncateResult.messages)

View file

@ -1376,6 +1376,7 @@ export class ClineProvider
customCondensingPrompt,
codebaseIndexConfig,
codebaseIndexModels,
profileThresholds,
} = await this.getState()
const telemetryKey = process.env.POSTHOG_API_KEY
@ -1483,6 +1484,7 @@ export class ClineProvider
codebaseIndexEmbedderModelId: "",
},
mdmCompliant: this.checkMdmCompliance(),
profileThresholds: profileThresholds ?? {},
}
}
@ -1632,6 +1634,7 @@ export class ClineProvider
codebaseIndexEmbedderBaseUrl: "",
codebaseIndexEmbedderModelId: "",
},
profileThresholds: stateValues.profileThresholds ?? {},
}
}

View file

@ -522,6 +522,7 @@ describe("ClineProvider", () => {
autoCondenseContextPercent: 100,
cloudIsAuthenticated: false,
sharingEnabled: false,
profileThresholds: {},
}
const message: ExtensionMessage = {

View file

@ -1119,6 +1119,10 @@ export const webviewMessageHandler = async (
await updateGlobalState("customCondensingPrompt", message.text)
await provider.postStateToWebview()
break
case "profileThresholds":
await updateGlobalState("profileThresholds", message.values)
await provider.postStateToWebview()
break
case "autoApprovalEnabled":
await updateGlobalState("autoApprovalEnabled", message.bool ?? false)
await provider.postStateToWebview()

View file

@ -213,6 +213,7 @@ export type ExtensionState = Pick<
| "customCondensingPrompt"
| "codebaseIndexConfig"
| "codebaseIndexModels"
| "profileThresholds"
> & {
version: string
clineMessages: ClineMessage[]
@ -259,6 +260,7 @@ export type ExtensionState = Pick<
autoCondenseContextPercent: number
marketplaceItems?: MarketplaceItem[]
marketplaceInstalledMetadata?: { project: Record<string, any>; global: Record<string, any> }
profileThresholds: Record<string, number>
}
export interface ClineSayTool {

View file

@ -159,6 +159,7 @@ export interface WebviewMessage {
| "indexCleared"
| "focusPanelRequest"
| "codebaseIndexConfig"
| "profileThresholds"
| "setHistoryPreviewCollapsed"
| "openExternal"
| "filterMarketplaceItems"
@ -170,6 +171,7 @@ export interface WebviewMessage {
| "marketplaceInstallResult"
| "fetchMarketplaceData"
| "switchTab"
| "profileThresholds"
text?: string
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account"
disabled?: boolean

View file

@ -1,4 +1,5 @@
import { HTMLAttributes } from "react"
import React from "react"
import { useAppTranslation } from "@/i18n/TranslationContext"
import { VSCodeCheckbox, VSCodeTextArea } from "@vscode/webview-ui-toolkit/react"
import { Database, FoldVertical } from "lucide-react"
@ -62,6 +63,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
showRooIgnoredFiles?: boolean
maxReadFileLine?: number
maxConcurrentFileReads?: number
profileThresholds?: Record<string, number>
setCachedStateField: SetCachedStateField<
| "autoCondenseContext"
| "autoCondenseContextPercent"
@ -72,6 +74,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
| "showRooIgnoredFiles"
| "maxReadFileLine"
| "maxConcurrentFileReads"
| "profileThresholds"
>
}
@ -87,10 +90,41 @@ export const ContextManagementSettings = ({
setCachedStateField,
maxReadFileLine,
maxConcurrentFileReads,
profileThresholds = {},
className,
...props
}: ContextManagementSettingsProps) => {
const { t } = useAppTranslation()
const [selectedThresholdProfile, setSelectedThresholdProfile] = React.useState<string>("default")
// Helper function to get the current threshold value based on selected profile
const getCurrentThresholdValue = () => {
if (selectedThresholdProfile === "default") {
return autoCondenseContextPercent
}
const profileThreshold = profileThresholds[selectedThresholdProfile]
if (profileThreshold === undefined || profileThreshold === -1) {
return autoCondenseContextPercent // Use default if profile not configured or set to -1
}
return profileThreshold
}
// Helper function to handle threshold changes
const handleThresholdChange = (value: number) => {
if (selectedThresholdProfile === "default") {
setCachedStateField("autoCondenseContextPercent", value)
} else {
const newThresholds = {
...profileThresholds,
[selectedThresholdProfile]: value,
}
setCachedStateField("profileThresholds", newThresholds)
vscode.postMessage({
type: "profileThresholds",
values: newThresholds,
})
}
}
return (
<div className={cn("flex flex-col gap-2", className)} {...props}>
<SectionHeader description={t("settings:contextManagement.description")}>
@ -220,29 +254,76 @@ export const ContextManagementSettings = ({
<div className="flex flex-col gap-3 pl-3 border-l-2 border-vscode-button-background">
<div className="flex items-center gap-4 font-bold">
<FoldVertical size={16} />
<div>{t("settings:contextManagement.autoCondenseContextPercent.label")}</div>
<div>{t("settings:contextManagement.condensingThreshold.label")}</div>
</div>
<div>
<Select
value={selectedThresholdProfile || "default"}
onValueChange={(value) => {
setSelectedThresholdProfile(value)
}}
data-testid="threshold-profile-select">
<SelectTrigger className="w-full">
<SelectValue
placeholder={
t("settings:contextManagement.condensingThreshold.selectProfile") ||
"Select profile for threshold"
}
/>
</SelectTrigger>
<SelectContent>
<SelectItem value="default">
{t("settings:contextManagement.condensingThreshold.defaultProfile") ||
"Default (applies to all unconfigured profiles)"}
</SelectItem>
{(listApiConfigMeta || []).map((config) => {
const profileThreshold = profileThresholds[config.id]
const thresholdDisplay =
profileThreshold !== undefined
? profileThreshold === -1
? ` ${t(
"settings:contextManagement.condensingThreshold.usesGlobal",
{
threshold: autoCondenseContextPercent,
},
)}`
: ` (${profileThreshold}%)`
: ""
return (
<SelectItem key={config.id} value={config.id}>
{config.name}
{thresholdDisplay}
</SelectItem>
)
})}
</SelectContent>
</Select>
</div>
{/* Threshold Slider */}
<div>
<div className="flex items-center gap-2">
<Slider
min={5}
min={10}
max={100}
step={1}
value={[autoCondenseContextPercent]}
onValueChange={([value]) =>
setCachedStateField("autoCondenseContextPercent", value)
}
data-testid="auto-condense-percent-slider"
value={[getCurrentThresholdValue()]}
onValueChange={([value]) => handleThresholdChange(value)}
data-testid="condense-threshold-slider"
/>
<span className="w-20">{autoCondenseContextPercent}%</span>
<span className="w-20">{getCurrentThresholdValue()}%</span>
</div>
<div className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:contextManagement.autoCondenseContextPercent.description")}
{selectedThresholdProfile === "default"
? t("settings:contextManagement.condensingThreshold.defaultDescription", {
threshold: autoCondenseContextPercent,
})
: t("settings:contextManagement.condensingThreshold.profileDescription")}
</div>
</div>
{/* API Configuration Selection */}
<div className="flex flex-col gap-3">
<div>
<div className="flex items-center gap-4 font-bold">
<span className="codicon codicon-settings-gear" />
<div>{t("settings:contextManagement.condensingApiConfiguration.label")}</div>
@ -286,7 +367,7 @@ export const ContextManagementSettings = ({
</div>
{/* Custom Prompt Section */}
<div className="flex flex-col gap-3">
<div>
<div className="flex items-center gap-4 font-bold">
<span className="codicon codicon-edit" />
<div>{t("settings:contextManagement.customCondensingPrompt.label")}</div>

View file

@ -172,6 +172,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
codebaseIndexConfig,
codebaseIndexModels,
customSupportPrompts,
profileThresholds,
} = cachedState
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
@ -315,6 +316,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
vscode.postMessage({ type: "codebaseIndexConfig", values: codebaseIndexConfig })
vscode.postMessage({ type: "profileThresholds", values: profileThresholds })
setChangeDetected(false)
}
}
@ -644,6 +646,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
showRooIgnoredFiles={showRooIgnoredFiles}
maxReadFileLine={maxReadFileLine}
maxConcurrentFileReads={maxConcurrentFileReads}
profileThresholds={profileThresholds}
setCachedStateField={setCachedStateField}
/>
)}

View file

@ -49,6 +49,7 @@ describe("ContextManagementSettings", () => {
maxWorkspaceFiles: 200,
showRooIgnoredFiles: false,
setCachedStateField: vitest.fn(),
profileThresholds: {},
}
beforeEach(() => {
@ -173,18 +174,17 @@ describe("ContextManagementSettings", () => {
}
render(<ContextManagementSettings {...propsWithAutoCondense} />)
// Should render the auto condense section
// Should render the auto condense section
const autoCondenseCheckbox = screen.getByTestId("auto-condense-context-checkbox")
expect(autoCondenseCheckbox).toBeInTheDocument()
// Should render the slider with correct value
const slider = screen.getByTestId("auto-condense-percent-slider")
// Should render the threshold slider with correct value
const slider = screen.getByTestId("condense-threshold-slider")
expect(slider).toBeInTheDocument()
// Should render the API config select
const apiSelect = screen.getByRole("combobox")
expect(apiSelect).toBeInTheDocument()
// Should render both select dropdowns (profile and API config)
const selects = screen.getAllByRole("combobox")
expect(selects).toHaveLength(2)
// Should render the custom prompt textarea
const textarea = screen.getByRole("textbox")
@ -207,7 +207,7 @@ describe("ContextManagementSettings", () => {
it("toggles auto condense context setting", () => {
const mockSetCachedStateField = vitest.fn()
const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField }
const { rerender } = render(<ContextManagementSettings {...props} />)
render(<ContextManagementSettings {...props} />)
const checkbox = screen.getByTestId("auto-condense-context-checkbox")
expect(checkbox).toBeChecked()
@ -215,42 +215,25 @@ describe("ContextManagementSettings", () => {
// Toggle off
fireEvent.click(checkbox)
expect(mockSetCachedStateField).toHaveBeenCalledWith("autoCondenseContext", false)
// Re-render with updated props to simulate the state change
rerender(<ContextManagementSettings {...props} autoCondenseContext={false} />)
// Additional settings should not be visible when disabled
expect(screen.queryByTestId("auto-condense-percent-slider")).not.toBeInTheDocument()
expect(screen.queryByRole("combobox")).not.toBeInTheDocument()
expect(screen.queryByRole("textbox")).not.toBeInTheDocument()
})
it("shows additional settings when auto condense is enabled", () => {
render(<ContextManagementSettings {...autoCondenseProps} />)
// Additional settings should be visible
expect(screen.getByTestId("auto-condense-percent-slider")).toBeInTheDocument()
expect(screen.getByRole("combobox")).toBeInTheDocument()
expect(screen.getByTestId("condense-threshold-slider")).toBeInTheDocument()
// Two comboboxes: one for profile selection, one for API config
expect(screen.getAllByRole("combobox")).toHaveLength(2)
expect(screen.getByRole("textbox")).toBeInTheDocument()
})
it("hides additional settings when auto condense is disabled", () => {
const props = { ...autoCondenseProps, autoCondenseContext: false }
render(<ContextManagementSettings {...props} />)
// Additional settings should not be visible
expect(screen.queryByTestId("auto-condense-percent-slider")).not.toBeInTheDocument()
expect(screen.queryByRole("combobox")).not.toBeInTheDocument()
expect(screen.queryByRole("textbox")).not.toBeInTheDocument()
})
it("updates auto condense context percent", () => {
const mockSetCachedStateField = vitest.fn()
const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField }
render(<ContextManagementSettings {...props} />)
// Find the auto condense percent slider
const slider = screen.getByTestId("auto-condense-percent-slider")
// Find the condense threshold slider
const slider = screen.getByTestId("condense-threshold-slider")
// Test slider interaction
slider.focus()
@ -273,7 +256,9 @@ describe("ContextManagementSettings", () => {
const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField }
render(<ContextManagementSettings {...props} />)
const apiSelect = screen.getByRole("combobox")
// Get the second combobox (API config select)
const selects = screen.getAllByRole("combobox")
const apiSelect = selects[1]
fireEvent.click(apiSelect)
const configOption = screen.getByText("Config 1")
@ -295,8 +280,9 @@ describe("ContextManagementSettings", () => {
const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField }
render(<ContextManagementSettings {...props} />)
// Test selecting default config
const apiSelect = screen.getByRole("combobox")
// Test selecting default config - get the second combobox (API config)
const selects = screen.getAllByRole("combobox")
const apiSelect = selects[1]
fireEvent.click(apiSelect)
const defaultOption = screen.getByText(
"settings:contextManagement.condensingApiConfiguration.useCurrentConfig",
@ -463,9 +449,14 @@ describe("ContextManagementSettings", () => {
}
render(<ContextManagementSettings {...propsWithoutAutoCondense} />)
expect(screen.queryByText("settings:experimental.autoCondenseContextPercent.label")).not.toBeInTheDocument()
expect(screen.queryByText("settings:experimental.condensingApiConfiguration.label")).not.toBeInTheDocument()
expect(screen.queryByText("settings:experimental.customCondensingPrompt.label")).not.toBeInTheDocument()
// When auto condense is false, all condensing-related UI should not be visible
expect(screen.queryByTestId("condense-threshold-slider")).not.toBeInTheDocument()
expect(
screen.queryByText("settings:contextManagement.condensingApiConfiguration.label"),
).not.toBeInTheDocument()
expect(
screen.queryByText("settings:contextManagement.customCondensingPrompt.label"),
).not.toBeInTheDocument()
})
it("renders max read file controls with default value when maxReadFileLine is undefined", () => {

View file

@ -44,6 +44,8 @@ export interface ExtensionStateContextType extends ExtensionState {
setCustomCondensingPrompt: (value: string) => void
marketplaceItems?: any[]
marketplaceInstalledMetadata?: MarketplaceInstalledMetadata
profileThresholds: Record<string, number>
setProfileThresholds: (value: Record<string, number>) => void
setApiConfiguration: (config: ProviderSettings) => void
setCustomInstructions: (value?: string) => void
setAlwaysAllowReadOnly: (value: boolean) => void
@ -201,6 +203,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
organizationAllowList: ORGANIZATION_ALLOW_ALL,
autoCondenseContext: true,
autoCondenseContextPercent: 100,
profileThresholds: {},
codebaseIndexConfig: {
codebaseIndexEnabled: false,
codebaseIndexQdrantUrl: "http://localhost:6333",
@ -345,6 +348,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
cloudIsAuthenticated: state.cloudIsAuthenticated ?? false,
marketplaceItems,
marketplaceInstalledMetadata,
profileThresholds: state.profileThresholds ?? {},
setExperimentEnabled: (id, enabled) =>
setState((prevState) => ({ ...prevState, experiments: { ...prevState.experiments, [id]: enabled } })),
setApiConfiguration,
@ -429,6 +433,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setCondensingApiConfigId: (value) => setState((prevState) => ({ ...prevState, condensingApiConfigId: value })),
setCustomCondensingPrompt: (value) =>
setState((prevState) => ({ ...prevState, customCondensingPrompt: value })),
setProfileThresholds: (value) => setState((prevState) => ({ ...prevState, profileThresholds: value })),
}
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>

View file

@ -207,6 +207,7 @@ describe("mergeExtensionState", () => {
autoCondenseContextPercent: 100,
cloudIsAuthenticated: false,
sharingEnabled: false,
profileThresholds: {},
}
const prevState: ExtensionState = {

View file

@ -370,7 +370,8 @@
"hint": "Buit = utilitzar indicació per defecte"
},
"autoCondenseContext": {
"name": "Activar automàticament la condensació intel·ligent de context"
"name": "Activar automàticament la condensació intel·ligent de context",
"description": "Quan està activat, Roo condensarà automàticament el context quan s'assoleixi el llindar. Quan està desactivat, encara pots activar manualment la condensació de context."
},
"openTabs": {
"label": "Límit de context de pestanyes obertes",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Límit de lectures simultànies",
"description": "Nombre màxim de fitxers que l'eina 'read_file' pot processar simultàniament. Els valors més alts poden accelerar la lectura de múltiples fitxers petits però augmenten l'ús de memòria."
},
"condensingThreshold": {
"label": "Llindar d'activació de condensació",
"selectProfile": "Configura el llindar per al perfil",
"defaultProfile": "Per defecte global (tots els perfils)",
"defaultDescription": "Quan el context arribi a aquest percentatge, es condensarà automàticament per a tots els perfils tret que tinguin configuracions personalitzades",
"profileDescription": "Llindar personalitzat només per a aquest perfil (substitueix el per defecte global)",
"inheritDescription": "Aquest perfil hereta el llindar per defecte global ({{threshold}}%)",
"usesGlobal": "(utilitza global {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Leer = Standard-Prompt verwenden"
},
"autoCondenseContext": {
"name": "Intelligente Kontextkomprimierung automatisch auslösen"
"name": "Intelligente Kontextkomprimierung automatisch auslösen",
"description": "Wenn aktiviert, wird Roo automatisch den Kontext komprimieren, wenn der Schwellenwert erreicht wird. Wenn deaktiviert, können Sie die Kontextkomprimierung weiterhin manuell auslösen."
},
"openTabs": {
"label": "Geöffnete Tabs Kontextlimit",
@ -393,6 +394,15 @@
"description": "Roo liest diese Anzahl von Zeilen, wenn das Modell keine Start-/Endwerte angibt. Wenn diese Zahl kleiner als die Gesamtzahl der Zeilen ist, erstellt Roo einen Zeilennummernindex der Codedefinitionen. Spezialfälle: -1 weist Roo an, die gesamte Datei zu lesen (ohne Indexierung), und 0 weist an, keine Zeilen zu lesen und nur Zeilenindizes für minimalen Kontext bereitzustellen. Niedrigere Werte minimieren die anfängliche Kontextnutzung und ermöglichen präzise nachfolgende Zeilenbereich-Lesungen. Explizite Start-/End-Anfragen sind von dieser Einstellung nicht begrenzt.",
"lines": "Zeilen",
"always_full_read": "Immer die gesamte Datei lesen"
},
"condensingThreshold": {
"label": "Schwellenwert für Kontextkomprimierung",
"selectProfile": "Profil für Schwellenwert konfigurieren",
"defaultProfile": "Globaler Standard (alle Profile)",
"defaultDescription": "Wenn der Kontext diesen Prozentsatz erreicht, wird er automatisch für alle Profile komprimiert, es sei denn, sie haben benutzerdefinierte Einstellungen",
"profileDescription": "Benutzerdefinierter Schwellenwert nur für dieses Profil (überschreibt globalen Standard)",
"inheritDescription": "Dieses Profil erbt den globalen Standard-Schwellenwert ({{threshold}}%)",
"usesGlobal": "(verwendet global {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Empty = use default prompt"
},
"autoCondenseContext": {
"name": "Automatically trigger intelligent context condensing"
"name": "Automatically trigger intelligent context condensing",
"description": "When enabled, Roo will automatically condense the context when the threshold is reached. When disabled, you can still manually trigger context condensing."
},
"openTabs": {
"label": "Open tabs context limit",
@ -393,6 +394,15 @@
"description": "Roo reads this number of lines when the model omits start/end values. If this number is less than the file's total, Roo generates a line number index of code definitions. Special cases: -1 instructs Roo to read the entire file (without indexing), and 0 instructs it to read no lines and provides line indexes only for minimal context. Lower values minimize initial context usage, enabling precise subsequent line-range reads. Explicit start/end requests are not limited by this setting.",
"lines": "lines",
"always_full_read": "Always read entire file"
},
"condensingThreshold": {
"label": "Condensing Trigger Threshold",
"selectProfile": "Configure threshold for profile",
"defaultProfile": "Global Default (all profiles)",
"defaultDescription": "When context reaches this percentage, it will be automatically condensed for all profiles unless they have custom settings",
"profileDescription": "Custom threshold for this profile only (overrides global default)",
"inheritDescription": "This profile inherits the global default threshold ({{threshold}}%)",
"usesGlobal": "(uses global {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Vacío = usar prompt predeterminado"
},
"autoCondenseContext": {
"name": "Activar automáticamente la condensación inteligente de contexto"
"name": "Activar automáticamente la condensación inteligente de contexto",
"description": "Cuando está habilitado, Roo condensará automáticamente el contexto cuando se alcance el umbral. Cuando está deshabilitado, aún puedes activar manualmente la condensación de contexto."
},
"openTabs": {
"label": "Límite de contexto de pestañas abiertas",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Límite de lecturas simultáneas",
"description": "Número máximo de archivos que la herramienta 'read_file' puede procesar simultáneamente. Valores más altos pueden acelerar la lectura de múltiples archivos pequeños pero aumentan el uso de memoria."
},
"condensingThreshold": {
"label": "Umbral de condensación de contexto",
"selectProfile": "Configurar umbral para perfil",
"defaultProfile": "Predeterminado global (todos los perfiles)",
"defaultDescription": "Cuando el contexto alcance este porcentaje, se condensará automáticamente para todos los perfiles a menos que tengan configuraciones personalizadas",
"profileDescription": "Umbral personalizado solo para este perfil (anula el predeterminado global)",
"inheritDescription": "Este perfil hereda el umbral predeterminado global ({{threshold}}%)",
"usesGlobal": "(usa global {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Vide = utiliser le prompt par défaut"
},
"autoCondenseContext": {
"name": "Déclencher automatiquement la condensation intelligente du contexte"
"name": "Déclencher automatiquement la condensation intelligente du contexte",
"description": "Lorsque cette option est activée, Roo condensera automatiquement le contexte lorsque le seuil est atteint. Lorsqu'elle est désactivée, vous pouvez toujours déclencher manuellement la condensation du contexte."
},
"openTabs": {
"label": "Limite de contexte des onglets ouverts",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Limite de lectures simultanées",
"description": "Nombre maximum de fichiers que l'outil 'read_file' peut traiter simultanément. Des valeurs plus élevées peuvent accélérer la lecture de plusieurs petits fichiers mais augmentent l'utilisation de la mémoire."
},
"condensingThreshold": {
"label": "Seuil de condensation du contexte",
"selectProfile": "Configurer le seuil pour le profil",
"defaultProfile": "Par défaut global (tous les profils)",
"defaultDescription": "Lorsque le contexte atteint ce pourcentage, il sera automatiquement condensé pour tous les profils sauf s'ils ont des paramètres personnalisés",
"profileDescription": "Seuil personnalisé pour ce profil uniquement (remplace le défaut global)",
"inheritDescription": "Ce profil hérite du seuil par défaut global ({{threshold}}%)",
"usesGlobal": "(utilise global {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "खाली = डिफ़ॉल्ट प्रॉम्प्ट का उपयोग करें"
},
"autoCondenseContext": {
"name": "बुद्धिमान संदर्भ संघनन को स्वचालित रूप से ट्रिगर करें"
"name": "बुद्धिमान संदर्भ संघनन को स्वचालित रूप से ट्रिगर करें",
"description": "जब सक्षम हो, तो Roo स्वचालित रूप से संदर्भ को संघनित करेगा जब सीमा पहुंच जाएगी। जब अक्षम हो, तो आप अभी भी मैन्युअल रूप से संदर्भ संघनन को ट्रिगर कर सकते हैं।"
},
"openTabs": {
"label": "खुले टैब संदर्भ सीमा",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "एक साथ फ़ाइल पढ़ने की सीमा",
"description": "'read_file' टूल द्वारा एक साथ प्रोसेस की जा सकने वाली अधिकतम फ़ाइलों की संख्या। उच्च मान कई छोटी फ़ाइलों को पढ़ने की गति बढ़ा सकते हैं लेकिन मेमोरी उपयोग बढ़ा देते हैं।"
},
"condensingThreshold": {
"label": "संघनन ट्रिगर सीमा",
"selectProfile": "प्रोफ़ाइल के लिए सीमा कॉन्फ़िगर करें",
"defaultProfile": "वैश्विक डिफ़ॉल्ट (सभी प्रोफ़ाइल)",
"defaultDescription": "जब संदर्भ इस प्रतिशत तक पहुंचता है, तो यह सभी प्रोफ़ाइल के लिए स्वचालित रूप से संघनित हो जाएगा जब तक कि उनकी कस्टम सेटिंग्स न हों",
"profileDescription": "केवल इस प्रोफ़ाइल के लिए कस्टम सीमा (वैश्विक डिफ़ॉल्ट को ओवरराइड करता है)",
"inheritDescription": "यह प्रोफ़ाइल वैश्विक डिफ़ॉल्ट सीमा को इनहेरिट करता है ({{threshold}}%)",
"usesGlobal": "(वैश्विक {{threshold}}% का उपयोग करता है)"
}
},
"terminal": {

View file

@ -374,7 +374,17 @@
"hint": "Kosong = gunakan prompt default"
},
"autoCondenseContext": {
"name": "Secara otomatis memicu kondensasi konteks cerdas"
"name": "Secara otomatis memicu kondensasi konteks cerdas",
"description": "Ketika diaktifkan, Roo akan secara otomatis mengondensasi konteks ketika ambang batas tercapai. Ketika dinonaktifkan, kamu masih dapat memicu kondensasi konteks secara manual."
},
"condensingThreshold": {
"label": "Ambang Batas Pemicu Kondensasi",
"selectProfile": "Konfigurasi ambang batas untuk profil",
"defaultProfile": "Default Global (semua profil)",
"defaultDescription": "Ketika konteks mencapai persentase ini, akan secara otomatis dikondensasi untuk semua profil kecuali mereka memiliki pengaturan kustom",
"profileDescription": "Ambang batas kustom untuk profil ini saja (menimpa default global)",
"inheritDescription": "Profil ini mewarisi ambang batas default global ({{threshold}}%)",
"usesGlobal": "(menggunakan global {{threshold}}%)"
},
"openTabs": {
"label": "Batas konteks tab terbuka",

View file

@ -370,7 +370,8 @@
"hint": "Vuoto = usa prompt predefinito"
},
"autoCondenseContext": {
"name": "Attiva automaticamente la condensazione intelligente del contesto"
"name": "Attiva automaticamente la condensazione intelligente del contesto",
"description": "Quando abilitato, Roo condenserà automaticamente il contesto quando viene raggiunta la soglia. Quando disabilitato, puoi ancora attivare manualmente la condensazione del contesto."
},
"openTabs": {
"label": "Limite contesto schede aperte",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Limite letture simultanee",
"description": "Numero massimo di file che lo strumento 'read_file' può elaborare contemporaneamente. Valori più alti possono velocizzare la lettura di più file piccoli ma aumentano l'utilizzo della memoria."
},
"condensingThreshold": {
"label": "Soglia di attivazione condensazione",
"selectProfile": "Configura soglia per profilo",
"defaultProfile": "Predefinito globale (tutti i profili)",
"defaultDescription": "Quando il contesto raggiunge questa percentuale, verrà automaticamente condensato per tutti i profili a meno che non abbiano impostazioni personalizzate",
"profileDescription": "Soglia personalizzata solo per questo profilo (sovrascrive il predefinito globale)",
"inheritDescription": "Questo profilo eredita la soglia predefinita globale ({{threshold}}%)",
"usesGlobal": "(usa globale {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "空 = デフォルトプロンプトを使用"
},
"autoCondenseContext": {
"name": "インテリジェントなコンテキスト圧縮を自動的にトリガーする"
"name": "インテリジェントなコンテキスト圧縮を自動的にトリガーする",
"description": "有効にすると、Rooは閾値に達したときに自動的にコンテキストを圧縮します。無効にすると、手動でコンテキスト圧縮をトリガーできます。"
},
"openTabs": {
"label": "オープンタブコンテキスト制限",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "同時ファイル読み取り制限",
"description": "read_file ツールが同時に処理できるファイルの最大数。値を高くすると複数の小さなファイルの読み取りが速くなる可能性がありますが、メモリ使用量が増加します。"
},
"condensingThreshold": {
"label": "圧縮トリガーしきい値",
"selectProfile": "プロファイルのしきい値を設定",
"defaultProfile": "グローバルデフォルト(全プロファイル)",
"defaultDescription": "コンテキストがこの割合に達すると、カスタム設定がない限り、すべてのプロファイルで自動的に圧縮されます",
"profileDescription": "このプロファイルのみのカスタムしきい値(グローバルデフォルトを上書き)",
"inheritDescription": "このプロファイルはグローバルデフォルトしきい値を継承します({{threshold}}%",
"usesGlobal": "(グローバル {{threshold}}% を使用)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "비어있음 = 기본 프롬프트 사용"
},
"autoCondenseContext": {
"name": "지능적 컨텍스트 압축 자동 트리거"
"name": "지능적 컨텍스트 압축 자동 트리거",
"description": "활성화되면 Roo는 임계값에 도달했을 때 자동으로 컨텍스트를 압축합니다. 비활성화되면 여전히 수동으로 컨텍스트 압축을 트리거할 수 있습니다."
},
"openTabs": {
"label": "열린 탭 컨텍스트 제한",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "동시 파일 읽기 제한",
"description": "read_file 도구가 동시에 처리할 수 있는 최대 파일 수입니다. 높은 값은 여러 작은 파일을 읽는 속도를 높일 수 있지만 메모리 사용량이 증가합니다."
},
"condensingThreshold": {
"label": "압축 트리거 임계값",
"selectProfile": "프로필 임계값 구성",
"defaultProfile": "글로벌 기본값 (모든 프로필)",
"defaultDescription": "컨텍스트가 이 비율에 도달하면 사용자 정의 설정이 없는 한 모든 프로필에 대해 자동으로 압축됩니다",
"profileDescription": "이 프로필만을 위한 사용자 정의 임계값 (글로벌 기본값 재정의)",
"inheritDescription": "이 프로필은 글로벌 기본 임계값을 상속합니다 ({{threshold}}%)",
"usesGlobal": "(글로벌 {{threshold}}% 사용)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Leeg = gebruik standaardprompt"
},
"autoCondenseContext": {
"name": "Automatisch intelligente contextcompressie activeren"
"name": "Automatisch intelligente contextcompressie activeren",
"description": "Wanneer ingeschakeld, zal Roo automatisch de context comprimeren wanneer de drempel wordt bereikt. Wanneer uitgeschakeld, kun je nog steeds handmatig contextcompressie activeren."
},
"openTabs": {
"label": "Limiet geopende tabbladen in context",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Limiet gelijktijdige bestandslezingen",
"description": "Maximum aantal bestanden dat de 'read_file' tool tegelijkertijd kan verwerken. Hogere waarden kunnen het lezen van meerdere kleine bestanden versnellen maar verhogen het geheugengebruik."
},
"condensingThreshold": {
"label": "Compressie trigger drempelwaarde",
"selectProfile": "Drempelwaarde voor profiel configureren",
"defaultProfile": "Globale standaard (alle profielen)",
"defaultDescription": "Wanneer de context dit percentage bereikt, wordt het automatisch gecomprimeerd voor alle profielen tenzij ze aangepaste instellingen hebben",
"profileDescription": "Aangepaste drempelwaarde alleen voor dit profiel (overschrijft globale standaard)",
"inheritDescription": "Dit profiel erft de globale standaard drempelwaarde ({{threshold}}%)",
"usesGlobal": "(gebruikt globaal {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Puste = użyj domyślnego monitu"
},
"autoCondenseContext": {
"name": "Automatycznie wyzwalaj inteligentną kondensację kontekstu"
"name": "Automatycznie wyzwalaj inteligentną kondensację kontekstu",
"description": "Gdy włączone, Roo automatycznie skondensuje kontekst po osiągnięciu progu. Gdy wyłączone, nadal możesz ręcznie wyzwolić kondensację kontekstu."
},
"openTabs": {
"label": "Limit kontekstu otwartych kart",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Limit jednoczesnych odczytów",
"description": "Maksymalna liczba plików, które narzędzie 'read_file' może przetwarzać jednocześnie. Wyższe wartości mogą przyspieszyć odczyt wielu małych plików, ale zwiększają zużycie pamięci."
},
"condensingThreshold": {
"label": "Próg wyzwalania kondensacji",
"selectProfile": "Skonfiguruj próg dla profilu",
"defaultProfile": "Globalny domyślny (wszystkie profile)",
"defaultDescription": "Gdy kontekst osiągnie ten procent, zostanie automatycznie skondensowany dla wszystkich profili, chyba że mają niestandardowe ustawienia",
"profileDescription": "Niestandardowy próg tylko dla tego profilu (zastępuje globalny domyślny)",
"inheritDescription": "Ten profil dziedziczy globalny domyślny próg ({{threshold}}%)",
"usesGlobal": "(używa globalnego {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Vazio = usar prompt padrão"
},
"autoCondenseContext": {
"name": "Acionar automaticamente a condensação inteligente de contexto"
"name": "Acionar automaticamente a condensação inteligente de contexto",
"description": "Quando habilitado, o Roo condensará automaticamente o contexto quando o limite for atingido. Quando desabilitado, você ainda pode acionar manualmente a condensação de contexto."
},
"openTabs": {
"label": "Limite de contexto de abas abertas",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Limite de leituras simultâneas",
"description": "Número máximo de arquivos que a ferramenta 'read_file' pode processar simultaneamente. Valores mais altos podem acelerar a leitura de vários arquivos pequenos, mas aumentam o uso de memória."
},
"condensingThreshold": {
"label": "Limite de Ativação de Condensação",
"selectProfile": "Configurar limite para perfil",
"defaultProfile": "Padrão Global (todos os perfis)",
"defaultDescription": "Quando o contexto atingir essa porcentagem, será automaticamente condensado para todos os perfis, a menos que tenham configurações personalizadas",
"profileDescription": "Limite personalizado apenas para este perfil (substitui o padrão global)",
"inheritDescription": "Este perfil herda o limite padrão global ({{threshold}}%)",
"usesGlobal": "(usa global {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Пусто = использовать промпт по умолчанию"
},
"autoCondenseContext": {
"name": "Автоматически запускать интеллектуальное сжатие контекста"
"name": "Автоматически запускать интеллектуальное сжатие контекста",
"description": "Когда включено, Roo будет автоматически сжимать контекст при достижении порога. Когда отключено, вы все еще можете вручную запускать сжатие контекста."
},
"openTabs": {
"label": "Лимит контекста открытых вкладок",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Лимит одновременного чтения",
"description": "Максимальное количество файлов, которые инструмент 'read_file' может обрабатывать одновременно. Более высокие значения могут ускорить чтение нескольких небольших файлов, но увеличивают использование памяти."
},
"condensingThreshold": {
"label": "Порог запуска сжатия",
"selectProfile": "Настроить порог для профиля",
"defaultProfile": "Глобальный по умолчанию (все профили)",
"defaultDescription": "Когда контекст достигнет этого процента, он будет автоматически сжат для всех профилей, если у них нет пользовательских настроек",
"profileDescription": "Пользовательский порог только для этого профиля (переопределяет глобальный по умолчанию)",
"inheritDescription": "Этот профиль наследует глобальный порог по умолчанию ({{threshold}}%)",
"usesGlobal": "(использует глобальный {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Boş = varsayılan promptu kullan"
},
"autoCondenseContext": {
"name": "Akıllı bağlam sıkıştırmayı otomatik olarak tetikle"
"name": "Akıllı bağlam sıkıştırmayı otomatik olarak tetikle",
"description": "Etkinleştirildiğinde, Roo eşiğe ulaşıldığında bağlamı otomatik olarak sıkıştırır. Devre dışı bırakıldığında, bağlam sıkıştırmayı hala manuel olarak tetikleyebilirsiniz."
},
"openTabs": {
"label": "Açık sekmeler bağlam sınırı",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Eşzamanlı dosya okuma sınırı",
"description": "'read_file' aracının aynı anda işleyebileceği maksimum dosya sayısı. Daha yüksek değerler birden çok küçük dosyanın okunmasını hızlandırabilir ancak bellek kullanımını artırır."
},
"condensingThreshold": {
"label": "Sıkıştırma Tetikleme Eşiği",
"selectProfile": "Profil için eşik yapılandır",
"defaultProfile": "Küresel Varsayılan (tüm profiller)",
"defaultDescription": "Bağlam bu yüzdeye ulaştığında, özel ayarları olmadıkça tüm profiller için otomatik olarak sıkıştırılacak",
"profileDescription": "Sadece bu profil için özel eşik (küresel varsayılanı geçersiz kılar)",
"inheritDescription": "Bu profil küresel varsayılan eşiği miras alır ({{threshold}}%)",
"usesGlobal": "(küresel {{threshold}}% kullanır)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "Để trống = sử dụng prompt mặc định"
},
"autoCondenseContext": {
"name": "Tự động kích hoạt nén ngữ cảnh thông minh"
"name": "Tự động kích hoạt nén ngữ cảnh thông minh",
"description": "Khi được bật, Roo sẽ tự động nén ngữ cảnh khi đạt đến ngưỡng. Khi bị tắt, bạn vẫn có thể kích hoạt nén ngữ cảnh thủ công."
},
"openTabs": {
"label": "Giới hạn ngữ cảnh tab đang mở",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "Giới hạn đọc file đồng thời",
"description": "Số lượng file tối đa mà công cụ 'read_file' có thể xử lý cùng lúc. Giá trị cao hơn có thể tăng tốc độ đọc nhiều file nhỏ nhưng sẽ tăng mức sử dụng bộ nhớ."
},
"condensingThreshold": {
"label": "Ngưỡng kích hoạt nén",
"selectProfile": "Cấu hình ngưỡng cho hồ sơ",
"defaultProfile": "Mặc định toàn cục (tất cả hồ sơ)",
"defaultDescription": "Khi ngữ cảnh đạt đến tỷ lệ phần trăm này, nó sẽ được tự động nén cho tất cả hồ sơ trừ khi chúng có cài đặt tùy chỉnh",
"profileDescription": "Ngưỡng tùy chỉnh chỉ cho hồ sơ này (ghi đè mặc định toàn cục)",
"inheritDescription": "Hồ sơ này kế thừa ngưỡng mặc định toàn cục ({{threshold}}%)",
"usesGlobal": "(sử dụng toàn cục {{threshold}}%)"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "留空 = 使用默认提示词"
},
"autoCondenseContext": {
"name": "自动触发智能上下文压缩"
"name": "自动触发智能上下文压缩",
"description": "启用时Roo 将在达到阈值时自动压缩上下文。禁用时,您仍可以手动触发上下文压缩。"
},
"openTabs": {
"label": "标签页数量限制",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "并发文件读取限制",
"description": "read_file 工具可以同时处理的最大文件数。较高的值可能会加快读取多个小文件的速度,但会增加内存使用量。"
},
"condensingThreshold": {
"label": "压缩触发阈值",
"selectProfile": "配置配置文件阈值",
"defaultProfile": "全局默认(所有配置文件)",
"defaultDescription": "当上下文达到此百分比时,将自动为所有配置文件压缩,除非它们有自定义设置",
"profileDescription": "仅此配置文件的自定义阈值(覆盖全局默认)",
"inheritDescription": "此配置文件继承全局默认阈值({{threshold}}%",
"usesGlobal": "(使用全局 {{threshold}}%"
}
},
"terminal": {

View file

@ -370,7 +370,8 @@
"hint": "留空 = 使用預設提示"
},
"autoCondenseContext": {
"name": "自動觸發智慧上下文壓縮"
"name": "自動觸發智慧上下文壓縮",
"description": "啟用時Roo 會在達到閾值時自動壓縮上下文。停用時,您仍可手動觸發上下文壓縮。"
},
"openTabs": {
"label": "開啟分頁的上下文限制",
@ -393,6 +394,15 @@
"maxConcurrentFileReads": {
"label": "並行檔案讀取限制",
"description": "read_file 工具可以同時處理的最大檔案數。較高的值可能會加快讀取多個小檔案的速度,但會增加記憶體使用量。"
},
"condensingThreshold": {
"label": "壓縮觸發閾值",
"selectProfile": "設定檔案閾值",
"defaultProfile": "全域預設(所有檔案)",
"defaultDescription": "當上下文達到此百分比時,將自動為所有檔案壓縮,除非它們有自訂設定",
"profileDescription": "僅此檔案的自訂閾值(覆蓋全域預設)",
"inheritDescription": "此檔案繼承全域預設閾值({{threshold}}%",
"usesGlobal": "(使用全域 {{threshold}}%"
}
},
"terminal": {