File size: 3,222 Bytes
5f43c7d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""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