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.
Files changed (117) hide show
  1. hackagent/__init__.py +23 -0
  2. hackagent/agent.py +193 -0
  3. hackagent/api/__init__.py +1 -0
  4. hackagent/api/agent/__init__.py +1 -0
  5. hackagent/api/agent/agent_create.py +340 -0
  6. hackagent/api/agent/agent_destroy.py +136 -0
  7. hackagent/api/agent/agent_list.py +234 -0
  8. hackagent/api/agent/agent_partial_update.py +354 -0
  9. hackagent/api/agent/agent_retrieve.py +227 -0
  10. hackagent/api/agent/agent_update.py +354 -0
  11. hackagent/api/attack/__init__.py +1 -0
  12. hackagent/api/attack/attack_create.py +264 -0
  13. hackagent/api/attack/attack_destroy.py +140 -0
  14. hackagent/api/attack/attack_list.py +242 -0
  15. hackagent/api/attack/attack_partial_update.py +278 -0
  16. hackagent/api/attack/attack_retrieve.py +235 -0
  17. hackagent/api/attack/attack_update.py +278 -0
  18. hackagent/api/key/__init__.py +1 -0
  19. hackagent/api/key/key_create.py +168 -0
  20. hackagent/api/key/key_destroy.py +97 -0
  21. hackagent/api/key/key_list.py +158 -0
  22. hackagent/api/key/key_retrieve.py +150 -0
  23. hackagent/api/prompt/__init__.py +1 -0
  24. hackagent/api/prompt/prompt_create.py +160 -0
  25. hackagent/api/prompt/prompt_destroy.py +98 -0
  26. hackagent/api/prompt/prompt_list.py +173 -0
  27. hackagent/api/prompt/prompt_partial_update.py +174 -0
  28. hackagent/api/prompt/prompt_retrieve.py +151 -0
  29. hackagent/api/prompt/prompt_update.py +174 -0
  30. hackagent/api/result/__init__.py +1 -0
  31. hackagent/api/result/result_create.py +160 -0
  32. hackagent/api/result/result_destroy.py +98 -0
  33. hackagent/api/result/result_list.py +233 -0
  34. hackagent/api/result/result_partial_update.py +178 -0
  35. hackagent/api/result/result_retrieve.py +151 -0
  36. hackagent/api/result/result_trace_create.py +178 -0
  37. hackagent/api/result/result_update.py +174 -0
  38. hackagent/api/run/__init__.py +1 -0
  39. hackagent/api/run/run_create.py +172 -0
  40. hackagent/api/run/run_destroy.py +104 -0
  41. hackagent/api/run/run_list.py +260 -0
  42. hackagent/api/run/run_partial_update.py +186 -0
  43. hackagent/api/run/run_result_create.py +178 -0
  44. hackagent/api/run/run_retrieve.py +163 -0
  45. hackagent/api/run/run_run_tests_create.py +172 -0
  46. hackagent/api/run/run_update.py +186 -0
  47. hackagent/attacks/AdvPrefix/README.md +7 -0
  48. hackagent/attacks/AdvPrefix/__init__.py +0 -0
  49. hackagent/attacks/AdvPrefix/completer.py +438 -0
  50. hackagent/attacks/AdvPrefix/config.py +59 -0
  51. hackagent/attacks/AdvPrefix/preprocessing.py +521 -0
  52. hackagent/attacks/AdvPrefix/scorer.py +259 -0
  53. hackagent/attacks/AdvPrefix/scorer_parser.py +498 -0
  54. hackagent/attacks/AdvPrefix/selector.py +246 -0
  55. hackagent/attacks/AdvPrefix/step1_generate.py +324 -0
  56. hackagent/attacks/AdvPrefix/step4_compute_ce.py +293 -0
  57. hackagent/attacks/AdvPrefix/step6_get_completions.py +387 -0
  58. hackagent/attacks/AdvPrefix/step7_evaluate_responses.py +289 -0
  59. hackagent/attacks/AdvPrefix/step8_aggregate_evaluations.py +177 -0
  60. hackagent/attacks/AdvPrefix/step9_select_prefixes.py +59 -0
  61. hackagent/attacks/AdvPrefix/utils.py +192 -0
  62. hackagent/attacks/__init__.py +6 -0
  63. hackagent/attacks/advprefix.py +1136 -0
  64. hackagent/attacks/base.py +50 -0
  65. hackagent/attacks/strategies.py +539 -0
  66. hackagent/branding.py +143 -0
  67. hackagent/client.py +328 -0
  68. hackagent/errors.py +31 -0
  69. hackagent/logger.py +67 -0
  70. hackagent/models/__init__.py +71 -0
  71. hackagent/models/agent.py +240 -0
  72. hackagent/models/agent_request.py +169 -0
  73. hackagent/models/agent_type_enum.py +12 -0
  74. hackagent/models/attack.py +154 -0
  75. hackagent/models/attack_request.py +82 -0
  76. hackagent/models/evaluation_status_enum.py +14 -0
  77. hackagent/models/organization_minimal.py +68 -0
  78. hackagent/models/paginated_agent_list.py +123 -0
  79. hackagent/models/paginated_attack_list.py +123 -0
  80. hackagent/models/paginated_prompt_list.py +123 -0
  81. hackagent/models/paginated_result_list.py +123 -0
  82. hackagent/models/paginated_run_list.py +123 -0
  83. hackagent/models/paginated_user_api_key_list.py +123 -0
  84. hackagent/models/patched_agent_request.py +176 -0
  85. hackagent/models/patched_attack_request.py +92 -0
  86. hackagent/models/patched_prompt_request.py +162 -0
  87. hackagent/models/patched_result_request.py +237 -0
  88. hackagent/models/patched_run_request.py +138 -0
  89. hackagent/models/prompt.py +226 -0
  90. hackagent/models/prompt_request.py +155 -0
  91. hackagent/models/result.py +294 -0
  92. hackagent/models/result_list_evaluation_status.py +14 -0
  93. hackagent/models/result_request.py +232 -0
  94. hackagent/models/run.py +233 -0
  95. hackagent/models/run_list_status.py +12 -0
  96. hackagent/models/run_request.py +133 -0
  97. hackagent/models/status_enum.py +12 -0
  98. hackagent/models/step_type_enum.py +14 -0
  99. hackagent/models/trace.py +121 -0
  100. hackagent/models/trace_request.py +94 -0
  101. hackagent/models/user_api_key.py +201 -0
  102. hackagent/models/user_api_key_request.py +73 -0
  103. hackagent/models/user_profile_minimal.py +76 -0
  104. hackagent/py.typed +1 -0
  105. hackagent/router/__init__.py +11 -0
  106. hackagent/router/adapters/__init__.py +5 -0
  107. hackagent/router/adapters/google_adk.py +658 -0
  108. hackagent/router/adapters/litellm_adapter.py +290 -0
  109. hackagent/router/base.py +48 -0
  110. hackagent/router/router.py +753 -0
  111. hackagent/types.py +46 -0
  112. hackagent/utils.py +61 -0
  113. hackagent/vulnerabilities/__init__.py +0 -0
  114. hackagent-0.1.0.dist-info/LICENSE +202 -0
  115. hackagent-0.1.0.dist-info/METADATA +173 -0
  116. hackagent-0.1.0.dist-info/RECORD +117 -0
  117. 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
@@ -0,0 +1,6 @@
1
+ from .strategies import AttackStrategy, AdvPrefix
2
+
3
+ __all__ = [
4
+ "AttackStrategy",
5
+ "AdvPrefix",
6
+ ]