Accumulate investigation paths and preserve failed attempts across rounds. Keep graph annotations separate from execution state, synchronize the API contract, and consolidate documentation.
95 lines
3.7 KiB
Python
95 lines
3.7 KiB
Python
from uuid import uuid4
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from app.domain.schemas.operational_task import (
|
|
AgentArtifactsCommand,
|
|
InvestigationDiagramNodeRef,
|
|
InvestigationProgress,
|
|
InvestigationReportInput,
|
|
)
|
|
|
|
|
|
def test_waiting_and_unknown_node_states_survive_progress_and_final_report():
|
|
diagram = {
|
|
"title": "等待系统结果",
|
|
"mermaid": "flowchart LR\nDONE --> WAIT --> UNKNOWN --> UNSET",
|
|
"node_refs": [
|
|
{"node_id": "DONE", "label": "查询完成", "status": "completed"},
|
|
{"node_id": "WAIT", "label": "等待系统结果", "status": "waiting"},
|
|
{"node_id": "UNKNOWN", "label": "未知", "status": None},
|
|
{"node_id": "UNSET", "label": "未确认"},
|
|
],
|
|
}
|
|
progress = InvestigationProgress(summary="等待系统结果", diagram=diagram)
|
|
report = InvestigationReportInput(
|
|
title="报告", current_conclusion="已确认当前结果", conclusion_boundary="仅限查询范围",
|
|
stage="final", outcome="concluded", data_gaps=[], diagram=diagram,
|
|
)
|
|
assert report.diagram == progress.diagram
|
|
assert [node.status for node in report.diagram.node_refs] == ["recorded", "needs_input", None, None]
|
|
assert "status" not in report.diagram.node_refs[-1].model_fields_set
|
|
|
|
|
|
def test_unknown_node_state_is_rejected():
|
|
with pytest.raises(ValidationError):
|
|
InvestigationDiagramNodeRef(node_id="A", label="查询", status="blocked")
|
|
|
|
|
|
def test_class_attached_nodes_are_valid_declarations_without_accepting_partial_ids():
|
|
payload = {"request_id": uuid4(), "source_session_id": "session-1", "progress": {
|
|
"summary": "核查", "diagram": {"title": "路线", "mermaid": "flowchart TD\nQUERY:::running --> REVIEW:::pending",
|
|
"node_refs": [{"node_id": "QUERY", "label": "核查", "status": "running"},
|
|
{"node_id": "REVIEW", "label": "复核", "status": "pending"}]},
|
|
}}
|
|
assert AgentArtifactsCommand.model_validate(payload).progress.diagram.node_refs[0].status == "reference"
|
|
payload["progress"]["diagram"]["node_refs"][0]["node_id"] = "QUER"
|
|
with pytest.raises(ValidationError, match="QUER"):
|
|
AgentArtifactsCommand.model_validate(payload)
|
|
|
|
|
|
@pytest.mark.parametrize("artifact", ["progress", "report"])
|
|
def test_artifact_write_rejects_node_refs_missing_from_mermaid(artifact):
|
|
diagram = {
|
|
"title": "当前路线",
|
|
"mermaid": "flowchart TD\nA[绑定任务] --> B[核查证据]",
|
|
"node_refs": [
|
|
{"node_id": "ctx", "label": "绑定任务", "status": "completed"},
|
|
{"node_id": "B", "label": "核查证据", "status": "running"},
|
|
],
|
|
}
|
|
payload = (
|
|
{"summary": "正在核查", "diagram": diagram}
|
|
if artifact == "progress"
|
|
else {
|
|
"title": "调查报告",
|
|
"current_conclusion": "已确认当前范围",
|
|
"conclusion_boundary": "仅限已核查资料",
|
|
"stage": "final",
|
|
"outcome": "concluded",
|
|
"data_gaps": [],
|
|
"diagram": diagram,
|
|
}
|
|
)
|
|
|
|
with pytest.raises(ValidationError, match="ctx"):
|
|
AgentArtifactsCommand.model_validate({
|
|
"request_id": uuid4(),
|
|
"source_session_id": "session-1",
|
|
artifact: payload,
|
|
})
|
|
|
|
|
|
def test_historical_progress_keeps_read_compatibility_for_undeclared_node_refs():
|
|
progress = InvestigationProgress.model_validate({
|
|
"summary": "旧进度",
|
|
"diagram": {
|
|
"title": "旧图",
|
|
"mermaid": "flowchart TD\nA[绑定任务]",
|
|
"node_refs": [{"node_id": "ctx", "label": "绑定任务", "status": "completed"}],
|
|
},
|
|
})
|
|
|
|
assert progress.diagram.node_refs[0].node_id == "ctx"
|