dreadnode 1.14.0__tar.gz → 1.15.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.
- {dreadnode-1.14.0 → dreadnode-1.15.0}/PKG-INFO +6 -5
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/__init__.py +7 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/__init__.py +3 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/agent.py +72 -5
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/events.py +3 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/hooks/__init__.py +3 -0
- dreadnode-1.15.0/dreadnode/agent/hooks/backoff.py +134 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/reactions.py +1 -1
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/tools/__init__.py +10 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/tools/base.py +4 -0
- dreadnode-1.15.0/dreadnode/airt/__init__.py +29 -0
- dreadnode-1.15.0/dreadnode/airt/attack/__init__.py +19 -0
- dreadnode-1.15.0/dreadnode/airt/attack/hop_skip_jump.py +89 -0
- dreadnode-1.15.0/dreadnode/airt/attack/nes.py +86 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/attack/prompt.py +3 -3
- dreadnode-1.15.0/dreadnode/airt/attack/simba.py +78 -0
- dreadnode-1.15.0/dreadnode/airt/attack/zoo.py +84 -0
- dreadnode-1.15.0/dreadnode/airt/search/__init__.py +6 -0
- dreadnode-1.15.0/dreadnode/airt/search/hop_skip_jump.py +242 -0
- dreadnode-1.15.0/dreadnode/airt/search/image_utils.py +96 -0
- dreadnode-1.15.0/dreadnode/airt/search/nes.py +173 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/search/simba.py +30 -9
- dreadnode-1.15.0/dreadnode/airt/search/zoo.py +313 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/target/llm.py +1 -1
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/api/client.py +5 -23
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/agent/cli.py +25 -14
- dreadnode-1.15.0/dreadnode/cli/attack/__init__.py +3 -0
- dreadnode-1.15.0/dreadnode/cli/attack/cli.py +164 -0
- dreadnode-1.15.0/dreadnode/cli/docker.py +387 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/eval/cli.py +25 -21
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/github.py +23 -31
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/main.py +93 -44
- dreadnode-1.15.0/dreadnode/cli/platform/cli.py +291 -0
- dreadnode-1.15.0/dreadnode/cli/platform/compose.py +212 -0
- dreadnode-1.15.0/dreadnode/cli/platform/constants.py +16 -0
- dreadnode-1.15.0/dreadnode/cli/platform/download.py +95 -0
- {dreadnode-1.14.0/dreadnode/cli/platform/utils → dreadnode-1.15.0/dreadnode/cli/platform}/env_mgmt.py +13 -10
- dreadnode-1.15.0/dreadnode/cli/platform/tag.py +40 -0
- dreadnode-1.15.0/dreadnode/cli/platform/version.py +216 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/profile/cli.py +16 -14
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/shared.py +6 -3
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/study/cli.py +32 -28
- dreadnode-1.15.0/dreadnode/cli/task/__init__.py +3 -0
- dreadnode-1.15.0/dreadnode/cli/task/cli.py +164 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/image.py +17 -1
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/discovery.py +21 -7
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/eval/console.py +6 -7
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/eval/dataset.py +1 -1
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/eval/eval.py +156 -42
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/eval/events.py +1 -3
- dreadnode-1.15.0/dreadnode/eval/format.py +338 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/eval/result.py +49 -11
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/eval/sample.py +6 -2
- dreadnode-1.15.0/dreadnode/format.py +60 -0
- dreadnode-1.15.0/dreadnode/logging_.py +80 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/main.py +26 -6
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/meta/config.py +63 -13
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/meta/context.py +14 -9
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/meta/hydrate.py +14 -8
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/meta/introspect.py +153 -51
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/console.py +129 -126
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/events.py +1 -5
- dreadnode-1.15.0/dreadnode/optimization/format.py +157 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/result.py +17 -7
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/sampling.py +128 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/search/boundary.py +34 -17
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/search/graph.py +16 -4
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/search/optuna_.py +8 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/search/random.py +39 -11
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/stop.py +2 -16
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/study.py +238 -80
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/trial.py +66 -8
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/base.py +8 -7
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/image.py +8 -7
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/json.py +4 -2
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/similarity.py +2 -2
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/task.py +122 -93
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/tracing/span.py +6 -1
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/image.py +3 -3
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/user_config.py +2 -2
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/util.py +127 -64
- dreadnode-1.15.0/examples/airt/beam_search.ipynb +57 -0
- dreadnode-1.15.0/examples/airt/graph_of_attacks_with_pruning.ipynb +179 -0
- dreadnode-1.15.0/examples/airt/tap_vs_goat_eval.ipynb +2303 -0
- dreadnode-1.15.0/examples/airt/tree_of_attacks_with_pruning.ipynb +181 -0
- dreadnode-1.15.0/examples/data_export.ipynb +133 -0
- dreadnode-1.15.0/examples/log_artifact.ipynb +182 -0
- dreadnode-1.15.0/examples/log_object/audio.ipynb +191 -0
- dreadnode-1.15.0/examples/log_object/image.ipynb +290 -0
- dreadnode-1.15.0/examples/log_object/object3d.ipynb +109 -0
- dreadnode-1.15.0/examples/log_object/table.ipynb +157 -0
- dreadnode-1.15.0/examples/log_object/video.ipynb +242 -0
- dreadnode-1.15.0/examples/model_training.ipynb +118 -0
- dreadnode-1.15.0/examples/rigging.ipynb +95 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/pyproject.toml +9 -13
- dreadnode-1.15.0/tests/cli/test_config.py +79 -0
- dreadnode-1.15.0/tests/cli/test_docker.py +161 -0
- dreadnode-1.15.0/tests/cli/test_github.py +201 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/tests/test_meta.py +31 -3
- dreadnode-1.14.0/dreadnode/airt/__init__.py +0 -18
- dreadnode-1.14.0/dreadnode/airt/attack/__init__.py +0 -6
- dreadnode-1.14.0/dreadnode/airt/search/__init__.py +0 -4
- dreadnode-1.14.0/dreadnode/airt/search/hop_skip_jump.py +0 -195
- dreadnode-1.14.0/dreadnode/airt/search/image_utils.py +0 -46
- dreadnode-1.14.0/dreadnode/cli/platform/cli.py +0 -164
- dreadnode-1.14.0/dreadnode/cli/platform/configure.py +0 -47
- dreadnode-1.14.0/dreadnode/cli/platform/constants.py +0 -12
- dreadnode-1.14.0/dreadnode/cli/platform/docker_.py +0 -463
- dreadnode-1.14.0/dreadnode/cli/platform/download.py +0 -144
- dreadnode-1.14.0/dreadnode/cli/platform/login.py +0 -20
- dreadnode-1.14.0/dreadnode/cli/platform/schemas.py +0 -117
- dreadnode-1.14.0/dreadnode/cli/platform/start.py +0 -71
- dreadnode-1.14.0/dreadnode/cli/platform/status.py +0 -51
- dreadnode-1.14.0/dreadnode/cli/platform/stop.py +0 -21
- dreadnode-1.14.0/dreadnode/cli/platform/upgrade.py +0 -64
- dreadnode-1.14.0/dreadnode/cli/platform/utils/printing.py +0 -43
- dreadnode-1.14.0/dreadnode/cli/platform/utils/versions.py +0 -184
- dreadnode-1.14.0/dreadnode/eval/format.py +0 -118
- dreadnode-1.14.0/dreadnode/logging_.py +0 -69
- dreadnode-1.14.0/dreadnode/optimization/format.py +0 -83
- dreadnode-1.14.0/dreadnode/tracing/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/.gitignore +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/LICENSE +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/README.md +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/__main__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/error.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/format.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/hooks/base.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/hooks/summarize.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/prompts/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/prompts/summarize.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/result.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/stop.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/thread.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/tools/fs.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/tools/planning.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/tools/reporting.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/agent/tools/tasking.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/attack/base.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/attack/goat.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/attack/tap.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/target/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/target/base.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/airt/target/custom.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/api/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/api/models.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/api/util.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/artifact/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/artifact/credential_manager.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/artifact/merger.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/artifact/storage.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/artifact/tree_builder.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/agent/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/api.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/eval/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/platform/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/profile/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/cli/study/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/common_types.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/constants.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/convert.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/audio.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/base.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/object_3d.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/table.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/text.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/data_types/video.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/error.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/eval/__init__.py +0 -0
- {dreadnode-1.14.0/dreadnode/cli/platform/utils → dreadnode-1.15.0/dreadnode/integrations}/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/integrations/transformers.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/meta/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/metric.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/object.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/collectors.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/search/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/optimization/search/base.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/py.typed +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/classification.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/consistency.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/contains.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/crucible.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/format.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/harm.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/judge.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/length.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/lexical.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/pii.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/readability.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/rigging.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/sentiment.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/scorers/util.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/serialization.py +0 -0
- {dreadnode-1.14.0/dreadnode/integrations → dreadnode-1.15.0/dreadnode/tracing}/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/tracing/constants.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/tracing/exporters.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/__init__.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/base.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/cipher.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/encoding.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/perturbation.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/refine.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/stylistic.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/substitution.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/swap.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/transforms/text.py +0 -0
- {dreadnode-1.14.0 → dreadnode-1.15.0}/dreadnode/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dreadnode
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.15.0
|
|
4
4
|
Summary: Dreadnode SDK
|
|
5
5
|
Project-URL: Homepage, https://github.com/dreadnode/sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/dreadnode/sdk
|
|
@@ -213,16 +213,17 @@ Requires-Dist: coolname<3.0.0,>=2.2.0
|
|
|
213
213
|
Requires-Dist: cyclopts<4.0.0,>=3.22.2
|
|
214
214
|
Requires-Dist: fsspec[s3]<=2025.3.0,>=2023.1.0
|
|
215
215
|
Requires-Dist: httpx<1.0.0,>=0.28.0
|
|
216
|
-
Requires-Dist: jsonpath>=0.82.2
|
|
217
216
|
Requires-Dist: logfire<=3.20.0,>=3.5.3
|
|
218
217
|
Requires-Dist: loguru>=0.7.3
|
|
219
218
|
Requires-Dist: numpy<=2.2.6
|
|
220
219
|
Requires-Dist: optuna<5.0.0,>=4.5.0
|
|
221
220
|
Requires-Dist: pandas<3.0.0,>=2.2.3
|
|
222
221
|
Requires-Dist: pydantic<3.0.0,>=2.9.2
|
|
222
|
+
Requires-Dist: python-jsonpath>=2.0.1
|
|
223
223
|
Requires-Dist: python-ulid<4.0.0,>=3.0.0
|
|
224
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
224
225
|
Requires-Dist: rigging<4.0.0,>=3.2.1
|
|
225
|
-
Requires-Dist: universal-pathlib<0.
|
|
226
|
+
Requires-Dist: universal-pathlib<0.4.0,>=0.3.3
|
|
226
227
|
Provides-Extra: all
|
|
227
228
|
Requires-Dist: confusables<2.0.0,>=1.2.0; extra == 'all'
|
|
228
229
|
Requires-Dist: datasets<5.0.0,>=4.0.0; extra == 'all'
|
|
@@ -230,7 +231,7 @@ Requires-Dist: moviepy<3.0.0,>=2.1.2; extra == 'all'
|
|
|
230
231
|
Requires-Dist: nltk<4.0.0,>=3.9.1; extra == 'all'
|
|
231
232
|
Requires-Dist: pillow<12.0.0,>=11.2.1; extra == 'all'
|
|
232
233
|
Requires-Dist: presidio-analyzer<3.0.0,>=2.2.359; extra == 'all'
|
|
233
|
-
Requires-Dist: pyarrow<
|
|
234
|
+
Requires-Dist: pyarrow<22.1.0,>=22.0.0; extra == 'all'
|
|
234
235
|
Requires-Dist: rapidfuzz>=3.14.1; extra == 'all'
|
|
235
236
|
Requires-Dist: scikit-learn<2.0.0,>=1.7.1; extra == 'all'
|
|
236
237
|
Requires-Dist: sentence-transformers<6.0.0,>=5.1.0; extra == 'all'
|
|
@@ -253,7 +254,7 @@ Requires-Dist: textblob<1.0.0,>=0.19.0; extra == 'scoring'
|
|
|
253
254
|
Requires-Dist: textstat<1.0.0,>=0.7.10; extra == 'scoring'
|
|
254
255
|
Provides-Extra: training
|
|
255
256
|
Requires-Dist: datasets<5.0.0,>=4.0.0; extra == 'training'
|
|
256
|
-
Requires-Dist: pyarrow<
|
|
257
|
+
Requires-Dist: pyarrow<22.1.0,>=22.0.0; extra == 'training'
|
|
257
258
|
Requires-Dist: transformers<5.0.0,>=4.41.0; extra == 'training'
|
|
258
259
|
Provides-Extra: transforms
|
|
259
260
|
Requires-Dist: art<7.0.0,>=6.5; extra == 'transforms'
|
|
@@ -37,6 +37,7 @@ from dreadnode.version import VERSION
|
|
|
37
37
|
|
|
38
38
|
if t.TYPE_CHECKING:
|
|
39
39
|
from dreadnode import agent, airt, eval, optimization, scorers, transforms # noqa: A004
|
|
40
|
+
from dreadnode.agent import Agent, tool, tool_method
|
|
40
41
|
from dreadnode.data_types import Audio, Image, Table, Video
|
|
41
42
|
|
|
42
43
|
logger.disable("dreadnode")
|
|
@@ -75,6 +76,7 @@ __version__ = VERSION
|
|
|
75
76
|
|
|
76
77
|
__all__ = [
|
|
77
78
|
"DEFAULT_INSTANCE",
|
|
79
|
+
"Agent",
|
|
78
80
|
"Audio",
|
|
79
81
|
"Code",
|
|
80
82
|
"Config",
|
|
@@ -138,6 +140,8 @@ __all__ = [
|
|
|
138
140
|
"task",
|
|
139
141
|
"task_and_run",
|
|
140
142
|
"task_span",
|
|
143
|
+
"tool",
|
|
144
|
+
"tool_method",
|
|
141
145
|
"transforms",
|
|
142
146
|
]
|
|
143
147
|
|
|
@@ -147,6 +151,9 @@ __lazy_components__: dict[str, str] = {
|
|
|
147
151
|
"Image": "dreadnode.data_types",
|
|
148
152
|
"Table": "dreadnode.data_types",
|
|
149
153
|
"Video": "dreadnode.data_types",
|
|
154
|
+
"Agent": "dreadnode.agent",
|
|
155
|
+
"tool": "dreadnode.agent",
|
|
156
|
+
"tool_method": "dreadnode.agent",
|
|
150
157
|
}
|
|
151
158
|
|
|
152
159
|
|
|
@@ -4,6 +4,7 @@ from dreadnode.agent import error, events, hooks, reactions, result, stop, tools
|
|
|
4
4
|
from dreadnode.agent.agent import Agent
|
|
5
5
|
from dreadnode.agent.result import AgentResult
|
|
6
6
|
from dreadnode.agent.thread import Thread
|
|
7
|
+
from dreadnode.agent.tools import tool, tool_method
|
|
7
8
|
|
|
8
9
|
Agent.model_rebuild()
|
|
9
10
|
Thread.model_rebuild()
|
|
@@ -20,5 +21,7 @@ __all__ = [
|
|
|
20
21
|
"reactions",
|
|
21
22
|
"result",
|
|
22
23
|
"stop",
|
|
24
|
+
"tool",
|
|
25
|
+
"tool_method",
|
|
23
26
|
"tools",
|
|
24
27
|
]
|
|
@@ -4,8 +4,10 @@ from contextlib import aclosing, asynccontextmanager
|
|
|
4
4
|
from copy import deepcopy
|
|
5
5
|
|
|
6
6
|
import rigging as rg
|
|
7
|
-
from
|
|
8
|
-
from
|
|
7
|
+
from loguru import logger
|
|
8
|
+
from pydantic import ConfigDict, Field, PrivateAttr, SkipValidation, field_validator
|
|
9
|
+
from rigging.message import inject_system_content
|
|
10
|
+
from ulid import ULID # can't access via rg
|
|
9
11
|
|
|
10
12
|
from dreadnode.agent.error import MaxStepsError
|
|
11
13
|
from dreadnode.agent.events import (
|
|
@@ -83,7 +85,7 @@ class Agent(Model):
|
|
|
83
85
|
caching: rg.caching.CacheMode | None = Config(default=None, repr=False)
|
|
84
86
|
"""How to handle cache_control entries on inference messages."""
|
|
85
87
|
|
|
86
|
-
tools: list[AnyTool | Toolset] = Config(default_factory=list)
|
|
88
|
+
tools: t.Annotated[list[AnyTool | Toolset], SkipValidation] = Config(default_factory=list)
|
|
87
89
|
"""Tools the agent can use."""
|
|
88
90
|
tool_mode: ToolMode = Config(default="auto", repr=False)
|
|
89
91
|
"""The tool calling mode to use."""
|
|
@@ -236,6 +238,8 @@ class Agent(Model):
|
|
|
236
238
|
try:
|
|
237
239
|
messages = rg.caching.apply_cache_mode_to_messages(self.caching, [messages])[0]
|
|
238
240
|
|
|
241
|
+
logger.trace(f"Generating with model '{generator.model}'. Messages: {messages!r}")
|
|
242
|
+
|
|
239
243
|
generated = (await generator.generate_messages([messages], [params]))[0]
|
|
240
244
|
if isinstance(generated, BaseException):
|
|
241
245
|
raise generated # noqa: TRY301
|
|
@@ -251,6 +255,7 @@ class Agent(Model):
|
|
|
251
255
|
)
|
|
252
256
|
|
|
253
257
|
except Exception as error: # noqa: BLE001
|
|
258
|
+
logger.error(f"Error during generation: {error}", exc_info=True)
|
|
254
259
|
chat = rg.Chat(
|
|
255
260
|
messages,
|
|
256
261
|
[],
|
|
@@ -275,6 +280,14 @@ class Agent(Model):
|
|
|
275
280
|
) -> t.AsyncGenerator[AgentEvent, None]:
|
|
276
281
|
events: list[AgentEvent] = []
|
|
277
282
|
stop_conditions = self.stop_conditions
|
|
283
|
+
session_id = ULID()
|
|
284
|
+
|
|
285
|
+
logger.info(
|
|
286
|
+
f"Starting Agent '{self.name}' ({session_id}): "
|
|
287
|
+
f"model='{self.model}', "
|
|
288
|
+
f"max_steps={self.max_steps}, "
|
|
289
|
+
f"tools={[tool.name for tool in self.all_tools]}"
|
|
290
|
+
)
|
|
278
291
|
|
|
279
292
|
# Event dispatcher
|
|
280
293
|
|
|
@@ -290,6 +303,11 @@ class Agent(Model):
|
|
|
290
303
|
if not applicable_hooks:
|
|
291
304
|
return
|
|
292
305
|
|
|
306
|
+
logger.debug(
|
|
307
|
+
f"Agent '{self.name}' ({session_id}) dispatching '{type(event).__name__}': "
|
|
308
|
+
f"applicable_hooks={[get_callable_name(h, short=True) for h in applicable_hooks]}"
|
|
309
|
+
)
|
|
310
|
+
|
|
293
311
|
# Run all applicable hooks and collect their reactions
|
|
294
312
|
hook_reactions: dict[str, Reaction | None] = {}
|
|
295
313
|
for hook in applicable_hooks:
|
|
@@ -308,6 +326,10 @@ class Agent(Model):
|
|
|
308
326
|
if reaction is None:
|
|
309
327
|
continue
|
|
310
328
|
|
|
329
|
+
logger.debug(
|
|
330
|
+
f"Agent '{self.name}' ({session_id}) hook '{hook_name}' returned reaction: {reaction!r}"
|
|
331
|
+
)
|
|
332
|
+
|
|
311
333
|
if not isinstance(reaction, Reaction):
|
|
312
334
|
warn_at_user_stacklevel(
|
|
313
335
|
f"Hook '{hook_name}' returned {reaction}, but expected a Reaction.",
|
|
@@ -368,6 +390,7 @@ class Agent(Model):
|
|
|
368
390
|
"unknown",
|
|
369
391
|
)
|
|
370
392
|
reacted_event = Reacted(
|
|
393
|
+
session_id=session_id,
|
|
371
394
|
agent=self,
|
|
372
395
|
thread=thread,
|
|
373
396
|
messages=messages,
|
|
@@ -383,6 +406,9 @@ class Agent(Model):
|
|
|
383
406
|
return
|
|
384
407
|
|
|
385
408
|
if isinstance(winning_reaction, RetryWithFeedback):
|
|
409
|
+
logger.debug(
|
|
410
|
+
f"Agent '{self.name}' ({session_id}) injecting feedback for retry: '{winning_reaction.feedback}'"
|
|
411
|
+
)
|
|
386
412
|
messages.append(rg.Message("user", winning_reaction.feedback))
|
|
387
413
|
raise Retry(messages=messages) from winning_reaction
|
|
388
414
|
|
|
@@ -395,6 +421,7 @@ class Agent(Model):
|
|
|
395
421
|
) -> t.AsyncGenerator[AgentEvent, None]:
|
|
396
422
|
async for event in _dispatch(
|
|
397
423
|
ToolStart(
|
|
424
|
+
session_id=session_id,
|
|
398
425
|
agent=self,
|
|
399
426
|
thread=thread,
|
|
400
427
|
messages=messages,
|
|
@@ -404,6 +431,10 @@ class Agent(Model):
|
|
|
404
431
|
):
|
|
405
432
|
yield event
|
|
406
433
|
|
|
434
|
+
logger.debug(
|
|
435
|
+
f"Executing tool '{tool_call.name}' with args: {tool_call.function.arguments}"
|
|
436
|
+
)
|
|
437
|
+
|
|
407
438
|
message: rg.Message
|
|
408
439
|
stop = False
|
|
409
440
|
tool = next((t for t in self.all_tools if t.name == tool_call.name), None)
|
|
@@ -416,6 +447,7 @@ class Agent(Model):
|
|
|
416
447
|
except Exception as e:
|
|
417
448
|
async for event in _dispatch(
|
|
418
449
|
AgentError(
|
|
450
|
+
session_id=session_id,
|
|
419
451
|
agent=self,
|
|
420
452
|
thread=thread,
|
|
421
453
|
messages=messages,
|
|
@@ -426,12 +458,14 @@ class Agent(Model):
|
|
|
426
458
|
yield event
|
|
427
459
|
raise
|
|
428
460
|
else:
|
|
461
|
+
logger.warning(f"Tool '{tool_call.name}' not found.")
|
|
429
462
|
message = rg.Message.from_model(
|
|
430
463
|
rg.model.SystemErrorModel(content=f"Tool '{tool_call.name}' not found.")
|
|
431
464
|
)
|
|
432
465
|
|
|
433
466
|
async for event in _dispatch(
|
|
434
467
|
ToolEnd(
|
|
468
|
+
session_id=session_id,
|
|
435
469
|
agent=self,
|
|
436
470
|
thread=thread,
|
|
437
471
|
messages=messages,
|
|
@@ -447,6 +481,7 @@ class Agent(Model):
|
|
|
447
481
|
|
|
448
482
|
async for event in _dispatch(
|
|
449
483
|
AgentStart(
|
|
484
|
+
session_id=session_id,
|
|
450
485
|
agent=self,
|
|
451
486
|
thread=thread,
|
|
452
487
|
messages=messages,
|
|
@@ -464,6 +499,7 @@ class Agent(Model):
|
|
|
464
499
|
try:
|
|
465
500
|
async for event in _dispatch(
|
|
466
501
|
StepStart(
|
|
502
|
+
session_id=session_id,
|
|
467
503
|
agent=self,
|
|
468
504
|
thread=thread,
|
|
469
505
|
messages=messages,
|
|
@@ -479,6 +515,7 @@ class Agent(Model):
|
|
|
479
515
|
if step_chat.failed and step_chat.error:
|
|
480
516
|
async for event in _dispatch(
|
|
481
517
|
AgentError(
|
|
518
|
+
session_id=session_id,
|
|
482
519
|
agent=self,
|
|
483
520
|
thread=thread,
|
|
484
521
|
messages=messages,
|
|
@@ -493,6 +530,7 @@ class Agent(Model):
|
|
|
493
530
|
|
|
494
531
|
async for event in _dispatch(
|
|
495
532
|
GenerationEnd(
|
|
533
|
+
session_id=session_id,
|
|
496
534
|
agent=self,
|
|
497
535
|
thread=thread,
|
|
498
536
|
messages=messages,
|
|
@@ -506,6 +544,7 @@ class Agent(Model):
|
|
|
506
544
|
# Check for stop conditions
|
|
507
545
|
|
|
508
546
|
if any(cond(events) for cond in stop_conditions):
|
|
547
|
+
logger.info("A stop condition was met. Ending run.")
|
|
509
548
|
break
|
|
510
549
|
|
|
511
550
|
# Check if stalled
|
|
@@ -514,8 +553,13 @@ class Agent(Model):
|
|
|
514
553
|
if not stop_conditions:
|
|
515
554
|
break
|
|
516
555
|
|
|
556
|
+
logger.warning(
|
|
557
|
+
f"Agent '{self.name}' ({session_id}) stalled: No tool calls and no stop conditions met."
|
|
558
|
+
)
|
|
559
|
+
|
|
517
560
|
async for event in _dispatch(
|
|
518
561
|
AgentStalled(
|
|
562
|
+
session_id=session_id,
|
|
519
563
|
agent=self,
|
|
520
564
|
thread=thread,
|
|
521
565
|
messages=messages,
|
|
@@ -578,7 +622,25 @@ class Agent(Model):
|
|
|
578
622
|
thread.messages = messages
|
|
579
623
|
thread.events.extend(events)
|
|
580
624
|
|
|
625
|
+
total_usage = _total_usage_from_events(events)
|
|
626
|
+
log_message = (
|
|
627
|
+
f"Agent '{self.name}' finished: "
|
|
628
|
+
f"reason='{stop_reason}', "
|
|
629
|
+
f"steps={step - 1}, "
|
|
630
|
+
f"total_tokens={total_usage.total_tokens}, "
|
|
631
|
+
f"in_tokens={total_usage.input_tokens}, "
|
|
632
|
+
f"out_tokens={total_usage.output_tokens}"
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
if stop_reason == "finished":
|
|
636
|
+
logger.success(log_message)
|
|
637
|
+
elif stop_reason == "error":
|
|
638
|
+
logger.error(f"{log_message}, error='{error!r}'")
|
|
639
|
+
else:
|
|
640
|
+
logger.warning(log_message)
|
|
641
|
+
|
|
581
642
|
yield AgentEnd(
|
|
643
|
+
session_id=session_id,
|
|
582
644
|
agent=self,
|
|
583
645
|
thread=thread,
|
|
584
646
|
messages=messages,
|
|
@@ -646,9 +708,10 @@ class Agent(Model):
|
|
|
646
708
|
"user_input": user_input,
|
|
647
709
|
"messages": messages,
|
|
648
710
|
"instructions": self.instructions,
|
|
649
|
-
"tools": [t.name for t in self.all_tools],
|
|
650
711
|
"hooks": [get_callable_name(hook, short=True) for hook in self.hooks],
|
|
651
712
|
"stop_conditions": [s.name for s in self.stop_conditions],
|
|
713
|
+
"tools": [t.name for t in self.all_tools],
|
|
714
|
+
"tool_schemas": [t.api_definition for t in self.all_tools],
|
|
652
715
|
}
|
|
653
716
|
)
|
|
654
717
|
trace_params.update(
|
|
@@ -669,13 +732,17 @@ class Agent(Model):
|
|
|
669
732
|
yield event
|
|
670
733
|
finally:
|
|
671
734
|
if last_event is not None:
|
|
672
|
-
|
|
735
|
+
# TODO(nick): Don't love having to inject here, but it's the most accurate in
|
|
736
|
+
# in terms of ensuring we don't miss the system component of messages
|
|
737
|
+
final_messages = inject_system_content(last_event.messages, self.get_prompt())
|
|
738
|
+
log_outputs(messages=final_messages, token_usage=last_event.total_usage)
|
|
673
739
|
|
|
674
740
|
if isinstance(last_event, AgentEnd):
|
|
675
741
|
log_outputs(
|
|
676
742
|
to="both",
|
|
677
743
|
steps_taken=min(0, last_event.result.steps - 1),
|
|
678
744
|
reason=last_event.stop_reason,
|
|
745
|
+
failed=last_event.result.failed,
|
|
679
746
|
)
|
|
680
747
|
if last_event.result.error:
|
|
681
748
|
log_output("error", last_event.result.error, to="both")
|
|
@@ -9,6 +9,7 @@ from rich.panel import Panel
|
|
|
9
9
|
from rich.rule import Rule
|
|
10
10
|
from rich.table import Table
|
|
11
11
|
from rich.text import Text
|
|
12
|
+
from ulid import ULID
|
|
12
13
|
|
|
13
14
|
from dreadnode.agent.format import format_message
|
|
14
15
|
from dreadnode.agent.reactions import (
|
|
@@ -39,6 +40,8 @@ class AgentEvent:
|
|
|
39
40
|
)
|
|
40
41
|
"""The timestamp of when the event occurred (UTC)."""
|
|
41
42
|
|
|
43
|
+
session_id: ULID = field(repr=False)
|
|
44
|
+
"""The unique identifier for the agent run session."""
|
|
42
45
|
agent: "Agent" = field(repr=False)
|
|
43
46
|
"""The agent associated with this event."""
|
|
44
47
|
thread: "Thread" = field(repr=False)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from dreadnode.agent.hooks.backoff import backoff_on_error, backoff_on_ratelimit
|
|
1
2
|
from dreadnode.agent.hooks.base import (
|
|
2
3
|
Hook,
|
|
3
4
|
retry_with_feedback,
|
|
@@ -6,6 +7,8 @@ from dreadnode.agent.hooks.summarize import summarize_when_long
|
|
|
6
7
|
|
|
7
8
|
__all__ = [
|
|
8
9
|
"Hook",
|
|
10
|
+
"backoff_on_error",
|
|
11
|
+
"backoff_on_ratelimit",
|
|
9
12
|
"retry_with_feedback",
|
|
10
13
|
"summarize_when_long",
|
|
11
14
|
]
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import random
|
|
3
|
+
import time
|
|
4
|
+
import typing as t
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from loguru import logger
|
|
8
|
+
|
|
9
|
+
from dreadnode.agent.events import AgentError, AgentEvent, StepStart
|
|
10
|
+
from dreadnode.agent.reactions import Reaction, Retry
|
|
11
|
+
|
|
12
|
+
if t.TYPE_CHECKING:
|
|
13
|
+
from ulid import ULID
|
|
14
|
+
|
|
15
|
+
from dreadnode.agent.hooks.base import Hook
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class BackoffState:
|
|
20
|
+
tries: int = 0
|
|
21
|
+
start_time: float | None = None
|
|
22
|
+
last_step_seen: int = -1
|
|
23
|
+
|
|
24
|
+
def reset(self, step: int = -1) -> None:
|
|
25
|
+
self.tries = 0
|
|
26
|
+
self.start_time = None
|
|
27
|
+
self.last_step_seen = step
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def backoff_on_error(
|
|
31
|
+
exception_types: type[Exception] | t.Iterable[type[Exception]],
|
|
32
|
+
*,
|
|
33
|
+
max_tries: int = 8,
|
|
34
|
+
max_time: float = 300.0,
|
|
35
|
+
base_factor: float = 1.0,
|
|
36
|
+
jitter: bool = True,
|
|
37
|
+
) -> "Hook":
|
|
38
|
+
"""
|
|
39
|
+
Creates a hook that retries with exponential backoff when specific errors occur.
|
|
40
|
+
|
|
41
|
+
It listens for `AgentError` events and, if the error matches, waits for an
|
|
42
|
+
exponentially increasing duration before issuing a `Retry` reaction.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
exception_types: An exception type or iterable of types to catch.
|
|
46
|
+
max_tries: The maximum number of retries before giving up.
|
|
47
|
+
max_time: The maximum total time in seconds to wait before giving up.
|
|
48
|
+
base_factor: The base duration (in seconds) for the backoff calculation.
|
|
49
|
+
jitter: If True, adds a random jitter to the wait time to prevent synchronized retries.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
An agent hook that implements the backoff logic.
|
|
53
|
+
"""
|
|
54
|
+
exceptions = (
|
|
55
|
+
tuple(exception_types) if isinstance(exception_types, t.Iterable) else (exception_types,)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
session_states: dict[ULID, BackoffState] = {}
|
|
59
|
+
|
|
60
|
+
async def backoff_hook(event: "AgentEvent") -> "Reaction | None":
|
|
61
|
+
state = session_states.setdefault(event.session_id, BackoffState())
|
|
62
|
+
|
|
63
|
+
if isinstance(event, StepStart):
|
|
64
|
+
if event.step > state.last_step_seen:
|
|
65
|
+
state.reset(event.step)
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
if not isinstance(event, AgentError) or not isinstance(event.error, exceptions):
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
if state.start_time is None:
|
|
72
|
+
state.start_time = time.monotonic()
|
|
73
|
+
|
|
74
|
+
if state.tries >= max_tries:
|
|
75
|
+
logger.warning(
|
|
76
|
+
f"Backoff aborted for session {event.session_id}: maximum tries ({max_tries}) exceeded."
|
|
77
|
+
)
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
if (time.monotonic() - state.start_time) >= max_time:
|
|
81
|
+
logger.warning(
|
|
82
|
+
f"Backoff aborted for session {event.session_id}: maximum time ({max_time:.2f}s) exceeded."
|
|
83
|
+
)
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
state.tries += 1
|
|
87
|
+
|
|
88
|
+
seconds = base_factor * (2 ** (state.tries - 1))
|
|
89
|
+
if jitter:
|
|
90
|
+
seconds += random.uniform(0, base_factor) # noqa: S311 # nosec
|
|
91
|
+
|
|
92
|
+
logger.warning(
|
|
93
|
+
f"Backing off for {seconds:.2f}s (try {state.tries}/{max_tries}) on session {event.session_id} due to error: {event.error}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
await asyncio.sleep(seconds)
|
|
97
|
+
return Retry()
|
|
98
|
+
|
|
99
|
+
return backoff_hook
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def backoff_on_ratelimit(
|
|
103
|
+
*,
|
|
104
|
+
max_tries: int = 8,
|
|
105
|
+
max_time: float = 300.0,
|
|
106
|
+
base_factor: float = 1.0,
|
|
107
|
+
jitter: bool = True,
|
|
108
|
+
) -> "Hook":
|
|
109
|
+
"""
|
|
110
|
+
A convenient default backoff hook for common, ephemeral LLM errors.
|
|
111
|
+
|
|
112
|
+
This hook retries on `litellm.exceptions.RateLimitError` and `litellm.exceptions.APIError`
|
|
113
|
+
with an exponential backoff strategy for up to 5 minutes.
|
|
114
|
+
|
|
115
|
+
See `backoff_on_error` for more details.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
max_tries: The maximum number of retries before giving up.
|
|
119
|
+
max_time: The maximum total time in seconds to wait before giving up.
|
|
120
|
+
base_factor: The base duration (in seconds) for the backoff calculation.
|
|
121
|
+
jitter: If True, adds a random jitter to the wait time to prevent synchronized retries.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
An agent hook that implements the backoff logic.
|
|
125
|
+
"""
|
|
126
|
+
import litellm.exceptions
|
|
127
|
+
|
|
128
|
+
return backoff_on_error(
|
|
129
|
+
(litellm.exceptions.RateLimitError, litellm.exceptions.APIError),
|
|
130
|
+
max_time=max_time,
|
|
131
|
+
max_tries=max_tries,
|
|
132
|
+
base_factor=base_factor,
|
|
133
|
+
jitter=jitter,
|
|
134
|
+
)
|
|
@@ -3,7 +3,12 @@ import typing as t
|
|
|
3
3
|
|
|
4
4
|
from dreadnode.agent.tools.base import (
|
|
5
5
|
AnyTool,
|
|
6
|
+
FunctionCall,
|
|
7
|
+
FunctionDefinition,
|
|
6
8
|
Tool,
|
|
9
|
+
ToolCall,
|
|
10
|
+
ToolDefinition,
|
|
11
|
+
ToolMode,
|
|
7
12
|
Toolset,
|
|
8
13
|
discover_tools_on_obj,
|
|
9
14
|
tool,
|
|
@@ -15,7 +20,12 @@ if t.TYPE_CHECKING:
|
|
|
15
20
|
|
|
16
21
|
__all__ = [
|
|
17
22
|
"AnyTool",
|
|
23
|
+
"FunctionCall",
|
|
24
|
+
"FunctionDefinition",
|
|
18
25
|
"Tool",
|
|
26
|
+
"ToolCall",
|
|
27
|
+
"ToolDefinition",
|
|
28
|
+
"ToolMode",
|
|
19
29
|
"Toolset",
|
|
20
30
|
"discover_tools_on_obj",
|
|
21
31
|
"fs",
|
|
@@ -8,6 +8,10 @@ from dreadnode.meta import Component, Config, Model
|
|
|
8
8
|
|
|
9
9
|
Tool = tools.Tool
|
|
10
10
|
ToolMode = tools.ToolMode
|
|
11
|
+
ToolCall = tools.ToolCall
|
|
12
|
+
FunctionCall = tools.FunctionCall
|
|
13
|
+
ToolDefinition = tools.ToolDefinition
|
|
14
|
+
FunctionDefinition = tools.FunctionDefinition
|
|
11
15
|
|
|
12
16
|
AnyTool = Tool[t.Any, t.Any]
|
|
13
17
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from dreadnode.airt import attack, search
|
|
2
|
+
from dreadnode.airt.attack import (
|
|
3
|
+
Attack,
|
|
4
|
+
goat_attack,
|
|
5
|
+
hop_skip_jump_attack,
|
|
6
|
+
nes_attack,
|
|
7
|
+
prompt_attack,
|
|
8
|
+
simba_attack,
|
|
9
|
+
tap_attack,
|
|
10
|
+
zoo_attack,
|
|
11
|
+
)
|
|
12
|
+
from dreadnode.airt.target import CustomTarget, LLMTarget, Target
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"Attack",
|
|
16
|
+
"CustomTarget",
|
|
17
|
+
"LLMTarget",
|
|
18
|
+
"Target",
|
|
19
|
+
"attack",
|
|
20
|
+
"goat_attack",
|
|
21
|
+
"hop_skip_jump_attack",
|
|
22
|
+
"nes_attack",
|
|
23
|
+
"prompt_attack",
|
|
24
|
+
"search",
|
|
25
|
+
"simba_attack",
|
|
26
|
+
"tap_attack",
|
|
27
|
+
"target",
|
|
28
|
+
"zoo_attack",
|
|
29
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from dreadnode.airt.attack.base import Attack
|
|
2
|
+
from dreadnode.airt.attack.goat import goat_attack
|
|
3
|
+
from dreadnode.airt.attack.hop_skip_jump import hop_skip_jump_attack
|
|
4
|
+
from dreadnode.airt.attack.nes import nes_attack
|
|
5
|
+
from dreadnode.airt.attack.prompt import prompt_attack
|
|
6
|
+
from dreadnode.airt.attack.simba import simba_attack
|
|
7
|
+
from dreadnode.airt.attack.tap import tap_attack
|
|
8
|
+
from dreadnode.airt.attack.zoo import zoo_attack
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Attack",
|
|
12
|
+
"goat_attack",
|
|
13
|
+
"hop_skip_jump_attack",
|
|
14
|
+
"nes_attack",
|
|
15
|
+
"prompt_attack",
|
|
16
|
+
"simba_attack",
|
|
17
|
+
"tap_attack",
|
|
18
|
+
"zoo_attack",
|
|
19
|
+
]
|