Skip to content

Commit 4729176

Browse files
committed
Merge branch 'main' into cte/remove-model-info-from-settings
2 parents de3e2a5 + a354c01 commit 4729176

File tree

9 files changed

+72
-95
lines changed

9 files changed

+72
-95
lines changed

.changeset/lazy-rats-end.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": minor
3+
---
4+
5+
Updates default model id for Unbound from claude 3.5 to 3.7

esbuild.js

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,23 @@ const copyWasmFiles = {
2929
name: "copy-wasm-files",
3030
setup(build) {
3131
build.onEnd(() => {
32-
// tree sitter
33-
const sourceDir = path.join(__dirname, "node_modules", "web-tree-sitter")
34-
const targetDir = path.join(__dirname, "dist")
35-
36-
// Copy tree-sitter.wasm
37-
fs.copyFileSync(path.join(sourceDir, "tree-sitter.wasm"), path.join(targetDir, "tree-sitter.wasm"))
38-
39-
// Copy language-specific WASM files
40-
const languageWasmDir = path.join(__dirname, "node_modules", "tree-sitter-wasms", "out")
32+
const nodeModulesDir = path.join(__dirname, "node_modules")
33+
const distDir = path.join(__dirname, "dist")
34+
35+
// tiktoken
36+
fs.copyFileSync(
37+
path.join(nodeModulesDir, "tiktoken", "tiktoken_bg.wasm"),
38+
path.join(distDir, "tiktoken_bg.wasm"),
39+
)
40+
41+
// tree-sitter WASM
42+
fs.copyFileSync(
43+
path.join(nodeModulesDir, "web-tree-sitter", "tree-sitter.wasm"),
44+
path.join(distDir, "tree-sitter.wasm"),
45+
)
46+
47+
// language-specific tree-sitter WASMs
48+
const languageWasmDir = path.join(nodeModulesDir, "tree-sitter-wasms", "out")
4149
const languages = [
4250
"typescript",
4351
"tsx",
@@ -57,7 +65,7 @@ const copyWasmFiles = {
5765

5866
languages.forEach((lang) => {
5967
const filename = `tree-sitter-${lang}.wasm`
60-
fs.copyFileSync(path.join(languageWasmDir, filename), path.join(targetDir, filename))
68+
fs.copyFileSync(path.join(languageWasmDir, filename), path.join(distDir, filename))
6169
})
6270
})
6371
},

package-lock.json

Lines changed: 7 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,6 @@
429429
"get-folder-size": "^5.0.0",
430430
"i18next": "^24.2.2",
431431
"isbinaryfile": "^5.0.2",
432-
"js-tiktoken": "^1.0.19",
433432
"mammoth": "^1.8.0",
434433
"monaco-vscode-textmate-theme-converter": "^0.1.7",
435434
"node-cache": "^5.1.2",
@@ -451,6 +450,7 @@
451450
"string-similarity": "^4.0.4",
452451
"strip-ansi": "^7.1.0",
453452
"strip-bom": "^5.0.0",
453+
"tiktoken": "^1.0.21",
454454
"tmp": "^0.2.3",
455455
"tree-sitter-wasms": "^0.1.11",
456456
"turndown": "^7.2.0",

src/api/providers/base-provider.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { Anthropic } from "@anthropic-ai/sdk"
22
import { ApiHandler } from ".."
33
import { ModelInfo } from "../../shared/api"
44
import { ApiStream } from "../transform/stream"
5-
import { Tiktoken } from "js-tiktoken/lite"
6-
import o200kBase from "js-tiktoken/ranks/o200k_base"
5+
import { Tiktoken } from "tiktoken/lite"
6+
import o200kBase from "tiktoken/encoders/o200k_base"
77

88
// Reuse the fudge factor used in the original code
99
const TOKEN_FUDGE_FACTOR = 1.5
@@ -34,21 +34,23 @@ export abstract class BaseProvider implements ApiHandler {
3434

3535
// Lazily create and cache the encoder if it doesn't exist
3636
if (!this.encoder) {
37-
this.encoder = new Tiktoken(o200kBase)
37+
this.encoder = new Tiktoken(o200kBase.bpe_ranks, o200kBase.special_tokens, o200kBase.pat_str)
3838
}
3939

4040
// Process each content block using the cached encoder
4141
for (const block of content) {
4242
if (block.type === "text") {
4343
// Use tiktoken for text token counting
4444
const text = block.text || ""
45+
4546
if (text.length > 0) {
4647
const tokens = this.encoder.encode(text)
4748
totalTokens += tokens.length
4849
}
4950
} else if (block.type === "image") {
5051
// For images, calculate based on data size
5152
const imageSource = block.source
53+
5254
if (imageSource && typeof imageSource === "object" && "data" in imageSource) {
5355
const base64Data = imageSource.data as string
5456
totalTokens += Math.ceil(Math.sqrt(base64Data.length))

src/core/sliding-window/__tests__/sliding-window.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import { Anthropic } from "@anthropic-ai/sdk"
44

55
import { ModelInfo } from "../../../shared/api"
6-
import { ApiHandler } from "../../../api"
76
import { BaseProvider } from "../../../api/providers/base-provider"
8-
import { TOKEN_BUFFER_PERCENTAGE } from "../index"
9-
import { estimateTokenCount, truncateConversation, truncateConversationIfNeeded } from "../index"
7+
import {
8+
TOKEN_BUFFER_PERCENTAGE,
9+
estimateTokenCount,
10+
truncateConversation,
11+
truncateConversationIfNeeded,
12+
} from "../index"
1013

1114
// Create a mock ApiHandler for testing
1215
class MockApiHandler extends BaseProvider {
@@ -231,7 +234,6 @@ describe("truncateConversationIfNeeded", () => {
231234

232235
it("should not truncate if tokens are below max tokens threshold", async () => {
233236
const modelInfo = createModelInfo(100000, 30000)
234-
const maxTokens = 100000 - 30000 // 70000
235237
const dynamicBuffer = modelInfo.contextWindow * TOKEN_BUFFER_PERCENTAGE // 10000
236238
const totalTokens = 70000 - dynamicBuffer - 1 // Just below threshold - buffer
237239

@@ -250,7 +252,6 @@ describe("truncateConversationIfNeeded", () => {
250252

251253
it("should truncate if tokens are above max tokens threshold", async () => {
252254
const modelInfo = createModelInfo(100000, 30000)
253-
const maxTokens = 100000 - 30000 // 70000
254255
const totalTokens = 70001 // Above threshold
255256

256257
// Create messages with very small content in the last one to avoid token overflow
@@ -390,7 +391,6 @@ describe("truncateConversationIfNeeded", () => {
390391

391392
it("should truncate if tokens are within TOKEN_BUFFER_PERCENTAGE of the threshold", async () => {
392393
const modelInfo = createModelInfo(100000, 30000)
393-
const maxTokens = 100000 - 30000 // 70000
394394
const dynamicBuffer = modelInfo.contextWindow * TOKEN_BUFFER_PERCENTAGE // 10% of 100000 = 10000
395395
const totalTokens = 70000 - dynamicBuffer + 1 // Just within the dynamic buffer of threshold (70000)
396396

src/integrations/editor/DiffViewProvider.ts

Lines changed: 9 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ export class DiffViewProvider {
1717
originalContent: string | undefined
1818
private createdDirs: string[] = []
1919
private documentWasOpen = false
20-
private originalViewColumn?: vscode.ViewColumn // Store the original view column
2120
private relPath?: string
2221
private newContent?: string
2322
private activeDiffEditor?: vscode.TextEditor
@@ -66,22 +65,11 @@ export class DiffViewProvider {
6665
.filter(
6766
(tab) => tab.input instanceof vscode.TabInputText && arePathsEqual(tab.input.uri.fsPath, absolutePath),
6867
)
69-
// Check if the document is already open and store its state
70-
// DO NOT close the original tab to preserve pin status
7168
for (const tab of tabs) {
72-
if (tab.input instanceof vscode.TabInputText && arePathsEqual(tab.input.uri.fsPath, absolutePath)) {
73-
this.originalViewColumn = tab.group.viewColumn
74-
this.documentWasOpen = true
75-
// Ensure the tab is not dirty before proceeding, but don't close it
76-
if (tab.isDirty) {
77-
// Find the document associated with the tab and save it
78-
const doc = vscode.workspace.textDocuments.find((d) => arePathsEqual(d.uri.fsPath, absolutePath))
79-
if (doc) {
80-
await doc.save()
81-
}
82-
}
83-
break // Found the relevant tab, no need to check others
69+
if (!tab.isDirty) {
70+
await vscode.window.tabGroups.close(tab)
8471
}
72+
this.documentWasOpen = true
8573
}
8674
this.activeDiffEditor = await this.openDiffEditor()
8775
this.fadedOverlayController = new DecorationController("fadedOverlay", this.activeDiffEditor)
@@ -168,31 +156,9 @@ export class DiffViewProvider {
168156
await updatedDocument.save()
169157
}
170158

171-
// Close the diff view first
159+
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), { preview: false })
172160
await this.closeAllDiffViews()
173161

174-
// If the original document was open, try to focus it.
175-
// VS Code should handle showing the updated content automatically since the file was saved.
176-
if (this.documentWasOpen && this.originalViewColumn) {
177-
// Find the editor for the original document and reveal it
178-
const originalEditor = vscode.window.visibleTextEditors.find(
179-
(editor) =>
180-
arePathsEqual(editor.document.uri.fsPath, absolutePath) &&
181-
editor.viewColumn === this.originalViewColumn,
182-
)
183-
if (originalEditor) {
184-
// Reveal a range (e.g., the start) to ensure focus
185-
const position = new vscode.Position(0, 0)
186-
originalEditor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.AtTop)
187-
} else {
188-
// Fallback if editor not found (shouldn't happen often if documentWasOpen is true)
189-
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
190-
preview: false,
191-
viewColumn: this.originalViewColumn,
192-
})
193-
}
194-
}
195-
196162
/*
197163
Getting diagnostics before and after the file edit is a better approach than
198164
automatically tracking problems in real-time. This method ensures we only
@@ -271,28 +237,12 @@ export class DiffViewProvider {
271237
await vscode.workspace.applyEdit(edit)
272238
await updatedDocument.save()
273239
console.log(`File ${absolutePath} has been reverted to its original content.`)
274-
// Close the diff view first
275-
await this.closeAllDiffViews()
276-
277-
// If the document was originally open, ensure it's focused.
278-
// The revert logic already applied the original content and saved.
279-
if (this.documentWasOpen && this.originalViewColumn) {
280-
const originalEditor = vscode.window.visibleTextEditors.find(
281-
(editor) =>
282-
arePathsEqual(editor.document.uri.fsPath, absolutePath) &&
283-
editor.viewColumn === this.originalViewColumn,
284-
)
285-
if (originalEditor) {
286-
const position = new vscode.Position(0, 0)
287-
originalEditor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.AtTop)
288-
} else {
289-
// Fallback
290-
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
291-
preview: false,
292-
viewColumn: this.originalViewColumn,
293-
})
294-
}
240+
if (this.documentWasOpen) {
241+
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
242+
preview: false,
243+
})
295244
}
245+
await this.closeAllDiffViews()
296246
}
297247

298248
// edit is done
@@ -408,7 +358,6 @@ export class DiffViewProvider {
408358
this.originalContent = undefined
409359
this.createdDirs = []
410360
this.documentWasOpen = false
411-
this.originalViewColumn = undefined // Reset stored view column
412361
this.activeDiffEditor = undefined
413362
this.fadedOverlayController = undefined
414363
this.activeLineController = undefined

src/shared/__tests__/modes.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ describe("FileRestrictionError", () => {
271271
expect(debugMode).toBeDefined()
272272
expect(debugMode).toMatchObject({
273273
slug: "debug",
274-
name: "Debug",
274+
name: "🪲 Debug",
275275
roleDefinition:
276276
"You are Roo, an expert software debugger specializing in systematic problem diagnosis and resolution.",
277277
groups: ["read", "edit", "browser", "command", "mcp"],
@@ -292,7 +292,7 @@ describe("FileRestrictionError", () => {
292292
const result = await getFullModeDetails("debug")
293293
expect(result).toMatchObject({
294294
slug: "debug",
295-
name: "Debug",
295+
name: "🪲 Debug",
296296
roleDefinition:
297297
"You are Roo, an expert software debugger specializing in systematic problem diagnosis and resolution.",
298298
})

src/shared/modes.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@ export function getToolsForMode(groups: readonly GroupEntry[]): string[] {
5454
export const modes: readonly ModeConfig[] = [
5555
{
5656
slug: "code",
57-
name: "Code",
57+
name: "💻 Code",
5858
roleDefinition:
5959
"You are Roo, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.",
6060
groups: ["read", "edit", "browser", "command", "mcp"],
6161
},
6262
{
6363
slug: "architect",
64-
name: "Architect",
64+
name: "🏗️ Architect",
6565
roleDefinition:
6666
"You are Roo, an experienced technical leader who is inquisitive and an excellent planner. Your goal is to gather information and get context to create a detailed plan for accomplishing the user's task, which the user will review and approve before they switch into another mode to implement the solution.",
6767
groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "browser", "mcp"],
@@ -70,7 +70,7 @@ export const modes: readonly ModeConfig[] = [
7070
},
7171
{
7272
slug: "ask",
73-
name: "Ask",
73+
name: "Ask",
7474
roleDefinition:
7575
"You are Roo, a knowledgeable technical assistant focused on answering questions and providing information about software development, technology, and related topics.",
7676
groups: ["read", "browser", "mcp"],
@@ -79,13 +79,28 @@ export const modes: readonly ModeConfig[] = [
7979
},
8080
{
8181
slug: "debug",
82-
name: "Debug",
82+
name: "🪲 Debug",
8383
roleDefinition:
8484
"You are Roo, an expert software debugger specializing in systematic problem diagnosis and resolution.",
8585
groups: ["read", "edit", "browser", "command", "mcp"],
8686
customInstructions:
8787
"Reflect on 5-7 different possible sources of the problem, distill those down to 1-2 most likely sources, and then add logs to validate your assumptions. Explicitly ask the user to confirm the diagnosis before fixing the problem.",
8888
},
89+
{
90+
slug: "orchestrator",
91+
name: "🪃 Orchestrator",
92+
roleDefinition:
93+
"You are Roo, a strategic workflow orchestrator who coordinates complex tasks by delegating them to appropriate specialized modes. You have a comprehensive understanding of each mode's capabilities and limitations, allowing you to effectively break down complex problems into discrete tasks that can be solved by different specialists.",
94+
groups: [
95+
"read",
96+
["edit", { fileRegex: "\\.roomodes$|custom_modes\\.json$", description: "Mode configuration files only" }],
97+
"browser",
98+
"command",
99+
"mcp",
100+
],
101+
customInstructions:
102+
"Your role is to coordinate complex workflows by delegating tasks to specialized modes. As an orchestrator, you should:\n\n1. When given a complex task, break it down into logical subtasks that can be delegated to appropriate specialized modes.\n\n2. For each subtask, use the `new_task` tool to delegate. Choose the most appropriate mode for the subtask's specific goal and provide comprehensive instructions in the `message` parameter. These instructions must include:\n * All necessary context from the parent task or previous subtasks required to complete the work.\n * A clearly defined scope, specifying exactly what the subtask should accomplish.\n * An explicit statement that the subtask should *only* perform the work outlined in these instructions and not deviate.\n * An instruction for the subtask to signal completion by using the `attempt_completion` tool, providing a concise yet thorough summary of the outcome in the `result` parameter, keeping in mind that this summary will be the source of truth used to keep track of what was completed on this project.\n * A statement that these specific instructions supersede any conflicting general instructions the subtask's mode might have.\n\n3. Track and manage the progress of all subtasks. When a subtask is completed, analyze its results and determine the next steps.\n\n4. Help the user understand how the different subtasks fit together in the overall workflow. Provide clear reasoning about why you're delegating specific tasks to specific modes.\n\n5. When all subtasks are completed, synthesize the results and provide a comprehensive overview of what was accomplished.\n\n6. Ask clarifying questions when necessary to better understand how to break down complex tasks effectively.\n\n7. Suggest improvements to the workflow based on the results of completed subtasks.\n\nUse subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.",
103+
},
89104
] as const
90105

91106
// Export the default mode slug

0 commit comments

Comments
 (0)