forked from admin/PlantAI-rag-new
- paper_writer_service(8097):FastAPI + MCP streamable-http 单端点,9 工具
(propose_paper_outline/write_paper_section/get_paper_progress/search_refs/
revise_paper_section/revise_paper/get_paper/complete_paper/cancel_paper),
SQLite 三表(papers/paper_sections/citations,WAL),GB/T 7714 引用协议
- BFF:services/paper/{mcp_client,agent}.py(裸 JSON-RPC 客户端 + 规则状态机)、
routers/paper.py、schemas.py 4 个 Paper*Block + ArtifactBlock 加 paper_id/citation_count、
config.py 开关、main.py 条件注册、docgen.py 抽 insert_artifact 公共 helper
- 前端:intent.js paperIntent 纯函数、Composer docgen 分支 sub-route、sendPaper/轮询、
PaperBriefCard/PaperOutlineCard/PaperProgressCard、DocPane cite-chip
- deploy/paper_restart.sh + toggle_paper.sh;compile_sdk.sh 白名单追加 paper 文件
- tests/paper 26 条(工具逻辑 + MCP 协议 + BFF 状态机 + 块 schema + 前端 intent 单测)
36 lines
1.2 KiB
Python
36 lines
1.2 KiB
Python
"""tests/paper/test_paper_blocks_schema.py —— 块 schema 回归(未知块拒绝 + 新块通过)。"""
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from pydantic import TypeAdapter
|
|
|
|
from app import schemas
|
|
|
|
_BLOCK = TypeAdapter(schemas.Block)
|
|
|
|
|
|
def test_paper_blocks_validate():
|
|
cases = [
|
|
{"type": "paper_brief", "paper_id": "p1", "status": "pending", "fields": []},
|
|
{"type": "paper_outline", "paper_id": "p1", "title": "t", "status": "pending", "sections": []},
|
|
{"type": "paper_progress", "paper_id": "p1", "status": "writing", "sections": [], "current_section_id": ""},
|
|
{"type": "paper_refs", "paper_id": "p1", "references": [], "disclaimer": ""},
|
|
]
|
|
for c in cases:
|
|
b = _BLOCK.validate_python(c)
|
|
assert b.type == c["type"]
|
|
|
|
|
|
def test_artifact_block_paper_fields():
|
|
b = _BLOCK.validate_python({
|
|
"type": "artifact", "artifact_id": "a1", "title": "t",
|
|
"paper_id": "p1", "citation_count": 3,
|
|
})
|
|
assert b.paper_id == "p1"
|
|
assert b.citation_count == 3
|
|
|
|
|
|
def test_unknown_block_rejected():
|
|
with pytest.raises(Exception):
|
|
_BLOCK.validate_python({"type": "totally_unknown_block"})
|