from app.schemas.steward import StewardRuntimeDecisionRequest from app.services.steward_runtime_decision_agent import ( STEWARD_RUNTIME_DECISION_FUNCTION_NAME, StewardRuntimeDecisionAgent, ) class _FakeToolCall: def __init__(self, name, arguments): self.name = name self.arguments = arguments class _FakeRuntimeResult: def __init__(self, tool_call=None): self.tool_call = tool_call def calls_as_dicts(self): return [{"tool": self.tool_call.name if self.tool_call else ""}] class _FakeRuntime: def __init__(self, payload): self.payload = payload self.last_messages = [] self.last_tools = [] self.last_tool_choice = None def complete_with_tool_call(self, messages, tools, tool_choice, **kwargs): self.last_messages = messages self.last_tools = tools self.last_tool_choice = tool_choice if self.payload is None: return _FakeRuntimeResult() return _FakeRuntimeResult(_FakeToolCall(STEWARD_RUNTIME_DECISION_FUNCTION_NAME, self.payload)) def test_steward_runtime_decision_uses_function_calling_context(): runtime = _FakeRuntime( { "next_action": "submit_current_application", "target_task_id": "task-application-beijing", "target_message_id": "msg-application-preview", "field_key": "", "field_value": "", "confirmation_required": False, "question": "", "response_text": "", "rationale": "用户确认当前申请核对表无误。", } ) result = StewardRuntimeDecisionAgent(runtime).decide( StewardRuntimeDecisionRequest( user_message="确认", runtime_state={ "waiting_for": "application_submit_confirmation", "pending_application": { "message_id": "msg-application-preview", "task_id": "task-application-beijing", "ready_to_submit": True, }, "remaining_tasks": [ {"task_id": "task-reimbursement-meal", "task_type": "reimbursement"} ], }, ) ) assert result.decision_source == "llm_function_call" assert result.next_action == "submit_current_application" assert result.target_message_id == "msg-application-preview" assert result.target_task_id == "task-application-beijing" assert runtime.last_tool_choice["function"]["name"] == STEWARD_RUNTIME_DECISION_FUNCTION_NAME assert "runtime_state" in runtime.last_messages[-1]["content"] def test_steward_runtime_decision_fallback_keeps_current_context(): runtime = _FakeRuntime(None) result = StewardRuntimeDecisionAgent(runtime).decide( StewardRuntimeDecisionRequest( user_message="确认", runtime_state={ "pending_steward_action": { "message_id": "msg-next-task", "target_task_id": "task-reimbursement-meal", } }, ) ) assert result.decision_source == "rule_fallback" assert result.next_action == "continue_next_task" assert result.target_message_id == "msg-next-task" assert result.target_task_id == "task-reimbursement-meal" def test_steward_runtime_decision_fallback_reads_persisted_steward_state(): runtime = _FakeRuntime(None) result = StewardRuntimeDecisionAgent(runtime).decide( StewardRuntimeDecisionRequest( user_message="我坐高铁", runtime_state={}, context_json={ "conversation_state": { "steward_state": { "active_flow": "travel_application", "flows": { "travel_application": { "flow_id": "travel_application", "intent": "travel_application_create", "fields": { "expense_type": "travel", "time_range": "2026-07-02", "location": "北京", "reason": "客户现场支撑", }, "missing_fields": ["transport_mode"], } }, } } }, ) ) assert result.decision_source == "rule_fallback" assert result.next_action == "fill_current_slot" assert result.target_task_id == "travel_application" assert result.field_key == "transport_mode" assert result.field_value == "我坐高铁" assert result.steward_state["flows"]["travel_application"]["fields"]["transport_mode"] == "我坐高铁" assert result.steward_state["flows"]["travel_application"]["missing_fields"] == [] def test_steward_runtime_decision_fallback_confirms_selected_flow(): runtime = _FakeRuntime(None) result = StewardRuntimeDecisionAgent(runtime).decide( StewardRuntimeDecisionRequest( user_message="补办出差申请", runtime_state={}, context_json={ "conversation_state": { "steward_state": { "version": "steward.flow_state.v2", "active_flow": "", "pending_flow_confirmation": { "status": "pending", "source_message": "2月20-23日去上海出差辅助国网仿生产环境部署", "reason": "缺少申请或报销动作词。", "candidate_flows": [ { "flow_id": "travel_application", "label": "补办出差申请", "confidence": 0.52, }, { "flow_id": "travel_reimbursement", "label": "发起费用报销", "confidence": 0.48, }, ], }, "flows": { "travel_application": { "flow_id": "travel_application", "intent": "travel_application_create", "status": "pending_flow_confirmation", "fields": { "time_range": "2026-02-20", "location": "上海", "expense_type": "travel", "reason": "辅助国网仿生产环境部署", }, "missing_fields": ["transport_mode"], }, "travel_reimbursement": { "flow_id": "travel_reimbursement", "intent": "travel_reimbursement_draft", "status": "pending_flow_confirmation", "fields": { "time_range": "2026-02-20", "location": "上海", "expense_type": "travel", "reason": "辅助国网仿生产环境部署", }, "missing_fields": [], }, }, } } }, ) ) assert result.decision_source == "rule_fallback" assert result.next_action == "continue_selected_flow" assert result.target_task_id == "travel_application" assert result.steward_state["active_flow"] == "travel_application" assert result.steward_state["pending_flow_confirmation"]["status"] == "confirmed" assert result.steward_state["flows"]["travel_application"]["status"] == "collecting" def test_steward_runtime_decision_fallback_confirms_reimbursement_flow(): runtime = _FakeRuntime(None) result = StewardRuntimeDecisionAgent(runtime).decide( StewardRuntimeDecisionRequest( user_message="发起费用报销", runtime_state={ "steward_state": { "version": "steward.flow_state.v2", "active_flow": "", "pending_flow_confirmation": { "status": "pending", "candidate_flows": [ {"flow_id": "travel_application", "label": "补办出差申请"}, {"flow_id": "travel_reimbursement", "label": "发起费用报销"}, ], }, "flows": { "travel_reimbursement": { "flow_id": "travel_reimbursement", "intent": "travel_reimbursement_draft", "status": "pending_flow_confirmation", "fields": { "time_range": "2026-02-20", "location": "上海", "expense_type": "travel", "reason": "辅助国网仿生产环境部署", }, "missing_fields": [], } }, } }, ) ) assert result.decision_source == "rule_fallback" assert result.next_action == "continue_selected_flow" assert result.target_task_id == "travel_reimbursement" assert result.steward_state["active_flow"] == "travel_reimbursement" assert result.steward_state["pending_flow_confirmation"]["status"] == "confirmed"