Skip to content

Commit fcd0426

Browse files
fix: LLM validation hangs on welcome state (#176)
1 parent 04f09cb commit fcd0426

File tree

7 files changed

+81
-9
lines changed

7 files changed

+81
-9
lines changed

.changeset/three-numbers-cough.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": patch
3+
---
4+
5+
Resolved an issue where LLM validation could become stuck in the welcome state, preventing further progress.

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: "Release"
33
on:
44
push:
55
branches:
6-
- release
6+
- main
77
workflow_dispatch:
88

99
permissions:

src/core/controller/index.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,29 @@ export class Controller {
158158
// TAG:HAI
159159
private async getExpertManager(): Promise<ExpertManager> {
160160
if (!this.expertManager) {
161-
const { embeddingConfiguration } = await getAllExtensionState(this.context, this.workspaceId)
162-
this.expertManager = new ExpertManager(this.context, this.workspaceId, embeddingConfiguration)
161+
this.expertManager = new ExpertManager(this.context, this.workspaceId)
163162
}
164163
return this.expertManager
165164
}
166165

166+
/**
167+
* Initialize embeddings in ExpertManager
168+
*/
169+
public async initializeExpertManagerEmbeddings(): Promise<void> {
170+
if (!this.expertManager) {
171+
this.expertManager = new ExpertManager(this.context, this.workspaceId)
172+
}
173+
const { embeddingConfiguration } = await getAllExtensionState(this.context, this.workspaceId)
174+
const embeddingHandler = buildEmbeddingHandler({
175+
...embeddingConfiguration,
176+
maxRetries: 0,
177+
})
178+
const isEmbeddingValid = await embeddingHandler.validateAPIKey()
179+
if (isEmbeddingValid) {
180+
this.expertManager.initializeEmbeddings(embeddingConfiguration)
181+
}
182+
}
183+
167184
/*
168185
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.
169186
- https://vscode-docs.readthedocs.io/en/stable/extensions/patterns-and-principles/

src/core/experts/ExpertManager.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,29 @@ export class ExpertManager {
2121
private workspaceId: string
2222
private fileManager: ExpertFileManager
2323
private documentProcessor: DocumentProcessor
24-
private vectorStoreManager: VectorStoreManager
24+
private vectorStoreManager?: VectorStoreManager
2525

2626
/**
2727
* Create a new ExpertManager
2828
*/
29-
constructor(extensionContext: vscode.ExtensionContext, workspaceId: string, embeddingConfig: EmbeddingConfiguration) {
29+
constructor(extensionContext: vscode.ExtensionContext, workspaceId: string) {
3030
this.extensionContext = extensionContext
3131
this.workspaceId = workspaceId
3232
this.fileManager = new ExpertFileManager()
3333
this.documentProcessor = new DocumentProcessor(extensionContext, workspaceId)
3434

35-
// Initialize embedding client and vector store manager
35+
// No embedding initialization here
36+
}
37+
38+
/**
39+
* Initialize embedding client and vector store manager
40+
*/
41+
public initializeEmbeddings(embeddingConfig: EmbeddingConfiguration): void {
3642
const embeddings = VectorStoreManager.initializeEmbeddings(embeddingConfig)
3743
this.vectorStoreManager = new VectorStoreManager({
3844
embeddings,
3945
embeddingConfig,
40-
workspaceId,
46+
workspaceId: this.workspaceId,
4147
})
4248

4349
this.connectProcessorToVectorStore()
@@ -134,6 +140,9 @@ export class ExpertManager {
134140
suburl: string,
135141
title?: string,
136142
): Promise<void> => {
143+
if (!this.vectorStoreManager) {
144+
throw new Error("Vector store manager not initialized. Please initialize embeddings first.")
145+
}
137146
await this.vectorStoreManager.chunkAndStore({
138147
markdown,
139148
expertName,
@@ -165,6 +174,9 @@ export class ExpertManager {
165174

166175
if (isDeepCrawl) {
167176
// For deepcrawl experts, delete chunks and re-crawl
177+
if (!this.vectorStoreManager) {
178+
throw new Error("Vector store manager not initialized. Please initialize embeddings first.")
179+
}
168180
await this.vectorStoreManager.deleteChunk(linkUrl, expertName, workspacePath)
169181
await this.documentProcessor.crawlAndConvertToMarkdown(
170182
linkUrl,
@@ -321,7 +333,9 @@ export class ExpertManager {
321333
const isDeepCrawl = metadata.deepCrawl || false
322334

323335
// Delete from vector DB regardless (since the URL might have been crawled before)
324-
await this.vectorStoreManager.deleteChunk(linkUrl, expertName, workspacePath)
336+
if (this.vectorStoreManager) {
337+
await this.vectorStoreManager.deleteChunk(linkUrl, expertName, workspacePath)
338+
}
325339

326340
// Update regular status.json if it exists
327341
if (await this.fileManager.readStatusFile(statusFilePath)) {
@@ -783,6 +797,9 @@ export class ExpertManager {
783797
* Search for a query in the expert's vector store
784798
*/
785799
async search(query: string, expertName: string, workspacePath: string, k?: number): Promise<string> {
800+
if (!this.vectorStoreManager) {
801+
throw new Error("Vector store manager not initialized. Please initialize embeddings first.")
802+
}
786803
return this.vectorStoreManager.search(query, expertName, workspacePath, k)
787804
}
788805
}

src/core/task/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4646,7 +4646,8 @@ export class Task {
46464646
this.consecutiveMistakeCount = 0
46474647

46484648
// Create ExpertManager instance and search for the query
4649-
const expertManager = new ExpertManager(this.context, this.taskId, this.embeddingConfiguration)
4649+
const expertManager = new ExpertManager(this.context, this.taskId)
4650+
expertManager.initializeEmbeddings(this.embeddingConfiguration)
46504651
const searchResults = await expertManager.search(query, expertName, cwd)
46514652

46524653
// Format the complete message with search results

src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ export async function activate(context: vscode.ExtensionContext) {
217217
WebviewProvider.getAllInstances().forEach((instance) => {
218218
const openExperts = async (instance?: WebviewProvider) => {
219219
await instance?.controller.postStateToWebview()
220+
instance?.controller.initializeExpertManagerEmbeddings()
220221
instance?.controller.postMessageToWebview({
221222
type: "action",
222223
action: "expertsButtonClicked",

webview-ui/src/components/experts/ExpertsView.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,37 @@ const ExpertsView: React.FC<ExpertsViewProps> = ({ onDone }) => {
735735
/>
736736
<p className="description-text">Sets the crawl timeout for each page.</p>
737737
</FormGroup>
738+
{deepCrawl && (
739+
<div
740+
className="info-message"
741+
style={{
742+
display: "flex",
743+
alignItems: "flex-start",
744+
gap: "8px",
745+
color: "var(--vscode-foreground)",
746+
fontSize: "12px",
747+
padding: "8px",
748+
backgroundColor: "var(--vscode-editorWidget-background)",
749+
border: "1px solid var(--vscode-widget-border)",
750+
borderRadius: "4px",
751+
marginBottom: "16px",
752+
}}>
753+
<i
754+
className="codicon codicon-info"
755+
style={{
756+
fontSize: "14px",
757+
marginTop: "2px",
758+
color: "var(--vscode-textLink-foreground)",
759+
}}
760+
/>
761+
<span>
762+
Important: If you change the embedding configuration, any experts with DeepCrawl
763+
enabled must be deleted and recreated using the updated settings. Experts rely on
764+
a consistent embedding setup — using different configurations can prevent them
765+
from functioning properly.
766+
</span>
767+
</div>
768+
)}
738769
</>
739770
)}
740771
{!isEmbeddingValid && (

0 commit comments

Comments
 (0)