aiverify-moonshot 0.4.9__py3-none-any.whl → 0.4.11__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: aiverify-moonshot
3
- Version: 0.4.9
3
+ Version: 0.4.11
4
4
  Summary: AI Verify advances Gen AI testing with Project Moonshot.
5
5
  Project-URL: Repository, https://github.com/aiverify-foundation/moonshot
6
6
  Project-URL: Documentation, https://aiverify-foundation.github.io/moonshot/
@@ -15,38 +15,38 @@ Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: Programming Language :: Python :: 3
16
16
  Classifier: Programming Language :: Python :: 3.11
17
17
  Requires-Python: >=3.11
18
- Requires-Dist: datasets==2.21.0
19
- Requires-Dist: ijson==3.3.0
20
- Requires-Dist: jinja2==3.1.4
21
- Requires-Dist: numpy==1.26.4
22
- Requires-Dist: pandas==2.2.2
18
+ Requires-Dist: datasets>=2.21.0
19
+ Requires-Dist: ijson>=3.3.0
20
+ Requires-Dist: jinja2>=3.1.4
21
+ Requires-Dist: numpy>=1.26.4
22
+ Requires-Dist: pandas>=2.2.2
23
23
  Requires-Dist: pydantic==2.8.2
24
- Requires-Dist: pyparsing==3.1.4
25
- Requires-Dist: python-dotenv==1.0.1
26
- Requires-Dist: python-slugify==8.0.4
27
- Requires-Dist: xxhash==3.5.0
24
+ Requires-Dist: pyparsing>=3.1.4
25
+ Requires-Dist: python-dotenv>=1.0.1
26
+ Requires-Dist: python-slugify>=8.0.4
27
+ Requires-Dist: xxhash>=3.5.0
28
28
  Provides-Extra: all
29
- Requires-Dist: cmd2==2.4.3; extra == 'all'
30
- Requires-Dist: dependency-injector==4.41.0; extra == 'all'
31
- Requires-Dist: fastapi==0.112.2; extra == 'all'
32
- Requires-Dist: rich==13.8.0; extra == 'all'
33
- Requires-Dist: typing-extensions==4.12.2; extra == 'all'
34
- Requires-Dist: uvicorn==0.30.6; extra == 'all'
29
+ Requires-Dist: cmd2>=2.4.3; extra == 'all'
30
+ Requires-Dist: dependency-injector>=4.41.0; extra == 'all'
31
+ Requires-Dist: fastapi>=0.112.2; extra == 'all'
32
+ Requires-Dist: rich>=13.8.0; extra == 'all'
33
+ Requires-Dist: typing-extensions>=4.12.2; extra == 'all'
34
+ Requires-Dist: uvicorn>=0.30.6; extra == 'all'
35
35
  Provides-Extra: cli
36
- Requires-Dist: cmd2==2.4.3; extra == 'cli'
37
- Requires-Dist: rich==13.8.0; extra == 'cli'
36
+ Requires-Dist: cmd2>=2.4.3; extra == 'cli'
37
+ Requires-Dist: rich>=13.8.0; extra == 'cli'
38
38
  Provides-Extra: web-api
39
- Requires-Dist: dependency-injector==4.41.0; extra == 'web-api'
40
- Requires-Dist: fastapi==0.112.2; extra == 'web-api'
41
- Requires-Dist: typing-extensions==4.12.2; extra == 'web-api'
42
- Requires-Dist: uvicorn==0.30.6; extra == 'web-api'
39
+ Requires-Dist: dependency-injector>=4.41.0; extra == 'web-api'
40
+ Requires-Dist: fastapi>=0.112.2; extra == 'web-api'
41
+ Requires-Dist: typing-extensions>=4.12.2; extra == 'web-api'
42
+ Requires-Dist: uvicorn>=0.30.6; extra == 'web-api'
43
43
  Description-Content-Type: text/markdown
44
44
 
45
45
  <div align="center">
46
46
 
47
47
  ![Moonshot Logo](https://github.com/aiverify-foundation/moonshot/raw/main/misc/aiverify-moonshot-logo.png)
48
48
 
49
- **Version 0.4.9**
49
+ **Version 0.4.11**
50
50
 
51
51
  A simple and modular tool to evaluate any LLM application.
52
52
 
@@ -9,7 +9,7 @@ moonshot/integrations/cli/cli.py,sha256=9tnzcxcSOjblxCUpyh3pK0ke0bLs3s-63OxXtYoZ
9
9
  moonshot/integrations/cli/cli_errors.py,sha256=wDwBtxZcHPWIJa6ZVW0MoWm81aeqmhYhi7SLI7TQ4_4,23565
10
10
  moonshot/integrations/cli/benchmark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  moonshot/integrations/cli/benchmark/benchmark.py,sha256=QUxr6DU11-XeH6Y3j1uPsZsotshgy64G_cWNf0Rn2_U,6303
12
- moonshot/integrations/cli/benchmark/cookbook.py,sha256=h9exPhLKLRa9a1qWB2WptZ35gcVov332tjHDO9ECs0o,29639
12
+ moonshot/integrations/cli/benchmark/cookbook.py,sha256=pgXTKqYAeDj0tLsCN71SCrKM4DDgswwqxJhXaPQmAeU,29518
13
13
  moonshot/integrations/cli/benchmark/datasets.py,sha256=Uq5XMNWUp775sz9jCZUZHHmkumPFI7cHVRueHgWm70Q,8965
14
14
  moonshot/integrations/cli/benchmark/metrics.py,sha256=SHs-hIa4CIPyOJtxK2U4D6IRHy3ZNsRtZlAMGvF9Qxw,8310
15
15
  moonshot/integrations/cli/benchmark/recipe.py,sha256=yVFX3pwNzDL0a95rjlQd4cek06M9blv5jIeYB26jOKk,32481
@@ -34,7 +34,7 @@ moonshot/integrations/cli/utils/process_data.py,sha256=QVL5vp2_8ZgGicmCAdeYEHkeb
34
34
  moonshot/integrations/web_api/.env.dev,sha256=0z5_Ut8rF-UqFZtgjkH2qoqORhD5_nSs2w_OeX2SteI,182
35
35
  moonshot/integrations/web_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  moonshot/integrations/web_api/__main__.py,sha256=MdnLi_ZF-olAAEJwTPU1iGYFYwo-fNWNT2qfchkH3y4,2050
37
- moonshot/integrations/web_api/app.py,sha256=IucbtkC1n2l0Mx55St0e7FFWa_hV7Mdg64Sv9AZ41Ro,3651
37
+ moonshot/integrations/web_api/app.py,sha256=x9yYCUE78d8uNE6ws87236mHCYTSHqy2KWQdWZey0ns,3652
38
38
  moonshot/integrations/web_api/container.py,sha256=DVkJG_qm7ItcG6tgMYOqIj07wpKhPWOOfy6-bEv72y4,5915
39
39
  moonshot/integrations/web_api/logging_conf.py,sha256=t3EGRV6tZhV732KXe8_Tiy0fiwVAWxZX5Tt8VTgrrfg,3388
40
40
  moonshot/integrations/web_api/log/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -113,13 +113,14 @@ moonshot/src/api/api_result.py,sha256=M5zKF7ytKp237UZusLSYJ7QVfui85Ys0WEaYySGcAK
113
113
  moonshot/src/api/api_run.py,sha256=3PrETAVcFnJ09R0-xhWiFkEfqL6eYj4B2voEGJDPznU,2936
114
114
  moonshot/src/api/api_runner.py,sha256=cH0rxWREjc2qKmt4Tuwr-fEMrYDBE_TKRw0jOohNEgU,4179
115
115
  moonshot/src/api/api_session.py,sha256=OGH05ZxAwo_hKI-RNaJ-jCp_v-zcTm-9bHUclpq2z4Q,10978
116
- moonshot/src/bookmark/bookmark.py,sha256=T9dUGtw_l_3PeZT0iO2vFzPiSntX9MFurE9Gcop_JcM,11649
116
+ moonshot/src/bookmark/bookmark.py,sha256=Gf9wZ5wmJUmatHChr0_3tVyUbPMfpCVeEfujQQjIv18,11867
117
117
  moonshot/src/bookmark/bookmark_arguments.py,sha256=cB5m2zB8255WVdacmC2-ZYNyaoK4-gOM_Qwb_JDR-34,1449
118
118
  moonshot/src/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
119
  moonshot/src/configs/env_variables.py,sha256=eF__UJN37LCzIB4pv_T7G-kQHlOa657QA7IpL1d_0MM,7150
120
120
  moonshot/src/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
- moonshot/src/connectors/connector.py,sha256=e0ZCX9m83ezjMiY5H8gbWE64IStsNQqxzVwGtMwShPY,13396
122
- moonshot/src/connectors/connector_prompt_arguments.py,sha256=cIlAgbFk2g_XUZ0stVM904Ng2g4GYP2LyiAjktmhEQM,470
121
+ moonshot/src/connectors/connector.py,sha256=MkOtC2pr5SwHp8xe5oRhC77BEfNmo883LsBhl4VpKnQ,13555
122
+ moonshot/src/connectors/connector_prompt_arguments.py,sha256=gZ5jKwyZOPhMYQOfRE-Uyo4H4KoP1ngvXIXDcwEkkG0,630
123
+ moonshot/src/connectors/connector_response.py,sha256=UHrX5tTDGrfPUXoIvPeMUOEXqJxlAo8vgGMHBPzDc0k,712
123
124
  moonshot/src/connectors_endpoints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
124
125
  moonshot/src/connectors_endpoints/connector_endpoint.py,sha256=hrSvq7iw1IigZssKTcdotkcN8stG8Ov7AlJ8xxZcAJo,9526
125
126
  moonshot/src/connectors_endpoints/connector_endpoint_arguments.py,sha256=8WyD0EfrlhGM9rqrzoAcF-YWmSWiWdfpO91E7w6HPY0,2318
@@ -139,7 +140,7 @@ moonshot/src/recipes/recipe.py,sha256=PE4mimP7Y7lDanXib2uMrd9KpLWOxRdg0Cps5rLRQx
139
140
  moonshot/src/recipes/recipe_arguments.py,sha256=9LdVJidB6Sci941QvnudBznvx9_NVCl8r-HvzSZInlY,3914
140
141
  moonshot/src/redteaming/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
141
142
  moonshot/src/redteaming/attack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
- moonshot/src/redteaming/attack/attack_module.py,sha256=tbVfLs8FkBSQwpbWMkx6Ad7qrQt778boSG6h68lsLQk,26827
143
+ moonshot/src/redteaming/attack/attack_module.py,sha256=R2nfAKiPlEpgtWPHPANyciBxfiKg4YCEusvOg8p-EYM,27905
143
144
  moonshot/src/redteaming/attack/attack_module_arguments.py,sha256=L8H6poNj7xNWLUr6jfuSkwE7TNV0aTPaZBal4OvL7IA,1225
144
145
  moonshot/src/redteaming/attack/context_strategy.py,sha256=KiAw85Pl8tuTzQ2d3CkZrjn3Ddp7BnlT5Gc67TTnq4M,4821
145
146
  moonshot/src/redteaming/context_strategy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -158,7 +159,7 @@ moonshot/src/runners/runner_arguments.py,sha256=Bg4OPSmgr9jZKNAwPH0T3epEHw-6qGrf
158
159
  moonshot/src/runners/runner_type.py,sha256=jOfnAnaCYp-rPTRJXhM8hin_dinlR0sMwmimQXvLcJ0,100
159
160
  moonshot/src/runs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
160
161
  moonshot/src/runs/run.py,sha256=3Y_256IfOv5zpeujVPsA5YdX7uZjGMRvg0VencUwgLw,14339
161
- moonshot/src/runs/run_arguments.py,sha256=G043ERvHIU_dd0JghboZgxDWCcjYOaDwue1ieDunDKA,6443
162
+ moonshot/src/runs/run_arguments.py,sha256=rYMyAJrMYNwQq1yPSEXFv7fe6h17ZH37DXKEOixYEko,7450
162
163
  moonshot/src/runs/run_progress.py,sha256=d1BcNo6Kp4vA165TDx_xebl8JDo92aV-YutPxsgCOxE,6495
163
164
  moonshot/src/runs/run_status.py,sha256=TRtizcDzPxf6aQ2c3OovM6IQKJ0VCBhqDWvn7UBw5Zg,251
164
165
  moonshot/src/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -171,9 +172,9 @@ moonshot/src/utils/import_modules.py,sha256=T9zTN59PFnvY2rjyWhSV9KSIAHxWV1pyBemF
171
172
  moonshot/src/utils/log.py,sha256=YNgD7Eh2OT36XlmVBKCGUTAh9TRp4Akfe4kDdvHASgs,2502
172
173
  moonshot/src/utils/pagination.py,sha256=5seymyRoqyENIhKllAatr1T91kMCGFslcvRnJHyMSvc,814
173
174
  moonshot/src/utils/timeit.py,sha256=TvuF0w8KWhp0oZFY0cUU3UY0xlGKjchb0OkfYfgVTlc,866
174
- aiverify_moonshot-0.4.9.dist-info/METADATA,sha256=vuUKDpxqkTsxqeBCGZ6hAP5LcHl0xyZFklGL1-Fyv7Q,12388
175
- aiverify_moonshot-0.4.9.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
176
- aiverify_moonshot-0.4.9.dist-info/licenses/AUTHORS.md,sha256=mmAbe3i3sT8JZHJMBhxp3i1xRehV0g7WB4T_eyIBuBs,59
177
- aiverify_moonshot-0.4.9.dist-info/licenses/LICENSE.md,sha256=53izDRmJZZCjpYGfyLqlxnGQN-aNWBxasuzuMXC5Ias,11347
178
- aiverify_moonshot-0.4.9.dist-info/licenses/NOTICES.md,sha256=vS1zZYAnGjCJdwQ13xv3b2zc30wOS98ZnCKluT-AhHs,123266
179
- aiverify_moonshot-0.4.9.dist-info/RECORD,,
175
+ aiverify_moonshot-0.4.11.dist-info/METADATA,sha256=Yf_5kXixSCJzVEeC5vRW3uId1RKe1XLDLnLabE0S_AQ,12390
176
+ aiverify_moonshot-0.4.11.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
177
+ aiverify_moonshot-0.4.11.dist-info/licenses/AUTHORS.md,sha256=mmAbe3i3sT8JZHJMBhxp3i1xRehV0g7WB4T_eyIBuBs,59
178
+ aiverify_moonshot-0.4.11.dist-info/licenses/LICENSE.md,sha256=53izDRmJZZCjpYGfyLqlxnGQN-aNWBxasuzuMXC5Ias,11347
179
+ aiverify_moonshot-0.4.11.dist-info/licenses/NOTICES.md,sha256=vS1zZYAnGjCJdwQ13xv3b2zc30wOS98ZnCKluT-AhHs,123266
180
+ aiverify_moonshot-0.4.11.dist-info/RECORD,,
@@ -467,7 +467,10 @@ def _display_view_cookbook(cookbook_info):
467
467
  recipes_list = api_read_recipes(recipes)
468
468
  if recipes_list:
469
469
  table = Table(
470
- title="View Cookbook", show_lines=True, expand=True, header_style="bold"
470
+ title=f'Cookbook "{name}"',
471
+ show_lines=True,
472
+ expand=True,
473
+ header_style="bold",
471
474
  )
472
475
  table.add_column("No.", width=2)
473
476
  table.add_column("Recipe", justify="left", width=78)
@@ -482,7 +485,6 @@ def _display_view_cookbook(cookbook_info):
482
485
  datasets,
483
486
  prompt_templates,
484
487
  metrics,
485
- attack_strategies,
486
488
  grading_scale,
487
489
  stats,
488
490
  ) = recipe.values()
@@ -494,9 +496,6 @@ def _display_view_cookbook(cookbook_info):
494
496
  "Prompt Templates", prompt_templates
495
497
  )
496
498
  metrics_info = display_view_list_format("Metrics", metrics)
497
- attack_strategies_info = display_view_list_format(
498
- "Attack Strategies", attack_strategies
499
- )
500
499
  grading_scale_info = _display_view_grading_scale_format(
501
500
  "Grading Scale", grading_scale
502
501
  )
@@ -506,7 +505,9 @@ def _display_view_cookbook(cookbook_info):
506
505
  f"[red]id: {id}[/red]\n\n[blue]{name}[/blue]\n{description}\n\n"
507
506
  f"{tags_info}\n\n{categories_info}\n\n{grading_scale_info}\n\n{stats_info}"
508
507
  )
509
- contains_info = f"{datasets_info}\n\n{prompt_templates_info}\n\n{metrics_info}\n\n{attack_strategies_info}"
508
+ contains_info = (
509
+ f"{datasets_info}\n\n{prompt_templates_info}\n\n{metrics_info}"
510
+ )
510
511
 
511
512
  table.add_section()
512
513
  table.add_row(str(recipe_id), recipe_info, contains_info)
@@ -71,7 +71,7 @@ def create_app(cfg: providers.Configuration) -> CustomFastAPI:
71
71
  }
72
72
 
73
73
  app: CustomFastAPI = CustomFastAPI(
74
- title="Project Moonshot", version="0.4.9", **app_kwargs
74
+ title="Project Moonshot", version="0.4.11", **app_kwargs
75
75
  )
76
76
 
77
77
  if cfg.cors.enabled():
@@ -11,9 +11,9 @@ from moonshot.src.messages_constants import (
11
11
  BOOKMARK_ADD_BOOKMARK_VALIDATION_ERROR,
12
12
  BOOKMARK_DELETE_ALL_BOOKMARK_ERROR,
13
13
  BOOKMARK_DELETE_ALL_BOOKMARK_SUCCESS,
14
- BOOKMARK_DELETE_BOOKMARK_FAIL,
15
14
  BOOKMARK_DELETE_BOOKMARK_ERROR,
16
15
  BOOKMARK_DELETE_BOOKMARK_ERROR_1,
16
+ BOOKMARK_DELETE_BOOKMARK_FAIL,
17
17
  BOOKMARK_DELETE_BOOKMARK_SUCCESS,
18
18
  BOOKMARK_EXPORT_BOOKMARK_ERROR,
19
19
  BOOKMARK_EXPORT_BOOKMARK_VALIDATION_ERROR,
@@ -186,7 +186,9 @@ class Bookmark:
186
186
  if (
187
187
  bookmark_info is not None
188
188
  and isinstance(bookmark_info, tuple)
189
- and all(isinstance(item, str) for item in bookmark_info)
189
+ and all(
190
+ isinstance(item, str) for item in bookmark_info[1:]
191
+ ) # Check if the rest are strings besides id
190
192
  ):
191
193
  return BookmarkArguments.from_tuple_to_dict(bookmark_info)
192
194
  else:
@@ -210,9 +212,11 @@ class Bookmark:
210
212
  """
211
213
  if isinstance(bookmark_name, str) and bookmark_name:
212
214
  try:
213
-
214
215
  bookmark_info = Storage.read_database_record(
215
- self.db_instance, (bookmark_name,), Bookmark.sql_select_bookmark_record)
216
+ self.db_instance,
217
+ (bookmark_name,),
218
+ Bookmark.sql_select_bookmark_record,
219
+ )
216
220
  if bookmark_info is not None:
217
221
  sql_delete_bookmark_record = textwrap.dedent(
218
222
  f"""
@@ -222,7 +226,10 @@ class Bookmark:
222
226
  Storage.delete_database_record_in_table(
223
227
  self.db_instance, sql_delete_bookmark_record
224
228
  )
225
- return {"success": True, "message": BOOKMARK_DELETE_BOOKMARK_SUCCESS}
229
+ return {
230
+ "success": True,
231
+ "message": BOOKMARK_DELETE_BOOKMARK_SUCCESS,
232
+ }
226
233
  else:
227
234
  return {"success": False, "message": BOOKMARK_DELETE_BOOKMARK_FAIL}
228
235
  except Exception as e:
@@ -10,6 +10,7 @@ from typing import Callable
10
10
 
11
11
  from moonshot.src.configs.env_variables import EnvVariables
12
12
  from moonshot.src.connectors.connector_prompt_arguments import ConnectorPromptArguments
13
+ from moonshot.src.connectors.connector_response import ConnectorResponse
13
14
  from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
14
15
  ConnectorEndpointArguments,
15
16
  )
@@ -168,9 +169,9 @@ class Connector:
168
169
  return wrapper
169
170
 
170
171
  @abstractmethod
171
- async def get_response(self, prompt: str) -> str:
172
+ async def get_response(self, prompt: str) -> ConnectorResponse:
172
173
  """
173
- Abstract method to be implemented by subclasses to get a response from the connector.
174
+ Abstract method to be implemented by subclasses to obtain a response from the connector.
174
175
 
175
176
  This method should asynchronously send a prompt to the connector's API and return the response.
176
177
 
@@ -178,7 +179,8 @@ class Connector:
178
179
  prompt (str): The input prompt to be sent to the connector.
179
180
 
180
181
  Returns:
181
- str: The response received from the connector.
182
+ ConnectorResponse: An instance containing the response received from the connector and any
183
+ additional metadata.
182
184
  """
183
185
  pass
184
186
 
@@ -277,7 +279,7 @@ class Connector:
277
279
  object, which is used to generate the prediction. The method also optionally takes a `prompt_callback` function,
278
280
  which is called after the prediction is generated.
279
281
 
280
- The method first prints a message indicating that it is predicting the prompt. It then records the start time
282
+ The method logs a message indicating that it is predicting the prompt. It then records the start time
281
283
  and uses the `connector` to generate a prediction for the `generated_prompt`. The duration of the prediction
282
284
  is calculated and stored in the `generated_prompt`.
283
285
 
@@ -4,14 +4,21 @@ from typing import Any
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
+ from moonshot.src.connectors.connector_response import ConnectorResponse
8
+
7
9
 
8
10
  class ConnectorPromptArguments(BaseModel):
11
+ class Config:
12
+ arbitrary_types_allowed = True
13
+
9
14
  prompt_index: int # The index of the prompt in the dataset
10
15
 
11
16
  prompt: str # The actual prompt text
12
17
 
13
18
  target: Any # The target response for the prompt
14
19
 
15
- predicted_results: Any = "" # The predicted results, default is an empty string
20
+ predicted_results: ConnectorResponse | None = (
21
+ None # The predicted results, default is None
22
+ )
16
23
 
17
24
  duration: float = 0.0 # The duration it took to get the results, default is 0.0
@@ -0,0 +1,20 @@
1
+ class ConnectorResponse:
2
+ def __init__(self, response: str, context: list = []):
3
+ """
4
+ Initializes a ConnectorResponse instance.
5
+
6
+ Args:
7
+ response (str): The response text from the connector.
8
+ context (list, optional): Additional context or metadata related to the response. Defaults to an empty list.
9
+ """
10
+ self.response = response
11
+ self.context = context
12
+
13
+ def to_dict(self) -> dict:
14
+ """
15
+ Converts the ConnectorResponse instance to a dictionary.
16
+
17
+ Returns:
18
+ dict: A dictionary representation of the ConnectorResponse instance.
19
+ """
20
+ return {"response": self.response, "context": self.context}
@@ -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
  )