results.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. from __future__ import annotations
  2. from collections import Counter
  3. from typing import Any
  4. from .common import (
  5. EventLoader,
  6. decision_context,
  7. decision_event_refs,
  8. event_notices,
  9. event_unit,
  10. find_round,
  11. load_events,
  12. )
  13. from .schema import field, payload
  14. def project_round_result(
  15. detail_ref: str,
  16. round_index: int,
  17. bundle: dict[str, Any],
  18. view: dict[str, Any],
  19. load_event: EventLoader,
  20. ) -> dict[str, Any]:
  21. round_ = find_round(view, round_index)
  22. if round_ is None:
  23. raise KeyError(detail_ref)
  24. branches = round_.get("branches") or []
  25. result = round_.get("result") or {}
  26. evaluation = round_.get("overallEvaluation") or {}
  27. events = load_events(load_event, decision_event_refs(decision_context(evaluation)))
  28. domain_rows = [
  29. item for item in bundle.get("domainInfo") or []
  30. if int(item.get("round_index") or 0) == round_index
  31. ]
  32. statuses = Counter(str(item.get("status") or "unknown") for item in branches)
  33. inputs = [
  34. field(f"round:{round_index}:result:goal", "本轮目标", ((round_.get("goal") or {}).get("card") or {}).get("primary", {}).get("value"), source_kind="database", source_label="script_build_round", source_ref=f"round:{round_index}:goal", field_path="goal", relation="standing-constraint"),
  35. field(f"round:{round_index}:result:review", "整体评审", evaluation, source_kind="runtime-event", source_label="整体评审运行事件", source_ref=evaluation.get("detailRef"), relation="explicit-basis", completeness="complete" if evaluation.get("detailRef") else "partial"),
  36. ]
  37. outputs = [
  38. field(f"round:{round_index}:result:summary", "本轮目标完成情况", (result.get("card") or {}).get("primary", {}).get("value"), source_kind="calculation", source_label="本轮业务记录聚合", source_ref=detail_ref, field_path="result.card.primary", relation="persisted-output"),
  39. field(f"round:{round_index}:result:dispositions", "方案处置", dict(statuses), source_kind="calculation", source_label="分支状态统计", source_ref=detail_ref, field_path="branches.status", relation="persisted-output"),
  40. field(f"round:{round_index}:result:domain", "领域事实", domain_rows, source_kind="calculation", source_label="按 round_index 筛选 script_build_domain_info", source_ref=detail_ref, field_path="", relation="persisted-output", completeness="complete"),
  41. field(f"round:{round_index}:result:changes", "主脚本变化", [item.get("output") for item in branches if item.get("output")], source_kind="calculation", source_label="候选处置与当前产物聚合", source_ref=f"artifact:round:{round_index}", field_path="branches[].output", relation="persisted-output"),
  42. field(f"round:{round_index}:result:next", "下一步", next((item.get("value") for item in (result.get("card") or {}).get("secondary") or [] if item.get("key") == "next"), None), source_kind="calculation", source_label="本轮状态与下一轮记录", source_ref=detail_ref, field_path="result.card.secondary.next", relation="persisted-output"),
  43. ]
  44. same_round_reviews = [
  45. item for item in bundle.get("events") or []
  46. if item.get("event_name") == "script_evaluator"
  47. and int(item.get("round_index") or 0) == round_index
  48. ]
  49. notices = event_notices(events)
  50. if not events and same_round_reviews:
  51. notices.append({"level": "warning", "message": "发现同轮评审,但无法安全关联到具体候选。"})
  52. return payload(
  53. "round-result",
  54. "calculated",
  55. inputs=inputs,
  56. units=[event_unit(item) for item in events],
  57. outputs=outputs,
  58. runtime_summary="本轮产出由候选分支处置、领域事实、整体评审和下一轮状态计算聚合。",
  59. calculation="按 round_index 聚合 Branch、DomainInfo、Evaluation 和下一轮记录;不伪造独立 Agent I/O。",
  60. notices=notices,
  61. completeness="complete" if outputs[0]["value"] else "partial",
  62. business_modules=[
  63. {"id": "completion", "title": "本轮目标完成情况", "sourceIds": [inputs[0]["id"], outputs[0]["id"]]},
  64. {"id": "dispositions", "title": "方案处置", "sourceIds": [outputs[1]["id"]]},
  65. {"id": "domain", "title": "领域事实", "sourceIds": [outputs[2]["id"]]},
  66. {"id": "review", "title": "整体评审", "sourceIds": [inputs[1]["id"]]},
  67. {"id": "changes", "title": "主脚本变化", "sourceIds": [outputs[3]["id"]]},
  68. {"id": "next", "title": "下一步", "sourceIds": [outputs[4]["id"]]},
  69. ],
  70. card_fields=[
  71. {"key": "status", "label": "状态", "sourceIds": [outputs[0]["id"]], "transform": "使用轮次业务状态"},
  72. {"key": "accepted", "label": "采用数", "sourceIds": [outputs[1]["id"]], "transform": "merged 计数"},
  73. {"key": "next", "label": "下一步", "sourceIds": [outputs[4]["id"]], "transform": "直接使用结构化下一步"},
  74. ],
  75. )
  76. def project_final_result(
  77. detail_ref: str, bundle: dict[str, Any], view: dict[str, Any]
  78. ) -> dict[str, Any]:
  79. record = bundle.get("record") or {}
  80. final = view.get("finalResult") or {}
  81. artifact = bundle.get("currentArtifact") or {}
  82. paragraphs = artifact.get("paragraphs") or []
  83. elements = artifact.get("elements") or []
  84. links = artifact.get("paragraphElements") or artifact.get("paragraph_elements") or []
  85. branches = bundle.get("branches") or []
  86. status_counts = Counter(str(item.get("status") or "unknown") for item in branches)
  87. outputs = [
  88. field("final:status", "构建结论", record.get("status"), source_kind="database", source_label="script_build_record", source_ref=detail_ref, field_path="status", relation="persisted-output"),
  89. field("final:summary", "摘要", record.get("summary") or record.get("error_message"), source_kind="database", source_label="script_build_record", source_ref=detail_ref, field_path="summary" if record.get("summary") else "error_message", relation="persisted-output"),
  90. field("final:rounds", "轮次与方案统计", {"roundCount": len(bundle.get("rounds") or []), "branchCounts": dict(status_counts)}, source_kind="calculation", source_label="Round / Branch 记录计数", source_ref=detail_ref, field_path="rounds / branches", relation="persisted-output"),
  91. field("final:artifact-scale", "最终脚本规模", {"paragraphs": len(paragraphs), "elements": len(elements), "links": len(links)}, source_kind="artifact", source_label="当前主脚本", source_ref="artifact:base:current", field_path="recordCounts", relation="persisted-output"),
  92. field("final:artifact", "主脚本入口", "artifact:base:current", source_kind="artifact", source_label="当前主脚本", source_ref="artifact:base:current", field_path="snapshotRef", relation="persisted-output"),
  93. field("final:version", "版本说明", "当前保存的最终主脚本,不是历史轮次快照。", source_kind="calculation", source_label="产物精度规则", source_ref="artifact:base:current", field_path="historicalVersion", relation="persisted-output"),
  94. ]
  95. return payload(
  96. "final-result",
  97. "calculated",
  98. inputs=[],
  99. units=[],
  100. outputs=outputs,
  101. runtime_summary="最终结果是 Run 记录、全部轮次/分支和当前主脚本的计算聚合。",
  102. calculation="直接读取 Run 状态与摘要,对 Round / Branch / Artifact 做确定性计数。",
  103. notices=[] if artifact else [{"level": "warning", "message": "未找到当前主脚本产物。"}],
  104. completeness="complete" if record and artifact else "partial" if record else "missing",
  105. business_modules=[
  106. {"id": "conclusion", "title": "构建结论", "sourceIds": [outputs[0]["id"]]},
  107. {"id": "summary", "title": "摘要或失败原因", "sourceIds": [outputs[1]["id"]]},
  108. {"id": "stats", "title": "轮次与方案统计", "sourceIds": [outputs[2]["id"]]},
  109. {"id": "scale", "title": "最终脚本规模", "sourceIds": [outputs[3]["id"]]},
  110. {"id": "artifact", "title": "主脚本入口", "sourceIds": [outputs[4]["id"]]},
  111. {"id": "version", "title": "版本说明", "sourceIds": [outputs[5]["id"]]},
  112. ],
  113. card_fields=[
  114. {"key": "status", "label": "状态", "sourceIds": [outputs[0]["id"]], "transform": "直接使用 Run 状态"},
  115. {"key": "summary", "label": "摘要", "sourceIds": [outputs[1]["id"]], "transform": "优先 summary,失败时使用 error_message"},
  116. {"key": "scriptScale", "label": "脚本规模", "sourceIds": [outputs[3]["id"]], "transform": "段落/元素/关联计数"},
  117. ],
  118. )