aiverify-moonshot 0.4.1__py3-none-any.whl → 0.4.2__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.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/METADATA +2 -2
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/RECORD +59 -49
- moonshot/__main__.py +77 -35
- moonshot/api.py +14 -0
- moonshot/integrations/cli/benchmark/benchmark.py +29 -13
- moonshot/integrations/cli/benchmark/cookbook.py +36 -6
- moonshot/integrations/cli/benchmark/datasets.py +33 -3
- moonshot/integrations/cli/benchmark/metrics.py +33 -3
- moonshot/integrations/cli/benchmark/recipe.py +36 -6
- moonshot/integrations/cli/benchmark/result.py +33 -3
- moonshot/integrations/cli/benchmark/run.py +34 -3
- moonshot/integrations/cli/common/common.py +12 -6
- moonshot/integrations/cli/common/connectors.py +73 -9
- moonshot/integrations/cli/common/prompt_template.py +38 -3
- moonshot/integrations/cli/redteam/attack_module.py +75 -24
- moonshot/integrations/cli/redteam/context_strategy.py +77 -23
- moonshot/integrations/cli/redteam/prompt_template.py +1 -1
- moonshot/integrations/cli/redteam/redteam.py +52 -6
- moonshot/integrations/cli/redteam/session.py +539 -43
- moonshot/integrations/web_api/__main__.py +2 -0
- moonshot/integrations/web_api/app.py +6 -6
- moonshot/integrations/web_api/container.py +12 -2
- moonshot/integrations/web_api/routes/bookmark.py +173 -0
- moonshot/integrations/web_api/schemas/bookmark_create_dto.py +13 -0
- moonshot/integrations/web_api/services/bookmark_service.py +90 -0
- moonshot/integrations/web_api/services/utils/file_manager.py +52 -0
- moonshot/integrations/web_api/status_updater/moonshot_ui_webhook.py +0 -1
- moonshot/integrations/web_api/temp/.gitkeep +0 -0
- moonshot/src/api/api_bookmark.py +95 -0
- moonshot/src/api/api_connector_endpoint.py +1 -1
- moonshot/src/api/api_context_strategy.py +2 -2
- moonshot/src/api/api_session.py +1 -1
- moonshot/src/bookmark/bookmark.py +257 -0
- moonshot/src/bookmark/bookmark_arguments.py +38 -0
- moonshot/src/configs/env_variables.py +12 -2
- moonshot/src/connectors/connector.py +15 -7
- moonshot/src/connectors_endpoints/connector_endpoint.py +65 -49
- moonshot/src/cookbooks/cookbook.py +57 -37
- moonshot/src/datasets/dataset.py +9 -5
- moonshot/src/metrics/metric.py +8 -4
- moonshot/src/metrics/metric_interface.py +8 -2
- moonshot/src/prompt_templates/prompt_template.py +5 -1
- moonshot/src/recipes/recipe.py +38 -25
- moonshot/src/redteaming/attack/attack_module.py +18 -8
- moonshot/src/redteaming/attack/context_strategy.py +6 -2
- moonshot/src/redteaming/session/session.py +15 -11
- moonshot/src/results/result.py +7 -3
- moonshot/src/runners/runner.py +65 -42
- moonshot/src/runs/run.py +15 -11
- moonshot/src/runs/run_progress.py +7 -3
- moonshot/src/storage/db_interface.py +14 -0
- moonshot/src/storage/storage.py +33 -2
- moonshot/src/utils/find_feature.py +45 -0
- moonshot/src/utils/log.py +66 -0
- moonshot/src/utils/timeit.py +8 -1
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/WHEEL +0 -0
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/AUTHORS.md +0 -0
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/LICENSE.md +0 -0
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/NOTICES.md +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from moonshot.src.bookmark.bookmark_arguments import BookmarkArguments
|
|
4
|
+
from moonshot.src.configs.env_variables import EnvVariables
|
|
5
|
+
from moonshot.src.storage.storage import Storage
|
|
6
|
+
from moonshot.src.utils.log import configure_logger
|
|
7
|
+
|
|
8
|
+
# Create a logger for this module
|
|
9
|
+
logger = configure_logger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Bookmark:
|
|
13
|
+
_instance = None
|
|
14
|
+
|
|
15
|
+
def __new__(cls, db_name="bookmark"):
|
|
16
|
+
"""
|
|
17
|
+
Create a new instance of the Bookmark class or return the existing instance.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
db_name (str): The name of the database.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Bookmark: The singleton instance of the Bookmark class.
|
|
24
|
+
"""
|
|
25
|
+
if cls._instance is None:
|
|
26
|
+
cls._instance = super(Bookmark, cls).__new__(cls)
|
|
27
|
+
cls._instance.__init_instance(db_name)
|
|
28
|
+
return cls._instance
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_instance(cls, db_name="bookmark"):
|
|
32
|
+
"""
|
|
33
|
+
Get the singleton instance of the Bookmark class.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
db_name (str): The name of the database.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Bookmark: The singleton instance of the Bookmark class.
|
|
40
|
+
"""
|
|
41
|
+
if cls._instance is None:
|
|
42
|
+
cls._instance = super(Bookmark, cls).__new__(cls)
|
|
43
|
+
cls._instance.__init_instance(db_name)
|
|
44
|
+
return cls._instance
|
|
45
|
+
|
|
46
|
+
sql_create_bookmark_table = """
|
|
47
|
+
CREATE TABLE IF NOT EXISTS bookmark (
|
|
48
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
49
|
+
name TEXT NOT NULL UNIQUE,
|
|
50
|
+
prompt TEXT NOT NULL,
|
|
51
|
+
prepared_prompt TEXT NOT NULL,
|
|
52
|
+
response TEXT NOT NULL,
|
|
53
|
+
context_strategy TEXT,
|
|
54
|
+
prompt_template TEXT,
|
|
55
|
+
attack_module TEXT,
|
|
56
|
+
metric TEXT,
|
|
57
|
+
bookmark_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
58
|
+
);
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
sql_insert_bookmark_record = """
|
|
62
|
+
INSERT INTO bookmark (
|
|
63
|
+
name, prompt, prepared_prompt, response, context_strategy, prompt_template, attack_module,
|
|
64
|
+
metric, bookmark_time)
|
|
65
|
+
VALUES (?,?,?,?,?,?,?,?,?);
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
sql_select_bookmarks_record = """
|
|
69
|
+
SELECT * FROM bookmark;
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
sql_select_bookmark_record = """
|
|
73
|
+
SELECT * FROM bookmark WHERE name = ? ;
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
sql_delete_bookmark_records = """
|
|
77
|
+
DELETE FROM bookmark;
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init_instance(self, db_name) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Initialize the database instance for the Bookmark class.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
db_name (str): The name of the database.
|
|
86
|
+
"""
|
|
87
|
+
self.db_instance = Storage.create_database_connection(
|
|
88
|
+
EnvVariables.BOOKMARKS.name, db_name, "db"
|
|
89
|
+
)
|
|
90
|
+
Storage.create_database_table(
|
|
91
|
+
self.db_instance, Bookmark.sql_create_bookmark_table
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def add_bookmark(self, bookmark: BookmarkArguments) -> dict:
|
|
95
|
+
"""
|
|
96
|
+
Add a new bookmark to the database and return the success status.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
bookmark (BookmarkArguments): The bookmark data to add.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
bool: True if the bookmark was added successfully, False otherwise.
|
|
103
|
+
"""
|
|
104
|
+
bookmark.bookmark_time = datetime.now().replace(microsecond=0).isoformat(" ")
|
|
105
|
+
|
|
106
|
+
data = (
|
|
107
|
+
bookmark.name,
|
|
108
|
+
bookmark.prompt,
|
|
109
|
+
bookmark.prepared_prompt,
|
|
110
|
+
bookmark.response,
|
|
111
|
+
bookmark.context_strategy,
|
|
112
|
+
bookmark.prompt_template,
|
|
113
|
+
bookmark.attack_module,
|
|
114
|
+
bookmark.metric,
|
|
115
|
+
bookmark.bookmark_time,
|
|
116
|
+
)
|
|
117
|
+
try:
|
|
118
|
+
results = Storage.create_database_record(
|
|
119
|
+
self.db_instance, data, Bookmark.sql_insert_bookmark_record
|
|
120
|
+
)
|
|
121
|
+
if results is not None:
|
|
122
|
+
return {"success": True, "message": "Bookmark added successfully."}
|
|
123
|
+
else:
|
|
124
|
+
raise Exception("Error inserting record into database.")
|
|
125
|
+
except Exception as e:
|
|
126
|
+
error_message = f"Failed to add bookmark record: {e}"
|
|
127
|
+
return {"success": False, "message": error_message}
|
|
128
|
+
|
|
129
|
+
def get_all_bookmarks(self) -> list[dict]:
|
|
130
|
+
"""
|
|
131
|
+
Retrieve all bookmarks from the database.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
list[dict]: A list of all bookmarks as dictionaries.
|
|
135
|
+
"""
|
|
136
|
+
list_of_bookmarks_tuples = Storage.read_database_records(
|
|
137
|
+
self.db_instance,
|
|
138
|
+
Bookmark.sql_select_bookmarks_record,
|
|
139
|
+
)
|
|
140
|
+
if list_of_bookmarks_tuples:
|
|
141
|
+
list_of_bookmarks = [
|
|
142
|
+
BookmarkArguments.from_tuple_to_dict(bookmark_tuple)
|
|
143
|
+
for bookmark_tuple in list_of_bookmarks_tuples
|
|
144
|
+
]
|
|
145
|
+
else:
|
|
146
|
+
list_of_bookmarks = []
|
|
147
|
+
return list_of_bookmarks
|
|
148
|
+
|
|
149
|
+
def get_bookmark(self, bookmark_name: str) -> dict:
|
|
150
|
+
"""
|
|
151
|
+
Retrieve a bookmark by its unique name.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
bookmark_name (int): The unique name for the bookmark.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
dict: The bookmark information as a dictionary.
|
|
158
|
+
|
|
159
|
+
Raises:
|
|
160
|
+
RuntimeError: If the bookmark cannot be found.
|
|
161
|
+
"""
|
|
162
|
+
if bookmark_name is not None:
|
|
163
|
+
bookmark_info = Storage.read_database_record(
|
|
164
|
+
self.db_instance, (bookmark_name,), Bookmark.sql_select_bookmark_record
|
|
165
|
+
)
|
|
166
|
+
if bookmark_info is not None:
|
|
167
|
+
return BookmarkArguments.from_tuple_to_dict(bookmark_info)
|
|
168
|
+
else:
|
|
169
|
+
raise RuntimeError(
|
|
170
|
+
f"[Bookmark] No record found for bookmark name {bookmark_name}"
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
raise RuntimeError(f"[Bookmark] Invalid bookmark name: {bookmark_name}")
|
|
174
|
+
|
|
175
|
+
def delete_bookmark(self, bookmark_name: str) -> dict:
|
|
176
|
+
"""
|
|
177
|
+
Delete a bookmark by its unique name.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
bookmark_name (str): The unique name for the bookmark to be deleted.
|
|
181
|
+
"""
|
|
182
|
+
if bookmark_name is not None:
|
|
183
|
+
try:
|
|
184
|
+
sql_delete_bookmark_record = f"""
|
|
185
|
+
DELETE FROM bookmark WHERE name = '{bookmark_name}';
|
|
186
|
+
"""
|
|
187
|
+
Storage.delete_database_record_in_table(
|
|
188
|
+
self.db_instance, sql_delete_bookmark_record
|
|
189
|
+
)
|
|
190
|
+
return {"success": True, "message": "Bookmark record deleted."}
|
|
191
|
+
except Exception as e:
|
|
192
|
+
error_message = f"Failed to delete bookmark record: {e}"
|
|
193
|
+
return {"success": False, "message": error_message}
|
|
194
|
+
else:
|
|
195
|
+
error_message = f"[Bookmark] Invalid bookmark name: {bookmark_name}"
|
|
196
|
+
return {"success": False, "message": error_message}
|
|
197
|
+
|
|
198
|
+
def delete_all_bookmark(self) -> dict:
|
|
199
|
+
"""
|
|
200
|
+
Delete all bookmarks from the database and return the operation result.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
dict: A dictionary with 'success' status and 'message' containing an error message if failed.
|
|
204
|
+
"""
|
|
205
|
+
try:
|
|
206
|
+
Storage.delete_database_record_in_table(
|
|
207
|
+
self.db_instance, Bookmark.sql_delete_bookmark_records
|
|
208
|
+
)
|
|
209
|
+
return {"success": True, "message": "All bookmark records deleted."}
|
|
210
|
+
except Exception as e:
|
|
211
|
+
error_message = f"Failed to delete all bookmark records: {e}"
|
|
212
|
+
return {"success": False, "message": error_message}
|
|
213
|
+
|
|
214
|
+
def export_bookmarks(self, export_file_name: str = "bookmarks") -> str:
|
|
215
|
+
"""
|
|
216
|
+
Export all bookmarks to a JSON file.
|
|
217
|
+
|
|
218
|
+
This method retrieves all bookmarks from the database, converts them to a JSON format,
|
|
219
|
+
and writes them to a file in the 'moonshot-data/bookmark' directory with the provided file name.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
export_file_name (str): The base name of the file to export the bookmarks to.
|
|
223
|
+
The '.json' extension will be appended to this base name.
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
str: The path to the exported JSON file containing the bookmarks.
|
|
227
|
+
"""
|
|
228
|
+
list_of_bookmarks_tuples = Storage.read_database_records(
|
|
229
|
+
self.db_instance,
|
|
230
|
+
Bookmark.sql_select_bookmarks_record,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
if list_of_bookmarks_tuples is not None:
|
|
234
|
+
bookmarks_json = [
|
|
235
|
+
BookmarkArguments.from_tuple_to_dict(bookmark_tuple)
|
|
236
|
+
for bookmark_tuple in list_of_bookmarks_tuples
|
|
237
|
+
]
|
|
238
|
+
else:
|
|
239
|
+
bookmarks_json = []
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
return Storage.create_object(
|
|
243
|
+
EnvVariables.BOOKMARKS.name,
|
|
244
|
+
export_file_name,
|
|
245
|
+
{"bookmarks": bookmarks_json},
|
|
246
|
+
"json",
|
|
247
|
+
)
|
|
248
|
+
except Exception as e:
|
|
249
|
+
logger.error(f"Failed to export bookmarks - {str(e)}.")
|
|
250
|
+
raise e
|
|
251
|
+
|
|
252
|
+
def close(self) -> None:
|
|
253
|
+
"""
|
|
254
|
+
Close the database connection.
|
|
255
|
+
"""
|
|
256
|
+
if self.db_instance:
|
|
257
|
+
Storage.close_database_connection(self.db_instance)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BookmarkArguments(BaseModel):
|
|
7
|
+
name: str = Field(min_length=1)
|
|
8
|
+
prompt: str = Field(min_length=1)
|
|
9
|
+
prepared_prompt: str = Field(min_length=1)
|
|
10
|
+
response: str = Field(min_length=1)
|
|
11
|
+
context_strategy: str
|
|
12
|
+
prompt_template: str
|
|
13
|
+
attack_module: str
|
|
14
|
+
metric: str
|
|
15
|
+
bookmark_time: str
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def from_tuple_to_dict(cls, values: tuple) -> dict:
|
|
19
|
+
"""
|
|
20
|
+
Creates a dictionary from a tuple of values representing BookmarkArguments fields.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
values (tuple): A tuple containing the fields of BookmarkArguments in order.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
dict: A dictionary representing the BookmarkArguments.
|
|
27
|
+
"""
|
|
28
|
+
return {
|
|
29
|
+
"name": values[1],
|
|
30
|
+
"prompt": values[2],
|
|
31
|
+
"prepared_prompt": values[3],
|
|
32
|
+
"response": values[4],
|
|
33
|
+
"context_strategy": values[5],
|
|
34
|
+
"prompt_template": values[6],
|
|
35
|
+
"attack_module": values[7],
|
|
36
|
+
"metric": values[8],
|
|
37
|
+
"bookmark_time": values[9],
|
|
38
|
+
}
|
|
@@ -2,11 +2,17 @@ import importlib.resources
|
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
+
from moonshot.src.utils.log import configure_logger
|
|
6
|
+
|
|
7
|
+
# Create a logger for this module
|
|
8
|
+
logger = configure_logger(__name__)
|
|
9
|
+
|
|
5
10
|
__app_name__ = "moonshot"
|
|
6
11
|
|
|
7
12
|
|
|
8
13
|
class EnvVariables(Enum):
|
|
9
14
|
ATTACK_MODULES = "ATTACK_MODULES"
|
|
15
|
+
BOOKMARKS = "BOOKMARKS"
|
|
10
16
|
CONNECTORS = "CONNECTORS"
|
|
11
17
|
CONNECTORS_ENDPOINTS = "CONNECTORS_ENDPOINTS"
|
|
12
18
|
CONTEXT_STRATEGY = "CONTEXT_STRATEGY"
|
|
@@ -31,6 +37,10 @@ class EnvironmentVars:
|
|
|
31
37
|
env_vars.get(EnvVariables.ATTACK_MODULES.value),
|
|
32
38
|
str(importlib.resources.files(__app_name__).joinpath("data/attack-modules")),
|
|
33
39
|
]
|
|
40
|
+
BOOKMARKS = [
|
|
41
|
+
env_vars.get(EnvVariables.BOOKMARKS.value),
|
|
42
|
+
str(importlib.resources.files(__app_name__).joinpath("data/generated-outputs/bookmarks")),
|
|
43
|
+
]
|
|
34
44
|
CONNECTORS = [
|
|
35
45
|
env_vars.get(EnvVariables.CONNECTORS.value),
|
|
36
46
|
str(importlib.resources.files(__app_name__).joinpath("data/connectors")),
|
|
@@ -133,14 +143,14 @@ class EnvironmentVars:
|
|
|
133
143
|
if given_path.exists():
|
|
134
144
|
EnvironmentVars.__dict__[key][0] = str(given_path)
|
|
135
145
|
else:
|
|
136
|
-
|
|
146
|
+
logger.warning(
|
|
137
147
|
f"Unable to set {key}. The provided path {given_path} does not exist. ",
|
|
138
148
|
"The stock set will be used.",
|
|
139
149
|
)
|
|
140
150
|
else:
|
|
141
151
|
unset_keys.append(key)
|
|
142
152
|
if unset_keys:
|
|
143
|
-
|
|
153
|
+
logger.warning(
|
|
144
154
|
f"Unable to retrieve the following environment variables: {unset_keys}. The stock set will be used."
|
|
145
155
|
)
|
|
146
156
|
|
|
@@ -15,6 +15,10 @@ from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
|
|
|
15
15
|
)
|
|
16
16
|
from moonshot.src.storage.storage import Storage
|
|
17
17
|
from moonshot.src.utils.import_modules import get_instance
|
|
18
|
+
from moonshot.src.utils.log import configure_logger
|
|
19
|
+
|
|
20
|
+
# Create a logger for this module
|
|
21
|
+
logger = configure_logger(__name__)
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
def perform_retry(func):
|
|
@@ -42,13 +46,15 @@ def perform_retry(func):
|
|
|
42
46
|
try:
|
|
43
47
|
return await func(self, *args, **kwargs)
|
|
44
48
|
except Exception as exc:
|
|
45
|
-
|
|
49
|
+
logger.warning(f"Operation failed. {str(exc)} - Retrying...")
|
|
46
50
|
|
|
47
51
|
# Perform retry
|
|
48
52
|
retry_count += 1
|
|
49
53
|
if retry_count <= self.retries_times:
|
|
50
54
|
delay = base_delay * (2**retry_count)
|
|
51
|
-
|
|
55
|
+
logger.warning(
|
|
56
|
+
f"Attempt {retry_count}, Retrying in {delay} seconds..."
|
|
57
|
+
)
|
|
52
58
|
await sleep(delay)
|
|
53
59
|
# Raise an exception
|
|
54
60
|
raise ConnectionError("Failed to get response.")
|
|
@@ -228,7 +234,7 @@ class Connector:
|
|
|
228
234
|
return Connector.load(ep_args)
|
|
229
235
|
|
|
230
236
|
except Exception as e:
|
|
231
|
-
|
|
237
|
+
logger.error(f"Failed to create connector: {str(e)}")
|
|
232
238
|
raise e
|
|
233
239
|
|
|
234
240
|
@staticmethod
|
|
@@ -255,7 +261,7 @@ class Connector:
|
|
|
255
261
|
]
|
|
256
262
|
|
|
257
263
|
except Exception as e:
|
|
258
|
-
|
|
264
|
+
logger.error(f"Failed to get available connectors: {str(e)}")
|
|
259
265
|
raise e
|
|
260
266
|
|
|
261
267
|
@staticmethod
|
|
@@ -292,14 +298,16 @@ class Connector:
|
|
|
292
298
|
Exception: If there is an error during prediction.
|
|
293
299
|
"""
|
|
294
300
|
try:
|
|
295
|
-
|
|
301
|
+
logger.info(
|
|
302
|
+
f"Predicting prompt {generated_prompt.prompt_index} [{connector.id}]"
|
|
303
|
+
)
|
|
296
304
|
|
|
297
305
|
start_time = time.perf_counter()
|
|
298
306
|
generated_prompt.predicted_results = await connector.get_response(
|
|
299
307
|
generated_prompt.prompt
|
|
300
308
|
)
|
|
301
309
|
generated_prompt.duration = time.perf_counter() - start_time
|
|
302
|
-
|
|
310
|
+
logger.debug(
|
|
303
311
|
f"[Prompt {generated_prompt.prompt_index}] took {generated_prompt.duration:.4f}s"
|
|
304
312
|
)
|
|
305
313
|
|
|
@@ -311,7 +319,7 @@ class Connector:
|
|
|
311
319
|
return generated_prompt
|
|
312
320
|
|
|
313
321
|
except Exception as e:
|
|
314
|
-
|
|
322
|
+
logger.error(f"Failed to get prediction: {str(e)}")
|
|
315
323
|
raise e
|
|
316
324
|
|
|
317
325
|
def set_system_prompt(self, system_prompt: str) -> None:
|
|
@@ -8,33 +8,39 @@ from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
|
|
|
8
8
|
ConnectorEndpointArguments,
|
|
9
9
|
)
|
|
10
10
|
from moonshot.src.storage.storage import Storage
|
|
11
|
+
from moonshot.src.utils.log import configure_logger
|
|
12
|
+
|
|
13
|
+
# Create a logger for this module
|
|
14
|
+
logger = configure_logger(__name__)
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
class ConnectorEndpoint:
|
|
14
18
|
@staticmethod
|
|
15
19
|
def create(ep_args: ConnectorEndpointArguments) -> str:
|
|
16
20
|
"""
|
|
17
|
-
Creates a new connector endpoint.
|
|
21
|
+
Creates a new connector endpoint and stores its details as a JSON object.
|
|
22
|
+
|
|
23
|
+
This method accepts a ConnectorEndpointArguments object, generates a unique slugified ID from the endpoint's
|
|
24
|
+
name, and stores the endpoint's details in a JSON file within a specified directory.
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
successful, the unique ID of the new endpoint is returned. If any error arises during the process, an exception
|
|
23
|
-
is raised and the error message is logged.
|
|
26
|
+
The directory path is determined by the `EnvVariables.CONNECTORS_ENDPOINTS` environment variable.
|
|
27
|
+
Upon successful creation, the method returns the unique ID of the endpoint.
|
|
28
|
+
If an error occurs during the creation process, the method raises an exception and logs the error message.
|
|
24
29
|
|
|
25
30
|
Args:
|
|
26
|
-
ep_args (ConnectorEndpointArguments):
|
|
31
|
+
ep_args (ConnectorEndpointArguments): The details of the endpoint to be created,
|
|
32
|
+
encapsulated in a ConnectorEndpointArguments object.
|
|
27
33
|
|
|
28
34
|
Returns:
|
|
29
|
-
str: The unique ID of the newly created endpoint.
|
|
35
|
+
str: The unique ID of the newly created endpoint, derived from slugifying the endpoint's name.
|
|
30
36
|
|
|
31
37
|
Raises:
|
|
32
|
-
Exception: If
|
|
38
|
+
Exception: If an error occurs during the creation process, including issues with storing the endpoint's
|
|
39
|
+
details.
|
|
33
40
|
"""
|
|
34
41
|
try:
|
|
35
42
|
ep_id = slugify(ep_args.name, lowercase=True)
|
|
36
43
|
ep_info = {
|
|
37
|
-
"id": ep_id,
|
|
38
44
|
"name": ep_args.name,
|
|
39
45
|
"connector_type": ep_args.connector_type,
|
|
40
46
|
"uri": ep_args.uri,
|
|
@@ -51,59 +57,63 @@ class ConnectorEndpoint:
|
|
|
51
57
|
return ep_id
|
|
52
58
|
|
|
53
59
|
except Exception as e:
|
|
54
|
-
|
|
60
|
+
logger.error(f"Failed to create endpoint: {str(e)}")
|
|
55
61
|
raise e
|
|
56
62
|
|
|
57
63
|
@staticmethod
|
|
58
64
|
@validate_call
|
|
59
65
|
def read(ep_id: str) -> ConnectorEndpointArguments:
|
|
60
66
|
"""
|
|
61
|
-
|
|
67
|
+
Retrieves the details of a specified endpoint by its ID.
|
|
62
68
|
|
|
63
|
-
This method
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
error
|
|
69
|
+
This method searches for the endpoint's corresponding JSON file within the directory defined by the
|
|
70
|
+
`EnvVariables.CONNECTORS_ENDPOINTS` environment variable. It then constructs and returns a
|
|
71
|
+
ConnectorEndpointArguments object populated with the endpoint's details. If the endpoint ID is not found or
|
|
72
|
+
any other error occurs, an exception is raised with an appropriate error message.
|
|
67
73
|
|
|
68
74
|
Args:
|
|
69
|
-
ep_id (str): The unique
|
|
75
|
+
ep_id (str): The unique identifier of the endpoint whose details are to be retrieved.
|
|
70
76
|
|
|
71
77
|
Returns:
|
|
72
|
-
ConnectorEndpointArguments: An
|
|
78
|
+
ConnectorEndpointArguments: An instance filled with the endpoint's details.
|
|
73
79
|
|
|
74
80
|
Raises:
|
|
75
|
-
|
|
81
|
+
RuntimeError: If the endpoint ID is empty or the specified endpoint does not exist.
|
|
82
|
+
Exception: For any issues encountered during the file reading or data parsing process.
|
|
76
83
|
"""
|
|
77
84
|
try:
|
|
78
|
-
if ep_id:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
raise RuntimeError("
|
|
85
|
+
if not ep_id:
|
|
86
|
+
raise RuntimeError("Connector Endpoint ID is empty.")
|
|
87
|
+
|
|
88
|
+
endpoint_details = ConnectorEndpoint._read_endpoint(ep_id)
|
|
89
|
+
if not endpoint_details:
|
|
90
|
+
raise RuntimeError(f"Endpoint with ID '{ep_id}' does not exist.")
|
|
91
|
+
|
|
92
|
+
return ConnectorEndpointArguments(**endpoint_details)
|
|
84
93
|
|
|
85
94
|
except Exception as e:
|
|
86
|
-
|
|
95
|
+
logger.error(f"Failed to read endpoint: {str(e)}")
|
|
87
96
|
raise e
|
|
88
97
|
|
|
89
98
|
@staticmethod
|
|
90
99
|
def _read_endpoint(ep_id: str) -> dict:
|
|
91
100
|
"""
|
|
92
|
-
|
|
101
|
+
Retrieves the endpoint's information from a JSON file, including its creation datetime.
|
|
93
102
|
|
|
94
|
-
This method
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
method.
|
|
103
|
+
This internal method is designed to fetch the details of a specific endpoint by its ID. It searches for the
|
|
104
|
+
corresponding JSON file within the directory specified by `EnvVariables.CONNECTORS_ENDPOINTS`. The method
|
|
105
|
+
returns a dictionary containing the endpoint's information, enriched with the creation datetime. Errors
|
|
106
|
+
encountered during this process are managed by the method that invokes this one.
|
|
98
107
|
|
|
99
108
|
Args:
|
|
100
|
-
ep_id (str): The unique identifier of the endpoint
|
|
109
|
+
ep_id (str): The unique identifier of the endpoint whose information is being retrieved.
|
|
101
110
|
|
|
102
111
|
Returns:
|
|
103
|
-
dict: A dictionary
|
|
112
|
+
dict: A dictionary with the endpoint's information, including its creation datetime.
|
|
104
113
|
"""
|
|
105
|
-
connector_endpoint_info =
|
|
106
|
-
|
|
114
|
+
connector_endpoint_info = {"id": ep_id}
|
|
115
|
+
connector_endpoint_info.update(
|
|
116
|
+
Storage.read_object(EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json")
|
|
107
117
|
)
|
|
108
118
|
creation_datetime = Storage.get_creation_datetime(
|
|
109
119
|
EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json"
|
|
@@ -116,35 +126,41 @@ class ConnectorEndpoint:
|
|
|
116
126
|
@staticmethod
|
|
117
127
|
def update(ep_args: ConnectorEndpointArguments) -> bool:
|
|
118
128
|
"""
|
|
119
|
-
Updates the endpoint information based on the provided
|
|
129
|
+
Updates the endpoint information in the storage based on the provided ConnectorEndpointArguments object.
|
|
130
|
+
|
|
131
|
+
This method serializes the provided ConnectorEndpointArguments object into a dictionary, excluding the 'id' and
|
|
132
|
+
'created_date' keys. It then persists the updated information to the corresponding JSON file within the
|
|
133
|
+
directory defined by `EnvVariables.CONNECTORS_ENDPOINTS`.
|
|
120
134
|
|
|
121
|
-
This
|
|
122
|
-
'created_date' key if it exists. It then writes the updated information to the corresponding JSON file
|
|
123
|
-
in the directory specified by `EnvVariables.CONNECTORS_ENDPOINTS`.
|
|
135
|
+
This operation ensures that the endpoint's mutable attributes are updated according to the provided arguments.
|
|
124
136
|
|
|
125
137
|
Args:
|
|
126
|
-
ep_args (ConnectorEndpointArguments):
|
|
138
|
+
ep_args (ConnectorEndpointArguments): The object encapsulating the updated attributes of the endpoint.
|
|
127
139
|
|
|
128
140
|
Returns:
|
|
129
|
-
bool:
|
|
141
|
+
bool: Indicates whether the update operation was successful. Returns True if the update was successfully
|
|
142
|
+
persisted to the storage; otherwise, an exception is raised.
|
|
130
143
|
|
|
131
144
|
Raises:
|
|
132
|
-
Exception:
|
|
145
|
+
Exception: Signifies a failure in the update process, potentially due to issues with data serialization or
|
|
146
|
+
storage access.
|
|
133
147
|
"""
|
|
134
148
|
try:
|
|
135
|
-
#
|
|
136
|
-
# Remove created_date if it exists
|
|
149
|
+
# Serialize the ConnectorEndpointArguments object to a dictionary and remove derived properties
|
|
137
150
|
ep_info = ep_args.to_dict()
|
|
138
|
-
ep_info.pop("
|
|
151
|
+
ep_info.pop("id", None) # The 'id' is derived and should not be written
|
|
152
|
+
ep_info.pop(
|
|
153
|
+
"created_date", None
|
|
154
|
+
) # The 'created_date' is derived and should not be written
|
|
139
155
|
|
|
140
|
-
# Write the updated endpoint information to the
|
|
156
|
+
# Write the updated endpoint information to the storage
|
|
141
157
|
Storage.create_object(
|
|
142
158
|
EnvVariables.CONNECTORS_ENDPOINTS.name, ep_args.id, ep_info, "json"
|
|
143
159
|
)
|
|
144
160
|
return True
|
|
145
161
|
|
|
146
162
|
except Exception as e:
|
|
147
|
-
|
|
163
|
+
logger.error(f"Failed to update endpoint: {str(e)}")
|
|
148
164
|
raise e
|
|
149
165
|
|
|
150
166
|
@staticmethod
|
|
@@ -171,7 +187,7 @@ class ConnectorEndpoint:
|
|
|
171
187
|
return True
|
|
172
188
|
|
|
173
189
|
except Exception as e:
|
|
174
|
-
|
|
190
|
+
logger.error(f"Failed to delete endpoint: {str(e)}")
|
|
175
191
|
raise e
|
|
176
192
|
|
|
177
193
|
@staticmethod
|
|
@@ -207,5 +223,5 @@ class ConnectorEndpoint:
|
|
|
207
223
|
return retn_eps_ids, retn_eps
|
|
208
224
|
|
|
209
225
|
except Exception as e:
|
|
210
|
-
|
|
226
|
+
logger.error(f"Failed to get available endpoints: {str(e)}")
|
|
211
227
|
raise e
|