fix(rag): Resolve RAG test failures and race conditions
- Fixed circular import in chromadb by using lazy imports in ag_engine.py. - Moved RAG engine initialization to background threads in AppController to avoid blocking UI. - Added _rag_engine_lock to prevent race conditions during engine re-initialization. - Updated Gemini embedding model to gemini-embedding-001 (available) from ext-embedding-004 (not found). - Fixed _rebuild_rag_index to use fresh ag_engine instance from self in every iteration. - Optimized est_rag_phase4_final_verify.py and est_rag_phase4_stress.py to wait for RAG sync before continuing. - Added dummy embedding fallback in LocalEmbeddingProvider if sentence-transformers fails to load.
This commit is contained in:
+33
-14
@@ -1,4 +1,3 @@
|
||||
import chromadb
|
||||
import copy
|
||||
import inspect
|
||||
import json
|
||||
@@ -750,6 +749,7 @@ class AppController:
|
||||
self._pending_gui_tasks_lock: threading.Lock = threading.Lock()
|
||||
self._pending_dialog_lock: threading.Lock = threading.Lock()
|
||||
self._api_event_queue_lock: threading.Lock = threading.Lock()
|
||||
self._rag_engine_lock: threading.Lock = threading.Lock()
|
||||
|
||||
# --- Internal State ---
|
||||
self._ai_status: str = "idle"
|
||||
@@ -1186,6 +1186,31 @@ class AppController:
|
||||
from src import summarize
|
||||
return summarize._summary_cache
|
||||
|
||||
@property
|
||||
def rag_enabled(self) -> bool:
|
||||
return self.rag_config.enabled if self.rag_config else False
|
||||
def _sync_rag_engine(self):
|
||||
"""
|
||||
Re-initializes the RAG engine in a background thread to avoid blocking the UI.
|
||||
"""
|
||||
self._set_rag_status("initializing...")
|
||||
def _task():
|
||||
try:
|
||||
from src import rag_engine
|
||||
engine = rag_engine.RAGEngine(self.rag_config, self.active_project_root)
|
||||
with self._rag_engine_lock:
|
||||
self.rag_engine = engine
|
||||
self._set_rag_status("ready")
|
||||
# If the engine is empty and we have files, trigger indexing
|
||||
if self.rag_engine and self.rag_engine.is_empty() and self.files:
|
||||
self._rebuild_rag_index()
|
||||
except Exception as e:
|
||||
self._set_rag_status(f"error: {e}")
|
||||
sys.stderr.write(f"[DEBUG RAG] Failed to sync engine: {e}\n")
|
||||
sys.stderr.flush()
|
||||
|
||||
threading.Thread(target=_task, daemon=True).start()
|
||||
|
||||
@property
|
||||
def rag_enabled(self) -> bool:
|
||||
return self.rag_config.enabled if self.rag_config else False
|
||||
@@ -1193,8 +1218,7 @@ class AppController:
|
||||
def rag_enabled(self, value: bool) -> None:
|
||||
if self.rag_config:
|
||||
self.rag_config.enabled = value
|
||||
from src import rag_engine
|
||||
self.rag_engine = rag_engine.RAGEngine(self.rag_config, self.active_project_root)
|
||||
self._sync_rag_engine()
|
||||
|
||||
@property
|
||||
def rag_source(self) -> str:
|
||||
@@ -1203,8 +1227,7 @@ class AppController:
|
||||
def rag_source(self, value: str) -> None:
|
||||
if self.rag_config:
|
||||
self.rag_config.vector_store.provider = value
|
||||
from src import rag_engine
|
||||
if self.rag_engine: self.rag_engine = rag_engine.RAGEngine(self.rag_config, self.active_project_root)
|
||||
self._sync_rag_engine()
|
||||
|
||||
@property
|
||||
def rag_emb_provider(self) -> str:
|
||||
@@ -1213,8 +1236,7 @@ class AppController:
|
||||
def rag_emb_provider(self, value: str) -> None:
|
||||
if self.rag_config:
|
||||
self.rag_config.embedding_provider = value
|
||||
from src import rag_engine
|
||||
if self.rag_engine: self.rag_engine = rag_engine.RAGEngine(self.rag_config, self.active_project_root)
|
||||
self._sync_rag_engine()
|
||||
|
||||
@property
|
||||
def rag_chunk_size(self) -> int:
|
||||
@@ -1351,9 +1373,11 @@ class AppController:
|
||||
# 1. Incremental indexing of current files in parallel
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
|
||||
futures = []
|
||||
def do_index(p):
|
||||
if self.rag_engine: self.rag_engine.index_file(p)
|
||||
for f in self.files:
|
||||
path = f.path if hasattr(f, "path") else str(f)
|
||||
futures.append(executor.submit(self.rag_engine.index_file, path))
|
||||
futures.append(executor.submit(do_index, path))
|
||||
concurrent.futures.wait(futures)
|
||||
|
||||
# 2. Cleanup stale entries (files no longer tracked)
|
||||
@@ -1596,12 +1620,7 @@ class AppController:
|
||||
|
||||
self.rag_engine = None
|
||||
if self.rag_config.enabled:
|
||||
def _init_rag_engine():
|
||||
from src import rag_engine
|
||||
self.rag_engine = rag_engine.RAGEngine(self.rag_config, self.active_project_root)
|
||||
if self.rag_engine.is_empty():
|
||||
self._rebuild_rag_index()
|
||||
threading.Thread(target=_init_rag_engine, daemon=True).start()
|
||||
self._sync_rag_engine()
|
||||
|
||||
from src.personas import PersonaManager
|
||||
self.persona_manager = PersonaManager(Path(self.active_project_path).parent if self.active_project_path else None)
|
||||
|
||||
Reference in New Issue
Block a user