Skip to content

Commit 781c6ee

Browse files
magesh-presidioanand-presidio
authored andcommitted
feat: experts document index (#165)
1 parent b2e55a8 commit 781c6ee

File tree

27 files changed

+1975
-439
lines changed

27 files changed

+1975
-439
lines changed

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
POST_HOG_HOST: ${{ secrets.POST_HOG_API_URL }}
8989
run: |
9090
# Required to generate the .vsix
91-
vsce package --out "hai-build-code-generator-${{ steps.get_version.outputs.version }}.vsix"
91+
vsce package --out "hai-build-code-generator-${{ steps.get_version.outputs.version }}.vsix" --allow-package-secrets sendgrid
9292
9393
if [ "${{ github.event.inputs.release-type }}" = "pre-release" ]; then
9494
npm run publish:marketplace:prerelease

.github/workflows/release-dev.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
6464
# Build the VSIX package
6565
echo "Output Package Name: $PACKAGE_NAME-$BUILD_VERSION.vsix"
66-
npx @vscode/vsce package --out "$PACKAGE_NAME-$BUILD_VERSION.vsix"
66+
npx @vscode/vsce package --out "$PACKAGE_NAME-$BUILD_VERSION.vsix" --allow-package-secrets sendgrid
6767
env:
6868
LANGFUSE_API_URL: ${{ secrets.LANGFUSE_API_URL }}
6969
LANGFUSE_API_KEY: ${{ secrets.LANGFUSE_API_KEY }}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@
171171
{
172172
"command": "hai.expertsButtonClicked",
173173
"title": "Experts",
174-
"icon": "$(gist)",
174+
"icon": "$(robot)",
175175
"category": "HAI Build"
176176
}
177177
],
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export const customToolUseNames = ["find_relevant_files", "code_security_scan"]
1+
export const customToolUseNames = ["find_relevant_files", "code_security_scan", "custom_expert_context"]
22

3-
export const customToolParamNames = ["task"]
3+
export const customToolParamNames = ["task", "query", "expertName"]

src/core/controller/index.ts

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import { isLocalMcp, getLocalMcpDetails, getLocalMcp, getAllLocalMcps } from "@u
7676
import { getStarCount } from "../../services/github/github"
7777
import { openFile } from "@integrations/misc/open-file"
7878
import { posthogClientProvider } from "@/services/posthog/PostHogClientProvider"
79+
import { ExpertFileManager } from "../experts/ExpertFileManager"
7980

8081
/*
8182
https://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

Comments
 (0)