attacklm 0.7.0__tar.gz → 0.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. {attacklm-0.7.0 → attacklm-0.7.1}/CHANGELOG.md +24 -0
  2. {attacklm-0.7.0 → attacklm-0.7.1}/PKG-INFO +25 -3
  3. {attacklm-0.7.0 → attacklm-0.7.1}/README.md +24 -2
  4. attacklm-0.7.1/attacklm-gui/README.md +148 -0
  5. attacklm-0.7.1/attacklm-gui/pyproject.toml +19 -0
  6. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/__init__.py +3 -0
  7. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/app.py +58 -0
  8. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/cli.py +17 -0
  9. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/presets.py +170 -0
  10. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/runner.py +223 -0
  11. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/screens/__init__.py +1 -0
  12. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/screens/command_forms.py +343 -0
  13. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/screens/main_menu.py +101 -0
  14. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/screens/train_form.py +451 -0
  15. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/screens/train_live.py +328 -0
  16. attacklm-0.7.1/attacklm-gui/src/attacklm_gui/widgets/__init__.py +1 -0
  17. attacklm-0.7.1/attacklm-gui/tests/test_gui.py +208 -0
  18. {attacklm-0.7.0 → attacklm-0.7.1}/hf/README.md +4 -0
  19. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/train_template.py +73 -3
  20. attacklm-0.7.1/src/attacklm/__version__.py +1 -0
  21. attacklm-0.7.0/src/attacklm/__version__.py +0 -1
  22. {attacklm-0.7.0 → attacklm-0.7.1}/.github/workflows/release.yml +0 -0
  23. {attacklm-0.7.0 → attacklm-0.7.1}/.gitignore +0 -0
  24. {attacklm-0.7.0 → attacklm-0.7.1}/ATTRIBUTION.md +0 -0
  25. {attacklm-0.7.0 → attacklm-0.7.1}/CONTRIBUTING.md +0 -0
  26. {attacklm-0.7.0 → attacklm-0.7.1}/EVALUATION.md +0 -0
  27. {attacklm-0.7.0 → attacklm-0.7.1}/LICENSE +0 -0
  28. {attacklm-0.7.0 → attacklm-0.7.1}/MANIFEST.in +0 -0
  29. {attacklm-0.7.0 → attacklm-0.7.1}/Makefile +0 -0
  30. {attacklm-0.7.0 → attacklm-0.7.1}/NOTICE +0 -0
  31. {attacklm-0.7.0 → attacklm-0.7.1}/QA_BEFORE_RELEASES.md +0 -0
  32. {attacklm-0.7.0 → attacklm-0.7.1}/REPLAY_PLAN.md +0 -0
  33. {attacklm-0.7.0 → attacklm-0.7.1}/data/ATTRIBUTION.md +0 -0
  34. {attacklm-0.7.0 → attacklm-0.7.1}/data/LEGAL.md +0 -0
  35. {attacklm-0.7.0 → attacklm-0.7.1}/data/REMOVAL.md +0 -0
  36. {attacklm-0.7.0 → attacklm-0.7.1}/data/bench/questions.jsonl +0 -0
  37. {attacklm-0.7.0 → attacklm-0.7.1}/data/bench/speed_context.txt +0 -0
  38. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/ATTRIBUTION.md +0 -0
  39. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/GEMINI_RESEARCH_2026-06-11.md +0 -0
  40. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/acquisition_report.json +0 -0
  41. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/manifest.json +0 -0
  42. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/README.md +0 -0
  43. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/_index.json +0 -0
  44. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
  45. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
  46. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
  47. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
  48. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
  49. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
  50. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
  51. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
  52. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
  53. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
  54. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
  55. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
  56. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
  57. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
  58. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
  59. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
  60. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/elastic-rules/defensive/detection_engineering/data.jsonl +0 -0
  61. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
  62. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
  63. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
  64. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
  65. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
  66. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
  67. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
  68. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
  69. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
  70. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
  71. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
  72. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
  73. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
  74. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
  75. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
  76. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
  77. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
  78. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
  79. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
  80. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
  81. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
  82. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
  83. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
  84. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
  85. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
  86. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
  87. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
  88. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
  89. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
  90. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/mordor/defensive/threat_hunting/data.jsonl +0 -0
  91. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
  92. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
  93. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/nist-ir/defensive/incident_response/data.jsonl +0 -0
  94. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
  95. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
  96. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
  97. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
  98. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
  99. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
  100. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
  101. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
  102. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
  103. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
  104. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
  105. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
  106. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
  107. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
  108. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
  109. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
  110. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
  111. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/sigma-hq/defensive/detection_engineering/data.jsonl +0 -0
  112. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
  113. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
  114. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/splunk-content/defensive/detection_engineering/data.jsonl +0 -0
  115. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
  116. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
  117. {attacklm-0.7.0 → attacklm-0.7.1}/data/datasets/buckets/sources/threathunter-playbook/defensive/threat_hunting/data.jsonl +0 -0
  118. {attacklm-0.7.0 → attacklm-0.7.1}/data/golden/prompts.jsonl +0 -0
  119. {attacklm-0.7.0 → attacklm-0.7.1}/data/reference/prompts.jsonl +0 -0
  120. {attacklm-0.7.0 → attacklm-0.7.1}/data/steering/prompts/opsec_aware.txt +0 -0
  121. {attacklm-0.7.0 → attacklm-0.7.1}/data/steering/prompts/opsec_unaware.txt +0 -0
  122. {attacklm-0.7.0 → attacklm-0.7.1}/data/steering/prompts/succinct.txt +0 -0
  123. {attacklm-0.7.0 → attacklm-0.7.1}/data/steering/prompts/verbose.txt +0 -0
  124. {attacklm-0.7.0 → attacklm-0.7.1}/experiments/README.md +0 -0
  125. {attacklm-0.7.0 → attacklm-0.7.1}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
  126. {attacklm-0.7.0 → attacklm-0.7.1}/hf/.gitattributes +0 -0
  127. {attacklm-0.7.0 → attacklm-0.7.1}/hf/data/manifest.json +0 -0
  128. {attacklm-0.7.0 → attacklm-0.7.1}/hf/dataset_infos.json +0 -0
  129. {attacklm-0.7.0 → attacklm-0.7.1}/hf/scripts/build_hf_dataset.py +0 -0
  130. {attacklm-0.7.0 → attacklm-0.7.1}/hf/scripts/push_to_hf.py +0 -0
  131. {attacklm-0.7.0 → attacklm-0.7.1}/hpo_runs/.gitkeep +0 -0
  132. {attacklm-0.7.0 → attacklm-0.7.1}/hpo_runs/hpo_state.json +0 -0
  133. {attacklm-0.7.0 → attacklm-0.7.1}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
  134. {attacklm-0.7.0 → attacklm-0.7.1}/logs/.gitkeep +0 -0
  135. {attacklm-0.7.0 → attacklm-0.7.1}/notes/BLUE_TEAM_DESIGN_v0.5.0.md +0 -0
  136. {attacklm-0.7.0 → attacklm-0.7.1}/notes/EVAL_DESIGN_v0.4.0.md +0 -0
  137. {attacklm-0.7.0 → attacklm-0.7.1}/notes/STEERING_REVIEW_v0.4.0.md +0 -0
  138. {attacklm-0.7.0 → attacklm-0.7.1}/pipeline.example.yaml +0 -0
  139. {attacklm-0.7.0 → attacklm-0.7.1}/presets/blue-team.json +0 -0
  140. {attacklm-0.7.0 → attacklm-0.7.1}/presets/purple-team.json +0 -0
  141. {attacklm-0.7.0 → attacklm-0.7.1}/presets/red-team.json +0 -0
  142. {attacklm-0.7.0 → attacklm-0.7.1}/pyproject.toml +0 -0
  143. {attacklm-0.7.0 → attacklm-0.7.1}/requirements.txt +0 -0
  144. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/_eval_loader.py +0 -0
  145. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_cloud_attack_dataset.py +0 -0
  146. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_ics_dataset.py +0 -0
  147. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_phishing_dataset.py +0 -0
  148. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_red_team_tactics.py +0 -0
  149. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_replay_general.py +0 -0
  150. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_supply_chain_dataset.py +0 -0
  151. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_web_attack_dataset.py +0 -0
  152. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/acquire_wireless_dataset.py +0 -0
  153. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/audit_dataset.py +0 -0
  154. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/balance_buckets.py +0 -0
  155. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/bucket_loader.py +0 -0
  156. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/build.py +0 -0
  157. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/clone_repos.sh +0 -0
  158. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/collect_reference.py +0 -0
  159. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/compare_scores.py +0 -0
  160. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/convert_to_gguf.py +0 -0
  161. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/demo.py +0 -0
  162. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/device_utils.py +0 -0
  163. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/domain_bench.py +0 -0
  164. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/eval_retention.py +0 -0
  165. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_ai_tools_to_jsonl.py +0 -0
  166. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
  167. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_by_tactic.py +0 -0
  168. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
  169. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_elastic_rules.py +0 -0
  170. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
  171. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_mordor.py +0 -0
  172. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_nist_ir.py +0 -0
  173. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_rta_to_jsonl.py +0 -0
  174. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_sigma_defensive.py +0 -0
  175. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_splunk_content.py +0 -0
  176. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/extract_threathunter_playbook.py +0 -0
  177. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/generate_synthetic_scarce.py +0 -0
  178. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/golden_vectors.py +0 -0
  179. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/hpo_runner.py +0 -0
  180. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/import_gguf.sh +0 -0
  181. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/import_to_lmstudio.sh +0 -0
  182. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/infer.py +0 -0
  183. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/init_pipeline.py +0 -0
  184. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/merge_adapter.py +0 -0
  185. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/mitre_tactic_lookup.py +0 -0
  186. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/parse_metasploit_to_jsonl.py +0 -0
  187. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/pipeline.py +0 -0
  188. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/rebuild_manifest.py +0 -0
  189. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/register_ollama.py +0 -0
  190. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/reorganize_buckets.py +0 -0
  191. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/replay_mixer.py +0 -0
  192. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/score_candidates.py +0 -0
  193. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/setup_buckets.py +0 -0
  194. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/speed_bench.py +0 -0
  195. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/steering.py +0 -0
  196. {attacklm-0.7.0 → attacklm-0.7.1}/scripts/train_all.py +0 -0
  197. {attacklm-0.7.0 → attacklm-0.7.1}/src/attacklm/__init__.py +0 -0
  198. {attacklm-0.7.0 → attacklm-0.7.1}/src/attacklm/_project_root.py +0 -0
  199. {attacklm-0.7.0 → attacklm-0.7.1}/src/attacklm/cli.py +0 -0
  200. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_balance_buckets.py +0 -0
  201. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_collect_reference.py +0 -0
  202. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_compare_scores.py +0 -0
  203. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_domain_bench.py +0 -0
  204. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_eval_loader.py +0 -0
  205. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_eval_retention.py +0 -0
  206. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_golden_vectors.py +0 -0
  207. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_init_pipeline.py +0 -0
  208. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_replay_mixer.py +0 -0
  209. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_score_candidates.py +0 -0
  210. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_speed_bench.py +0 -0
  211. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_steering.py +0 -0
  212. {attacklm-0.7.0 → attacklm-0.7.1}/tests/test_thinking_models.py +0 -0
  213. {attacklm-0.7.0 → attacklm-0.7.1}/uv.lock +0 -0
@@ -4,6 +4,30 @@ All notable changes to AttackLM are documented in this file. Versions follow [Se
4
4
 
5
5
  ---
6
6
 
7
+ ## [0.7.1] — 2026-06-30 — GUI, VRAM fixes, dataset caching
8
+
9
+ ### Added
10
+ - **attacklm-gui**: Terminal-based TUI wrapper (Textual) for all CLI commands
11
+ - Form-based training config with 40+ params in 5 tabs (Basic, LoRA, GaLore, Advanced, Hardware)
12
+ - Live training monitor with loss sparkline, VRAM gauge, progress bar, log viewer
13
+ - One-click screens for extract, balance, infer, merge, build, pipeline, init
14
+ - 5 built-in presets (3B Q-GaLore, 3B LoRA, 7B Q-GaLore, 7B QLoRA, etc.)
15
+ - Pause/resume/quit controls during training
16
+ - Works in terminal-only environments (no X11/WSLg required)
17
+ - **Dataset caching**: Tokenized datasets saved to disk after first run, reloaded in ~1s on subsequent runs (keyed by dataset + model + max_length + packing)
18
+ - **config.json fix**: Training runs now preserve HF model architecture fields (model_type, architectures, hidden_size, etc.) for GGUF conversion compatibility
19
+
20
+ ### Fixed
21
+ - **VRAM fragmentation**: Removed `device_map="auto"` for single-GPU training — was splitting model across GPU+CPU, creating meta tensors, and leaving VRAM fragmented. Model now loads directly to GPU.
22
+ - **Spectrum crash on 7B**: Skip meta-device tensors in SNR computation (caused by CPU-offloaded layers from device_map="auto")
23
+ - **VRAM parsing**: Added regex for compact VRAM format (`VRAM X/Y GB (A alloc + C cache)`) in training output parser
24
+
25
+ ### Changed
26
+ - Moved attacklm-gui into the main AttackLM repo under `attacklm-gui/`
27
+ - 17 GUI tests passing
28
+
29
+ ---
30
+
7
31
  ## [0.7.0] — 2026-06-29 — Defensive data extraction, test fixes, script cleanup
8
32
 
9
33
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: attacklm
3
- Version: 0.7.0
3
+ Version: 0.7.1
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
@@ -205,6 +205,27 @@ AttackLM — QLoRA fine-tuning pipeline for a MITRE ATT&CK-grounded security AI
205
205
 
206
206
  ---
207
207
 
208
+ ## GUI (New in v0.7.1)
209
+
210
+ AttackLM now includes a terminal-based GUI for all commands. No more memorizing 40+ CLI flags.
211
+
212
+ ```bash
213
+ pip install attacklm-gui
214
+ attacklm-gui
215
+ ```
216
+
217
+ Features:
218
+ - **Training form** with 40+ params in 5 tabs (Basic, LoRA, GaLore, Advanced, Hardware)
219
+ - **Live training monitor** with loss sparkline, VRAM gauge, progress bar, and log viewer
220
+ - **One-click screens** for extract, balance, infer, merge, build, pipeline, and init
221
+ - **5 built-in presets** (3B Q-GaLore, 3B LoRA, 7B Q-GaLore, 7B QLoRA, etc.)
222
+ - **Pause/resume/quit** controls during training
223
+ - Works in **terminal-only** environments — no X11, no browser, no GPU required. Works over SSH and WSL.
224
+
225
+ The CLI still works exactly as before. The GUI is a thin wrapper that constructs and runs CLI commands.
226
+
227
+ ---
228
+
208
229
  ## Install
209
230
  The recommended way to install the full CUDA training stack:
210
231
 
@@ -348,7 +369,8 @@ This layout allows the pipeline to deterministically extract data from upstream
348
369
  ## CLI Reference
349
370
  | Command | Description |
350
371
  |---------|-------------|
351
- | `attacklm-init` | One-shot init: clone $\rightarrow$ extract $\rightarrow$ attribute $\rightarrow$ buckets |
372
+ | `attacklm-gui` | Terminal GUI for all commands (new in v0.7.1) |
373
+ | `attacklm-init` | One-shot init: clone → extract → attribute → buckets |
352
374
  | `attacklm-train` | Train a single QLoRA adapter |
353
375
  | `attacklm-train-all` | Orchestrated training for all buckets / HPO |
354
376
  | `attacklm-balance` | Build a balanced subset of buckets |
@@ -356,7 +378,7 @@ This layout allows the pipeline to deterministically extract data from upstream
356
378
  | `attacklm-infer` | Smoke-test inference |
357
379
  | `attacklm-merge` | Merge LoRA adapter into base model |
358
380
  | `attacklm-gguf` | Convert merged model to GGUF (llama.cpp) |
359
- | `attacklm-build` | One-shot merge $\rightarrow$ GGUF $\rightarrow$ install |
381
+ | `attacklm-build` | One-shot merge GGUF install |
360
382
  | `attacklm-demo` | Multi-agent orchestrator demo |
361
383
  | `attacklm-extract` | Extract data from cloned repositories |
362
384
  | `attacklm-buckets` | Organize data into bucket structure |
@@ -7,6 +7,27 @@ AttackLM — QLoRA fine-tuning pipeline for a MITRE ATT&CK-grounded security AI
7
7
 
8
8
  ---
9
9
 
10
+ ## GUI (New in v0.7.1)
11
+
12
+ AttackLM now includes a terminal-based GUI for all commands. No more memorizing 40+ CLI flags.
13
+
14
+ ```bash
15
+ pip install attacklm-gui
16
+ attacklm-gui
17
+ ```
18
+
19
+ Features:
20
+ - **Training form** with 40+ params in 5 tabs (Basic, LoRA, GaLore, Advanced, Hardware)
21
+ - **Live training monitor** with loss sparkline, VRAM gauge, progress bar, and log viewer
22
+ - **One-click screens** for extract, balance, infer, merge, build, pipeline, and init
23
+ - **5 built-in presets** (3B Q-GaLore, 3B LoRA, 7B Q-GaLore, 7B QLoRA, etc.)
24
+ - **Pause/resume/quit** controls during training
25
+ - Works in **terminal-only** environments — no X11, no browser, no GPU required. Works over SSH and WSL.
26
+
27
+ The CLI still works exactly as before. The GUI is a thin wrapper that constructs and runs CLI commands.
28
+
29
+ ---
30
+
10
31
  ## Install
11
32
  The recommended way to install the full CUDA training stack:
12
33
 
@@ -150,7 +171,8 @@ This layout allows the pipeline to deterministically extract data from upstream
150
171
  ## CLI Reference
151
172
  | Command | Description |
152
173
  |---------|-------------|
153
- | `attacklm-init` | One-shot init: clone $\rightarrow$ extract $\rightarrow$ attribute $\rightarrow$ buckets |
174
+ | `attacklm-gui` | Terminal GUI for all commands (new in v0.7.1) |
175
+ | `attacklm-init` | One-shot init: clone → extract → attribute → buckets |
154
176
  | `attacklm-train` | Train a single QLoRA adapter |
155
177
  | `attacklm-train-all` | Orchestrated training for all buckets / HPO |
156
178
  | `attacklm-balance` | Build a balanced subset of buckets |
@@ -158,7 +180,7 @@ This layout allows the pipeline to deterministically extract data from upstream
158
180
  | `attacklm-infer` | Smoke-test inference |
159
181
  | `attacklm-merge` | Merge LoRA adapter into base model |
160
182
  | `attacklm-gguf` | Convert merged model to GGUF (llama.cpp) |
161
- | `attacklm-build` | One-shot merge $\rightarrow$ GGUF $\rightarrow$ install |
183
+ | `attacklm-build` | One-shot merge GGUF install |
162
184
  | `attacklm-demo` | Multi-agent orchestrator demo |
163
185
  | `attacklm-extract` | Extract data from cloned repositories |
164
186
  | `attacklm-buckets` | Organize data into bucket structure |
@@ -0,0 +1,148 @@
1
+ # AttackLM GUI
2
+
3
+ Terminal-based GUI wrapper for the [AttackLM](https://github.com/Veedubin/AttackLM) CLI training tools. Built with [Textual](https://textual.textualize.io/).
4
+
5
+ ## Why?
6
+
7
+ AttackLM has 21 CLI commands and `attacklm-train` alone has 40+ parameters. Remembering all the flags is painful. The GUI provides:
8
+
9
+ - **Form-based parameter input** with tabs, presets, and validation
10
+ - **Live training monitoring** with loss charts, VRAM gauges, and log streaming
11
+ - **One-click commands** for extract, balance, infer, merge, build, and more
12
+ - **Works everywhere** — terminal-only, no X11 required (WSL, SSH, headless)
13
+
14
+ The CLI still works exactly as before. The GUI is a thin wrapper that constructs and runs CLI commands.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pip install attacklm-gui
20
+ ```
21
+
22
+ Or from source:
23
+
24
+ ```bash
25
+ git clone https://github.com/Veedubin/AttackLM.git
26
+ cd AttackLM-Models/attacklm-gui
27
+ pip install -e .
28
+ ```
29
+
30
+ Requires `attacklm` (the CLI package) and `textual>=2.0`.
31
+
32
+ ## Usage
33
+
34
+ ```bash
35
+ attacklm-gui
36
+ ```
37
+
38
+ ### Main Menu
39
+
40
+ ```
41
+ ┌──────────────────────────────────────┐
42
+ │ AttackLM GUI v0.1.0 │
43
+ │ │
44
+ │ 🏋️ Train Model │
45
+ │ 📊 Extract Data │
46
+ │ ⚖️ Balance Dataset │
47
+ │ 🧠 Run Inference │
48
+ │ 🔗 Merge Adapter │
49
+ │ 📦 Build & Install │
50
+ │ 🔧 Pipeline │
51
+ │ 🚀 Init Dataset │
52
+ └──────────────────────────────────────┘
53
+ ```
54
+
55
+ ### Training Form
56
+
57
+ The training form organizes 40+ parameters into tabs:
58
+
59
+ | Tab | Parameters |
60
+ |-----|-----------|
61
+ | **Basic** | dataset, output, base model, epochs, batch size, max length |
62
+ | **LoRA** | rank, alpha, dropout, DoRA, RSLoRA, target modules, PiSSA |
63
+ | **GaLore** | Q-GaLore, rank, 32-bit, Spectrum layer freezing |
64
+ | **Advanced** | eval split, early stopping, save steps, gradient accum, optimizer, packing, live LR |
65
+ | **Hardware** | precision (BF16/FP16/FP32), multi-GPU, MoE safe, auto-tune |
66
+
67
+ **Presets** save and load complete configurations. Built-in presets:
68
+ - `3B Q-GaLore Spectrum` — full-parameter training on 16GB GPU
69
+ - `3B Q-GaLore Rank 128` — higher quality variant
70
+ - `3B LoRA Default` — standard QLoRA
71
+ - `7B Q-GaLore` — for 24GB GPUs
72
+ - `7B QLoRA Default` — standard QLoRA for 7B
73
+
74
+ ### Live Training Monitor
75
+
76
+ ```
77
+ ┌─────────────────────────────────────────────────────┐
78
+ │ Training: attacklm-3b-qgalore-spectrum │
79
+ │ Epoch 12/30 | Step 1896 | Elapsed: 1h 23m │
80
+ ├──────────────────────┬──────────────────────────────┤
81
+ │ Loss: 1.1143 ▂▃▅▆▇ │ VRAM: 5.9/15.6 GB (62%) │
82
+ │ Eval Loss: 1.176 │ alloc: 5.9 cache: 4.8 │
83
+ │ Trend: ↓ -0.0116 │ ████████░░░░ │
84
+ ├──────────────────────┴──────────────────────────────┤
85
+ │ Log Output (scrolling) │
86
+ │ Epoch 12/20 58% | loss 1.1143 | 2,844 tok/s ... │
87
+ ├─────────────────────────────────────────────────────┤
88
+ │ [P]ause [S]top at checkpoint [Q]uit │
89
+ └─────────────────────────────────────────────────────┘
90
+ ```
91
+
92
+ Controls:
93
+ - **Pause/Resume** — SIGSTOP/SIGCONT the training process
94
+ - **Stop at Checkpoint** — graceful stop after current eval
95
+ - **Quit** — kill training immediately
96
+
97
+ ### Other Commands
98
+
99
+ | Screen | What it does |
100
+ |--------|-------------|
101
+ | **Extract** | Run data extractors on upstream sources |
102
+ | **Balance** | Balance a dataset with cap size |
103
+ | **Inference** | Run a trained model with a prompt |
104
+ | **Merge** | Merge LoRA adapter into base model |
105
+ | **Build** | Merge → GGUF → install to LM Studio |
106
+ | **Pipeline** | Run a YAML training pipeline |
107
+ | **Init** | One-click dataset initialization |
108
+
109
+ ## Keyboard Shortcuts
110
+
111
+ | Key | Action |
112
+ |-----|--------|
113
+ | `q` | Quit |
114
+ | `m` | Return to main menu |
115
+ | `Tab` | Next field |
116
+ | `Enter` | Activate button |
117
+ | `Esc` | Go back |
118
+
119
+ ## Architecture
120
+
121
+ ```
122
+ attacklm-gui/
123
+ ├── src/attacklm_gui/
124
+ │ ├── app.py # Textual App entry point
125
+ │ ├── cli.py # CLI entry point
126
+ │ ├── runner.py # Subprocess manager + output parser
127
+ │ ├── presets.py # Save/load training presets
128
+ │ ├── screens/
129
+ │ │ ├── main_menu.py # Command launcher
130
+ │ │ ├── train_form.py # Training parameter form
131
+ │ │ ├── train_live.py # Live training monitor
132
+ │ │ └── command_forms.py # Other command screens
133
+ │ └── widgets/
134
+ │ └── __init__.py
135
+ └── tests/
136
+ └── test_gui.py
137
+ ```
138
+
139
+ The GUI never touches AttackLM's internal logic. It constructs CLI command strings and runs them via `asyncio.create_subprocess_exec`. All training, extraction, and inference logic stays in `scripts/*.py`.
140
+
141
+ ## Requirements
142
+
143
+ - Python 3.10+
144
+ - Linux (any flavor) or WSL
145
+ - Terminal with 256-color support
146
+ - AttackLM installed (`pip install attacklm[all]`)
147
+
148
+ No X11, no GPU, no browser required. Works over SSH.
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "attacklm-gui"
3
+ version = "0.1.0"
4
+ description = "Terminal GUI wrapper for AttackLM CLI training tools"
5
+ requires-python = ">=3.10"
6
+ dependencies = [
7
+ "textual>=2.0",
8
+ "attacklm",
9
+ ]
10
+
11
+ [project.scripts]
12
+ attacklm-gui = "attacklm_gui.cli:main"
13
+
14
+ [build-system]
15
+ requires = ["setuptools>=75"]
16
+ build-backend = "setuptools.build_meta"
17
+
18
+ [tool.setuptools.packages.find]
19
+ where = ["src"]
@@ -0,0 +1,3 @@
1
+ """AttackLM GUI — Terminal-based wrapper for the AttackLM CLI."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,58 @@
1
+ """Main Textual application for AttackLM GUI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from textual.app import App, ComposeResult
8
+ from textual.binding import Binding
9
+ from textual.widgets import Header, Footer
10
+
11
+ from attacklm_gui.presets import ensure_builtin_presets
12
+ from attacklm_gui.screens.main_menu import MainMenuScreen
13
+
14
+
15
+ class AttackLMApp(App):
16
+ """Terminal GUI wrapper for AttackLM CLI tools."""
17
+
18
+ TITLE = "AttackLM GUI"
19
+ SUB_TITLE = "v0.1.0"
20
+ CSS_PATH = None # We'll use inline CSS for now
21
+
22
+ BINDINGS = [
23
+ Binding("q", "quit", "Quit", show=True),
24
+ Binding("m", "main_menu", "Main Menu", show=True),
25
+ Binding("?", "help", "Help", show=False),
26
+ ]
27
+
28
+ def __init__(self) -> None:
29
+ super().__init__()
30
+ self.attacklm_dir = self._find_attacklm_dir()
31
+
32
+ def _find_attacklm_dir(self) -> Path:
33
+ """Find the AttackLM project directory."""
34
+ # Try common locations
35
+ candidates = [
36
+ Path.cwd(),
37
+ Path.home() / "Projects" / "reverse_engineering" / "AttackLM",
38
+ Path.home() / "AttackLM",
39
+ ]
40
+ for c in candidates:
41
+ if (c / "pyproject.toml").exists() and (
42
+ c / "scripts" / "train_template.py"
43
+ ).exists():
44
+ return c
45
+ return Path.cwd()
46
+
47
+ def compose(self) -> ComposeResult:
48
+ yield Header()
49
+ yield Footer()
50
+
51
+ def on_mount(self) -> None:
52
+ ensure_builtin_presets()
53
+ self.push_screen(MainMenuScreen())
54
+
55
+ def action_main_menu(self) -> None:
56
+ """Return to main menu."""
57
+ while len(self.screen_stack) > 1:
58
+ self.pop_screen()
@@ -0,0 +1,17 @@
1
+ """CLI entry point for attacklm-gui."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+
7
+ def main() -> int:
8
+ """Launch the AttackLM TUI."""
9
+ from attacklm_gui.app import AttackLMApp
10
+
11
+ app = AttackLMApp()
12
+ app.run()
13
+ return 0
14
+
15
+
16
+ if __name__ == "__main__":
17
+ sys.exit(main())
@@ -0,0 +1,170 @@
1
+ """Configuration preset management for AttackLM training parameters."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from dataclasses import dataclass, field
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+
11
+ PRESETS_DIR = Path.home() / ".config" / "attacklm" / "presets"
12
+
13
+
14
+ @dataclass
15
+ class Preset:
16
+ """A saved training configuration."""
17
+
18
+ name: str
19
+ params: dict[str, Any] = field(default_factory=dict)
20
+ description: str = ""
21
+
22
+ @property
23
+ def filename(self) -> str:
24
+ return f"{self.name.lower().replace(' ', '_')}.json"
25
+
26
+ @property
27
+ def path(self) -> Path:
28
+ return PRESETS_DIR / self.filename
29
+
30
+ def save(self) -> None:
31
+ """Save preset to disk."""
32
+ PRESETS_DIR.mkdir(parents=True, exist_ok=True)
33
+ data = {
34
+ "name": self.name,
35
+ "description": self.description,
36
+ "params": self.params,
37
+ }
38
+ with open(self.path, "w") as f:
39
+ json.dump(data, f, indent=2)
40
+
41
+ @classmethod
42
+ def load(cls, name: str) -> Preset | None:
43
+ """Load a preset by name."""
44
+ filename = f"{name.lower().replace(' ', '_')}.json"
45
+ path = PRESETS_DIR / filename
46
+ if not path.exists():
47
+ return None
48
+ with open(path) as f:
49
+ data = json.load(f)
50
+ return cls(
51
+ name=data["name"],
52
+ params=data.get("params", {}),
53
+ description=data.get("description", ""),
54
+ )
55
+
56
+ @classmethod
57
+ def list_all(cls) -> list[str]:
58
+ """List all saved preset names."""
59
+ PRESETS_DIR.mkdir(parents=True, exist_ok=True)
60
+ presets = []
61
+ for p in sorted(PRESETS_DIR.glob("*.json")):
62
+ try:
63
+ with open(p) as f:
64
+ data = json.load(f)
65
+ presets.append(data.get("name", p.stem))
66
+ except (json.JSONDecodeError, OSError):
67
+ pass
68
+ return presets
69
+
70
+ @classmethod
71
+ def delete(cls, name: str) -> bool:
72
+ """Delete a preset by name. Returns True if deleted."""
73
+ filename = f"{name.lower().replace(' ', '_')}.json"
74
+ path = PRESETS_DIR / filename
75
+ if path.exists():
76
+ path.unlink()
77
+ return True
78
+ return False
79
+
80
+
81
+ # --- Built-in presets ---
82
+
83
+ BUILTIN_PRESETS: list[Preset] = [
84
+ Preset(
85
+ name="3B Q-GaLore Spectrum",
86
+ description="Q-GaLore full-parameter training for 3B models on 16GB GPU",
87
+ params={
88
+ "use_qgalore": True,
89
+ "spectrum": 0.5,
90
+ "galore_rank": 64,
91
+ "epochs": 20,
92
+ "batch_size": 1,
93
+ "max_length": 12000,
94
+ "packing": True,
95
+ "early_stop_steps": 5,
96
+ "live_lr": True,
97
+ "optim": "paged_adamw_8bit",
98
+ },
99
+ ),
100
+ Preset(
101
+ name="3B Q-GaLore Rank 128",
102
+ description="Higher-rank Q-GaLore for better quality on 3B models",
103
+ params={
104
+ "use_qgalore": True,
105
+ "spectrum": 0.5,
106
+ "galore_rank": 128,
107
+ "epochs": 30,
108
+ "batch_size": 1,
109
+ "max_length": 12000,
110
+ "packing": True,
111
+ "early_stop_steps": 5,
112
+ "live_lr": True,
113
+ "optim": "paged_adamw_8bit",
114
+ },
115
+ ),
116
+ Preset(
117
+ name="3B LoRA Default",
118
+ description="Standard QLoRA training for 3B models",
119
+ params={
120
+ "lora_r": 16,
121
+ "lora_alpha": 32,
122
+ "lora_dropout": 0.05,
123
+ "epochs": 10,
124
+ "batch_size": 2,
125
+ "max_length": 2048,
126
+ "packing": False,
127
+ "early_stop_steps": 5,
128
+ "optim": "paged_adamw_8bit",
129
+ },
130
+ ),
131
+ Preset(
132
+ name="7B Q-GaLore",
133
+ description="Q-GaLore for 7B models on 24GB GPU",
134
+ params={
135
+ "use_qgalore": True,
136
+ "spectrum": 0.5,
137
+ "galore_rank": 128,
138
+ "epochs": 20,
139
+ "batch_size": 1,
140
+ "max_length": 8192,
141
+ "packing": True,
142
+ "early_stop_steps": 5,
143
+ "live_lr": True,
144
+ "optim": "paged_adamw_8bit",
145
+ },
146
+ ),
147
+ Preset(
148
+ name="7B QLoRA Default",
149
+ description="Standard QLoRA for 7B models",
150
+ params={
151
+ "lora_r": 16,
152
+ "lora_alpha": 32,
153
+ "lora_dropout": 0.05,
154
+ "epochs": 10,
155
+ "batch_size": 2,
156
+ "max_length": 2048,
157
+ "packing": False,
158
+ "early_stop_steps": 5,
159
+ "optim": "paged_adamw_8bit",
160
+ },
161
+ ),
162
+ ]
163
+
164
+
165
+ def ensure_builtin_presets() -> None:
166
+ """Create built-in presets if they don't exist."""
167
+ existing = set(Preset.list_all())
168
+ for preset in BUILTIN_PRESETS:
169
+ if preset.name not in existing:
170
+ preset.save()