hackagent 0.3.1__py3-none-any.whl

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 (183) hide show
  1. hackagent/__init__.py +12 -0
  2. hackagent/agent.py +214 -0
  3. hackagent/api/__init__.py +1 -0
  4. hackagent/api/agent/__init__.py +1 -0
  5. hackagent/api/agent/agent_create.py +347 -0
  6. hackagent/api/agent/agent_destroy.py +140 -0
  7. hackagent/api/agent/agent_list.py +242 -0
  8. hackagent/api/agent/agent_partial_update.py +361 -0
  9. hackagent/api/agent/agent_retrieve.py +235 -0
  10. hackagent/api/agent/agent_update.py +361 -0
  11. hackagent/api/apilogs/__init__.py +1 -0
  12. hackagent/api/apilogs/apilogs_list.py +170 -0
  13. hackagent/api/apilogs/apilogs_retrieve.py +162 -0
  14. hackagent/api/attack/__init__.py +1 -0
  15. hackagent/api/attack/attack_create.py +275 -0
  16. hackagent/api/attack/attack_destroy.py +146 -0
  17. hackagent/api/attack/attack_list.py +254 -0
  18. hackagent/api/attack/attack_partial_update.py +289 -0
  19. hackagent/api/attack/attack_retrieve.py +247 -0
  20. hackagent/api/attack/attack_update.py +289 -0
  21. hackagent/api/checkout/__init__.py +1 -0
  22. hackagent/api/checkout/checkout_create.py +225 -0
  23. hackagent/api/generate/__init__.py +1 -0
  24. hackagent/api/generate/generate_create.py +253 -0
  25. hackagent/api/judge/__init__.py +1 -0
  26. hackagent/api/judge/judge_create.py +253 -0
  27. hackagent/api/key/__init__.py +1 -0
  28. hackagent/api/key/key_create.py +179 -0
  29. hackagent/api/key/key_destroy.py +103 -0
  30. hackagent/api/key/key_list.py +170 -0
  31. hackagent/api/key/key_retrieve.py +162 -0
  32. hackagent/api/organization/__init__.py +1 -0
  33. hackagent/api/organization/organization_create.py +208 -0
  34. hackagent/api/organization/organization_destroy.py +104 -0
  35. hackagent/api/organization/organization_list.py +170 -0
  36. hackagent/api/organization/organization_me_retrieve.py +126 -0
  37. hackagent/api/organization/organization_partial_update.py +222 -0
  38. hackagent/api/organization/organization_retrieve.py +163 -0
  39. hackagent/api/organization/organization_update.py +222 -0
  40. hackagent/api/prompt/__init__.py +1 -0
  41. hackagent/api/prompt/prompt_create.py +171 -0
  42. hackagent/api/prompt/prompt_destroy.py +104 -0
  43. hackagent/api/prompt/prompt_list.py +185 -0
  44. hackagent/api/prompt/prompt_partial_update.py +185 -0
  45. hackagent/api/prompt/prompt_retrieve.py +163 -0
  46. hackagent/api/prompt/prompt_update.py +185 -0
  47. hackagent/api/result/__init__.py +1 -0
  48. hackagent/api/result/result_create.py +175 -0
  49. hackagent/api/result/result_destroy.py +106 -0
  50. hackagent/api/result/result_list.py +249 -0
  51. hackagent/api/result/result_partial_update.py +193 -0
  52. hackagent/api/result/result_retrieve.py +167 -0
  53. hackagent/api/result/result_trace_create.py +177 -0
  54. hackagent/api/result/result_update.py +189 -0
  55. hackagent/api/run/__init__.py +1 -0
  56. hackagent/api/run/run_create.py +187 -0
  57. hackagent/api/run/run_destroy.py +112 -0
  58. hackagent/api/run/run_list.py +291 -0
  59. hackagent/api/run/run_partial_update.py +201 -0
  60. hackagent/api/run/run_result_create.py +177 -0
  61. hackagent/api/run/run_retrieve.py +179 -0
  62. hackagent/api/run/run_run_tests_create.py +187 -0
  63. hackagent/api/run/run_update.py +201 -0
  64. hackagent/api/user/__init__.py +1 -0
  65. hackagent/api/user/user_create.py +212 -0
  66. hackagent/api/user/user_destroy.py +106 -0
  67. hackagent/api/user/user_list.py +174 -0
  68. hackagent/api/user/user_me_retrieve.py +126 -0
  69. hackagent/api/user/user_me_update.py +196 -0
  70. hackagent/api/user/user_partial_update.py +226 -0
  71. hackagent/api/user/user_retrieve.py +167 -0
  72. hackagent/api/user/user_update.py +226 -0
  73. hackagent/attacks/AdvPrefix/__init__.py +41 -0
  74. hackagent/attacks/AdvPrefix/completions.py +416 -0
  75. hackagent/attacks/AdvPrefix/config.py +259 -0
  76. hackagent/attacks/AdvPrefix/evaluation.py +745 -0
  77. hackagent/attacks/AdvPrefix/evaluators.py +564 -0
  78. hackagent/attacks/AdvPrefix/generate.py +711 -0
  79. hackagent/attacks/AdvPrefix/utils.py +307 -0
  80. hackagent/attacks/__init__.py +35 -0
  81. hackagent/attacks/advprefix.py +507 -0
  82. hackagent/attacks/base.py +106 -0
  83. hackagent/attacks/strategies.py +906 -0
  84. hackagent/cli/__init__.py +19 -0
  85. hackagent/cli/commands/__init__.py +20 -0
  86. hackagent/cli/commands/agent.py +100 -0
  87. hackagent/cli/commands/attack.py +417 -0
  88. hackagent/cli/commands/config.py +301 -0
  89. hackagent/cli/commands/results.py +327 -0
  90. hackagent/cli/config.py +249 -0
  91. hackagent/cli/main.py +515 -0
  92. hackagent/cli/tui/__init__.py +31 -0
  93. hackagent/cli/tui/actions_logger.py +200 -0
  94. hackagent/cli/tui/app.py +288 -0
  95. hackagent/cli/tui/base.py +137 -0
  96. hackagent/cli/tui/logger.py +318 -0
  97. hackagent/cli/tui/views/__init__.py +33 -0
  98. hackagent/cli/tui/views/agents.py +488 -0
  99. hackagent/cli/tui/views/attacks.py +624 -0
  100. hackagent/cli/tui/views/config.py +244 -0
  101. hackagent/cli/tui/views/dashboard.py +307 -0
  102. hackagent/cli/tui/views/results.py +1210 -0
  103. hackagent/cli/tui/widgets/__init__.py +24 -0
  104. hackagent/cli/tui/widgets/actions.py +346 -0
  105. hackagent/cli/tui/widgets/logs.py +435 -0
  106. hackagent/cli/utils.py +276 -0
  107. hackagent/client.py +286 -0
  108. hackagent/errors.py +37 -0
  109. hackagent/logger.py +83 -0
  110. hackagent/models/__init__.py +109 -0
  111. hackagent/models/agent.py +223 -0
  112. hackagent/models/agent_request.py +129 -0
  113. hackagent/models/api_token_log.py +184 -0
  114. hackagent/models/attack.py +154 -0
  115. hackagent/models/attack_request.py +82 -0
  116. hackagent/models/checkout_session_request_request.py +76 -0
  117. hackagent/models/checkout_session_response.py +59 -0
  118. hackagent/models/choice.py +81 -0
  119. hackagent/models/choice_message.py +67 -0
  120. hackagent/models/evaluation_status_enum.py +14 -0
  121. hackagent/models/generate_error_response.py +59 -0
  122. hackagent/models/generate_request_request.py +212 -0
  123. hackagent/models/generate_success_response.py +115 -0
  124. hackagent/models/generic_error_response.py +70 -0
  125. hackagent/models/message_request.py +67 -0
  126. hackagent/models/organization.py +102 -0
  127. hackagent/models/organization_minimal.py +68 -0
  128. hackagent/models/organization_request.py +71 -0
  129. hackagent/models/paginated_agent_list.py +123 -0
  130. hackagent/models/paginated_api_token_log_list.py +123 -0
  131. hackagent/models/paginated_attack_list.py +123 -0
  132. hackagent/models/paginated_organization_list.py +123 -0
  133. hackagent/models/paginated_prompt_list.py +123 -0
  134. hackagent/models/paginated_result_list.py +123 -0
  135. hackagent/models/paginated_run_list.py +123 -0
  136. hackagent/models/paginated_user_api_key_list.py +123 -0
  137. hackagent/models/paginated_user_profile_list.py +123 -0
  138. hackagent/models/patched_agent_request.py +128 -0
  139. hackagent/models/patched_attack_request.py +92 -0
  140. hackagent/models/patched_organization_request.py +71 -0
  141. hackagent/models/patched_prompt_request.py +125 -0
  142. hackagent/models/patched_result_request.py +237 -0
  143. hackagent/models/patched_run_request.py +138 -0
  144. hackagent/models/patched_user_profile_request.py +99 -0
  145. hackagent/models/prompt.py +220 -0
  146. hackagent/models/prompt_request.py +126 -0
  147. hackagent/models/result.py +294 -0
  148. hackagent/models/result_list_evaluation_status.py +14 -0
  149. hackagent/models/result_request.py +232 -0
  150. hackagent/models/run.py +233 -0
  151. hackagent/models/run_list_status.py +12 -0
  152. hackagent/models/run_request.py +133 -0
  153. hackagent/models/status_enum.py +12 -0
  154. hackagent/models/step_type_enum.py +14 -0
  155. hackagent/models/trace.py +121 -0
  156. hackagent/models/trace_request.py +94 -0
  157. hackagent/models/usage.py +75 -0
  158. hackagent/models/user_api_key.py +201 -0
  159. hackagent/models/user_api_key_request.py +73 -0
  160. hackagent/models/user_profile.py +135 -0
  161. hackagent/models/user_profile_minimal.py +76 -0
  162. hackagent/models/user_profile_request.py +99 -0
  163. hackagent/router/__init__.py +25 -0
  164. hackagent/router/adapters/__init__.py +20 -0
  165. hackagent/router/adapters/base.py +63 -0
  166. hackagent/router/adapters/google_adk.py +671 -0
  167. hackagent/router/adapters/litellm_adapter.py +524 -0
  168. hackagent/router/adapters/openai_adapter.py +426 -0
  169. hackagent/router/router.py +969 -0
  170. hackagent/router/types.py +54 -0
  171. hackagent/tracking/__init__.py +42 -0
  172. hackagent/tracking/context.py +163 -0
  173. hackagent/tracking/decorators.py +299 -0
  174. hackagent/tracking/tracker.py +441 -0
  175. hackagent/types.py +54 -0
  176. hackagent/utils.py +194 -0
  177. hackagent/vulnerabilities/__init__.py +13 -0
  178. hackagent/vulnerabilities/prompts.py +81 -0
  179. hackagent-0.3.1.dist-info/METADATA +122 -0
  180. hackagent-0.3.1.dist-info/RECORD +183 -0
  181. hackagent-0.3.1.dist-info/WHEEL +4 -0
  182. hackagent-0.3.1.dist-info/entry_points.txt +2 -0
  183. hackagent-0.3.1.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,249 @@
1
+ # Copyright 2025 - AI4I. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ CLI Configuration Management
17
+
18
+ Handles configuration loading from environment variables, files, and command line arguments.
19
+ Uses standardized priority order: CLI args > Config file > Environment > Default
20
+ """
21
+
22
+ import json
23
+ import os
24
+ from pathlib import Path
25
+ from typing import Optional
26
+
27
+ # Sentinel object to detect if a parameter was explicitly passed
28
+ _UNSET = object()
29
+
30
+ # Verbosity level constants (aligned with logging levels)
31
+ VERBOSITY_ERROR = 0 # Only errors
32
+ VERBOSITY_WARNING = 1 # Errors and warnings
33
+ VERBOSITY_INFO = 2 # Errors, warnings, and info
34
+ VERBOSITY_DEBUG = 3 # Everything including debug
35
+
36
+ VERBOSITY_NAMES = {
37
+ 0: "ERROR",
38
+ 1: "WARNING",
39
+ 2: "INFO",
40
+ 3: "DEBUG",
41
+ }
42
+
43
+ VERBOSITY_LEVELS = {
44
+ "error": 0,
45
+ "warning": 1,
46
+ "info": 2,
47
+ "debug": 3,
48
+ }
49
+
50
+
51
+ class CLIConfig:
52
+ """CLI configuration management with multiple sources"""
53
+
54
+ def __init__(
55
+ self,
56
+ api_key=_UNSET,
57
+ base_url=_UNSET,
58
+ config_file=_UNSET,
59
+ verbose=_UNSET,
60
+ output_format=_UNSET,
61
+ ):
62
+ """Initialize with explicit tracking of what was passed via CLI"""
63
+ # Store defaults
64
+ self._defaults = {
65
+ "api_key": None,
66
+ "base_url": "https://api.hackagent.dev",
67
+ "output_format": "table",
68
+ "verbose": VERBOSITY_WARNING, # Default to WARNING level
69
+ }
70
+
71
+ # Track what was explicitly passed using sentinel values
72
+ self._cli_overrides = set()
73
+
74
+ # Set attributes and track overrides
75
+ # Only mark as CLI override if explicitly provided AND not None
76
+ if api_key is not _UNSET:
77
+ self.api_key = api_key
78
+ # Only treat as CLI override if actually provided (not None from missing env var)
79
+ if api_key is not None:
80
+ self._cli_overrides.add("api_key")
81
+ else:
82
+ self.api_key = self._defaults["api_key"]
83
+
84
+ if base_url is not _UNSET:
85
+ self.base_url = base_url
86
+ # Only treat as CLI override if actually provided (not None from missing env var)
87
+ if base_url is not None:
88
+ self._cli_overrides.add("base_url")
89
+ else:
90
+ self.base_url = self._defaults["base_url"]
91
+
92
+ if config_file is not _UNSET:
93
+ self.config_file = config_file
94
+ # config_file doesn't need to be tracked as an override
95
+ else:
96
+ self.config_file = None
97
+
98
+ if verbose is not _UNSET:
99
+ self.verbose = verbose
100
+ # Only treat as CLI override if actually provided and > 0
101
+ # (Click's count option returns 0 when not specified, so 0 means not set)
102
+ if verbose is not None and verbose > 0:
103
+ self._cli_overrides.add("verbose")
104
+ else:
105
+ self.verbose = self._defaults["verbose"]
106
+
107
+ if output_format is not _UNSET:
108
+ self.output_format = output_format
109
+ # Only treat as CLI override if actually provided (not None from missing env var)
110
+ if output_format is not None:
111
+ self._cli_overrides.add("output_format")
112
+ else:
113
+ self.output_format = self._defaults["output_format"]
114
+
115
+ # STANDARDIZED PRIORITY ORDER:
116
+ # 1. CLI arguments (tracked in _cli_overrides)
117
+ # 2. Config file
118
+ # 3. Environment variables
119
+ # 4. Defaults (already set)
120
+
121
+ # Initialize config overrides tracking
122
+ self._config_overrides = set()
123
+
124
+ if self.config_file:
125
+ self._load_from_file(self.config_file)
126
+ else:
127
+ self._load_default_config()
128
+
129
+ # Load from environment AFTER config file (lower priority)
130
+ self._load_from_env()
131
+
132
+ def _load_from_env(self):
133
+ """Load from environment variables (only if not already set by CLI or config)"""
134
+ # Only load from env if not explicitly set via CLI args
135
+ # AND (not set by config file OR config file has None value)
136
+ if "api_key" not in self._cli_overrides:
137
+ # Use env if no config override, or if config set None
138
+ if (
139
+ "api_key" not in self._config_overrides
140
+ or getattr(self, "api_key", None) is None
141
+ ):
142
+ env_api_key = os.getenv("HACKAGENT_API_KEY")
143
+ if env_api_key:
144
+ self.api_key = env_api_key
145
+
146
+ # Only load output_format from env if not set by CLI or config
147
+ if "output_format" not in self._cli_overrides:
148
+ # Use env if no config override, or if config set None
149
+ if (
150
+ "output_format" not in self._config_overrides
151
+ or getattr(self, "output_format", None) is None
152
+ ):
153
+ env_format = os.getenv("HACKAGENT_OUTPUT_FORMAT")
154
+ if env_format:
155
+ self.output_format = env_format
156
+
157
+ def _load_from_file(self, config_path: str):
158
+ """Load from configuration file (JSON or YAML)"""
159
+ path = Path(config_path)
160
+ if not path.exists():
161
+ return
162
+
163
+ try:
164
+ with open(path) as f:
165
+ if path.suffix.lower() in [".yaml", ".yml"]:
166
+ try:
167
+ import yaml
168
+
169
+ config_data = yaml.safe_load(f)
170
+ except ImportError:
171
+ raise ImportError(
172
+ "PyYAML required for YAML config files. Install with: pip install pyyaml"
173
+ )
174
+ else:
175
+ config_data = json.load(f)
176
+
177
+ # STANDARDIZED PRIORITY: CLI args > Config file > Env vars > Defaults
178
+ # Never override CLI arguments, but override defaults and environment will be loaded later
179
+ for key, value in config_data.items():
180
+ # Skip base_url as it's always from CLI/env
181
+ if key == "base_url":
182
+ continue
183
+
184
+ # Never override CLI arguments
185
+ if key in self._cli_overrides:
186
+ continue
187
+
188
+ # Set config file values (env will be loaded later for None values)
189
+ if hasattr(self, key):
190
+ setattr(self, key, value)
191
+ # Track that this was set by config file (even if None)
192
+ self._config_overrides.add(key)
193
+ except Exception as e:
194
+ raise ValueError(f"Failed to load config file {config_path}: {e}")
195
+
196
+ def _load_default_config(self):
197
+ """Load from default config file"""
198
+ default_config = Path.home() / ".hackagent" / "config.json"
199
+ if default_config.exists():
200
+ self._load_from_file(str(default_config))
201
+
202
+ def save(self, path: Optional[str] = None):
203
+ """Save configuration to file"""
204
+ if not path:
205
+ config_dir = Path.home() / ".hackagent"
206
+ config_dir.mkdir(parents=True, exist_ok=True)
207
+ path = config_dir / "config.json"
208
+
209
+ Path(path).parent.mkdir(parents=True, exist_ok=True)
210
+ with open(path, "w") as f:
211
+ # Don't save None values or base_url (always hardcoded)
212
+ config_dict = {}
213
+ for attr in ["api_key", "output_format", "verbose"]:
214
+ value = getattr(self, attr, None)
215
+ if value is not None:
216
+ config_dict[attr] = value
217
+ json.dump(config_dict, f, indent=2)
218
+
219
+ def validate(self):
220
+ """Validate configuration"""
221
+ if not self.api_key:
222
+ raise ValueError(
223
+ "API key is required. Set HACKAGENT_API_KEY environment variable, "
224
+ "use --api-key flag, or run 'hackagent config set --api-key YOUR_KEY'"
225
+ )
226
+
227
+ if not self.base_url:
228
+ raise ValueError("Base URL is required")
229
+
230
+ def should_show_info(self) -> bool:
231
+ """Check if INFO level messages should be displayed"""
232
+ return self.verbose >= VERBOSITY_INFO
233
+
234
+ def should_show_warning(self) -> bool:
235
+ """Check if WARNING level messages should be displayed"""
236
+ return self.verbose >= VERBOSITY_WARNING
237
+
238
+ def should_show_debug(self) -> bool:
239
+ """Check if DEBUG level messages should be displayed"""
240
+ return self.verbose >= VERBOSITY_DEBUG
241
+
242
+ def get_verbosity_name(self) -> str:
243
+ """Get the name of the current verbosity level"""
244
+ return VERBOSITY_NAMES.get(self.verbose, "UNKNOWN")
245
+
246
+ @property
247
+ def default_config_path(self) -> Path:
248
+ """Get the default configuration file path"""
249
+ return Path.home() / ".hackagent" / "config.json"