84 lines
3.3 KiB
Python
84 lines
3.3 KiB
Python
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
|