Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
289 changes: 269 additions & 20 deletions package-lock.json

Large diffs are not rendered by default.

30 changes: 23 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
"title": "New Task",
"icon": "$(add)"
},
{
"command": "roo-cline.researchButtonClicked",
"title": "Deep Research (β)",
"icon": "$(telescope)"
},
{
"command": "roo-cline.mcpButtonClicked",
"title": "MCP Servers",
Expand Down Expand Up @@ -207,34 +212,39 @@
"when": "view == roo-cline.SidebarProvider"
},
{
"command": "roo-cline.promptsButtonClicked",
"command": "roo-cline.researchButtonClicked",
"group": "navigation@2",
"when": "view == roo-cline.SidebarProvider"
},
{
"command": "roo-cline.mcpButtonClicked",
"command": "roo-cline.promptsButtonClicked",
"group": "navigation@3",
"when": "view == roo-cline.SidebarProvider"
},
{
"command": "roo-cline.historyButtonClicked",
"command": "roo-cline.mcpButtonClicked",
"group": "navigation@4",
"when": "view == roo-cline.SidebarProvider"
},
{
"command": "roo-cline.popoutButtonClicked",
"command": "roo-cline.historyButtonClicked",
"group": "navigation@5",
"when": "view == roo-cline.SidebarProvider"
},
{
"command": "roo-cline.settingsButtonClicked",
"command": "roo-cline.popoutButtonClicked",
"group": "navigation@6",
"when": "view == roo-cline.SidebarProvider"
},
{
"command": "roo-cline.helpButtonClicked",
"command": "roo-cline.settingsButtonClicked",
"group": "navigation@7",
"when": "view == roo-cline.SidebarProvider"
},
{
"command": "roo-cline.helpButtonClicked",
"group": "navigation@8",
"when": "view == roo-cline.SidebarProvider"
}
]
},
Expand Down Expand Up @@ -308,6 +318,8 @@
"@anthropic-ai/vertex-sdk": "^0.4.1",
"@aws-sdk/client-bedrock-runtime": "^3.706.0",
"@google/generative-ai": "^0.18.0",
"@hookform/resolvers": "^4.0.0",
"@mendable/firecrawl-js": "^1.16.0",
"@mistralai/mistralai": "^1.3.6",
"@modelcontextprotocol/sdk": "^1.0.1",
"@types/clone-deep": "^4.0.4",
Expand All @@ -329,15 +341,18 @@
"get-folder-size": "^5.0.0",
"globby": "^14.0.2",
"isbinaryfile": "^5.0.2",
"js-tiktoken": "^1.0.18",
"mammoth": "^1.8.0",
"monaco-vscode-textmate-theme-converter": "^0.1.7",
"openai": "^4.78.1",
"os-name": "^6.0.0",
"p-limit": "^6.2.0",
"p-wait-for": "^5.0.2",
"pdf-parse": "^1.1.1",
"pretty-bytes": "^6.1.1",
"puppeteer-chromium-resolver": "^23.0.0",
"puppeteer-core": "^23.4.0",
"react-hook-form": "^7.54.2",
"serialize-error": "^11.0.3",
"simple-git": "^3.27.0",
"sound-play": "^1.1.0",
Expand All @@ -346,8 +361,9 @@
"tmp": "^0.2.3",
"tree-sitter-wasms": "^0.1.11",
"turndown": "^7.2.0",
"use-callback-ref": "^1.3.3",
"web-tree-sitter": "^0.22.6",
"zod": "^3.23.8"
"zod": "^3.24.2"
},
"devDependencies": {
"@changesets/cli": "^2.27.10",
Expand Down
3 changes: 3 additions & 0 deletions src/__mocks__/p-limit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const pLimit = (concurrency) => async (fn) => fn()

module.exports = pLimit
3 changes: 3 additions & 0 deletions src/activate/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
await provider.postStateToWebview()
await provider.postMessageToWebview({ type: "action", action: "chatButtonClicked" })
},
"roo-cline.researchButtonClicked": () => {
provider.postMessageToWebview({ type: "action", action: "researchButtonClicked" })
},
"roo-cline.mcpButtonClicked": () => {
provider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" })
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// <reference types="jest" />

import { applyContextMatching, applyDMP, applyGitFallback } from "../edit-strategies"
import { Hunk } from "../types"

Expand Down Expand Up @@ -275,7 +277,7 @@ describe("applyGitFallback", () => {
expect(result.result.join("\n")).toEqual("line1\nnew line2\nline3")
expect(result.confidence).toBe(1)
expect(result.strategy).toBe("git-fallback")
})
}, 10_000)

it("should return original content with 0 confidence when changes cannot be applied", async () => {
const hunk = {
Expand All @@ -291,5 +293,5 @@ describe("applyGitFallback", () => {
expect(result.result).toEqual(content)
expect(result.confidence).toBe(0)
expect(result.strategy).toBe("git-fallback")
})
}, 10_000)
})
117 changes: 116 additions & 1 deletion src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import { GlobalFileNames } from "../../shared/globalFileNames"
import type { SecretKey, GlobalStateKey } from "../../shared/globalState"
import { HistoryItem } from "../../shared/HistoryItem"
import { ApiConfigMeta, ExtensionMessage } from "../../shared/ExtensionMessage"
import { checkoutDiffPayloadSchema, checkoutRestorePayloadSchema, WebviewMessage } from "../../shared/WebviewMessage"
import {
checkoutDiffPayloadSchema,
checkoutRestorePayloadSchema,
researchInputPayloadSchema,
researchTaskPayloadSchema,
WebviewMessage,
} from "../../shared/WebviewMessage"
import { Mode, CustomModePrompts, PromptComponent, defaultModeSlug } from "../../shared/modes"
import { checkExistKey } from "../../shared/checkExistApiConfig"
import { EXPERIMENT_IDS, experiments as Experiments, experimentDefault, ExperimentId } from "../../shared/experiments"
Expand Down Expand Up @@ -45,6 +51,7 @@ import { getVsCodeLmModels } from "../../api/providers/vscode-lm"
import { getLmStudioModels } from "../../api/providers/lmstudio"
import { ACTION_NAMES } from "../CodeActionProvider"
import { Cline } from "../Cline"
import { DeepResearchService } from "../../services/deep-research/DeepResearchService"
import { openMention } from "../mentions"
import { getNonce } from "./getNonce"
import { getUri } from "./getUri"
Expand All @@ -62,6 +69,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
private view?: vscode.WebviewView | vscode.WebviewPanel
private isViewLaunched = false
private cline?: Cline
private deepResearchService?: DeepResearchService
private workspaceTracker?: WorkspaceTracker
protected mcpHub?: McpHub // Change from private to protected
private latestAnnouncementId = "jan-21-2025-custom-modes" // update to some unique identifier when we add a new announcement
Expand Down Expand Up @@ -1523,6 +1531,107 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.updateGlobalState("mode", defaultModeSlug)
await this.postStateToWebview()
}
break
case "research.task": {
const result = researchTaskPayloadSchema.safeParse(message.payload)

if (!result.success) {
console.warn(
`[ClineProvider#research.task] Invalid payload: ${JSON.stringify(message.payload)}`,
)
break
}

if (result.success && !this.deepResearchService) {
const { session } = result.data
this.deepResearchService = new DeepResearchService(session, this)
await this.deepResearchService.input(session.query)
}

break
}
case "research.input": {
const result = researchInputPayloadSchema.safeParse(message.payload)

if (!result.success) {
console.warn(
`[ClineProvider#research.input] Invalid payload: ${JSON.stringify(message.payload)}`,
)
break
}

if (result.success && this.deepResearchService) {
const { content } = result.data.message
this.deepResearchService.input(content)
}

break
}
case "research.viewReport":
await this.deepResearchService?.viewReport()
break
case "research.createTask":
await this.deepResearchService?.createTask()
break
case "research.getTasks":
const tasks = await DeepResearchService.getTasks(this.context.globalStorageUri.fsPath)

await this.postMessageToWebview({
type: "research.history",
text: JSON.stringify(
tasks
.sort((a, b) => b.createdAt - a.createdAt)
.map((task) => ({
taskId: task.taskId,
query: task.inquiry.initialQuery,
createdAt: task.createdAt,
})),
),
})

break
case "research.getTask":
if (message.text) {
const task = await DeepResearchService.getTask(
this.context.globalStorageUri.fsPath,
message.text,
)

await this.postMessageToWebview({ type: "research.task", text: JSON.stringify(task) })
}

break
case "research.deleteTask":
if (message.text) {
try {
await DeepResearchService.deleteTask(this.context.globalStorageUri.fsPath, message.text)
const tasks = await DeepResearchService.getTasks(this.context.globalStorageUri.fsPath)

await this.postMessageToWebview({
type: "research.history",
text: JSON.stringify(
tasks
.sort((a, b) => b.createdAt - a.createdAt)
.map((task) => ({
taskId: task.taskId,
query: task.inquiry.initialQuery,
createdAt: task.createdAt,
})),
),
})
} catch (error) {
vscode.window.showErrorMessage("Failed to delete research task.")
}
}

break
case "research.abort":
await this.deepResearchService?.abort()
break
case "research.reset":
await this.deepResearchService?.abort()
this.deepResearchService = undefined
break
}
},
null,
Expand Down Expand Up @@ -1671,6 +1780,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
requestyModelId,
requestyModelInfo,
modelTemperature,
firecrawlApiKey,
} = apiConfiguration
await Promise.all([
this.updateGlobalState("apiProvider", apiProvider),
Expand Down Expand Up @@ -1719,6 +1829,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.updateGlobalState("requestyModelId", requestyModelId),
this.updateGlobalState("requestyModelInfo", requestyModelInfo),
this.updateGlobalState("modelTemperature", modelTemperature),
this.storeSecret("firecrawlApiKey", firecrawlApiKey),
])
if (this.cline) {
this.cline.api = buildApiHandler(apiConfiguration)
Expand Down Expand Up @@ -2211,6 +2322,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
requestyModelInfo,
modelTemperature,
maxOpenTabsContext,
firecrawlApiKey,
] = await Promise.all([
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
this.getGlobalState("apiModelId") as Promise<string | undefined>,
Expand Down Expand Up @@ -2294,6 +2406,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.getGlobalState("requestyModelInfo") as Promise<ModelInfo | undefined>,
this.getGlobalState("modelTemperature") as Promise<number | undefined>,
this.getGlobalState("maxOpenTabsContext") as Promise<number | undefined>,
this.getSecret("firecrawlApiKey") as Promise<string | undefined>,
])

let apiProvider: ApiProvider
Expand Down Expand Up @@ -2358,6 +2471,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
requestyModelId,
requestyModelInfo,
modelTemperature,
firecrawlApiKey,
},
lastShownAnnouncementId,
customInstructions,
Expand Down Expand Up @@ -2495,6 +2609,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
"mistralApiKey",
"unboundApiKey",
"requestyApiKey",
"firecrawlApiKey",
]
for (const key of secretKeys) {
await this.storeSecret(key, undefined)
Expand Down
Loading