attacklm 0.5.2__tar.gz → 0.5.4__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 (208) hide show
  1. {attacklm-0.5.2 → attacklm-0.5.4}/.gitignore +1 -0
  2. {attacklm-0.5.2 → attacklm-0.5.4}/PKG-INFO +14 -5
  3. {attacklm-0.5.2 → attacklm-0.5.4}/README.md +11 -4
  4. {attacklm-0.5.2 → attacklm-0.5.4}/pyproject.toml +20 -1
  5. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/train_all.py +10 -0
  6. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/train_template.py +140 -30
  7. attacklm-0.5.4/src/attacklm/__version__.py +1 -0
  8. attacklm-0.5.2/src/attacklm/__version__.py +0 -1
  9. {attacklm-0.5.2 → attacklm-0.5.4}/.github/workflows/release.yml +0 -0
  10. {attacklm-0.5.2 → attacklm-0.5.4}/ATTRIBUTION.md +0 -0
  11. {attacklm-0.5.2 → attacklm-0.5.4}/CHANGELOG.md +0 -0
  12. {attacklm-0.5.2 → attacklm-0.5.4}/CONTRIBUTING.md +0 -0
  13. {attacklm-0.5.2 → attacklm-0.5.4}/EVALUATION.md +0 -0
  14. {attacklm-0.5.2 → attacklm-0.5.4}/LICENSE +0 -0
  15. {attacklm-0.5.2 → attacklm-0.5.4}/MANIFEST.in +0 -0
  16. {attacklm-0.5.2 → attacklm-0.5.4}/Makefile +0 -0
  17. {attacklm-0.5.2 → attacklm-0.5.4}/NOTICE +0 -0
  18. {attacklm-0.5.2 → attacklm-0.5.4}/QA_BEFORE_RELEASES.md +0 -0
  19. {attacklm-0.5.2 → attacklm-0.5.4}/REPLAY_PLAN.md +0 -0
  20. {attacklm-0.5.2 → attacklm-0.5.4}/data/ATTRIBUTION.md +0 -0
  21. {attacklm-0.5.2 → attacklm-0.5.4}/data/LEGAL.md +0 -0
  22. {attacklm-0.5.2 → attacklm-0.5.4}/data/REMOVAL.md +0 -0
  23. {attacklm-0.5.2 → attacklm-0.5.4}/data/bench/questions.jsonl +0 -0
  24. {attacklm-0.5.2 → attacklm-0.5.4}/data/bench/speed_context.txt +0 -0
  25. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/ATTRIBUTION.md +0 -0
  26. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/GEMINI_RESEARCH_2026-06-11.md +0 -0
  27. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/acquisition_report.json +0 -0
  28. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/manifest.json +0 -0
  29. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/README.md +0 -0
  30. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/_index.json +0 -0
  31. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
  32. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
  33. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
  34. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
  35. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
  36. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
  37. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
  38. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
  39. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
  40. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
  41. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
  42. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
  43. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
  44. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
  45. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
  46. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
  47. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
  48. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
  49. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
  50. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
  51. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
  52. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
  53. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
  54. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
  55. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
  56. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
  57. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
  58. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
  59. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
  60. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
  61. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
  62. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
  63. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
  64. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
  65. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
  66. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
  67. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
  68. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
  69. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
  70. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
  71. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
  72. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
  73. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
  74. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
  75. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
  76. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
  77. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
  78. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
  79. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
  80. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
  81. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
  82. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
  83. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
  84. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
  85. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
  86. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
  87. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
  88. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
  89. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
  90. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
  91. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
  92. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
  93. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
  94. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
  95. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
  96. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
  97. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
  98. {attacklm-0.5.2 → attacklm-0.5.4}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
  99. {attacklm-0.5.2 → attacklm-0.5.4}/data/golden/prompts.jsonl +0 -0
  100. {attacklm-0.5.2 → attacklm-0.5.4}/data/reference/prompts.jsonl +0 -0
  101. {attacklm-0.5.2 → attacklm-0.5.4}/data/steering/prompts/opsec_aware.txt +0 -0
  102. {attacklm-0.5.2 → attacklm-0.5.4}/data/steering/prompts/opsec_unaware.txt +0 -0
  103. {attacklm-0.5.2 → attacklm-0.5.4}/data/steering/prompts/succinct.txt +0 -0
  104. {attacklm-0.5.2 → attacklm-0.5.4}/data/steering/prompts/verbose.txt +0 -0
  105. {attacklm-0.5.2 → attacklm-0.5.4}/experiments/README.md +0 -0
  106. {attacklm-0.5.2 → attacklm-0.5.4}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
  107. {attacklm-0.5.2 → attacklm-0.5.4}/hf/.gitattributes +0 -0
  108. {attacklm-0.5.2 → attacklm-0.5.4}/hf/README.md +0 -0
  109. {attacklm-0.5.2 → attacklm-0.5.4}/hf/data/manifest.json +0 -0
  110. {attacklm-0.5.2 → attacklm-0.5.4}/hf/dataset_infos.json +0 -0
  111. {attacklm-0.5.2 → attacklm-0.5.4}/hf/scripts/build_hf_dataset.py +0 -0
  112. {attacklm-0.5.2 → attacklm-0.5.4}/hf/scripts/push_to_hf.py +0 -0
  113. {attacklm-0.5.2 → attacklm-0.5.4}/hpo_runs/.gitkeep +0 -0
  114. {attacklm-0.5.2 → attacklm-0.5.4}/hpo_runs/hpo_state.json +0 -0
  115. {attacklm-0.5.2 → attacklm-0.5.4}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
  116. {attacklm-0.5.2 → attacklm-0.5.4}/logs/.gitkeep +0 -0
  117. {attacklm-0.5.2 → attacklm-0.5.4}/notes/BLUE_TEAM_DESIGN_v0.5.0.md +0 -0
  118. {attacklm-0.5.2 → attacklm-0.5.4}/notes/EVAL_DESIGN_v0.4.0.md +0 -0
  119. {attacklm-0.5.2 → attacklm-0.5.4}/notes/STEERING_REVIEW_v0.4.0.md +0 -0
  120. {attacklm-0.5.2 → attacklm-0.5.4}/presets/blue-team.json +0 -0
  121. {attacklm-0.5.2 → attacklm-0.5.4}/presets/purple-team.json +0 -0
  122. {attacklm-0.5.2 → attacklm-0.5.4}/presets/red-team.json +0 -0
  123. {attacklm-0.5.2 → attacklm-0.5.4}/requirements.txt +0 -0
  124. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/_eval_loader.py +0 -0
  125. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_cloud_attack_dataset.py +0 -0
  126. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_ics_dataset.py +0 -0
  127. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_phishing_dataset.py +0 -0
  128. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_red_team_tactics.py +0 -0
  129. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_replay_general.py +0 -0
  130. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_supply_chain_dataset.py +0 -0
  131. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_web_attack_dataset.py +0 -0
  132. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/acquire_wireless_dataset.py +0 -0
  133. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/add_attribution.py +0 -0
  134. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/audit_dataset.py +0 -0
  135. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/augment_attribution.py +0 -0
  136. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/balance_buckets.py +0 -0
  137. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/bucket_loader.py +0 -0
  138. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/build.py +0 -0
  139. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/classify_unrouted_modules.py +0 -0
  140. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/clone_repos.sh +0 -0
  141. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/collect_reference.py +0 -0
  142. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/compare_scores.py +0 -0
  143. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/convert_to_gguf.py +0 -0
  144. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/dedupe_and_import_llm.py +0 -0
  145. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/demo.py +0 -0
  146. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/device_utils.py +0 -0
  147. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/domain_bench.py +0 -0
  148. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/eval_retention.py +0 -0
  149. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_ai_tools_to_jsonl.py +0 -0
  150. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
  151. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_by_tactic.py +0 -0
  152. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
  153. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_elastic_rules.py +0 -0
  154. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
  155. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_mordor.py +0 -0
  156. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_nist_ir.py +0 -0
  157. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_rta_to_jsonl.py +0 -0
  158. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_sigma_defensive.py +0 -0
  159. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_splunk_content.py +0 -0
  160. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/extract_threathunter_playbook.py +0 -0
  161. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_dataset.py +0 -0
  162. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_dataset_deterministic.py +0 -0
  163. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_hybrid_dataset.py +0 -0
  164. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_metasploit_dataset.py +0 -0
  165. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_orchestrator.py +0 -0
  166. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_prompt_injection.py +0 -0
  167. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_source_layout.py +0 -0
  168. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/generate_synthetic_scarce.py +0 -0
  169. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/golden_vectors.py +0 -0
  170. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/hpo_runner.py +0 -0
  171. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/import_gguf.sh +0 -0
  172. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/import_to_lmstudio.sh +0 -0
  173. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/infer.py +0 -0
  174. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/init_pipeline.py +0 -0
  175. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/llm_generate_wrapper.py +0 -0
  176. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/merge_adapter.py +0 -0
  177. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/migrate_buckets_to_v021.py +0 -0
  178. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/migrate_v015_to_v020.py +0 -0
  179. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/mitre_tactic_lookup.py +0 -0
  180. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/parse_metasploit_to_jsonl.py +0 -0
  181. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/rebuild_manifest.py +0 -0
  182. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/register_ollama.py +0 -0
  183. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/reorganize_buckets.py +0 -0
  184. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/replay_mixer.py +0 -0
  185. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/run_all_acquisitions.py +0 -0
  186. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/score_candidates.py +0 -0
  187. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/scrub_bpl_callback.py +0 -0
  188. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/setup_buckets.py +0 -0
  189. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/speed_bench.py +0 -0
  190. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/stamp_and_reorg.py +0 -0
  191. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/steering.py +0 -0
  192. {attacklm-0.5.2 → attacklm-0.5.4}/scripts/validate_per_category.py +0 -0
  193. {attacklm-0.5.2 → attacklm-0.5.4}/src/attacklm/__init__.py +0 -0
  194. {attacklm-0.5.2 → attacklm-0.5.4}/src/attacklm/cli.py +0 -0
  195. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_balance_buckets.py +0 -0
  196. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_collect_reference.py +0 -0
  197. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_compare_scores.py +0 -0
  198. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_domain_bench.py +0 -0
  199. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_eval_loader.py +0 -0
  200. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_eval_retention.py +0 -0
  201. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_golden_vectors.py +0 -0
  202. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_init_pipeline.py +0 -0
  203. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_replay_mixer.py +0 -0
  204. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_score_candidates.py +0 -0
  205. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_speed_bench.py +0 -0
  206. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_steering.py +0 -0
  207. {attacklm-0.5.2 → attacklm-0.5.4}/tests/test_thinking_models.py +0 -0
  208. {attacklm-0.5.2 → attacklm-0.5.4}/uv.lock +0 -0
@@ -214,3 +214,4 @@ hf/data/*.parquet
214
214
  #
215
215
  # All archive contents are preserved locally but never pushed to remote.
216
216
  archive/
217
+ unsloth_compiled_cache/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: attacklm
3
- Version: 0.5.2
3
+ Version: 0.5.4
4
4
  Summary: QLoRA-fine-tuned Qwen2.5-Coder for offensive/defensive security and AI red-teaming
5
5
  Project-URL: Homepage, https://github.com/Veedubin/AttackLM
6
6
  Project-URL: Repository, https://github.com/Veedubin/AttackLM
@@ -203,6 +203,8 @@ Requires-Dist: torch==2.12.0; extra == 'train-rocm'
203
203
  Requires-Dist: torchvision==0.27.0; extra == 'train-rocm'
204
204
  Requires-Dist: transformers==5.10.2; extra == 'train-rocm'
205
205
  Requires-Dist: trl==1.5.1; extra == 'train-rocm'
206
+ Provides-Extra: unsloth
207
+ Requires-Dist: unsloth>=2026.6; extra == 'unsloth'
206
208
  Description-Content-Type: text/markdown
207
209
 
208
210
  # AttackLM
@@ -279,17 +281,20 @@ The full per-source map:
279
281
  # 1. Install uv (Python package manager, ~10MB)
280
282
  curl -LsSf https://astral.sh/uv/install.sh | sh
281
283
 
282
- # 2. Install AttackLM from PyPI with the full CUDA training stack
284
+ # 2. Install PyTorch + Triton first (required by flash-attn and Unsloth)
285
+ uv pip install torch==2.12.0 torchvision==0.27.0 triton
286
+
287
+ # 3. Install AttackLM from PyPI with the full CUDA training stack
283
288
  uv pip install "attacklm[all]"
284
289
 
285
- # 3. Clone the repo for the training data (the PyPI package is code-only)
290
+ # 4. Clone the repo for the training data (the PyPI package is code-only)
286
291
  git clone https://github.com/Veedubin/AttackLM.git
287
292
  cd AttackLM
288
293
 
289
- # 4. Initialize the dataset (probes local `data/` first; falls back to git clone)
294
+ # 5. Initialize the dataset (probes local `data/` first; falls back to git clone)
290
295
  attacklm-init --yes
291
296
 
292
- # 5. Train
297
+ # 6. Train
293
298
  attacklm-train-all --single-model \
294
299
  --dataset base/ \
295
300
  --base-model huihui-ai/Qwen2.5-Coder-3B-Instruct-abliterated \
@@ -339,6 +344,10 @@ build anything by hand.
339
344
 
340
345
  **Install from PyPI (recommended):**
341
346
  ```bash
347
+ # PyTorch + Triton must be installed first (flash-attn and Unsloth need them)
348
+ uv pip install torch==2.12.0 torchvision==0.27.0 triton
349
+
350
+ # Then install AttackLM
342
351
  uv pip install "attacklm[all]" # CUDA training stack
343
352
  uv pip install "attacklm[all-rocm]" # ROCm training stack
344
353
  uv pip install "attacklm[infer]" # CPU / Apple Silicon (inference only)
@@ -72,17 +72,20 @@ The full per-source map:
72
72
  # 1. Install uv (Python package manager, ~10MB)
73
73
  curl -LsSf https://astral.sh/uv/install.sh | sh
74
74
 
75
- # 2. Install AttackLM from PyPI with the full CUDA training stack
75
+ # 2. Install PyTorch + Triton first (required by flash-attn and Unsloth)
76
+ uv pip install torch==2.12.0 torchvision==0.27.0 triton
77
+
78
+ # 3. Install AttackLM from PyPI with the full CUDA training stack
76
79
  uv pip install "attacklm[all]"
77
80
 
78
- # 3. Clone the repo for the training data (the PyPI package is code-only)
81
+ # 4. Clone the repo for the training data (the PyPI package is code-only)
79
82
  git clone https://github.com/Veedubin/AttackLM.git
80
83
  cd AttackLM
81
84
 
82
- # 4. Initialize the dataset (probes local `data/` first; falls back to git clone)
85
+ # 5. Initialize the dataset (probes local `data/` first; falls back to git clone)
83
86
  attacklm-init --yes
84
87
 
85
- # 5. Train
88
+ # 6. Train
86
89
  attacklm-train-all --single-model \
87
90
  --dataset base/ \
88
91
  --base-model huihui-ai/Qwen2.5-Coder-3B-Instruct-abliterated \
@@ -132,6 +135,10 @@ build anything by hand.
132
135
 
133
136
  **Install from PyPI (recommended):**
134
137
  ```bash
138
+ # PyTorch + Triton must be installed first (flash-attn and Unsloth need them)
139
+ uv pip install torch==2.12.0 torchvision==0.27.0 triton
140
+
141
+ # Then install AttackLM
135
142
  uv pip install "attacklm[all]" # CUDA training stack
136
143
  uv pip install "attacklm[all-rocm]" # ROCm training stack
137
144
  uv pip install "attacklm[infer]" # CPU / Apple Silicon (inference only)
@@ -179,6 +179,16 @@ convert = [
179
179
  "gguf",
180
180
  "llama-cpp-python",
181
181
  ]
182
+ # Unsloth: 2-5x faster training, 70% less VRAM.
183
+ # NOTE: Unsloth requires trl<=0.24.0 which conflicts with our trl==1.5.1.
184
+ # Install Unsloth in a separate venv or let pip resolve the conflict:
185
+ # pip install unsloth # will downgrade trl automatically
186
+ # Then use: attacklm-train-all --use-unsloth ...
187
+ # The [unsloth] extra is provided for convenience but is NOT included
188
+ # in [all] due to the trl version conflict.
189
+ unsloth = [
190
+ "unsloth>=2026.6",
191
+ ]
182
192
  dev = [
183
193
  "pytest",
184
194
  "ruff",
@@ -234,4 +244,13 @@ packages = ["src/attacklm"]
234
244
  [tool.hatch.build.targets.wheel.force-include]
235
245
 
236
246
  [tool.hatch.version]
237
- path = "src/attacklm/__version__.py"
247
+ path = "src/attacklm/__version__.py"
248
+
249
+ # ── Build-time dependencies for packages that don't declare them ────────────────
250
+ # flash-attn and causal-conv1d need torch at build time but don't list it in
251
+ # their build-system.requires. Without this, `uv pip install attacklm[all]` fails
252
+ # with "ModuleNotFoundError: No module named 'torch'" during the flash-attn build.
253
+ # This tells uv to pre-install torch before building these packages.
254
+ [tool.uv.extra-build-dependencies]
255
+ flash-attn = ["torch"]
256
+ causal-conv1d = ["torch"]
@@ -418,6 +418,8 @@ def build_train_cmd(
418
418
  cmd.extend(["--target-modules", args.target_modules])
419
419
  if getattr(args, "moe_safe_target", False):
420
420
  cmd.append("--moe-safe-target")
421
+ if getattr(args, "use_unsloth", False):
422
+ cmd.append("--use-unsloth")
421
423
  # v0.1.6+: pass dataset specs so train_template can record them in
422
424
  # state.json[dataset.specs] (reproducibility).
423
425
  if dataset_specs:
@@ -736,6 +738,14 @@ def main():
736
738
  help="Restrict LoRA to attention + MLP, force bf16, disable 4-bit quantization "
737
739
  "for MoE models in train_template.py (default: OFF).",
738
740
  )
741
+ parser.add_argument(
742
+ "--use-unsloth",
743
+ action="store_true",
744
+ default=False,
745
+ help="Use Unsloth's optimized model loading and LoRA kernels "
746
+ "(2-5x faster, 70% less VRAM). Requires 'pip install unsloth'. "
747
+ "Passed through to train_template.py (default: OFF).",
748
+ )
739
749
  # ---- Experience replay flags ----
740
750
  parser.add_argument(
741
751
  "--replay-source",
@@ -355,6 +355,20 @@ Examples:
355
355
  "per Unsloth guidance. Default: OFF."
356
356
  ),
357
357
  )
358
+ parser.add_argument(
359
+ "--use-unsloth",
360
+ action="store_true",
361
+ default=False,
362
+ help=(
363
+ "Use Unsloth's optimized model loading and LoRA kernels. "
364
+ "Unsloth provides 2-5x faster training, 70% less VRAM, and "
365
+ "8x longer context support vs standard HF QLoRA. Requires "
366
+ "'uv pip install attacklm[unsloth]' or 'pip install unsloth'. "
367
+ "When enabled, Unsloth's FastLanguageModel replaces the "
368
+ "standard AutoModelForCausalLM + BitsAndBytes pipeline. "
369
+ "Default: OFF (standard HF QLoRA)."
370
+ ),
371
+ )
358
372
 
359
373
  return parser.parse_args()
360
374
 
@@ -1431,12 +1445,17 @@ def main() -> None:
1431
1445
  if args.moe_safe_target
1432
1446
  else "OFF"
1433
1447
  )
1448
+ _unsloth_display = (
1449
+ "ON (FastLanguageModel + optimized LoRA kernels)" if args.use_unsloth else "OFF"
1450
+ )
1434
1451
 
1435
1452
  print("=" * 60)
1436
1453
  print(" TRAINING PLAN")
1437
1454
  print("=" * 60)
1438
1455
  print(f" Model: {args.base_model}")
1439
- if not args.moe_safe_target:
1456
+ if args.use_unsloth:
1457
+ print(" Quantization: 4-bit (Unsloth internal)")
1458
+ elif not args.moe_safe_target:
1440
1459
  print(" Quantization: 4-bit NF4 (double quant)")
1441
1460
  else:
1442
1461
  print(" Quantization: NONE (bf16 full-precision for MoE)")
@@ -1448,6 +1467,7 @@ def main() -> None:
1448
1467
  print(f" DoRA: {_dora_display}")
1449
1468
  print(f" LoftQ init: {_loftq_display}")
1450
1469
  print(f" MoE-safe target: {_moe_display}")
1470
+ print(f" Unsloth: {_unsloth_display}")
1451
1471
  print(f" Epochs: {args.epochs}")
1452
1472
  print(f" Batch size: {args.batch_size}")
1453
1473
  print(f" Max seq length: {args.max_length}")
@@ -1482,6 +1502,12 @@ def main() -> None:
1482
1502
  print(" Memory estimate for Qwen2.5-7B QLoRA:")
1483
1503
  print(" ~10-12 GB VRAM at batch_size=2, max_length=2048")
1484
1504
  print(" ~6-8 GB VRAM at batch_size=1, max_length=1024")
1505
+ if args.use_unsloth:
1506
+ print("")
1507
+ print(" With --use-unsloth (70% less VRAM):")
1508
+ print(" ~4-5 GB VRAM at batch_size=2, max_length=2048")
1509
+ print(" ~3-4 GB VRAM at batch_size=1, max_length=1024")
1510
+ print(" ~13B model fits in 16GB with Unsloth QLoRA")
1485
1511
  print("=" * 60)
1486
1512
  return
1487
1513
 
@@ -1585,6 +1611,22 @@ def main() -> None:
1585
1611
  )
1586
1612
  sys.exit(1)
1587
1613
 
1614
+ # --- Unsloth: import and verify availability ---
1615
+ _unsloth_available = False
1616
+ if args.use_unsloth:
1617
+ try:
1618
+ from unsloth import FastLanguageModel, is_bfloat16_supported
1619
+
1620
+ _unsloth_available = True
1621
+ print(" Unsloth: loaded (FastLanguageModel available)")
1622
+ except ImportError:
1623
+ print(
1624
+ "ERROR: --use-unsloth requires the 'unsloth' package.\n"
1625
+ " Install: uv pip install attacklm[unsloth]\n"
1626
+ " Or: pip install unsloth"
1627
+ )
1628
+ sys.exit(1)
1629
+
1588
1630
  # --- Build quantization config ---
1589
1631
  import torch
1590
1632
 
@@ -1617,18 +1659,25 @@ def main() -> None:
1617
1659
  # BitsAndBytes 4-bit does not support MoE expert weights per Unsloth
1618
1660
  # guidance. For MoE models, we load in bf16 and only apply LoRA to the
1619
1661
  # attention + MLP modules (excluding router/gate/lm_head).
1620
- skip_quantization = args.moe_safe_target
1662
+ # --use-unsloth: Unsloth handles quantization internally via its own
1663
+ # load_in_4bit parameter. We skip BitsAndBytes entirely.
1664
+ skip_quantization = args.moe_safe_target or args.use_unsloth
1621
1665
 
1622
1666
  if skip_quantization:
1623
- bnb_config = None # No quantization for MoE-safe mode
1624
- # Force bf16 for MoE models
1625
- if compute_type != "bf16":
1626
- print(
1627
- " --moe-safe-target: overriding compute dtype to bf16 "
1628
- "(required for MoE models without 4-bit quantization)"
1629
- )
1630
- compute_type = "bf16"
1631
- compute_dtype = torch.bfloat16
1667
+ bnb_config = None # No quantization for MoE-safe or Unsloth mode
1668
+ if args.moe_safe_target:
1669
+ # Force bf16 for MoE models
1670
+ if compute_type != "bf16":
1671
+ print(
1672
+ " --moe-safe-target: overriding compute dtype to bf16 "
1673
+ "(required for MoE models without 4-bit quantization)"
1674
+ )
1675
+ compute_type = "bf16"
1676
+ compute_dtype = torch.bfloat16
1677
+ elif args.use_unsloth:
1678
+ # Unsloth handles dtype internally; we still set compute_dtype
1679
+ # for the SFTConfig mixed-precision flags
1680
+ compute_dtype = torch.bfloat16 if compute_type == "bf16" else torch.float16
1632
1681
  else:
1633
1682
  bnb_config = get_quantization_config()
1634
1683
 
@@ -1658,6 +1707,8 @@ def main() -> None:
1658
1707
 
1659
1708
  print(f"Loading model: {args.base_model}")
1660
1709
  print(f" Detected quantization: {quant_label}")
1710
+ if args.use_unsloth:
1711
+ print(" Unsloth: enabled (FastLanguageModel + optimized LoRA kernels)")
1661
1712
 
1662
1713
  # LoftQ init: if the model is already quantized, LoftQ cannot apply.
1663
1714
  # Print a warning and fall back to default init.
@@ -1728,9 +1779,36 @@ def main() -> None:
1728
1779
  pass
1729
1780
 
1730
1781
  try:
1731
- model = AutoModelForCausalLM.from_pretrained(
1732
- base_model_resolved, **load_kwargs
1733
- )
1782
+ if args.use_unsloth and _unsloth_available:
1783
+ # --- Unsloth model loading path ---
1784
+ # Unsloth's FastLanguageModel handles 4-bit quantization
1785
+ # internally (no BitsAndBytesConfig needed). It also
1786
+ # provides optimized LoRA kernels that are 2-5x faster
1787
+ # and use 70% less VRAM than standard HF QLoRA.
1788
+ print(" Loading with Unsloth FastLanguageModel...")
1789
+ model, tokenizer = FastLanguageModel.from_pretrained(
1790
+ model_name=base_model_resolved,
1791
+ max_seq_length=args.max_length,
1792
+ load_in_4bit=True,
1793
+ dtype=None, # Auto-detect from GPU
1794
+ trust_remote_code=True,
1795
+ )
1796
+ # Unsloth returns (model, tokenizer) — use its tokenizer
1797
+ # which has the correct chat template and special tokens
1798
+ model, tokenizer = FastLanguageModel.from_pretrained(
1799
+ model_name=base_model_resolved,
1800
+ max_seq_length=args.max_length,
1801
+ load_in_4bit=True,
1802
+ dtype=None, # Auto-detect from GPU
1803
+ trust_remote_code=True,
1804
+ )
1805
+ if tokenizer.pad_token is None:
1806
+ tokenizer.pad_token = tokenizer.eos_token
1807
+ print(" Unsloth: model loaded with internal 4-bit quantization")
1808
+ else:
1809
+ model = AutoModelForCausalLM.from_pretrained(
1810
+ base_model_resolved, **load_kwargs
1811
+ )
1734
1812
  except (ImportError, ValueError, ModuleNotFoundError) as e:
1735
1813
  error_str = str(e).lower()
1736
1814
  if "flash" in error_str or "flash_attention" in error_str:
@@ -1901,24 +1979,56 @@ def main() -> None:
1901
1979
  # (before training plan display) so they can appear in the plan output.
1902
1980
  # The LoftQ warning for pre-quantized models was also printed earlier.
1903
1981
 
1904
- lora_config = get_qlora_config(
1905
- lora_r=args.lora_r,
1906
- lora_alpha=args.lora_alpha,
1907
- lora_dropout=args.lora_dropout,
1908
- use_rslora=args.use_rslora,
1909
- target_modules=target_modules_list,
1910
- use_dora=args.use_dora,
1911
- init_lora_weights=init_lora_weights,
1912
- )
1913
-
1914
- if args.use_dora:
1915
- print(" DoRA/QDoRA enabled (use_dora=True)")
1916
- if args.use_rslora:
1917
- print(" RSLoRA enabled (use_rslora=True)")
1982
+ if args.use_unsloth and _unsloth_available:
1983
+ # Unsloth LoRA path: FastLanguageModel.get_peft_model uses
1984
+ # optimized Triton kernels for 2-5x faster training and
1985
+ # 70% less VRAM than standard HF PEFT.
1986
+ print(" Unsloth: applying optimized LoRA via FastLanguageModel.get_peft_model")
1987
+ model = FastLanguageModel.get_peft_model(
1988
+ model,
1989
+ r=args.lora_r,
1990
+ lora_alpha=args.lora_alpha,
1991
+ lora_dropout=args.lora_dropout,
1992
+ target_modules=target_modules_list
1993
+ or [
1994
+ "q_proj",
1995
+ "k_proj",
1996
+ "v_proj",
1997
+ "o_proj",
1998
+ "gate_proj",
1999
+ "up_proj",
2000
+ "down_proj",
2001
+ ],
2002
+ use_gradient_checkpointing="unsloth", # Unsloth's optimized checkpointing
2003
+ random_state=42,
2004
+ use_rslora=args.use_rslora,
2005
+ loftq_config=None, # Unsloth handles quantization internally
2006
+ )
2007
+ if args.use_dora:
2008
+ print(
2009
+ " WARNING: DoRA not supported by Unsloth's get_peft_model. "
2010
+ "Falling back to standard LoRA. Use --no-use-unsloth for DoRA."
2011
+ )
1918
2012
  else:
1919
- print(" RSLoRA disabled (classic LoRA scaling alpha/r)")
2013
+ lora_config = get_qlora_config(
2014
+ lora_r=args.lora_r,
2015
+ lora_alpha=args.lora_alpha,
2016
+ lora_dropout=args.lora_dropout,
2017
+ use_rslora=args.use_rslora,
2018
+ target_modules=target_modules_list,
2019
+ use_dora=args.use_dora,
2020
+ init_lora_weights=init_lora_weights,
2021
+ )
2022
+
2023
+ if args.use_dora:
2024
+ print(" DoRA/QDoRA enabled (use_dora=True)")
2025
+ if args.use_rslora:
2026
+ print(" RSLoRA enabled (use_rslora=True)")
2027
+ else:
2028
+ print(" RSLoRA disabled (classic LoRA scaling alpha/r)")
2029
+
2030
+ model = get_peft_model(model, lora_config)
1920
2031
 
1921
- model = get_peft_model(model, lora_config)
1922
2032
  model.print_trainable_parameters()
1923
2033
 
1924
2034
  # --- Formatting function for chat template ---
@@ -0,0 +1 @@
1
+ __version__ = "0.5.4"
@@ -1 +0,0 @@
1
- __version__ = "0.5.2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes