Agents sometimes repeat the same failing tool call forever, burning tokens. Detect it from the action history.
Each action is a (tool, args) pair, where args is a dict. Two actions are the same if the tool matches and the args are equal (key order doesn't matter).
Implement detect_loop(actions, max_repeats=3, window=6) returning a reason string or None:
"repeat:<tool>" if the same action occurs max_repeats times in a row at the end of the history."cycle:<n>" if the last 2*n actions are the same length-n sequence repeated twice, for the smallest n from 2 to window // 2 (e.g. search → read → search → read).None.