from __future__ import annotations from app.schemas.steward import ( StewardCandidateFlow, StewardFlowStatePatch, StewardPendingFlowConfirmation, StewardPlanResponse, ) from app.services.steward_flow_state import StewardFlowStateService def test_state_merge_keeps_application_and_reimbursement_flows() -> None: service = StewardFlowStateService() state = service.merge_state( {}, StewardFlowStatePatch( active_flow="travel_application", flow_id="travel_application", intent="travel_application_create", fields={"expense_type": "travel", "location": "上海", "reason": "客户现场支撑"}, missing_fields=["transport_mode"], ), ) state = service.merge_state( state, StewardFlowStatePatch( active_flow="travel_reimbursement", flow_id="travel_reimbursement", intent="travel_reimbursement_draft", fields={"amount": "708.00", "invoice_no": "NO-1"}, linked_application_claim_id="claim-app-001", ), ) assert state["active_flow"] == "travel_reimbursement" assert state["flows"]["travel_application"]["fields"]["location"] == "上海" assert state["flows"]["travel_application"]["missing_fields"] == ["transport_mode"] assert state["flows"]["travel_reimbursement"]["fields"]["amount"] == "708.00" assert state["flows"]["travel_reimbursement"]["linked_application_claim_id"] == "claim-app-001" def test_state_merge_filters_non_ontology_fields() -> None: service = StewardFlowStateService() state = service.merge_state( {}, StewardFlowStatePatch( active_flow="travel_application", flow_id="travel_application", intent="travel_application_create", fields={ "location": "上海", "invented_field": "x", "occurred_date": "2026-06-15", }, ), ) assert state["flows"]["travel_application"]["fields"] == { "location": "上海", "time_range": "2026-06-15", } def test_state_merge_appends_traceable_events() -> None: service = StewardFlowStateService() state = service.merge_state( {}, StewardFlowStatePatch( active_flow="travel_application", flow_id="travel_application", intent="travel_application_create", fields={"location": "北京"}, evidence=[{"source": "user_message", "field": "location", "text": "去北京出差"}], ), ) assert len(state["events"]) == 1 assert state["events"][0]["flow_id"] == "travel_application" assert state["events"][0]["intent"] == "travel_application_create" assert state["events"][0]["fields"] == {"location": "北京"} assert state["events"][0]["evidence"][0]["text"] == "去北京出差" def test_state_merge_plan_keeps_pending_flow_confirmation() -> None: service = StewardFlowStateService() state = service.merge_plan( {}, StewardPlanResponse( plan_id="steward_plan_pending", plan_status="needs_flow_confirmation", planning_source="llm_function_call", next_action="confirm_flow", summary="需要先确认是申请还是报销。", pending_flow_confirmation=StewardPendingFlowConfirmation( status="pending", source_message="2月20-23日去上海出差辅助国网仿生产环境部署", reason="缺少申请或报销动作词。", candidate_flows=[ StewardCandidateFlow( flow_id="travel_application", label="补办出差申请", confidence=0.52, reason="可能是补办申请。", ontology_fields={ "time_range": "2026-02-20", "location": "上海", "expense_type": "travel", "reason": "辅助国网仿生产环境部署", }, missing_fields=["transport_mode"], ), StewardCandidateFlow( flow_id="travel_reimbursement", label="发起费用报销", confidence=0.48, reason="可能是发起报销。", ontology_fields={ "time_range": "2026-02-20", "location": "上海", "expense_type": "travel", "reason": "辅助国网仿生产环境部署", }, ), ], ), ), ) assert state["active_flow"] == "" assert state["pending_flow_confirmation"]["status"] == "pending" assert state["flows"]["travel_application"]["status"] == "pending_flow_confirmation" assert state["flows"]["travel_application"]["fields"]["location"] == "上海" assert state["flows"]["travel_application"]["missing_fields"] == ["transport_mode"] assert state["flows"]["travel_reimbursement"]["fields"]["time_range"] == "2026-02-20"