hackagent 0.1.0__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.
- hackagent/__init__.py +23 -0
- hackagent/agent.py +193 -0
- hackagent/api/__init__.py +1 -0
- hackagent/api/agent/__init__.py +1 -0
- hackagent/api/agent/agent_create.py +340 -0
- hackagent/api/agent/agent_destroy.py +136 -0
- hackagent/api/agent/agent_list.py +234 -0
- hackagent/api/agent/agent_partial_update.py +354 -0
- hackagent/api/agent/agent_retrieve.py +227 -0
- hackagent/api/agent/agent_update.py +354 -0
- hackagent/api/attack/__init__.py +1 -0
- hackagent/api/attack/attack_create.py +264 -0
- hackagent/api/attack/attack_destroy.py +140 -0
- hackagent/api/attack/attack_list.py +242 -0
- hackagent/api/attack/attack_partial_update.py +278 -0
- hackagent/api/attack/attack_retrieve.py +235 -0
- hackagent/api/attack/attack_update.py +278 -0
- hackagent/api/key/__init__.py +1 -0
- hackagent/api/key/key_create.py +168 -0
- hackagent/api/key/key_destroy.py +97 -0
- hackagent/api/key/key_list.py +158 -0
- hackagent/api/key/key_retrieve.py +150 -0
- hackagent/api/prompt/__init__.py +1 -0
- hackagent/api/prompt/prompt_create.py +160 -0
- hackagent/api/prompt/prompt_destroy.py +98 -0
- hackagent/api/prompt/prompt_list.py +173 -0
- hackagent/api/prompt/prompt_partial_update.py +174 -0
- hackagent/api/prompt/prompt_retrieve.py +151 -0
- hackagent/api/prompt/prompt_update.py +174 -0
- hackagent/api/result/__init__.py +1 -0
- hackagent/api/result/result_create.py +160 -0
- hackagent/api/result/result_destroy.py +98 -0
- hackagent/api/result/result_list.py +233 -0
- hackagent/api/result/result_partial_update.py +178 -0
- hackagent/api/result/result_retrieve.py +151 -0
- hackagent/api/result/result_trace_create.py +178 -0
- hackagent/api/result/result_update.py +174 -0
- hackagent/api/run/__init__.py +1 -0
- hackagent/api/run/run_create.py +172 -0
- hackagent/api/run/run_destroy.py +104 -0
- hackagent/api/run/run_list.py +260 -0
- hackagent/api/run/run_partial_update.py +186 -0
- hackagent/api/run/run_result_create.py +178 -0
- hackagent/api/run/run_retrieve.py +163 -0
- hackagent/api/run/run_run_tests_create.py +172 -0
- hackagent/api/run/run_update.py +186 -0
- hackagent/attacks/AdvPrefix/README.md +7 -0
- hackagent/attacks/AdvPrefix/__init__.py +0 -0
- hackagent/attacks/AdvPrefix/completer.py +438 -0
- hackagent/attacks/AdvPrefix/config.py +59 -0
- hackagent/attacks/AdvPrefix/preprocessing.py +521 -0
- hackagent/attacks/AdvPrefix/scorer.py +259 -0
- hackagent/attacks/AdvPrefix/scorer_parser.py +498 -0
- hackagent/attacks/AdvPrefix/selector.py +246 -0
- hackagent/attacks/AdvPrefix/step1_generate.py +324 -0
- hackagent/attacks/AdvPrefix/step4_compute_ce.py +293 -0
- hackagent/attacks/AdvPrefix/step6_get_completions.py +387 -0
- hackagent/attacks/AdvPrefix/step7_evaluate_responses.py +289 -0
- hackagent/attacks/AdvPrefix/step8_aggregate_evaluations.py +177 -0
- hackagent/attacks/AdvPrefix/step9_select_prefixes.py +59 -0
- hackagent/attacks/AdvPrefix/utils.py +192 -0
- hackagent/attacks/__init__.py +6 -0
- hackagent/attacks/advprefix.py +1136 -0
- hackagent/attacks/base.py +50 -0
- hackagent/attacks/strategies.py +539 -0
- hackagent/branding.py +143 -0
- hackagent/client.py +328 -0
- hackagent/errors.py +31 -0
- hackagent/logger.py +67 -0
- hackagent/models/__init__.py +71 -0
- hackagent/models/agent.py +240 -0
- hackagent/models/agent_request.py +169 -0
- hackagent/models/agent_type_enum.py +12 -0
- hackagent/models/attack.py +154 -0
- hackagent/models/attack_request.py +82 -0
- hackagent/models/evaluation_status_enum.py +14 -0
- hackagent/models/organization_minimal.py +68 -0
- hackagent/models/paginated_agent_list.py +123 -0
- hackagent/models/paginated_attack_list.py +123 -0
- hackagent/models/paginated_prompt_list.py +123 -0
- hackagent/models/paginated_result_list.py +123 -0
- hackagent/models/paginated_run_list.py +123 -0
- hackagent/models/paginated_user_api_key_list.py +123 -0
- hackagent/models/patched_agent_request.py +176 -0
- hackagent/models/patched_attack_request.py +92 -0
- hackagent/models/patched_prompt_request.py +162 -0
- hackagent/models/patched_result_request.py +237 -0
- hackagent/models/patched_run_request.py +138 -0
- hackagent/models/prompt.py +226 -0
- hackagent/models/prompt_request.py +155 -0
- hackagent/models/result.py +294 -0
- hackagent/models/result_list_evaluation_status.py +14 -0
- hackagent/models/result_request.py +232 -0
- hackagent/models/run.py +233 -0
- hackagent/models/run_list_status.py +12 -0
- hackagent/models/run_request.py +133 -0
- hackagent/models/status_enum.py +12 -0
- hackagent/models/step_type_enum.py +14 -0
- hackagent/models/trace.py +121 -0
- hackagent/models/trace_request.py +94 -0
- hackagent/models/user_api_key.py +201 -0
- hackagent/models/user_api_key_request.py +73 -0
- hackagent/models/user_profile_minimal.py +76 -0
- hackagent/py.typed +1 -0
- hackagent/router/__init__.py +11 -0
- hackagent/router/adapters/__init__.py +5 -0
- hackagent/router/adapters/google_adk.py +658 -0
- hackagent/router/adapters/litellm_adapter.py +290 -0
- hackagent/router/base.py +48 -0
- hackagent/router/router.py +753 -0
- hackagent/types.py +46 -0
- hackagent/utils.py +61 -0
- hackagent/vulnerabilities/__init__.py +0 -0
- hackagent-0.1.0.dist-info/LICENSE +202 -0
- hackagent-0.1.0.dist-info/METADATA +173 -0
- hackagent-0.1.0.dist-info/RECORD +117 -0
- hackagent-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import logging
|
|
4
|
+
import litellm
|
|
5
|
+
from typing import List, Dict, Optional, Tuple, Any
|
|
6
|
+
|
|
7
|
+
# Imports needed for execute_processor_step
|
|
8
|
+
from typing import Callable # Keep for execute_processor_step
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__) # Use a logger specific to utils
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_checkpoint_path(run_dir: str, step_num: int) -> str:
|
|
15
|
+
"""Generate the standard path for a step's output checkpoint."""
|
|
16
|
+
filename = f"step{step_num}_output.csv"
|
|
17
|
+
return os.path.join(run_dir, filename)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def call_litellm_completion(
|
|
21
|
+
model_id: str,
|
|
22
|
+
messages: List[Dict[str, str]],
|
|
23
|
+
endpoint: Optional[str],
|
|
24
|
+
api_key: Optional[str],
|
|
25
|
+
timeout: int,
|
|
26
|
+
temperature: float,
|
|
27
|
+
max_tokens: int,
|
|
28
|
+
logprobs: bool = False,
|
|
29
|
+
top_p: float = 1.0,
|
|
30
|
+
logger: Optional[logging.Logger] = None,
|
|
31
|
+
) -> Tuple[Optional[str], Optional[Any], Optional[Exception]]:
|
|
32
|
+
"""
|
|
33
|
+
Wrapper function to call litellm.completion and handle common exceptions.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
model_id: The model identifier string for LiteLLM.
|
|
37
|
+
messages: The list of messages for the chat completion.
|
|
38
|
+
endpoint: The API base URL.
|
|
39
|
+
api_key: The API key.
|
|
40
|
+
timeout: Request timeout in seconds.
|
|
41
|
+
temperature: Sampling temperature.
|
|
42
|
+
max_tokens: Maximum new tokens to generate.
|
|
43
|
+
logprobs: Whether to request logprobs (default: False).
|
|
44
|
+
top_p: Top-p sampling parameter (default: 1.0).
|
|
45
|
+
logger: Optional logger instance.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
A tuple: (content_string, logprobs_object, error_object).
|
|
49
|
+
- If successful: returns (content, logprobs_data, None). content and logprobs_data may be None depending on the API response.
|
|
50
|
+
- If error occurs: returns (None, None, error_object).
|
|
51
|
+
"""
|
|
52
|
+
litellm.drop_params = True # Drop unsupported parameters
|
|
53
|
+
|
|
54
|
+
if logger is None:
|
|
55
|
+
logger = logging.getLogger(__name__) # Fallback logger
|
|
56
|
+
|
|
57
|
+
content_string: Optional[str] = None
|
|
58
|
+
logprobs_data: Optional[Any] = None
|
|
59
|
+
error_object: Optional[Exception] = None
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
litellm_kwargs = {
|
|
63
|
+
"model": model_id,
|
|
64
|
+
"messages": messages,
|
|
65
|
+
"max_tokens": max_tokens,
|
|
66
|
+
"temperature": temperature,
|
|
67
|
+
"top_p": top_p,
|
|
68
|
+
"endpoint": endpoint,
|
|
69
|
+
"api_key": api_key,
|
|
70
|
+
"timeout": timeout,
|
|
71
|
+
"logprobs": logprobs,
|
|
72
|
+
}
|
|
73
|
+
# Filter out None values, especially api_key and endpoint if not provided
|
|
74
|
+
litellm_kwargs = {k: v for k, v in litellm_kwargs.items() if v is not None}
|
|
75
|
+
|
|
76
|
+
logger.debug(
|
|
77
|
+
f"Calling litellm.completion with kwargs: { {k: v for k, v in litellm_kwargs.items() if k != 'api_key'} }"
|
|
78
|
+
) # Don't log key
|
|
79
|
+
response = litellm.completion(**litellm_kwargs)
|
|
80
|
+
|
|
81
|
+
# Extract content
|
|
82
|
+
if (
|
|
83
|
+
response
|
|
84
|
+
and response.choices
|
|
85
|
+
and response.choices[0].message
|
|
86
|
+
and response.choices[0].message.content
|
|
87
|
+
):
|
|
88
|
+
content_string = response.choices[0].message.content
|
|
89
|
+
else:
|
|
90
|
+
logger.warning(
|
|
91
|
+
f"LiteLLM call successful but no content found in response structure. Model: {model_id}"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Extract logprobs if requested and available
|
|
95
|
+
if logprobs:
|
|
96
|
+
if response and response.choices and response.choices[0].logprobs:
|
|
97
|
+
logprobs_data = response.choices[0].logprobs
|
|
98
|
+
else:
|
|
99
|
+
logger.warning(
|
|
100
|
+
f"Logprobs were requested but not found in response structure. Model: {model_id}"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
except litellm.exceptions.BadRequestError as llm_bad_req_err:
|
|
104
|
+
logger.error(f"LiteLLM Bad Request Error: {llm_bad_req_err}")
|
|
105
|
+
error_object = llm_bad_req_err
|
|
106
|
+
except litellm.exceptions.APIError as llm_api_err:
|
|
107
|
+
logger.error(f"LiteLLM API Error: {llm_api_err}")
|
|
108
|
+
error_object = llm_api_err
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error(f"Generic error during LiteLLM call: {e}", exc_info=True)
|
|
111
|
+
error_object = e
|
|
112
|
+
|
|
113
|
+
return content_string, logprobs_data, error_object
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def execute_processor_step(
|
|
117
|
+
input_df: pd.DataFrame,
|
|
118
|
+
logger: logging.Logger, # This logger is passed in, not using the module-level logger directly
|
|
119
|
+
run_dir: str,
|
|
120
|
+
processor_instance: Any,
|
|
121
|
+
processor_method_name: str,
|
|
122
|
+
step_number: int,
|
|
123
|
+
step_name_for_logging: str,
|
|
124
|
+
log_success_details_template: str,
|
|
125
|
+
**processor_method_kwargs: Any,
|
|
126
|
+
) -> pd.DataFrame:
|
|
127
|
+
"""
|
|
128
|
+
Executes a generic step in the pipeline that involves calling a method on a processor object.
|
|
129
|
+
Now resides in the main utils.py.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
input_df: The input DataFrame.
|
|
133
|
+
logger: The logger instance passed from the calling context (e.g., AdvPrefixAttack).
|
|
134
|
+
run_dir: The directory for the current run, for saving checkpoints.
|
|
135
|
+
processor_instance: The instance of the processor (e.g., PrefixPreprocessor).
|
|
136
|
+
processor_method_name: The name of the method to call on the processor_instance.
|
|
137
|
+
step_number: The current step number in the pipeline.
|
|
138
|
+
step_name_for_logging: A descriptive name for this step for logging purposes.
|
|
139
|
+
log_success_details_template: A string template for the success log message.
|
|
140
|
+
It should accept a 'count' keyword for len(processed_df).
|
|
141
|
+
**processor_method_kwargs: Additional keyword arguments to pass to the processor method.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
The processed DataFrame, or the original DataFrame if an error occurs or input is empty.
|
|
145
|
+
"""
|
|
146
|
+
logger.info(f"--- Running Step {step_number}: {step_name_for_logging} ---")
|
|
147
|
+
|
|
148
|
+
if input_df.empty:
|
|
149
|
+
logger.warning(
|
|
150
|
+
f"Step {step_number} ({step_name_for_logging}) received an empty DataFrame. Skipping."
|
|
151
|
+
)
|
|
152
|
+
return input_df
|
|
153
|
+
|
|
154
|
+
processed_df: pd.DataFrame
|
|
155
|
+
try:
|
|
156
|
+
method_to_call: Callable[..., pd.DataFrame] = getattr(
|
|
157
|
+
processor_instance, processor_method_name
|
|
158
|
+
)
|
|
159
|
+
if processor_method_kwargs:
|
|
160
|
+
processed_df = method_to_call(input_df, **processor_method_kwargs)
|
|
161
|
+
else:
|
|
162
|
+
processed_df = method_to_call(input_df)
|
|
163
|
+
|
|
164
|
+
except AttributeError:
|
|
165
|
+
logger.error(
|
|
166
|
+
f"Processor object does not have method '{processor_method_name}'. Step {step_number} ({step_name_for_logging}) failed.",
|
|
167
|
+
exc_info=True,
|
|
168
|
+
)
|
|
169
|
+
return input_df
|
|
170
|
+
except Exception as e:
|
|
171
|
+
logger.error(
|
|
172
|
+
f"Error during {processor_instance.__class__.__name__}.{processor_method_name} for Step {step_number} ({step_name_for_logging}): {e}",
|
|
173
|
+
exc_info=True,
|
|
174
|
+
)
|
|
175
|
+
return input_df
|
|
176
|
+
|
|
177
|
+
# This now calls get_checkpoint_path defined in this same utils.py file
|
|
178
|
+
output_path = get_checkpoint_path(run_dir, step_number)
|
|
179
|
+
try:
|
|
180
|
+
processed_df.to_csv(output_path, index=False)
|
|
181
|
+
count = len(processed_df)
|
|
182
|
+
success_details = log_success_details_template.format(count=count)
|
|
183
|
+
logger.info(
|
|
184
|
+
f"Step {step_number} ({step_name_for_logging}) complete. {success_details}"
|
|
185
|
+
)
|
|
186
|
+
logger.info(f"Checkpoint saved to {output_path}")
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.error(
|
|
189
|
+
f"Failed to save checkpoint for Step {step_number} ({step_name_for_logging}) to {output_path}: {e}"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
return processed_df
|