failstep 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.
- failstep-0.1.0/.gitattributes +12 -0
- failstep-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +48 -0
- failstep-0.1.0/.github/ISSUE_TEMPLATE/config.yml +1 -0
- failstep-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +9 -0
- failstep-0.1.0/.github/workflows/ci.yml +45 -0
- failstep-0.1.0/.github/workflows/publish.yml +24 -0
- failstep-0.1.0/.gitignore +64 -0
- failstep-0.1.0/CHANGELOG.md +11 -0
- failstep-0.1.0/CONTRIBUTING.md +38 -0
- failstep-0.1.0/LICENSE +21 -0
- failstep-0.1.0/PKG-INFO +159 -0
- failstep-0.1.0/README.md +105 -0
- failstep-0.1.0/docs/ARCHITECTURE.md +117 -0
- failstep-0.1.0/docs/COMPETITORS.md +51 -0
- failstep-0.1.0/docs/DECISIONS.md +103 -0
- failstep-0.1.0/docs/OUTPUT.md +290 -0
- failstep-0.1.0/docs/PHASES.md +171 -0
- failstep-0.1.0/docs/POSITIONING.md +96 -0
- failstep-0.1.0/docs/PRODUCT.md +148 -0
- failstep-0.1.0/docs/STACK.md +113 -0
- failstep-0.1.0/docs/TESTING.md +245 -0
- failstep-0.1.0/docs/TRACE_FORMAT.md +85 -0
- failstep-0.1.0/examples/traces/empty-retrieval.json +34 -0
- failstep-0.1.0/examples/traces/malformed-json.json +19 -0
- failstep-0.1.0/examples/traces/otel-retry-loop.json +198 -0
- failstep-0.1.0/examples/traces/retry-loop.json +83 -0
- failstep-0.1.0/examples/traces/schema-mismatch.json +40 -0
- failstep-0.1.0/examples/traces/success.json +47 -0
- failstep-0.1.0/examples/traces/timeout.json +33 -0
- failstep-0.1.0/examples/traces/tool-failure.json +19 -0
- failstep-0.1.0/pyproject.toml +68 -0
- failstep-0.1.0/src/failstep/__init__.py +3 -0
- failstep-0.1.0/src/failstep/__main__.py +4 -0
- failstep-0.1.0/src/failstep/adapters.py +628 -0
- failstep-0.1.0/src/failstep/cli.py +227 -0
- failstep-0.1.0/src/failstep/compare.py +119 -0
- failstep-0.1.0/src/failstep/detectors/__init__.py +29 -0
- failstep-0.1.0/src/failstep/detectors/malformed.py +115 -0
- failstep-0.1.0/src/failstep/detectors/retrieval.py +292 -0
- failstep-0.1.0/src/failstep/detectors/retry.py +52 -0
- failstep-0.1.0/src/failstep/detectors/schema.py +134 -0
- failstep-0.1.0/src/failstep/detectors/timeout.py +83 -0
- failstep-0.1.0/src/failstep/detectors/tool_error.py +95 -0
- failstep-0.1.0/src/failstep/diagnose.py +56 -0
- failstep-0.1.0/src/failstep/errors.py +11 -0
- failstep-0.1.0/src/failstep/evidence.py +67 -0
- failstep-0.1.0/src/failstep/llm.py +234 -0
- failstep-0.1.0/src/failstep/models.py +93 -0
- failstep-0.1.0/src/failstep/normalize.py +147 -0
- failstep-0.1.0/src/failstep/parser.py +137 -0
- failstep-0.1.0/src/failstep/redact.py +25 -0
- failstep-0.1.0/src/failstep/report.py +617 -0
- failstep-0.1.0/tests/conftest.py +26 -0
- failstep-0.1.0/tests/goldens/compare-retry-loop.json +77 -0
- failstep-0.1.0/tests/goldens/compare-retry-loop.md +21 -0
- failstep-0.1.0/tests/goldens/compare-retry-loop.terminal.txt +19 -0
- failstep-0.1.0/tests/goldens/empty-retrieval.terminal.txt +24 -0
- failstep-0.1.0/tests/goldens/fix-retry-loop.json +29 -0
- failstep-0.1.0/tests/goldens/fix-retry-loop.md +10 -0
- failstep-0.1.0/tests/goldens/fix-retry-loop.terminal.txt +11 -0
- failstep-0.1.0/tests/goldens/fix-success.terminal.txt +9 -0
- failstep-0.1.0/tests/goldens/inspect-otel-retry-loop.terminal.txt +14 -0
- failstep-0.1.0/tests/goldens/inspect-retry-loop.json +124 -0
- failstep-0.1.0/tests/goldens/inspect-retry-loop.terminal.txt +17 -0
- failstep-0.1.0/tests/goldens/multi-failure.json +456 -0
- failstep-0.1.0/tests/goldens/multi-failure.md +21 -0
- failstep-0.1.0/tests/goldens/multi-failure.terminal.txt +26 -0
- failstep-0.1.0/tests/goldens/otel-retry-loop.json +91 -0
- failstep-0.1.0/tests/goldens/otel-retry-loop.md +17 -0
- failstep-0.1.0/tests/goldens/otel-retry-loop.terminal.txt +22 -0
- failstep-0.1.0/tests/goldens/retrieval-silent.json +162 -0
- failstep-0.1.0/tests/goldens/retrieval-silent.md +18 -0
- failstep-0.1.0/tests/goldens/retrieval-silent.terminal.txt +24 -0
- failstep-0.1.0/tests/goldens/retry-loop.json +91 -0
- failstep-0.1.0/tests/goldens/retry-loop.md +17 -0
- failstep-0.1.0/tests/goldens/retry-loop.terminal.txt +22 -0
- failstep-0.1.0/tests/goldens/success.terminal.txt +18 -0
- failstep-0.1.0/tests/goldens/timeout-missing-duration.json +73 -0
- failstep-0.1.0/tests/goldens/timeout-missing-duration.terminal.txt +20 -0
- failstep-0.1.0/tests/test_cli_exit.py +125 -0
- failstep-0.1.0/tests/test_compare.py +147 -0
- failstep-0.1.0/tests/test_detectors/test_detectors.py +96 -0
- failstep-0.1.0/tests/test_detectors/test_retrieval.py +107 -0
- failstep-0.1.0/tests/test_detectors/test_traps.py +233 -0
- failstep-0.1.0/tests/test_diagnose.py +250 -0
- failstep-0.1.0/tests/test_fix.py +106 -0
- failstep-0.1.0/tests/test_honesty.py +163 -0
- failstep-0.1.0/tests/test_inspect.py +70 -0
- failstep-0.1.0/tests/test_llm.py +232 -0
- failstep-0.1.0/tests/test_otel.py +111 -0
- failstep-0.1.0/tests/test_parser.py +262 -0
- failstep-0.1.0/tests/test_redact.py +20 -0
- failstep-0.1.0/tests/test_release.py +58 -0
- failstep-0.1.0/tests/test_sniff.py +48 -0
- failstep-0.1.0/tests/traces/healthy-busy.json +176 -0
- failstep-0.1.0/tests/traces/langchain-steps.json +10 -0
- failstep-0.1.0/tests/traces/leftover-secret.json +44 -0
- failstep-0.1.0/tests/traces/malformed-invalid.json +20 -0
- failstep-0.1.0/tests/traces/malformed-output-schema.json +38 -0
- failstep-0.1.0/tests/traces/malformed-silent.json +85 -0
- failstep-0.1.0/tests/traces/minimal.jsonl +3 -0
- failstep-0.1.0/tests/traces/multi-failure.json +350 -0
- failstep-0.1.0/tests/traces/openai-messages.json +64 -0
- failstep-0.1.0/tests/traces/otel-http-only.json +28 -0
- failstep-0.1.0/tests/traces/otel-python-export.json +93 -0
- failstep-0.1.0/tests/traces/otel-schema.json +62 -0
- failstep-0.1.0/tests/traces/otel-success.json +148 -0
- failstep-0.1.0/tests/traces/otel-tool-error.json +122 -0
- failstep-0.1.0/tests/traces/retrieval-conflict-silent.json +32 -0
- failstep-0.1.0/tests/traces/retrieval-conflict.json +43 -0
- failstep-0.1.0/tests/traces/retrieval-healthy.json +38 -0
- failstep-0.1.0/tests/traces/retrieval-silent.json +61 -0
- failstep-0.1.0/tests/traces/retrieval-then-fail.json +51 -0
- failstep-0.1.0/tests/traces/retry-silent.json +157 -0
- failstep-0.1.0/tests/traces/schema-silent.json +58 -0
- failstep-0.1.0/tests/traces/schema-traps.json +129 -0
- failstep-0.1.0/tests/traces/timeout-dominate.json +40 -0
- failstep-0.1.0/tests/traces/timeout-llm.json +20 -0
- failstep-0.1.0/tests/traces/timeout-missing-duration.json +19 -0
- failstep-0.1.0/tests/traces/timeout-multiple.json +31 -0
- failstep-0.1.0/tests/traces/timeout-recovered.json +54 -0
- failstep-0.1.0/tests/traces/tool-empty-error.json +22 -0
- failstep-0.1.0/tests/traces/tool-http-recovered.json +98 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Bug
|
|
2
|
+
description: A command printed the wrong finding, crashed, or accepted garbage.
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: input
|
|
6
|
+
id: version
|
|
7
|
+
attributes:
|
|
8
|
+
label: failstep version
|
|
9
|
+
placeholder: "0.1.0"
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: command
|
|
14
|
+
attributes:
|
|
15
|
+
label: Command
|
|
16
|
+
description: Exact command, including flags.
|
|
17
|
+
render: shell
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: expected
|
|
22
|
+
attributes:
|
|
23
|
+
label: Expected
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: actual
|
|
28
|
+
attributes:
|
|
29
|
+
label: Actual
|
|
30
|
+
description: Paste stdout. Redact secrets.
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: fixture
|
|
35
|
+
attributes:
|
|
36
|
+
label: Trace
|
|
37
|
+
description: Minimal JSON, or a path under examples/traces or tests/traces. Redact secrets. Do not paste API keys.
|
|
38
|
+
render: json
|
|
39
|
+
- type: input
|
|
40
|
+
id: python
|
|
41
|
+
attributes:
|
|
42
|
+
label: Python
|
|
43
|
+
placeholder: "3.12.0"
|
|
44
|
+
- type: input
|
|
45
|
+
id: os
|
|
46
|
+
attributes:
|
|
47
|
+
label: OS
|
|
48
|
+
placeholder: Windows 11 / Ubuntu 24.04
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: ${{ matrix.os }} / py${{ matrix.python-version }}
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, windows-latest]
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
- name: Install
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
python -m pip install -e ".[dev]"
|
|
29
|
+
- name: Ruff
|
|
30
|
+
run: python -m ruff check .
|
|
31
|
+
- name: Pytest
|
|
32
|
+
run: python -m pytest
|
|
33
|
+
|
|
34
|
+
package:
|
|
35
|
+
name: sdist and wheel
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
- uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.12"
|
|
42
|
+
- name: Build
|
|
43
|
+
run: |
|
|
44
|
+
python -m pip install --upgrade pip build
|
|
45
|
+
python -m build
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
pypi:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: pypi
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
- name: Build
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip build
|
|
23
|
+
python -m build
|
|
24
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
.venv/
|
|
3
|
+
venv/
|
|
4
|
+
env/
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
*.so
|
|
9
|
+
.Python
|
|
10
|
+
*.egg-info/
|
|
11
|
+
*.egg
|
|
12
|
+
dist/
|
|
13
|
+
build/
|
|
14
|
+
wheels/
|
|
15
|
+
pip-wheel-metadata/
|
|
16
|
+
|
|
17
|
+
# Test / lint / type / coverage
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.ruff_cache/
|
|
20
|
+
.mypy_cache/
|
|
21
|
+
.coverage
|
|
22
|
+
.coverage.*
|
|
23
|
+
htmlcov/
|
|
24
|
+
coverage.xml
|
|
25
|
+
.tox/
|
|
26
|
+
.nox/
|
|
27
|
+
.hypothesis/
|
|
28
|
+
.cache/
|
|
29
|
+
|
|
30
|
+
# uv (lock is optional for a library CLI; pyproject is the source of truth)
|
|
31
|
+
.uv/
|
|
32
|
+
uv.lock
|
|
33
|
+
|
|
34
|
+
# Env / secrets — never publish
|
|
35
|
+
.env
|
|
36
|
+
|
|
37
|
+
.env.*
|
|
38
|
+
!.env.example
|
|
39
|
+
*.pem
|
|
40
|
+
*.key
|
|
41
|
+
|
|
42
|
+
# OS
|
|
43
|
+
.DS_Store
|
|
44
|
+
Thumbs.db
|
|
45
|
+
ehthumbs.db
|
|
46
|
+
desktop.ini
|
|
47
|
+
|
|
48
|
+
# Editors
|
|
49
|
+
.idea/
|
|
50
|
+
.vscode/
|
|
51
|
+
*.swp
|
|
52
|
+
*.swo
|
|
53
|
+
*~
|
|
54
|
+
*.orig
|
|
55
|
+
|
|
56
|
+
# Local leftovers — never publish
|
|
57
|
+
MOVED.md
|
|
58
|
+
_chatgpt_share*
|
|
59
|
+
*.tmp
|
|
60
|
+
*.temp
|
|
61
|
+
~$*
|
|
62
|
+
|
|
63
|
+
# Jupyter
|
|
64
|
+
.ipynb_checkpoints/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- `inspect`, `diagnose`, `compare`, `fix`, `version`
|
|
6
|
+
- Detectors FS001–FS008 (malformed, schema, tool failure, retry, timeout, empty retrieval, duplicate chunks, conflicting sources)
|
|
7
|
+
- Native JSON/JSONL, OpenAI messages, LangChain `intermediate_steps`, exported OpenTelemetry GenAI JSON
|
|
8
|
+
- Optional leftover LLM (`FS000`) only when `FAILSTEP_LLM_URL` is set and no error finding exists
|
|
9
|
+
- `compare` counts finding-id and run-field diffs
|
|
10
|
+
- `fix` prints the recommendation as a patch and does not write files
|
|
11
|
+
- Exit codes 0/1/2/3
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
Python 3.11 or newer.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
pip install -e ".[dev]"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`uv sync --extra dev` is optional.
|
|
12
|
+
|
|
13
|
+
## Checks
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
python -m pytest
|
|
17
|
+
python -m ruff check .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Run those before every pull request.
|
|
21
|
+
|
|
22
|
+
## Pull requests
|
|
23
|
+
|
|
24
|
+
- One change. Update goldens in the same PR if output changed.
|
|
25
|
+
- A detector must fire on a fixture, stay silent on `examples/traces/success.json`, and copy evidence from the file.
|
|
26
|
+
- Do not add `confidence`, cost, or health scores.
|
|
27
|
+
- Do not call a real LLM in tests.
|
|
28
|
+
- Unknown trace shape is exit 2, never a silent empty run.
|
|
29
|
+
|
|
30
|
+
Trace contract: `docs/TRACE_FORMAT.md`.
|
|
31
|
+
Report contract: `docs/OUTPUT.md`.
|
|
32
|
+
Test contract: `docs/TESTING.md`.
|
|
33
|
+
|
|
34
|
+
## Release
|
|
35
|
+
|
|
36
|
+
Version lives in `pyproject.toml` and `src/failstep/__init__.py`. Keep them equal. Add a `CHANGELOG.md` entry.
|
|
37
|
+
|
|
38
|
+
GitHub Actions publishes to PyPI on a GitHub Release. That needs a `pypi` environment on the repo and a trusted publisher on PyPI. Do not put a PyPI token in the repository.
|
failstep-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 failstep 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.
|
failstep-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: failstep
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A local CLI that diagnoses why one AI agent run failed.
|
|
5
|
+
Project-URL: Homepage, https://github.com/AbdelazizBs/failstep
|
|
6
|
+
Project-URL: Repository, https://github.com/AbdelazizBs/failstep
|
|
7
|
+
Project-URL: Issues, https://github.com/AbdelazizBs/failstep/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/AbdelazizBs/failstep/blob/master/CHANGELOG.md
|
|
9
|
+
Author: failstep contributors
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 failstep contributors
|
|
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,cli,debug,llm,trace
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Environment :: Console
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
42
|
+
Requires-Python: >=3.11
|
|
43
|
+
Requires-Dist: pydantic>=2.0
|
|
44
|
+
Requires-Dist: rich>=13.0
|
|
45
|
+
Requires-Dist: typer>=0.12
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
48
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
49
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
50
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
51
|
+
Provides-Extra: llm
|
|
52
|
+
Requires-Dist: httpx>=0.27; extra == 'llm'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# failstep
|
|
56
|
+
|
|
57
|
+
A local CLI that diagnoses **why one AI agent run failed**.
|
|
58
|
+
|
|
59
|
+
Not a dashboard. Not an eval suite. Not a coding-agent linter. Not an LLM wrapper.
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
pip install failstep
|
|
63
|
+
failstep diagnose examples/traces/retry-loop.json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
No API key. No network. A root cause, quoted evidence, and what to change.
|
|
67
|
+
|
|
68
|
+
Repo: [github.com/AbdelazizBs/failstep](https://github.com/AbdelazizBs/failstep)
|
|
69
|
+
|
|
70
|
+
[](https://github.com/AbdelazizBs/failstep/actions/workflows/ci.yml)
|
|
71
|
+
|
|
72
|
+
`inspect` prints the run. `diagnose` names the failed step. `compare` counts diffs. `fix` prints the recommendation.
|
|
73
|
+
|
|
74
|
+
## 60 seconds
|
|
75
|
+
|
|
76
|
+
From a clone (Python 3.11+):
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
pip install -e ".[dev]"
|
|
80
|
+
python -m failstep diagnose examples/traces/retry-loop.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
failstep 0.1.0
|
|
85
|
+
file examples/traces/retry-loop.json
|
|
86
|
+
run checkout-agent
|
|
87
|
+
status failed
|
|
88
|
+
duration 14820 ms
|
|
89
|
+
steps 8
|
|
90
|
+
|
|
91
|
+
root cause
|
|
92
|
+
FS004 retry loop
|
|
93
|
+
steps 3-5 search_docs
|
|
94
|
+
|
|
95
|
+
evidence
|
|
96
|
+
identical calls 3
|
|
97
|
+
tool search_docs
|
|
98
|
+
args {"query": "refund policy"}
|
|
99
|
+
outputs unchanged
|
|
100
|
+
|
|
101
|
+
recommendation
|
|
102
|
+
Cap identical tool retries at 1. Return the first error to the model.
|
|
103
|
+
|
|
104
|
+
secondary
|
|
105
|
+
none
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Exit `1` when there is a finding (`--fail-on error`, the default). A clean run exits `0`. Garbage input exits `2`. It never prints healthy.
|
|
109
|
+
|
|
110
|
+
If `failstep` is not on PATH:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
python -m failstep diagnose examples/traces/retry-loop.json
|
|
114
|
+
python -m failstep inspect examples/traces/retry-loop.json
|
|
115
|
+
python -m failstep version
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
failstep inspect TRACE [--format terminal|json|markdown]
|
|
120
|
+
failstep diagnose TRACE [--format terminal|json|markdown] [--fail-on error|warning] [--no-llm] [--no-redact]
|
|
121
|
+
failstep compare OLD NEW [--format terminal|json|markdown]
|
|
122
|
+
failstep fix TRACE [--format terminal|json|markdown]
|
|
123
|
+
failstep version
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Native JSON and JSONL. Also OpenAI `messages` + `tool_calls`, LangChain `intermediate_steps`, and exported OpenTelemetry GenAI JSON (`resourceSpans` or `{spans: [...]}`). Contract: [docs/TRACE_FORMAT.md](docs/TRACE_FORMAT.md).
|
|
127
|
+
How the report must look: [docs/OUTPUT.md](docs/OUTPUT.md).
|
|
128
|
+
|
|
129
|
+
Detectors: FS001 malformed output, FS002 tool schema, FS003 tool failure, FS004 retry loop, FS005 timeout, FS006 empty retrieval, FS007 duplicate chunks, FS008 conflicting sources. Optional leftover (`FS000`) only if `FAILSTEP_LLM_URL` is set, httpx is installed (`pip install failstep[llm]`), and no error finding exists. `--no-llm` skips it. Secrets are redacted before the request.
|
|
130
|
+
|
|
131
|
+
## Tests
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
python -m pytest
|
|
135
|
+
python -m ruff check .
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
If you use uv: `uv sync --extra dev` then `uv run pytest` / `uv run ruff check .`.
|
|
139
|
+
|
|
140
|
+
## Design
|
|
141
|
+
|
|
142
|
+
| Doc | What it is |
|
|
143
|
+
|---|---|
|
|
144
|
+
| [docs/PRODUCT.md](docs/PRODUCT.md) | What we ship, the +, quality bar |
|
|
145
|
+
| [docs/POSITIONING.md](docs/POSITIONING.md) | Exact difference vs lookalikes |
|
|
146
|
+
| [docs/STACK.md](docs/STACK.md) | Free open-source stack |
|
|
147
|
+
| [docs/OUTPUT.md](docs/OUTPUT.md) | How the diagnosis looks (terminal / JSON / markdown) |
|
|
148
|
+
| [docs/TESTING.md](docs/TESTING.md) | How each phase is proven |
|
|
149
|
+
| [docs/PHASES.md](docs/PHASES.md) | Build order. Do not skip. |
|
|
150
|
+
| [docs/TRACE_FORMAT.md](docs/TRACE_FORMAT.md) | Native trace contract |
|
|
151
|
+
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Modules and pipeline |
|
|
152
|
+
| [docs/COMPETITORS.md](docs/COMPETITORS.md) | Market scan |
|
|
153
|
+
| [docs/DECISIONS.md](docs/DECISIONS.md) | Locked decisions |
|
|
154
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Setup, tests, pull requests |
|
|
155
|
+
| [CHANGELOG.md](CHANGELOG.md) | Shipped versions |
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT. See [LICENSE](LICENSE).
|
failstep-0.1.0/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# failstep
|
|
2
|
+
|
|
3
|
+
A local CLI that diagnoses **why one AI agent run failed**.
|
|
4
|
+
|
|
5
|
+
Not a dashboard. Not an eval suite. Not a coding-agent linter. Not an LLM wrapper.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
pip install failstep
|
|
9
|
+
failstep diagnose examples/traces/retry-loop.json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
No API key. No network. A root cause, quoted evidence, and what to change.
|
|
13
|
+
|
|
14
|
+
Repo: [github.com/AbdelazizBs/failstep](https://github.com/AbdelazizBs/failstep)
|
|
15
|
+
|
|
16
|
+
[](https://github.com/AbdelazizBs/failstep/actions/workflows/ci.yml)
|
|
17
|
+
|
|
18
|
+
`inspect` prints the run. `diagnose` names the failed step. `compare` counts diffs. `fix` prints the recommendation.
|
|
19
|
+
|
|
20
|
+
## 60 seconds
|
|
21
|
+
|
|
22
|
+
From a clone (Python 3.11+):
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
pip install -e ".[dev]"
|
|
26
|
+
python -m failstep diagnose examples/traces/retry-loop.json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
failstep 0.1.0
|
|
31
|
+
file examples/traces/retry-loop.json
|
|
32
|
+
run checkout-agent
|
|
33
|
+
status failed
|
|
34
|
+
duration 14820 ms
|
|
35
|
+
steps 8
|
|
36
|
+
|
|
37
|
+
root cause
|
|
38
|
+
FS004 retry loop
|
|
39
|
+
steps 3-5 search_docs
|
|
40
|
+
|
|
41
|
+
evidence
|
|
42
|
+
identical calls 3
|
|
43
|
+
tool search_docs
|
|
44
|
+
args {"query": "refund policy"}
|
|
45
|
+
outputs unchanged
|
|
46
|
+
|
|
47
|
+
recommendation
|
|
48
|
+
Cap identical tool retries at 1. Return the first error to the model.
|
|
49
|
+
|
|
50
|
+
secondary
|
|
51
|
+
none
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Exit `1` when there is a finding (`--fail-on error`, the default). A clean run exits `0`. Garbage input exits `2`. It never prints healthy.
|
|
55
|
+
|
|
56
|
+
If `failstep` is not on PATH:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
python -m failstep diagnose examples/traces/retry-loop.json
|
|
60
|
+
python -m failstep inspect examples/traces/retry-loop.json
|
|
61
|
+
python -m failstep version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
failstep inspect TRACE [--format terminal|json|markdown]
|
|
66
|
+
failstep diagnose TRACE [--format terminal|json|markdown] [--fail-on error|warning] [--no-llm] [--no-redact]
|
|
67
|
+
failstep compare OLD NEW [--format terminal|json|markdown]
|
|
68
|
+
failstep fix TRACE [--format terminal|json|markdown]
|
|
69
|
+
failstep version
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Native JSON and JSONL. Also OpenAI `messages` + `tool_calls`, LangChain `intermediate_steps`, and exported OpenTelemetry GenAI JSON (`resourceSpans` or `{spans: [...]}`). Contract: [docs/TRACE_FORMAT.md](docs/TRACE_FORMAT.md).
|
|
73
|
+
How the report must look: [docs/OUTPUT.md](docs/OUTPUT.md).
|
|
74
|
+
|
|
75
|
+
Detectors: FS001 malformed output, FS002 tool schema, FS003 tool failure, FS004 retry loop, FS005 timeout, FS006 empty retrieval, FS007 duplicate chunks, FS008 conflicting sources. Optional leftover (`FS000`) only if `FAILSTEP_LLM_URL` is set, httpx is installed (`pip install failstep[llm]`), and no error finding exists. `--no-llm` skips it. Secrets are redacted before the request.
|
|
76
|
+
|
|
77
|
+
## Tests
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
python -m pytest
|
|
81
|
+
python -m ruff check .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If you use uv: `uv sync --extra dev` then `uv run pytest` / `uv run ruff check .`.
|
|
85
|
+
|
|
86
|
+
## Design
|
|
87
|
+
|
|
88
|
+
| Doc | What it is |
|
|
89
|
+
|---|---|
|
|
90
|
+
| [docs/PRODUCT.md](docs/PRODUCT.md) | What we ship, the +, quality bar |
|
|
91
|
+
| [docs/POSITIONING.md](docs/POSITIONING.md) | Exact difference vs lookalikes |
|
|
92
|
+
| [docs/STACK.md](docs/STACK.md) | Free open-source stack |
|
|
93
|
+
| [docs/OUTPUT.md](docs/OUTPUT.md) | How the diagnosis looks (terminal / JSON / markdown) |
|
|
94
|
+
| [docs/TESTING.md](docs/TESTING.md) | How each phase is proven |
|
|
95
|
+
| [docs/PHASES.md](docs/PHASES.md) | Build order. Do not skip. |
|
|
96
|
+
| [docs/TRACE_FORMAT.md](docs/TRACE_FORMAT.md) | Native trace contract |
|
|
97
|
+
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Modules and pipeline |
|
|
98
|
+
| [docs/COMPETITORS.md](docs/COMPETITORS.md) | Market scan |
|
|
99
|
+
| [docs/DECISIONS.md](docs/DECISIONS.md) | Locked decisions |
|
|
100
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Setup, tests, pull requests |
|
|
101
|
+
| [CHANGELOG.md](CHANGELOG.md) | Shipped versions |
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
V1 is a local CLI. No server. No database. No UI.
|
|
4
|
+
|
|
5
|
+
Package and command: **failstep**. Python 3.11+, pip-installable, `python -m failstep` as backup.
|
|
6
|
+
|
|
7
|
+
## Pipeline
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
trace.json / trace.jsonl / otel.json
|
|
11
|
+
|
|
|
12
|
+
v
|
|
13
|
+
parser sniff format, reject garbage (exit 2)
|
|
14
|
+
|
|
|
15
|
+
v
|
|
16
|
+
normalize Run + Step (Pydantic)
|
|
17
|
+
|
|
|
18
|
+
v
|
|
19
|
+
detectors FS001-FS008, evidence only
|
|
20
|
+
|
|
|
21
|
+
+-- findings --> report (one root cause + secondary)
|
|
22
|
+
|
|
|
23
|
+
+-- compare two reports, counted diffs only
|
|
24
|
+
+-- fix print the recommendation; never writes files
|
|
25
|
+
|
|
|
26
|
+
+-- no error finding
|
|
27
|
+
|
|
|
28
|
+
v
|
|
29
|
+
optional LLM (Phase 4, if configured)
|
|
30
|
+
|
|
|
31
|
+
v
|
|
32
|
+
report or "Insufficient evidence."
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Layout
|
|
36
|
+
|
|
37
|
+
Phase 8 (shipped). CI, sdist/wheel, changelog, contributing, issue templates.
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
src/failstep/
|
|
41
|
+
__init__.py
|
|
42
|
+
__main__.py
|
|
43
|
+
cli.py
|
|
44
|
+
errors.py
|
|
45
|
+
models.py
|
|
46
|
+
parser.py
|
|
47
|
+
adapters.py
|
|
48
|
+
normalize.py
|
|
49
|
+
evidence.py
|
|
50
|
+
diagnose.py
|
|
51
|
+
compare.py
|
|
52
|
+
report.py
|
|
53
|
+
redact.py
|
|
54
|
+
llm.py
|
|
55
|
+
detectors/
|
|
56
|
+
__init__.py
|
|
57
|
+
malformed.py
|
|
58
|
+
schema.py
|
|
59
|
+
tool_error.py
|
|
60
|
+
retry.py
|
|
61
|
+
timeout.py
|
|
62
|
+
retrieval.py
|
|
63
|
+
|
|
64
|
+
tests/
|
|
65
|
+
examples/traces/
|
|
66
|
+
docs/
|
|
67
|
+
.github/
|
|
68
|
+
pyproject.toml
|
|
69
|
+
README.md
|
|
70
|
+
CONTRIBUTING.md
|
|
71
|
+
CHANGELOG.md
|
|
72
|
+
LICENSE
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
No providers package. No FastAPI.
|
|
76
|
+
|
|
77
|
+
## Internal model
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
Run id, name, status, duration_ms, error, tokens_in/out, steps[]
|
|
81
|
+
Step index, id, type, name, input, output, error, latency_ms, tokens, metadata
|
|
82
|
+
Finding id (FS00x), detector, category, title, severity, step_ids,
|
|
83
|
+
evidence[], recommendation,
|
|
84
|
+
source (deterministic | heuristic | llm)
|
|
85
|
+
Report run, root_cause, secondary[], findings[]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
No confidence field on Finding.
|
|
89
|
+
|
|
90
|
+
Nested OTEL spans flatten to ordered steps. Optional `parent_id` in metadata.
|
|
91
|
+
|
|
92
|
+
## Detector order
|
|
93
|
+
|
|
94
|
+
1. FS001 MalformedOutput
|
|
95
|
+
2. FS002 ToolSchema
|
|
96
|
+
3. FS003 ToolFailure
|
|
97
|
+
4. FS004 RetryLoop
|
|
98
|
+
5. FS005 Timeout
|
|
99
|
+
6. FS006 EmptyRetrieval
|
|
100
|
+
7. FS007 DuplicateChunks
|
|
101
|
+
8. FS008 ConflictingSources
|
|
102
|
+
|
|
103
|
+
Root cause = highest severity (`error` then `warning`), then this order, then first step index.
|
|
104
|
+
|
|
105
|
+
FS005 thresholds: step `latency_ms >= 15000` (error), run `duration_ms >= 30000` (error), one step `>= 80%` of run and `>= 5000ms` (warning).
|
|
106
|
+
|
|
107
|
+
## Output
|
|
108
|
+
|
|
109
|
+
Contract: `docs/OUTPUT.md`. Tests freeze it (`docs/TESTING.md`).
|
|
110
|
+
|
|
111
|
+
Terminal is the product. JSON is CI. Markdown is for GitHub comments.
|
|
112
|
+
|
|
113
|
+
ASCII-safe. No required emoji. No confidence field. One root cause, then secondary.
|
|
114
|
+
|
|
115
|
+
## Security
|
|
116
|
+
|
|
117
|
+
Traces are untrusted. Redact secrets before any LLM call. Default path never uploads. `--no-redact` warns.
|