knowledge-rag 4.1.0__tar.gz → 4.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/PKG-INFO +5 -1
  2. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/README.md +4 -0
  3. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/__init__.py +1 -1
  4. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/server.py +12 -10
  5. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/pyproject.toml +1 -1
  6. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/.gitignore +0 -0
  7. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/LICENSE +0 -0
  8. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/config.example.yaml +0 -0
  9. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/config.py +0 -0
  10. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/guarded.py +0 -0
  11. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/ingestion.py +0 -0
  12. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/instance_lock.py +0 -0
  13. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/metrics.py +0 -0
  14. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/preflight.py +0 -0
  15. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/mcp_server/ratelimit.py +0 -0
  16. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/npm/README.md +0 -0
  17. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/presets/cybersecurity.yaml +0 -0
  18. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/presets/developer.yaml +0 -0
  19. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/presets/general.yaml +0 -0
  20. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/presets/research.yaml +0 -0
  21. {knowledge_rag-4.1.0 → knowledge_rag-4.1.2}/requirements.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: knowledge-rag
3
- Version: 4.1.0
3
+ Version: 4.1.2
4
4
  Summary: Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 12 MCP Tools + 20 Format Parsers. Zero external servers.
5
5
  Project-URL: Homepage, https://github.com/lyonzin/knowledge-rag
6
6
  Project-URL: Repository, https://github.com/lyonzin/knowledge-rag
@@ -1409,6 +1409,10 @@ Common issues:
1409
1409
 
1410
1410
  ### Unreleased
1411
1411
 
1412
+ ### v4.1.1 (2026-06-17)
1413
+
1414
+ - **FIX**: All `_indexed_docs` iterations now use `list()` snapshot, preventing `dictionary changed size during iteration` crash when FileWatcher modifies the index concurrently with MCP tool calls (affects `search_knowledge`, `search_similar`, `update_document`, `remove_document`, `evaluate_retrieval`, `list_categories`, `list_documents`)
1415
+
1412
1416
  ### v4.1.0 (2026-06-17)
1413
1417
 
1414
1418
  - **Added:** `query_expansion_groups` config for symmetric synonym expansion (#92)
@@ -1369,6 +1369,10 @@ Common issues:
1369
1369
 
1370
1370
  ### Unreleased
1371
1371
 
1372
+ ### v4.1.1 (2026-06-17)
1373
+
1374
+ - **FIX**: All `_indexed_docs` iterations now use `list()` snapshot, preventing `dictionary changed size during iteration` crash when FileWatcher modifies the index concurrently with MCP tool calls (affects `search_knowledge`, `search_similar`, `update_document`, `remove_document`, `evaluate_retrieval`, `list_categories`, `list_documents`)
1375
+
1372
1376
  ### v4.1.0 (2026-06-17)
1373
1377
 
1374
1378
  - **Added:** `query_expansion_groups` config for symmetric synonym expansion (#92)
@@ -8,7 +8,7 @@ import sys # noqa: I001
8
8
  _original_stdout = sys.stdout
9
9
  sys.stdout = sys.stderr
10
10
 
11
- __version__ = "4.1.0"
11
+ __version__ = "4.1.2"
12
12
  __author__ = "Ailton Rocha (Lyon.)"
13
13
 
14
14
  from .config import Config # noqa: E402
@@ -836,7 +836,9 @@ class DocumentWatcher(FileSystemEventHandler):
836
836
  f"{stats['updated']} updated, {stats['deleted']} deleted"
837
837
  )
838
838
  except Exception as e:
839
- print(f"[WATCHER] Reindex failed: {e}")
839
+ import traceback as _tb
840
+
841
+ print(f"[WATCHER] Reindex failed: {e}\n{_tb.format_exc()}")
840
842
  finally:
841
843
  self._reindex_lock.release()
842
844
 
@@ -1050,7 +1052,7 @@ class KnowledgeOrchestrator:
1050
1052
  print(f"[INDEX] Scanning {stats['total_files']} documents...")
1051
1053
 
1052
1054
  path_to_docid: Dict[str, str] = {}
1053
- for doc_id, info in self._indexed_docs.items():
1055
+ for doc_id, info in list(self._indexed_docs.items()):
1054
1056
  path_to_docid[info.get("source", "")] = doc_id
1055
1057
 
1056
1058
  current_paths = {str(doc.source) for doc in documents}
@@ -1516,7 +1518,7 @@ class KnowledgeOrchestrator:
1516
1518
 
1517
1519
  # Find the doc_id from metadata lookup
1518
1520
  doc_id = None
1519
- for did, info in self._indexed_docs.items():
1521
+ for did, info in list(self._indexed_docs.items()):
1520
1522
  stored = str(Path(info.get("source", "")).resolve())
1521
1523
  if stored == str(Path(source).resolve()):
1522
1524
  doc_id = did
@@ -1709,7 +1711,7 @@ class KnowledgeOrchestrator:
1709
1711
  filepath_resolved = str(filepath.resolve())
1710
1712
 
1711
1713
  doc_id = None
1712
- for did, info in self._indexed_docs.items():
1714
+ for did, info in list(self._indexed_docs.items()):
1713
1715
  stored = str(Path(info.get("source", "")).resolve())
1714
1716
  if stored == filepath_resolved:
1715
1717
  doc_id = did
@@ -1763,7 +1765,7 @@ class KnowledgeOrchestrator:
1763
1765
  filepath_resolved = str(Path(filepath).resolve())
1764
1766
 
1765
1767
  doc_id = None
1766
- for did, info in self._indexed_docs.items():
1768
+ for did, info in list(self._indexed_docs.items()):
1767
1769
  stored = str(Path(info.get("source", "")).resolve())
1768
1770
  if stored == filepath_resolved:
1769
1771
  doc_id = did
@@ -1824,7 +1826,7 @@ class KnowledgeOrchestrator:
1824
1826
  filepath_resolved = str(Path(filepath).resolve())
1825
1827
 
1826
1828
  doc_id = None
1827
- for did, info in self._indexed_docs.items():
1829
+ for did, info in list(self._indexed_docs.items()):
1828
1830
  stored = str(Path(info.get("source", "")).resolve())
1829
1831
  if stored == filepath_resolved:
1830
1832
  doc_id = did
@@ -1936,7 +1938,7 @@ class KnowledgeOrchestrator:
1936
1938
  def list_categories(self) -> Dict[str, int]:
1937
1939
  """List all categories with document counts"""
1938
1940
  categories = {}
1939
- for doc_info in self._indexed_docs.values():
1941
+ for doc_info in list(self._indexed_docs.values()):
1940
1942
  cat = doc_info.get("category", "unknown")
1941
1943
  categories[cat] = categories.get(cat, 0) + 1
1942
1944
  return categories
@@ -1944,7 +1946,7 @@ class KnowledgeOrchestrator:
1944
1946
  def list_documents(self, category: Optional[str] = None) -> List[Dict[str, str]]:
1945
1947
  """List all indexed documents, optionally filtered by category"""
1946
1948
  docs = []
1947
- for doc_id, info in self._indexed_docs.items():
1949
+ for doc_id, info in list(self._indexed_docs.items()):
1948
1950
  if category and info.get("category") != category:
1949
1951
  continue
1950
1952
  docs.append(
@@ -1986,7 +1988,8 @@ class KnowledgeOrchestrator:
1986
1988
  def _save_metadata(self) -> None:
1987
1989
  """Save index metadata to disk"""
1988
1990
  self._metadata_file.parent.mkdir(parents=True, exist_ok=True)
1989
- self._metadata_file.write_text(json.dumps(self._indexed_docs, indent=2, ensure_ascii=False), encoding="utf-8")
1991
+ snapshot = dict(self._indexed_docs)
1992
+ self._metadata_file.write_text(json.dumps(snapshot, indent=2, ensure_ascii=False), encoding="utf-8")
1990
1993
 
1991
1994
 
1992
1995
  # =============================================================================
@@ -2445,7 +2448,6 @@ def evaluate_retrieval(test_cases: str) -> str:
2445
2448
 
2446
2449
  orchestrator = get_orchestrator()
2447
2450
  results = orchestrator.evaluate_retrieval(cases)
2448
-
2449
2451
  return json.dumps({"status": "success", **results}, indent=2)
2450
2452
 
2451
2453
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "knowledge-rag"
7
- version = "4.1.0"
7
+ version = "4.1.2"
8
8
  description = "Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 12 MCP Tools + 20 Format Parsers. Zero external servers."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes