aiverify-moonshot 0.4.10__py3-none-any.whl → 0.5.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 (37) hide show
  1. {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/METADATA +24 -26
  2. {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/RECORD +37 -36
  3. {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/WHEEL +1 -1
  4. moonshot/integrations/cli/benchmark/cookbook.py +8 -11
  5. moonshot/integrations/cli/benchmark/recipe.py +1 -5
  6. moonshot/integrations/cli/cli_errors.py +3 -0
  7. moonshot/integrations/cli/common/connectors.py +22 -10
  8. moonshot/integrations/web_api/app.py +1 -1
  9. moonshot/integrations/web_api/schemas/endpoint_create_dto.py +1 -0
  10. moonshot/integrations/web_api/services/endpoint_service.py +1 -0
  11. moonshot/src/api/api_bookmark.py +16 -5
  12. moonshot/src/api/api_connector.py +3 -3
  13. moonshot/src/api/api_connector_endpoint.py +6 -3
  14. moonshot/src/api/api_context_strategy.py +2 -2
  15. moonshot/src/api/api_cookbook.py +6 -6
  16. moonshot/src/api/api_dataset.py +5 -5
  17. moonshot/src/api/api_environment_variables.py +3 -0
  18. moonshot/src/api/api_metrics.py +1 -1
  19. moonshot/src/api/api_prompt_template.py +9 -0
  20. moonshot/src/api/api_recipe.py +3 -3
  21. moonshot/src/api/api_red_teaming.py +4 -8
  22. moonshot/src/api/api_result.py +10 -6
  23. moonshot/src/api/api_run.py +3 -3
  24. moonshot/src/api/api_runner.py +7 -6
  25. moonshot/src/api/api_session.py +11 -7
  26. moonshot/src/bookmark/bookmark.py +12 -5
  27. moonshot/src/connectors/connector.py +127 -62
  28. moonshot/src/connectors/connector_prompt_arguments.py +15 -5
  29. moonshot/src/connectors/connector_response.py +15 -0
  30. moonshot/src/connectors_endpoints/connector_endpoint.py +32 -20
  31. moonshot/src/connectors_endpoints/connector_endpoint_arguments.py +4 -1
  32. moonshot/src/messages_constants.py +85 -3
  33. moonshot/src/redteaming/attack/attack_module.py +34 -7
  34. moonshot/src/runs/run_arguments.py +43 -20
  35. {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/AUTHORS.md +0 -0
  36. {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/LICENSE.md +0 -0
  37. {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/NOTICES.md +0 -0
@@ -15,7 +15,9 @@ BOOKMARK_GET_BOOKMARK_ERROR_1 = "[Bookmark] Invalid bookmark name: {message}"
15
15
  # BOOKMARK - delete_bookmark
16
16
  # ------------------------------------------------------------------------------
17
17
  BOOKMARK_DELETE_BOOKMARK_SUCCESS = "[Bookmark] Bookmark record deleted."
18
- BOOKMARK_DELETE_BOOKMARK_FAIL = "[Bookmark] Bookmark record not found. Unable to delete."
18
+ BOOKMARK_DELETE_BOOKMARK_FAIL = (
19
+ "[Bookmark] Bookmark record not found. Unable to delete."
20
+ )
19
21
  BOOKMARK_DELETE_BOOKMARK_ERROR = (
20
22
  "[Bookmark] Failed to delete bookmark record: {message}"
21
23
  )
@@ -33,9 +35,89 @@ BOOKMARK_DELETE_ALL_BOOKMARK_ERROR = (
33
35
  # BOOKMARK - export_bookmarks
34
36
  # ------------------------------------------------------------------------------
35
37
  BOOKMARK_EXPORT_BOOKMARK_ERROR = "[Bookmark] Failed to export bookmarks: {message}"
36
- BOOKMARK_EXPORT_BOOKMARK_VALIDATION_ERROR = "Export filename must be a non-empty string"
38
+ BOOKMARK_EXPORT_BOOKMARK_VALIDATION_ERROR = (
39
+ "Export filename must be a non-empty string."
40
+ )
37
41
 
38
42
  # ------------------------------------------------------------------------------
39
43
  # BOOKMARK ARGUMENTS - from_tuple_to_dict
40
44
  # ------------------------------------------------------------------------------
41
- BOOKMARK_ARGUMENTS_FROM_TUPLE_TO_DICT_VALIDATION_ERROR = "[BookmarkArguments] Failed to convert to dictionary because of the insufficient number of values" # noqa: E501
45
+ BOOKMARK_ARGUMENTS_FROM_TUPLE_TO_DICT_VALIDATION_ERROR = "[BookmarkArguments] Failed to convert to dictionary because of the insufficient number of values." # noqa: E501
46
+
47
+ # ------------------------------------------------------------------------------
48
+ # CONNECTOR - perform_retry_callback
49
+ # ------------------------------------------------------------------------------
50
+ CONNECTOR_PERFORM_RETRY_CALLBACK_ERROR = "[Connector ID: {connector_id}] Attempt {attempt_no} failed due to error: {message}" # noqa: E501
51
+
52
+ # ------------------------------------------------------------------------------
53
+ # CONNECTOR - load
54
+ # ------------------------------------------------------------------------------
55
+ CONNECTOR_LOAD_CONNECTOR_ENDPOINT_ARGUMENTS_VALIDATION_ERROR = "[Connector] The 'ep_args' argument must be an instance of ConnectorEndpointArguments and not None." # noqa: E501
56
+ CONNECTOR_LOAD_CONNECTOR_INSTANCE_RUNTIME_ERROR = (
57
+ "[Connector] Failed to get connector instance: {message}"
58
+ )
59
+
60
+ # ------------------------------------------------------------------------------
61
+ # CONNECTOR - create
62
+ # ------------------------------------------------------------------------------
63
+ CONNECTOR_CREATE_CONNECTOR_ENDPOINT_ARGUMENTS_VALIDATION_ERROR = "[Connector] The 'ep_args' argument must be an instance of ConnectorEndpointArguments and not None." # noqa: E501
64
+ CONNECTOR_CREATE_ERROR = "[Connector] Failed to create connector: {message}"
65
+
66
+ # ------------------------------------------------------------------------------
67
+ # CONNECTOR - get_available_items
68
+ # ------------------------------------------------------------------------------
69
+ CONNECTOR_GET_AVAILABLE_ITEMS_ERROR = (
70
+ "[Connector] Failed to get available connectors: {message}"
71
+ )
72
+
73
+ # ------------------------------------------------------------------------------
74
+ # CONNECTOR - get_prediction
75
+ # ------------------------------------------------------------------------------
76
+ CONNECTOR_GET_PREDICTION_ARGUMENTS_GENERATED_PROMPT_VALIDATION_ERROR = "[Connector] The 'generated_prompt' argument must be an instance of ConnectorPromptArguments and not None." # noqa: E501
77
+ CONNECTOR_GET_PREDICTION_ARGUMENTS_CONNECTOR_VALIDATION_ERROR = "[Connector] The 'connector' argument must be an instance of Connector and not None." # noqa: E501
78
+ CONNECTOR_GET_PREDICTION_INFO = (
79
+ "[Connector ID: {connector_id}] Predicting Prompt Index {prompt_index}."
80
+ )
81
+ CONNECTOR_GET_PREDICTION_TIME_TAKEN_INFO = "[Connector ID: {connector_id}] Prompt Index {prompt_index} took {prompt_duration}s." # noqa: E501
82
+ CONNECTOR_GET_PREDICTION_ERROR = "[Connector ID: {connector_id}] Prompt Index {prompt_index} failed to get prediction: {message}" # noqa: E501
83
+
84
+ # ------------------------------------------------------------------------------
85
+ # CONNECTOR - set_system_prompt
86
+ # ------------------------------------------------------------------------------
87
+ CONNECTOR_SET_SYSTEM_PROMPT_VALIDATION_ERROR = "[Connector] The 'system_prompt' argument must be an instance of string and not None." # noqa: E501
88
+
89
+ # ------------------------------------------------------------------------------
90
+ # CONNECTOR ENDPOINT - create
91
+ # ------------------------------------------------------------------------------
92
+ CONNECTOR_ENDPOINT_CREATE_ERROR = (
93
+ "[ConnectorEndpoint] Failed to create connector endpoint: {message}"
94
+ )
95
+
96
+ # ------------------------------------------------------------------------------
97
+ # CONNECTOR ENDPOINT - read
98
+ # ------------------------------------------------------------------------------
99
+ CONNECTOR_ENDPOINT_READ_INVALID = "Invalid connector endpoint id - {ep_id}"
100
+ CONNECTOR_ENDPOINT_READ_ERROR = (
101
+ "[ConnectorEndpoint] Failed to read connector endpoint: {message}"
102
+ )
103
+
104
+ # ------------------------------------------------------------------------------
105
+ # CONNECTOR ENDPOINT - update
106
+ # ------------------------------------------------------------------------------
107
+ CONNECTOR_ENDPOINT_UPDATE_ERROR = (
108
+ "[ConnectorEndpoint] Failed to update connector endpoint: {message}"
109
+ )
110
+
111
+ # ------------------------------------------------------------------------------
112
+ # CONNECTOR ENDPOINT - delete
113
+ # ------------------------------------------------------------------------------
114
+ CONNECTOR_ENDPOINT_DELETE_ERROR = (
115
+ "[ConnectorEndpoint] Failed to delete connector endpoint: {message}"
116
+ )
117
+
118
+ # ------------------------------------------------------------------------------
119
+ # CONNECTOR ENDPOINT - get_available_items
120
+ # ------------------------------------------------------------------------------
121
+ CONNECTOR_ENDPOINT_GET_AVAILABLE_ITEMS_ERROR = (
122
+ "[ConnectorEndpoint] Failed to get available connector endpoints: {message}"
123
+ )
@@ -31,6 +31,22 @@ class AttackModule:
31
31
  INSERT INTO {} (connection_id,context_strategy,prompt_template,attack_module,
32
32
  metric,prompt,prepared_prompt,system_prompt,predicted_result,duration,prompt_time)VALUES(?,?,?,?,?,?,?,?,?,?,?)
33
33
  """
34
+ sql_create_chat_history_table = """
35
+ CREATE TABLE IF NOT EXISTS {} (
36
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
37
+ connection_id text NOT NULL,
38
+ context_strategy text,
39
+ prompt_template text,
40
+ attack_module text,
41
+ metric text,
42
+ prompt text NOT NULL,
43
+ prepared_prompt text NOT NULL,
44
+ system_prompt text,
45
+ predicted_result text NOT NULL,
46
+ duration text NOT NULL,
47
+ prompt_time text NOT NULL
48
+ );
49
+ """
34
50
 
35
51
  def __init__(self, am_id: str, am_arguments: AttackModuleArguments | None = None):
36
52
  self.id = am_id
@@ -261,6 +277,15 @@ class AttackModule:
261
277
  list: A list of consolidated responses from the specified LLM connector.
262
278
  """
263
279
  consolidated_responses = []
280
+
281
+ # perform a check to see if the target endpoint has its table in the db. if not, create one
282
+ endpoint_id = target_llm_connector.id.replace("-", "_")
283
+ if not Storage.check_database_table_exists(self.db_instance, endpoint_id):
284
+ Storage.create_database_table(
285
+ self.db_instance,
286
+ AttackModule.sql_create_chat_history_table.format(endpoint_id),
287
+ )
288
+
264
289
  for prepared_prompt in list_of_prompts:
265
290
  if self.cancel_event.is_set():
266
291
  logger.warning(
@@ -316,6 +341,7 @@ class AttackModule:
316
341
  chat_record_tuple (tuple): A tuple containing the chat record information.
317
342
  chat_record_id (str): The ID of the chat record.
318
343
  """
344
+
319
345
  endpoint_id = chat_record_id.replace("-", "_")
320
346
  Storage.create_database_record(
321
347
  self.db_instance,
@@ -623,7 +649,8 @@ class RedTeamingPromptArguments(BaseModel):
623
649
 
624
650
  This method collects all the attributes of the RedTeamingPromptArguments instance and forms a tuple
625
651
  with the attribute values in this specific order: conn_id, cs_id, pt_id, am_id, me_id, original_prompt,
626
- connector_prompt.prompt, connector_prompt.predicted_results, connector_prompt.duration, start_time.
652
+ connector_prompt.prompt, system_prompt, connector_prompt.predicted_results.response,
653
+ connector_prompt.duration, start_time.
627
654
 
628
655
  Returns:
629
656
  tuple: A tuple representation of the RedTeamingPromptArguments instance.
@@ -637,21 +664,21 @@ class RedTeamingPromptArguments(BaseModel):
637
664
  self.original_prompt,
638
665
  self.connector_prompt.prompt,
639
666
  self.system_prompt,
640
- str(self.connector_prompt.predicted_results),
667
+ self.connector_prompt.predicted_results.response if self.connector_prompt.predicted_results else "",
641
668
  str(self.connector_prompt.duration),
642
669
  self.start_time,
643
670
  )
644
671
 
645
672
  def to_dict(self) -> dict:
646
673
  """
647
- Converts the RedTeamingPromptArguments instance into a dict.
674
+ Converts the RedTeamingPromptArguments instance into a dictionary.
648
675
 
649
- This method collects all the attributes of the RedTeamingPromptArguments instance and forms a dict
650
- with the keys: conn_id, cs_id, pt_id, am_id, me_id, original_prompt, prepared_prompt, system_prompt
676
+ This method collects all the attributes of the RedTeamingPromptArguments instance and forms a dictionary
677
+ with the keys: conn_id, cs_id, pt_id, am_id, me_id, original_prompt, system_prompt, prepared_prompt,
651
678
  response, duration, start_time.
652
679
 
653
680
  Returns:
654
- dict: A dict representation of the RedTeamingPromptArguments instance.
681
+ dict: A dictionary representation of the RedTeamingPromptArguments instance.
655
682
  """
656
683
  return {
657
684
  "conn_id": self.conn_id,
@@ -662,7 +689,7 @@ class RedTeamingPromptArguments(BaseModel):
662
689
  "original_prompt": self.original_prompt,
663
690
  "prepared_prompt": self.connector_prompt.prompt,
664
691
  "system_prompt": self.system_prompt,
665
- "response": str(self.connector_prompt.predicted_results),
692
+ "response": self.connector_prompt.predicted_results.response if self.connector_prompt.predicted_results else "",
666
693
  "duration": str(self.connector_prompt.duration),
667
694
  "start_time": self.start_time,
668
695
  }
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import ast
4
+ import json
4
5
 
5
6
  from pydantic import BaseModel
6
7
 
@@ -83,20 +84,7 @@ class RunArguments(BaseModel):
83
84
  Returns:
84
85
  tuple: A tuple containing the run arguments ready for database insertion.
85
86
  """
86
- return (
87
- self.runner_id,
88
- self.runner_type.name.lower(),
89
- str(self.runner_args),
90
- str(self.endpoints),
91
- self.results_file,
92
- self.start_time,
93
- self.end_time,
94
- self.duration,
95
- str(self.error_messages),
96
- str(self.raw_results),
97
- str(self.results),
98
- self.status.name.lower(),
99
- )
87
+ return self._to_tuple(include_run_id=False)
100
88
 
101
89
  def to_tuple(self) -> tuple:
102
90
  """
@@ -112,7 +100,42 @@ class RunArguments(BaseModel):
112
100
  Returns:
113
101
  tuple: A tuple containing the serialized attributes of the RunArguments instance.
114
102
  """
115
- return (
103
+ return self._to_tuple(include_run_id=True)
104
+
105
+ def _to_tuple(self, include_run_id: bool) -> tuple:
106
+ """
107
+ Converts the RunArguments object to a tuple format.
108
+
109
+ This method serializes the RunArguments instance into a tuple, including or excluding the run_id based on the
110
+ include_run_id parameter. It ensures that all dictionary keys are converted to strings and JSON-encodes
111
+ the raw_results and results attributes.
112
+
113
+ Args:
114
+ include_run_id (bool): A flag indicating whether to include the run_id in the resulting tuple.
115
+
116
+ Returns:
117
+ tuple: A tuple containing the serialized attributes of the RunArguments instance.
118
+ """
119
+
120
+ def convert_keys_to_str(d):
121
+ """
122
+ Recursively converts all keys in a dictionary to strings.
123
+
124
+ Args:
125
+ d (dict): The dictionary whose keys need to be converted.
126
+
127
+ Returns:
128
+ dict: A new dictionary with all keys converted to strings.
129
+ """
130
+
131
+ def convert_value(v):
132
+ if isinstance(v, dict):
133
+ return {str(k): convert_value(val) for k, val in v.items()}
134
+ return v
135
+
136
+ return {str(k): convert_value(v) for k, v in d.items()}
137
+
138
+ base_tuple = (
116
139
  self.runner_id,
117
140
  self.runner_type.name.lower(),
118
141
  str(self.runner_args),
@@ -122,11 +145,11 @@ class RunArguments(BaseModel):
122
145
  self.end_time,
123
146
  self.duration,
124
147
  str(self.error_messages),
125
- str(self.raw_results),
126
- str(self.results),
148
+ json.dumps(convert_keys_to_str(self.raw_results)),
149
+ json.dumps(self.results),
127
150
  self.status.name.lower(),
128
- self.run_id,
129
151
  )
152
+ return base_tuple + (self.run_id,) if include_run_id else base_tuple
130
153
 
131
154
  @classmethod
132
155
  def from_tuple(cls, run_record: tuple) -> RunArguments:
@@ -156,7 +179,7 @@ class RunArguments(BaseModel):
156
179
  end_time=float(run_record[7]),
157
180
  duration=run_record[8],
158
181
  error_messages=ast.literal_eval(run_record[9]),
159
- raw_results=ast.literal_eval(run_record[10]),
160
- results=ast.literal_eval(run_record[11]),
182
+ raw_results=json.loads(run_record[10]),
183
+ results=json.loads(run_record[11]),
161
184
  status=RunStatus(run_record[12]),
162
185
  )