beamlit 0.0.33rc49__py3-none-any.whl → 0.0.34__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.
- beamlit/agents/__init__.py +2 -1
- beamlit/agents/chat.py +16 -4
- beamlit/agents/decorator.py +68 -155
- beamlit/agents/thread.py +14 -0
- beamlit/api/workspaces/workspace_quotas_request.py +97 -0
- beamlit/authentication/clientcredentials.py +5 -3
- beamlit/authentication/device_mode.py +4 -4
- beamlit/common/__init__.py +1 -2
- beamlit/common/instrumentation.py +202 -34
- beamlit/common/settings.py +7 -64
- beamlit/deploy/deploy.py +64 -60
- beamlit/deploy/format.py +10 -0
- beamlit/functions/__init__.py +2 -2
- beamlit/functions/decorator.py +149 -1
- beamlit/functions/github/github.py +0 -1
- beamlit/models/__init__.py +51 -11
- beamlit/models/agent.py +27 -15
- beamlit/models/agent_metadata.py +1 -1
- beamlit/models/agent_render.py +45 -0
- beamlit/models/agent_spec.py +32 -5
- beamlit/models/core_event.py +88 -0
- beamlit/models/core_spec.py +14 -5
- beamlit/models/core_spec_configurations.py +1 -1
- beamlit/models/core_status.py +3 -20
- beamlit/models/environment.py +2 -2
- beamlit/models/environment_metadata.py +1 -1
- beamlit/models/function.py +27 -15
- beamlit/models/function_metadata.py +1 -1
- beamlit/models/function_render.py +45 -0
- beamlit/models/function_spec.py +14 -5
- beamlit/models/histogram_bucket.py +79 -0
- beamlit/models/histogram_stats.py +88 -0
- beamlit/models/increase_and_rate_metric.py +0 -9
- beamlit/models/integration_connection.py +2 -2
- beamlit/models/integration_connection_spec.py +11 -2
- beamlit/models/integration_repository.py +88 -0
- beamlit/models/last_n_requests_metric.py +88 -0
- beamlit/models/latency_metric.py +124 -0
- beamlit/models/metadata.py +1 -1
- beamlit/models/metric.py +18 -9
- beamlit/models/metrics.py +81 -46
- beamlit/models/metrics_models.py +45 -0
- beamlit/models/metrics_request_total_per_code.py +45 -0
- beamlit/models/metrics_rps_per_code.py +45 -0
- beamlit/models/model.py +27 -15
- beamlit/models/model_metadata.py +1 -1
- beamlit/models/model_provider.py +2 -2
- beamlit/models/model_render.py +45 -0
- beamlit/models/model_spec.py +14 -14
- beamlit/models/pending_invitation_accept.py +1 -1
- beamlit/models/pending_invitation_render.py +3 -3
- beamlit/models/policy.py +2 -2
- beamlit/models/provider_config.py +1 -1
- beamlit/models/repository.py +70 -0
- beamlit/models/repository_type_0.py +70 -0
- beamlit/models/request_duration_over_time_metric.py +97 -0
- beamlit/models/request_duration_over_time_metrics.py +74 -0
- beamlit/models/request_total_by_origin_metric.py +103 -0
- beamlit/models/request_total_by_origin_metric_request_total_by_origin.py +45 -0
- beamlit/models/request_total_by_origin_metric_request_total_by_origin_and_code.py +45 -0
- beamlit/models/request_total_metric.py +115 -0
- beamlit/models/request_total_metric_request_total_per_code.py +45 -0
- beamlit/models/request_total_metric_rps_per_code.py +45 -0
- beamlit/models/resource_deployment_metrics.py +6 -4
- beamlit/models/resource_deployment_metrics_query_per_second_per_region_per_code.py +1 -1
- beamlit/models/resource_environment_metrics.py +155 -75
- beamlit/models/resource_environment_metrics_request_total_per_code.py +45 -0
- beamlit/models/resource_environment_metrics_rps_per_code.py +45 -0
- beamlit/models/resource_metrics.py +1 -1
- beamlit/models/runtime.py +2 -2
- beamlit/models/store_agent.py +1 -1
- beamlit/models/store_function.py +1 -1
- beamlit/models/token_rate_metric.py +88 -0
- beamlit/models/token_rate_metrics.py +106 -0
- beamlit/models/token_total_metric.py +106 -0
- beamlit/models/workspace.py +17 -8
- beamlit/serve/app.py +9 -13
- {beamlit-0.0.33rc49.dist-info → beamlit-0.0.34.dist-info}/METADATA +21 -3
- {beamlit-0.0.33rc49.dist-info → beamlit-0.0.34.dist-info}/RECORD +80 -52
- beamlit/common/generate.py +0 -196
- {beamlit-0.0.33rc49.dist-info → beamlit-0.0.34.dist-info}/WHEEL +0 -0
beamlit/agents/__init__.py
CHANGED
beamlit/agents/chat.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
from logging import getLogger
|
2
|
+
from typing import Tuple, Union
|
2
3
|
|
4
|
+
from langchain_core.language_models import BaseChatModel
|
5
|
+
|
6
|
+
from beamlit.api.models import get_model
|
3
7
|
from beamlit.authentication import get_authentication_headers, new_client
|
4
8
|
from beamlit.common.settings import get_settings
|
5
9
|
from beamlit.models import Model
|
@@ -39,11 +43,17 @@ def get_cohere_chat_model(**kwargs):
|
|
39
43
|
|
40
44
|
return ChatCohere(**kwargs)
|
41
45
|
|
42
|
-
def get_chat_model(name: str, agent_model: Model):
|
46
|
+
def get_chat_model(name: str, agent_model: Union[Model, None] = None) -> Tuple[BaseChatModel, str, str]:
|
43
47
|
settings = get_settings()
|
44
48
|
client = new_client()
|
45
49
|
|
46
|
-
|
50
|
+
if agent_model is None:
|
51
|
+
try:
|
52
|
+
agent_model = get_model.sync(name, client=client, environment=settings.environment)
|
53
|
+
except Exception:
|
54
|
+
logger.warning(f"Model {name} not found, defaulting to gpt-4o-mini")
|
55
|
+
|
56
|
+
environment = (agent_model and agent_model.metadata and agent_model.metadata.environment) or settings.environment
|
47
57
|
headers = get_authentication_headers(settings)
|
48
58
|
headers["X-Beamlit-Environment"] = environment
|
49
59
|
|
@@ -84,7 +94,8 @@ def get_chat_model(name: str, agent_model: Model):
|
|
84
94
|
}
|
85
95
|
|
86
96
|
provider = (
|
87
|
-
agent_model
|
97
|
+
agent_model
|
98
|
+
and agent_model.spec
|
88
99
|
and agent_model.spec.runtime
|
89
100
|
and agent_model.spec.runtime.type_
|
90
101
|
)
|
@@ -93,7 +104,8 @@ def get_chat_model(name: str, agent_model: Model):
|
|
93
104
|
provider = "openai"
|
94
105
|
|
95
106
|
model = (
|
96
|
-
agent_model
|
107
|
+
agent_model
|
108
|
+
and agent_model.spec
|
97
109
|
and agent_model.spec.runtime
|
98
110
|
and agent_model.spec.runtime.model
|
99
111
|
)
|
beamlit/agents/decorator.py
CHANGED
@@ -1,122 +1,24 @@
|
|
1
1
|
# Import necessary modules
|
2
|
-
import ast
|
3
|
-
import asyncio
|
4
2
|
import functools
|
5
|
-
import
|
6
|
-
import os
|
3
|
+
import inspect
|
7
4
|
from logging import getLogger
|
8
5
|
|
9
|
-
from langchain_core.tools import Tool
|
10
6
|
from langgraph.checkpoint.memory import MemorySaver
|
11
7
|
from langgraph.prebuilt import create_react_agent
|
12
8
|
|
13
|
-
from beamlit.api.models import get_model
|
9
|
+
from beamlit.api.models import get_model, list_models
|
14
10
|
from beamlit.authentication import new_client
|
15
|
-
from beamlit.common import
|
16
|
-
from beamlit.common.settings import get_settings, init
|
11
|
+
from beamlit.common.settings import init
|
17
12
|
from beamlit.errors import UnexpectedStatus
|
18
|
-
from beamlit.functions
|
19
|
-
from beamlit.functions.remote.remote import RemoteToolkit
|
13
|
+
from beamlit.functions import get_functions
|
20
14
|
from beamlit.models import Agent, AgentMetadata, AgentSpec
|
21
15
|
|
22
|
-
from .chain import ChainToolkit
|
23
16
|
from .chat import get_chat_model
|
24
17
|
|
25
18
|
|
26
|
-
def get_functions(client, dir="src/functions", from_decorator="function", remote_functions_empty=True):
|
27
|
-
functions = []
|
28
|
-
logger = getLogger(__name__)
|
29
|
-
settings = get_settings()
|
30
|
-
|
31
|
-
# Walk through all Python files in functions directory and subdirectories
|
32
|
-
if not os.path.exists(dir):
|
33
|
-
if remote_functions_empty:
|
34
|
-
logger.warn(f"Functions directory {dir} not found")
|
35
|
-
return []
|
36
|
-
for root, _, files in os.walk(dir):
|
37
|
-
for file in files:
|
38
|
-
if file.endswith(".py"):
|
39
|
-
file_path = os.path.join(root, file)
|
40
|
-
# Read and compile the file content
|
41
|
-
with open(file_path) as f:
|
42
|
-
try:
|
43
|
-
file_content = f.read()
|
44
|
-
# Parse the file content to find decorated functions
|
45
|
-
tree = ast.parse(file_content)
|
46
|
-
|
47
|
-
# Look for function definitions with decorators
|
48
|
-
for node in ast.walk(tree):
|
49
|
-
if (
|
50
|
-
not isinstance(node, ast.FunctionDef)
|
51
|
-
and not isinstance(node, ast.AsyncFunctionDef)
|
52
|
-
) or len(node.decorator_list) == 0:
|
53
|
-
continue
|
54
|
-
decorator = node.decorator_list[0]
|
55
|
-
|
56
|
-
decorator_name = ""
|
57
|
-
if isinstance(decorator, ast.Call):
|
58
|
-
decorator_name = decorator.func.id
|
59
|
-
if isinstance(decorator, ast.Name):
|
60
|
-
decorator_name = decorator.id
|
61
|
-
|
62
|
-
if decorator_name == from_decorator:
|
63
|
-
# Get the function name and decorator name
|
64
|
-
func_name = node.name
|
65
|
-
|
66
|
-
# Import the module to get the actual function
|
67
|
-
spec = importlib.util.spec_from_file_location(func_name, file_path)
|
68
|
-
module = importlib.util.module_from_spec(spec)
|
69
|
-
spec.loader.exec_module(module)
|
70
|
-
# Check if kit=True in the decorator arguments
|
71
|
-
is_kit = False
|
72
|
-
if isinstance(decorator, ast.Call):
|
73
|
-
for keyword in decorator.keywords:
|
74
|
-
if keyword.arg == "kit" and isinstance(
|
75
|
-
keyword.value, ast.Constant
|
76
|
-
):
|
77
|
-
is_kit = keyword.value.value
|
78
|
-
if is_kit and not settings.remote:
|
79
|
-
kit_functions = get_functions(
|
80
|
-
client,
|
81
|
-
dir=os.path.join(root),
|
82
|
-
from_decorator="kit",
|
83
|
-
remote_functions_empty=remote_functions_empty,
|
84
|
-
)
|
85
|
-
functions.extend(kit_functions)
|
86
|
-
|
87
|
-
# Get the decorated function
|
88
|
-
if not is_kit and hasattr(module, func_name):
|
89
|
-
func = getattr(module, func_name)
|
90
|
-
if settings.remote:
|
91
|
-
toolkit = RemoteToolkit(client, slugify(func.__name__))
|
92
|
-
toolkit.initialize()
|
93
|
-
functions.extend(toolkit.get_tools())
|
94
|
-
else:
|
95
|
-
if asyncio.iscoroutinefunction(func):
|
96
|
-
functions.append(
|
97
|
-
Tool(
|
98
|
-
name=func.__name__,
|
99
|
-
description=func.__doc__,
|
100
|
-
func=func,
|
101
|
-
coroutine=func,
|
102
|
-
)
|
103
|
-
)
|
104
|
-
else:
|
105
|
-
functions.append(
|
106
|
-
Tool(
|
107
|
-
name=func.__name__,
|
108
|
-
description=func.__doc__,
|
109
|
-
func=func,
|
110
|
-
)
|
111
|
-
)
|
112
|
-
except Exception as e:
|
113
|
-
logger.warning(f"Error processing {file_path}: {e!s}")
|
114
|
-
return functions
|
115
|
-
|
116
|
-
|
117
19
|
def agent(
|
118
20
|
agent: Agent | dict = None,
|
119
|
-
|
21
|
+
override_model=None,
|
120
22
|
override_agent=None,
|
121
23
|
mcp_hub=None,
|
122
24
|
remote_functions=None,
|
@@ -129,31 +31,34 @@ def agent(
|
|
129
31
|
)
|
130
32
|
|
131
33
|
client = new_client()
|
132
|
-
chat_model =
|
34
|
+
chat_model = override_model or None
|
133
35
|
settings = init()
|
134
36
|
|
135
37
|
def wrapper(func):
|
38
|
+
agent_kwargs = any(
|
39
|
+
param.name == "agent"
|
40
|
+
for param in inspect.signature(func).parameters.values()
|
41
|
+
)
|
42
|
+
model_kwargs = any(
|
43
|
+
param.name == "model"
|
44
|
+
for param in inspect.signature(func).parameters.values()
|
45
|
+
)
|
46
|
+
functions_kwargs = any(
|
47
|
+
param.name == "functions"
|
48
|
+
for param in inspect.signature(func).parameters.values()
|
49
|
+
)
|
136
50
|
@functools.wraps(func)
|
137
51
|
def wrapped(*args, **kwargs):
|
138
|
-
|
139
|
-
settings.agent.agent
|
140
|
-
|
141
|
-
settings.agent.
|
142
|
-
|
143
|
-
|
144
|
-
)
|
52
|
+
if agent_kwargs:
|
53
|
+
kwargs["agent"] = settings.agent.agent
|
54
|
+
if model_kwargs:
|
55
|
+
kwargs["model"] = settings.agent.chat_model
|
56
|
+
if functions_kwargs:
|
57
|
+
kwargs["functions"] = settings.agent.functions
|
58
|
+
return func(*args, **kwargs)
|
145
59
|
|
146
60
|
return wrapped
|
147
61
|
|
148
|
-
# Initialize functions array to store decorated functions
|
149
|
-
functions = get_functions(
|
150
|
-
client,
|
151
|
-
dir=settings.agent.functions_directory,
|
152
|
-
remote_functions_empty=not remote_functions,
|
153
|
-
)
|
154
|
-
|
155
|
-
settings.agent.functions = functions
|
156
|
-
|
157
62
|
if agent is not None:
|
158
63
|
metadata = AgentMetadata(**agent.get("metadata", {}))
|
159
64
|
spec = AgentSpec(**agent.get("spec", {}))
|
@@ -184,44 +89,52 @@ def agent(
|
|
184
89
|
settings.agent.chat_model = chat_model
|
185
90
|
logger.info(f"Chat model configured, using: {provider}:{model}")
|
186
91
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
92
|
+
functions = get_functions(
|
93
|
+
client=client,
|
94
|
+
dir=settings.agent.functions_directory,
|
95
|
+
mcp_hub=mcp_hub,
|
96
|
+
remote_functions=remote_functions,
|
97
|
+
chain=agent.spec.agent_chain,
|
98
|
+
remote_functions_empty=not remote_functions,
|
99
|
+
warning=chat_model is not None,
|
100
|
+
)
|
101
|
+
settings.agent.functions = functions
|
196
102
|
|
197
|
-
if
|
198
|
-
|
103
|
+
if override_agent is None:
|
104
|
+
if chat_model is None:
|
105
|
+
models_select = ""
|
199
106
|
try:
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
if override_agent is None and chat_model is not None:
|
107
|
+
models = list_models.sync_detailed(
|
108
|
+
environment=settings.environment, client=client
|
109
|
+
)
|
110
|
+
models = ", ".join([model.metadata.name for model in models.parsed])
|
111
|
+
models_select = f"You can select one from the your models: {models}"
|
112
|
+
except Exception:
|
113
|
+
pass
|
114
|
+
|
115
|
+
raise ValueError(f"You must provide a model.\n"
|
116
|
+
f"{models_select}\n"
|
117
|
+
f"You can create one at {settings.app_url}/{settings.workspace}/global-inference-network/models/create\n"
|
118
|
+
"Add it to your agent spec\n"
|
119
|
+
"agent={\n"
|
120
|
+
" \"metadata\": {\n"
|
121
|
+
f" \"name\": \"{agent.metadata.name}\",\n"
|
122
|
+
" },\n"
|
123
|
+
" \"spec\": {\n"
|
124
|
+
" \"model\": \"MODEL_NAME\",\n"
|
125
|
+
f" \"description\": \"{agent.spec.description}\",\n"
|
126
|
+
" },\n"
|
127
|
+
"}")
|
222
128
|
memory = MemorySaver()
|
223
|
-
|
224
|
-
|
129
|
+
if len(functions) == 0:
|
130
|
+
raise ValueError("You can define this function in directory "
|
131
|
+
f'"{settings.agent.functions_directory}". Here is a sample function you can use:\n\n'
|
132
|
+
"from beamlit.functions import function\n\n"
|
133
|
+
"@function()\n"
|
134
|
+
"def hello_world(query: str):\n"
|
135
|
+
" return 'Hello, world!'\n")
|
136
|
+
_agent = create_react_agent(chat_model, functions, checkpointer=memory)
|
137
|
+
settings.agent.agent = _agent
|
225
138
|
else:
|
226
139
|
settings.agent.agent = override_agent
|
227
140
|
return wrapper
|
beamlit/agents/thread.py
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
import jwt
|
3
|
+
from fastapi import Request
|
4
|
+
|
5
|
+
|
6
|
+
def get_default_thread(request: Request) -> str:
|
7
|
+
if request.headers.get("X-Beamlit-Sub"):
|
8
|
+
return request.headers.get("X-Beamlit-Sub")
|
9
|
+
authorization = request.headers.get("Authorization", request.headers.get("X-Beamlit-Authorization"))
|
10
|
+
if authorization and len(authorization.split("Bearer ")) > 1:
|
11
|
+
token = authorization.split(" ")[1]
|
12
|
+
decoded = jwt.decode(token, options={"verify_signature": False})
|
13
|
+
return decoded["sub"]
|
14
|
+
return ""
|
@@ -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
|
+
workspace_name: str,
|
13
|
+
) -> dict[str, Any]:
|
14
|
+
_kwargs: dict[str, Any] = {
|
15
|
+
"method": "put",
|
16
|
+
"url": f"/workspaces/{workspace_name}/quotas",
|
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
|
+
workspace_name: str,
|
42
|
+
*,
|
43
|
+
client: AuthenticatedClient,
|
44
|
+
) -> Response[Any]:
|
45
|
+
"""Request workspace quotas
|
46
|
+
|
47
|
+
Send a request to update quotas for a workspace.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
workspace_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
|
+
workspace_name=workspace_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
|
+
workspace_name: str,
|
73
|
+
*,
|
74
|
+
client: AuthenticatedClient,
|
75
|
+
) -> Response[Any]:
|
76
|
+
"""Request workspace quotas
|
77
|
+
|
78
|
+
Send a request to update quotas for a workspace.
|
79
|
+
|
80
|
+
Args:
|
81
|
+
workspace_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
|
+
workspace_name=workspace_name,
|
93
|
+
)
|
94
|
+
|
95
|
+
response = await client.get_async_httpx_client().request(**kwargs)
|
96
|
+
|
97
|
+
return _build_response(client=client, response=response)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import base64
|
2
2
|
import json
|
3
|
-
import time
|
4
3
|
from dataclasses import dataclass
|
4
|
+
from datetime import datetime, timedelta
|
5
5
|
from typing import Generator, Optional
|
6
6
|
|
7
7
|
import requests
|
@@ -55,11 +55,13 @@ class ClientCredentials(Auth):
|
|
55
55
|
except Exception as e:
|
56
56
|
return Exception(f"Failed to decode/parse JWT claims: {str(e)}")
|
57
57
|
|
58
|
-
exp_time =
|
58
|
+
exp_time = datetime.fromtimestamp(claims["exp"])
|
59
|
+
current_time = datetime.now()
|
59
60
|
# Refresh if token expires in less than 10 minutes
|
60
|
-
if
|
61
|
+
if current_time + timedelta(minutes=10) > exp_time:
|
61
62
|
return self.do_refresh()
|
62
63
|
|
64
|
+
|
63
65
|
return None
|
64
66
|
|
65
67
|
def auth_flow(self, request: Request) -> Generator[Request, Response, None]:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import base64
|
2
2
|
import json
|
3
|
-
import time
|
4
3
|
from dataclasses import dataclass
|
4
|
+
from datetime import datetime, timedelta
|
5
5
|
from typing import Dict, Generator, Optional
|
6
6
|
|
7
7
|
from httpx import Auth, Request, Response, post
|
@@ -65,10 +65,10 @@ class BearerToken(Auth):
|
|
65
65
|
claims = json.loads(claims_bytes)
|
66
66
|
except Exception as e:
|
67
67
|
return Exception(f"Failed to decode/parse JWT claims: {str(e)}")
|
68
|
-
|
69
|
-
|
68
|
+
exp_time = datetime.fromtimestamp(claims["exp"])
|
69
|
+
current_time = datetime.now()
|
70
70
|
# Refresh if token expires in less than 10 minutes
|
71
|
-
if
|
71
|
+
if current_time + timedelta(minutes=10) > exp_time:
|
72
72
|
return self.do_refresh()
|
73
73
|
|
74
74
|
return None
|
beamlit/common/__init__.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from .error import HTTPError
|
2
2
|
from .logger import init as init_logger
|
3
3
|
from .secrets import Secret
|
4
|
-
from .settings import Settings, get_settings, init
|
4
|
+
from .settings import Settings, get_settings, init
|
5
5
|
from .slugify import slugify
|
6
6
|
from .utils import copy_folder
|
7
7
|
|
@@ -9,7 +9,6 @@ __all__ = [
|
|
9
9
|
"Secret",
|
10
10
|
"Settings",
|
11
11
|
"get_settings",
|
12
|
-
"init_agent",
|
13
12
|
"init",
|
14
13
|
"copy_folder",
|
15
14
|
"init_logger",
|