Skip to content

Commit 7457b58

Browse files
committed
fix: address PR #5582 review feedback
- Standardize default max diagnostic messages to 50 across all files - Extract diagnostic settings to centralized constants and helper functions - Add comprehensive documentation for diagnostic settings - Update UI to always show max diagnostic messages slider - Add unit tests for ContextManagementSettings component - Improve code organization and maintainability
1 parent 3fe4964 commit 7457b58

File tree

11 files changed

+196
-53
lines changed

11 files changed

+196
-53
lines changed

packages/types/src/global-settings.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,15 @@ export const globalSettingsSchema = z.object({
5454
autoCondenseContextPercent: z.number().optional(),
5555
maxConcurrentFileReads: z.number().optional(),
5656

57+
/**
58+
* Whether to include diagnostic messages (errors, warnings) in tool outputs
59+
* @default true
60+
*/
5761
includeDiagnosticMessages: z.boolean().optional(),
62+
/**
63+
* Maximum number of diagnostic messages to include in tool outputs
64+
* @default 50
65+
*/
5866
maxDiagnosticMessages: z.number().optional(),
5967

6068
browserToolEnabled: z.boolean().optional(),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Constants for diagnostic settings
3+
*/
4+
5+
/**
6+
* Default value for whether to include diagnostic messages in tool outputs
7+
*/
8+
export const DEFAULT_INCLUDE_DIAGNOSTIC_MESSAGES = true
9+
10+
/**
11+
* Default maximum number of diagnostic messages to include in tool outputs
12+
*/
13+
export const DEFAULT_MAX_DIAGNOSTIC_MESSAGES = 50

src/core/tools/applyDiffTool.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { formatResponse } from "../prompts/responses"
1111
import { fileExistsAtPath } from "../../utils/fs"
1212
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
1313
import { unescapeHtmlEntities } from "../../utils/text-normalization"
14+
import { getDiagnosticSettings } from "./helpers/diagnosticSettings"
1415

1516
export async function applyDiffToolLegacy(
1617
cline: Task,
@@ -141,10 +142,8 @@ export async function applyDiffToolLegacy(
141142
cline.consecutiveMistakeCount = 0
142143
cline.consecutiveMistakeCountForApplyDiff.delete(relPath)
143144

144-
// Get diagnostic settings from state
145-
const state = await cline.providerRef?.deref()?.getState()
146-
const includeDiagnosticMessages = state?.includeDiagnosticMessages ?? true
147-
const maxDiagnosticMessages = state?.maxDiagnosticMessages
145+
// Get diagnostic settings
146+
const { includeDiagnosticMessages, maxDiagnosticMessages } = await getDiagnosticSettings(cline)
148147

149148
// Update DiffViewProvider with diagnostic settings
150149
cline.diffViewProvider.updateDiagnosticSettings(includeDiagnosticMessages, maxDiagnosticMessages)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Task } from "../../task/Task"
2+
import {
3+
DEFAULT_INCLUDE_DIAGNOSTIC_MESSAGES,
4+
DEFAULT_MAX_DIAGNOSTIC_MESSAGES,
5+
} from "../../constants/diagnosticSettings"
6+
7+
/**
8+
* Retrieves diagnostic settings from the provider state
9+
* @param cline - The Task instance
10+
* @returns Object containing diagnostic settings with defaults
11+
*/
12+
export async function getDiagnosticSettings(cline: Task): Promise<{
13+
includeDiagnosticMessages: boolean
14+
maxDiagnosticMessages: number
15+
}> {
16+
const state = await cline.providerRef?.deref()?.getState()
17+
18+
return {
19+
includeDiagnosticMessages: state?.includeDiagnosticMessages ?? DEFAULT_INCLUDE_DIAGNOSTIC_MESSAGES,
20+
maxDiagnosticMessages: state?.maxDiagnosticMessages ?? DEFAULT_MAX_DIAGNOSTIC_MESSAGES,
21+
}
22+
}

src/core/tools/insertContentTool.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ClineSayTool } from "../../shared/ExtensionMessage"
1010
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
1111
import { fileExistsAtPath } from "../../utils/fs"
1212
import { insertGroups } from "../diff/insert-groups"
13+
import { getDiagnosticSettings } from "./helpers/diagnosticSettings"
1314

1415
export async function insertContentTool(
1516
cline: Task,
@@ -98,14 +99,11 @@ export async function insertContentTool(
9899
cline.diffViewProvider.editType = fileExists ? "modify" : "create"
99100
cline.diffViewProvider.originalContent = fileContent
100101

101-
// Update diagnostic settings from global state
102-
const state = await cline.providerRef?.deref()?.getState()
103-
if (state) {
104-
cline.diffViewProvider.updateDiagnosticSettings(
105-
state.includeDiagnosticMessages ?? true,
106-
state.maxDiagnosticMessages ?? 5,
107-
)
108-
}
102+
// Get diagnostic settings
103+
const { includeDiagnosticMessages, maxDiagnosticMessages } = await getDiagnosticSettings(cline)
104+
105+
// Update DiffViewProvider with diagnostic settings
106+
cline.diffViewProvider.updateDiagnosticSettings(includeDiagnosticMessages, maxDiagnosticMessages)
109107
const lines = fileExists ? fileContent.split("\n") : []
110108

111109
const updatedContent = insertGroups(lines, [

src/core/tools/searchAndReplaceTool.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ClineSayTool } from "../../shared/ExtensionMessage"
1111
import { getReadablePath } from "../../utils/path"
1212
import { fileExistsAtPath } from "../../utils/fs"
1313
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
14+
import { getDiagnosticSettings } from "./helpers/diagnosticSettings"
1415

1516
/**
1617
* Tool for performing search and replace operations on files
@@ -190,14 +191,11 @@ export async function searchAndReplaceTool(
190191
cline.diffViewProvider.editType = "modify"
191192
cline.diffViewProvider.originalContent = fileContent
192193

193-
// Update diagnostic settings from global state
194-
const state = await cline.providerRef?.deref()?.getState()
195-
if (state) {
196-
cline.diffViewProvider.updateDiagnosticSettings(
197-
state.includeDiagnosticMessages ?? true,
198-
state.maxDiagnosticMessages ?? 5,
199-
)
200-
}
194+
// Get diagnostic settings
195+
const { includeDiagnosticMessages, maxDiagnosticMessages } = await getDiagnosticSettings(cline)
196+
197+
// Update DiffViewProvider with diagnostic settings
198+
cline.diffViewProvider.updateDiagnosticSettings(includeDiagnosticMessages, maxDiagnosticMessages)
201199

202200
// Generate and validate diff
203201
const diff = formatResponse.createPrettyPatch(validRelPath, fileContent, newContent)

src/core/tools/writeToFileTool.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { getReadablePath } from "../../utils/path"
1313
import { isPathOutsideWorkspace } from "../../utils/pathUtils"
1414
import { detectCodeOmission } from "../../integrations/editor/detect-omission"
1515
import { unescapeHtmlEntities } from "../../utils/text-normalization"
16+
import { getDiagnosticSettings } from "./helpers/diagnosticSettings"
1617

1718
export async function writeToFileTool(
1819
cline: Task,
@@ -96,10 +97,8 @@ export async function writeToFileTool(
9697
isProtected: isWriteProtected,
9798
}
9899

99-
// Get diagnostic settings from state
100-
const state = await cline.providerRef?.deref()?.getState()
101-
const includeDiagnosticMessages = state?.includeDiagnosticMessages ?? true
102-
const maxDiagnosticMessages = state?.maxDiagnosticMessages
100+
// Get diagnostic settings
101+
const { includeDiagnosticMessages, maxDiagnosticMessages } = await getDiagnosticSettings(cline)
103102

104103
// Update DiffViewProvider with diagnostic settings
105104
cline.diffViewProvider.updateDiagnosticSettings(includeDiagnosticMessages, maxDiagnosticMessages)

src/core/webview/ClineProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import { WebviewMessage } from "../../shared/WebviewMessage"
6969
import { EMBEDDING_MODEL_PROFILES } from "../../shared/embeddingModels"
7070
import { ProfileValidator } from "../../shared/ProfileValidator"
7171
import { getWorkspaceGitInfo } from "../../utils/git"
72+
import { DEFAULT_INCLUDE_DIAGNOSTIC_MESSAGES, DEFAULT_MAX_DIAGNOSTIC_MESSAGES } from "../constants/diagnosticSettings"
7273

7374
/**
7475
* https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@@ -1676,8 +1677,8 @@ export class ClineProvider
16761677
},
16771678
profileThresholds: stateValues.profileThresholds ?? {},
16781679
// Add diagnostic message settings
1679-
includeDiagnosticMessages: stateValues.includeDiagnosticMessages ?? true,
1680-
maxDiagnosticMessages: stateValues.maxDiagnosticMessages ?? 5,
1680+
includeDiagnosticMessages: stateValues.includeDiagnosticMessages ?? DEFAULT_INCLUDE_DIAGNOSTIC_MESSAGES,
1681+
maxDiagnosticMessages: stateValues.maxDiagnosticMessages ?? DEFAULT_MAX_DIAGNOSTIC_MESSAGES,
16811682
}
16821683
}
16831684

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

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -263,27 +263,25 @@ export const ContextManagementSettings = ({
263263
</div>
264264
</div>
265265

266-
{includeDiagnosticMessages && (
267-
<div>
268-
<span className="block font-medium mb-1">
269-
{t("settings:contextManagement.diagnostics.maxMessages.label")}
270-
</span>
271-
<div className="flex items-center gap-2">
272-
<Slider
273-
min={1}
274-
max={100}
275-
step={1}
276-
value={[maxDiagnosticMessages ?? 50]}
277-
onValueChange={([value]) => setCachedStateField("maxDiagnosticMessages", value)}
278-
data-testid="max-diagnostic-messages-slider"
279-
/>
280-
<span className="w-10">{maxDiagnosticMessages ?? 50}</span>
281-
</div>
282-
<div className="text-vscode-descriptionForeground text-sm mt-1">
283-
{t("settings:contextManagement.diagnostics.maxMessages.description")}
284-
</div>
266+
<div>
267+
<span className="block font-medium mb-1">
268+
{t("settings:contextManagement.diagnostics.maxMessages.label")}
269+
</span>
270+
<div className="flex items-center gap-2">
271+
<Slider
272+
min={1}
273+
max={100}
274+
step={1}
275+
value={[maxDiagnosticMessages ?? 50]}
276+
onValueChange={([value]) => setCachedStateField("maxDiagnosticMessages", value)}
277+
data-testid="max-diagnostic-messages-slider"
278+
/>
279+
<span className="w-10">{maxDiagnosticMessages ?? 50}</span>
285280
</div>
286-
)}
281+
<div className="text-vscode-descriptionForeground text-sm mt-1">
282+
{t("settings:contextManagement.diagnostics.maxMessages.description")}
283+
</div>
284+
</div>
287285
</Section>
288286
<Section className="pt-2">
289287
<VSCodeCheckbox

webview-ui/src/components/settings/__tests__/ContextManagementSettings.spec.tsx

Lines changed: 113 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ vi.mock("@/components/ui", () => ({
99
Slider: ({ value, onValueChange, "data-testid": dataTestId, disabled }: any) => (
1010
<input
1111
type="range"
12-
value={value[0]}
12+
value={value?.[0] ?? 0}
1313
onChange={(e) => onValueChange([parseFloat(e.target.value)])}
1414
data-testid={dataTestId}
1515
disabled={disabled}
@@ -97,8 +97,9 @@ describe("ContextManagementSettings", () => {
9797
const checkbox = screen.getByTestId("include-diagnostic-messages-checkbox")
9898
expect(checkbox.querySelector("input")).not.toBeChecked()
9999

100-
// Slider should not be rendered when diagnostics are disabled
101-
expect(screen.queryByTestId("max-diagnostic-messages-slider")).not.toBeInTheDocument()
100+
// Slider should still be rendered when diagnostics are disabled
101+
expect(screen.getByTestId("max-diagnostic-messages-slider")).toBeInTheDocument()
102+
expect(screen.getByText("50")).toBeInTheDocument()
102103
})
103104

104105
it("calls setCachedStateField when include diagnostic messages checkbox is toggled", async () => {
@@ -125,15 +126,15 @@ describe("ContextManagementSettings", () => {
125126
})
126127
})
127128

128-
it("hides slider when include diagnostic messages is unchecked", () => {
129+
it("keeps slider visible when include diagnostic messages is unchecked", () => {
129130
const { rerender } = render(<ContextManagementSettings {...defaultProps} includeDiagnosticMessages={true} />)
130131

131132
const slider = screen.getByTestId("max-diagnostic-messages-slider")
132133
expect(slider).toBeInTheDocument()
133134

134-
// Update to disabled
135+
// Update to disabled - slider should still be visible
135136
rerender(<ContextManagementSettings {...defaultProps} includeDiagnosticMessages={false} />)
136-
expect(screen.queryByTestId("max-diagnostic-messages-slider")).not.toBeInTheDocument()
137+
expect(screen.getByTestId("max-diagnostic-messages-slider")).toBeInTheDocument()
137138
})
138139

139140
it("displays correct max diagnostic messages value", () => {
@@ -158,4 +159,110 @@ describe("ContextManagementSettings", () => {
158159
expect(screen.getByTestId("show-rooignored-files-checkbox")).toBeInTheDocument()
159160
expect(screen.getByTestId("auto-condense-context-checkbox")).toBeInTheDocument()
160161
})
162+
163+
describe("Edge cases for maxDiagnosticMessages", () => {
164+
it("handles zero value correctly", async () => {
165+
const setCachedStateField = vi.fn()
166+
render(
167+
<ContextManagementSettings
168+
{...defaultProps}
169+
maxDiagnosticMessages={0}
170+
setCachedStateField={setCachedStateField}
171+
/>,
172+
)
173+
174+
expect(screen.getByText("0")).toBeInTheDocument()
175+
176+
const slider = screen.getByTestId("max-diagnostic-messages-slider")
177+
expect(slider).toHaveValue("0")
178+
})
179+
180+
it("handles negative values by displaying them", async () => {
181+
const setCachedStateField = vi.fn()
182+
render(
183+
<ContextManagementSettings
184+
{...defaultProps}
185+
maxDiagnosticMessages={-10}
186+
setCachedStateField={setCachedStateField}
187+
/>,
188+
)
189+
190+
// Component displays the actual negative value in the text span
191+
expect(screen.getByText("-10")).toBeInTheDocument()
192+
193+
// Note: The actual slider behavior with negative values depends on the implementation
194+
// In this case, we're just verifying the component renders without errors
195+
})
196+
197+
it("handles very large numbers by capping at maximum", async () => {
198+
const setCachedStateField = vi.fn()
199+
const largeNumber = 1000
200+
render(
201+
<ContextManagementSettings
202+
{...defaultProps}
203+
maxDiagnosticMessages={largeNumber}
204+
setCachedStateField={setCachedStateField}
205+
/>,
206+
)
207+
208+
// Should display the actual value even if it exceeds slider max
209+
expect(screen.getByText(largeNumber.toString())).toBeInTheDocument()
210+
211+
// Slider value would be capped at max (100)
212+
const slider = screen.getByTestId("max-diagnostic-messages-slider")
213+
expect(slider).toHaveValue("100")
214+
})
215+
216+
it("enforces maximum value constraint", async () => {
217+
const setCachedStateField = vi.fn()
218+
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
219+
220+
const slider = screen.getByTestId("max-diagnostic-messages-slider")
221+
222+
// Test that setting value above 100 gets capped
223+
fireEvent.change(slider, { target: { value: "150" } })
224+
225+
await waitFor(() => {
226+
// Should be capped at 100 (the slider's max)
227+
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", 100)
228+
})
229+
})
230+
231+
it("handles boundary value at minimum (0)", async () => {
232+
const setCachedStateField = vi.fn()
233+
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
234+
235+
const slider = screen.getByTestId("max-diagnostic-messages-slider")
236+
fireEvent.change(slider, { target: { value: "0" } })
237+
238+
await waitFor(() => {
239+
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", 0)
240+
})
241+
})
242+
243+
it("handles boundary value at maximum (100)", async () => {
244+
const setCachedStateField = vi.fn()
245+
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
246+
247+
const slider = screen.getByTestId("max-diagnostic-messages-slider")
248+
fireEvent.change(slider, { target: { value: "100" } })
249+
250+
await waitFor(() => {
251+
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", 100)
252+
})
253+
})
254+
255+
it("handles decimal values by parsing as float", async () => {
256+
const setCachedStateField = vi.fn()
257+
render(<ContextManagementSettings {...defaultProps} setCachedStateField={setCachedStateField} />)
258+
259+
const slider = screen.getByTestId("max-diagnostic-messages-slider")
260+
fireEvent.change(slider, { target: { value: "50.7" } })
261+
262+
await waitFor(() => {
263+
// The mock slider component parses as float
264+
expect(setCachedStateField).toHaveBeenCalledWith("maxDiagnosticMessages", 50.7)
265+
})
266+
})
267+
})
161268
})

0 commit comments

Comments
 (0)