Skip to content

Commit e856612

Browse files
committed
Deep research
1 parent 2e52b1c commit e856612

34 files changed

+2645
-32
lines changed

package-lock.json

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

package.json

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@
7474
"title": "New Task",
7575
"icon": "$(add)"
7676
},
77+
{
78+
"command": "roo-cline.researchButtonClicked",
79+
"title": "Deep Research (β)",
80+
"icon": "$(telescope)"
81+
},
7782
{
7883
"command": "roo-cline.mcpButtonClicked",
7984
"title": "MCP Servers",
@@ -207,34 +212,39 @@
207212
"when": "view == roo-cline.SidebarProvider"
208213
},
209214
{
210-
"command": "roo-cline.promptsButtonClicked",
215+
"command": "roo-cline.researchButtonClicked",
211216
"group": "navigation@2",
212217
"when": "view == roo-cline.SidebarProvider"
213218
},
214219
{
215-
"command": "roo-cline.mcpButtonClicked",
220+
"command": "roo-cline.promptsButtonClicked",
216221
"group": "navigation@3",
217222
"when": "view == roo-cline.SidebarProvider"
218223
},
219224
{
220-
"command": "roo-cline.historyButtonClicked",
225+
"command": "roo-cline.mcpButtonClicked",
221226
"group": "navigation@4",
222227
"when": "view == roo-cline.SidebarProvider"
223228
},
224229
{
225-
"command": "roo-cline.popoutButtonClicked",
230+
"command": "roo-cline.historyButtonClicked",
226231
"group": "navigation@5",
227232
"when": "view == roo-cline.SidebarProvider"
228233
},
229234
{
230-
"command": "roo-cline.settingsButtonClicked",
235+
"command": "roo-cline.popoutButtonClicked",
231236
"group": "navigation@6",
232237
"when": "view == roo-cline.SidebarProvider"
233238
},
234239
{
235-
"command": "roo-cline.helpButtonClicked",
240+
"command": "roo-cline.settingsButtonClicked",
236241
"group": "navigation@7",
237242
"when": "view == roo-cline.SidebarProvider"
243+
},
244+
{
245+
"command": "roo-cline.helpButtonClicked",
246+
"group": "navigation@8",
247+
"when": "view == roo-cline.SidebarProvider"
238248
}
239249
]
240250
},
@@ -308,6 +318,8 @@
308318
"@anthropic-ai/vertex-sdk": "^0.4.1",
309319
"@aws-sdk/client-bedrock-runtime": "^3.706.0",
310320
"@google/generative-ai": "^0.18.0",
321+
"@hookform/resolvers": "^4.0.0",
322+
"@mendable/firecrawl-js": "^1.16.0",
311323
"@mistralai/mistralai": "^1.3.6",
312324
"@modelcontextprotocol/sdk": "^1.0.1",
313325
"@types/clone-deep": "^4.0.4",
@@ -329,15 +341,18 @@
329341
"get-folder-size": "^5.0.0",
330342
"globby": "^14.0.2",
331343
"isbinaryfile": "^5.0.2",
344+
"js-tiktoken": "^1.0.18",
332345
"mammoth": "^1.8.0",
333346
"monaco-vscode-textmate-theme-converter": "^0.1.7",
334347
"openai": "^4.78.1",
335348
"os-name": "^6.0.0",
349+
"p-limit": "^6.2.0",
336350
"p-wait-for": "^5.0.2",
337351
"pdf-parse": "^1.1.1",
338352
"pretty-bytes": "^6.1.1",
339353
"puppeteer-chromium-resolver": "^23.0.0",
340354
"puppeteer-core": "^23.4.0",
355+
"react-hook-form": "^7.54.2",
341356
"serialize-error": "^11.0.3",
342357
"simple-git": "^3.27.0",
343358
"sound-play": "^1.1.0",
@@ -346,8 +361,9 @@
346361
"tmp": "^0.2.3",
347362
"tree-sitter-wasms": "^0.1.11",
348363
"turndown": "^7.2.0",
364+
"use-callback-ref": "^1.3.3",
349365
"web-tree-sitter": "^0.22.6",
350-
"zod": "^3.23.8"
366+
"zod": "^3.24.2"
351367
},
352368
"devDependencies": {
353369
"@changesets/cli": "^2.27.10",

src/__mocks__/p-limit.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const pLimit = (concurrency) => async (fn) => fn()
2+
3+
module.exports = pLimit

src/activate/registerCommands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
2424
await provider.postStateToWebview()
2525
await provider.postMessageToWebview({ type: "action", action: "chatButtonClicked" })
2626
},
27+
"roo-cline.researchButtonClicked": () => {
28+
provider.postMessageToWebview({ type: "action", action: "researchButtonClicked" })
29+
},
2730
"roo-cline.mcpButtonClicked": () => {
2831
provider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" })
2932
},

src/core/webview/ClineProvider.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,18 @@ import { ApiConfiguration, ApiProvider, ModelInfo } from "../../shared/api"
2020
import { findLast } from "../../shared/array"
2121
import { ApiConfigMeta, ExtensionMessage } from "../../shared/ExtensionMessage"
2222
import { HistoryItem } from "../../shared/HistoryItem"
23-
import { checkoutDiffPayloadSchema, checkoutRestorePayloadSchema, WebviewMessage } from "../../shared/WebviewMessage"
23+
import {
24+
checkoutDiffPayloadSchema,
25+
checkoutRestorePayloadSchema,
26+
researchTaskPayloadSchema,
27+
researchInputPayloadSchema,
28+
WebviewMessage,
29+
} from "../../shared/WebviewMessage"
2430
import { Mode, CustomModePrompts, PromptComponent, defaultModeSlug } from "../../shared/modes"
2531
import { SYSTEM_PROMPT } from "../prompts/system"
2632
import { fileExistsAtPath } from "../../utils/fs"
2733
import { Cline } from "../Cline"
34+
import { DeepResearchService } from "../../services/deep-research/DeepResearchService"
2835
import { openMention } from "../mentions"
2936
import { getNonce } from "./getNonce"
3037
import { getUri } from "./getUri"
@@ -60,6 +67,8 @@ type SecretKey =
6067
| "mistralApiKey"
6168
| "unboundApiKey"
6269
| "requestyApiKey"
70+
| "firecrawlApiKey"
71+
6372
type GlobalStateKey =
6473
| "apiProvider"
6574
| "apiModelId"
@@ -148,6 +157,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
148157
private view?: vscode.WebviewView | vscode.WebviewPanel
149158
private isViewLaunched = false
150159
private cline?: Cline
160+
private deepResearchService?: DeepResearchService
151161
private workspaceTracker?: WorkspaceTracker
152162
protected mcpHub?: McpHub // Change from private to protected
153163
private latestAnnouncementId = "jan-21-2025-custom-modes" // update to some unique identifier when we add a new announcement
@@ -1513,6 +1523,55 @@ export class ClineProvider implements vscode.WebviewViewProvider {
15131523
await this.updateGlobalState("mode", defaultModeSlug)
15141524
await this.postStateToWebview()
15151525
}
1526+
break
1527+
case "research.task": {
1528+
const result = researchTaskPayloadSchema.safeParse(message.payload)
1529+
1530+
if (!result.success) {
1531+
console.warn(
1532+
`[ClineProvider#research.task] Invalid payload: ${JSON.stringify(message.payload)}`,
1533+
)
1534+
break
1535+
}
1536+
1537+
if (result.success && !this.deepResearchService) {
1538+
const { session } = result.data
1539+
this.deepResearchService = new DeepResearchService(session, this)
1540+
this.deepResearchService.input(session.query)
1541+
}
1542+
1543+
break
1544+
}
1545+
case "research.input": {
1546+
const result = researchInputPayloadSchema.safeParse(message.payload)
1547+
1548+
if (!result.success) {
1549+
console.warn(
1550+
`[ClineProvider#research.input] Invalid payload: ${JSON.stringify(message.payload)}`,
1551+
)
1552+
break
1553+
}
1554+
1555+
if (result.success && this.deepResearchService) {
1556+
const { content } = result.data.message
1557+
this.deepResearchService.input(content)
1558+
}
1559+
1560+
break
1561+
}
1562+
case "research.viewReport":
1563+
this.deepResearchService?.viewReport()
1564+
break
1565+
case "research.createTask":
1566+
this.deepResearchService?.createTask()
1567+
break
1568+
case "research.abort":
1569+
this.deepResearchService?.abort()
1570+
break
1571+
case "research.reset":
1572+
this.deepResearchService?.abort()
1573+
this.deepResearchService = undefined
1574+
break
15161575
}
15171576
},
15181577
null,
@@ -1660,6 +1719,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
16601719
requestyModelId,
16611720
requestyModelInfo,
16621721
modelTemperature,
1722+
firecrawlApiKey,
16631723
} = apiConfiguration
16641724
await Promise.all([
16651725
this.updateGlobalState("apiProvider", apiProvider),
@@ -1707,6 +1767,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
17071767
this.updateGlobalState("requestyModelId", requestyModelId),
17081768
this.updateGlobalState("requestyModelInfo", requestyModelInfo),
17091769
this.updateGlobalState("modelTemperature", modelTemperature),
1770+
this.storeSecret("firecrawlApiKey", firecrawlApiKey),
17101771
])
17111772
if (this.cline) {
17121773
this.cline.api = buildApiHandler(apiConfiguration)
@@ -2591,6 +2652,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
25912652
requestyModelInfo,
25922653
modelTemperature,
25932654
maxOpenTabsContext,
2655+
firecrawlApiKey,
25942656
] = await Promise.all([
25952657
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
25962658
this.getGlobalState("apiModelId") as Promise<string | undefined>,
@@ -2673,6 +2735,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
26732735
this.getGlobalState("requestyModelInfo") as Promise<ModelInfo | undefined>,
26742736
this.getGlobalState("modelTemperature") as Promise<number | undefined>,
26752737
this.getGlobalState("maxOpenTabsContext") as Promise<number | undefined>,
2738+
this.getSecret("firecrawlApiKey") as Promise<string | undefined>,
26762739
])
26772740

26782741
let apiProvider: ApiProvider
@@ -2736,6 +2799,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
27362799
requestyModelId,
27372800
requestyModelInfo,
27382801
modelTemperature,
2802+
firecrawlApiKey,
27392803
},
27402804
lastShownAnnouncementId,
27412805
customInstructions,
@@ -2892,6 +2956,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
28922956
"mistralApiKey",
28932957
"unboundApiKey",
28942958
"requestyApiKey",
2959+
"firecrawlApiKey",
28952960
]
28962961
for (const key of secretKeys) {
28972962
await this.storeSecret(key, undefined)

0 commit comments

Comments
 (0)