aiverify-moonshot 0.4.11__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {aiverify_moonshot-0.4.11.dist-info → aiverify_moonshot-0.5.0.dist-info}/METADATA +3 -5
  2. {aiverify_moonshot-0.4.11.dist-info → aiverify_moonshot-0.5.0.dist-info}/RECORD +34 -34
  3. {aiverify_moonshot-0.4.11.dist-info → aiverify_moonshot-0.5.0.dist-info}/WHEEL +1 -1
  4. moonshot/integrations/cli/benchmark/cookbook.py +1 -5
  5. moonshot/integrations/cli/benchmark/recipe.py +1 -5
  6. moonshot/integrations/cli/cli_errors.py +3 -0
  7. moonshot/integrations/cli/common/connectors.py +22 -10
  8. moonshot/integrations/web_api/app.py +1 -1
  9. moonshot/integrations/web_api/schemas/endpoint_create_dto.py +1 -0
  10. moonshot/integrations/web_api/services/endpoint_service.py +1 -0
  11. moonshot/src/api/api_bookmark.py +16 -5
  12. moonshot/src/api/api_connector.py +3 -3
  13. moonshot/src/api/api_connector_endpoint.py +6 -3
  14. moonshot/src/api/api_context_strategy.py +2 -2
  15. moonshot/src/api/api_cookbook.py +6 -6
  16. moonshot/src/api/api_dataset.py +5 -5
  17. moonshot/src/api/api_environment_variables.py +3 -0
  18. moonshot/src/api/api_metrics.py +1 -1
  19. moonshot/src/api/api_prompt_template.py +9 -0
  20. moonshot/src/api/api_recipe.py +3 -3
  21. moonshot/src/api/api_red_teaming.py +4 -8
  22. moonshot/src/api/api_result.py +10 -6
  23. moonshot/src/api/api_run.py +3 -3
  24. moonshot/src/api/api_runner.py +7 -6
  25. moonshot/src/api/api_session.py +11 -7
  26. moonshot/src/connectors/connector.py +121 -58
  27. moonshot/src/connectors/connector_prompt_arguments.py +7 -4
  28. moonshot/src/connectors/connector_response.py +5 -10
  29. moonshot/src/connectors_endpoints/connector_endpoint.py +32 -20
  30. moonshot/src/connectors_endpoints/connector_endpoint_arguments.py +4 -1
  31. moonshot/src/messages_constants.py +85 -3
  32. {aiverify_moonshot-0.4.11.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/AUTHORS.md +0 -0
  33. {aiverify_moonshot-0.4.11.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/LICENSE.md +0 -0
  34. {aiverify_moonshot-0.4.11.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/NOTICES.md +0 -0
@@ -79,7 +79,7 @@ def api_read_recipes(rec_ids: conlist(str, min_length=1)) -> list[dict]:
79
79
  and returns a list of dictionaries containing each recipe's information.
80
80
 
81
81
  Args:
82
- rec_ids (list[str]): The IDs of the recipes.
82
+ rec_ids (conlist(str, min_length=1)): The IDs of the recipes.
83
83
 
84
84
  Returns:
85
85
  list[dict]: A list of dictionaries, each containing a recipe's information.
@@ -155,7 +155,7 @@ def api_get_all_recipe() -> list[dict]:
155
155
  """
156
156
  Retrieves all available recipes.
157
157
 
158
- This function calls the get_available_recipes method to retrieve all available recipes. It then converts each
158
+ This function calls the get_available_items method to retrieve all available recipes. It then converts each
159
159
  recipe into a dictionary using the to_dict method and returns a list of these dictionaries.
160
160
 
161
161
  Returns:
@@ -169,7 +169,7 @@ def api_get_all_recipe_name() -> list[str]:
169
169
  """
170
170
  Retrieves all available recipe names.
171
171
 
172
- This function calls the get_available_recipes method to retrieve all available recipes. It then extracts the names
172
+ This function calls the get_available_items method to retrieve all available recipes. It then extracts the names
173
173
  of each recipe and returns a list of these names.
174
174
 
175
175
  Returns:
@@ -11,9 +11,7 @@ def api_get_all_attack_modules() -> list[str]:
11
11
  Retrieves all available attack module IDs.
12
12
 
13
13
  This function calls the `get_available_items` method from the `AttackModule` class to retrieve all available
14
- attack modules.
15
-
16
- It then extracts the IDs of each attack module and returns a list of these IDs.
14
+ attack modules. It then extracts the IDs of each attack module and returns a list of these IDs.
17
15
 
18
16
  Returns:
19
17
  list[str]: A list of strings, each representing an attack module ID.
@@ -27,10 +25,8 @@ def api_get_all_attack_module_metadata() -> list[dict]:
27
25
  Retrieves metadata for all available attack modules.
28
26
 
29
27
  This function calls the `get_available_items` method from the `AttackModule` class to retrieve all available
30
- attack modules metadata.
31
-
32
- It then extracts the metadata for each attack module and returns a list of dictionaries, each containing the
33
- metadata of an attack module.
28
+ attack modules. It then extracts the metadata for each attack module and returns a list of dictionaries,
29
+ each containing the metadata of an attack module.
34
30
 
35
31
  Returns:
36
32
  list[dict]: A list of dictionaries, each representing the metadata of an attack module.
@@ -44,7 +40,7 @@ def api_delete_attack_module(am_id: str) -> bool:
44
40
  """
45
41
  Deletes an attack module by its identifier.
46
42
 
47
- This function takes an attack module ID as input and calls the delete method from the AttackModule class
43
+ This function takes an attack module ID as input and calls the `delete` method from the `AttackModule` class
48
44
  to remove the specified attack module from storage.
49
45
 
50
46
  Args:
@@ -11,7 +11,7 @@ def api_read_result(res_id: str) -> dict:
11
11
  """
12
12
  Reads a result and returns its information.
13
13
 
14
- This function takes a result ID as input, reads the corresponding database file from the storage manager,
14
+ This function takes a result ID as input, reads the corresponding result from the storage manager,
15
15
  and returns a dictionary containing the result's information.
16
16
 
17
17
  Args:
@@ -28,7 +28,7 @@ def api_read_results(res_ids: conlist(str, min_length=1)) -> list[dict]:
28
28
  """
29
29
  Reads multiple results and returns their information.
30
30
 
31
- This function takes a list of result IDs as input, reads the corresponding database files from the storage manager,
31
+ This function takes a list of result IDs as input, reads the corresponding results from the storage manager,
32
32
  and returns a list of dictionaries, each containing a result's information.
33
33
 
34
34
  Args:
@@ -37,7 +37,6 @@ def api_read_results(res_ids: conlist(str, min_length=1)) -> list[dict]:
37
37
  Returns:
38
38
  list[dict]: A list of dictionaries, each containing a result's information.
39
39
  """
40
-
41
40
  return [Result.read(res_id) for res_id in res_ids]
42
41
 
43
42
 
@@ -63,11 +62,13 @@ def api_delete_result(res_id: str) -> bool:
63
62
 
64
63
  def api_get_all_result() -> list[dict]:
65
64
  """
66
- This function retrieves all available results and returns them as a list of dictionaries. Each dictionary
67
- represents a result and contains its information.
65
+ This function retrieves all available results and returns them as a list of dictionaries.
66
+
67
+ This function calls the get_available_items method from the Result class to retrieve all available results.
68
+ It then returns a list of dictionaries, each containing the details of a result.
68
69
 
69
70
  Returns:
70
- list[dict]: A list of dictionaries, each representing a result.
71
+ list[dict]: A list of dictionaries, each representing a result's details.
71
72
  """
72
73
  _, results = Result.get_available_items()
73
74
  return [result for result in results]
@@ -77,6 +78,9 @@ def api_get_all_result_name() -> list[str]:
77
78
  """
78
79
  This function retrieves all available result names and returns them as a list.
79
80
 
81
+ This function calls the get_available_items method from the Result class to retrieve all available results.
82
+ It then extracts the names of each result and returns a list of these names.
83
+
80
84
  Returns:
81
85
  list[str]: A list of result names.
82
86
  """
@@ -14,7 +14,7 @@ def api_get_all_run(runner_id: str = "") -> list[dict]:
14
14
 
15
15
  Args:
16
16
  runner_id (str, optional): The ID of the runner to retrieve runs for. If empty, runs for all runners
17
- are retrieved.
17
+ are retrieved.
18
18
 
19
19
  Returns:
20
20
  list[dict]: A list of dictionaries, each representing a run's data.
@@ -34,8 +34,8 @@ def _api_get_available_runs(
34
34
  RunArguments instances representing the runs.
35
35
 
36
36
  Args:
37
- runner_id (str): The ID of the runner for which to retrieve run information. If empty, information for
38
- all runners is retrieved.
37
+ runner_id (str, optional): The ID of the runner for which to retrieve run information. If empty, information
38
+ for all runners is retrieved.
39
39
 
40
40
  Returns:
41
41
  tuple[list[str], list[RunArguments]]: A tuple containing a list of runner IDs and a list of RunArguments
@@ -20,7 +20,7 @@ def api_create_runner(
20
20
  Creates a new runner.
21
21
 
22
22
  This function takes the name, endpoints, and an optional progress callback function to create a new Runner instance.
23
- The id of the runner is generated from the name of the runner using the slugify function,
23
+ The ID of the runner is generated from the name of the runner using the slugify function,
24
24
  so it does not need to be provided.
25
25
 
26
26
  Args:
@@ -59,7 +59,8 @@ def api_load_runner(
59
59
 
60
60
  Args:
61
61
  runner_id (str): The ID of the runner to be loaded.
62
- progress_callback_func (Callable | None): The progress callback function to be used by the runner.
62
+ progress_callback_func (Callable | None, optional): An optional progress callback function for the runner.
63
+ Defaults to None.
63
64
 
64
65
  Returns:
65
66
  Runner: An initialized Runner object.
@@ -108,8 +109,8 @@ def api_get_all_runner() -> list[dict]:
108
109
  """
109
110
  Retrieves all available runners.
110
111
 
111
- This function calls the get_available_items method to retrieve all available runners. It then converts each
112
- runner into a dictionary using the to_dict method and returns a list of these dictionaries.
112
+ This function calls the get_available_items method from the Runner class to retrieve all available runners.
113
+ It then converts each runner into a dictionary using the to_dict method and returns a list of these dictionaries.
113
114
 
114
115
  Returns:
115
116
  list[dict]: A list of dictionaries, each representing a runner.
@@ -122,8 +123,8 @@ def api_get_all_runner_name() -> list[str]:
122
123
  """
123
124
  Retrieves all available runner names.
124
125
 
125
- This function calls the get_available_items method to retrieve all available runners. It then extracts the names of
126
- each runner and returns a list of these names.
126
+ This function calls the get_available_items method from the Runner class to retrieve all available runners.
127
+ It then extracts the names of each runner and returns a list of these names.
127
128
 
128
129
  Returns:
129
130
  list[str]: A list of runner names.
@@ -43,11 +43,14 @@ def api_create_session(
43
43
  Args:
44
44
  runner_id (str): The unique identifier of the runner for which the session is to be created.
45
45
  database_instance (Any): The database instance to be used for the session.
46
- endpoints (list): A list of endpoints for the session.
46
+ endpoints (list[str]): A list of endpoints for the session.
47
47
  runner_args (dict): A dictionary of arguments for the runner.
48
48
 
49
49
  Returns:
50
- Session
50
+ Session: A new Session object.
51
+
52
+ Raises:
53
+ RuntimeError: If the runner_id is empty or if the database_instance is not provided.
51
54
  """
52
55
  if isinstance(database_instance, DBInterface):
53
56
  if runner_id:
@@ -86,16 +89,16 @@ def api_get_all_session_names() -> list[str]:
86
89
  return session_names
87
90
 
88
91
 
89
- def api_get_available_session_info() -> tuple[list, list]:
92
+ def api_get_available_session_info() -> tuple[list[str], list[dict]]:
90
93
  """
91
- Retrieves the IDs and database instances of runners with active sessions.
94
+ Retrieves the IDs and metadata of runners with active sessions.
92
95
 
93
- This function retrieves the IDs and database instances of runners with active sessions by querying all runners
96
+ This function retrieves the IDs and metadata of runners with active sessions by querying all runners
94
97
  and checking if each runner has an active session. It returns a tuple containing a list of runner IDs and a list
95
98
  of corresponding session metadata for runners with active sessions.
96
99
 
97
100
  Returns:
98
- tuple[list[str], list[str]]: A tuple containing a list of runner IDs and a list of corresponding session
101
+ tuple[list[str], list[dict]]: A tuple containing a list of runner IDs and a list of corresponding session
99
102
  metadata for runners with active sessions.
100
103
  """
101
104
  runners_info = api_get_all_runner()
@@ -122,7 +125,8 @@ def api_get_all_session_metadata() -> list[dict]:
122
125
  This function retrieves the metadata for all active sessions by calling the `api_get_available_session_info` method.
123
126
 
124
127
  Returns:
125
- list: A list containing the metadata for all active sessions, sorted by created datetime in descending order.
128
+ list[dict]: A list containing the metadata for all active sessions, sorted by created datetime in
129
+ descending order.
126
130
  """
127
131
  _, session_metadata_list = api_get_available_session_info()
128
132
  return sorted(
@@ -3,17 +3,32 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import time
5
5
  from abc import abstractmethod
6
- from asyncio import sleep
7
- from functools import wraps
6
+ from functools import partial, wraps
8
7
  from pathlib import Path
9
8
  from typing import Callable
10
9
 
10
+ from tenacity import RetryCallState, retry, stop_after_attempt, wait_random_exponential
11
+
11
12
  from moonshot.src.configs.env_variables import EnvVariables
12
13
  from moonshot.src.connectors.connector_prompt_arguments import ConnectorPromptArguments
13
14
  from moonshot.src.connectors.connector_response import ConnectorResponse
14
15
  from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
15
16
  ConnectorEndpointArguments,
16
17
  )
18
+ from moonshot.src.messages_constants import (
19
+ CONNECTOR_CREATE_CONNECTOR_ENDPOINT_ARGUMENTS_VALIDATION_ERROR,
20
+ CONNECTOR_CREATE_ERROR,
21
+ CONNECTOR_GET_AVAILABLE_ITEMS_ERROR,
22
+ CONNECTOR_GET_PREDICTION_ARGUMENTS_CONNECTOR_VALIDATION_ERROR,
23
+ CONNECTOR_GET_PREDICTION_ARGUMENTS_GENERATED_PROMPT_VALIDATION_ERROR,
24
+ CONNECTOR_GET_PREDICTION_ERROR,
25
+ CONNECTOR_GET_PREDICTION_INFO,
26
+ CONNECTOR_GET_PREDICTION_TIME_TAKEN_INFO,
27
+ CONNECTOR_LOAD_CONNECTOR_ENDPOINT_ARGUMENTS_VALIDATION_ERROR,
28
+ CONNECTOR_LOAD_CONNECTOR_INSTANCE_RUNTIME_ERROR,
29
+ CONNECTOR_PERFORM_RETRY_CALLBACK_ERROR,
30
+ CONNECTOR_SET_SYSTEM_PROMPT_VALIDATION_ERROR,
31
+ )
17
32
  from moonshot.src.storage.storage import Storage
18
33
  from moonshot.src.utils.import_modules import get_instance
19
34
  from moonshot.src.utils.log import configure_logger
@@ -22,43 +37,56 @@ from moonshot.src.utils.log import configure_logger
22
37
  logger = configure_logger(__name__)
23
38
 
24
39
 
40
+ def perform_retry_callback(connector_id: str, retry_state: RetryCallState) -> None:
41
+ """
42
+ Callback function to log retry attempts with detailed information.
43
+
44
+ This function is called by the tenacity library before each retry attempt.
45
+ It logs the retry attempt number, the sleep time before the next attempt,
46
+ the error message that caused the retry, and the connector ID.
47
+
48
+ Args:
49
+ connector_id (str): The ID of the connector.
50
+ retry_state (RetryCallState): The state of the retry call, which includes
51
+ information about the current attempt, the exception raised, and the next action.
52
+ """
53
+ sleep_time = retry_state.idle_for if retry_state else 0
54
+ exception = (
55
+ retry_state.outcome.exception() if retry_state.outcome else "Unknown exception"
56
+ )
57
+ logger.error(
58
+ CONNECTOR_PERFORM_RETRY_CALLBACK_ERROR.format(
59
+ connector_id=connector_id,
60
+ attempt_no=retry_state.attempt_number,
61
+ sleep=f"{sleep_time:.2f}",
62
+ message=str(exception),
63
+ )
64
+ )
65
+
66
+
25
67
  def perform_retry(func):
26
68
  """
27
- A decorator to perform retries on a function.
69
+ A decorator to perform retries on a function using tenacity.
28
70
 
29
- This decorator wraps a function to enable retrying the function call
30
- if it fails. The number of retries and the delay between retries
31
- are determined by the `retries_times` and `allow_retries`
32
- attributes of the class instance.
71
+ This decorator wraps an asynchronous function to enable retrying the function call
72
+ if it fails. The number of attempts and the delay between attempts
73
+ are determined by the `max_attempts` attribute of the class instance.
33
74
 
34
- Parameters:
35
- - func (Callable): The function to be wrapped and retried.
75
+ Args:
76
+ func (Callable): The asynchronous function to be wrapped and retried.
36
77
 
37
78
  Returns:
38
- - Callable: A wrapper function that includes retry logic.
79
+ Callable: A wrapper function that includes retry logic.
39
80
  """
40
81
 
41
82
  async def wrapper(self, *args, **kwargs):
42
- if self.allow_retries:
43
- retry_count = 0
44
- base_delay = 1
45
- while retry_count <= self.retries_times:
46
- # Perform the request
47
- try:
48
- return await func(self, *args, **kwargs)
49
- except Exception as exc:
50
- logger.warning(f"Operation failed. {str(exc)} - Retrying...")
51
-
52
- # Perform retry
53
- retry_count += 1
54
- if retry_count <= self.retries_times:
55
- delay = base_delay * (2**retry_count)
56
- logger.warning(
57
- f"Attempt {retry_count}, Retrying in {delay} seconds..."
58
- )
59
- await sleep(delay)
60
- # Raise an exception
61
- raise ConnectionError("Failed to get response.")
83
+ retry_decorator = retry(
84
+ wait=wait_random_exponential(min=1, max=60),
85
+ stop=stop_after_attempt(self.max_attempts),
86
+ after=partial(perform_retry_callback, self.id),
87
+ reraise=True,
88
+ )
89
+ return await retry_decorator(func)(self, *args, **kwargs)
62
90
 
63
91
  return wrapper
64
92
 
@@ -71,6 +99,7 @@ class Connector:
71
99
  self.token = ep_args.token
72
100
  self.max_concurrency = ep_args.max_concurrency
73
101
  self.max_calls_per_second = ep_args.max_calls_per_second
102
+ self.model = ep_args.model
74
103
  self.params = ep_args.params
75
104
 
76
105
  # Rate limiting
@@ -80,21 +109,19 @@ class Connector:
80
109
  self.updated_at = time.time()
81
110
  self.semaphore = asyncio.Semaphore(ep_args.max_concurrency)
82
111
 
83
- # Set Prompts if they exists
112
+ # Set Prompts if they exist
84
113
  self.pre_prompt = ep_args.params.get("pre_prompt", "")
85
114
  self.post_prompt = ep_args.params.get("post_prompt", "")
86
115
  self.system_prompt = ep_args.params.get("system_prompt", "")
87
116
 
88
117
  # Connection timeout
89
118
  self.timeout = ep_args.params.get("timeout", 600)
90
- self.allow_retries = ep_args.params.get("allow_retries", True)
91
- self.retries_times = ep_args.params.get("num_of_retries", 3)
119
+ self.max_attempts = ep_args.params.get("max_attempts", 3)
92
120
 
93
121
  # Optional params
94
122
  excluded_keys = {
95
- "allow_retries",
96
123
  "timeout",
97
- "num_of_retries",
124
+ "max_attempts",
98
125
  "pre_prompt",
99
126
  "post_prompt",
100
127
  "system_prompt",
@@ -114,10 +141,6 @@ class Connector:
114
141
 
115
142
  The method updates the `updated_at` attribute to the current time after tokens are added, ensuring that
116
143
  the next token addition will be calculated based on the correct elapsed time.
117
-
118
- Usage:
119
- # Assume `self` is an instance of a class with `rate_limiter`, `tokens`, and `updated_at` attributes.
120
- await self.add_tokens()
121
144
  """
122
145
  now = time.time()
123
146
  elapsed = now - self.updated_at
@@ -144,11 +167,6 @@ class Connector:
144
167
 
145
168
  Returns:
146
169
  Callable: The decorated function wrapped with rate limiting logic.
147
-
148
- Usage:
149
- @rate_limited
150
- async def some_async_function(*args, **kwargs):
151
- # Function implementation
152
170
  """
153
171
 
154
172
  @wraps(func)
@@ -187,7 +205,7 @@ class Connector:
187
205
  @classmethod
188
206
  def load(cls, ep_args: ConnectorEndpointArguments) -> Connector:
189
207
  """
190
- This method dynamically loads a connector instance based on the provided endpoint arguments.
208
+ Dynamically loads a connector instance based on the provided endpoint arguments.
191
209
 
192
210
  The connector type specified in the `ep_args` is used to dynamically load the corresponding
193
211
  connector class. The connector is then instantiated with the provided endpoint arguments. If the
@@ -203,17 +221,24 @@ class Connector:
203
221
  Raises:
204
222
  RuntimeError: If the specified connector type does not match any available connector classes.
205
223
  """
224
+ if ep_args is None or not isinstance(ep_args, ConnectorEndpointArguments):
225
+ raise ValueError(
226
+ CONNECTOR_LOAD_CONNECTOR_ENDPOINT_ARGUMENTS_VALIDATION_ERROR
227
+ )
228
+
206
229
  connector_instance = get_instance(
207
230
  ep_args.connector_type,
208
231
  Storage.get_filepath(
209
232
  EnvVariables.CONNECTORS.name, ep_args.connector_type, "py"
210
233
  ),
211
234
  )
212
- if connector_instance:
235
+ if connector_instance and isinstance(connector_instance, Callable):
213
236
  return connector_instance(ep_args)
214
237
  else:
215
238
  raise RuntimeError(
216
- f"Unable to get defined connector instance - {ep_args.connector_type}"
239
+ CONNECTOR_LOAD_CONNECTOR_INSTANCE_RUNTIME_ERROR.format(
240
+ message=ep_args.connector_type
241
+ )
217
242
  )
218
243
 
219
244
  @staticmethod
@@ -223,7 +248,7 @@ class Connector:
223
248
 
224
249
  This method takes a ConnectorEndpointArguments object, which contains the necessary information
225
250
  to initialize and return a Connector object. The Connector object is created by calling the
226
- `load_connector` method, which dynamically loads and initializes the connector based on the
251
+ `load` method, which dynamically loads and initializes the connector based on the
227
252
  endpoint arguments provided.
228
253
 
229
254
  Args:
@@ -231,12 +256,20 @@ class Connector:
231
256
 
232
257
  Returns:
233
258
  Connector: An initialized Connector object based on the provided endpoint arguments.
259
+
260
+ Raises:
261
+ ValueError: If the provided endpoint arguments are invalid.
262
+ Exception: If there is an error during the creation of the connector.
234
263
  """
235
264
  try:
265
+ if ep_args is None or not isinstance(ep_args, ConnectorEndpointArguments):
266
+ raise ValueError(
267
+ CONNECTOR_CREATE_CONNECTOR_ENDPOINT_ARGUMENTS_VALIDATION_ERROR
268
+ )
236
269
  return Connector.load(ep_args)
237
270
 
238
271
  except Exception as e:
239
- logger.error(f"Failed to create connector: {str(e)}")
272
+ logger.error(CONNECTOR_CREATE_ERROR.format(message=str(e)))
240
273
  raise e
241
274
 
242
275
  @staticmethod
@@ -245,7 +278,7 @@ class Connector:
245
278
  Fetches a list of all available connector types.
246
279
 
247
280
  This method employs the `get_connectors` method to locate all Python files in the directory
248
- defined by the `EnvironmentVars.CONNECTORS` environment variable. It subsequently excludes any files that are
281
+ defined by the `EnvVariables.CONNECTORS` environment variable. It subsequently excludes any files that are
249
282
  not intended to be exposed as connectors (those containing "__" in their names). The method yields a list of the
250
283
  names of these connector types.
251
284
 
@@ -263,7 +296,7 @@ class Connector:
263
296
  ]
264
297
 
265
298
  except Exception as e:
266
- logger.error(f"Failed to get available connectors: {str(e)}")
299
+ logger.error(CONNECTOR_GET_AVAILABLE_ITEMS_ERROR.format(message=str(e)))
267
300
  raise e
268
301
 
269
302
  @staticmethod
@@ -299,9 +332,24 @@ class Connector:
299
332
  Raises:
300
333
  Exception: If there is an error during prediction.
301
334
  """
335
+ if generated_prompt is None or not isinstance(
336
+ generated_prompt, ConnectorPromptArguments
337
+ ):
338
+ raise ValueError(
339
+ CONNECTOR_GET_PREDICTION_ARGUMENTS_GENERATED_PROMPT_VALIDATION_ERROR
340
+ )
341
+
342
+ if connector is None or not isinstance(connector, Connector):
343
+ raise ValueError(
344
+ CONNECTOR_GET_PREDICTION_ARGUMENTS_CONNECTOR_VALIDATION_ERROR
345
+ )
346
+
302
347
  try:
303
348
  logger.info(
304
- f"Predicting prompt {generated_prompt.prompt_index} [{connector.id}]"
349
+ CONNECTOR_GET_PREDICTION_INFO.format(
350
+ connector_id=connector.id,
351
+ prompt_index=generated_prompt.prompt_index,
352
+ )
305
353
  )
306
354
 
307
355
  start_time = time.perf_counter()
@@ -310,7 +358,11 @@ class Connector:
310
358
  )
311
359
  generated_prompt.duration = time.perf_counter() - start_time
312
360
  logger.debug(
313
- f"[Prompt {generated_prompt.prompt_index}] took {generated_prompt.duration:.4f}s"
361
+ CONNECTOR_GET_PREDICTION_TIME_TAKEN_INFO.format(
362
+ connector_id=connector.id,
363
+ prompt_index=generated_prompt.prompt_index,
364
+ prompt_duration=f"{generated_prompt.duration:.4f}",
365
+ )
314
366
  )
315
367
 
316
368
  # Call prompt callback
@@ -321,17 +373,28 @@ class Connector:
321
373
  return generated_prompt
322
374
 
323
375
  except Exception as e:
324
- logger.error(f"Failed to get prediction: {str(e)}")
376
+ logger.error(
377
+ CONNECTOR_GET_PREDICTION_ERROR.format(
378
+ connector_id=connector.id,
379
+ prompt_index=generated_prompt.prompt_index,
380
+ message=str(e),
381
+ )
382
+ )
325
383
  raise e
326
384
 
327
385
  def set_system_prompt(self, system_prompt: str) -> None:
328
386
  """
329
- Assigns a new system prompt to this connector instance.
387
+ Sets a new system prompt for this connector instance.
330
388
 
331
- The system prompt serves as a preconfigured command or message that the connector can use to initiate
332
- interactions or execute specific operations.
389
+ The system prompt is a predefined message or command that the connector can use to start interactions
390
+ or perform specific tasks.
333
391
 
334
- Parameters:
392
+ Args:
335
393
  system_prompt (str): The new system prompt to set for this connector.
394
+
395
+ Raises:
396
+ ValueError: If the provided system prompt is not a string or is None.
336
397
  """
398
+ if system_prompt is None or not isinstance(system_prompt, str):
399
+ raise ValueError(CONNECTOR_SET_SYSTEM_PROMPT_VALIDATION_ERROR)
337
400
  self.system_prompt = system_prompt
@@ -1,8 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any
3
+ from typing import Annotated, Any
4
4
 
5
- from pydantic import BaseModel
5
+ from pydantic import BaseModel, Field
6
6
 
7
7
  from moonshot.src.connectors.connector_response import ConnectorResponse
8
8
 
@@ -11,7 +11,9 @@ class ConnectorPromptArguments(BaseModel):
11
11
  class Config:
12
12
  arbitrary_types_allowed = True
13
13
 
14
- prompt_index: int # The index of the prompt in the dataset
14
+ prompt_index: Annotated[
15
+ int, Field(strict=True, ge=0)
16
+ ] # The index of the prompt in the dataset
15
17
 
16
18
  prompt: str # The actual prompt text
17
19
 
@@ -21,4 +23,5 @@ class ConnectorPromptArguments(BaseModel):
21
23
  None # The predicted results, default is None
22
24
  )
23
25
 
24
- duration: float = 0.0 # The duration it took to get the results, default is 0.0
26
+ # The duration it took to get the results, must be a positive float
27
+ duration: Annotated[float, Field(strict=True, ge=0.0)] = 0.0
@@ -1,14 +1,9 @@
1
- class ConnectorResponse:
2
- def __init__(self, response: str, context: list = []):
3
- """
4
- Initializes a ConnectorResponse instance.
1
+ from pydantic import BaseModel
5
2
 
6
- Args:
7
- response (str): The response text from the connector.
8
- context (list, optional): Additional context or metadata related to the response. Defaults to an empty list.
9
- """
10
- self.response = response
11
- self.context = context
3
+
4
+ class ConnectorResponse(BaseModel):
5
+ response: str = ""
6
+ context: list = []
12
7
 
13
8
  def to_dict(self) -> dict:
14
9
  """