hackagent 0.15.0__tar.gz → 0.16.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. {hackagent-0.15.0 → hackagent-0.16.0}/.gitignore +5 -0
  2. hackagent-0.16.0/PKG-INFO +121 -0
  3. hackagent-0.16.0/README.md +80 -0
  4. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/decorators/base.py +17 -3
  5. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/mml/image_encoder.py +35 -17
  6. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/hermes/README.md +7 -5
  7. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/commands/examples.py +48 -0
  8. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/app.py +26 -0
  9. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/form.py +7 -3
  10. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/schema.py +20 -0
  11. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/cli.py +12 -0
  12. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/codex.py +6 -3
  13. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/hermes.py +46 -16
  14. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/overrides.py +7 -1
  15. {hackagent-0.15.0 → hackagent-0.16.0}/pyproject.toml +3 -3
  16. hackagent-0.15.0/PKG-INFO +0 -204
  17. hackagent-0.15.0/README.md +0 -163
  18. {hackagent-0.15.0 → hackagent-0.16.0}/LICENSE +0 -0
  19. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/__init__.py +0 -0
  20. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/_version.py +0 -0
  21. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/__init__.py +0 -0
  22. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/_lib/__init__.py +0 -0
  23. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/_lib/graphviz.py +0 -0
  24. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/_lib/prompt_parser.py +0 -0
  25. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/_lib/response.py +0 -0
  26. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/_lib/templates.py +0 -0
  27. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/_lib/transforms.py +0 -0
  28. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/__init__.py +0 -0
  29. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/__init__.py +0 -0
  30. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/advprefix/__init__.py +0 -0
  31. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/advprefix/attack.py +0 -0
  32. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/advprefix/config.py +0 -0
  33. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/advprefix/prompts.py +0 -0
  34. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/autodan_turbo/__init__.py +0 -0
  35. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/autodan_turbo/attack.py +0 -0
  36. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/autodan_turbo/config.py +0 -0
  37. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/autodan_turbo/library.py +0 -0
  38. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/autodan_turbo/prompts.py +0 -0
  39. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/bon/__init__.py +0 -0
  40. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/bon/attack.py +0 -0
  41. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/bon/augment.py +0 -0
  42. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/bon/config.py +0 -0
  43. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pair/__init__.py +0 -0
  44. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pair/attack.py +0 -0
  45. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pair/config.py +0 -0
  46. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pair/prompts.py +0 -0
  47. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pap/__init__.py +0 -0
  48. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pap/attack.py +0 -0
  49. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pap/config.py +0 -0
  50. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/pap/taxonomy.py +0 -0
  51. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/tap/__init__.py +0 -0
  52. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/tap/attack.py +0 -0
  53. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/tap/config.py +0 -0
  54. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/adaptive/tap/prompts.py +0 -0
  55. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/contract.py +0 -0
  56. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/__init__.py +0 -0
  57. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/rag/__init__.py +0 -0
  58. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/rag/attack.py +0 -0
  59. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/rag/config.py +0 -0
  60. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/rag/prompts.py +0 -0
  61. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/rag/retrieval.py +0 -0
  62. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/tool_output_ipi/__init__.py +0 -0
  63. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/tool_output_ipi/attack.py +0 -0
  64. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/tool_output_ipi/config.py +0 -0
  65. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/indirect/tool_output_ipi/prompts.py +0 -0
  66. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/iterative.py +0 -0
  67. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/multi_turn/__init__.py +0 -0
  68. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/multi_turn/crescendo/__init__.py +0 -0
  69. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/multi_turn/crescendo/attack.py +0 -0
  70. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/multi_turn/crescendo/config.py +0 -0
  71. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/multi_turn/crescendo/prompts.py +0 -0
  72. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/registry.py +0 -0
  73. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/__init__.py +0 -0
  74. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/base.py +0 -0
  75. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/baseline/__init__.py +0 -0
  76. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/baseline/attack.py +0 -0
  77. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/baseline/config.py +0 -0
  78. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/__init__.py +0 -0
  79. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/attack.py +0 -0
  80. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/config.py +0 -0
  81. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/demonstrations.py +0 -0
  82. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/encodings/__init__.py +0 -0
  83. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/encodings/base.py +0 -0
  84. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/encodings/byte_escape.py +0 -0
  85. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/encodings/mapping.py +0 -0
  86. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/encodings/prompts.py +0 -0
  87. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/cipherchat/encodings/registry.py +0 -0
  88. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/fc/__init__.py +0 -0
  89. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/fc/attack.py +0 -0
  90. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/fc/config.py +0 -0
  91. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/fc/flowchart_renderer.py +0 -0
  92. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/fc/prompts.py +0 -0
  93. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/flipattack/__init__.py +0 -0
  94. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/flipattack/attack.py +0 -0
  95. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/flipattack/config.py +0 -0
  96. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/flipattack/prompts.py +0 -0
  97. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/__init__.py +0 -0
  98. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/attack.py +0 -0
  99. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/config.py +0 -0
  100. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/decorators/__init__.py +0 -0
  101. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/decorators/compiler.py +0 -0
  102. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/decorators/llm.py +0 -0
  103. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/decorators/static.py +0 -0
  104. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/h4rm3l/programs.py +0 -0
  105. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/mml/__init__.py +0 -0
  106. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/mml/attack.py +0 -0
  107. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/mml/config.py +0 -0
  108. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/mml/prompts.py +0 -0
  109. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/static_template/__init__.py +0 -0
  110. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/static_template/attack.py +0 -0
  111. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/static_template/config.py +0 -0
  112. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/static/static_template/templates.py +0 -0
  113. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/attacks/techniques/trace.py +0 -0
  114. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/__init__.py +0 -0
  115. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/attacks.py +0 -0
  116. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/__init__.py +0 -0
  117. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/base.py +0 -0
  118. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/craft_adversarial_data/__init__.py +0 -0
  119. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/craft_adversarial_data/profile.py +0 -0
  120. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/craft_adversarial_data/types.py +0 -0
  121. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/craft_adversarial_data/vulnerabilities.py +0 -0
  122. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/credential_exposure/__init__.py +0 -0
  123. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/credential_exposure/profile.py +0 -0
  124. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/credential_exposure/types.py +0 -0
  125. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/credential_exposure/vulnerabilities.py +0 -0
  126. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/excessive_agency/__init__.py +0 -0
  127. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/excessive_agency/profile.py +0 -0
  128. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/excessive_agency/types.py +0 -0
  129. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/excessive_agency/vulnerabilities.py +0 -0
  130. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/input_manipulation_attack/__init__.py +0 -0
  131. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/input_manipulation_attack/profile.py +0 -0
  132. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/input_manipulation_attack/types.py +0 -0
  133. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/input_manipulation_attack/vulnerabilities.py +0 -0
  134. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/jailbreak/__init__.py +0 -0
  135. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/jailbreak/profile.py +0 -0
  136. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/jailbreak/types.py +0 -0
  137. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/jailbreak/vulnerabilities.py +0 -0
  138. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/malicious_tool_invocation/__init__.py +0 -0
  139. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/malicious_tool_invocation/profile.py +0 -0
  140. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/malicious_tool_invocation/types.py +0 -0
  141. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/malicious_tool_invocation/vulnerabilities.py +0 -0
  142. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/misinformation/__init__.py +0 -0
  143. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/misinformation/profile.py +0 -0
  144. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/misinformation/types.py +0 -0
  145. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/misinformation/vulnerabilities.py +0 -0
  146. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/model_evasion/__init__.py +0 -0
  147. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/model_evasion/profile.py +0 -0
  148. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/model_evasion/types.py +0 -0
  149. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/model_evasion/vulnerabilities.py +0 -0
  150. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/profile_helpers.py +0 -0
  151. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/profile_types.py +0 -0
  152. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/prompt_injection/__init__.py +0 -0
  153. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/prompt_injection/profile.py +0 -0
  154. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/prompt_injection/templates.py +0 -0
  155. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/prompt_injection/types.py +0 -0
  156. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/prompt_injection/vulnerabilities.py +0 -0
  157. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/public_facing_application_exploitation/__init__.py +0 -0
  158. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/public_facing_application_exploitation/profile.py +0 -0
  159. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/public_facing_application_exploitation/types.py +0 -0
  160. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/public_facing_application_exploitation/vulnerabilities.py +0 -0
  161. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/registry.py +0 -0
  162. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/sensitive_information_disclosure/__init__.py +0 -0
  163. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/sensitive_information_disclosure/profile.py +0 -0
  164. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/sensitive_information_disclosure/types.py +0 -0
  165. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/sensitive_information_disclosure/vulnerabilities.py +0 -0
  166. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/system_prompt_leakage/__init__.py +0 -0
  167. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/system_prompt_leakage/profile.py +0 -0
  168. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/system_prompt_leakage/types.py +0 -0
  169. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/system_prompt_leakage/vulnerabilities.py +0 -0
  170. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/utils.py +0 -0
  171. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/vector_embedding_weaknesses_exploit/__init__.py +0 -0
  172. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/vector_embedding_weaknesses_exploit/profile.py +0 -0
  173. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/vector_embedding_weaknesses_exploit/types.py +0 -0
  174. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/risks/vector_embedding_weaknesses_exploit/vulnerabilities.py +0 -0
  175. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/catalog/taxonomy.py +0 -0
  176. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/client.py +0 -0
  177. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/__init__.py +0 -0
  178. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/async_utils.py +0 -0
  179. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/__init__.py +0 -0
  180. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/_base.py +0 -0
  181. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/completion.py +0 -0
  182. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/enums.py +0 -0
  183. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/judging.py +0 -0
  184. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/messages.py +0 -0
  185. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/protocols.py +0 -0
  186. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/contracts/specs.py +0 -0
  187. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/defaults.py +0 -0
  188. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/errors.py +0 -0
  189. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/logging.py +0 -0
  190. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/core/settings.py +0 -0
  191. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/__init__.py +0 -0
  192. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/base.py +0 -0
  193. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/calibration.py +0 -0
  194. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/config.py +0 -0
  195. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/goals.py +0 -0
  196. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/intents.py +0 -0
  197. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/labelling.py +0 -0
  198. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/omnisafebench/dataset.json +0 -0
  199. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/presets.py +0 -0
  200. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/providers/__init__.py +0 -0
  201. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/providers/file.py +0 -0
  202. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/providers/huggingface.py +0 -0
  203. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/providers/url_json.py +0 -0
  204. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/registry.py +0 -0
  205. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/taxonomy.py +0 -0
  206. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/datasets/taxonomy.yaml +0 -0
  207. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/__init__.py +0 -0
  208. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/audit.py +0 -0
  209. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/base.py +0 -0
  210. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/config.py +0 -0
  211. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/judges.py +0 -0
  212. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/metrics.py +0 -0
  213. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/panel.py +0 -0
  214. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/evaluation/patterns.py +0 -0
  215. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/__init__.py +0 -0
  216. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/claude/README.md +0 -0
  217. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/claude/flipattack-claude.yaml +0 -0
  218. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/claude/flipattack-ollama.yaml +0 -0
  219. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/codex/README.md +0 -0
  220. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/codex/h4rm3l-codex.yaml +0 -0
  221. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/codex/h4rm3l-ollama.yaml +0 -0
  222. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/google_adk/jailbreak_eval/__init__.py +0 -0
  223. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/google_adk/jailbreak_eval/advprefix-adk.yaml +0 -0
  224. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/google_adk/jailbreak_eval/agent.py +0 -0
  225. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/google_adk/multi_tool_agent/__init__.py +0 -0
  226. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/google_adk/multi_tool_agent/advprefix-multi-tool.yaml +0 -0
  227. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/google_adk/multi_tool_agent/agent.py +0 -0
  228. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/hermes/flipattack-hermes.yaml +0 -0
  229. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/langchain/rag/README.md +0 -0
  230. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/langchain/rag/advprefix-corpbot.yaml +0 -0
  231. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/langchain/rag/agent_client.py +0 -0
  232. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/langchain/rag/agent_server.py +0 -0
  233. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/langchain/rag/ingest.py +0 -0
  234. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/langchain/rag/policies.pdf +0 -0
  235. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/langchain/rag/read_db.py +0 -0
  236. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/litellm_multi_provider/README.md +0 -0
  237. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/litellm_multi_provider/__init__.py +0 -0
  238. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/litellm_multi_provider/tap-any-provider.yaml +0 -0
  239. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/ollama/flipattack-local.yaml +0 -0
  240. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/ollama/h4rm3l-demo.yaml +0 -0
  241. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/ollama/risk-evaluation.yaml +0 -0
  242. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/db_tool_sandbox/README.md +0 -0
  243. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/db_tool_sandbox/agent.py +0 -0
  244. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/db_tool_sandbox/flipattack-sqldesk.yaml +0 -0
  245. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/db_tool_sandbox/sandbox.db +0 -0
  246. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/multi_judge/README.md +0 -0
  247. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/multi_judge/flipattack-multi-judge.yaml +0 -0
  248. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/pc_tool_sandbox/README.md +0 -0
  249. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/pc_tool_sandbox/agent.py +0 -0
  250. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/pc_tool_sandbox/confidential/db_credentials.txt +0 -0
  251. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/pc_tool_sandbox/pair-vaultdesk.yaml +0 -0
  252. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/quick_evaluation/README.md +0 -0
  253. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/quick_evaluation/h4rm3l-granite.yaml +0 -0
  254. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/rag/README.md +0 -0
  255. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/rag/agent_server.py +0 -0
  256. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/rag/h4rm3l-corpbot.yaml +0 -0
  257. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/rag/ingest.py +0 -0
  258. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/openai_sdk/rag/policies.pdf +0 -0
  259. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/rag/.gitignore +0 -0
  260. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/rag/indirect-injection.yaml +0 -0
  261. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/rag/test_data/gender_studies_overview.txt +0 -0
  262. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/vllm/risk-evaluation.yaml +0 -0
  263. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/web/README.md +0 -0
  264. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/web/plan.py +0 -0
  265. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/examples/web/tap-site-chatbot.yaml +0 -0
  266. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/__init__.py +0 -0
  267. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/__init__.py +0 -0
  268. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/banner.py +0 -0
  269. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/bootstrap.py +0 -0
  270. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/commands/__init__.py +0 -0
  271. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/commands/campaign.py +0 -0
  272. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/commands/config.py +0 -0
  273. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/commands/datasets.py +0 -0
  274. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/commands/results.py +0 -0
  275. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/commands/web.py +0 -0
  276. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/config.py +0 -0
  277. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/help_page.py +0 -0
  278. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/logging_setup.py +0 -0
  279. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/main.py +0 -0
  280. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/safe_stdio.py +0 -0
  281. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/cli/utils.py +0 -0
  282. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/__init__.py +0 -0
  283. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/base.py +0 -0
  284. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/events.py +0 -0
  285. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/logger.py +0 -0
  286. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/theme.py +0 -0
  287. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/__init__.py +0 -0
  288. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/agents.py +0 -0
  289. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/audit.py +0 -0
  290. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/__init__.py +0 -0
  291. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/builder.py +0 -0
  292. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/draft.py +0 -0
  293. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/outline.py +0 -0
  294. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/report.py +0 -0
  295. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/screens.py +0 -0
  296. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/campaign/welcome.py +0 -0
  297. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/config.py +0 -0
  298. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/__init__.py +0 -0
  299. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/export.py +0 -0
  300. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/formatters/__init__.py +0 -0
  301. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/formatters/datetimes.py +0 -0
  302. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/formatters/http.py +0 -0
  303. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/formatters/run_report.py +0 -0
  304. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/formatters/summaries.py +0 -0
  305. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/formatters/text.py +0 -0
  306. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/formatters/traces.py +0 -0
  307. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/views/results/tab.py +0 -0
  308. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/widgets/__init__.py +0 -0
  309. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/widgets/actions.py +0 -0
  310. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/widgets/clipboard.py +0 -0
  311. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/tui/widgets/logs.py +0 -0
  312. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/web/__init__.py +0 -0
  313. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/web/_local_api.py +0 -0
  314. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/web/_proxy.py +0 -0
  315. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/web/_serializers.py +0 -0
  316. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/web/_static.py +0 -0
  317. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/interfaces/web/static/.gitignore +0 -0
  318. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/__init__.py +0 -0
  319. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/build.py +0 -0
  320. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/__init__.py +0 -0
  321. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/adk.py +0 -0
  322. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/browser.py +0 -0
  323. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/claude.py +0 -0
  324. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/litellm.py +0 -0
  325. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/completions/web.py +0 -0
  326. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/config.py +0 -0
  327. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/connect.py +0 -0
  328. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/embeddings.py +0 -0
  329. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/factory.py +0 -0
  330. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/guardrail.py +0 -0
  331. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/model.py +0 -0
  332. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/provider_config.py +0 -0
  333. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/response.py +0 -0
  334. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/retry.py +0 -0
  335. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/models/target_params.py +0 -0
  336. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/__init__.py +0 -0
  337. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/__init__.py +0 -0
  338. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/audit.py +0 -0
  339. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/loader.py +0 -0
  340. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/preflight.py +0 -0
  341. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/resolve.py +0 -0
  342. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/results.py +0 -0
  343. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/runner.py +0 -0
  344. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/spec.py +0 -0
  345. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/campaign/tracking.py +0 -0
  346. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/planning/__init__.py +0 -0
  347. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/planning/catalog.py +0 -0
  348. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/planning/planner.py +0 -0
  349. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/orchestrator/planning/web.py +0 -0
  350. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/__init__.py +0 -0
  351. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/__init__.py +0 -0
  352. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/__init__.py +0 -0
  353. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/agent/__init__.py +0 -0
  354. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/agent/agent_create.py +0 -0
  355. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/agent/agent_destroy.py +0 -0
  356. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/agent/agent_list.py +0 -0
  357. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/agent/agent_partial_update.py +0 -0
  358. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/agent/agent_retrieve.py +0 -0
  359. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/agent/agent_update.py +0 -0
  360. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/apilogs/__init__.py +0 -0
  361. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/apilogs/apilogs_list.py +0 -0
  362. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/apilogs/apilogs_retrieve.py +0 -0
  363. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/apilogs/apilogs_summary_retrieve.py +0 -0
  364. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/attack/__init__.py +0 -0
  365. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/attack/attack_create.py +0 -0
  366. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/attack/attack_destroy.py +0 -0
  367. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/attack/attack_list.py +0 -0
  368. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/attack/attack_partial_update.py +0 -0
  369. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/attack/attack_retrieve.py +0 -0
  370. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/attack/attack_update.py +0 -0
  371. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/checkout/__init__.py +0 -0
  372. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/checkout/checkout_create.py +0 -0
  373. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/generate/__init__.py +0 -0
  374. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/generate/v1_chat_completions_create.py +0 -0
  375. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/judge/__init__.py +0 -0
  376. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/judge/judge_create.py +0 -0
  377. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/key/__init__.py +0 -0
  378. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/key/key_context_retrieve.py +0 -0
  379. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/key/key_create.py +0 -0
  380. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/key/key_destroy.py +0 -0
  381. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/key/key_list.py +0 -0
  382. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/key/key_retrieve.py +0 -0
  383. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/models.py +0 -0
  384. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/__init__.py +0 -0
  385. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/organization_create.py +0 -0
  386. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/organization_destroy.py +0 -0
  387. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/organization_list.py +0 -0
  388. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/organization_me_retrieve.py +0 -0
  389. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/organization_partial_update.py +0 -0
  390. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/organization_retrieve.py +0 -0
  391. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/organization/organization_update.py +0 -0
  392. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/__init__.py +0 -0
  393. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/result_create.py +0 -0
  394. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/result_destroy.py +0 -0
  395. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/result_list.py +0 -0
  396. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/result_partial_update.py +0 -0
  397. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/result_retrieve.py +0 -0
  398. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/result_trace_create.py +0 -0
  399. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/result/result_update.py +0 -0
  400. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/__init__.py +0 -0
  401. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_create.py +0 -0
  402. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_destroy.py +0 -0
  403. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_list.py +0 -0
  404. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_partial_update.py +0 -0
  405. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_result_create.py +0 -0
  406. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_retrieve.py +0 -0
  407. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_run_tests_create.py +0 -0
  408. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/run/run_update.py +0 -0
  409. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/scripts/generate.py +0 -0
  410. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/scripts/generate.sh +0 -0
  411. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/scripts/openapi-python-client.yaml +0 -0
  412. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/__init__.py +0 -0
  413. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_create.py +0 -0
  414. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_destroy.py +0 -0
  415. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_list.py +0 -0
  416. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_me_retrieve.py +0 -0
  417. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_me_update.py +0 -0
  418. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_partial_update.py +0 -0
  419. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_retrieve.py +0 -0
  420. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/api/user/user_update.py +0 -0
  421. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/client.py +0 -0
  422. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/errors.py +0 -0
  423. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/_http/types.py +0 -0
  424. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/buckets.py +0 -0
  425. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/local.py +0 -0
  426. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/records.py +0 -0
  427. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/remote.py +0 -0
  428. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/storage/store.py +0 -0
  429. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/tracking/__init__.py +0 -0
  430. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/tracking/evaluation.py +0 -0
  431. {hackagent-0.15.0 → hackagent-0.16.0}/hackagent/tracking/serialize.py +0 -0
@@ -72,6 +72,7 @@ htmlcov/
72
72
  .cache
73
73
  nosetests.xml
74
74
  coverage.xml
75
+ coverage.json
75
76
  *.cover
76
77
  .hypothesis/
77
78
  .pytest_cache/
@@ -150,3 +151,7 @@ snapshot_report.html
150
151
  # Web UI bundle (built by scripts/build_webui.sh)
151
152
  hackagent/interfaces/web/static/*
152
153
  !hackagent/interfaces/web/static/.gitignore
154
+
155
+ # Results exported from the TUI (hackagent/interfaces/tui/views/results/export.py)
156
+ hackagent_results_*.csv
157
+ hackagent_results_*.json
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.5
2
+ Name: hackagent
3
+ Version: 0.16.0
4
+ Summary: HackAgent is an open-source security toolkit to detect vulnerabilities of your AI Agents.
5
+ Author-email: AI Security Lab <ais@ai4i.it>
6
+ License: Apache-2.0
7
+ License-File: LICENSE
8
+ Keywords: agents,ai,security,testing,vulnerabilities
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: click>=8.1.0
19
+ Requires-Dist: httpx>=0.27.0
20
+ Requires-Dist: litellm>=1.69.2
21
+ Requires-Dist: openai>=1.0.0
22
+ Requires-Dist: pydantic[email]>=2.0
23
+ Requires-Dist: python-dateutil>=2.8.0
24
+ Requires-Dist: pyyaml>=6.0.0
25
+ Requires-Dist: rich>=14.0.0
26
+ Provides-Extra: browser
27
+ Requires-Dist: playwright>=1.40; extra == 'browser'
28
+ Provides-Extra: hf
29
+ Requires-Dist: datasets>=2.14.0; extra == 'hf'
30
+ Provides-Extra: rag
31
+ Requires-Dist: faiss-cpu>=1.13.2; extra == 'rag'
32
+ Requires-Dist: numpy>=1.26; extra == 'rag'
33
+ Provides-Extra: tui
34
+ Requires-Dist: textual>=1.0.0; extra == 'tui'
35
+ Provides-Extra: vision
36
+ Requires-Dist: pillow>=10.0.0; extra == 'vision'
37
+ Provides-Extra: web
38
+ Requires-Dist: flask>=3.1.3; extra == 'web'
39
+ Requires-Dist: hackagent-webui<1.0,>=0.2; extra == 'web'
40
+ Description-Content-Type: text/markdown
41
+
42
+ <div align="center">
43
+
44
+ <img src="https://docs.hackagent.dev/img/banner.svg" alt="HackAgent" width="800">
45
+
46
+ **The open-source red-team toolkit for AI models and agents**
47
+
48
+ [Docs](https://docs.hackagent.dev/) · [App](https://app.hackagent.dev/) · [API](https://api.hackagent.dev/schema/redoc)
49
+
50
+ [![PyPI](https://img.shields.io/pypi/v/hackagent)](https://pypi.org/project/hackagent/)
51
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
52
+ ![License](https://img.shields.io/badge/license-Apache%202.0-green)
53
+ ![CI](https://img.shields.io/github/actions/workflow/status/AISecurityLab/hackagent/ci.yml)
54
+ ![Coverage](https://img.shields.io/codecov/c/github/AISecurityLab/hackagent)
55
+
56
+ </div>
57
+
58
+ HackAgent attacks your AI model or agent with research-backed techniques —
59
+ jailbreaks, prompt injection, tool misuse — and has judge models score every
60
+ reply. You get a measured success rate per attack, so you can see how exposed a
61
+ target is and whether a fix helped.
62
+
63
+ ## See it run
64
+
65
+ **Terminal UI.** Start from an example, change what you need, run it.
66
+
67
+ <img src="https://raw.githubusercontent.com/AISecurityLab/hackagent/main/docs/static/gifs/hackagent-tui.gif" alt="Building and running a campaign in the HackAgent terminal UI" width="100%">
68
+
69
+ **Command line.** The same campaign is one YAML file you can edit, check and run, in a shell or in CI.
70
+
71
+ <img src="https://raw.githubusercontent.com/AISecurityLab/hackagent/main/docs/static/gifs/hackagent-cli.gif" alt="Copying, editing, validating and running a campaign from the command line" width="100%">
72
+
73
+ **Dashboard.** Browse runs, results and traces with `hackagent web`, or on [app.hackagent.dev](https://app.hackagent.dev/).
74
+
75
+ <img src="https://raw.githubusercontent.com/AISecurityLab/hackagent/main/docs/static/gifs/hackagent-dashboard.gif" alt="Browsing campaign results in the HackAgent dashboard" width="100%">
76
+
77
+ ## Quick start
78
+
79
+ ```bash
80
+ pip install 'hackagent[tui]'
81
+ hackagent # opens the terminal UI
82
+ ```
83
+
84
+ Or run an example end to end, fully local, with [Ollama](https://ollama.com):
85
+
86
+ ```bash
87
+ ollama pull gemma3:4b
88
+ hackagent examples copy h4rm3l-demo
89
+ hackagent campaign run h4rm3l-demo.yaml
90
+ ```
91
+
92
+ No API key needed: results go to a local database unless a campaign says
93
+ otherwise.
94
+
95
+ ## Learn more
96
+
97
+ - [Installation](https://docs.hackagent.dev/getting-started/installation) — extras, and standalone binaries that need no Python
98
+ - [Your first campaign](https://docs.hackagent.dev/getting-started/first-campaign) — write, check and run one
99
+ - [Concepts](https://docs.hackagent.dev/concepts) — attacks, judges and how a run works
100
+ - [Attacks](https://docs.hackagent.dev/reference/attacks) and the [campaign file reference](https://docs.hackagent.dev/reference/campaign)
101
+ - [Dashboard](https://docs.hackagent.dev/getting-started/dashboard) — `hackagent web`, locally or against your account
102
+
103
+ Questions? Join the [discussions](https://github.com/AISecurityLab/hackagent/discussions) or email ais@ai4i.it.
104
+
105
+ ## Responsible use
106
+
107
+ HackAgent is for authorized security testing only. Test systems you own or
108
+ have written permission to test, and report what you find through coordinated
109
+ disclosure. Read the [responsible disclosure guidelines](https://docs.hackagent.dev/security/responsible-disclosure)
110
+ and our [security policy](SECURITY.md).
111
+
112
+ ## Contributing
113
+
114
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and
115
+ [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
116
+
117
+ ## License
118
+
119
+ Licensed under Apache-2.0. See [LICENSE](LICENSE). HackAgent is intended for
120
+ security research and AI safety improvement; the authors are not responsible
121
+ for misuse.
@@ -0,0 +1,80 @@
1
+ <div align="center">
2
+
3
+ <img src="https://docs.hackagent.dev/img/banner.svg" alt="HackAgent" width="800">
4
+
5
+ **The open-source red-team toolkit for AI models and agents**
6
+
7
+ [Docs](https://docs.hackagent.dev/) · [App](https://app.hackagent.dev/) · [API](https://api.hackagent.dev/schema/redoc)
8
+
9
+ [![PyPI](https://img.shields.io/pypi/v/hackagent)](https://pypi.org/project/hackagent/)
10
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
11
+ ![License](https://img.shields.io/badge/license-Apache%202.0-green)
12
+ ![CI](https://img.shields.io/github/actions/workflow/status/AISecurityLab/hackagent/ci.yml)
13
+ ![Coverage](https://img.shields.io/codecov/c/github/AISecurityLab/hackagent)
14
+
15
+ </div>
16
+
17
+ HackAgent attacks your AI model or agent with research-backed techniques —
18
+ jailbreaks, prompt injection, tool misuse — and has judge models score every
19
+ reply. You get a measured success rate per attack, so you can see how exposed a
20
+ target is and whether a fix helped.
21
+
22
+ ## See it run
23
+
24
+ **Terminal UI.** Start from an example, change what you need, run it.
25
+
26
+ <img src="https://raw.githubusercontent.com/AISecurityLab/hackagent/main/docs/static/gifs/hackagent-tui.gif" alt="Building and running a campaign in the HackAgent terminal UI" width="100%">
27
+
28
+ **Command line.** The same campaign is one YAML file you can edit, check and run, in a shell or in CI.
29
+
30
+ <img src="https://raw.githubusercontent.com/AISecurityLab/hackagent/main/docs/static/gifs/hackagent-cli.gif" alt="Copying, editing, validating and running a campaign from the command line" width="100%">
31
+
32
+ **Dashboard.** Browse runs, results and traces with `hackagent web`, or on [app.hackagent.dev](https://app.hackagent.dev/).
33
+
34
+ <img src="https://raw.githubusercontent.com/AISecurityLab/hackagent/main/docs/static/gifs/hackagent-dashboard.gif" alt="Browsing campaign results in the HackAgent dashboard" width="100%">
35
+
36
+ ## Quick start
37
+
38
+ ```bash
39
+ pip install 'hackagent[tui]'
40
+ hackagent # opens the terminal UI
41
+ ```
42
+
43
+ Or run an example end to end, fully local, with [Ollama](https://ollama.com):
44
+
45
+ ```bash
46
+ ollama pull gemma3:4b
47
+ hackagent examples copy h4rm3l-demo
48
+ hackagent campaign run h4rm3l-demo.yaml
49
+ ```
50
+
51
+ No API key needed: results go to a local database unless a campaign says
52
+ otherwise.
53
+
54
+ ## Learn more
55
+
56
+ - [Installation](https://docs.hackagent.dev/getting-started/installation) — extras, and standalone binaries that need no Python
57
+ - [Your first campaign](https://docs.hackagent.dev/getting-started/first-campaign) — write, check and run one
58
+ - [Concepts](https://docs.hackagent.dev/concepts) — attacks, judges and how a run works
59
+ - [Attacks](https://docs.hackagent.dev/reference/attacks) and the [campaign file reference](https://docs.hackagent.dev/reference/campaign)
60
+ - [Dashboard](https://docs.hackagent.dev/getting-started/dashboard) — `hackagent web`, locally or against your account
61
+
62
+ Questions? Join the [discussions](https://github.com/AISecurityLab/hackagent/discussions) or email ais@ai4i.it.
63
+
64
+ ## Responsible use
65
+
66
+ HackAgent is for authorized security testing only. Test systems you own or
67
+ have written permission to test, and report what you find through coordinated
68
+ disclosure. Read the [responsible disclosure guidelines](https://docs.hackagent.dev/security/responsible-disclosure)
69
+ and our [security policy](SECURITY.md).
70
+
71
+ ## Contributing
72
+
73
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and
74
+ [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
75
+
76
+ ## License
77
+
78
+ Licensed under Apache-2.0. See [LICENSE](LICENSE). HackAgent is intended for
79
+ security research and AI safety improvement; the authors are not responsible
80
+ for misuse.
@@ -9,13 +9,27 @@ import inspect
9
9
  from collections.abc import Awaitable
10
10
  from typing import TypeAlias
11
11
 
12
- from numpy.random import RandomState
13
-
14
12
  from ...base import Completion
15
13
 
16
14
  DecorationResult: TypeAlias = str | Awaitable[str]
17
15
 
18
16
 
17
+ def _random_state(seed: int):
18
+ """A seeded numpy RandomState, imported when the first decorator is built.
19
+
20
+ Not at module level, so the attack's settings can be read without numpy,
21
+ as the TUI and campaign validation do for every attack.
22
+ """
23
+ try:
24
+ from numpy.random import RandomState
25
+ except ImportError as exc:
26
+ raise ImportError(
27
+ "numpy is required for the h4rm3l attack. "
28
+ "Install with: pip install 'hackagent[rag]'"
29
+ ) from exc
30
+ return RandomState(seed=seed)
31
+
32
+
19
33
  class PromptDecorator:
20
34
  """Base class for all h4rm3l decorators.
21
35
 
@@ -24,7 +38,7 @@ class PromptDecorator:
24
38
  """
25
39
 
26
40
  def __init__(self, seed: int = 42) -> None:
27
- self._random_state = RandomState(seed=seed)
41
+ self._random_state = _random_state(seed)
28
42
  self._chain: list[PromptDecorator] = [self]
29
43
 
30
44
  def decorate(self, prompt: str) -> DecorationResult:
@@ -15,35 +15,52 @@ All images are returned as base64-encoded data URLs suitable for inclusion
15
15
  in multimodal LLM API requests.
16
16
  """
17
17
 
18
+ from __future__ import annotations
19
+
18
20
  import base64
19
21
  import io
20
22
  import random
21
23
  import textwrap
22
- from typing import Any, Dict, List
23
-
24
- try:
25
- from PIL import Image, ImageDraw, ImageFont
26
- except ImportError:
27
- raise ImportError(
28
- "Pillow is required for the MML attack. "
29
- "Install with: pip install 'hackagent[vision]'"
30
- )
24
+ from types import ModuleType
25
+ from typing import TYPE_CHECKING, Any, Dict, List
26
+
27
+ if TYPE_CHECKING:
28
+ from PIL import Image, ImageFont
29
+
30
+
31
+ def _pil() -> ModuleType:
32
+ """Pillow, imported when the first image is drawn.
33
+
34
+ Not at module level, so the attack's settings can be read without the
35
+ vision extra, as the TUI and campaign validation do for every attack.
36
+ """
37
+ try:
38
+ import PIL.Image
39
+ import PIL.ImageDraw
40
+ import PIL.ImageFont
41
+ except ImportError as exc:
42
+ raise ImportError(
43
+ "Pillow is required for the MML attack. "
44
+ "Install with: pip install 'hackagent[vision]'"
45
+ ) from exc
46
+ return PIL
31
47
 
32
48
 
33
49
  def _get_font(font_size: int) -> ImageFont.FreeTypeFont:
34
50
  """Load a monospace font, falling back to the default if unavailable."""
51
+ fonts = _pil().ImageFont
35
52
  try:
36
- return ImageFont.truetype("DejaVuSansMono.ttf", font_size)
53
+ return fonts.truetype("DejaVuSansMono.ttf", font_size)
37
54
  except (OSError, IOError):
38
55
  try:
39
- return ImageFont.truetype("DejaVuSans.ttf", font_size)
56
+ return fonts.truetype("DejaVuSans.ttf", font_size)
40
57
  except (OSError, IOError):
41
58
  try:
42
- return ImageFont.truetype(
59
+ return fonts.truetype(
43
60
  "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", font_size
44
61
  )
45
62
  except (OSError, IOError):
46
- return ImageFont.load_default()
63
+ return fonts.load_default()
47
64
 
48
65
 
49
66
  def _render_text_to_image(
@@ -67,8 +84,9 @@ def _render_text_to_image(
67
84
  Returns:
68
85
  A PIL Image with the text rendered on it.
69
86
  """
70
- img = Image.new("RGB", (width, height), color=background_color)
71
- draw = ImageDraw.Draw(img)
87
+ pil = _pil()
88
+ img = pil.Image.new("RGB", (width, height), color=background_color)
89
+ draw = pil.ImageDraw.Draw(img)
72
90
  font = _get_font(font_size)
73
91
 
74
92
  # Wrap text to fit within the image width
@@ -255,7 +273,7 @@ def encode_mirror(
255
273
  prompt, image_width, image_height, font_size, background_color, text_color
256
274
  )
257
275
  # Mirror horizontally
258
- img = img.transpose(Image.FLIP_LEFT_RIGHT)
276
+ img = img.transpose(_pil().Image.FLIP_LEFT_RIGHT)
259
277
 
260
278
  words = prompt.split()
261
279
  scrambled_words = words.copy()
@@ -407,7 +425,7 @@ def encode_mixed(
407
425
  )
408
426
 
409
427
  # Apply mirror and rotation
410
- img = img.transpose(Image.FLIP_LEFT_RIGHT)
428
+ img = img.transpose(_pil().Image.FLIP_LEFT_RIGHT)
411
429
  img = img.rotate(180)
412
430
 
413
431
  # Scramble original words
@@ -53,13 +53,13 @@ Then run:
53
53
  | Config key | Maps to | Default |
54
54
  |---|---|---|
55
55
  | `name` (required) | `-m <model>` | — |
56
- | `binary` | argv[0], checked with `shutil.which` at construction | `hermes` |
56
+ | `binary` | argv[0], checked with `shutil.which` at construction. `ollama` starts Hermes with `ollama launch hermes --model <name>` | `hermes` |
57
57
  | `provider` | `--provider <provider>` | unset |
58
58
  | `cwd` | working directory Hermes operates in | unset |
59
59
  | `timeout` | `subprocess.run(..., timeout=)` seconds | `600` |
60
- | `ignore_user_config` | `--ignore-user-config` | `True` |
60
+ | `ignore_user_config` | `--ignore-user-config` | `True`, or `False` when `binary` is `ollama` |
61
61
  | `safe_mode` | `--safe-mode` | `False` |
62
- | `source` | `--source <source>` | `hackagent` |
62
+ | `source` | `--source <source>` | unset |
63
63
  | `extra_args` | appended raw flags | `[]` |
64
64
 
65
65
  ---
@@ -71,9 +71,10 @@ Unlike Claude Code, Hermes is stateful: it keeps long-term memory in `~/.hermes/
71
71
  The adapter therefore defaults to isolation:
72
72
 
73
73
  - `--ignore-user-config` is always passed unless you explicitly set `"ignore_user_config": False`, so the target uses defaults plus `.env` credentials only and never reads `~/.hermes/config.yaml`.
74
+ - Through Ollama (`binary: ollama`) `--ignore-user-config` is off by default: `ollama launch hermes` writes the model into `~/.hermes/config.yaml`, so Hermes has to read it. Isolate the run with a dedicated `hermes profile` instead.
74
75
  - `-r`/`--resume` and `-c`/`--continue` are never passed, so every attack turn is a fresh session.
75
76
  - `"safe_mode": True` opts into `--safe-mode` for maximum isolation (all customizations disabled).
76
- - `--source hackagent` is passed so Hermes-side logs are attributable to HackAgent runs.
77
+ - `--source` is not passed by default: recent Hermes versions accept it only under `hermes chat`, not with `-z`. Set `source` if your version takes it.
77
78
 
78
79
  For stronger separation still, point `cwd` at a scratch directory and/or run the target under a dedicated `hermes profile` so the operator's real profile, memory and skills are never touched.
79
80
 
@@ -82,7 +83,8 @@ For stronger separation still, point `cwd` at a scratch directory and/or run the
82
83
  ### Notes
83
84
 
84
85
  - `hermes -z` returns bare text with no structured metadata (no session id, cost or exit reason), so the adapter relies on exit codes: `0` success, `1` delivery/backend failure, `2` usage error. A non-zero exit with usable stdout is captured as the target's response (a refusal is a legitimate response to judge); exit `2` always fails loudly.
85
- - The prompt is fed via **stdin**, never argv, so adversarial payloads starting with `-` are not parsed as CLI flags.
86
+ - The prompt is passed as `--oneshot=<prompt>`, the value of `-z`. Joined to the option with `=`, an adversarial payload starting with `-` is not parsed as a CLI flag.
87
+ - As one argument, the prompt is limited by the OS: about 127 KiB on Linux and macOS, 30,000 bytes on Windows. A longer prompt fails that turn with an error instead of reaching Hermes.
86
88
  - The `endpoint` field is present for HackAgent compatibility but is ignored for this local setup.
87
89
  - If the configured binary is not on `PATH`, the setup fails before the attack runs.
88
90
  - `hermes serve` (a headless backend over JSON-RPC/WebSocket) is out of scope here; this example covers the local CLI-driven path only.
@@ -8,6 +8,7 @@ Launch ready-to-run example scenarios from the CLI.
8
8
  """
9
9
 
10
10
  import importlib
11
+ import re
11
12
  import os
12
13
  import socket
13
14
  import shutil
@@ -17,6 +18,7 @@ import time
17
18
  from dataclasses import dataclass
18
19
  from pathlib import Path
19
20
  from types import ModuleType
21
+ from typing import Optional
20
22
  from urllib.error import URLError
21
23
  from urllib.parse import urljoin
22
24
  from urllib.request import urlopen
@@ -513,10 +515,56 @@ def list_examples():
513
515
  console.print(f" [dim]{line}[/dim]")
514
516
  console.print(
515
517
  "\n[dim]Run one with:[/dim] hackagent examples run <name>\n"
518
+ "[dim]Or copy it here to edit:[/dim] hackagent examples copy <name>\n"
516
519
  "[dim]A name's last part is enough when it is unique.[/dim]"
517
520
  )
518
521
 
519
522
 
523
+ #: Where the docs site serves the campaign JSON Schema.
524
+ CAMPAIGN_SCHEMA_URL = "https://docs.hackagent.dev/schema/campaign.schema.json"
525
+
526
+ #: An editor schema hint pointing at a relative path, as the examples have.
527
+ _SCHEMA_HINT = re.compile(r"^(# yaml-language-server: \$schema=)(?!https?://)\S+", re.M)
528
+
529
+
530
+ @examples.command(name="copy")
531
+ @click.argument("name")
532
+ @click.argument("destination", required=False, type=click.Path(path_type=Path))
533
+ @click.option("--force", is_flag=True, help="Overwrite a file that is already there.")
534
+ @handle_errors
535
+ def copy_example(name: str, destination: Optional[Path], force: bool):
536
+ """📄 Copy an example campaign here, to edit and run as your own.
537
+
538
+ DESTINATION is a file or a folder, the current folder by default.
539
+ """
540
+ key, source = _resolve_example_name(name)
541
+ target = destination or Path(".")
542
+ if target.is_dir():
543
+ target = target / source.name
544
+ if target.exists() and not force:
545
+ raise click.ClickException(
546
+ f"{target} already exists; use --force to replace it."
547
+ )
548
+ # Copied as it is, comments included: they explain the example. Only the
549
+ # editor's schema hint changes, from a path inside this repository to the
550
+ # schema the docs site publishes.
551
+ text = source.read_text(encoding="utf-8")
552
+ text = _SCHEMA_HINT.sub(rf"\g<1>{CAMPAIGN_SCHEMA_URL}", text, count=1)
553
+ target.write_text(text, encoding="utf-8")
554
+
555
+ console.print(f"[green]Copied[/green] {key} → {target}")
556
+ folder = key.rsplit("/", 1)[0] if "/" in key else ""
557
+ if folder in _TARGETS or folder in _MANUAL_TARGETS:
558
+ console.print(
559
+ "[yellow]Its agent is not copied: start it the way "
560
+ f"`hackagent examples run {key}` does, or point the target elsewhere.[/yellow]"
561
+ )
562
+ console.print(
563
+ f"[dim]Edit it, then run it with:[/dim] hackagent campaign run {target}",
564
+ soft_wrap=True,
565
+ )
566
+
567
+
520
568
  @examples.command(name="run")
521
569
  @click.argument("name")
522
570
  @handle_errors
@@ -13,6 +13,7 @@ app of its own, opened by starting ``HackAgentTUI`` on it, which is how the
13
13
  welcome screen reaches past results.
14
14
  """
15
15
 
16
+ import os
16
17
  from pathlib import Path
17
18
  from typing import Any
18
19
 
@@ -28,6 +29,27 @@ from hackagent.interfaces.tui.views.config import ConfigTab
28
29
  from hackagent.interfaces.tui.views.results import ResultsTab
29
30
 
30
31
 
32
+ def _start_multiprocessing_tracker() -> None:
33
+ """Start multiprocessing's resource tracker while stderr is still a file.
34
+
35
+ Textual replaces ``sys.stderr`` with an object that has no file
36
+ descriptor. The first multiprocessing lock made after that starts the
37
+ tracker, which hands its child stderr's descriptor and fails with
38
+ "bad value(s) in fds_to_keep". tqdm makes such a lock whenever
39
+ ``datasets`` loads a Hugging Face dataset, so a campaign whose goals come
40
+ from a preset could not run in the TUI. Started here, the tracker is
41
+ already running when that lock is made.
42
+ """
43
+ if os.name != "posix": # Windows has no resource tracker.
44
+ return
45
+ from multiprocessing import resource_tracker
46
+
47
+ try:
48
+ resource_tracker.ensure_running()
49
+ except Exception: # noqa: BLE001 - never stop the TUI from opening over it
50
+ pass
51
+
52
+
31
53
  class HackAgentTUI(App):
32
54
  """HackAgent Terminal User Interface Application"""
33
55
 
@@ -204,6 +226,10 @@ class HackAgentTUI(App):
204
226
  """Expose the HackAgent brand palette as CSS variables."""
205
227
  return {**super().get_css_variables(), **css_variables()}
206
228
 
229
+ def run(self, *args: Any, **kwargs: Any) -> Any:
230
+ _start_multiprocessing_tracker()
231
+ return super().run(*args, **kwargs)
232
+
207
233
  def compose(self) -> ComposeResult:
208
234
  """One view and a footer.
209
235
 
@@ -62,6 +62,9 @@ class FieldRow(Horizontal):
62
62
  self.draft = draft
63
63
  self.box = box
64
64
  self.issue: Optional[str] = None
65
+ # Kept rather than queried: Textual can remove the row's children
66
+ # before a pending mount refreshes it, as when the app closes at once.
67
+ self._state = Static("", classes="state")
65
68
 
66
69
  @property
67
70
  def path(self) -> Path:
@@ -70,7 +73,7 @@ class FieldRow(Horizontal):
70
73
  def compose(self) -> ComposeResult:
71
74
  yield Static(_label_markup(self.field.label_in(self.box)), classes="label")
72
75
  yield self._editor()
73
- yield Static("", classes="state")
76
+ yield self._state
74
77
 
75
78
  def on_mount(self) -> None:
76
79
  self.refresh_state()
@@ -159,7 +162,8 @@ class FieldRow(Horizontal):
159
162
  elif self.field.kind == "tristate":
160
163
  self._commit(event.value == "true")
161
164
  else:
162
- self._commit(event.value)
165
+ # The widget holds text; the campaign needs the schema's type.
166
+ self._commit(self.field.choice_value(str(event.value)))
163
167
 
164
168
  def on_text_area_changed(self, event: TextArea.Changed) -> None:
165
169
  event.stop()
@@ -203,7 +207,7 @@ class FieldRow(Horizontal):
203
207
  # No default and not required: leaving it out sends nothing, and
204
208
  # whatever is on the other end picks.
205
209
  text = "[dim]not sent[/dim]"
206
- self.query_one(".state", Static).update(text)
210
+ self._state.update(text)
207
211
 
208
212
 
209
213
  def _label_markup(label: str) -> str:
@@ -80,6 +80,9 @@ class FieldDef:
80
80
  default: Any
81
81
  description: str
82
82
  choices: tuple[str, ...] = ()
83
+ #: What each choice stands for, in the same order: ``2`` for the choice
84
+ #: ``"2"`` of ``Literal[1, 2]``. Empty when the choices are the values.
85
+ choice_values: tuple[Any, ...] = ()
83
86
  advanced: bool = False
84
87
  #: The model this field belongs to. Two models can share a field name, so
85
88
  #: anything keyed on fields must key on this too.
@@ -123,6 +126,13 @@ class FieldDef:
123
126
  return ", ".join(str(item) for item in self.default)
124
127
  return str(self.default)
125
128
 
129
+ def choice_value(self, choice: str) -> Any:
130
+ """The value a choice stands for, with the type the schema expects."""
131
+ for text, value in zip(self.choices, self.choice_values):
132
+ if text == choice:
133
+ return value
134
+ return choice
135
+
126
136
  def is_default(self, value: Any) -> bool:
127
137
  """Whether ``value`` is what the schema would use anyway."""
128
138
  if self.default is MISSING:
@@ -185,6 +195,15 @@ def _kind(annotation: Any) -> tuple[Optional[str], tuple[str, ...]]:
185
195
  return None, ()
186
196
 
187
197
 
198
+ def _choice_values(annotation: Any) -> tuple[Any, ...]:
199
+ """The values behind a choice field's labels, as :func:`_kind` lists them."""
200
+ if get_origin(annotation) is Literal:
201
+ return get_args(annotation)
202
+ if isinstance(annotation, type) and issubclass(annotation, enum.Enum):
203
+ return tuple(member.value for member in annotation)
204
+ return ()
205
+
206
+
188
207
  def discriminated_variants(
189
208
  info: FieldInfo,
190
209
  ) -> tuple[Optional[str], dict[str, type[BaseModel]]]:
@@ -279,6 +298,7 @@ def model_fields(
279
298
  default=default,
280
299
  description=info.description or "",
281
300
  choices=choices,
301
+ choice_values=_choice_values(annotation) if kind == "choice" else (),
282
302
  advanced=bool(_advanced_flag(info)),
283
303
  owner=model,
284
304
  )
@@ -16,6 +16,7 @@ Subclasses set the class attributes, read their own options in
16
16
  from __future__ import annotations
17
17
 
18
18
  import asyncio
19
+ import os
19
20
  import shutil
20
21
  from abc import abstractmethod
21
22
  from typing import Any, ClassVar, Dict, List, Mapping, Optional, Sequence
@@ -62,6 +63,16 @@ def last_user_text(messages: List[Dict[str, Any]]) -> Optional[str]:
62
63
  return None
63
64
 
64
65
 
66
+ def is_ollama_launcher(binary: str) -> bool:
67
+ """Whether ``binary`` is Ollama, which starts an agent with ``ollama launch``.
68
+
69
+ Only the executable's name counts, so an agent installed under a folder
70
+ called ``ollama`` still runs natively.
71
+ """
72
+ name = os.path.basename(binary).lower()
73
+ return name in ("ollama", "ollama.exe")
74
+
75
+
65
76
  class SubprocessCLIModel(Model):
66
77
  """A :class:`Model` that answers each turn by running a local CLI."""
67
78
 
@@ -192,5 +203,6 @@ __all__ = [
192
203
  "CLIConfigurationError",
193
204
  "CLIInteractionError",
194
205
  "SubprocessCLIModel",
206
+ "is_ollama_launcher",
195
207
  "last_user_text",
196
208
  ]
@@ -26,6 +26,7 @@ from hackagent.models.completions.cli import (
26
26
  CLIConfigurationError,
27
27
  CLIInteractionError,
28
28
  SubprocessCLIModel,
29
+ is_ollama_launcher,
29
30
  last_user_text,
30
31
  )
31
32
 
@@ -194,9 +195,7 @@ def _get_codex_custom_llm_class():
194
195
  def _build_argv(self) -> List[str]:
195
196
  """Assemble the CLI argv based on whether we use codex natively or via ollama."""
196
197
  argv = [self.binary]
197
- is_ollama = "ollama" in self.binary.lower()
198
-
199
- if is_ollama:
198
+ if is_ollama_launcher(self.binary):
200
199
  # ollama arguments
201
200
  argv.extend(["launch", "codex"])
202
201
  if self.model:
@@ -213,6 +212,10 @@ def _get_codex_custom_llm_class():
213
212
  if self.model:
214
213
  argv.extend(["-m", self.model])
215
214
 
215
+ # Attacks run in throwaway folders, and codex exec refuses to start
216
+ # outside a Git repository without this.
217
+ argv.append("--skip-git-repo-check")
218
+
216
219
  # Codex does not need an HTTP endpoint here. Prompt text is passed
217
220
  # through stdin by _run, matching the Claude Code backend style.
218
221