aiverify-moonshot 0.4.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 (163) hide show
  1. aiverify_moonshot-0.4.0.dist-info/METADATA +249 -0
  2. aiverify_moonshot-0.4.0.dist-info/RECORD +163 -0
  3. aiverify_moonshot-0.4.0.dist-info/WHEEL +4 -0
  4. aiverify_moonshot-0.4.0.dist-info/licenses/AUTHORS.md +5 -0
  5. aiverify_moonshot-0.4.0.dist-info/licenses/LICENSE.md +201 -0
  6. aiverify_moonshot-0.4.0.dist-info/licenses/NOTICES.md +3340 -0
  7. moonshot/__init__.py +0 -0
  8. moonshot/__main__.py +198 -0
  9. moonshot/api.py +155 -0
  10. moonshot/integrations/__init__.py +0 -0
  11. moonshot/integrations/cli/__init__.py +0 -0
  12. moonshot/integrations/cli/__main__.py +25 -0
  13. moonshot/integrations/cli/active_session_cfg.py +1 -0
  14. moonshot/integrations/cli/benchmark/__init__.py +0 -0
  15. moonshot/integrations/cli/benchmark/benchmark.py +186 -0
  16. moonshot/integrations/cli/benchmark/cookbook.py +545 -0
  17. moonshot/integrations/cli/benchmark/datasets.py +164 -0
  18. moonshot/integrations/cli/benchmark/metrics.py +141 -0
  19. moonshot/integrations/cli/benchmark/recipe.py +598 -0
  20. moonshot/integrations/cli/benchmark/result.py +216 -0
  21. moonshot/integrations/cli/benchmark/run.py +140 -0
  22. moonshot/integrations/cli/benchmark/runner.py +174 -0
  23. moonshot/integrations/cli/cli.py +64 -0
  24. moonshot/integrations/cli/common/__init__.py +0 -0
  25. moonshot/integrations/cli/common/common.py +72 -0
  26. moonshot/integrations/cli/common/connectors.py +325 -0
  27. moonshot/integrations/cli/common/display_helper.py +42 -0
  28. moonshot/integrations/cli/common/prompt_template.py +94 -0
  29. moonshot/integrations/cli/initialisation/__init__.py +0 -0
  30. moonshot/integrations/cli/initialisation/initialisation.py +14 -0
  31. moonshot/integrations/cli/redteam/__init__.py +0 -0
  32. moonshot/integrations/cli/redteam/attack_module.py +70 -0
  33. moonshot/integrations/cli/redteam/context_strategy.py +147 -0
  34. moonshot/integrations/cli/redteam/prompt_template.py +67 -0
  35. moonshot/integrations/cli/redteam/redteam.py +90 -0
  36. moonshot/integrations/cli/redteam/session.py +467 -0
  37. moonshot/integrations/web_api/.env.dev +7 -0
  38. moonshot/integrations/web_api/__init__.py +0 -0
  39. moonshot/integrations/web_api/__main__.py +56 -0
  40. moonshot/integrations/web_api/app.py +125 -0
  41. moonshot/integrations/web_api/container.py +146 -0
  42. moonshot/integrations/web_api/log/.gitkeep +0 -0
  43. moonshot/integrations/web_api/logging_conf.py +114 -0
  44. moonshot/integrations/web_api/routes/__init__.py +0 -0
  45. moonshot/integrations/web_api/routes/attack_modules.py +66 -0
  46. moonshot/integrations/web_api/routes/benchmark.py +116 -0
  47. moonshot/integrations/web_api/routes/benchmark_result.py +175 -0
  48. moonshot/integrations/web_api/routes/context_strategy.py +129 -0
  49. moonshot/integrations/web_api/routes/cookbook.py +225 -0
  50. moonshot/integrations/web_api/routes/dataset.py +120 -0
  51. moonshot/integrations/web_api/routes/endpoint.py +282 -0
  52. moonshot/integrations/web_api/routes/metric.py +78 -0
  53. moonshot/integrations/web_api/routes/prompt_template.py +128 -0
  54. moonshot/integrations/web_api/routes/recipe.py +219 -0
  55. moonshot/integrations/web_api/routes/redteam.py +609 -0
  56. moonshot/integrations/web_api/routes/runner.py +239 -0
  57. moonshot/integrations/web_api/schemas/__init__.py +0 -0
  58. moonshot/integrations/web_api/schemas/benchmark_runner_dto.py +13 -0
  59. moonshot/integrations/web_api/schemas/cookbook_create_dto.py +19 -0
  60. moonshot/integrations/web_api/schemas/cookbook_response_model.py +9 -0
  61. moonshot/integrations/web_api/schemas/dataset_response_dto.py +9 -0
  62. moonshot/integrations/web_api/schemas/endpoint_create_dto.py +21 -0
  63. moonshot/integrations/web_api/schemas/endpoint_response_model.py +11 -0
  64. moonshot/integrations/web_api/schemas/prompt_response_model.py +14 -0
  65. moonshot/integrations/web_api/schemas/prompt_template_response_model.py +10 -0
  66. moonshot/integrations/web_api/schemas/recipe_create_dto.py +32 -0
  67. moonshot/integrations/web_api/schemas/recipe_response_model.py +7 -0
  68. moonshot/integrations/web_api/schemas/session_create_dto.py +16 -0
  69. moonshot/integrations/web_api/schemas/session_prompt_dto.py +7 -0
  70. moonshot/integrations/web_api/schemas/session_response_model.py +38 -0
  71. moonshot/integrations/web_api/services/__init__.py +0 -0
  72. moonshot/integrations/web_api/services/attack_module_service.py +34 -0
  73. moonshot/integrations/web_api/services/auto_red_team_test_manager.py +86 -0
  74. moonshot/integrations/web_api/services/auto_red_team_test_state.py +57 -0
  75. moonshot/integrations/web_api/services/base_service.py +8 -0
  76. moonshot/integrations/web_api/services/benchmark_result_service.py +25 -0
  77. moonshot/integrations/web_api/services/benchmark_test_manager.py +106 -0
  78. moonshot/integrations/web_api/services/benchmark_test_state.py +56 -0
  79. moonshot/integrations/web_api/services/benchmarking_service.py +31 -0
  80. moonshot/integrations/web_api/services/context_strategy_service.py +22 -0
  81. moonshot/integrations/web_api/services/cookbook_service.py +194 -0
  82. moonshot/integrations/web_api/services/dataset_service.py +20 -0
  83. moonshot/integrations/web_api/services/endpoint_service.py +65 -0
  84. moonshot/integrations/web_api/services/metric_service.py +14 -0
  85. moonshot/integrations/web_api/services/prompt_template_service.py +39 -0
  86. moonshot/integrations/web_api/services/recipe_service.py +155 -0
  87. moonshot/integrations/web_api/services/runner_service.py +147 -0
  88. moonshot/integrations/web_api/services/session_service.py +350 -0
  89. moonshot/integrations/web_api/services/utils/exceptions_handler.py +41 -0
  90. moonshot/integrations/web_api/services/utils/results_formatter.py +47 -0
  91. moonshot/integrations/web_api/status_updater/interface/benchmark_progress_callback.py +14 -0
  92. moonshot/integrations/web_api/status_updater/interface/redteam_progress_callback.py +14 -0
  93. moonshot/integrations/web_api/status_updater/moonshot_ui_webhook.py +72 -0
  94. moonshot/integrations/web_api/types/types.py +99 -0
  95. moonshot/src/__init__.py +0 -0
  96. moonshot/src/api/__init__.py +0 -0
  97. moonshot/src/api/api_connector.py +58 -0
  98. moonshot/src/api/api_connector_endpoint.py +162 -0
  99. moonshot/src/api/api_context_strategy.py +57 -0
  100. moonshot/src/api/api_cookbook.py +160 -0
  101. moonshot/src/api/api_dataset.py +46 -0
  102. moonshot/src/api/api_environment_variables.py +17 -0
  103. moonshot/src/api/api_metrics.py +51 -0
  104. moonshot/src/api/api_prompt_template.py +43 -0
  105. moonshot/src/api/api_recipe.py +182 -0
  106. moonshot/src/api/api_red_teaming.py +59 -0
  107. moonshot/src/api/api_result.py +84 -0
  108. moonshot/src/api/api_run.py +74 -0
  109. moonshot/src/api/api_runner.py +132 -0
  110. moonshot/src/api/api_session.py +290 -0
  111. moonshot/src/configs/__init__.py +0 -0
  112. moonshot/src/configs/env_variables.py +187 -0
  113. moonshot/src/connectors/__init__.py +0 -0
  114. moonshot/src/connectors/connector.py +327 -0
  115. moonshot/src/connectors/connector_prompt_arguments.py +17 -0
  116. moonshot/src/connectors_endpoints/__init__.py +0 -0
  117. moonshot/src/connectors_endpoints/connector_endpoint.py +211 -0
  118. moonshot/src/connectors_endpoints/connector_endpoint_arguments.py +54 -0
  119. moonshot/src/cookbooks/__init__.py +0 -0
  120. moonshot/src/cookbooks/cookbook.py +225 -0
  121. moonshot/src/cookbooks/cookbook_arguments.py +34 -0
  122. moonshot/src/datasets/__init__.py +0 -0
  123. moonshot/src/datasets/dataset.py +255 -0
  124. moonshot/src/datasets/dataset_arguments.py +50 -0
  125. moonshot/src/metrics/__init__.py +0 -0
  126. moonshot/src/metrics/metric.py +192 -0
  127. moonshot/src/metrics/metric_interface.py +95 -0
  128. moonshot/src/prompt_templates/__init__.py +0 -0
  129. moonshot/src/prompt_templates/prompt_template.py +103 -0
  130. moonshot/src/recipes/__init__.py +0 -0
  131. moonshot/src/recipes/recipe.py +340 -0
  132. moonshot/src/recipes/recipe_arguments.py +111 -0
  133. moonshot/src/redteaming/__init__.py +0 -0
  134. moonshot/src/redteaming/attack/__init__.py +0 -0
  135. moonshot/src/redteaming/attack/attack_module.py +618 -0
  136. moonshot/src/redteaming/attack/attack_module_arguments.py +44 -0
  137. moonshot/src/redteaming/attack/context_strategy.py +131 -0
  138. moonshot/src/redteaming/context_strategy/__init__.py +0 -0
  139. moonshot/src/redteaming/context_strategy/context_strategy_interface.py +46 -0
  140. moonshot/src/redteaming/session/__init__.py +0 -0
  141. moonshot/src/redteaming/session/chat.py +209 -0
  142. moonshot/src/redteaming/session/red_teaming_progress.py +128 -0
  143. moonshot/src/redteaming/session/red_teaming_type.py +6 -0
  144. moonshot/src/redteaming/session/session.py +775 -0
  145. moonshot/src/results/__init__.py +0 -0
  146. moonshot/src/results/result.py +119 -0
  147. moonshot/src/results/result_arguments.py +44 -0
  148. moonshot/src/runners/__init__.py +0 -0
  149. moonshot/src/runners/runner.py +476 -0
  150. moonshot/src/runners/runner_arguments.py +46 -0
  151. moonshot/src/runners/runner_type.py +6 -0
  152. moonshot/src/runs/__init__.py +0 -0
  153. moonshot/src/runs/run.py +344 -0
  154. moonshot/src/runs/run_arguments.py +162 -0
  155. moonshot/src/runs/run_progress.py +145 -0
  156. moonshot/src/runs/run_status.py +10 -0
  157. moonshot/src/storage/__init__.py +0 -0
  158. moonshot/src/storage/db_interface.py +128 -0
  159. moonshot/src/storage/io_interface.py +31 -0
  160. moonshot/src/storage/storage.py +525 -0
  161. moonshot/src/utils/__init__.py +0 -0
  162. moonshot/src/utils/import_modules.py +96 -0
  163. moonshot/src/utils/timeit.py +25 -0
@@ -0,0 +1,155 @@
1
+ from moonshot.src.recipes.recipe_arguments import RecipeArguments as Recipe
2
+
3
+ from .... import api as moonshot_api
4
+ from ..schemas.recipe_create_dto import RecipeCreateDTO, RecipeUpdateDTO
5
+ from ..schemas.recipe_response_model import RecipeResponseModel
6
+ from ..services.base_service import BaseService
7
+ from ..services.utils.exceptions_handler import exception_handler
8
+
9
+
10
+ class RecipeService(BaseService):
11
+ @exception_handler
12
+ def create_recipe(self, recipe_data: RecipeCreateDTO) -> None:
13
+ """
14
+ Create a new recipe with the given data.
15
+
16
+ Args:
17
+ recipe_data (RecipeCreateDTO): Data transfer object containing recipe details.
18
+ """
19
+ moonshot_api.api_create_recipe(
20
+ name=recipe_data.name,
21
+ description=recipe_data.description,
22
+ tags=recipe_data.tags,
23
+ categories=recipe_data.categories,
24
+ datasets=recipe_data.datasets,
25
+ prompt_templates=recipe_data.prompt_templates,
26
+ metrics=recipe_data.metrics,
27
+ attack_modules=recipe_data.attack_modules,
28
+ grading_scale=recipe_data.grading_scale,
29
+ )
30
+
31
+ @exception_handler
32
+ def get_all_recipes(
33
+ self,
34
+ tags: str,
35
+ categories: str,
36
+ sort_by: str,
37
+ count: bool,
38
+ ids: str | None = None,
39
+ ) -> list[RecipeResponseModel]:
40
+ """
41
+ Retrieve all recipes, with optional filters for tags, categories, sorting, and including prompt counts.
42
+
43
+ Args:
44
+ ids (str, optional): Filter recipes by IDs. If None, no ID-based filtering is applied.
45
+ tags (str, optional): Filter recipes by tags. If None, no tag-based filtering is applied.
46
+ categories (str, optional): Filter recipes by categories. If None, no category-based filtering is applied.
47
+ sort_by (str, optional): Sort recipes by a specified field. If None, no sorting is applied.
48
+ count (bool, optional): Include the total prompt count in each recipe if True.
49
+
50
+ Returns:
51
+ list[RecipeResponseModel]: A list of recipe, filtered and sorted, with optional prompt counts.
52
+ """
53
+ filtered_recipes: list[RecipeResponseModel] = []
54
+
55
+ if ids:
56
+ recipe_ids = ids.split(",")
57
+ recipes = [moonshot_api.api_read_recipe(id) for id in recipe_ids]
58
+ else:
59
+ recipes = moonshot_api.api_get_all_recipe()
60
+
61
+ for recipe_dict in recipes:
62
+ recipe = RecipeResponseModel(**recipe_dict)
63
+ if count:
64
+ recipe.total_prompt_in_recipe = get_total_prompt_in_recipe(recipe)
65
+ filtered_recipes.append(recipe)
66
+
67
+ # TODO - do all filtering in 1 pass
68
+ if tags:
69
+ filtered_recipes = [
70
+ recipe for recipe in filtered_recipes if tags in recipe.tags
71
+ ]
72
+
73
+ if categories:
74
+ categories_list = categories.split(",") if categories else []
75
+ if categories_list:
76
+ filtered_recipes = [
77
+ recipe
78
+ for recipe in filtered_recipes
79
+ if any(
80
+ category.lower() in (cat.lower() for cat in recipe.categories)
81
+ for category in categories_list
82
+ )
83
+ ]
84
+ if sort_by:
85
+ if sort_by == "id":
86
+ filtered_recipes.sort(key=lambda x: x.id)
87
+
88
+ return filtered_recipes
89
+
90
+ @exception_handler
91
+ def get_all_recipes_name(self) -> list[str]:
92
+ """
93
+ Retrieve the names of all recipes.
94
+
95
+ Returns:
96
+ list[str]: A list of recipe names.
97
+ """
98
+ recipes = moonshot_api.api_get_all_recipe_name()
99
+ return recipes
100
+
101
+ @exception_handler
102
+ def update_recipe(self, recipe_data: RecipeUpdateDTO, recipe_id: str) -> None:
103
+ """
104
+ Update an existing recipe with new data.
105
+
106
+ Args:
107
+ recipe_data (RecipeCreateDTO): Data transfer object containing new recipe details.
108
+ recipe_id (str): The ID of the recipe to update.
109
+ """
110
+ update_data = {
111
+ k: v
112
+ for k, v in recipe_data.to_dict().items()
113
+ if v is not None and k not in ["id", "stats"]
114
+ }
115
+
116
+ moonshot_api.api_update_recipe(rec_id=recipe_id, **update_data)
117
+
118
+ @exception_handler
119
+ def delete_recipe(self, recipe_id: str) -> None:
120
+ """
121
+ Delete a recipe by its ID.
122
+
123
+ Args:
124
+ recipe_id (str): The ID of the recipe to delete.
125
+ """
126
+ moonshot_api.api_delete_recipe(recipe_id)
127
+
128
+
129
+ @staticmethod
130
+ def get_total_prompt_in_recipe(recipe: Recipe) -> int:
131
+ """
132
+ Calculate the total number of prompts in a recipe.
133
+
134
+ This function sums up the number of dataset prompts and then multiplies
135
+ the result by the number of prompt templates if they exist.
136
+
137
+ Args:
138
+ recipe (Recipe): The recipe object containing the stats and
139
+ prompt templates information.
140
+
141
+ Returns:
142
+ int: The total count of prompts within the recipe.
143
+ """
144
+ # Initialize total prompt count
145
+ total_prompt_count = 0
146
+
147
+ # Add counts from dataset prompts if available
148
+ datasets_prompts = recipe.stats.get("num_of_datasets_prompts", {})
149
+ total_prompt_count += sum(datasets_prompts.values())
150
+
151
+ # If there are prompt templates, scale the total count by the number of templates
152
+ if recipe.prompt_templates:
153
+ total_prompt_count *= len(recipe.prompt_templates)
154
+
155
+ return total_prompt_count
@@ -0,0 +1,147 @@
1
+ from typing import Callable
2
+
3
+ from moonshot.src.runners.runner import Runner
4
+
5
+ from .... import api as moonshot_api
6
+ from ..services.base_service import BaseService
7
+ from ..services.utils.exceptions_handler import exception_handler
8
+ from ..types.types import TestRunProgress
9
+
10
+
11
+ class RunnerService(BaseService):
12
+ @exception_handler
13
+ def get_all_runner(self) -> list[dict]:
14
+ """
15
+ Retrieves all runners.
16
+
17
+ Returns:
18
+ A list of dictionaries, where each dictionary contains the details of a runner.
19
+ """
20
+ runners = moonshot_api.api_get_all_runner()
21
+ return runners
22
+
23
+ @exception_handler
24
+ def get_all_runner_name(self) -> list[str]:
25
+ """
26
+ Retrieves the names of all runners.
27
+
28
+ Returns:
29
+ A list of strings, where each string is the name of a runner.
30
+ """
31
+ runners = moonshot_api.api_get_all_runner_name()
32
+ return runners
33
+
34
+ @exception_handler
35
+ def get_runner_by_id(self, runner_id: str) -> dict | None:
36
+ """
37
+ Retrieves a runner by its ID.
38
+
39
+ Args:
40
+ runner_id: The unique identifier of the runner.
41
+
42
+ Returns:
43
+ A dictionary containing the runner's details if found, otherwise None.
44
+ """
45
+ runner = moonshot_api.api_read_runner(runner_id)
46
+ return runner
47
+
48
+ @exception_handler
49
+ def delete_run(self, runner_id: str) -> None:
50
+ """
51
+ Deletes a runner by its ID.
52
+
53
+ Args:
54
+ runner_id: The unique identifier of the runner to be deleted.
55
+ """
56
+ moonshot_api.api_delete_runner(runner_id)
57
+
58
+ @exception_handler
59
+ def create_runner(
60
+ self,
61
+ runner_name: str,
62
+ endpoints: list[str],
63
+ description: str,
64
+ progress_callback_func: Callable[[TestRunProgress], None] = None,
65
+ ) -> Runner:
66
+ """
67
+ Creates a new runner with the specified details.
68
+
69
+ Args:
70
+ runner_name: The name of the runner.
71
+ endpoints: A list of endpoints the runner will interact with.
72
+ description: A brief description of the runner.
73
+ progress_callback_func: An optional callback function for progress updates.
74
+
75
+ Returns:
76
+ An instance of Runner.
77
+ """
78
+ return moonshot_api.api_create_runner(
79
+ name=runner_name,
80
+ endpoints=endpoints,
81
+ description=description,
82
+ progress_callback_func=progress_callback_func,
83
+ )
84
+
85
+ @exception_handler
86
+ def load_runner(
87
+ self,
88
+ runner_id: str,
89
+ progress_callback_func: Callable[[TestRunProgress], None] = None,
90
+ ) -> Runner:
91
+ """
92
+ Loads a runner by its ID.
93
+
94
+ Args:
95
+ runner_id: The unique identifier of the runner to be loaded.
96
+ progress_callback_func: An optional callback function for progress updates.
97
+
98
+ Returns:
99
+ An instance of Runner.
100
+ """
101
+ return moonshot_api.api_load_runner(
102
+ runner_id, progress_callback_func=progress_callback_func
103
+ )
104
+
105
+ @exception_handler
106
+ def get_run_details_by_runner(self, runner_id: str, run_id: int):
107
+ """
108
+ Retrieves the details of a specific run by the runner ID and run ID.
109
+
110
+ Args:
111
+ runner_id: The unique identifier of the runner.
112
+ run_id: The unique identifier of the run.
113
+
114
+ Returns:
115
+ A dictionary containing the details of the run if found, otherwise an empty dictionary.
116
+ """
117
+ runs = moonshot_api.api_get_all_run(runner_id)
118
+ retn = {}
119
+ run_id_int = int(run_id)
120
+ for run in runs:
121
+ run_id_from_run = int(run.get("run_id"))
122
+ if run_id_from_run == run_id_int:
123
+ retn = {
124
+ "run_id": run.get("run_id"),
125
+ "runner_id": run.get("runner_id"),
126
+ "runner_args": run.get("runner_args"),
127
+ "endpoints": run.get("endpoints"),
128
+ "start_time": run.get("start_time"),
129
+ }
130
+ return retn
131
+
132
+ @exception_handler
133
+ def get_runs_id_in_runner(self, runner_id) -> list[int]:
134
+ """
135
+ Retrieves a list of run IDs for a given runner.
136
+
137
+ Args:
138
+ runner_id: The unique identifier of the runner.
139
+
140
+ Returns:
141
+ A list of integers, where each integer is the ID of a run associated with the runner.
142
+ """
143
+ runs = moonshot_api.api_get_all_run(runner_id)
144
+ retn = []
145
+ for run in runs:
146
+ retn.append(run.get("run_id"))
147
+ return retn
@@ -0,0 +1,350 @@
1
+ from dependency_injector.wiring import inject
2
+
3
+ from moonshot.src.api.api_session import api_create_session
4
+ from moonshot.src.runners.runner import Runner
5
+
6
+ from .... import api as moonshot_api
7
+ from ..schemas.prompt_response_model import PromptResponseModel
8
+ from ..schemas.session_create_dto import SessionCreateDTO
9
+ from ..schemas.session_prompt_dto import SessionPromptDTO
10
+ from ..schemas.session_response_model import SessionMetadataModel, SessionResponseModel
11
+ from ..services.auto_red_team_test_manager import AutoRedTeamTestManager
12
+ from ..services.runner_service import RunnerService
13
+ from ..services.utils.exceptions_handler import exception_handler
14
+ from ..status_updater.interface.redteam_progress_callback import (
15
+ InterfaceRedTeamProgressCallback,
16
+ )
17
+ from .base_service import BaseService
18
+
19
+
20
+ class SessionService(BaseService):
21
+ active_runner: Runner
22
+
23
+ @inject
24
+ def __init__(
25
+ self,
26
+ auto_red_team_test_manager: AutoRedTeamTestManager,
27
+ progress_status_updater: InterfaceRedTeamProgressCallback,
28
+ runner_service: RunnerService,
29
+ ) -> None:
30
+ """
31
+ Initialize the SessionService with dependencies.
32
+
33
+ Args:
34
+ progress_status_updater (InterfaceRedTeamProgressCallback): The callback interface for progress updates.
35
+ runner_service (RunnerService): The service for managing runners.
36
+ """
37
+ self.auto_red_team_test_manager = auto_red_team_test_manager
38
+ self.progress_status_updater = progress_status_updater
39
+ self.runner_service = runner_service
40
+ super().__init__()
41
+
42
+ @exception_handler
43
+ def create_new_session(
44
+ self, session_create_dto: SessionCreateDTO
45
+ ) -> SessionResponseModel:
46
+ """
47
+ Create a new session with a new runner and return the session metadata.
48
+
49
+ Args:
50
+ session_create_dto (SessionCreateDTO): Data transfer object containing session creation details.
51
+
52
+ Returns:
53
+ SessionMetadataModel: The metadata of the newly created session.
54
+ """
55
+ # Create a new runner instance using the runner service
56
+ runner = self.runner_service.create_runner(
57
+ runner_name=session_create_dto.name,
58
+ endpoints=session_create_dto.endpoints,
59
+ description=session_create_dto.description,
60
+ progress_callback_func=self.progress_status_updater.on_art_progress_update,
61
+ )
62
+ self.active_runner = runner
63
+
64
+ # Prepare runner arguments for session creation
65
+ runner_args = {
66
+ "context_strategy": session_create_dto.context_strategy,
67
+ "prompt_template": session_create_dto.prompt_template,
68
+ "cs_num_of_prev_prompts": session_create_dto.cs_num_of_prev_prompts,
69
+ "attack_module": session_create_dto.attack_module,
70
+ "metric": session_create_dto.metric,
71
+ "system_prompt": session_create_dto.system_prompt,
72
+ }
73
+
74
+ # Create a new session if the runner has a database instance
75
+ if runner.database_instance:
76
+ api_create_session(
77
+ runner.id, runner.database_instance, runner.endpoints, runner_args
78
+ )
79
+
80
+ # Load and return the session metadata
81
+ session_metadata_dict = moonshot_api.api_load_session(runner.id)
82
+ if session_metadata_dict is None:
83
+ raise ValueError(f"No session metadata found for runner ID {runner.id}")
84
+
85
+ return SessionResponseModel(
86
+ session_name=runner.name,
87
+ session_description=runner.description,
88
+ session=SessionMetadataModel(**session_metadata_dict),
89
+ chat_records=None,
90
+ )
91
+
92
+ @exception_handler
93
+ def get_all_session(self) -> list[SessionMetadataModel]:
94
+ """
95
+ Retrieve all session metadata.
96
+
97
+ Returns:
98
+ list[SessionMetadataModel]: A list of session metadata models for all sessions.
99
+ """
100
+ retn_session = []
101
+ runners_with_session = moonshot_api.api_get_all_runner()
102
+ sessions_metadata_dicts = moonshot_api.api_get_all_session_metadata()
103
+
104
+ runners_dict = {runner['id']: runner for runner in runners_with_session}
105
+
106
+ for session in sessions_metadata_dicts:
107
+ sess_id = session.get("session_id")
108
+ if sess_id in runners_dict:
109
+ session['description'] = runners_dict[sess_id]['description']
110
+ retn_session.append(session)
111
+
112
+ return [
113
+ SessionMetadataModel(**metadata) for metadata in sessions_metadata_dicts
114
+ ]
115
+
116
+ @exception_handler
117
+ def get_all_sessions_names(self) -> list[str]:
118
+ """
119
+ Retrieve a list of all session names.
120
+
121
+ This method calls the moonshot API to get the names of all sessions and returns them.
122
+
123
+ Returns:
124
+ list[str]: A list of session names.
125
+ """
126
+ sessions = moonshot_api.api_get_all_session_names()
127
+ return sessions
128
+
129
+ @exception_handler
130
+ def get_session_by_runner_id(
131
+ self, runner_id: str, include_history: bool
132
+ ) -> SessionResponseModel:
133
+ """
134
+ Retrieve session information by runner ID, optionally including chat history.
135
+
136
+ Args:
137
+ runner_id (str): The unique identifier of the runner.
138
+ include_history (bool): Flag to determine if chat history should be included.
139
+
140
+ Returns:
141
+ SessionResponseModel: An object containing session metadata and optionally chat records.
142
+ """
143
+ runner: Runner = self.runner_service.load_runner(
144
+ runner_id, self.progress_status_updater.on_art_progress_update
145
+ )
146
+ self.active_runner = runner
147
+ session_metadata_dict = moonshot_api.api_load_session(self.active_runner.id)
148
+
149
+ if not isinstance(session_metadata_dict, dict):
150
+ raise ValueError(
151
+ f"Session metadata for runner ID {runner.id} must be a dictionary."
152
+ )
153
+
154
+ session_chat = (
155
+ moonshot_api.api_get_all_chats_from_session(runner.id)
156
+ if include_history
157
+ else None
158
+ )
159
+
160
+ return SessionResponseModel(
161
+ session_name=runner.name,
162
+ session_description=runner.description,
163
+ session=SessionMetadataModel(**session_metadata_dict),
164
+ chat_records=session_chat,
165
+ )
166
+
167
+ @exception_handler
168
+ def update_session_chat(self, runner_id: str):
169
+ """
170
+ Update the chat for the current session.
171
+
172
+ Args:
173
+ runner_id (str): The unique identifier of the runner.
174
+
175
+ Returns:
176
+ The updated chat records for the session.
177
+ """
178
+ if self.active_runner.id != runner_id:
179
+ raise RuntimeError("Active session and requested session do not match.")
180
+ session_chat = moonshot_api.api_get_all_chats_from_session(
181
+ self.active_runner.id
182
+ )
183
+ return session_chat
184
+
185
+ @exception_handler
186
+ def delete_session(self, runner_id: str) -> None:
187
+ """
188
+ Delete a session by runner ID.
189
+
190
+ This method calls the moonshot API to delete the session associated with the given runner ID.
191
+
192
+ Args:
193
+ runner_id (str): The unique identifier of the runner whose session is to be deleted.
194
+ """
195
+ moonshot_api.api_delete_session(runner_id)
196
+
197
+ @exception_handler
198
+ def select_prompt_template(self, runner_id: str, prompt_template_name: str = ""):
199
+ """
200
+ Select a prompt template for the current session.
201
+
202
+ Args:
203
+ runner_id (str): The unique identifier of the runner.
204
+ prompt_template_name (str): The name of the prompt template to be selected.
205
+ """
206
+ if self.active_runner.id != runner_id:
207
+ raise RuntimeError("Active session and requested session do not match.")
208
+ moonshot_api.api_update_prompt_template(
209
+ self.active_runner.id, prompt_template_name
210
+ )
211
+
212
+ @exception_handler
213
+ def select_ctx_strategy(
214
+ self, runner_id: str, ctx_strategy_name: str = "", num_of_prompt: int = 5
215
+ ) -> None:
216
+ """
217
+ Select a context strategy for the current session.
218
+
219
+ Args:
220
+ runner_id (str): The unique identifier of the runner.
221
+ ctx_strategy_name (str): The name of the context strategy to be selected.
222
+ num_of_prompt (int): The number of previous prompts to consider in the strategy.
223
+ """
224
+ if self.active_runner.id != runner_id:
225
+ raise RuntimeError("Active session and requested session do not match.")
226
+ moonshot_api.api_update_context_strategy(
227
+ self.active_runner.id, ctx_strategy_name
228
+ )
229
+ moonshot_api.api_update_cs_num_of_prev_prompts(
230
+ self.active_runner.id, num_of_prompt
231
+ )
232
+
233
+ @exception_handler
234
+ def select_attack_module(self, runner_id: str, attack_module_name: str = ""):
235
+ """
236
+ Select an attack module for the current session.
237
+
238
+ Args:
239
+ runner_id (str): The unique identifier of the runner.
240
+ attack_module_name (str): The name of the attack module to be selected.
241
+ """
242
+ if self.active_runner.id != runner_id:
243
+ raise RuntimeError("Active session and requested session do not match.")
244
+ moonshot_api.api_update_attack_module(self.active_runner.id, attack_module_name)
245
+
246
+ @exception_handler
247
+ def select_metric(self, runner_id: str, metric_name: str = ""):
248
+ """
249
+ Select a metric for the current session.
250
+
251
+ Args:
252
+ runner_id (str): The unique identifier of the runner.
253
+ metric_name (str): The name of the metric to be selected.
254
+ """
255
+ if self.active_runner.id != runner_id:
256
+ raise RuntimeError("Active session and requested session do not match.")
257
+ moonshot_api.api_update_metric(self.active_runner.id, metric_name)
258
+
259
+ @exception_handler
260
+ def update_system_prompt(self, runner_id: str, system_prompt: str = ""):
261
+ """
262
+ Update the system prompt for the current session.
263
+
264
+ Args:
265
+ runner_id (str): The unique identifier of the runner.
266
+ system_prompt (str): The new system prompt to be set.
267
+ """
268
+ if self.active_runner.id != runner_id:
269
+ raise RuntimeError("Active session and requested session do not match.")
270
+ moonshot_api.api_update_system_prompt(self.active_runner.id, system_prompt)
271
+
272
+ @exception_handler
273
+ async def send_prompt(
274
+ self, runner_id: str, prompt: SessionPromptDTO, batch_size: int = 5
275
+ ) -> PromptResponseModel | str:
276
+ """
277
+ Send a prompt to the runner for processing.
278
+
279
+ Args:
280
+ runner_id (str): The unique identifier of the runner.
281
+ prompt (SessionPromptDTO): The prompt data transfer object containing user prompt details.
282
+
283
+ Returns:
284
+ The result of the red teaming operation initiated by the prompt.
285
+ """
286
+ if self.active_runner.id != runner_id:
287
+ raise RuntimeError("Active session and requested session do not match.")
288
+
289
+ session_metadata = moonshot_api.api_load_session(self.active_runner.id)
290
+ if session_metadata is None:
291
+ raise RuntimeError(
292
+ f"No session metadata found for runner ID: {self.active_runner.id}"
293
+ )
294
+
295
+ def get_metadata_value(key, default=""):
296
+ return session_metadata.get(key, default)
297
+
298
+ prompt_template = get_metadata_value("prompt_template")
299
+ context_strategy = get_metadata_value("context_strategy")
300
+ num_of_prev_prompts = get_metadata_value("cs_num_of_prev_prompts")
301
+ attack_module = get_metadata_value("attack_module")
302
+ system_prompt = get_metadata_value("system_prompt")
303
+ metric = get_metadata_value("metric")
304
+
305
+ rt_args = {
306
+ "prompt": prompt.user_prompt,
307
+ "system_prompt": system_prompt,
308
+ "context_strategy_info": [
309
+ {
310
+ "context_strategy_id": context_strategy,
311
+ "num_of_prev_prompts": num_of_prev_prompts,
312
+ }
313
+ ]
314
+ if context_strategy
315
+ else [],
316
+ "prompt_template_ids": [prompt_template] if prompt_template else [],
317
+ }
318
+
319
+ if attack_module:
320
+ rt_args["attack_module_id"] = attack_module
321
+ rt_args["metric_ids"] = [metric] if metric else []
322
+ id = await self.auto_red_team_test_manager.schedule_art_task(
323
+ rt_args, self.active_runner, batch_size
324
+ )
325
+ return id
326
+ else:
327
+ response = await self.active_runner.run_red_teaming(
328
+ {"manual_rt_args": rt_args}
329
+ )
330
+ return PromptResponseModel.model_validate(response)
331
+
332
+ @exception_handler
333
+ async def cancel_auto_redteam(self, runner_id: str):
334
+ if self.active_runner.id != runner_id:
335
+ raise RuntimeError("Active session and requested session do not match.")
336
+
337
+ await self.auto_red_team_test_manager.cancel_task(self.active_runner.id)
338
+
339
+ @exception_handler
340
+ async def end_session(self, runner_id: str):
341
+ """
342
+ End the current session.
343
+
344
+ Args:
345
+ runner_id (str): The unique identifier of the runner whose session is to be ended.
346
+ """
347
+ if self.active_runner.id != runner_id:
348
+ raise RuntimeError("Active session and requested session do not match.")
349
+
350
+ self.active_runner.close()
@@ -0,0 +1,41 @@
1
+ import asyncio
2
+ from typing import Any, Callable
3
+ from pydantic import ValidationError
4
+
5
+ class ServiceException(Exception):
6
+ error_code: str
7
+ msg: str
8
+
9
+ def __init__(self, msg: str, method_name: str, error_code: str = 'UnknownSessionError'):
10
+ self.error_code = error_code
11
+ message = f"[ServiceException] {error_code} in {method_name} - {msg}"
12
+ self.msg = message
13
+ super().__init__(message)
14
+
15
+ def exception_handler(func: Callable[..., Any]) -> Callable[..., Any]:
16
+ if asyncio.iscoroutinefunction(func):
17
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
18
+ try:
19
+ return await func(*args, **kwargs)
20
+ except FileNotFoundError as e:
21
+ raise ServiceException(f"A file not found error occurred: {e}", func.__name__, "FileNotFound")
22
+ except ValidationError as e:
23
+ raise ServiceException(f"A validation error occurred: {e}", func.__name__, "ValidationError")
24
+ except ValueError as e:
25
+ raise ServiceException(f"An value error occurred: {e}", func.__name__, "ValueError")
26
+ except Exception as e:
27
+ raise ServiceException(f"An unexpected error occurred: {e}", func.__name__, "UnexpectedError")
28
+ return async_wrapper
29
+ else:
30
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
31
+ try:
32
+ return func(*args, **kwargs)
33
+ except FileNotFoundError as e:
34
+ raise ServiceException(f"A file not found error occurred: {e}", func.__name__, "FileNotFound")
35
+ except ValidationError as e:
36
+ raise ServiceException(f"A validation error occurred: {e}", func.__name__, "ValidationError")
37
+ except ValueError as e:
38
+ raise ServiceException(f"An value error occurred: {e}", func.__name__, "ValueError")
39
+ except Exception as e:
40
+ raise ServiceException(f"An unexpected error occurred: {e}", func.__name__, "UnexpectedError")
41
+ return wrapper