PMFlow/backend/tests/test_pmflow_ai_answer_verif...

84 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import inspect
from app.schemas.rag import RAGAskRequest
from app.services.pmflow_ai_answer_verifier_registry import PMFlowAIAnswerVerifierRegistry
from app.services.pmflow_ai_static_contract_registry import PMFlowAIStaticContractRegistry
from app.services.pmflow_ai_turn_runtime_service import PMFlowAITurnRuntimeService
def _service() -> PMFlowAITurnRuntimeService:
return PMFlowAITurnRuntimeService(object(), tenant_id=1)
def _assistant_identity_state():
return _service().build_initial_turn_state(
request=RAGAskRequest(question="说明你的能力边界"),
route_plan={},
turn_hypothesis={
"normalized_goal": "assistant_identity",
"desired_outcome": "说明助手身份和能力边界",
"answer_shape": "general_answer",
"goal_frames": [
{
"frame_id": "assistant-profile",
"operation_kind": "explain_assistant",
"target_scope": {
"scope_type": "current_space",
"binding_strength": "surface",
"source": "turn_goal_assessment",
},
"target_object_requirement": "none",
"source_policy": "none",
"answer_shape": "general_answer",
"confidence": 0.9,
}
],
"operation_gaps": [],
},
)
def test_packet_ah_static_contract_verifier_rejects_mismatched_final_answer() -> None:
state = _assistant_identity_state()
payload = {
"_runtime_payload_kind": "final_answer",
"answer": "我还没有拿到足够证据来做这轮判断。",
"customer_evidence_packet": {"source_summary": []},
}
failure = PMFlowAIAnswerVerifierRegistry().verify_payload(turn_state=state, payload=payload)
assert failure is not None
assert failure.failure_type == "static_contract_mismatch"
assert failure.next_action_hint == "synthesize_answer"
assert failure.state_patch["needs_internal_evidence"] is False
def test_packet_ah_static_contract_verifier_accepts_registered_contract_payload() -> None:
state = _assistant_identity_state()
contract = PMFlowAIStaticContractRegistry().resolve_for_turn_state(state)
assert contract is not None
payload = {
"_runtime_payload_kind": "final_answer",
"answer": "我是 PMFlow AI,是 PMFlow 里的项目操作副驾。",
"customer_evidence_packet": {"source_summary": list(contract.source_summary)},
"answer_runtime_packet": {
"objective": {"evidence_to_use": list(contract.source_summary)},
"plan": {"draft_sources": ["产品能力或披露边界合同"]},
"draft": {"source_renderer": "产品能力或披露边界合同"},
},
}
failure = _service()._verify_runtime_payload(turn_state=state, payload=payload)
assert failure is None
def test_packet_ah_runtime_payload_verifier_delegates_to_registry() -> None:
source = inspect.getsource(PMFlowAITurnRuntimeService._verify_runtime_payload)
assert "PMFlowAIAnswerVerifierRegistry" in source
assert "wrong_source_or_missing_project_operating_state" not in source
assert "goal_fulfillment_missing_project_operating_facets" not in source
assert "interaction_not_user_actionable" not in source