sharepoint-knowledge 0.2.1__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.
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/PKG-INFO +2 -2
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/pyproject.toml +2 -2
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/cli_sp.py +3 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/crawl_sp.py +24 -2
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/server_sp.py +15 -8
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge.egg-info/PKG-INFO +2 -2
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge.egg-info/requires.txt +1 -1
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/README.md +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/setup.cfg +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/__init__.py +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/auth_sp.py +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/client_sp.py +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/settings_sp.py +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge.egg-info/SOURCES.txt +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge.egg-info/dependency_links.txt +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge.egg-info/entry_points.txt +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge.egg-info/top_level.txt +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/tests/test_agent_doc_consistency.py +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/tests/test_client_sp.py +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/tests/test_crawl_sp.py +0 -0
- {sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/tests/test_server_flow_sp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sharepoint-knowledge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: SharePoint connector for the grounded-Q&A engine — site pages + document libraries, Entra device-code sign-in, local models, cited answers
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://github.com/nkunal1992/agents
|
|
@@ -11,7 +11,7 @@ Requires-Dist: msal>=1.31
|
|
|
11
11
|
Requires-Dist: httpx>=0.27
|
|
12
12
|
Requires-Dist: mcp>=1.8
|
|
13
13
|
Provides-Extra: models
|
|
14
|
-
Requires-Dist: confluence-knowledge[models]>=0.5.
|
|
14
|
+
Requires-Dist: confluence-knowledge[models]>=0.5.3; extra == "models"
|
|
15
15
|
Provides-Extra: dev
|
|
16
16
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
17
17
|
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sharepoint-knowledge"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.3"
|
|
8
8
|
description = "SharePoint connector for the grounded-Q&A engine — site pages + document libraries, Entra device-code sign-in, local models, cited answers"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -18,7 +18,7 @@ dependencies = [
|
|
|
18
18
|
|
|
19
19
|
[project.optional-dependencies]
|
|
20
20
|
models = [
|
|
21
|
-
"confluence-knowledge[models]>=0.5.
|
|
21
|
+
"confluence-knowledge[models]>=0.5.3",
|
|
22
22
|
]
|
|
23
23
|
dev = [
|
|
24
24
|
"pytest>=8.0",
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/cli_sp.py
RENAMED
|
@@ -153,6 +153,9 @@ def main() -> None:
|
|
|
153
153
|
import subprocess
|
|
154
154
|
cmd = [sys.executable, "-m", "pip", "install", "-U",
|
|
155
155
|
"sharepoint-knowledge[models]"]
|
|
156
|
+
# a running MCP server holds open files — quit the IDE first
|
|
157
|
+
print("note: quit the IDE (or stop the MCP server) before updating —"
|
|
158
|
+
" a running server can't be replaced cleanly", flush=True)
|
|
156
159
|
if os.name == "nt":
|
|
157
160
|
print("on Windows, upgrade via the venv python directly:\n "
|
|
158
161
|
+ " ".join(f'"{c}"' if " " in c else c for c in cmd))
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/crawl_sp.py
RENAMED
|
@@ -23,7 +23,7 @@ from confluence_knowledge.settings import SetupError
|
|
|
23
23
|
MAX_FILE_BYTES = 25 * 1024 * 1024
|
|
24
24
|
MAX_FILES = 20_000
|
|
25
25
|
|
|
26
|
-
from confluence_knowledge.retrieval import
|
|
26
|
+
from confluence_knowledge.retrieval import MODEL_MARKER as _MODEL_ID
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def resolve_root(client: ConfluenceClient, url: str) -> tuple[str, str]:
|
|
@@ -197,6 +197,21 @@ class SPCrawler:
|
|
|
197
197
|
|
|
198
198
|
queue: list[str] = job["queue"]
|
|
199
199
|
errors: list[str] = job["errors"]
|
|
200
|
+
# deny/gone errors drop the item from the snapshot; transient
|
|
201
|
+
# failures keep the previously-indexed content
|
|
202
|
+
keep_failed: set[str] = set()
|
|
203
|
+
# Mid-crawl model change: already-embedded pages live in the OLD
|
|
204
|
+
# vector space — finishing would publish mixed dims. Wipe + fail;
|
|
205
|
+
# start_crawl rebuilds under the new model.
|
|
206
|
+
stamped = self.index.model_id()
|
|
207
|
+
if stamped is not None and stamped != _MODEL_ID and queue:
|
|
208
|
+
self.index.clear_scope()
|
|
209
|
+
errors = errors + [
|
|
210
|
+
(f"model changed mid-crawl ({stamped} → {_MODEL_ID}) — "
|
|
211
|
+
"index cleared; run start_crawl")]
|
|
212
|
+
self.index.save_job(job_id, "error", [], errors)
|
|
213
|
+
return {"job_id": job_id, "state": "error",
|
|
214
|
+
"remaining": 0, "errors": errors}
|
|
200
215
|
seen_raw = self.index.meta_get(f"seen:{job_id}")
|
|
201
216
|
seen: set[str] = set(json.loads(seen_raw)) if seen_raw else set()
|
|
202
217
|
levels_raw = self.index.meta_get(f"levels:{job_id}")
|
|
@@ -252,6 +267,13 @@ class SPCrawler:
|
|
|
252
267
|
continue
|
|
253
268
|
except AccessError as e:
|
|
254
269
|
errors.append(f"{entry}: {e}")
|
|
270
|
+
if not any(m in str(e) for m in
|
|
271
|
+
("401", "403", "404", "permission", "not found")):
|
|
272
|
+
# seen stores the built page_id — page: / file: prefixed
|
|
273
|
+
last = entry.split(":")[-1]
|
|
274
|
+
keep_failed.add(
|
|
275
|
+
f"page:{last}" if entry.startswith("page:")
|
|
276
|
+
else f"file:{last}")
|
|
255
277
|
continue
|
|
256
278
|
pid = page["page_id"]
|
|
257
279
|
if pid in seen:
|
|
@@ -273,7 +295,7 @@ class SPCrawler:
|
|
|
273
295
|
seen.add(pid)
|
|
274
296
|
|
|
275
297
|
self._checkpoint(job_id, queue, errors, seen, levels, warns)
|
|
276
|
-
self.index.publish(seen)
|
|
298
|
+
self.index.publish(seen | keep_failed)
|
|
277
299
|
self.index.set_model_id(_MODEL_ID)
|
|
278
300
|
self.index.save_job(job_id, "done" if not queue else "running",
|
|
279
301
|
queue, errors)
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/server_sp.py
RENAMED
|
@@ -10,7 +10,9 @@ import threading
|
|
|
10
10
|
from confluence_knowledge.client import AccessError, SecurityException
|
|
11
11
|
from confluence_knowledge.index import Index
|
|
12
12
|
from confluence_knowledge.retrieval import (
|
|
13
|
-
EMBED_MODEL_ID,
|
|
13
|
+
MODEL_MARKER as EMBED_MODEL_ID,
|
|
14
|
+
)
|
|
15
|
+
from confluence_knowledge.retrieval import (
|
|
14
16
|
LocalEmbedder,
|
|
15
17
|
LocalReranker,
|
|
16
18
|
LocalSparseEmbedder,
|
|
@@ -28,7 +30,7 @@ from .settings_sp import APP_NAME, SPProfile, graph_base, home, index_root, work
|
|
|
28
30
|
mcp = FastMCP("sharepoint-knowledge")
|
|
29
31
|
|
|
30
32
|
_scopes: dict[str, dict] = {}
|
|
31
|
-
_evidence_sets: dict[str,
|
|
33
|
+
_evidence_sets: dict[str, dict] = {} # set_id → {scope, ev}
|
|
32
34
|
_indexes: dict[str, Index] = {}
|
|
33
35
|
_clients: dict[str, object] = {}
|
|
34
36
|
_EMBEDDER = None
|
|
@@ -309,7 +311,10 @@ def search(scope_handle: str, question: str) -> dict:
|
|
|
309
311
|
"— run start_crawl once to rebuild it, then search again"}
|
|
310
312
|
ev = retrieve(idx, question, _embedder(), _reranker(), sparse=_sparse())
|
|
311
313
|
set_id = f"ev:{len(_evidence_sets)}:{s['key'][:8]}"
|
|
312
|
-
|
|
314
|
+
# bound the session cache — sets are never reused after the turn ends
|
|
315
|
+
while len(_evidence_sets) >= 32:
|
|
316
|
+
_evidence_sets.pop(next(iter(_evidence_sets)))
|
|
317
|
+
_evidence_sets[set_id] = {"scope": s["key"], "ev": ev}
|
|
313
318
|
return {
|
|
314
319
|
"evidence_set": set_id,
|
|
315
320
|
"coverage": _coverage(idx),
|
|
@@ -317,7 +322,9 @@ def search(scope_handle: str, question: str) -> dict:
|
|
|
317
322
|
"evidence": [
|
|
318
323
|
{"chunk_id": e["chunk_id"], "page_title": e["page_title"],
|
|
319
324
|
"page_url": e["page_url"], "heading": e["heading"],
|
|
320
|
-
"score": e.get("rerank_score"), "text": e["text"][:
|
|
325
|
+
"score": e.get("rerank_score"), "text": e["text"][:12000],
|
|
326
|
+
"low_confidence": e.get("low_confidence", False),
|
|
327
|
+
"truncated": len(e["text"]) > 12000}
|
|
321
328
|
for e in ev
|
|
322
329
|
],
|
|
323
330
|
}
|
|
@@ -343,12 +350,12 @@ def get_evidence(scope_handle: str, chunk_ids: list[str]) -> dict:
|
|
|
343
350
|
@mcp.tool()
|
|
344
351
|
def verify_citations(scope_handle: str, evidence_set: str,
|
|
345
352
|
mappings: list[dict]) -> dict:
|
|
346
|
-
_scope(scope_handle)
|
|
347
|
-
|
|
348
|
-
if
|
|
353
|
+
s = _scope(scope_handle)
|
|
354
|
+
rec = _evidence_sets.get(evidence_set)
|
|
355
|
+
if rec is None or rec["scope"] != s["key"]:
|
|
349
356
|
raise SecurityException(
|
|
350
357
|
"unknown or cross-scope evidence set — run search again and cite its evidence_set")
|
|
351
|
-
return check_citations(ev, mappings)
|
|
358
|
+
return check_citations(rec["ev"], mappings)
|
|
352
359
|
|
|
353
360
|
|
|
354
361
|
def main() -> None:
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sharepoint-knowledge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: SharePoint connector for the grounded-Q&A engine — site pages + document libraries, Entra device-code sign-in, local models, cited answers
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://github.com/nkunal1992/agents
|
|
@@ -11,7 +11,7 @@ Requires-Dist: msal>=1.31
|
|
|
11
11
|
Requires-Dist: httpx>=0.27
|
|
12
12
|
Requires-Dist: mcp>=1.8
|
|
13
13
|
Provides-Extra: models
|
|
14
|
-
Requires-Dist: confluence-knowledge[models]>=0.5.
|
|
14
|
+
Requires-Dist: confluence-knowledge[models]>=0.5.3; extra == "models"
|
|
15
15
|
Provides-Extra: dev
|
|
16
16
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
17
17
|
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
File without changes
|
|
File without changes
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/__init__.py
RENAMED
|
File without changes
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/auth_sp.py
RENAMED
|
File without changes
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/client_sp.py
RENAMED
|
File without changes
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/src/sharepoint_knowledge/settings_sp.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sharepoint_knowledge-0.2.1 → sharepoint_knowledge-0.2.3}/tests/test_agent_doc_consistency.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|