Setting for number of terminal lines to return from commands

This commit is contained in:
Matt Rubens
2024-12-30 23:02:26 -08:00
parent 667312e48c
commit c8b8eff147
8 changed files with 72 additions and 5 deletions

View File

@@ -0,0 +1,5 @@
---
"roo-cline": patch
---
Add a setting to control the number of terminal output lines to pass to the model when executing commands

View File

@@ -20,6 +20,7 @@ A fork of Cline, an autonomous coding agent, with some additional experimental f
- Per-tool MCP auto-approval - Per-tool MCP auto-approval
- Enable/disable MCP servers - Enable/disable MCP servers
- Configurable delay after auto-writes to allow diagnostics to detect potential problems - Configurable delay after auto-writes to allow diagnostics to detect potential problems
- Control the number of terminal output lines to pass to the model when executing commands
- Runs alongside the original Cline - Runs alongside the original Cline
## Disclaimer ## Disclaimer

View File

@@ -721,9 +721,9 @@ export class Cline {
} }
} }
let result = "" let lines: string[] = []
process.on("line", (line) => { process.on("line", (line) => {
result += line + "\n" lines.push(line)
if (!didContinue) { if (!didContinue) {
sendCommandOutput(line) sendCommandOutput(line)
} else { } else {
@@ -731,6 +731,22 @@ export class Cline {
} }
}) })
const getFormattedOutput = async () => {
const { terminalOutputLineLimit } = await this.providerRef.deref()?.getState() ?? {}
const limit = terminalOutputLineLimit ?? 0
if (limit > 0 && lines.length > limit) {
const beforeLimit = Math.floor(limit * 0.2) // 20% of lines before
const afterLimit = limit - beforeLimit // remaining 80% after
return [
...lines.slice(0, beforeLimit),
`\n[...${lines.length - limit} lines omitted...]\n`,
...lines.slice(-afterLimit)
].join('\n')
}
return lines.join('\n')
}
let completed = false let completed = false
process.once("completed", () => { process.once("completed", () => {
completed = true completed = true
@@ -749,7 +765,8 @@ export class Cline {
// grouping command_output messages despite any gaps anyways) // grouping command_output messages despite any gaps anyways)
await delay(50) await delay(50)
result = result.trim() const output = await getFormattedOutput()
const result = output.trim()
if (userFeedback) { if (userFeedback) {
await this.say("user_feedback", userFeedback.text, userFeedback.images) await this.say("user_feedback", userFeedback.text, userFeedback.images)

View File

@@ -76,6 +76,7 @@ type GlobalStateKey =
| "fuzzyMatchThreshold" | "fuzzyMatchThreshold"
| "preferredLanguage" // Language setting for Cline's communication | "preferredLanguage" // Language setting for Cline's communication
| "writeDelayMs" | "writeDelayMs"
| "terminalOutputLineLimit"
export const GlobalFileNames = { export const GlobalFileNames = {
apiConversationHistory: "api_conversation_history.json", apiConversationHistory: "api_conversation_history.json",
@@ -642,6 +643,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.updateGlobalState("writeDelayMs", message.value) await this.updateGlobalState("writeDelayMs", message.value)
await this.postStateToWebview() await this.postStateToWebview()
break break
case "terminalOutputLineLimit":
await this.updateGlobalState("terminalOutputLineLimit", message.value)
await this.postStateToWebview()
break
case "deleteMessage": { case "deleteMessage": {
const answer = await vscode.window.showInformationMessage( const answer = await vscode.window.showInformationMessage(
"Are you sure you want to delete this message and all subsequent messages?", "Are you sure you want to delete this message and all subsequent messages?",
@@ -1046,6 +1051,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
screenshotQuality, screenshotQuality,
preferredLanguage, preferredLanguage,
writeDelayMs, writeDelayMs,
terminalOutputLineLimit,
} = await this.getState() } = await this.getState()
const allowedCommands = vscode.workspace const allowedCommands = vscode.workspace
@@ -1075,6 +1081,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
screenshotQuality: screenshotQuality ?? 75, screenshotQuality: screenshotQuality ?? 75,
preferredLanguage: preferredLanguage ?? 'English', preferredLanguage: preferredLanguage ?? 'English',
writeDelayMs: writeDelayMs ?? 1000, writeDelayMs: writeDelayMs ?? 1000,
terminalOutputLineLimit: terminalOutputLineLimit ?? 500,
} }
} }
@@ -1174,6 +1181,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
preferredLanguage, preferredLanguage,
writeDelayMs, writeDelayMs,
screenshotQuality, screenshotQuality,
terminalOutputLineLimit,
] = await Promise.all([ ] = await Promise.all([
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>, this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
this.getGlobalState("apiModelId") as Promise<string | undefined>, this.getGlobalState("apiModelId") as Promise<string | undefined>,
@@ -1218,6 +1226,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.getGlobalState("preferredLanguage") as Promise<string | undefined>, this.getGlobalState("preferredLanguage") as Promise<string | undefined>,
this.getGlobalState("writeDelayMs") as Promise<number | undefined>, this.getGlobalState("writeDelayMs") as Promise<number | undefined>,
this.getGlobalState("screenshotQuality") as Promise<number | undefined>, this.getGlobalState("screenshotQuality") as Promise<number | undefined>,
this.getGlobalState("terminalOutputLineLimit") as Promise<number | undefined>,
]) ])
let apiProvider: ApiProvider let apiProvider: ApiProvider
@@ -1279,6 +1288,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
screenshotQuality: screenshotQuality ?? 75, screenshotQuality: screenshotQuality ?? 75,
fuzzyMatchThreshold: fuzzyMatchThreshold ?? 1.0, fuzzyMatchThreshold: fuzzyMatchThreshold ?? 1.0,
writeDelayMs: writeDelayMs ?? 1000, writeDelayMs: writeDelayMs ?? 1000,
terminalOutputLineLimit: terminalOutputLineLimit ?? 500,
preferredLanguage: preferredLanguage ?? (() => { preferredLanguage: preferredLanguage ?? (() => {
// Get VSCode's locale setting // Get VSCode's locale setting
const vscodeLang = vscode.env.language; const vscodeLang = vscode.env.language;

View File

@@ -61,6 +61,7 @@ export interface ExtensionState {
fuzzyMatchThreshold?: number fuzzyMatchThreshold?: number
preferredLanguage: string preferredLanguage: string
writeDelayMs: number writeDelayMs: number
terminalOutputLineLimit?: number
} }
export interface ClineMessage { export interface ClineMessage {

View File

@@ -48,6 +48,7 @@ export interface WebviewMessage {
| "enhancedPrompt" | "enhancedPrompt"
| "draggedImages" | "draggedImages"
| "deleteMessage" | "deleteMessage"
| "terminalOutputLineLimit"
text?: string text?: string
disabled?: boolean disabled?: boolean
askResponse?: ClineAskResponse askResponse?: ClineAskResponse

View File

@@ -46,6 +46,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
setWriteDelayMs, setWriteDelayMs,
screenshotQuality, screenshotQuality,
setScreenshotQuality, setScreenshotQuality,
terminalOutputLineLimit,
setTerminalOutputLineLimit,
} = useExtensionState() } = useExtensionState()
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined) const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
const [modelIdErrorMessage, setModelIdErrorMessage] = useState<string | undefined>(undefined) const [modelIdErrorMessage, setModelIdErrorMessage] = useState<string | undefined>(undefined)
@@ -76,6 +78,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
vscode.postMessage({ type: "preferredLanguage", text: preferredLanguage }) vscode.postMessage({ type: "preferredLanguage", text: preferredLanguage })
vscode.postMessage({ type: "writeDelayMs", value: writeDelayMs }) vscode.postMessage({ type: "writeDelayMs", value: writeDelayMs })
vscode.postMessage({ type: "screenshotQuality", value: screenshotQuality ?? 75 }) vscode.postMessage({ type: "screenshotQuality", value: screenshotQuality ?? 75 })
vscode.postMessage({ type: "terminalOutputLineLimit", value: terminalOutputLineLimit ?? 500 })
onDone() onDone()
} }
} }
@@ -210,6 +213,31 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
</p> </p>
</div> </div>
<div style={{ marginBottom: 5 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
<span style={{ fontWeight: "500", minWidth: '150px' }}>Terminal output limit</span>
<input
type="range"
min="100"
max="5000"
step="100"
value={terminalOutputLineLimit ?? 500}
onChange={(e) => setTerminalOutputLineLimit(parseInt(e.target.value))}
style={{
flexGrow: 1,
accentColor: 'var(--vscode-button-background)',
height: '2px'
}}
/>
<span style={{ minWidth: '45px', textAlign: 'left' }}>
{terminalOutputLineLimit ?? 500}
</span>
</div>
<p style={{ fontSize: "12px", marginTop: "5px", color: "var(--vscode-descriptionForeground)" }}>
Maximum number of lines to include in terminal output when executing commands. When exceeded lines will be removed from the middle, saving tokens.
</p>
</div>
<div style={{ marginBottom: 5 }}> <div style={{ marginBottom: 5 }}>
<VSCodeCheckbox checked={diffEnabled} onChange={(e: any) => setDiffEnabled(e.target.checked)}> <VSCodeCheckbox checked={diffEnabled} onChange={(e: any) => setDiffEnabled(e.target.checked)}>
<span style={{ fontWeight: "500" }}>Enable editing through diffs</span> <span style={{ fontWeight: "500" }}>Enable editing through diffs</span>
@@ -431,7 +459,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
<div style={{ marginBottom: 10 }}> <div style={{ marginBottom: 10 }}>
<div style={{ marginBottom: 15 }}> <div style={{ marginBottom: 15 }}>
<h3 style={{ color: "var(--vscode-foreground)", margin: 0, marginBottom: 15 }}>Browser Settings</h3> <h3 style={{ color: "var(--vscode-foreground)", margin: 0, marginBottom: 15 }}>Browser Settings</h3>
<label style={{ fontWeight: "500", display: "block", marginBottom: 5 }}>Viewport Size</label> <label style={{ fontWeight: "500", display: "block", marginBottom: 5 }}>Viewport size</label>
<select <select
value={browserViewportSize} value={browserViewportSize}
onChange={(e) => setBrowserViewportSize(e.target.value)} onChange={(e) => setBrowserViewportSize(e.target.value)}
@@ -460,7 +488,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
<div style={{ marginBottom: 15 }}> <div style={{ marginBottom: 15 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
<span style={{ fontWeight: "500", minWidth: '100px' }}>Screenshot Quality</span> <span style={{ fontWeight: "500", minWidth: '100px' }}>Screenshot quality</span>
<input <input
type="range" type="range"
min="1" min="1"

View File

@@ -39,6 +39,8 @@ export interface ExtensionStateContextType extends ExtensionState {
setWriteDelayMs: (value: number) => void setWriteDelayMs: (value: number) => void
screenshotQuality?: number screenshotQuality?: number
setScreenshotQuality: (value: number) => void setScreenshotQuality: (value: number) => void
terminalOutputLineLimit?: number
setTerminalOutputLineLimit: (value: number) => void
} }
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined) export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@@ -58,6 +60,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
writeDelayMs: 1000, writeDelayMs: 1000,
browserViewportSize: "900x600", browserViewportSize: "900x600",
screenshotQuality: 75, screenshotQuality: 75,
terminalOutputLineLimit: 500,
}) })
const [didHydrateState, setDidHydrateState] = useState(false) const [didHydrateState, setDidHydrateState] = useState(false)
const [showWelcome, setShowWelcome] = useState(false) const [showWelcome, setShowWelcome] = useState(false)
@@ -176,6 +179,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setPreferredLanguage: (value) => setState((prevState) => ({ ...prevState, preferredLanguage: value })), setPreferredLanguage: (value) => setState((prevState) => ({ ...prevState, preferredLanguage: value })),
setWriteDelayMs: (value) => setState((prevState) => ({ ...prevState, writeDelayMs: value })), setWriteDelayMs: (value) => setState((prevState) => ({ ...prevState, writeDelayMs: value })),
setScreenshotQuality: (value) => setState((prevState) => ({ ...prevState, screenshotQuality: value })), setScreenshotQuality: (value) => setState((prevState) => ({ ...prevState, screenshotQuality: value })),
setTerminalOutputLineLimit: (value) => setState((prevState) => ({ ...prevState, terminalOutputLineLimit: value })),
} }
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider> return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>