Function bodies 18 total
build_command function · python · L42-L76 (35 LOC)src/aumai_reasonflow/cli.py
def build_command(input_path: Path, output_path: Path | None) -> None:
"""Build a ReasoningChain from a JSON specification file.
The spec file should be a JSON object with keys:
chain_id, title, description (optional), steps (list of step objects).
Example:
aumai-reasonflow build --input spec.json --output chain.json
"""
raw = json.loads(input_path.read_text(encoding="utf-8"))
chain_id = raw.get("chain_id", "chain_1")
title = raw.get("title", "Untitled Chain")
description = raw.get("description")
builder = ChainBuilder(chain_id=chain_id, title=title, description=description)
for step_spec in raw.get("steps", []):
try:
step_type = StepType(step_spec.get("step_type", "inference"))
builder.add_step(
step_id=step_spec["step_id"],
content=step_spec["content"],
step_type=step_type,
depends_on=step_spec.get("depends_on", []),
validate_command function · python · L81-L109 (29 LOC)src/aumai_reasonflow/cli.py
def validate_command(chain_file: Path) -> None:
"""Validate a reasoning chain JSON file for logical fallacies.
CHAIN_FILE: Path to a saved ReasoningChain JSON file.
Example:
aumai-reasonflow validate chain.json
"""
try:
data = json.loads(chain_file.read_text(encoding="utf-8"))
chain = ReasoningChain.model_validate(data)
except Exception as exc:
click.echo(f"ERROR loading chain: {exc}", err=True)
sys.exit(1)
detector = FallacyDetector()
validation = detector.validate(chain)
status = "VALID" if validation.is_valid else "INVALID"
click.echo(f"Chain '{chain.title}': {status}")
click.echo(f"Steps: {validation.step_count} Errors: {len(validation.errors)} Warnings: {len(validation.warnings)}")
for issue in validation.issues:
icon = "ERROR" if issue.severity == "error" else "WARN "
click.echo(f" [{icon}] {issue.step_id}: {issue.message}")
if not validation.is_valid:
sysvisualize_command function · python · L129-L154 (26 LOC)src/aumai_reasonflow/cli.py
def visualize_command(
chain_file: Path, output_format: str, output_path: Path | None
) -> None:
"""Render a reasoning chain as Mermaid or plain text.
CHAIN_FILE: Path to a saved ReasoningChain JSON file.
Example:
aumai-reasonflow visualize chain.json --format mermaid
"""
try:
data = json.loads(chain_file.read_text(encoding="utf-8"))
chain = ReasoningChain.model_validate(data)
except Exception as exc:
click.echo(f"ERROR loading chain: {exc}", err=True)
sys.exit(1)
viz = ChainVisualizer()
rendered = viz.to_mermaid(chain) if output_format == "mermaid" else viz.to_text(chain)
if output_path:
output_path.write_text(rendered, encoding="utf-8")
click.echo(f"Wrote {output_format} diagram to {output_path}")
else:
click.echo(rendered)ChainBuilder.__init__ method · python · L42-L53 (12 LOC)src/aumai_reasonflow/core.py
def __init__(self, chain_id: str, title: str, description: Optional[str] = None) -> None:
"""Initialise the builder.
Args:
chain_id: Unique ID for the chain.
title: Short title for the chain.
description: Optional longer description.
"""
self._chain = ReasoningChain(
chain_id=chain_id, title=title, description=description
)
self._issue_counter = 0ChainBuilder.add_step method · python · L55-L87 (33 LOC)src/aumai_reasonflow/core.py
def add_step(
self,
step_id: str,
content: str,
step_type: StepType,
depends_on: Optional[list[str]] = None,
confidence: float = 1.0,
notes: Optional[str] = None,
) -> "ChainBuilder":
"""Add a generic step to the chain.
Args:
step_id: Unique identifier for this step.
content: Natural-language statement.
step_type: Type classification.
depends_on: List of step IDs this step depends on.
confidence: Confidence level in [0, 1].
notes: Optional annotations.
Returns:
Self, for method chaining.
"""
self._chain.add_step(
ReasoningStep(
step_id=step_id,
content=content,
step_type=step_type,
depends_on=depends_on or [],
confidence=confidence,
notes=notes,
)
)
return selfChainBuilder.premise method · python · L89-L97 (9 LOC)src/aumai_reasonflow/core.py
def premise(
self,
step_id: str,
content: str,
confidence: float = 1.0,
notes: Optional[str] = None,
) -> "ChainBuilder":
"""Add a PREMISE step."""
return self.add_step(step_id, content, StepType.PREMISE, confidence=confidence, notes=notes)ChainBuilder.inference method · python · L99-L110 (12 LOC)src/aumai_reasonflow/core.py
def inference(
self,
step_id: str,
content: str,
depends_on: Optional[list[str]] = None,
confidence: float = 1.0,
notes: Optional[str] = None,
) -> "ChainBuilder":
"""Add an INFERENCE step."""
return self.add_step(
step_id, content, StepType.INFERENCE, depends_on=depends_on, confidence=confidence, notes=notes
)Repobility · code-quality intelligence platform · https://repobility.com
ChainBuilder.conclusion method · python · L112-L123 (12 LOC)src/aumai_reasonflow/core.py
def conclusion(
self,
step_id: str,
content: str,
depends_on: Optional[list[str]] = None,
confidence: float = 1.0,
notes: Optional[str] = None,
) -> "ChainBuilder":
"""Add a CONCLUSION step."""
return self.add_step(
step_id, content, StepType.CONCLUSION, depends_on=depends_on, confidence=confidence, notes=notes
)ChainBuilder.assumption method · python · L125-L133 (9 LOC)src/aumai_reasonflow/core.py
def assumption(
self,
step_id: str,
content: str,
confidence: float = 0.8,
notes: Optional[str] = None,
) -> "ChainBuilder":
"""Add an ASSUMPTION step."""
return self.add_step(step_id, content, StepType.ASSUMPTION, confidence=confidence, notes=notes)ChainBuilder.evidence method · python · L135-L146 (12 LOC)src/aumai_reasonflow/core.py
def evidence(
self,
step_id: str,
content: str,
depends_on: Optional[list[str]] = None,
confidence: float = 1.0,
notes: Optional[str] = None,
) -> "ChainBuilder":
"""Add an EVIDENCE step."""
return self.add_step(
step_id, content, StepType.EVIDENCE, depends_on=depends_on, confidence=confidence, notes=notes
)ChainBuilder.build method · python · L148-L154 (7 LOC)src/aumai_reasonflow/core.py
def build(self) -> ReasoningChain:
"""Finalise and return the constructed chain.
Returns:
The assembled ReasoningChain.
"""
return self._chainChainVisualizer.to_mermaid method · python · L181-L207 (27 LOC)src/aumai_reasonflow/core.py
def to_mermaid(self, chain: ReasoningChain) -> str:
"""Render the chain as a Mermaid flowchart (top-down).
Args:
chain: The ReasoningChain to render.
Returns:
Mermaid diagram string.
"""
lines: list[str] = [f"flowchart TD", f" %% {chain.title}"]
for step_id, step in chain.steps.items():
safe_id = self._safe_id(step_id)
label = self._truncate(step.content, 40)
open_shape, close_shape = self._MERMAID_SHAPES.get(
step.step_type, ("[", "]")
)
lines.append(f' {safe_id}{open_shape}"{label}"{close_shape}')
# Edges
for step_id, step in chain.steps.items():
safe_id = self._safe_id(step_id)
for dep_id in step.depends_on:
safe_dep = self._safe_id(dep_id)
lines.append(f" {safe_dep} --> {safe_id}")
return "\n".join(lines)ChainVisualizer.to_text method · python · L209-L239 (31 LOC)src/aumai_reasonflow/core.py
def to_text(self, chain: ReasoningChain, indent: str = " ") -> str:
"""Render the chain as an indented text outline.
Args:
chain: The ReasoningChain to render.
indent: Indentation string per dependency level.
Returns:
Plain-text representation.
"""
lines: list[str] = [
f"Chain: {chain.title} (id={chain.chain_id})",
]
if chain.description:
lines.append(f"Description: {chain.description}")
lines.append("")
# Topological order
ordered = self._topological_sort(chain)
for step in ordered:
depth = self._depth(step.step_id, chain)
prefix = indent * depth
conf_str = f"[{step.confidence:.0%}]"
lines.append(
f"{prefix}[{step.step_type.value.upper()}] {conf_str} {step.step_id}: {step.content}"
)
if step.notes:
lines.append(f"{prefix} NOTE:ChainVisualizer._depth method · python · L253-L278 (26 LOC)src/aumai_reasonflow/core.py
def _depth(
self,
step_id: str,
chain: ReasoningChain,
visited: set[str] | None = None,
) -> int:
"""Compute the dependency depth of a step (0 = no dependencies).
Args:
step_id: The step whose depth to compute.
chain: The containing ReasoningChain.
visited: Set of step IDs already on the current recursion path,
used to break cycles and prevent infinite recursion.
Returns:
Integer depth; 0 means the step has no dependencies.
"""
if visited is None:
visited = set()
if step_id in visited:
return 0
step = chain.steps.get(step_id)
if not step or not step.depends_on:
return 0
visited = visited | {step_id}
return 1 + max(self._depth(dep, chain, visited) for dep in step.depends_on)ChainVisualizer._topological_sort method · python · L280-L298 (19 LOC)src/aumai_reasonflow/core.py
def _topological_sort(self, chain: ReasoningChain) -> list[ReasoningStep]:
"""Return steps in topological (dependency-first) order."""
visited: set[str] = set()
result: list[ReasoningStep] = []
def visit(step_id: str) -> None:
if step_id in visited:
return
visited.add(step_id)
step = chain.steps.get(step_id)
if step is None:
return
for dep_id in step.depends_on:
visit(dep_id)
result.append(step)
for sid in chain.steps:
visit(sid)
return resultCitation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
FallacyDetector.validate method · python · L323-L395 (73 LOC)src/aumai_reasonflow/core.py
def validate(self, chain: ReasoningChain) -> ChainValidation:
"""Validate a reasoning chain and return all detected issues.
Args:
chain: The ReasoningChain to validate.
Returns:
ChainValidation describing validity and all issues found.
"""
issues: list[ValidationIssue] = []
issue_counter = 0
def add_issue(
step_id: str, fallacy: FallacyType, message: str, severity: str = "error"
) -> None:
nonlocal issue_counter
issue_counter += 1
issues.append(
ValidationIssue(
issue_id=f"issue_{issue_counter:04d}",
step_id=step_id,
fallacy_type=fallacy,
message=message,
severity=severity,
)
)
# 1. Broken / undefined references
all_ids = set(chain.steps.keys())
for step_id, step in chain.steps.iFallacyDetector._detect_cycles method · python · L397-L434 (38 LOC)src/aumai_reasonflow/core.py
def _detect_cycles(self, chain: ReasoningChain) -> set[str]:
"""Return the set of step IDs involved in dependency cycles.
When a back-edge to a GRAY ancestor is found, all nodes on the current
DFS path from that ancestor to the current node are added to the cyclic
set, not just the ancestor itself.
"""
WHITE, GRAY, BLACK = 0, 1, 2
colors: dict[str, int] = {sid: WHITE for sid in chain.steps}
cyclic: set[str] = set()
# path_stack tracks the current DFS path for cycle-member extraction
path_stack: list[str] = []
def dfs(step_id: str) -> None:
if step_id not in colors:
return
if colors[step_id] == GRAY:
# Back-edge found: add all nodes in the cycle (from the ancestor
# to the current end of the path stack).
ancestor_index = path_stack.index(step_id)
for node_in_cycle in path_stack[ancestor_indexReasoningChain.add_step method · python · L63-L74 (12 LOC)src/aumai_reasonflow/models.py
def add_step(self, step: ReasoningStep) -> None:
"""Add a step to the chain.
Args:
step: The ReasoningStep to add.
Raises:
ValueError: If a step with the same ID already exists.
"""
if step.step_id in self.steps:
raise ValueError(f"Step '{step.step_id}' already exists in chain.")
self.steps[step.step_id] = step