her / engine /core /loops.py
geekwrestler's picture
Squash history (purge pre-scrub demo session blobs)
5f43c7d
"""loops.py — retry-loop detection on a turn's Bash calls.
A REAL loop (the only kind counted, the only kind that earns advice) =
the same EXACT full Bash command string occurs >= 2x within a turn
AND >= 1 of those occurrences errored.
NEVER truncate the command (the POC truncated to a 55-char prefix and invented
six loops; with the exact-string rule the fixture has ZERO). Pure code, NO model.
A separate, clearly-weaker `near_identical` hint groups by a NORMALIZED command
(whitespace collapsed). It is explicitly NOT a real loop and is NEVER counted as
one — it is only a soft signal for the narrator to *consider*, never assert.
"""
from __future__ import annotations
import re
from dataclasses import dataclass, field
from typing import Any
_WS_RE = re.compile(r"\s+")
@dataclass
class Loop:
"""A real retry loop within a turn."""
command: str # the exact, un-truncated command string
count: int # how many times it ran in this turn
errored: int # how many of those runs errored
@dataclass
class NearIdentical:
"""A clearly-weaker hint: same NORMALIZED command >= 2x. NOT a real loop."""
normalized: str
count: int
errored: int
@dataclass
class TurnLoops:
turn: int
loops: list[Loop] = field(default_factory=list) # real loops only
near_identical: list[NearIdentical] = field(default_factory=list) # weak hints
def _bash_command(tc: Any) -> str:
inp = tc.input if isinstance(tc.input, dict) else {}
return str(inp.get("command", "") or "")
def _normalize(cmd: str) -> str:
return _WS_RE.sub(" ", cmd).strip()
def detect_loops(turn) -> TurnLoops:
"""Detect real loops + near-identical hints for one turn's Bash calls."""
out = TurnLoops(turn=turn.i)
# exact full command string → list of (errored?) occurrences
exact: dict[str, list[bool]] = {}
norm: dict[str, list[bool]] = {}
for tc in turn.tools:
if tc.name != "Bash":
continue
cmd = _bash_command(tc)
if not cmd:
continue
err = bool(getattr(tc, "errored", False))
exact.setdefault(cmd, []).append(err)
norm.setdefault(_normalize(cmd), []).append(err)
# REAL loop: exact command >= 2x AND at least one errored
for cmd, errs in exact.items():
if len(errs) >= 2 and any(errs):
out.loops.append(Loop(command=cmd, count=len(errs), errored=sum(errs)))
# WEAK hint: normalized command >= 2x (regardless of error), but only if it
# is not already a counted exact loop. Clearly weaker; never a real loop.
exact_norms = {_normalize(c) for c, e in exact.items() if len(e) >= 2 and any(e)}
for ncmd, errs in norm.items():
if len(errs) >= 2 and ncmd not in exact_norms:
out.near_identical.append(
NearIdentical(normalized=ncmd, count=len(errs), errored=sum(errs))
)
return out
def detect_all_loops(turns) -> dict[int, TurnLoops]:
"""Map turn index → TurnLoops for every turn that has any Bash signal."""
result: dict[int, TurnLoops] = {}
for t in turns:
tl = detect_loops(t)
if tl.loops or tl.near_identical:
result[t.i] = tl
return result