Skip to content

Commit

Permalink
Create a structure for different diff strategies, starting with unifi…
Browse files Browse the repository at this point in the history
…ed (#55)
  • Loading branch information
mrubens authored Dec 9, 2024
1 parent 39b51fa commit da31a23
Show file tree
Hide file tree
Showing 13 changed files with 422 additions and 129 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Roo Cline Changelog

## [2.1.15]

- Incorporate dbasclpy's [PR](https://github.com/RooVetGit/Roo-Cline/pull/54) to add support for gemini-exp-1206
- Make it clear that diff editing is very experimental

## [2.1.14]

- Fix bug where diffs were not being applied correctly and try Aider's [unified diff prompt](https://github.com/Aider-AI/aider/blob/3995accd0ca71cea90ef76d516837f8c2731b9fe/aider/coders/udiff_prompts.py#L75-L105)
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ A fork of Cline, an autonomous coding agent, with some added experimental config
- Auto-approval capabilities for commands, write, and browser operations
- Support for .clinerules per-project custom instructions
- Ability to run side-by-side with Cline
- Code is unit-tested
- Support for playing sound effects
- Support for OpenRouter compression
- Support for editing through diffs
- Support for editing through diffs (very experimental)
- Support for gemini-exp-1206

Here's an example of Roo-Cline autonomously creating a snake game with "Always approve write operations" and "Always approve browser actions" turned on:

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "Roo Cline",
"description": "A fork of Cline, an autonomous coding agent, with some added experimental configuration and automation features.",
"publisher": "RooVeterinaryInc",
"version": "2.1.14",
"version": "2.1.15",
"icon": "assets/icons/rocket.png",
"galleryBanner": {
"color": "#617A91",
Expand Down Expand Up @@ -147,7 +147,7 @@
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"check-types": "tsc --noEmit",
"lint": "eslint src --ext ts",
"test": "vscode-test",
"test": "jest",
"install:all": "npm install && cd webview-ui && npm install",
"start:webview": "cd webview-ui && npm run start",
"build:webview": "cd webview-ui && npm run build",
Expand Down
4 changes: 2 additions & 2 deletions src/api/providers/__tests__/openrouter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ describe('OpenRouterHandler', () => {
baseURL: 'https://openrouter.ai/api/v1',
apiKey: mockOptions.openRouterApiKey,
defaultHeaders: {
'HTTP-Referer': 'https://cline.bot',
'X-Title': 'Cline',
'HTTP-Referer': 'https://github.com/RooVetGit/Roo-Cline',
'X-Title': 'Roo-Cline',
},
})
})
Expand Down
4 changes: 2 additions & 2 deletions src/api/providers/openrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export class OpenRouterHandler implements ApiHandler {
baseURL: "https://openrouter.ai/api/v1",
apiKey: this.options.openRouterApiKey,
defaultHeaders: {
"HTTP-Referer": "https://cline.bot", // Optional, for including your app on openrouter.ai rankings.
"X-Title": "Cline", // Optional. Shows in rankings on openrouter.ai.
"HTTP-Referer": "https://github.com/RooVetGit/Roo-Cline", // Optional, for including your app on openrouter.ai rankings.
"X-Title": "Roo-Cline", // Optional. Shows in rankings on openrouter.ai.
},
})
}
Expand Down
31 changes: 10 additions & 21 deletions src/core/Cline.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk"
import * as diff from "diff"
import cloneDeep from "clone-deep"
import { DiffStrategy, getDiffStrategy, UnifiedDiffStrategy } from "./diff/DiffStrategy"
import delay from "delay"
import fs from "fs/promises"
import os from "os"
Expand Down Expand Up @@ -65,7 +65,7 @@ export class Cline {
private browserSession: BrowserSession
private didEditFile: boolean = false
customInstructions?: string
diffEnabled?: boolean
diffStrategy?: DiffStrategy

apiConversationHistory: Anthropic.MessageParam[] = []
clineMessages: ClineMessage[] = []
Expand Down Expand Up @@ -107,7 +107,9 @@ export class Cline {
this.browserSession = new BrowserSession(provider.context)
this.diffViewProvider = new DiffViewProvider(cwd)
this.customInstructions = customInstructions
this.diffEnabled = diffEnabled
if (diffEnabled && this.api.getModel().id) {
this.diffStrategy = getDiffStrategy(this.api.getModel().id)
}
if (historyItem) {
this.taskId = historyItem.id
this.resumeTaskFromHistory()
Expand Down Expand Up @@ -752,7 +754,7 @@ export class Cline {
}

async *attemptApiRequest(previousApiReqIndex: number): ApiStream {
const systemPrompt = await SYSTEM_PROMPT(cwd, this.api.getModel().info.supportsComputerUse ?? false, !!this.diffEnabled) + await addCustomInstructions(this.customInstructions ?? '', cwd)
const systemPrompt = await SYSTEM_PROMPT(cwd, this.api.getModel().info.supportsComputerUse ?? false, this.diffStrategy) + await addCustomInstructions(this.customInstructions ?? '', cwd)

// If the previous API request's total token usage is close to the context window, truncate the conversation history to free up space for the new request
if (previousApiReqIndex >= 0) {
Expand Down Expand Up @@ -1104,7 +1106,7 @@ export class Cline {

// Check for code omissions before proceeding
if (detectCodeOmission(this.diffViewProvider.originalContent || "", newContent)) {
if (this.diffEnabled) {
if (this.diffStrategy) {
await this.diffViewProvider.revertChanges()
pushToolResult(formatResponse.toolError(
"Content appears to be truncated. Found comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file."
Expand Down Expand Up @@ -1220,25 +1222,13 @@ export class Cline {
const originalContent = await fs.readFile(absolutePath, "utf-8")

// Apply the diff to the original content
let newContent = diff.applyPatch(originalContent, diffContent) as string | false
let newContent = this.diffStrategy?.applyDiff(originalContent, diffContent) ?? false
if (newContent === false) {
await this.say("error", `Error applying diff to file: ${absolutePath}`)
pushToolResult(`Error applying diff to file: ${absolutePath}`)
break
}

// Create a diff for display purposes
const diffRepresentation = diff
.diffLines(originalContent, newContent)
.map((part) => {
const prefix = part.added ? "+" : part.removed ? "-" : " "
return (part.value || "")
.split("\n")
.map((line) => (line ? prefix + line : ""))
.join("\n")
})
.join("")

// Show diff view before asking for approval
this.diffViewProvider.editType = "modify"
await this.diffViewProvider.open(relPath);
Expand All @@ -1247,7 +1237,7 @@ export class Cline {

const completeMessage = JSON.stringify({
...sharedMessageProps,
diff: diffRepresentation,
diff: diffContent,
} satisfies ClineSayTool)

const didApprove = await askApproval("tool", completeMessage)
Expand Down Expand Up @@ -2287,5 +2277,4 @@ export class Cline {

return `<environment_details>\n${details.trim()}\n</environment_details>`
}
}

}
16 changes: 16 additions & 0 deletions src/core/diff/DiffStrategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { DiffStrategy } from './types'
import { UnifiedDiffStrategy } from './strategies/unified'

/**
* Get the appropriate diff strategy for the given model
* @param model The name of the model being used (e.g., 'gpt-4', 'claude-3-opus')
* @returns The appropriate diff strategy for the model
*/
export function getDiffStrategy(model: string): DiffStrategy {
// For now, return UnifiedDiffStrategy for all models
// This architecture allows for future optimizations based on model capabilities
return new UnifiedDiffStrategy()
}

export type { DiffStrategy }
export { UnifiedDiffStrategy }
Loading

0 comments on commit da31a23

Please sign in to comment.