local-knowledge 0.2.2__tar.gz → 0.2.3__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 (19) hide show
  1. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/PKG-INFO +2 -2
  2. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/pyproject.toml +2 -2
  3. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge/crawl_local.py +3 -1
  4. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge/server_local.py +12 -7
  5. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge.egg-info/PKG-INFO +2 -2
  6. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge.egg-info/requires.txt +1 -1
  7. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/README.md +0 -0
  8. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/setup.cfg +0 -0
  9. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge/__init__.py +0 -0
  10. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge/cli_local.py +0 -0
  11. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge/settings_local.py +0 -0
  12. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge.egg-info/SOURCES.txt +0 -0
  13. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge.egg-info/dependency_links.txt +0 -0
  14. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge.egg-info/entry_points.txt +0 -0
  15. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/src/local_knowledge.egg-info/top_level.txt +0 -0
  16. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/tests/test_agent_doc_consistency.py +0 -0
  17. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/tests/test_crawl_local.py +0 -0
  18. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/tests/test_extract_files.py +0 -0
  19. {local_knowledge-0.2.2 → local_knowledge-0.2.3}/tests/test_server_flow_local.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: local-knowledge
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Local file/folder indexer + grounded-Q&A MCP service — same engine as confluence-knowledge, no credentials needed
5
5
  License: MIT
6
6
  Project-URL: Repository, https://github.com/nkunal1992/agents
@@ -20,7 +20,7 @@ Requires-Dist: openpyxl>=3.1
20
20
  Requires-Dist: mcp<2,>=1.6
21
21
  Requires-Dist: pip-system-certs>=5.0
22
22
  Provides-Extra: models
23
- Requires-Dist: confluence-knowledge[models]>=0.5.2; extra == "models"
23
+ Requires-Dist: confluence-knowledge[models]>=0.5.3; extra == "models"
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: pytest>=8.0; extra == "dev"
26
26
  Requires-Dist: pytest-cov>=5.0; extra == "dev"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "local-knowledge"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Local file/folder indexer + grounded-Q&A MCP service — same engine as confluence-knowledge, no credentials needed"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -27,7 +27,7 @@ dependencies = [
27
27
 
28
28
  [project.optional-dependencies]
29
29
  models = [
30
- "confluence-knowledge[models]>=0.5.2",
30
+ "confluence-knowledge[models]>=0.5.3",
31
31
  ]
32
32
  dev = [
33
33
  "pytest>=8.0",
@@ -133,6 +133,7 @@ class LocalCrawler:
133
133
 
134
134
  queue: list[str] = job["queue"]
135
135
  errors: list[str] = job["errors"]
136
+ keep_failed: set[str] = set() # transient read fails keep old content
136
137
  # Mid-crawl model change: already-embedded pages live in the OLD
137
138
  # vector space — finishing would publish mixed dims. Wipe + fail;
138
139
  # start_crawl rebuilds under the new model.
@@ -186,6 +187,7 @@ class LocalCrawler:
186
187
  page, chunks = self._page(path)
187
188
  except SetupError as e:
188
189
  errors.append(str(e))
190
+ keep_failed.add(self._rel(path))
189
191
  continue
190
192
  rel = page["page_id"]
191
193
  if rel in seen:
@@ -208,7 +210,7 @@ class LocalCrawler:
208
210
  # persist final seen/levels/warns too — the in-loop checkpoint runs
209
211
  # before each item is processed, so the last item would undercount
210
212
  self._checkpoint(job_id, queue, errors, seen, levels, warns)
211
- self.index.publish(seen)
213
+ self.index.publish(seen | keep_failed)
212
214
  self.index.set_model_id(_MODEL_ID)
213
215
  self.index.save_job(job_id, "done" if not queue else "running",
214
216
  queue, errors)
@@ -32,7 +32,7 @@ from .settings_local import APP_NAME, LocalProfile, home, index_root, workdir
32
32
  mcp = FastMCP("local-knowledge")
33
33
 
34
34
  _scopes: dict[str, dict] = {}
35
- _evidence_sets: dict[str, list[dict]] = {}
35
+ _evidence_sets: dict[str, dict] = {} # set_id → {scope, ev}
36
36
  _indexes: dict[str, Index] = {}
37
37
  _EMBEDDER = None
38
38
  _RERANKER = None
@@ -269,7 +269,10 @@ def search(scope_handle: str, question: str) -> dict:
269
269
  "— run start_crawl once to rebuild it, then search again"}
270
270
  ev = retrieve(idx, question, _embedder(), _reranker(), sparse=_sparse())
271
271
  set_id = f"ev:{len(_evidence_sets)}:{s['key'][:8]}"
272
- _evidence_sets[set_id] = ev
272
+ # bound the session cache — sets are never reused after the turn ends
273
+ while len(_evidence_sets) >= 32:
274
+ _evidence_sets.pop(next(iter(_evidence_sets)))
275
+ _evidence_sets[set_id] = {"scope": s["key"], "ev": ev}
273
276
  return {
274
277
  "evidence_set": set_id,
275
278
  "coverage": _coverage(idx),
@@ -277,7 +280,9 @@ def search(scope_handle: str, question: str) -> dict:
277
280
  "evidence": [
278
281
  {"chunk_id": e["chunk_id"], "page_title": e["page_title"],
279
282
  "page_url": e["page_url"], "heading": e["heading"],
280
- "score": e.get("rerank_score"), "text": e["text"][:2000]}
283
+ "score": e.get("rerank_score"), "text": e["text"][:12000],
284
+ "low_confidence": e.get("low_confidence", False),
285
+ "truncated": len(e["text"]) > 12000}
281
286
  for e in ev
282
287
  ],
283
288
  }
@@ -303,12 +308,12 @@ def get_evidence(scope_handle: str, chunk_ids: list[str]) -> dict:
303
308
  @mcp.tool()
304
309
  def verify_citations(scope_handle: str, evidence_set: str,
305
310
  mappings: list[dict]) -> dict:
306
- _scope(scope_handle)
307
- ev = _evidence_sets.get(evidence_set)
308
- if ev is None or not evidence_set.endswith(_scopes[scope_handle]["key"][:8]):
311
+ s = _scope(scope_handle)
312
+ rec = _evidence_sets.get(evidence_set)
313
+ if rec is None or rec["scope"] != s["key"]:
309
314
  raise SecurityException(
310
315
  "unknown or cross-scope evidence set — run search again and cite its evidence_set")
311
- return check_citations(ev, mappings)
316
+ return check_citations(rec["ev"], mappings)
312
317
 
313
318
 
314
319
  def main() -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: local-knowledge
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Local file/folder indexer + grounded-Q&A MCP service — same engine as confluence-knowledge, no credentials needed
5
5
  License: MIT
6
6
  Project-URL: Repository, https://github.com/nkunal1992/agents
@@ -20,7 +20,7 @@ Requires-Dist: openpyxl>=3.1
20
20
  Requires-Dist: mcp<2,>=1.6
21
21
  Requires-Dist: pip-system-certs>=5.0
22
22
  Provides-Extra: models
23
- Requires-Dist: confluence-knowledge[models]>=0.5.2; extra == "models"
23
+ Requires-Dist: confluence-knowledge[models]>=0.5.3; extra == "models"
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: pytest>=8.0; extra == "dev"
26
26
  Requires-Dist: pytest-cov>=5.0; extra == "dev"
@@ -12,4 +12,4 @@ pytest-cov>=5.0
12
12
  ruff>=0.6
13
13
 
14
14
  [models]
15
- confluence-knowledge[models]>=0.5.2
15
+ confluence-knowledge[models]>=0.5.3