Skip to content

Commit 170f5cd

Browse files
feat: Document link for custom experts (#99)
1 parent ae1d060 commit 170f5cd

File tree

14 files changed

+1059
-362
lines changed

14 files changed

+1059
-362
lines changed

.changeset/shy-hats-jump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"hai-build-code-generator": minor
3+
---
4+
5+
Ability to add reference document link for custom experts

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@
447447
"tar": "^7.4.3",
448448
"tree-sitter-wasms": "^0.1.11",
449449
"turndown": "^7.2.0",
450+
"uuid": "^11.1.0",
450451
"watcher": "^2.3.1",
451452
"web-tree-sitter": "^0.22.6",
452453
"zod": "^3.24.2"

src/core/controller/index.ts

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ import { CodeContextErrorMessage, CodeIndexStartMessage } from "../webview/custo
6262
import { CodeContextAdditionAgent } from "../../integrations/code-prep/CodeContextAddition"
6363
import { ICodeIndexProgress } from "../../integrations/code-prep/type"
6464
import { VectorizeCodeAgent } from "../../integrations/code-prep/VectorizeCodeAgent"
65-
import { ExpertData } from "../../../webview-ui/src/types/experts"
65+
import { ExpertData } from "../../shared/experts"
6666
import { buildEmbeddingHandler } from "../../embedding"
6767
import { HaiBuildDefaults } from "../../shared/haiDefaults"
6868
import { deleteFromContextDirectory } from "../../utils/delete-helper"
@@ -114,9 +114,9 @@ export class Controller {
114114
console.error("Failed to cleanup legacy checkpoints:", error)
115115
})
116116

117-
this.expertManager = new ExpertManager()
118117
this.codeIndexAbortController = new AbortController()
119118
this.workspaceId = getWorkspaceID() || ""
119+
this.expertManager = new ExpertManager(this.context, this.workspaceId)
120120
this.isSideBar = isSideBar
121121
this.vsCodeWorkSpaceFolderFsPath = (getWorkspacePath() || "").trim()
122122
if (this.vsCodeWorkSpaceFolderFsPath) {
@@ -779,8 +779,8 @@ export class Controller {
779779
}
780780
break
781781
case "expertPrompt":
782+
const expertName = message.text || ""
782783
if (message.category === "viewExpert") {
783-
const expertName = message.text || ""
784784
if (message.isDefault && message.prompt) {
785785
try {
786786
// Create a unique URI for this expert prompt
@@ -806,39 +806,58 @@ export class Controller {
806806
}
807807
}
808808
} else {
809-
await this.updateExpertPrompt(message.prompt)
809+
await this.updateExpertPrompt(message.prompt, expertName)
810810
}
811-
812811
break
813812
case "saveExpert":
814813
if (message.text) {
815814
const expert = JSON.parse(message.text) as ExpertData
816815
await this.expertManager.saveExpert(this.vsCodeWorkSpaceFolderFsPath, expert)
817-
818-
// Send updated experts list back to webview
819-
const experts = await this.expertManager.readExperts(this.vsCodeWorkSpaceFolderFsPath)
820-
await this.postMessageToWebview({
821-
type: "expertsUpdated",
822-
experts,
823-
})
816+
await this.loadExperts()
824817
}
825818
break
826819
case "deleteExpert":
827820
if (message.text) {
828821
const expertName = message.text
829822
await this.expertManager.deleteExpert(this.vsCodeWorkSpaceFolderFsPath, expertName)
830-
831-
// Send updated experts list back to webview
832-
const experts = await this.expertManager.readExperts(this.vsCodeWorkSpaceFolderFsPath)
833-
await this.postMessageToWebview({
834-
type: "expertsUpdated",
835-
experts,
836-
})
823+
await this.loadExperts()
837824
}
838825
break
839826
case "loadExperts":
840827
await this.loadExperts()
841828
break
829+
case "refreshDocumentLink":
830+
if (message.text && message.expert) {
831+
await this.expertManager.refreshDocumentLink(this.vsCodeWorkSpaceFolderFsPath, message.expert, message.text)
832+
}
833+
await this.loadExperts()
834+
break
835+
case "deleteDocumentLink":
836+
if (message.text && message.expert) {
837+
try {
838+
await this.expertManager.deleteDocumentLink(
839+
this.vsCodeWorkSpaceFolderFsPath,
840+
message.expert,
841+
message.text,
842+
)
843+
await this.loadExperts()
844+
} catch (error) {
845+
console.error(`Failed to delete document link for expert ${message.expert}:`, error)
846+
vscode.window.showErrorMessage(`Failed to delete document link: ${error.message}`)
847+
}
848+
}
849+
break
850+
case "addDocumentLink":
851+
if (message.text && message.expert) {
852+
try {
853+
await this.expertManager.addDocumentLink(this.vsCodeWorkSpaceFolderFsPath, message.expert, message.text)
854+
await this.loadExperts()
855+
} catch (error) {
856+
console.error(`Failed to add document link for expert ${message.expert}:`, error)
857+
vscode.window.showErrorMessage(`Failed to add document link: ${error.message}`)
858+
}
859+
}
860+
break
842861
case "onHaiConfigure":
843862
const isConfigureEnabled = message.bool !== undefined ? message.bool : true
844863

@@ -2516,12 +2535,21 @@ Here is the project's README to help you get started:\n\n${mcpDetails.readmeCont
25162535
}
25172536
}
25182537

2519-
async updateExpertPrompt(prompt?: string) {
2520-
// User may be clearing the field
2521-
await customUpdateState(this.context, "expertPrompt", prompt || undefined)
2538+
async updateExpertPrompt(prompt?: string, expertName?: string) {
2539+
let additionalContext = ""
2540+
2541+
if (expertName) {
2542+
additionalContext = await this.getExpertDocumentsContent(expertName)
2543+
}
2544+
2545+
const updatedPrompt = prompt ? `${prompt}${additionalContext}` : additionalContext
2546+
2547+
await customUpdateState(this.context, "expertPrompt", updatedPrompt || undefined)
2548+
25222549
if (this.task) {
2523-
this.task.expertPrompt = prompt || undefined
2550+
this.task.expertPrompt = updatedPrompt || undefined
25242551
}
2552+
25252553
await this.postStateToWebview()
25262554
}
25272555

@@ -2541,4 +2569,35 @@ Here is the project's README to help you get started:\n\n${mcpDetails.readmeCont
25412569
experts,
25422570
})
25432571
}
2572+
2573+
private async getExpertDocumentsContent(expertName: string): Promise<string> {
2574+
const expertPath = await this.expertManager.getExpertPromptPath(this.vsCodeWorkSpaceFolderFsPath, expertName)
2575+
2576+
if (!expertPath) {
2577+
return ""
2578+
}
2579+
2580+
const docsDir = path.join(path.dirname(expertPath), ExpertManager.DOCS_DIR)
2581+
const statusFilePath = path.join(docsDir, ExpertManager.STATUS_FILE)
2582+
2583+
if (!(await fileExistsAtPath(statusFilePath))) {
2584+
return ""
2585+
}
2586+
2587+
const statusData = JSON.parse(await fs.readFile(statusFilePath, "utf-8"))
2588+
let additionalContext = ""
2589+
let documentCounter = 1
2590+
for (const document of statusData) {
2591+
if (document.status === "completed" && document.filename) {
2592+
const docFilePath = path.join(docsDir, document.filename)
2593+
if (await fileExistsAtPath(docFilePath)) {
2594+
const docContent = await fs.readFile(docFilePath, "utf-8")
2595+
additionalContext += `\n\n### Document-${documentCounter} Reference\n${docContent}`
2596+
documentCounter++
2597+
}
2598+
}
2599+
}
2600+
2601+
return additionalContext
2602+
}
25442603
}

0 commit comments

Comments
 (0)