dreadnode 1.15.1__tar.gz → 1.15.2__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.15.1 → dreadnode-1.15.2}/PKG-INFO +1 -1
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/agent.py +24 -8
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/hooks/__init__.py +2 -0
- dreadnode-1.15.2/dreadnode/agent/hooks/metrics.py +84 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/base.py +13 -8
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/agent/cli.py +0 -2
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/attack/cli.py +0 -2
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/eval/cli.py +0 -2
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/study/cli.py +0 -2
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/task/cli.py +2 -1
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/eval.py +1 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/study.py +9 -1
- {dreadnode-1.15.1 → dreadnode-1.15.2}/pyproject.toml +1 -1
- {dreadnode-1.15.1 → dreadnode-1.15.2}/.gitignore +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/LICENSE +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/README.md +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/__main__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/error.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/events.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/format.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/hooks/backoff.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/hooks/base.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/hooks/summarize.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/prompts/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/prompts/summarize.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/reactions.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/result.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/stop.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/thread.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/execute.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/fs.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/memory.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/planning.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/reporting.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/agent/tools/tasking.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/base.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/goat.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/hop_skip_jump.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/nes.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/prompt.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/simba.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/tap.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/attack/zoo.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/search/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/search/hop_skip_jump.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/search/image_utils.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/search/nes.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/search/simba.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/search/zoo.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/target/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/target/base.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/target/custom.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/airt/target/llm.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/api/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/api/client.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/api/models.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/api/util.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/artifact/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/artifact/credential_manager.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/artifact/merger.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/artifact/storage.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/artifact/tree_builder.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/agent/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/api.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/attack/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/docker.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/eval/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/github.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/main.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/cli.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/compose.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/constants.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/download.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/env_mgmt.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/tag.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/platform/version.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/profile/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/profile/cli.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/shared.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/study/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/cli/task/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/common_types.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/constants.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/convert.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/audio.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/base.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/image.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/object_3d.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/table.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/text.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/data_types/video.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/discovery.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/error.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/console.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/dataset.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/events.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/format.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/result.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/eval/sample.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/format.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/integrations/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/integrations/transformers.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/logging_.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/main.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/meta/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/meta/config.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/meta/context.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/meta/hydrate.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/meta/introspect.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/metric.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/object.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/collectors.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/console.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/events.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/format.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/result.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/sampling.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/search/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/search/base.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/search/boundary.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/search/graph.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/search/optuna_.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/search/random.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/stop.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/optimization/trial.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/py.typed +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/base.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/classification.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/consistency.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/contains.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/crucible.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/format.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/harm.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/image.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/json.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/judge.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/length.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/lexical.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/pii.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/readability.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/rigging.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/sentiment.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/similarity.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/scorers/util.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/serialization.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/task.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/tracing/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/tracing/constants.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/tracing/exporters.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/tracing/span.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/__init__.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/base.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/cipher.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/encoding.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/image.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/perturbation.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/refine.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/stylistic.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/substitution.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/swap.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/transforms/text.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/user_config.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/util.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/dreadnode/version.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/airt/beam_search.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/airt/graph_of_attacks_with_pruning.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/airt/tap_vs_goat_eval.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/airt/tree_of_attacks_with_pruning.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/data_export.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/log_artifact.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/log_object/audio.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/log_object/image.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/log_object/object3d.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/log_object/table.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/log_object/video.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/model_training.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/examples/rigging.ipynb +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/tests/cli/test_config.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/tests/cli/test_docker.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/tests/cli/test_github.py +0 -0
- {dreadnode-1.15.1 → dreadnode-1.15.2}/tests/test_meta.py +0 -0
|
@@ -2,10 +2,11 @@ import inspect
|
|
|
2
2
|
import typing as t
|
|
3
3
|
from contextlib import aclosing, asynccontextmanager
|
|
4
4
|
from copy import deepcopy
|
|
5
|
+
from textwrap import dedent
|
|
5
6
|
|
|
6
7
|
import rigging as rg
|
|
7
8
|
from loguru import logger
|
|
8
|
-
from pydantic import ConfigDict, Field, PrivateAttr, SkipValidation, field_validator
|
|
9
|
+
from pydantic import AfterValidator, ConfigDict, Field, PrivateAttr, SkipValidation, field_validator
|
|
9
10
|
from rigging.message import inject_system_content
|
|
10
11
|
from ulid import ULID # can't access via rg
|
|
11
12
|
|
|
@@ -71,14 +72,18 @@ class Agent(Model):
|
|
|
71
72
|
|
|
72
73
|
name: str
|
|
73
74
|
"""The name of the agent."""
|
|
74
|
-
description: str = ""
|
|
75
|
+
description: t.Annotated[str, AfterValidator(dedent)] = ""
|
|
75
76
|
"""A brief description of the agent's purpose."""
|
|
76
77
|
tags: list[str] = Config(default_factory=lambda: ["agent"])
|
|
77
78
|
"""A list of tags associated with the agent."""
|
|
79
|
+
label: str | None = Config(default=None)
|
|
80
|
+
"""Specific label for tracing, otherwise derived from the name."""
|
|
78
81
|
|
|
79
82
|
model: str | None = Config(default=None)
|
|
80
83
|
"""Inference model (rigging generator identifier)."""
|
|
81
|
-
instructions: str | None = Config(
|
|
84
|
+
instructions: t.Annotated[str | None, AfterValidator(lambda x: dedent(x) if x else x)] = Config(
|
|
85
|
+
default=None
|
|
86
|
+
)
|
|
82
87
|
"""The agent's core instructions."""
|
|
83
88
|
max_steps: int = Config(default=10)
|
|
84
89
|
"""The maximum number of steps (generation + tool calls)."""
|
|
@@ -90,15 +95,15 @@ class Agent(Model):
|
|
|
90
95
|
tool_mode: ToolMode = Config(default="auto", repr=False)
|
|
91
96
|
"""The tool calling mode to use."""
|
|
92
97
|
|
|
93
|
-
hooks: list[Hook] =
|
|
98
|
+
hooks: list[Hook] = Field(default_factory=list, exclude=True, repr=False)
|
|
94
99
|
"""Hooks to run at various points in the agent's lifecycle."""
|
|
95
|
-
stop_conditions: list[StopCondition] =
|
|
100
|
+
stop_conditions: list[StopCondition] = Field(default_factory=list)
|
|
96
101
|
"""The logical condition for successfully stopping a run."""
|
|
97
102
|
thread: Thread = Field(default_factory=Thread, exclude=True, repr=False)
|
|
98
103
|
"""Stateful thread for this agent, for when otherwise not specified during execution."""
|
|
99
|
-
scorers: ScorersLike[AgentResult] =
|
|
104
|
+
scorers: ScorersLike[AgentResult] = Field(default_factory=list)
|
|
100
105
|
"""Scorers to evaluate the agent output."""
|
|
101
|
-
assert_scores: list[str] | t.Literal[True] =
|
|
106
|
+
assert_scores: list[str] | t.Literal[True] = Field(default_factory=list)
|
|
102
107
|
"""Scores to ensure are truthy, otherwise the agent task is marked as failed."""
|
|
103
108
|
|
|
104
109
|
_generator: rg.Generator | None = PrivateAttr(None, init=False)
|
|
@@ -716,14 +721,25 @@ class Agent(Model):
|
|
|
716
721
|
)
|
|
717
722
|
trace_params.update(
|
|
718
723
|
{
|
|
724
|
+
"name": self.name,
|
|
719
725
|
"model": self.model,
|
|
720
726
|
"max_steps": self.max_steps,
|
|
721
727
|
"tool_mode": self.tool_mode,
|
|
728
|
+
"tool_count": len(self.all_tools),
|
|
729
|
+
"instructions_length": len(self.instructions or ""),
|
|
730
|
+
"stop_condition_count": len(self.stop_conditions),
|
|
731
|
+
"message_count": len(messages),
|
|
722
732
|
}
|
|
723
733
|
)
|
|
724
734
|
|
|
725
735
|
last_event: AgentEvent | None = None
|
|
726
|
-
with task_and_run(
|
|
736
|
+
with task_and_run(
|
|
737
|
+
name=self.name,
|
|
738
|
+
tags=self.tags,
|
|
739
|
+
label=self.label,
|
|
740
|
+
inputs=trace_inputs,
|
|
741
|
+
params=trace_params,
|
|
742
|
+
):
|
|
727
743
|
try:
|
|
728
744
|
async with aclosing(self._stream(thread, messages, hooks, commit=commit)) as stream:
|
|
729
745
|
async for event in stream:
|
|
@@ -3,6 +3,7 @@ from dreadnode.agent.hooks.base import (
|
|
|
3
3
|
Hook,
|
|
4
4
|
retry_with_feedback,
|
|
5
5
|
)
|
|
6
|
+
from dreadnode.agent.hooks.metrics import tool_metrics
|
|
6
7
|
from dreadnode.agent.hooks.summarize import summarize_when_long
|
|
7
8
|
|
|
8
9
|
__all__ = [
|
|
@@ -11,4 +12,5 @@ __all__ = [
|
|
|
11
12
|
"backoff_on_ratelimit",
|
|
12
13
|
"retry_with_feedback",
|
|
13
14
|
"summarize_when_long",
|
|
15
|
+
"tool_metrics",
|
|
14
16
|
]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
|
|
3
|
+
from dreadnode.agent.events import AgentEvent, ToolEnd, ToolStart
|
|
4
|
+
from dreadnode.agent.hooks import Hook
|
|
5
|
+
from dreadnode.meta import Config, component
|
|
6
|
+
|
|
7
|
+
if t.TYPE_CHECKING:
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def tool_metrics(*, detailed: bool = False) -> Hook:
|
|
12
|
+
"""
|
|
13
|
+
Creates an agent hook to log metrics about tool usage, execution time, and success rates.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
detailed: If True, logs metrics for each specific tool in addition to general stats.
|
|
17
|
+
If False, only logs aggregate statistics across all tools.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
An async hook function that can be registered with an agent.
|
|
21
|
+
"""
|
|
22
|
+
_start_times: dict[str, datetime] = {}
|
|
23
|
+
|
|
24
|
+
@component
|
|
25
|
+
async def tool_metrics(
|
|
26
|
+
event: AgentEvent,
|
|
27
|
+
*,
|
|
28
|
+
detailed: bool = Config(
|
|
29
|
+
default=detailed,
|
|
30
|
+
help="If True, logs metrics for each specific tool in addition to general stats.",
|
|
31
|
+
),
|
|
32
|
+
) -> None:
|
|
33
|
+
"""The actual hook implementation that processes agent events."""
|
|
34
|
+
from dreadnode import log_metric
|
|
35
|
+
|
|
36
|
+
if isinstance(event, ToolStart):
|
|
37
|
+
log_metric("tool/total_count", 1, step=event.step, mode="count")
|
|
38
|
+
_start_times[event.tool_call.id] = event.timestamp
|
|
39
|
+
|
|
40
|
+
if detailed:
|
|
41
|
+
tool_name = event.tool_call.name
|
|
42
|
+
log_metric(f"tool/count.{tool_name}", 1, step=event.step, mode="count")
|
|
43
|
+
|
|
44
|
+
elif isinstance(event, ToolEnd):
|
|
45
|
+
tool_name = event.tool_call.name
|
|
46
|
+
start_time = _start_times.pop(event.tool_call.id, event.timestamp)
|
|
47
|
+
duration_seconds = (event.timestamp - start_time).total_seconds()
|
|
48
|
+
errored = "error" in event.message.metadata
|
|
49
|
+
|
|
50
|
+
log_metric("tool/total_time", duration_seconds, step=event.step, mode="sum")
|
|
51
|
+
log_metric("tool/success_rate", 0 if errored else 1, step=event.step, mode="avg")
|
|
52
|
+
|
|
53
|
+
if errored:
|
|
54
|
+
log_metric("tool/failed_count", 1, step=event.step, mode="count")
|
|
55
|
+
|
|
56
|
+
if detailed:
|
|
57
|
+
log_metric(
|
|
58
|
+
f"tool/time.{tool_name}",
|
|
59
|
+
duration_seconds,
|
|
60
|
+
step=event.step,
|
|
61
|
+
mode="sum",
|
|
62
|
+
)
|
|
63
|
+
log_metric(
|
|
64
|
+
f"tool/avg_time.{tool_name}",
|
|
65
|
+
duration_seconds,
|
|
66
|
+
step=event.step,
|
|
67
|
+
mode="avg",
|
|
68
|
+
)
|
|
69
|
+
log_metric(
|
|
70
|
+
f"tool/success_rate.{tool_name}",
|
|
71
|
+
0 if errored else 1,
|
|
72
|
+
step=event.step,
|
|
73
|
+
mode="avg",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if errored:
|
|
77
|
+
log_metric(
|
|
78
|
+
f"tool/failed_count.{tool_name}",
|
|
79
|
+
1,
|
|
80
|
+
step=event.step,
|
|
81
|
+
mode="count",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return tool_metrics
|
|
@@ -4,7 +4,7 @@ from pydantic import ConfigDict
|
|
|
4
4
|
from rigging import tools
|
|
5
5
|
from rigging.tools.base import ToolMethod as RiggingToolMethod
|
|
6
6
|
|
|
7
|
-
from dreadnode.meta import Component,
|
|
7
|
+
from dreadnode.meta import Component, Model
|
|
8
8
|
|
|
9
9
|
Tool = tools.Tool
|
|
10
10
|
ToolMode = tools.ToolMode
|
|
@@ -103,18 +103,18 @@ def tool_method(
|
|
|
103
103
|
description: str | None = None,
|
|
104
104
|
catch: bool | t.Iterable[type[Exception]] | None = None,
|
|
105
105
|
truncate: int | None = None,
|
|
106
|
-
) -> t.Callable[[t.Callable[P, R]], RiggingToolMethod[P, R]]: ...
|
|
106
|
+
) -> t.Callable[[t.Callable[t.Concatenate[t.Any, P], R]], RiggingToolMethod[P, R]]: ...
|
|
107
107
|
|
|
108
108
|
|
|
109
109
|
@t.overload
|
|
110
110
|
def tool_method(
|
|
111
|
-
func: t.Callable[P, R],
|
|
111
|
+
func: t.Callable[t.Concatenate[t.Any, P], R],
|
|
112
112
|
/,
|
|
113
113
|
) -> RiggingToolMethod[P, R]: ...
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
def tool_method(
|
|
117
|
-
func: t.Callable[P, R] | None = None,
|
|
117
|
+
func: t.Callable[t.Concatenate[t.Any, P], R] | None = None,
|
|
118
118
|
/,
|
|
119
119
|
*,
|
|
120
120
|
variants: list[str] | None = None,
|
|
@@ -122,7 +122,10 @@ def tool_method(
|
|
|
122
122
|
description: str | None = None,
|
|
123
123
|
catch: bool | t.Iterable[type[Exception]] | None = None,
|
|
124
124
|
truncate: int | None = None,
|
|
125
|
-
) ->
|
|
125
|
+
) -> (
|
|
126
|
+
t.Callable[[t.Callable[t.Concatenate[t.Any, P], R]], RiggingToolMethod[P, R]]
|
|
127
|
+
| RiggingToolMethod[P, R]
|
|
128
|
+
):
|
|
126
129
|
"""
|
|
127
130
|
Marks a method on a Toolset as a tool, adding it to specified variants.
|
|
128
131
|
|
|
@@ -143,7 +146,9 @@ def tool_method(
|
|
|
143
146
|
truncate: The maximum number of characters for the tool's output.
|
|
144
147
|
"""
|
|
145
148
|
|
|
146
|
-
def make_tool_method(
|
|
149
|
+
def make_tool_method(
|
|
150
|
+
func: t.Callable[t.Concatenate[t.Any, P], R],
|
|
151
|
+
) -> RiggingToolMethod[P, R]:
|
|
147
152
|
tool_method_descriptor: RiggingToolMethod[P, R] = tools.tool_method(
|
|
148
153
|
name=name,
|
|
149
154
|
description=description,
|
|
@@ -168,7 +173,7 @@ class Toolset(Model):
|
|
|
168
173
|
- A `get_tools` method for discovering methods decorated with `@dreadnode.tool_method`.
|
|
169
174
|
"""
|
|
170
175
|
|
|
171
|
-
variant: str =
|
|
176
|
+
variant: str | None = None
|
|
172
177
|
"""The variant for filtering tools available in this toolset."""
|
|
173
178
|
|
|
174
179
|
model_config = ConfigDict(arbitrary_types_allowed=True, use_attribute_docstrings=True)
|
|
@@ -190,7 +195,7 @@ class Toolset(Model):
|
|
|
190
195
|
continue
|
|
191
196
|
|
|
192
197
|
variants = getattr(class_member, TOOL_VARIANTS_ATTR, [])
|
|
193
|
-
if variant in variants:
|
|
198
|
+
if not variant or not variants or variant in variants:
|
|
194
199
|
bound_tool = t.cast("AnyTool", getattr(self, name))
|
|
195
200
|
tools.append(bound_tool)
|
|
196
201
|
seen_names.add(name)
|
|
@@ -139,8 +139,6 @@ async def run( # noqa: PLR0912, PLR0915
|
|
|
139
139
|
agent_cli.__annotations__["config"] = config_annotation
|
|
140
140
|
|
|
141
141
|
help_text = f"Run the '{agent_name}' agent."
|
|
142
|
-
if agent_blueprint.__doc__:
|
|
143
|
-
help_text += "\n\n" + agent_blueprint.__doc__
|
|
144
142
|
if agent_blueprint.description:
|
|
145
143
|
help_text += "\n\n" + agent_blueprint.description
|
|
146
144
|
|
|
@@ -128,8 +128,6 @@ async def run( # noqa: PLR0912, PLR0915
|
|
|
128
128
|
attack_cli.__annotations__["config"] = config_annotation
|
|
129
129
|
|
|
130
130
|
help_text = f"Run the '{attack_name}' attack."
|
|
131
|
-
if attack_blueprint.__doc__:
|
|
132
|
-
help_text += "\n\n" + attack_blueprint.__doc__
|
|
133
131
|
if attack_blueprint.description:
|
|
134
132
|
help_text += "\n\n" + attack_blueprint.description
|
|
135
133
|
|
|
@@ -129,8 +129,6 @@ async def run( # noqa: PLR0912, PLR0915
|
|
|
129
129
|
eval_cli.__annotations__["config"] = config_annotation
|
|
130
130
|
|
|
131
131
|
help_text = f"Run the '{eval_name}' eval."
|
|
132
|
-
if eval_blueprint.__doc__:
|
|
133
|
-
help_text += "\n\n" + eval_blueprint.__doc__
|
|
134
132
|
if eval_blueprint.description:
|
|
135
133
|
help_text += "\n\n" + eval_blueprint.description
|
|
136
134
|
|
|
@@ -130,8 +130,6 @@ async def run( # noqa: PLR0912, PLR0915
|
|
|
130
130
|
study_cli.__annotations__["config"] = config_annotation
|
|
131
131
|
|
|
132
132
|
help_text = f"Run the '{study_name}' study."
|
|
133
|
-
if study_blueprint.__doc__:
|
|
134
|
-
help_text += "\n\n" + study_blueprint.__doc__
|
|
135
133
|
if study_blueprint.description:
|
|
136
134
|
help_text += "\n\n" + study_blueprint.description
|
|
137
135
|
|
|
@@ -4,6 +4,7 @@ import itertools
|
|
|
4
4
|
import typing as t
|
|
5
5
|
from inspect import isawaitable
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from textwrap import dedent
|
|
7
8
|
|
|
8
9
|
import cyclopts
|
|
9
10
|
import rich
|
|
@@ -131,7 +132,7 @@ async def run( # noqa: PLR0912, PLR0915
|
|
|
131
132
|
|
|
132
133
|
help_text = f"Run the '{task_name}' task."
|
|
133
134
|
if task_blueprint.__doc__:
|
|
134
|
-
help_text += "\n\n" + task_blueprint.__doc__
|
|
135
|
+
help_text += "\n\n" + dedent(task_blueprint.__doc__)
|
|
135
136
|
|
|
136
137
|
task_app = cyclopts.App(
|
|
137
138
|
name=task_name,
|
|
@@ -58,6 +58,8 @@ class Study(Model, t.Generic[CandidateT, OutputT]):
|
|
|
58
58
|
"""A brief description of the study's purpose."""
|
|
59
59
|
tags: list[str] = Config(default_factory=lambda: ["study"])
|
|
60
60
|
"""A list of tags associated with the study for logging."""
|
|
61
|
+
label: str | None = Config(default=None)
|
|
62
|
+
"""Specific label for tracing, otherwise derived from the name."""
|
|
61
63
|
|
|
62
64
|
search_strategy: SkipValidation[Search[CandidateT]]
|
|
63
65
|
"""The search strategy to use for suggesting new trials."""
|
|
@@ -575,7 +577,13 @@ class Study(Model, t.Generic[CandidateT, OutputT]):
|
|
|
575
577
|
log_outputs(to=log_to, **outputs)
|
|
576
578
|
|
|
577
579
|
with (
|
|
578
|
-
task_and_run(
|
|
580
|
+
task_and_run(
|
|
581
|
+
name=self.name,
|
|
582
|
+
tags=self.tags,
|
|
583
|
+
inputs=trace_inputs,
|
|
584
|
+
params=trace_params,
|
|
585
|
+
label=self.label,
|
|
586
|
+
),
|
|
579
587
|
contextlib.ExitStack() as stack,
|
|
580
588
|
):
|
|
581
589
|
stack.callback(log_study, last_event)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|