Files
FusionAGI/fusionagi/reasoning/meta_reasoning.py
defiQUG c052b07662
Some checks failed
Tests / test (3.10) (push) Has been cancelled
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.12) (push) Has been cancelled
Tests / lint (push) Has been cancelled
Tests / docker (push) Has been cancelled
Initial commit: add .gitignore and README
2026-02-09 21:51:42 -08:00

86 lines
2.6 KiB
Python

"""Meta-reasoning: challenge assumptions, detect contradictions, revisit nodes."""
from __future__ import annotations
from typing import Any
from fusionagi.schemas.atomic import AtomicSemanticUnit, AtomicUnitType
from fusionagi.reasoning.tot import ThoughtNode, expand_node
from fusionagi._logger import logger
def challenge_assumptions(
units: list[AtomicSemanticUnit],
current_conclusion: str,
) -> list[str]:
"""
Identify and flag assumptions in units that support the conclusion.
"""
flagged: list[str] = []
conclusion_lower = current_conclusion.lower()
for u in units:
if u.type == AtomicUnitType.ASSUMPTION:
flagged.append(u.content)
elif "assume" in u.content.lower() or "assumption" in u.content.lower():
flagged.append(u.content)
elif u.type == AtomicUnitType.CONSTRAINT:
if any(w in conclusion_lower for w in ["must", "should", "require"]):
flagged.append(f"Constraint may be assumed: {u.content[:100]}")
logger.debug("Assumptions flagged", extra={"count": len(flagged)})
return flagged
def detect_contradictions(
units: list[AtomicSemanticUnit],
) -> list[tuple[str, str]]:
"""
Find conflicting units (heuristic: negation mismatch, same subject).
"""
neg_words = {"not", "no", "never", "none", "cannot", "shouldn't", "won't", "don't", "doesn't"}
pairs: list[tuple[str, str]] = []
for i, a in enumerate(units):
wa = set(a.content.lower().split())
for b in units[i + 1:]:
wb = set(b.content.lower().split())
a_neg = bool(wa & neg_words)
b_neg = bool(wb & neg_words)
if a_neg != b_neg:
overlap = len(wa & wb) / max(len(wa), 1)
if overlap > 0.2:
pairs.append((a.unit_id, b.unit_id))
logger.debug("Contradictions detected", extra={"count": len(pairs)})
return pairs
def revisit_node(
tree: ThoughtNode | None,
node_id: str,
new_evidence: str,
) -> ThoughtNode | None:
"""
Re-expand a node when new evidence arrives.
Creates a new child with the new evidence.
"""
if tree is None:
return None
def find_node(n: ThoughtNode) -> ThoughtNode | None:
if n.node_id == node_id:
return n
for c in n.children:
found = find_node(c)
if found:
return found
return None
node = find_node(tree)
if not node:
return tree
child = expand_node(node, new_evidence)
child.metadata["revisit_evidence"] = new_evidence[:200]
return tree