dreadnode 1.16.0__tar.gz → 1.17.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. {dreadnode-1.16.0 → dreadnode-1.17.1}/.gitignore +1 -0
  2. {dreadnode-1.16.0 → dreadnode-1.17.1}/PKG-INFO +12 -4
  3. {dreadnode-1.16.0 → dreadnode-1.17.1}/README.md +1 -1
  4. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/__init__.py +3 -1
  5. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/agent.py +11 -3
  6. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/hooks/summarize.py +7 -1
  7. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/tools/base.py +68 -2
  8. dreadnode-1.17.1/dreadnode/agent/tools/fs.py +867 -0
  9. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/__init__.py +2 -0
  10. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/base.py +3 -0
  11. dreadnode-1.17.1/dreadnode/airt/attack/crescendo.py +221 -0
  12. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/goat.py +116 -14
  13. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/prompt.py +44 -22
  14. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/tap.py +7 -2
  15. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/target/llm.py +37 -13
  16. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/api/client.py +18 -11
  17. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/api/models.py +1 -1
  18. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/main.py +1 -0
  19. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/constants.py +18 -0
  20. dreadnode-1.17.1/dreadnode/data/assets/adversarial_benchmark_subset.csv +71 -0
  21. dreadnode-1.17.1/dreadnode/data/assets/ai_safety.csv +81 -0
  22. dreadnode-1.17.1/dreadnode/data/assets/bomb.jpg +0 -0
  23. dreadnode-1.17.1/dreadnode/data/assets/meth.png +0 -0
  24. dreadnode-1.17.1/dreadnode/data/templates/crescendo/variant_1.yaml +69 -0
  25. dreadnode-1.17.1/dreadnode/data/templates/crescendo/variant_2.yaml +43 -0
  26. dreadnode-1.17.1/dreadnode/data/templates/crescendo/variant_3.yaml +24 -0
  27. dreadnode-1.17.1/dreadnode/data/templates/crescendo/variant_4.yaml +49 -0
  28. dreadnode-1.17.1/dreadnode/data/templates/crescendo/variant_5.yaml +56 -0
  29. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/__init__.py +14 -1
  30. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/image.py +2 -2
  31. dreadnode-1.17.1/dreadnode/data_types/message.py +229 -0
  32. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/text.py +1 -1
  33. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/console.py +1 -1
  34. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/eval.py +137 -37
  35. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/events.py +19 -0
  36. dreadnode-1.17.1/dreadnode/eval/hooks/__init__.py +13 -0
  37. dreadnode-1.17.1/dreadnode/eval/hooks/base.py +26 -0
  38. dreadnode-1.17.1/dreadnode/eval/hooks/transforms.py +104 -0
  39. dreadnode-1.17.1/dreadnode/eval/reactions.py +35 -0
  40. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/sample.py +2 -1
  41. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/logging_.py +1 -1
  42. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/main.py +12 -7
  43. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/collectors.py +1 -1
  44. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/console.py +51 -10
  45. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/stop.py +18 -13
  46. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/study.py +96 -71
  47. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/trial.py +9 -0
  48. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/tracing/span.py +4 -2
  49. dreadnode-1.17.1/dreadnode/transforms/cipher.py +625 -0
  50. dreadnode-1.17.1/dreadnode/transforms/encoding.py +598 -0
  51. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/transforms/image.py +95 -0
  52. dreadnode-1.17.1/dreadnode/transforms/multimodal.py +155 -0
  53. dreadnode-1.17.1/dreadnode/transforms/perturbation.py +1492 -0
  54. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/transforms/refine.py +59 -18
  55. dreadnode-1.17.1/dreadnode/transforms/text.py +599 -0
  56. dreadnode-1.17.1/examples/airt/ai_red_teaming_eval.ipynb +1898 -0
  57. dreadnode-1.17.1/examples/airt/crescendo_attack.ipynb +162 -0
  58. dreadnode-1.17.1/examples/airt/graph_of_attacks_with_pruning.ipynb +181 -0
  59. dreadnode-1.17.1/examples/airt/multimodal_attack_eval.ipynb +263 -0
  60. dreadnode-1.17.1/examples/airt/tap_vs_goat_eval.ipynb +549 -0
  61. dreadnode-1.17.1/examples/airt/tree_of_attacks_with_pruning.ipynb +183 -0
  62. dreadnode-1.17.1/examples/airt/tree_of_attacks_with_pruning_transforms.ipynb +186 -0
  63. {dreadnode-1.16.0 → dreadnode-1.17.1}/pyproject.toml +14 -8
  64. dreadnode-1.17.1/tests/test_agent_lifecycle.py +239 -0
  65. dreadnode-1.16.0/dreadnode/agent/tools/fs.py +0 -395
  66. dreadnode-1.16.0/dreadnode/transforms/cipher.py +0 -68
  67. dreadnode-1.16.0/dreadnode/transforms/encoding.py +0 -79
  68. dreadnode-1.16.0/dreadnode/transforms/perturbation.py +0 -307
  69. dreadnode-1.16.0/dreadnode/transforms/text.py +0 -158
  70. dreadnode-1.16.0/examples/airt/graph_of_attacks_with_pruning.ipynb +0 -179
  71. dreadnode-1.16.0/examples/airt/tap_vs_goat_eval.ipynb +0 -2303
  72. dreadnode-1.16.0/examples/airt/tree_of_attacks_with_pruning.ipynb +0 -181
  73. {dreadnode-1.16.0 → dreadnode-1.17.1}/LICENSE +0 -0
  74. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/__main__.py +0 -0
  75. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/__init__.py +0 -0
  76. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/error.py +0 -0
  77. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/events.py +0 -0
  78. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/format.py +0 -0
  79. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/hooks/__init__.py +0 -0
  80. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/hooks/backoff.py +0 -0
  81. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/hooks/base.py +0 -0
  82. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/hooks/metrics.py +0 -0
  83. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/prompts/__init__.py +0 -0
  84. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/prompts/summarize.py +0 -0
  85. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/reactions.py +0 -0
  86. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/result.py +0 -0
  87. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/stop.py +0 -0
  88. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/thread.py +0 -0
  89. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/tools/__init__.py +0 -0
  90. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/tools/execute.py +0 -0
  91. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/tools/memory.py +0 -0
  92. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/tools/planning.py +0 -0
  93. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/tools/reporting.py +0 -0
  94. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/agent/tools/tasking.py +0 -0
  95. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/__init__.py +0 -0
  96. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/hop_skip_jump.py +0 -0
  97. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/nes.py +0 -0
  98. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/simba.py +0 -0
  99. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/attack/zoo.py +0 -0
  100. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/search/__init__.py +0 -0
  101. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/search/hop_skip_jump.py +0 -0
  102. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/search/image_utils.py +0 -0
  103. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/search/nes.py +0 -0
  104. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/search/simba.py +0 -0
  105. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/search/zoo.py +0 -0
  106. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/target/__init__.py +0 -0
  107. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/target/base.py +0 -0
  108. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/airt/target/custom.py +0 -0
  109. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/api/__init__.py +0 -0
  110. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/api/util.py +0 -0
  111. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/artifact/__init__.py +0 -0
  112. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/artifact/credential_manager.py +0 -0
  113. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/artifact/merger.py +0 -0
  114. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/artifact/storage.py +0 -0
  115. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/artifact/tree_builder.py +0 -0
  116. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/__init__.py +0 -0
  117. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/agent/__init__.py +0 -0
  118. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/agent/cli.py +0 -0
  119. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/api.py +0 -0
  120. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/attack/__init__.py +0 -0
  121. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/attack/cli.py +0 -0
  122. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/docker.py +0 -0
  123. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/eval/__init__.py +0 -0
  124. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/eval/cli.py +0 -0
  125. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/github.py +0 -0
  126. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/__init__.py +0 -0
  127. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/cli.py +0 -0
  128. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/compose.py +0 -0
  129. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/constants.py +0 -0
  130. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/download.py +0 -0
  131. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/env_mgmt.py +0 -0
  132. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/tag.py +0 -0
  133. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/platform/version.py +0 -0
  134. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/profile/__init__.py +0 -0
  135. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/profile/cli.py +0 -0
  136. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/rbac/__init__.py +0 -0
  137. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/rbac/organizations.py +0 -0
  138. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/rbac/workspaces.py +0 -0
  139. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/shared.py +0 -0
  140. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/study/__init__.py +0 -0
  141. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/study/cli.py +0 -0
  142. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/task/__init__.py +0 -0
  143. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/cli/task/cli.py +0 -0
  144. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/common_types.py +0 -0
  145. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/convert.py +0 -0
  146. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/audio.py +0 -0
  147. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/base.py +0 -0
  148. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/object_3d.py +0 -0
  149. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/table.py +0 -0
  150. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/data_types/video.py +0 -0
  151. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/discovery.py +0 -0
  152. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/error.py +0 -0
  153. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/__init__.py +0 -0
  154. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/dataset.py +0 -0
  155. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/format.py +0 -0
  156. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/eval/result.py +0 -0
  157. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/exporter.py +0 -0
  158. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/format.py +0 -0
  159. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/integrations/__init__.py +0 -0
  160. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/integrations/transformers.py +0 -0
  161. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/meta/__init__.py +0 -0
  162. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/meta/config.py +0 -0
  163. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/meta/context.py +0 -0
  164. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/meta/hydrate.py +0 -0
  165. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/meta/introspect.py +0 -0
  166. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/metric.py +0 -0
  167. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/object.py +0 -0
  168. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/__init__.py +0 -0
  169. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/events.py +0 -0
  170. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/format.py +0 -0
  171. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/result.py +0 -0
  172. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/sampling.py +0 -0
  173. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/search/__init__.py +0 -0
  174. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/search/base.py +0 -0
  175. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/search/boundary.py +0 -0
  176. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/search/graph.py +0 -0
  177. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/search/optuna_.py +0 -0
  178. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/optimization/search/random.py +0 -0
  179. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/py.typed +0 -0
  180. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/__init__.py +0 -0
  181. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/base.py +0 -0
  182. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/classification.py +0 -0
  183. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/consistency.py +0 -0
  184. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/contains.py +0 -0
  185. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/crucible.py +0 -0
  186. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/format.py +0 -0
  187. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/harm.py +0 -0
  188. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/image.py +0 -0
  189. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/json.py +0 -0
  190. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/judge.py +0 -0
  191. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/length.py +0 -0
  192. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/lexical.py +0 -0
  193. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/pii.py +0 -0
  194. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/readability.py +0 -0
  195. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/rigging.py +0 -0
  196. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/sentiment.py +0 -0
  197. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/similarity.py +0 -0
  198. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/scorers/util.py +0 -0
  199. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/serialization.py +0 -0
  200. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/task.py +0 -0
  201. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/tracing/__init__.py +0 -0
  202. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/tracing/constants.py +0 -0
  203. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/tracing/exporters.py +0 -0
  204. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/transforms/__init__.py +0 -0
  205. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/transforms/base.py +0 -0
  206. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/transforms/stylistic.py +0 -0
  207. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/transforms/substitution.py +0 -0
  208. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/transforms/swap.py +0 -0
  209. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/user_config.py +0 -0
  210. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/util.py +0 -0
  211. {dreadnode-1.16.0 → dreadnode-1.17.1}/dreadnode/version.py +0 -0
  212. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/airt/beam_search.ipynb +0 -0
  213. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/data_export.ipynb +0 -0
  214. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/log_artifact.ipynb +0 -0
  215. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/log_object/audio.ipynb +0 -0
  216. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/log_object/image.ipynb +0 -0
  217. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/log_object/object3d.ipynb +0 -0
  218. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/log_object/table.ipynb +0 -0
  219. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/log_object/video.ipynb +0 -0
  220. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/model_training.ipynb +0 -0
  221. {dreadnode-1.16.0 → dreadnode-1.17.1}/examples/rigging.ipynb +0 -0
  222. {dreadnode-1.16.0 → dreadnode-1.17.1}/tests/cli/test_config.py +0 -0
  223. {dreadnode-1.16.0 → dreadnode-1.17.1}/tests/cli/test_docker.py +0 -0
  224. {dreadnode-1.16.0 → dreadnode-1.17.1}/tests/cli/test_github.py +0 -0
  225. {dreadnode-1.16.0 → dreadnode-1.17.1}/tests/test_agent.py +0 -0
  226. {dreadnode-1.16.0 → dreadnode-1.17.1}/tests/test_meta.py +0 -0
  227. {dreadnode-1.16.0 → dreadnode-1.17.1}/tests/test_task_output_linking.py +0 -0
@@ -156,6 +156,7 @@ venv.bak/
156
156
 
157
157
  # mkdocs documentation
158
158
  /site
159
+ debug.html
159
160
 
160
161
  # mypy
161
162
  .mypy_cache/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dreadnode
3
- Version: 1.16.0
3
+ Version: 1.17.1
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
@@ -208,14 +208,22 @@ License: Apache License
208
208
  See the License for the specific language governing permissions and
209
209
  limitations under the License.
210
210
  License-File: LICENSE
211
+ Classifier: License :: OSI Approved :: Apache Software License
212
+ Classifier: Operating System :: OS Independent
213
+ Classifier: Programming Language :: Python :: 3
214
+ Classifier: Programming Language :: Python :: 3.10
215
+ Classifier: Programming Language :: Python :: 3.11
216
+ Classifier: Programming Language :: Python :: 3.12
217
+ Classifier: Programming Language :: Python :: 3.13
211
218
  Requires-Python: <3.14,>=3.10
219
+ Requires-Dist: aiofiles<25.0.0,>=24.1.0
212
220
  Requires-Dist: coolname<3.0.0,>=2.2.0
213
221
  Requires-Dist: cyclopts>=4.2.0
214
- Requires-Dist: fsspec[s3]<=2025.3.0,>=2023.1.0
222
+ Requires-Dist: fsspec[s3]<=2025.12.0,>=2023.1.0
215
223
  Requires-Dist: httpx<1.0.0,>=0.28.0
216
224
  Requires-Dist: logfire<=3.20.0,>=3.5.3
217
225
  Requires-Dist: loguru>=0.7.3
218
- Requires-Dist: numpy<=2.2.6
226
+ Requires-Dist: numpy<=2.3.5
219
227
  Requires-Dist: optuna<5.0.0,>=4.5.0
220
228
  Requires-Dist: pandas<3.0.0,>=2.2.3
221
229
  Requires-Dist: pydantic<3.0.0,>=2.9.2
@@ -278,7 +286,7 @@ Dreadnode Strikes SDK
278
286
  <img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/dreadnode">
279
287
  <img alt="PyPI - Version" src="https://img.shields.io/pypi/v/dreadnode">
280
288
  <img alt="GitHub License" src="https://img.shields.io/github/license/dreadnode/sdk">
281
- <img alt="Tests" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/tests.yaml">
289
+ <img alt="Tests" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/test.yaml">
282
290
  <img alt="Pre-Commit" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/pre-commit.yaml">
283
291
  <img alt="Renovate" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/renovate.yaml">
284
292
  </h4>
@@ -16,7 +16,7 @@ Dreadnode Strikes SDK
16
16
  <img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/dreadnode">
17
17
  <img alt="PyPI - Version" src="https://img.shields.io/pypi/v/dreadnode">
18
18
  <img alt="GitHub License" src="https://img.shields.io/github/license/dreadnode/sdk">
19
- <img alt="Tests" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/tests.yaml">
19
+ <img alt="Tests" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/test.yaml">
20
20
  <img alt="Pre-Commit" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/pre-commit.yaml">
21
21
  <img alt="Renovate" src="https://img.shields.io/github/actions/workflow/status/dreadnode/sdk/renovate.yaml">
22
22
  </h4>
@@ -38,7 +38,7 @@ from dreadnode.version import VERSION
38
38
  if t.TYPE_CHECKING:
39
39
  from dreadnode import agent, airt, eval, optimization, scorers, transforms # noqa: A004
40
40
  from dreadnode.agent import Agent, tool, tool_method
41
- from dreadnode.data_types import Audio, Image, Table, Video
41
+ from dreadnode.data_types import Audio, Image, Message, Table, Video
42
42
 
43
43
  logger.disable("dreadnode")
44
44
 
@@ -88,6 +88,7 @@ __all__ = [
88
88
  "EnvVar",
89
89
  "Image",
90
90
  "Markdown",
91
+ "Message",
91
92
  "Metric",
92
93
  "MetricDict",
93
94
  "Object",
@@ -151,6 +152,7 @@ __lazy_components__: dict[str, str] = {
151
152
  "Image": "dreadnode.data_types",
152
153
  "Table": "dreadnode.data_types",
153
154
  "Video": "dreadnode.data_types",
155
+ "Message": "dreadnode.data_types",
154
156
  "Agent": "dreadnode.agent",
155
157
  "tool": "dreadnode.agent",
156
158
  "tool_method": "dreadnode.agent",
@@ -2,7 +2,7 @@ import inspect
2
2
  import json
3
3
  import re
4
4
  import typing as t
5
- from contextlib import aclosing, asynccontextmanager
5
+ from contextlib import AsyncExitStack, aclosing, asynccontextmanager
6
6
  from copy import deepcopy
7
7
  from textwrap import dedent
8
8
 
@@ -875,8 +875,16 @@ class Agent(Model):
875
875
  commit: CommitBehavior = "always",
876
876
  ) -> t.AsyncIterator[t.AsyncGenerator[AgentEvent, None]]:
877
877
  thread = thread or self.thread
878
- async with aclosing(self._stream_traced(thread, user_input, commit=commit)) as stream:
879
- yield stream
878
+
879
+ async with AsyncExitStack() as stack:
880
+ # Ensure all tools are properly entered if they
881
+ # are context managers before we start using them
882
+ for tool_container in self.tools:
883
+ if hasattr(tool_container, "__aenter__") and hasattr(tool_container, "__aexit__"):
884
+ await stack.enter_async_context(tool_container)
885
+
886
+ async with aclosing(self._stream_traced(thread, user_input, commit=commit)) as stream:
887
+ yield stream
880
888
 
881
889
  async def run(
882
890
  self,
@@ -49,6 +49,7 @@ def summarize_when_long(
49
49
  model: str | rg.Generator | None = None,
50
50
  max_tokens: int = 100_000,
51
51
  min_messages_to_keep: int = 5,
52
+ guidance: str = "",
52
53
  ) -> "Hook":
53
54
  """
54
55
  Creates a hook to manage the agent's context window by summarizing the conversation history.
@@ -64,6 +65,7 @@ def summarize_when_long(
64
65
  max_tokens: The maximum number of tokens allowed in the context window before summarization is triggered
65
66
  (default is None, meaning no proactive summarization).
66
67
  min_messages_to_keep: The minimum number of messages to retain after summarization (default is 5).
68
+ guidance: Additional guidance for the summarization process (default is "").
67
69
  """
68
70
 
69
71
  if min_messages_to_keep < 2:
@@ -85,6 +87,10 @@ def summarize_when_long(
85
87
  min_messages_to_keep: int = Config(
86
88
  5, help="Minimum number of messages to retain after summarization"
87
89
  ),
90
+ guidance: str = Config(
91
+ guidance,
92
+ help="Additional guidance for the summarization process",
93
+ ),
88
94
  ) -> Reaction | None:
89
95
  should_summarize = False
90
96
 
@@ -149,7 +155,7 @@ def summarize_when_long(
149
155
 
150
156
  # Generate the summary and rebuild the messages
151
157
  summary = await summarize_conversation.bind(summarizer_model)(
152
- "\n".join(str(msg) for msg in messages_to_summarize)
158
+ "\n".join(str(msg) for msg in messages_to_summarize), guidance=guidance
153
159
  )
154
160
  summary_content = (
155
161
  f"<conversation-summary messages={len(messages_to_summarize)}>\n"
@@ -1,6 +1,8 @@
1
+ import asyncio
2
+ import functools
1
3
  import typing as t
2
4
 
3
- from pydantic import ConfigDict
5
+ from pydantic import ConfigDict, PrivateAttr
4
6
  from rigging import tools
5
7
  from rigging.tools.base import ToolMethod as RiggingToolMethod
6
8
 
@@ -171,18 +173,82 @@ class Toolset(Model):
171
173
  - Pydantic's declarative syntax for defining state (fields).
172
174
  - Automatic application of the `@configurable` decorator.
173
175
  - A `get_tools` method for discovering methods decorated with `@dreadnode.tool_method`.
176
+ - Support for async context management, with automatic re-entrancy handling.
174
177
  """
175
178
 
179
+ model_config = ConfigDict(arbitrary_types_allowed=True, use_attribute_docstrings=True)
180
+
176
181
  variant: str | None = None
177
182
  """The variant for filtering tools available in this toolset."""
178
183
 
179
- model_config = ConfigDict(arbitrary_types_allowed=True, use_attribute_docstrings=True)
184
+ # Context manager magic
185
+ _entry_ref_count: int = PrivateAttr(default=0)
186
+ _context_handle: object = PrivateAttr(default=None)
187
+ _entry_lock: asyncio.Lock = PrivateAttr(default_factory=asyncio.Lock)
180
188
 
181
189
  @property
182
190
  def name(self) -> str:
183
191
  """The name of the toolset, derived from the class name."""
184
192
  return self.__class__.__name__
185
193
 
194
+ def __init_subclass__(cls, **kwargs: t.Any) -> None:
195
+ super().__init_subclass__(**kwargs)
196
+
197
+ # This essentially ensures that if the Toolset is any kind of context manager,
198
+ # it will be re-entrant, and only actually enter/exit once. This means we can
199
+ # safely build auto-entry/exit logic into our Agent class without worrying about
200
+ # breaking the code if the user happens to enter a toolset manually before using
201
+ # it in an agent.
202
+
203
+ original_aenter = cls.__dict__.get("__aenter__")
204
+ original_enter = cls.__dict__.get("__enter__")
205
+ original_aexit = cls.__dict__.get("__aexit__")
206
+ original_exit = cls.__dict__.get("__exit__")
207
+
208
+ has_enter = callable(original_aenter) or callable(original_enter)
209
+ has_exit = callable(original_aexit) or callable(original_exit)
210
+
211
+ if has_enter and not has_exit:
212
+ raise TypeError(
213
+ f"{cls.__name__} defining __aenter__ or __enter__ must also define __aexit__ or __exit__"
214
+ )
215
+ if has_exit and not has_enter:
216
+ raise TypeError(
217
+ f"{cls.__name__} defining __aexit__ or __exit__ must also define __aenter__ or __enter__"
218
+ )
219
+ if original_aenter and original_enter:
220
+ raise TypeError(f"{cls.__name__} cannot define both __aenter__ and __enter__")
221
+ if original_aexit and original_exit:
222
+ raise TypeError(f"{cls.__name__} cannot define both __aexit__ and __exit__")
223
+
224
+ @functools.wraps(original_aenter or original_enter) # type: ignore[arg-type]
225
+ async def aenter_wrapper(self: "Toolset", *args: t.Any, **kwargs: t.Any) -> t.Any:
226
+ async with self._entry_lock:
227
+ if self._entry_ref_count == 0:
228
+ handle = None
229
+ if original_aenter:
230
+ handle = await original_aenter(self, *args, **kwargs)
231
+ elif original_enter:
232
+ handle = original_enter(self, *args, **kwargs)
233
+ self._context_handle = handle if handle is not None else self
234
+ self._entry_ref_count += 1
235
+ return self._context_handle
236
+
237
+ cls.__aenter__ = aenter_wrapper # type: ignore[attr-defined]
238
+
239
+ @functools.wraps(original_aexit or original_exit) # type: ignore[arg-type]
240
+ async def aexit_wrapper(self: "Toolset", *args: t.Any, **kwargs: t.Any) -> t.Any:
241
+ async with self._entry_lock:
242
+ self._entry_ref_count -= 1
243
+ if self._entry_ref_count == 0:
244
+ if original_aexit:
245
+ await original_aexit(self, *args, **kwargs)
246
+ elif original_exit:
247
+ original_exit(self, *args, **kwargs)
248
+ self._context_handle = None
249
+
250
+ cls.__aexit__ = aexit_wrapper # type: ignore[attr-defined]
251
+
186
252
  def get_tools(self, *, variant: str | None = None) -> list[AnyTool]:
187
253
  variant = variant or self.variant
188
254