feat: Add settings to control diagnostic messages (#5524) (#5582)

Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: Daniel Riccio <ricciodaniel98@gmail.com>
Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com>
This commit is contained in:
Hannes Rudolph 2025-07-23 12:49:41 -06:00 • committed by GitHub
parent d720d35483
commit 0323256006
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 1203 additions and 215 deletions

View file

@ -72,6 +72,17 @@ export const globalSettingsSchema = z.object({
autoCondenseContextPercent: z.number().optional(),
maxConcurrentFileReads: z.number().optional(),
/**
* Whether to include diagnostic messages (errors, warnings) in tool outputs
* @default true
*/
includeDiagnosticMessages: z.boolean().optional(),
/**
* Maximum number of diagnostic messages to include in tool outputs
* @default 50
*/
maxDiagnosticMessages: z.number().optional(),
browserToolEnabled: z.boolean().optional(),
browserViewportSize: z.string().optional(),
screenshotQuality: z.number().optional(),
@ -261,6 +272,9 @@ export const EVALS_SETTINGS: RooCodeSettings = {
showRooIgnoredFiles: true,
maxReadFileLine: -1, // -1 to enable full file reading.
includeDiagnosticMessages: true,
maxDiagnosticMessages: 50,
language: "en",
telemetrySetting: "enabled",

View file

@ -80,6 +80,8 @@ export async function parseMentions(
fileContextTracker?: FileContextTracker,
rooIgnoreController?: RooIgnoreController,
showRooIgnoredFiles: boolean = true,
includeDiagnosticMessages: boolean = true,
maxDiagnosticMessages: number = 50,
): Promise<string> {
const mentions: Set<string> = new Set()
let parsedText = text.replace(mentionRegexGlobal, (match, mention) => {
@ -165,7 +167,7 @@ export async function parseMentions(
}
} else if (mention === "problems") {
try {
const problems = await getWorkspaceProblems(cwd)
const problems = await getWorkspaceProblems(cwd, includeDiagnosticMessages, maxDiagnosticMessages)
parsedText += `\n\n<workspace_diagnostics>\n${problems}\n</workspace_diagnostics>`
} catch (error) {
parsedText += `\n\n<workspace_diagnostics>\nError fetching diagnostics: ${error.message}\n</workspace_diagnostics>`
@ -286,12 +288,18 @@ async function getFileOrFolderContent(
}
}
async function getWorkspaceProblems(cwd: string): Promise<string> {
async function getWorkspaceProblems(
cwd: string,
includeDiagnosticMessages: boolean = true,
maxDiagnosticMessages: number = 50,
): Promise<string> {
const diagnostics = vscode.languages.getDiagnostics()
const result = await diagnosticsToProblemsString(
diagnostics,
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
cwd,
includeDiagnosticMessages,
maxDiagnosticMessages,
)
if (!result) {
return "No errors or warnings detected."

View file

@ -13,6 +13,8 @@ export async function processUserContentMentions({
fileContextTracker,
rooIgnoreController,
showRooIgnoredFiles = true,
includeDiagnosticMessages = true,
maxDiagnosticMessages = 50,
}: {
userContent: Anthropic.Messages.ContentBlockParam[]
cwd: string
@ -20,6 +22,8 @@ export async function processUserContentMentions({
fileContextTracker: FileContextTracker
rooIgnoreController?: any
showRooIgnoredFiles?: boolean
includeDiagnosticMessages?: boolean
maxDiagnosticMessages?: number
}) {
// Process userContent array, which contains various block types:
// TextBlockParam, ImageBlockParam, ToolUseBlockParam, and ToolResultBlockParam.
@ -46,6 +50,8 @@ export async function processUserContentMentions({
fileContextTracker,
rooIgnoreController,
showRooIgnoredFiles,
includeDiagnosticMessages,
maxDiagnosticMessages,
),
}
}
@ -63,6 +69,8 @@ export async function processUserContentMentions({
fileContextTracker,
rooIgnoreController,
showRooIgnoredFiles,
includeDiagnosticMessages,
maxDiagnosticMessages,
),
}
}
@ -81,6 +89,8 @@ export async function processUserContentMentions({
fileContextTracker,
rooIgnoreController,
showRooIgnoredFiles,
includeDiagnosticMessages,
maxDiagnosticMessages,
),
}
}

View file

@ -260,7 +260,7 @@ export class Task extends EventEmitter<ClineEvents> {
this.consecutiveMistakeLimit = consecutiveMistakeLimit ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
this.providerRef = new WeakRef(provider)
this.globalStoragePath = provider.context.globalStorageUri.fsPath
this.diffViewProvider = new DiffViewProvider(this.cwd)
this.diffViewProvider = new DiffViewProvider(this.cwd, this)
this.enableCheckpoints = enableCheckpoints
this.rootTask = rootTask
@ -1225,7 +1225,11 @@ export class Task extends EventEmitter<ClineEvents> {
}),
)
const { showRooIgnoredFiles = true } = (await this.providerRef.deref()?.getState()) ?? {}
const {
showRooIgnoredFiles = true,
includeDiagnosticMessages = true,
maxDiagnosticMessages = 50,
} = (await this.providerRef.deref()?.getState()) ?? {}
const parsedUserContent = await processUserContentMentions({
userContent,
@ -1234,6 +1238,8 @@ export class Task extends EventEmitter<ClineEvents> {
fileContextTracker: this.fileContextTracker,
rooIgnoreController: this.rooIgnoreController,
showRooIgnoredFiles,
includeDiagnosticMessages,
maxDiagnosticMessages,
})
const environmentDetails = await getEnvironmentDetails(this, includeFileDetails)

View file

@ -96,6 +96,7 @@ describe("insertContentTool", () => {
finalContent: "final content",
}),
scrollToFirstDiff: vi.fn(),
updateDiagnosticSettings: vi.fn(),
pushToolWriteResult: vi.fn().mockImplementation(async function (
this: any,
task: any,

View file

@ -157,6 +157,7 @@ describe("writeToFileTool", () => {
finalContent: "final content",
}),
scrollToFirstDiff: vi.fn(),
updateDiagnosticSettings: vi.fn(),
pushToolWriteResult: vi.fn().mockImplementation(async function (
this: any,
task: any,

View file

@ -1439,7 +1439,8 @@ export class ClineProvider
profileThresholds,
alwaysAllowFollowupQuestions,
followupAutoApproveTimeoutMs,
diagnosticsEnabled,
includeDiagnosticMessages,
maxDiagnosticMessages,
} = await this.getState()
const telemetryKey = process.env.POSTHOG_API_KEY
@ -1560,7 +1561,8 @@ export class ClineProvider
hasOpenedModeSelector: this.getGlobalState("hasOpenedModeSelector") ?? false,
alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false,
followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 60000,
diagnosticsEnabled: diagnosticsEnabled ?? true,
includeDiagnosticMessages: includeDiagnosticMessages ?? true,
maxDiagnosticMessages: maxDiagnosticMessages ?? 50,
}
}
@ -1726,6 +1728,9 @@ export class ClineProvider
codebaseIndexSearchMinScore: stateValues.codebaseIndexConfig?.codebaseIndexSearchMinScore,
},
profileThresholds: stateValues.profileThresholds ?? {},
// Add diagnostic message settings
includeDiagnosticMessages: stateValues.includeDiagnosticMessages ?? true,
maxDiagnosticMessages: stateValues.maxDiagnosticMessages ?? 50,
}
}

View file

@ -1254,6 +1254,16 @@ export const webviewMessageHandler = async (
await updateGlobalState("maxConcurrentFileReads", valueToSave)
await provider.postStateToWebview()
break
case "includeDiagnosticMessages":
// Only apply default if the value is truly undefined (not false)
const includeValue = message.bool !== undefined ? message.bool : true
await updateGlobalState("includeDiagnosticMessages", includeValue)
await provider.postStateToWebview()
break
case "maxDiagnosticMessages":
await updateGlobalState("maxDiagnosticMessages", message.value ?? 50)
await provider.postStateToWebview()
break
case "setHistoryPreviewCollapsed": // Add the new case handler
await updateGlobalState("historyPreviewCollapsed", message.bool ?? false)
// No need to call postStateToWebview here as the UI already updated optimistically

View file

@ -383,4 +383,234 @@ describe("diagnosticsToProblemsString", () => {
expect(vscode.workspace.fs.stat).toHaveBeenCalledWith(fileUri)
expect(vscode.workspace.openTextDocument).toHaveBeenCalledWith(fileUri)
})
it("should return empty string when includeDiagnostics is false", async () => {
// Mock file URI
const fileUri = vscode.Uri.file("/path/to/file.ts")
// Create diagnostics
const diagnostics = [
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error message", vscode.DiagnosticSeverity.Error),
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning message", vscode.DiagnosticSeverity.Warning),
]
// Mock fs.stat to return file type
const mockStat = {
type: vscode.FileType.File,
}
vscode.workspace.fs.stat = vitest.fn().mockResolvedValue(mockStat)
// Mock document content
const mockDocument = {
lineAt: vitest.fn((line) => ({
text: `Line ${line + 1} content`,
})),
}
vscode.workspace.openTextDocument = vitest.fn().mockResolvedValue(mockDocument)
// Test with includeDiagnostics set to false
const result = await diagnosticsToProblemsString(
[[fileUri, diagnostics]],
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
"/path/to",
false, // includeDiagnostics
)
// Verify empty string is returned
expect(result).toBe("")
// Verify no file operations were performed
expect(vscode.workspace.fs.stat).not.toHaveBeenCalled()
expect(vscode.workspace.openTextDocument).not.toHaveBeenCalled()
})
it("should limit diagnostics based on count when maxDiagnostics is specified", async () => {
// Mock file URI
const fileUri = vscode.Uri.file("/path/to/file.ts")
// Create multiple diagnostics with varying message lengths
const diagnostics = [
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error 1", vscode.DiagnosticSeverity.Error),
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning 1", vscode.DiagnosticSeverity.Warning),
new vscode.Diagnostic(new vscode.Range(2, 0, 2, 10), "Error 2", vscode.DiagnosticSeverity.Error),
new vscode.Diagnostic(new vscode.Range(3, 0, 3, 10), "Warning 2", vscode.DiagnosticSeverity.Warning),
new vscode.Diagnostic(new vscode.Range(4, 0, 4, 10), "Error 3", vscode.DiagnosticSeverity.Error),
]
// Mock fs.stat to return file type
const mockStat = {
type: vscode.FileType.File,
}
vscode.workspace.fs.stat = vitest.fn().mockResolvedValue(mockStat)
// Mock document content
const mockDocument = {
lineAt: vitest.fn((line) => ({
text: `Line ${line + 1} content`,
})),
}
vscode.workspace.openTextDocument = vitest.fn().mockResolvedValue(mockDocument)
// Test with maxDiagnostics set to 3 (should include exactly 3 diagnostics)
const result = await diagnosticsToProblemsString(
[[fileUri, diagnostics]],
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
"/path/to",
true, // includeDiagnostics
3, // maxDiagnostics (count limit)
)
// Verify that exactly 3 diagnostics are included, prioritizing errors
expect(result).toContain("Error 1")
expect(result).toContain("Error 2")
expect(result).toContain("Error 3")
// Warnings should not be included since we have 3 errors and limit is 3
expect(result).not.toContain("Warning 1")
expect(result).not.toContain("Warning 2")
// Verify the limit message is included
expect(result).toContain("2 more problems omitted to prevent context overflow")
})
it("should prioritize errors over warnings when limiting diagnostics by count", async () => {
// Mock file URIs
const fileUri1 = vscode.Uri.file("/path/to/file1.ts")
const fileUri2 = vscode.Uri.file("/path/to/file2.ts")
// Create diagnostics with mixed severities
const diagnostics1 = [
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Warning in file1", vscode.DiagnosticSeverity.Warning),
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Error in file1", vscode.DiagnosticSeverity.Error),
]
const diagnostics2 = [
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error in file2", vscode.DiagnosticSeverity.Error),
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning in file2", vscode.DiagnosticSeverity.Warning),
new vscode.Diagnostic(
new vscode.Range(2, 0, 2, 10),
"Info in file2",
vscode.DiagnosticSeverity.Information,
),
]
// Mock fs.stat to return file type
const mockStat = {
type: vscode.FileType.File,
}
vscode.workspace.fs.stat = vitest.fn().mockResolvedValue(mockStat)
// Mock document content
const mockDocument = {
lineAt: vitest.fn((line) => ({
text: `Line ${line + 1} content`,
})),
}
vscode.workspace.openTextDocument = vitest.fn().mockResolvedValue(mockDocument)
// Test with maxDiagnostics set to 2 (should include exactly 2 diagnostics)
const result = await diagnosticsToProblemsString(
[
[fileUri1, diagnostics1],
[fileUri2, diagnostics2],
],
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning, vscode.DiagnosticSeverity.Information],
"/path/to",
true, // includeDiagnostics
2, // maxDiagnostics (count limit)
)
// Verify exactly 2 errors are included (prioritized over warnings)
expect(result).toContain("Error in file1")
expect(result).toContain("Error in file2")
// Warnings and info should not be included
expect(result).not.toContain("Warning in file1")
expect(result).not.toContain("Warning in file2")
expect(result).not.toContain("Info in file2")
// Verify the limit message is included
expect(result).toContain("3 more problems omitted to prevent context overflow")
})
it("should handle maxDiagnostics with no limit when undefined", async () => {
// Mock file URI
const fileUri = vscode.Uri.file("/path/to/file.ts")
// Create multiple diagnostics
const diagnostics = [
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error 1", vscode.DiagnosticSeverity.Error),
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning 1", vscode.DiagnosticSeverity.Warning),
new vscode.Diagnostic(new vscode.Range(2, 0, 2, 10), "Error 2", vscode.DiagnosticSeverity.Error),
]
// Mock fs.stat to return file type
const mockStat = {
type: vscode.FileType.File,
}
vscode.workspace.fs.stat = vitest.fn().mockResolvedValue(mockStat)
// Mock document content
const mockDocument = {
lineAt: vitest.fn((line) => ({
text: `Line ${line + 1} content`,
})),
}
vscode.workspace.openTextDocument = vitest.fn().mockResolvedValue(mockDocument)
// Test with maxDiagnostics undefined
const result = await diagnosticsToProblemsString(
[[fileUri, diagnostics]],
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
"/path/to",
true, // includeDiagnostics
undefined, // maxDiagnostics
)
// Verify all diagnostics are included
expect(result).toContain("Error 1")
expect(result).toContain("Warning 1")
expect(result).toContain("Error 2")
// Verify no limit message is included
expect(result).not.toContain("(Showing")
})
it("should handle maxDiagnostics of 0 as no limit", async () => {
// Mock file URI
const fileUri = vscode.Uri.file("/path/to/file.ts")
// Create multiple diagnostics
const diagnostics = [
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error 1", vscode.DiagnosticSeverity.Error),
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning 1", vscode.DiagnosticSeverity.Warning),
]
// Mock fs.stat to return file type
const mockStat = {
type: vscode.FileType.File,
}
vscode.workspace.fs.stat = vitest.fn().mockResolvedValue(mockStat)
// Mock document content
const mockDocument = {
lineAt: vitest.fn((line) => ({
text: `Line ${line + 1} content`,
})),
}
vscode.workspace.openTextDocument = vitest.fn().mockResolvedValue(mockDocument)
// Test with maxDiagnostics set to 0
const result = await diagnosticsToProblemsString(
[[fileUri, diagnostics]],
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
"/path/to",
true, // includeDiagnostics
0, // maxDiagnostics (should be treated as no limit)
)
// Verify all diagnostics are included
expect(result).toContain("Error 1")
expect(result).toContain("Warning 1")
// Verify no limit message is included
expect(result).not.toContain("(Showing")
})
})

View file

@ -74,55 +74,170 @@ export async function diagnosticsToProblemsString(
diagnostics: [vscode.Uri, vscode.Diagnostic[]][],
severities: vscode.DiagnosticSeverity[],
cwd: string,
includeDiagnosticMessages: boolean = true,
maxDiagnosticMessages?: number,
): Promise<string> {
// If diagnostics are disabled, return empty string
if (!includeDiagnosticMessages) {
return ""
}
const documents = new Map<vscode.Uri, vscode.TextDocument>()
const fileStats = new Map<vscode.Uri, vscode.FileStat>()
let result = ""
for (const [uri, fileDiagnostics] of diagnostics) {
const problems = fileDiagnostics
.filter((d) => severities.includes(d.severity))
.sort((a, b) => a.range.start.line - b.range.start.line)
if (problems.length > 0) {
result += `\n\n${path.relative(cwd, uri.fsPath).toPosix()}`
for (const diagnostic of problems) {
let label: string
switch (diagnostic.severity) {
case vscode.DiagnosticSeverity.Error:
label = "Error"
break
case vscode.DiagnosticSeverity.Warning:
label = "Warning"
break
case vscode.DiagnosticSeverity.Information:
label = "Information"
break
case vscode.DiagnosticSeverity.Hint:
label = "Hint"
break
default:
label = "Diagnostic"
// If we have a limit, use count-based limiting
if (maxDiagnosticMessages && maxDiagnosticMessages > 0) {
let includedCount = 0
let totalCount = 0
// Flatten all diagnostics with their URIs
const allDiagnostics: { uri: vscode.Uri; diagnostic: vscode.Diagnostic; formattedText?: string }[] = []
for (const [uri, fileDiagnostics] of diagnostics) {
const filtered = fileDiagnostics.filter((d) => severities.includes(d.severity))
for (const diagnostic of filtered) {
allDiagnostics.push({ uri, diagnostic })
totalCount++
}
}
// Sort by severity (errors first) and then by line number
allDiagnostics.sort((a, b) => {
const severityDiff = a.diagnostic.severity - b.diagnostic.severity
if (severityDiff !== 0) return severityDiff
return a.diagnostic.range.start.line - b.diagnostic.range.start.line
})
// Process diagnostics up to the count limit
const includedDiagnostics: typeof allDiagnostics = []
for (const item of allDiagnostics) {
// Stop if we've reached the count limit
if (includedCount >= maxDiagnosticMessages) {
break
}
// Format the diagnostic
let label: string
switch (item.diagnostic.severity) {
case vscode.DiagnosticSeverity.Error:
label = "Error"
break
case vscode.DiagnosticSeverity.Warning:
label = "Warning"
break
case vscode.DiagnosticSeverity.Information:
label = "Information"
break
case vscode.DiagnosticSeverity.Hint:
label = "Hint"
break
default:
label = "Diagnostic"
}
const line = item.diagnostic.range.start.line + 1
const source = item.diagnostic.source ? `${item.diagnostic.source} ` : ""
// Pre-format the diagnostic text
let diagnosticText = ""
try {
let fileStat = fileStats.get(item.uri)
if (!fileStat) {
fileStat = await vscode.workspace.fs.stat(item.uri)
fileStats.set(item.uri, fileStat)
}
const line = diagnostic.range.start.line + 1 // VSCode lines are 0-indexed
const source = diagnostic.source ? `${diagnostic.source} ` : ""
try {
let fileStat = fileStats.get(uri)
if (!fileStat) {
fileStat = await vscode.workspace.fs.stat(uri)
fileStats.set(uri, fileStat)
if (fileStat.type === vscode.FileType.File) {
const document = documents.get(item.uri) || (await vscode.workspace.openTextDocument(item.uri))
documents.set(item.uri, document)
const lineContent = document.lineAt(item.diagnostic.range.start.line).text
diagnosticText = `\n- [${source}${label}] ${line} | ${lineContent} : ${item.diagnostic.message}`
} else {
diagnosticText = `\n- [${source}${label}] 1 | (directory) : ${item.diagnostic.message}`
}
} catch {
diagnosticText = `\n- [${source}${label}] ${line} | (unavailable) : ${item.diagnostic.message}`
}
item.formattedText = diagnosticText
includedDiagnostics.push(item)
includedCount++
}
// Group included diagnostics by URI for output
const groupedDiagnostics = new Map<string, { uri: vscode.Uri; diagnostics: typeof allDiagnostics }>()
for (const item of includedDiagnostics) {
const key = item.uri.toString()
if (!groupedDiagnostics.has(key)) {
groupedDiagnostics.set(key, { uri: item.uri, diagnostics: [] })
}
groupedDiagnostics.get(key)!.diagnostics.push(item)
}
// Build the output
for (const { uri, diagnostics: fileDiagnostics } of groupedDiagnostics.values()) {
const sortedDiagnostics = fileDiagnostics.sort(
(a, b) => a.diagnostic.range.start.line - b.diagnostic.range.start.line,
)
if (sortedDiagnostics.length > 0) {
result += `\n\n${path.relative(cwd, uri.fsPath).toPosix()}`
for (const item of sortedDiagnostics) {
result += item.formattedText
}
}
}
// Add a note if we hit the limit
if (totalCount > includedCount) {
result += `\n\n... ${totalCount - includedCount} more problems omitted to prevent context overflow`
}
} else {
// No limit, process all diagnostics as before
for (const [uri, fileDiagnostics] of diagnostics) {
const problems = fileDiagnostics
.filter((d) => severities.includes(d.severity))
.sort((a, b) => a.range.start.line - b.range.start.line)
if (problems.length > 0) {
result += `\n\n${path.relative(cwd, uri.fsPath).toPosix()}`
for (const diagnostic of problems) {
let label: string
switch (diagnostic.severity) {
case vscode.DiagnosticSeverity.Error:
label = "Error"
break
case vscode.DiagnosticSeverity.Warning:
label = "Warning"
break
case vscode.DiagnosticSeverity.Information:
label = "Information"
break
case vscode.DiagnosticSeverity.Hint:
label = "Hint"
break
default:
label = "Diagnostic"
}
if (fileStat.type === vscode.FileType.File) {
const document = documents.get(uri) || (await vscode.workspace.openTextDocument(uri))
documents.set(uri, document)
const lineContent = document.lineAt(diagnostic.range.start.line).text
result += `\n- [${source}${label}] ${line} | ${lineContent} : ${diagnostic.message}`
} else {
result += `\n- [${source}${label}] 1 | (directory) : ${diagnostic.message}`
const line = diagnostic.range.start.line + 1 // VSCode lines are 0-indexed
const source = diagnostic.source ? `${diagnostic.source} ` : ""
try {
let fileStat = fileStats.get(uri)
if (!fileStat) {
fileStat = await vscode.workspace.fs.stat(uri)
fileStats.set(uri, fileStat)
}
if (fileStat.type === vscode.FileType.File) {
const document = documents.get(uri) || (await vscode.workspace.openTextDocument(uri))
documents.set(uri, document)
const lineContent = document.lineAt(diagnostic.range.start.line).text
result += `\n- [${source}${label}] ${line} | ${lineContent} : ${diagnostic.message}`
} else {
result += `\n- [${source}${label}] 1 | (directory) : ${diagnostic.message}`
}
} catch {
result += `\n- [${source}${label}] ${line} | (unavailable) : ${diagnostic.message}`
}
} catch {
result += `\n- [${source}${label}] ${line} | (unavailable) : ${diagnostic.message}`
}
}
}
}
return result.trim()
}

View file

@ -36,8 +36,14 @@ export class DiffViewProvider {
private activeLineController?: DecorationController
private streamedLines: string[] = []
private preDiagnostics: [vscode.Uri, vscode.Diagnostic[]][] = []
private taskRef: WeakRef<Task>
constructor(private cwd: string) {}
constructor(
private cwd: string,
task: Task,
) {
this.taskRef = new WeakRef(task)
}
async open(relPath: string): Promise<void> {
this.relPath = relPath
@ -234,12 +240,20 @@ export class DiffViewProvider {
const postDiagnostics = vscode.languages.getDiagnostics()
// Get diagnostic settings from state
const task = this.taskRef.deref()
const state = await task?.providerRef.deref()?.getState()
const includeDiagnosticMessages = state?.includeDiagnosticMessages ?? true
const maxDiagnosticMessages = state?.maxDiagnosticMessages ?? 50
const newProblems = await diagnosticsToProblemsString(
getNewDiagnostics(this.preDiagnostics, postDiagnostics),
[
vscode.DiagnosticSeverity.Error, // only including errors since warnings can be distracting (if user wants to fix warnings they can use the @problems mention)
],
this.cwd,
includeDiagnosticMessages,
maxDiagnosticMessages,
) // Will be empty string if no errors.
newProblemsMessage =

View file

@ -101,6 +101,7 @@ describe("DiffViewProvider", () => {
let diffViewProvider: DiffViewProvider
const mockCwd = "/mock/cwd"
let mockWorkspaceEdit: { replace: any; delete: any }
let mockTask: any
beforeEach(() => {
vi.clearAllMocks()
@ -110,7 +111,19 @@ describe("DiffViewProvider", () => {
}
vi.mocked(vscode.WorkspaceEdit).mockImplementation(() => mockWorkspaceEdit as any)
diffViewProvider = new DiffViewProvider(mockCwd)
// Create a mock Task instance
mockTask = {
providerRef: {
deref: vi.fn().mockReturnValue({
getState: vi.fn().mockResolvedValue({
includeDiagnosticMessages: true,
maxDiagnosticMessages: 50,
}),
}),
},
}
diffViewProvider = new DiffViewProvider(mockCwd, mockTask)
// Mock the necessary properties and methods
;(diffViewProvider as any).relPath = "test.txt"
;(diffViewProvider as any).activeDiffEditor = {

View file

@ -234,6 +234,8 @@ export type ExtensionState = Pick<
| "codebaseIndexConfig"
| "codebaseIndexModels"
| "profileThresholds"
| "includeDiagnosticMessages"
| "maxDiagnosticMessages"
> & {
version: string
clineMessages: ClineMessage[]

View file

@ -162,6 +162,8 @@ export interface WebviewMessage {
| "language"
| "maxReadFileLine"
| "maxConcurrentFileReads"
| "includeDiagnosticMessages"
| "maxDiagnosticMessages"
| "searchFiles"
| "toggleApiConfigPin"
| "setHistoryPreviewCollapsed"

View file

@ -20,7 +20,6 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
alwaysAllowWrite?: boolean
alwaysAllowWriteOutsideWorkspace?: boolean
alwaysAllowWriteProtected?: boolean
writeDelayMs: number
alwaysAllowBrowser?: boolean
alwaysApproveResubmit?: boolean
requestDelaySeconds: number
@ -39,7 +38,6 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
| "alwaysAllowWrite"
| "alwaysAllowWriteOutsideWorkspace"
| "alwaysAllowWriteProtected"
| "writeDelayMs"
| "alwaysAllowBrowser"
| "alwaysApproveResubmit"
| "requestDelaySeconds"
@ -61,7 +59,6 @@ export const AutoApproveSettings = ({
alwaysAllowWrite,
alwaysAllowWriteOutsideWorkspace,
alwaysAllowWriteProtected,
writeDelayMs,
alwaysAllowBrowser,
alwaysApproveResubmit,
requestDelaySeconds,
@ -216,22 +213,6 @@ export const AutoApproveSettings = ({
{t("settings:autoApprove.write.protected.description")}
</div>
</div>
<div>
<div className="flex items-center gap-2">
<Slider
min={0}
max={5000}
step={100}
value={[writeDelayMs]}
onValueChange={([value]) => setCachedStateField("writeDelayMs", value)}
data-testid="write-delay-slider"
/>
<span className="w-20">{writeDelayMs}ms</span>
</div>
<div className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:autoApprove.write.delayLabel")}
</div>
</div>
</div>
)}

View file

@ -5,7 +5,7 @@ import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
import { Database, FoldVertical } from "lucide-react"
import { cn } from "@/lib/utils"
import { Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider } from "@/components/ui"
import { Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider, Button } from "@/components/ui"
import { SetCachedStateField } from "./types"
import { SectionHeader } from "./SectionHeader"
@ -22,6 +22,9 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
maxReadFileLine?: number
maxConcurrentFileReads?: number
profileThresholds?: Record<string, number>
includeDiagnosticMessages?: boolean
maxDiagnosticMessages?: number
writeDelayMs: number
setCachedStateField: SetCachedStateField<
| "autoCondenseContext"
| "autoCondenseContextPercent"
@ -31,6 +34,9 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
| "maxReadFileLine"
| "maxConcurrentFileReads"
| "profileThresholds"
| "includeDiagnosticMessages"
| "maxDiagnosticMessages"
| "writeDelayMs"
>
}
@ -45,6 +51,9 @@ export const ContextManagementSettings = ({
maxReadFileLine,
maxConcurrentFileReads,
profileThresholds = {},
includeDiagnosticMessages,
maxDiagnosticMessages,
writeDelayMs,
className,
...props
}: ContextManagementSettingsProps) => {
@ -196,6 +205,95 @@ export const ContextManagementSettings = ({
{t("settings:contextManagement.maxReadFile.description")}
</div>
</div>
<div>
<VSCodeCheckbox
checked={includeDiagnosticMessages}
onChange={(e: any) => setCachedStateField("includeDiagnosticMessages", e.target.checked)}
data-testid="include-diagnostic-messages-checkbox">
<label className="block font-medium mb-1">
{t("settings:contextManagement.diagnostics.includeMessages.label")}
</label>
</VSCodeCheckbox>
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-3">
{t("settings:contextManagement.diagnostics.includeMessages.description")}
</div>
</div>
<div>
<span className="block font-medium mb-1">
{t("settings:contextManagement.diagnostics.maxMessages.label")}
</span>
<div className="flex items-center gap-2">
<Slider
min={1}
max={100}
step={1}
value={[
maxDiagnosticMessages !== undefined && maxDiagnosticMessages <= 0
? 100
: (maxDiagnosticMessages ?? 50),
]}
onValueChange={([value]) => {
// When slider reaches 100, set to -1 (unlimited)
setCachedStateField("maxDiagnosticMessages", value === 100 ? -1 : value)
}}
data-testid="max-diagnostic-messages-slider"
aria-label={t("settings:contextManagement.diagnostics.maxMessages.label")}
aria-valuemin={1}
aria-valuemax={100}
aria-valuenow={
maxDiagnosticMessages !== undefined && maxDiagnosticMessages <= 0
? 100
: (maxDiagnosticMessages ?? 50)
}
aria-valuetext={
(maxDiagnosticMessages !== undefined && maxDiagnosticMessages <= 0) ||
maxDiagnosticMessages === 100
? t("settings:contextManagement.diagnostics.maxMessages.unlimitedLabel")
: `${maxDiagnosticMessages ?? 50} ${t("settings:contextManagement.diagnostics.maxMessages.label")}`
}
/>
<span className="w-20 text-sm font-medium">
{(maxDiagnosticMessages !== undefined && maxDiagnosticMessages <= 0) ||
maxDiagnosticMessages === 100
? t("settings:contextManagement.diagnostics.maxMessages.unlimitedLabel")
: (maxDiagnosticMessages ?? 50)}
</span>
<Button
variant="ghost"
size="sm"
onClick={() => setCachedStateField("maxDiagnosticMessages", 50)}
title={t("settings:contextManagement.diagnostics.maxMessages.resetTooltip")}
className="p-1 h-6 w-6"
disabled={maxDiagnosticMessages === 50}>
<span className="codicon codicon-discard" />
</Button>
</div>
<div className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:contextManagement.diagnostics.maxMessages.description")}
</div>
</div>
<div>
<span className="block font-medium mb-1">
{t("settings:contextManagement.diagnostics.delayAfterWrite.label")}
</span>
<div className="flex items-center gap-2">
<Slider
min={0}
max={5000}
step={100}
value={[writeDelayMs]}
onValueChange={([value]) => setCachedStateField("writeDelayMs", value)}
data-testid="write-delay-slider"
/>
<span className="w-20">{writeDelayMs}ms</span>
</div>
<div className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:contextManagement.diagnostics.delayAfterWrite.description")}
</div>
</div>
</Section>
<Section className="pt-2">
<VSCodeCheckbox

View file

@ -177,6 +177,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
alwaysAllowFollowupQuestions,
alwaysAllowUpdateTodoList,
followupAutoApproveTimeoutMs,
includeDiagnosticMessages,
maxDiagnosticMessages,
} = cachedState
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
@ -320,6 +322,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
vscode.postMessage({ type: "showRooIgnoredFiles", bool: showRooIgnoredFiles })
vscode.postMessage({ type: "maxReadFileLine", value: maxReadFileLine ?? -1 })
vscode.postMessage({ type: "maxConcurrentFileReads", value: cachedState.maxConcurrentFileReads ?? 5 })
vscode.postMessage({ type: "includeDiagnosticMessages", bool: includeDiagnosticMessages })
vscode.postMessage({ type: "maxDiagnosticMessages", value: maxDiagnosticMessages ?? 50 })
vscode.postMessage({ type: "currentApiConfigName", text: currentApiConfigName })
vscode.postMessage({ type: "updateExperimental", values: experiments })
vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: alwaysAllowModeSwitch })
@ -606,7 +610,6 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
alwaysAllowWrite={alwaysAllowWrite}
alwaysAllowWriteOutsideWorkspace={alwaysAllowWriteOutsideWorkspace}
alwaysAllowWriteProtected={alwaysAllowWriteProtected}
writeDelayMs={writeDelayMs}
alwaysAllowBrowser={alwaysAllowBrowser}
alwaysApproveResubmit={alwaysApproveResubmit}
requestDelaySeconds={requestDelaySeconds}
@ -666,6 +669,9 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
maxReadFileLine={maxReadFileLine}
maxConcurrentFileReads={maxConcurrentFileReads}
profileThresholds={profileThresholds}
includeDiagnosticMessages={includeDiagnosticMessages}
maxDiagnosticMessages={maxDiagnosticMessages}
writeDelayMs={writeDelayMs}
setCachedStateField={setCachedStateField}
/>
)}

View file

@ -1,122 +1,320 @@
import { render, screen, fireEvent } from "@/utils/test-utils"
// npx vitest src/components/settings/__tests__/ContextManagementSettings.spec.tsx
import { ContextManagementSettings } from "@src/components/settings/ContextManagementSettings"
import { render, screen, fireEvent, waitFor } from "@/utils/test-utils"
import { ContextManagementSettings } from "../ContextManagementSettings"
// Mock translation hook to return the key as the translation
vitest.mock("@/i18n/TranslationContext", () => ({
// Mock the translation hook
vi.mock("@/hooks/useAppTranslation", () => ({
useAppTranslation: () => ({
t: (key: string) => key,
t: (key: string) => {
// Return specific translations for our test cases
if (key === "settings:contextManagement.diagnostics.maxMessages.unlimitedLabel") {
return "Unlimited"
}
return key
},
}),
}))
// Mock the UI components
vi.mock("@/components/ui", () => ({
...vi.importActual("@/components/ui"),
Slider: ({ value, onValueChange, "data-testid": dataTestId, disabled }: any) => (
<input
type="range"
value={value?.[0] ?? 0}
onChange={(e) => onValueChange([parseFloat(e.target.value)])}
onKeyDown={(e) => {
const currentValue = value?.[0] ?? 0
if (e.key === "ArrowRight") {
onValueChange([currentValue + 1])
} else if (e.key === "ArrowLeft") {
onValueChange([currentValue - 1])
}
}}
data-testid={dataTestId}
disabled={disabled}
role="slider"
/>
),
Input: ({ value, onChange, "data-testid": dataTestId, ...props }: any) => (
<input value={value} onChange={onChange} data-testid={dataTestId} {...props} />
),
Button: ({ children, onClick, ...props }: any) => (
<button onClick={onClick} {...props}>
{children}
</button>
),
Select: ({ children, ...props }: any) => (
<div role="combobox" {...props}>
{children}
</div>
),
SelectTrigger: ({ children, ...props }: any) => <div {...props}>{children}</div>,
SelectValue: ({ children, ...props }: any) => <div {...props}>{children}</div>,
SelectContent: ({ children, ...props }: any) => <div {...props}>{children}</div>,
SelectItem: ({ children, ...props }: any) => <div {...props}>{children}</div>,
}))
// Mock vscode utilities - this is necessary since we're not in a VSCode environment
vitest.mock("@/utils/vscode", () => ({
vi.mock("@/utils/vscode", () => ({
vscode: {
postMessage: vitest.fn(),
postMessage: vi.fn(),
},
}))
// Mock VSCode components to behave like standard HTML elements
vitest.mock("@vscode/webview-ui-toolkit/react", () => ({
vi.mock("@vscode/webview-ui-toolkit/react", () => ({
VSCodeCheckbox: ({ checked, onChange, children, "data-testid": dataTestId, ...props }: any) => (
<div>
<label data-testid={dataTestId} {...props}>
<input
type="checkbox"
checked={checked}
onChange={onChange}
data-testid={dataTestId}
aria-label={children?.props?.children || children}
role="checkbox"
aria-checked={checked}
{...props}
checked={checked || false}
aria-checked={checked || false}
onChange={(e: any) => onChange?.({ target: { checked: e.target.checked } })}
/>
{children}
</div>
),
VSCodeTextArea: ({ value, onChange, rows, className, ...props }: any) => (
<textarea value={value} onChange={onChange} rows={rows} className={className} role="textbox" {...props} />
</label>
),
VSCodeTextArea: ({ value, onChange, ...props }: any) => <textarea value={value} onChange={onChange} {...props} />,
}))
describe("ContextManagementSettings", () => {
const defaultProps = {
autoCondenseContext: true,
autoCondenseContextPercent: 100,
autoCondenseContext: false,
autoCondenseContextPercent: 80,
condensingApiConfigId: undefined,
customCondensingPrompt: undefined,
listApiConfigMeta: [],
maxOpenTabsContext: 20,
maxWorkspaceFiles: 200,
showRooIgnoredFiles: false,
setCachedStateField: vitest.fn(),
maxReadFileLine: -1,
maxConcurrentFileReads: 5,
profileThresholds: {},
includeDiagnosticMessages: true,
maxDiagnosticMessages: 50,
writeDelayMs: 1000,
setCachedStateField: vi.fn(),
}
beforeEach(() => {
vitest.clearAllMocks()
vi.clearAllMocks()
})
it("renders all controls", () => {
it("renders diagnostic settings", () => {
render(<ContextManagementSettings {...defaultProps} />)
// Open tabs context limit
const openTabsSlider = screen.getByTestId("open-tabs-limit-slider")
expect(openTabsSlider).toBeInTheDocument()
// Check for diagnostic checkbox
expect(screen.getByTestId("include-diagnostic-messages-checkbox")).toBeInTheDocument()
// Workspace files limit
const workspaceFilesSlider = screen.getByTestId("workspace-files-limit-slider")
expect(workspaceFilesSlider).toBeInTheDocument()
// Show .rooignore'd files
const showRooIgnoredFilesCheckbox = screen.getByTestId("show-rooignored-files-checkbox")
expect(showRooIgnoredFilesCheckbox).toBeInTheDocument()
expect(screen.getByTestId("show-rooignored-files-checkbox")).not.toBeChecked()
// Check for slider
expect(screen.getByTestId("max-diagnostic-messages-slider")).toBeInTheDocument()
expect(screen.getByText("50")).toBeInTheDocument()
})
it("updates open tabs context limit", () => {
const mockSetCachedStateField = vitest.fn()
const props = { ...defaultProps, setCachedStateField: mockSetCachedStateField }
render(<ContextManagementSettings {...props} />)
it("renders with diagnostic messages enabled", () => {
render(<ContextManagementSettings {...defaultProps} includeDiagnosticMessages={true} />)
const slider = screen.getByTestId("open-tabs-limit-slider")
const checkbox = screen.getByTestId("include-diagnostic-messages-checkbox")
expect(checkbox.querySelector("input")).toBeChecked()
const slider = screen.getByTestId("max-diagnostic-messages-slider")
expect(slider).toBeInTheDocument()
// Check that the current value is displayed
expect(screen.getByText("20")).toBeInTheDocument()
// Test slider interaction using keyboard events (ArrowRight increases value)
slider.focus()
fireEvent.keyDown(slider, { key: "ArrowRight" })
// The callback should have been called with the new value (20 + 1 = 21)
expect(mockSetCachedStateField).toHaveBeenCalledWith("maxOpenTabsContext", 21)
expect(slider).toHaveValue("50")
})
it("updates workspace files limit", () => {
const mockSetCachedStateField = vitest.fn()
const props = { ...defaultProps, setCachedStateField: mockSetCachedStateField }
render(<ContextManagementSettings {...props} />)
it("renders with diagnostic messages disabled", () => {
render(<ContextManagementSettings {...defaultProps} includeDiagnosticMessages={false} />)
const slider = screen.getByTestId("workspace-files-limit-slider")
expect(slider).toBeInTheDocument()
const checkbox = screen.getByTestId("include-diagnostic-messages-checkbox")
expect(checkbox.querySelector("input")).not.toBeChecked()
// Check that the current value is displayed
expect(screen.getByText("200")).toBeInTheDocument()
// Test slider interaction using keyboard events (ArrowRight increases value)
slider.focus()
fireEvent.keyDown(slider, { key: "ArrowRight" })
// The callback should have been called with the new value (200 + 1 = 201)
expect(mockSetCachedStateField).toHaveBeenCalledWith("maxWorkspaceFiles", 201)
// Slider should still be rendered when diagnostics are disabled
expect(screen.getByTestId("max-diagnostic-messages-slider")).toBeInTheDocument()
expect(screen.getByText("50")).toBeInTheDocument()
})
it("updates show rooignored files setting", () => {
render(<ContextManagementSettings {...defaultProps} />)
it("calls setCachedStateField when include diagnostic messages checkbox is toggled", async () => {
const setCachedStateField = vi.fn()
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
const checkbox = screen.getByTestId("show-rooignored-files-checkbox")
const checkbox = screen.getByTestId("include-diagnostic-messages-checkbox").querySelector("input")!
fireEvent.click(checkbox)
expect(defaultProps.setCachedStateField).toHaveBeenCalledWith("showRooIgnoredFiles", true)
await waitFor(() => {
expect(setCachedStateField).toHaveBeenCalledWith("includeDiagnosticMessages", false)
})
})
it("calls setCachedStateField when max diagnostic messages slider is changed", async () => {
const setCachedStateField = vi.fn()
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
const slider = screen.getByTestId("max-diagnostic-messages-slider")
fireEvent.change(slider, { target: { value: "100" } })
await waitFor(() => {
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", -1)
})
})
it("keeps slider visible when include diagnostic messages is unchecked", () => {
const { rerender } = render(<ContextManagementSettings {...defaultProps} includeDiagnosticMessages={true} />)
const slider = screen.getByTestId("max-diagnostic-messages-slider")
expect(slider).toBeInTheDocument()
// Update to disabled - slider should still be visible
rerender(<ContextManagementSettings {...defaultProps} includeDiagnosticMessages={false} />)
expect(screen.getByTestId("max-diagnostic-messages-slider")).toBeInTheDocument()
})
it("displays correct max diagnostic messages value", () => {
const { rerender } = render(<ContextManagementSettings {...defaultProps} maxDiagnosticMessages={25} />)
expect(screen.getByText("25")).toBeInTheDocument()
// Update value - 100 should display as "Unlimited"
rerender(<ContextManagementSettings {...defaultProps} maxDiagnosticMessages={100} />)
expect(
screen.getByText("settings:contextManagement.diagnostics.maxMessages.unlimitedLabel"),
).toBeInTheDocument()
// Test unlimited value (-1) displays as "Unlimited"
rerender(<ContextManagementSettings {...defaultProps} maxDiagnosticMessages={-1} />)
expect(
screen.getByText("settings:contextManagement.diagnostics.maxMessages.unlimitedLabel"),
).toBeInTheDocument()
})
it("renders other context management settings", () => {
render(<ContextManagementSettings {...defaultProps} />)
// Check for other sliders
expect(screen.getByTestId("open-tabs-limit-slider")).toBeInTheDocument()
expect(screen.getByTestId("workspace-files-limit-slider")).toBeInTheDocument()
expect(screen.getByTestId("max-concurrent-file-reads-slider")).toBeInTheDocument()
// Check for checkboxes
expect(screen.getByTestId("show-rooignored-files-checkbox")).toBeInTheDocument()
expect(screen.getByTestId("auto-condense-context-checkbox")).toBeInTheDocument()
})
describe("Edge cases for maxDiagnosticMessages", () => {
it("handles zero value as unlimited", async () => {
const setCachedStateField = vi.fn()
render(
<ContextManagementSettings
{...defaultProps}
maxDiagnosticMessages={0}
setCachedStateField={setCachedStateField}
/>,
)
// Zero is now treated as unlimited
expect(
screen.getByText("settings:contextManagement.diagnostics.maxMessages.unlimitedLabel"),
).toBeInTheDocument()
const slider = screen.getByTestId("max-diagnostic-messages-slider")
// Zero should map to slider position 100 (unlimited)
expect(slider).toHaveValue("100")
})
it("handles negative values as unlimited", async () => {
const setCachedStateField = vi.fn()
render(
<ContextManagementSettings
{...defaultProps}
maxDiagnosticMessages={-10}
setCachedStateField={setCachedStateField}
/>,
)
// Component displays "Unlimited" for any negative value
expect(
screen.getByText("settings:contextManagement.diagnostics.maxMessages.unlimitedLabel"),
).toBeInTheDocument()
// Slider should be at max position (100) for negative values
const slider = screen.getByTestId("max-diagnostic-messages-slider")
expect(slider).toHaveValue("100")
})
it("handles very large numbers by capping at maximum", async () => {
const setCachedStateField = vi.fn()
const largeNumber = 1000
render(
<ContextManagementSettings
{...defaultProps}
maxDiagnosticMessages={largeNumber}
setCachedStateField={setCachedStateField}
/>,
)
// Should display the actual value even if it exceeds slider max
expect(screen.getByText(largeNumber.toString())).toBeInTheDocument()
// Slider value would be capped at max (100)
const slider = screen.getByTestId("max-diagnostic-messages-slider")
expect(slider).toHaveValue("100")
})
it("enforces maximum value constraint", async () => {
const setCachedStateField = vi.fn()
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
const slider = screen.getByTestId("max-diagnostic-messages-slider")
// Test that setting value above 100 gets capped
fireEvent.change(slider, { target: { value: "150" } })
await waitFor(() => {
// Should be capped at 100, which maps to -1 (unlimited)
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", -1)
})
})
it("handles boundary value at minimum (1)", async () => {
const setCachedStateField = vi.fn()
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
const slider = screen.getByTestId("max-diagnostic-messages-slider")
fireEvent.change(slider, { target: { value: "1" } })
await waitFor(() => {
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", 1)
})
})
it("handles boundary value at maximum (100) as unlimited (-1)", async () => {
const setCachedStateField = vi.fn()
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
const slider = screen.getByTestId("max-diagnostic-messages-slider")
fireEvent.change(slider, { target: { value: "100" } })
await waitFor(() => {
// When slider is at 100, it should set the value to -1 (unlimited)
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", -1)
})
})
it("handles decimal values by parsing as float", async () => {
const setCachedStateField = vi.fn()
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
const slider = screen.getByTestId("max-diagnostic-messages-slider")
fireEvent.change(slider, { target: { value: "50.7" } })
await waitFor(() => {
// The mock slider component parses as float
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", 50.7)
})
})
})
it("renders max read file line controls", () => {
@ -201,7 +399,8 @@ describe("ContextManagementSettings", () => {
render(<ContextManagementSettings {...props} />)
const checkbox = screen.getByTestId("auto-condense-context-checkbox")
expect(checkbox).toBeChecked()
const input = checkbox.querySelector('input[type="checkbox"]')
expect(input).toBeChecked()
// Toggle off
fireEvent.click(checkbox)
@ -238,89 +437,47 @@ describe("ContextManagementSettings", () => {
})
})
describe("Edge cases and validation", () => {
it("handles invalid max read file line input", () => {
const mockSetCachedStateField = vitest.fn()
const propsWithMaxReadFileLine = {
...defaultProps,
maxReadFileLine: 500,
setCachedStateField: mockSetCachedStateField,
}
render(<ContextManagementSettings {...propsWithMaxReadFileLine} />)
it("renders max read file line controls with -1 value", () => {
const propsWithMaxReadFileLine = {
...defaultProps,
maxReadFileLine: -1,
}
render(<ContextManagementSettings {...propsWithMaxReadFileLine} />)
const input = screen.getByTestId("max-read-file-line-input")
const checkbox = screen.getByTestId("max-read-file-always-full-checkbox")
const input = checkbox.querySelector('input[type="checkbox"]')
expect(input).toBeChecked()
})
// Test invalid input (non-numeric)
fireEvent.change(input, { target: { value: "abc" } })
expect(mockSetCachedStateField).not.toHaveBeenCalled()
it("handles boundary values for sliders", () => {
const mockSetCachedStateField = vitest.fn()
const props = {
...defaultProps,
maxOpenTabsContext: 0,
maxWorkspaceFiles: 500,
setCachedStateField: mockSetCachedStateField,
}
render(<ContextManagementSettings {...props} />)
// Test negative value below -1
fireEvent.change(input, { target: { value: "-5" } })
expect(mockSetCachedStateField).not.toHaveBeenCalled()
// Check boundary values are displayed
expect(screen.getByText("0")).toBeInTheDocument() // min open tabs
expect(screen.getByText("500")).toBeInTheDocument() // max workspace files
})
// Test valid input
fireEvent.change(input, { target: { value: "1000" } })
expect(mockSetCachedStateField).toHaveBeenCalledWith("maxReadFileLine", 1000)
})
it("handles undefined optional props gracefully", () => {
const propsWithUndefined = {
...defaultProps,
showRooIgnoredFiles: undefined,
maxReadFileLine: undefined,
}
it("selects input text on click", () => {
const propsWithMaxReadFileLine = {
...defaultProps,
maxReadFileLine: 500,
}
render(<ContextManagementSettings {...propsWithMaxReadFileLine} />)
expect(() => {
render(<ContextManagementSettings {...propsWithUndefined} />)
}).not.toThrow()
const input = screen.getByTestId("max-read-file-line-input") as HTMLInputElement
const selectSpy = vitest.spyOn(input, "select")
fireEvent.click(input)
expect(selectSpy).toHaveBeenCalled()
})
it("disables max read file input when always full read is checked", () => {
const propsWithAlwaysFullRead = {
...defaultProps,
maxReadFileLine: -1,
}
render(<ContextManagementSettings {...propsWithAlwaysFullRead} />)
const input = screen.getByTestId("max-read-file-line-input")
expect(input).toBeDisabled()
const checkbox = screen.getByTestId("max-read-file-always-full-checkbox")
expect(checkbox).toBeChecked()
})
it("handles boundary values for sliders", () => {
const mockSetCachedStateField = vitest.fn()
const props = {
...defaultProps,
maxOpenTabsContext: 0,
maxWorkspaceFiles: 500,
setCachedStateField: mockSetCachedStateField,
}
render(<ContextManagementSettings {...props} />)
// Check boundary values are displayed
expect(screen.getByText("0")).toBeInTheDocument() // min open tabs
expect(screen.getByText("500")).toBeInTheDocument() // max workspace files
})
it("handles undefined optional props gracefully", () => {
const propsWithUndefined = {
...defaultProps,
showRooIgnoredFiles: undefined,
maxReadFileLine: undefined,
}
expect(() => {
render(<ContextManagementSettings {...propsWithUndefined} />)
}).not.toThrow()
// Should use default values
expect(screen.getByText("20")).toBeInTheDocument() // default maxOpenTabsContext
expect(screen.getByText("200")).toBeInTheDocument() // default maxWorkspaceFiles
})
// Should use default values
expect(screen.getByText("20")).toBeInTheDocument() // default maxOpenTabsContext
expect(screen.getByText("200")).toBeInTheDocument() // default maxWorkspaceFiles
})
describe("Conditional rendering", () => {

View file

@ -134,6 +134,10 @@ export interface ExtensionStateContextType extends ExtensionState {
routerModels?: RouterModels
alwaysAllowUpdateTodoList?: boolean
setAlwaysAllowUpdateTodoList: (value: boolean) => void
includeDiagnosticMessages?: boolean
setIncludeDiagnosticMessages: (value: boolean) => void
maxDiagnosticMessages?: number
setMaxDiagnosticMessages: (value: number) => void
}
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@ -229,6 +233,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
},
codebaseIndexModels: { ollama: {}, openai: {} },
alwaysAllowUpdateTodoList: true,
includeDiagnosticMessages: true,
maxDiagnosticMessages: 50,
})
const [didHydrateState, setDidHydrateState] = useState(false)
@ -474,6 +480,14 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setAlwaysAllowUpdateTodoList: (value) => {
setState((prevState) => ({ ...prevState, alwaysAllowUpdateTodoList: value }))
},
includeDiagnosticMessages: state.includeDiagnosticMessages,
setIncludeDiagnosticMessages: (value) => {
setState((prevState) => ({ ...prevState, includeDiagnosticMessages: value }))
},
maxDiagnosticMessages: state.maxDiagnosticMessages,
setMaxDiagnosticMessages: (value) => {
setState((prevState) => ({ ...prevState, maxDiagnosticMessages: value }))
},
}
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>

View file

@ -488,6 +488,22 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Inclou automàticament diagnòstics al context",
"description": "Quan està activat, els missatges de diagnòstic (errors) dels fitxers editats s'inclouran automàticament al context. Sempre pots incloure manualment tots els diagnòstics de l'espai de treball utilitzant @problems."
},
"maxMessages": {
"label": "Màxim de missatges de diagnòstic",
"description": "Nombre màxim de missatges de diagnòstic a incloure per fitxer. Aquest límit s'aplica tant a la inclusió automàtica (quan la casella està activada) com a les mencions manuals de @problems. Valors més alts proporcionen més context però augmenten l'ús de tokens.",
"resetTooltip": "Restablir al valor per defecte (50)",
"unlimitedLabel": "Il·limitat"
},
"delayAfterWrite": {
"label": "Retard després d'escriptures per permetre que els diagnòstics detectin possibles problemes",
"description": "Temps d'espera després d'escriptures de fitxers abans de continuar, permetent que les eines de diagnòstic processin els canvis i detectin problemes."
}
},
"condensingThreshold": {
"label": "Llindar d'activació de condensació",
"selectProfile": "Configura el llindar per al perfil",

View file

@ -488,6 +488,22 @@
"lines": "Zeilen",
"always_full_read": "Immer die gesamte Datei lesen"
},
"diagnostics": {
"includeMessages": {
"label": "Diagnosen automatisch in den Kontext aufnehmen",
"description": "Wenn aktiviert, werden Diagnosenachrichten (Fehler) aus bearbeiteten Dateien automatisch in den Kontext aufgenommen. Sie können jederzeit alle Workspace-Diagnosen manuell mit @problems einbeziehen."
},
"maxMessages": {
"label": "Maximale Anzahl von Diagnosenachrichten",
"description": "Maximale Anzahl von Diagnosenachrichten, die pro Datei eingeschlossen werden. Dieses Limit gilt sowohl für die automatische Einbeziehung (wenn das Kontrollkästchen aktiviert ist) als auch für manuelle @problems-Erwähnungen. Höhere Werte bieten mehr Kontext, erhöhen aber den Token-Verbrauch.",
"resetTooltip": "Auf Standardwert zurücksetzen (50)",
"unlimitedLabel": "Unbegrenzt"
},
"delayAfterWrite": {
"label": "Verzögerung nach Schreibvorgängen, damit Diagnosen potenzielle Probleme erkennen können",
"description": "Wartezeit nach Dateischreibvorgängen vor dem Fortfahren, damit Diagnosetools Änderungen verarbeiten und Probleme erkennen können."
}
},
"condensingThreshold": {
"label": "Schwellenwert für Kontextkomprimierung",
"selectProfile": "Profil für Schwellenwert konfigurieren",

View file

@ -488,6 +488,22 @@
"lines": "lines",
"always_full_read": "Always read entire file"
},
"diagnostics": {
"includeMessages": {
"label": "Automatically include diagnostics in context",
"description": "When enabled, diagnostic messages (errors) from edited files will be automatically included in the context. You can always manually include all workspace diagnostics using @problems."
},
"maxMessages": {
"label": "Maximum diagnostic messages",
"description": "Limits the number of diagnostic messages (errors, warnings) included in the context. When set, only this many diagnostics will be shown, prioritizing errors over warnings. Set to 0 for unlimited diagnostics.",
"resetTooltip": "Reset to default value (50)",
"unlimitedLabel": "Unlimited"
},
"delayAfterWrite": {
"label": "Delay after writes to allow diagnostics to detect potential problems",
"description": "Time to wait after file writes before proceeding, allowing diagnostic tools to process changes and detect issues."
}
},
"condensingThreshold": {
"label": "Condensing Trigger Threshold",
"selectProfile": "Configure threshold for profile",

View file

@ -488,6 +488,22 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Incluir automáticamente diagnósticos en el contexto",
"description": "Cuando está habilitado, los mensajes de diagnóstico (errores) de los archivos editados se incluirán automáticamente en el contexto. Siempre puedes incluir manualmente todos los diagnósticos del espacio de trabajo usando @problems."
},
"maxMessages": {
"label": "Máximo de mensajes de diagnóstico",
"description": "Número máximo de mensajes de diagnóstico a incluir por archivo. Este límite se aplica tanto a la inclusión automática (cuando la casilla está habilitada) como a las menciones manuales de @problems. Valores más altos proporcionan más contexto pero aumentan el uso de tokens.",
"resetTooltip": "Restablecer al valor predeterminado (50)",
"unlimitedLabel": "Ilimitado"
},
"delayAfterWrite": {
"label": "Retraso después de escrituras para permitir que los diagnósticos detecten problemas potenciales",
"description": "Tiempo de espera después de escrituras de archivos antes de continuar, permitiendo que las herramientas de diagnóstico procesen cambios y detecten problemas."
}
},
"condensingThreshold": {
"label": "Umbral de condensación de contexto",
"selectProfile": "Configurar umbral para perfil",

View file

@ -488,6 +488,22 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Inclure automatiquement les diagnostics dans le contexte",
"description": "Lorsque cette option est activée, les messages de diagnostic (erreurs) des fichiers modifiés seront automatiquement inclus dans le contexte. Vous pouvez toujours inclure manuellement tous les diagnostics de l'espace de travail en utilisant @problems."
},
"maxMessages": {
"label": "Nombre maximum de messages de diagnostic",
"description": "Nombre maximum de messages de diagnostic à inclure par fichier. Cette limite s'applique à la fois à l'inclusion automatique (lorsque la case est cochée) et aux mentions manuelles @problems. Des valeurs plus élevées fournissent plus de contexte mais augmentent l'utilisation des jetons.",
"resetTooltip": "Réinitialiser à la valeur par défaut (50)",
"unlimitedLabel": "Illimité"
},
"delayAfterWrite": {
"label": "Délai après les écritures pour permettre aux diagnostics de détecter les problèmes potentiels",
"description": "Temps d'attente après les écritures de fichiers avant de continuer, permettant aux outils de diagnostic de traiter les modifications et de détecter les problèmes."
}
},
"condensingThreshold": {
"label": "Seuil de condensation du contexte",
"selectProfile": "Configurer le seuil pour le profil",

View file

@ -488,6 +488,23 @@
"label": "एक साथ फ़ाइल पढ़ने की सीमा",
"description": "'read_file' टूल द्वारा एक साथ प्रोसेस की जा सकने वाली अधिकतम फ़ाइलों की संख्या। उच्च मान कई छोटी फ़ाइलों को पढ़ने की गति बढ़ा सकते हैं लेकिन मेमोरी उपयोग बढ़ा देते हैं।"
},
"diagnostics": {
"includeMessages": {
"label": "स्वचालित रूप से संदर्भ में डायग्नोस्टिक शामिल करें",
"description": "जब सक्षम होता है, तो संपादित फ़ाइलों से डायग्नोस्टिक संदेश (त्रुटियां) स्वचालित रूप से संदर्भ में शामिल किए जाएंगे। आप हमेशा @problems का उपयोग करके सभी कार्यक्षेत्र डायग्नोस्टिक को मैन्युअल रूप से शामिल कर सकते हैं।"
},
"maxMessages": {
"label": "अधिकतम डायग्नोस्टिक संदेश",
"description": "प्रति फ़ाइल शामिल किए जाने वाले डायग्नोस्टिक संदेशों की अधिकतम संख्या। यह सीमा स्वचालित समावेशन (जब चेकबॉक्स सक्षम है) और मैन्युअल @problems उल्लेख दोनों पर लागू होती है। उच्च मान अधिक संदर्भ प्रदान करते हैं लेकिन टोकन उपयोग बढ़ाते हैं।",
"resetTooltip": "डिफ़ॉल्ट मान पर रीसेट करें (50)",
"unlimited": "असीमित डायग्नोस्टिक संदेश",
"unlimitedLabel": "असीमित"
},
"delayAfterWrite": {
"label": "संभावित समस्याओं का पता लगाने के लिए डायग्नोस्टिक्स को अनुमति देने के लिए लिखने के बाद देरी",
"description": "फ़ाइल लिखने के बाद आगे बढ़ने से पहले प्रतीक्षा करने का समय, डायग्नोस्टिक टूल को परिवर्तनों को संसाधित करने और समस्याओं का पता लगाने की अनुमति देता है।"
}
},
"condensingThreshold": {
"label": "संघनन ट्रिगर सीमा",
"selectProfile": "प्रोफ़ाइल के लिए सीमा कॉन्फ़िगर करें",

View file

@ -470,6 +470,23 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Secara otomatis sertakan diagnostik dalam konteks",
"description": "Ketika diaktifkan, pesan diagnostik (error) dari file yang diedit akan secara otomatis disertakan dalam konteks. Kamu selalu dapat menyertakan semua diagnostik workspace secara manual menggunakan @problems."
},
"maxMessages": {
"label": "Pesan diagnostik maksimum",
"description": "Jumlah maksimum pesan diagnostik yang akan disertakan per file. Batas ini berlaku untuk penyertaan otomatis (ketika checkbox diaktifkan) dan penyebutan manual @problems. Nilai yang lebih tinggi memberikan lebih banyak konteks tetapi meningkatkan penggunaan token.",
"resetTooltip": "Reset ke nilai default (50)",
"unlimited": "Pesan diagnostik tidak terbatas",
"unlimitedLabel": "Tak terbatas"
},
"delayAfterWrite": {
"label": "Tunda setelah penulisan untuk memungkinkan diagnostik mendeteksi potensi masalah",
"description": "Waktu tunggu setelah penulisan file sebelum melanjutkan, memungkinkan alat diagnostik untuk memproses perubahan dan mendeteksi masalah."
}
},
"condensingThreshold": {
"label": "Ambang Batas Pemicu Kondensasi",
"selectProfile": "Konfigurasi ambang batas untuk profil",

View file

@ -488,6 +488,23 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Includi automaticamente la diagnostica nel contesto",
"description": "Quando abilitato, i messaggi diagnostici (errori) dai file modificati verranno automaticamente inclusi nel contesto. Puoi sempre includere manualmente tutta la diagnostica del workspace usando @problems."
},
"maxMessages": {
"label": "Numero massimo di messaggi diagnostici",
"description": "Numero massimo di messaggi diagnostici da includere per file. Questo limite si applica sia all'inclusione automatica (quando la casella è abilitata) che alle menzioni manuali di @problems. Valori più alti forniscono più contesto ma aumentano l'utilizzo dei token.",
"resetTooltip": "Ripristina al valore predefinito (50)",
"unlimited": "Messaggi diagnostici illimitati",
"unlimitedLabel": "Illimitato"
},
"delayAfterWrite": {
"label": "Ritardo dopo le scritture per consentire alla diagnostica di rilevare potenziali problemi",
"description": "Tempo di attesa dopo la scrittura dei file prima di procedere, consentendo agli strumenti di diagnostica di elaborare le modifiche e rilevare i problemi."
}
},
"condensingThreshold": {
"label": "Soglia di attivazione condensazione",
"selectProfile": "Configura soglia per profilo",

View file

@ -488,6 +488,23 @@
"label": "同時ファイル読み取り制限",
"description": "read_file ツールが同時に処理できるファイルの最大数。値を高くすると複数の小さなファイルの読み取りが速くなる可能性がありますが、メモリ使用量が増加します。"
},
"diagnostics": {
"includeMessages": {
"label": "診断を自動的にコンテキストに含める",
"description": "有効にすると、編集されたファイルからの診断メッセージ(エラー)が自動的にコンテキストに含まれます。@problemsを使用して、いつでも手動ですべてのワークスペース診断を含めることができます。"
},
"maxMessages": {
"label": "最大診断メッセージ数",
"description": "ファイルごとに含める診断メッセージの最大数。この制限は、自動インクルード(チェックボックスが有効な場合)と手動の@problemsメンションの両方に適用されます。値を高くするとより多くのコンテキストが提供されますが、トークンの使用量が増加します。",
"resetTooltip": "デフォルト値(50)にリセット",
"unlimited": "無制限の診断メッセージ",
"unlimitedLabel": "無制限"
},
"delayAfterWrite": {
"label": "書き込み後に診断が潜在的な問題を検出できるように遅延させる",
"description": "ファイルの書き込み後に処理を続行するまでの待機時間。これにより、診断ツールが変更を処理して問題を検出できます。"
}
},
"condensingThreshold": {
"label": "圧縮トリガーしきい値",
"selectProfile": "プロファイルのしきい値を設定",

View file

@ -488,6 +488,23 @@
"label": "동시 파일 읽기 제한",
"description": "read_file 도구가 동시에 처리할 수 있는 최대 파일 수입니다. 높은 값은 여러 작은 파일을 읽는 속도를 높일 수 있지만 메모리 사용량이 증가합니다."
},
"diagnostics": {
"includeMessages": {
"label": "진단을 자동으로 컨텍스트에 포함",
"description": "활성화되면 편집된 파일의 진단 메시지(오류)가 자동으로 컨텍스트에 포함됩니다. @problems를 사용하여 언제든지 모든 워크스페이스 진단을 수동으로 포함할 수 있습니다."
},
"maxMessages": {
"label": "최대 진단 메시지",
"description": "파일당 포함할 최대 진단 메시지 수입니다. 이 제한은 자동 포함(체크박스가 활성화된 경우)과 수동 @problems 언급 모두에 적용됩니다. 값이 높을수록 더 많은 컨텍스트를 제공하지만 토큰 사용량이 증가합니다.",
"resetTooltip": "기본값(50)으로 재설정",
"unlimited": "무제한 진단 메시지",
"unlimitedLabel": "무제한"
},
"delayAfterWrite": {
"label": "진단이 잠재적인 문제를 감지할 수 있도록 쓰기 후 지연",
"description": "파일 쓰기 후 계속 진행하기 전에 대기하는 시간으로, 진단 도구가 변경 사항을 처리하고 문제를 감지할 수 있도록 합니다."
}
},
"condensingThreshold": {
"label": "압축 트리거 임계값",
"selectProfile": "프로필 임계값 구성",

View file

@ -488,6 +488,23 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Automatisch diagnostiek opnemen in context",
"description": "Indien ingeschakeld, worden diagnostische berichten (fouten) van bewerkte bestanden automatisch opgenomen in de context. Je kunt altijd handmatig alle werkruimte-diagnostiek opnemen met @problems."
},
"maxMessages": {
"label": "Maximale diagnostische berichten",
"description": "Maximaal aantal diagnostische berichten dat per bestand moet worden opgenomen. Deze limiet geldt voor zowel automatische opname (wanneer checkbox is ingeschakeld) als handmatige @problems vermeldingen. Hogere waarden bieden meer context maar verhogen het tokengebruik.",
"resetTooltip": "Reset naar standaardwaarde (50)",
"unlimited": "Onbeperkte diagnostische berichten",
"unlimitedLabel": "Onbeperkt"
},
"delayAfterWrite": {
"label": "Vertraging na het schrijven om diagnostiek potentiële problemen te laten detecteren",
"description": "Wachttijd na het schrijven van bestanden voordat u doorgaat, zodat diagnostische hulpmiddelen wijzigingen kunnen verwerken en problemen kunnen detecteren."
}
},
"condensingThreshold": {
"label": "Compressie trigger drempelwaarde",
"selectProfile": "Drempelwaarde voor profiel configureren",

View file

@ -488,6 +488,23 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Automatycznie dołączaj diagnostykę do kontekstu",
"description": "Gdy włączone, komunikaty diagnostyczne (błędy) z edytowanych plików będą automatycznie dołączane do kontekstu. Zawsze możesz ręcznie dołączyć całą diagnostykę obszaru roboczego używając @problems."
},
"maxMessages": {
"label": "Maksymalna liczba komunikatów diagnostycznych",
"description": "Maksymalna liczba komunikatów diagnostycznych dołączanych na plik. Ten limit dotyczy zarówno automatycznego dołączania (gdy pole wyboru jest włączone) jak i ręcznych wzmianek @problems. Wyższe wartości dostarczają więcej kontekstu, ale zwiększają zużycie tokenów.",
"resetTooltip": "Resetuj do wartości domyślnej (50)",
"unlimited": "Nieograniczone komunikaty diagnostyczne",
"unlimitedLabel": "Nieograniczone"
},
"delayAfterWrite": {
"label": "Opóźnienie po zapisie, aby umożliwić diagnostyce wykrycie potencjalnych problemów",
"description": "Czas oczekiwania po zapisie plików przed kontynuowaniem, aby narzędzia diagnostyczne mogły przetworzyć zmiany i wykryć problemy."
}
},
"condensingThreshold": {
"label": "Próg wyzwalania kondensacji",
"selectProfile": "Skonfiguruj próg dla profilu",

View file

@ -488,6 +488,23 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Incluir diagnósticos automaticamente no contexto",
"description": "Quando ativado, mensagens de diagnóstico (erros) de arquivos editados serão automaticamente incluídas no contexto. Você sempre pode incluir manualmente todos os diagnósticos do espaço de trabalho usando @problems."
},
"maxMessages": {
"label": "Máximo de mensagens de diagnóstico",
"description": "Número máximo de mensagens de diagnóstico a serem incluídas por arquivo. Este limite se aplica tanto à inclusão automática (quando a caixa de seleção está ativada) quanto às menções manuais de @problems. Valores mais altos fornecem mais contexto, mas aumentam o uso de tokens.",
"resetTooltip": "Redefinir para o valor padrão (50)",
"unlimited": "Mensagens de diagnóstico ilimitadas",
"unlimitedLabel": "Ilimitado"
},
"delayAfterWrite": {
"label": "Atraso após as gravações para permitir que os diagnósticos detectem possíveis problemas",
"description": "Tempo de espera após a gravação de arquivos antes de prosseguir, permitindo que as ferramentas de diagnóstico processem as alterações e detectem problemas."
}
},
"condensingThreshold": {
"label": "Limite de Ativação de Condensação",
"selectProfile": "Configurar limite para perfil",

View file

@ -488,6 +488,23 @@
"label": "Лимит одновременного чтения",
"description": "Максимальное количество файлов, которые инструмент 'read_file' может обрабатывать одновременно. Более высокие значения могут ускорить чтение нескольких небольших файлов, но увеличивают использование памяти."
},
"diagnostics": {
"includeMessages": {
"label": "Автоматически включать диагностику в контекст",
"description": "Если включено, диагностические сообщения (ошибки) из редактируемых файлов будут автоматически включаться в контекст. Вы всегда можете вручную включить всю диагностику рабочей области, используя @problems."
},
"maxMessages": {
"label": "Максимальное количество диагностических сообщений",
"description": "Максимальное количество диагностических сообщений для включения в файл. Этот лимит применяется как к автоматическому включению (когда флажок включен), так и к ручным упоминаниям @problems. Более высокие значения предоставляют больше контекста, но увеличивают использование токенов.",
"resetTooltip": "Сбросить к значению по умолчанию (50)",
"unlimited": "Неограниченные диагностические сообщения",
"unlimitedLabel": "Неограниченно"
},
"delayAfterWrite": {
"label": "Задержка после записи, чтобы диагностика могла обнаружить потенциальные проблемы",
"description": "Время ожидания после записи файлов перед продолжением, чтобы средства диагностики могли обработать изменения и выявить проблемы."
}
},
"condensingThreshold": {
"label": "Порог запуска сжатия",
"selectProfile": "Настроить порог для профиля",

View file

@ -488,6 +488,23 @@
"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."
},
"diagnostics": {
"includeMessages": {
"label": "Tanı mesajlarını otomatik olarak bağlama dahil et",
"description": "Etkinleştirildiğinde, düzenlenen dosyalardan tanı mesajları (hatalar) otomatik olarak bağlama dahil edilecektir. @problems kullanarak tüm çalışma alanı tanı mesajlarını her zaman manuel olarak dahil edebilirsiniz."
},
"maxMessages": {
"label": "Maksimum tanı mesajı",
"description": "Dosya başına dahil edilecek maksimum tanı mesajı sayısı. Bu sınır hem otomatik dahil etme (onay kutusu etkinleştirildiğinde) hem de manuel @problems bahisleri için geçerlidir. Daha yüksek değerler daha fazla bağlam sağlar ancak jeton kullanımını artırır.",
"resetTooltip": "Varsayılan değere sıfırla (50)",
"unlimited": "Sınırsız tanı mesajları",
"unlimitedLabel": "Sınırsız"
},
"delayAfterWrite": {
"label": "Potansiyel sorunları tespit etmek için tanılamaya izin vermek üzere yazmalardan sonra gecikme",
"description": "Devam etmeden önce dosya yazımlarından sonra beklenecek süre, tanılama araçlarının değişiklikleri işlemesine ve sorunları tespit etmesine olanak tanır."
}
},
"condensingThreshold": {
"label": "Sıkıştırma Tetikleme Eşiği",
"selectProfile": "Profil için eşik yapılandır",

View file

@ -488,6 +488,23 @@
"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ớ."
},
"diagnostics": {
"includeMessages": {
"label": "Tự động bao gồm chẩn đoán trong ngữ cảnh",
"description": "Khi được bật, thông báo chẩn đoán (lỗi) từ các tệp đã chỉnh sửa sẽ tự động được bao gồm trong ngữ cảnh. Bạn luôn có thể bao gồm thủ công tất cả chẩn đoán của workspace bằng cách sử dụng @problems."
},
"maxMessages": {
"label": "Thông báo chẩn đoán tối đa",
"description": "Số lượng thông báo chẩn đoán tối đa được bao gồm cho mỗi tệp. Giới hạn này áp dụng cho cả việc bao gồm tự động (khi hộp kiểm được bật) và đề cập thủ công @problems. Giá trị cao hơn cung cấp nhiều ngữ cảnh hơn nhưng tăng mức sử dụng token.",
"resetTooltip": "Đặt lại về giá trị mặc định (50)",
"unlimited": "Thông báo chẩn đoán không giới hạn",
"unlimitedLabel": "Không giới hạn"
},
"delayAfterWrite": {
"label": "Trì hoãn sau khi ghi để cho phép chẩn đoán phát hiện các sự cố tiềm ẩn",
"description": "Thời gian chờ sau khi ghi tệp trước khi tiếp tục, cho phép các công cụ chẩn đoán xử lý các thay đổi và phát hiện sự cố."
}
},
"condensingThreshold": {
"label": "Ngưỡng kích hoạt nén",
"selectProfile": "Cấu hình ngưỡng cho hồ sơ",

View file

@ -488,6 +488,23 @@
"label": "并发文件读取限制",
"description": "read_file 工具可以同时处理的最大文件数。较高的值可能会加快读取多个小文件的速度,但会增加内存使用量。"
},
"diagnostics": {
"includeMessages": {
"label": "自动在上下文中包含诊断",
"description": "启用后,来自已编辑文件的诊断消息(错误)将自动包含在上下文中。您始终可以使用 @problems 手动包含所有工作区诊断。"
},
"maxMessages": {
"label": "最大诊断消息数",
"description": "每个文件包含的最大诊断消息数。此限制适用于自动包含(启用复选框时)和手动 @problems 提及。较高的值提供更多上下文,但会增加令牌使用量。",
"resetTooltip": "重置为默认值 (50)",
"unlimited": "无限制诊断消息",
"unlimitedLabel": "无限制"
},
"delayAfterWrite": {
"label": "写入后延迟以允许诊断程序检测潜在问题",
"description": "在继续之前写入文件后等待的时间,允许诊断工具处理更改并检测问题。"
}
},
"condensingThreshold": {
"label": "压缩触发阈值",
"selectProfile": "配置配置文件阈值",

View file

@ -488,6 +488,23 @@
"label": "並行檔案讀取限制",
"description": "read_file 工具可以同時處理的最大檔案數。較高的值可能會加快讀取多個小檔案的速度,但會增加記憶體使用量。"
},
"diagnostics": {
"includeMessages": {
"label": "自動在上下文中包含診斷",
"description": "啟用後,來自已編輯檔案的診斷訊息(錯誤)將自動包含在上下文中。您隨時可以使用 @problems 手動包含所有工作區診斷。"
},
"maxMessages": {
"label": "最大診斷訊息數",
"description": "每個檔案包含的最大診斷訊息數。此限制適用於自動包含(當核取方塊啟用時)和手動 @problems 提及。較高的值提供更多上下文,但會增加權杖使用量。",
"resetTooltip": "重設為預設值 (50)",
"unlimited": "無限制診斷訊息",
"unlimitedLabel": "無限制"
},
"delayAfterWrite": {
"label": "寫入後延遲以允許診斷程式偵測潛在問題",
"description": "在繼續之前寫入檔案後等待的時間,允許診斷工具處理變更並偵測問題。"
}
},
"condensingThreshold": {
"label": "壓縮觸發閾值",
"selectProfile": "設定檔案閾值",