from __future__ import annotations import re from collections.abc import Callable from typing import Any from .implementation import ( project_branch_output, project_creative, project_data_decision, project_domain_info, project_implementation_task, project_multipath_decision, ) from .planning import ( project_implementation_plan, project_objective, project_round_goal, ) from .results import project_final_result, project_round_result from .summaries import ( project_branch_summary, project_missing_convergence, project_missing_round_evaluation, project_round_summary, ) from .retrieval import ( project_direct_group, project_event, project_retrieval_agent, project_retrieval_stage, ) class CardDataNotFound(LookupError): pass class CardBusinessDataProjector: """Read-only application projector for one card's complete data flow. The HTTP adapter supplies plain bundle/view dictionaries and a lazy event loader. The projector has no database or FastAPI dependency. """ def project( self, detail_ref: str, *, bundle: dict[str, Any], view: dict[str, Any], load_event: Callable[[int], dict[str, Any]], ) -> dict[str, Any]: ref = str(detail_ref or "").strip() try: if ref == "run:objective": return project_objective(bundle, view, load_event) if ref in {"run:final-result", "artifact:base:current", "base:current"}: return project_final_result("run:final-result", bundle, view) if ref.startswith("event:"): return project_event(ref, load_event) if ref.startswith("retrieval-direct:"): return project_direct_group(ref, view, load_event) if ref.startswith("retrieval-agent:"): return project_retrieval_agent(ref, view, load_event) if ref.startswith("data-decision:"): return project_data_decision(ref, bundle, view, load_event) if ref.startswith("creative:"): return project_creative(ref, bundle, view, load_event) if ref.startswith("multipath-decision:"): return project_multipath_decision(ref, bundle, view, load_event) if ref.startswith("domain-info:"): return project_domain_info(ref, bundle) match = re.fullmatch(r"round:(\d+)", ref) if match: return project_round_summary( ref, int(match.group(1)), bundle, view, load_event ) match = re.fullmatch(r"round:(\d+):branch:(\d+)", ref) if match: return project_branch_summary( ref, int(match.group(1)), int(match.group(2)), bundle, view, load_event, ) match = re.fullmatch(r"round:(\d+):(goal|plan|result)", ref) if match: round_index = int(match.group(1)) role = match.group(2) if role == "goal": return project_round_goal(ref, round_index, bundle, view, load_event) if role == "plan": return project_implementation_plan(ref, round_index, bundle, view, load_event) return project_round_result(ref, round_index, bundle, view, load_event) match = re.fullmatch(r"round:(\d+):evaluation", ref) if match: return project_missing_round_evaluation( ref, int(match.group(1)), bundle, view ) match = re.fullmatch( r"round:(\d+):[^:]+:(review|decision)-missing", ref ) if match: return project_missing_convergence( ref, int(match.group(1)), match.group(2), view, ) match = re.fullmatch(r"round:(\d+):branch:(\d+):(task|retrieval|output)", ref) if match: round_index, branch_id = int(match.group(1)), int(match.group(2)) role = match.group(3) if role == "task": return project_implementation_task(ref, round_index, branch_id, bundle, view, load_event) if role == "retrieval": return project_retrieval_stage(ref, round_index, branch_id, view, load_event) return project_branch_output(ref, round_index, branch_id, bundle, view) except KeyError as exc: raise CardDataNotFound(f"未找到卡片数据 {ref}") from exc raise CardDataNotFound(f"未找到卡片数据 {ref}")