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,168 @@
1
+ """
2
+ This module provides functionalities to interact with MCP (Multi-Client Platform) servers.
3
+ It includes classes for managing MCP clients, creating dynamic schemas, and integrating MCP tools into Blaxel.
4
+ """
5
+
6
+ import asyncio
7
+ import logging
8
+ import warnings
9
+ from typing import Any, AsyncIterator, Callable
10
+
11
+ import pydantic
12
+ import pydantic_core
13
+ import requests
14
+ import typing_extensions as t
15
+ from langchain_core.tools.base import BaseTool, BaseToolkit, ToolException
16
+ from mcp import ClientSession
17
+ from mcp.types import CallToolResult, ListToolsResult
18
+
19
+ from blaxel.aimon.settings import get_settings
20
+ from blaxel.authentication import get_authentication_headers
21
+ from blaxel.authentication.authentication import AuthenticatedClient
22
+ from blaxel.functions.mcp.client import websocket_client
23
+
24
+ from .utils import create_schema_model
25
+
26
+ settings = get_settings()
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ class MCPClient:
32
+ def __init__(self, client: AuthenticatedClient, url: str, fallback_url: str | None = None):
33
+ self.client = client
34
+ self.url = url
35
+ self.fallback_url = fallback_url
36
+
37
+ async def list_ws_tools(self, is_fallback: bool = False) -> ListToolsResult:
38
+ if is_fallback:
39
+ url = self.fallback_url
40
+ else:
41
+ url = self.url
42
+ try:
43
+ async with websocket_client(url, headers=get_authentication_headers(settings)) as (read_stream, write_stream):
44
+ logger.debug("WebSocket connection established")
45
+ async with ClientSession(read_stream, write_stream) as client:
46
+ await client.initialize()
47
+ response = await client.list_tools()
48
+ logger.debug(f"WebSocket tools: {response}")
49
+ return response
50
+ except Exception as e:
51
+ logger.error(f"Error listing tools: {e}")
52
+ logger.debug("WebSocket not available, trying HTTP")
53
+ return None # Signal to list_tools() to try HTTP instead
54
+
55
+ async def list_tools(self) -> ListToolsResult:
56
+ logger.debug(f"Listing tools for {self.url}")
57
+ try:
58
+ result = await self.list_ws_tools(is_fallback=False)
59
+ return result
60
+ except Exception as e: # Fallback to Public endpoint
61
+ if self.fallback_url:
62
+ try:
63
+ result = await self.list_ws_tools(is_fallback=True)
64
+ return result
65
+ except Exception as e:
66
+ raise e
67
+ else:
68
+ raise e
69
+
70
+
71
+ async def call_tool(
72
+ self,
73
+ tool_name: str,
74
+ arguments: dict[str, Any] = None,
75
+ is_fallback: bool = False,
76
+ ) -> requests.Response | AsyncIterator[CallToolResult]:
77
+ if is_fallback:
78
+ url = self.fallback_url
79
+ else:
80
+ url = self.url
81
+ try:
82
+ async with websocket_client(url, headers=get_authentication_headers(settings)) as (read_stream, write_stream):
83
+ async with ClientSession(read_stream, write_stream) as session:
84
+ await session.initialize()
85
+ response = await session.call_tool(tool_name, arguments or {})
86
+ content = pydantic_core.to_json(response).decode()
87
+ if response.isError:
88
+ raise ToolException(content)
89
+ return content
90
+ except Exception as e:
91
+ raise e
92
+
93
+
94
+ class MCPTool(BaseTool):
95
+ """
96
+ Tool for interacting with MCP server-hosted tools.
97
+
98
+ Attributes:
99
+ client (MCPClient): The MCP client instance.
100
+ handle_tool_error (bool | str | Callable[[ToolException], str] | None): Error handling strategy.
101
+ """
102
+
103
+ client: MCPClient
104
+ handle_tool_error: bool | str | Callable[[ToolException], str] | None = True
105
+
106
+ @t.override
107
+ def _run(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
108
+ warnings.warn(
109
+ "Invoke this tool asynchronousely using `ainvoke`. This method exists only to satisfy standard tests.",
110
+ stacklevel=1,
111
+ )
112
+ return asyncio.run(self._arun(*args, **kwargs))
113
+
114
+ @t.override
115
+ async def _arun(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
116
+ try:
117
+ return await self.client.call_tool(self.name, arguments=kwargs)
118
+ except Exception as e:
119
+ if self.client.fallback_url:
120
+ try:
121
+ return await self.client.call_tool(self.name, arguments=kwargs, is_fallback=True) # Fallback to Public endpoint
122
+ except Exception as e:
123
+ raise e
124
+ else:
125
+ raise e
126
+
127
+ @t.override
128
+ @property
129
+ def tool_call_schema(self) -> type[pydantic.BaseModel]:
130
+ assert self.args_schema is not None # noqa: S101
131
+ return self.args_schema
132
+
133
+ class MCPToolkit(BaseToolkit):
134
+ """
135
+ Toolkit for managing MCP server tools.
136
+
137
+ Attributes:
138
+ client (MCPClient): The MCP client instance.
139
+ _tools (ListToolsResult | None): Cached list of tools from the MCP server.
140
+ """
141
+
142
+ client: MCPClient
143
+ """The MCP session used to obtain the tools"""
144
+
145
+ _tools: ListToolsResult | None = None
146
+ model_config = pydantic.ConfigDict(arbitrary_types_allowed=True)
147
+
148
+ async def initialize(self) -> None:
149
+ """Initialize the session and retrieve tools list"""
150
+ if self._tools is None:
151
+ response = await self.client.list_tools()
152
+ self._tools = response
153
+
154
+ @t.override
155
+ async def get_tools(self) -> list[BaseTool]:
156
+ if self._tools is None:
157
+ raise RuntimeError("Must initialize the toolkit first")
158
+
159
+ return [
160
+ MCPTool(
161
+ client=self.client,
162
+ name=tool.name,
163
+ description=tool.description or "",
164
+ args_schema=create_schema_model(tool.name, tool.inputSchema),
165
+ )
166
+ # list_tools returns a PaginatedResult, but I don't see a way to pass the cursor to retrieve more tools
167
+ for tool in self._tools.tools
168
+ ]
@@ -0,0 +1,56 @@
1
+ """
2
+ This module provides functionalities to interact with MCP (Multi-Client Platform) servers.
3
+ It includes classes for managing MCP clients, creating dynamic schemas, and integrating MCP tools into Blaxel.
4
+ """
5
+ import pydantic
6
+ import typing_extensions as t
7
+ from pydantic.json_schema import JsonSchemaValue
8
+ from pydantic_core import core_schema as cs
9
+
10
+ TYPE_MAP = {
11
+ "integer": int,
12
+ "number": float,
13
+ "array": list,
14
+ "object": dict,
15
+ "boolean": bool,
16
+ "string": str,
17
+ "null": type(None),
18
+ }
19
+
20
+ FIELD_DEFAULTS = {
21
+ int: 0,
22
+ float: 0.0,
23
+ list: [],
24
+ bool: False,
25
+ str: "",
26
+ type(None): None,
27
+ }
28
+
29
+ def configure_field(name: str, type_: dict[str, t.Any], required: list[str]) -> tuple[type, t.Any]:
30
+ field_type = TYPE_MAP[type_["type"]]
31
+ default_ = FIELD_DEFAULTS.get(field_type) if name not in required else ...
32
+ return field_type, default_
33
+
34
+ def create_schema_model(name: str, schema: dict[str, t.Any]) -> type[pydantic.BaseModel]:
35
+ # Create a new model class that returns our JSON schema.
36
+ # LangChain requires a BaseModel class.
37
+ class SchemaBase(pydantic.BaseModel):
38
+ model_config = pydantic.ConfigDict(extra="allow")
39
+
40
+ @t.override
41
+ @classmethod
42
+ def __get_pydantic_json_schema__(
43
+ cls, core_schema: cs.CoreSchema, handler: pydantic.GetJsonSchemaHandler
44
+ ) -> JsonSchemaValue:
45
+ return schema
46
+
47
+ # Since this langchain patch, we need to synthesize pydantic fields from the schema
48
+ # https://github.com/langchain-ai/langchain/commit/033ac417609297369eb0525794d8b48a425b8b33
49
+ required = schema.get("required", [])
50
+ fields: dict[str, t.Any] = {
51
+ name: configure_field(name, type_, required) for name, type_ in schema["properties"].items()
52
+ }
53
+
54
+ return pydantic.create_model(f"{name}Schema", __base__=SchemaBase, **fields)
55
+
56
+
@@ -0,0 +1,183 @@
1
+ """
2
+ This module provides functionalities to integrate remote functions into Blaxel.
3
+ It includes classes for creating dynamic schemas based on function parameters and managing remote toolkits.
4
+ """
5
+
6
+ import asyncio
7
+ import os
8
+ import warnings
9
+ from dataclasses import dataclass
10
+ from typing import Callable
11
+
12
+ import pydantic
13
+ import typing_extensions as t
14
+ from langchain_core.tools.base import BaseTool, ToolException
15
+
16
+ from blaxel.aimon.settings import get_settings
17
+ from blaxel.api.functions import get_function, list_functions
18
+ from blaxel.authentication.authentication import AuthenticatedClient
19
+ from blaxel.errors import UnexpectedStatus
20
+ from blaxel.functions.mcp.mcp import MCPClient, MCPToolkit
21
+ from blaxel.models import Function, StoreFunctionParameter
22
+ from blaxel.run import RunClient
23
+
24
+
25
+ def create_dynamic_schema(name: str, parameters: list[StoreFunctionParameter]) -> type[pydantic.BaseModel]:
26
+ """
27
+ Creates a dynamic Pydantic schema based on function parameters.
28
+
29
+ Args:
30
+ name (str): The name of the schema.
31
+ parameters (list[StoreFunctionParameter]): List of parameter objects.
32
+
33
+ Returns:
34
+ type[pydantic.BaseModel]: The dynamically created Pydantic model.
35
+ """
36
+ field_definitions = {}
37
+ for param in parameters:
38
+ field_type = str
39
+ if param.type_ == "number":
40
+ field_type = float
41
+ elif param.type_ == "integer":
42
+ field_type = int
43
+ elif param.type_ == "boolean":
44
+ field_type = bool
45
+
46
+ field_definitions[param.name] = (
47
+ field_type,
48
+ pydantic.Field(description=param.description or "")
49
+ )
50
+ return pydantic.create_model(
51
+ f"{name}Schema",
52
+ **field_definitions
53
+ )
54
+
55
+
56
+ class RemoteTool(BaseTool):
57
+ """
58
+ Tool for interacting with remote functions.
59
+
60
+ Attributes:
61
+ client (RunClient): The client used to execute remote function calls.
62
+ resource_name (str): The name of the remote resource.
63
+ kit (bool): Indicates whether the tool is part of a function kit.
64
+ handle_tool_error (bool | str | Callable[[ToolException], str] | None): Error handling strategy.
65
+ """
66
+
67
+ client: RunClient
68
+ resource_name: str
69
+ kit: bool = False
70
+ handle_tool_error: bool | str | Callable[[ToolException], str] | None = True
71
+ service_name: str | None = None
72
+ cloud: bool = False
73
+ @t.override
74
+ def _run(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
75
+ warnings.warn(
76
+ "Invoke this tool asynchronousely using `ainvoke`. This method exists only to satisfy standard tests.",
77
+ stacklevel=1,
78
+ )
79
+ return asyncio.run(self._arun(*args, **kwargs))
80
+
81
+ @t.override
82
+ async def _arun(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
83
+ body = {**kwargs}
84
+ if self.kit:
85
+ body["name"] = self.name
86
+ result = self.client.run(
87
+ "function",
88
+ self.resource_name,
89
+ "POST",
90
+ cloud=self.cloud,
91
+ service_name=self.service_name,
92
+ json=body,
93
+ )
94
+ return result.text
95
+
96
+ @t.override
97
+ @property
98
+ def tool_call_schema(self) -> type[pydantic.BaseModel]:
99
+ assert self.args_schema is not None # noqa: S101
100
+ return self.args_schema
101
+
102
+ @dataclass
103
+ class RemoteToolkit:
104
+ """
105
+ Toolkit for managing remote function tools.
106
+
107
+ Attributes:
108
+ client (AuthenticatedClient): The authenticated client instance.
109
+ function (str): The name of the remote function to integrate.
110
+ _function (Function | None): Cached Function object after initialization.
111
+ """
112
+ client: AuthenticatedClient
113
+ function: str
114
+ _function: Function | None = None
115
+ _service_name: str | None = None
116
+ model_config = pydantic.ConfigDict(arbitrary_types_allowed=True)
117
+
118
+ async def initialize(self) -> None:
119
+ """Initialize the session and retrieve the remote function details."""
120
+ if self._function is None:
121
+ try:
122
+ response = get_function.sync_detailed(self.function, client=self.client)
123
+ function_name = self.function.upper().replace("-", "_")
124
+ if os.getenv(f"BL_FUNCTION_{function_name}_SERVICE_NAME"):
125
+ self._service_name = os.getenv(f"BL_FUNCTION_{function_name}_SERVICE_NAME")
126
+ self._function = response.parsed
127
+ except UnexpectedStatus as e:
128
+ functions = list_functions.sync_detailed(
129
+ client=self.client,
130
+ ).parsed
131
+ names = [
132
+ f.metadata.name
133
+ for f in functions
134
+ ]
135
+ raise RuntimeError(
136
+ f"error: {e.status_code}. Available functions: {', '.join(names)}"
137
+ )
138
+
139
+ async def get_tools(self) -> list[BaseTool]:
140
+ settings = get_settings()
141
+ if self._function is None:
142
+ raise RuntimeError("Must initialize the toolkit first")
143
+
144
+ if self._function.spec.integration_connections:
145
+ fallback_url = None
146
+ url = f"{settings.run_url}/{settings.workspace}/functions/{self._function.metadata.name}"
147
+ if self._service_name:
148
+ fallback_url = f"https://{self._service_name}.{settings.run_internal_hostname}"
149
+ url = f"https://{self._service_name}.{settings.run_internal_hostname}"
150
+ mcp_client = MCPClient(self.client, url, fallback_url)
151
+ mcp_toolkit = MCPToolkit(client=mcp_client, url=url)
152
+ await mcp_toolkit.initialize()
153
+ return await mcp_toolkit.get_tools()
154
+
155
+ if self._function.spec.kit:
156
+ return [
157
+ RemoteTool(
158
+ client=RunClient(self.client),
159
+ name=func.name,
160
+ resource_name=self._function.metadata.name,
161
+ kit=True,
162
+ description=func.description or "",
163
+ args_schema=create_dynamic_schema(func.name, func.parameters),
164
+ cloud=settings.cloud,
165
+ service_name=self._service_name,
166
+ )
167
+ for func in self._function.spec.kit
168
+ ]
169
+
170
+ return [
171
+ RemoteTool(
172
+ client=RunClient(self.client),
173
+ name=self._function.metadata.name,
174
+ resource_name=self._function.metadata.name,
175
+ description=self._function.spec.description or "",
176
+ args_schema=create_dynamic_schema(
177
+ self._function.metadata.name,
178
+ self._function.spec.parameters
179
+ ),
180
+ cloud=settings.cloud,
181
+ service_name=self._service_name,
182
+ )
183
+ ]
@@ -0,0 +1,233 @@
1
+ """Contains all the data models used in inputs/outputs"""
2
+
3
+ from .acl import ACL
4
+ from .agent import Agent
5
+ from .agent_chain import AgentChain
6
+ from .agent_spec import AgentSpec
7
+ from .api_key import ApiKey
8
+ from .configuration import Configuration
9
+ from .continent import Continent
10
+ from .core_event import CoreEvent
11
+ from .core_spec import CoreSpec
12
+ from .core_spec_configurations import CoreSpecConfigurations
13
+ from .country import Country
14
+ from .create_api_key_for_service_account_body import CreateApiKeyForServiceAccountBody
15
+ from .create_workspace_service_account_body import CreateWorkspaceServiceAccountBody
16
+ from .create_workspace_service_account_response_200 import CreateWorkspaceServiceAccountResponse200
17
+ from .delete_workspace_service_account_response_200 import DeleteWorkspaceServiceAccountResponse200
18
+ from .entrypoint import Entrypoint
19
+ from .entrypoint_env import EntrypointEnv
20
+ from .flavor import Flavor
21
+ from .form import Form
22
+ from .form_config import FormConfig
23
+ from .form_oauthomitempty import FormOauthomitempty
24
+ from .form_secrets import FormSecrets
25
+ from .function import Function
26
+ from .function_kit import FunctionKit
27
+ from .function_spec import FunctionSpec
28
+ from .get_trace_ids_response_200 import GetTraceIdsResponse200
29
+ from .get_trace_logs_response_200 import GetTraceLogsResponse200
30
+ from .get_trace_response_200 import GetTraceResponse200
31
+ from .get_workspace_service_accounts_response_200_item import (
32
+ GetWorkspaceServiceAccountsResponse200Item,
33
+ )
34
+ from .histogram_bucket import HistogramBucket
35
+ from .histogram_stats import HistogramStats
36
+ from .integration_connection import IntegrationConnection
37
+ from .integration_connection_spec import IntegrationConnectionSpec
38
+ from .integration_connection_spec_config import IntegrationConnectionSpecConfig
39
+ from .integration_connection_spec_secret import IntegrationConnectionSpecSecret
40
+ from .integration_model import IntegrationModel
41
+ from .integration_repository import IntegrationRepository
42
+ from .invite_workspace_user_body import InviteWorkspaceUserBody
43
+ from .knowledgebase import Knowledgebase
44
+ from .knowledgebase_spec import KnowledgebaseSpec
45
+ from .knowledgebase_spec_options import KnowledgebaseSpecOptions
46
+ from .last_n_requests_metric import LastNRequestsMetric
47
+ from .latency_metric import LatencyMetric
48
+ from .location_response import LocationResponse
49
+ from .mcp_definition import MCPDefinition
50
+ from .mcp_definition_entrypoint import MCPDefinitionEntrypoint
51
+ from .mcp_definition_form import MCPDefinitionForm
52
+ from .metadata import Metadata
53
+ from .metadata_labels import MetadataLabels
54
+ from .metric import Metric
55
+ from .metrics import Metrics
56
+ from .metrics_models import MetricsModels
57
+ from .metrics_request_total_per_code import MetricsRequestTotalPerCode
58
+ from .metrics_rps_per_code import MetricsRpsPerCode
59
+ from .model import Model
60
+ from .model_private_cluster import ModelPrivateCluster
61
+ from .model_spec import ModelSpec
62
+ from .o_auth import OAuth
63
+ from .owner_fields import OwnerFields
64
+ from .pending_invitation import PendingInvitation
65
+ from .pending_invitation_accept import PendingInvitationAccept
66
+ from .pending_invitation_render import PendingInvitationRender
67
+ from .pending_invitation_render_invited_by import PendingInvitationRenderInvitedBy
68
+ from .pending_invitation_render_workspace import PendingInvitationRenderWorkspace
69
+ from .pending_invitation_workspace_details import PendingInvitationWorkspaceDetails
70
+ from .pod_template_spec import PodTemplateSpec
71
+ from .policy import Policy
72
+ from .policy_location import PolicyLocation
73
+ from .policy_max_tokens import PolicyMaxTokens
74
+ from .policy_spec import PolicySpec
75
+ from .private_cluster import PrivateCluster
76
+ from .private_location import PrivateLocation
77
+ from .repository import Repository
78
+ from .request_duration_over_time_metric import RequestDurationOverTimeMetric
79
+ from .request_duration_over_time_metrics import RequestDurationOverTimeMetrics
80
+ from .request_total_by_origin_metric import RequestTotalByOriginMetric
81
+ from .request_total_by_origin_metric_request_total_by_origin import (
82
+ RequestTotalByOriginMetricRequestTotalByOrigin,
83
+ )
84
+ from .request_total_by_origin_metric_request_total_by_origin_and_code import (
85
+ RequestTotalByOriginMetricRequestTotalByOriginAndCode,
86
+ )
87
+ from .request_total_metric import RequestTotalMetric
88
+ from .request_total_metric_request_total_per_code import RequestTotalMetricRequestTotalPerCode
89
+ from .request_total_metric_rps_per_code import RequestTotalMetricRpsPerCode
90
+ from .resource_log import ResourceLog
91
+ from .resource_metrics import ResourceMetrics
92
+ from .resource_metrics_request_total_per_code import ResourceMetricsRequestTotalPerCode
93
+ from .resource_metrics_rps_per_code import ResourceMetricsRpsPerCode
94
+ from .revision_configuration import RevisionConfiguration
95
+ from .revision_metadata import RevisionMetadata
96
+ from .runtime import Runtime
97
+ from .runtime_startup_probe import RuntimeStartupProbe
98
+ from .serverless_config import ServerlessConfig
99
+ from .spec_configuration import SpecConfiguration
100
+ from .store_agent import StoreAgent
101
+ from .store_agent_labels import StoreAgentLabels
102
+ from .store_configuration import StoreConfiguration
103
+ from .store_configuration_option import StoreConfigurationOption
104
+ from .store_function import StoreFunction
105
+ from .store_function_kit import StoreFunctionKit
106
+ from .store_function_labels import StoreFunctionLabels
107
+ from .store_function_parameter import StoreFunctionParameter
108
+ from .time_fields import TimeFields
109
+ from .token_rate_metric import TokenRateMetric
110
+ from .token_rate_metrics import TokenRateMetrics
111
+ from .token_total_metric import TokenTotalMetric
112
+ from .trace_ids_response import TraceIdsResponse
113
+ from .update_workspace_service_account_body import UpdateWorkspaceServiceAccountBody
114
+ from .update_workspace_service_account_response_200 import UpdateWorkspaceServiceAccountResponse200
115
+ from .update_workspace_user_role_body import UpdateWorkspaceUserRoleBody
116
+ from .websocket_channel import WebsocketChannel
117
+ from .workspace import Workspace
118
+ from .workspace_labels import WorkspaceLabels
119
+ from .workspace_user import WorkspaceUser
120
+
121
+ __all__ = (
122
+ "ACL",
123
+ "Agent",
124
+ "AgentChain",
125
+ "AgentSpec",
126
+ "ApiKey",
127
+ "Configuration",
128
+ "Continent",
129
+ "CoreEvent",
130
+ "CoreSpec",
131
+ "CoreSpecConfigurations",
132
+ "Country",
133
+ "CreateApiKeyForServiceAccountBody",
134
+ "CreateWorkspaceServiceAccountBody",
135
+ "CreateWorkspaceServiceAccountResponse200",
136
+ "DeleteWorkspaceServiceAccountResponse200",
137
+ "Entrypoint",
138
+ "EntrypointEnv",
139
+ "Flavor",
140
+ "Form",
141
+ "FormConfig",
142
+ "FormOauthomitempty",
143
+ "FormSecrets",
144
+ "Function",
145
+ "FunctionKit",
146
+ "FunctionSpec",
147
+ "GetTraceIdsResponse200",
148
+ "GetTraceLogsResponse200",
149
+ "GetTraceResponse200",
150
+ "GetWorkspaceServiceAccountsResponse200Item",
151
+ "HistogramBucket",
152
+ "HistogramStats",
153
+ "IntegrationConnection",
154
+ "IntegrationConnectionSpec",
155
+ "IntegrationConnectionSpecConfig",
156
+ "IntegrationConnectionSpecSecret",
157
+ "IntegrationModel",
158
+ "IntegrationRepository",
159
+ "InviteWorkspaceUserBody",
160
+ "Knowledgebase",
161
+ "KnowledgebaseSpec",
162
+ "KnowledgebaseSpecOptions",
163
+ "LastNRequestsMetric",
164
+ "LatencyMetric",
165
+ "LocationResponse",
166
+ "MCPDefinition",
167
+ "MCPDefinitionEntrypoint",
168
+ "MCPDefinitionForm",
169
+ "Metadata",
170
+ "MetadataLabels",
171
+ "Metric",
172
+ "Metrics",
173
+ "MetricsModels",
174
+ "MetricsRequestTotalPerCode",
175
+ "MetricsRpsPerCode",
176
+ "Model",
177
+ "ModelPrivateCluster",
178
+ "ModelSpec",
179
+ "OAuth",
180
+ "OwnerFields",
181
+ "PendingInvitation",
182
+ "PendingInvitationAccept",
183
+ "PendingInvitationRender",
184
+ "PendingInvitationRenderInvitedBy",
185
+ "PendingInvitationRenderWorkspace",
186
+ "PendingInvitationWorkspaceDetails",
187
+ "PodTemplateSpec",
188
+ "Policy",
189
+ "PolicyLocation",
190
+ "PolicyMaxTokens",
191
+ "PolicySpec",
192
+ "PrivateCluster",
193
+ "PrivateLocation",
194
+ "Repository",
195
+ "RequestDurationOverTimeMetric",
196
+ "RequestDurationOverTimeMetrics",
197
+ "RequestTotalByOriginMetric",
198
+ "RequestTotalByOriginMetricRequestTotalByOrigin",
199
+ "RequestTotalByOriginMetricRequestTotalByOriginAndCode",
200
+ "RequestTotalMetric",
201
+ "RequestTotalMetricRequestTotalPerCode",
202
+ "RequestTotalMetricRpsPerCode",
203
+ "ResourceLog",
204
+ "ResourceMetrics",
205
+ "ResourceMetricsRequestTotalPerCode",
206
+ "ResourceMetricsRpsPerCode",
207
+ "RevisionConfiguration",
208
+ "RevisionMetadata",
209
+ "Runtime",
210
+ "RuntimeStartupProbe",
211
+ "ServerlessConfig",
212
+ "SpecConfiguration",
213
+ "StoreAgent",
214
+ "StoreAgentLabels",
215
+ "StoreConfiguration",
216
+ "StoreConfigurationOption",
217
+ "StoreFunction",
218
+ "StoreFunctionKit",
219
+ "StoreFunctionLabels",
220
+ "StoreFunctionParameter",
221
+ "TimeFields",
222
+ "TokenRateMetric",
223
+ "TokenRateMetrics",
224
+ "TokenTotalMetric",
225
+ "TraceIdsResponse",
226
+ "UpdateWorkspaceServiceAccountBody",
227
+ "UpdateWorkspaceServiceAccountResponse200",
228
+ "UpdateWorkspaceUserRoleBody",
229
+ "WebsocketChannel",
230
+ "Workspace",
231
+ "WorkspaceLabels",
232
+ "WorkspaceUser",
233
+ )