158 lines
5.6 KiB
Python
158 lines
5.6 KiB
Python
import time
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
import app.services.pmflow_ai_turn_runtime_service as runtime_module
|
|
from app.schemas.rag import RAGAskRequest
|
|
from app.services.customer_answer_presentation_service import CustomerAnswerPresentationService
|
|
from app.services.pmflow_ai_turn_runtime_service import (
|
|
PMFlowAITurnRuntimeService,
|
|
_apply_project_operating_answer_verification_to_answer,
|
|
_apply_project_operating_answer_verification_to_canvas,
|
|
_apply_project_operating_answer_verification_to_packet,
|
|
)
|
|
|
|
|
|
def _service() -> PMFlowAITurnRuntimeService:
|
|
return PMFlowAITurnRuntimeService(object(), tenant_id=1)
|
|
|
|
|
|
def _project_followup_state():
|
|
return _service().build_initial_turn_state(
|
|
request=RAGAskRequest(question="这个项目今天怎么推进"),
|
|
route_plan={},
|
|
turn_hypothesis={
|
|
"normalized_goal": "项目推进建议",
|
|
"desired_outcome": "基于项目运行态给出下一步",
|
|
"answer_shape": "execution_guidance",
|
|
"goal_frames": [
|
|
{
|
|
"frame_id": "project-followup",
|
|
"operation_kind": "inspect_object",
|
|
"target_scope": {"scope_type": "current_project", "binding_strength": "explicit"},
|
|
"target_object_requirement": "single",
|
|
"source_policy": "internal",
|
|
"answer_shape": "execution_guidance",
|
|
"confidence": 0.82,
|
|
}
|
|
],
|
|
"operation_gaps": [],
|
|
},
|
|
)
|
|
|
|
|
|
def _unsafe_project_verification() -> dict:
|
|
return {
|
|
"packet_version": "project_operating_answer_verification.v1",
|
|
"project_ref": "project:141",
|
|
"safe_next_actions": [
|
|
{
|
|
"display_label": "整理加密评审材料",
|
|
"safety": "prepare_only",
|
|
"reason": "来自项目运行态证据。",
|
|
"target_ref": "project:141",
|
|
},
|
|
{
|
|
"display_label": "TurnState runtime_steps 不应展示",
|
|
"safety": "prepare_only",
|
|
"reason": "problem_frame 不应展示",
|
|
"target_ref": "project:141",
|
|
},
|
|
],
|
|
"blocked_actions": [
|
|
{
|
|
"display_label": "PMFlowAITurnState 不应展示",
|
|
"safety": "blocked",
|
|
"reason": "answer_runtime_packet 不应展示",
|
|
"target_ref": "project:141",
|
|
}
|
|
],
|
|
"answer_boundaries": [
|
|
"测试质量证据不足,不能当成已验证结论。",
|
|
"evidence_findings 不应展示。",
|
|
],
|
|
"can_claim_full_execution_guidance": False,
|
|
}
|
|
|
|
|
|
def test_packet_aq_project_verification_projection_filters_internal_runtime_terms() -> None:
|
|
verification = _unsafe_project_verification()
|
|
|
|
answer = _apply_project_operating_answer_verification_to_answer(
|
|
answer="当前可以继续推进。",
|
|
verification=verification,
|
|
)
|
|
packet = _apply_project_operating_answer_verification_to_packet(
|
|
packet={"limitations": [], "suggested_actions": []},
|
|
verification=verification,
|
|
)
|
|
canvas = _apply_project_operating_answer_verification_to_canvas(
|
|
canvas={"limitations": [], "next_actions": []},
|
|
verification=verification,
|
|
)
|
|
|
|
joined = "\n".join(
|
|
[
|
|
answer,
|
|
str(packet.get("limitations")),
|
|
str(packet.get("suggested_actions")),
|
|
str(canvas.get("limitations")),
|
|
str(canvas.get("next_actions")),
|
|
]
|
|
)
|
|
assert "整理加密评审材料" in joined
|
|
assert "测试质量证据不足" in joined
|
|
assert "TurnState" not in joined
|
|
assert "runtime_steps" not in joined
|
|
assert "problem_frame" not in joined
|
|
assert "PMFlowAITurnState" not in joined
|
|
assert "answer_runtime_packet" not in joined
|
|
assert "evidence_findings" not in joined
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_packet_aq_quality_gate_runs_after_project_verification_amendments(monkeypatch) -> None:
|
|
service = _service()
|
|
state = _project_followup_state()
|
|
|
|
async def render_base_answer(*, request, turn_state):
|
|
_ = request, turn_state
|
|
return "当前可以继续推进。"
|
|
|
|
def unsafe_verification(turn_state):
|
|
_ = turn_state
|
|
return _unsafe_project_verification()
|
|
|
|
monkeypatch.setattr(service, "_render_answer_from_registry", render_base_answer)
|
|
monkeypatch.setattr(runtime_module, "_project_operating_answer_verification_packet", unsafe_verification)
|
|
|
|
payload = await service._run_state_answer_synthesis(
|
|
request=RAGAskRequest(question="这个项目今天怎么推进"),
|
|
current_user=SimpleNamespace(id=1, tenant_id=1),
|
|
route_plan={},
|
|
turn_state=state,
|
|
presentation_service=CustomerAnswerPresentationService(object(), tenant_id=1),
|
|
started_at=time.perf_counter(),
|
|
)
|
|
|
|
joined = "\n".join(
|
|
[
|
|
str(payload.get("answer")),
|
|
str(payload.get("answer_runtime_packet")),
|
|
str(payload.get("customer_evidence_packet")),
|
|
str(payload.get("answer_canvas")),
|
|
]
|
|
)
|
|
assert "整理加密评审材料" in joined
|
|
assert "测试质量证据不足" in joined
|
|
assert "TurnState" not in joined
|
|
assert "runtime_steps" not in joined
|
|
assert "problem_frame" not in joined
|
|
assert "PMFlowAITurnState" not in joined
|
|
assert "answer_runtime_packet 不应展示" not in joined
|
|
assert "evidence_findings" not in joined
|
|
assert " ".join(payload["answer_runtime_packet"]["draft"]["answer_text"].split()) == " ".join(
|
|
payload["answer"].split()
|
|
)
|