@@ -76,6 +76,7 @@ import { isLocalMcp, getLocalMcpDetails, getLocalMcp, getAllLocalMcps } from "@u
7676import { getStarCount } from "../../services/github/github"
7777import { openFile } from "@integrations/misc/open-file"
7878import { posthogClientProvider } from "@/services/posthog/PostHogClientProvider"
79+ import { ExpertFileManager } from "../experts/ExpertFileManager"
7980
8081/*
8182https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@@ -104,7 +105,7 @@ export class Controller {
104105 private vsCodeWorkSpaceFolderFsPath ! : string
105106 private codeIndexAbortController : AbortController
106107 private isSideBar : boolean
107- private expertManager : ExpertManager
108+ private expertManager : ExpertManager | undefined
108109 private isCodeIndexInProgress : boolean = false
109110
110111 constructor (
@@ -139,7 +140,6 @@ export class Controller {
139140 // TAG:HAI
140141 this . codeIndexAbortController = new AbortController ( )
141142 this . workspaceId = getWorkspaceID ( ) || ""
142- this . expertManager = new ExpertManager ( this . context , this . workspaceId )
143143 this . isSideBar = isSideBar
144144 this . vsCodeWorkSpaceFolderFsPath = ( getWorkspacePath ( ) || "" ) . trim ( )
145145 if ( this . vsCodeWorkSpaceFolderFsPath ) {
@@ -155,6 +155,15 @@ export class Controller {
155155 this . disposables . push ( registration )
156156 }
157157
158+ // TAG:HAI
159+ private async getExpertManager ( ) : Promise < ExpertManager > {
160+ if ( ! this . expertManager ) {
161+ const { embeddingConfiguration } = await getAllExtensionState ( this . context , this . workspaceId )
162+ this . expertManager = new ExpertManager ( this . context , this . workspaceId , embeddingConfiguration )
163+ }
164+ return this . expertManager
165+ }
166+
158167 /*
159168 VSCode extensions use the disposable pattern to clean up resources when the sidebar/editor tab is closed by the user or system. This applies to event listening, commands, interacting with the UI, etc.
160169 - https://vscode-docs.readthedocs.io/en/stable/extensions/patterns-and-principles/
@@ -209,6 +218,8 @@ export class Controller {
209218 taskHistory,
210219 embeddingConfiguration,
211220 expertPrompt,
221+ expertName,
222+ isDeepCrawlEnabled,
212223 buildContextOptions,
213224 } = await getAllExtensionState ( this . context , this . workspaceId )
214225
@@ -245,6 +256,8 @@ export class Controller {
245256 enableCheckpointsSetting ?? true ,
246257 customInstructions ,
247258 expertPrompt ,
259+ expertName ,
260+ isDeepCrawlEnabled ,
248261 buildContextOptions ,
249262 task ,
250263 images ,
@@ -1993,6 +2006,7 @@ Commit message:`
19932006 }
19942007
19952008 async customWebViewMessageHandlers ( message : WebviewMessage ) {
2009+ const expertManager = await this . getExpertManager ( )
19962010 switch ( message . type ) {
19972011 case "requestOllamaEmbeddingModels" :
19982012 const ollamaEmbeddingModels = await this . getOllamaEmbeddingModels ( message . text )
@@ -2014,49 +2028,65 @@ Commit message:`
20142028 break
20152029 }
20162030 break
2017- case "expertPrompt " :
2031+ case "selectExpert " :
20182032 const expertName = message . text || ""
2019- if ( message . category === "viewExpert" ) {
2020- if ( message . isDefault && message . prompt ) {
2021- try {
2022- // Create a unique URI for this expert prompt
2023- const encodedContent = Buffer . from ( message . prompt ) . toString ( "base64" )
2024- const uri = vscode . Uri . parse ( `${ EXPERT_PROMPT_URI_SCHEME } :${ expertName } .md?${ encodedContent } ` )
2033+ const expertPrompt = message . prompt || ""
2034+ const isDeepCrawlEnabled = ! ! message . isDeepCrawlEnabled
2035+ await customUpdateState ( this . context , "expertPrompt" , expertPrompt || undefined )
2036+ await customUpdateState ( this . context , "expertName" , expertName || undefined )
2037+ await customUpdateState ( this . context , "isDeepCrawlEnabled" , isDeepCrawlEnabled )
2038+ if ( ! isDeepCrawlEnabled ) {
2039+ await this . updateExpertPrompt ( message . prompt , expertName )
2040+ }
2041+ break
2042+ case "viewExpertPrompt" :
2043+ const viewExpertName = message . text || ""
20252044
2026- // Open the document
2027- const document = await vscode . workspace . openTextDocument ( uri )
2028- await vscode . window . showTextDocument ( document , { preview : false } )
2029- } catch ( error ) {
2030- console . error ( "Error creating or opening the virtual document:" , error )
2031- }
2032- } else {
2033- // For custom experts, use the existing path
2034- const promptPath = await this . expertManager . getExpertPromptPath (
2035- this . vsCodeWorkSpaceFolderFsPath ,
2036- expertName ,
2037- )
2038- if ( promptPath ) {
2039- openFile ( promptPath )
2040- } else {
2041- vscode . window . showErrorMessage ( `Could not find prompt file for expert: ${ expertName } ` )
2042- }
2045+ if ( message . isDefault && message . prompt ) {
2046+ try {
2047+ const encodedContent = Buffer . from ( message . prompt ) . toString ( "base64" )
2048+ const uri = vscode . Uri . parse ( `${ EXPERT_PROMPT_URI_SCHEME } :${ viewExpertName } .md?${ encodedContent } ` )
2049+ const document = await vscode . workspace . openTextDocument ( uri )
2050+ await vscode . window . showTextDocument ( document , { preview : false } )
2051+ } catch ( error ) {
2052+ console . error ( "Error creating or opening the virtual document:" , error )
20432053 }
20442054 } else {
2045- await this . updateExpertPrompt ( message . prompt , expertName )
2055+ const expertManager = await this . getExpertManager ( )
2056+ const promptPath = await expertManager . getExpertPromptPath ( this . vsCodeWorkSpaceFolderFsPath , viewExpertName )
2057+ if ( promptPath ) {
2058+ openFile ( promptPath )
2059+ } else {
2060+ vscode . window . showErrorMessage ( `Could not find prompt file for expert: ${ viewExpertName } ` )
2061+ }
20462062 }
20472063 break
20482064 case "saveExpert" :
20492065 if ( message . text ) {
20502066 const expert = JSON . parse ( message . text ) as ExpertData
2051- await this . expertManager . saveExpert ( this . vsCodeWorkSpaceFolderFsPath , expert )
2067+ await expertManager . saveExpert ( this . vsCodeWorkSpaceFolderFsPath , expert )
20522068 await this . loadExperts ( )
20532069 }
20542070 break
20552071 case "deleteExpert" :
20562072 if ( message . text ) {
2057- const expertName = message . text
2058- await this . expertManager . deleteExpert ( this . vsCodeWorkSpaceFolderFsPath , expertName )
2073+ const expertToDelete = message . text
2074+ const { expertName } = await getAllExtensionState ( this . context , this . workspaceId )
2075+
2076+ // Delete the expert
2077+ const expertManager = await this . getExpertManager ( )
2078+ await expertManager . deleteExpert ( this . vsCodeWorkSpaceFolderFsPath , expertToDelete )
2079+
2080+ // Clear selected expert state if the deleted expert was selected
2081+ if ( expertName === expertToDelete ) {
2082+ await customUpdateState ( this . context , "expertName" , undefined )
2083+ await customUpdateState ( this . context , "expertPrompt" , undefined )
2084+ await customUpdateState ( this . context , "isDeepCrawlEnabled" , false )
2085+ }
2086+
2087+ // Reload experts to update the UI
20592088 await this . loadExperts ( )
2089+ await this . loadDefaultExperts ( )
20602090 }
20612091 break
20622092 case "loadExperts" :
@@ -2067,18 +2097,14 @@ Commit message:`
20672097 break
20682098 case "refreshDocumentLink" :
20692099 if ( message . text && message . expert ) {
2070- await this . expertManager . refreshDocumentLink ( this . vsCodeWorkSpaceFolderFsPath , message . expert , message . text )
2100+ await expertManager . refreshDocumentLink ( this . vsCodeWorkSpaceFolderFsPath , message . expert , message . text )
20712101 }
20722102 await this . loadExperts ( )
20732103 break
20742104 case "deleteDocumentLink" :
20752105 if ( message . text && message . expert ) {
20762106 try {
2077- await this . expertManager . deleteDocumentLink (
2078- this . vsCodeWorkSpaceFolderFsPath ,
2079- message . expert ,
2080- message . text ,
2081- )
2107+ await expertManager . deleteDocumentLink ( this . vsCodeWorkSpaceFolderFsPath , message . expert , message . text )
20822108 await this . loadExperts ( )
20832109 } catch ( error ) {
20842110 console . error ( `Failed to delete document link for expert ${ message . expert } :` , error )
@@ -2089,7 +2115,7 @@ Commit message:`
20892115 case "addDocumentLink" :
20902116 if ( message . text && message . expert ) {
20912117 try {
2092- await this . expertManager . addDocumentLink ( this . vsCodeWorkSpaceFolderFsPath , message . expert , message . text )
2118+ await expertManager . addDocumentLink ( this . vsCodeWorkSpaceFolderFsPath , message . expert , message . text )
20932119 await this . loadExperts ( )
20942120 } catch ( error ) {
20952121 console . error ( `Failed to add document link for expert ${ message . expert } :` , error )
@@ -2280,30 +2306,35 @@ Commit message:`
22802306 }
22812307
22822308 async loadExperts ( ) {
2283- const experts = await this . expertManager . readExperts ( this . vsCodeWorkSpaceFolderFsPath )
2309+ const expertManager = await this . getExpertManager ( )
2310+ const { experts, selectedExpert } = await expertManager . readExperts ( this . vsCodeWorkSpaceFolderFsPath )
22842311 await this . postMessageToWebview ( {
22852312 type : "expertsUpdated" ,
22862313 experts,
2314+ selectedExpert,
22872315 } )
22882316 }
22892317
22902318 async loadDefaultExperts ( ) {
2291- const experts = await this . expertManager . loadDefaultExperts ( )
2319+ const expertManager = await this . getExpertManager ( )
2320+ const { experts, selectedExpert } = await expertManager . loadDefaultExperts ( )
22922321 await this . postMessageToWebview ( {
22932322 type : "defaultExpertsLoaded" ,
22942323 experts,
2324+ selectedExpert,
22952325 } )
22962326 }
22972327
22982328 private async getExpertDocumentsContent ( expertName : string ) : Promise < string > {
2299- const expertPath = await this . expertManager . getExpertPromptPath ( this . vsCodeWorkSpaceFolderFsPath , expertName )
2329+ const expertManager = await this . getExpertManager ( )
2330+ const expertPath = await expertManager . getExpertPromptPath ( this . vsCodeWorkSpaceFolderFsPath , expertName )
23002331
23012332 if ( ! expertPath ) {
23022333 return ""
23032334 }
23042335
2305- const docsDir = path . join ( path . dirname ( expertPath ) , ExpertManager . DOCS_DIR )
2306- const statusFilePath = path . join ( docsDir , ExpertManager . STATUS_FILE )
2336+ const docsDir = path . join ( path . dirname ( expertPath ) , ExpertFileManager . DOCS_DIR )
2337+ const statusFilePath = path . join ( docsDir , ExpertFileManager . STATUS_FILE )
23072338
23082339 if ( ! ( await fileExistsAtPath ( statusFilePath ) ) ) {
23092340 return ""
0 commit comments