"""Parse bullet lists with optional [verdict] tags and comment tags.""" from __future__ import annotations import re _BULLET_RE = re.compile(r"^\s*[-*•]\s+(.*\S)\s*$") _COMMENT_RE = re.compile(r"(.*?)", re.IGNORECASE | re.DOTALL) _VERDICT_RE = re.compile( r"^\[(supported|uncertain|contradicted)\]\s*", re.IGNORECASE, ) _VALID_VERDICTS = frozenset({"supported", "uncertain", "contradicted"}) def parse_bullets(text: str) -> list[tuple[str, str, str]]: """Return [(point_text, comment, verdict), ...] from a bullet markdown block. Optional leading tags: `[supported]`, `[uncertain]`, `[contradicted]`. Default verdict is `uncertain` (needs web check). """ points: list[tuple[str, str, str]] = [] for line in (text or "").splitlines(): match = _BULLET_RE.match(line) if not match: continue body = match.group(1).strip() comments = _COMMENT_RE.findall(body) comment = " ".join(c.strip() for c in comments if c.strip()) clean = _COMMENT_RE.sub("", body).strip() verdict = "uncertain" verdict_match = _VERDICT_RE.match(clean) if verdict_match: verdict = verdict_match.group(1).lower() clean = clean[verdict_match.end() :].strip() if clean: points.append((clean, comment, verdict)) return points def bullets_to_claims( *, message_id: str, rewritten: str, citations: list | None = None, start_order: int = 0, ) -> list[dict]: """Turn rewritten bullets into Claim dicts (preliminary verdict from tags).""" cites = citations or [] claims: list[dict] = [] points = parse_bullets(rewritten) if not points: # Fallback: whole rewrite as one uncertain factual point raw = (rewritten or "").strip() if not raw: return [] return [ { "id": f"{message_id}-0", "message_id": message_id, "order": 0, "text": raw, "is_claim": True, "comment": "", "verdict": "uncertain", "reason": "non-bullet fallback", "citations": cites, } ] for i, (text, comment, verdict) in enumerate(points): if verdict not in _VALID_VERDICTS: verdict = "uncertain" reason = comment or ( "common knowledge" if verdict == "supported" else "needs web check" ) claims.append( { "id": f"{message_id}-{start_order + i}", "message_id": message_id, "order": start_order + i, "text": text, "is_claim": True, "comment": comment, "verdict": verdict, "reason": reason, "citations": list(cites) if verdict == "uncertain" else [], } ) return claims