@@ -20,11 +20,18 @@ import { ApiConfiguration, ApiProvider, ModelInfo } from "../../shared/api"
2020import { findLast } from "../../shared/array"
2121import { ApiConfigMeta , ExtensionMessage } from "../../shared/ExtensionMessage"
2222import { 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"
2430import { Mode , CustomModePrompts , PromptComponent , defaultModeSlug } from "../../shared/modes"
2531import { SYSTEM_PROMPT } from "../prompts/system"
2632import { fileExistsAtPath } from "../../utils/fs"
2733import { Cline } from "../Cline"
34+ import { DeepResearchService } from "../../services/deep-research/DeepResearchService"
2835import { openMention } from "../mentions"
2936import { getNonce } from "./getNonce"
3037import { getUri } from "./getUri"
@@ -60,6 +67,8 @@ type SecretKey =
6067 | "mistralApiKey"
6168 | "unboundApiKey"
6269 | "requestyApiKey"
70+ | "firecrawlApiKey"
71+
6372type 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
@@ -1526,6 +1536,107 @@ export class ClineProvider implements vscode.WebviewViewProvider {
15261536 await this . updateGlobalState ( "mode" , defaultModeSlug )
15271537 await this . postStateToWebview ( )
15281538 }
1539+ break
1540+ case "research.task" : {
1541+ const result = researchTaskPayloadSchema . safeParse ( message . payload )
1542+
1543+ if ( ! result . success ) {
1544+ console . warn (
1545+ `[ClineProvider#research.task] Invalid payload: ${ JSON . stringify ( message . payload ) } ` ,
1546+ )
1547+ break
1548+ }
1549+
1550+ if ( result . success && ! this . deepResearchService ) {
1551+ const { session } = result . data
1552+ this . deepResearchService = new DeepResearchService ( session , this )
1553+ await this . deepResearchService . input ( session . query )
1554+ }
1555+
1556+ break
1557+ }
1558+ case "research.input" : {
1559+ const result = researchInputPayloadSchema . safeParse ( message . payload )
1560+
1561+ if ( ! result . success ) {
1562+ console . warn (
1563+ `[ClineProvider#research.input] Invalid payload: ${ JSON . stringify ( message . payload ) } ` ,
1564+ )
1565+ break
1566+ }
1567+
1568+ if ( result . success && this . deepResearchService ) {
1569+ const { content } = result . data . message
1570+ this . deepResearchService . input ( content )
1571+ }
1572+
1573+ break
1574+ }
1575+ case "research.viewReport" :
1576+ await this . deepResearchService ?. viewReport ( )
1577+ break
1578+ case "research.createTask" :
1579+ await this . deepResearchService ?. createTask ( )
1580+ break
1581+ case "research.getTasks" :
1582+ const tasks = await DeepResearchService . getTasks ( this . context . globalStorageUri . fsPath )
1583+
1584+ await this . postMessageToWebview ( {
1585+ type : "research.history" ,
1586+ text : JSON . stringify (
1587+ tasks
1588+ . sort ( ( a , b ) => b . createdAt - a . createdAt )
1589+ . map ( ( task ) => ( {
1590+ taskId : task . taskId ,
1591+ query : task . inquiry . initialQuery ,
1592+ createdAt : task . createdAt ,
1593+ } ) ) ,
1594+ ) ,
1595+ } )
1596+
1597+ break
1598+ case "research.getTask" :
1599+ if ( message . text ) {
1600+ const task = await DeepResearchService . getTask (
1601+ this . context . globalStorageUri . fsPath ,
1602+ message . text ,
1603+ )
1604+
1605+ await this . postMessageToWebview ( { type : "research.task" , text : JSON . stringify ( task ) } )
1606+ }
1607+
1608+ break
1609+ case "research.deleteTask" :
1610+ if ( message . text ) {
1611+ try {
1612+ await DeepResearchService . deleteTask ( this . context . globalStorageUri . fsPath , message . text )
1613+ const tasks = await DeepResearchService . getTasks ( this . context . globalStorageUri . fsPath )
1614+
1615+ await this . postMessageToWebview ( {
1616+ type : "research.history" ,
1617+ text : JSON . stringify (
1618+ tasks
1619+ . sort ( ( a , b ) => b . createdAt - a . createdAt )
1620+ . map ( ( task ) => ( {
1621+ taskId : task . taskId ,
1622+ query : task . inquiry . initialQuery ,
1623+ createdAt : task . createdAt ,
1624+ } ) ) ,
1625+ ) ,
1626+ } )
1627+ } catch ( error ) {
1628+ vscode . window . showErrorMessage ( "Failed to delete research task." )
1629+ }
1630+ }
1631+
1632+ break
1633+ case "research.abort" :
1634+ await this . deepResearchService ?. abort ( )
1635+ break
1636+ case "research.reset" :
1637+ await this . deepResearchService ?. abort ( )
1638+ this . deepResearchService = undefined
1639+ break
15291640 }
15301641 } ,
15311642 null ,
@@ -1673,6 +1784,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
16731784 requestyModelId,
16741785 requestyModelInfo,
16751786 modelTemperature,
1787+ firecrawlApiKey,
16761788 } = apiConfiguration
16771789 await Promise . all ( [
16781790 this . updateGlobalState ( "apiProvider" , apiProvider ) ,
@@ -1720,6 +1832,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
17201832 this . updateGlobalState ( "requestyModelId" , requestyModelId ) ,
17211833 this . updateGlobalState ( "requestyModelInfo" , requestyModelInfo ) ,
17221834 this . updateGlobalState ( "modelTemperature" , modelTemperature ) ,
1835+ this . storeSecret ( "firecrawlApiKey" , firecrawlApiKey ) ,
17231836 ] )
17241837 if ( this . cline ) {
17251838 this . cline . api = buildApiHandler ( apiConfiguration )
@@ -2603,6 +2716,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
26032716 requestyModelInfo ,
26042717 modelTemperature ,
26052718 maxOpenTabsContext ,
2719+ firecrawlApiKey ,
26062720 ] = await Promise . all ( [
26072721 this . getGlobalState ( "apiProvider" ) as Promise < ApiProvider | undefined > ,
26082722 this . getGlobalState ( "apiModelId" ) as Promise < string | undefined > ,
@@ -2685,6 +2799,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
26852799 this . getGlobalState ( "requestyModelInfo" ) as Promise < ModelInfo | undefined > ,
26862800 this . getGlobalState ( "modelTemperature" ) as Promise < number | undefined > ,
26872801 this . getGlobalState ( "maxOpenTabsContext" ) as Promise < number | undefined > ,
2802+ this . getSecret ( "firecrawlApiKey" ) as Promise < string | undefined > ,
26882803 ] )
26892804
26902805 let apiProvider : ApiProvider
@@ -2748,6 +2863,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
27482863 requestyModelId,
27492864 requestyModelInfo,
27502865 modelTemperature,
2866+ firecrawlApiKey,
27512867 } ,
27522868 lastShownAnnouncementId,
27532869 customInstructions,
@@ -2905,6 +3021,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
29053021 "mistralApiKey" ,
29063022 "unboundApiKey" ,
29073023 "requestyApiKey" ,
3024+ "firecrawlApiKey" ,
29083025 ]
29093026 for ( const key of secretKeys ) {
29103027 await this . storeSecret ( key , undefined )
0 commit comments