feat: 重构处理历史与通知留痕追踪

This commit is contained in:
2026-06-04 00:49:33 +08:00
parent d0841e533f
commit 77d9420d43
13 changed files with 431 additions and 96 deletions

View File

@@ -1,6 +1,7 @@
from agent_core.orchestrator import build_messages, run_agent
from agent_core.rag.ingest import _split_text, ingest_document
from agent_core.rag.retriever import retrieve
from agent_core.schemas.outputs import SUPPORTED_OUTPUT_TYPES
def test_run_agent_returns_structured_result_from_llm_output():
@@ -248,3 +249,59 @@ def test_retrieve_returns_empty_when_query_has_no_overlap(tmp_path):
)
assert chunks == []
def test_registration_risk_result_includes_owner_fields_and_notification_payload():
scenario = {
"id": "document_review",
"name": "注册审核智能体",
"agent": {
"role": "注册审核助手",
"goal": "输出风险结果",
"instructions": ["输出结构化风险结果"],
},
"rag": {"enabled": False},
"tools": [],
"output": {"type": "registration_risk_report"},
}
provider_response = """
{
"summary": "存在高风险项,需人工复核。",
"highest_risk_level": "high",
"pass_status": "blocked",
"owner_roles": [
{
"owner_role": "注册资料负责人",
"owner_name": "张三",
"department": "注册事务部",
"chapter_scope": "CH1",
"risk_scope": "字段冲突",
"feishu_user_id": "ou_demo_1",
"feishu_open_id": "on_demo_1",
"feishu_name": "张三",
"notify_enabled": true
}
],
"notify_reason": "task_completed"
}
"""
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()})
owner = result.notification_payload["owners"][0]
assert result.structured_output["output_type"] == "registration_risk_report"
assert owner["owner_role"] == "注册资料负责人"
assert owner["feishu_user_id"] == "ou_demo_1"
assert owner["feishu_open_id"] == "on_demo_1"
assert result.notification_payload["notify_reason"] == "task_completed"
def test_supported_output_types_include_word_export_and_feishu_notification():
assert "registration_word_export_report" in SUPPORTED_OUTPUT_TYPES
assert "feishu_notification_report" in SUPPORTED_OUTPUT_TYPES

View File

@@ -1,8 +1,8 @@
from django.urls import reverse
from agent_core.results import AgentResult
from apps.audit.models import AgentAuditLog, DemoBusinessRecord
from apps.audit.services import create_audit_log
from apps.audit.models import AgentAuditLog, DemoBusinessRecord, NotificationRecord
from apps.audit.services import create_audit_log, create_notification_record
from agent_core.tools.builtin_tools import query_demo_records
@@ -117,3 +117,80 @@ def test_query_demo_records_reads_demo_business_record_table(db):
assert result["records"][0]["title"] == "A线缺陷"
assert result["records"][0]["payload"] == {"rate": 0.12}
def test_audit_log_records_batch_conversation_and_product_context(db):
result = AgentResult(answer="回答", status="success")
log = create_audit_log(
"document_review",
"注册审核智能体",
"开始审核",
result,
batch_id="SUB-20260604-001",
conversation_id="conv-001",
product_name="新型冠状病毒 2019-nCoV 核酸检测试剂盒",
)
assert log.batch_id == "SUB-20260604-001"
assert log.conversation_id == "conv-001"
assert log.product_name == "新型冠状病毒 2019-nCoV 核酸检测试剂盒"
def test_create_notification_record_persists_task_completed_and_task_failed(db):
completed = create_notification_record(
batch_id="SUB-20260604-001",
conversation_id="conv-001",
product_name="产品A",
trigger_source="risk_report",
notify_reason="task_completed",
owner_role="注册资料负责人",
feishu_user_id="ou_demo_1",
message_status="sent",
web_detail_url="https://example.com/detail/1",
receipt={"message_id": "msg-1"},
)
failed = create_notification_record(
batch_id="SUB-20260604-001",
conversation_id="conv-001",
product_name="产品A",
trigger_source="risk_report",
notify_reason="task_failed",
owner_role="注册资料负责人",
feishu_user_id="ou_demo_1",
message_status="failed",
web_detail_url="https://example.com/detail/1",
receipt={"message_id": "msg-2"},
)
assert NotificationRecord.objects.count() == 2
assert completed.notify_reason == "task_completed"
assert failed.notify_reason == "task_failed"
def test_audit_list_supports_batch_and_product_filters(client, db):
create_audit_log(
"document_review",
"注册审核智能体",
"问题一",
AgentResult(answer="回答一", status="success"),
batch_id="SUB-20260604-001",
conversation_id="conv-001",
product_name="产品A",
)
create_audit_log(
"document_review",
"注册审核智能体",
"问题二",
AgentResult(answer="回答二", status="success"),
batch_id="SUB-20260604-002",
conversation_id="conv-002",
product_name="产品B",
)
response = client.get(reverse("audit:list"), {"keyword": "产品A"})
content = response.content.decode("utf-8")
assert response.status_code == 200
assert "产品A" in content
assert "产品B" not in content

View File

@@ -2,6 +2,7 @@ from django.urls import reverse
from agent_core.results import AgentResult
from apps.audit.models import AgentAuditLog
from apps.audit.models import NotificationRecord
from apps.chat.models import Conversation
from apps.documents.models import SubmissionBatch, UploadedDocument
@@ -126,3 +127,45 @@ def test_chat_renders_three_column_workspace_and_node_results(client, db):
assert "上传区" in content
assert "资料包导入 / 已完成" in content
assert "目录汇总 / 处理中" in content
def test_chat_execution_creates_notification_record_from_agent_result(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",
"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.notify_reason == "task_completed"
assert record.batch_id == batch.batch_id