beamlit 0.0.55rc103__py3-none-any.whl → 0.0.56rc105__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 (41) hide show
  1. beamlit/agents/chain.py +14 -0
  2. beamlit/agents/decorator.py +6 -3
  3. beamlit/api/default/list_mcp_hub_definitions.py +127 -0
  4. beamlit/api/generation/__init__.py +0 -0
  5. beamlit/api/generation/run_information_generation_agent.py +168 -0
  6. beamlit/api/knowledgebases/delete_knowledgebase.py +18 -18
  7. beamlit/api/knowledgebases/get_knowledgebase.py +18 -18
  8. beamlit/api/knowledgebases/update_knowledgebase.py +14 -14
  9. beamlit/common/settings.py +2 -0
  10. beamlit/deploy/deploy.py +5 -2
  11. beamlit/functions/common.py +16 -0
  12. beamlit/functions/local/local.py +49 -0
  13. beamlit/functions/mcp/mcp.py +64 -74
  14. beamlit/functions/mcp/utils.py +56 -0
  15. beamlit/functions/remote/remote.py +16 -2
  16. beamlit/models/__init__.py +30 -0
  17. beamlit/models/agent_information_request.py +63 -0
  18. beamlit/models/agent_information_response.py +88 -0
  19. beamlit/models/agent_spec.py +9 -0
  20. beamlit/models/entrypoint.py +96 -0
  21. beamlit/models/entrypoint_env.py +45 -0
  22. beamlit/models/form.py +120 -0
  23. beamlit/models/form_config.py +45 -0
  24. beamlit/models/form_oauthomitempty.py +45 -0
  25. beamlit/models/form_secrets.py +45 -0
  26. beamlit/models/mcp_definition.py +188 -0
  27. beamlit/models/mcp_definition_entrypoint.py +45 -0
  28. beamlit/models/mcp_definition_form.py +45 -0
  29. beamlit/models/mcp_hub_artifact.py +188 -0
  30. beamlit/models/mcp_hub_artifact_entrypoint.py +45 -0
  31. beamlit/models/mcp_hub_artifact_form.py +45 -0
  32. beamlit/models/model_spec.py +0 -9
  33. beamlit/models/o_auth.py +72 -0
  34. beamlit/models/workspace.py +9 -9
  35. beamlit/run.py +25 -9
  36. {beamlit-0.0.55rc103.dist-info → beamlit-0.0.56rc105.dist-info}/METADATA +1 -1
  37. {beamlit-0.0.55rc103.dist-info → beamlit-0.0.56rc105.dist-info}/RECORD +40 -21
  38. beamlit/api/workspaces/workspace_quotas_request.py +0 -97
  39. {beamlit-0.0.55rc103.dist-info → beamlit-0.0.56rc105.dist-info}/WHEEL +0 -0
  40. {beamlit-0.0.55rc103.dist-info → beamlit-0.0.56rc105.dist-info}/entry_points.txt +0 -0
  41. {beamlit-0.0.55rc103.dist-info → beamlit-0.0.56rc105.dist-info}/licenses/LICENSE +0 -0
@@ -10,7 +10,7 @@ from ...types import Response
10
10
 
11
11
 
12
12
  def _get_kwargs(
13
- knowledgebase_id: str,
13
+ knowledgebase_name: str,
14
14
  *,
15
15
  body: Knowledgebase,
16
16
  ) -> dict[str, Any]:
@@ -18,7 +18,7 @@ def _get_kwargs(
18
18
 
19
19
  _kwargs: dict[str, Any] = {
20
20
  "method": "put",
21
- "url": f"/knowledgebases/{knowledgebase_id}",
21
+ "url": f"/knowledgebases/{knowledgebase_name}",
22
22
  }
23
23
 
24
24
  _body = body.to_dict()
@@ -51,7 +51,7 @@ def _build_response(*, client: Union[AuthenticatedClient, Client], response: htt
51
51
 
52
52
 
53
53
  def sync_detailed(
54
- knowledgebase_id: str,
54
+ knowledgebase_name: str,
55
55
  *,
56
56
  client: AuthenticatedClient,
57
57
  body: Knowledgebase,
@@ -61,7 +61,7 @@ def sync_detailed(
61
61
  Updates an knowledgebase.
62
62
 
63
63
  Args:
64
- knowledgebase_id (str):
64
+ knowledgebase_name (str):
65
65
  body (Knowledgebase): Knowledgebase
66
66
 
67
67
  Raises:
@@ -73,7 +73,7 @@ def sync_detailed(
73
73
  """
74
74
 
75
75
  kwargs = _get_kwargs(
76
- knowledgebase_id=knowledgebase_id,
76
+ knowledgebase_name=knowledgebase_name,
77
77
  body=body,
78
78
  )
79
79
 
@@ -85,7 +85,7 @@ def sync_detailed(
85
85
 
86
86
 
87
87
  def sync(
88
- knowledgebase_id: str,
88
+ knowledgebase_name: str,
89
89
  *,
90
90
  client: AuthenticatedClient,
91
91
  body: Knowledgebase,
@@ -95,7 +95,7 @@ def sync(
95
95
  Updates an knowledgebase.
96
96
 
97
97
  Args:
98
- knowledgebase_id (str):
98
+ knowledgebase_name (str):
99
99
  body (Knowledgebase): Knowledgebase
100
100
 
101
101
  Raises:
@@ -107,14 +107,14 @@ def sync(
107
107
  """
108
108
 
109
109
  return sync_detailed(
110
- knowledgebase_id=knowledgebase_id,
110
+ knowledgebase_name=knowledgebase_name,
111
111
  client=client,
112
112
  body=body,
113
113
  ).parsed
114
114
 
115
115
 
116
116
  async def asyncio_detailed(
117
- knowledgebase_id: str,
117
+ knowledgebase_name: str,
118
118
  *,
119
119
  client: AuthenticatedClient,
120
120
  body: Knowledgebase,
@@ -124,7 +124,7 @@ async def asyncio_detailed(
124
124
  Updates an knowledgebase.
125
125
 
126
126
  Args:
127
- knowledgebase_id (str):
127
+ knowledgebase_name (str):
128
128
  body (Knowledgebase): Knowledgebase
129
129
 
130
130
  Raises:
@@ -136,7 +136,7 @@ async def asyncio_detailed(
136
136
  """
137
137
 
138
138
  kwargs = _get_kwargs(
139
- knowledgebase_id=knowledgebase_id,
139
+ knowledgebase_name=knowledgebase_name,
140
140
  body=body,
141
141
  )
142
142
 
@@ -146,7 +146,7 @@ async def asyncio_detailed(
146
146
 
147
147
 
148
148
  async def asyncio(
149
- knowledgebase_id: str,
149
+ knowledgebase_name: str,
150
150
  *,
151
151
  client: AuthenticatedClient,
152
152
  body: Knowledgebase,
@@ -156,7 +156,7 @@ async def asyncio(
156
156
  Updates an knowledgebase.
157
157
 
158
158
  Args:
159
- knowledgebase_id (str):
159
+ knowledgebase_name (str):
160
160
  body (Knowledgebase): Knowledgebase
161
161
 
162
162
  Raises:
@@ -169,7 +169,7 @@ async def asyncio(
169
169
 
170
170
  return (
171
171
  await asyncio_detailed(
172
- knowledgebase_id=knowledgebase_id,
172
+ knowledgebase_name=knowledgebase_name,
173
173
  client=client,
174
174
  body=body,
175
175
  )
@@ -83,9 +83,11 @@ class Settings(BaseSettings):
83
83
  base_url: str = Field(default="https://api.beamlit.com/v0")
84
84
  app_url: str = Field(default="https://app.beamlit.com")
85
85
  run_url: str = Field(default="https://run.beamlit.com")
86
+ run_internal_hostname: str = Field(default="internal.run.beamlit.com")
86
87
  registry_url: str = Field(default="https://us.registry.beamlit.com")
87
88
  log_level: str = Field(default="INFO")
88
89
  enable_opentelemetry: bool = Field(default=False)
90
+ cloud: bool = Field(default=False)
89
91
  agent: SettingsAgent = SettingsAgent()
90
92
  server: SettingsServer = SettingsServer()
91
93
  authentication: SettingsAuthentication = SettingsAuthentication()
beamlit/deploy/deploy.py CHANGED
@@ -59,6 +59,7 @@ def set_default_values(resource: Resource, deployment: Agent | Function):
59
59
  return deployment
60
60
 
61
61
  def get_beamlit_deployment_from_resource(
62
+ settings: Settings,
62
63
  resource: Resource,
63
64
  ) -> Agent | Function:
64
65
  """
@@ -75,6 +76,7 @@ def get_beamlit_deployment_from_resource(
75
76
  if isinstance(arg.value, ast.Dict):
76
77
  value = arg_to_dict(arg.value)
77
78
  metadata = EnvironmentMetadata(**value.get("metadata", {}))
79
+ metadata.environment = settings.environment
78
80
  spec = AgentSpec(**value.get("spec", {}))
79
81
  agent = Agent(metadata=metadata, spec=spec)
80
82
  if not agent.spec.prompt:
@@ -84,6 +86,7 @@ def get_beamlit_deployment_from_resource(
84
86
  if isinstance(arg.value, ast.Dict):
85
87
  value = arg_to_dict(arg.value)
86
88
  metadata = EnvironmentMetadata(**value.get("metadata", {}))
89
+ metadata.environment = settings.environment
87
90
  spec = FunctionSpec(**value.get("spec", {}))
88
91
  func = Function(metadata=metadata, spec=spec)
89
92
  if not func.spec.parameters:
@@ -265,13 +268,13 @@ def generate_beamlit_deployment(directory: str, name: str):
265
268
  functions: list[tuple[Resource, Function]] = []
266
269
  agents: list[tuple[Resource, Agent]] = []
267
270
  for resource in get_resources("agent", settings.server.directory):
268
- agent = get_beamlit_deployment_from_resource(resource)
271
+ agent = get_beamlit_deployment_from_resource(settings, resource)
269
272
  if name and agent.metadata.name != name:
270
273
  agent.metadata.name = slugify(name)
271
274
  if agent:
272
275
  agents.append((resource, agent))
273
276
  for resource in get_resources("function", settings.server.directory):
274
- function = get_beamlit_deployment_from_resource(resource)
277
+ function = get_beamlit_deployment_from_resource(settings, resource)
275
278
  if function:
276
279
  functions.append((resource, function))
277
280
 
@@ -28,6 +28,7 @@ from beamlit.authentication import new_client
28
28
  from beamlit.client import AuthenticatedClient
29
29
  from beamlit.common import slugify
30
30
  from beamlit.common.settings import get_settings
31
+ from beamlit.functions.local.local import LocalToolKit
31
32
  from beamlit.functions.remote.remote import RemoteToolkit
32
33
  from beamlit.models import AgentChain
33
34
 
@@ -35,10 +36,12 @@ logger = getLogger(__name__)
35
36
 
36
37
  def get_functions(
37
38
  remote_functions: Union[list[str], None] = None,
39
+ local_functions: Union[list[dict], None] = None,
38
40
  client: Union[AuthenticatedClient, None] = None,
39
41
  dir: Union[str, None] = None,
40
42
  chain: Union[list[AgentChain], None] = None,
41
43
  remote_functions_empty: bool = True,
44
+ local_functions_empty: bool = True,
42
45
  from_decorator: str = "function",
43
46
  warning: bool = True,
44
47
  ):
@@ -140,6 +143,7 @@ def get_functions(
140
143
  client=client,
141
144
  dir=os.path.join(root),
142
145
  remote_functions_empty=remote_functions_empty,
146
+ local_functions_empty=local_functions_empty,
143
147
  from_decorator="kit",
144
148
  )
145
149
  functions.extend(kit_functions)
@@ -187,6 +191,18 @@ def get_functions(
187
191
  f"Traceback:\n{traceback.format_exc()}"
188
192
  )
189
193
  logger.warn(f"Failed to initialize remote function {function}: {e!s}")
194
+ if local_functions:
195
+ for function in local_functions:
196
+ try:
197
+ toolkit = LocalToolKit(client, function)
198
+ toolkit.initialize()
199
+ functions.extend(toolkit.get_tools())
200
+ except Exception as e:
201
+ logger.debug(
202
+ f"Failed to initialize local function {function}: {e!s}\n"
203
+ f"Traceback:\n{traceback.format_exc()}"
204
+ )
205
+ logger.warn(f"Failed to initialize local function {function}: {e!s}")
190
206
 
191
207
  if chain:
192
208
  toolkit = ChainToolkit(client, chain)
@@ -0,0 +1,49 @@
1
+ from dataclasses import dataclass
2
+
3
+ import pydantic
4
+ from langchain_core.tools.base import BaseTool
5
+
6
+ from beamlit.authentication.authentication import AuthenticatedClient
7
+ from beamlit.functions.mcp.mcp import MCPClient, MCPToolkit
8
+ from beamlit.models import Function
9
+
10
+
11
+ @dataclass
12
+ class LocalToolKit:
13
+ """
14
+ Toolkit for managing local tools.
15
+
16
+ Attributes:
17
+ client (AuthenticatedClient): The authenticated client instance.
18
+ function (str): The name of the local function to integrate.
19
+ _function (Function | None): Cached Function object after initialization.
20
+ """
21
+ client: AuthenticatedClient
22
+ local_function: dict
23
+ _function: Function | None = None
24
+ model_config = pydantic.ConfigDict(arbitrary_types_allowed=True)
25
+
26
+ def initialize(self) -> None:
27
+ """Initialize the session and retrieve the local function details."""
28
+ if self._function is None:
29
+ try:
30
+ # For local functions, we directly create the Function object
31
+ # based on the local function name
32
+ self._function = Function(
33
+ metadata={"name": self.local_function['name']},
34
+ spec={
35
+ "configurations": {
36
+ "url": self.local_function['url'],
37
+ "sse": self.local_function['sse'],
38
+ },
39
+ "description": self.local_function['description'] or "",
40
+ }
41
+ )
42
+ except Exception as e:
43
+ raise RuntimeError(f"Failed to initialize local function: {e}")
44
+
45
+ def get_tools(self) -> list[BaseTool]:
46
+ mcp_client = MCPClient(self.client, self._function.spec["configurations"]["url"], sse=self._function.spec["configurations"]["sse"])
47
+ mcp_toolkit = MCPToolkit(client=mcp_client)
48
+ mcp_toolkit.initialize()
49
+ return mcp_toolkit.get_tools()
@@ -4,91 +4,87 @@ It includes classes for managing MCP clients, creating dynamic schemas, and inte
4
4
  """
5
5
 
6
6
  import asyncio
7
+ import logging
7
8
  import warnings
8
- from typing import Any, Callable
9
+ from typing import Any, AsyncIterator, Callable
9
10
 
10
11
  import pydantic
11
12
  import pydantic_core
12
13
  import requests
13
14
  import typing_extensions as t
14
15
  from langchain_core.tools.base import BaseTool, BaseToolkit, ToolException
16
+ from mcp import ClientSession
17
+ from mcp.client.sse import sse_client
15
18
  from mcp.types import CallToolResult, ListToolsResult
16
- from pydantic.json_schema import JsonSchemaValue
17
- from pydantic_core import core_schema as cs
18
19
 
19
20
  from beamlit.authentication.authentication import AuthenticatedClient
20
21
  from beamlit.common.settings import get_settings
21
22
 
22
- settings = get_settings()
23
+ from .utils import create_schema_model
23
24
 
24
- TYPE_MAP = {
25
- "integer": int,
26
- "number": float,
27
- "array": list,
28
- "object": dict,
29
- "boolean": bool,
30
- "string": str,
31
- "null": type(None),
32
- }
33
-
34
- FIELD_DEFAULTS = {
35
- int: 0,
36
- float: 0.0,
37
- list: [],
38
- bool: False,
39
- str: "",
40
- type(None): None,
41
- }
42
-
43
- def configure_field(name: str, type_: dict[str, t.Any], required: list[str]) -> tuple[type, t.Any]:
44
- field_type = TYPE_MAP[type_["type"]]
45
- default_ = FIELD_DEFAULTS.get(field_type) if name not in required else ...
46
- return field_type, default_
47
-
48
- def create_schema_model(name: str, schema: dict[str, t.Any]) -> type[pydantic.BaseModel]:
49
- # Create a new model class that returns our JSON schema.
50
- # LangChain requires a BaseModel class.
51
- class SchemaBase(pydantic.BaseModel):
52
- model_config = pydantic.ConfigDict(extra="allow")
53
-
54
- @t.override
55
- @classmethod
56
- def __get_pydantic_json_schema__(
57
- cls, core_schema: cs.CoreSchema, handler: pydantic.GetJsonSchemaHandler
58
- ) -> JsonSchemaValue:
59
- return schema
60
-
61
- # Since this langchain patch, we need to synthesize pydantic fields from the schema
62
- # https://github.com/langchain-ai/langchain/commit/033ac417609297369eb0525794d8b48a425b8b33
63
- required = schema.get("required", [])
64
- fields: dict[str, t.Any] = {
65
- name: configure_field(name, type_, required) for name, type_ in schema["properties"].items()
66
- }
67
-
68
- return pydantic.create_model(f"{name}Schema", __base__=SchemaBase, **fields)
25
+ settings = get_settings()
69
26
 
27
+ logger = logging.getLogger(__name__)
70
28
 
71
29
 
72
30
  class MCPClient:
73
31
  def __init__(self, client: AuthenticatedClient, url: str):
74
32
  self.client = client
75
33
  self.url = url
76
-
77
- def list_tools(self) -> requests.Response:
78
- client = self.client.get_httpx_client()
79
- response = client.request("GET", f"{self.url}/tools/list")
80
- response.raise_for_status()
81
- return response
82
-
83
- def call_tool(self, tool_name: str, arguments: dict[str, Any] = None) -> requests.Response:
84
- client = self.client.get_httpx_client()
85
- response = client.request(
86
- "POST",
87
- f"{self.url}/tools/call",
88
- json={"name": tool_name, "arguments": arguments},
89
- )
90
- response.raise_for_status()
91
- return response
34
+ self._sse = False
35
+
36
+ async def list_sse_tools(self) -> ListToolsResult:
37
+ # Create a new context for each SSE connection
38
+ try:
39
+ async with sse_client(f"{self.url}/sse") as (read_stream, write_stream):
40
+ async with ClientSession(read_stream, write_stream) as session:
41
+ await session.initialize()
42
+ response = await session.list_tools()
43
+ return response
44
+ except Exception:
45
+ self._sse = False
46
+ logger.info("SSE not available, trying HTTP")
47
+ return None # Signal to list_tools() to try HTTP instead
48
+
49
+ def list_tools(self) -> ListToolsResult:
50
+ try:
51
+ loop = asyncio.get_event_loop()
52
+ result = loop.run_until_complete(self.list_sse_tools())
53
+ if result is None: # SSE failed, try HTTP
54
+ raise Exception("SSE failed")
55
+ self._sse = True
56
+ return result
57
+ except Exception: # Fallback to HTTP
58
+ client = self.client.get_httpx_client()
59
+ response = client.request("GET", f"{self.url}/tools/list")
60
+ response.raise_for_status()
61
+ return ListToolsResult(**response.json())
62
+
63
+ async def call_tool(
64
+ self,
65
+ tool_name: str,
66
+ arguments: dict[str, Any] = None,
67
+ ) -> requests.Response | AsyncIterator[CallToolResult]:
68
+ if self._sse:
69
+ async with sse_client(f"{self.url}/sse") as (read_stream, write_stream):
70
+ async with ClientSession(read_stream, write_stream) as session:
71
+ await session.initialize()
72
+ response = await session.call_tool(tool_name, arguments or {})
73
+ content = pydantic_core.to_json(response).decode()
74
+ return content
75
+ else: # Fallback to HTTP
76
+ client = self.client.get_httpx_client()
77
+ response = client.request(
78
+ "POST",
79
+ f"{self.url}/tools/call",
80
+ json={"name": tool_name, "arguments": arguments},
81
+ )
82
+ response.raise_for_status()
83
+ result = CallToolResult(response.json())
84
+ if result.isError:
85
+ raise ToolException(result.content)
86
+ content = pydantic_core.to_json(result.content).decode()
87
+ return content
92
88
 
93
89
  class MCPTool(BaseTool):
94
90
  """
@@ -97,6 +93,7 @@ class MCPTool(BaseTool):
97
93
  Attributes:
98
94
  client (MCPClient): The MCP client instance.
99
95
  handle_tool_error (bool | str | Callable[[ToolException], str] | None): Error handling strategy.
96
+ sse (bool): Whether to use SSE streaming for responses.
100
97
  """
101
98
 
102
99
  client: MCPClient
@@ -112,13 +109,7 @@ class MCPTool(BaseTool):
112
109
 
113
110
  @t.override
114
111
  async def _arun(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
115
- result = self.client.call_tool(self.name, arguments=kwargs)
116
- response = result.json()
117
- result = CallToolResult(**response)
118
- if result.isError:
119
- raise ToolException(result.content)
120
- content = pydantic_core.to_json(result.content).decode()
121
- return content
112
+ return await self.client.call_tool(self.name, arguments=kwargs)
122
113
 
123
114
  @t.override
124
115
  @property
@@ -139,14 +130,13 @@ class MCPToolkit(BaseToolkit):
139
130
  """The MCP session used to obtain the tools"""
140
131
 
141
132
  _tools: ListToolsResult | None = None
142
-
143
133
  model_config = pydantic.ConfigDict(arbitrary_types_allowed=True)
144
134
 
145
135
  def initialize(self) -> None:
146
136
  """Initialize the session and retrieve tools list"""
147
137
  if self._tools is None:
148
138
  response = self.client.list_tools()
149
- self._tools = ListToolsResult(**response.json())
139
+ self._tools = response
150
140
 
151
141
  @t.override
152
142
  def get_tools(self) -> list[BaseTool]:
@@ -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 Beamlit.
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
+
@@ -4,6 +4,7 @@ It includes classes for creating dynamic schemas based on function parameters an
4
4
  """
5
5
 
6
6
  import asyncio
7
+ import os
7
8
  import warnings
8
9
  from dataclasses import dataclass
9
10
  from typing import Callable
@@ -67,7 +68,8 @@ class RemoteTool(BaseTool):
67
68
  resource_name: str
68
69
  kit: bool = False
69
70
  handle_tool_error: bool | str | Callable[[ToolException], str] | None = True
70
-
71
+ service_name: str | None = None
72
+ cloud: bool = False
71
73
  @t.override
72
74
  def _run(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
73
75
  warnings.warn(
@@ -87,7 +89,9 @@ class RemoteTool(BaseTool):
87
89
  self.resource_name,
88
90
  settings.environment,
89
91
  "POST",
90
- json=body
92
+ cloud=self.cloud,
93
+ service_name=self.service_name,
94
+ json=body,
91
95
  )
92
96
  return result.text
93
97
 
@@ -110,6 +114,7 @@ class RemoteToolkit:
110
114
  client: AuthenticatedClient
111
115
  function: str
112
116
  _function: Function | None = None
117
+ _service_name: str | None = None
113
118
  model_config = pydantic.ConfigDict(arbitrary_types_allowed=True)
114
119
 
115
120
  def initialize(self) -> None:
@@ -117,6 +122,9 @@ class RemoteToolkit:
117
122
  if self._function is None:
118
123
  try:
119
124
  response = get_function.sync_detailed(self.function, client=self.client)
125
+ function_name = self.function.upper().replace("-", "_")
126
+ if os.getenv(f"BL_FUNCTION_{function_name}_SERVICE_NAME"):
127
+ self._service_name = os.getenv(f"BL_FUNCTION_{function_name}_SERVICE_NAME")
120
128
  self._function = response.parsed
121
129
  except UnexpectedStatus as e:
122
130
  settings = get_settings()
@@ -139,6 +147,8 @@ class RemoteToolkit:
139
147
 
140
148
  if self._function.spec.integration_connections:
141
149
  url = f"{settings.run_url}/{settings.workspace}/functions/{self._function.metadata.name}"
150
+ if self._service_name:
151
+ url = f"https://{self._service_name}.{settings.run_internal_hostname}"
142
152
  mcp_client = MCPClient(self.client, url)
143
153
  mcp_toolkit = MCPToolkit(client=mcp_client)
144
154
  mcp_toolkit.initialize()
@@ -153,6 +163,8 @@ class RemoteToolkit:
153
163
  kit=True,
154
164
  description=func.description or "",
155
165
  args_schema=create_dynamic_schema(func.name, func.parameters),
166
+ cloud=settings.cloud,
167
+ service_name=self._service_name,
156
168
  )
157
169
  for func in self._function.spec.kit
158
170
  ]
@@ -167,5 +179,7 @@ class RemoteToolkit:
167
179
  self._function.metadata.name,
168
180
  self._function.spec.parameters
169
181
  ),
182
+ cloud=settings.cloud,
183
+ service_name=self._service_name,
170
184
  )
171
185
  ]
@@ -5,6 +5,8 @@ from .agent import Agent
5
5
  from .agent_chain import AgentChain
6
6
  from .agent_history import AgentHistory
7
7
  from .agent_history_event import AgentHistoryEvent
8
+ from .agent_information_request import AgentInformationRequest
9
+ from .agent_information_response import AgentInformationResponse
8
10
  from .agent_release import AgentRelease
9
11
  from .agent_spec import AgentSpec
10
12
  from .api_key import ApiKey
@@ -18,11 +20,17 @@ from .create_api_key_for_service_account_body import CreateApiKeyForServiceAccou
18
20
  from .create_workspace_service_account_body import CreateWorkspaceServiceAccountBody
19
21
  from .create_workspace_service_account_response_200 import CreateWorkspaceServiceAccountResponse200
20
22
  from .delete_workspace_service_account_response_200 import DeleteWorkspaceServiceAccountResponse200
23
+ from .entrypoint import Entrypoint
24
+ from .entrypoint_env import EntrypointEnv
21
25
  from .environment import Environment
22
26
  from .environment_metadata import EnvironmentMetadata
23
27
  from .environment_metrics import EnvironmentMetrics
24
28
  from .environment_spec import EnvironmentSpec
25
29
  from .flavor import Flavor
30
+ from .form import Form
31
+ from .form_config import FormConfig
32
+ from .form_oauthomitempty import FormOauthomitempty
33
+ from .form_secrets import FormSecrets
26
34
  from .function import Function
27
35
  from .function_kit import FunctionKit
28
36
  from .function_release import FunctionRelease
@@ -49,6 +57,12 @@ from .knowledgebase_spec_options import KnowledgebaseSpecOptions
49
57
  from .last_n_requests_metric import LastNRequestsMetric
50
58
  from .latency_metric import LatencyMetric
51
59
  from .location_response import LocationResponse
60
+ from .mcp_definition import MCPDefinition
61
+ from .mcp_definition_entrypoint import MCPDefinitionEntrypoint
62
+ from .mcp_definition_form import MCPDefinitionForm
63
+ from .mcp_hub_artifact import MCPHubArtifact
64
+ from .mcp_hub_artifact_entrypoint import MCPHubArtifactEntrypoint
65
+ from .mcp_hub_artifact_form import MCPHubArtifactForm
52
66
  from .metadata import Metadata
53
67
  from .metadata_labels import MetadataLabels
54
68
  from .metric import Metric
@@ -60,6 +74,7 @@ from .model import Model
60
74
  from .model_private_cluster import ModelPrivateCluster
61
75
  from .model_release import ModelRelease
62
76
  from .model_spec import ModelSpec
77
+ from .o_auth import OAuth
63
78
  from .owner_fields import OwnerFields
64
79
  from .pending_invitation import PendingInvitation
65
80
  from .pending_invitation_accept import PendingInvitationAccept
@@ -125,6 +140,8 @@ __all__ = (
125
140
  "AgentChain",
126
141
  "AgentHistory",
127
142
  "AgentHistoryEvent",
143
+ "AgentInformationRequest",
144
+ "AgentInformationResponse",
128
145
  "AgentRelease",
129
146
  "AgentSpec",
130
147
  "ApiKey",
@@ -138,11 +155,17 @@ __all__ = (
138
155
  "CreateWorkspaceServiceAccountBody",
139
156
  "CreateWorkspaceServiceAccountResponse200",
140
157
  "DeleteWorkspaceServiceAccountResponse200",
158
+ "Entrypoint",
159
+ "EntrypointEnv",
141
160
  "Environment",
142
161
  "EnvironmentMetadata",
143
162
  "EnvironmentMetrics",
144
163
  "EnvironmentSpec",
145
164
  "Flavor",
165
+ "Form",
166
+ "FormConfig",
167
+ "FormOauthomitempty",
168
+ "FormSecrets",
146
169
  "Function",
147
170
  "FunctionKit",
148
171
  "FunctionRelease",
@@ -167,6 +190,12 @@ __all__ = (
167
190
  "LastNRequestsMetric",
168
191
  "LatencyMetric",
169
192
  "LocationResponse",
193
+ "MCPDefinition",
194
+ "MCPDefinitionEntrypoint",
195
+ "MCPDefinitionForm",
196
+ "MCPHubArtifact",
197
+ "MCPHubArtifactEntrypoint",
198
+ "MCPHubArtifactForm",
170
199
  "Metadata",
171
200
  "MetadataLabels",
172
201
  "Metric",
@@ -178,6 +207,7 @@ __all__ = (
178
207
  "ModelPrivateCluster",
179
208
  "ModelRelease",
180
209
  "ModelSpec",
210
+ "OAuth",
181
211
  "OwnerFields",
182
212
  "PendingInvitation",
183
213
  "PendingInvitationAccept",