knowledge-rag 4.3.1__tar.gz → 4.4.0__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.3.1 → knowledge_rag-4.4.0}/PKG-INFO +16 -1
  2. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/README.md +15 -0
  3. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/__init__.py +1 -1
  4. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/server.py +26 -2
  5. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/pyproject.toml +1 -1
  6. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/.gitignore +0 -0
  7. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/LICENSE +0 -0
  8. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/config.example.yaml +0 -0
  9. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/config.py +0 -0
  10. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/guarded.py +0 -0
  11. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/ingestion.py +0 -0
  12. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/instance_lock.py +0 -0
  13. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/metrics.py +0 -0
  14. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/preflight.py +0 -0
  15. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/mcp_server/ratelimit.py +0 -0
  16. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/npm/README.md +0 -0
  17. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/presets/cybersecurity.yaml +0 -0
  18. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/presets/developer.yaml +0 -0
  19. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/presets/general.yaml +0 -0
  20. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/presets/research.yaml +0 -0
  21. {knowledge_rag-4.3.1 → knowledge_rag-4.4.0}/requirements.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: knowledge-rag
3
- Version: 4.3.1
3
+ Version: 4.4.0
4
4
  Summary: Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 13 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
@@ -1449,6 +1449,21 @@ Common issues:
1449
1449
 
1450
1450
  ### Unreleased
1451
1451
 
1452
+ ### v4.4.0 (2026-07-06) — Cross-Platform Installer & Hybrid Search Category Filter
1453
+
1454
+ - **NEW**: Cross-platform, multi-LLM-client installer (`install.py`) driving both `install.sh` (Linux/macOS) and `install.ps1` (Windows) as thin wrappers. One codebase, one behavior across every OS.
1455
+ - **NEW**: Auto-detects and registers `knowledge-rag` in 8 LLM clients — Claude Code, Claude Desktop, Cursor, Windsurf, VS Code (Copilot Chat), Cline, Gemini CLI, Zed — writing to each tool's canonical config path with the correct JSON schema per client (VS Code uses `servers`, Zed uses `context_servers`, everyone else uses `mcpServers`).
1456
+ - **NEW**: `--for <clients>` / `--exclude <clients>` opt-in/opt-out selection, `--dry-run` preview, `--list-clients` registry inspection, `--pypi-version <ver>` pinning, `--skip-init` / `--skip-model` for fast reruns. See `python install.py --help`.
1457
+ - **FIX**: `install.ps1` no longer writes MCP config to `~/.claude/mcp.json` (a stale secondary path); it now targets `~/.claude.json` — the file Claude Code actually reads — via idempotent JSON merge that preserves every existing MCP server entry with an automatic `.knowledge-rag.bak` backup.
1458
+ - **FIX**: `install.ps1` gains PyPI mode (`pip install knowledge-rag`) and runs `mcp_server.server init` on install — feature parity with `install.sh`.
1459
+ - **FIX**: MCP server spec no longer uses the fragile `cmd /c cd /d ... && python ...` wrapper on Windows; it emits the standard `command` + `cwd` shape supported natively by every modern client.
1460
+ - **FIX**: `install.sh` guards against `sh install.sh` (bash-only features now emit a clear error instead of a cryptic syntax failure).
1461
+ - **FIX**: Both scripts now correctly advertise **13 MCP tools** (was outdated at 12; `get_reindex_status` shipped in v4.3.0).
1462
+ - **FIX**: Windows-side `install.ps1` prefers `winget install Python.Python.3.12 --scope user` (no admin), falls back to python.org 3.12.7 (was pinned to 3.12.0).
1463
+ - **FIX**: Hybrid search now applies the active category filter to BM25 results before RRF fusion, preventing keyword-only BM25 hits from other categories from leaking into filtered searches. Both leak paths are closed: BM25 candidates are metadata-filtered before RRF (with `top_k` widened to `max_results * 20` to compensate for post-filter drop), and the fallback fetch during fusion re-checks `category` before adding a chunk to `combined_scores`. Note: the `category_filter` guard now also applies to the keyword-routed category — `_route_by_keywords()`-inferred routing filters BM25 too, consistent with the semantic branch. Users with warm `query_cache` entries should restart the server to invalidate stale results. (#109, thanks @Hohlas)
1464
+ - **TEST**: New `tests/test_installer_no_data_loss.py` (22 tests) locks in the installer's zero-data-loss contract across all three JSON schemas (`mcpServers` / `servers` / `context_servers`): top-level keys preserved, sibling MCP servers byte-identical, `.knowledge-rag.bak` backup written before every mutation, idempotent second run, `--dry-run` writes nothing, atomic `os.replace` write. Baseline: 231 → 266.
1465
+ - **TEST**: New `TestHybridCategoryFilter::test_bm25_results_respect_category_filter` in `tests/test_search.py` — deterministic regression covering BM25-only hits with mixed categories. Baseline: 266 → 267.
1466
+
1452
1467
  ### v4.3.1 (2026-06-22) — Hybrid Search Fixes
1453
1468
 
1454
1469
  - **FIX**: Accept `"general"` as a valid category in `search_knowledge`. The parser hardcodes `"general"` as the fallback in `_detect_category` (`ingestion.py`), but the validator only built `valid_categories` from `config.keyword_routes` + `config.category_mappings.values()` — so users who customized `config.yaml` and dropped the default `"general": "general"` mapping hit `Invalid category` even though the index contained `general` documents. Validator now always tolerates `"general"`. (#98, thanks @Hohlas)
@@ -1401,6 +1401,21 @@ Common issues:
1401
1401
 
1402
1402
  ### Unreleased
1403
1403
 
1404
+ ### v4.4.0 (2026-07-06) — Cross-Platform Installer & Hybrid Search Category Filter
1405
+
1406
+ - **NEW**: Cross-platform, multi-LLM-client installer (`install.py`) driving both `install.sh` (Linux/macOS) and `install.ps1` (Windows) as thin wrappers. One codebase, one behavior across every OS.
1407
+ - **NEW**: Auto-detects and registers `knowledge-rag` in 8 LLM clients — Claude Code, Claude Desktop, Cursor, Windsurf, VS Code (Copilot Chat), Cline, Gemini CLI, Zed — writing to each tool's canonical config path with the correct JSON schema per client (VS Code uses `servers`, Zed uses `context_servers`, everyone else uses `mcpServers`).
1408
+ - **NEW**: `--for <clients>` / `--exclude <clients>` opt-in/opt-out selection, `--dry-run` preview, `--list-clients` registry inspection, `--pypi-version <ver>` pinning, `--skip-init` / `--skip-model` for fast reruns. See `python install.py --help`.
1409
+ - **FIX**: `install.ps1` no longer writes MCP config to `~/.claude/mcp.json` (a stale secondary path); it now targets `~/.claude.json` — the file Claude Code actually reads — via idempotent JSON merge that preserves every existing MCP server entry with an automatic `.knowledge-rag.bak` backup.
1410
+ - **FIX**: `install.ps1` gains PyPI mode (`pip install knowledge-rag`) and runs `mcp_server.server init` on install — feature parity with `install.sh`.
1411
+ - **FIX**: MCP server spec no longer uses the fragile `cmd /c cd /d ... && python ...` wrapper on Windows; it emits the standard `command` + `cwd` shape supported natively by every modern client.
1412
+ - **FIX**: `install.sh` guards against `sh install.sh` (bash-only features now emit a clear error instead of a cryptic syntax failure).
1413
+ - **FIX**: Both scripts now correctly advertise **13 MCP tools** (was outdated at 12; `get_reindex_status` shipped in v4.3.0).
1414
+ - **FIX**: Windows-side `install.ps1` prefers `winget install Python.Python.3.12 --scope user` (no admin), falls back to python.org 3.12.7 (was pinned to 3.12.0).
1415
+ - **FIX**: Hybrid search now applies the active category filter to BM25 results before RRF fusion, preventing keyword-only BM25 hits from other categories from leaking into filtered searches. Both leak paths are closed: BM25 candidates are metadata-filtered before RRF (with `top_k` widened to `max_results * 20` to compensate for post-filter drop), and the fallback fetch during fusion re-checks `category` before adding a chunk to `combined_scores`. Note: the `category_filter` guard now also applies to the keyword-routed category — `_route_by_keywords()`-inferred routing filters BM25 too, consistent with the semantic branch. Users with warm `query_cache` entries should restart the server to invalidate stale results. (#109, thanks @Hohlas)
1416
+ - **TEST**: New `tests/test_installer_no_data_loss.py` (22 tests) locks in the installer's zero-data-loss contract across all three JSON schemas (`mcpServers` / `servers` / `context_servers`): top-level keys preserved, sibling MCP servers byte-identical, `.knowledge-rag.bak` backup written before every mutation, idempotent second run, `--dry-run` writes nothing, atomic `os.replace` write. Baseline: 231 → 266.
1417
+ - **TEST**: New `TestHybridCategoryFilter::test_bm25_results_respect_category_filter` in `tests/test_search.py` — deterministic regression covering BM25-only hits with mixed categories. Baseline: 266 → 267.
1418
+
1404
1419
  ### v4.3.1 (2026-06-22) — Hybrid Search Fixes
1405
1420
 
1406
1421
  - **FIX**: Accept `"general"` as a valid category in `search_knowledge`. The parser hardcodes `"general"` as the fallback in `_detect_category` (`ingestion.py`), but the validator only built `valid_categories` from `config.keyword_routes` + `config.category_mappings.values()` — so users who customized `config.yaml` and dropped the default `"general": "general"` mapping hit `Invalid category` even though the index contained `general` documents. Validator now always tolerates `"general"`. (#98, thanks @Hohlas)
@@ -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.3.1"
11
+ __version__ = "4.4.0"
12
12
  __author__ = "Ailton Rocha (Lyon.)"
13
13
 
14
14
  from .config import Config # noqa: E402
@@ -1474,6 +1474,12 @@ class KnowledgeOrchestrator:
1474
1474
  elif routed_category:
1475
1475
  where_filter = {"category": routed_category}
1476
1476
 
1477
+ def _matches_category(metadata: Dict[str, Any]) -> bool:
1478
+ if not where_filter:
1479
+ return True
1480
+ expected_category = where_filter.get("category")
1481
+ return not expected_category or metadata.get("category") == expected_category
1482
+
1477
1483
  # Parallel Semantic + BM25 search (threaded for latency reduction)
1478
1484
  from concurrent.futures import ThreadPoolExecutor
1479
1485
 
@@ -1507,8 +1513,23 @@ class KnowledgeOrchestrator:
1507
1513
  r = {}
1508
1514
  if hybrid_alpha < 1.0:
1509
1515
  try:
1510
- bm25_hits = self.bm25_index.search(query_text, top_k=max_results * 3)
1511
- for rank, (chunk_id, bm25_score) in enumerate(bm25_hits):
1516
+ bm25_top_k = max_results * (20 if where_filter else 3)
1517
+ bm25_hits = self.bm25_index.search(query_text, top_k=bm25_top_k)
1518
+
1519
+ if where_filter:
1520
+ chunk_ids = [chunk_id for chunk_id, _ in bm25_hits]
1521
+ metadata_by_id = {}
1522
+ if chunk_ids:
1523
+ fetched = self.collection.get(ids=chunk_ids, include=["metadatas"])
1524
+ metadata_by_id = dict(zip(fetched.get("ids", []), fetched.get("metadatas", [])))
1525
+
1526
+ bm25_hits = [
1527
+ (chunk_id, bm25_score)
1528
+ for chunk_id, bm25_score in bm25_hits
1529
+ if _matches_category(metadata_by_id.get(chunk_id, {}))
1530
+ ]
1531
+
1532
+ for rank, (chunk_id, bm25_score) in enumerate(bm25_hits[: max_results * 3]):
1512
1533
  r[chunk_id] = {"rank": rank + 1, "bm25_score": bm25_score}
1513
1534
  except Exception as e:
1514
1535
  print(f"[WARN] BM25 search failed: {e}")
@@ -1558,6 +1579,9 @@ class KnowledgeOrchestrator:
1558
1579
  except Exception:
1559
1580
  continue
1560
1581
 
1582
+ if not _matches_category(data.get("metadata", {})):
1583
+ continue
1584
+
1561
1585
  combined_scores[chunk_id] = {
1562
1586
  "rrf_score": combined_rrf,
1563
1587
  "semantic_rank": semantic_rank if chunk_id in semantic_results else None,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "knowledge-rag"
7
- version = "4.3.1"
7
+ version = "4.4.0"
8
8
  description = "Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 13 MCP Tools + 20 Format Parsers. Zero external servers."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes