looplens 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- looplens-0.1.0/.github/workflows/ci.yml +43 -0
- looplens-0.1.0/.github/workflows/release.yml +53 -0
- looplens-0.1.0/.gitignore +31 -0
- looplens-0.1.0/CLAUDE.md +65 -0
- looplens-0.1.0/LAUNCH.md +170 -0
- looplens-0.1.0/PKG-INFO +250 -0
- looplens-0.1.0/PRD.md +1736 -0
- looplens-0.1.0/README.md +224 -0
- looplens-0.1.0/ROADMAP.md +84 -0
- looplens-0.1.0/docs/media/looplens-live-loop-detection.gif +0 -0
- looplens-0.1.0/examples/handoff_bounce_agent.py +34 -0
- looplens-0.1.0/examples/looping_agent.py +31 -0
- looplens-0.1.0/examples/real_research_agent_openai.py +153 -0
- looplens-0.1.0/examples/retry_storm_agent.py +23 -0
- looplens-0.1.0/examples/simple_agent.py +16 -0
- looplens-0.1.0/looplens/__init__.py +17 -0
- looplens-0.1.0/looplens/cli.py +339 -0
- looplens-0.1.0/looplens/config.py +56 -0
- looplens-0.1.0/looplens/sdk.py +306 -0
- looplens-0.1.0/looplens/server/__init__.py +1 -0
- looplens-0.1.0/looplens/server/__main__.py +10 -0
- looplens-0.1.0/looplens/server/_ui/assets/index-D-EP9mOV.css +1 -0
- looplens-0.1.0/looplens/server/_ui/assets/index-Dpao4I-T.js +68 -0
- looplens-0.1.0/looplens/server/_ui/index.html +13 -0
- looplens-0.1.0/looplens/server/app.py +90 -0
- looplens-0.1.0/looplens/server/db.py +214 -0
- looplens-0.1.0/looplens/server/detectors.py +273 -0
- looplens-0.1.0/looplens/server/metrics.py +99 -0
- looplens-0.1.0/looplens/server/models.py +180 -0
- looplens-0.1.0/looplens/server/routes.py +151 -0
- looplens-0.1.0/looplens/server/websocket.py +72 -0
- looplens-0.1.0/pyproject.toml +53 -0
- looplens-0.1.0/tests/test_detectors.py +131 -0
- looplens-0.1.0/tests/test_sdk.py +111 -0
- looplens-0.1.0/tests/test_stream.py +72 -0
- looplens-0.1.0/traces/sample_run.jsonl +11 -0
- looplens-0.1.0/ui/README.md +25 -0
- looplens-0.1.0/ui/index.html +12 -0
- looplens-0.1.0/ui/package-lock.json +2722 -0
- looplens-0.1.0/ui/package.json +26 -0
- looplens-0.1.0/ui/postcss.config.js +6 -0
- looplens-0.1.0/ui/src/App.tsx +22 -0
- looplens-0.1.0/ui/src/api.ts +102 -0
- looplens-0.1.0/ui/src/components/EventDrawer.tsx +58 -0
- looplens-0.1.0/ui/src/components/MetricsBar.tsx +29 -0
- looplens-0.1.0/ui/src/components/Timeline.tsx +46 -0
- looplens-0.1.0/ui/src/components/WarningCard.tsx +23 -0
- looplens-0.1.0/ui/src/index.css +14 -0
- looplens-0.1.0/ui/src/lib.ts +58 -0
- looplens-0.1.0/ui/src/main.tsx +24 -0
- looplens-0.1.0/ui/src/pages/RunDetailPage.tsx +109 -0
- looplens-0.1.0/ui/src/pages/RunsPage.tsx +89 -0
- looplens-0.1.0/ui/tailwind.config.js +14 -0
- looplens-0.1.0/ui/tsconfig.json +20 -0
- looplens-0.1.0/ui/tsconfig.node.json +12 -0
- looplens-0.1.0/ui/vite.config.ts +22 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: pytest (py${{ matrix.python-version }})
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
cache: pip
|
|
23
|
+
- name: Install (server + dev deps)
|
|
24
|
+
run: pip install -e ".[dev]"
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: pytest -q
|
|
27
|
+
|
|
28
|
+
ui-build:
|
|
29
|
+
name: UI build check
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
- uses: actions/setup-node@v4
|
|
34
|
+
with:
|
|
35
|
+
node-version: "20"
|
|
36
|
+
cache: npm
|
|
37
|
+
cache-dependency-path: ui/package-lock.json
|
|
38
|
+
- name: Install UI deps
|
|
39
|
+
run: npm --prefix ui ci
|
|
40
|
+
- name: Build UI bundle
|
|
41
|
+
run: npm --prefix ui run build
|
|
42
|
+
- name: Assert bundle was produced
|
|
43
|
+
run: test -f looplens/server/_ui/index.html
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when you push a version tag, e.g. `git tag v0.1.0 && git push --tags`.
|
|
4
|
+
# The UI is built first and force-included into the wheel (see pyproject `artifacts`),
|
|
5
|
+
# so the published package installs with zero Node.
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: Build wheel + sdist
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: "20"
|
|
19
|
+
cache: npm
|
|
20
|
+
cache-dependency-path: ui/package-lock.json
|
|
21
|
+
- name: Build UI bundle into looplens/server/_ui
|
|
22
|
+
run: |
|
|
23
|
+
npm --prefix ui ci
|
|
24
|
+
npm --prefix ui run build
|
|
25
|
+
test -f looplens/server/_ui/index.html
|
|
26
|
+
- uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
- name: Build distributions
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade build
|
|
32
|
+
python -m build
|
|
33
|
+
- name: Verify the wheel bundles the UI
|
|
34
|
+
run: |
|
|
35
|
+
python -m zipfile -l dist/*.whl | grep -q "looplens/server/_ui/index.html"
|
|
36
|
+
- uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: dist
|
|
39
|
+
path: dist/
|
|
40
|
+
|
|
41
|
+
publish:
|
|
42
|
+
name: Publish to PyPI
|
|
43
|
+
needs: build
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
environment: pypi
|
|
46
|
+
permissions:
|
|
47
|
+
id-token: write # trusted publishing (OIDC) — no API token stored
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/download-artifact@v4
|
|
50
|
+
with:
|
|
51
|
+
name: dist
|
|
52
|
+
path: dist/
|
|
53
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.env
|
|
11
|
+
|
|
12
|
+
# LoopLens local data
|
|
13
|
+
*.db
|
|
14
|
+
*.db-wal
|
|
15
|
+
*.db-shm
|
|
16
|
+
.looplens/
|
|
17
|
+
looplens.env
|
|
18
|
+
looplens-traces/
|
|
19
|
+
|
|
20
|
+
# Node / UI
|
|
21
|
+
node_modules/
|
|
22
|
+
ui/dist/
|
|
23
|
+
ui/.vite/
|
|
24
|
+
# Built dashboard bundled into the wheel (regenerated by `npm --prefix ui run build`)
|
|
25
|
+
looplens/server/_ui/
|
|
26
|
+
|
|
27
|
+
# Editor / OS
|
|
28
|
+
.vscode/
|
|
29
|
+
.idea/
|
|
30
|
+
.DS_Store
|
|
31
|
+
Thumbs.db
|
looplens-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
|
4
|
+
|
|
5
|
+
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
|
6
|
+
|
|
7
|
+
## 1. Think Before Coding
|
|
8
|
+
|
|
9
|
+
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
|
10
|
+
|
|
11
|
+
Before implementing:
|
|
12
|
+
- State your assumptions explicitly. If uncertain, ask.
|
|
13
|
+
- If multiple interpretations exist, present them - don't pick silently.
|
|
14
|
+
- If a simpler approach exists, say so. Push back when warranted.
|
|
15
|
+
- If something is unclear, stop. Name what's confusing. Ask.
|
|
16
|
+
|
|
17
|
+
## 2. Simplicity First
|
|
18
|
+
|
|
19
|
+
**Minimum code that solves the problem. Nothing speculative.**
|
|
20
|
+
|
|
21
|
+
- No features beyond what was asked.
|
|
22
|
+
- No abstractions for single-use code.
|
|
23
|
+
- No "flexibility" or "configurability" that wasn't requested.
|
|
24
|
+
- No error handling for impossible scenarios.
|
|
25
|
+
- If you write 200 lines and it could be 50, rewrite it.
|
|
26
|
+
|
|
27
|
+
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
|
28
|
+
|
|
29
|
+
## 3. Surgical Changes
|
|
30
|
+
|
|
31
|
+
**Touch only what you must. Clean up only your own mess.**
|
|
32
|
+
|
|
33
|
+
When editing existing code:
|
|
34
|
+
- Don't "improve" adjacent code, comments, or formatting.
|
|
35
|
+
- Don't refactor things that aren't broken.
|
|
36
|
+
- Match existing style, even if you'd do it differently.
|
|
37
|
+
- If you notice unrelated dead code, mention it - don't delete it.
|
|
38
|
+
|
|
39
|
+
When your changes create orphans:
|
|
40
|
+
- Remove imports/variables/functions that YOUR changes made unused.
|
|
41
|
+
- Don't remove pre-existing dead code unless asked.
|
|
42
|
+
|
|
43
|
+
The test: Every changed line should trace directly to the user's request.
|
|
44
|
+
|
|
45
|
+
## 4. Goal-Driven Execution
|
|
46
|
+
|
|
47
|
+
**Define success criteria. Loop until verified.**
|
|
48
|
+
|
|
49
|
+
Transform tasks into verifiable goals:
|
|
50
|
+
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
|
51
|
+
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
|
52
|
+
- "Refactor X" → "Ensure tests pass before and after"
|
|
53
|
+
|
|
54
|
+
For multi-step tasks, state a brief plan:
|
|
55
|
+
```
|
|
56
|
+
1. [Step] → verify: [check]
|
|
57
|
+
2. [Step] → verify: [check]
|
|
58
|
+
3. [Step] → verify: [check]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|
looplens-0.1.0/LAUNCH.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# LoopLens — Launch Assets
|
|
2
|
+
|
|
3
|
+
Copy-paste launch posts for each channel. Replace `REPO_URL` with the GitHub
|
|
4
|
+
link and attach the demo GIF where noted.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## One-liner
|
|
9
|
+
|
|
10
|
+
> LoopLens — Chrome DevTools for AI agent loops. See your agent run live and get
|
|
11
|
+
> warned the moment it repeats itself, retries blindly, or stops making progress.
|
|
12
|
+
|
|
13
|
+
## The hook (problem → product)
|
|
14
|
+
|
|
15
|
+
Your agent "works." The terminal scrolls. It looks busy. Then it burns 5 LLM
|
|
16
|
+
calls searching the same thing 5 times and gives up — and you only find out from
|
|
17
|
+
the final error. LoopLens makes the loop visible *while it runs* and tells you,
|
|
18
|
+
in plain language, that the agent is stuck and where.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## GitHub release notes (v0.1.0)
|
|
23
|
+
|
|
24
|
+
**LoopLens v0.1.0 — local-first loop debugger for AI agents.**
|
|
25
|
+
|
|
26
|
+
- 🪄 **Zero-friction install:** `pip install "looplens[server]"` — no Node, no
|
|
27
|
+
build step; the dashboard is bundled in the wheel.
|
|
28
|
+
- 🧩 **Zero-dependency SDK:** pure-stdlib `trace()` / `event()` / `@observe`.
|
|
29
|
+
Drops into LangGraph, CrewAI, OpenAI Agents SDK, or a plain `while` loop
|
|
30
|
+
without pinning anything or touching your agent's deps.
|
|
31
|
+
- 📺 **Live timeline** over SSE: LLM calls, tool calls, retries, handoffs, state.
|
|
32
|
+
- 🚨 **Six transparent loop detectors:** repeated tool call, similar-input
|
|
33
|
+
repeat, no-progress loop, retry storm, long-running step, cost spike.
|
|
34
|
+
- 🩺 **Health score** (0–100 → Healthy / Warning / Likely stuck / Failed).
|
|
35
|
+
- 💾 **Local-first:** SQLite, no auth, no cloud, no API key. JSONL import/export.
|
|
36
|
+
- 🛟 **Fail-silent:** if the dashboard is down, the SDK buffers to JSONL and
|
|
37
|
+
never crashes your agent.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install "looplens[server]"
|
|
41
|
+
looplens dev
|
|
42
|
+
looplens demo # watch it trip a loop warning live
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
MIT. Feedback and framework-adapter requests welcome.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Hacker News (Show HN)
|
|
50
|
+
|
|
51
|
+
**Title:** Show HN: LoopLens – a local-first loop debugger for AI agents
|
|
52
|
+
|
|
53
|
+
**Body:**
|
|
54
|
+
|
|
55
|
+
I kept shipping agents that *looked* like they were working — the logs scrolled,
|
|
56
|
+
tools fired — but they were quietly stuck calling the same tool over and over,
|
|
57
|
+
burning tokens, and failing at the end. Generic tracing tools show me spans;
|
|
58
|
+
they don't tell me the loop is unhealthy.
|
|
59
|
+
|
|
60
|
+
LoopLens is a small local tool focused on exactly that. You add a tiny zero-dep
|
|
61
|
+
SDK to the agent you already have, run a local dashboard, and watch the loop live.
|
|
62
|
+
It raises rule-based warnings — repeated tool call, no-progress loop, retry
|
|
63
|
+
storm, cost spike — with a plain-English "what happened / why it matters / where /
|
|
64
|
+
how to fix."
|
|
65
|
+
|
|
66
|
+
It's deliberately *not* another observability platform: no auth, no cloud, no
|
|
67
|
+
eval datasets, no graph-first UI. Just timeline + warnings + metrics, local-first.
|
|
68
|
+
|
|
69
|
+
The detectors are transparent rules (no black-box scoring), the SDK is pure
|
|
70
|
+
stdlib so it won't fight your agent's dependencies, and the `[server]` install
|
|
71
|
+
ships the prebuilt UI so there's no Node/npm step.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install "looplens[server]" && looplens dev && looplens demo
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Repo: REPO_URL — would love feedback, especially on which framework adapter
|
|
78
|
+
(LangGraph / CrewAI / OpenAI Agents SDK) to build first.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## X / Twitter (thread)
|
|
83
|
+
|
|
84
|
+
1/ Your agent isn't "thinking." It's calling `search_docs("refund policy")` for
|
|
85
|
+
the 5th time and about to give up. You'll find out from the final error.
|
|
86
|
+
|
|
87
|
+
I built **LoopLens** to make that visible *while it runs.* 🧵
|
|
88
|
+
|
|
89
|
+
2/ It's Chrome DevTools, but for agent loops. Add a tiny zero-dep SDK, open a
|
|
90
|
+
local dashboard, watch every LLM call / tool call / retry stream in live.
|
|
91
|
+
|
|
92
|
+
3/ The point isn't logs — it's *opinions*. LoopLens warns you:
|
|
93
|
+
• repeated tool call
|
|
94
|
+
• no-progress loop
|
|
95
|
+
• retry storm
|
|
96
|
+
• cost spike
|
|
97
|
+
…each with what happened, why, where, and how to fix.
|
|
98
|
+
|
|
99
|
+
4/ Local-first: SQLite, no auth, no cloud, no API key. The SDK is pure stdlib so
|
|
100
|
+
it won't conflict with LangGraph / CrewAI / OpenAI Agents SDK / your custom loop.
|
|
101
|
+
If the dashboard's down it buffers to JSONL and never crashes your agent.
|
|
102
|
+
|
|
103
|
+
5/ Install is one line — the dashboard ships prebuilt, no Node:
|
|
104
|
+
`pip install "looplens[server]" && looplens dev && looplens demo`
|
|
105
|
+
[attach GIF]
|
|
106
|
+
Repo + roadmap 👇 REPO_URL
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## LinkedIn
|
|
111
|
+
|
|
112
|
+
Agent development is becoming **loop engineering**. Agents don't answer once —
|
|
113
|
+
they plan, call tools, retry, hand off, and loop until success or budget runs
|
|
114
|
+
out. When that loop goes wrong, it's mostly invisible: the logs look busy while
|
|
115
|
+
the agent repeats itself and burns tokens.
|
|
116
|
+
|
|
117
|
+
I built **LoopLens** — a local-first, real-time debugger focused purely on loop
|
|
118
|
+
health. Add a zero-dependency Python SDK to the agent you already have, open a
|
|
119
|
+
local dashboard, and watch the run live. It raises transparent, rule-based
|
|
120
|
+
warnings — repeated tool call, no-progress loop, retry storm, cost spike — each
|
|
121
|
+
with a plain-English explanation and a suggested fix.
|
|
122
|
+
|
|
123
|
+
It's intentionally narrow: not another observability platform — no auth, no
|
|
124
|
+
cloud, no eval suite. Just the fastest way to see *why your agent got stuck.*
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
pip install "looplens[server]"
|
|
128
|
+
looplens dev
|
|
129
|
+
looplens demo
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Open-source (MIT). Roadmap includes LangGraph / CrewAI / OpenAI Agents SDK
|
|
133
|
+
adapters — feedback on ordering welcome. REPO_URL
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Reddit (r/LangChain, r/AI_Agents, r/LocalLLaMA)
|
|
138
|
+
|
|
139
|
+
**Title:** I built a local-first "loop debugger" for AI agents — see why it got
|
|
140
|
+
stuck, live
|
|
141
|
+
|
|
142
|
+
Sharing a tool I built to scratch my own itch. My agents kept looking busy while
|
|
143
|
+
secretly repeating the same tool call and failing at the end. LoopLens shows the
|
|
144
|
+
loop live and warns you the moment it detects repeated calls, no-progress loops,
|
|
145
|
+
retry storms, or cost spikes — in plain language, with a suggested fix.
|
|
146
|
+
|
|
147
|
+
- zero-dependency SDK (pure stdlib — drops into LangGraph/CrewAI/OpenAI Agents
|
|
148
|
+
SDK/custom loops without dependency conflicts)
|
|
149
|
+
- local-first: SQLite, no auth, no cloud, no API key
|
|
150
|
+
- one-line install, dashboard bundled (no Node build step)
|
|
151
|
+
- fail-silent: buffers to JSONL if the dashboard's down, never crashes your agent
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pip install "looplens[server]" && looplens dev && looplens demo
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
It's an MVP and deliberately narrow (loop health, not full observability).
|
|
158
|
+
Repo + roadmap: REPO_URL. What framework adapter should I build first?
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Demo script (for the GIF / video — ~30s)
|
|
163
|
+
|
|
164
|
+
1. Split screen: terminal (left) running `looplens demo`, dashboard (right).
|
|
165
|
+
2. Watch the timeline fill: `agent_started` → `llm_call` → `tool_call` repeating.
|
|
166
|
+
3. By the 3rd `web_search`, a **warning card** appears: *"Same tool called
|
|
167
|
+
repeatedly with similar input — possible no-progress loop."*
|
|
168
|
+
4. Health score ticks down from 100 → "Likely stuck."
|
|
169
|
+
5. Click an event → drawer shows the raw JSON (identical inputs each call).
|
|
170
|
+
6. End card: `pip install "looplens[server]"` + repo URL.
|
looplens-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: looplens
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local-first real-time debugger for AI agent loops — Chrome DevTools for agent loops.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ashutosh-rath02/looplens
|
|
6
|
+
Project-URL: Repository, https://github.com/ashutosh-rath02/looplens
|
|
7
|
+
Author: Ashutosh Rath
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: agents,ai,debugging,llm,loops,observability
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
13
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
14
|
+
Requires-Dist: pydantic>=2.0; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: typer>=0.9; extra == 'dev'
|
|
17
|
+
Requires-Dist: uvicorn[standard]>=0.27; extra == 'dev'
|
|
18
|
+
Requires-Dist: watchdog>=3.0; extra == 'dev'
|
|
19
|
+
Provides-Extra: server
|
|
20
|
+
Requires-Dist: fastapi>=0.110; extra == 'server'
|
|
21
|
+
Requires-Dist: pydantic>=2.0; extra == 'server'
|
|
22
|
+
Requires-Dist: typer>=0.9; extra == 'server'
|
|
23
|
+
Requires-Dist: uvicorn[standard]>=0.27; extra == 'server'
|
|
24
|
+
Requires-Dist: watchdog>=3.0; extra == 'server'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# LoopLens
|
|
28
|
+
|
|
29
|
+
[](https://github.com/ashutosh-rath02/looplens/actions/workflows/ci.yml)
|
|
30
|
+
|
|
31
|
+
**Chrome DevTools for AI agent loops.** A local-first, real-time debugger that
|
|
32
|
+
shows your agent's execution live and warns when it repeats itself, burns
|
|
33
|
+
tokens, retries blindly, or stops making progress.
|
|
34
|
+
|
|
35
|
+
LoopLens gives you:
|
|
36
|
+
|
|
37
|
+
- live timeline of agent execution
|
|
38
|
+
- LLM-call and tool-call visibility
|
|
39
|
+
- retry and handoff tracking
|
|
40
|
+
- token and cost metrics
|
|
41
|
+
- loop warnings (repeated tool, no-progress, retry storm, cost spike, …)
|
|
42
|
+
- JSONL import/export
|
|
43
|
+
- a local-first UI — no login, no cloud, no API key
|
|
44
|
+
|
|
45
|
+
## See it in action
|
|
46
|
+
|
|
47
|
+
A looping agent calls `web_search` over and over. As events stream in live, the
|
|
48
|
+
metrics climb and LoopLens flags **Repeated tool call** and **No-progress loop**
|
|
49
|
+
— the warning counts track the repeat count in real time, and the health score
|
|
50
|
+
drops to *Warning*.
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
## Drop it into any project
|
|
55
|
+
|
|
56
|
+
LoopLens is **not a standalone app you rebuild your agent inside**. It's a tiny
|
|
57
|
+
SDK you add to the agent you already have, plus a dashboard you open when you
|
|
58
|
+
want to look.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from looplens import trace, event
|
|
62
|
+
|
|
63
|
+
with trace("research-agent"):
|
|
64
|
+
event("tool_call_started", tool="web_search", input={"query": "AI agents"})
|
|
65
|
+
event("tool_call_completed", tool="web_search", output={"results": 5})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or wrap a function with `@observe` to capture inputs, outputs, latency, and
|
|
69
|
+
errors automatically:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from looplens import observe
|
|
73
|
+
|
|
74
|
+
@observe(kind="tool")
|
|
75
|
+
def web_search(query):
|
|
76
|
+
...
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The base install is **pure-stdlib with zero third-party dependencies**, so it
|
|
80
|
+
won't conflict with anything in your agent's environment. Events are sent from a
|
|
81
|
+
background thread (your loop never blocks). If the dashboard is running, events
|
|
82
|
+
stream to it live; if not, the SDK buffers to a local JSONL file and **never
|
|
83
|
+
crashes your app**.
|
|
84
|
+
|
|
85
|
+
Configure via environment variables:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
LOOPLENS_ENDPOINT=http://127.0.0.1:8765 # where the dashboard listens
|
|
89
|
+
LOOPLENS_ENABLED=true # set false to make the SDK a no-op
|
|
90
|
+
LOOPLENS_PROJECT=default
|
|
91
|
+
LOOPLENS_CAPTURE_INPUTS=true
|
|
92
|
+
LOOPLENS_CAPTURE_OUTPUTS=true
|
|
93
|
+
LOOPLENS_TRACE_DIR=looplens-traces # JSONL fallback location
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Install
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install looplens # the SDK (drop into your agent — zero deps)
|
|
100
|
+
pip install "looplens[server]" # adds the dashboard (FastAPI + prebuilt UI)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
That's it — **no Node, no npm, no build step.** The `[server]` extra ships the
|
|
104
|
+
compiled React dashboard inside the wheel, so `looplens dev` serves a ready UI on
|
|
105
|
+
the first run. (`pipx install "looplens[server]"`, `uv pip install`, and
|
|
106
|
+
`uv tool install` work the same way.)
|
|
107
|
+
|
|
108
|
+
### Works with any agent or framework
|
|
109
|
+
|
|
110
|
+
The base `looplens` SDK is **pure Python stdlib with zero third-party
|
|
111
|
+
dependencies**, so it installs cleanly next to any agent stack and pins nothing:
|
|
112
|
+
|
|
113
|
+
- **LangGraph / LangChain**, **CrewAI**, **AutoGen**, **OpenAI Agents SDK**,
|
|
114
|
+
**Pydantic AI**, or a hand-rolled `while` loop — if it's Python, you can
|
|
115
|
+
instrument it with `trace()` / `event()` / `@observe`.
|
|
116
|
+
- No API key, no login, no network egress — events go to `127.0.0.1` only, and
|
|
117
|
+
the SDK is a no-op when `LOOPLENS_ENABLED=false`.
|
|
118
|
+
- Fail-silent by design: if the dashboard isn't running it buffers to JSONL and
|
|
119
|
+
**never raises into your agent**.
|
|
120
|
+
|
|
121
|
+
## Quickstart
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pip install "looplens[server]"
|
|
125
|
+
looplens dev # start backend + prebuilt UI, opens http://localhost:8765
|
|
126
|
+
looplens demo # run a sample looping agent that trips a warning
|
|
127
|
+
looplens doctor # check the port, SDK->server round-trip, and JSONL fallback
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`looplens dev` opens the dashboard in your browser automatically (pass
|
|
131
|
+
`--no-open` to skip). If it doesn't, open <http://localhost:8765> yourself and
|
|
132
|
+
watch the run appear live.
|
|
133
|
+
|
|
134
|
+
## Architecture
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Your agent app ──(looplens SDK)──▶ Local FastAPI server ──▶ SQLite
|
|
138
|
+
│
|
|
139
|
+
└──(live stream)──▶ React UI
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- **SDK** (`looplens`): `trace()` + `event()`, background HTTP send, JSONL
|
|
143
|
+
fallback, fail-silent. Zero third-party deps.
|
|
144
|
+
- **Server** (`looplens[server]`): FastAPI + SQLite + Pydantic, loop detectors,
|
|
145
|
+
metrics, real-time stream.
|
|
146
|
+
- **UI**: React + Vite + TypeScript + Tailwind.
|
|
147
|
+
|
|
148
|
+
## Examples
|
|
149
|
+
|
|
150
|
+
Runnable agents under `examples/` exercise the detectors. Start the dashboard
|
|
151
|
+
(`looplens dev`), then run any of them:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
python examples/simple_agent.py # a healthy run — no warnings
|
|
155
|
+
python examples/looping_agent.py # repeated tool call + no-progress loop
|
|
156
|
+
python examples/retry_storm_agent.py # retry storm
|
|
157
|
+
python examples/handoff_bounce_agent.py # two agents ping-ponging handoffs
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`looplens demo` runs the looping agent without needing the file checked out.
|
|
161
|
+
|
|
162
|
+
`examples/real_research_agent_openai.py` is a **real** agent — it makes live
|
|
163
|
+
OpenAI calls (function calling) against a tiny corpus that lacks the answer, so
|
|
164
|
+
the model genuinely loops. Needs `pip install openai` and `OPENAI_API_KEY`
|
|
165
|
+
(optionally `OPENAI_MODEL`):
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
OPENAI_API_KEY=sk-... PYTHONPATH=. python examples/real_research_agent_openai.py
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Build status
|
|
172
|
+
|
|
173
|
+
This repo is being built phase by phase (see `PRD.md` section 24).
|
|
174
|
+
|
|
175
|
+
- [x] **Phase 0** — repo scaffold, packaging, config
|
|
176
|
+
- [x] **Phase 1** — FastAPI backend + SQLite + API routes + metrics
|
|
177
|
+
- [x] **Phase 2** — Python SDK (`trace` / `event` / `@observe`, background sender, JSONL fallback)
|
|
178
|
+
- [x] **Phase 3** — CLI (`init / server / ui / dev / watch / import / export / demo`)
|
|
179
|
+
- [x] **Phase 6** — loop detection rules (repeated tool, similar input, no-progress, retry storm, long step, cost spike)
|
|
180
|
+
- [x] **Phase 4** — React UI (runs list, run detail, live timeline, metrics bar, warnings, event drawer)
|
|
181
|
+
- [x] **Phase 5** — real-time streaming (SSE: live events + metrics + warnings)
|
|
182
|
+
- [x] **Phase 7** — polish, examples, demo
|
|
183
|
+
|
|
184
|
+
## Running from source
|
|
185
|
+
|
|
186
|
+
The published wheel ships the prebuilt dashboard, so end users never touch Node.
|
|
187
|
+
Building **from a git checkout** is the only time you need npm — once, to compile
|
|
188
|
+
the UI into the Python package:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
pip install -e ".[server]" # backend + CLI
|
|
192
|
+
npm --prefix ui install # one-time UI deps
|
|
193
|
+
npm --prefix ui run build # compiles the React bundle into looplens/server/_ui/
|
|
194
|
+
python -m looplens.server # or: looplens server (serves API + UI)
|
|
195
|
+
looplens demo # seed a looping run that trips warnings
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Open `http://localhost:8765` for the dashboard. The backend serves the bundled UI,
|
|
199
|
+
so it's a single URL. For UI development with hot reload, run `npm --prefix ui run
|
|
200
|
+
dev` (Vite on :5173, proxies `/api` to the backend). Interactive API docs are at
|
|
201
|
+
`http://localhost:8765/docs`.
|
|
202
|
+
|
|
203
|
+
Packaging a release: run `npm --prefix ui run build` first, then `python -m build`
|
|
204
|
+
— the wheel force-includes `looplens/server/_ui/` so it's installable with zero
|
|
205
|
+
Node.
|
|
206
|
+
|
|
207
|
+
## How loop detection works
|
|
208
|
+
|
|
209
|
+
Detection is **rule-based and transparent** (PRD §17) — no black-box scoring. On
|
|
210
|
+
every event the backend re-scans the run and raises (or updates) warnings:
|
|
211
|
+
|
|
212
|
+
| Warning | Fires when |
|
|
213
|
+
| --- | --- |
|
|
214
|
+
| `repeated_tool_call` | same tool ≥3× within the last 8 **tool calls** (window slides over tool calls, not raw events, so interleaved ReAct traces still trip it) |
|
|
215
|
+
| `repeated_tool_call_similar_input` | same tool ≥3× with ≥85% similar input |
|
|
216
|
+
| `repeated_tool_call_exact_input` | same tool ≥3× with **byte-identical** input — highest-confidence repeat signal |
|
|
217
|
+
| `no_progress` | a tool repeats with no `state_updated` / `memory_write` between calls |
|
|
218
|
+
| `retry_storm` | `retry_triggered` ≥3× in the run |
|
|
219
|
+
| `long_running_step` | a step over 30s |
|
|
220
|
+
| `cost_spike` | one event > 50% of run cost so far (above a $0.05 floor) |
|
|
221
|
+
| `handoff_bounce` | control ping-pongs between the same two agents (A→B→A→B) |
|
|
222
|
+
|
|
223
|
+
Each warning carries a health penalty; the run's score (0–100) maps to
|
|
224
|
+
**Healthy / Warning / Likely stuck / Failed**.
|
|
225
|
+
|
|
226
|
+
## Limitations (MVP)
|
|
227
|
+
|
|
228
|
+
- **Manual instrumentation only.** Framework adapters (LangGraph, OpenAI Agents
|
|
229
|
+
SDK, CrewAI) are on the V1 roadmap; today you call `trace()`/`event()`/`@observe`.
|
|
230
|
+
- **Rule-based detection**, not semantic — similar-input uses string similarity,
|
|
231
|
+
not embeddings.
|
|
232
|
+
- **Near-real-time, not push**: the SSE stream polls SQLite every ~0.5s.
|
|
233
|
+
- **Single local user, no auth** — local-first by design, not a production service.
|
|
234
|
+
|
|
235
|
+
## Tests
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
pip install -e ".[dev]"
|
|
239
|
+
pytest -q # SDK resilience, all eight detectors, and the SSE stream
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Roadmap
|
|
243
|
+
|
|
244
|
+
See [`ROADMAP.md`](ROADMAP.md) for what's next — PyPI release, CI, and framework
|
|
245
|
+
adapters (LangGraph, OpenAI Agents SDK, CrewAI) to remove manual instrumentation.
|
|
246
|
+
Launch copy lives in [`LAUNCH.md`](LAUNCH.md).
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT
|