[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-83118":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":12,"subscribersCount":12,"size":12,"stars1d":12,"stars7d":15,"stars30d":15,"stars90d":12,"forks30d":12,"starsTrendScore":12,"compositeScore":16,"rankGlobal":9,"rankLanguage":9,"license":17,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":18,"topics":21,"createdAt":9,"pushedAt":9,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":12,"starSnapshotCount":12,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},83118,"loopbuster","liuchunwei732-cmyk\u002Floopbuster","liuchunwei732-cmyk","A unified anti-dead-loop toolkit for LLM agents — loop detection, budget ceiling, state stasis guard, and circuit breaker in one library.",null,"Python",102,0,52,1,45,64.5,"MIT License",false,"main",true,[],"2026-06-12 04:01:40","# LoopBuster 🛑\n\n> **Break the infinite loops of your AI Agents. Stop burning tokens on dead-ends.**\n\n[![Python](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fpython-3.9%2B-blue)](https:\u002F\u002Fpython.org)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-green)](LICENSE)\n\u003C\u003C\u003C\u003C\u003C\u003C\u003C HEAD\n[![PyPI](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fpypi-v0.3.0-orange)](https:\u002F\u002Fpypi.org\u002Fproject\u002Floopbuster\u002F)\n\n---\n\n## Why LoopBuster?\n\nLLM Agents are powerful, but they get stuck. When an agent repeatedly calls the same tool with slightly different arguments, cycles through A→B→C→A→B→C, or produces identical outputs across steps, you are burning money on useless API calls.\n\nExisting solutions are either:\n- **Too simple** — string matching that misses fuzzy loops and cycles\n- **Too heavy** — embedding-based similarity that adds latency, cost, and dependencies\n- **Framework-specific** — tied to LangGraph, AutoGen, or CrewAI\n\nLoopBuster sits in the middle: **lightweight (zero hard dependencies), framework-agnostic, and semantically aware through multi-factor similarity scoring.**\n\n---\n\n## Features\n\n| Component | What it does |\n|---|---|\n| **4 detection strategies** | ExactRepeat, FuzzyRepeat, CycleDetection, OutputStagnation |\n| **Multi-factor similarity** | Jaccard + normalized Levenshtein + dict structure similarity, with noise denoising |\n| **Adaptive thresholds** | Tightens\u002Frelaxes based on action diversity — stops false alarms on diverse tasks |\n| **3 hard guards** | BudgetCeiling ($ cap), RepeatCallGuard (exact limit), StateStasis (no-change detection) |\n| **Circuit breaker** | Pre-flight checks before tool calls (WARN \u002F BLOCK \u002F SUGGEST_ALTERNATIVE) |\n| **Stuck report** | Diagnostic report: diversity ratio, top repeated patterns, token waste estimate, recommendations |\n| **Async support** | `AsyncLoopBuster` with hung coroutine detection and action timeout |\n| **Framework integrations** | LangGraph, CrewAI, AutoGen (drop-in guard nodes) |\n| **MCP protocol** | stdio-based MCP server for tool-calling LLMs |\n| **Storage backends** | Memory (default) and Redis (distributed) |\n| **Dashboard** | Real-time monitoring of detection state and resource usage |\n| **Zero hard deps** | Core library uses only stdlib; optional features add dependencies only when needed |\n\n---\n\n## Quick Start\n\n```bash\npip install loopbuster\n```\n\n```python\nfrom loopbuster import LoopBuster\n\n# Basic usage\nbuster = LoopBuster(similarity_threshold=0.85)\n\nfor step in agent_loop():\n    decision = buster.check(tool=step.tool, args=step.args, output=step.output)\n    if decision.is_loop:\n        print(f\"🛑 Loop detected: {decision.reason}\")\n        break\n```\n\n> 📓 **[Interactive Demo Notebook](notebooks\u002Floopbuster_demo.ipynb)** — Step through exact repeat, fuzzy repeat, cycle detection, adaptive thresholds, and more in a Jupyter notebook.\n\n---\n\n## Architecture\n\n```mermaid\ngraph LR\n    A[Agent Action] --> B[4 Detection Strategies]\n    B --> C{Guard Layer}\n    C -->|Pass| D[Execute]\n    C -->|Fail| E[Intervention]\n    E --> F{Pause \u002F Block \u002F Suggest \u002F Escalate}\n```\n\n---\n\n## Detection Strategies\n\n| Strategy | How it works | False positive rate |\n|---|---|---|\n| ExactRepeat | Same (tool, args) repeated identically | Low |\n| FuzzyRepeat | Multi-factor similarity (Jaccard + Levenshtein + dict structure) with noise denoising | Medium |\n| CycleDetection | A→B→C→A→B→C sequence pattern recognition | Low |\n| OutputStagnation | Tool output unchanged across calls | Medium-High |\n\n### Why multi-factor similarity?\n\nSimple string matching (e.g., Levenshtein directly on serialized args) fails on:\n\n- **Volatile fields** — `request_id`, `timestamp`, `nonce`, `trace_id` differ between calls even when the intent is identical\n- **Nested structures** — two dicts with the same shape but different leaf values should be recognized as similar\n- **Order shuffling** — long lists where element order is meaningless\n\nLoopBuster's approach:\n\n```\nargs_similarity(args1, args2) =\n    if dicts:\n        0.6 * text_sim(Jaccard + Levenshtein) + 0.4 * struct_sim(key overlap + type matching)\n    else:\n        0.5 * Jaccard + 0.5 * Levenshtein\n```\n\nWith pre-processing:\n\n| Step | What | Example |\n|---|---|---|\n| UUID masking | `550e8400-e29b-...` → `\u003CUUID>` | Prevents UUID differences from lowering similarity |\n| Timestamp masking | `2024-01-15T09:30:00Z` → `\u003CTIMESTAMP>` | Same for timestamps |\n| Hash masking | 64-char hex strings → `\u003CHASH>` | Same for hashes |\n| Volatile key stripping | `request_id`, `trace_id`, `created_at` → `\u003CVOLATILE>` | Prevents key-level noise |\n| Long list set-ification | Lists > 20 items → sorted set | Prevents order-based false negatives |\n| Deep nesting limit | Max 10 levels → `\u003CDEEP>` | Prevents stack overflow on recursive structures |\n\n---\n\n## Advanced Usage\n\n### With Budget Ceiling and Guards\n\n```python\nfrom loopbuster import LoopBuster\n\nwith LoopBuster(\n    budget_usd=5.0,                 # Dollar cap on LLM spend\n    max_repeats=5,                  # Hard limit on exact (tool, args) repeats\n    stasis_steps=10,                # Agent state hasn't changed for N steps\n) as lb:\n    for step in agent_loop():\n        # Track spend\n        lb.record_tokens(\"gpt-4o\", input=500, output=200)\n\n        # Check for loops\n        decision = lb.check(tool=step.tool, args=step.args, output=step.output)\n        if decision.should_stop:\n            lb.record_state(step.state)\n            break\n```\n\n### Adaptive Thresholds\n\nTired of tuning `warn_threshold` and `stop_threshold` manually? AdaptiveActionConfig adjusts them based on action diversity:\n\n```python\nfrom loopbuster import LoopBuster\nfrom loopbuster.types import AdaptiveActionConfig\n\nwith LoopBuster(action_config=AdaptiveActionConfig()) as lb:\n    for step in agent_loop():\n        decision = lb.check(tool=step.tool, args=step.args)\n        # Diverse actions → relaxed thresholds (fewer false positives)\n        # Repetitive actions → tightened thresholds (faster intervention)\n```\n\n### Async Loop Detection\n\nFor async agent frameworks:\n\n```python\nfrom loopbuster import AsyncLoopBuster\n\nasync with AsyncLoopBuster(action_timeout=30.0, max_slow_actions=3) as lb:\n    async for action in agent_async_loop(task):\n        decision = await lb.acheck(tool=action.tool, args=action.args)\n        if decision.should_stop:\n            break\n```\n\nOr use the async generator wrapper:\n\n```python\nasync for tool, args, decision in AsyncLoopBuster.watch(\n    my_agent_async_gen(task),\n    budget_usd=5.0,\n):\n    if decision.should_stop:\n        break\n    # process action...\n```\n\n### Circuit Breaker (Pre-flight Check)\n\nCheck BEFORE a tool call whether it would be blocked:\n\n```python\nfrom loopbuster import CircuitBreaker, BreakerAction\n\nbreaker = CircuitBreaker(max_repeats=3, action=BreakerAction.BLOCK)\nlb = LoopBuster(circuit_breaker=breaker)\n\nfor step in agent_loop():\n    # Pre-flight check\n    pre = lb.breaker_check(tool=step.tool, args=step.args)\n    if pre.blocked:\n        suggestion = pre.alternative_suggestion\n        # Try a different approach\n        break\n\n    decision = lb.check(tool=step.tool, args=step.args)\n```\n\n### Stuck Report\n\nGenerate a diagnostic report after execution:\n\n```python\nwith LoopBuster() as lb:\n    for step in agent_loop():\n        decision = lb.check(tool=step.tool, args=step.args)\n        if decision.should_stop:\n            break\n\nreport = lb.report()\n# {\n#   \"total_actions\": 15,\n#   \"diversity_ratio\": 0.33,\n#   \"redundant_actions\": 8,\n#   \"top_repeated_patterns\": [(\"search:{q=same...}\", 6), ...],\n#   \"token_waste_estimate\": \"$0.42\",\n#   \"recommendations\": [...]\n# }\n```\n\n### Framework Integrations\n\n#### LangGraph\n\n```python\nfrom loopbuster.integrations import langgraph_guard\n\n# Use as a conditional edge node\ngraph.add_conditional_edges(\n    \"agent\",\n    langgraph_guard(similarity_threshold=0.85),\n    {True: \"fallback\", False: \"continue\"}\n)\n```\n\n#### CrewAI\n\n```python\nfrom loopbuster.integrations import CrewAIGuardTool\n\nguard = CrewAIGuardTool(budget_usd=5.0)\n# Add guard to your Crew's tool list\n```\n\n#### AutoGen\n\n```python\nfrom loopbuster.integrations import AutogenGuardAgent\n\nguard_agent = AutogenGuardAgent(\n    name=\"loop_guard\",\n    system_message=\"I monitor for infinite loops.\"\n)\n```\n\n---\n\n## MCP Server\n\nLoopBuster ships with a stdio-based MCP server that exposes detection as a tool:\n\n```bash\npip install loopbuster[mcp]\npython -m loopbuster.mcp_server\n```\n\nTools available:\n- `check_cycle` — detect if an agent action is looping\n- `get_report` — generate diagnostic report from current session\n- `reset_session` — clear detection history\n- `configure` — update detection parameters at runtime\n\n---\n\n## Design Decisions\n\n| Question | Answer |\n|---|---|\n| **Why Strategy pattern?** | Each detection algorithm is an independent class. Users compose their own set, and adding a new strategy doesn't touch existing code (open-closed principle). |\n| **Why zero hard dependencies?** | The core library uses only Python stdlib. No one wants to install numpy, torch, or sentence-transformers just to detect a loop. Optional features (Redis, Dashboard, AI integrations) are opt-in. |\n| **Why ContextVar?** | `threading.local()` leaks across coroutines in async contexts. `contextvars.ContextVar` provides proper async isolation. |\n| **Why check() returns Decision, not bool?** | The caller decides what to do. A WARN might pause, a STOP might switch tools, an ESCALATE might alert a human. The library detects; the application decides. |\n| **Why multi-factor similarity instead of embeddings?** | Embedding models add latency (50-200ms per call), cost (API or local GPU), and dependency weight. For loop detection, Jaccard + Levenshtein + structure matching achieves 95%+ of the accuracy at \u003C1μs per check. |\n| **Why adaptive thresholds?** | A fixed threshold that works for a search agent will false-alarm on a coding agent that naturally calls the same tools repeatedly. Diversity-awareness solves this without per-agent tuning. |\n\n---\n=======\n\nLoopBuster is a **framework-agnostic** anti-dead-loop toolkit for LLM agents. It detects when agents get stuck in repetitive patterns—exact repeats, fuzzy repeats, cycles, output stagnation—and takes action before you burn through your API budget.\n\n## What makes LoopBuster different?\n\n| Feature | What it does |\n|---------|-------------|\n| **4 detection strategies** | Exact Repeat, Fuzzy Repeat, Cycle Detection, Output Stagnation |\n| **Good vs Bad cycle** | ProgressSignal tracks information gain—repetition with progress is OK, repetition without progress is not |\n| **Predictive risk scoring** | RiskScorer warns *before* a full pattern forms (entropy collapse, state revisitation, progress decay) |\n| **Root cause analysis** | When a loop is detected, RootCauseAnalyzer infers *why* and suggests what to do |\n| **3 hard guards** | BudgetCeiling ($$ cap), RepeatCallGuard, StateStasis |\n| **Adaptive thresholds** | Tightens when diversity drops, relaxes when exploration is healthy |\n| **Circuit breaker** | Pre-flight hard gate against exact (tool, args) repeats |\n| **Async support** | AsyncLoopBuster with hung coroutine detection |\n| **5 framework integrations** | LangChain, AutoGen, CrewAI, LangGraph, LlamaIndex |\n| **MCP server** | Drop-in for MCP-compatible environments |\n| **REST API + Dashboard** | FastAPI dashboard with live intercept logs |\n| **Distributed state** | Redis backend for multi-process deployments |\n| **0 hard dependencies** | Core is pure Python—extras are optional |\n\n## Architecture\n\n```\nAgent Action\n    ↓\n┌─────────────────────────────────────┐\n│         LoopBuster Engine           │\n│  ┌───────┐ ┌──────────┐ ┌────────┐ │\n│  │4 Strat.│ │RiskScorer│ │Guards  │ │\n│  │(pattern│ │(predict) │ │(hard   │ │\n│  │ match) │ │          │ │limit)  │ │\n│  └───┬───┘ └────┬─────┘ └───┬────┘ │\n│      └──────────┼────────────┘      │\n│                 ↓                   │\n│          Decision                    │\n└─────────────────────────────────────┘\n    ↓         ↓         ↓\n  Allow     Warn      Stop\u002FEScalate\n```\n\n## Quick Start\n\n```bash\npip install loopbuster\n```\n\n```python\nfrom loopbuster import LoopBuster\n>>>>>>> codex\u002Fdeep-detection-v0.3.0\n\nwith LoopBuster(budget_usd=5.0) as lb:\n    for step in agent_loop(task):\n        decision = lb.check(\n            tool=step.tool,\n            args=step.args,\n            output=step.output,\n        )\n        if decision.should_stop:\n            # React: break, log, ask user\n            expl = decision.explain(lb.action_history)\n            print(f\"🛑 {expl.summary}\")\n            print(f\"💡 {expl.suggestion}\")\n            break\n```\n\n\u003C\u003C\u003C\u003C\u003C\u003C\u003C HEAD\n| Scenario | Type | Expected | Detected | Match |\n|---|---|---|---|---|\n| 3× identical search | Exact repeat | Loop | ✓ | ✓ |\n| 5× identical search | Exact repeat | Loop | ✓ | ✓ |\n| 3× identical API call | Exact repeat | Loop | ✓ | ✓ |\n| A→B cycle × 4.5 | Cycle | Loop | ✓ | ✓ |\n| A→B→C cycle × 3 | Cycle | Loop | ✓ | ✓ |\n| Same query + incrementing page | Fuzzy repeat (sim≥0.75 threshold) | Loop | ✓ | ✓ |\n| Same query + different locale | Fuzzy repeat (structure + text sim) | Loop | ✓ | ✓ |\n| Same output 3× | Stagnation | Loop | ✓ | ✓ |\n| Same output 5× | Stagnation | Loop | ✓ | ✓ |\n| 4× UUID-varying request IDs (same query) | Denoised → identical | Loop | ✓ | ✓ |\n| 4× timestamp-varying args (same query) | Denoised → identical | Loop | ✓ | ✓ |\n| Single call | Normal | No loop | ✓ | ✓ |\n| 5 diverse search queries | Normal | No loop | ✓ | ✓ |\n| 3 explore-mode queries | Normal | No loop | ✓ | ✓ |\n| Read + Write different files | Normal | No loop | ✓ | ✓ |\n| Diverse outputs | Normal | No loop | ✓ | ✓ |\n| Empty action sequence | Edge | No loop | ✓ | ✓ |\n| Different queries with volatile IDs | Edge | No false positive | ✓ | ✓ |\n| Nested dict args with volatile timestamps | Edge | Denoised → high sim | ✓ | ✓ |\n| Long list args (reversed order) | Edge | Order-insensitive | ✓ | ✓ |\n\n**Results:**\n- Total scenarios: **20**\n- True positives: **13**\n- True negatives: **7**\n- False positives: **0**\n- False negatives: **0**\n- Precision: **100%**\n- Recall: **100%**\n\n> Note: 100% metrics on synthetic benchmarks. Real-world performance depends on your agent's specific behavior patterns. Run your own traces for production tuning.\n\n---\n\n## Installation\n\n```bash\n# Core (zero deps beyond stdlib)\npip install loopbuster\n\n# With Redis support\npip install loopbuster[redis]\n\n# With Dashboard\npip install loopbuster[dashboard]\n\n# Everything\npip install loopbuster[all]\n\n# Development\npip install loopbuster[dev]\n```\n\n---\n\n## Project Structure\n\n```\nsrc\u002Floopbuster\u002F\n├── __init__.py          # Public API\n├── engine.py            # Core engine (LoopBuster)\n├── async_engine.py      # Async wrapper (AsyncLoopBuster)\n├── strategies.py        # 4 detection strategies + Composite\n├── similarity.py        # Multi-factor similarity engine\n├── circuit.py           # Circuit breaker (pre-flight gate)\n├── guards.py            # BudgetCeiling, RepeatCallGuard, StateStasis\n├── types.py             # Action, Decision, ActionConfig, AdaptiveActionConfig\n├── decorator.py         # @buster decorator\n├── mcp_server.py        # MCP stdio server\n├── api\u002F                 # REST API layer\n├── backends\u002F            # Storage backends (Memory, Redis)\n├── integrations\u002F        # LangGraph, CrewAI, AutoGen integrations\n├── pricing\u002F             # LLM pricing models\n└── storage\u002F             # Storage implementations\n```\n\n---\n=======\n## Detection Strategies\n\n| Strategy | What it detects | False positive rate |\n|---|---|---|\n| **ExactRepeat** | Identical (tool, args) consecutive calls | Low |\n| **FuzzyRepeat** | Near-identical args (Jaccard + edit distance) | Medium |\n| **CycleDetection** | A→B→C→A repeating sequences | Low |\n| **OutputStagnation** | Tool returns same output repeatedly | Medium |\n\n## Deep Detection (v0.3+)\n\n### ProgressSignal — Good vs Bad Cycles\n\n```python\nfrom loopbuster import ProgressSignal\n\nps = ProgressSignal(window=5)\n\n# Good cycle: each call produces new information\nps.record(\"Paris population: 2.1M\")\nps.record(\"Tokyo population: 14M\")       # gain ≈ 0.85 (new info)\nps.record(\"London population: 8.9M\")      # gain ≈ 0.85\n\n# Bad cycle: same output repeatedly\nps.record(\"Paris population: 2.1M\")\nps.record(\"Paris population: 2.1M\")       # gain \u003C 0.1 (stagnation)\nps.record(\"Paris population: 2.1M\")       # gain ≈ 0.0\n```\n\n### RiskScorer — Predictive Warning\n\n```python\nfrom loopbuster import LoopBuster, Action\n\nlb = LoopBuster()\nfor step in agent_loop:\n    decision = lb.check(step.tool, step.args, step.output)\n\n    # Check risk BEFORE any strategy fires\n    risk = lb.risk_score\n    if risk and risk.is_warning:\n        print(f\"⚠️ {risk.summary}\")\n        # entropy=0.8 → tool set collapsing\n        # revisitation=0.7 → revisiting same states\n```\n\n### RootCauseAnalyzer — Why it happened\n\n```python\ndecision = lb.check(tool=\"search\", args={\"q\": \"python\"})\nif decision.is_loop:\n    expl = decision.explain(lb.action_history)\n    # expl.root_cause_label = \"Exact Tool Repeat\"\n    # expl.suggestion = \"Consider adding a termination condition...\"\n    print(f\"🔍 {expl.detail}\")\n    print(f\"💡 {expl.suggestion}\")\n```\n\n### Decision.explain()\n\nEvery `Decision` now has an `explain()` method:\n\n```python\nif decision.is_loop:\n    expl = decision.explain(lb.action_history)\n    print(expl.summary)       # High-level summary\n    print(expl.detail)        # Detailed analysis\n    print(expl.suggestion)    # Actionable next step\n    print(expl.root_cause)    # RootCause enum\n```\n\n## Guards (Hard Limits)\n\nThree guards complement pattern detection with hard boundaries:\n\n| Guard | Trigger |\n|---|---|\n| **BudgetCeiling** | Cumulative LLM API spend exceeds `$limit` |\n| **RepeatCallGuard** | Same (tool, args) appears N times in a window |\n| **StateStasis** | Agent state unchanged for N consecutive steps |\n\n```python\nlb = LoopBuster(\n    budget_usd=5.0,       # BudgetCeiling\n    max_repeats=3,        # RepeatCallGuard\n    stasis_steps=5,       # StateStasis\n)\n```\n\n## Adaptive Thresholds\n\nInstead of fixed WARN\u002FSTOP\u002FESCALATE counts, `AdaptiveActionConfig` adjusts thresholds in real time based on action diversity:\n\n```python\nfrom loopbuster import AdaptiveActionConfig, LoopBuster\n\nconfig = AdaptiveActionConfig(\n    base_warn=3, base_stop=5, base_escalate=8,\n)\nwith LoopBuster(action_config=config) as lb:\n    ...\n```\n\n- Low diversity (agent stuck on 2-3 tools) → thresholds tighten (faster intervention)\n- High diversity (agent exploring many tools) → thresholds relax (fewer false positives)\n\n## Framework Integrations\n\n### LangChain\n\n```python\nfrom loopbuster import LoopBuster\nfrom loopbuster.integrations.langchain import LoopBusterCallback\n\nlb = LoopBuster(budget_usd=5.0)\ncallback = LoopBusterCallback(lb)\nagent_executor = AgentExecutor.from_agent_and_tools(\n    agent=agent, tools=tools, callbacks=[callback],\n)\n```\n\n### LlamaIndex\n\n```python\nfrom loopbuster import LoopBuster\nfrom loopbuster.integrations.llamaindex import LoopBusterCallback\n\nlb = LoopBuster(budget_usd=5.0)\ncallback = LoopBusterCallback(lb)\nfrom llama_index.core import Settings\nSettings.callback_manager.add_handler(callback)\n```\n\n### Generic\n\n```python\nfrom loopbuster.integrations import LoopBusterCallback\n\ncallback = LoopBusterCallback(on_stop=lambda d: raise StopException(d))\nfor action in agent_loop:\n    decision = callback.before_tool_call(action.tool, action.args)\n    if not decision.should_stop:\n        result = execute_tool(action.tool, action.args)\n```\n\n## Async Support\n\n```python\nfrom loopbuster import AsyncLoopBuster\n\nasync with AsyncLoopBuster(budget_usd=5.0) as lb:\n    async for step in agent_async_loop():\n        decision = await lb.acheck(tool=step.tool, args=step.args)\n        if decision.should_stop:\n            break\n```\n\nHung coroutine detection:\n\n```python\nasync with AsyncLoopBuster(action_timeout=30.0, max_slow_actions=3) as lb:\n    # If an action takes >30s, it's flagged as hung\n    # After 3 consecutive hangs → ESCALATE\n    ...\n```\n\n## Decorator\n\n```python\nfrom loopbuster import buster\n\n@buster(budget_usd=5.0, max_repeats=3)\ndef run_my_agent(task):\n    from loopbuster import current\n    for step in agent_loop(task):\n        decision = current().check(tool=step.tool, args=step.args)\n        if decision.should_stop:\n            break\n```\n\n## MCP Server\n\n```bash\npython -m loopbuster.mcp_server\n```\n\n## REST API + Dashboard\n\n```python\nfrom loopbuster import LoopBuster\n\nlb = LoopBuster()\n# ... run agent ...\nlb.start_dashboard(port=8080)\n```\n\nOr standalone:\n\n```bash\npip install loopbuster[dashboard]\n# Requires REDIS_URL env var for persistence\nuvicorn loopbuster.api.server:app --port 8000\n```\n\n## Stuck Report\n\n```python\nwith LoopBuster(budget_usd=5.0) as lb:\n    for step in agent_loop():\n        lb.check(tool=step.tool, args=step.args)\n\nreport = lb.report()\nprint(report[\"risk_score\"][\"summary\"])\nprint(report[\"recommendations\"])\n```\n\n## CLI Benchmark\n\n```bash\npython benchmark\u002Fscenarios.py\n```\n\n## Design Decisions\n\n- **Strategy pattern**: Each detection algorithm is an independent class. Users compose their own.\n- **Zero core dependencies**: The detection engine is pure Python. Optional features bring their own deps.\n- **ContextVar for context**: Thread-safe, async-safe, no leaky global state.\n- **Decision object**: The engine detects; the caller decides how to react.\n- **Deep detection as opt-in**: ProgressSignal and RiskScorer add no overhead if you don't use them directly—they're always running, but you choose whether to inspect the output.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md).\n>>>>>>> codex\u002Fdeep-detection-v0.3.0\n\n## License\n\nMIT\n","LoopBuster 是一个专为LLM代理设计的统一防死循环工具包，集成了循环检测、预算上限控制、状态停滞保护和断路器功能。其核心功能包括四种检测策略（精确重复、模糊重复、循环检测和输出停滞）、多因素相似度评分（结合Jaccard、归一化Levenshtein以及字典结构相似性，并进行噪声降噪处理）及自适应阈值调整机制等，旨在以轻量级、框架无关的方式解决AI代理在执行过程中可能遇到的无限循环问题。此外，LoopBuster还支持异步操作、多种存储后端选择以及实时监控等功能。它适用于任何需要防止LLM代理陷入无用API调用循环的场景，如自动化任务流程、对话系统等，帮助开发者有效避免资源浪费。",2,"2026-06-11 04:10:12","CREATED_QUERY"]