diff --git a/agent_core/structured_output.py b/agent_core/structured_output.py index 262fb3a..d1d48ee 100644 --- a/agent_core/structured_output.py +++ b/agent_core/structured_output.py @@ -83,6 +83,7 @@ OUTPUT_FIELD_TEMPLATES = { "registration_word_export_report": { "summary": "", "export_status": "draft_only", + "can_export_formally": False, "blocked_items": [], "download_url": "", }, diff --git a/apps/chat/views.py b/apps/chat/views.py index 50a10a0..9984196 100644 --- a/apps/chat/views.py +++ b/apps/chat/views.py @@ -161,13 +161,18 @@ def _build_workspace_summary(conversation: Conversation, batch: SubmissionBatch notify_status = node_status_map.get("飞书通知", "待处理") export_status = node_status_map.get("Word 回填导出", "待处理") highest_risk_level = "高" if risk_status in {"已阻断", "待复核"} else "中" + latest_summary = conversation.latest_summary or {} + structured_output = latest_summary.get("structured_output") or {} + explicit_export_flag = structured_output.get("can_export_formally") export_allowed = ( - "否" + "是" + if explicit_export_flag is True + else "否" + if explicit_export_flag is False + else "否" if risk_status in {"已阻断", "待复核"} or export_status in {"已阻断", "待复核", "失败"} else "是" ) - latest_summary = conversation.latest_summary or {} - structured_output = latest_summary.get("structured_output") or {} return { "highest_risk_level": highest_risk_level, "export_allowed": export_allowed, diff --git a/tests/test_agent_core.py b/tests/test_agent_core.py index c685210..c469053 100644 --- a/tests/test_agent_core.py +++ b/tests/test_agent_core.py @@ -511,3 +511,40 @@ def test_feishu_notification_report_builds_notification_payload_with_receipt_and assert result.notification_payload["message_status"] == "sent" assert result.notification_payload["web_detail_url"] == "https://example.com/audit/3" assert result.notification_payload["receipt"]["message_id"] == "msg-3" + + +def test_registration_word_export_report_preserves_formal_export_flag_and_blocked_items(): + scenario = { + "id": "document_review", + "name": "注册审核智能体", + "agent": { + "role": "注册审核助手", + "goal": "输出导出结果", + "instructions": ["输出结构化导出结果"], + }, + "rag": {"enabled": False}, + "tools": [], + "output": {"type": "registration_word_export_report"}, + } + provider_response = """ + { + "summary": "已生成草稿导出包。", + "export_status": "draft_only", + "can_export_formally": false, + "blocked_items": ["风险项未清零", "需人工复核后再导出"], + "download_url": "/downloads/registration-draft.docx" + } + """ + + class FakeProvider: + def generate(self, messages, response_format=None): + from agent_core.llm_provider import LLMResponse + + return LLMResponse(content=provider_response, model_name="demo-model", success=True) + + result = run_agent(scenario, "请输出导出结果", options={"llm_provider": FakeProvider()}) + + assert result.structured_output["can_export_formally"] is False + assert result.structured_output["download_url"] == "/downloads/registration-draft.docx" + assert result.structured_output["blocked_items"] == ["风险项未清零", "需人工复核后再导出"] + assert result.node_results[6]["status"] == "待复核" diff --git a/tests/test_chat.py b/tests/test_chat.py index da32432..0d932c6 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -401,6 +401,35 @@ def test_chat_page_blocks_formal_export_when_word_export_node_is_blocked(client, assert "/downloads/export.docx" in content +def test_chat_page_uses_structured_formal_export_flag_when_node_status_is_completed(client, db): + batch, conversation = _create_conversation_with_batch() + conversation.node_results = [ + {"label": "资料包导入", "status": "已完成"}, + {"label": "目录汇总", "status": "已完成"}, + {"label": "法规完整性检查", "status": "已完成"}, + {"label": "字段抽取", "status": "已完成"}, + {"label": "一致性核查", "status": "已完成"}, + {"label": "风险预警", "status": "已完成"}, + {"label": "Word 回填导出", "status": "已完成"}, + {"label": "飞书通知", "status": "待处理"}, + ] + conversation.latest_summary = { + "structured_output": { + "can_export_formally": False, + "download_url": "/downloads/review-only.docx", + } + } + conversation.save(update_fields=["node_results", "latest_summary", "updated_at"]) + + response = client.get(reverse("chat:detail", args=[conversation.conversation_id])) + + content = response.content.decode("utf-8") + assert response.status_code == 200 + assert "是否允许正式导出" in content + assert ">否<" in content + assert "/downloads/review-only.docx" in content + + def test_chat_upload_keeps_existing_conversation_binding_and_adds_documents(client, db): batch, conversation = _create_conversation_with_batch() existing_document = UploadedDocument.objects.create(