beamlit 0.0.18__py3-none-any.whl → 0.0.20rc1__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 (73) hide show
  1. beamlit/api/agents/create_agent.py +14 -9
  2. beamlit/api/agents/get_agent_deployment.py +22 -1
  3. beamlit/api/agents/update_agent.py +14 -9
  4. beamlit/api/functions/create_function.py +14 -9
  5. beamlit/api/functions/update_function.py +14 -9
  6. beamlit/api/{authentication_providers/list_organizations_for_authentication_provider.py → integrations/create_integration_connection.py} +45 -41
  7. beamlit/api/integrations/delete_integration_connection.py +158 -0
  8. beamlit/api/integrations/get_integration.py +97 -0
  9. beamlit/api/integrations/get_integration_connection.py +154 -0
  10. beamlit/api/integrations/get_integration_connection_model.py +97 -0
  11. beamlit/api/integrations/get_integration_model.py +97 -0
  12. beamlit/api/integrations/list_integration_connection_models.py +97 -0
  13. beamlit/api/{authentication_providers/list_models_for_authentication_provider.py → integrations/list_integration_connections.py} +24 -48
  14. beamlit/api/integrations/list_integration_models.py +97 -0
  15. beamlit/api/integrations/update_integration_connection.py +180 -0
  16. beamlit/authentication/__init__.py +2 -1
  17. beamlit/authentication/authentication.py +3 -0
  18. beamlit/authentication/clientcredentials.py +99 -0
  19. beamlit/authentication/credentials.py +7 -1
  20. beamlit/authentication/device_mode.py +0 -2
  21. beamlit/common/generate.py +166 -0
  22. beamlit/common/logger.py +30 -0
  23. beamlit/common/settings.py +112 -0
  24. beamlit/common/utils.py +13 -0
  25. beamlit/models/__init__.py +50 -24
  26. beamlit/models/agent_deployment.py +117 -49
  27. beamlit/models/{agent_deployment_configuration.py → agent_deployment_configuration_type_0.py} +5 -5
  28. beamlit/models/agent_deployment_history.py +46 -13
  29. beamlit/models/agent_deployment_history_event.py +78 -22
  30. beamlit/models/{function_deployment_pod_template.py → agent_deployment_pod_template_type_0.py} +5 -5
  31. beamlit/models/agent_with_deployments.py +174 -0
  32. beamlit/models/deployment_configurations.py +19 -6
  33. beamlit/models/deployment_serverless_config_type_0.py +218 -0
  34. beamlit/models/environment_metrics.py +19 -0
  35. beamlit/models/function_deployment.py +110 -42
  36. beamlit/models/{function_deployment_configuration.py → function_deployment_configuration_type_0.py} +5 -5
  37. beamlit/models/{agent_deployment_pod_template.py → function_deployment_pod_template_type_0.py} +5 -5
  38. beamlit/models/function_with_deployments.py +174 -0
  39. beamlit/models/increase_and_rate_metric.py +102 -0
  40. beamlit/models/integration.py +196 -0
  41. beamlit/models/integration_config.py +43 -0
  42. beamlit/models/integration_connection.py +196 -0
  43. beamlit/models/integration_connection_config.py +43 -0
  44. beamlit/models/integration_connection_secret.py +59 -0
  45. beamlit/models/integration_model.py +142 -0
  46. beamlit/models/integration_secret.py +59 -0
  47. beamlit/models/metrics.py +61 -20
  48. beamlit/models/model_deployment.py +96 -64
  49. beamlit/models/{model_deployment_pod_template.py → model_deployment_pod_template_type_0.py} +5 -5
  50. beamlit/models/policy.py +8 -34
  51. beamlit/models/provider_config.py +0 -9
  52. beamlit/models/resource_deployment_metrics.py +231 -36
  53. beamlit/models/resource_deployment_metrics_inference_per_region_type_0.py +75 -0
  54. beamlit/models/{resource_deployment_metrics_inference_per_second_per_region.py → resource_deployment_metrics_inference_per_second_per_region_type_0.py} +5 -5
  55. beamlit/models/resource_deployment_metrics_query_per_region_per_code_type_0.py +73 -0
  56. beamlit/models/{resource_deployment_metrics_query_per_second_per_region_per_code.py → resource_deployment_metrics_query_per_second_per_region_per_code_type_0.py} +5 -5
  57. beamlit/models/resource_metrics.py +36 -0
  58. beamlit/models/runtime.py +29 -12
  59. beamlit/models/{runtime_readiness_probe.py → runtime_readiness_probe_type_0.py} +5 -5
  60. beamlit/models/store_agent.py +29 -13
  61. beamlit/models/{store_agent_labels.py → store_agent_labels_type_0.py} +5 -5
  62. beamlit/models/store_configuration.py +15 -4
  63. beamlit/models/store_configuration_option.py +18 -5
  64. beamlit/models/store_function.py +29 -13
  65. beamlit/models/{store_function_labels.py → store_function_labels_type_0.py} +5 -5
  66. beamlit/run.py +49 -0
  67. {beamlit-0.0.18.dist-info → beamlit-0.0.20rc1.dist-info}/METADATA +5 -2
  68. {beamlit-0.0.18.dist-info → beamlit-0.0.20rc1.dist-info}/RECORD +70 -46
  69. beamlit/api/authentication_providers/get_model_with_repo_for_authentication_provider.py +0 -184
  70. beamlit/models/deployment_serverless_config.py +0 -129
  71. beamlit/models/labels.py +0 -43
  72. /beamlit/api/{authentication_providers → integrations}/__init__.py +0 -0
  73. {beamlit-0.0.18.dist-info → beamlit-0.0.20rc1.dist-info}/WHEEL +0 -0
@@ -5,16 +5,14 @@ import httpx
5
5
 
6
6
  from ... import errors
7
7
  from ...client import AuthenticatedClient, Client
8
- from ...models.authentication_provider_model import AuthenticationProviderModel
8
+ from ...models.integration_connection import IntegrationConnection
9
9
  from ...types import Response
10
10
 
11
11
 
12
- def _get_kwargs(
13
- authentication_provider_name: str,
14
- ) -> dict[str, Any]:
12
+ def _get_kwargs() -> dict[str, Any]:
15
13
  _kwargs: dict[str, Any] = {
16
14
  "method": "get",
17
- "url": f"/authentication_providers/{authentication_provider_name}/models",
15
+ "url": "/integrations/connections",
18
16
  }
19
17
 
20
18
  return _kwargs
@@ -22,12 +20,12 @@ def _get_kwargs(
22
20
 
23
21
  def _parse_response(
24
22
  *, client: Union[AuthenticatedClient, Client], response: httpx.Response
25
- ) -> Optional[List["AuthenticationProviderModel"]]:
23
+ ) -> Optional[List["IntegrationConnection"]]:
26
24
  if response.status_code == 200:
27
25
  response_200 = []
28
26
  _response_200 = response.json()
29
27
  for response_200_item_data in _response_200:
30
- response_200_item = AuthenticationProviderModel.from_dict(response_200_item_data)
28
+ response_200_item = IntegrationConnection.from_dict(response_200_item_data)
31
29
 
32
30
  response_200.append(response_200_item)
33
31
 
@@ -40,7 +38,7 @@ def _parse_response(
40
38
 
41
39
  def _build_response(
42
40
  *, client: Union[AuthenticatedClient, Client], response: httpx.Response
43
- ) -> Response[List["AuthenticationProviderModel"]]:
41
+ ) -> Response[List["IntegrationConnection"]]:
44
42
  return Response(
45
43
  status_code=HTTPStatus(response.status_code),
46
44
  content=response.content,
@@ -50,28 +48,22 @@ def _build_response(
50
48
 
51
49
 
52
50
  def sync_detailed(
53
- authentication_provider_name: str,
54
51
  *,
55
52
  client: AuthenticatedClient,
56
- ) -> Response[List["AuthenticationProviderModel"]]:
57
- """List models for a authentication provider
53
+ ) -> Response[List["IntegrationConnection"]]:
54
+ """List integrations connections
58
55
 
59
- Returns a list of all models for an integration by ID.
60
-
61
- Args:
62
- authentication_provider_name (str):
56
+ Returns a list of all connections integrations in the workspace.
63
57
 
64
58
  Raises:
65
59
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
66
60
  httpx.TimeoutException: If the request takes longer than Client.timeout.
67
61
 
68
62
  Returns:
69
- Response[List['AuthenticationProviderModel']]
63
+ Response[List['IntegrationConnection']]
70
64
  """
71
65
 
72
- kwargs = _get_kwargs(
73
- authentication_provider_name=authentication_provider_name,
74
- )
66
+ kwargs = _get_kwargs()
75
67
 
76
68
  response = client.get_httpx_client().request(
77
69
  **kwargs,
@@ -81,54 +73,43 @@ def sync_detailed(
81
73
 
82
74
 
83
75
  def sync(
84
- authentication_provider_name: str,
85
76
  *,
86
77
  client: AuthenticatedClient,
87
- ) -> Optional[List["AuthenticationProviderModel"]]:
88
- """List models for a authentication provider
89
-
90
- Returns a list of all models for an integration by ID.
78
+ ) -> Optional[List["IntegrationConnection"]]:
79
+ """List integrations connections
91
80
 
92
- Args:
93
- authentication_provider_name (str):
81
+ Returns a list of all connections integrations in the workspace.
94
82
 
95
83
  Raises:
96
84
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
97
85
  httpx.TimeoutException: If the request takes longer than Client.timeout.
98
86
 
99
87
  Returns:
100
- List['AuthenticationProviderModel']
88
+ List['IntegrationConnection']
101
89
  """
102
90
 
103
91
  return sync_detailed(
104
- authentication_provider_name=authentication_provider_name,
105
92
  client=client,
106
93
  ).parsed
107
94
 
108
95
 
109
96
  async def asyncio_detailed(
110
- authentication_provider_name: str,
111
97
  *,
112
98
  client: AuthenticatedClient,
113
- ) -> Response[List["AuthenticationProviderModel"]]:
114
- """List models for a authentication provider
99
+ ) -> Response[List["IntegrationConnection"]]:
100
+ """List integrations connections
115
101
 
116
- Returns a list of all models for an integration by ID.
117
-
118
- Args:
119
- authentication_provider_name (str):
102
+ Returns a list of all connections integrations in the workspace.
120
103
 
121
104
  Raises:
122
105
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
123
106
  httpx.TimeoutException: If the request takes longer than Client.timeout.
124
107
 
125
108
  Returns:
126
- Response[List['AuthenticationProviderModel']]
109
+ Response[List['IntegrationConnection']]
127
110
  """
128
111
 
129
- kwargs = _get_kwargs(
130
- authentication_provider_name=authentication_provider_name,
131
- )
112
+ kwargs = _get_kwargs()
132
113
 
133
114
  response = await client.get_async_httpx_client().request(**kwargs)
134
115
 
@@ -136,28 +117,23 @@ async def asyncio_detailed(
136
117
 
137
118
 
138
119
  async def asyncio(
139
- authentication_provider_name: str,
140
120
  *,
141
121
  client: AuthenticatedClient,
142
- ) -> Optional[List["AuthenticationProviderModel"]]:
143
- """List models for a authentication provider
144
-
145
- Returns a list of all models for an integration by ID.
122
+ ) -> Optional[List["IntegrationConnection"]]:
123
+ """List integrations connections
146
124
 
147
- Args:
148
- authentication_provider_name (str):
125
+ Returns a list of all connections integrations in the workspace.
149
126
 
150
127
  Raises:
151
128
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
152
129
  httpx.TimeoutException: If the request takes longer than Client.timeout.
153
130
 
154
131
  Returns:
155
- List['AuthenticationProviderModel']
132
+ List['IntegrationConnection']
156
133
  """
157
134
 
158
135
  return (
159
136
  await asyncio_detailed(
160
- authentication_provider_name=authentication_provider_name,
161
137
  client=client,
162
138
  )
163
139
  ).parsed
@@ -0,0 +1,97 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, Optional, Union
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...types import Response
9
+
10
+
11
+ def _get_kwargs(
12
+ integration_name: str,
13
+ ) -> dict[str, Any]:
14
+ _kwargs: dict[str, Any] = {
15
+ "method": "get",
16
+ "url": f"/integrations/{integration_name}/models",
17
+ }
18
+
19
+ return _kwargs
20
+
21
+
22
+ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
23
+ if response.status_code == 200:
24
+ return None
25
+ if client.raise_on_unexpected_status:
26
+ raise errors.UnexpectedStatus(response.status_code, response.content)
27
+ else:
28
+ return None
29
+
30
+
31
+ def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]:
32
+ return Response(
33
+ status_code=HTTPStatus(response.status_code),
34
+ content=response.content,
35
+ headers=response.headers,
36
+ parsed=_parse_response(client=client, response=response),
37
+ )
38
+
39
+
40
+ def sync_detailed(
41
+ integration_name: str,
42
+ *,
43
+ client: AuthenticatedClient,
44
+ ) -> Response[Any]:
45
+ """List integration models
46
+
47
+ Returns a list of all models for an integration.
48
+
49
+ Args:
50
+ integration_name (str):
51
+
52
+ Raises:
53
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
54
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
55
+
56
+ Returns:
57
+ Response[Any]
58
+ """
59
+
60
+ kwargs = _get_kwargs(
61
+ integration_name=integration_name,
62
+ )
63
+
64
+ response = client.get_httpx_client().request(
65
+ **kwargs,
66
+ )
67
+
68
+ return _build_response(client=client, response=response)
69
+
70
+
71
+ async def asyncio_detailed(
72
+ integration_name: str,
73
+ *,
74
+ client: AuthenticatedClient,
75
+ ) -> Response[Any]:
76
+ """List integration models
77
+
78
+ Returns a list of all models for an integration.
79
+
80
+ Args:
81
+ integration_name (str):
82
+
83
+ Raises:
84
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
85
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
86
+
87
+ Returns:
88
+ Response[Any]
89
+ """
90
+
91
+ kwargs = _get_kwargs(
92
+ integration_name=integration_name,
93
+ )
94
+
95
+ response = await client.get_async_httpx_client().request(**kwargs)
96
+
97
+ return _build_response(client=client, response=response)
@@ -0,0 +1,180 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, Optional, Union
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...models.integration_connection import IntegrationConnection
9
+ from ...types import Response
10
+
11
+
12
+ def _get_kwargs(
13
+ connection_name: str,
14
+ *,
15
+ body: IntegrationConnection,
16
+ ) -> dict[str, Any]:
17
+ headers: dict[str, Any] = {}
18
+
19
+ _kwargs: dict[str, Any] = {
20
+ "method": "put",
21
+ "url": f"/integrations/connections/{connection_name}",
22
+ }
23
+
24
+ _body = body.to_dict()
25
+
26
+ _kwargs["json"] = _body
27
+ headers["Content-Type"] = "application/json"
28
+
29
+ _kwargs["headers"] = headers
30
+ return _kwargs
31
+
32
+
33
+ def _parse_response(
34
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
35
+ ) -> Optional[IntegrationConnection]:
36
+ if response.status_code == 200:
37
+ response_200 = IntegrationConnection.from_dict(response.json())
38
+
39
+ return response_200
40
+ if client.raise_on_unexpected_status:
41
+ raise errors.UnexpectedStatus(response.status_code, response.content)
42
+ else:
43
+ return None
44
+
45
+
46
+ def _build_response(
47
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
48
+ ) -> Response[IntegrationConnection]:
49
+ return Response(
50
+ status_code=HTTPStatus(response.status_code),
51
+ content=response.content,
52
+ headers=response.headers,
53
+ parsed=_parse_response(client=client, response=response),
54
+ )
55
+
56
+
57
+ def sync_detailed(
58
+ connection_name: str,
59
+ *,
60
+ client: Union[AuthenticatedClient, Client],
61
+ body: IntegrationConnection,
62
+ ) -> Response[IntegrationConnection]:
63
+ """Update integration connection
64
+
65
+ Update an integration connection by integration name and connection name.
66
+
67
+ Args:
68
+ connection_name (str):
69
+ body (IntegrationConnection): Integration Connection
70
+
71
+ Raises:
72
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
73
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
74
+
75
+ Returns:
76
+ Response[IntegrationConnection]
77
+ """
78
+
79
+ kwargs = _get_kwargs(
80
+ connection_name=connection_name,
81
+ body=body,
82
+ )
83
+
84
+ response = client.get_httpx_client().request(
85
+ **kwargs,
86
+ )
87
+
88
+ return _build_response(client=client, response=response)
89
+
90
+
91
+ def sync(
92
+ connection_name: str,
93
+ *,
94
+ client: Union[AuthenticatedClient, Client],
95
+ body: IntegrationConnection,
96
+ ) -> Optional[IntegrationConnection]:
97
+ """Update integration connection
98
+
99
+ Update an integration connection by integration name and connection name.
100
+
101
+ Args:
102
+ connection_name (str):
103
+ body (IntegrationConnection): Integration Connection
104
+
105
+ Raises:
106
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
107
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
108
+
109
+ Returns:
110
+ IntegrationConnection
111
+ """
112
+
113
+ return sync_detailed(
114
+ connection_name=connection_name,
115
+ client=client,
116
+ body=body,
117
+ ).parsed
118
+
119
+
120
+ async def asyncio_detailed(
121
+ connection_name: str,
122
+ *,
123
+ client: Union[AuthenticatedClient, Client],
124
+ body: IntegrationConnection,
125
+ ) -> Response[IntegrationConnection]:
126
+ """Update integration connection
127
+
128
+ Update an integration connection by integration name and connection name.
129
+
130
+ Args:
131
+ connection_name (str):
132
+ body (IntegrationConnection): Integration Connection
133
+
134
+ Raises:
135
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
136
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
137
+
138
+ Returns:
139
+ Response[IntegrationConnection]
140
+ """
141
+
142
+ kwargs = _get_kwargs(
143
+ connection_name=connection_name,
144
+ body=body,
145
+ )
146
+
147
+ response = await client.get_async_httpx_client().request(**kwargs)
148
+
149
+ return _build_response(client=client, response=response)
150
+
151
+
152
+ async def asyncio(
153
+ connection_name: str,
154
+ *,
155
+ client: Union[AuthenticatedClient, Client],
156
+ body: IntegrationConnection,
157
+ ) -> Optional[IntegrationConnection]:
158
+ """Update integration connection
159
+
160
+ Update an integration connection by integration name and connection name.
161
+
162
+ Args:
163
+ connection_name (str):
164
+ body (IntegrationConnection): Integration Connection
165
+
166
+ Raises:
167
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
168
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
169
+
170
+ Returns:
171
+ IntegrationConnection
172
+ """
173
+
174
+ return (
175
+ await asyncio_detailed(
176
+ connection_name=connection_name,
177
+ client=client,
178
+ body=body,
179
+ )
180
+ ).parsed
@@ -2,7 +2,7 @@ from .apikey import ApiKeyProvider
2
2
  from .authentication import (PublicProvider, RunClientWithCredentials,
3
3
  new_client_with_credentials)
4
4
  from .credentials import (Config, ContextConfig, Credentials, WorkspaceConfig,
5
- load_credentials)
5
+ load_credentials, load_credentials_from_config)
6
6
  from .device_mode import (BearerToken, DeviceLogin, DeviceLoginFinalizeRequest,
7
7
  DeviceLoginFinalizeResponse, DeviceLoginResponse)
8
8
 
@@ -16,6 +16,7 @@ __all__ = (
16
16
  "Credentials",
17
17
  "WorkspaceConfig",
18
18
  "load_credentials",
19
+ "load_credentials_from_config",
19
20
  "BearerToken",
20
21
  "DeviceLogin",
21
22
  "DeviceLoginFinalizeRequest",
@@ -5,6 +5,7 @@ from httpx import Auth, Request, Response
5
5
 
6
6
  from ..client import AuthenticatedClient
7
7
  from .apikey import ApiKeyProvider
8
+ from .clientcredentials import ClientCredentials
8
9
  from .credentials import Credentials
9
10
  from .device_mode import BearerToken
10
11
 
@@ -29,6 +30,8 @@ def new_client_with_credentials(config: RunClientWithCredentials):
29
30
  provider = ApiKeyProvider(config.credentials, config.workspace)
30
31
  elif config.credentials.access_token:
31
32
  provider = BearerToken(config.credentials, config.workspace, config.api_url)
33
+ elif config.credentials.client_credentials:
34
+ provider = ClientCredentials(config.credentials, config.workspace, config.api_url)
32
35
  else:
33
36
  provider = PublicProvider()
34
37
 
@@ -0,0 +1,99 @@
1
+ import base64
2
+ import json
3
+ import time
4
+ from dataclasses import dataclass
5
+ from typing import Generator, Optional
6
+
7
+ import requests
8
+ from beamlit.common.settings import get_settings
9
+ from httpx import Auth, Request, Response, post
10
+
11
+
12
+ @dataclass
13
+ class DeviceLoginFinalizeResponse:
14
+ access_token: str
15
+ expires_in: int
16
+ refresh_token: str
17
+ token_type: str
18
+
19
+
20
+ class ClientCredentials(Auth):
21
+ def __init__(self, credentials, workspace_name: str, base_url: str):
22
+ self.credentials = credentials
23
+ self.workspace_name = workspace_name
24
+ self.base_url = base_url
25
+
26
+ def refresh_if_needed(self) -> Optional[Exception]:
27
+ # Need to refresh token if expires in less than 10 minutes
28
+ parts = self.credentials.access_token.split('.')
29
+ if len(parts) != 3:
30
+ return Exception("Invalid JWT token format")
31
+ try:
32
+ claims_bytes = base64.urlsafe_b64decode(parts[1] + '=' * (-len(parts[1]) % 4))
33
+ claims = json.loads(claims_bytes)
34
+ except Exception as e:
35
+ return Exception(f"Failed to decode/parse JWT claims: {str(e)}")
36
+
37
+ exp_time = time.gmtime(claims['exp'])
38
+ # Refresh if token expires in less than 10 minutes
39
+ if time.time() + (10 * 60) > time.mktime(exp_time):
40
+ return self.do_refresh()
41
+
42
+ return None
43
+
44
+ def auth_flow(self, request: Request) -> Generator[Request, Response, None]:
45
+ settings = get_settings()
46
+ if self.credentials.client_credentials and not self.credentials.refresh_token:
47
+ headers = { "Authorization": f"Basic {self.credentials.client_credentials}" }
48
+ body = { "grant_type": "client_credentials" }
49
+ response = requests.post(f"{settings.base_url}/oauth/token", headers=headers, json=body)
50
+ response.raise_for_status()
51
+ self.credentials.access_token = response.json()['access_token']
52
+ self.credentials.refresh_token = response.json()['refresh_token']
53
+ self.credentials.expires_in = response.json()['expires_in']
54
+ err = self.refresh_if_needed()
55
+ if err:
56
+ return err
57
+
58
+ request.headers['X-Beamlit-Authorization'] = f'Bearer {self.credentials.access_token}'
59
+ request.headers['X-Beamlit-Workspace'] = self.workspace_name
60
+ yield request
61
+
62
+ def do_refresh(self) -> Optional[Exception]:
63
+ if not self.credentials.refresh_token:
64
+ return Exception("No refresh token to refresh")
65
+
66
+ url = f"{self.base_url}/oauth/token"
67
+ refresh_data = {
68
+ "grant_type": "refresh_token",
69
+ "refresh_token": self.credentials.refresh_token,
70
+ "device_code": self.credentials.device_code,
71
+ "client_id": "beamlit"
72
+ }
73
+
74
+ try:
75
+ response = post(
76
+ url,
77
+ json=refresh_data,
78
+ headers={"Content-Type": "application/json"}
79
+ )
80
+ response.raise_for_status()
81
+ finalize_response = DeviceLoginFinalizeResponse(**response.json())
82
+
83
+ if not finalize_response.refresh_token:
84
+ finalize_response.refresh_token = self.credentials.refresh_token
85
+
86
+ from .credentials import Credentials, save_credentials
87
+ creds = Credentials(
88
+ access_token=finalize_response.access_token,
89
+ refresh_token=finalize_response.refresh_token,
90
+ expires_in=finalize_response.expires_in,
91
+ device_code=self.credentials.device_code
92
+ )
93
+
94
+ self.credentials = creds
95
+ save_credentials(self.workspace_name, creds)
96
+ return None
97
+
98
+ except Exception as e:
99
+ return Exception(f"Failed to refresh token: {str(e)}")
@@ -3,6 +3,7 @@ from pathlib import Path
3
3
  from typing import List
4
4
 
5
5
  import yaml
6
+ from beamlit.common.settings import Settings
6
7
 
7
8
 
8
9
  @dataclass
@@ -12,7 +13,7 @@ class Credentials:
12
13
  refresh_token: str = ""
13
14
  expires_in: int = 0
14
15
  device_code: str = ""
15
-
16
+ client_credentials: str = ""
16
17
  @dataclass
17
18
  class WorkspaceConfig:
18
19
  name: str
@@ -115,6 +116,11 @@ def load_credentials(workspace_name: str) -> Credentials:
115
116
  return workspace.credentials
116
117
  return Credentials()
117
118
 
119
+ def load_credentials_from_config(config: Settings) -> Credentials:
120
+ return Credentials(
121
+ api_key=config.api_key,
122
+ client_credentials=config.client_credentials
123
+ )
118
124
 
119
125
  def create_home_dir_if_missing():
120
126
  home_dir = Path.home()
@@ -86,13 +86,11 @@ class BearerToken(Auth):
86
86
  }
87
87
 
88
88
  try:
89
- print(refresh_data)
90
89
  response = post(
91
90
  url,
92
91
  json=refresh_data,
93
92
  headers={"Content-Type": "application/json"}
94
93
  )
95
- print(response.text)
96
94
  response.raise_for_status()
97
95
  finalize_response = DeviceLoginFinalizeResponse(**response.json())
98
96