swarm-test 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.
- swarm_test-0.1.0/.github/workflows/ci.yml +95 -0
- swarm_test-0.1.0/.gitignore +41 -0
- swarm_test-0.1.0/LICENSE +21 -0
- swarm_test-0.1.0/PKG-INFO +248 -0
- swarm_test-0.1.0/README.md +203 -0
- swarm_test-0.1.0/examples/areengine_swarm_test.py +254 -0
- swarm_test-0.1.0/examples/research_crew.py +307 -0
- swarm_test-0.1.0/pyproject.toml +102 -0
- swarm_test-0.1.0/swarm_test/__init__.py +43 -0
- swarm_test-0.1.0/swarm_test/attacks/__init__.py +1 -0
- swarm_test-0.1.0/swarm_test/attacks/base.py +38 -0
- swarm_test-0.1.0/swarm_test/attacks/blast_radius.py +201 -0
- swarm_test-0.1.0/swarm_test/attacks/cascade.py +120 -0
- swarm_test-0.1.0/swarm_test/attacks/collusion.py +247 -0
- swarm_test-0.1.0/swarm_test/attacks/context_leakage.py +168 -0
- swarm_test-0.1.0/swarm_test/attacks/intent_drift.py +247 -0
- swarm_test-0.1.0/swarm_test/cli.py +155 -0
- swarm_test-0.1.0/swarm_test/core/__init__.py +1 -0
- swarm_test-0.1.0/swarm_test/core/graph.py +219 -0
- swarm_test-0.1.0/swarm_test/core/interceptor.py +153 -0
- swarm_test-0.1.0/swarm_test/core/models.py +184 -0
- swarm_test-0.1.0/swarm_test/core/probe.py +209 -0
- swarm_test-0.1.0/swarm_test/integrations/__init__.py +1 -0
- swarm_test-0.1.0/swarm_test/integrations/base.py +106 -0
- swarm_test-0.1.0/swarm_test/integrations/crewai_adapter.py +144 -0
- swarm_test-0.1.0/swarm_test/reporters/__init__.py +1 -0
- swarm_test-0.1.0/swarm_test/reporters/console.py +151 -0
- swarm_test-0.1.0/swarm_test/reporters/html.py +337 -0
- swarm_test-0.1.0/tests/test_core.py +764 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, develop]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test (Python ${{ 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"]
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
cache: pip
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
pip install -e ".[dev]"
|
|
31
|
+
|
|
32
|
+
- name: Run tests with coverage
|
|
33
|
+
run: |
|
|
34
|
+
pytest tests/ -v --cov=swarm_test --cov-report=term-missing --cov-report=xml --cov-fail-under=70
|
|
35
|
+
|
|
36
|
+
- name: Upload coverage to Codecov
|
|
37
|
+
uses: codecov/codecov-action@v4
|
|
38
|
+
if: matrix.python-version == '3.11'
|
|
39
|
+
with:
|
|
40
|
+
file: ./coverage.xml
|
|
41
|
+
fail_ci_if_error: false
|
|
42
|
+
|
|
43
|
+
lint:
|
|
44
|
+
name: Lint
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- name: Set up Python
|
|
50
|
+
uses: actions/setup-python@v5
|
|
51
|
+
with:
|
|
52
|
+
python-version: "3.11"
|
|
53
|
+
cache: pip
|
|
54
|
+
|
|
55
|
+
- name: Install linting tools
|
|
56
|
+
run: |
|
|
57
|
+
pip install ruff black mypy
|
|
58
|
+
|
|
59
|
+
- name: Run ruff
|
|
60
|
+
run: ruff check swarm_test/
|
|
61
|
+
|
|
62
|
+
- name: Run black check
|
|
63
|
+
run: black --check swarm_test/
|
|
64
|
+
|
|
65
|
+
- name: Run mypy
|
|
66
|
+
run: mypy swarm_test/ --ignore-missing-imports
|
|
67
|
+
|
|
68
|
+
example:
|
|
69
|
+
name: Run example
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v4
|
|
73
|
+
|
|
74
|
+
- name: Set up Python
|
|
75
|
+
uses: actions/setup-python@v5
|
|
76
|
+
with:
|
|
77
|
+
python-version: "3.11"
|
|
78
|
+
cache: pip
|
|
79
|
+
|
|
80
|
+
- name: Install package
|
|
81
|
+
run: pip install -e ".[dev]"
|
|
82
|
+
|
|
83
|
+
- name: Run research_crew example
|
|
84
|
+
run: python examples/research_crew.py
|
|
85
|
+
timeout-minutes: 2
|
|
86
|
+
|
|
87
|
+
- name: Test CLI probe
|
|
88
|
+
run: swarm-test --help
|
|
89
|
+
|
|
90
|
+
- name: Test CLI scan
|
|
91
|
+
run: |
|
|
92
|
+
swarm-test scan \
|
|
93
|
+
--agents ResearchAgent --agents DataAgent --agents WriterAgent \
|
|
94
|
+
--edges "ResearchAgent:DataAgent" --edges "DataAgent:WriterAgent" \
|
|
95
|
+
--name "ci-test-swarm"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
venv/
|
|
14
|
+
.venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# Testing
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# Generated reports (keep examples intact)
|
|
23
|
+
/*.html
|
|
24
|
+
|
|
25
|
+
# Environment variables
|
|
26
|
+
.env
|
|
27
|
+
.env.*
|
|
28
|
+
|
|
29
|
+
# Claude Code
|
|
30
|
+
.claude/
|
|
31
|
+
|
|
32
|
+
# IDE
|
|
33
|
+
.vscode/
|
|
34
|
+
.idea/
|
|
35
|
+
*.swp
|
|
36
|
+
*.swo
|
|
37
|
+
*~
|
|
38
|
+
|
|
39
|
+
# OS
|
|
40
|
+
.DS_Store
|
|
41
|
+
Thumbs.db
|
swarm_test-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 swarm-test contributors
|
|
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.
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: swarm-test
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The first reliability testing framework for multi-agent AI systems
|
|
5
|
+
Project-URL: Homepage, https://github.com/surajkumar811/swarm-test
|
|
6
|
+
Project-URL: Documentation, https://github.com/surajkumar811/swarm-test#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/surajkumar811/swarm-test
|
|
8
|
+
Project-URL: Issues, https://github.com/surajkumar811/swarm-test/issues
|
|
9
|
+
Author: swarm-test contributors
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agents,ai,autogen,chaos,crewai,langchain,multi-agent,reliability,testing
|
|
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 :: Testing
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: click>=8.1
|
|
24
|
+
Requires-Dist: colorlog>=6.7
|
|
25
|
+
Requires-Dist: jinja2>=3.1
|
|
26
|
+
Requires-Dist: networkx>=3.1
|
|
27
|
+
Requires-Dist: pydantic>=2.0
|
|
28
|
+
Requires-Dist: python-dotenv>=1.0
|
|
29
|
+
Requires-Dist: rich>=13.0
|
|
30
|
+
Provides-Extra: crewai
|
|
31
|
+
Requires-Dist: crewai>=0.28; extra == 'crewai'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: black>=23.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ipython; extra == 'dev'
|
|
35
|
+
Requires-Dist: mypy>=1.7; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=7.4; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
40
|
+
Requires-Dist: types-networkx; extra == 'dev'
|
|
41
|
+
Provides-Extra: langchain
|
|
42
|
+
Requires-Dist: langchain>=0.1; extra == 'langchain'
|
|
43
|
+
Requires-Dist: langgraph>=0.0.20; extra == 'langchain'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# swarm-test
|
|
47
|
+
|
|
48
|
+
**The first reliability testing framework for multi-agent AI systems.**
|
|
49
|
+
|
|
50
|
+
swarm-test builds a NetworkX interaction graph of your agent swarm and runs 5 automated chaos tests to surface cascade failures, context leakage, intent drift, collusion, and blast radius risks — all from a 3-line API.
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from swarm_test import SwarmProbe
|
|
54
|
+
|
|
55
|
+
probe = SwarmProbe(crew)
|
|
56
|
+
report = probe.run_all()
|
|
57
|
+
report.print_summary()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
| Test | What it checks |
|
|
65
|
+
|---|---|
|
|
66
|
+
| **Cascade Failure** | Which agents, if they fail, bring down the most of the swarm |
|
|
67
|
+
| **Context Leakage** | Sensitive data (credentials, PII) crossing agent boundaries |
|
|
68
|
+
| **Intent Drift** | Agents acting outside their role; prompt injection; goal hijacking |
|
|
69
|
+
| **Collusion Detection** | Dense cliques, echo chambers, orchestrator-bypass cycles |
|
|
70
|
+
| **Blast Radius** | Single points of failure, critical path, redundancy score |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install swarm-test
|
|
78
|
+
# or with framework extras:
|
|
79
|
+
pip install "swarm-test[crewai]"
|
|
80
|
+
pip install "swarm-test[langchain]"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
From source:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
git clone https://github.com/surajkumar811/swarm-test
|
|
87
|
+
cd swarm-test
|
|
88
|
+
pip install -e ".[dev]"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Quick Start
|
|
94
|
+
|
|
95
|
+
### With a CrewAI crew
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from crewai import Crew, Agent, Task
|
|
99
|
+
from swarm_test import SwarmProbe
|
|
100
|
+
|
|
101
|
+
researcher = Agent(role="researcher", goal="...", backstory="...")
|
|
102
|
+
writer = Agent(role="writer", goal="...", backstory="...")
|
|
103
|
+
crew = Crew(agents=[researcher, writer], tasks=[...])
|
|
104
|
+
|
|
105
|
+
probe = SwarmProbe(crew, swarm_name="my-crew")
|
|
106
|
+
report = probe.run_all()
|
|
107
|
+
report.print_summary()
|
|
108
|
+
report.to_html("report.html") # D3 graph visualization
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Static graph (no live swarm)
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from swarm_test import SwarmProbe, AgentNode, InteractionEvent, EventType
|
|
115
|
+
|
|
116
|
+
a = AgentNode(name="Fetcher", role="researcher")
|
|
117
|
+
b = AgentNode(name="Summarizer", role="writer")
|
|
118
|
+
|
|
119
|
+
probe = SwarmProbe(
|
|
120
|
+
swarm_name="my-swarm",
|
|
121
|
+
agents=[a, b],
|
|
122
|
+
events=[InteractionEvent(
|
|
123
|
+
source_agent_id=a.id,
|
|
124
|
+
target_agent_id=b.id,
|
|
125
|
+
event_type=EventType.TASK_DELEGATE,
|
|
126
|
+
)],
|
|
127
|
+
)
|
|
128
|
+
report = probe.run_all()
|
|
129
|
+
report.print_summary()
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### CLI
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Run against a Python script containing a `crew` variable
|
|
136
|
+
swarm-test probe my_crew.py --output report.html --fail-on-critical
|
|
137
|
+
|
|
138
|
+
# Static scan from the command line
|
|
139
|
+
swarm-test scan \
|
|
140
|
+
--agents Researcher --agents Analyst --agents Writer \
|
|
141
|
+
--edges "Researcher:Analyst" --edges "Analyst:Writer" \
|
|
142
|
+
--output report.html
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Architecture
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
swarm_test/
|
|
151
|
+
├── core/
|
|
152
|
+
│ ├── models.py # Pydantic models (AgentNode, Finding, SwarmReport, …)
|
|
153
|
+
│ ├── graph.py # NetworkX SwarmGraph
|
|
154
|
+
│ ├── interceptor.py # Monkey-patch agent methods, sensitive-data scanner
|
|
155
|
+
│ └── probe.py # SwarmProbe — main entry point
|
|
156
|
+
├── attacks/
|
|
157
|
+
│ ├── cascade.py # Cascade failure simulation
|
|
158
|
+
│ ├── context_leakage.py # Sensitive-data boundary check
|
|
159
|
+
│ ├── intent_drift.py # Role violations + goal hijacking
|
|
160
|
+
│ ├── collusion.py # Clique/echo-chamber/cycle detection
|
|
161
|
+
│ └── blast_radius.py # Topological SPOF + redundancy analysis
|
|
162
|
+
├── integrations/
|
|
163
|
+
│ ├── base.py # BaseAdapter
|
|
164
|
+
│ └── crewai_adapter.py # CrewAI Crew ingestion
|
|
165
|
+
├── reporters/
|
|
166
|
+
│ ├── console.py # Rich terminal output
|
|
167
|
+
│ └── html.py # D3 force-directed graph report
|
|
168
|
+
└── cli.py # Click CLI
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Report Output
|
|
174
|
+
|
|
175
|
+
### Terminal (Rich)
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
─────────────────── SWARM-TEST RELIABILITY REPORT ───────────────────
|
|
179
|
+
|
|
180
|
+
Summary
|
|
181
|
+
Swarm: research-crew-demo Framework: crewai
|
|
182
|
+
Agents: 4 Edges: 6
|
|
183
|
+
Risk Score: 45/100
|
|
184
|
+
Duration: 12ms
|
|
185
|
+
|
|
186
|
+
╭─────────────────── Test Results ─────────────────────╮
|
|
187
|
+
│ Test Status Findings Critical High │
|
|
188
|
+
│ cascade_failure FAILED 2 1 1 │
|
|
189
|
+
│ context_leakage PASSED 0 0 0 │
|
|
190
|
+
│ intent_drift PASSED 0 0 0 │
|
|
191
|
+
│ collusion_detection PASSED 0 0 0 │
|
|
192
|
+
│ blast_radius FAILED 1 1 0 │
|
|
193
|
+
╰───────────────────────────────────────────────────────╯
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### HTML Report
|
|
197
|
+
|
|
198
|
+
Interactive D3.js force-directed graph showing agent nodes, interaction edges, and color-coded findings.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Extending
|
|
203
|
+
|
|
204
|
+
### Custom attack
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from swarm_test.attacks.base import BaseAttack
|
|
208
|
+
from swarm_test.core.models import Finding, Severity, TestResult
|
|
209
|
+
|
|
210
|
+
class MyCustomAttack(BaseAttack):
|
|
211
|
+
name = "my_custom_attack"
|
|
212
|
+
|
|
213
|
+
def run(self, graph):
|
|
214
|
+
findings = []
|
|
215
|
+
# ... analyze graph.graph, graph.events ...
|
|
216
|
+
return TestResult(test_name=self.name, findings=findings)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Custom adapter
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from swarm_test.integrations.base import BaseAdapter
|
|
223
|
+
|
|
224
|
+
class MyFrameworkAdapter(BaseAdapter):
|
|
225
|
+
framework_name = "my-framework"
|
|
226
|
+
|
|
227
|
+
def _ingest_impl(self, swarm, graph):
|
|
228
|
+
for raw_agent in swarm.my_agents:
|
|
229
|
+
node = self._make_agent_node(raw_agent.name, raw_agent.role)
|
|
230
|
+
graph.add_agent(node)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Development
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
pip install -e ".[dev]"
|
|
239
|
+
pytest tests/ -v --cov=swarm_test
|
|
240
|
+
ruff check swarm_test/
|
|
241
|
+
black swarm_test/
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# swarm-test
|
|
2
|
+
|
|
3
|
+
**The first reliability testing framework for multi-agent AI systems.**
|
|
4
|
+
|
|
5
|
+
swarm-test builds a NetworkX interaction graph of your agent swarm and runs 5 automated chaos tests to surface cascade failures, context leakage, intent drift, collusion, and blast radius risks — all from a 3-line API.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from swarm_test import SwarmProbe
|
|
9
|
+
|
|
10
|
+
probe = SwarmProbe(crew)
|
|
11
|
+
report = probe.run_all()
|
|
12
|
+
report.print_summary()
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
| Test | What it checks |
|
|
20
|
+
|---|---|
|
|
21
|
+
| **Cascade Failure** | Which agents, if they fail, bring down the most of the swarm |
|
|
22
|
+
| **Context Leakage** | Sensitive data (credentials, PII) crossing agent boundaries |
|
|
23
|
+
| **Intent Drift** | Agents acting outside their role; prompt injection; goal hijacking |
|
|
24
|
+
| **Collusion Detection** | Dense cliques, echo chambers, orchestrator-bypass cycles |
|
|
25
|
+
| **Blast Radius** | Single points of failure, critical path, redundancy score |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install swarm-test
|
|
33
|
+
# or with framework extras:
|
|
34
|
+
pip install "swarm-test[crewai]"
|
|
35
|
+
pip install "swarm-test[langchain]"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
From source:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git clone https://github.com/surajkumar811/swarm-test
|
|
42
|
+
cd swarm-test
|
|
43
|
+
pip install -e ".[dev]"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
### With a CrewAI crew
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from crewai import Crew, Agent, Task
|
|
54
|
+
from swarm_test import SwarmProbe
|
|
55
|
+
|
|
56
|
+
researcher = Agent(role="researcher", goal="...", backstory="...")
|
|
57
|
+
writer = Agent(role="writer", goal="...", backstory="...")
|
|
58
|
+
crew = Crew(agents=[researcher, writer], tasks=[...])
|
|
59
|
+
|
|
60
|
+
probe = SwarmProbe(crew, swarm_name="my-crew")
|
|
61
|
+
report = probe.run_all()
|
|
62
|
+
report.print_summary()
|
|
63
|
+
report.to_html("report.html") # D3 graph visualization
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Static graph (no live swarm)
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from swarm_test import SwarmProbe, AgentNode, InteractionEvent, EventType
|
|
70
|
+
|
|
71
|
+
a = AgentNode(name="Fetcher", role="researcher")
|
|
72
|
+
b = AgentNode(name="Summarizer", role="writer")
|
|
73
|
+
|
|
74
|
+
probe = SwarmProbe(
|
|
75
|
+
swarm_name="my-swarm",
|
|
76
|
+
agents=[a, b],
|
|
77
|
+
events=[InteractionEvent(
|
|
78
|
+
source_agent_id=a.id,
|
|
79
|
+
target_agent_id=b.id,
|
|
80
|
+
event_type=EventType.TASK_DELEGATE,
|
|
81
|
+
)],
|
|
82
|
+
)
|
|
83
|
+
report = probe.run_all()
|
|
84
|
+
report.print_summary()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### CLI
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Run against a Python script containing a `crew` variable
|
|
91
|
+
swarm-test probe my_crew.py --output report.html --fail-on-critical
|
|
92
|
+
|
|
93
|
+
# Static scan from the command line
|
|
94
|
+
swarm-test scan \
|
|
95
|
+
--agents Researcher --agents Analyst --agents Writer \
|
|
96
|
+
--edges "Researcher:Analyst" --edges "Analyst:Writer" \
|
|
97
|
+
--output report.html
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Architecture
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
swarm_test/
|
|
106
|
+
├── core/
|
|
107
|
+
│ ├── models.py # Pydantic models (AgentNode, Finding, SwarmReport, …)
|
|
108
|
+
│ ├── graph.py # NetworkX SwarmGraph
|
|
109
|
+
│ ├── interceptor.py # Monkey-patch agent methods, sensitive-data scanner
|
|
110
|
+
│ └── probe.py # SwarmProbe — main entry point
|
|
111
|
+
├── attacks/
|
|
112
|
+
│ ├── cascade.py # Cascade failure simulation
|
|
113
|
+
│ ├── context_leakage.py # Sensitive-data boundary check
|
|
114
|
+
│ ├── intent_drift.py # Role violations + goal hijacking
|
|
115
|
+
│ ├── collusion.py # Clique/echo-chamber/cycle detection
|
|
116
|
+
│ └── blast_radius.py # Topological SPOF + redundancy analysis
|
|
117
|
+
├── integrations/
|
|
118
|
+
│ ├── base.py # BaseAdapter
|
|
119
|
+
│ └── crewai_adapter.py # CrewAI Crew ingestion
|
|
120
|
+
├── reporters/
|
|
121
|
+
│ ├── console.py # Rich terminal output
|
|
122
|
+
│ └── html.py # D3 force-directed graph report
|
|
123
|
+
└── cli.py # Click CLI
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Report Output
|
|
129
|
+
|
|
130
|
+
### Terminal (Rich)
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
─────────────────── SWARM-TEST RELIABILITY REPORT ───────────────────
|
|
134
|
+
|
|
135
|
+
Summary
|
|
136
|
+
Swarm: research-crew-demo Framework: crewai
|
|
137
|
+
Agents: 4 Edges: 6
|
|
138
|
+
Risk Score: 45/100
|
|
139
|
+
Duration: 12ms
|
|
140
|
+
|
|
141
|
+
╭─────────────────── Test Results ─────────────────────╮
|
|
142
|
+
│ Test Status Findings Critical High │
|
|
143
|
+
│ cascade_failure FAILED 2 1 1 │
|
|
144
|
+
│ context_leakage PASSED 0 0 0 │
|
|
145
|
+
│ intent_drift PASSED 0 0 0 │
|
|
146
|
+
│ collusion_detection PASSED 0 0 0 │
|
|
147
|
+
│ blast_radius FAILED 1 1 0 │
|
|
148
|
+
╰───────────────────────────────────────────────────────╯
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### HTML Report
|
|
152
|
+
|
|
153
|
+
Interactive D3.js force-directed graph showing agent nodes, interaction edges, and color-coded findings.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Extending
|
|
158
|
+
|
|
159
|
+
### Custom attack
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from swarm_test.attacks.base import BaseAttack
|
|
163
|
+
from swarm_test.core.models import Finding, Severity, TestResult
|
|
164
|
+
|
|
165
|
+
class MyCustomAttack(BaseAttack):
|
|
166
|
+
name = "my_custom_attack"
|
|
167
|
+
|
|
168
|
+
def run(self, graph):
|
|
169
|
+
findings = []
|
|
170
|
+
# ... analyze graph.graph, graph.events ...
|
|
171
|
+
return TestResult(test_name=self.name, findings=findings)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Custom adapter
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from swarm_test.integrations.base import BaseAdapter
|
|
178
|
+
|
|
179
|
+
class MyFrameworkAdapter(BaseAdapter):
|
|
180
|
+
framework_name = "my-framework"
|
|
181
|
+
|
|
182
|
+
def _ingest_impl(self, swarm, graph):
|
|
183
|
+
for raw_agent in swarm.my_agents:
|
|
184
|
+
node = self._make_agent_node(raw_agent.name, raw_agent.role)
|
|
185
|
+
graph.add_agent(node)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Development
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
pip install -e ".[dev]"
|
|
194
|
+
pytest tests/ -v --cov=swarm_test
|
|
195
|
+
ruff check swarm_test/
|
|
196
|
+
black swarm_test/
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT — see [LICENSE](LICENSE).
|