Skip to content

Commit 480066d

Browse files
authored
HOTFIX--MCP-deploy-method-missing (#680)
* added deploy method to connection tool * BUG-620: fix mcp deploy error
1 parent d7d05d2 commit 480066d

File tree

13 files changed

+457
-147
lines changed

13 files changed

+457
-147
lines changed

.pre-commit-config.yaml

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,4 @@
11
repos:
2-
- repo: local
3-
hooks:
4-
- id: pytest-check
5-
name: pytest-check
6-
entry: coverage run --source=. -m pytest tests/unit
7-
language: python
8-
pass_filenames: false
9-
types: [python]
10-
always_run: true
11-
12-
- repo: https://github.com/psf/black
13-
rev: 25.1.0
14-
hooks:
15-
- id: black
16-
language_version: python3
17-
args: # arguments to configure black
18-
- --line-length=128
19-
202
- repo: https://github.com/pre-commit/pre-commit-hooks
213
rev: v5.0.0 # Use the latest version
224
hooks:
@@ -25,16 +7,19 @@ repos:
257
- id: check-merge-conflict
268
- id: check-added-large-files
279

28-
- repo: https://github.com/pycqa/flake8
29-
rev: 7.2.0
30-
hooks:
31-
- id: flake8
32-
args: # arguments to configure flake8
33-
- --ignore=E402,E501,E203,W503
34-
3510
- repo: https://github.com/astral-sh/ruff-pre-commit
3611
rev: v0.12.12
3712
hooks:
3813
- id: ruff
3914
args: [--fix]
4015
- id: ruff-format
16+
17+
- repo: local
18+
hooks:
19+
- id: pytest-check
20+
name: pytest-check
21+
entry: coverage run --source=. -m pytest tests/unit
22+
language: python
23+
pass_filenames: false
24+
types: [python]
25+
always_run: true

aixplain/exceptions/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
"""
2-
Error message registry for aiXplain SDK.
1+
"""Error message registry for aiXplain SDK.
32
43
This module maintains a centralized registry of error messages used throughout the aiXplain ecosystem.
54
It allows developers to look up existing error messages and reuse them instead of creating new ones.
@@ -9,6 +8,7 @@
98
AixplainBaseException,
109
AuthenticationError,
1110
ValidationError,
11+
AlreadyDeployedError,
1212
ResourceError,
1313
BillingError,
1414
SupplierError,
@@ -19,12 +19,11 @@
1919

2020

2121
def get_error_from_status_code(status_code: int, error_details: str = None) -> AixplainBaseException:
22-
"""
23-
Map HTTP status codes to appropriate exception types.
22+
"""Map HTTP status codes to appropriate exception types.
2423
2524
Args:
2625
status_code (int): The HTTP status code to map.
27-
default_message (str, optional): The default message to use if no specific message is available.
26+
error_details (str, optional): Additional error details to include in the message.
2827
2928
Returns:
3029
AixplainBaseException: An exception of the appropriate type.
@@ -112,5 +111,6 @@ def get_error_from_status_code(status_code: int, error_details: str = None) -> A
112111
# Catch-all for other client/server errors
113112
category = "Client" if 400 <= status_code < 500 else "Server"
114113
return InternalError(
115-
message=f"Unspecified {category} Error (Status {status_code}) {error_details}".strip(), status_code=status_code
114+
message=f"Unspecified {category} Error (Status {status_code}) {error_details}".strip(),
115+
status_code=status_code,
116116
)

aixplain/exceptions/types.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Exception types and error handling for the aiXplain SDK."""
2+
13
from enum import Enum
24
from typing import Optional, Dict, Any
35

@@ -121,6 +123,17 @@ def __init__(
121123
retry_recommended: bool = False,
122124
error_code: Optional[ErrorCode] = None,
123125
):
126+
"""Initialize the base exception with structured error information.
127+
128+
Args:
129+
message: Error message describing the issue.
130+
category: Category of the error (default: UNKNOWN).
131+
severity: Severity level of the error (default: ERROR).
132+
status_code: HTTP status code if applicable.
133+
details: Additional error context and details.
134+
retry_recommended: Whether retrying the operation might succeed.
135+
error_code: Standardized error code for the exception.
136+
"""
124137
self.message = message
125138
self.category = category
126139
self.severity = severity
@@ -163,6 +176,12 @@ class AuthenticationError(AixplainBaseException):
163176
"""Raised when authentication fails."""
164177

165178
def __init__(self, message: str, **kwargs):
179+
"""Initialize authentication error.
180+
181+
Args:
182+
message: Error message describing the authentication issue.
183+
**kwargs: Additional keyword arguments passed to parent class.
184+
"""
166185
super().__init__(
167186
message=message,
168187
category=ErrorCategory.AUTHENTICATION,
@@ -177,6 +196,12 @@ class ValidationError(AixplainBaseException):
177196
"""Raised when input validation fails."""
178197

179198
def __init__(self, message: str, **kwargs):
199+
"""Initialize validation error.
200+
201+
Args:
202+
message: Error message describing the validation issue.
203+
**kwargs: Additional keyword arguments passed to parent class.
204+
"""
180205
super().__init__(
181206
message=message,
182207
category=ErrorCategory.VALIDATION,
@@ -187,10 +212,34 @@ def __init__(self, message: str, **kwargs):
187212
)
188213

189214

215+
class AlreadyDeployedError(AixplainBaseException):
216+
"""Raised when attempting to deploy an asset that is already deployed."""
217+
218+
def __init__(self, message: str, **kwargs):
219+
"""Initialize already deployed error.
220+
221+
Args:
222+
message: Error message describing the deployment state conflict.
223+
**kwargs: Additional keyword arguments passed to parent class.
224+
"""
225+
super().__init__(
226+
message=message,
227+
retry_recommended=kwargs.pop("retry_recommended", False),
228+
error_code=ErrorCode.AX_VAL_ERROR,
229+
**kwargs,
230+
)
231+
232+
190233
class ResourceError(AixplainBaseException):
191234
"""Raised when a resource is unavailable."""
192235

193236
def __init__(self, message: str, **kwargs):
237+
"""Initialize resource error.
238+
239+
Args:
240+
message: Error message describing the resource issue.
241+
**kwargs: Additional keyword arguments passed to parent class.
242+
"""
194243
super().__init__(
195244
message=message,
196245
category=ErrorCategory.RESOURCE,
@@ -205,6 +254,12 @@ class BillingError(AixplainBaseException):
205254
"""Raised when there are billing issues."""
206255

207256
def __init__(self, message: str, **kwargs):
257+
"""Initialize billing error.
258+
259+
Args:
260+
message: Error message describing the billing issue.
261+
**kwargs: Additional keyword arguments passed to parent class.
262+
"""
208263
super().__init__(
209264
message=message,
210265
category=ErrorCategory.BILLING,
@@ -219,6 +274,12 @@ class SupplierError(AixplainBaseException):
219274
"""Raised when there are issues with external suppliers."""
220275

221276
def __init__(self, message: str, **kwargs):
277+
"""Initialize supplier error.
278+
279+
Args:
280+
message: Error message describing the supplier issue.
281+
**kwargs: Additional keyword arguments passed to parent class.
282+
"""
222283
super().__init__(
223284
message=message,
224285
category=ErrorCategory.SUPPLIER,
@@ -233,6 +294,12 @@ class NetworkError(AixplainBaseException):
233294
"""Raised when there are network connectivity issues."""
234295

235296
def __init__(self, message: str, **kwargs):
297+
"""Initialize network error.
298+
299+
Args:
300+
message: Error message describing the network issue.
301+
**kwargs: Additional keyword arguments passed to parent class.
302+
"""
236303
super().__init__(
237304
message=message,
238305
category=ErrorCategory.NETWORK,
@@ -247,6 +314,12 @@ class ServiceError(AixplainBaseException):
247314
"""Raised when a service is unavailable."""
248315

249316
def __init__(self, message: str, **kwargs):
317+
"""Initialize service error.
318+
319+
Args:
320+
message: Error message describing the service issue.
321+
**kwargs: Additional keyword arguments passed to parent class.
322+
"""
250323
super().__init__(
251324
message=message,
252325
category=ErrorCategory.SERVICE,
@@ -261,6 +334,12 @@ class InternalError(AixplainBaseException):
261334
"""Raised when there is an internal system error."""
262335

263336
def __init__(self, message: str, **kwargs):
337+
"""Initialize internal error.
338+
339+
Args:
340+
message: Error message describing the internal issue.
341+
**kwargs: Additional keyword arguments passed to parent class.
342+
"""
264343
# Server errors (5xx) should generally be retryable
265344
status_code = kwargs.get("status_code")
266345
retry_recommended = kwargs.pop("retry_recommended", False)

aixplain/modules/agent/__init__.py

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
__author__ = "aiXplain"
1+
"""Agent module for aiXplain SDK.
2+
3+
This module provides the Agent class and related functionality for creating and managing
4+
AI agents that can execute tasks using various tools and models.
25
3-
"""
46
Copyright 2024 The aiXplain SDK authors
57
68
Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,6 +22,8 @@
2022
Description:
2123
Agentification Class
2224
"""
25+
26+
__author__ = "aiXplain"
2327
import json
2428
import logging
2529
import re
@@ -33,7 +37,7 @@
3337
from aixplain.modules.model import Model
3438
from aixplain.modules.agent.agent_task import WorkflowTask, AgentTask
3539
from aixplain.modules.agent.output_format import OutputFormat
36-
from aixplain.modules.agent.tool import Tool
40+
from aixplain.modules.agent.tool import Tool, DeployableTool
3741
from aixplain.modules.agent.agent_response import AgentResponse
3842
from aixplain.modules.agent.agent_response_data import AgentResponseData
3943
from aixplain.modules.agent.utils import process_variables, validate_history
@@ -48,7 +52,7 @@
4852
import warnings
4953

5054

51-
class Agent(Model, DeployableMixin[Tool]):
55+
class Agent(Model, DeployableMixin[Union[Tool, DeployableTool]]):
5256
"""An advanced AI system that performs tasks using specialized tools from the aiXplain marketplace.
5357
5458
This class represents an AI agent that can understand natural language instructions,
@@ -124,6 +128,8 @@ def __init__(
124128
Defaults to AssetStatus.DRAFT.
125129
tasks (List[AgentTask], optional): List of tasks the Agent can perform.
126130
Defaults to empty list.
131+
workflow_tasks (List[WorkflowTask], optional): List of workflow tasks
132+
the Agent can execute. Defaults to empty list.
127133
output_format (OutputFormat, optional): default output format for agent responses. Defaults to OutputFormat.TEXT.
128134
expected_output (Union[BaseModel, Text, dict], optional): expected output. Defaults to None.
129135
**additional_info: Additional configuration parameters.
@@ -144,7 +150,8 @@ def __init__(
144150
self.status = status
145151
if tasks:
146152
warnings.warn(
147-
"The 'tasks' parameter is deprecated and will be removed in a future version. " "Use 'workflow_tasks' instead.",
153+
"The 'tasks' parameter is deprecated and will be removed in a future version. "
154+
"Use 'workflow_tasks' instead.",
148155
DeprecationWarning,
149156
stacklevel=2,
150157
)
@@ -171,9 +178,9 @@ def _validate(self) -> None:
171178
from aixplain.utils.llm_utils import get_llm_instance
172179

173180
# validate name
174-
assert (
175-
re.match(r"^[a-zA-Z0-9 \-\(\)]*$", self.name) is not None
176-
), "Agent Creation Error: Agent name contains invalid characters. Only alphanumeric characters, spaces, hyphens, and brackets are allowed."
181+
assert re.match(r"^[a-zA-Z0-9 \-\(\)]*$", self.name) is not None, (
182+
"Agent Creation Error: Agent name contains invalid characters. Only alphanumeric characters, spaces, hyphens, and brackets are allowed."
183+
)
177184

178185
llm = get_llm_instance(self.llm_id, api_key=self.api_key)
179186

@@ -233,6 +240,14 @@ def validate(self, raise_exception: bool = False) -> bool:
233240
return self.is_valid
234241

235242
def generate_session_id(self, history: list = None) -> str:
243+
"""Generate a unique session ID for agent conversations.
244+
245+
Args:
246+
history (list, optional): Previous conversation history. Defaults to None.
247+
248+
Returns:
249+
str: A unique session identifier based on timestamp and random components.
250+
"""
236251
if history:
237252
validate_history(history)
238253
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
@@ -307,6 +322,7 @@ def run(
307322
max_iterations (int, optional): maximum number of iterations between the agent and the tools. Defaults to 10.
308323
output_format (OutputFormat, optional): response format. If not provided, uses the format set during initialization.
309324
expected_output (Union[BaseModel, Text, dict], optional): expected output. Defaults to None.
325+
310326
Returns:
311327
Dict: parsed output from model
312328
"""
@@ -406,10 +422,10 @@ def run_async(
406422
expected_output (Union[BaseModel, Text, dict], optional): expected output. Defaults to None.
407423
output_format (ResponseFormat, optional): response format. Defaults to TEXT.
408424
evolve (Union[Dict[str, Any], EvolveParam, None], optional): evolve the agent configuration. Can be a dictionary, EvolveParam instance, or None.
425+
409426
Returns:
410427
dict: polling URL in response
411428
"""
412-
413429
if session_id is not None and history is not None:
414430
raise ValueError("Provide either `session_id` or `history`, not both.")
415431

@@ -434,7 +450,9 @@ def run_async(
434450
assert data is not None or query is not None, "Either 'data' or 'query' must be provided."
435451
if data is not None:
436452
if isinstance(data, dict):
437-
assert "query" in data and data["query"] is not None, "When providing a dictionary, 'query' must be provided."
453+
assert "query" in data and data["query"] is not None, (
454+
"When providing a dictionary, 'query' must be provided."
455+
)
438456
query = data.get("query")
439457
if session_id is None:
440458
session_id = data.get("session_id")
@@ -447,7 +465,9 @@ def run_async(
447465

448466
# process content inputs
449467
if content is not None:
450-
assert FileFactory.check_storage_type(query) == StorageType.TEXT, "When providing 'content', query must be text."
468+
assert FileFactory.check_storage_type(query) == StorageType.TEXT, (
469+
"When providing 'content', query must be text."
470+
)
451471

452472
if isinstance(content, list):
453473
assert len(content) <= 3, "The maximum number of content inputs is 3."
@@ -511,6 +531,11 @@ def run_async(
511531
)
512532

513533
def to_dict(self) -> Dict:
534+
"""Convert the Agent instance to a dictionary representation.
535+
536+
Returns:
537+
Dict: Dictionary containing the agent's configuration and metadata.
538+
"""
514539
from aixplain.factories.agent_factory.utils import build_tool_payload
515540

516541
return {
@@ -674,9 +699,9 @@ def delete(self) -> None:
674699
"referencing it."
675700
)
676701
else:
677-
message = f"Agent Deletion Error (HTTP {r.status_code}): " f"{error_message}."
702+
message = f"Agent Deletion Error (HTTP {r.status_code}): {error_message}."
678703
except ValueError:
679-
message = f"Agent Deletion Error (HTTP {r.status_code}): " "There was an error in deleting the agent."
704+
message = f"Agent Deletion Error (HTTP {r.status_code}): There was an error in deleting the agent."
680705
logging.error(message)
681706
raise Exception(message)
682707

@@ -701,7 +726,7 @@ def update(self) -> None:
701726
stack = inspect.stack()
702727
if len(stack) > 2 and stack[1].function != "save":
703728
warnings.warn(
704-
"update() is deprecated and will be removed in a future version. " "Please use save() instead.",
729+
"update() is deprecated and will be removed in a future version. Please use save() instead.",
705730
DeprecationWarning,
706731
stacklevel=2,
707732
)

0 commit comments

Comments
 (0)