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.
Files changed (261) hide show
  1. blaxel/__init__.py +8 -0
  2. blaxel/agents/__init__.py +5 -0
  3. blaxel/agents/chain.py +153 -0
  4. blaxel/agents/chat.py +286 -0
  5. blaxel/agents/decorator.py +208 -0
  6. blaxel/agents/thread.py +24 -0
  7. blaxel/agents/voice/openai.py +255 -0
  8. blaxel/agents/voice/utils.py +25 -0
  9. blaxel/api/__init__.py +1 -0
  10. blaxel/api/agents/__init__.py +0 -0
  11. blaxel/api/agents/create_agent.py +155 -0
  12. blaxel/api/agents/delete_agent.py +146 -0
  13. blaxel/api/agents/get_agent.py +146 -0
  14. blaxel/api/agents/get_agent_logs.py +151 -0
  15. blaxel/api/agents/get_agent_metrics.py +150 -0
  16. blaxel/api/agents/get_agent_trace_ids.py +201 -0
  17. blaxel/api/agents/list_agent_revisions.py +155 -0
  18. blaxel/api/agents/list_agents.py +127 -0
  19. blaxel/api/agents/update_agent.py +168 -0
  20. blaxel/api/configurations/__init__.py +0 -0
  21. blaxel/api/configurations/get_configuration.py +122 -0
  22. blaxel/api/default/__init__.py +0 -0
  23. blaxel/api/default/get_trace.py +150 -0
  24. blaxel/api/default/get_trace_ids.py +218 -0
  25. blaxel/api/default/get_trace_logs.py +186 -0
  26. blaxel/api/default/list_mcp_hub_definitions.py +127 -0
  27. blaxel/api/functions/__init__.py +0 -0
  28. blaxel/api/functions/create_function.py +155 -0
  29. blaxel/api/functions/delete_function.py +146 -0
  30. blaxel/api/functions/get_function.py +146 -0
  31. blaxel/api/functions/get_function_logs.py +151 -0
  32. blaxel/api/functions/get_function_metrics.py +150 -0
  33. blaxel/api/functions/get_function_trace_ids.py +201 -0
  34. blaxel/api/functions/list_function_revisions.py +158 -0
  35. blaxel/api/functions/list_functions.py +131 -0
  36. blaxel/api/functions/update_function.py +168 -0
  37. blaxel/api/integrations/__init__.py +0 -0
  38. blaxel/api/integrations/create_integration_connection.py +167 -0
  39. blaxel/api/integrations/delete_integration_connection.py +158 -0
  40. blaxel/api/integrations/get_integration.py +97 -0
  41. blaxel/api/integrations/get_integration_connection.py +158 -0
  42. blaxel/api/integrations/get_integration_connection_model.py +104 -0
  43. blaxel/api/integrations/get_integration_connection_model_endpoint_configurations.py +97 -0
  44. blaxel/api/integrations/list_integration_connection_models.py +97 -0
  45. blaxel/api/integrations/list_integration_connections.py +139 -0
  46. blaxel/api/integrations/update_integration_connection.py +180 -0
  47. blaxel/api/invitations/__init__.py +0 -0
  48. blaxel/api/invitations/list_all_pending_invitations.py +142 -0
  49. blaxel/api/knowledgebases/__init__.py +0 -0
  50. blaxel/api/knowledgebases/create_knowledgebase.py +163 -0
  51. blaxel/api/knowledgebases/delete_knowledgebase.py +154 -0
  52. blaxel/api/knowledgebases/get_knowledgebase.py +154 -0
  53. blaxel/api/knowledgebases/list_knowledgebase_revisions.py +158 -0
  54. blaxel/api/knowledgebases/list_knowledgebases.py +139 -0
  55. blaxel/api/knowledgebases/update_knowledgebase.py +176 -0
  56. blaxel/api/locations/__init__.py +0 -0
  57. blaxel/api/locations/list_locations.py +139 -0
  58. blaxel/api/metrics/__init__.py +0 -0
  59. blaxel/api/metrics/get_metrics.py +130 -0
  60. blaxel/api/models/__init__.py +0 -0
  61. blaxel/api/models/create_model.py +163 -0
  62. blaxel/api/models/delete_model.py +154 -0
  63. blaxel/api/models/get_model.py +154 -0
  64. blaxel/api/models/get_model_logs.py +155 -0
  65. blaxel/api/models/get_model_metrics.py +158 -0
  66. blaxel/api/models/get_model_trace_ids.py +201 -0
  67. blaxel/api/models/list_model_revisions.py +158 -0
  68. blaxel/api/models/list_models.py +135 -0
  69. blaxel/api/models/update_model.py +176 -0
  70. blaxel/api/policies/__init__.py +0 -0
  71. blaxel/api/policies/create_policy.py +167 -0
  72. blaxel/api/policies/delete_policy.py +154 -0
  73. blaxel/api/policies/get_policy.py +154 -0
  74. blaxel/api/policies/list_policies.py +139 -0
  75. blaxel/api/policies/update_policy.py +180 -0
  76. blaxel/api/privateclusters/__init__.py +0 -0
  77. blaxel/api/privateclusters/create_private_cluster.py +132 -0
  78. blaxel/api/privateclusters/delete_private_cluster.py +156 -0
  79. blaxel/api/privateclusters/get_private_cluster.py +159 -0
  80. blaxel/api/privateclusters/get_private_cluster_health.py +97 -0
  81. blaxel/api/privateclusters/list_private_clusters.py +140 -0
  82. blaxel/api/privateclusters/update_private_cluster.py +156 -0
  83. blaxel/api/privateclusters/update_private_cluster_health.py +97 -0
  84. blaxel/api/service_accounts/__init__.py +0 -0
  85. blaxel/api/service_accounts/create_api_key_for_service_account.py +177 -0
  86. blaxel/api/service_accounts/create_workspace_service_account.py +170 -0
  87. blaxel/api/service_accounts/delete_api_key_for_service_account.py +104 -0
  88. blaxel/api/service_accounts/delete_workspace_service_account.py +160 -0
  89. blaxel/api/service_accounts/get_workspace_service_accounts.py +141 -0
  90. blaxel/api/service_accounts/list_api_keys_for_service_account.py +163 -0
  91. blaxel/api/service_accounts/update_workspace_service_account.py +183 -0
  92. blaxel/api/store/__init__.py +0 -0
  93. blaxel/api/store/get_store_agent.py +146 -0
  94. blaxel/api/store/get_store_function.py +146 -0
  95. blaxel/api/store/list_store_agents.py +131 -0
  96. blaxel/api/store/list_store_functions.py +131 -0
  97. blaxel/api/workspaces/__init__.py +0 -0
  98. blaxel/api/workspaces/accept_workspace_invitation.py +161 -0
  99. blaxel/api/workspaces/create_worspace.py +163 -0
  100. blaxel/api/workspaces/decline_workspace_invitation.py +158 -0
  101. blaxel/api/workspaces/delete_workspace.py +154 -0
  102. blaxel/api/workspaces/get_workspace.py +154 -0
  103. blaxel/api/workspaces/invite_workspace_user.py +174 -0
  104. blaxel/api/workspaces/leave_workspace.py +161 -0
  105. blaxel/api/workspaces/list_workspace_users.py +139 -0
  106. blaxel/api/workspaces/list_workspaces.py +139 -0
  107. blaxel/api/workspaces/remove_workspace_user.py +101 -0
  108. blaxel/api/workspaces/update_workspace.py +176 -0
  109. blaxel/api/workspaces/update_workspace_user_role.py +187 -0
  110. blaxel/authentication/__init__.py +45 -0
  111. blaxel/authentication/apikey.py +50 -0
  112. blaxel/authentication/authentication.py +176 -0
  113. blaxel/authentication/clientcredentials.py +103 -0
  114. blaxel/authentication/credentials.py +295 -0
  115. blaxel/authentication/device_mode.py +197 -0
  116. blaxel/client.py +281 -0
  117. blaxel/common/__init__.py +17 -0
  118. blaxel/common/error.py +27 -0
  119. blaxel/common/instrumentation.py +317 -0
  120. blaxel/common/logger.py +60 -0
  121. blaxel/common/secrets.py +39 -0
  122. blaxel/common/settings.py +150 -0
  123. blaxel/common/slugify.py +18 -0
  124. blaxel/common/utils.py +34 -0
  125. blaxel/deploy/__init__.py +8 -0
  126. blaxel/deploy/deploy.py +316 -0
  127. blaxel/deploy/format.py +46 -0
  128. blaxel/deploy/parser.py +192 -0
  129. blaxel/errors.py +16 -0
  130. blaxel/functions/__init__.py +7 -0
  131. blaxel/functions/common.py +228 -0
  132. blaxel/functions/decorator.py +64 -0
  133. blaxel/functions/local/local.py +48 -0
  134. blaxel/functions/mcp/client.py +96 -0
  135. blaxel/functions/mcp/mcp.py +168 -0
  136. blaxel/functions/mcp/utils.py +56 -0
  137. blaxel/functions/remote/remote.py +183 -0
  138. blaxel/models/__init__.py +233 -0
  139. blaxel/models/acl.py +133 -0
  140. blaxel/models/agent.py +126 -0
  141. blaxel/models/agent_chain.py +88 -0
  142. blaxel/models/agent_spec.py +346 -0
  143. blaxel/models/api_key.py +142 -0
  144. blaxel/models/configuration.py +85 -0
  145. blaxel/models/continent.py +70 -0
  146. blaxel/models/core_event.py +97 -0
  147. blaxel/models/core_spec.py +249 -0
  148. blaxel/models/core_spec_configurations.py +77 -0
  149. blaxel/models/country.py +70 -0
  150. blaxel/models/create_api_key_for_service_account_body.py +69 -0
  151. blaxel/models/create_workspace_service_account_body.py +71 -0
  152. blaxel/models/create_workspace_service_account_response_200.py +105 -0
  153. blaxel/models/delete_workspace_service_account_response_200.py +96 -0
  154. blaxel/models/entrypoint.py +96 -0
  155. blaxel/models/entrypoint_env.py +45 -0
  156. blaxel/models/flavor.py +70 -0
  157. blaxel/models/form.py +120 -0
  158. blaxel/models/form_config.py +45 -0
  159. blaxel/models/form_oauthomitempty.py +45 -0
  160. blaxel/models/form_secrets.py +45 -0
  161. blaxel/models/function.py +126 -0
  162. blaxel/models/function_kit.py +97 -0
  163. blaxel/models/function_spec.py +310 -0
  164. blaxel/models/get_trace_ids_response_200.py +45 -0
  165. blaxel/models/get_trace_logs_response_200.py +45 -0
  166. blaxel/models/get_trace_response_200.py +45 -0
  167. blaxel/models/get_workspace_service_accounts_response_200_item.py +96 -0
  168. blaxel/models/histogram_bucket.py +79 -0
  169. blaxel/models/histogram_stats.py +88 -0
  170. blaxel/models/integration_connection.py +96 -0
  171. blaxel/models/integration_connection_spec.py +114 -0
  172. blaxel/models/integration_connection_spec_config.py +45 -0
  173. blaxel/models/integration_connection_spec_secret.py +45 -0
  174. blaxel/models/integration_model.py +162 -0
  175. blaxel/models/integration_repository.py +88 -0
  176. blaxel/models/invite_workspace_user_body.py +60 -0
  177. blaxel/models/knowledgebase.py +126 -0
  178. blaxel/models/knowledgebase_spec.py +163 -0
  179. blaxel/models/knowledgebase_spec_options.py +45 -0
  180. blaxel/models/last_n_requests_metric.py +79 -0
  181. blaxel/models/latency_metric.py +144 -0
  182. blaxel/models/location_response.py +113 -0
  183. blaxel/models/mcp_definition.py +188 -0
  184. blaxel/models/mcp_definition_entrypoint.py +45 -0
  185. blaxel/models/mcp_definition_form.py +45 -0
  186. blaxel/models/metadata.py +139 -0
  187. blaxel/models/metadata_labels.py +45 -0
  188. blaxel/models/metric.py +79 -0
  189. blaxel/models/metrics.py +169 -0
  190. blaxel/models/metrics_models.py +45 -0
  191. blaxel/models/metrics_request_total_per_code.py +45 -0
  192. blaxel/models/metrics_rps_per_code.py +45 -0
  193. blaxel/models/model.py +126 -0
  194. blaxel/models/model_private_cluster.py +79 -0
  195. blaxel/models/model_spec.py +249 -0
  196. blaxel/models/o_auth.py +72 -0
  197. blaxel/models/owner_fields.py +70 -0
  198. blaxel/models/pending_invitation.py +124 -0
  199. blaxel/models/pending_invitation_accept.py +85 -0
  200. blaxel/models/pending_invitation_render.py +147 -0
  201. blaxel/models/pending_invitation_render_invited_by.py +88 -0
  202. blaxel/models/pending_invitation_render_workspace.py +70 -0
  203. blaxel/models/pending_invitation_workspace_details.py +72 -0
  204. blaxel/models/pod_template_spec.py +45 -0
  205. blaxel/models/policy.py +96 -0
  206. blaxel/models/policy_location.py +70 -0
  207. blaxel/models/policy_max_tokens.py +106 -0
  208. blaxel/models/policy_spec.py +151 -0
  209. blaxel/models/private_cluster.py +183 -0
  210. blaxel/models/private_location.py +61 -0
  211. blaxel/models/repository.py +70 -0
  212. blaxel/models/request_duration_over_time_metric.py +97 -0
  213. blaxel/models/request_duration_over_time_metrics.py +80 -0
  214. blaxel/models/request_total_by_origin_metric.py +115 -0
  215. blaxel/models/request_total_by_origin_metric_request_total_by_origin.py +45 -0
  216. blaxel/models/request_total_by_origin_metric_request_total_by_origin_and_code.py +45 -0
  217. blaxel/models/request_total_metric.py +123 -0
  218. blaxel/models/request_total_metric_request_total_per_code.py +45 -0
  219. blaxel/models/request_total_metric_rps_per_code.py +45 -0
  220. blaxel/models/resource_log.py +79 -0
  221. blaxel/models/resource_metrics.py +270 -0
  222. blaxel/models/resource_metrics_request_total_per_code.py +45 -0
  223. blaxel/models/resource_metrics_rps_per_code.py +45 -0
  224. blaxel/models/revision_configuration.py +97 -0
  225. blaxel/models/revision_metadata.py +124 -0
  226. blaxel/models/runtime.py +196 -0
  227. blaxel/models/runtime_startup_probe.py +45 -0
  228. blaxel/models/serverless_config.py +80 -0
  229. blaxel/models/spec_configuration.py +70 -0
  230. blaxel/models/store_agent.py +178 -0
  231. blaxel/models/store_agent_labels.py +45 -0
  232. blaxel/models/store_configuration.py +151 -0
  233. blaxel/models/store_configuration_option.py +79 -0
  234. blaxel/models/store_function.py +211 -0
  235. blaxel/models/store_function_kit.py +97 -0
  236. blaxel/models/store_function_labels.py +45 -0
  237. blaxel/models/store_function_parameter.py +88 -0
  238. blaxel/models/time_fields.py +70 -0
  239. blaxel/models/token_rate_metric.py +88 -0
  240. blaxel/models/token_rate_metrics.py +120 -0
  241. blaxel/models/token_total_metric.py +106 -0
  242. blaxel/models/trace_ids_response.py +45 -0
  243. blaxel/models/update_workspace_service_account_body.py +69 -0
  244. blaxel/models/update_workspace_service_account_response_200.py +96 -0
  245. blaxel/models/update_workspace_user_role_body.py +60 -0
  246. blaxel/models/websocket_channel.py +88 -0
  247. blaxel/models/workspace.py +148 -0
  248. blaxel/models/workspace_labels.py +45 -0
  249. blaxel/models/workspace_user.py +115 -0
  250. blaxel/py.typed +1 -0
  251. blaxel/run.py +108 -0
  252. blaxel/serve/app.py +131 -0
  253. blaxel/serve/middlewares/__init__.py +10 -0
  254. blaxel/serve/middlewares/accesslog.py +32 -0
  255. blaxel/serve/middlewares/processtime.py +28 -0
  256. blaxel/types.py +46 -0
  257. blaxel-0.64.0.dist-info/METADATA +96 -0
  258. blaxel-0.64.0.dist-info/RECORD +261 -0
  259. blaxel-0.64.0.dist-info/WHEEL +4 -0
  260. blaxel-0.64.0.dist-info/entry_points.txt +2 -0
  261. blaxel-0.64.0.dist-info/licenses/LICENSE +21 -0
@@ -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])
@@ -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
@@ -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"]
@@ -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)
@@ -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