agentfault 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.
Files changed (102) hide show
  1. agentfault-0.1.0/.github/workflows/ci.yml +68 -0
  2. agentfault-0.1.0/.github/workflows/langchain-example.yml +40 -0
  3. agentfault-0.1.0/.github/workflows/langgraph-integration.yml +38 -0
  4. agentfault-0.1.0/.github/workflows/publish.yml +114 -0
  5. agentfault-0.1.0/.gitignore +8 -0
  6. agentfault-0.1.0/.vscode/settings.json +21 -0
  7. agentfault-0.1.0/CHANGELOG.md +24 -0
  8. agentfault-0.1.0/CONTRIBUTING.md +38 -0
  9. agentfault-0.1.0/LICENSE +21 -0
  10. agentfault-0.1.0/PKG-INFO +146 -0
  11. agentfault-0.1.0/README.md +100 -0
  12. agentfault-0.1.0/RELEASE_CHECKLIST.md +30 -0
  13. agentfault-0.1.0/docs/custom-adapters.md +30 -0
  14. agentfault-0.1.0/examples/__init__.py +0 -0
  15. agentfault-0.1.0/examples/basic_scenario.py +22 -0
  16. agentfault-0.1.0/examples/basic_world.py +48 -0
  17. agentfault-0.1.0/examples/langchain_benchmark.py +140 -0
  18. agentfault-0.1.0/examples/langgraph_integration.py +143 -0
  19. agentfault-0.1.0/examples/openai_benchmark.py +61 -0
  20. agentfault-0.1.0/examples/run_agent.py +60 -0
  21. agentfault-0.1.0/pyproject.toml +69 -0
  22. agentfault-0.1.0/src/agentfault/__init__.py +54 -0
  23. agentfault-0.1.0/src/agentfault/agent/__init__.py +5 -0
  24. agentfault-0.1.0/src/agentfault/agent/base.py +11 -0
  25. agentfault-0.1.0/src/agentfault/agent/deterministic.py +80 -0
  26. agentfault-0.1.0/src/agentfault/agent/naive.py +55 -0
  27. agentfault-0.1.0/src/agentfault/benchmarks/__init__.py +17 -0
  28. agentfault-0.1.0/src/agentfault/benchmarks/models.py +141 -0
  29. agentfault-0.1.0/src/agentfault/benchmarks/packs/__init__.py +3 -0
  30. agentfault-0.1.0/src/agentfault/benchmarks/packs/buying.py +237 -0
  31. agentfault-0.1.0/src/agentfault/benchmarks/runner.py +83 -0
  32. agentfault-0.1.0/src/agentfault/cli.py +112 -0
  33. agentfault-0.1.0/src/agentfault/commerce/__init__.py +23 -0
  34. agentfault-0.1.0/src/agentfault/commerce/environment.py +119 -0
  35. agentfault-0.1.0/src/agentfault/commerce/models.py +45 -0
  36. agentfault-0.1.0/src/agentfault/commerce/tools.py +44 -0
  37. agentfault-0.1.0/src/agentfault/integrations/langgraph.py +227 -0
  38. agentfault-0.1.0/src/agentfault/integrations/openai/__init__.py +9 -0
  39. agentfault-0.1.0/src/agentfault/integrations/openai/agent.py +156 -0
  40. agentfault-0.1.0/src/agentfault/integrations/openai/tools.py +17 -0
  41. agentfault-0.1.0/src/agentfault/pytest_plugin.py +68 -0
  42. agentfault-0.1.0/src/agentfault/testing/__init__.py +19 -0
  43. agentfault-0.1.0/src/agentfault/testing/assertion.py +27 -0
  44. agentfault-0.1.0/src/agentfault/testing/assertions/__init__.py +7 -0
  45. agentfault-0.1.0/src/agentfault/testing/assertions/budget.py +39 -0
  46. agentfault-0.1.0/src/agentfault/testing/assertions/prohibited_action.py +21 -0
  47. agentfault-0.1.0/src/agentfault/testing/perturbations/__init__.py +12 -0
  48. agentfault-0.1.0/src/agentfault/testing/perturbations/base.py +8 -0
  49. agentfault-0.1.0/src/agentfault/testing/perturbations/change_inventory.py +14 -0
  50. agentfault-0.1.0/src/agentfault/testing/perturbations/change_price.py +14 -0
  51. agentfault-0.1.0/src/agentfault/testing/perturbations/fail_tool.py +22 -0
  52. agentfault-0.1.0/src/agentfault/testing/runner.py +107 -0
  53. agentfault-0.1.0/src/agentfault/testing/scenario.py +19 -0
  54. agentfault-0.1.0/src/agentfault/testing/scenario_loader.py +42 -0
  55. agentfault-0.1.0/src/agentfault/testing/scenario_result.py +14 -0
  56. agentfault-0.1.0/src/agentfault/testing/scenario_runner.py +99 -0
  57. agentfault-0.1.0/src/agentfault/testing/triggers/__init__.py +8 -0
  58. agentfault-0.1.0/src/agentfault/testing/triggers/base.py +9 -0
  59. agentfault-0.1.0/src/agentfault/testing/triggers/tool.py +20 -0
  60. agentfault-0.1.0/src/agentfault/tools/__init__.py +13 -0
  61. agentfault-0.1.0/src/agentfault/tools/errors.py +9 -0
  62. agentfault-0.1.0/src/agentfault/tools/executor.py +19 -0
  63. agentfault-0.1.0/src/agentfault/tools/registry.py +24 -0
  64. agentfault-0.1.0/src/agentfault/tools/tool.py +69 -0
  65. agentfault-0.1.0/src/agentfault/trajectory/__init__.py +5 -0
  66. agentfault-0.1.0/src/agentfault/trajectory/models.py +16 -0
  67. agentfault-0.1.0/tests/__init__.py +0 -0
  68. agentfault-0.1.0/tests/agent/__init__.py +0 -0
  69. agentfault-0.1.0/tests/agent/test_agent.py +63 -0
  70. agentfault-0.1.0/tests/agent/test_naive.py +34 -0
  71. agentfault-0.1.0/tests/benchmarks/test_buying_agent.py +47 -0
  72. agentfault-0.1.0/tests/benchmarks/test_runner.py +113 -0
  73. agentfault-0.1.0/tests/commerce/__init__.py +0 -0
  74. agentfault-0.1.0/tests/commerce/test_commerce.py +71 -0
  75. agentfault-0.1.0/tests/examples/test_langchain_benchmark.py +74 -0
  76. agentfault-0.1.0/tests/examples/test_langgraph_integration.py +26 -0
  77. agentfault-0.1.0/tests/examples/test_openai_benchmark.py +31 -0
  78. agentfault-0.1.0/tests/integrations/__init__.py +0 -0
  79. agentfault-0.1.0/tests/integrations/openai/__init__.py +0 -0
  80. agentfault-0.1.0/tests/integrations/openai/test_agent.py +255 -0
  81. agentfault-0.1.0/tests/integrations/openai/test_serialization.py +49 -0
  82. agentfault-0.1.0/tests/integrations/openai/test_tool_schema.py +40 -0
  83. agentfault-0.1.0/tests/test_cli.py +65 -0
  84. agentfault-0.1.0/tests/test_pytest_plugin.py +14 -0
  85. agentfault-0.1.0/tests/testing/__init__.py +0 -0
  86. agentfault-0.1.0/tests/testing/assertions/__init__.py +0 -0
  87. agentfault-0.1.0/tests/testing/assertions/test_budget.py +42 -0
  88. agentfault-0.1.0/tests/testing/mutations/__init__.py +0 -0
  89. agentfault-0.1.0/tests/testing/mutations/test_inventory_mutation.py +12 -0
  90. agentfault-0.1.0/tests/testing/mutations/test_price_mutation.py +12 -0
  91. agentfault-0.1.0/tests/testing/test_agent_runner.py +207 -0
  92. agentfault-0.1.0/tests/testing/test_fail_tool.py +9 -0
  93. agentfault-0.1.0/tests/testing/test_scenario.py +91 -0
  94. agentfault-0.1.0/tests/testing/test_scenario_runner.py +472 -0
  95. agentfault-0.1.0/tests/testing/test_tool_failure_recovery.py +165 -0
  96. agentfault-0.1.0/tests/testing/triggers/__init__.py +0 -0
  97. agentfault-0.1.0/tests/testing/triggers/mocks/__init__.py +5 -0
  98. agentfault-0.1.0/tests/testing/triggers/mocks/failing_agent.py +20 -0
  99. agentfault-0.1.0/tests/testing/triggers/test_tool.py +17 -0
  100. agentfault-0.1.0/tests/tools/__init__.py +0 -0
  101. agentfault-0.1.0/tests/tools/test_tools.py +20 -0
  102. agentfault-0.1.0/uv.lock +611 -0
@@ -0,0 +1,68 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ name: Python ${{ matrix.python-version }}
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version: ["3.12", "3.13", "3.14"]
20
+
21
+ steps:
22
+ - name: Check out repository
23
+ uses: actions/checkout@v4
24
+
25
+ - name: Set up Python
26
+ uses: actions/setup-python@v5
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+
30
+ - name: Set up uv
31
+ uses: astral-sh/setup-uv@v6
32
+ with:
33
+ enable-cache: true
34
+ cache-dependency-glob: uv.lock
35
+
36
+ - name: Install project and development dependencies
37
+ run: uv sync --locked --extra dev
38
+
39
+ - name: Run tests
40
+ run: uv run --locked pytest
41
+
42
+ - name: Lint
43
+ run: uv run --locked ruff check .
44
+
45
+ - name: Type-check
46
+ run: uv run --locked mypy src/agentfault
47
+
48
+ - name: Build distributions
49
+ run: uv build
50
+
51
+ - name: Install wheel in a clean environment and smoke-test it
52
+ shell: bash
53
+ run: |
54
+ python -m venv .venv-wheel-smoke
55
+ source .venv-wheel-smoke/bin/activate
56
+ python -m pip install --upgrade pip
57
+ python -m pip install dist/*.whl "pytest>=8.3,<9"
58
+ python - <<'PY'
59
+ from pathlib import Path
60
+ import agentfault
61
+
62
+ installed_from = Path(agentfault.__file__).resolve()
63
+ assert "site-packages" in str(installed_from), installed_from
64
+ print(f"Installed package: {installed_from}")
65
+ PY
66
+ agentfault --help
67
+ PYTHONPATH="$GITHUB_WORKSPACE" agentfault run examples.basic_scenario:build_scenario
68
+ pytest -q
@@ -0,0 +1,40 @@
1
+ name: LangChain example
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - "examples/langchain_benchmark.py"
7
+ - "tests/examples/test_langchain_benchmark.py"
8
+ - ".github/workflows/langchain-example.yml"
9
+ - "README.md"
10
+ - "docs/custom-adapters.md"
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ langchain-example:
18
+ name: LangChain example (Python 3.12)
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Check out repository
22
+ uses: actions/checkout@v4
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.12"
28
+
29
+ - name: Install project and integration dependencies
30
+ run: |
31
+ python -m pip install --upgrade pip
32
+ python -m pip install -e . "langchain-openai>=0.3,<2" "pytest>=8.3,<9"
33
+
34
+ - name: Test adapter without model API calls
35
+ run: pytest -q tests/examples/test_langchain_benchmark.py
36
+
37
+ - name: Check example formatting
38
+ run: |
39
+ python -m pip install "ruff>=0.12,<0.13"
40
+ ruff check examples/langchain_benchmark.py tests/examples/test_langchain_benchmark.py
@@ -0,0 +1,38 @@
1
+ name: LangGraph integration
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - "src/agentfault/integrations/langgraph.py"
7
+ - "examples/langgraph_integration.py"
8
+ - "tests/examples/test_langgraph_integration.py"
9
+ - "docs/custom-adapters.md"
10
+ - ".github/workflows/langgraph-integration.yml"
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ langgraph-integration:
18
+ name: LangGraph integration (Python 3.12)
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Check out repository
22
+ uses: actions/checkout@v4
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.12"
28
+
29
+ - name: Install package and LangGraph integration dependencies
30
+ run: |
31
+ python -m pip install --upgrade pip
32
+ python -m pip install -e . "langgraph>=1.0,<2" "pytest>=8.3,<9"
33
+
34
+ - name: Run LangGraph integration test
35
+ run: pytest -q tests/examples/test_langgraph_integration.py
36
+
37
+ - name: Run example
38
+ run: python -m examples.langgraph_integration
@@ -0,0 +1,114 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ name: Test (Python ${{ matrix.python-version }})
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.12", "3.13", "3.14"]
19
+ steps:
20
+ - name: Check out repository
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Set up Python
24
+ uses: actions/setup-python@v5
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+
28
+ - name: Set up uv
29
+ uses: astral-sh/setup-uv@v6
30
+ with:
31
+ enable-cache: true
32
+ cache-dependency-glob: uv.lock
33
+
34
+ - name: Install project and development dependencies
35
+ run: uv sync --locked --extra dev
36
+
37
+ - name: Run tests
38
+ run: uv run --locked pytest
39
+
40
+ - name: Lint
41
+ run: uv run --locked ruff check .
42
+
43
+ - name: Type-check
44
+ run: uv run --locked mypy src/agentfault
45
+
46
+ build:
47
+ name: Build and verify distributions
48
+ needs: test
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - name: Check out repository
52
+ uses: actions/checkout@v4
53
+
54
+ - name: Set up Python
55
+ uses: actions/setup-python@v5
56
+ with:
57
+ python-version: "3.12"
58
+
59
+ - name: Set up uv
60
+ uses: astral-sh/setup-uv@v6
61
+ with:
62
+ enable-cache: true
63
+ cache-dependency-glob: uv.lock
64
+
65
+ - name: Ensure tag matches package version
66
+ run: |
67
+ python - <<'PY'
68
+ import os
69
+ import tomllib
70
+ from pathlib import Path
71
+
72
+ with Path("pyproject.toml").open("rb") as f:
73
+ project = tomllib.load(f)["project"]
74
+
75
+ expected = f"v{project['version']}"
76
+ actual = os.environ["GITHUB_REF_NAME"]
77
+ if actual != expected:
78
+ raise SystemExit(
79
+ f"Release tag {actual!r} does not match package version {expected!r}"
80
+ )
81
+ print(f"Preparing {project['name']} {project['version']}")
82
+ PY
83
+
84
+ - name: Build source distribution and wheel
85
+ run: uv build
86
+
87
+ - name: Validate distribution metadata
88
+ run: uv run --with twine twine check dist/*
89
+
90
+ - name: Upload distributions
91
+ uses: actions/upload-artifact@v4
92
+ with:
93
+ name: python-package-distributions
94
+ path: dist/
95
+ if-no-files-found: error
96
+
97
+ publish:
98
+ name: Publish to PyPI
99
+ needs: build
100
+ runs-on: ubuntu-latest
101
+ environment:
102
+ name: pypi
103
+ url: https://pypi.org/project/agentfault/
104
+ permissions:
105
+ id-token: write
106
+ steps:
107
+ - name: Download distributions
108
+ uses: actions/download-artifact@v4
109
+ with:
110
+ name: python-package-distributions
111
+ path: dist/
112
+
113
+ - name: Publish distributions
114
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ .env
2
+ .venv/
3
+ __pycache__/
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ .ruff_cache/
7
+ *.egg-info/
8
+ *.py[cod]
@@ -0,0 +1,21 @@
1
+ {
2
+ "[python]": {
3
+ "editor.defaultFormatter": "charliermarsh.ruff",
4
+ "editor.formatOnSave": true,
5
+ "editor.codeActionsOnSave": {
6
+ "source.fixAll.ruff": "always",
7
+ "source.organizeImports.ruff": "always"
8
+ },
9
+ "editor.tabSize": 4,
10
+ "editor.insertSpaces": true,
11
+ "editor.detectIndentation": false,
12
+ "editor.rulers": [88]
13
+ },
14
+ "files.trimTrailingWhitespace": true,
15
+ "files.insertFinalNewline": true,
16
+ "files.trimFinalNewlines": true,
17
+ "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
18
+ "python.analysis.autoImportCompletions": true,
19
+ "python.analysis.extraPaths": ["./src"],
20
+ "ruff.importStrategy": "fromEnvironment"
21
+ }
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ Notable changes to Agent Fault are documented here.
4
+
5
+ This project is in alpha. Until the first release is tagged, changes are collected under `Unreleased`.
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+ - A versioned benchmark API with per-case results, assertion evidence, tool-call summaries, and scoring withheld for incomplete runs.
11
+ - The `buying-agent@1.0.0` benchmark suite for safe purchases under price and inventory changes.
12
+ - OpenAI and LangChain examples for the Benchmark API, plus a native LangGraph custom-scenario example.
13
+ - An optional LangChain integration workflow that checks adapter behavior without model API calls.
14
+ - CI validation for Python 3.12, 3.13, and 3.14, including a clean-wheel installation smoke test.
15
+
16
+ ### Changed
17
+ - The README is organized around the two public use cases: reusable benchmarks and custom scenarios, with framework examples for OpenAI, LangChain, and LangGraph.
18
+ - The product's display name is written as **Agent Fault**; the Python import package and distribution identifier remain `agentfault`.
19
+ - The deterministic commerce reference agent rechecks the offer price and inventory after adding an item to the cart.
20
+
21
+ ### Notes
22
+ - APIs are in alpha and may change before the first stable release.
23
+ - The built-in benchmark currently covers buying agents; other categories can use custom scenarios or add versioned suites.
24
+ - The first release version and date will be recorded when a release is actually published.
@@ -0,0 +1,38 @@
1
+ # Contributing to AgentFault
2
+
3
+ Thanks for contributing. AgentFault is an alpha project focused on testing how tool-using agents behave when the environment changes or tools fail.
4
+
5
+ ## Development setup
6
+
7
+ Requirements: Python 3.12 or newer and [uv](https://docs.astral.sh/uv/).
8
+
9
+ From the repository root:
10
+
11
+ ```bash
12
+ uv sync --extra dev
13
+ ```
14
+
15
+ ## Checks before opening a pull request
16
+
17
+ Run the test suite, lint, type-check, and package build:
18
+
19
+ ```bash
20
+ uv run pytest
21
+ uv run ruff check .
22
+ uv run mypy src/agentfault
23
+ uv build
24
+ ```
25
+
26
+ GitHub Actions runs the same checks on Python 3.12, 3.13, and 3.14, then installs the built wheel in a clean environment and smoke-tests the CLI and pytest integration.
27
+
28
+ ## Change guidelines
29
+
30
+ - Keep agent execution generic. Domain-specific behavior belongs in environments, tools, scenarios, perturbations, or assertions.
31
+ - Prefer small, runnable examples that demonstrate one behavioral contract.
32
+ - When changing scenario behavior, add a test that covers the expected outcome and relevant trajectory evidence.
33
+ - Do not make an intentionally failing example appear to pass. Document expected failure behavior explicitly.
34
+ - Avoid adding runtime dependencies unless they are needed for a clear user-facing capability.
35
+
36
+ ## Pull requests
37
+
38
+ Use a focused change with a Conventional Commit-style title, explain the motivation and behavioral impact, and note the checks you ran. Do not claim checks passed unless you ran them or CI reports success.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 danishmerani95
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,146 @@
1
+ Metadata-Version: 2.5
2
+ Name: agentfault
3
+ Version: 0.1.0
4
+ Summary: Agent Fault: open-source stateful reliability testing for AI agents
5
+ Project-URL: Homepage, https://github.com/danishmerani95/AgentFault
6
+ Project-URL: Repository, https://github.com/danishmerani95/AgentFault
7
+ Project-URL: Issues, https://github.com/danishmerani95/AgentFault/issues
8
+ Project-URL: Changelog, https://github.com/danishmerani95/AgentFault/blob/main/CHANGELOG.md
9
+ Author: Agent Fault Contributors
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 danishmerani95
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: agent-reliability,agents,ai,evaluation,failure-injection,reliability,testing
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.12
36
+ Classifier: Programming Language :: Python :: 3.13
37
+ Classifier: Programming Language :: Python :: 3.14
38
+ Requires-Python: >=3.12
39
+ Requires-Dist: openai>=1.0
40
+ Requires-Dist: python-dotenv>=1.0
41
+ Provides-Extra: dev
42
+ Requires-Dist: mypy<2,>=1.17; extra == 'dev'
43
+ Requires-Dist: pytest<9,>=8.3; extra == 'dev'
44
+ Requires-Dist: ruff<0.13,>=0.12; extra == 'dev'
45
+ Description-Content-Type: text/markdown
46
+
47
+ # Agent Fault
48
+
49
+ **Break the world around your agent. Verify its behavior.**
50
+
51
+ Agent Fault tests tool-using AI agents against changing conditions: a price rises, inventory disappears, an account is suspended, or a tool fails while the agent is working.
52
+
53
+ It offers two APIs over the same stateful testing engine.
54
+
55
+ ## 1. Benchmark API
56
+
57
+ **Use it to compare an agent against a reusable, versioned test suite.**
58
+
59
+ The built-in `buying-agent@1.0.0` benchmark contains five deterministic scenarios covering:
60
+
61
+ - Buying an eligible offer within budget.
62
+ - Price increases before validation.
63
+ - Inventory disappearing before cart creation.
64
+ - Price increases after an item enters the cart.
65
+ - Inventory disappearing after an item enters the cart.
66
+
67
+ A benchmark returns a pass percentage, per-case results, failed assertions, and observed tool calls. If any case has an execution error, the headline score is withheld rather than treating an invalid run as a pass or failure.
68
+
69
+ The API accepts an agent factory that implements AgentFault's `Agent` contract. OpenAI has a built-in adapter; other frameworks can provide an adapter for their tool-call loop.
70
+
71
+ Run the OpenAI example (requires an OpenAI API key; all tools still use a synthetic test environment):
72
+
73
+ ```bash
74
+ uv sync --extra dev
75
+ export OPENAI_API_KEY=...
76
+ uv run python -m examples.openai_benchmark
77
+ ```
78
+
79
+ The example is in [`examples/openai_benchmark.py`](examples/openai_benchmark.py). It prints a JSON report and can be adapted to use your own prompts, model, and agent.
80
+
81
+ The [LangChain benchmark example](examples/langchain_benchmark.py) uses LangChain's `ChatOpenAI` and `bind_tools` APIs with the same versioned buying benchmark. AgentFault deliberately executes one tool call at a time, so the model's next decision sees the result and any state change introduced by the scenario. It requires an OpenAI API key and keeps all tool execution in the synthetic test world:
82
+
83
+ ```bash
84
+ export OPENAI_API_KEY=...
85
+ uv run --with "langchain-openai>=0.3,<2" python -m examples.langchain_benchmark
86
+ ```
87
+
88
+ This is a LangChain chat-model adapter, not a wrapper around an arbitrary LangChain `AgentExecutor`; the AgentFault runner owns the tool loop to make stateful interventions deterministic.
89
+
90
+ ## 2. Custom Scenario API
91
+
92
+ **Use it to test a failure mode specific to your application.**
93
+
94
+ A scenario defines your agent, isolated environment and tools, an optional perturbation, and assertions about acceptable behavior. Use it for buying, support, research, operations, or any workflow where an agent's actions depend on tool results or changing state.
95
+
96
+ For an agent that implements `Agent`, compose a `Scenario` and run it with `ScenarioRunner`:
97
+
98
+ ```python
99
+ from agentfault.testing import Scenario, ScenarioRunner
100
+ from agentfault.testing.assertions import MaxPriceAssertion
101
+ from agentfault.testing.perturbations import ChangePrice
102
+ from agentfault.testing.triggers import AfterTool
103
+ from agentfault.tools import ToolRegistry
104
+
105
+ # Supply these from your application or a test fixture:
106
+ # agent_under_test, test_environment, and the Tool objects.
107
+ tool_registry = ToolRegistry(test_tools)
108
+
109
+ scenario = Scenario(
110
+ name="price changes during checkout",
111
+ agent=agent_under_test,
112
+ environment=test_environment,
113
+ perturbations=[
114
+ (AfterTool("get_offers_for_product"),
115
+ ChangePrice("offer_sony_1", new_price=179.0)),
116
+ ],
117
+ assertions=[MaxPriceAssertion(max_price=150.0)],
118
+ )
119
+ result = ScenarioRunner(tool_registry).run(scenario)
120
+ assert result.passed, [item.message for item in result.assertions if not item.passed]
121
+ ```
122
+
123
+ For a graph that owns its own decision loop, use its integration runner instead of wrapping the entire graph as a generic `Agent`.
124
+
125
+ Run the LangGraph example (requires LangGraph; no model API key is needed):
126
+
127
+ ```bash
128
+ uv run --with "langgraph>=1.0,<2" python -m examples.langgraph_integration
129
+ ```
130
+
131
+ The [LangGraph example](examples/langgraph_integration.py) uses a real `StateGraph` and `ToolNode`, a scripted decision node, and a fake account/refund world. It shows a custom scenario that suspends an account after lookup and checks that no refund tool is called. The current LangGraph integration supports synchronous `invoke`, sequential calls routed through the configured `ToolNode`; async execution, parallel calls, and other tool paths are not yet supported.
132
+
133
+ ## Use cases
134
+
135
+ - **Buying agents:** stop unsafe purchases when prices or inventory change.
136
+ - **Support agents:** verify permissions and account state before refunds or account changes.
137
+ - **Search and research agents:** test stale, missing, or contradictory information.
138
+ - **Operations and workflow agents:** inject tool failures and check recovery or safe stopping.
139
+
140
+ The built-in benchmark currently covers buying. Other roles can be tested today with custom scenarios; additional benchmark packs can use the same versioned suite API.
141
+
142
+ ## Safety and scope
143
+
144
+ Use fixtures, fake services, or an isolated sandbox. AgentFault does not make production tools safe automatically. Only actions routed through the configured executor/interceptor are recorded and can be perturbed.
145
+
146
+ Project status: **alpha**. APIs may change. See [custom adapter notes](docs/custom-adapters.md), [contributing](CONTRIBUTING.md), and the [changelog](CHANGELOG.md).
@@ -0,0 +1,100 @@
1
+ # Agent Fault
2
+
3
+ **Break the world around your agent. Verify its behavior.**
4
+
5
+ Agent Fault tests tool-using AI agents against changing conditions: a price rises, inventory disappears, an account is suspended, or a tool fails while the agent is working.
6
+
7
+ It offers two APIs over the same stateful testing engine.
8
+
9
+ ## 1. Benchmark API
10
+
11
+ **Use it to compare an agent against a reusable, versioned test suite.**
12
+
13
+ The built-in `buying-agent@1.0.0` benchmark contains five deterministic scenarios covering:
14
+
15
+ - Buying an eligible offer within budget.
16
+ - Price increases before validation.
17
+ - Inventory disappearing before cart creation.
18
+ - Price increases after an item enters the cart.
19
+ - Inventory disappearing after an item enters the cart.
20
+
21
+ A benchmark returns a pass percentage, per-case results, failed assertions, and observed tool calls. If any case has an execution error, the headline score is withheld rather than treating an invalid run as a pass or failure.
22
+
23
+ The API accepts an agent factory that implements AgentFault's `Agent` contract. OpenAI has a built-in adapter; other frameworks can provide an adapter for their tool-call loop.
24
+
25
+ Run the OpenAI example (requires an OpenAI API key; all tools still use a synthetic test environment):
26
+
27
+ ```bash
28
+ uv sync --extra dev
29
+ export OPENAI_API_KEY=...
30
+ uv run python -m examples.openai_benchmark
31
+ ```
32
+
33
+ The example is in [`examples/openai_benchmark.py`](examples/openai_benchmark.py). It prints a JSON report and can be adapted to use your own prompts, model, and agent.
34
+
35
+ The [LangChain benchmark example](examples/langchain_benchmark.py) uses LangChain's `ChatOpenAI` and `bind_tools` APIs with the same versioned buying benchmark. AgentFault deliberately executes one tool call at a time, so the model's next decision sees the result and any state change introduced by the scenario. It requires an OpenAI API key and keeps all tool execution in the synthetic test world:
36
+
37
+ ```bash
38
+ export OPENAI_API_KEY=...
39
+ uv run --with "langchain-openai>=0.3,<2" python -m examples.langchain_benchmark
40
+ ```
41
+
42
+ This is a LangChain chat-model adapter, not a wrapper around an arbitrary LangChain `AgentExecutor`; the AgentFault runner owns the tool loop to make stateful interventions deterministic.
43
+
44
+ ## 2. Custom Scenario API
45
+
46
+ **Use it to test a failure mode specific to your application.**
47
+
48
+ A scenario defines your agent, isolated environment and tools, an optional perturbation, and assertions about acceptable behavior. Use it for buying, support, research, operations, or any workflow where an agent's actions depend on tool results or changing state.
49
+
50
+ For an agent that implements `Agent`, compose a `Scenario` and run it with `ScenarioRunner`:
51
+
52
+ ```python
53
+ from agentfault.testing import Scenario, ScenarioRunner
54
+ from agentfault.testing.assertions import MaxPriceAssertion
55
+ from agentfault.testing.perturbations import ChangePrice
56
+ from agentfault.testing.triggers import AfterTool
57
+ from agentfault.tools import ToolRegistry
58
+
59
+ # Supply these from your application or a test fixture:
60
+ # agent_under_test, test_environment, and the Tool objects.
61
+ tool_registry = ToolRegistry(test_tools)
62
+
63
+ scenario = Scenario(
64
+ name="price changes during checkout",
65
+ agent=agent_under_test,
66
+ environment=test_environment,
67
+ perturbations=[
68
+ (AfterTool("get_offers_for_product"),
69
+ ChangePrice("offer_sony_1", new_price=179.0)),
70
+ ],
71
+ assertions=[MaxPriceAssertion(max_price=150.0)],
72
+ )
73
+ result = ScenarioRunner(tool_registry).run(scenario)
74
+ assert result.passed, [item.message for item in result.assertions if not item.passed]
75
+ ```
76
+
77
+ For a graph that owns its own decision loop, use its integration runner instead of wrapping the entire graph as a generic `Agent`.
78
+
79
+ Run the LangGraph example (requires LangGraph; no model API key is needed):
80
+
81
+ ```bash
82
+ uv run --with "langgraph>=1.0,<2" python -m examples.langgraph_integration
83
+ ```
84
+
85
+ The [LangGraph example](examples/langgraph_integration.py) uses a real `StateGraph` and `ToolNode`, a scripted decision node, and a fake account/refund world. It shows a custom scenario that suspends an account after lookup and checks that no refund tool is called. The current LangGraph integration supports synchronous `invoke`, sequential calls routed through the configured `ToolNode`; async execution, parallel calls, and other tool paths are not yet supported.
86
+
87
+ ## Use cases
88
+
89
+ - **Buying agents:** stop unsafe purchases when prices or inventory change.
90
+ - **Support agents:** verify permissions and account state before refunds or account changes.
91
+ - **Search and research agents:** test stale, missing, or contradictory information.
92
+ - **Operations and workflow agents:** inject tool failures and check recovery or safe stopping.
93
+
94
+ The built-in benchmark currently covers buying. Other roles can be tested today with custom scenarios; additional benchmark packs can use the same versioned suite API.
95
+
96
+ ## Safety and scope
97
+
98
+ Use fixtures, fake services, or an isolated sandbox. AgentFault does not make production tools safe automatically. Only actions routed through the configured executor/interceptor are recorded and can be perturbed.
99
+
100
+ Project status: **alpha**. APIs may change. See [custom adapter notes](docs/custom-adapters.md), [contributing](CONTRIBUTING.md), and the [changelog](CHANGELOG.md).
@@ -0,0 +1,30 @@
1
+ # First Release Checklist
2
+
3
+ Use this checklist before publishing the first public Agent Fault release. Do not publish automatically from this checklist; repository visibility, package identity, version, and destination are deliberate release decisions.
4
+
5
+ ## Project identity and license
6
+
7
+ - [ ] Confirm the repository is intended to be public before publishing.
8
+ - [x] Display-name decision: use **Agent Fault**. A separate product named AgentFault exists at [agentfault.com](https://agentfault.com/); the similar name remains a potential source of confusion, so the public description should clearly state that this project is an open-source AI-agent reliability testing library.
9
+ - [ ] Verify the PyPI distribution name `agentfault` directly against PyPI before upload; availability has not yet been conclusively established.
10
+ - [x] License decision confirmed: use the MIT License. Keep the `LICENSE` file and package metadata consistent with MIT.
11
+ - [ ] Review ownership and copyright information in `LICENSE`.
12
+ - [ ] Review the README, contributor guide, changelog, and example scenario commands for accuracy.
13
+
14
+ ## Package readiness
15
+
16
+ - [x] Confirm the version in `pyproject.toml` (`0.1.0`) is the intended first alpha release version.
17
+ - [x] Confirm `uv.lock` is in sync with the project configuration (the current main-branch CI uses `uv sync --locked` successfully).
18
+ - [ ] Run CI on the exact commit intended for release and require all checks to pass.
19
+ - [ ] Build the source distribution and wheel with `uv build`.
20
+ - [ ] Inspect the distributions and metadata before upload; test installing the wheel in a clean environment.
21
+ - [ ] Verify the CLI entry point and pytest plugin work from the installed distribution.
22
+
23
+ ## Publish and announce
24
+
25
+ - [ ] Decide on and configure the trusted publishing or PyPI credentials workflow.
26
+ - [ ] Publish only after the above checks and owner approval.
27
+ - [ ] Create a version tag (for example, `v0.1.0`) that matches the released package.
28
+ - [ ] Create a GitHub release with notes drawn from `CHANGELOG.md`.
29
+ - [ ] Verify the published package can be installed into a fresh environment and the documented quick start works.
30
+ - [ ] Announce the release with the repository link and clear alpha-status expectations.