from __future__ import annotations from typing import Any from .common import ( EventLoader, decision_context, decision_event_refs, event_content, event_notices, event_unit, find_branch, find_by_id, find_detail, find_raw_branch, integer, load_events, suffix_int, ) from .schema import field, payload def project_implementation_task( detail_ref: str, round_index: int, branch_id: int, bundle: dict[str, Any], view: dict[str, Any], load_event: EventLoader, ) -> dict[str, Any]: raw = find_raw_branch(bundle, branch_id) or {} branch = find_branch(view, round_index, branch_id) or {} stage = branch.get("retrievalStage") or {} implementer_id = integer(stage.get("implementerEventId")) events = load_events(load_event, [implementer_id] if implementer_id else []) full_task = _agent_task(events[0]) if events else None task_value = full_task or raw.get("impl_task") or raw.get("target") task_source = "runtime-event" if full_task else "database" task_source_label = "实现 Agent Event Body" if full_task else "script_build_branch(历史回退)" task_source_ref = f"event:{implementer_id}" if full_task and implementer_id else detail_ref inputs = [ field( f"branch:{branch_id}:task", "完整实现任务", task_value, source_kind=task_source, source_label=task_source_label, source_ref=task_source_ref, field_path="input.content.task" if full_task else "impl_task", relation="direct-input", completeness="complete" if full_task else "partial" if task_value else "missing", ), field( f"branch:{branch_id}:path-type", "实现范围", raw.get("path_type"), source_kind="database", source_label="script_build_branch", source_ref=detail_ref, field_path="path_type", relation="standing-constraint", ), field( f"branch:{branch_id}:target", "实现目标", raw.get("target"), source_kind="database", source_label="script_build_branch", source_ref=detail_ref, field_path="target", relation="standing-constraint", ), ] notices = event_notices(events) if task_value and not full_task: notices.append({"level": "warning", "message": "未找到完整实现 Agent 输入,当前使用 Branch 字段作历史回退。"}) return payload( "implementation-task", "single-event" if events else "business-record", inputs=inputs, units=[event_unit(item, label="实现 Agent") for item in events], outputs=[], runtime_summary="任务作为实现 Agent 的完整输入执行。" if events else "该历史记录没有可用的实现 Agent Event Body。", notices=notices, completeness="complete" if full_task else "partial" if task_value else "missing", business_modules=[ # The readable Inspector sections are parsed from the complete # implementer task. Keep all six source modules on that exact # Event input so the source Inspector can bind every displayed # section to a text span. Branch.target remains available to the # canvas summary below, but must not masquerade as the section's # original source. {"id": "scope", "title": "实现范围", "sourceIds": [inputs[0]["id"]]}, {"id": "method", "title": "实施方法", "sourceIds": [inputs[0]["id"]]}, {"id": "goal", "title": "完整目标", "sourceIds": [inputs[0]["id"]]}, {"id": "constraints", "title": "参考依据与约束", "sourceIds": [inputs[0]["id"]]}, {"id": "avoid", "title": "需要避免", "sourceIds": [inputs[0]["id"]]}, {"id": "deliverable", "title": "预期交付", "sourceIds": [inputs[0]["id"]]}, ], card_fields=[ {"key": "scope", "label": "范围", "sourceIds": [inputs[2]["id"]], "transform": "直接使用结构化 target"}, {"key": "method", "label": "方法", "sourceIds": [inputs[0]["id"]], "transform": "使用任务中的实施方法段"}, {"key": "target", "label": "目标", "sourceIds": [inputs[2]["id"], inputs[0]["id"]], "transform": "优先结构化 target"}, ], ) def project_data_decision( detail_ref: str, bundle: dict[str, Any], view: dict[str, Any], load_event: EventLoader, ) -> dict[str, Any]: record_id = suffix_int(detail_ref) row = find_by_id(bundle.get("dataDecisions") or [], record_id) if row is None: raise KeyError(detail_ref) node = find_detail(view, detail_ref) context = decision_context(node) events = load_events(load_event, decision_event_refs(context)) sources = row.get("sources") if isinstance(row.get("sources"), list) else [] inputs = [ field( f"data-decision:{record_id}:source:{index}", f"参与判断的数据 {index}", source, source_kind="database", source_label="script_build_data_decision.sources", source_ref=detail_ref, field_path=f"sources[{index - 1}]", relation="explicit-basis", ) for index, source in enumerate(sources, 1) ] outputs = [ field(f"data-decision:{record_id}:decision", "明确取舍", row.get("decision"), source_kind="database", source_label="script_build_data_decision", source_ref=detail_ref, field_path="decision", relation="persisted-output"), field(f"data-decision:{record_id}:reasoning", "取舍理由", row.get("reasoning"), source_kind="database", source_label="script_build_data_decision", source_ref=detail_ref, field_path="reasoning", relation="persisted-output"), ] return payload( "data-decision", "business-record", inputs=inputs, units=[event_unit(item) for item in events], outputs=outputs, runtime_summary="这是独立落库的业务取舍记录;不伪造一次不存在的 Agent I/O。", notices=event_notices(events) + ([] if events else [{"level": "info", "message": "未找到能与该取舍记录一对一安全关联的运行事件。"}]), completeness="complete" if row.get("decision") and sources else "partial", business_modules=[ {"id": "sources", "title": "参与判断的数据", "sourceIds": [item["id"] for item in inputs]}, {"id": "tradeoff", "title": "采用 / 组合 / 舍弃", "sourceIds": [outputs[0]["id"]]}, {"id": "decision", "title": "明确取舍", "sourceIds": [outputs[0]["id"]]}, {"id": "reason", "title": "理由", "sourceIds": [outputs[1]["id"]]}, {"id": "source-completeness", "title": "来源完整性", "sourceIds": [item["id"] for item in inputs]}, ], card_fields=[ {"key": "conclusion", "label": "取舍结论", "sourceIds": [outputs[0]["id"]], "transform": "直接使用业务记录"}, {"key": "sourceCount", "label": "来源数", "sourceIds": [item["id"] for item in inputs], "transform": "明确来源数量"}, {"key": "reason", "label": "核心理由", "sourceIds": [outputs[1]["id"]], "transform": "使用结构化理由"}, ], ) def project_creative( detail_ref: str, bundle: dict[str, Any], view: dict[str, Any], load_event: EventLoader, ) -> dict[str, Any]: node = find_detail(view, detail_ref) if node is None: raise KeyError(detail_ref) context = decision_context(node) seed_id = suffix_int(detail_ref) seed = find_by_id(bundle.get("events") or [], seed_id) round_index = integer((seed or {}).get("round_index")) branch_id = integer((seed or {}).get("branch_id")) refs = decision_event_refs(context) if seed_id is not None: refs.append(f"event:{seed_id}") # Explicit round/branch/scope metadata is safe lineage. It also captures # script mutation calls omitted by the old think_and_plan-only refs. implementer_ids = { integer(item.get("id")) for item in bundle.get("events") or [] if item.get("event_name") == "script_implementer" and integer(item.get("round_index")) == round_index and integer(item.get("branch_id")) == branch_id } for item in bundle.get("events") or []: if integer(item.get("round_index")) != round_index or integer(item.get("branch_id")) != branch_id: continue if integer(item.get("scope_event_id")) in implementer_ids or integer(item.get("id")) in implementer_ids: refs.append(f"event:{item.get('id')}") events = load_events(load_event, refs) raw_branch = find_raw_branch(bundle, branch_id or -1) or {} candidate = raw_branch.get("candidate_snapshot") or {} snapshot = candidate.get("snapshot") if isinstance(candidate, dict) else None visible_inputs = [] for index, source in enumerate(context.get("evidence") or context.get("inputs") or [], 1): if not isinstance(source, dict): continue observed = str(source.get("observedRelation") or "") relation = "direct-input" if observed == "read-by-actor" else "previous-result" if observed == "returned-to-actor" else "available-upstream" visible_inputs.append(field(f"creative:{seed_id}:input:{index}", str(source.get("label") or f"创作依据 {index}"), source.get("summary") or source.get("value"), source_kind="runtime-event" if source.get("detailRef") else "database", source_label="实现过程中可确认的数据", source_ref=source.get("detailRef"), field_path="output.content" if source.get("detailRef") else "", relation=relation)) explicit_basis = [ field( f"creative:{seed_id}:explicit-basis:{index}", str(item.get("label") or f"明确采用的数据取舍 {index}"), {"decision": item.get("label"), "reasoning": item.get("value")}, source_kind="database", source_label="script_build_data_decision", source_ref=item.get("detailRef"), field_path="", relation="explicit-basis", ) for index, item in enumerate(context.get("explicitBasis") or [], 1) if isinstance(item, dict) and str(item.get("detailRef") or "").startswith("data-decision:") ] change_fields = [ field( f"creative:{seed_id}:change:{index}", str(item.get("label") or f"脚本改动 {index}"), {"status": item.get("value"), "note": item.get("note")}, source_kind="runtime-event", source_label="脚本修改运行事件", source_ref=item.get("detailRef"), field_path="", relation="run-output", ) for index, item in enumerate(context.get("runtimeActions") or [], 1) if isinstance(item, dict) and str(item.get("detailRef") or "").startswith("event:") ] outputs = [ field(f"creative:{seed_id}:snapshot", "产出的候选表", snapshot, source_kind="artifact", source_label="候选分支快照", source_ref=f"artifact:branch:{branch_id}" if branch_id else None, field_path="candidate_snapshot.snapshot", relation="persisted-output", completeness="complete" if snapshot else "missing"), field(f"creative:{seed_id}:assessment", "实现者自评", raw_branch.get("self_assessment"), source_kind="database", source_label="script_build_branch", source_ref=f"round:{round_index}:branch:{branch_id}:output", field_path="self_assessment", relation="persisted-output"), ] notices = event_notices(events) if visible_inputs: notices.append({"level": "info", "message": "可确认是上游信息,但无法确认是否被本次决策采用。"}) if not events: notices.append({"level": "warning", "message": "候选产出存在,但未保存可安全关联的完整创作过程。"}) card_kind = "creative" if events else "candidate-output-fallback" return payload( card_kind, "event-sequence" if events else "business-record", inputs=[*visible_inputs, *explicit_basis], units=[event_unit(item) for item in events], outputs=[*outputs, *change_fields], runtime_summary=(f"按明确的轮次、分支和实现 Agent scope 串起 {len(events)} 个创作/修改事件。" if events else "只能展示候选快照和实现者自评。"), notices=notices, completeness="complete" if events and snapshot else "partial" if snapshot or raw_branch.get("self_assessment") else "missing", business_modules=[ {"id": "process", "title": "创作处理", "sourceIds": []}, {"id": "basis", "title": "明确采用的数据取舍", "sourceIds": [item["id"] for item in explicit_basis]}, {"id": "available", "title": "可确认的上游信息", "sourceIds": [item["id"] for item in visible_inputs]}, {"id": "changes", "title": "实际脚本改动", "sourceIds": [item["id"] for item in change_fields]}, {"id": "candidate", "title": "产出的候选表", "sourceIds": [outputs[0]["id"]]}, {"id": "uncertainty", "title": "存疑项 / 完整性", "sourceIds": [outputs[1]["id"]]}, ], ) def project_multipath_decision( detail_ref: str, bundle: dict[str, Any], view: dict[str, Any], load_event: EventLoader, ) -> dict[str, Any]: record_id = suffix_int(detail_ref) row = find_by_id(bundle.get("multipathDecisions") or [], record_id) if row is None: raise KeyError(detail_ref) node = find_detail(view, detail_ref) context = decision_context(node) events = load_events(load_event, decision_event_refs(context)) branch_ids = row.get("branch_ids") if isinstance(row.get("branch_ids"), list) else [] inputs = [field(f"multipath:{record_id}:branch:{branch_id}", f"候选方案 {branch_id}", find_raw_branch(bundle, integer(branch_id) or -1), source_kind="database", source_label="script_build_branch", source_ref=f"round:{row.get('round_index')}:branch:{branch_id}", field_path="", relation="available-upstream") for branch_id in branch_ids] review_events = [ item for item in bundle.get("events") or [] if item.get("event_name") == "script_multipath_evaluator" and integer(item.get("round_index")) == integer(row.get("round_index")) ] attached_ids = {integer(item.get("id")) for item in events} unscoped_reviews = [item for item in review_events if integer(item.get("id")) not in attached_ids] for item in unscoped_reviews: inputs.append(field(f"multipath:{record_id}:review:{item.get('id')}", "同轮多方案评审", item.get("agentOutputData") or item.get("output_preview"), source_kind="runtime-event", source_label="同轮评审事件(候选范围未安全关联)", source_ref=f"event:{item.get('id')}", field_path="output", relation="available-upstream", completeness="partial")) outputs = [ field(f"multipath:{record_id}:decision", "最终决定", row.get("decision"), source_kind="database", source_label="script_build_multipath_decision", source_ref=detail_ref, field_path="decision", relation="persisted-output"), field(f"multipath:{record_id}:reasoning", "决策理由", row.get("reasoning"), source_kind="database", source_label="script_build_multipath_decision", source_ref=detail_ref, field_path="reasoning", relation="persisted-output"), ] notices = event_notices(events) notices.append({"level": "info", "message": "候选分支可确认是本次取舍对象;除非有明确评审关联,不宣称其内容已被采用。"}) if unscoped_reviews: notices.append({"level": "warning", "message": "发现同轮评审,但无法安全关联到具体候选。"}) return payload( "multipath-decision", "business-record", inputs=inputs, units=[event_unit(item) for item in events], outputs=outputs, runtime_summary="主 Agent 多路决策以业务表为最终事实,评审 Event 只在有可靠关联时作为明确依据。", notices=notices, completeness="complete" if row.get("decision") and branch_ids else "partial", business_modules=[ {"id": "scope", "title": "取舍对象", "sourceIds": [item["id"] for item in inputs if ":branch:" in item["id"]]}, {"id": "comparison", "title": "评审建议与最终决定", "sourceIds": [item["id"] for item in inputs if ":review:" in item["id"]] + [outputs[0]["id"]]}, {"id": "outcomes", "title": "逐方案处置", "sourceIds": [item["id"] for item in inputs if ":branch:" in item["id"]]}, {"id": "reason", "title": "决策理由", "sourceIds": [outputs[1]["id"]]}, {"id": "strength", "title": "关联强度", "sourceIds": [item["id"] for item in inputs]}, ], ) def project_branch_output( detail_ref: str, round_index: int, branch_id: int, bundle: dict[str, Any], view: dict[str, Any], ) -> dict[str, Any]: raw = find_raw_branch(bundle, branch_id) branch = find_branch(view, round_index, branch_id) if raw is None or branch is None: raise KeyError(detail_ref) output = branch.get("output") or {} if output.get("type") == "domain-info": facts = [ item for item in bundle.get("domainInfo") or [] if integer(item.get("branch_id")) == branch_id ] outputs = [field(f"branch:{branch_id}:facts", "已核实领域事实", facts, source_kind="database", source_label="script_build_domain_info", source_ref=detail_ref, field_path="domainInfo", relation="persisted-output")] return payload( "domain-facts", "aggregate", outputs=outputs, runtime_summary="按 branch_id 聚合该领域信息方案写入的事实。", calculation="只按显式 branch_id 关联,不使用文本相似度。", # A successful branch-scoped lookup returning zero rows is a # complete empty result, not a missing source record. completeness="complete", business_modules=[ {"id": "facts", "title": "已核实事实", "sourceIds": [outputs[0]["id"]]}, {"id": "verification", "title": "核实说明", "sourceIds": [outputs[0]["id"]]}, {"id": "sources", "title": "出处", "sourceIds": [outputs[0]["id"]]}, {"id": "usage", "title": "用途与存疑状态", "sourceIds": [outputs[0]["id"]]}, ], ) candidate = raw.get("candidate_snapshot") or {} snapshot = candidate.get("snapshot") if isinstance(candidate, dict) else None outputs = [ field(f"branch:{branch_id}:candidate", "形成了什么", snapshot, source_kind="artifact", source_label="候选分支快照", source_ref=f"artifact:branch:{branch_id}", field_path="candidate_snapshot.snapshot", relation="persisted-output", completeness="complete" if snapshot else "missing"), field(f"branch:{branch_id}:assessment", "实现者自评", raw.get("self_assessment"), source_kind="database", source_label="script_build_branch", source_ref=detail_ref, field_path="self_assessment", relation="persisted-output"), ] return payload( "candidate-output-fallback", "business-record", outputs=outputs, runtime_summary="候选产出回退详情只展示候选快照和自评,不伪造未保存的创作过程。", notices=[{"level": "warning", "message": "未保存可安全关联的完整创作过程。"}], completeness="partial" if snapshot or raw.get("self_assessment") else "missing", business_modules=[ {"id": "output", "title": "形成了什么", "sourceIds": [outputs[0]["id"]]}, {"id": "assessment", "title": "实现者自评", "sourceIds": [outputs[1]["id"]]}, {"id": "missing", "title": "创作过程缺失说明", "sourceIds": [item["id"] for item in outputs]}, ], ) def project_domain_info(detail_ref: str, bundle: dict[str, Any]) -> dict[str, Any]: record_id = suffix_int(detail_ref) row = find_by_id(bundle.get("domainInfo") or [], record_id) if row is None: raise KeyError(detail_ref) outputs = [ field(f"domain:{record_id}:fact", "已核实事实", row.get("content"), source_kind="database", source_label="script_build_domain_info", source_ref=detail_ref, field_path="content", relation="persisted-output"), field(f"domain:{record_id}:note", "核实说明", row.get("note"), source_kind="database", source_label="script_build_domain_info", source_ref=detail_ref, field_path="note", relation="persisted-output"), field(f"domain:{record_id}:source", "信息出处", row.get("source"), source_kind="database", source_label="script_build_domain_info", source_ref=detail_ref, field_path="source", relation="persisted-output"), ] return payload( "domain-fact", "business-record", outputs=outputs, runtime_summary="这是独立落库的已核实领域事实。", completeness="complete" if row.get("content") and row.get("source") else "partial", business_modules=[ {"id": "fact", "title": "已核实事实", "sourceIds": [outputs[0]["id"]]}, {"id": "verification", "title": "核实说明", "sourceIds": [outputs[1]["id"]]}, {"id": "source", "title": "出处", "sourceIds": [outputs[2]["id"]]}, {"id": "usage", "title": "用途与存疑状态", "sourceIds": [item["id"] for item in outputs]}, ], ) def _agent_task(event: dict[str, Any]) -> Any: content = event_content(event.get("input")) return content.get("task") if isinstance(content, dict) else content