kb-memory 2.1.1__tar.gz → 2.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.
- {kb_memory-2.1.1 → kb_memory-2.1.2}/PKG-INFO +6 -10
- {kb_memory-2.1.1 → kb_memory-2.1.2}/README.md +5 -9
- kb_memory-2.1.2/kb/__init__.py +2 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/api.py +3 -5
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/watcher.py +22 -2
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb_memory.egg-info/PKG-INFO +6 -10
- {kb_memory-2.1.1 → kb_memory-2.1.2}/pyproject.toml +1 -1
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n10_ask.py +3 -1
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n15_watcher.py +35 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_v21_bootstrap.py +1 -1
- kb_memory-2.1.1/kb/__init__.py +0 -2
- {kb_memory-2.1.1 → kb_memory-2.1.2}/LICENSE +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/__main__.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/audit.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/bm25.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/cli.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/config.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/consolidation.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/discovery.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/embedder.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/eval.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/governance.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/i18n.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/idle.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/ingest.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/llm.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/logging_setup.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/mcp.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/models.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/monitor.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/reranker.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/retriever.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/scopes.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/service.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/sparse.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb/storage.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb_memory.egg-info/SOURCES.txt +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb_memory.egg-info/dependency_links.txt +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb_memory.egg-info/entry_points.txt +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb_memory.egg-info/requires.txt +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/kb_memory.egg-info/top_level.txt +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/setup.cfg +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_agent_isolation.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_api_auth.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_charset_json.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_consolidation.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_embed_model_resolution.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_hotfix_validation.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_improvements_bm25_batch.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_improvements_concurrency.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_improvements_isolation_recall.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n01_config.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n02_models.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n03_embedder.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n04_storage.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n05_bm25.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n06_retriever_service.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n07_api.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n08_api_ext.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n09_llm.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n11_routing.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n12_mcp.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n13_ingest.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n13_ingest_extra.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n14_web.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n16_regression.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n17_logging.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n18_logs_api.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n18_logs_doc.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n18_monitor.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n19_nav.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n21_decay.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n21_metadata.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n22_dedup.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n22_governance.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n23_audit.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n23_cli.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n24_reranker.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n25_sparse.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n26_eval.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n27_perf.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n28_cli.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n29_security.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n30_mcp_stdio.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n31_serve_probe.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_n32_hybrid_fusion_recall.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_skill_package.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_user_experience_fixes.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_v21_i18n.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_v21_packaging.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_v21_runtime.py +0 -0
- {kb_memory-2.1.1 → kb_memory-2.1.2}/tests/test_watcher_missing_dir.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kb-memory
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: Local-first agent memory & knowledge service: hybrid retrieval + memory governance (decay / dedup / freshness), REST + MCP dual protocol, fully usable offline without an LLM
|
|
5
5
|
Author: fish827-08
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -60,7 +60,7 @@ Dynamic: license-file
|
|
|
60
60
|
|
|
61
61
|
<!-- GitHub Topics: mcp, memory-service, rag, ai-agent, knowledge-base, local-first, llm, claude-code, hybrid-search, embedding -->
|
|
62
62
|
|
|
63
|
-
**kb** 是本地优先、完全免费的 Agent 记忆与知识服务(v2.1.
|
|
63
|
+
**kb** 是本地优先、完全免费的 Agent 记忆与知识服务(v2.1.2)。
|
|
64
64
|
|
|
65
65
|
> 开源协议:[Apache-2.0](LICENSE)(含专利授权,可商用)。
|
|
66
66
|
|
|
@@ -150,7 +150,7 @@ curl http://127.0.0.1:8000/api/v1/healthz
|
|
|
150
150
|
>
|
|
151
151
|
> **CPU 即可运行,不占显卡**:全新安装默认拿到 CPU 版 torch(`device=cpu`),
|
|
152
152
|
> 不占用 GPU 显存,无独立显卡的机器也能完整使用。有显卡想加速(大库、批量入库)
|
|
153
|
-
> 可另装 CUDA 版 torch
|
|
153
|
+
> 可另装 CUDA 版 torch 后显式 `KB_DEVICE=cuda` 启用 GPU 加速。
|
|
154
154
|
>
|
|
155
155
|
> **LLM 默认关闭(`KB_LLM_MODE=off`)**:服务启动不会探测/加载/调用任何大模型,
|
|
156
156
|
> 零显存、零成本、纯离线;记忆写入、文档入库、混合检索完整可用。
|
|
@@ -398,18 +398,14 @@ python -m kb dedup --threshold 0.92 # 语义去重
|
|
|
398
398
|
```
|
|
399
399
|
kb/ kb 服务源码(config / models / embedder / storage / bm25 / retriever /
|
|
400
400
|
service / llm / ingest / watcher / api / mcp / cli + reranker / sparse / eval)
|
|
401
|
-
tests/ kb 验收测试(
|
|
402
|
-
docs/
|
|
401
|
+
tests/ kb 验收测试(425 项通过 / 1 跳过,含 eval_zh_50.jsonl 检索评测数据集)
|
|
402
|
+
docs/ 用户指南、开发者手册与设计文档
|
|
403
403
|
kb_data/ kb 运行数据(gitignore)
|
|
404
|
-
_archive/ 旧学习项目 + 历史 spec/plan 归档(仅本地保留,禁止参考)
|
|
405
404
|
```
|
|
406
405
|
|
|
407
406
|
## 更多文档
|
|
408
407
|
|
|
409
|
-
-
|
|
410
|
-
- **AI 接力文档(AI 助手入口)**:[PROJECT.md](PROJECT.md)(项目状态 / 进度看板 / 接手指南)
|
|
408
|
+
- **用户使用手册**:[docs/USER_GUIDE.md](docs/USER_GUIDE.md)
|
|
411
409
|
- 设计文档(需求、架构、API、里程碑):`docs/superpowers/specs/2026-08-23-kb-memory-service-design.md`
|
|
412
410
|
- **v2.1 设计(当前)**:`docs/superpowers/specs/2026-10-20-kb-v2.1-design.md`
|
|
413
411
|
- 开发者维护手册:`docs/DEV_HANDBOOK.md`
|
|
414
|
-
- AI 协作规范:`AGENTS.md`
|
|
415
|
-
- 历史 spec / 节点计划已归档到本地 `_archive/docs/`(不上传,不再作为开发依据)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<!-- GitHub Topics: mcp, memory-service, rag, ai-agent, knowledge-base, local-first, llm, claude-code, hybrid-search, embedding -->
|
|
12
12
|
|
|
13
|
-
**kb** 是本地优先、完全免费的 Agent 记忆与知识服务(v2.1.
|
|
13
|
+
**kb** 是本地优先、完全免费的 Agent 记忆与知识服务(v2.1.2)。
|
|
14
14
|
|
|
15
15
|
> 开源协议:[Apache-2.0](LICENSE)(含专利授权,可商用)。
|
|
16
16
|
|
|
@@ -100,7 +100,7 @@ curl http://127.0.0.1:8000/api/v1/healthz
|
|
|
100
100
|
>
|
|
101
101
|
> **CPU 即可运行,不占显卡**:全新安装默认拿到 CPU 版 torch(`device=cpu`),
|
|
102
102
|
> 不占用 GPU 显存,无独立显卡的机器也能完整使用。有显卡想加速(大库、批量入库)
|
|
103
|
-
> 可另装 CUDA 版 torch
|
|
103
|
+
> 可另装 CUDA 版 torch 后显式 `KB_DEVICE=cuda` 启用 GPU 加速。
|
|
104
104
|
>
|
|
105
105
|
> **LLM 默认关闭(`KB_LLM_MODE=off`)**:服务启动不会探测/加载/调用任何大模型,
|
|
106
106
|
> 零显存、零成本、纯离线;记忆写入、文档入库、混合检索完整可用。
|
|
@@ -348,18 +348,14 @@ python -m kb dedup --threshold 0.92 # 语义去重
|
|
|
348
348
|
```
|
|
349
349
|
kb/ kb 服务源码(config / models / embedder / storage / bm25 / retriever /
|
|
350
350
|
service / llm / ingest / watcher / api / mcp / cli + reranker / sparse / eval)
|
|
351
|
-
tests/ kb 验收测试(
|
|
352
|
-
docs/
|
|
351
|
+
tests/ kb 验收测试(425 项通过 / 1 跳过,含 eval_zh_50.jsonl 检索评测数据集)
|
|
352
|
+
docs/ 用户指南、开发者手册与设计文档
|
|
353
353
|
kb_data/ kb 运行数据(gitignore)
|
|
354
|
-
_archive/ 旧学习项目 + 历史 spec/plan 归档(仅本地保留,禁止参考)
|
|
355
354
|
```
|
|
356
355
|
|
|
357
356
|
## 更多文档
|
|
358
357
|
|
|
359
|
-
-
|
|
360
|
-
- **AI 接力文档(AI 助手入口)**:[PROJECT.md](PROJECT.md)(项目状态 / 进度看板 / 接手指南)
|
|
358
|
+
- **用户使用手册**:[docs/USER_GUIDE.md](docs/USER_GUIDE.md)
|
|
361
359
|
- 设计文档(需求、架构、API、里程碑):`docs/superpowers/specs/2026-08-23-kb-memory-service-design.md`
|
|
362
360
|
- **v2.1 设计(当前)**:`docs/superpowers/specs/2026-10-20-kb-v2.1-design.md`
|
|
363
361
|
- 开发者维护手册:`docs/DEV_HANDBOOK.md`
|
|
364
|
-
- AI 协作规范:`AGENTS.md`
|
|
365
|
-
- 历史 spec / 节点计划已归档到本地 `_archive/docs/`(不上传,不再作为开发依据)
|
|
@@ -562,7 +562,7 @@ def create_app(settings: Settings | None = None,
|
|
|
562
562
|
"未安装 watchdog,目录监听已禁用"
|
|
563
563
|
"(pip install \"kb-memory[ingest]\" 可启用)")
|
|
564
564
|
else:
|
|
565
|
-
watcher = KBWatcher(kb, wd)
|
|
565
|
+
watcher = KBWatcher(kb, wd, ignore_dir=kb.settings.data_dir)
|
|
566
566
|
watcher.start()
|
|
567
567
|
# 本地监控 Agent(TASK-0017):serve 模式默认启用,仅读配置决定间隔;
|
|
568
568
|
# TestClient 测试默认不启动(monitor_enabled 默认 False,测试按需开)
|
|
@@ -811,11 +811,9 @@ def create_app(settings: Settings | None = None,
|
|
|
811
811
|
try:
|
|
812
812
|
return kb.ask(body.question, agent_id=body.agent_id,
|
|
813
813
|
client=body.client, project=body.project)
|
|
814
|
-
except LLMDisabledError:
|
|
814
|
+
except LLMDisabledError as exc:
|
|
815
815
|
raise HTTPException(status_code=503, detail={
|
|
816
|
-
"error": "LLM_DISABLED",
|
|
817
|
-
"message": "未检测到可用的 LLM:请在 .env 配置 KB_LLM_MODE=local "
|
|
818
|
-
"(Ollama)或 KB_LLM_API_KEY 启用云端(任意 OpenAI 兼容服务商)"})
|
|
816
|
+
"error": "LLM_DISABLED", "message": str(exc)})
|
|
819
817
|
|
|
820
818
|
@app.get("/api/v1/audit")
|
|
821
819
|
def audit(client: str | None = None, project: str | None = None,
|
|
@@ -47,10 +47,16 @@ def _is_supported(path: Path) -> bool:
|
|
|
47
47
|
class KBWatcher:
|
|
48
48
|
"""目录监听器:watchdog Observer 采集事件 + 后台 worker 去抖处理。"""
|
|
49
49
|
|
|
50
|
-
def __init__(self, service, watch_dir: Path, debounce_seconds: float = 2.0
|
|
51
|
-
|
|
50
|
+
def __init__(self, service, watch_dir: Path, debounce_seconds: float = 2.0,
|
|
51
|
+
ignore_dir: Path | None = None):
|
|
52
|
+
"""service 为 KBService;watch_dir 为监听目录(仅顶层,不递归)。
|
|
53
|
+
|
|
54
|
+
ignore_dir 为服务数据目录:与 watch_dir 重合时 start() 跳过监听,
|
|
55
|
+
避免把 bm25_corpus.json 等数据文件反复入库(自我入库死循环)。
|
|
56
|
+
"""
|
|
52
57
|
self.service = service
|
|
53
58
|
self.watch_dir = Path(watch_dir)
|
|
59
|
+
self.ignore_dir = Path(ignore_dir) if ignore_dir is not None else None
|
|
54
60
|
self.debounce_seconds = debounce_seconds
|
|
55
61
|
self._pending: dict[Path, float] = {} # 待入库路径 → 最近一次事件时间
|
|
56
62
|
self._deletes: queue.Queue[str] = queue.Queue() # 待删除 source(文件名)
|
|
@@ -60,6 +66,15 @@ class KBWatcher:
|
|
|
60
66
|
self._worker: threading.Thread | None = None
|
|
61
67
|
|
|
62
68
|
# ---- 生命周期 ----
|
|
69
|
+
def _overlaps_data_dir(self) -> bool:
|
|
70
|
+
"""监听目录是否就是数据目录(相对路径/符号链接解析后比较)。"""
|
|
71
|
+
if self.ignore_dir is None:
|
|
72
|
+
return False
|
|
73
|
+
try:
|
|
74
|
+
return self.watch_dir.resolve() == self.ignore_dir.resolve()
|
|
75
|
+
except OSError:
|
|
76
|
+
return False
|
|
77
|
+
|
|
63
78
|
def start(self) -> None:
|
|
64
79
|
"""启动 watchdog Observer 与后台处理线程。
|
|
65
80
|
|
|
@@ -75,6 +90,11 @@ class KBWatcher:
|
|
|
75
90
|
logger.info("监听目录不存在或不可用,跳过目录监听:%s",
|
|
76
91
|
self.watch_dir)
|
|
77
92
|
return
|
|
93
|
+
if self._overlaps_data_dir():
|
|
94
|
+
logger.warning(
|
|
95
|
+
"监听目录与数据目录相同(%s),已跳过目录监听以避免自我入库;"
|
|
96
|
+
"请把 KB_WATCH_DIR 指向数据目录之外", self.watch_dir)
|
|
97
|
+
return
|
|
78
98
|
self._observer = Observer()
|
|
79
99
|
self._observer.schedule(_EventHandler(self), str(self.watch_dir),
|
|
80
100
|
recursive=False)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kb-memory
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: Local-first agent memory & knowledge service: hybrid retrieval + memory governance (decay / dedup / freshness), REST + MCP dual protocol, fully usable offline without an LLM
|
|
5
5
|
Author: fish827-08
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -60,7 +60,7 @@ Dynamic: license-file
|
|
|
60
60
|
|
|
61
61
|
<!-- GitHub Topics: mcp, memory-service, rag, ai-agent, knowledge-base, local-first, llm, claude-code, hybrid-search, embedding -->
|
|
62
62
|
|
|
63
|
-
**kb** 是本地优先、完全免费的 Agent 记忆与知识服务(v2.1.
|
|
63
|
+
**kb** 是本地优先、完全免费的 Agent 记忆与知识服务(v2.1.2)。
|
|
64
64
|
|
|
65
65
|
> 开源协议:[Apache-2.0](LICENSE)(含专利授权,可商用)。
|
|
66
66
|
|
|
@@ -150,7 +150,7 @@ curl http://127.0.0.1:8000/api/v1/healthz
|
|
|
150
150
|
>
|
|
151
151
|
> **CPU 即可运行,不占显卡**:全新安装默认拿到 CPU 版 torch(`device=cpu`),
|
|
152
152
|
> 不占用 GPU 显存,无独立显卡的机器也能完整使用。有显卡想加速(大库、批量入库)
|
|
153
|
-
> 可另装 CUDA 版 torch
|
|
153
|
+
> 可另装 CUDA 版 torch 后显式 `KB_DEVICE=cuda` 启用 GPU 加速。
|
|
154
154
|
>
|
|
155
155
|
> **LLM 默认关闭(`KB_LLM_MODE=off`)**:服务启动不会探测/加载/调用任何大模型,
|
|
156
156
|
> 零显存、零成本、纯离线;记忆写入、文档入库、混合检索完整可用。
|
|
@@ -398,18 +398,14 @@ python -m kb dedup --threshold 0.92 # 语义去重
|
|
|
398
398
|
```
|
|
399
399
|
kb/ kb 服务源码(config / models / embedder / storage / bm25 / retriever /
|
|
400
400
|
service / llm / ingest / watcher / api / mcp / cli + reranker / sparse / eval)
|
|
401
|
-
tests/ kb 验收测试(
|
|
402
|
-
docs/
|
|
401
|
+
tests/ kb 验收测试(425 项通过 / 1 跳过,含 eval_zh_50.jsonl 检索评测数据集)
|
|
402
|
+
docs/ 用户指南、开发者手册与设计文档
|
|
403
403
|
kb_data/ kb 运行数据(gitignore)
|
|
404
|
-
_archive/ 旧学习项目 + 历史 spec/plan 归档(仅本地保留,禁止参考)
|
|
405
404
|
```
|
|
406
405
|
|
|
407
406
|
## 更多文档
|
|
408
407
|
|
|
409
|
-
-
|
|
410
|
-
- **AI 接力文档(AI 助手入口)**:[PROJECT.md](PROJECT.md)(项目状态 / 进度看板 / 接手指南)
|
|
408
|
+
- **用户使用手册**:[docs/USER_GUIDE.md](docs/USER_GUIDE.md)
|
|
411
409
|
- 设计文档(需求、架构、API、里程碑):`docs/superpowers/specs/2026-08-23-kb-memory-service-design.md`
|
|
412
410
|
- **v2.1 设计(当前)**:`docs/superpowers/specs/2026-10-20-kb-v2.1-design.md`
|
|
413
411
|
- 开发者维护手册:`docs/DEV_HANDBOOK.md`
|
|
414
|
-
- AI 协作规范:`AGENTS.md`
|
|
415
|
-
- 历史 spec / 节点计划已归档到本地 `_archive/docs/`(不上传,不再作为开发依据)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "kb-memory"
|
|
7
|
-
version = "2.1.
|
|
7
|
+
version = "2.1.2"
|
|
8
8
|
description = "Local-first agent memory & knowledge service: hybrid retrieval + memory governance (decay / dedup / freshness), REST + MCP dual protocol, fully usable offline without an LLM"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -51,4 +51,6 @@ def test_禁用转503(env_isolated):
|
|
|
51
51
|
r = c.post("/api/v1/ask", json={"question": "测试"})
|
|
52
52
|
assert r.status_code == 503
|
|
53
53
|
assert r.json()["error"] == "LLM_DISABLED"
|
|
54
|
-
|
|
54
|
+
# 默认 KB_LLM_MODE=off:必须说明是主动关闭,而不是误报 Ollama 不可用
|
|
55
|
+
assert "已关闭" in r.json()["message"]
|
|
56
|
+
assert "KB_LLM_MODE=off" in r.json()["message"]
|
|
@@ -39,3 +39,38 @@ def test_文件删除级联清理(env_isolated):
|
|
|
39
39
|
assert s.list_records(q="将被删除")[1] == 0
|
|
40
40
|
finally:
|
|
41
41
|
w.stop()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_监听目录与数据目录相同时跳过(tmp_path, caplog):
|
|
45
|
+
"""watch_dir == data_dir 时 listener 会把自己的 bm25 语料反复入库,必须跳过。"""
|
|
46
|
+
from kb.watcher import KBWatcher
|
|
47
|
+
|
|
48
|
+
class FakeService:
|
|
49
|
+
def add_document(self, path): # pragma: no cover - 不应被调用
|
|
50
|
+
raise AssertionError("不应入库")
|
|
51
|
+
|
|
52
|
+
data = tmp_path / "data"
|
|
53
|
+
data.mkdir()
|
|
54
|
+
w = KBWatcher(FakeService(), data, ignore_dir=data)
|
|
55
|
+
with caplog.at_level("WARNING", logger="kb.watcher"):
|
|
56
|
+
w.start()
|
|
57
|
+
try:
|
|
58
|
+
assert w._observer is None
|
|
59
|
+
assert w._worker is None
|
|
60
|
+
assert "自我入库" in caplog.text
|
|
61
|
+
finally:
|
|
62
|
+
w.stop()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_监听目录与数据目录不同仍正常监听(tmp_path):
|
|
66
|
+
"""ignore_dir 只拦截与监听目录重合的数据目录,不影响正常监听。"""
|
|
67
|
+
from kb.watcher import KBWatcher
|
|
68
|
+
|
|
69
|
+
watch = tmp_path / "watch"; watch.mkdir()
|
|
70
|
+
data = tmp_path / "data"; data.mkdir()
|
|
71
|
+
w = KBWatcher(object(), watch, ignore_dir=data)
|
|
72
|
+
w.start()
|
|
73
|
+
try:
|
|
74
|
+
assert w._observer is not None and w._worker is not None
|
|
75
|
+
finally:
|
|
76
|
+
w.stop()
|
|
@@ -107,7 +107,7 @@ class FailingFirstPipRunner(FakeRunner):
|
|
|
107
107
|
if "pip install kb-memory" in joined \
|
|
108
108
|
and "--extra-index-url" not in joined:
|
|
109
109
|
return SimpleNamespace(returncode=1, stdout="")
|
|
110
|
-
return SimpleNamespace(returncode=0, stdout="2.1.
|
|
110
|
+
return SimpleNamespace(returncode=0, stdout="2.1.2\n")
|
|
111
111
|
|
|
112
112
|
|
|
113
113
|
def test_pip源缺包时自动官方兜底(boot, tmp_path, capsys):
|
kb_memory-2.1.1/kb/__init__.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|