test_retrieval_detail_projection.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from app.retrieval_detail_projection import (
  2. project_retrieval_event,
  3. summarize_retrieval_output,
  4. )
  5. def _event(event_id, name, input_value, output_value, **overrides):
  6. event = {
  7. "id": event_id,
  8. "event_type": "tool_call",
  9. "event_name": name,
  10. "status": "ok",
  11. "ended_at": "2026-07-14T20:00:00",
  12. "input": {"contentType": "json", "content": input_value},
  13. "output": {"contentType": "json", "content": output_value},
  14. }
  15. event.update(overrides)
  16. return event
  17. def test_case_hit_preserves_conditions_and_complete_case_content():
  18. detail = project_retrieval_event(
  19. _event(
  20. 4607,
  21. "search_script_decode_case",
  22. {"keyword": "毛驴效应", "top_k": 3, "return_field": "主脉络"},
  23. {
  24. "success": True,
  25. "count": 2,
  26. "results": [
  27. {
  28. "post_id": "case-a",
  29. "account": "每天心理学",
  30. "score": 0.7032,
  31. "return_field": "主脉络",
  32. "data": [{"id": "段落1", "详细描述": "完整解构内容"}],
  33. },
  34. {
  35. "post_id": "case-b",
  36. "account": "每天心理学",
  37. "score": 0.68,
  38. "return_field": "主脉络",
  39. "data": [{"id": "段落1", "详细描述": "第二条"}],
  40. },
  41. ],
  42. },
  43. )
  44. )
  45. assert detail["detailKind"] == "retrieval-event"
  46. assert detail["sourceKind"] == "agent-query"
  47. assert detail["outcome"] == {
  48. "state": "hit",
  49. "count": 2,
  50. "message": "查询成功,返回 2 条结果。",
  51. }
  52. assert [item["title"] for item in detail["items"]] == [
  53. "每天心理学 · Case 1",
  54. "每天心理学 · Case 2",
  55. ]
  56. assert detail["items"][0]["sections"][0]["value"][0]["详细描述"] == "完整解构内容"
  57. assert [field["label"] for field in detail["queryConditions"]] == ["关键词", "最多返回", "返回内容"]
  58. def test_successful_empty_is_not_a_failure_and_keeps_query_conditions():
  59. detail = project_retrieval_event(
  60. _event(
  61. 4603,
  62. "search_script_decode_case",
  63. {"keyword": "毛驴效应", "account_name": "每天一点心理学", "top_k": 3},
  64. {"success": True, "count": 0, "results": []},
  65. )
  66. )
  67. assert detail["outcome"] == {
  68. "state": "empty",
  69. "count": 0,
  70. "message": "查询执行成功,没有匹配数据。",
  71. }
  72. assert detail["items"] == []
  73. assert {item["label"] for item in detail["queryConditions"]} == {"关键词", "账号", "最多返回"}
  74. def test_text_failure_exposes_readable_parameter_error():
  75. detail = project_retrieval_event(
  76. _event(
  77. 4066,
  78. "search_script_decode_case",
  79. {"return_field": "写法"},
  80. "错误: return_field 仅支持 ['主脉络', '主题']",
  81. status="error",
  82. )
  83. )
  84. assert detail["outcome"]["state"] == "failure"
  85. assert detail["outcome"]["errorKind"] == "parameter"
  86. assert "return_field 仅支持" in detail["outcome"]["message"]
  87. def test_knowledge_list_count_and_content_are_projected():
  88. detail = project_retrieval_event(
  89. _event(
  90. 4574,
  91. "search_knowledge",
  92. {"keyword": "决策瘫痪", "max_count": 3},
  93. [
  94. {"id": 1, "title": "知识 A", "purpose": "用于核对", "content": "正文 A"},
  95. {"id": 2, "title": "知识 B", "purpose": "用于行动建议", "content": "正文 B"},
  96. ],
  97. )
  98. )
  99. assert detail["outcome"]["count"] == 2
  100. assert detail["outcome"]["state"] == "hit"
  101. assert detail["items"][1]["sections"] == [{"title": "完整内容", "value": "正文 B"}]
  102. def test_direct_tool_has_direct_source_and_structured_output():
  103. detail = project_retrieval_event(
  104. _event(
  105. 4650,
  106. "get_script_snapshot",
  107. {"script_build_id": 444},
  108. {"script_build": {"id": 444}, "paragraphs": [{"id": 2284}], "elements": []},
  109. )
  110. )
  111. assert detail["sourceKind"] == "direct-tool"
  112. assert detail["outcome"]["state"] == "hit"
  113. assert [section["title"] for section in detail["items"][0]["sections"]] == ["脚本概况", "段落"]
  114. def test_terminal_run_marks_unfinished_event_interrupted_before_other_rules():
  115. detail = project_retrieval_event(
  116. _event(
  117. 5000,
  118. "search_knowledge",
  119. {"keyword": "决策"},
  120. [{"title": "还未完成的结果"}],
  121. status="running",
  122. ended_at=None,
  123. ),
  124. run_status="failed",
  125. )
  126. assert detail["outcome"]["state"] == "interrupted"
  127. assert detail["items"] == []
  128. def test_light_summary_does_not_include_full_results():
  129. summary = summarize_retrieval_output(
  130. "search_script_decode_case",
  131. raw_status="ok",
  132. ended_at="2026-07-14T20:00:00",
  133. output={"success": True, "count": 1, "results": [{"data": "x" * 1000}]},
  134. )
  135. assert summary == {"state": "hit", "count": 1, "error": None}
  136. assert "results" not in summary