beamlit 0.0.56rc106__py3-none-any.whl → 0.0.57__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 (92) hide show
  1. beamlit/agents/chain.py +0 -2
  2. beamlit/agents/chat.py +20 -8
  3. beamlit/agents/decorator.py +112 -99
  4. beamlit/agents/thread.py +5 -9
  5. beamlit/api/agents/delete_agent.py +1 -22
  6. beamlit/api/agents/get_agent.py +1 -22
  7. beamlit/api/agents/get_agent_metrics.py +13 -34
  8. beamlit/api/agents/get_agent_trace_ids.py +44 -14
  9. beamlit/api/agents/{list_agent_history.py → list_agent_revisions.py} +21 -17
  10. beamlit/api/agents/list_agents.py +4 -36
  11. beamlit/api/default/get_trace_ids.py +0 -15
  12. beamlit/api/default/list_mcp_hub_definitions.py +12 -12
  13. beamlit/api/functions/delete_function.py +1 -22
  14. beamlit/api/functions/get_function.py +1 -22
  15. beamlit/api/functions/get_function_metrics.py +13 -34
  16. beamlit/api/functions/get_function_trace_ids.py +44 -14
  17. beamlit/api/functions/{create_function_release.py → list_function_revisions.py} +26 -18
  18. beamlit/api/functions/list_functions.py +4 -36
  19. beamlit/api/knowledgebases/create_knowledgebase.py +4 -4
  20. beamlit/api/knowledgebases/delete_knowledgebase.py +5 -26
  21. beamlit/api/knowledgebases/get_knowledgebase.py +1 -22
  22. beamlit/api/{environments/get_environment_metrics.py → knowledgebases/list_knowledgebase_revisions.py} +34 -34
  23. beamlit/api/knowledgebases/list_knowledgebases.py +4 -36
  24. beamlit/api/models/create_model.py +4 -8
  25. beamlit/api/models/delete_model.py +1 -22
  26. beamlit/api/models/get_model.py +1 -22
  27. beamlit/api/models/get_model_metrics.py +13 -34
  28. beamlit/api/models/get_model_trace_ids.py +44 -14
  29. beamlit/api/models/{release_model.py → list_model_revisions.py} +26 -22
  30. beamlit/api/models/list_models.py +4 -36
  31. beamlit/api/models/update_model.py +4 -8
  32. beamlit/authentication/authentication.py +11 -8
  33. beamlit/authentication/clientcredentials.py +15 -28
  34. beamlit/authentication/credentials.py +2 -7
  35. beamlit/common/settings.py +1 -4
  36. beamlit/deploy/deploy.py +15 -9
  37. beamlit/functions/common.py +16 -16
  38. beamlit/functions/local/local.py +4 -5
  39. beamlit/functions/mcp/client.py +96 -0
  40. beamlit/functions/mcp/mcp.py +56 -43
  41. beamlit/functions/remote/remote.py +9 -11
  42. beamlit/models/__init__.py +8 -38
  43. beamlit/models/agent.py +6 -6
  44. beamlit/models/function.py +6 -6
  45. beamlit/models/knowledgebase.py +6 -6
  46. beamlit/models/last_n_requests_metric.py +0 -9
  47. beamlit/models/model.py +7 -7
  48. beamlit/models/{resource_environment_metrics.py → resource_metrics.py} +20 -26
  49. beamlit/models/{resource_environment_metrics_request_total_per_code.py → resource_metrics_request_total_per_code.py} +5 -5
  50. beamlit/models/{resource_environment_metrics_rps_per_code.py → resource_metrics_rps_per_code.py} +5 -5
  51. beamlit/models/{model_release.py → revision_metadata.py} +20 -20
  52. beamlit/models/runtime.py +2 -2
  53. beamlit/models/workspace.py +0 -9
  54. beamlit/run.py +3 -7
  55. beamlit/serve/app.py +4 -8
  56. {beamlit-0.0.56rc106.dist-info → beamlit-0.0.57.dist-info}/METADATA +2 -1
  57. {beamlit-0.0.56rc106.dist-info → beamlit-0.0.57.dist-info}/RECORD +63 -91
  58. beamlit/api/agents/create_agent_release.py +0 -146
  59. beamlit/api/agents/delete_agent_history.py +0 -155
  60. beamlit/api/agents/get_agent_history.py +0 -155
  61. beamlit/api/agents/put_agent_history.py +0 -181
  62. beamlit/api/environments/__init__.py +0 -0
  63. beamlit/api/environments/create_environment.py +0 -167
  64. beamlit/api/environments/delete_environment.py +0 -154
  65. beamlit/api/environments/get_environment.py +0 -154
  66. beamlit/api/environments/list_environments.py +0 -139
  67. beamlit/api/environments/update_environment.py +0 -180
  68. beamlit/api/generation/__init__.py +0 -0
  69. beamlit/api/generation/run_information_generation_agent.py +0 -168
  70. beamlit/api/history/__init__.py +0 -0
  71. beamlit/api/history/get_agents_history.py +0 -155
  72. beamlit/api/history/list_agents_history.py +0 -131
  73. beamlit/models/agent_history.py +0 -167
  74. beamlit/models/agent_history_event.py +0 -133
  75. beamlit/models/agent_information_request.py +0 -63
  76. beamlit/models/agent_information_response.py +0 -79
  77. beamlit/models/agent_release.py +0 -70
  78. beamlit/models/environment.py +0 -96
  79. beamlit/models/environment_metadata.py +0 -148
  80. beamlit/models/environment_metrics.py +0 -77
  81. beamlit/models/environment_spec.py +0 -63
  82. beamlit/models/function_release.py +0 -70
  83. beamlit/models/knowledgebase_release.py +0 -70
  84. beamlit/models/mcp_hub_artifact.py +0 -188
  85. beamlit/models/mcp_hub_artifact_entrypoint.py +0 -45
  86. beamlit/models/mcp_hub_artifact_form.py +0 -45
  87. /beamlit/api/agents/{get_agent_environment_logs.py → get_agent_logs.py} +0 -0
  88. /beamlit/api/functions/{get_function_environment_logs.py → get_function_logs.py} +0 -0
  89. /beamlit/api/models/{get_model_environment_logs.py → get_model_logs.py} +0 -0
  90. {beamlit-0.0.56rc106.dist-info → beamlit-0.0.57.dist-info}/WHEEL +0 -0
  91. {beamlit-0.0.56rc106.dist-info → beamlit-0.0.57.dist-info}/entry_points.txt +0 -0
  92. {beamlit-0.0.56rc106.dist-info → beamlit-0.0.57.dist-info}/licenses/LICENSE +0 -0
@@ -5,7 +5,7 @@ import httpx
5
5
 
6
6
  from ... import errors
7
7
  from ...client import AuthenticatedClient, Client
8
- from ...models.model_release import ModelRelease
8
+ from ...models.revision_metadata import RevisionMetadata
9
9
  from ...types import Response
10
10
 
11
11
 
@@ -13,16 +13,18 @@ def _get_kwargs(
13
13
  model_name: str,
14
14
  ) -> dict[str, Any]:
15
15
  _kwargs: dict[str, Any] = {
16
- "method": "post",
17
- "url": f"/models/{model_name}/release",
16
+ "method": "get",
17
+ "url": f"/models/{model_name}/revisions",
18
18
  }
19
19
 
20
20
  return _kwargs
21
21
 
22
22
 
23
- def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[ModelRelease]:
23
+ def _parse_response(
24
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
25
+ ) -> Optional[RevisionMetadata]:
24
26
  if response.status_code == 200:
25
- response_200 = ModelRelease.from_dict(response.json())
27
+ response_200 = RevisionMetadata.from_dict(response.json())
26
28
 
27
29
  return response_200
28
30
  if client.raise_on_unexpected_status:
@@ -31,7 +33,9 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
31
33
  return None
32
34
 
33
35
 
34
- def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[ModelRelease]:
36
+ def _build_response(
37
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
38
+ ) -> Response[RevisionMetadata]:
35
39
  return Response(
36
40
  status_code=HTTPStatus(response.status_code),
37
41
  content=response.content,
@@ -44,10 +48,10 @@ def sync_detailed(
44
48
  model_name: str,
45
49
  *,
46
50
  client: AuthenticatedClient,
47
- ) -> Response[ModelRelease]:
48
- """Release model from an environment
51
+ ) -> Response[RevisionMetadata]:
52
+ """List model revisions
49
53
 
50
- Make a release for a model from an environment to another.
54
+ Returns revisions for a model by name.
51
55
 
52
56
  Args:
53
57
  model_name (str):
@@ -57,7 +61,7 @@ def sync_detailed(
57
61
  httpx.TimeoutException: If the request takes longer than Client.timeout.
58
62
 
59
63
  Returns:
60
- Response[ModelRelease]
64
+ Response[RevisionMetadata]
61
65
  """
62
66
 
63
67
  kwargs = _get_kwargs(
@@ -75,10 +79,10 @@ def sync(
75
79
  model_name: str,
76
80
  *,
77
81
  client: AuthenticatedClient,
78
- ) -> Optional[ModelRelease]:
79
- """Release model from an environment
82
+ ) -> Optional[RevisionMetadata]:
83
+ """List model revisions
80
84
 
81
- Make a release for a model from an environment to another.
85
+ Returns revisions for a model by name.
82
86
 
83
87
  Args:
84
88
  model_name (str):
@@ -88,7 +92,7 @@ def sync(
88
92
  httpx.TimeoutException: If the request takes longer than Client.timeout.
89
93
 
90
94
  Returns:
91
- ModelRelease
95
+ RevisionMetadata
92
96
  """
93
97
 
94
98
  return sync_detailed(
@@ -101,10 +105,10 @@ async def asyncio_detailed(
101
105
  model_name: str,
102
106
  *,
103
107
  client: AuthenticatedClient,
104
- ) -> Response[ModelRelease]:
105
- """Release model from an environment
108
+ ) -> Response[RevisionMetadata]:
109
+ """List model revisions
106
110
 
107
- Make a release for a model from an environment to another.
111
+ Returns revisions for a model by name.
108
112
 
109
113
  Args:
110
114
  model_name (str):
@@ -114,7 +118,7 @@ async def asyncio_detailed(
114
118
  httpx.TimeoutException: If the request takes longer than Client.timeout.
115
119
 
116
120
  Returns:
117
- Response[ModelRelease]
121
+ Response[RevisionMetadata]
118
122
  """
119
123
 
120
124
  kwargs = _get_kwargs(
@@ -130,10 +134,10 @@ async def asyncio(
130
134
  model_name: str,
131
135
  *,
132
136
  client: AuthenticatedClient,
133
- ) -> Optional[ModelRelease]:
134
- """Release model from an environment
137
+ ) -> Optional[RevisionMetadata]:
138
+ """List model revisions
135
139
 
136
- Make a release for a model from an environment to another.
140
+ Returns revisions for a model by name.
137
141
 
138
142
  Args:
139
143
  model_name (str):
@@ -143,7 +147,7 @@ async def asyncio(
143
147
  httpx.TimeoutException: If the request takes longer than Client.timeout.
144
148
 
145
149
  Returns:
146
- ModelRelease
150
+ RevisionMetadata
147
151
  """
148
152
 
149
153
  return (
@@ -6,23 +6,13 @@ import httpx
6
6
  from ... import errors
7
7
  from ...client import AuthenticatedClient, Client
8
8
  from ...models.model import Model
9
- from ...types import UNSET, Response, Unset
9
+ from ...types import Response
10
10
 
11
11
 
12
- def _get_kwargs(
13
- *,
14
- environment: Union[Unset, str] = UNSET,
15
- ) -> dict[str, Any]:
16
- params: dict[str, Any] = {}
17
-
18
- params["environment"] = environment
19
-
20
- params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
21
-
12
+ def _get_kwargs() -> dict[str, Any]:
22
13
  _kwargs: dict[str, Any] = {
23
14
  "method": "get",
24
15
  "url": "/models",
25
- "params": params,
26
16
  }
27
17
 
28
18
  return _kwargs
@@ -56,15 +46,11 @@ def _build_response(*, client: Union[AuthenticatedClient, Client], response: htt
56
46
  def sync_detailed(
57
47
  *,
58
48
  client: AuthenticatedClient,
59
- environment: Union[Unset, str] = UNSET,
60
49
  ) -> Response[list["Model"]]:
61
50
  """List models
62
51
 
63
52
  Returns a list of all models in the workspace.
64
53
 
65
- Args:
66
- environment (Union[Unset, str]):
67
-
68
54
  Raises:
69
55
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
70
56
  httpx.TimeoutException: If the request takes longer than Client.timeout.
@@ -73,9 +59,7 @@ def sync_detailed(
73
59
  Response[list['Model']]
74
60
  """
75
61
 
76
- kwargs = _get_kwargs(
77
- environment=environment,
78
- )
62
+ kwargs = _get_kwargs()
79
63
 
80
64
  response = client.get_httpx_client().request(
81
65
  **kwargs,
@@ -87,15 +71,11 @@ def sync_detailed(
87
71
  def sync(
88
72
  *,
89
73
  client: AuthenticatedClient,
90
- environment: Union[Unset, str] = UNSET,
91
74
  ) -> Optional[list["Model"]]:
92
75
  """List models
93
76
 
94
77
  Returns a list of all models in the workspace.
95
78
 
96
- Args:
97
- environment (Union[Unset, str]):
98
-
99
79
  Raises:
100
80
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
101
81
  httpx.TimeoutException: If the request takes longer than Client.timeout.
@@ -106,22 +86,17 @@ def sync(
106
86
 
107
87
  return sync_detailed(
108
88
  client=client,
109
- environment=environment,
110
89
  ).parsed
111
90
 
112
91
 
113
92
  async def asyncio_detailed(
114
93
  *,
115
94
  client: AuthenticatedClient,
116
- environment: Union[Unset, str] = UNSET,
117
95
  ) -> Response[list["Model"]]:
118
96
  """List models
119
97
 
120
98
  Returns a list of all models in the workspace.
121
99
 
122
- Args:
123
- environment (Union[Unset, str]):
124
-
125
100
  Raises:
126
101
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
127
102
  httpx.TimeoutException: If the request takes longer than Client.timeout.
@@ -130,9 +105,7 @@ async def asyncio_detailed(
130
105
  Response[list['Model']]
131
106
  """
132
107
 
133
- kwargs = _get_kwargs(
134
- environment=environment,
135
- )
108
+ kwargs = _get_kwargs()
136
109
 
137
110
  response = await client.get_async_httpx_client().request(**kwargs)
138
111
 
@@ -142,15 +115,11 @@ async def asyncio_detailed(
142
115
  async def asyncio(
143
116
  *,
144
117
  client: AuthenticatedClient,
145
- environment: Union[Unset, str] = UNSET,
146
118
  ) -> Optional[list["Model"]]:
147
119
  """List models
148
120
 
149
121
  Returns a list of all models in the workspace.
150
122
 
151
- Args:
152
- environment (Union[Unset, str]):
153
-
154
123
  Raises:
155
124
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
156
125
  httpx.TimeoutException: If the request takes longer than Client.timeout.
@@ -162,6 +131,5 @@ async def asyncio(
162
131
  return (
163
132
  await asyncio_detailed(
164
133
  client=client,
165
- environment=environment,
166
134
  )
167
135
  ).parsed
@@ -62,8 +62,7 @@ def sync_detailed(
62
62
 
63
63
  Args:
64
64
  model_name (str):
65
- body (Model): Logical object representing a model, that can be instantiated in multiple
66
- environments as model deployments
65
+ body (Model): Logical object representing a model
67
66
 
68
67
  Raises:
69
68
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -97,8 +96,7 @@ def sync(
97
96
 
98
97
  Args:
99
98
  model_name (str):
100
- body (Model): Logical object representing a model, that can be instantiated in multiple
101
- environments as model deployments
99
+ body (Model): Logical object representing a model
102
100
 
103
101
  Raises:
104
102
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -127,8 +125,7 @@ async def asyncio_detailed(
127
125
 
128
126
  Args:
129
127
  model_name (str):
130
- body (Model): Logical object representing a model, that can be instantiated in multiple
131
- environments as model deployments
128
+ body (Model): Logical object representing a model
132
129
 
133
130
  Raises:
134
131
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -160,8 +157,7 @@ async def asyncio(
160
157
 
161
158
  Args:
162
159
  model_name (str):
163
- body (Model): Logical object representing a model, that can be instantiated in multiple
164
- environments as model deployments
160
+ body (Model): Logical object representing a model
165
161
 
166
162
  Raises:
167
163
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -7,21 +7,18 @@ It also includes utilities for creating authenticated clients and managing authe
7
7
  from dataclasses import dataclass
8
8
  from typing import Dict, Generator
9
9
 
10
- from httpx import Auth, Request, Response
11
-
12
10
  from beamlit.common.settings import Settings, get_settings
11
+ from httpx import Auth, Request, Response
13
12
 
14
13
  from ..client import AuthenticatedClient
15
14
  from .apikey import ApiKeyProvider
16
15
  from .clientcredentials import ClientCredentials
17
- from .credentials import (
18
- Credentials,
19
- current_context,
20
- load_credentials,
21
- load_credentials_from_settings,
22
- )
16
+ from .credentials import (Credentials, current_context, load_credentials,
17
+ load_credentials_from_settings)
23
18
  from .device_mode import BearerToken
24
19
 
20
+ global provider_singleton
21
+ provider_singleton = None
25
22
 
26
23
  class PublicProvider(Auth):
27
24
  """
@@ -144,6 +141,11 @@ def get_authentication_headers(settings: Settings) -> Dict[str, str]:
144
141
  Returns:
145
142
  Dict[str, str]: A dictionary of authentication headers.
146
143
  """
144
+ global provider_singleton
145
+
146
+ if provider_singleton:
147
+ return provider_singleton.get_headers()
148
+
147
149
  context = current_context()
148
150
  if context.workspace and not settings.authentication.client.credentials:
149
151
  credentials = load_credentials(context.workspace)
@@ -165,4 +167,5 @@ def get_authentication_headers(settings: Settings) -> Dict[str, str]:
165
167
 
166
168
  if provider is None:
167
169
  return None
170
+ provider_singleton = provider
168
171
  return provider.get_headers()
@@ -4,16 +4,13 @@ authentication for Beamlit. It manages token refreshing and authentication flows
4
4
  client credentials and refresh tokens.
5
5
  """
6
6
 
7
- import base64
8
- import json
9
7
  from dataclasses import dataclass
10
8
  from datetime import datetime, timedelta
11
9
  from typing import Generator, Optional
12
10
 
13
11
  import requests
14
- from httpx import Auth, Request, Response, post
15
-
16
12
  from beamlit.common.settings import get_settings
13
+ from httpx import Auth, Request, Response, post
17
14
 
18
15
 
19
16
  @dataclass
@@ -39,6 +36,7 @@ class ClientCredentials(Auth):
39
36
  base_url (str): The base URL for authentication.
40
37
  """
41
38
  self.credentials = credentials
39
+ self.expires_at = None
42
40
  self.workspace_name = workspace_name
43
41
  self.base_url = base_url
44
42
 
@@ -52,16 +50,15 @@ class ClientCredentials(Auth):
52
50
  Raises:
53
51
  Exception: If token refresh fails.
54
52
  """
55
- err = self.refresh_if_needed()
53
+ err = self.get_token()
56
54
  if err:
57
55
  raise err
58
-
59
56
  return {
60
57
  "X-Beamlit-Authorization": f"Bearer {self.credentials.access_token}",
61
58
  "X-Beamlit-Workspace": self.workspace_name,
62
59
  }
63
60
 
64
- def refresh_if_needed(self) -> Optional[Exception]:
61
+ def get_token(self) -> Optional[Exception]:
65
62
  """
66
63
  Checks if the access token needs to be refreshed and performs the refresh if necessary.
67
64
 
@@ -69,33 +66,23 @@ class ClientCredentials(Auth):
69
66
  Optional[Exception]: An exception if refreshing fails, otherwise None.
70
67
  """
71
68
  settings = get_settings()
72
- if self.credentials.client_credentials and not self.credentials.refresh_token:
69
+ if self.need_token():
73
70
  headers = {"Authorization": f"Basic {self.credentials.client_credentials}", "Content-Type": "application/json"}
74
71
  body = {"grant_type": "client_credentials"}
75
72
  response = requests.post(f"{settings.base_url}/oauth/token", headers=headers, json=body)
76
73
  response.raise_for_status()
77
- self.credentials.access_token = response.json()["access_token"]
78
- self.credentials.refresh_token = response.json()["refresh_token"]
79
- self.credentials.expires_in = response.json()["expires_in"]
80
-
81
- # Need to refresh token if expires in less than 10 minutes
82
- parts = self.credentials.access_token.split(".")
83
- if len(parts) != 3:
84
- return Exception("Invalid JWT token format")
85
- try:
86
- claims_bytes = base64.urlsafe_b64decode(parts[1] + "=" * (-len(parts[1]) % 4))
87
- claims = json.loads(claims_bytes)
88
- except Exception as e:
89
- return Exception(f"Failed to decode/parse JWT claims: {str(e)}")
90
-
91
- exp_time = datetime.fromtimestamp(claims["exp"])
92
- current_time = datetime.now()
93
- # Refresh if token expires in less than 10 minutes
94
- if current_time + timedelta(minutes=10) > exp_time:
95
- return self.do_refresh()
96
-
74
+ creds = response.json()
75
+ self.credentials.access_token = creds["access_token"]
76
+ self.credentials.refresh_token = creds["refresh_token"]
77
+ self.credentials.expires_in = creds["expires_in"]
78
+ self.expires_at = datetime.now() + timedelta(seconds=self.credentials.expires_in)
97
79
  return None
98
80
 
81
+ def need_token(self):
82
+ if not self.expires_at:
83
+ return True
84
+ return datetime.now() > self.expires_at - timedelta(minutes=10)
85
+
99
86
  def auth_flow(self, request: Request) -> Generator[Request, Response, None]:
100
87
  """
101
88
  Processes the authentication flow by ensuring tokens are valid and adding necessary headers.
@@ -57,10 +57,8 @@ class ContextConfig:
57
57
 
58
58
  Attributes:
59
59
  workspace (str): The name of the current workspace.
60
- environment (str): The current environment (e.g., development, production).
61
60
  """
62
61
  workspace: str = ""
63
- environment: str = ""
64
62
 
65
63
 
66
64
  @dataclass
@@ -108,7 +106,6 @@ class Config:
108
106
  ],
109
107
  "context": {
110
108
  "workspace": self.context.workspace,
111
- "environment": self.context.environment,
112
109
  },
113
110
  }
114
111
 
@@ -186,17 +183,15 @@ def current_context() -> ContextConfig:
186
183
  return config.context
187
184
 
188
185
 
189
- def set_current_workspace(workspace_name: str, environment: str):
186
+ def set_current_workspace(workspace_name: str):
190
187
  """
191
- Sets the current workspace and environment in the configuration.
188
+ Sets the current workspace in the configuration.
192
189
 
193
190
  Parameters:
194
191
  workspace_name (str): The name of the workspace to set as current.
195
- environment (str): The environment to set for the workspace.
196
192
  """
197
193
  config = load_config()
198
194
  config.context.workspace = workspace_name
199
- config.context.environment = environment
200
195
  save_config(config)
201
196
 
202
197
 
@@ -76,7 +76,6 @@ class Settings(BaseSettings):
76
76
  )
77
77
 
78
78
  workspace: str
79
- environment: str = Field(default="production")
80
79
  remote: bool = Field(default=False)
81
80
  type: str = Field(default="agent")
82
81
  name: str = Field(default="beamlit-agent")
@@ -130,7 +129,7 @@ def init() -> Settings:
130
129
  """
131
130
  Initializes the settings by parsing the `beamlit.yaml` file and setting up logging.
132
131
 
133
- This function reads workspace and environment configurations from the current context,
132
+ This function reads workspace configuration from the current context,
134
133
  initializes the global SETTINGS variable, and configures the logger based on the log level.
135
134
 
136
135
  Returns:
@@ -144,8 +143,6 @@ def init() -> Settings:
144
143
  kwargs = {}
145
144
  if context.workspace:
146
145
  kwargs["workspace"] = context.workspace
147
- if context.environment:
148
- kwargs["environment"] = context.environment
149
146
 
150
147
  SETTINGS = Settings(**kwargs)
151
148
  init_logger(SETTINGS.log_level)
beamlit/deploy/deploy.py CHANGED
@@ -23,10 +23,10 @@ from beamlit.common.settings import Settings, get_settings, init
23
23
  from beamlit.models import (
24
24
  Agent,
25
25
  AgentSpec,
26
- EnvironmentMetadata,
27
26
  Flavor,
28
27
  Function,
29
28
  FunctionSpec,
29
+ Metadata,
30
30
  MetadataLabels,
31
31
  )
32
32
 
@@ -49,13 +49,20 @@ def set_default_values(resource: Resource, deployment: Agent | Function):
49
49
  """
50
50
  settings = get_settings()
51
51
  deployment.metadata.workspace = settings.workspace
52
- deployment.metadata.environment = settings.environment
53
52
  if not deployment.metadata.name:
54
53
  deployment.metadata.name = slugify(resource.name)
55
54
  if not deployment.metadata.display_name:
56
55
  deployment.metadata.display_name = deployment.metadata.name
57
56
  if not deployment.spec.description:
58
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))
59
66
  return deployment
60
67
 
61
68
  def get_beamlit_deployment_from_resource(
@@ -75,8 +82,7 @@ def get_beamlit_deployment_from_resource(
75
82
  if arg.arg == "agent":
76
83
  if isinstance(arg.value, ast.Dict):
77
84
  value = arg_to_dict(arg.value)
78
- metadata = EnvironmentMetadata(**value.get("metadata", {}))
79
- metadata.environment = settings.environment
85
+ metadata = Metadata(**value.get("metadata", {}))
80
86
  spec = AgentSpec(**value.get("spec", {}))
81
87
  agent = Agent(metadata=metadata, spec=spec)
82
88
  if not agent.spec.prompt:
@@ -85,18 +91,17 @@ def get_beamlit_deployment_from_resource(
85
91
  if arg.arg == "function":
86
92
  if isinstance(arg.value, ast.Dict):
87
93
  value = arg_to_dict(arg.value)
88
- metadata = EnvironmentMetadata(**value.get("metadata", {}))
89
- metadata.environment = settings.environment
94
+ metadata = Metadata(**value.get("metadata", {}))
90
95
  spec = FunctionSpec(**value.get("spec", {}))
91
96
  func = Function(metadata=metadata, spec=spec)
92
97
  if not func.spec.parameters:
93
98
  func.spec.parameters = get_parameters(resource)
94
99
  return set_default_values(resource, func)
95
100
  if resource.type == "agent":
96
- agent = Agent(metadata=EnvironmentMetadata(), spec=AgentSpec())
101
+ agent = Agent(metadata=Metadata(), spec=AgentSpec())
97
102
  return set_default_values(resource, agent)
98
103
  if resource.type == "function":
99
- func = Function(metadata=EnvironmentMetadata(), spec=FunctionSpec())
104
+ func = Function(metadata=Metadata(), spec=FunctionSpec())
100
105
  func.spec.parameters = get_parameters(resource)
101
106
  return set_default_values(resource, func)
102
107
  return None
@@ -134,7 +139,8 @@ def get_agent_yaml(
134
139
  agent.spec.repository = agent_response.spec.repository
135
140
  except Exception:
136
141
  pass
137
- agent.spec.functions = [slugify(function.metadata.name) for (_, function) in functions]
142
+ agent.spec.functions = agent.spec.functions or []
143
+ agent.spec.functions = agent.spec.functions + [slugify(function.metadata.name) for (_, function) in functions]
138
144
  agent.metadata.labels = agent.metadata.labels and MetadataLabels.from_dict(agent.metadata.labels) or MetadataLabels()
139
145
  agent.metadata.labels["x-beamlit-auto-generated"] = "true"
140
146
  agent_yaml = yaml.dump(agent.to_dict())
@@ -34,7 +34,7 @@ from beamlit.models import AgentChain
34
34
 
35
35
  logger = getLogger(__name__)
36
36
 
37
- def get_functions(
37
+ async def get_functions(
38
38
  remote_functions: Union[list[str], None] = None,
39
39
  local_functions: Union[list[dict], None] = None,
40
40
  client: Union[AuthenticatedClient, None] = None,
@@ -139,7 +139,7 @@ def get_functions(
139
139
  ):
140
140
  is_kit = keyword.value.value
141
141
  if is_kit and not settings.remote:
142
- kit_functions = get_functions(
142
+ kit_functions = await get_functions(
143
143
  client=client,
144
144
  dir=os.path.join(root),
145
145
  remote_functions_empty=remote_functions_empty,
@@ -153,8 +153,8 @@ def get_functions(
153
153
  func = getattr(module, func_name)
154
154
  if settings.remote:
155
155
  toolkit = RemoteToolkit(client, slugify(func.__name__))
156
- toolkit.initialize()
157
- functions.extend(toolkit.get_tools())
156
+ await toolkit.initialize()
157
+ functions.extend(await toolkit.get_tools())
158
158
  else:
159
159
  if asyncio.iscoroutinefunction(func):
160
160
  functions.append(
@@ -183,20 +183,21 @@ def get_functions(
183
183
  for function in remote_functions:
184
184
  try:
185
185
  toolkit = RemoteToolkit(client, function)
186
- toolkit.initialize()
187
- functions.extend(toolkit.get_tools())
186
+ await toolkit.initialize()
187
+ functions.extend(await toolkit.get_tools())
188
188
  except Exception as e:
189
- logger.debug(
190
- f"Failed to initialize remote function {function}: {e!s}\n"
191
- f"Traceback:\n{traceback.format_exc()}"
192
- )
193
- logger.warn(f"Failed to initialize remote function {function}: {e!s}")
189
+ if not isinstance(e, RuntimeError):
190
+ logger.debug(
191
+ f"Failed to initialize remote function {function}: {e!s}\n"
192
+ f"Traceback:\n{traceback.format_exc()}"
193
+ )
194
+ logger.warn(f"Failed to initialize remote function {function}: {e!s}")
194
195
  if local_functions:
195
196
  for function in local_functions:
196
197
  try:
197
198
  toolkit = LocalToolKit(client, function)
198
- toolkit.initialize()
199
- functions.extend(toolkit.get_tools())
199
+ await toolkit.initialize()
200
+ functions.extend(await toolkit.get_tools())
200
201
  except Exception as e:
201
202
  logger.debug(
202
203
  f"Failed to initialize local function {function}: {e!s}\n"
@@ -206,8 +207,7 @@ def get_functions(
206
207
 
207
208
  if chain:
208
209
  toolkit = ChainToolkit(client, chain)
209
- toolkit.initialize()
210
- functions.extend(toolkit.get_tools())
211
-
210
+ await toolkit.initialize()
211
+ functions.extend(await toolkit.get_tools())
212
212
  return functions
213
213
 
@@ -23,7 +23,7 @@ class LocalToolKit:
23
23
  _function: Function | None = None
24
24
  model_config = pydantic.ConfigDict(arbitrary_types_allowed=True)
25
25
 
26
- def initialize(self) -> None:
26
+ async def initialize(self) -> None:
27
27
  """Initialize the session and retrieve the local function details."""
28
28
  if self._function is None:
29
29
  try:
@@ -34,7 +34,6 @@ class LocalToolKit:
34
34
  spec={
35
35
  "configurations": {
36
36
  "url": self.local_function['url'],
37
- "sse": self.local_function['sse'],
38
37
  },
39
38
  "description": self.local_function['description'] or "",
40
39
  }
@@ -42,8 +41,8 @@ class LocalToolKit:
42
41
  except Exception as e:
43
42
  raise RuntimeError(f"Failed to initialize local function: {e}")
44
43
 
45
- def get_tools(self) -> list[BaseTool]:
44
+ async def get_tools(self) -> list[BaseTool]:
46
45
  mcp_client = MCPClient(self.client, self._function.spec["configurations"]["url"], sse=self._function.spec["configurations"]["sse"])
47
46
  mcp_toolkit = MCPToolkit(client=mcp_client)
48
- mcp_toolkit.initialize()
49
- return mcp_toolkit.get_tools()
47
+ await mcp_toolkit.initialize()
48
+ return await mcp_toolkit.get_tools()