dreadnode 2.0.35__tar.gz → 2.0.36__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 (713) hide show
  1. {dreadnode-2.0.35 → dreadnode-2.0.36}/PKG-INFO +4 -1
  2. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/agent.py +35 -1
  3. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/__init__.py +74 -0
  4. dreadnode-2.0.36/dreadnode/airt/_base.py +213 -0
  5. dreadnode-2.0.36/dreadnode/airt/art_engine.py +183 -0
  6. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/assessment.py +11 -1
  7. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/crescendo.py +8 -4
  8. dreadnode-2.0.36/dreadnode/airt/evasion/__init__.py +46 -0
  9. dreadnode-2.0.36/dreadnode/airt/evasion/_base.py +399 -0
  10. dreadnode-2.0.36/dreadnode/airt/evasion/_text_common.py +198 -0
  11. dreadnode-2.0.36/dreadnode/airt/evasion/bae.py +62 -0
  12. dreadnode-2.0.36/dreadnode/airt/evasion/boundary.py +57 -0
  13. dreadnode-2.0.36/dreadnode/airt/evasion/deepwordbug.py +72 -0
  14. dreadnode-2.0.36/dreadnode/airt/evasion/hopskipjump.py +86 -0
  15. dreadnode-2.0.36/dreadnode/airt/evasion/pwws.py +112 -0
  16. dreadnode-2.0.36/dreadnode/airt/evasion/simba.py +67 -0
  17. dreadnode-2.0.36/dreadnode/airt/evasion/square.py +73 -0
  18. dreadnode-2.0.36/dreadnode/airt/evasion/text.py +90 -0
  19. dreadnode-2.0.36/dreadnode/airt/evasion/textbugger.py +69 -0
  20. dreadnode-2.0.36/dreadnode/airt/evasion/textfooler.py +48 -0
  21. dreadnode-2.0.36/dreadnode/airt/evasion/zoo.py +83 -0
  22. dreadnode-2.0.36/dreadnode/airt/extraction/__init__.py +63 -0
  23. dreadnode-2.0.36/dreadnode/airt/extraction/_base.py +703 -0
  24. dreadnode-2.0.36/dreadnode/airt/extraction/activethief.py +108 -0
  25. dreadnode-2.0.36/dreadnode/airt/extraction/copycat.py +32 -0
  26. dreadnode-2.0.36/dreadnode/airt/extraction/distillation.py +35 -0
  27. dreadnode-2.0.36/dreadnode/airt/extraction/equation_solving.py +34 -0
  28. dreadnode-2.0.36/dreadnode/airt/extraction/jacobian.py +82 -0
  29. dreadnode-2.0.36/dreadnode/airt/extraction/knockoff.py +34 -0
  30. dreadnode-2.0.36/dreadnode/airt/inversion/__init__.py +32 -0
  31. dreadnode-2.0.36/dreadnode/airt/inversion/_base.py +262 -0
  32. dreadnode-2.0.36/dreadnode/airt/inversion/confidence.py +80 -0
  33. dreadnode-2.0.36/dreadnode/airt/inversion/nes_inversion.py +100 -0
  34. dreadnode-2.0.36/dreadnode/airt/membership/__init__.py +59 -0
  35. dreadnode-2.0.36/dreadnode/airt/membership/_base.py +416 -0
  36. dreadnode-2.0.36/dreadnode/airt/membership/entropy.py +30 -0
  37. dreadnode-2.0.36/dreadnode/airt/membership/label_only.py +86 -0
  38. dreadnode-2.0.36/dreadnode/airt/membership/lira.py +83 -0
  39. dreadnode-2.0.36/dreadnode/airt/membership/loss.py +30 -0
  40. dreadnode-2.0.36/dreadnode/airt/membership/shadow_model.py +85 -0
  41. dreadnode-2.0.36/dreadnode/airt/membership/threshold.py +148 -0
  42. dreadnode-2.0.36/dreadnode/airt/model_export.py +129 -0
  43. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/__init__.py +12 -0
  44. dreadnode-2.0.36/dreadnode/airt/targets/prediction.py +211 -0
  45. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/api/models.py +24 -1
  46. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/airt.py +291 -5
  47. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/args.py +8 -0
  48. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/capability.py +18 -5
  49. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/evaluation.py +91 -0
  50. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/main.py +2 -0
  51. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/client/managed_client.py +2 -0
  52. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/client/models.py +2 -0
  53. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/client/runtime_client.py +63 -9
  54. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/main.py +18 -0
  55. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/print_mode.py +7 -1
  56. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/app.py +146 -10
  57. dreadnode-2.0.36/dreadnode/app/server/auth.py +120 -0
  58. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/capability_manager.py +50 -1
  59. dreadnode-2.0.36/dreadnode/app/server/runtime_token.py +395 -0
  60. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/session_hydrator.py +44 -0
  61. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/websocket.py +192 -21
  62. dreadnode-2.0.36/dreadnode/app/server/ws_auth.py +111 -0
  63. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/app.py +85 -0
  64. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/capabilities.py +15 -2
  65. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/models.py +5 -0
  66. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/sessions_manager.py +97 -5
  67. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/turn_coordinator.py +14 -0
  68. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/conversation.py +38 -1
  69. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/tool.py +21 -3
  70. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/agent-output.md +5 -0
  71. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/dependencies-and-checks.md +3 -3
  72. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/hooks.md +20 -1
  73. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/policies.md +21 -0
  74. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/tools.md +21 -0
  75. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/sdk/capabilities.md +1 -0
  76. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/tui/default-tools.md +11 -0
  77. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/airt.md +26 -0
  78. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/evaluation.md +5 -0
  79. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/install.py +79 -11
  80. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/loader.py +404 -46
  81. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/environment.py +6 -1
  82. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/proxy.py +57 -0
  83. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/study.py +31 -0
  84. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/constants.py +26 -0
  85. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/language.py +18 -9
  86. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/refine.py +9 -4
  87. {dreadnode-2.0.35 → dreadnode-2.0.36}/pyproject.toml +26 -2
  88. dreadnode-2.0.35/dreadnode/app/server/auth.py +0 -66
  89. dreadnode-2.0.35/dreadnode/app/server/ws_auth.py +0 -76
  90. {dreadnode-2.0.35 → dreadnode-2.0.36}/.gitignore +0 -0
  91. {dreadnode-2.0.35 → dreadnode-2.0.36}/LICENSE +0 -0
  92. {dreadnode-2.0.35 → dreadnode-2.0.36}/README.md +0 -0
  93. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/__init__.py +0 -0
  94. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/__main__.py +0 -0
  95. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/__init__.py +0 -0
  96. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/engines/AGENTS.md +0 -0
  97. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/engines/__init__.py +0 -0
  98. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/engines/base.py +0 -0
  99. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/engines/claude_code.py +0 -0
  100. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/engines/native.py +0 -0
  101. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/events.py +0 -0
  102. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/exceptions.py +0 -0
  103. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/format.py +0 -0
  104. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/hooks.py +0 -0
  105. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/judge.py +0 -0
  106. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/mcp/__init__.py +0 -0
  107. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/mcp/auth.py +0 -0
  108. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/mcp/client.py +0 -0
  109. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/mcp/config.py +0 -0
  110. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/mcp/server.py +0 -0
  111. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/process_judge.py +0 -0
  112. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/reactions.py +0 -0
  113. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/sanitize.py +0 -0
  114. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/skills.py +0 -0
  115. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/stopping.py +0 -0
  116. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/subagent.py +0 -0
  117. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/tool_resolution.py +0 -0
  118. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/tools.py +0 -0
  119. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/agents/trajectory.py +0 -0
  120. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/adversarial_reasoning.py +0 -0
  121. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/advpromptier.py +0 -0
  122. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/alignment_faking.py +0 -0
  123. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analogy_escalation.py +0 -0
  124. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analytics/__init__.py +0 -0
  125. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analytics/aggregator.py +0 -0
  126. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analytics/classifier.py +0 -0
  127. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analytics/compliance.py +0 -0
  128. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analytics/engine.py +0 -0
  129. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analytics/recommendations.py +0 -0
  130. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/analytics/types.py +0 -0
  131. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/aprt_progressive.py +0 -0
  132. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/__init__.py +0 -0
  133. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/defense.py +0 -0
  134. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/failure.py +0 -0
  135. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/gate.py +0 -0
  136. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/memory.py +0 -0
  137. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/modes.py +0 -0
  138. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/probes.py +0 -0
  139. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/recon.py +0 -0
  140. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/router.py +0 -0
  141. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/atlas/strategy.py +0 -0
  142. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/attention_shifting.py +0 -0
  143. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/autodan_turbo.py +0 -0
  144. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/autoredteamer.py +0 -0
  145. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/beast.py +0 -0
  146. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/compliance/__init__.py +0 -0
  147. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/compliance/atlas.py +0 -0
  148. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/compliance/nist.py +0 -0
  149. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/compliance/owasp.py +0 -0
  150. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/compliance/owasp_agentic.py +0 -0
  151. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/compliance/saif.py +0 -0
  152. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/constants.py +0 -0
  153. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/cot_jailbreak.py +0 -0
  154. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/__init__.py +0 -0
  155. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/assets/audio/adversarial_query.mp3 +0 -0
  156. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/assets/image/bomb.jpg +0 -0
  157. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/assets/image/meth.png +0 -0
  158. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/prompts/adversarial_benchmark_subset.csv +0 -0
  159. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/prompts/ai_safety.csv +0 -0
  160. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/data_exfiltration.yaml +0 -0
  161. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/goal_hijacking.yaml +0 -0
  162. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/idor.yaml +0 -0
  163. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/memory_poisoning.yaml +0 -0
  164. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/privilege_escalation.yaml +0 -0
  165. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/rce.yaml +0 -0
  166. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/scope_creep.yaml +0 -0
  167. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/tool_chaining.yaml +0 -0
  168. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/tool_selection_safety.yaml +0 -0
  169. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/unbounded_agency.yaml +0 -0
  170. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/rubrics/web_chatbot_security.yaml +0 -0
  171. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/templates/crescendo/variant_1.yaml +0 -0
  172. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/templates/crescendo/variant_2.yaml +0 -0
  173. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/templates/crescendo/variant_3.yaml +0 -0
  174. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/templates/crescendo/variant_4.yaml +0 -0
  175. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/data/templates/crescendo/variant_5.yaml +0 -0
  176. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/deep_inception.py +0 -0
  177. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/drattack.py +0 -0
  178. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/echo_chamber.py +0 -0
  179. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/events.py +0 -0
  180. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/genetic_persona.py +0 -0
  181. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/goat.py +0 -0
  182. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/goat_v2.py +0 -0
  183. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/gptfuzzer.py +0 -0
  184. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/humor_bypass.py +0 -0
  185. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/image.py +0 -0
  186. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/j2_meta.py +0 -0
  187. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/jbdistill.py +0 -0
  188. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/jbfuzz.py +0 -0
  189. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/lrm_autonomous.py +0 -0
  190. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/mapf.py +0 -0
  191. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/message_parts.py +0 -0
  192. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/multimodal.py +0 -0
  193. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/nexus.py +0 -0
  194. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/pair.py +0 -0
  195. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/persona_hijack.py +0 -0
  196. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/prompt.py +0 -0
  197. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/quantization_safety.py +0 -0
  198. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/rainbow.py +0 -0
  199. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/refusal_aware.py +0 -0
  200. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/renellm.py +0 -0
  201. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/reporting/__init__.py +0 -0
  202. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/reporting/json_report.py +0 -0
  203. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/reporting/llm_summary.py +0 -0
  204. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/reporting/markdown.py +0 -0
  205. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/reward_hacking.py +0 -0
  206. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/salami_slicing.py +0 -0
  207. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/self_persuasion.py +0 -0
  208. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/siren.py +0 -0
  209. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/tap.py +0 -0
  210. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/target.py +0 -0
  211. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/auth.py +0 -0
  212. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/factory.py +0 -0
  213. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/http.py +0 -0
  214. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/message.py +0 -0
  215. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/spec.py +0 -0
  216. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/streaming/__init__.py +0 -0
  217. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/targets/streaming/nova_sonic.py +0 -0
  218. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/templatefuzz.py +0 -0
  219. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/tmap_trajectory.py +0 -0
  220. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/trojail.py +0 -0
  221. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/airt/watermark_removal.py +0 -0
  222. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/__init__.py +0 -0
  223. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/api/__init__.py +0 -0
  224. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/api/client.py +0 -0
  225. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/__init__.py +0 -0
  226. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/dataset.py +0 -0
  227. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/environment.py +0 -0
  228. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/inference_model.py +0 -0
  229. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/judge.py +0 -0
  230. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/model.py +0 -0
  231. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/optimize.py +0 -0
  232. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/runtime.py +0 -0
  233. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/sandbox.py +0 -0
  234. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/secret.py +0 -0
  235. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/session.py +0 -0
  236. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/shared.py +0 -0
  237. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/task.py +0 -0
  238. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/task_set.py +0 -0
  239. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/__init__.py +0 -0
  240. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/__init__.py +0 -0
  241. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/challenge/Dockerfile +0 -0
  242. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/docker-compose.yaml +0 -0
  243. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/provision.sh +0 -0
  244. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/solution.sh +0 -0
  245. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/task-remote.yaml.tmpl +0 -0
  246. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/task.yaml.tmpl +0 -0
  247. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/teardown.sh +0 -0
  248. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/templates/init/verify.sh +0 -0
  249. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/train.py +0 -0
  250. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/cli/worlds.py +0 -0
  251. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/client/__init__.py +0 -0
  252. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/client/interactive.py +0 -0
  253. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/client/transports.py +0 -0
  254. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/config.py +0 -0
  255. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/env.py +0 -0
  256. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/model_catalog.py +0 -0
  257. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/paths.py +0 -0
  258. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/__init__.py +0 -0
  259. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/model_resolution.py +0 -0
  260. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/prompt.py +0 -0
  261. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/prompt_registry.py +0 -0
  262. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/runtime_events.py +0 -0
  263. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/session_persistence.py +0 -0
  264. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/turn_coordinator.py +0 -0
  265. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/utils.py +0 -0
  266. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/server/worker_manager.py +0 -0
  267. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/__init__.py +0 -0
  268. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/auth_flow.py +0 -0
  269. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/capabilities_manager.py +0 -0
  270. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/command_dispatcher.py +0 -0
  271. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/commands.py +0 -0
  272. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/connection.py +0 -0
  273. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/dreadnode.tcss +0 -0
  274. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/error_handler.py +0 -0
  275. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/model_manager.py +0 -0
  276. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/model_variants.py +0 -0
  277. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/profile_manager.py +0 -0
  278. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/runtime_cache.py +0 -0
  279. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screen_router.py +0 -0
  280. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/__init__.py +0 -0
  281. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/auth.py +0 -0
  282. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/base.py +0 -0
  283. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/capability_docs.py +0 -0
  284. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/connection_error.py +0 -0
  285. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/console.py +0 -0
  286. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/environments.py +0 -0
  287. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/evaluations.py +0 -0
  288. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/raw_spans.py +0 -0
  289. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/readme.py +0 -0
  290. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/runtimes.py +0 -0
  291. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/sandboxes.py +0 -0
  292. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/secrets.py +0 -0
  293. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/services.py +0 -0
  294. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/sessions.py +0 -0
  295. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/theme_showcase.py +0 -0
  296. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/traces.py +0 -0
  297. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/screens/workspaces.py +0 -0
  298. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/spans_reader.py +0 -0
  299. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/status_messages.py +0 -0
  300. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/theme.py +0 -0
  301. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/tool_format.py +0 -0
  302. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/turn_lifecycle.py +0 -0
  303. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/turn_reducer.py +0 -0
  304. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/turn_state_phase.py +0 -0
  305. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/update_check.py +0 -0
  306. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/__init__.py +0 -0
  307. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/agent_dialog.py +0 -0
  308. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/agent_suggester.py +0 -0
  309. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/composer.py +0 -0
  310. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/confirm_modal.py +0 -0
  311. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/context_bar.py +0 -0
  312. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/flash.py +0 -0
  313. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/header_bar.py +0 -0
  314. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/help_panel.py +0 -0
  315. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/human_prompt.py +0 -0
  316. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/mention_overlay.py +0 -0
  317. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/message_queue.py +0 -0
  318. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/new_messages_pill.py +0 -0
  319. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/overlay_mixin.py +0 -0
  320. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/permission_prompt.py +0 -0
  321. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/profile_dialog.py +0 -0
  322. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/prompt_info.py +0 -0
  323. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/rewind_picker.py +0 -0
  324. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/session_sidebar.py +0 -0
  325. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/skills_dialog.py +0 -0
  326. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/slash_overlay.py +0 -0
  327. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/status_bar.py +0 -0
  328. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/throbber.py +0 -0
  329. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/tool_progress.py +0 -0
  330. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/tools_dialog.py +0 -0
  331. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/welcome.py +0 -0
  332. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/widgets/whoami.py +0 -0
  333. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/app/tui/wire_events.py +0 -0
  334. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/__init__.py +0 -0
  335. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/MAINTAINING.md +0 -0
  336. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/agents/dreadnode.md +0 -0
  337. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/capability.yaml +0 -0
  338. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/SKILL.md +0 -0
  339. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/capability-improvement.md +0 -0
  340. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/methodology-grounding.md +0 -0
  341. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/prior-art-audit.md +0 -0
  342. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/promoting-capabilities.md +0 -0
  343. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/quality-bar.md +0 -0
  344. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/INDEX.md +0 -0
  345. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/agents.md +0 -0
  346. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/custom-engines.md +0 -0
  347. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/engines.md +0 -0
  348. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/env-vars.md +0 -0
  349. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/events.md +0 -0
  350. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/flags.md +0 -0
  351. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/installing.md +0 -0
  352. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/manifest.md +0 -0
  353. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/mcp-servers.md +0 -0
  354. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/overview.md +0 -0
  355. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/publishing.md +0 -0
  356. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/quickstart.md +0 -0
  357. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/skills.md +0 -0
  358. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/workers-reference.md +0 -0
  359. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/workers.md +0 -0
  360. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/capabilities/writing-skills.md +0 -0
  361. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references/sdk/agents.md +0 -0
  362. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/references-and-depth.md +0 -0
  363. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/runtime-default-capability.md +0 -0
  364. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/SKILL.md +0 -0
  365. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/INDEX.md +0 -0
  366. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/capability.md +0 -0
  367. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/dataset.md +0 -0
  368. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/env.md +0 -0
  369. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/inference-model.md +0 -0
  370. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/main.md +0 -0
  371. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/model.md +0 -0
  372. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/optimize.md +0 -0
  373. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/overview.md +0 -0
  374. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/runtime.md +0 -0
  375. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/sandbox.md +0 -0
  376. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/secret.md +0 -0
  377. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/task-set.md +0 -0
  378. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/task.md +0 -0
  379. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/train.md +0 -0
  380. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/cli/worlds.md +0 -0
  381. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/getting-started/authentication.md +0 -0
  382. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/SKILL.md +0 -0
  383. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/INDEX.md +0 -0
  384. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/capabilities/installing.md +0 -0
  385. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/capabilities/overview.md +0 -0
  386. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/getting-started/authentication.md +0 -0
  387. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/getting-started/overview.md +0 -0
  388. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/getting-started/quickstart.md +0 -0
  389. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/chat-models.md +0 -0
  390. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/credits.md +0 -0
  391. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/organizations.md +0 -0
  392. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/overview.md +0 -0
  393. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/projects.md +0 -0
  394. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/secrets.md +0 -0
  395. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/settings.md +0 -0
  396. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/platform/workspaces.md +0 -0
  397. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/runtimes/configuration.md +0 -0
  398. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/runtimes/managing.md +0 -0
  399. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/runtimes/manifest-reference.md +0 -0
  400. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/runtimes/overview.md +0 -0
  401. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/runtimes/quickstart.md +0 -0
  402. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/runtimes/serve.md +0 -0
  403. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/sandboxes/environment-lifecycle.md +0 -0
  404. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/sandboxes/inspecting.md +0 -0
  405. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/sandboxes/overview.md +0 -0
  406. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-concepts/references/sandboxes/runtime-limits.md +0 -0
  407. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/getting-started/SKILL.md +0 -0
  408. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/dreadnode/skills/research-capabilities/SKILL.md +0 -0
  409. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/.gitignore +0 -0
  410. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/capability.yaml +0 -0
  411. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/hooks/__init__.py +0 -0
  412. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/hooks/observer.py +0 -0
  413. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/self_improvement_lib/__init__.py +0 -0
  414. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/self_improvement_lib/classifier.py +0 -0
  415. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/self_improvement_lib/reflector_goal.py +0 -0
  416. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/self_improvement_lib/skill_io.py +0 -0
  417. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/skills-promoted/.gitkeep +0 -0
  418. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/skills-proposed/.gitkeep +0 -0
  419. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/tools/__init__.py +0 -0
  420. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/tools/reflector.py +0 -0
  421. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/builtin_capabilities/self-improvement/tools/skill_stats.py +0 -0
  422. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/__init__.py +0 -0
  423. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/capability.py +0 -0
  424. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/flags.py +0 -0
  425. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/sync.py +0 -0
  426. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/tool_rules.py +0 -0
  427. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/types.py +0 -0
  428. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/worker.py +0 -0
  429. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/capabilities/worker_runner.py +0 -0
  430. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/__init__.py +0 -0
  431. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/conditions.py +0 -0
  432. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/discovery.py +0 -0
  433. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/exceptions.py +0 -0
  434. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/execution.py +0 -0
  435. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/hook.py +0 -0
  436. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/judge.py +0 -0
  437. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/load.py +0 -0
  438. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/log.py +0 -0
  439. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/meta/__init__.py +0 -0
  440. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/meta/config.py +0 -0
  441. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/meta/context.py +0 -0
  442. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/meta/hydrate.py +0 -0
  443. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/meta/introspect.py +0 -0
  444. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/metric.py +0 -0
  445. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/object.py +0 -0
  446. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/scorer.py +0 -0
  447. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/serialization.py +0 -0
  448. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/stopping.py +0 -0
  449. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/task.py +0 -0
  450. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/templating.py +0 -0
  451. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/transforms.py +0 -0
  452. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/__init__.py +0 -0
  453. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/audio.py +0 -0
  454. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/base.py +0 -0
  455. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/common.py +0 -0
  456. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/image.py +0 -0
  457. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/object_3d.py +0 -0
  458. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/table.py +0 -0
  459. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/text.py +0 -0
  460. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/types/video.py +0 -0
  461. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/core/util.py +0 -0
  462. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/datasets/__init__.py +0 -0
  463. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/datasets/dataset.py +0 -0
  464. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/datasets/hf.py +0 -0
  465. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/datasets/local.py +0 -0
  466. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/evaluations/__init__.py +0 -0
  467. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/evaluations/console.py +0 -0
  468. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/evaluations/evaluation.py +0 -0
  469. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/evaluations/events.py +0 -0
  470. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/evaluations/format.py +0 -0
  471. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/evaluations/result.py +0 -0
  472. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/evaluations/sample.py +0 -0
  473. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/__init__.py +0 -0
  474. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/caching.py +0 -0
  475. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/chat.py +0 -0
  476. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/data.py +0 -0
  477. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/exceptions.py +0 -0
  478. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/generator/__init__.py +0 -0
  479. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/generator/base.py +0 -0
  480. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/generator/http.py +0 -0
  481. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/generator/litellm_.py +0 -0
  482. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/generator/transformers_.py +0 -0
  483. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/generator/vllm_.py +0 -0
  484. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/message.py +0 -0
  485. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/models.py +0 -0
  486. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/parsing.py +0 -0
  487. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/tokenizer/__init__.py +0 -0
  488. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/tokenizer/base.py +0 -0
  489. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/tokenizer/transformers_.py +0 -0
  490. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/generators/utils.py +0 -0
  491. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/items/__init__.py +0 -0
  492. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/items/config.py +0 -0
  493. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/items/models.py +0 -0
  494. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/judges/__init__.py +0 -0
  495. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/judges/outcome.py +0 -0
  496. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/judges/trajectory.py +0 -0
  497. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/judges/trajectory_tools.py +0 -0
  498. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/models/__init__.py +0 -0
  499. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/models/hf.py +0 -0
  500. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/models/local.py +0 -0
  501. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/models/model.py +0 -0
  502. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/__init__.py +0 -0
  503. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/adapters/__init__.py +0 -0
  504. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/adapters/_env_eval.py +0 -0
  505. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/adapters/agent.py +0 -0
  506. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/adapters/env.py +0 -0
  507. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/adapters/runtime.py +0 -0
  508. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/adapters/stack.py +0 -0
  509. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/api.py +0 -0
  510. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/backends/__init__.py +0 -0
  511. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/backends/base.py +0 -0
  512. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/backends/gepa.py +0 -0
  513. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/collectors.py +0 -0
  514. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/config.py +0 -0
  515. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/console.py +0 -0
  516. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/events.py +0 -0
  517. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/format.py +0 -0
  518. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/jobs.py +0 -0
  519. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/result.py +0 -0
  520. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/sampler.py +0 -0
  521. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/sampling.py +0 -0
  522. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/search.py +0 -0
  523. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/stopping.py +0 -0
  524. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/optimization/trial.py +0 -0
  525. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/packaging/__init__.py +0 -0
  526. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/packaging/loader.py +0 -0
  527. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/packaging/manifest.py +0 -0
  528. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/packaging/oci.py +0 -0
  529. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/packaging/package.py +0 -0
  530. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/packaging/task_validation.py +0 -0
  531. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/policies/__init__.py +0 -0
  532. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/policies/guard.py +0 -0
  533. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/policies/reconciliation.py +0 -0
  534. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/policies/rubrics/process/default.yaml +0 -0
  535. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/py.typed +0 -0
  536. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/__init__.py +0 -0
  537. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/boundary.py +0 -0
  538. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/fuzzing.py +0 -0
  539. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/graph.py +0 -0
  540. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/grid.py +0 -0
  541. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/image.py +0 -0
  542. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/mapelites.py +0 -0
  543. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/optuna.py +0 -0
  544. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/random.py +0 -0
  545. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/registry.py +0 -0
  546. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/samplers/strategy.py +0 -0
  547. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/__init__.py +0 -0
  548. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/advanced_jailbreak_detection.py +0 -0
  549. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/agent_security.py +0 -0
  550. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/agentic.py +0 -0
  551. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/agentic_workflow.py +0 -0
  552. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/attack_outcome.py +0 -0
  553. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/classification.py +0 -0
  554. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/consistency.py +0 -0
  555. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/contains.py +0 -0
  556. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/cosine_sim.py +0 -0
  557. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/credentials.py +0 -0
  558. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/crucible.py +0 -0
  559. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/documentation_security.py +0 -0
  560. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/exfiltration_detection.py +0 -0
  561. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/format.py +0 -0
  562. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/harm.py +0 -0
  563. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/ide_security.py +0 -0
  564. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/image.py +0 -0
  565. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/json.py +0 -0
  566. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/judge.py +0 -0
  567. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/judge_ensemble.py +0 -0
  568. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/length.py +0 -0
  569. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/lexical.py +0 -0
  570. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/mcp_security.py +0 -0
  571. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/memorization.py +0 -0
  572. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/multi_agent_security.py +0 -0
  573. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/pii.py +0 -0
  574. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/prompt_leak.py +0 -0
  575. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/readability.py +0 -0
  576. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/reasoning_security.py +0 -0
  577. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/sentiment.py +0 -0
  578. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/similarity.py +0 -0
  579. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/structural_detection.py +0 -0
  580. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/scorers/supply_chain_detection.py +0 -0
  581. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/storage/__init__.py +0 -0
  582. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/storage/providers.py +0 -0
  583. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/storage/session_store.py +0 -0
  584. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/storage/storage.py +0 -0
  585. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/__init__.py +0 -0
  586. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/_ripgrep.py +0 -0
  587. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/apply_patch.py +0 -0
  588. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/dreadnode_cli.py +0 -0
  589. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/editing.py +0 -0
  590. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/execute.py +0 -0
  591. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/fetch.py +0 -0
  592. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/glob.py +0 -0
  593. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/grep.py +0 -0
  594. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/interaction.py +0 -0
  595. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/ls.py +0 -0
  596. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/memory.py +0 -0
  597. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/project_memory.py +0 -0
  598. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/read.py +0 -0
  599. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/report.py +0 -0
  600. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/report_items.py +0 -0
  601. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/task.py +0 -0
  602. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/think.py +0 -0
  603. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/todo.py +0 -0
  604. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/trajectory_search.py +0 -0
  605. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/web_extract.py +0 -0
  606. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/web_search.py +0 -0
  607. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tools/write.py +0 -0
  608. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/__init__.py +0 -0
  609. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/convert.py +0 -0
  610. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/exporter.py +0 -0
  611. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/exporters.py +0 -0
  612. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/span.py +0 -0
  613. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/spans.py +0 -0
  614. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/tracing/trace_converter.py +0 -0
  615. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/__init__.py +0 -0
  616. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/_progress.py +0 -0
  617. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/base.py +0 -0
  618. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/dpo.py +0 -0
  619. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/env_rollouts.py +0 -0
  620. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/etl/__init__.py +0 -0
  621. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/etl/_common.py +0 -0
  622. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/etl/rl.py +0 -0
  623. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/etl/sft.py +0 -0
  624. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/etl/worlds.py +0 -0
  625. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/events.py +0 -0
  626. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/grpo.py +0 -0
  627. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/jobs.py +0 -0
  628. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/models.py +0 -0
  629. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ppo.py +0 -0
  630. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/prime.py +0 -0
  631. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/__init__.py +0 -0
  632. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/async_trainer.py +0 -0
  633. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/config.py +0 -0
  634. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/coordinator.py +0 -0
  635. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/distributed.py +0 -0
  636. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/dpo.py +0 -0
  637. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/experience.py +0 -0
  638. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/fsdp2_learner.py +0 -0
  639. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/inference.py +0 -0
  640. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/learner.py +0 -0
  641. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/multi_turn.py +0 -0
  642. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/ppo.py +0 -0
  643. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/reward_model.py +0 -0
  644. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/rollout_env.py +0 -0
  645. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/rollout_worker.py +0 -0
  646. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/sft.py +0 -0
  647. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/ray/trainer.py +0 -0
  648. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/recipes.py +0 -0
  649. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rewards/__init__.py +0 -0
  650. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rewards/aggregator.py +0 -0
  651. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rewards/functions.py +0 -0
  652. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rewards/scorer_bridge.py +0 -0
  653. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rewards/shaping.py +0 -0
  654. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rewards/types.py +0 -0
  655. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rollouts/__init__.py +0 -0
  656. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rollouts/adapters.py +0 -0
  657. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rollouts/agent_rollout.py +0 -0
  658. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rollouts/orchestrator.py +0 -0
  659. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rollouts/types.py +0 -0
  660. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/rollouts/worlds.py +0 -0
  661. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/serving/__init__.py +0 -0
  662. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/serving/vllm_client.py +0 -0
  663. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/sft.py +0 -0
  664. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/tinker/__init__.py +0 -0
  665. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/tinker/config.py +0 -0
  666. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/tinker/data.py +0 -0
  667. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/tinker/renderer.py +0 -0
  668. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/tinker/rl.py +0 -0
  669. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/tinker/trainer.py +0 -0
  670. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/tinker_sft.py +0 -0
  671. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/training/utils.py +0 -0
  672. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/__init__.py +0 -0
  673. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/advanced_jailbreak.py +0 -0
  674. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/adversarial_suffix.py +0 -0
  675. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/agent_skill.py +0 -0
  676. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/agentic_workflow.py +0 -0
  677. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/audio.py +0 -0
  678. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/backdoor_finetune.py +0 -0
  679. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/browser_agent_attacks.py +0 -0
  680. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/cipher.py +0 -0
  681. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/competitive_parity.py +0 -0
  682. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/constitutional.py +0 -0
  683. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/document.py +0 -0
  684. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/documentation_poison.py +0 -0
  685. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/encoding.py +0 -0
  686. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/exfiltration.py +0 -0
  687. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/flip_attack.py +0 -0
  688. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/guardrail_bypass.py +0 -0
  689. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/ide_injection.py +0 -0
  690. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/image.py +0 -0
  691. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/injection.py +0 -0
  692. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/json_tools.py +0 -0
  693. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/logic_bomb.py +0 -0
  694. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/mcp_attacks.py +0 -0
  695. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/multi_agent_attacks.py +0 -0
  696. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/multimodal_attacks.py +0 -0
  697. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/persuasion.py +0 -0
  698. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/perturbation.py +0 -0
  699. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/pii_extraction.py +0 -0
  700. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/pythonic_tools.py +0 -0
  701. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/rag_poisoning.py +0 -0
  702. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/reasoning_attacks.py +0 -0
  703. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/response_steering.py +0 -0
  704. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/structural_exploits.py +0 -0
  705. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/stylistic.py +0 -0
  706. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/substitution.py +0 -0
  707. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/supply_chain.py +0 -0
  708. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/swap.py +0 -0
  709. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/system_prompt_extraction.py +0 -0
  710. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/text.py +0 -0
  711. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/video.py +0 -0
  712. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/transforms/xml_tools.py +0 -0
  713. {dreadnode-2.0.35 → dreadnode-2.0.36}/dreadnode/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dreadnode
3
- Version: 2.0.35
3
+ Version: 2.0.36
4
4
  Summary: Dreadnode SDK
5
5
  Project-URL: Homepage, https://dreadnode.io
6
6
  Project-URL: Documentation, https://docs.dreadnode.io
@@ -51,6 +51,9 @@ Requires-Dist: transformers>=4.57.1
51
51
  Requires-Dist: uvicorn>=0.34.0
52
52
  Requires-Dist: websockets>=14.0
53
53
  Requires-Dist: xmltodict>=1.0.2
54
+ Provides-Extra: airt-ml
55
+ Requires-Dist: scikit-learn<2.0.0,>=1.7.1; extra == 'airt-ml'
56
+ Requires-Dist: torch>=2.9.0; extra == 'airt-ml'
54
57
  Provides-Extra: all
55
58
  Requires-Dist: confusables<2.0.0,>=1.2.0; extra == 'all'
56
59
  Requires-Dist: moviepy<3.0.0,>=2.1.2; extra == 'all'
@@ -133,6 +133,31 @@ def _is_transient_api_error(error: BaseException) -> bool:
133
133
  return False
134
134
 
135
135
 
136
+ def _replayable(messages: list[Message]) -> list[Message]:
137
+ """Drop assistant messages that carry nothing worth sending back.
138
+
139
+ A generation stopped by a content filter leaves an empty assistant message.
140
+ The trajectory keeps it — it is the record of what the provider did, and
141
+ the transcript renders a warning from it — but replaying it on the next
142
+ turn sends an empty text block, which some providers reject outright
143
+ (see ``CacheControlOnEmptyTextFixup``) and none can use (ENG-7585).
144
+
145
+ Reasoning lives in ``metadata``, not ``content``, so a thinking-only
146
+ message is still replayable and must survive this filter.
147
+ """
148
+
149
+ def carries_nothing(message: Message) -> bool:
150
+ return (
151
+ message.role == "assistant"
152
+ and not message.content
153
+ and not message.tool_calls
154
+ and not message.metadata.get("reasoning_content")
155
+ and not message.metadata.get("thinking_blocks")
156
+ )
157
+
158
+ return [message for message in messages if not carries_nothing(message)]
159
+
160
+
136
161
  class Agent(Executor[AgentEvent, Trajectory]):
137
162
  """
138
163
  Agent abstraction for applying tools, event logic, and message state to LLM generation.
@@ -776,7 +801,7 @@ class Agent(Executor[AgentEvent, Trajectory]):
776
801
  """
777
802
  traj = trajectory if trajectory is not None else self.trajectory
778
803
  messages = [
779
- *deepcopy(traj.messages),
804
+ *_replayable(deepcopy(traj.messages)),
780
805
  Message(
781
806
  "user",
782
807
  str(self._current_input),
@@ -925,6 +950,15 @@ class Agent(Executor[AgentEvent, Trajectory]):
925
950
  break
926
951
 
927
952
  step_chat.generated[-1].metadata.update(step_chat.extra)
953
+ # The provider's stop reason belongs to the assistant
954
+ # message, not to a particular event stream — stamping it
955
+ # here (before any event is dispatched) lets hooks,
956
+ # transcript reloads and non-live consumers all recover the
957
+ # same outcome live GenerationEnd observers see (ENG-7585).
958
+ if step_chat.stop_reason:
959
+ step_chat.generated[-1].metadata["generation_stop_reason"] = (
960
+ step_chat.stop_reason
961
+ )
928
962
  for msg in step_chat.generated:
929
963
  msg.metadata.setdefault("agent", self.name)
930
964
  msg.metadata.setdefault("model", self.model_name)
@@ -54,6 +54,16 @@ Image adversarial attacks:
54
54
 
55
55
  Multimodal attacks:
56
56
  - multimodal_attack: Transform-based multimodal probing (vision, audio, text)
57
+
58
+ Traditional-ML attacks (query a classifier predict API via PredictionTargetSpec):
59
+ - equation_solving_extraction: linear-model weight recovery (Tramèr'16)
60
+ - jacobian_extraction: Jacobian dataset augmentation (Papernot'17)
61
+ - copycat_extraction: hard-label distillation (CopycatCNN)
62
+ - knockoff_extraction: soft-label transfer-set extraction (Knockoff Nets)
63
+ - threshold_membership: confidence/entropy/loss-threshold membership inference (Yeom'18)
64
+ - label_only_membership: label-only membership inference (Choquette-Choo'21)
65
+ - confidence_inversion: MI-Face confidence-maximizing model inversion (Fredrikson'15)
66
+ - nes_inversion: NES-based confidence-maximizing model inversion
57
67
  """
58
68
 
59
69
  from dreadnode.airt.adversarial_reasoning import adversarial_reasoning_attack
@@ -72,6 +82,27 @@ from dreadnode.airt.crescendo import crescendo_attack
72
82
  from dreadnode.airt.deep_inception import deep_inception_attack
73
83
  from dreadnode.airt.drattack import drattack
74
84
  from dreadnode.airt.echo_chamber import echo_chamber_attack
85
+ from dreadnode.airt.evasion import (
86
+ bae_evasion,
87
+ boundary_evasion,
88
+ deepwordbug_evasion,
89
+ hopskipjump_evasion,
90
+ pwws_evasion,
91
+ simba_evasion,
92
+ square_evasion,
93
+ text_evasion,
94
+ textbugger_evasion,
95
+ textfooler_evasion,
96
+ zoo_evasion,
97
+ )
98
+ from dreadnode.airt.extraction import (
99
+ activethief_extraction,
100
+ copycat_extraction,
101
+ distillation_extraction,
102
+ equation_solving_extraction,
103
+ jacobian_extraction,
104
+ knockoff_extraction,
105
+ )
75
106
  from dreadnode.airt.genetic_persona import genetic_persona_attack
76
107
  from dreadnode.airt.goat import goat_attack
77
108
  from dreadnode.airt.goat_v2 import goat_v2_attack
@@ -83,11 +114,23 @@ from dreadnode.airt.image import (
83
114
  simba_attack,
84
115
  zoo_attack,
85
116
  )
117
+ from dreadnode.airt.inversion import (
118
+ confidence_inversion,
119
+ nes_inversion,
120
+ )
86
121
  from dreadnode.airt.j2_meta import j2_meta_attack
87
122
  from dreadnode.airt.jbdistill import jbdistill_attack
88
123
  from dreadnode.airt.jbfuzz import jbfuzz_attack
89
124
  from dreadnode.airt.lrm_autonomous import lrm_autonomous_attack
90
125
  from dreadnode.airt.mapf import mapf_attack
126
+ from dreadnode.airt.membership import (
127
+ entropy_membership,
128
+ label_only_membership,
129
+ lira_membership,
130
+ loss_membership,
131
+ shadow_model_membership,
132
+ threshold_membership,
133
+ )
91
134
  from dreadnode.airt.multimodal import multimodal_attack
92
135
  from dreadnode.airt.nexus import nexus_attack
93
136
  from dreadnode.airt.pair import pair_attack
@@ -104,8 +147,11 @@ from dreadnode.airt.siren import siren_attack
104
147
  from dreadnode.airt.tap import tap_attack
105
148
  from dreadnode.airt.target import extract_response_text, extract_tool_calls
106
149
  from dreadnode.airt.targets import (
150
+ Prediction,
151
+ PredictionTargetSpec,
107
152
  TargetAuth,
108
153
  TargetSpec,
154
+ build_prediction_target,
109
155
  build_target,
110
156
  nova_sonic_target,
111
157
  )
@@ -116,8 +162,11 @@ from dreadnode.airt.watermark_removal import watermark_removal_attack
116
162
 
117
163
  __all__ = [
118
164
  "Assessment",
165
+ "Prediction",
166
+ "PredictionTargetSpec",
119
167
  "TargetAuth",
120
168
  "TargetSpec",
169
+ "activethief_extraction",
121
170
  "adversarial_reasoning_attack",
122
171
  "advpromptier_attack",
123
172
  "alignment_faking_attack",
@@ -127,13 +176,22 @@ __all__ = [
127
176
  "attention_shifting_attack",
128
177
  "autodan_turbo_attack",
129
178
  "autoredteamer_attack",
179
+ "bae_evasion",
130
180
  "beast_attack",
181
+ "boundary_evasion",
182
+ "build_prediction_target",
131
183
  "build_target",
184
+ "confidence_inversion",
185
+ "copycat_extraction",
132
186
  "cot_jailbreak_attack",
133
187
  "crescendo_attack",
134
188
  "deep_inception_attack",
189
+ "deepwordbug_evasion",
190
+ "distillation_extraction",
135
191
  "drattack",
136
192
  "echo_chamber_attack",
193
+ "entropy_membership",
194
+ "equation_solving_extraction",
137
195
  "extract_response_text",
138
196
  "extract_tool_calls",
139
197
  "genetic_persona_attack",
@@ -141,19 +199,27 @@ __all__ = [
141
199
  "goat_v2_attack",
142
200
  "gptfuzzer_attack",
143
201
  "hopskipjump_attack",
202
+ "hopskipjump_evasion",
144
203
  "humor_bypass_attack",
145
204
  "j2_meta_attack",
205
+ "jacobian_extraction",
146
206
  "jbdistill_attack",
147
207
  "jbfuzz_attack",
208
+ "knockoff_extraction",
209
+ "label_only_membership",
210
+ "lira_membership",
211
+ "loss_membership",
148
212
  "lrm_autonomous_attack",
149
213
  "mapf_attack",
150
214
  "multimodal_attack",
151
215
  "nes_attack",
216
+ "nes_inversion",
152
217
  "nexus_attack",
153
218
  "nova_sonic_target",
154
219
  "pair_attack",
155
220
  "persona_hijack_attack",
156
221
  "prompt_attack",
222
+ "pwws_evasion",
157
223
  "quantization_safety_attack",
158
224
  "rainbow_attack",
159
225
  "refusal_aware_attack",
@@ -161,12 +227,20 @@ __all__ = [
161
227
  "reward_hacking_attack",
162
228
  "salami_slicing_attack",
163
229
  "self_persuasion_attack",
230
+ "shadow_model_membership",
164
231
  "simba_attack",
232
+ "simba_evasion",
165
233
  "siren_attack",
234
+ "square_evasion",
166
235
  "tap_attack",
167
236
  "templatefuzz_attack",
237
+ "text_evasion",
238
+ "textbugger_evasion",
239
+ "textfooler_evasion",
240
+ "threshold_membership",
168
241
  "tmap_trajectory_attack",
169
242
  "trojail_attack",
170
243
  "watermark_removal_attack",
171
244
  "zoo_attack",
245
+ "zoo_evasion",
172
246
  ]
@@ -0,0 +1,213 @@
1
+ """Shared base class for the black-box traditional-ML attacks.
2
+
3
+ Extraction, membership inference, and evasion all probe a black-box predict API
4
+ through the same :class:`PredictionTargetSpec` contract, count their queries,
5
+ capture a sample of the (input -> prediction) pairs they send, emit a top-level
6
+ ``study`` span, and enforce a query budget. This module factors that shared
7
+ plumbing into :class:`BlackBoxAttack` so each family only implements its own
8
+ algorithm and its own result-to-span mapping.
9
+
10
+ The base also provides ``_trace_step`` - a capped per-iteration span that records
11
+ the intermediate adversarial state (distance, best score, candidate label /
12
+ confidence, queries so far). Because we own the algorithm loop, every step of the
13
+ attack trajectory is visible in the platform's Traces tab, which is exactly what
14
+ off-the-shelf frameworks (ART, TextAttack) make hard to surface.
15
+ """
16
+
17
+ import typing as t
18
+ from contextlib import nullcontext, suppress
19
+
20
+ import numpy as np
21
+
22
+ from dreadnode.airt.targets.prediction import (
23
+ Prediction,
24
+ PredictionTargetSpec,
25
+ QueryInput,
26
+ predict_many,
27
+ )
28
+
29
+
30
+ @t.runtime_checkable
31
+ class AttackResult(t.Protocol):
32
+ """The common surface every attack result exposes so :meth:`BlackBoxAttack.run`
33
+ can emit spans generically."""
34
+
35
+ query_samples: list[dict[str, t.Any]]
36
+
37
+ @property
38
+ def best_score(self) -> float: ...
39
+
40
+ @property
41
+ def metrics_detail(self) -> dict[str, t.Any]: ...
42
+
43
+
44
+ def sample_input_preview(x: t.Any, n: int = 60) -> str:
45
+ """A compact, display-safe preview of a queried input (text snippet or a few
46
+ numeric features) for the finding's query sample table."""
47
+ if isinstance(x, str):
48
+ return x if len(x) <= n else x[:n] + "..."
49
+ try:
50
+ arr = np.asarray(x, dtype=np.float64).ravel()
51
+ except Exception:
52
+ return str(x)[:n]
53
+ head = ", ".join(f"{v:.3g}" for v in arr[:6])
54
+ return f"[{head}{', ...' if arr.size > 6 else ''}] ({arr.size}d)"
55
+
56
+
57
+ class BlackBoxAttack:
58
+ """Base for a configured black-box attack against a predict API.
59
+
60
+ Subclasses set :attr:`attack_domain` (`model_extraction` /
61
+ `membership_inference` / `adversarial_ml`), a default goal, and implement
62
+ :meth:`_attack_name`, :meth:`_execute`, and :meth:`_span_attributes`. The
63
+ query counter, query-sample capture, phase/step tracing, and the top-level
64
+ ``study`` span are shared here.
65
+ """
66
+
67
+ #: One of "model_extraction", "membership_inference", "adversarial_ml".
68
+ attack_domain: str = ""
69
+ default_goal: str = ""
70
+ default_goal_category: str = ""
71
+
72
+ def __init__(
73
+ self,
74
+ *,
75
+ target: PredictionTargetSpec,
76
+ modality: str = "tabular",
77
+ max_queries: int = 500,
78
+ max_iterations: int = 30,
79
+ seed: int | None = None,
80
+ airt_assessment_id: str | None = None,
81
+ airt_target_model: str | None = None,
82
+ airt_goal: str | None = None,
83
+ airt_goal_category: str | None = None,
84
+ ) -> None:
85
+ self.target = target
86
+ self.modality = modality
87
+ self.max_queries = max_queries
88
+ self.max_iterations = max_iterations
89
+ self.rng = np.random.default_rng(seed)
90
+ self.airt_assessment_id = airt_assessment_id
91
+ self.airt_target_model = airt_target_model or target.name
92
+ self.airt_goal = airt_goal or self.default_goal
93
+ self.airt_goal_category = airt_goal_category or self.default_goal_category
94
+ self._query_count = 0
95
+ #: A sample of real (input -> prediction) pairs so the finding can show
96
+ #: the actual queries the attacker sent, not just the total count.
97
+ self._query_samples: list[dict[str, t.Any]] = []
98
+
99
+ # -- target I/O -------------------------------------------------------- #
100
+ async def _query(self, xs: t.Sequence[QueryInput]) -> list[Prediction]:
101
+ """Query the target, count the queries, and capture a sample."""
102
+ preds = await predict_many(self.target, xs)
103
+ self._query_count += len(xs)
104
+ self._capture_samples(xs, preds)
105
+ return preds
106
+
107
+ def _capture_samples(
108
+ self, xs: t.Sequence[QueryInput], preds: t.Sequence[Prediction], limit: int = 12
109
+ ) -> None:
110
+ for x, p in zip(xs, preds, strict=False):
111
+ if len(self._query_samples) >= limit:
112
+ return
113
+ vec = p.vector
114
+ conf = float(max(vec)) if vec is not None and len(vec) else None
115
+ self._query_samples.append(
116
+ {
117
+ "input": sample_input_preview(x),
118
+ "label": p.hard_label,
119
+ "confidence": round(conf, 4) if conf is not None else None,
120
+ }
121
+ )
122
+
123
+ # -- budget ------------------------------------------------------------ #
124
+ def _budget_left(self) -> int:
125
+ return max(0, self.max_queries - self._query_count)
126
+
127
+ def _over_budget(self) -> bool:
128
+ return self._query_count >= self.max_queries
129
+
130
+ # -- tracing ----------------------------------------------------------- #
131
+ def _phase(self, name: str, **attrs: t.Any) -> t.Any:
132
+ """A coarse task-span phase (e.g. 'perturb + probe target')."""
133
+ try:
134
+ import dreadnode as dn
135
+
136
+ return dn.task_span(name, type="task", attributes={str(k): v for k, v in attrs.items()})
137
+ except Exception:
138
+ return nullcontext()
139
+
140
+ def _trace_step(
141
+ self,
142
+ iteration: int,
143
+ *,
144
+ input: t.Any = None,
145
+ output: t.Any = None,
146
+ metrics: dict[str, float] | None = None,
147
+ **attrs: t.Any,
148
+ ) -> None:
149
+ """Emit a point-in-time span for one algorithm iteration, recording the
150
+ intermediate adversarial state so the full attack trajectory is
151
+ inspectable in the Traces tab.
152
+
153
+ ``input`` is the current candidate (perturbed text / feature vector /
154
+ image preview) the attacker sent; ``output`` is the target's response at
155
+ this step (predicted label + confidence); ``metrics`` are the scalar
156
+ signals (distance, confidence, fidelity) plotted over the run. Capped
157
+ (first 20 iterations, then every 10th) so a long run does not explode the
158
+ trace tree."""
159
+ if iteration >= 20 and iteration % 10 != 0:
160
+ return
161
+ with self._phase(f"step {iteration}", iteration=iteration, **attrs) as span:
162
+ if span is None or not hasattr(span, "log_input"):
163
+ return
164
+ with suppress(Exception):
165
+ if input is not None:
166
+ span.log_input("candidate", input)
167
+ if output is not None:
168
+ span.log_output("prediction", output)
169
+ for key, value in (metrics or {}).items():
170
+ span.log_metric(key, float(value), step=iteration)
171
+
172
+ # -- run scaffold ------------------------------------------------------ #
173
+ @property
174
+ def _attack_name(self) -> str:
175
+ raise NotImplementedError
176
+
177
+ def _study_kwargs(self) -> dict[str, t.Any]:
178
+ """Extra ``study_span`` kwargs beyond the common set (e.g. distance norm)."""
179
+ return {}
180
+
181
+ def _span_attributes(self, result: t.Any) -> dict[str, t.Any]:
182
+ """Map the result onto the ``AIRT_ATTRIBUTE_*`` span attributes to set.
183
+ ``None`` values are skipped."""
184
+ raise NotImplementedError
185
+
186
+ async def _execute(self) -> t.Any:
187
+ raise NotImplementedError
188
+
189
+ async def run(self) -> t.Any:
190
+ import json
191
+
192
+ from dreadnode.tracing.constants import AIRT_ATTRIBUTE_METRICS_DETAIL
193
+ from dreadnode.tracing.spans import study_span
194
+
195
+ with study_span(
196
+ name=self._attack_name,
197
+ airt_assessment_id=self.airt_assessment_id,
198
+ airt_attack_name=self._attack_name,
199
+ airt_attack_domain=self.attack_domain,
200
+ airt_target_model=self.airt_target_model,
201
+ airt_input_modality=self.modality,
202
+ airt_goal=self.airt_goal,
203
+ airt_goal_category=self.airt_goal_category,
204
+ **self._study_kwargs(),
205
+ ) as span:
206
+ result = await self._execute()
207
+ if hasattr(result, "query_samples"):
208
+ result.query_samples = self._query_samples
209
+ for key, value in self._span_attributes(result).items():
210
+ if value is not None:
211
+ span.set_attribute(key, value)
212
+ span.set_attribute(AIRT_ATTRIBUTE_METRICS_DETAIL, json.dumps(result.metrics_detail))
213
+ return result
@@ -0,0 +1,183 @@
1
+ """Optional ART (Adversarial Robustness Toolbox) engine for the traditional-ML
2
+ privacy attacks.
3
+
4
+ When ``adversarial-robustness-toolbox`` is installed (the ``airt-ml`` extra), the
5
+ extraction and membership attacks route their core step through ART's reference
6
+ implementations - CopycatCNN / KnockoffNets for extraction, the black-box
7
+ membership inference attacks for membership - instead of the native
8
+ numpy/sklearn engine. Everything here is import-guarded: if ART (or torch) is
9
+ missing, :func:`art_available` returns ``False`` and callers fall back to the
10
+ native engine, so the base SDK never hard-depends on ART.
11
+
12
+ The victim is always wrapped as a black-box: ART only ever sees a
13
+ ``predict_fn`` backed by predictions we already collected from the target's API,
14
+ so no extra queries are issued and the attack stays honestly black-box.
15
+ """
16
+
17
+ import typing as t
18
+
19
+ import numpy as np
20
+ from loguru import logger
21
+
22
+
23
+ def art_available() -> bool:
24
+ """True when the Adversarial Robustness Toolbox and torch import cleanly.
25
+
26
+ We check for ``art.attacks.extraction`` specifically, not just ``import art``:
27
+ the top-level ``art`` name is also owned by the ASCII-art package the SDK
28
+ depends on, so a bare ``import art`` would false-positive on that library.
29
+ ART is not a hard dependency (it collides with the ASCII-art ``art``); this
30
+ returns True only in an environment where the adversarial toolbox is actually
31
+ installed, otherwise the native engine runs.
32
+ """
33
+ try:
34
+ import torch # noqa: F401
35
+ from art.attacks.extraction import CopycatCNN # noqa: F401
36
+ from art.estimators.classification import BlackBoxClassifier # noqa: F401
37
+ except Exception:
38
+ return False
39
+ return True
40
+
41
+
42
+ def _cached_victim(
43
+ x: np.ndarray,
44
+ proba: np.ndarray,
45
+ nb_classes: int,
46
+ ) -> t.Any:
47
+ """A BlackBoxClassifier whose predict_fn replays already-collected target
48
+ probabilities, keyed by feature-row bytes - ART "queries" it without issuing
49
+ a single extra network call."""
50
+ from art.estimators.classification import BlackBoxClassifier
51
+
52
+ lookup = {row.tobytes(): proba[i] for i, row in enumerate(np.ascontiguousarray(x))}
53
+ uniform = np.full(nb_classes, 1.0 / nb_classes)
54
+
55
+ def predict_fn(batch: np.ndarray) -> np.ndarray:
56
+ rows = np.ascontiguousarray(batch, dtype=x.dtype)
57
+ return np.asarray([lookup.get(r.tobytes(), uniform) for r in rows])
58
+
59
+ return BlackBoxClassifier(
60
+ predict_fn=predict_fn,
61
+ input_shape=(x.shape[1],),
62
+ nb_classes=nb_classes,
63
+ )
64
+
65
+
66
+ def _torch_thieved(n_features: int, nb_classes: int) -> t.Any:
67
+ """A small torch MLP wrapped as an ART PyTorchClassifier - the surrogate that
68
+ ART trains to replicate the victim."""
69
+ import torch
70
+ from art.estimators.classification import PyTorchClassifier
71
+ from torch import nn
72
+
73
+ torch.manual_seed(0)
74
+ model = nn.Sequential(
75
+ nn.Linear(n_features, 128),
76
+ nn.ReLU(),
77
+ nn.Linear(128, 64),
78
+ nn.ReLU(),
79
+ nn.Linear(64, nb_classes),
80
+ )
81
+ return PyTorchClassifier(
82
+ model=model,
83
+ loss=nn.CrossEntropyLoss(),
84
+ optimizer=torch.optim.Adam(model.parameters(), lr=1e-3),
85
+ input_shape=(n_features,),
86
+ nb_classes=nb_classes,
87
+ clip_values=(-1e9, 1e9),
88
+ device_type="cpu",
89
+ )
90
+
91
+
92
+ def art_extract_surrogate(
93
+ strategy: str,
94
+ x: np.ndarray,
95
+ proba: np.ndarray,
96
+ nb_classes: int,
97
+ *,
98
+ nb_epochs: int = 30,
99
+ ) -> t.Any | None:
100
+ """Train a thieved classifier with ART's CopycatCNN (copycat) or KnockoffNets
101
+ (knockoff) against a cached black-box victim.
102
+
103
+ Returns the trained ART classifier (its ``.predict`` yields probabilities), or
104
+ ``None`` if ART is unavailable or the run fails - the caller then falls back to
105
+ the native surrogate. Only ``copycat`` and ``knockoff`` map onto ART; the other
106
+ strategies stay native.
107
+ """
108
+ if strategy not in ("copycat", "knockoff") or not art_available():
109
+ return None
110
+ try:
111
+ from art.attacks.extraction import CopycatCNN, KnockoffNets
112
+
113
+ x = np.ascontiguousarray(x, dtype=np.float32)
114
+ victim = _cached_victim(x, proba, nb_classes)
115
+ thieved = _torch_thieved(x.shape[1], nb_classes)
116
+ n = len(x)
117
+ if strategy == "copycat":
118
+ attack: t.Any = CopycatCNN(
119
+ classifier=victim,
120
+ batch_size_fit=32,
121
+ batch_size_query=32,
122
+ nb_epochs=nb_epochs,
123
+ nb_stolen=n,
124
+ use_probability=False,
125
+ )
126
+ else: # knockoff - soft-label transfer set
127
+ attack = KnockoffNets(
128
+ classifier=victim,
129
+ batch_size_fit=32,
130
+ batch_size_query=32,
131
+ nb_epochs=nb_epochs,
132
+ nb_stolen=n,
133
+ sampling_strategy="random",
134
+ reward="all",
135
+ verbose=False,
136
+ use_probability=True,
137
+ )
138
+ stolen = attack.extract(x=x, thieved_classifier=thieved)
139
+ except Exception as e: # pragma: no cover - defensive fallback
140
+ logger.warning("ART extraction ({}) failed, falling back to native: {}", strategy, e)
141
+ return None
142
+ else:
143
+ logger.debug("ART {} extraction trained thieved classifier on {} samples", strategy, n)
144
+ return stolen
145
+
146
+
147
+ def art_membership_scores(
148
+ method: str,
149
+ members_x: np.ndarray,
150
+ nonmembers_x: np.ndarray,
151
+ member_proba: np.ndarray,
152
+ nonmember_proba: np.ndarray,
153
+ member_labels: np.ndarray,
154
+ nonmember_labels: np.ndarray,
155
+ nb_classes: int,
156
+ ) -> np.ndarray | None:
157
+ """Per-record membership scores via ART's black-box rule-based membership
158
+ inference (Yeom et al.). Returns an array aligned to
159
+ ``[members..., nonmembers...]`` in ``[0, 1]``, or ``None`` to fall back to
160
+ native. Only the ``threshold`` method maps onto ART's black-box rule-based
161
+ attack; ``label_only`` stays native.
162
+ """
163
+ if method != "threshold" or not art_available():
164
+ return None
165
+ try:
166
+ from art.attacks.inference.membership_inference import (
167
+ MembershipInferenceBlackBoxRuleBased,
168
+ )
169
+
170
+ x = np.ascontiguousarray(np.vstack([members_x, nonmembers_x]), dtype=np.float32)
171
+ proba = np.vstack([member_proba, nonmember_proba])
172
+ labels = np.concatenate([member_labels, nonmember_labels]).astype(int)
173
+ victim = _cached_victim(x, proba, nb_classes)
174
+ attack = MembershipInferenceBlackBoxRuleBased(classifier=victim)
175
+ scores = np.asarray(attack.infer(x, labels, probabilities=True), dtype=np.float64)
176
+ # infer(probabilities=True) returns (N, 2) = [P(non-member), P(member)];
177
+ # the member column is the per-record membership score.
178
+ if scores.ndim == 2 and scores.shape[1] == 2:
179
+ scores = scores[:, 1]
180
+ return scores.ravel()
181
+ except Exception as e: # pragma: no cover - defensive fallback
182
+ logger.warning("ART membership (threshold) failed, falling back to native: {}", e)
183
+ return None
@@ -181,6 +181,12 @@ class Assessment:
181
181
  async def __aenter__(self) -> Assessment:
182
182
  self._context_token = _current_assessment.set(self)
183
183
  self._tracing_enabled = True
184
+ # Register on enter so the assessment id is available to any attack run
185
+ # inside the block - including the traditional-ML privacy attacks that
186
+ # call their own .run() (not assessment.run()). study_span picks up the
187
+ # active assessment via the _current_assessment ContextVar, so the user
188
+ # never has to call register()/complete() or pass airt_assessment_id.
189
+ await self._ensure_started()
184
190
  return self
185
191
 
186
192
  async def __aexit__(
@@ -296,7 +302,11 @@ class Assessment:
296
302
 
297
303
  async def _finalize(self) -> None:
298
304
  """Flush pending OTEL spans and mark complete."""
299
- if not self._attack_results:
305
+ # Complete when there is something to finalize: the generative path
306
+ # populates _attack_results, while the privacy attacks emit study spans
307
+ # under a registered assessment (id set on __aenter__). Skip only when
308
+ # both are absent (offline / never used).
309
+ if not self._attack_results and self._assessment_id is None:
300
310
  return
301
311
 
302
312
  # Flush pending OTEL spans BEFORE marking complete so CH has data
@@ -15,6 +15,7 @@ from dreadnode.core.meta import TrialCandidate
15
15
  from dreadnode.core.scorer import Scorer
16
16
  from dreadnode.core.transforms import Transform, TransformsLike
17
17
  from dreadnode.generators.generator import Generator, get_generator
18
+ from dreadnode.generators.proxy import resolve_dn_model_to_generator
18
19
  from dreadnode.optimization import Study
19
20
  from dreadnode.optimization.stopping import score_value
20
21
  from dreadnode.samplers import iterative_sampler
@@ -122,12 +123,15 @@ def crescendo_attack(
122
123
  # Replace {goal} placeholder in the template
123
124
  system_prompt_template = variant_system_prompt.format(goal=goal)
124
125
 
125
- # Resolve generator once for reuse across turns
126
+ # Resolve generator once for reuse across turns. `dn/*` ids route through the
127
+ # platform gateway (get_generator can't resolve them); non-dn strings pass
128
+ # through unchanged.
129
+ resolved_attacker = resolve_dn_model_to_generator(attacker_model)
126
130
  attacker_generator: Generator
127
- if isinstance(attacker_model, Generator):
128
- attacker_generator = attacker_model
131
+ if isinstance(resolved_attacker, Generator):
132
+ attacker_generator = resolved_attacker
129
133
  else:
130
- attacker_generator = get_generator(attacker_model)
134
+ attacker_generator = get_generator(resolved_attacker)
131
135
 
132
136
  # Create the refiner that generates the next prompt in the conversation
133
137
  async def crescendo_refiner(trials: "list[Trial[str]]") -> str: