longguard 0.1.1__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.
- longguard-0.1.1/.github/release.yml +20 -0
- longguard-0.1.1/.github/workflows/ci.yml +48 -0
- longguard-0.1.1/.github/workflows/docs.yml +29 -0
- longguard-0.1.1/.github/workflows/release.yml +45 -0
- longguard-0.1.1/.gitignore +45 -0
- longguard-0.1.1/CONTRIBUTING.md +64 -0
- longguard-0.1.1/LICENSE +21 -0
- longguard-0.1.1/PKG-INFO +275 -0
- longguard-0.1.1/README.md +222 -0
- longguard-0.1.1/SECURITY.md +22 -0
- longguard-0.1.1/docs/concepts/detectors.md +87 -0
- longguard-0.1.1/docs/concepts/how-it-works.md +50 -0
- longguard-0.1.1/docs/concepts/reflect-and-pivot.md +44 -0
- longguard-0.1.1/docs/contributing.md +60 -0
- longguard-0.1.1/docs/getting-started.md +126 -0
- longguard-0.1.1/docs/guides/configuration.md +75 -0
- longguard-0.1.1/docs/guides/reporting.md +79 -0
- longguard-0.1.1/docs/index.md +73 -0
- longguard-0.1.1/docs/integrations/langchain.md +49 -0
- longguard-0.1.1/docs/integrations/langgraph.md +80 -0
- longguard-0.1.1/examples/custom_detector.py +246 -0
- longguard-0.1.1/examples/langchain_agent.py +166 -0
- longguard-0.1.1/examples/langgraph_basic.py +224 -0
- longguard-0.1.1/mkdocs.yml +68 -0
- longguard-0.1.1/pyproject.toml +101 -0
- longguard-0.1.1/src/longguard/__init__.py +127 -0
- longguard-0.1.1/src/longguard/config.py +133 -0
- longguard-0.1.1/src/longguard/core/__init__.py +34 -0
- longguard-0.1.1/src/longguard/core/breaker.py +480 -0
- longguard-0.1.1/src/longguard/core/detectors/__init__.py +24 -0
- longguard-0.1.1/src/longguard/core/detectors/base.py +110 -0
- longguard-0.1.1/src/longguard/core/detectors/dead_end.py +252 -0
- longguard-0.1.1/src/longguard/core/detectors/semantic_osc.py +201 -0
- longguard-0.1.1/src/longguard/core/detectors/token_velocity.py +165 -0
- longguard-0.1.1/src/longguard/core/detectors/tool_repeat.py +84 -0
- longguard-0.1.1/src/longguard/core/pivot.py +177 -0
- longguard-0.1.1/src/longguard/core/reporter.py +187 -0
- longguard-0.1.1/src/longguard/core/step.py +133 -0
- longguard-0.1.1/src/longguard/integrations/__init__.py +14 -0
- longguard-0.1.1/src/longguard/integrations/langchain.py +284 -0
- longguard-0.1.1/src/longguard/integrations/langgraph.py +361 -0
- longguard-0.1.1/src/longguard/integrations/strands.py +222 -0
- longguard-0.1.1/tests/__init__.py +1 -0
- longguard-0.1.1/tests/conftest.py +101 -0
- longguard-0.1.1/tests/test_breaker.py +355 -0
- longguard-0.1.1/tests/test_config.py +157 -0
- longguard-0.1.1/tests/test_dead_end.py +372 -0
- longguard-0.1.1/tests/test_langchain_integration.py +147 -0
- longguard-0.1.1/tests/test_langgraph_integration.py +235 -0
- longguard-0.1.1/tests/test_pivot.py +167 -0
- longguard-0.1.1/tests/test_reporter.py +183 -0
- longguard-0.1.1/tests/test_semantic_osc.py +137 -0
- longguard-0.1.1/tests/test_step.py +181 -0
- longguard-0.1.1/tests/test_strands_integration.py +132 -0
- longguard-0.1.1/tests/test_token_velocity.py +151 -0
- longguard-0.1.1/tests/test_tool_repeat.py +183 -0
- longguard-0.1.1/uv.lock +3307 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
changelog:
|
|
2
|
+
categories:
|
|
3
|
+
- title: "🚀 Features & Enhancements"
|
|
4
|
+
labels:
|
|
5
|
+
- "enhancement"
|
|
6
|
+
- "feature"
|
|
7
|
+
- title: "🐛 Bug Fixes"
|
|
8
|
+
labels:
|
|
9
|
+
- "bug"
|
|
10
|
+
- "fix"
|
|
11
|
+
- title: "📝 Documentation"
|
|
12
|
+
labels:
|
|
13
|
+
- "documentation"
|
|
14
|
+
- "docs"
|
|
15
|
+
- title: "🧰 Maintenance & CI"
|
|
16
|
+
labels:
|
|
17
|
+
- "maintenance"
|
|
18
|
+
- "ci"
|
|
19
|
+
- "dependencies"
|
|
20
|
+
- "chore"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main, master ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test on Python ${{ matrix.python-version }} (${{ matrix.os }})
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-latest, macos-latest]
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v3
|
|
24
|
+
with:
|
|
25
|
+
version: "latest"
|
|
26
|
+
|
|
27
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
28
|
+
run: uv python install ${{ matrix.python-version }}
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: |
|
|
32
|
+
uv sync --python ${{ matrix.python-version }} --extra dev
|
|
33
|
+
|
|
34
|
+
- name: Run Ruff Linter & Formatter
|
|
35
|
+
run: |
|
|
36
|
+
uv run --python ${{ matrix.python-version }} ruff check src/ tests/
|
|
37
|
+
|
|
38
|
+
- name: Run MyPy Type Checker
|
|
39
|
+
run: |
|
|
40
|
+
uv run --python ${{ matrix.python-version }} mypy src/
|
|
41
|
+
|
|
42
|
+
- name: Run Pytest Suite with Coverage
|
|
43
|
+
run: |
|
|
44
|
+
uv run --python ${{ matrix.python-version }} pytest tests/ --cov=longguard --cov-report=xml --cov-report=term-missing
|
|
45
|
+
|
|
46
|
+
- name: Verify Package Build
|
|
47
|
+
run: |
|
|
48
|
+
uv build
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Deploy Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
deploy:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v3
|
|
19
|
+
with:
|
|
20
|
+
version: "latest"
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
run: uv python install 3.12
|
|
24
|
+
|
|
25
|
+
- name: Install documentation dependencies
|
|
26
|
+
run: uv sync --extra docs
|
|
27
|
+
|
|
28
|
+
- name: Deploy to GitHub Pages
|
|
29
|
+
run: uv run mkdocs gh-deploy --force
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-and-release:
|
|
14
|
+
name: Build and Create GitHub Release
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
|
|
21
|
+
- name: Install uv
|
|
22
|
+
uses: astral-sh/setup-uv@v3
|
|
23
|
+
with:
|
|
24
|
+
version: "latest"
|
|
25
|
+
|
|
26
|
+
- name: Set up Python
|
|
27
|
+
run: uv python install 3.12
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: uv sync --extra dev
|
|
31
|
+
|
|
32
|
+
- name: Run Test Suite
|
|
33
|
+
run: uv run pytest tests/ -v
|
|
34
|
+
|
|
35
|
+
- name: Build sdist and wheel
|
|
36
|
+
run: uv build
|
|
37
|
+
|
|
38
|
+
- name: Create GitHub Release
|
|
39
|
+
uses: softprops/action-gh-release@v2
|
|
40
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
41
|
+
with:
|
|
42
|
+
files: dist/*
|
|
43
|
+
generate_release_notes: true
|
|
44
|
+
draft: false
|
|
45
|
+
prerelease: false
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
env/
|
|
9
|
+
venv/
|
|
10
|
+
ENV/
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
.eggs/
|
|
17
|
+
|
|
18
|
+
# Testing and coverage
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
.tox/
|
|
23
|
+
|
|
24
|
+
# Linter and type-checker caches
|
|
25
|
+
.ruff_cache/
|
|
26
|
+
.mypy_cache/
|
|
27
|
+
|
|
28
|
+
# OS artifacts
|
|
29
|
+
.DS_Store
|
|
30
|
+
Thumbs.db
|
|
31
|
+
|
|
32
|
+
# IDEs
|
|
33
|
+
.idea/
|
|
34
|
+
.vscode/
|
|
35
|
+
*.swp
|
|
36
|
+
*.swo
|
|
37
|
+
|
|
38
|
+
# Environment variables & secrets
|
|
39
|
+
.env
|
|
40
|
+
.env.*
|
|
41
|
+
*.local
|
|
42
|
+
|
|
43
|
+
# Documentation build output
|
|
44
|
+
site/
|
|
45
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Contributing to LongGuard
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to **LongGuard**! We welcome bug reports, feature requests, documentation improvements, and pull requests.
|
|
4
|
+
|
|
5
|
+
LongGuard is an open-source project by [EnDevSols](https://github.com/ENDEVSOLS).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Development Setup
|
|
10
|
+
|
|
11
|
+
LongGuard uses [`uv`](https://github.com/astral-sh/uv) for fast and deterministic Python environment management.
|
|
12
|
+
|
|
13
|
+
### 1. Clone the repository
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/ENDEVSOLS/LongGuard.git
|
|
17
|
+
cd LongGuard
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Install dependencies
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Install package with all dev dependencies
|
|
24
|
+
uv sync --extra dev
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. Run Tests
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Run all unit tests
|
|
31
|
+
uv run pytest tests/ -v
|
|
32
|
+
|
|
33
|
+
# Run with test coverage
|
|
34
|
+
uv run pytest tests/ --cov=longguard --cov-report=term-missing
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 4. Code Quality Checks
|
|
38
|
+
|
|
39
|
+
We enforce formatting and linting with **Ruff** and strict static typing with **MyPy**:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Run linter
|
|
43
|
+
uv run ruff check src/ tests/
|
|
44
|
+
|
|
45
|
+
# Run type checker
|
|
46
|
+
uv run mypy src/
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Ensure all tests, lint checks, and type checks pass before submitting a Pull Request.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Pull Request Guidelines
|
|
54
|
+
|
|
55
|
+
1. **Focus on solving real agent failure modes**: If adding a new detector, provide synthetic or real-world traces in `tests/` demonstrating both positive detection and non-interference on legitimate tasks.
|
|
56
|
+
2. **Keep overhead minimal**: Loop detection runs synchronously on each agent step; algorithms should execute in sub-millisecond time.
|
|
57
|
+
3. **Preserve framework neutrality**: Core detection mechanisms (`src/longguard/core/`) must remain independent of specific agent frameworks (LangGraph, LangChain, etc.). Framework integrations belong in `src/longguard/integrations/`.
|
|
58
|
+
4. **Follow Semantic Versioning**: Major for breaking changes, minor for new detectors/adapters, patch for bug fixes.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
By contributing to LongGuard, you agree that your contributions will be licensed under the [MIT License](LICENSE).
|
longguard-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 EnDevSols
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
longguard-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: longguard
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Circuit breaker middleware for LangGraph/LangChain agents — detect loops, inject Reflect & Pivot, prevent runaway costs
|
|
5
|
+
Project-URL: Homepage, https://github.com/ENDEVSOLS/LongGuard
|
|
6
|
+
Project-URL: Repository, https://github.com/ENDEVSOLS/LongGuard
|
|
7
|
+
Project-URL: Issues, https://github.com/ENDEVSOLS/LongGuard/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/ENDEVSOLS/LongGuard#readme
|
|
9
|
+
Author-email: EnDevSols <info@endevsols.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agents,circuit-breaker,cost-control,langchain,langgraph,llm,loop-detection
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: numpy>=1.24.0
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Requires-Dist: langchain-core>=1.0.0; extra == 'all'
|
|
26
|
+
Requires-Dist: langchain>=1.0.0; extra == 'all'
|
|
27
|
+
Requires-Dist: langgraph>=1.0.0; extra == 'all'
|
|
28
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'all'
|
|
29
|
+
Requires-Dist: mkdocs>=1.5.0; extra == 'all'
|
|
30
|
+
Requires-Dist: pymdown-extensions>=10.7; extra == 'all'
|
|
31
|
+
Requires-Dist: sentence-transformers>=2.7.0; extra == 'all'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: mkdocs>=1.5.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: mypy<2.0.0,>=1.5.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-asyncio>=1.0.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.5.0; extra == 'dev'
|
|
40
|
+
Provides-Extra: docs
|
|
41
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
42
|
+
Requires-Dist: mkdocs>=1.5.0; extra == 'docs'
|
|
43
|
+
Requires-Dist: pymdown-extensions>=10.7; extra == 'docs'
|
|
44
|
+
Provides-Extra: embeddings
|
|
45
|
+
Requires-Dist: sentence-transformers>=2.7.0; extra == 'embeddings'
|
|
46
|
+
Provides-Extra: langchain
|
|
47
|
+
Requires-Dist: langchain-core>=1.0.0; extra == 'langchain'
|
|
48
|
+
Requires-Dist: langchain>=1.0.0; extra == 'langchain'
|
|
49
|
+
Provides-Extra: langgraph
|
|
50
|
+
Requires-Dist: langchain-core>=1.0.0; extra == 'langgraph'
|
|
51
|
+
Requires-Dist: langgraph>=1.0.0; extra == 'langgraph'
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
|
|
54
|
+
<div align="center">
|
|
55
|
+
|
|
56
|
+
# LongGuard 🛡️
|
|
57
|
+
|
|
58
|
+
**In-Flight Circuit Breaker & Reasoning Loop Recovery for AI Agents**
|
|
59
|
+
|
|
60
|
+
*Stop runaway agent loops, prevent token budget blowouts, and inject "Reflect & Pivot" guidance before crashes happen.*
|
|
61
|
+
|
|
62
|
+
[](https://github.com/ENDEVSOLS/LongGuard/actions/workflows/ci.yml)
|
|
63
|
+
[](https://endevsols.github.io/LongGuard/)
|
|
64
|
+
[](https://pypi.org/project/longguard/)
|
|
65
|
+
[](https://www.python.org/downloads/)
|
|
66
|
+
[](https://opensource.org/licenses/MIT)
|
|
67
|
+
[](https://github.com/langchain-ai/langgraph)
|
|
68
|
+
[](https://github.com/langchain-ai/langchain)
|
|
69
|
+
|
|
70
|
+
[**Read Documentation**](https://endevsols.github.io/LongGuard/) • [**Report Bug**](https://github.com/ENDEVSOLS/LongGuard/issues) • [**EnDevSols AI Suite**](https://github.com/ENDEVSOLS)
|
|
71
|
+
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## ⚡ What is LongGuard?
|
|
77
|
+
|
|
78
|
+
When autonomous LLM agents (LangGraph, LangChain, or custom loops) hit an unexpected hurdle, they often **get stuck in repetitive reasoning loops**:
|
|
79
|
+
- Calling the exact same tool with the exact same parameters over and over.
|
|
80
|
+
- Spinning between two reasoning thoughts (semantic oscillation).
|
|
81
|
+
- Aimlessly wandering with zero progress while burning thousands of tokens.
|
|
82
|
+
|
|
83
|
+
Frameworks like LangGraph have a built-in `recursion_limit`, but it is a **hard crash** (`GraphRecursionError`) that drops state, fails the user request, and provides zero opportunity for recovery.
|
|
84
|
+
|
|
85
|
+
**LongGuard is an intelligent circuit breaker middleware.** It monitors your agent's chain-of-thought in real time, catches loops early, injects a **"Reflect & Pivot"** prompt to guide the agent back on track, and only terminates gracefully if recovery fails.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
┌─────────────────────────────────┐
|
|
89
|
+
│ Agent Execution Loop │
|
|
90
|
+
└────────────────┬────────────────┘
|
|
91
|
+
│ Step N
|
|
92
|
+
▼
|
|
93
|
+
┌─────────────────────┐
|
|
94
|
+
│ LongGuard Hook │
|
|
95
|
+
└──────────┬──────────┘
|
|
96
|
+
│
|
|
97
|
+
┌───────────────────┴───────────────────┐
|
|
98
|
+
▼ ▼
|
|
99
|
+
[ No Loop Detected ] [ Loop Detected! ]
|
|
100
|
+
│ │
|
|
101
|
+
State: CLOSED ▼
|
|
102
|
+
(Normal execution) State: REFLECTING
|
|
103
|
+
│
|
|
104
|
+
Inject "Reflect & Pivot"
|
|
105
|
+
Prompt into Context
|
|
106
|
+
│
|
|
107
|
+
┌─────────────┴─────────────┐
|
|
108
|
+
▼ ▼
|
|
109
|
+
[ Recovers ] [ Still Stuck ]
|
|
110
|
+
│ │
|
|
111
|
+
State: CLOSED State: OPEN
|
|
112
|
+
(Runs to end) (Graceful Termination)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 🚀 Quick Start
|
|
118
|
+
|
|
119
|
+
### 1. Installation
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Core package (zero heavy dependencies)
|
|
123
|
+
pip install longguard
|
|
124
|
+
|
|
125
|
+
# With LangGraph integration
|
|
126
|
+
pip install longguard[langgraph]
|
|
127
|
+
|
|
128
|
+
# With LangChain integration
|
|
129
|
+
pip install longguard[langchain]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 2. LangGraph Integration (1 Line)
|
|
133
|
+
|
|
134
|
+
Compatible with **LangGraph 1.0+** and modern multimodal models (Claude, Gemini, OpenAI):
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from langgraph.graph import StateGraph
|
|
138
|
+
from longguard.integrations.langgraph import add_guard_to_graph
|
|
139
|
+
from longguard import GuardConfig
|
|
140
|
+
|
|
141
|
+
# 1. Define your standard LangGraph workflow
|
|
142
|
+
workflow = StateGraph(AgentState)
|
|
143
|
+
workflow.add_node("agent", agent_node)
|
|
144
|
+
workflow.add_node("tools", tool_node)
|
|
145
|
+
workflow.add_edge("agent", "tools")
|
|
146
|
+
workflow.add_conditional_edges("tools", should_continue)
|
|
147
|
+
|
|
148
|
+
# 2. Wrap with LongGuard — that's it!
|
|
149
|
+
workflow = add_guard_to_graph(workflow, GuardConfig())
|
|
150
|
+
app = workflow.compile()
|
|
151
|
+
|
|
152
|
+
# 3. Access execution analytics after the run
|
|
153
|
+
guard = workflow.__longguard__
|
|
154
|
+
print(guard.get_report().summary())
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 3. Standalone / Custom Agent Loop
|
|
158
|
+
|
|
159
|
+
If you run a custom `while` loop or proprietary agent orchestrator:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from longguard import CircuitBreaker, GuardConfig, AgentStep
|
|
163
|
+
|
|
164
|
+
breaker = CircuitBreaker(GuardConfig(
|
|
165
|
+
tool_repeat_threshold=3, # 3 identical tool calls = trigger
|
|
166
|
+
max_tokens_per_run=50_000, # Hard token cap
|
|
167
|
+
))
|
|
168
|
+
|
|
169
|
+
for step in run_agent():
|
|
170
|
+
decision = breaker.check(AgentStep(
|
|
171
|
+
step_number=step.index,
|
|
172
|
+
thought=step.thought,
|
|
173
|
+
action=step.tool_name,
|
|
174
|
+
action_input=step.arguments,
|
|
175
|
+
observation=step.tool_output,
|
|
176
|
+
tokens_used=step.tokens,
|
|
177
|
+
))
|
|
178
|
+
|
|
179
|
+
if decision.action == "reflect":
|
|
180
|
+
# Inject the recovery advice into your agent's message list
|
|
181
|
+
messages.append({"role": "user", "content": decision.inject_prompt})
|
|
182
|
+
elif decision.action == "kill":
|
|
183
|
+
print(f"Halted safely: {decision.reason}")
|
|
184
|
+
break
|
|
185
|
+
|
|
186
|
+
# View summary report
|
|
187
|
+
print(breaker.report.summary())
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 🔍 The 4 Loop Detectors
|
|
193
|
+
|
|
194
|
+
LongGuard runs four lightweight detectors concurrently at every step:
|
|
195
|
+
|
|
196
|
+
| Detector | What It Catches | Real-World Example |
|
|
197
|
+
|---|---|---|
|
|
198
|
+
| **Tool Repeat** | Calling the same tool with identical inputs $\ge N$ times | Agent calls `web_search("apple stock 2026")` 4 times with zero param changes |
|
|
199
|
+
| **Semantic Oscillation** | Cycling between the same concepts in thoughts | Agent reasons "I should search A", then "No, B", then "Actually A", then "No, B" |
|
|
200
|
+
| **Dead-End Drift** | Zero new information or observations for 5+ steps | Agent makes queries that return blank results or repetitive error strings |
|
|
201
|
+
| **Token Velocity** | Sudden exponential token spikes per step | Agent dumps huge raw HTML payloads into thought context, blowing budget |
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## 🔄 The Circuit Breaker State Machine
|
|
206
|
+
|
|
207
|
+
LongGuard adapts standard distributed systems circuit breaker patterns to LLM cognition:
|
|
208
|
+
|
|
209
|
+
1. **`CLOSED` (Normal)**: All checks pass. The agent runs freely.
|
|
210
|
+
2. **`REFLECTING` (Intervention)**: A loop was detected. LongGuard injects an automated **Reflect & Pivot prompt** instructing the agent:
|
|
211
|
+
> *"You have called {tool} {count} times with the same arguments. Stop. Try a different tool or synthesize your current findings."*
|
|
212
|
+
3. **`HALF-OPEN` (Observation)**: The agent gets one chance to demonstrate progress following reflection.
|
|
213
|
+
4. **`OPEN` (Graceful Termination)**: If the loop persists after reflection, LongGuard terminates execution cleanly, preserving full trace telemetry and token usage.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 📊 LongGuard vs. LangGraph `recursion_limit`
|
|
218
|
+
|
|
219
|
+
| Capability | LangGraph `recursion_limit` | LongGuard 🛡️ |
|
|
220
|
+
|---|:---:|:---:|
|
|
221
|
+
| **Detects Tool-Repeat Loops** | ❌ No | ✅ **Yes** |
|
|
222
|
+
| **Detects Semantic Reasoning Loops** | ❌ No | ✅ **Yes** |
|
|
223
|
+
| **Detects Sudden Cost / Token Spikes** | ❌ No | ✅ **Yes** |
|
|
224
|
+
| **Auto-Injects Recovery Prompts** | ❌ No | ✅ **Yes** |
|
|
225
|
+
| **Exit Behavior** | 💥 Unhandled Exception (`Crash`) | 🛡️ **Graceful State Preservation** |
|
|
226
|
+
| **Run Reporting & Telemetry** | ❌ No | ✅ **JSON & Summary Reports** |
|
|
227
|
+
| **Configurable Thresholds** | ❌ Single integer | ✅ **Granular `GuardConfig`** |
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## ⚙️ Configuration at a Glance
|
|
232
|
+
|
|
233
|
+
All behavior can be customized via `GuardConfig`:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from longguard import GuardConfig
|
|
237
|
+
|
|
238
|
+
config = GuardConfig(
|
|
239
|
+
# Loop Detection Sensitivity
|
|
240
|
+
tool_repeat_threshold=3, # Number of repeated tool calls before reflection
|
|
241
|
+
tool_repeat_window=6, # History window to examine
|
|
242
|
+
dead_end_threshold=5, # Steps with no progress before triggering
|
|
243
|
+
token_velocity_multiplier=3.0, # Spike multiplier vs rolling baseline
|
|
244
|
+
|
|
245
|
+
# Hard Safety Guardrails
|
|
246
|
+
max_tokens_per_run=50_000, # Hard stop if agent burns > 50k tokens
|
|
247
|
+
max_steps=30, # Maximum steps permitted
|
|
248
|
+
max_reflections=2, # Maximum recovery attempts before kill
|
|
249
|
+
)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
👉 *For detailed documentation on custom detectors, embedding backends, and LangSmith telemetry, see the [Full Documentation](https://endevsols.github.io/LongGuard/).*
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 🌐 Part of the EnDevSols AI Infrastructure Suite
|
|
257
|
+
|
|
258
|
+
LongGuard works alongside our other open-source tools to secure production LLM pipelines:
|
|
259
|
+
|
|
260
|
+
- [**LongParser**](https://github.com/ENDEVSOLS/LongParser) — Fast, privacy-first local document parser (PDF, DOCX, XLSX).
|
|
261
|
+
- [**LongProbe**](https://github.com/ENDEVSOLS/LongProbe) — Sub-second RAG retrieval regression testing with pytest.
|
|
262
|
+
- [**LongTracer**](https://github.com/ENDEVSOLS/LongTracer) — Post-generation hallucination detection & claim verification.
|
|
263
|
+
- [**LongGuard**](https://github.com/ENDEVSOLS/LongGuard) — In-flight runtime cognitive circuit breaker & loop recovery.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 🤝 Contributing & Community
|
|
268
|
+
|
|
269
|
+
We love contributions!
|
|
270
|
+
- Submit bug reports and feature ideas via [GitHub Issues](https://github.com/ENDEVSOLS/LongGuard/issues).
|
|
271
|
+
- See [CONTRIBUTING.md](CONTRIBUTING.md) for development environment setup and testing guidelines.
|
|
272
|
+
|
|
273
|
+
## 📄 License
|
|
274
|
+
|
|
275
|
+
LongGuard is open-source software released under the [MIT License](LICENSE).
|