docs: update HANDOFF.md — Stage 9 completed, Stage 10 next
This commit is contained in:
@@ -27,6 +27,7 @@ from typing import Any
|
||||
from uuid import UUID
|
||||
|
||||
from nsct.models.schemas import SynthesisClaimModel, SynthesisReportModel
|
||||
from pydantic import ValidationError as PydanticValidationError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -178,15 +179,8 @@ def _extract_report_from_parsed(
|
||||
parsed: dict[str, Any],
|
||||
llm_model: str,
|
||||
topic: str,
|
||||
) -> dict[str, Any]:
|
||||
"""Wandelt die geparste LLM-Antwort in ein SynthesisReportModel um.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict mit keys:
|
||||
research_topic, summary, confident_findings, uncertain_areas,
|
||||
contradictions, source_list, llm_model_used, generation_timestamp
|
||||
"""
|
||||
) -> SynthesisReportModel:
|
||||
"""Wandelt die geparste LLM-Antwort in ein SynthesisReportModel um."""
|
||||
summary = parsed.get("summary", "")
|
||||
if not isinstance(summary, str):
|
||||
summary = str(summary)
|
||||
@@ -204,56 +198,56 @@ def _extract_report_from_parsed(
|
||||
contradictions_raw = []
|
||||
|
||||
# confident_findings
|
||||
confident: list[dict[str, Any]] = []
|
||||
confident: list[SynthesisClaimModel] = []
|
||||
for item in confident_raw:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
try:
|
||||
claim = {
|
||||
"claim_text": str(item.get("claim_text", "")),
|
||||
"evidence_type": str(item.get("evidence_type", "secondary_report")),
|
||||
"source_independence_score": float(
|
||||
claim = SynthesisClaimModel(
|
||||
claim_text=str(item.get("claim_text", "")),
|
||||
evidence_type=str(item.get("evidence_type", "secondary_report")),
|
||||
source_independence_score=float(
|
||||
item.get("source_independence_score", 0.5)
|
||||
),
|
||||
"cross_source_support": float(item.get("cross_source_support", 0.0)),
|
||||
"contradiction_level": float(item.get("contradiction_level", 1.0)),
|
||||
"evidence_directness": float(item.get("evidence_directness", 0.5)),
|
||||
"source_id": item.get("source_id", ""),
|
||||
"source_url": str(item.get("source_url", "")),
|
||||
"source_title": item.get("source_title"),
|
||||
"evidence_span": item.get("evidence_span"),
|
||||
"confidence": float(item.get("confidence", 1.0)),
|
||||
}
|
||||
cross_source_support=float(item.get("cross_source_support", 0.0)),
|
||||
contradiction_level=float(item.get("contradiction_level", 1.0)),
|
||||
evidence_directness=float(item.get("evidence_directness", 0.5)),
|
||||
source_id=item.get("source_id", ""),
|
||||
source_url=str(item.get("source_url", "")),
|
||||
source_title=item.get("source_title"),
|
||||
evidence_span=item.get("evidence_span"),
|
||||
confidence=float(item.get("confidence", 1.0)),
|
||||
)
|
||||
confident.append(claim)
|
||||
except (ValueError, TypeError):
|
||||
except (ValueError, TypeError, PydanticValidationError):
|
||||
logger.warning("Skipping malformed confident finding: %s", item)
|
||||
|
||||
# uncertain_areas
|
||||
uncertain: list[dict[str, Any]] = []
|
||||
uncertain: list[SynthesisClaimModel] = []
|
||||
for item in uncertain_raw:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
try:
|
||||
claim = {
|
||||
"claim_text": str(item.get("claim_text", "")),
|
||||
"evidence_type": str(item.get("evidence_type", "speculation")),
|
||||
"source_independence_score": float(
|
||||
claim = SynthesisClaimModel(
|
||||
claim_text=str(item.get("claim_text", "")),
|
||||
evidence_type=str(item.get("evidence_type", "speculation")),
|
||||
source_independence_score=float(
|
||||
item.get("source_independence_score", 0.5)
|
||||
),
|
||||
"cross_source_support": float(item.get("cross_source_support", 0.0)),
|
||||
"contradiction_level": float(item.get("contradiction_level", 1.0)),
|
||||
"evidence_directness": float(item.get("evidence_directness", 0.5)),
|
||||
"source_id": item.get("source_id", ""),
|
||||
"source_url": str(item.get("source_url", "")),
|
||||
"source_title": item.get("source_title"),
|
||||
"evidence_span": item.get("evidence_span"),
|
||||
"confidence": float(item.get("confidence", 1.0)),
|
||||
}
|
||||
cross_source_support=float(item.get("cross_source_support", 0.0)),
|
||||
contradiction_level=float(item.get("contradiction_level", 1.0)),
|
||||
evidence_directness=float(item.get("evidence_directness", 0.5)),
|
||||
source_id=item.get("source_id", ""),
|
||||
source_url=str(item.get("source_url", "")),
|
||||
source_title=item.get("source_title"),
|
||||
evidence_span=item.get("evidence_span"),
|
||||
confidence=float(item.get("confidence", 1.0)),
|
||||
)
|
||||
uncertain.append(claim)
|
||||
except (ValueError, TypeError):
|
||||
except (ValueError, TypeError, PydanticValidationError):
|
||||
logger.warning("Skipping malformed uncertain area: %s", item)
|
||||
|
||||
# contradictions
|
||||
# contradictions — keep as plain dicts
|
||||
contradictions: list[dict[str, Any]] = []
|
||||
for item in contradictions_raw:
|
||||
if not isinstance(item, dict):
|
||||
@@ -279,32 +273,32 @@ def _extract_report_from_parsed(
|
||||
source_list: list[dict[str, Any]] = []
|
||||
seen_urls: set[str] = set()
|
||||
for claim in confident + uncertain:
|
||||
url = claim.get("source_url", "")
|
||||
url = claim.source_url if isinstance(claim, SynthesisClaimModel) else claim.get("source_url", "")
|
||||
if url and url not in seen_urls:
|
||||
seen_urls.add(url)
|
||||
source_list.append({
|
||||
"url": url,
|
||||
"title": claim.get("source_title"),
|
||||
"source_id": str(claim.get("source_id", "")),
|
||||
"title": (
|
||||
claim.source_title
|
||||
if isinstance(claim, SynthesisClaimModel)
|
||||
else claim.get("source_title")
|
||||
),
|
||||
"source_id": str(
|
||||
claim.source_id
|
||||
if isinstance(claim, SynthesisClaimModel)
|
||||
else claim.get("source_id", "")
|
||||
),
|
||||
})
|
||||
|
||||
return {
|
||||
"research_topic": topic,
|
||||
"summary": summary,
|
||||
"confident_findings": confident,
|
||||
"uncertain_areas": uncertain,
|
||||
"contradictions": contradictions,
|
||||
"source_list": source_list,
|
||||
"llm_model_used": llm_model,
|
||||
"generation_timestamp": datetime.now(timezone.utc),
|
||||
"methodology": (
|
||||
"NSCT Stage 9: Neutral Synthesis Engine. "
|
||||
"Bericht generiert aus evidenzbasierten Claims (Claims 0-8). "
|
||||
"Trennung von Fakten und Interpretation. "
|
||||
"Keine politischen Empfehlungen. "
|
||||
"Jede Aussage ist mit Quellen verknuepft (Provenance)."
|
||||
),
|
||||
}
|
||||
return SynthesisReportModel(
|
||||
research_topic=topic,
|
||||
summary=summary,
|
||||
confident_findings=confident,
|
||||
uncertain_areas=uncertain,
|
||||
contradictions=contradictions,
|
||||
source_list=source_list,
|
||||
llm_model_used=llm_model,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -595,14 +589,14 @@ class SynthesisStage(BaseStage):
|
||||
|
||||
logger.info(
|
||||
"Stage 9: Synthesis complete - %d confident, %d uncertain, %d contradictions",
|
||||
len(report["confident_findings"]),
|
||||
len(report["uncertain_areas"]),
|
||||
len(report["contradictions"]),
|
||||
len(report.confident_findings),
|
||||
len(report.uncertain_areas),
|
||||
len(report.contradictions),
|
||||
)
|
||||
|
||||
return StageResult(
|
||||
success=True,
|
||||
data=report,
|
||||
data=report.model_dump(),
|
||||
stage=self,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user