knowledge-rag 3.3.2__tar.gz → 3.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.
@@ -28,6 +28,7 @@ documents/**/*.csv
28
28
 
29
29
  # FastEmbed model cache
30
30
  .cache/
31
+ models_cache/
31
32
  *.onnx
32
33
 
33
34
  # Local scripts (not part of distribution)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: knowledge-rag
3
- Version: 3.3.2
3
+ Version: 3.4.0
4
4
  Summary: Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 12 MCP Tools. 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
@@ -38,7 +38,7 @@ Description-Content-Type: text/markdown
38
38
 
39
39
  <div align="center">
40
40
 
41
- ![Version](https://img.shields.io/badge/version-3.3.2-blue.svg)
41
+ ![Version](https://img.shields.io/badge/version-3.4.0-blue.svg)
42
42
  ![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12-green.svg)
43
43
  ![License](https://img.shields.io/badge/license-MIT-yellow.svg)
44
44
  ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)
@@ -61,7 +61,7 @@ Your documents become instantly searchable inside Claude Code — with reranking
61
61
 
62
62
  **12 MCP Tools** | **Hybrid Search + Cross-Encoder Reranking** | **Markdown-Aware Chunking** | **100% Local, Zero Cloud**
63
63
 
64
- [What's New](#whats-new-in-v330) | [Installation](#installation) | [Configuration](#configuration) | [API Reference](#api-reference) | [Architecture](#architecture)
64
+ [What's New](#whats-new-in-v340) | [Installation](#installation) | [Configuration](#configuration) | [API Reference](#api-reference) | [Architecture](#architecture)
65
65
 
66
66
  </div>
67
67
 
@@ -108,6 +108,40 @@ After the initial rebuild, startup and queries are faster than v2.x because ther
108
108
 
109
109
  ---
110
110
 
111
+ ## What's New in v3.4.0
112
+
113
+ ### Persistent Model Cache
114
+ Embedding models (~250MB) are now stored in `models_cache/` instead of `/tmp`. No more re-downloading after system reboots on Linux. Configurable via `paths.models_cache_dir` in config.yaml.
115
+
116
+ ### Exclude Patterns
117
+ Skip files and directories during indexing with glob patterns. Configure under `documents.exclude_patterns` in config.yaml:
118
+ ```yaml
119
+ documents:
120
+ exclude_patterns:
121
+ - "node_modules"
122
+ - ".venv"
123
+ - "__pycache__"
124
+ - ".git"
125
+ - "*.tmp"
126
+ ```
127
+ Patterns match against both full relative paths and individual path components — `"node_modules"` excludes it at any depth.
128
+
129
+ ### Jupyter Notebook Support (.ipynb)
130
+ Native parser extracts only markdown and code cell sources — no outputs, no execution counts, no base64-encoded images. Clean content for high-quality retrieval. Added to default supported formats.
131
+
132
+ ### MCP Protocol Stability
133
+ `stdout` is redirected to `stderr` before the MCP server starts. Prevents random library `print()` calls from corrupting the JSON-RPC stream — fixes "Failed to connect" errors in VS Code and IDE integrations.
134
+
135
+ ### File Watcher Resilience (Linux)
136
+ Server no longer crashes when system inotify limits are reached. Falls back gracefully to manual indexing with a clear warning message.
137
+
138
+ ### MetaTrader Support (.mq4, .mqh)
139
+ MQL4/MQL5 source files can now be indexed as code. Not enabled by default — add `.mq4` and `.mqh` to your `supported_formats` list to activate.
140
+
141
+ *Community credit: Features inspired by ideas from [@Hohlas](https://github.com/Hohlas) in [PR #18](https://github.com/lyonzin/knowledge-rag/pull/18).*
142
+
143
+ ---
144
+
111
145
  ## What's New in v3.3.0
112
146
 
113
147
  ### YAML Configuration System
@@ -966,6 +1000,7 @@ Pre-built configurations for common use cases. Each preset is a complete `config
966
1000
  |-------|---------|-------------|
967
1001
  | `paths.documents_dir` | `./documents` | Root folder scanned recursively for documents |
968
1002
  | `paths.data_dir` | `./data` | Internal storage for ChromaDB and index metadata |
1003
+ | `paths.models_cache_dir` | `./models_cache` | Persistent cache for embedding models (~250MB). Prevents re-download after reboots |
969
1004
 
970
1005
  Relative paths resolve from the project root. Absolute paths work too. The `KNOWLEDGE_RAG_DIR` environment variable overrides the project root.
971
1006
 
@@ -973,7 +1008,8 @@ Relative paths resolve from the project root. Absolute paths work too. The `KNOW
973
1008
 
974
1009
  | Field | Default | Description |
975
1010
  |-------|---------|-------------|
976
- | `documents.supported_formats` | .md .txt .pdf .py .json .docx .xlsx .pptx .csv | File extensions to index |
1011
+ | `documents.supported_formats` | .md .txt .pdf .py .json .docx .xlsx .pptx .csv .ipynb | File extensions to index |
1012
+ | `documents.exclude_patterns` | `[]` (empty) | Glob patterns for files/dirs to skip during indexing |
977
1013
  | `documents.chunking.chunk_size` | 1000 | Max characters per chunk |
978
1014
  | `documents.chunking.chunk_overlap` | 200 | Characters shared between consecutive chunks |
979
1015
 
@@ -1090,7 +1126,8 @@ knowledge-rag/
1090
1126
  ├── data/
1091
1127
  │ ├── chroma_db/ # ChromaDB vector database
1092
1128
  │ └── index_metadata.json # Incremental indexing state
1093
- ├── tests/ # Test suite (55 tests)
1129
+ ├── models_cache/ # Persistent embedding model cache
1130
+ ├── tests/ # Test suite (70+ tests)
1094
1131
  ├── venv/ # Python virtual environment
1095
1132
  ├── requirements.txt # Python dependencies
1096
1133
  ├── LICENSE # MIT License
@@ -1195,6 +1232,18 @@ With ~200 documents, expect ~300-500MB RAM. The embedding model (~50MB) and rera
1195
1232
 
1196
1233
  ## Changelog
1197
1234
 
1235
+ ### v3.4.0 (2026-04-16)
1236
+
1237
+ - **NEW**: `models_cache_dir` — persistent embedding model cache, prevents re-download after reboots
1238
+ - **NEW**: `exclude_patterns` — glob-based file/directory exclusion during indexing (under `documents:` section)
1239
+ - **NEW**: Jupyter Notebook (.ipynb) parser — extracts markdown and code cell sources only, ignores outputs and base64
1240
+ - **NEW**: MCP stdout protection — redirects stdout to stderr before server start, fixes "Failed to connect" errors
1241
+ - **NEW**: File watcher resilience — graceful fallback when Linux inotify limits are reached
1242
+ - **NEW**: MetaTrader (.mq4, .mqh) support — opt-in code parsing for MQL4/MQL5 files
1243
+ - **NEW**: 23 new tests (exclude patterns, ipynb parser, stdout protection)
1244
+ - **IMPROVED**: All 4 presets updated with new config fields
1245
+ - Community credit: [@Hohlas](https://github.com/Hohlas) ([PR #18](https://github.com/lyonzin/knowledge-rag/pull/18))
1246
+
1198
1247
  ### v3.3.2 (2026-04-06)
1199
1248
 
1200
1249
  - **FIX**: Full type validation on all YAML config values — wrong types warn and fall back to defaults
@@ -2,7 +2,7 @@
2
2
 
3
3
  <div align="center">
4
4
 
5
- ![Version](https://img.shields.io/badge/version-3.3.2-blue.svg)
5
+ ![Version](https://img.shields.io/badge/version-3.4.0-blue.svg)
6
6
  ![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12-green.svg)
7
7
  ![License](https://img.shields.io/badge/license-MIT-yellow.svg)
8
8
  ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)
@@ -25,7 +25,7 @@ Your documents become instantly searchable inside Claude Code — with reranking
25
25
 
26
26
  **12 MCP Tools** | **Hybrid Search + Cross-Encoder Reranking** | **Markdown-Aware Chunking** | **100% Local, Zero Cloud**
27
27
 
28
- [What's New](#whats-new-in-v330) | [Installation](#installation) | [Configuration](#configuration) | [API Reference](#api-reference) | [Architecture](#architecture)
28
+ [What's New](#whats-new-in-v340) | [Installation](#installation) | [Configuration](#configuration) | [API Reference](#api-reference) | [Architecture](#architecture)
29
29
 
30
30
  </div>
31
31
 
@@ -72,6 +72,40 @@ After the initial rebuild, startup and queries are faster than v2.x because ther
72
72
 
73
73
  ---
74
74
 
75
+ ## What's New in v3.4.0
76
+
77
+ ### Persistent Model Cache
78
+ Embedding models (~250MB) are now stored in `models_cache/` instead of `/tmp`. No more re-downloading after system reboots on Linux. Configurable via `paths.models_cache_dir` in config.yaml.
79
+
80
+ ### Exclude Patterns
81
+ Skip files and directories during indexing with glob patterns. Configure under `documents.exclude_patterns` in config.yaml:
82
+ ```yaml
83
+ documents:
84
+ exclude_patterns:
85
+ - "node_modules"
86
+ - ".venv"
87
+ - "__pycache__"
88
+ - ".git"
89
+ - "*.tmp"
90
+ ```
91
+ Patterns match against both full relative paths and individual path components — `"node_modules"` excludes it at any depth.
92
+
93
+ ### Jupyter Notebook Support (.ipynb)
94
+ Native parser extracts only markdown and code cell sources — no outputs, no execution counts, no base64-encoded images. Clean content for high-quality retrieval. Added to default supported formats.
95
+
96
+ ### MCP Protocol Stability
97
+ `stdout` is redirected to `stderr` before the MCP server starts. Prevents random library `print()` calls from corrupting the JSON-RPC stream — fixes "Failed to connect" errors in VS Code and IDE integrations.
98
+
99
+ ### File Watcher Resilience (Linux)
100
+ Server no longer crashes when system inotify limits are reached. Falls back gracefully to manual indexing with a clear warning message.
101
+
102
+ ### MetaTrader Support (.mq4, .mqh)
103
+ MQL4/MQL5 source files can now be indexed as code. Not enabled by default — add `.mq4` and `.mqh` to your `supported_formats` list to activate.
104
+
105
+ *Community credit: Features inspired by ideas from [@Hohlas](https://github.com/Hohlas) in [PR #18](https://github.com/lyonzin/knowledge-rag/pull/18).*
106
+
107
+ ---
108
+
75
109
  ## What's New in v3.3.0
76
110
 
77
111
  ### YAML Configuration System
@@ -930,6 +964,7 @@ Pre-built configurations for common use cases. Each preset is a complete `config
930
964
  |-------|---------|-------------|
931
965
  | `paths.documents_dir` | `./documents` | Root folder scanned recursively for documents |
932
966
  | `paths.data_dir` | `./data` | Internal storage for ChromaDB and index metadata |
967
+ | `paths.models_cache_dir` | `./models_cache` | Persistent cache for embedding models (~250MB). Prevents re-download after reboots |
933
968
 
934
969
  Relative paths resolve from the project root. Absolute paths work too. The `KNOWLEDGE_RAG_DIR` environment variable overrides the project root.
935
970
 
@@ -937,7 +972,8 @@ Relative paths resolve from the project root. Absolute paths work too. The `KNOW
937
972
 
938
973
  | Field | Default | Description |
939
974
  |-------|---------|-------------|
940
- | `documents.supported_formats` | .md .txt .pdf .py .json .docx .xlsx .pptx .csv | File extensions to index |
975
+ | `documents.supported_formats` | .md .txt .pdf .py .json .docx .xlsx .pptx .csv .ipynb | File extensions to index |
976
+ | `documents.exclude_patterns` | `[]` (empty) | Glob patterns for files/dirs to skip during indexing |
941
977
  | `documents.chunking.chunk_size` | 1000 | Max characters per chunk |
942
978
  | `documents.chunking.chunk_overlap` | 200 | Characters shared between consecutive chunks |
943
979
 
@@ -1054,7 +1090,8 @@ knowledge-rag/
1054
1090
  ├── data/
1055
1091
  │ ├── chroma_db/ # ChromaDB vector database
1056
1092
  │ └── index_metadata.json # Incremental indexing state
1057
- ├── tests/ # Test suite (55 tests)
1093
+ ├── models_cache/ # Persistent embedding model cache
1094
+ ├── tests/ # Test suite (70+ tests)
1058
1095
  ├── venv/ # Python virtual environment
1059
1096
  ├── requirements.txt # Python dependencies
1060
1097
  ├── LICENSE # MIT License
@@ -1159,6 +1196,18 @@ With ~200 documents, expect ~300-500MB RAM. The embedding model (~50MB) and rera
1159
1196
 
1160
1197
  ## Changelog
1161
1198
 
1199
+ ### v3.4.0 (2026-04-16)
1200
+
1201
+ - **NEW**: `models_cache_dir` — persistent embedding model cache, prevents re-download after reboots
1202
+ - **NEW**: `exclude_patterns` — glob-based file/directory exclusion during indexing (under `documents:` section)
1203
+ - **NEW**: Jupyter Notebook (.ipynb) parser — extracts markdown and code cell sources only, ignores outputs and base64
1204
+ - **NEW**: MCP stdout protection — redirects stdout to stderr before server start, fixes "Failed to connect" errors
1205
+ - **NEW**: File watcher resilience — graceful fallback when Linux inotify limits are reached
1206
+ - **NEW**: MetaTrader (.mq4, .mqh) support — opt-in code parsing for MQL4/MQL5 files
1207
+ - **NEW**: 23 new tests (exclude patterns, ipynb parser, stdout protection)
1208
+ - **IMPROVED**: All 4 presets updated with new config fields
1209
+ - Community credit: [@Hohlas](https://github.com/Hohlas) ([PR #18](https://github.com/lyonzin/knowledge-rag/pull/18))
1210
+
1162
1211
  ### v3.3.2 (2026-04-06)
1163
1212
 
1164
1213
  - **FIX**: Full type validation on all YAML config values — wrong types warn and fall back to defaults
@@ -39,6 +39,11 @@ paths:
39
39
  # You generally don't need to touch this.
40
40
  data_dir: "./data"
41
41
 
42
+ # Persistent cache for embedding models (~250MB).
43
+ # Prevents re-downloading after reboots (especially on Linux where /tmp is cleared).
44
+ # Default: ./models_cache (relative to project root)
45
+ models_cache_dir: "./models_cache"
46
+
42
47
 
43
48
  # ============================================================================
44
49
  # DOCUMENTS
@@ -58,6 +63,25 @@ documents:
58
63
  # - .csv # CSV data files
59
64
  # - .py # Python source code
60
65
  # - .json # JSON files
66
+ # - .ipynb # Jupyter Notebooks (extracts markdown + code cells)
67
+ # - .mq4 # MetaTrader MQL4 source (opt-in, add to enable)
68
+ # - .mqh # MetaTrader MQL4/5 headers (opt-in, add to enable)
69
+
70
+ # Exclude patterns — skip files/directories matching these patterns.
71
+ # Uses fnmatch glob syntax. Patterns match against relative paths AND
72
+ # individual path components (so "node_modules" matches at any depth).
73
+ #
74
+ # Examples:
75
+ # exclude_patterns:
76
+ # - "node_modules" # Skip node_modules at any depth
77
+ # - ".git" # Skip .git directories
78
+ # - "__pycache__" # Skip Python cache
79
+ # - ".venv" # Skip virtual environments
80
+ # - "*.tmp" # Skip .tmp files anywhere
81
+ # - "drafts/*" # Skip everything in top-level drafts/
82
+ #
83
+ # Default: [] (nothing excluded — all supported files are indexed)
84
+ exclude_patterns: []
61
85
 
62
86
  # How documents are split into searchable chunks.
63
87
  #
@@ -1,6 +1,6 @@
1
1
  """Knowledge RAG MCP Server - Local Retrieval-Augmented Generation System"""
2
2
 
3
- __version__ = "3.3.2"
3
+ __version__ = "3.4.0"
4
4
  __author__ = "Ailton Rocha (Lyon.)"
5
5
 
6
6
  from .config import Config
@@ -1,4 +1,4 @@
1
- """Configuration for Knowledge RAG System v3.3.2 — YAML-configurable"""
1
+ """Configuration for Knowledge RAG System v3.4.0 — YAML-configurable"""
2
2
 
3
3
  import os
4
4
  from dataclasses import dataclass, field
@@ -15,7 +15,7 @@ import yaml
15
15
  _source_dir = Path(__file__).parent.parent
16
16
 
17
17
 
18
- _SUPPORTED_SUFFIXES = frozenset([".md", ".txt", ".pdf", ".py", ".json", ".docx", ".xlsx", ".pptx", ".csv"])
18
+ _SUPPORTED_SUFFIXES = frozenset([".md", ".txt", ".pdf", ".py", ".json", ".docx", ".xlsx", ".pptx", ".csv", ".ipynb"])
19
19
 
20
20
 
21
21
  def _has_documents(path: Path) -> bool:
@@ -357,6 +357,9 @@ class Config:
357
357
  documents_dir: Path = field(
358
358
  default_factory=lambda: _resolve_path(_get("paths", "documents_dir", None), BASE_DIR / "documents")
359
359
  )
360
+ models_cache_dir: Path = field(
361
+ default_factory=lambda: _resolve_path(_get("paths", "models_cache_dir", None), BASE_DIR / "models_cache")
362
+ )
360
363
 
361
364
  # Chunking
362
365
  chunk_size: int = field(
@@ -419,10 +422,15 @@ class Config:
419
422
  # Supported formats
420
423
  supported_formats: List[str] = field(
421
424
  default_factory=lambda: _get(
422
- "documents", "supported_formats", [".md", ".txt", ".pdf", ".py", ".json", ".docx", ".xlsx", ".pptx", ".csv"]
425
+ "documents",
426
+ "supported_formats",
427
+ [".md", ".txt", ".pdf", ".py", ".json", ".docx", ".xlsx", ".pptx", ".csv", ".ipynb"],
423
428
  )
424
429
  )
425
430
 
431
+ # Exclude patterns for directory traversal
432
+ exclude_patterns: List[str] = field(default_factory=lambda: _get("documents", "exclude_patterns", []))
433
+
426
434
  # Category mappings
427
435
  category_mappings: Dict[str, str] = field(
428
436
  default_factory=lambda: _get_top("category_mappings", _DEFAULT_CATEGORY_MAPPINGS)
@@ -471,6 +479,13 @@ class Config:
471
479
  print("[WARN] supported_formats is empty or invalid, using defaults")
472
480
  self.supported_formats = [".md", ".txt", ".pdf", ".py", ".json", ".docx", ".xlsx", ".pptx", ".csv"]
473
481
 
482
+ # Validate exclude_patterns is a list of strings
483
+ if not isinstance(self.exclude_patterns, list):
484
+ print(f"[WARN] exclude_patterns={self.exclude_patterns!r} invalid, using []")
485
+ self.exclude_patterns = []
486
+ else:
487
+ self.exclude_patterns = [p for p in self.exclude_patterns if isinstance(p, str)]
488
+
474
489
  # Validate keyword_routes values are lists (not strings)
475
490
  for cat, keywords in list(self.keyword_routes.items()):
476
491
  if not isinstance(keywords, list):
@@ -481,6 +496,7 @@ class Config:
481
496
  self.data_dir.mkdir(parents=True, exist_ok=True)
482
497
  self.chroma_dir.mkdir(parents=True, exist_ok=True)
483
498
  self.documents_dir.mkdir(parents=True, exist_ok=True)
499
+ self.models_cache_dir.mkdir(parents=True, exist_ok=True)
484
500
 
485
501
 
486
502
  # Global config instance
@@ -1,9 +1,10 @@
1
1
  """Document Ingestion System for Knowledge RAG
2
2
 
3
3
  Multi-format document parsing, chunking, and metadata extraction.
4
- Supports: MD, PDF, TXT, PY, JSON, DOCX, XLSX, PPTX, CSV
4
+ Supports: MD, PDF, TXT, PY, JSON, DOCX, XLSX, PPTX, CSV, IPYNB, MQH, MQ4
5
5
  """
6
6
 
7
+ import fnmatch
7
8
  import hashlib
8
9
  import json
9
10
  import os
@@ -103,6 +104,9 @@ class DocumentParser:
103
104
  ".xlsx": self._parse_xlsx,
104
105
  ".pptx": self._parse_pptx,
105
106
  ".csv": self._parse_csv,
107
+ ".ipynb": self._parse_ipynb,
108
+ ".mqh": self._parse_code,
109
+ ".mq4": self._parse_code,
106
110
  }
107
111
 
108
112
  def parse_file(self, filepath: Path) -> Optional[Document]:
@@ -151,12 +155,41 @@ class DocumentParser:
151
155
 
152
156
  return doc
153
157
 
158
+ @staticmethod
159
+ def _should_exclude(path: Path, base_dir: Path, patterns: List[str]) -> bool:
160
+ """Check if a path matches any exclude pattern.
161
+
162
+ Uses fnmatch on the relative path (forward-slash normalized) and
163
+ also checks each path component individually for simple name patterns.
164
+ """
165
+ if not patterns:
166
+ return False
167
+
168
+ try:
169
+ rel = path.relative_to(base_dir)
170
+ except ValueError:
171
+ rel = path
172
+
173
+ rel_str = str(rel).replace("\\", "/")
174
+
175
+ for pattern in patterns:
176
+ # Full relative path match (e.g., "docs/drafts/*.tmp")
177
+ if fnmatch.fnmatch(rel_str, pattern):
178
+ return True
179
+ # Check each component (e.g., "node_modules" matches any/node_modules/deep)
180
+ for part in rel.parts:
181
+ if fnmatch.fnmatch(part, pattern):
182
+ return True
183
+
184
+ return False
185
+
154
186
  def parse_directory(self, directory: Path = None) -> List[Document]:
155
187
  """Parse all supported files in a directory recursively (follows symlinks)."""
156
188
  directory = Path(directory) if directory else config.documents_dir
157
189
  documents = []
158
190
  seen_dirs = set()
159
191
  supported = set(config.supported_formats)
192
+ exclude = config.exclude_patterns
160
193
 
161
194
  for root, dirs, files in os.walk(directory, followlinks=True):
162
195
  real_root = os.path.realpath(root)
@@ -165,10 +198,16 @@ class DocumentParser:
165
198
  continue
166
199
  seen_dirs.add(real_root)
167
200
 
201
+ # Filter out excluded directories in-place (prevents os.walk from descending)
202
+ if exclude:
203
+ dirs[:] = [d for d in dirs if not self._should_exclude(Path(root) / d, directory, exclude)]
204
+
168
205
  for fname in files:
169
206
  filepath = Path(root) / fname
170
207
  if filepath.suffix.lower() not in supported:
171
208
  continue
209
+ if exclude and self._should_exclude(filepath, directory, exclude):
210
+ continue
172
211
  try:
173
212
  doc = self.parse_file(filepath)
174
213
  if doc:
@@ -437,6 +476,59 @@ class DocumentParser:
437
476
  content = "\n".join(parts)
438
477
  return content, metadata
439
478
 
479
+ def _parse_ipynb(self, filepath: Path) -> tuple[str, Dict]:
480
+ """Parse Jupyter Notebook, extracting only markdown and code cell sources.
481
+
482
+ Ignores outputs, execution counts, cell metadata, and base64 images.
483
+ """
484
+ raw = filepath.read_text(encoding="utf-8", errors="ignore")
485
+ metadata = {
486
+ "type": "jupyter_notebook",
487
+ "title": filepath.stem,
488
+ "file_size": filepath.stat().st_size,
489
+ "modified": datetime.fromtimestamp(filepath.stat().st_mtime).isoformat(),
490
+ }
491
+
492
+ try:
493
+ nb = json.loads(raw)
494
+ except json.JSONDecodeError:
495
+ metadata["is_valid_json"] = False
496
+ return raw, metadata
497
+
498
+ metadata["is_valid_json"] = True
499
+ metadata["nbformat"] = nb.get("nbformat", 0)
500
+ kernel = nb.get("metadata", {}).get("kernelspec", {})
501
+ metadata["kernel"] = kernel.get("display_name", kernel.get("name", "unknown"))
502
+
503
+ cells = nb.get("cells", [])
504
+ metadata["cells"] = len(cells)
505
+ code_cells = 0
506
+ markdown_cells = 0
507
+
508
+ parts = []
509
+ for cell in cells:
510
+ cell_type = cell.get("cell_type", "")
511
+ source = cell.get("source", "")
512
+
513
+ if isinstance(source, list):
514
+ source = "".join(source)
515
+
516
+ if not source or not source.strip():
517
+ continue
518
+
519
+ if cell_type == "markdown":
520
+ parts.append(source)
521
+ markdown_cells += 1
522
+ elif cell_type == "code":
523
+ parts.append(f"```python\n{source}\n```")
524
+ code_cells += 1
525
+
526
+ metadata["code_cells"] = code_cells
527
+ metadata["markdown_cells"] = markdown_cells
528
+
529
+ content = "\n\n".join(parts)
530
+ return content, metadata
531
+
440
532
  # =========================================================================
441
533
  # Chunking
442
534
  # =========================================================================
@@ -19,8 +19,8 @@ Features:
19
19
  - CRUD operations via MCP tools (add, update, remove docs)
20
20
 
21
21
  Autor: Lyon (Ailton Rocha)
22
- Versao: 3.3.2
23
- Data: 2026-04-06
22
+ Versao: 3.4.0
23
+ Data: 2026-04-16
24
24
  """
25
25
 
26
26
  import hashlib
@@ -141,7 +141,7 @@ class FastEmbedEmbeddings:
141
141
  self.model_name = model or config.embedding_model
142
142
  self._dim = config.embedding_dim
143
143
  print(f"[INFO] Loading embedding model: {self.model_name} ({self._dim}D)...")
144
- self._model = TextEmbedding(model_name=self.model_name)
144
+ self._model = TextEmbedding(model_name=self.model_name, cache_dir=str(config.models_cache_dir))
145
145
  print("[INFO] Embedding model loaded successfully")
146
146
 
147
147
  def __call__(self, input: List[str]) -> List[List[float]]:
@@ -1899,12 +1899,21 @@ def main():
1899
1899
  print(f"[INFO] Indexed {stats['indexed']} documents with {stats['chunks_added']} chunks")
1900
1900
 
1901
1901
  # Start file watcher for auto-reindex on document changes
1902
- watcher = DocumentWatcher(get_orchestrator, debounce_seconds=5.0)
1903
- observer = Observer()
1904
- observer.schedule(watcher, str(config.documents_dir), recursive=True)
1905
- observer.daemon = True
1906
- observer.start()
1907
- print(f"[WATCHER] Monitoring {config.documents_dir} for changes")
1902
+ try:
1903
+ watcher = DocumentWatcher(get_orchestrator, debounce_seconds=5.0)
1904
+ observer = Observer()
1905
+ observer.schedule(watcher, str(config.documents_dir), recursive=True)
1906
+ observer.daemon = True
1907
+ observer.start()
1908
+ print(f"[WATCHER] Monitoring {config.documents_dir} for changes")
1909
+ except Exception as e:
1910
+ print(f"[WARN] Failed to start file watcher: {e}")
1911
+ print("[WARN] Auto-reindexing disabled. Use reindex_documents tool manually.")
1912
+
1913
+ # Redirect stdout to stderr to protect MCP stdio JSON-RPC stream.
1914
+ # Libraries (fastembed, chromadb, watchdog) may print() at runtime,
1915
+ # which would corrupt the protocol. This ONLY affects the server process.
1916
+ sys.stdout = sys.stderr
1908
1917
 
1909
1918
  mcp.run()
1910
1919
 
@@ -22,6 +22,7 @@
22
22
  paths:
23
23
  documents_dir: "./documents"
24
24
  data_dir: "./data"
25
+ models_cache_dir: "./models_cache"
25
26
 
26
27
 
27
28
  # ============================================================================
@@ -39,6 +40,9 @@ documents:
39
40
  - .xlsx
40
41
  - .pptx
41
42
  - .csv
43
+ - .ipynb # Jupyter Notebooks (exploit dev, research)
44
+
45
+ exclude_patterns: []
42
46
 
43
47
  chunking:
44
48
  chunk_size: 1000
@@ -17,6 +17,7 @@
17
17
  paths:
18
18
  documents_dir: "./documents"
19
19
  data_dir: "./data"
20
+ models_cache_dir: "./models_cache"
20
21
 
21
22
 
22
23
  # ============================================================================
@@ -32,6 +33,16 @@ documents:
32
33
  - .py # Python source code
33
34
  - .json # API schemas, configs
34
35
  - .csv # Data files, logs
36
+ - .ipynb # Jupyter Notebooks
37
+
38
+ exclude_patterns:
39
+ - "node_modules"
40
+ - ".venv"
41
+ - "__pycache__"
42
+ - ".git"
43
+ - "dist"
44
+ - "build"
45
+ - ".next"
35
46
 
36
47
  chunking:
37
48
  chunk_size: 1200 # Slightly larger for code + prose docs
@@ -26,6 +26,7 @@
26
26
  paths:
27
27
  documents_dir: "./documents"
28
28
  data_dir: "./data"
29
+ models_cache_dir: "./models_cache"
29
30
 
30
31
 
31
32
  # ============================================================================
@@ -39,6 +40,8 @@ documents:
39
40
  - .pdf
40
41
  - .docx
41
42
 
43
+ exclude_patterns: []
44
+
42
45
  chunking:
43
46
  chunk_size: 1000
44
47
  chunk_overlap: 200
@@ -17,6 +17,7 @@
17
17
  paths:
18
18
  documents_dir: "./documents"
19
19
  data_dir: "./data"
20
+ models_cache_dir: "./models_cache"
20
21
 
21
22
 
22
23
  # ============================================================================
@@ -32,6 +33,9 @@ documents:
32
33
  - .xlsx # Data tables, survey results
33
34
  - .pptx # Presentations, lecture slides
34
35
  - .csv # Experiment data, datasets
36
+ - .ipynb # Jupyter Notebooks (analysis, experiments)
37
+
38
+ exclude_patterns: []
35
39
 
36
40
  chunking:
37
41
  chunk_size: 1500 # Larger chunks — academic text needs more context
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "knowledge-rag"
7
- version = "3.3.2"
7
+ version = "3.4.0"
8
8
  description = "Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 12 MCP Tools. Zero external servers."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes