aiverify-moonshot 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. aiverify_moonshot-0.4.0.dist-info/METADATA +249 -0
  2. aiverify_moonshot-0.4.0.dist-info/RECORD +163 -0
  3. aiverify_moonshot-0.4.0.dist-info/WHEEL +4 -0
  4. aiverify_moonshot-0.4.0.dist-info/licenses/AUTHORS.md +5 -0
  5. aiverify_moonshot-0.4.0.dist-info/licenses/LICENSE.md +201 -0
  6. aiverify_moonshot-0.4.0.dist-info/licenses/NOTICES.md +3340 -0
  7. moonshot/__init__.py +0 -0
  8. moonshot/__main__.py +198 -0
  9. moonshot/api.py +155 -0
  10. moonshot/integrations/__init__.py +0 -0
  11. moonshot/integrations/cli/__init__.py +0 -0
  12. moonshot/integrations/cli/__main__.py +25 -0
  13. moonshot/integrations/cli/active_session_cfg.py +1 -0
  14. moonshot/integrations/cli/benchmark/__init__.py +0 -0
  15. moonshot/integrations/cli/benchmark/benchmark.py +186 -0
  16. moonshot/integrations/cli/benchmark/cookbook.py +545 -0
  17. moonshot/integrations/cli/benchmark/datasets.py +164 -0
  18. moonshot/integrations/cli/benchmark/metrics.py +141 -0
  19. moonshot/integrations/cli/benchmark/recipe.py +598 -0
  20. moonshot/integrations/cli/benchmark/result.py +216 -0
  21. moonshot/integrations/cli/benchmark/run.py +140 -0
  22. moonshot/integrations/cli/benchmark/runner.py +174 -0
  23. moonshot/integrations/cli/cli.py +64 -0
  24. moonshot/integrations/cli/common/__init__.py +0 -0
  25. moonshot/integrations/cli/common/common.py +72 -0
  26. moonshot/integrations/cli/common/connectors.py +325 -0
  27. moonshot/integrations/cli/common/display_helper.py +42 -0
  28. moonshot/integrations/cli/common/prompt_template.py +94 -0
  29. moonshot/integrations/cli/initialisation/__init__.py +0 -0
  30. moonshot/integrations/cli/initialisation/initialisation.py +14 -0
  31. moonshot/integrations/cli/redteam/__init__.py +0 -0
  32. moonshot/integrations/cli/redteam/attack_module.py +70 -0
  33. moonshot/integrations/cli/redteam/context_strategy.py +147 -0
  34. moonshot/integrations/cli/redteam/prompt_template.py +67 -0
  35. moonshot/integrations/cli/redteam/redteam.py +90 -0
  36. moonshot/integrations/cli/redteam/session.py +467 -0
  37. moonshot/integrations/web_api/.env.dev +7 -0
  38. moonshot/integrations/web_api/__init__.py +0 -0
  39. moonshot/integrations/web_api/__main__.py +56 -0
  40. moonshot/integrations/web_api/app.py +125 -0
  41. moonshot/integrations/web_api/container.py +146 -0
  42. moonshot/integrations/web_api/log/.gitkeep +0 -0
  43. moonshot/integrations/web_api/logging_conf.py +114 -0
  44. moonshot/integrations/web_api/routes/__init__.py +0 -0
  45. moonshot/integrations/web_api/routes/attack_modules.py +66 -0
  46. moonshot/integrations/web_api/routes/benchmark.py +116 -0
  47. moonshot/integrations/web_api/routes/benchmark_result.py +175 -0
  48. moonshot/integrations/web_api/routes/context_strategy.py +129 -0
  49. moonshot/integrations/web_api/routes/cookbook.py +225 -0
  50. moonshot/integrations/web_api/routes/dataset.py +120 -0
  51. moonshot/integrations/web_api/routes/endpoint.py +282 -0
  52. moonshot/integrations/web_api/routes/metric.py +78 -0
  53. moonshot/integrations/web_api/routes/prompt_template.py +128 -0
  54. moonshot/integrations/web_api/routes/recipe.py +219 -0
  55. moonshot/integrations/web_api/routes/redteam.py +609 -0
  56. moonshot/integrations/web_api/routes/runner.py +239 -0
  57. moonshot/integrations/web_api/schemas/__init__.py +0 -0
  58. moonshot/integrations/web_api/schemas/benchmark_runner_dto.py +13 -0
  59. moonshot/integrations/web_api/schemas/cookbook_create_dto.py +19 -0
  60. moonshot/integrations/web_api/schemas/cookbook_response_model.py +9 -0
  61. moonshot/integrations/web_api/schemas/dataset_response_dto.py +9 -0
  62. moonshot/integrations/web_api/schemas/endpoint_create_dto.py +21 -0
  63. moonshot/integrations/web_api/schemas/endpoint_response_model.py +11 -0
  64. moonshot/integrations/web_api/schemas/prompt_response_model.py +14 -0
  65. moonshot/integrations/web_api/schemas/prompt_template_response_model.py +10 -0
  66. moonshot/integrations/web_api/schemas/recipe_create_dto.py +32 -0
  67. moonshot/integrations/web_api/schemas/recipe_response_model.py +7 -0
  68. moonshot/integrations/web_api/schemas/session_create_dto.py +16 -0
  69. moonshot/integrations/web_api/schemas/session_prompt_dto.py +7 -0
  70. moonshot/integrations/web_api/schemas/session_response_model.py +38 -0
  71. moonshot/integrations/web_api/services/__init__.py +0 -0
  72. moonshot/integrations/web_api/services/attack_module_service.py +34 -0
  73. moonshot/integrations/web_api/services/auto_red_team_test_manager.py +86 -0
  74. moonshot/integrations/web_api/services/auto_red_team_test_state.py +57 -0
  75. moonshot/integrations/web_api/services/base_service.py +8 -0
  76. moonshot/integrations/web_api/services/benchmark_result_service.py +25 -0
  77. moonshot/integrations/web_api/services/benchmark_test_manager.py +106 -0
  78. moonshot/integrations/web_api/services/benchmark_test_state.py +56 -0
  79. moonshot/integrations/web_api/services/benchmarking_service.py +31 -0
  80. moonshot/integrations/web_api/services/context_strategy_service.py +22 -0
  81. moonshot/integrations/web_api/services/cookbook_service.py +194 -0
  82. moonshot/integrations/web_api/services/dataset_service.py +20 -0
  83. moonshot/integrations/web_api/services/endpoint_service.py +65 -0
  84. moonshot/integrations/web_api/services/metric_service.py +14 -0
  85. moonshot/integrations/web_api/services/prompt_template_service.py +39 -0
  86. moonshot/integrations/web_api/services/recipe_service.py +155 -0
  87. moonshot/integrations/web_api/services/runner_service.py +147 -0
  88. moonshot/integrations/web_api/services/session_service.py +350 -0
  89. moonshot/integrations/web_api/services/utils/exceptions_handler.py +41 -0
  90. moonshot/integrations/web_api/services/utils/results_formatter.py +47 -0
  91. moonshot/integrations/web_api/status_updater/interface/benchmark_progress_callback.py +14 -0
  92. moonshot/integrations/web_api/status_updater/interface/redteam_progress_callback.py +14 -0
  93. moonshot/integrations/web_api/status_updater/moonshot_ui_webhook.py +72 -0
  94. moonshot/integrations/web_api/types/types.py +99 -0
  95. moonshot/src/__init__.py +0 -0
  96. moonshot/src/api/__init__.py +0 -0
  97. moonshot/src/api/api_connector.py +58 -0
  98. moonshot/src/api/api_connector_endpoint.py +162 -0
  99. moonshot/src/api/api_context_strategy.py +57 -0
  100. moonshot/src/api/api_cookbook.py +160 -0
  101. moonshot/src/api/api_dataset.py +46 -0
  102. moonshot/src/api/api_environment_variables.py +17 -0
  103. moonshot/src/api/api_metrics.py +51 -0
  104. moonshot/src/api/api_prompt_template.py +43 -0
  105. moonshot/src/api/api_recipe.py +182 -0
  106. moonshot/src/api/api_red_teaming.py +59 -0
  107. moonshot/src/api/api_result.py +84 -0
  108. moonshot/src/api/api_run.py +74 -0
  109. moonshot/src/api/api_runner.py +132 -0
  110. moonshot/src/api/api_session.py +290 -0
  111. moonshot/src/configs/__init__.py +0 -0
  112. moonshot/src/configs/env_variables.py +187 -0
  113. moonshot/src/connectors/__init__.py +0 -0
  114. moonshot/src/connectors/connector.py +327 -0
  115. moonshot/src/connectors/connector_prompt_arguments.py +17 -0
  116. moonshot/src/connectors_endpoints/__init__.py +0 -0
  117. moonshot/src/connectors_endpoints/connector_endpoint.py +211 -0
  118. moonshot/src/connectors_endpoints/connector_endpoint_arguments.py +54 -0
  119. moonshot/src/cookbooks/__init__.py +0 -0
  120. moonshot/src/cookbooks/cookbook.py +225 -0
  121. moonshot/src/cookbooks/cookbook_arguments.py +34 -0
  122. moonshot/src/datasets/__init__.py +0 -0
  123. moonshot/src/datasets/dataset.py +255 -0
  124. moonshot/src/datasets/dataset_arguments.py +50 -0
  125. moonshot/src/metrics/__init__.py +0 -0
  126. moonshot/src/metrics/metric.py +192 -0
  127. moonshot/src/metrics/metric_interface.py +95 -0
  128. moonshot/src/prompt_templates/__init__.py +0 -0
  129. moonshot/src/prompt_templates/prompt_template.py +103 -0
  130. moonshot/src/recipes/__init__.py +0 -0
  131. moonshot/src/recipes/recipe.py +340 -0
  132. moonshot/src/recipes/recipe_arguments.py +111 -0
  133. moonshot/src/redteaming/__init__.py +0 -0
  134. moonshot/src/redteaming/attack/__init__.py +0 -0
  135. moonshot/src/redteaming/attack/attack_module.py +618 -0
  136. moonshot/src/redteaming/attack/attack_module_arguments.py +44 -0
  137. moonshot/src/redteaming/attack/context_strategy.py +131 -0
  138. moonshot/src/redteaming/context_strategy/__init__.py +0 -0
  139. moonshot/src/redteaming/context_strategy/context_strategy_interface.py +46 -0
  140. moonshot/src/redteaming/session/__init__.py +0 -0
  141. moonshot/src/redteaming/session/chat.py +209 -0
  142. moonshot/src/redteaming/session/red_teaming_progress.py +128 -0
  143. moonshot/src/redteaming/session/red_teaming_type.py +6 -0
  144. moonshot/src/redteaming/session/session.py +775 -0
  145. moonshot/src/results/__init__.py +0 -0
  146. moonshot/src/results/result.py +119 -0
  147. moonshot/src/results/result_arguments.py +44 -0
  148. moonshot/src/runners/__init__.py +0 -0
  149. moonshot/src/runners/runner.py +476 -0
  150. moonshot/src/runners/runner_arguments.py +46 -0
  151. moonshot/src/runners/runner_type.py +6 -0
  152. moonshot/src/runs/__init__.py +0 -0
  153. moonshot/src/runs/run.py +344 -0
  154. moonshot/src/runs/run_arguments.py +162 -0
  155. moonshot/src/runs/run_progress.py +145 -0
  156. moonshot/src/runs/run_status.py +10 -0
  157. moonshot/src/storage/__init__.py +0 -0
  158. moonshot/src/storage/db_interface.py +128 -0
  159. moonshot/src/storage/io_interface.py +31 -0
  160. moonshot/src/storage/storage.py +525 -0
  161. moonshot/src/utils/__init__.py +0 -0
  162. moonshot/src/utils/import_modules.py +96 -0
  163. moonshot/src/utils/timeit.py +25 -0
@@ -0,0 +1,327 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import time
5
+ from abc import abstractmethod
6
+ from asyncio import sleep
7
+ from functools import wraps
8
+ from pathlib import Path
9
+ from typing import Callable
10
+
11
+ from moonshot.src.configs.env_variables import EnvVariables
12
+ from moonshot.src.connectors.connector_prompt_arguments import ConnectorPromptArguments
13
+ from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
14
+ ConnectorEndpointArguments,
15
+ )
16
+ from moonshot.src.storage.storage import Storage
17
+ from moonshot.src.utils.import_modules import get_instance
18
+
19
+
20
+ def perform_retry(func):
21
+ """
22
+ A decorator to perform retries on a function.
23
+
24
+ This decorator wraps a function to enable retrying the function call
25
+ if it fails. The number of retries and the delay between retries
26
+ are determined by the `retries_times` and `allow_retries`
27
+ attributes of the class instance.
28
+
29
+ Parameters:
30
+ - func (Callable): The function to be wrapped and retried.
31
+
32
+ Returns:
33
+ - Callable: A wrapper function that includes retry logic.
34
+ """
35
+
36
+ async def wrapper(self, *args, **kwargs):
37
+ if self.allow_retries:
38
+ retry_count = 0
39
+ base_delay = 1
40
+ while retry_count <= self.retries_times:
41
+ # Perform the request
42
+ try:
43
+ return await func(self, *args, **kwargs)
44
+ except Exception as exc:
45
+ print(f"Operation failed. {str(exc)} - Retrying...")
46
+
47
+ # Perform retry
48
+ retry_count += 1
49
+ if retry_count <= self.retries_times:
50
+ delay = base_delay * (2**retry_count)
51
+ print(f"Attempt {retry_count}, Retrying in {delay} seconds...")
52
+ await sleep(delay)
53
+ # Raise an exception
54
+ raise ConnectionError("Failed to get response.")
55
+
56
+ return wrapper
57
+
58
+
59
+ class Connector:
60
+ def __init__(self, ep_args: ConnectorEndpointArguments) -> None:
61
+ self.id = ep_args.id
62
+
63
+ self.endpoint = ep_args.uri
64
+ self.token = ep_args.token
65
+ self.max_concurrency = ep_args.max_concurrency
66
+ self.max_calls_per_second = ep_args.max_calls_per_second
67
+ self.params = ep_args.params
68
+
69
+ # Rate limiting
70
+ self.rate_limiter = ep_args.max_calls_per_second
71
+ # Initialize the token count to the maximum limit
72
+ self.tokens = ep_args.max_calls_per_second
73
+ self.updated_at = time.time()
74
+ self.semaphore = asyncio.Semaphore(ep_args.max_concurrency)
75
+
76
+ # Set Prompts if they exists
77
+ self.pre_prompt = ep_args.params.get("pre_prompt", "")
78
+ self.post_prompt = ep_args.params.get("post_prompt", "")
79
+ self.system_prompt = ep_args.params.get("system_prompt", "")
80
+
81
+ # Connection timeout
82
+ self.timeout = ep_args.params.get("timeout", 600)
83
+ self.allow_retries = ep_args.params.get("allow_retries", True)
84
+ self.retries_times = ep_args.params.get("num_of_retries", 3)
85
+
86
+ # Optional params
87
+ excluded_keys = {
88
+ "allow_retries",
89
+ "timeout",
90
+ "num_of_retries",
91
+ "pre_prompt",
92
+ "post_prompt",
93
+ "system_prompt",
94
+ }
95
+ self.optional_params = {
96
+ k: v for k, v in ep_args.params.items() if k not in excluded_keys
97
+ }
98
+
99
+ async def _add_tokens(self) -> None:
100
+ """
101
+ Replenishes the token bucket based on the elapsed time since the last update.
102
+
103
+ This method calculates the number of tokens to add to the bucket by considering the time that has elapsed
104
+ since the tokens were last replenished. The rate at which tokens are added is determined by the `rate_limiter`
105
+ attribute, which defines the maximum number of tokens that can be added per second. The total number of tokens
106
+ in the bucket will never exceed the rate limit.
107
+
108
+ The method updates the `updated_at` attribute to the current time after tokens are added, ensuring that
109
+ the next token addition will be calculated based on the correct elapsed time.
110
+
111
+ Usage:
112
+ # Assume `self` is an instance of a class with `rate_limiter`, `tokens`, and `updated_at` attributes.
113
+ await self.add_tokens()
114
+ """
115
+ now = time.time()
116
+ elapsed = now - self.updated_at
117
+ # Add tokens based on elapsed time
118
+ increment = elapsed * self.rate_limiter
119
+ self.tokens = min(self.rate_limiter, self.tokens + increment)
120
+ self.updated_at = now
121
+
122
+ @staticmethod
123
+ def rate_limited(func: Callable) -> Callable:
124
+ """
125
+ A decorator to enforce rate limiting on an asynchronous function using a token bucket strategy.
126
+
127
+ This decorator ensures that the decorated function adheres to a rate limit specified by the `rate_limiter`
128
+ attribute of the class instance it belongs to. It uses a token bucket mechanism where tokens are added
129
+ to the bucket over time, and each function call consumes a token. If there are no tokens available,
130
+ the function's execution is delayed until the next token is added.
131
+
132
+ The decorator also uses an `asyncio.Semaphore` to control concurrency, allowing multiple instances of the
133
+ function to run in parallel up to a limit, without exceeding the rate limit.
134
+
135
+ Args:
136
+ func (Callable): The asynchronous function to be decorated.
137
+
138
+ Returns:
139
+ Callable: The decorated function wrapped with rate limiting logic.
140
+
141
+ Usage:
142
+ @rate_limited
143
+ async def some_async_function(*args, **kwargs):
144
+ # Function implementation
145
+ """
146
+
147
+ @wraps(func)
148
+ async def wrapper(self, *args, **kwargs):
149
+ async with self.semaphore:
150
+ # Wait for token availability
151
+ await self._add_tokens()
152
+ if self.tokens < 1:
153
+ # Calculate the time to wait until the next token is available
154
+ sleep_time = (1 - self.tokens) / self.rate_limiter
155
+ await asyncio.sleep(sleep_time)
156
+ # Re-check for token availability after sleeping
157
+ await self._add_tokens()
158
+ # Consume a token and proceed with the function call
159
+ self.tokens -= 1
160
+ return await func(self, *args, **kwargs)
161
+
162
+ return wrapper
163
+
164
+ @abstractmethod
165
+ async def get_response(self, prompt: str) -> str:
166
+ """
167
+ Abstract method to be implemented by subclasses to get a response from the connector.
168
+
169
+ This method should asynchronously send a prompt to the connector's API and return the response.
170
+
171
+ Args:
172
+ prompt (str): The input prompt to be sent to the connector.
173
+
174
+ Returns:
175
+ str: The response received from the connector.
176
+ """
177
+ pass
178
+
179
+ @classmethod
180
+ def load(cls, ep_args: ConnectorEndpointArguments) -> Connector:
181
+ """
182
+ This method dynamically loads a connector instance based on the provided endpoint arguments.
183
+
184
+ The connector type specified in the `ep_args` is used to dynamically load the corresponding
185
+ connector class. The connector is then instantiated with the provided endpoint arguments. If the
186
+ specified connector type does not correspond to any available connector classes, a RuntimeError is raised.
187
+
188
+ Args:
189
+ ep_args (ConnectorEndpointArguments): The endpoint arguments which include the connector type and
190
+ other necessary information.
191
+
192
+ Returns:
193
+ Connector: An instance of the specified connector class, initialized with the given endpoint arguments.
194
+
195
+ Raises:
196
+ RuntimeError: If the specified connector type does not match any available connector classes.
197
+ """
198
+ connector_instance = get_instance(
199
+ ep_args.connector_type,
200
+ Storage.get_filepath(
201
+ EnvVariables.CONNECTORS.name, ep_args.connector_type, "py"
202
+ ),
203
+ )
204
+ if connector_instance:
205
+ return connector_instance(ep_args)
206
+ else:
207
+ raise RuntimeError(
208
+ f"Unable to get defined connector instance - {ep_args.connector_type}"
209
+ )
210
+
211
+ @staticmethod
212
+ def create(ep_args: ConnectorEndpointArguments) -> Connector:
213
+ """
214
+ Creates a connector object based on the provided endpoint arguments.
215
+
216
+ This method takes a ConnectorEndpointArguments object, which contains the necessary information
217
+ to initialize and return a Connector object. The Connector object is created by calling the
218
+ `load_connector` method, which dynamically loads and initializes the connector based on the
219
+ endpoint arguments provided.
220
+
221
+ Args:
222
+ ep_args (ConnectorEndpointArguments): The endpoint arguments required to create the connector.
223
+
224
+ Returns:
225
+ Connector: An initialized Connector object based on the provided endpoint arguments.
226
+ """
227
+ try:
228
+ return Connector.load(ep_args)
229
+
230
+ except Exception as e:
231
+ print(f"Failed to create connector: {str(e)}")
232
+ raise e
233
+
234
+ @staticmethod
235
+ def get_available_items() -> list[str]:
236
+ """
237
+ Fetches a list of all available connector types.
238
+
239
+ This method employs the `get_connectors` method to locate all Python files in the directory
240
+ defined by the `EnvironmentVars.CONNECTORS` environment variable. It subsequently excludes any files that are
241
+ not intended to be exposed as connectors (those containing "__" in their names). The method yields a list of the
242
+ names of these connector types.
243
+
244
+ Returns:
245
+ list[str]: A list of strings, each denoting the name of a connector type.
246
+
247
+ Raises:
248
+ Exception: If an error occurs during the extraction of connector types.
249
+ """
250
+ try:
251
+ return [
252
+ Path(fp).stem
253
+ for fp in Storage.get_objects(EnvVariables.CONNECTORS.name, "py")
254
+ if "__" not in fp
255
+ ]
256
+
257
+ except Exception as e:
258
+ print(f"Failed to get available connectors: {str(e)}")
259
+ raise e
260
+
261
+ @staticmethod
262
+ async def get_prediction(
263
+ generated_prompt: ConnectorPromptArguments,
264
+ connector: Connector,
265
+ prompt_callback: Callable | None = None,
266
+ ) -> ConnectorPromptArguments:
267
+ """
268
+ Generates a prediction for a given prompt using a specified connector.
269
+
270
+ This method takes a `generated_prompt` object, which contains the prompt to be predicted, and a `connector`
271
+ object, which is used to generate the prediction. The method also optionally takes a `prompt_callback` function,
272
+ which is called after the prediction is generated.
273
+
274
+ The method first prints a message indicating that it is predicting the prompt. It then records the start time
275
+ and uses the `connector` to generate a prediction for the `generated_prompt`. The duration of the prediction
276
+ is calculated and stored in the `generated_prompt`.
277
+
278
+ If a `prompt_callback` function is provided, it is called with the `generated_prompt` and `connector.id` as
279
+ arguments.
280
+
281
+ The method then returns the `generated_prompt` with the generated prediction and duration.
282
+
283
+ Args:
284
+ generated_prompt (ConnectorPromptArguments): The prompt to be predicted.
285
+ connector (Connector): The connector to be used for prediction.
286
+ prompt_callback (Callable | None): An optional callback function to be called after prediction.
287
+
288
+ Returns:
289
+ ConnectorPromptArguments: The `generated_prompt` with the generated prediction and duration.
290
+
291
+ Raises:
292
+ Exception: If there is an error during prediction.
293
+ """
294
+ try:
295
+ print(f"Predicting prompt {generated_prompt.prompt_index} [{connector.id}]")
296
+
297
+ start_time = time.perf_counter()
298
+ generated_prompt.predicted_results = await connector.get_response(
299
+ generated_prompt.prompt
300
+ )
301
+ generated_prompt.duration = time.perf_counter() - start_time
302
+ print(
303
+ f"[Prompt {generated_prompt.prompt_index}] took {generated_prompt.duration:.4f}s"
304
+ )
305
+
306
+ # Call prompt callback
307
+ if prompt_callback:
308
+ prompt_callback(generated_prompt, connector.id)
309
+
310
+ # Return the updated prompt
311
+ return generated_prompt
312
+
313
+ except Exception as e:
314
+ print(f"Failed to get prediction: {str(e)}")
315
+ raise e
316
+
317
+ def set_system_prompt(self, system_prompt: str) -> None:
318
+ """
319
+ Assigns a new system prompt to this connector instance.
320
+
321
+ The system prompt serves as a preconfigured command or message that the connector can use to initiate
322
+ interactions or execute specific operations.
323
+
324
+ Parameters:
325
+ system_prompt (str): The new system prompt to set for this connector.
326
+ """
327
+ self.system_prompt = system_prompt
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from pydantic import BaseModel
6
+
7
+
8
+ class ConnectorPromptArguments(BaseModel):
9
+ prompt_index: int # The index of the prompt in the dataset
10
+
11
+ prompt: str # The actual prompt text
12
+
13
+ target: Any # The target response for the prompt
14
+
15
+ predicted_results: Any = "" # The predicted results, default is an empty string
16
+
17
+ duration: float = 0.0 # The duration it took to get the results, default is 0.0
File without changes
@@ -0,0 +1,211 @@
1
+ from pathlib import Path
2
+
3
+ from pydantic import validate_call
4
+ from slugify import slugify
5
+
6
+ from moonshot.src.configs.env_variables import EnvVariables
7
+ from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
8
+ ConnectorEndpointArguments,
9
+ )
10
+ from moonshot.src.storage.storage import Storage
11
+
12
+
13
+ class ConnectorEndpoint:
14
+ @staticmethod
15
+ def create(ep_args: ConnectorEndpointArguments) -> str:
16
+ """
17
+ Creates a new connector endpoint.
18
+
19
+ This method takes a ConnectorEndpointArguments object as input, generates a unique slugified ID based on the
20
+ endpoint's name, and then creates a new endpoint with the provided details. The endpoint information is stored
21
+ as a JSON object in the directory specified by `EnvVariables.CONNECTORS_ENDPOINTS`. If the operation is
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.
24
+
25
+ Args:
26
+ ep_args (ConnectorEndpointArguments): An object containing the details of the endpoint to be created.
27
+
28
+ Returns:
29
+ str: The unique ID of the newly created endpoint.
30
+
31
+ Raises:
32
+ Exception: If there's an error during the endpoint creation process.
33
+ """
34
+ try:
35
+ ep_id = slugify(ep_args.name, lowercase=True)
36
+ ep_info = {
37
+ "id": ep_id,
38
+ "name": ep_args.name,
39
+ "connector_type": ep_args.connector_type,
40
+ "uri": ep_args.uri,
41
+ "token": ep_args.token,
42
+ "max_calls_per_second": ep_args.max_calls_per_second,
43
+ "max_concurrency": ep_args.max_concurrency,
44
+ "params": ep_args.params,
45
+ }
46
+
47
+ # Write as json output
48
+ Storage.create_object(
49
+ EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, ep_info, "json"
50
+ )
51
+ return ep_id
52
+
53
+ except Exception as e:
54
+ print(f"Failed to create endpoint: {str(e)}")
55
+ raise e
56
+
57
+ @staticmethod
58
+ @validate_call
59
+ def read(ep_id: str) -> ConnectorEndpointArguments:
60
+ """
61
+ Fetches the details of a given endpoint.
62
+
63
+ This method takes an endpoint ID as input, finds the corresponding JSON file in the directory
64
+ specified by `EnvironmentVars.CONNECTORS_ENDPOINTS`, and returns a ConnectorEndpointArguments object
65
+ that contains the endpoint's details. If any error arises during the process, an exception is raised and the
66
+ error message is logged.
67
+
68
+ Args:
69
+ ep_id (str): The unique ID of the endpoint to be fetched.
70
+
71
+ Returns:
72
+ ConnectorEndpointArguments: An object encapsulating the details of the fetched endpoint.
73
+
74
+ Raises:
75
+ Exception: If there's an error during the file reading process or any other operation within the method.
76
+ """
77
+ try:
78
+ if ep_id:
79
+ return ConnectorEndpointArguments(
80
+ **ConnectorEndpoint._read_endpoint(ep_id)
81
+ )
82
+ else:
83
+ raise RuntimeError("Connector Endpoint ID is empty")
84
+
85
+ except Exception as e:
86
+ print(f"Failed to read endpoint: {str(e)}")
87
+ raise e
88
+
89
+ @staticmethod
90
+ def _read_endpoint(ep_id: str) -> dict:
91
+ """
92
+ Reads the endpoint information from a JSON file and adds the creation datetime.
93
+
94
+ This method accepts an endpoint ID as an argument, locates the corresponding JSON file in the directory
95
+ defined by `EnvironmentVars.CONNECTORS_ENDPOINTS`, and returns a dictionary that encapsulates the endpoint's
96
+ details along with its creation datetime. If any error occurs during the process, it is handled by the calling
97
+ method.
98
+
99
+ Args:
100
+ ep_id (str): The unique identifier of the endpoint to be retrieved.
101
+
102
+ Returns:
103
+ dict: A dictionary containing the details of the retrieved endpoint along with its creation datetime.
104
+ """
105
+ connector_endpoint_info = Storage.read_object(
106
+ EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json"
107
+ )
108
+ creation_datetime = Storage.get_creation_datetime(
109
+ EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json"
110
+ )
111
+ connector_endpoint_info["created_date"] = creation_datetime.replace(
112
+ microsecond=0
113
+ ).isoformat(" ")
114
+ return connector_endpoint_info
115
+
116
+ @staticmethod
117
+ def update(ep_args: ConnectorEndpointArguments) -> bool:
118
+ """
119
+ Updates the endpoint information based on the provided arguments.
120
+
121
+ This method takes a ConnectorEndpointArguments object, converts it to a dictionary, and removes the
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`.
124
+
125
+ Args:
126
+ ep_args (ConnectorEndpointArguments): An object containing the updated details of the endpoint.
127
+
128
+ Returns:
129
+ bool: True if the update operation was successful.
130
+
131
+ Raises:
132
+ Exception: If there's an error during the update process.
133
+ """
134
+ try:
135
+ # Convert the endpoint arguments to a dictionary
136
+ # Remove created_date if it exists
137
+ ep_info = ep_args.to_dict()
138
+ ep_info.pop("created_date", None)
139
+
140
+ # Write the updated endpoint information to the file
141
+ Storage.create_object(
142
+ EnvVariables.CONNECTORS_ENDPOINTS.name, ep_args.id, ep_info, "json"
143
+ )
144
+ return True
145
+
146
+ except Exception as e:
147
+ print(f"Failed to update endpoint: {str(e)}")
148
+ raise e
149
+
150
+ @staticmethod
151
+ @validate_call
152
+ def delete(ep_id: str) -> bool:
153
+ """
154
+ Deletes the endpoint with the specified ID.
155
+
156
+ This method attempts to delete the endpoint corresponding to the given ID from the storage.
157
+ If the deletion is successful, it returns True. If an error occurs, it prints an error message
158
+ and re-raises the exception.
159
+
160
+ Args:
161
+ ep_id (str): The unique identifier of the endpoint to be deleted.
162
+
163
+ Returns:
164
+ bool: True if the endpoint was successfully deleted.
165
+
166
+ Raises:
167
+ Exception: If the deletion process encounters an error.
168
+ """
169
+ try:
170
+ Storage.delete_object(EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json")
171
+ return True
172
+
173
+ except Exception as e:
174
+ print(f"Failed to delete endpoint: {str(e)}")
175
+ raise e
176
+
177
+ @staticmethod
178
+ def get_available_items() -> tuple[list[str], list[ConnectorEndpointArguments]]:
179
+ """
180
+ Fetches the details of all available endpoints.
181
+
182
+ This method traverses the specified directory for connector endpoints, reads the information of each endpoint
183
+ from its corresponding JSON file, and assembles a list of endpoint IDs along with their respective details.
184
+ It excludes any files that are not valid endpoints (for instance, system files that begin with "__").
185
+ The method returns a tuple comprising a list of endpoint IDs and a list of ConnectorEndpointArguments objects,
186
+ each encapsulating the details of an endpoint.
187
+
188
+ Returns:
189
+ tuple[list[str], list[ConnectorEndpointArguments]]: A tuple containing a list of endpoint IDs and a list of
190
+ ConnectorEndpointArguments objects with endpoint details.
191
+ """
192
+ try:
193
+ retn_eps = []
194
+ retn_eps_ids = []
195
+
196
+ eps = Storage.get_objects(EnvVariables.CONNECTORS_ENDPOINTS.name, "json")
197
+ for ep in eps:
198
+ if "__" in ep:
199
+ continue
200
+
201
+ ep_info = ConnectorEndpointArguments(
202
+ **ConnectorEndpoint._read_endpoint(Path(ep).stem)
203
+ )
204
+ retn_eps.append(ep_info)
205
+ retn_eps_ids.append(ep_info.id)
206
+
207
+ return retn_eps_ids, retn_eps
208
+
209
+ except Exception as e:
210
+ print(f"Failed to get available endpoints: {str(e)}")
211
+ raise e
@@ -0,0 +1,54 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class ConnectorEndpointArguments(BaseModel):
5
+ # id (str): The ID of the endpoint which is also the filename
6
+ # During creation, id is not required. The id is automatically generated and returned
7
+ id: str
8
+
9
+ name: str = Field(min_length=1) # name (str): The name for the endpoint.
10
+
11
+ connector_type: str # connector_type (str): The type of the LLM connector (e.g., 'GPT-3', 'Bert', etc.).
12
+
13
+ uri: str # uri (str): The URI (Uniform Resource Identifier) for the LLM connector's API.
14
+
15
+ token: str # token (str): The access token required to authenticate and access the LLM connector's API.
16
+
17
+ max_calls_per_second: int = Field(
18
+ gt=0
19
+ ) # max_calls_per_second (int): The number of api calls per second
20
+
21
+ max_concurrency: int = Field(
22
+ gt=0
23
+ ) # max_concurrency (int): The number of concurrent api calls
24
+
25
+ params: dict # params (dict): A dictionary that contains connection specified parameters
26
+
27
+ # created_date (str): The date and time the endpoint was created in isoformat without 'T'.
28
+ # During creation, created_date is not required. The created_date is automatically generated and returned
29
+ created_date: str = ""
30
+
31
+ def to_dict(self) -> dict:
32
+ """
33
+ Converts the ConnectorEndpointArguments instance into a dictionary.
34
+
35
+ This method takes all the attributes of the ConnectorEndpointArguments instance and constructs a dictionary
36
+ with attribute names as keys and their corresponding values. This includes the id, name, connector_type, uri,
37
+ token, max_calls_per_second, max_concurrency, params, and created_date. This dictionary can be used for
38
+ serialization purposes, such as storing the endpoint information in a JSON file or sending it over a network.
39
+
40
+ Returns:
41
+ dict: A dictionary representation of the ConnectorEndpointArguments instance.
42
+ """
43
+
44
+ return {
45
+ "id": self.id,
46
+ "name": self.name,
47
+ "connector_type": self.connector_type,
48
+ "uri": self.uri,
49
+ "token": self.token,
50
+ "max_calls_per_second": self.max_calls_per_second,
51
+ "max_concurrency": self.max_concurrency,
52
+ "params": self.params,
53
+ "created_date": self.created_date,
54
+ }
File without changes