aiverify-moonshot 0.4.10__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.
- {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/METADATA +24 -26
- {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/RECORD +37 -36
- {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/WHEEL +1 -1
- moonshot/integrations/cli/benchmark/cookbook.py +8 -11
- moonshot/integrations/cli/benchmark/recipe.py +1 -5
- moonshot/integrations/cli/cli_errors.py +3 -0
- moonshot/integrations/cli/common/connectors.py +22 -10
- moonshot/integrations/web_api/app.py +1 -1
- moonshot/integrations/web_api/schemas/endpoint_create_dto.py +1 -0
- moonshot/integrations/web_api/services/endpoint_service.py +1 -0
- moonshot/src/api/api_bookmark.py +16 -5
- moonshot/src/api/api_connector.py +3 -3
- moonshot/src/api/api_connector_endpoint.py +6 -3
- moonshot/src/api/api_context_strategy.py +2 -2
- moonshot/src/api/api_cookbook.py +6 -6
- moonshot/src/api/api_dataset.py +5 -5
- moonshot/src/api/api_environment_variables.py +3 -0
- moonshot/src/api/api_metrics.py +1 -1
- moonshot/src/api/api_prompt_template.py +9 -0
- moonshot/src/api/api_recipe.py +3 -3
- moonshot/src/api/api_red_teaming.py +4 -8
- moonshot/src/api/api_result.py +10 -6
- moonshot/src/api/api_run.py +3 -3
- moonshot/src/api/api_runner.py +7 -6
- moonshot/src/api/api_session.py +11 -7
- moonshot/src/bookmark/bookmark.py +12 -5
- moonshot/src/connectors/connector.py +127 -62
- moonshot/src/connectors/connector_prompt_arguments.py +15 -5
- moonshot/src/connectors/connector_response.py +15 -0
- moonshot/src/connectors_endpoints/connector_endpoint.py +32 -20
- moonshot/src/connectors_endpoints/connector_endpoint_arguments.py +4 -1
- moonshot/src/messages_constants.py +85 -3
- moonshot/src/redteaming/attack/attack_module.py +34 -7
- moonshot/src/runs/run_arguments.py +43 -20
- {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/AUTHORS.md +0 -0
- {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/LICENSE.md +0 -0
- {aiverify_moonshot-0.4.10.dist-info → aiverify_moonshot-0.5.0.dist-info}/licenses/NOTICES.md +0 -0
|
@@ -3,16 +3,32 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import time
|
|
5
5
|
from abc import abstractmethod
|
|
6
|
-
from
|
|
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
|
|
14
|
+
from moonshot.src.connectors.connector_response import ConnectorResponse
|
|
13
15
|
from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
|
|
14
16
|
ConnectorEndpointArguments,
|
|
15
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
|
+
)
|
|
16
32
|
from moonshot.src.storage.storage import Storage
|
|
17
33
|
from moonshot.src.utils.import_modules import get_instance
|
|
18
34
|
from moonshot.src.utils.log import configure_logger
|
|
@@ -21,43 +37,56 @@ from moonshot.src.utils.log import configure_logger
|
|
|
21
37
|
logger = configure_logger(__name__)
|
|
22
38
|
|
|
23
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
|
+
|
|
24
67
|
def perform_retry(func):
|
|
25
68
|
"""
|
|
26
|
-
A decorator to perform retries on a function.
|
|
69
|
+
A decorator to perform retries on a function using tenacity.
|
|
27
70
|
|
|
28
|
-
This decorator wraps
|
|
29
|
-
if it fails. The number of
|
|
30
|
-
are determined by the `
|
|
31
|
-
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.
|
|
32
74
|
|
|
33
|
-
|
|
34
|
-
|
|
75
|
+
Args:
|
|
76
|
+
func (Callable): The asynchronous function to be wrapped and retried.
|
|
35
77
|
|
|
36
78
|
Returns:
|
|
37
|
-
|
|
79
|
+
Callable: A wrapper function that includes retry logic.
|
|
38
80
|
"""
|
|
39
81
|
|
|
40
82
|
async def wrapper(self, *args, **kwargs):
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
except Exception as exc:
|
|
49
|
-
logger.warning(f"Operation failed. {str(exc)} - Retrying...")
|
|
50
|
-
|
|
51
|
-
# Perform retry
|
|
52
|
-
retry_count += 1
|
|
53
|
-
if retry_count <= self.retries_times:
|
|
54
|
-
delay = base_delay * (2**retry_count)
|
|
55
|
-
logger.warning(
|
|
56
|
-
f"Attempt {retry_count}, Retrying in {delay} seconds..."
|
|
57
|
-
)
|
|
58
|
-
await sleep(delay)
|
|
59
|
-
# Raise an exception
|
|
60
|
-
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)
|
|
61
90
|
|
|
62
91
|
return wrapper
|
|
63
92
|
|
|
@@ -70,6 +99,7 @@ class Connector:
|
|
|
70
99
|
self.token = ep_args.token
|
|
71
100
|
self.max_concurrency = ep_args.max_concurrency
|
|
72
101
|
self.max_calls_per_second = ep_args.max_calls_per_second
|
|
102
|
+
self.model = ep_args.model
|
|
73
103
|
self.params = ep_args.params
|
|
74
104
|
|
|
75
105
|
# Rate limiting
|
|
@@ -79,21 +109,19 @@ class Connector:
|
|
|
79
109
|
self.updated_at = time.time()
|
|
80
110
|
self.semaphore = asyncio.Semaphore(ep_args.max_concurrency)
|
|
81
111
|
|
|
82
|
-
# Set Prompts if they
|
|
112
|
+
# Set Prompts if they exist
|
|
83
113
|
self.pre_prompt = ep_args.params.get("pre_prompt", "")
|
|
84
114
|
self.post_prompt = ep_args.params.get("post_prompt", "")
|
|
85
115
|
self.system_prompt = ep_args.params.get("system_prompt", "")
|
|
86
116
|
|
|
87
117
|
# Connection timeout
|
|
88
118
|
self.timeout = ep_args.params.get("timeout", 600)
|
|
89
|
-
self.
|
|
90
|
-
self.retries_times = ep_args.params.get("num_of_retries", 3)
|
|
119
|
+
self.max_attempts = ep_args.params.get("max_attempts", 3)
|
|
91
120
|
|
|
92
121
|
# Optional params
|
|
93
122
|
excluded_keys = {
|
|
94
|
-
"allow_retries",
|
|
95
123
|
"timeout",
|
|
96
|
-
"
|
|
124
|
+
"max_attempts",
|
|
97
125
|
"pre_prompt",
|
|
98
126
|
"post_prompt",
|
|
99
127
|
"system_prompt",
|
|
@@ -113,10 +141,6 @@ class Connector:
|
|
|
113
141
|
|
|
114
142
|
The method updates the `updated_at` attribute to the current time after tokens are added, ensuring that
|
|
115
143
|
the next token addition will be calculated based on the correct elapsed time.
|
|
116
|
-
|
|
117
|
-
Usage:
|
|
118
|
-
# Assume `self` is an instance of a class with `rate_limiter`, `tokens`, and `updated_at` attributes.
|
|
119
|
-
await self.add_tokens()
|
|
120
144
|
"""
|
|
121
145
|
now = time.time()
|
|
122
146
|
elapsed = now - self.updated_at
|
|
@@ -143,11 +167,6 @@ class Connector:
|
|
|
143
167
|
|
|
144
168
|
Returns:
|
|
145
169
|
Callable: The decorated function wrapped with rate limiting logic.
|
|
146
|
-
|
|
147
|
-
Usage:
|
|
148
|
-
@rate_limited
|
|
149
|
-
async def some_async_function(*args, **kwargs):
|
|
150
|
-
# Function implementation
|
|
151
170
|
"""
|
|
152
171
|
|
|
153
172
|
@wraps(func)
|
|
@@ -168,9 +187,9 @@ class Connector:
|
|
|
168
187
|
return wrapper
|
|
169
188
|
|
|
170
189
|
@abstractmethod
|
|
171
|
-
async def get_response(self, prompt: str) ->
|
|
190
|
+
async def get_response(self, prompt: str) -> ConnectorResponse:
|
|
172
191
|
"""
|
|
173
|
-
Abstract method to be implemented by subclasses to
|
|
192
|
+
Abstract method to be implemented by subclasses to obtain a response from the connector.
|
|
174
193
|
|
|
175
194
|
This method should asynchronously send a prompt to the connector's API and return the response.
|
|
176
195
|
|
|
@@ -178,14 +197,15 @@ class Connector:
|
|
|
178
197
|
prompt (str): The input prompt to be sent to the connector.
|
|
179
198
|
|
|
180
199
|
Returns:
|
|
181
|
-
|
|
200
|
+
ConnectorResponse: An instance containing the response received from the connector and any
|
|
201
|
+
additional metadata.
|
|
182
202
|
"""
|
|
183
203
|
pass
|
|
184
204
|
|
|
185
205
|
@classmethod
|
|
186
206
|
def load(cls, ep_args: ConnectorEndpointArguments) -> Connector:
|
|
187
207
|
"""
|
|
188
|
-
|
|
208
|
+
Dynamically loads a connector instance based on the provided endpoint arguments.
|
|
189
209
|
|
|
190
210
|
The connector type specified in the `ep_args` is used to dynamically load the corresponding
|
|
191
211
|
connector class. The connector is then instantiated with the provided endpoint arguments. If the
|
|
@@ -201,17 +221,24 @@ class Connector:
|
|
|
201
221
|
Raises:
|
|
202
222
|
RuntimeError: If the specified connector type does not match any available connector classes.
|
|
203
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
|
+
|
|
204
229
|
connector_instance = get_instance(
|
|
205
230
|
ep_args.connector_type,
|
|
206
231
|
Storage.get_filepath(
|
|
207
232
|
EnvVariables.CONNECTORS.name, ep_args.connector_type, "py"
|
|
208
233
|
),
|
|
209
234
|
)
|
|
210
|
-
if connector_instance:
|
|
235
|
+
if connector_instance and isinstance(connector_instance, Callable):
|
|
211
236
|
return connector_instance(ep_args)
|
|
212
237
|
else:
|
|
213
238
|
raise RuntimeError(
|
|
214
|
-
|
|
239
|
+
CONNECTOR_LOAD_CONNECTOR_INSTANCE_RUNTIME_ERROR.format(
|
|
240
|
+
message=ep_args.connector_type
|
|
241
|
+
)
|
|
215
242
|
)
|
|
216
243
|
|
|
217
244
|
@staticmethod
|
|
@@ -221,7 +248,7 @@ class Connector:
|
|
|
221
248
|
|
|
222
249
|
This method takes a ConnectorEndpointArguments object, which contains the necessary information
|
|
223
250
|
to initialize and return a Connector object. The Connector object is created by calling the
|
|
224
|
-
`
|
|
251
|
+
`load` method, which dynamically loads and initializes the connector based on the
|
|
225
252
|
endpoint arguments provided.
|
|
226
253
|
|
|
227
254
|
Args:
|
|
@@ -229,12 +256,20 @@ class Connector:
|
|
|
229
256
|
|
|
230
257
|
Returns:
|
|
231
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.
|
|
232
263
|
"""
|
|
233
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
|
+
)
|
|
234
269
|
return Connector.load(ep_args)
|
|
235
270
|
|
|
236
271
|
except Exception as e:
|
|
237
|
-
logger.error(
|
|
272
|
+
logger.error(CONNECTOR_CREATE_ERROR.format(message=str(e)))
|
|
238
273
|
raise e
|
|
239
274
|
|
|
240
275
|
@staticmethod
|
|
@@ -243,7 +278,7 @@ class Connector:
|
|
|
243
278
|
Fetches a list of all available connector types.
|
|
244
279
|
|
|
245
280
|
This method employs the `get_connectors` method to locate all Python files in the directory
|
|
246
|
-
defined by the `
|
|
281
|
+
defined by the `EnvVariables.CONNECTORS` environment variable. It subsequently excludes any files that are
|
|
247
282
|
not intended to be exposed as connectors (those containing "__" in their names). The method yields a list of the
|
|
248
283
|
names of these connector types.
|
|
249
284
|
|
|
@@ -261,7 +296,7 @@ class Connector:
|
|
|
261
296
|
]
|
|
262
297
|
|
|
263
298
|
except Exception as e:
|
|
264
|
-
logger.error(
|
|
299
|
+
logger.error(CONNECTOR_GET_AVAILABLE_ITEMS_ERROR.format(message=str(e)))
|
|
265
300
|
raise e
|
|
266
301
|
|
|
267
302
|
@staticmethod
|
|
@@ -277,7 +312,7 @@ class Connector:
|
|
|
277
312
|
object, which is used to generate the prediction. The method also optionally takes a `prompt_callback` function,
|
|
278
313
|
which is called after the prediction is generated.
|
|
279
314
|
|
|
280
|
-
The method
|
|
315
|
+
The method logs a message indicating that it is predicting the prompt. It then records the start time
|
|
281
316
|
and uses the `connector` to generate a prediction for the `generated_prompt`. The duration of the prediction
|
|
282
317
|
is calculated and stored in the `generated_prompt`.
|
|
283
318
|
|
|
@@ -297,9 +332,24 @@ class Connector:
|
|
|
297
332
|
Raises:
|
|
298
333
|
Exception: If there is an error during prediction.
|
|
299
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
|
+
|
|
300
347
|
try:
|
|
301
348
|
logger.info(
|
|
302
|
-
|
|
349
|
+
CONNECTOR_GET_PREDICTION_INFO.format(
|
|
350
|
+
connector_id=connector.id,
|
|
351
|
+
prompt_index=generated_prompt.prompt_index,
|
|
352
|
+
)
|
|
303
353
|
)
|
|
304
354
|
|
|
305
355
|
start_time = time.perf_counter()
|
|
@@ -308,7 +358,11 @@ class Connector:
|
|
|
308
358
|
)
|
|
309
359
|
generated_prompt.duration = time.perf_counter() - start_time
|
|
310
360
|
logger.debug(
|
|
311
|
-
|
|
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
|
+
)
|
|
312
366
|
)
|
|
313
367
|
|
|
314
368
|
# Call prompt callback
|
|
@@ -319,17 +373,28 @@ class Connector:
|
|
|
319
373
|
return generated_prompt
|
|
320
374
|
|
|
321
375
|
except Exception as e:
|
|
322
|
-
logger.error(
|
|
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
|
+
)
|
|
323
383
|
raise e
|
|
324
384
|
|
|
325
385
|
def set_system_prompt(self, system_prompt: str) -> None:
|
|
326
386
|
"""
|
|
327
|
-
|
|
387
|
+
Sets a new system prompt for this connector instance.
|
|
328
388
|
|
|
329
|
-
The system prompt
|
|
330
|
-
|
|
389
|
+
The system prompt is a predefined message or command that the connector can use to start interactions
|
|
390
|
+
or perform specific tasks.
|
|
331
391
|
|
|
332
|
-
|
|
392
|
+
Args:
|
|
333
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.
|
|
334
397
|
"""
|
|
398
|
+
if system_prompt is None or not isinstance(system_prompt, str):
|
|
399
|
+
raise ValueError(CONNECTOR_SET_SYSTEM_PROMPT_VALIDATION_ERROR)
|
|
335
400
|
self.system_prompt = system_prompt
|
|
@@ -1,17 +1,27 @@
|
|
|
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
|
+
|
|
7
|
+
from moonshot.src.connectors.connector_response import ConnectorResponse
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class ConnectorPromptArguments(BaseModel):
|
|
9
|
-
|
|
11
|
+
class Config:
|
|
12
|
+
arbitrary_types_allowed = True
|
|
13
|
+
|
|
14
|
+
prompt_index: Annotated[
|
|
15
|
+
int, Field(strict=True, ge=0)
|
|
16
|
+
] # The index of the prompt in the dataset
|
|
10
17
|
|
|
11
18
|
prompt: str # The actual prompt text
|
|
12
19
|
|
|
13
20
|
target: Any # The target response for the prompt
|
|
14
21
|
|
|
15
|
-
predicted_results:
|
|
22
|
+
predicted_results: ConnectorResponse | None = (
|
|
23
|
+
None # The predicted results, default is None
|
|
24
|
+
)
|
|
16
25
|
|
|
17
|
-
|
|
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
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ConnectorResponse(BaseModel):
|
|
5
|
+
response: str = ""
|
|
6
|
+
context: list = []
|
|
7
|
+
|
|
8
|
+
def to_dict(self) -> dict:
|
|
9
|
+
"""
|
|
10
|
+
Converts the ConnectorResponse instance to a dictionary.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
dict: A dictionary representation of the ConnectorResponse instance.
|
|
14
|
+
"""
|
|
15
|
+
return {"response": self.response, "context": self.context}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
from pydantic import validate_call
|
|
3
|
+
from pydantic import constr, validate_call
|
|
4
4
|
from slugify import slugify
|
|
5
5
|
|
|
6
6
|
from moonshot.src.configs.env_variables import EnvVariables
|
|
7
7
|
from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
|
|
8
8
|
ConnectorEndpointArguments,
|
|
9
9
|
)
|
|
10
|
+
from moonshot.src.messages_constants import (
|
|
11
|
+
CONNECTOR_ENDPOINT_CREATE_ERROR,
|
|
12
|
+
CONNECTOR_ENDPOINT_DELETE_ERROR,
|
|
13
|
+
CONNECTOR_ENDPOINT_GET_AVAILABLE_ITEMS_ERROR,
|
|
14
|
+
CONNECTOR_ENDPOINT_READ_ERROR,
|
|
15
|
+
CONNECTOR_ENDPOINT_READ_INVALID,
|
|
16
|
+
CONNECTOR_ENDPOINT_UPDATE_ERROR,
|
|
17
|
+
)
|
|
10
18
|
from moonshot.src.storage.storage import Storage
|
|
11
19
|
from moonshot.src.utils.log import configure_logger
|
|
12
20
|
|
|
@@ -16,6 +24,7 @@ logger = configure_logger(__name__)
|
|
|
16
24
|
|
|
17
25
|
class ConnectorEndpoint:
|
|
18
26
|
@staticmethod
|
|
27
|
+
@validate_call
|
|
19
28
|
def create(ep_args: ConnectorEndpointArguments) -> str:
|
|
20
29
|
"""
|
|
21
30
|
Creates a new connector endpoint and stores its details as a JSON object.
|
|
@@ -47,6 +56,7 @@ class ConnectorEndpoint:
|
|
|
47
56
|
"token": ep_args.token,
|
|
48
57
|
"max_calls_per_second": ep_args.max_calls_per_second,
|
|
49
58
|
"max_concurrency": ep_args.max_concurrency,
|
|
59
|
+
"model": ep_args.model,
|
|
50
60
|
"params": ep_args.params,
|
|
51
61
|
}
|
|
52
62
|
|
|
@@ -57,12 +67,12 @@ class ConnectorEndpoint:
|
|
|
57
67
|
return ep_id
|
|
58
68
|
|
|
59
69
|
except Exception as e:
|
|
60
|
-
logger.error(
|
|
70
|
+
logger.error(CONNECTOR_ENDPOINT_CREATE_ERROR.format(message=str(e)))
|
|
61
71
|
raise e
|
|
62
72
|
|
|
63
73
|
@staticmethod
|
|
64
74
|
@validate_call
|
|
65
|
-
def read(ep_id:
|
|
75
|
+
def read(ep_id: constr(min_length=1)) -> ConnectorEndpointArguments:
|
|
66
76
|
"""
|
|
67
77
|
Retrieves the details of a specified endpoint by its ID.
|
|
68
78
|
|
|
@@ -72,27 +82,24 @@ class ConnectorEndpoint:
|
|
|
72
82
|
any other error occurs, an exception is raised with an appropriate error message.
|
|
73
83
|
|
|
74
84
|
Args:
|
|
75
|
-
ep_id (
|
|
85
|
+
ep_id (constr(min_length=1)): The unique identifier of the endpoint whose details are to be retrieved.
|
|
76
86
|
|
|
77
87
|
Returns:
|
|
78
88
|
ConnectorEndpointArguments: An instance filled with the endpoint's details.
|
|
79
89
|
|
|
80
90
|
Raises:
|
|
81
|
-
RuntimeError: If the
|
|
91
|
+
RuntimeError: If the specified endpoint does not exist.
|
|
82
92
|
Exception: For any issues encountered during the file reading or data parsing process.
|
|
83
93
|
"""
|
|
84
94
|
try:
|
|
85
|
-
if not ep_id:
|
|
86
|
-
raise RuntimeError("Connector Endpoint ID is empty.")
|
|
87
|
-
|
|
88
95
|
endpoint_details = ConnectorEndpoint._read_endpoint(ep_id)
|
|
89
96
|
if not endpoint_details:
|
|
90
|
-
raise RuntimeError(
|
|
97
|
+
raise RuntimeError(CONNECTOR_ENDPOINT_READ_INVALID.format(ep_id=ep_id))
|
|
91
98
|
|
|
92
99
|
return ConnectorEndpointArguments(**endpoint_details)
|
|
93
100
|
|
|
94
101
|
except Exception as e:
|
|
95
|
-
logger.error(
|
|
102
|
+
logger.error(CONNECTOR_ENDPOINT_READ_ERROR.format(message=str(e)))
|
|
96
103
|
raise e
|
|
97
104
|
|
|
98
105
|
@staticmethod
|
|
@@ -124,6 +131,7 @@ class ConnectorEndpoint:
|
|
|
124
131
|
return connector_endpoint_info
|
|
125
132
|
|
|
126
133
|
@staticmethod
|
|
134
|
+
@validate_call
|
|
127
135
|
def update(ep_args: ConnectorEndpointArguments) -> bool:
|
|
128
136
|
"""
|
|
129
137
|
Updates the endpoint information in the storage based on the provided ConnectorEndpointArguments object.
|
|
@@ -138,11 +146,10 @@ class ConnectorEndpoint:
|
|
|
138
146
|
ep_args (ConnectorEndpointArguments): The object encapsulating the updated attributes of the endpoint.
|
|
139
147
|
|
|
140
148
|
Returns:
|
|
141
|
-
bool:
|
|
142
|
-
persisted to the storage; otherwise, an exception is raised.
|
|
149
|
+
bool: True if the update was successfully persisted to the storage; otherwise, an exception is raised.
|
|
143
150
|
|
|
144
151
|
Raises:
|
|
145
|
-
Exception:
|
|
152
|
+
Exception: If the update process encounters an error, potentially due to issues with data serialization or
|
|
146
153
|
storage access.
|
|
147
154
|
"""
|
|
148
155
|
try:
|
|
@@ -160,24 +167,24 @@ class ConnectorEndpoint:
|
|
|
160
167
|
return True
|
|
161
168
|
|
|
162
169
|
except Exception as e:
|
|
163
|
-
logger.error(
|
|
170
|
+
logger.error(CONNECTOR_ENDPOINT_UPDATE_ERROR.format(message=str(e)))
|
|
164
171
|
raise e
|
|
165
172
|
|
|
166
173
|
@staticmethod
|
|
167
174
|
@validate_call
|
|
168
|
-
def delete(ep_id:
|
|
175
|
+
def delete(ep_id: constr(min_length=1)) -> bool:
|
|
169
176
|
"""
|
|
170
177
|
Deletes the endpoint with the specified ID.
|
|
171
178
|
|
|
172
179
|
This method attempts to delete the endpoint corresponding to the given ID from the storage.
|
|
173
|
-
If the deletion is successful, it returns True. If an error occurs, it
|
|
180
|
+
If the deletion is successful, it returns True. If an error occurs, it logs an error message
|
|
174
181
|
and re-raises the exception.
|
|
175
182
|
|
|
176
183
|
Args:
|
|
177
|
-
ep_id (
|
|
184
|
+
ep_id (constr(min_length=1)): The unique identifier of the endpoint to be deleted
|
|
178
185
|
|
|
179
186
|
Returns:
|
|
180
|
-
bool: True if the endpoint was successfully deleted.
|
|
187
|
+
bool: True if the endpoint was successfully deleted; otherwise, an exception is raised.
|
|
181
188
|
|
|
182
189
|
Raises:
|
|
183
190
|
Exception: If the deletion process encounters an error.
|
|
@@ -187,7 +194,7 @@ class ConnectorEndpoint:
|
|
|
187
194
|
return True
|
|
188
195
|
|
|
189
196
|
except Exception as e:
|
|
190
|
-
logger.error(
|
|
197
|
+
logger.error(CONNECTOR_ENDPOINT_DELETE_ERROR.format(message=str(e)))
|
|
191
198
|
raise e
|
|
192
199
|
|
|
193
200
|
@staticmethod
|
|
@@ -204,6 +211,9 @@ class ConnectorEndpoint:
|
|
|
204
211
|
Returns:
|
|
205
212
|
tuple[list[str], list[ConnectorEndpointArguments]]: A tuple containing a list of endpoint IDs and a list of
|
|
206
213
|
ConnectorEndpointArguments objects with endpoint details.
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
Exception: If the process of fetching available items encounters an error.
|
|
207
217
|
"""
|
|
208
218
|
try:
|
|
209
219
|
retn_eps = []
|
|
@@ -223,5 +233,7 @@ class ConnectorEndpoint:
|
|
|
223
233
|
return retn_eps_ids, retn_eps
|
|
224
234
|
|
|
225
235
|
except Exception as e:
|
|
226
|
-
logger.error(
|
|
236
|
+
logger.error(
|
|
237
|
+
CONNECTOR_ENDPOINT_GET_AVAILABLE_ITEMS_ERROR.format(message=str(e))
|
|
238
|
+
)
|
|
227
239
|
raise e
|
|
@@ -22,6 +22,8 @@ class ConnectorEndpointArguments(BaseModel):
|
|
|
22
22
|
gt=0
|
|
23
23
|
) # max_concurrency (int): The number of concurrent api calls
|
|
24
24
|
|
|
25
|
+
model: str # model (str): The model identifier for the LLM connector.
|
|
26
|
+
|
|
25
27
|
params: dict # params (dict): A dictionary that contains connection specified parameters
|
|
26
28
|
|
|
27
29
|
# created_date (str): The date and time the endpoint was created in isoformat without 'T'.
|
|
@@ -34,7 +36,7 @@ class ConnectorEndpointArguments(BaseModel):
|
|
|
34
36
|
|
|
35
37
|
This method takes all the attributes of the ConnectorEndpointArguments instance and constructs a dictionary
|
|
36
38
|
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
|
|
39
|
+
token, max_calls_per_second, max_concurrency, model, params, and created_date. This dictionary can be used for
|
|
38
40
|
serialization purposes, such as storing the endpoint information in a JSON file or sending it over a network.
|
|
39
41
|
|
|
40
42
|
Returns:
|
|
@@ -49,6 +51,7 @@ class ConnectorEndpointArguments(BaseModel):
|
|
|
49
51
|
"token": self.token,
|
|
50
52
|
"max_calls_per_second": self.max_calls_per_second,
|
|
51
53
|
"max_concurrency": self.max_concurrency,
|
|
54
|
+
"model": self.model,
|
|
52
55
|
"params": self.params,
|
|
53
56
|
"created_date": self.created_date,
|
|
54
57
|
}
|