From 2b40ddc487f843dc36e4b9f621edeabbec14d81a Mon Sep 17 00:00:00 2001 From: bruce Date: Thu, 4 Jun 2026 01:02:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8C=81=E4=B9=85=E5=8C=96=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E8=8A=82=E7=82=B9=E7=BB=93=E6=9E=9C=E4=B8=8E=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E9=80=9A=E7=9F=A5=E7=95=99=E7=97=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat/views.py | 25 ++++++++++++ tests/test_chat.py | 100 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/apps/chat/views.py b/apps/chat/views.py index 74d0f7d..a025919 100644 --- a/apps/chat/views.py +++ b/apps/chat/views.py @@ -1,3 +1,4 @@ +from django.utils import timezone from django.shortcuts import get_object_or_404, redirect, render from agent_core.orchestrator import run_agent @@ -70,8 +71,10 @@ def detail(request, conversation_id: str): conversation_id=conversation.conversation_id, product_name=conversation.product_name, ) + _apply_agent_result_to_conversation(conversation, result) _persist_notification_records(result) active_node = "risk" + conversation.refresh_from_db() workspace_summary = _build_workspace_summary(conversation, batch) return render( @@ -129,3 +132,25 @@ def _build_workspace_summary(conversation: Conversation, batch: SubmissionBatch "file_count": batch.file_count if batch else 0, "page_count": batch.page_count if batch else 0, } + + +def _apply_agent_result_to_conversation(conversation: Conversation, result: AgentResult) -> None: + conversation.task_status = result.status + if result.node_results: + conversation.node_results = result.node_results + conversation.latest_summary = { + "answer": result.answer, + "status": result.status, + "error": result.error, + "notification_payload": result.notification_payload, + } + conversation.last_run_at = timezone.now() + conversation.save( + update_fields=[ + "task_status", + "node_results", + "latest_summary", + "last_run_at", + "updated_at", + ] + ) diff --git a/tests/test_chat.py b/tests/test_chat.py index e314a49..a8daa12 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -172,6 +172,106 @@ def test_chat_execution_creates_notification_record_from_agent_result(client, db assert record.batch_id == batch.batch_id +def test_chat_execution_creates_failed_notification_record_and_updates_conversation(client, db, monkeypatch): + batch, conversation = _create_conversation_with_batch() + UploadedDocument.objects.create( + batch=batch, + scenario_id="document_review", + original_name="说明书.md", + file_type="md", + size=1, + status=UploadedDocument.STATUS_INDEXED, + ) + + monkeypatch.setattr( + "apps.chat.views.run_agent", + lambda *args, **kwargs: AgentResult( + answer="执行失败", + status="failed", + error="规则执行失败", + node_results=[ + {"code": "package_import", "label": "资料包导入", "status": "已完成"}, + {"code": "overview", "label": "目录汇总", "status": "已完成"}, + {"code": "risk", "label": "风险预警", "status": "已阻断"}, + {"code": "feishu_notify", "label": "飞书通知", "status": "失败"}, + ], + notification_payload={ + "batch_id": batch.batch_id, + "conversation_id": conversation.conversation_id, + "product_name": batch.product_name, + "notify_reason": "task_failed", + "owners": [ + { + "owner_role": "注册申报负责人", + "feishu_user_id": "ou_demo_2", + } + ], + }, + ), + ) + + response = client.post( + reverse("chat:detail", args=[conversation.conversation_id]), + {"message": "执行失败任务"}, + ) + + assert response.status_code == 200 + record = NotificationRecord.objects.get() + conversation.refresh_from_db() + assert record.notify_reason == "task_failed" + assert record.message_status == "failed" + assert conversation.task_status == "failed" + assert conversation.node_results[-1]["label"] == "飞书通知" + + +def test_chat_execution_persists_agent_node_results_to_conversation(client, db, monkeypatch): + batch, conversation = _create_conversation_with_batch() + UploadedDocument.objects.create( + batch=batch, + scenario_id="document_review", + original_name="说明书.md", + file_type="md", + size=1, + status=UploadedDocument.STATUS_INDEXED, + ) + + monkeypatch.setattr( + "apps.chat.views.run_agent", + lambda *args, **kwargs: AgentResult( + answer="已生成风险结论", + status="success", + node_results=[ + {"code": "package_import", "label": "资料包导入", "status": "已完成"}, + {"code": "overview", "label": "目录汇总", "status": "已完成"}, + {"code": "completeness", "label": "法规完整性检查", "status": "已完成"}, + {"code": "field_extraction", "label": "字段抽取", "status": "已完成"}, + {"code": "consistency", "label": "一致性核查", "status": "待复核"}, + {"code": "risk", "label": "风险预警", "status": "已阻断", "summary": "存在高风险"}, + {"code": "word_export", "label": "Word 回填导出", "status": "待处理"}, + {"code": "feishu_notify", "label": "飞书通知", "status": "待处理"}, + ], + notification_payload={ + "batch_id": batch.batch_id, + "conversation_id": conversation.conversation_id, + "product_name": batch.product_name, + "notify_reason": "task_completed", + "owners": [], + }, + ), + ) + + response = client.post( + reverse("chat:detail", args=[conversation.conversation_id]), + {"message": "执行节点任务"}, + ) + + assert response.status_code == 200 + conversation.refresh_from_db() + assert len(conversation.node_results) == 8 + assert conversation.task_status == "success" + assert conversation.latest_summary["answer"] == "已生成风险结论" + + def test_create_conversation_for_batch_initializes_eight_workflow_nodes(db): conversation = create_conversation_for_batch( "SUB-20260604-001",