loopstray
Detects LangChain AgentExecutor(...) (and
AgentExecutor.from_agent_and_tools(...)) construction calls with no
max_execution_time and/or no max_iterations set -- a poorly-behaved
agent stuck in an unconverged reasoning loop can run far longer, and cost
far more, than it needs to before anything stops it. Zero runtime
dependencies, pure ast-based static analysis -- it never imports or
executes the scanned code.
Why
A LangChain AgentExecutor runs a ReAct-style loop: reason, call a tool,
observe the result, reason again, until the agent decides it's done. A
demo with a handful of test prompts converges quickly every time -- so it
ships without either cap ever being set. Then a real user sends a request
the agent genuinely can't resolve, and instead of failing, it keeps
calling tools and re-reasoning, never converging, burning a fresh LLM API
call on every step.
This tool's own verified check of LangChain's source
(langchain_classic/agents/agent.py) found the two knobs behave
asymmetrically when left unset:
max_iterations: int | None = 15-- there is a hidden default iteration cap. Leaving it unset is not literally infinite looping.max_execution_time: float | None = None-- there is no default wall-clock cap at all. Fifteen iterations, each stuck on a slow tool call or a long reasoning step, can still run for minutes with nothing to stop it early -- often ending only when an infrastructure-level timeout finally kills the request, later and more expensively than an explicit cap would have allowed.
loopstray flags the two omissions at different severities to match this
verified, asymmetric reality, rather than treating "neither is set" as
one flat check. This is a distinct failure mode from this workspace's
llmbrittle (a single LLM call failing with no
cross-provider fallback -- the call errors out) and from Node's
stallwary (a streaming connection hanging at the network/transport
layer). loopstray is about a reasoning loop that never terminates on
its own, at the agent-framework level. See DETAILS.md for
the full, verified comparison and prior-art check.
Install
pip install loopstray
Usage
loopstray src/ # scan a directory recursively
loopstray mymodule.py # scan a single file
loopstray src/ --json # machine-readable output for CI
loopstray src/ --strict # also fail on LS002 (warning) findings
Exit codes: 0 clean, 1 an LS001 blocker is present (or any finding
under --strict), 2 usage/syntax error.
What it checks (v0.1)
| Rule | Severity | Meaning |
|---|---|---|
LS001 |
blocker | An AgentExecutor construction has no max_execution_time. No wall-clock ceiling exists at all -- LangChain's own default is unbounded time, regardless of any iteration cap. |
LS002 |
warning | An AgentExecutor construction has no max_iterations. LangChain's own hidden default of 15 still applies (not literally unbounded), but that default is invisible in this code and not pinned against future library changes. |
Suppress a line with a trailing # loopstray: ignore (or
# noqa: LS001).
Library usage
from loopstray import scan_file
findings = scan_file("mymodule.py")
for f in findings:
print(f)
See docs/USAGE.md for more, and DETAILS.md for design rationale, detection scope, and honest limitations.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loopstray-0.1.0.tar.gz.
File metadata
- Download URL: loopstray-0.1.0.tar.gz
- Upload date:
- Size: 14.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b369d21f8295db08f53d6684645843868de03f48befb7ae6e07a9ad2765613d5
|
|
| MD5 |
887375fc2a19fa33296aff4f843496f6
|
|
| BLAKE2b-256 |
fd68c12f08efd9232e215d5a2af2d6fbef7a9c5dabcc89384e5a46690c20d753
|
File details
Details for the file loopstray-0.1.0-py3-none-any.whl.
File metadata
- Download URL: loopstray-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ee25b467e7594a57bb924364dce8aa70b1f7f8234b17eedd58e528c98543ea2
|
|
| MD5 |
ee9c31f56009a7b6a26fe81f6e5a697b
|
|
| BLAKE2b-256 |
fb1a7ebf940e87dbc7cd6d4ecf5d6dd8b3d80bdbc87699245775ce3af2df41a0
|