blaxel 0.64.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.
- blaxel/__init__.py +8 -0
- blaxel/agents/__init__.py +5 -0
- blaxel/agents/chain.py +153 -0
- blaxel/agents/chat.py +286 -0
- blaxel/agents/decorator.py +208 -0
- blaxel/agents/thread.py +24 -0
- blaxel/agents/voice/openai.py +255 -0
- blaxel/agents/voice/utils.py +25 -0
- blaxel/api/__init__.py +1 -0
- blaxel/api/agents/__init__.py +0 -0
- blaxel/api/agents/create_agent.py +155 -0
- blaxel/api/agents/delete_agent.py +146 -0
- blaxel/api/agents/get_agent.py +146 -0
- blaxel/api/agents/get_agent_logs.py +151 -0
- blaxel/api/agents/get_agent_metrics.py +150 -0
- blaxel/api/agents/get_agent_trace_ids.py +201 -0
- blaxel/api/agents/list_agent_revisions.py +155 -0
- blaxel/api/agents/list_agents.py +127 -0
- blaxel/api/agents/update_agent.py +168 -0
- blaxel/api/configurations/__init__.py +0 -0
- blaxel/api/configurations/get_configuration.py +122 -0
- blaxel/api/default/__init__.py +0 -0
- blaxel/api/default/get_trace.py +150 -0
- blaxel/api/default/get_trace_ids.py +218 -0
- blaxel/api/default/get_trace_logs.py +186 -0
- blaxel/api/default/list_mcp_hub_definitions.py +127 -0
- blaxel/api/functions/__init__.py +0 -0
- blaxel/api/functions/create_function.py +155 -0
- blaxel/api/functions/delete_function.py +146 -0
- blaxel/api/functions/get_function.py +146 -0
- blaxel/api/functions/get_function_logs.py +151 -0
- blaxel/api/functions/get_function_metrics.py +150 -0
- blaxel/api/functions/get_function_trace_ids.py +201 -0
- blaxel/api/functions/list_function_revisions.py +158 -0
- blaxel/api/functions/list_functions.py +131 -0
- blaxel/api/functions/update_function.py +168 -0
- blaxel/api/integrations/__init__.py +0 -0
- blaxel/api/integrations/create_integration_connection.py +167 -0
- blaxel/api/integrations/delete_integration_connection.py +158 -0
- blaxel/api/integrations/get_integration.py +97 -0
- blaxel/api/integrations/get_integration_connection.py +158 -0
- blaxel/api/integrations/get_integration_connection_model.py +104 -0
- blaxel/api/integrations/get_integration_connection_model_endpoint_configurations.py +97 -0
- blaxel/api/integrations/list_integration_connection_models.py +97 -0
- blaxel/api/integrations/list_integration_connections.py +139 -0
- blaxel/api/integrations/update_integration_connection.py +180 -0
- blaxel/api/invitations/__init__.py +0 -0
- blaxel/api/invitations/list_all_pending_invitations.py +142 -0
- blaxel/api/knowledgebases/__init__.py +0 -0
- blaxel/api/knowledgebases/create_knowledgebase.py +163 -0
- blaxel/api/knowledgebases/delete_knowledgebase.py +154 -0
- blaxel/api/knowledgebases/get_knowledgebase.py +154 -0
- blaxel/api/knowledgebases/list_knowledgebase_revisions.py +158 -0
- blaxel/api/knowledgebases/list_knowledgebases.py +139 -0
- blaxel/api/knowledgebases/update_knowledgebase.py +176 -0
- blaxel/api/locations/__init__.py +0 -0
- blaxel/api/locations/list_locations.py +139 -0
- blaxel/api/metrics/__init__.py +0 -0
- blaxel/api/metrics/get_metrics.py +130 -0
- blaxel/api/models/__init__.py +0 -0
- blaxel/api/models/create_model.py +163 -0
- blaxel/api/models/delete_model.py +154 -0
- blaxel/api/models/get_model.py +154 -0
- blaxel/api/models/get_model_logs.py +155 -0
- blaxel/api/models/get_model_metrics.py +158 -0
- blaxel/api/models/get_model_trace_ids.py +201 -0
- blaxel/api/models/list_model_revisions.py +158 -0
- blaxel/api/models/list_models.py +135 -0
- blaxel/api/models/update_model.py +176 -0
- blaxel/api/policies/__init__.py +0 -0
- blaxel/api/policies/create_policy.py +167 -0
- blaxel/api/policies/delete_policy.py +154 -0
- blaxel/api/policies/get_policy.py +154 -0
- blaxel/api/policies/list_policies.py +139 -0
- blaxel/api/policies/update_policy.py +180 -0
- blaxel/api/privateclusters/__init__.py +0 -0
- blaxel/api/privateclusters/create_private_cluster.py +132 -0
- blaxel/api/privateclusters/delete_private_cluster.py +156 -0
- blaxel/api/privateclusters/get_private_cluster.py +159 -0
- blaxel/api/privateclusters/get_private_cluster_health.py +97 -0
- blaxel/api/privateclusters/list_private_clusters.py +140 -0
- blaxel/api/privateclusters/update_private_cluster.py +156 -0
- blaxel/api/privateclusters/update_private_cluster_health.py +97 -0
- blaxel/api/service_accounts/__init__.py +0 -0
- blaxel/api/service_accounts/create_api_key_for_service_account.py +177 -0
- blaxel/api/service_accounts/create_workspace_service_account.py +170 -0
- blaxel/api/service_accounts/delete_api_key_for_service_account.py +104 -0
- blaxel/api/service_accounts/delete_workspace_service_account.py +160 -0
- blaxel/api/service_accounts/get_workspace_service_accounts.py +141 -0
- blaxel/api/service_accounts/list_api_keys_for_service_account.py +163 -0
- blaxel/api/service_accounts/update_workspace_service_account.py +183 -0
- blaxel/api/store/__init__.py +0 -0
- blaxel/api/store/get_store_agent.py +146 -0
- blaxel/api/store/get_store_function.py +146 -0
- blaxel/api/store/list_store_agents.py +131 -0
- blaxel/api/store/list_store_functions.py +131 -0
- blaxel/api/workspaces/__init__.py +0 -0
- blaxel/api/workspaces/accept_workspace_invitation.py +161 -0
- blaxel/api/workspaces/create_worspace.py +163 -0
- blaxel/api/workspaces/decline_workspace_invitation.py +158 -0
- blaxel/api/workspaces/delete_workspace.py +154 -0
- blaxel/api/workspaces/get_workspace.py +154 -0
- blaxel/api/workspaces/invite_workspace_user.py +174 -0
- blaxel/api/workspaces/leave_workspace.py +161 -0
- blaxel/api/workspaces/list_workspace_users.py +139 -0
- blaxel/api/workspaces/list_workspaces.py +139 -0
- blaxel/api/workspaces/remove_workspace_user.py +101 -0
- blaxel/api/workspaces/update_workspace.py +176 -0
- blaxel/api/workspaces/update_workspace_user_role.py +187 -0
- blaxel/authentication/__init__.py +45 -0
- blaxel/authentication/apikey.py +50 -0
- blaxel/authentication/authentication.py +176 -0
- blaxel/authentication/clientcredentials.py +103 -0
- blaxel/authentication/credentials.py +295 -0
- blaxel/authentication/device_mode.py +197 -0
- blaxel/client.py +281 -0
- blaxel/common/__init__.py +17 -0
- blaxel/common/error.py +27 -0
- blaxel/common/instrumentation.py +317 -0
- blaxel/common/logger.py +60 -0
- blaxel/common/secrets.py +39 -0
- blaxel/common/settings.py +150 -0
- blaxel/common/slugify.py +18 -0
- blaxel/common/utils.py +34 -0
- blaxel/deploy/__init__.py +8 -0
- blaxel/deploy/deploy.py +316 -0
- blaxel/deploy/format.py +46 -0
- blaxel/deploy/parser.py +192 -0
- blaxel/errors.py +16 -0
- blaxel/functions/__init__.py +7 -0
- blaxel/functions/common.py +228 -0
- blaxel/functions/decorator.py +64 -0
- blaxel/functions/local/local.py +48 -0
- blaxel/functions/mcp/client.py +96 -0
- blaxel/functions/mcp/mcp.py +168 -0
- blaxel/functions/mcp/utils.py +56 -0
- blaxel/functions/remote/remote.py +183 -0
- blaxel/models/__init__.py +233 -0
- blaxel/models/acl.py +133 -0
- blaxel/models/agent.py +126 -0
- blaxel/models/agent_chain.py +88 -0
- blaxel/models/agent_spec.py +346 -0
- blaxel/models/api_key.py +142 -0
- blaxel/models/configuration.py +85 -0
- blaxel/models/continent.py +70 -0
- blaxel/models/core_event.py +97 -0
- blaxel/models/core_spec.py +249 -0
- blaxel/models/core_spec_configurations.py +77 -0
- blaxel/models/country.py +70 -0
- blaxel/models/create_api_key_for_service_account_body.py +69 -0
- blaxel/models/create_workspace_service_account_body.py +71 -0
- blaxel/models/create_workspace_service_account_response_200.py +105 -0
- blaxel/models/delete_workspace_service_account_response_200.py +96 -0
- blaxel/models/entrypoint.py +96 -0
- blaxel/models/entrypoint_env.py +45 -0
- blaxel/models/flavor.py +70 -0
- blaxel/models/form.py +120 -0
- blaxel/models/form_config.py +45 -0
- blaxel/models/form_oauthomitempty.py +45 -0
- blaxel/models/form_secrets.py +45 -0
- blaxel/models/function.py +126 -0
- blaxel/models/function_kit.py +97 -0
- blaxel/models/function_spec.py +310 -0
- blaxel/models/get_trace_ids_response_200.py +45 -0
- blaxel/models/get_trace_logs_response_200.py +45 -0
- blaxel/models/get_trace_response_200.py +45 -0
- blaxel/models/get_workspace_service_accounts_response_200_item.py +96 -0
- blaxel/models/histogram_bucket.py +79 -0
- blaxel/models/histogram_stats.py +88 -0
- blaxel/models/integration_connection.py +96 -0
- blaxel/models/integration_connection_spec.py +114 -0
- blaxel/models/integration_connection_spec_config.py +45 -0
- blaxel/models/integration_connection_spec_secret.py +45 -0
- blaxel/models/integration_model.py +162 -0
- blaxel/models/integration_repository.py +88 -0
- blaxel/models/invite_workspace_user_body.py +60 -0
- blaxel/models/knowledgebase.py +126 -0
- blaxel/models/knowledgebase_spec.py +163 -0
- blaxel/models/knowledgebase_spec_options.py +45 -0
- blaxel/models/last_n_requests_metric.py +79 -0
- blaxel/models/latency_metric.py +144 -0
- blaxel/models/location_response.py +113 -0
- blaxel/models/mcp_definition.py +188 -0
- blaxel/models/mcp_definition_entrypoint.py +45 -0
- blaxel/models/mcp_definition_form.py +45 -0
- blaxel/models/metadata.py +139 -0
- blaxel/models/metadata_labels.py +45 -0
- blaxel/models/metric.py +79 -0
- blaxel/models/metrics.py +169 -0
- blaxel/models/metrics_models.py +45 -0
- blaxel/models/metrics_request_total_per_code.py +45 -0
- blaxel/models/metrics_rps_per_code.py +45 -0
- blaxel/models/model.py +126 -0
- blaxel/models/model_private_cluster.py +79 -0
- blaxel/models/model_spec.py +249 -0
- blaxel/models/o_auth.py +72 -0
- blaxel/models/owner_fields.py +70 -0
- blaxel/models/pending_invitation.py +124 -0
- blaxel/models/pending_invitation_accept.py +85 -0
- blaxel/models/pending_invitation_render.py +147 -0
- blaxel/models/pending_invitation_render_invited_by.py +88 -0
- blaxel/models/pending_invitation_render_workspace.py +70 -0
- blaxel/models/pending_invitation_workspace_details.py +72 -0
- blaxel/models/pod_template_spec.py +45 -0
- blaxel/models/policy.py +96 -0
- blaxel/models/policy_location.py +70 -0
- blaxel/models/policy_max_tokens.py +106 -0
- blaxel/models/policy_spec.py +151 -0
- blaxel/models/private_cluster.py +183 -0
- blaxel/models/private_location.py +61 -0
- blaxel/models/repository.py +70 -0
- blaxel/models/request_duration_over_time_metric.py +97 -0
- blaxel/models/request_duration_over_time_metrics.py +80 -0
- blaxel/models/request_total_by_origin_metric.py +115 -0
- blaxel/models/request_total_by_origin_metric_request_total_by_origin.py +45 -0
- blaxel/models/request_total_by_origin_metric_request_total_by_origin_and_code.py +45 -0
- blaxel/models/request_total_metric.py +123 -0
- blaxel/models/request_total_metric_request_total_per_code.py +45 -0
- blaxel/models/request_total_metric_rps_per_code.py +45 -0
- blaxel/models/resource_log.py +79 -0
- blaxel/models/resource_metrics.py +270 -0
- blaxel/models/resource_metrics_request_total_per_code.py +45 -0
- blaxel/models/resource_metrics_rps_per_code.py +45 -0
- blaxel/models/revision_configuration.py +97 -0
- blaxel/models/revision_metadata.py +124 -0
- blaxel/models/runtime.py +196 -0
- blaxel/models/runtime_startup_probe.py +45 -0
- blaxel/models/serverless_config.py +80 -0
- blaxel/models/spec_configuration.py +70 -0
- blaxel/models/store_agent.py +178 -0
- blaxel/models/store_agent_labels.py +45 -0
- blaxel/models/store_configuration.py +151 -0
- blaxel/models/store_configuration_option.py +79 -0
- blaxel/models/store_function.py +211 -0
- blaxel/models/store_function_kit.py +97 -0
- blaxel/models/store_function_labels.py +45 -0
- blaxel/models/store_function_parameter.py +88 -0
- blaxel/models/time_fields.py +70 -0
- blaxel/models/token_rate_metric.py +88 -0
- blaxel/models/token_rate_metrics.py +120 -0
- blaxel/models/token_total_metric.py +106 -0
- blaxel/models/trace_ids_response.py +45 -0
- blaxel/models/update_workspace_service_account_body.py +69 -0
- blaxel/models/update_workspace_service_account_response_200.py +96 -0
- blaxel/models/update_workspace_user_role_body.py +60 -0
- blaxel/models/websocket_channel.py +88 -0
- blaxel/models/workspace.py +148 -0
- blaxel/models/workspace_labels.py +45 -0
- blaxel/models/workspace_user.py +115 -0
- blaxel/py.typed +1 -0
- blaxel/run.py +108 -0
- blaxel/serve/app.py +131 -0
- blaxel/serve/middlewares/__init__.py +10 -0
- blaxel/serve/middlewares/accesslog.py +32 -0
- blaxel/serve/middlewares/processtime.py +28 -0
- blaxel/types.py +46 -0
- blaxel-0.64.0.dist-info/METADATA +96 -0
- blaxel-0.64.0.dist-info/RECORD +261 -0
- blaxel-0.64.0.dist-info/WHEEL +4 -0
- blaxel-0.64.0.dist-info/entry_points.txt +2 -0
- blaxel-0.64.0.dist-info/licenses/LICENSE +21 -0
blaxel/common/logger.py
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
"""
|
2
|
+
This module provides a custom colored formatter for logging and an initialization function
|
3
|
+
to set up logging configurations for Blaxel applications.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import logging
|
7
|
+
|
8
|
+
|
9
|
+
class ColoredFormatter(logging.Formatter):
|
10
|
+
"""
|
11
|
+
A custom logging formatter that adds ANSI color codes to log levels for enhanced readability.
|
12
|
+
|
13
|
+
Attributes:
|
14
|
+
COLORS (dict): A mapping of log level names to their corresponding ANSI color codes.
|
15
|
+
"""
|
16
|
+
COLORS = {
|
17
|
+
"DEBUG": "\033[1;36m", # Cyan
|
18
|
+
"INFO": "\033[1;32m", # Green
|
19
|
+
"WARNING": "\033[1;33m", # Yellow
|
20
|
+
"ERROR": "\033[1;31m", # Red
|
21
|
+
"CRITICAL": "\033[1;41m", # Red background
|
22
|
+
}
|
23
|
+
|
24
|
+
def format(self, record):
|
25
|
+
"""
|
26
|
+
Formats the log record by adding color codes based on the log level.
|
27
|
+
|
28
|
+
Parameters:
|
29
|
+
record (LogRecord): The log record to format.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
str: The formatted log message with appropriate color codes.
|
33
|
+
"""
|
34
|
+
n_spaces = len("CRITICAL") - len(record.levelname)
|
35
|
+
tab = " " * n_spaces
|
36
|
+
color = self.COLORS.get(record.levelname, "\033[0m")
|
37
|
+
record.levelname = f"{color}{record.levelname}\033[0m:{tab}"
|
38
|
+
return super().format(record)
|
39
|
+
|
40
|
+
|
41
|
+
def init(log_level: str):
|
42
|
+
"""
|
43
|
+
Initializes the logging configuration for Blaxel.
|
44
|
+
|
45
|
+
This function clears existing handlers for specific loggers, sets up a colored formatter,
|
46
|
+
and configures the root logger with the specified log level.
|
47
|
+
|
48
|
+
Parameters:
|
49
|
+
log_level (str): The logging level to set (e.g., "DEBUG", "INFO").
|
50
|
+
"""
|
51
|
+
logging.getLogger("uvicorn.access").handlers.clear()
|
52
|
+
logging.getLogger("uvicorn.access").propagate = False
|
53
|
+
logging.getLogger("uvicorn.error").handlers.clear()
|
54
|
+
logging.getLogger("uvicorn.error").propagate = False
|
55
|
+
logging.getLogger("httpx").handlers.clear()
|
56
|
+
logging.getLogger("httpx").propagate = False
|
57
|
+
|
58
|
+
handler = logging.StreamHandler()
|
59
|
+
handler.setFormatter(ColoredFormatter("%(levelname)s %(name)s - %(message)s"))
|
60
|
+
logging.basicConfig(level=log_level, handlers=[handler])
|
blaxel/common/secrets.py
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
|
4
|
+
class Secret:
|
5
|
+
"""
|
6
|
+
A utility class for managing environment secrets.
|
7
|
+
|
8
|
+
Provides static methods to retrieve and set secret values, supporting both standard and
|
9
|
+
prefixed environment variable naming conventions.
|
10
|
+
"""
|
11
|
+
|
12
|
+
@staticmethod
|
13
|
+
def get(name: str):
|
14
|
+
"""
|
15
|
+
Retrieves the value of a secret environment variable.
|
16
|
+
|
17
|
+
This method first attempts to get the value using the standard name. If not found,
|
18
|
+
it tries with a "bl_" prefix.
|
19
|
+
|
20
|
+
Parameters:
|
21
|
+
name (str): The name of the environment variable to retrieve.
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
str: The value of the environment variable if found, otherwise an empty string.
|
25
|
+
"""
|
26
|
+
return os.getenv(name, os.getenv(f"bl_{name}"))
|
27
|
+
|
28
|
+
@staticmethod
|
29
|
+
def set(name: str, value: str):
|
30
|
+
"""
|
31
|
+
Sets the value of a secret environment variable.
|
32
|
+
|
33
|
+
This method sets the value using the standard name, allowing for consistent secret management.
|
34
|
+
|
35
|
+
Parameters:
|
36
|
+
name (str): The name of the environment variable to set.
|
37
|
+
value (str): The value to assign to the environment variable.
|
38
|
+
"""
|
39
|
+
os.environ[name] = value
|
@@ -0,0 +1,150 @@
|
|
1
|
+
"""
|
2
|
+
This module defines the configuration management system for Blaxel applications using Pydantic.
|
3
|
+
It includes dataclasses for various configuration aspects, such as agents, authentication, and server settings.
|
4
|
+
The module provides functions to initialize settings, load configurations from YAML files, and customize settings sources.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
from typing import Tuple, Type, Union
|
9
|
+
|
10
|
+
from langchain_core.language_models.chat_models import BaseChatModel
|
11
|
+
from langgraph.graph.graph import CompiledGraph
|
12
|
+
from pydantic import Field
|
13
|
+
from pydantic_settings import (
|
14
|
+
BaseSettings,
|
15
|
+
PydanticBaseSettingsSource,
|
16
|
+
SettingsConfigDict,
|
17
|
+
YamlConfigSettingsSource,
|
18
|
+
)
|
19
|
+
|
20
|
+
from blaxel.aimon.logger import init as init_logger
|
21
|
+
from blaxel.models import Agent, Function, Model
|
22
|
+
|
23
|
+
global SETTINGS
|
24
|
+
SETTINGS = None
|
25
|
+
|
26
|
+
class SettingsAgent(BaseSettings):
|
27
|
+
"""
|
28
|
+
Configuration settings for agents within Blaxel.
|
29
|
+
|
30
|
+
Attributes:
|
31
|
+
agent (Union[None, CompiledGraph]): The compiled agent graph.
|
32
|
+
chain (Union[None, list[Agent]]): A list of agent chains.
|
33
|
+
model (Union[None, Model]): The model configuration.
|
34
|
+
functions (Union[None, list[Function]]): A list of functions available to agents.
|
35
|
+
functions_directory (str): The directory path where agent functions are located.
|
36
|
+
chat_model (Union[None, BaseChatModel]): The chat model used by agents.
|
37
|
+
module (str): The module path to the main application.
|
38
|
+
"""
|
39
|
+
agent: Union[None, CompiledGraph] = None
|
40
|
+
chain: Union[None, list[Agent]] = None
|
41
|
+
model: Union[None, Model] = None
|
42
|
+
functions: Union[None, list[Function]] = None
|
43
|
+
functions_directory: str = Field(default="src/functions")
|
44
|
+
chat_model: Union[None, BaseChatModel] = None
|
45
|
+
module: str = Field(default="main.main")
|
46
|
+
|
47
|
+
|
48
|
+
class SettingsAuthenticationClient(BaseSettings):
|
49
|
+
"""
|
50
|
+
Configuration settings for authentication clients.
|
51
|
+
|
52
|
+
Attributes:
|
53
|
+
credentials (Union[None, str]): Client credentials for authentication.
|
54
|
+
"""
|
55
|
+
credentials: Union[None, str] = None
|
56
|
+
|
57
|
+
|
58
|
+
class SettingsAuthentication(BaseSettings):
|
59
|
+
apiKey: Union[None, str] = None
|
60
|
+
jwt: Union[None, str] = None
|
61
|
+
client: SettingsAuthenticationClient = SettingsAuthenticationClient()
|
62
|
+
|
63
|
+
|
64
|
+
class SettingsServer(BaseSettings):
|
65
|
+
module: str = Field(default="main.main")
|
66
|
+
port: int = Field(default=80)
|
67
|
+
host: str = Field(default="0.0.0.0")
|
68
|
+
directory: str = Field(default="src")
|
69
|
+
|
70
|
+
class Settings(BaseSettings):
|
71
|
+
model_config = SettingsConfigDict(
|
72
|
+
yaml_file="blaxel.yaml",
|
73
|
+
env_prefix="bl_",
|
74
|
+
env_nested_delimiter="_",
|
75
|
+
extra="ignore",
|
76
|
+
)
|
77
|
+
|
78
|
+
workspace: str
|
79
|
+
remote: bool = Field(default=False)
|
80
|
+
type: str = Field(default="agent")
|
81
|
+
name: str = Field(default="blaxel-agent")
|
82
|
+
base_url: str = Field(default="https://api.blaxel.ai/v0")
|
83
|
+
app_url: str = Field(default="https://app.blaxel.ai")
|
84
|
+
run_url: str = Field(default="https://run.blaxel.ai")
|
85
|
+
run_internal_hostname: str = Field(default="internal.run.blaxel.ai")
|
86
|
+
registry_url: str = Field(default="https://us.registry.blaxel.ai")
|
87
|
+
log_level: str = Field(default="INFO")
|
88
|
+
enable_opentelemetry: bool = Field(default=False)
|
89
|
+
cloud: bool = Field(default=False)
|
90
|
+
agent: SettingsAgent = SettingsAgent()
|
91
|
+
server: SettingsServer = SettingsServer()
|
92
|
+
authentication: SettingsAuthentication = SettingsAuthentication()
|
93
|
+
|
94
|
+
def __init__(self, **data):
|
95
|
+
super().__init__(**data)
|
96
|
+
if os.getenv('BL_ENV') == 'dev':
|
97
|
+
self.base_url = os.getenv('BL_BASE_URL') or "https://api.blaxel.dev/v0"
|
98
|
+
self.run_url = os.getenv('BL_RUN_URL') or "https://run.blaxel.dev"
|
99
|
+
self.registry_url = os.getenv('BL_REGISTRY_URL') or "https://eu.registry.blaxel.dev"
|
100
|
+
self.app_url = os.getenv('BL_APP_URL') or "https://app.blaxel.dev"
|
101
|
+
|
102
|
+
@classmethod
|
103
|
+
def settings_customise_sources(
|
104
|
+
cls,
|
105
|
+
settings_cls: Type[BaseSettings],
|
106
|
+
init_settings: PydanticBaseSettingsSource,
|
107
|
+
env_settings: PydanticBaseSettingsSource,
|
108
|
+
dotenv_settings: PydanticBaseSettingsSource,
|
109
|
+
file_secret_settings: PydanticBaseSettingsSource,
|
110
|
+
) -> Tuple[PydanticBaseSettingsSource, ...]:
|
111
|
+
return (
|
112
|
+
env_settings,
|
113
|
+
dotenv_settings,
|
114
|
+
file_secret_settings,
|
115
|
+
YamlConfigSettingsSource(settings_cls),
|
116
|
+
init_settings,
|
117
|
+
)
|
118
|
+
|
119
|
+
def get_settings() -> Settings:
|
120
|
+
"""
|
121
|
+
Retrieves the current settings instance.
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
Settings: The current settings configuration.
|
125
|
+
"""
|
126
|
+
return SETTINGS
|
127
|
+
|
128
|
+
def init() -> Settings:
|
129
|
+
"""
|
130
|
+
Initializes the settings by parsing the `blaxel.yaml` file and setting up logging.
|
131
|
+
|
132
|
+
This function reads workspace configuration from the current context,
|
133
|
+
initializes the global SETTINGS variable, and configures the logger based on the log level.
|
134
|
+
|
135
|
+
Returns:
|
136
|
+
Settings: The initialized settings configuration.
|
137
|
+
"""
|
138
|
+
from blaxel.authentication.credentials import current_context
|
139
|
+
|
140
|
+
global SETTINGS
|
141
|
+
|
142
|
+
context = current_context()
|
143
|
+
kwargs = {}
|
144
|
+
if context.workspace:
|
145
|
+
kwargs["workspace"] = context.workspace
|
146
|
+
|
147
|
+
SETTINGS = Settings(**kwargs)
|
148
|
+
init_logger(SETTINGS.log_level)
|
149
|
+
|
150
|
+
return SETTINGS
|
blaxel/common/slugify.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
"""
|
2
|
+
This module provides utility functions for string manipulation, including slugification.
|
3
|
+
The `slugify` function transforms a given string into a URL-friendly slug by replacing spaces and underscores with hyphens and converting the string to lowercase.
|
4
|
+
"""
|
5
|
+
|
6
|
+
def slugify(name: str) -> str:
|
7
|
+
"""
|
8
|
+
Converts a given string into a URL-friendly slug.
|
9
|
+
|
10
|
+
This function transforms the input string by converting it to lowercase and replacing spaces and underscores with hyphens.
|
11
|
+
|
12
|
+
Parameters:
|
13
|
+
name (str): The string to slugify.
|
14
|
+
|
15
|
+
Returns:
|
16
|
+
str: The slugified version of the input string.
|
17
|
+
"""
|
18
|
+
return name.lower().replace(" ", "-").replace("_", "-")
|
blaxel/common/utils.py
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
"""
|
2
|
+
This module provides utility functions for file operations within Blaxel.
|
3
|
+
It includes functions to copy folders and synchronize directory contents efficiently.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import filecmp
|
7
|
+
import os
|
8
|
+
import shutil
|
9
|
+
|
10
|
+
|
11
|
+
def copy_folder(source_folder: str, destination_folder: str):
|
12
|
+
"""
|
13
|
+
Copies the contents of the source folder to the destination folder.
|
14
|
+
|
15
|
+
This function recursively copies all files and subdirectories from the `source_folder` to the `destination_folder`.
|
16
|
+
It ensures that existing files are only overwritten if they differ from the source.
|
17
|
+
|
18
|
+
Parameters:
|
19
|
+
source_folder (str): The path to the source directory.
|
20
|
+
destination_folder (str): The path to the destination directory.
|
21
|
+
|
22
|
+
Raises:
|
23
|
+
FileNotFoundError: If the source folder does not exist.
|
24
|
+
PermissionError: If the program lacks permissions to read from the source or write to the destination.
|
25
|
+
"""
|
26
|
+
for file in os.listdir(source_folder):
|
27
|
+
if os.path.isdir(f"{source_folder}/{file}"):
|
28
|
+
if not os.path.exists(f"{destination_folder}/{file}"):
|
29
|
+
os.makedirs(f"{destination_folder}/{file}")
|
30
|
+
copy_folder(f"{source_folder}/{file}", f"{destination_folder}/{file}")
|
31
|
+
elif not os.path.exists(f"{destination_folder}/{file}") or not filecmp.cmp(
|
32
|
+
f"{source_folder}/{file}", f"{destination_folder}/{file}"
|
33
|
+
):
|
34
|
+
shutil.copy(f"{source_folder}/{file}", f"{destination_folder}/{file}")
|
@@ -0,0 +1,8 @@
|
|
1
|
+
"""
|
2
|
+
This module provides functions and classes to handle deployment processes within Blaxel.
|
3
|
+
It includes utilities to generate deployment configurations and manage deployment-related operations.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from .deploy import generate_blaxel_deployment
|
7
|
+
|
8
|
+
__all__ = ["generate_blaxel_deployment"]
|
blaxel/deploy/deploy.py
ADDED
@@ -0,0 +1,316 @@
|
|
1
|
+
"""
|
2
|
+
This module provides functionalities to generate and manage Blaxel deployment configurations.
|
3
|
+
It includes functions to set default deployment values, create deployment configurations from resources,
|
4
|
+
format deployments, and clean up auto-generated deployments.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import ast
|
8
|
+
import json
|
9
|
+
import os
|
10
|
+
import shutil
|
11
|
+
import sys
|
12
|
+
from logging import getLogger
|
13
|
+
from pathlib import Path
|
14
|
+
from typing import Literal
|
15
|
+
|
16
|
+
import yaml
|
17
|
+
|
18
|
+
from blaxel.aimon import slugify
|
19
|
+
from blaxel.aimon.settings import Settings, get_settings, init
|
20
|
+
from blaxel.api.agents import get_agent
|
21
|
+
from blaxel.authentication import new_client
|
22
|
+
from blaxel.client import AuthenticatedClient
|
23
|
+
from blaxel.models import (
|
24
|
+
Agent,
|
25
|
+
AgentSpec,
|
26
|
+
Flavor,
|
27
|
+
Function,
|
28
|
+
FunctionSpec,
|
29
|
+
Metadata,
|
30
|
+
MetadataLabels,
|
31
|
+
)
|
32
|
+
|
33
|
+
from .format import arg_to_dict
|
34
|
+
from .parser import Resource, get_description, get_parameters, get_resources
|
35
|
+
|
36
|
+
sys.path.insert(0, os.getcwd())
|
37
|
+
sys.path.insert(0, os.path.join(os.getcwd(), "src"))
|
38
|
+
|
39
|
+
def set_default_values(resource: Resource, deployment: Agent | Function):
|
40
|
+
"""
|
41
|
+
Sets default values for a deployment based on the resource and deployment type.
|
42
|
+
|
43
|
+
Parameters:
|
44
|
+
resource (Resource): The resource information.
|
45
|
+
deployment (Agent | Function): The deployment instance to set defaults for.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
Agent | Function: The updated deployment with default values set.
|
49
|
+
"""
|
50
|
+
settings = get_settings()
|
51
|
+
deployment.metadata.workspace = settings.workspace
|
52
|
+
if not deployment.metadata.name:
|
53
|
+
deployment.metadata.name = slugify(resource.name)
|
54
|
+
if not deployment.metadata.display_name:
|
55
|
+
deployment.metadata.display_name = deployment.metadata.name
|
56
|
+
if not deployment.spec.description:
|
57
|
+
deployment.spec.description = get_description(None, resource)
|
58
|
+
if isinstance(deployment, Agent):
|
59
|
+
deployment.spec.functions = []
|
60
|
+
for arg in resource.decorator.keywords:
|
61
|
+
if arg.arg == "remote_functions":
|
62
|
+
if isinstance(arg.value, ast.List):
|
63
|
+
for value in arg.value.elts:
|
64
|
+
if isinstance(value, ast.Constant):
|
65
|
+
deployment.spec.functions.append(slugify(value.value))
|
66
|
+
return deployment
|
67
|
+
|
68
|
+
def get_blaxel_deployment_from_resource(
|
69
|
+
settings: Settings,
|
70
|
+
resource: Resource,
|
71
|
+
) -> Agent | Function:
|
72
|
+
"""
|
73
|
+
Creates a deployment configuration from a given resource.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
resource (Resource): The resource to create a deployment for.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
Agent | Function: The deployment configuration.
|
80
|
+
"""
|
81
|
+
for arg in resource.decorator.keywords:
|
82
|
+
if arg.arg == "agent":
|
83
|
+
if isinstance(arg.value, ast.Dict):
|
84
|
+
value = arg_to_dict(arg.value)
|
85
|
+
metadata = Metadata(**value.get("metadata", {}))
|
86
|
+
spec = AgentSpec(**value.get("spec", {}))
|
87
|
+
agent = Agent(metadata=metadata, spec=spec)
|
88
|
+
if not agent.spec.prompt:
|
89
|
+
agent.spec.prompt = get_description(None, resource)
|
90
|
+
return set_default_values(resource, agent)
|
91
|
+
if arg.arg == "function":
|
92
|
+
if isinstance(arg.value, ast.Dict):
|
93
|
+
value = arg_to_dict(arg.value)
|
94
|
+
metadata = Metadata(**value.get("metadata", {}))
|
95
|
+
spec = FunctionSpec(**value.get("spec", {}))
|
96
|
+
func = Function(metadata=metadata, spec=spec)
|
97
|
+
if not func.spec.parameters:
|
98
|
+
func.spec.parameters = get_parameters(resource)
|
99
|
+
return set_default_values(resource, func)
|
100
|
+
if resource.type == "agent":
|
101
|
+
agent = Agent(metadata=Metadata(), spec=AgentSpec())
|
102
|
+
return set_default_values(resource, agent)
|
103
|
+
if resource.type == "function":
|
104
|
+
func = Function(metadata=Metadata(), spec=FunctionSpec())
|
105
|
+
func.spec.parameters = get_parameters(resource)
|
106
|
+
return set_default_values(resource, func)
|
107
|
+
return None
|
108
|
+
|
109
|
+
def get_flavors(flavors: list[Flavor]) -> str:
|
110
|
+
"""
|
111
|
+
Converts a list of Flavor objects to a JSON string.
|
112
|
+
|
113
|
+
Args:
|
114
|
+
flavors (list[Flavor]): List of Flavor objects.
|
115
|
+
|
116
|
+
Returns:
|
117
|
+
str: JSON string representation of flavors.
|
118
|
+
"""
|
119
|
+
if not flavors:
|
120
|
+
return "[]"
|
121
|
+
return json.dumps([flavor.to_dict() for flavor in flavors])
|
122
|
+
|
123
|
+
def get_agent_yaml(
|
124
|
+
agent: Agent, functions: list[tuple[Resource, Function]], settings: Settings, client: AuthenticatedClient
|
125
|
+
) -> str:
|
126
|
+
"""
|
127
|
+
Generates YAML configuration for an agent deployment.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
agent (Agent): Agent deployment configuration
|
131
|
+
functions (list[tuple[Resource, FunctionDeployment]]): List of associated functions
|
132
|
+
settings (Settings): Application settings
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
str: YAML configuration string
|
136
|
+
"""
|
137
|
+
try:
|
138
|
+
agent_response = get_agent.sync(agent.metadata.name, client=client)
|
139
|
+
agent.spec.repository = agent_response.spec.repository
|
140
|
+
except Exception:
|
141
|
+
pass
|
142
|
+
agent.spec.functions = agent.spec.functions or []
|
143
|
+
agent.spec.functions = agent.spec.functions + [slugify(function.metadata.name) for (_, function) in functions]
|
144
|
+
agent.metadata.labels = agent.metadata.labels and MetadataLabels.from_dict(agent.metadata.labels) or MetadataLabels()
|
145
|
+
agent.metadata.labels["x-blaxel-auto-generated"] = "true"
|
146
|
+
agent_yaml = yaml.dump(agent.to_dict())
|
147
|
+
template = f"""
|
148
|
+
apiVersion: blaxel.ai/v1alpha1
|
149
|
+
kind: Agent
|
150
|
+
{agent_yaml}
|
151
|
+
"""
|
152
|
+
return template
|
153
|
+
|
154
|
+
|
155
|
+
def get_function_yaml(function: Function, settings: Settings, client: AuthenticatedClient) -> str:
|
156
|
+
"""
|
157
|
+
Generates YAML configuration for a function deployment.
|
158
|
+
|
159
|
+
Args:
|
160
|
+
function (FunctionDeployment): Function deployment configuration
|
161
|
+
settings (Settings): Application settings
|
162
|
+
|
163
|
+
Returns:
|
164
|
+
str: YAML configuration string
|
165
|
+
"""
|
166
|
+
function.metadata.labels = function.metadata.labels and MetadataLabels.from_dict(function.metadata.labels) or MetadataLabels()
|
167
|
+
function.metadata.labels["x-blaxel-auto-generated"] = "true"
|
168
|
+
function_yaml = yaml.dump(function.to_dict())
|
169
|
+
return f"""
|
170
|
+
apiVersion: blaxel.ai/v1alpha1
|
171
|
+
kind: Function
|
172
|
+
{function_yaml}
|
173
|
+
"""
|
174
|
+
|
175
|
+
|
176
|
+
def dockerfile(
|
177
|
+
type: Literal["agent", "function"],
|
178
|
+
resource: Resource,
|
179
|
+
deployment: Agent | Function,
|
180
|
+
) -> str:
|
181
|
+
"""
|
182
|
+
Generates Dockerfile content for agent or function deployment.
|
183
|
+
|
184
|
+
Args:
|
185
|
+
type (Literal["agent", "function"]): Type of deployment
|
186
|
+
resource (Resource): Resource to be deployed
|
187
|
+
deployment (Agent | Function): Resource configuration
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
str: Dockerfile content
|
191
|
+
"""
|
192
|
+
settings = get_settings()
|
193
|
+
if type == "agent":
|
194
|
+
module = f"{resource.module.__file__.split('/')[-1].replace('.py', '')}.{resource.module.__name__}"
|
195
|
+
else:
|
196
|
+
module = f"functions.{resource.module.__file__.split('/')[-1].replace('.py', '')}.{resource.module.__name__}"
|
197
|
+
cmd = ["bl", "serve", "--port", "80", "--module", module]
|
198
|
+
if type == "agent":
|
199
|
+
cmd.append("--remote")
|
200
|
+
cmd_str = ",".join([f'"{c}"' for c in cmd])
|
201
|
+
return f"""
|
202
|
+
FROM python:3.12-slim
|
203
|
+
|
204
|
+
ARG UV_VERSION="latest"
|
205
|
+
RUN apt update && apt install -y curl build-essential
|
206
|
+
|
207
|
+
# Install uv.
|
208
|
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
209
|
+
RUN curl -fsSL https://raw.githubusercontent.com/beamlit/toolkit/main/install.sh | BINDIR=/bin sh
|
210
|
+
WORKDIR /blaxel
|
211
|
+
|
212
|
+
# Install the application dependencies.
|
213
|
+
COPY pyproject.toml /blaxel/pyproject.toml
|
214
|
+
COPY uv.lock /blaxel/uv.lock
|
215
|
+
|
216
|
+
COPY README.m[d] /blaxel/README.md
|
217
|
+
COPY LICENS[E] /blaxel/LICENSE
|
218
|
+
COPY {settings.server.directory} /blaxel/src
|
219
|
+
|
220
|
+
RUN uv sync --no-cache --no-dev
|
221
|
+
|
222
|
+
ENV PATH="/blaxel/.venv/bin:$PATH"
|
223
|
+
|
224
|
+
ENTRYPOINT [{cmd_str}]
|
225
|
+
"""
|
226
|
+
|
227
|
+
def clean_auto_generated(
|
228
|
+
directory: str,
|
229
|
+
type: Literal["agent", "function"],
|
230
|
+
deployments: list[tuple[Resource, Agent | Function]]
|
231
|
+
):
|
232
|
+
"""
|
233
|
+
Cleans up auto-generated deployments of a specific type.
|
234
|
+
|
235
|
+
Args:
|
236
|
+
directory (str): Base directory containing deployments.
|
237
|
+
type (Literal["agent", "function"]): Type of deployment to clean ("agent" or "function").
|
238
|
+
deployments (list[tuple[Resource, Agent | Function]]): List of deployment resources and configurations.
|
239
|
+
"""
|
240
|
+
|
241
|
+
deploy_dir = Path(directory) / f"{type}s"
|
242
|
+
deploy_names = [d.metadata.name for (_, d) in deployments]
|
243
|
+
|
244
|
+
if deploy_dir.exists():
|
245
|
+
for item_dir in deploy_dir.iterdir():
|
246
|
+
if item_dir.is_dir() and item_dir.name not in deploy_names:
|
247
|
+
yaml_file = item_dir / f"{type}.yaml"
|
248
|
+
if yaml_file.exists():
|
249
|
+
with open(yaml_file) as f:
|
250
|
+
try:
|
251
|
+
content = yaml.safe_load(f)
|
252
|
+
if content.get("metadata", {}).get("labels", {}).get("x-blaxel-auto-generated") == "true":
|
253
|
+
shutil.rmtree(item_dir)
|
254
|
+
except yaml.YAMLError:
|
255
|
+
continue
|
256
|
+
|
257
|
+
def generate_blaxel_deployment(directory: str, name: str):
|
258
|
+
"""
|
259
|
+
Generates all necessary deployment files for Blaxel agents and functions.
|
260
|
+
|
261
|
+
Args:
|
262
|
+
directory (str): Target directory for generated files.
|
263
|
+
name (str): Name identifier for the deployment.
|
264
|
+
|
265
|
+
Creates:
|
266
|
+
- Agent and function YAML configurations.
|
267
|
+
- Dockerfiles for each deployment.
|
268
|
+
- Directory structure for agents and functions.
|
269
|
+
"""
|
270
|
+
settings = init()
|
271
|
+
client = new_client()
|
272
|
+
logger = getLogger(__name__)
|
273
|
+
logger.info(f"Importing server module: {settings.server.module}")
|
274
|
+
functions: list[tuple[Resource, Function]] = []
|
275
|
+
agents: list[tuple[Resource, Agent]] = []
|
276
|
+
for resource in get_resources("agent", settings.server.directory):
|
277
|
+
agent = get_blaxel_deployment_from_resource(settings, resource)
|
278
|
+
if name and agent.metadata.name != name:
|
279
|
+
agent.metadata.name = slugify(name)
|
280
|
+
if agent:
|
281
|
+
agents.append((resource, agent))
|
282
|
+
for resource in get_resources("function", settings.server.directory):
|
283
|
+
function = get_blaxel_deployment_from_resource(settings, resource)
|
284
|
+
if function:
|
285
|
+
functions.append((resource, function))
|
286
|
+
|
287
|
+
agents_dir = os.path.join(directory, "agents")
|
288
|
+
functions_dir = os.path.join(directory, "functions")
|
289
|
+
# Create directory if it doesn't exist
|
290
|
+
os.makedirs(agents_dir, exist_ok=True)
|
291
|
+
os.makedirs(functions_dir, exist_ok=True)
|
292
|
+
for resource, agent in agents:
|
293
|
+
# write deployment file
|
294
|
+
agent_dir = os.path.join(agents_dir, agent.metadata.name)
|
295
|
+
os.makedirs(agent_dir, exist_ok=True)
|
296
|
+
with open(os.path.join(agent_dir, "agent.yaml"), "w") as f:
|
297
|
+
content = get_agent_yaml(agent, functions, settings, client)
|
298
|
+
f.write(content)
|
299
|
+
# write dockerfile for build
|
300
|
+
with open(os.path.join(agent_dir, "Dockerfile"), "w") as f:
|
301
|
+
content = dockerfile("agent", resource, agent)
|
302
|
+
f.write(content)
|
303
|
+
for resource, function in functions:
|
304
|
+
# write deployment file
|
305
|
+
function_dir = os.path.join(functions_dir, function.metadata.name)
|
306
|
+
os.makedirs(function_dir, exist_ok=True)
|
307
|
+
with open(os.path.join(function_dir, "function.yaml"), "w") as f:
|
308
|
+
content = get_function_yaml(function, settings, client)
|
309
|
+
f.write(content)
|
310
|
+
# write dockerfile for build
|
311
|
+
with open(os.path.join(function_dir, "Dockerfile"), "w") as f:
|
312
|
+
content = dockerfile("function", resource, function)
|
313
|
+
f.write(content)
|
314
|
+
|
315
|
+
clean_auto_generated(directory, "agent", agents)
|
316
|
+
clean_auto_generated(directory, "function", functions)
|
blaxel/deploy/format.py
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
"""
|
2
|
+
This module provides utility functions to format deployment configurations into YAML-compatible strings.
|
3
|
+
It includes functions to convert arguments, parameters, dictionaries, and agent chains into properly formatted JSON or YAML strings.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import ast
|
7
|
+
|
8
|
+
|
9
|
+
def arg_to_list(arg: ast.List):
|
10
|
+
value = []
|
11
|
+
for v in arg.elts:
|
12
|
+
value.append(format_value(v))
|
13
|
+
return value
|
14
|
+
|
15
|
+
def format_value(v):
|
16
|
+
"""
|
17
|
+
Formats an AST node value into its Python equivalent.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
v (ast.AST): The AST node to format.
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
Any: The formatted Python value.
|
24
|
+
"""
|
25
|
+
if isinstance(v, ast.Constant):
|
26
|
+
return v.value
|
27
|
+
elif isinstance(v, ast.Dict):
|
28
|
+
return arg_to_dict(v)
|
29
|
+
elif isinstance(v, ast.List):
|
30
|
+
return arg_to_list(v)
|
31
|
+
|
32
|
+
def arg_to_dict(arg: ast.keyword):
|
33
|
+
"""
|
34
|
+
Converts an AST keyword argument to a dictionary.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
arg (ast.keyword): The AST keyword argument.
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
dict: The resulting dictionary.
|
41
|
+
"""
|
42
|
+
value = {}
|
43
|
+
for k, v in zip(arg.keys, arg.values):
|
44
|
+
if isinstance(k, ast.Constant):
|
45
|
+
value[k.value] = format_value(v)
|
46
|
+
return value
|