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.
- aiverify_moonshot-0.4.0.dist-info/METADATA +249 -0
- aiverify_moonshot-0.4.0.dist-info/RECORD +163 -0
- aiverify_moonshot-0.4.0.dist-info/WHEEL +4 -0
- aiverify_moonshot-0.4.0.dist-info/licenses/AUTHORS.md +5 -0
- aiverify_moonshot-0.4.0.dist-info/licenses/LICENSE.md +201 -0
- aiverify_moonshot-0.4.0.dist-info/licenses/NOTICES.md +3340 -0
- moonshot/__init__.py +0 -0
- moonshot/__main__.py +198 -0
- moonshot/api.py +155 -0
- moonshot/integrations/__init__.py +0 -0
- moonshot/integrations/cli/__init__.py +0 -0
- moonshot/integrations/cli/__main__.py +25 -0
- moonshot/integrations/cli/active_session_cfg.py +1 -0
- moonshot/integrations/cli/benchmark/__init__.py +0 -0
- moonshot/integrations/cli/benchmark/benchmark.py +186 -0
- moonshot/integrations/cli/benchmark/cookbook.py +545 -0
- moonshot/integrations/cli/benchmark/datasets.py +164 -0
- moonshot/integrations/cli/benchmark/metrics.py +141 -0
- moonshot/integrations/cli/benchmark/recipe.py +598 -0
- moonshot/integrations/cli/benchmark/result.py +216 -0
- moonshot/integrations/cli/benchmark/run.py +140 -0
- moonshot/integrations/cli/benchmark/runner.py +174 -0
- moonshot/integrations/cli/cli.py +64 -0
- moonshot/integrations/cli/common/__init__.py +0 -0
- moonshot/integrations/cli/common/common.py +72 -0
- moonshot/integrations/cli/common/connectors.py +325 -0
- moonshot/integrations/cli/common/display_helper.py +42 -0
- moonshot/integrations/cli/common/prompt_template.py +94 -0
- moonshot/integrations/cli/initialisation/__init__.py +0 -0
- moonshot/integrations/cli/initialisation/initialisation.py +14 -0
- moonshot/integrations/cli/redteam/__init__.py +0 -0
- moonshot/integrations/cli/redteam/attack_module.py +70 -0
- moonshot/integrations/cli/redteam/context_strategy.py +147 -0
- moonshot/integrations/cli/redteam/prompt_template.py +67 -0
- moonshot/integrations/cli/redteam/redteam.py +90 -0
- moonshot/integrations/cli/redteam/session.py +467 -0
- moonshot/integrations/web_api/.env.dev +7 -0
- moonshot/integrations/web_api/__init__.py +0 -0
- moonshot/integrations/web_api/__main__.py +56 -0
- moonshot/integrations/web_api/app.py +125 -0
- moonshot/integrations/web_api/container.py +146 -0
- moonshot/integrations/web_api/log/.gitkeep +0 -0
- moonshot/integrations/web_api/logging_conf.py +114 -0
- moonshot/integrations/web_api/routes/__init__.py +0 -0
- moonshot/integrations/web_api/routes/attack_modules.py +66 -0
- moonshot/integrations/web_api/routes/benchmark.py +116 -0
- moonshot/integrations/web_api/routes/benchmark_result.py +175 -0
- moonshot/integrations/web_api/routes/context_strategy.py +129 -0
- moonshot/integrations/web_api/routes/cookbook.py +225 -0
- moonshot/integrations/web_api/routes/dataset.py +120 -0
- moonshot/integrations/web_api/routes/endpoint.py +282 -0
- moonshot/integrations/web_api/routes/metric.py +78 -0
- moonshot/integrations/web_api/routes/prompt_template.py +128 -0
- moonshot/integrations/web_api/routes/recipe.py +219 -0
- moonshot/integrations/web_api/routes/redteam.py +609 -0
- moonshot/integrations/web_api/routes/runner.py +239 -0
- moonshot/integrations/web_api/schemas/__init__.py +0 -0
- moonshot/integrations/web_api/schemas/benchmark_runner_dto.py +13 -0
- moonshot/integrations/web_api/schemas/cookbook_create_dto.py +19 -0
- moonshot/integrations/web_api/schemas/cookbook_response_model.py +9 -0
- moonshot/integrations/web_api/schemas/dataset_response_dto.py +9 -0
- moonshot/integrations/web_api/schemas/endpoint_create_dto.py +21 -0
- moonshot/integrations/web_api/schemas/endpoint_response_model.py +11 -0
- moonshot/integrations/web_api/schemas/prompt_response_model.py +14 -0
- moonshot/integrations/web_api/schemas/prompt_template_response_model.py +10 -0
- moonshot/integrations/web_api/schemas/recipe_create_dto.py +32 -0
- moonshot/integrations/web_api/schemas/recipe_response_model.py +7 -0
- moonshot/integrations/web_api/schemas/session_create_dto.py +16 -0
- moonshot/integrations/web_api/schemas/session_prompt_dto.py +7 -0
- moonshot/integrations/web_api/schemas/session_response_model.py +38 -0
- moonshot/integrations/web_api/services/__init__.py +0 -0
- moonshot/integrations/web_api/services/attack_module_service.py +34 -0
- moonshot/integrations/web_api/services/auto_red_team_test_manager.py +86 -0
- moonshot/integrations/web_api/services/auto_red_team_test_state.py +57 -0
- moonshot/integrations/web_api/services/base_service.py +8 -0
- moonshot/integrations/web_api/services/benchmark_result_service.py +25 -0
- moonshot/integrations/web_api/services/benchmark_test_manager.py +106 -0
- moonshot/integrations/web_api/services/benchmark_test_state.py +56 -0
- moonshot/integrations/web_api/services/benchmarking_service.py +31 -0
- moonshot/integrations/web_api/services/context_strategy_service.py +22 -0
- moonshot/integrations/web_api/services/cookbook_service.py +194 -0
- moonshot/integrations/web_api/services/dataset_service.py +20 -0
- moonshot/integrations/web_api/services/endpoint_service.py +65 -0
- moonshot/integrations/web_api/services/metric_service.py +14 -0
- moonshot/integrations/web_api/services/prompt_template_service.py +39 -0
- moonshot/integrations/web_api/services/recipe_service.py +155 -0
- moonshot/integrations/web_api/services/runner_service.py +147 -0
- moonshot/integrations/web_api/services/session_service.py +350 -0
- moonshot/integrations/web_api/services/utils/exceptions_handler.py +41 -0
- moonshot/integrations/web_api/services/utils/results_formatter.py +47 -0
- moonshot/integrations/web_api/status_updater/interface/benchmark_progress_callback.py +14 -0
- moonshot/integrations/web_api/status_updater/interface/redteam_progress_callback.py +14 -0
- moonshot/integrations/web_api/status_updater/moonshot_ui_webhook.py +72 -0
- moonshot/integrations/web_api/types/types.py +99 -0
- moonshot/src/__init__.py +0 -0
- moonshot/src/api/__init__.py +0 -0
- moonshot/src/api/api_connector.py +58 -0
- moonshot/src/api/api_connector_endpoint.py +162 -0
- moonshot/src/api/api_context_strategy.py +57 -0
- moonshot/src/api/api_cookbook.py +160 -0
- moonshot/src/api/api_dataset.py +46 -0
- moonshot/src/api/api_environment_variables.py +17 -0
- moonshot/src/api/api_metrics.py +51 -0
- moonshot/src/api/api_prompt_template.py +43 -0
- moonshot/src/api/api_recipe.py +182 -0
- moonshot/src/api/api_red_teaming.py +59 -0
- moonshot/src/api/api_result.py +84 -0
- moonshot/src/api/api_run.py +74 -0
- moonshot/src/api/api_runner.py +132 -0
- moonshot/src/api/api_session.py +290 -0
- moonshot/src/configs/__init__.py +0 -0
- moonshot/src/configs/env_variables.py +187 -0
- moonshot/src/connectors/__init__.py +0 -0
- moonshot/src/connectors/connector.py +327 -0
- moonshot/src/connectors/connector_prompt_arguments.py +17 -0
- moonshot/src/connectors_endpoints/__init__.py +0 -0
- moonshot/src/connectors_endpoints/connector_endpoint.py +211 -0
- moonshot/src/connectors_endpoints/connector_endpoint_arguments.py +54 -0
- moonshot/src/cookbooks/__init__.py +0 -0
- moonshot/src/cookbooks/cookbook.py +225 -0
- moonshot/src/cookbooks/cookbook_arguments.py +34 -0
- moonshot/src/datasets/__init__.py +0 -0
- moonshot/src/datasets/dataset.py +255 -0
- moonshot/src/datasets/dataset_arguments.py +50 -0
- moonshot/src/metrics/__init__.py +0 -0
- moonshot/src/metrics/metric.py +192 -0
- moonshot/src/metrics/metric_interface.py +95 -0
- moonshot/src/prompt_templates/__init__.py +0 -0
- moonshot/src/prompt_templates/prompt_template.py +103 -0
- moonshot/src/recipes/__init__.py +0 -0
- moonshot/src/recipes/recipe.py +340 -0
- moonshot/src/recipes/recipe_arguments.py +111 -0
- moonshot/src/redteaming/__init__.py +0 -0
- moonshot/src/redteaming/attack/__init__.py +0 -0
- moonshot/src/redteaming/attack/attack_module.py +618 -0
- moonshot/src/redteaming/attack/attack_module_arguments.py +44 -0
- moonshot/src/redteaming/attack/context_strategy.py +131 -0
- moonshot/src/redteaming/context_strategy/__init__.py +0 -0
- moonshot/src/redteaming/context_strategy/context_strategy_interface.py +46 -0
- moonshot/src/redteaming/session/__init__.py +0 -0
- moonshot/src/redteaming/session/chat.py +209 -0
- moonshot/src/redteaming/session/red_teaming_progress.py +128 -0
- moonshot/src/redteaming/session/red_teaming_type.py +6 -0
- moonshot/src/redteaming/session/session.py +775 -0
- moonshot/src/results/__init__.py +0 -0
- moonshot/src/results/result.py +119 -0
- moonshot/src/results/result_arguments.py +44 -0
- moonshot/src/runners/__init__.py +0 -0
- moonshot/src/runners/runner.py +476 -0
- moonshot/src/runners/runner_arguments.py +46 -0
- moonshot/src/runners/runner_type.py +6 -0
- moonshot/src/runs/__init__.py +0 -0
- moonshot/src/runs/run.py +344 -0
- moonshot/src/runs/run_arguments.py +162 -0
- moonshot/src/runs/run_progress.py +145 -0
- moonshot/src/runs/run_status.py +10 -0
- moonshot/src/storage/__init__.py +0 -0
- moonshot/src/storage/db_interface.py +128 -0
- moonshot/src/storage/io_interface.py +31 -0
- moonshot/src/storage/storage.py +525 -0
- moonshot/src/utils/__init__.py +0 -0
- moonshot/src/utils/import_modules.py +96 -0
- 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
|