diff --git a/agent_core/orchestrator.py b/agent_core/orchestrator.py index 5214e5d..78277f6 100644 --- a/agent_core/orchestrator.py +++ b/agent_core/orchestrator.py @@ -193,6 +193,11 @@ def _build_notification_payload(structured_output: dict, options: dict, status: "product_name": str(options.get("product_name", "")), "notify_reason": notify_reason, "owners": owners, + "mentioned_users": structured_output.get("mentioned_users") or [], + "message_status": structured_output.get("message_status") + or ("sent" if status == "success" else "failed"), + "web_detail_url": structured_output.get("web_detail_url", ""), + "receipt": structured_output.get("receipt") or {}, "status": status, } diff --git a/apps/chat/views.py b/apps/chat/views.py index 025d9dc..63ce642 100644 --- a/apps/chat/views.py +++ b/apps/chat/views.py @@ -135,6 +135,11 @@ def _persist_notification_records(result: AgentResult, *, web_detail_url: str = owners = payload.get("owners") or [] if not owners: return + resolved_detail_url = payload.get("web_detail_url") or web_detail_url + resolved_message_status = payload.get("message_status") or ( + "sent" if result.status == "success" else "failed" + ) + resolved_receipt = payload.get("receipt") or {"status": result.status} for owner in owners: create_notification_record( batch_id=payload.get("batch_id", ""), @@ -144,9 +149,9 @@ def _persist_notification_records(result: AgentResult, *, web_detail_url: str = notify_reason=payload.get("notify_reason", "task_completed"), owner_role=owner.get("owner_role", ""), feishu_user_id=owner.get("feishu_user_id", ""), - message_status="sent" if result.status == "success" else "failed", - web_detail_url=web_detail_url, - receipt={"status": result.status}, + message_status=resolved_message_status, + web_detail_url=resolved_detail_url, + receipt=resolved_receipt, ) diff --git a/tests/test_agent_core.py b/tests/test_agent_core.py index 4a4f9fd..c685210 100644 --- a/tests/test_agent_core.py +++ b/tests/test_agent_core.py @@ -460,3 +460,54 @@ owner_mappings: assert result.notification_payload["notify_reason"] == "task_failed" assert owner["owner_name"] == "孙七" assert owner["feishu_open_id"] == "on_failed_1" + + +def test_feishu_notification_report_builds_notification_payload_with_receipt_and_node_status(): + scenario = { + "id": "document_review", + "name": "注册审核智能体", + "agent": { + "role": "注册审核助手", + "goal": "输出通知结果", + "instructions": ["输出结构化通知结果"], + }, + "rag": {"enabled": False}, + "tools": [], + "output": {"type": "feishu_notification_report"}, + } + provider_response = """ + { + "batch_id": "SUB-20260604-003", + "conversation_id": "conv-003", + "notify_reason": "task_completed", + "mentioned_users": ["ou_demo_1"], + "message_status": "sent", + "web_detail_url": "https://example.com/audit/3", + "receipt": { + "message_id": "msg-3", + "status": "sent" + } + } + """ + + 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(), + "batch_id": "SUB-20260604-003", + "conversation_id": "conv-003", + "product_name": "产品C", + }, + ) + + assert result.node_results[7]["status"] == "已完成" + 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" diff --git a/tests/test_chat.py b/tests/test_chat.py index 7a3cdab..5e4a200 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -174,6 +174,51 @@ def test_chat_execution_creates_notification_record_from_agent_result(client, db assert record.web_detail_url.endswith(f"/audit/{AgentAuditLog.objects.get().id}/") +def test_chat_execution_uses_notification_payload_message_status_and_receipt(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", + notification_payload={ + "batch_id": batch.batch_id, + "conversation_id": conversation.conversation_id, + "product_name": batch.product_name, + "notify_reason": "task_completed", + "message_status": "sent", + "web_detail_url": "https://example.com/audit/custom", + "receipt": {"message_id": "msg-custom", "status": "sent"}, + "owners": [ + { + "owner_role": "注册资料负责人", + "feishu_user_id": "ou_demo_1", + } + ], + }, + ), + ) + + response = client.post( + reverse("chat:detail", args=[conversation.conversation_id]), + {"message": "执行通知任务"}, + ) + + assert response.status_code == 200 + record = NotificationRecord.objects.get() + assert record.message_status == "sent" + assert record.receipt["message_id"] == "msg-custom" + + def test_chat_execution_creates_failed_notification_record_and_updates_conversation(client, db, monkeypatch): batch, conversation = _create_conversation_with_batch() UploadedDocument.objects.create(