zcbot/tests/test_kb_block.py

78 lines
2.9 KiB
Python

"""kb_block 注入契约:零库冷启动 vs 有库全量。
背景(2026-07-24):零库时 kb_block 返回空串,agent 不知道 KB 机制存在,用户说
「放进我的知识库」被就近写进 .memory/。修复 = 零库注极简冷启动契约(建库步骤 +
INDEX 行格式 + 知识库/记忆分工),与 memory 空契约常驻同一课。本测试锁住两个分支。
"""
from __future__ import annotations
import sys
import tempfile
import unittest
from pathlib import Path
from uuid import UUID
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from core.kb import ( # noqa: E402
INDEX_LINE_FORMAT,
create_kb,
format_index_line,
kb_block,
)
_UID = UUID("6b14d2ab-7a6e-4d0b-8562-ea62a801e32c")
class TestKbBlock(unittest.TestCase):
def setUp(self):
self.ws = Path(tempfile.mkdtemp()) / "workspace"
def test_cold_start_injects_minimal_contract(self):
block = kb_block(self.ws, _UID, "/workspace/.kb")
# 机制存在 + 建库/入库指引 + 行格式契约都在
self.assertIn("个人知识库", block)
self.assertIn("还没有任何知识库", block)
self.assertIn("/workspace/.kb/<库名>/docs/", block)
self.assertIn(INDEX_LINE_FORMAT, block)
# 与记忆的分工写明(误写 .memory 正是要防的失败模式)
self.assertIn("短事实才写记忆", block)
# 冷启动块不含任何库清单
self.assertNotIn("### 库「", block)
def test_cold_start_host_path_display(self):
block = kb_block(self.ws, _UID, None)
root = self.ws / "users" / str(_UID) / ".kb"
self.assertIn(str(root), block)
def test_with_kb_injects_full_index(self):
d = create_kb(self.ws, _UID, "标准库")
assert d is not None
line = format_index_line(
title="水泥胶砂强度检验方法",
doc="docs/gbt17671.md",
source="sources/gbt17671.pdf",
summary="ISO 法测定水泥胶砂抗压抗折强度。",
keywords="水泥,强度,GB/T 17671",
)
(d / "INDEX.md").write_text(f"# 标准库\n\n{line}\n", encoding="utf-8")
block = kb_block(self.ws, _UID, "/workspace/.kb")
# 全量分支:库清单 + 条目 + 完整契约(对话内入库段)
self.assertIn("### 库「标准库」", block)
self.assertIn("水泥胶砂强度检验方法", block)
self.assertIn("对话内入库", block)
# 冷启动文案不应出现
self.assertNotIn("还没有任何知识库", block)
def test_empty_kb_counts_as_having_kb(self):
# 建了库但零文档:走全量分支(注库名 + 空库提示),不再是冷启动
create_kb(self.ws, _UID, "新库")
block = kb_block(self.ws, _UID, "/workspace/.kb")
self.assertIn("### 库「新库」", block)
self.assertIn("空库", block)
self.assertNotIn("还没有任何知识库", block)
if __name__ == "__main__":
unittest.main()