Skip to content

Commit 5eaedb1

Browse files
committed
feat: add maxReadFileLine to PromptVariables and update system prompt logic
1 parent 3e56f86 commit 5eaedb1

File tree

4 files changed

+233
-3
lines changed

4 files changed

+233
-3
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import * as vscode from "vscode"
2+
import * as os from "os"
3+
import { ClineProviderStatic, FormatLanguageUtil, PromptVariables } from "./test-types"
4+
5+
// Mock dependencies
6+
jest.mock("vscode", () => ({
7+
env: {
8+
language: "en",
9+
shell: "/bin/bash",
10+
},
11+
}))
12+
13+
jest.mock("os", () => ({
14+
type: jest.fn(),
15+
}))
16+
17+
// Create mock ClineProvider
18+
const MockClineProvider = {
19+
getInstance: jest.fn(),
20+
} as unknown as ClineProviderStatic
21+
22+
// Create mock formatLanguage utility
23+
const formatLanguage = jest.fn() as FormatLanguageUtil
24+
25+
describe("System Prompt Variables", () => {
26+
const mockCwd = "/test/workspace"
27+
const mockMode = "test-mode"
28+
const mockGetState = jest.fn()
29+
const mockProvider = {
30+
getState: mockGetState,
31+
}
32+
33+
beforeEach(() => {
34+
jest.clearAllMocks()
35+
jest.resetModules()
36+
;(os.type as jest.Mock).mockReturnValue("Linux")
37+
;(formatLanguage as jest.Mock).mockReturnValue("en-US")
38+
;(MockClineProvider.getInstance as jest.Mock).mockResolvedValue(mockProvider)
39+
40+
// Set up global variables that would normally be in scope
41+
globalThis.cwd = mockCwd
42+
globalThis.mode = mockMode
43+
globalThis.language = undefined
44+
})
45+
46+
it("should use maxReadFileLine from provider state when available", async () => {
47+
// Setup
48+
const mockState = { maxReadFileLine: 1000 }
49+
mockGetState.mockResolvedValue(mockState)
50+
51+
// Create test variables
52+
const provider = await MockClineProvider.getInstance()
53+
const { maxReadFileLine = 500 } = provider ? await provider.getState() : {}
54+
const testVariables: PromptVariables = {
55+
workspace: mockCwd,
56+
mode: mockMode,
57+
language: globalThis.language || formatLanguage(vscode.env.language),
58+
shell: vscode.env.shell,
59+
operatingSystem: os.type(),
60+
maxReadFileLine,
61+
}
62+
63+
// Verify
64+
expect(testVariables).toEqual({
65+
workspace: mockCwd,
66+
mode: mockMode,
67+
language: "en-US",
68+
shell: "/bin/bash",
69+
operatingSystem: "Linux",
70+
maxReadFileLine: 1000,
71+
})
72+
})
73+
74+
it("should default maxReadFileLine to 500 when not in provider state", async () => {
75+
// Setup
76+
mockGetState.mockResolvedValue({})
77+
78+
// Create test variables
79+
const provider = await MockClineProvider.getInstance()
80+
const { maxReadFileLine = 500 } = provider ? await provider.getState() : {}
81+
const testVariables: PromptVariables = {
82+
workspace: mockCwd,
83+
mode: mockMode,
84+
language: globalThis.language || formatLanguage(vscode.env.language),
85+
shell: vscode.env.shell,
86+
operatingSystem: os.type(),
87+
maxReadFileLine,
88+
}
89+
90+
// Verify
91+
expect(testVariables.maxReadFileLine).toBe(500)
92+
})
93+
94+
it("should default maxReadFileLine to 500 when provider is null", async () => {
95+
// Setup
96+
;(MockClineProvider.getInstance as jest.Mock).mockResolvedValue(null)
97+
98+
// Create test variables
99+
const provider = await MockClineProvider.getInstance()
100+
const { maxReadFileLine = 500 } = provider ? await provider.getState() : {}
101+
const testVariables: PromptVariables = {
102+
workspace: mockCwd,
103+
mode: mockMode,
104+
language: globalThis.language || formatLanguage(vscode.env.language),
105+
shell: vscode.env.shell,
106+
operatingSystem: os.type(),
107+
maxReadFileLine,
108+
}
109+
110+
// Verify
111+
expect(testVariables.maxReadFileLine).toBe(500)
112+
})
113+
114+
it("should use provided language when available", async () => {
115+
// Setup
116+
const providedLanguage = "fr"
117+
mockGetState.mockResolvedValue({})
118+
globalThis.language = providedLanguage
119+
120+
// Create test variables
121+
const provider = await MockClineProvider.getInstance()
122+
const { maxReadFileLine = 500 } = provider ? await provider.getState() : {}
123+
const testVariables: PromptVariables = {
124+
workspace: mockCwd,
125+
mode: mockMode,
126+
language: globalThis.language || formatLanguage(vscode.env.language),
127+
shell: vscode.env.shell,
128+
operatingSystem: os.type(),
129+
maxReadFileLine,
130+
}
131+
132+
// Verify
133+
expect(testVariables.language).toBe(providedLanguage)
134+
expect(formatLanguage).not.toHaveBeenCalled()
135+
})
136+
137+
it("should use formatted vscode language when input language is not provided", async () => {
138+
// Setup
139+
mockGetState.mockResolvedValue({})
140+
globalThis.language = undefined
141+
142+
// Create test variables
143+
const provider = await MockClineProvider.getInstance()
144+
const { maxReadFileLine = 500 } = provider ? await provider.getState() : {}
145+
const testVariables: PromptVariables = {
146+
workspace: mockCwd,
147+
mode: mockMode,
148+
language: globalThis.language || formatLanguage(vscode.env.language),
149+
shell: vscode.env.shell,
150+
operatingSystem: os.type(),
151+
maxReadFileLine,
152+
}
153+
154+
// Verify
155+
expect(formatLanguage).toHaveBeenCalledWith("en")
156+
expect(testVariables.language).toBe("en-US")
157+
})
158+
159+
it("should correctly populate all variables with mocked inputs", async () => {
160+
// Setup
161+
mockGetState.mockResolvedValue({ maxReadFileLine: 750 })
162+
163+
// Create test variables
164+
const provider = await MockClineProvider.getInstance()
165+
const { maxReadFileLine = 500 } = provider ? await provider.getState() : {}
166+
const testVariables: PromptVariables = {
167+
workspace: mockCwd,
168+
mode: mockMode,
169+
language: globalThis.language || formatLanguage(vscode.env.language),
170+
shell: vscode.env.shell,
171+
operatingSystem: os.type(),
172+
maxReadFileLine,
173+
}
174+
175+
// Verify
176+
expect(testVariables).toEqual({
177+
workspace: mockCwd,
178+
mode: mockMode,
179+
language: "en-US",
180+
shell: "/bin/bash",
181+
operatingSystem: "Linux",
182+
maxReadFileLine: 750,
183+
})
184+
185+
expect(os.type).toHaveBeenCalled()
186+
expect(MockClineProvider.getInstance).toHaveBeenCalled()
187+
expect(mockGetState).toHaveBeenCalled()
188+
})
189+
})
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Test types
2+
3+
// Provider types
4+
export interface ClineState {
5+
maxReadFileLine?: number
6+
}
7+
8+
export interface ClineProvider {
9+
getState(): Promise<ClineState>
10+
}
11+
12+
export interface ClineProviderStatic {
13+
getInstance(): Promise<ClineProvider | null>
14+
}
15+
16+
// Utility types
17+
export interface FormatLanguageUtil {
18+
(lang: string): string
19+
}
20+
21+
// Global declarations
22+
declare global {
23+
var cwd: string
24+
var mode: string
25+
var language: string | undefined
26+
}
27+
28+
export interface PromptVariables {
29+
workspace: string
30+
mode: string
31+
language: string
32+
shell: string
33+
operatingSystem: string
34+
maxReadFileLine: number
35+
}

src/core/prompts/sections/custom-system-prompt.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export type PromptVariables = {
99
language?: string
1010
shell?: string
1111
operatingSystem?: string
12+
maxReadFileLine?: number
1213
}
1314

1415
function interpolatePromptContent(content: string, variables: PromptVariables): string {
@@ -19,7 +20,10 @@ function interpolatePromptContent(content: string, variables: PromptVariables):
1920
variables[key as keyof PromptVariables] !== undefined
2021
) {
2122
const placeholder = new RegExp(`\\{\\{${key}\\}\\}`, "g")
22-
interpolatedContent = interpolatedContent.replace(placeholder, variables[key as keyof PromptVariables]!)
23+
interpolatedContent = interpolatedContent.replace(
24+
placeholder,
25+
String(variables[key as keyof PromptVariables]!),
26+
)
2327
}
2428
}
2529
return interpolatedContent

src/core/prompts/system.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import {
33
modes,
44
CustomModePrompts,
55
PromptComponent,
6-
getRoleDefinition,
76
defaultModeSlug,
87
ModeConfig,
98
getModeBySlug,
109
getGroupName,
1110
} from "../../shared/modes"
11+
import { ClineProvider } from "../webview/ClineProvider"
1212
import { PromptVariables } from "./sections/custom-system-prompt"
1313
import { DiffStrategy } from "../../shared/tools"
1414
import { McpHub } from "../../services/mcp/McpHub"
@@ -126,13 +126,15 @@ export const SYSTEM_PROMPT = async (
126126
return undefined
127127
}
128128

129-
// Try to load custom system prompt from file
129+
const provider = await ClineProvider.getInstance()
130+
const { maxReadFileLine = 500 } = provider ? await provider.getState() : {}
130131
const variablesForPrompt: PromptVariables = {
131132
workspace: cwd,
132133
mode: mode,
133134
language: language ?? formatLanguage(vscode.env.language),
134135
shell: vscode.env.shell,
135136
operatingSystem: os.type(),
137+
maxReadFileLine,
136138
}
137139
const fileCustomSystemPrompt = await loadSystemPromptFile(cwd, mode, variablesForPrompt)
138140

0 commit comments

Comments
 (0)