beamlit 0.0.22rc11__py3-none-any.whl → 0.0.23__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/chat.py CHANGED
@@ -37,12 +37,13 @@ def get_chat_model(agent_model: AgentDeployment):
37
37
  headers = get_authentication_headers(settings)
38
38
  headers["X-Beamlit-Environment"] = agent_model.environment
39
39
 
40
- jwt = headers.pop("X-Beamlit-Authorization").replace("Bearer ", "")
40
+ jwt = headers.get("X-Beamlit-Authorization", "").replace("Bearer ", "")
41
41
  params = {"environment": agent_model.environment}
42
42
  chat_classes = {
43
43
  "openai": {
44
44
  "func": get_openai_chat_model,
45
45
  "kwargs": {
46
+ "http_async_client": client.get_async_httpx_client(),
46
47
  "http_client": client.get_httpx_client(),
47
48
  },
48
49
  },
@@ -1,17 +1,18 @@
1
1
  # Import necessary modules
2
2
  import ast
3
+ import asyncio
3
4
  import importlib
4
5
  import os
5
6
  from logging import getLogger
6
7
 
7
- from langgraph.checkpoint.memory import MemorySaver
8
- from langgraph.prebuilt import create_react_agent
9
-
10
8
  from beamlit.api.models import get_model_deployment
11
9
  from beamlit.authentication import new_client
12
10
  from beamlit.common.settings import get_settings, init
13
11
  from beamlit.errors import UnexpectedStatus
14
12
  from beamlit.models import AgentDeployment
13
+ from langchain_core.tools import Tool
14
+ from langgraph.checkpoint.memory import MemorySaver
15
+ from langgraph.prebuilt import create_react_agent
15
16
 
16
17
  from .chat import get_chat_model
17
18
 
@@ -35,7 +36,7 @@ def get_functions(dir="src/functions", from_decorator="function"):
35
36
  # Look for function definitions with decorators
36
37
  for node in ast.walk(tree):
37
38
  if (
38
- not isinstance(node, ast.FunctionDef)
39
+ (not isinstance(node, ast.FunctionDef) and not isinstance(node, ast.AsyncFunctionDef))
39
40
  or len(node.decorator_list) == 0
40
41
  ):
41
42
  continue
@@ -73,7 +74,10 @@ def get_functions(dir="src/functions", from_decorator="function"):
73
74
  # Get the decorated function
74
75
  if not is_kit and hasattr(module, func_name):
75
76
  func = getattr(module, func_name)
76
- functions.append(func)
77
+ if asyncio.iscoroutinefunction(func):
78
+ functions.append(Tool(name=func.__name__, description=func.__doc__, func=func, coroutine=func))
79
+ else:
80
+ functions.append(Tool(name=func.__name__, description=func.__doc__, func=func))
77
81
  except Exception as e:
78
82
  logger.warning(f"Error processing {file_path}: {e!s}")
79
83
  return functions
@@ -51,7 +51,6 @@ def new_client():
51
51
  else:
52
52
  settings = get_settings()
53
53
  credentials = load_credentials_from_settings(settings)
54
-
55
54
  client_config = RunClientWithCredentials(
56
55
  credentials=credentials,
57
56
  workspace=settings.workspace,
@@ -130,7 +130,7 @@ def load_credentials(workspace_name: str) -> Credentials:
130
130
  def load_credentials_from_settings(settings: Settings) -> Credentials:
131
131
  return Credentials(
132
132
  api_key=settings.authentication.api_key,
133
- client_credentials=settings.authentication.client_credentials,
133
+ client_credentials=settings.authentication.client.credentials,
134
134
  )
135
135
 
136
136
 
beamlit/client.py CHANGED
@@ -248,7 +248,6 @@ class AuthenticatedClient:
248
248
  def get_async_httpx_client(self) -> httpx.AsyncClient:
249
249
  """Get the underlying httpx.AsyncClient, constructing a new one if not previously set"""
250
250
  if self._async_client is None:
251
- self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token
252
251
  self._async_client = httpx.AsyncClient(
253
252
  base_url=self._base_url,
254
253
  cookies=self._cookies,
@@ -2,16 +2,6 @@ import os
2
2
  from logging import getLogger
3
3
  from typing import List, Tuple, Type, Union
4
4
 
5
- from langchain_core.language_models.chat_models import BaseChatModel
6
- from langgraph.graph.graph import CompiledGraph
7
- from pydantic import Field
8
- from pydantic_settings import (
9
- BaseSettings,
10
- PydanticBaseSettingsSource,
11
- SettingsConfigDict,
12
- YamlConfigSettingsSource,
13
- )
14
-
15
5
  from beamlit.api.functions import get_function_deployment
16
6
  from beamlit.api.models import get_model_deployment
17
7
  from beamlit.client import AuthenticatedClient
@@ -20,6 +10,11 @@ from beamlit.models.agent_deployment import AgentDeployment
20
10
  from beamlit.models.function_deployment import FunctionDeployment
21
11
  from beamlit.models.model_deployment import ModelDeployment
22
12
  from beamlit.types import UNSET, Unset
13
+ from langchain_core.language_models.chat_models import BaseChatModel
14
+ from langgraph.graph.graph import CompiledGraph
15
+ from pydantic import Field
16
+ from pydantic_settings import (BaseSettings, PydanticBaseSettingsSource,
17
+ SettingsConfigDict, YamlConfigSettingsSource)
23
18
 
24
19
  global SETTINGS
25
20
  SETTINGS = None
@@ -39,10 +34,14 @@ class SettingsAgent(BaseSettings):
39
34
  module: str = Field(default="main.main")
40
35
 
41
36
 
37
+ class SettingsAuthenticationClient(BaseSettings):
38
+ credentials: Union[None, str] = None
39
+
40
+
42
41
  class SettingsAuthentication(BaseSettings):
43
42
  api_key: Union[None, str] = None
44
43
  jwt: Union[None, str] = None
45
- client_credentials: Union[None, str] = None
44
+ client: SettingsAuthenticationClient = SettingsAuthenticationClient()
46
45
 
47
46
 
48
47
  class SettingsServer(BaseSettings):
@@ -56,14 +55,17 @@ class Settings(BaseSettings):
56
55
  yaml_file="beamlit.yaml",
57
56
  env_prefix="bl_",
58
57
  env_nested_delimiter="_",
58
+ extra="ignore",
59
59
  )
60
60
 
61
61
  workspace: str
62
62
  environment: str = Field(default="production")
63
+ remote: bool = Field(default=False)
63
64
  type: str = Field(default="agent")
64
65
  name: str = Field(default="beamlit-agent")
65
66
  base_url: str = Field(default="https://api.beamlit.dev/v0")
66
67
  run_url: str = Field(default="https://run.beamlit.dev")
68
+ registry_url: str = Field(default="https://serverless-registry-production.beamlit.workers.dev")
67
69
  log_level: str = Field(default="INFO")
68
70
  agent: SettingsAgent = SettingsAgent()
69
71
  server: SettingsServer = SettingsServer()
@@ -0,0 +1,3 @@
1
+ from .deploy import generate_beamlit_deployment
2
+
3
+ __all__ = ["generate_beamlit_deployment"]
@@ -0,0 +1,503 @@
1
+ import ast
2
+ import importlib
3
+ import json
4
+ import os
5
+ import sys
6
+ from dataclasses import dataclass
7
+ from logging import getLogger
8
+ from typing import Callable, Literal
9
+
10
+ from beamlit.common.settings import Settings, get_settings, init
11
+ from beamlit.models import (AgentChain, AgentDeployment, Flavor,
12
+ FunctionDeployment, Runtime,
13
+ StoreFunctionParameter)
14
+
15
+ sys.path.insert(0, os.getcwd())
16
+ sys.path.insert(0, os.path.join(os.getcwd(), "src"))
17
+
18
+
19
+ @dataclass
20
+ class Resource:
21
+ type: Literal["agent", "function"]
22
+ module: Callable
23
+ name: str
24
+ decorator: ast.Call
25
+ func: Callable
26
+
27
+ def get_resources(from_decorator, dir="src") -> list[Resource]:
28
+ """
29
+ Scans through Python files in a directory to find functions decorated with a specific decorator.
30
+
31
+ Args:
32
+ from_decorator (str): The name of the decorator to search for
33
+ dir (str): The directory to scan, defaults to "src"
34
+
35
+ Returns:
36
+ list[Resource]: List of Resource objects containing information about decorated functions
37
+ """
38
+ resources = []
39
+ logger = getLogger(__name__)
40
+
41
+ # Walk through all Python files in resources directory and subdirectories
42
+ for root, _, files in os.walk(dir):
43
+ for file in files:
44
+ if file.endswith(".py"):
45
+ file_path = os.path.join(root, file)
46
+ # Read and compile the file content
47
+ with open(file_path) as f:
48
+ try:
49
+ file_content = f.read()
50
+ # Parse the file content to find decorated resources
51
+ tree = ast.parse(file_content)
52
+
53
+ # Look for function definitions with decorators
54
+ for node in ast.walk(tree):
55
+ if (
56
+ not isinstance(node, ast.FunctionDef) and not isinstance(node, ast.AsyncFunctionDef)
57
+ ) or len(node.decorator_list) == 0:
58
+ continue
59
+ decorator = node.decorator_list[0]
60
+
61
+ decorator_name = ""
62
+ if isinstance(decorator, ast.Call):
63
+ decorator_name = decorator.func.id
64
+ if isinstance(decorator, ast.Name):
65
+ decorator_name = decorator.id
66
+ if decorator_name == from_decorator:
67
+ # Get the function name and decorator name
68
+ func_name = node.name
69
+
70
+ # Import the module to get the actual function
71
+ spec = importlib.util.spec_from_file_location(func_name, file_path)
72
+ module = importlib.util.module_from_spec(spec)
73
+ spec.loader.exec_module(module)
74
+ # Check if kit=True in the decorator arguments
75
+
76
+ # Get the decorated function
77
+ if hasattr(module, func_name) and isinstance(decorator, ast.Call):
78
+
79
+ resources.append(
80
+ Resource(
81
+ type=decorator_name,
82
+ module=module,
83
+ name=func_name,
84
+ func=getattr(module, func_name),
85
+ decorator=decorator,
86
+ )
87
+ )
88
+ except Exception as e:
89
+ logger.warning(f"Error processing {file_path}: {e!s}")
90
+ return resources
91
+
92
+
93
+ def get_parameters(resource: Resource) -> list[StoreFunctionParameter]:
94
+ """
95
+ Extracts parameter information from a function's signature and docstring.
96
+
97
+ Args:
98
+ resource (Resource): The resource object containing the function to analyze
99
+
100
+ Returns:
101
+ list[StoreFunctionParameter]: List of parameter objects with name, type, required status, and description
102
+ """
103
+ parameters = []
104
+ # Get function signature
105
+ import inspect
106
+ sig = inspect.signature(resource.func)
107
+ # Get docstring for parameter descriptions
108
+ docstring = inspect.getdoc(resource.func)
109
+ param_descriptions = {}
110
+ if docstring:
111
+ # Parse docstring for parameter descriptions
112
+ lines = docstring.split('\n')
113
+ for line in lines:
114
+ line = line.strip().lower()
115
+ if line.startswith(':param '):
116
+ # Extract parameter name and description
117
+ param_line = line[7:].split(':', 1)
118
+ if len(param_line) == 2:
119
+ param_name = param_line[0].strip()
120
+ param_desc = param_line[1].strip()
121
+ param_descriptions[param_name] = param_desc
122
+ for name, param in sig.parameters.items():
123
+ # Skip *args and **kwargs parameters
124
+ if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD):
125
+
126
+ continue
127
+
128
+ param_type = "string" # Default type
129
+ type_mapping = {
130
+ 'str': 'string',
131
+ 'int': 'integer',
132
+ 'float': 'number',
133
+ 'bool': 'boolean',
134
+ 'list': 'array',
135
+ 'dict': 'object',
136
+ 'none': 'null'
137
+ }
138
+ if param.annotation != inspect.Parameter.empty:
139
+ # Map Python types to OpenAPI types
140
+ if hasattr(param.annotation, "__name__"):
141
+ param_type = param.annotation.__name__.lower()
142
+ else:
143
+ # Handle special types like Union, Optional etc
144
+ param_type = str(param.annotation).lower()
145
+ parameter = StoreFunctionParameter(
146
+ name=name,
147
+ type_=type_mapping.get(param_type, "string"),
148
+ required=param.default == inspect.Parameter.empty,
149
+ description=param_descriptions.get(name, f"Parameter {name}")
150
+ )
151
+ parameters.append(parameter)
152
+
153
+ return parameters
154
+
155
+
156
+ def get_description(description: str | None, resource: Resource) -> str:
157
+ """
158
+ Gets the description of a function from either a provided description or the function's docstring.
159
+
160
+ Args:
161
+ description (str | None): Optional explicit description
162
+ resource (Resource): The resource object containing the function
163
+
164
+ Returns:
165
+ str: The function description
166
+ """
167
+ if description:
168
+ return description
169
+ doc = resource.func.__doc__
170
+ if doc:
171
+ # Split docstring into sections and get only the description part
172
+ doc_lines = doc.split('\n')
173
+ description_lines = []
174
+ for line in doc_lines:
175
+ line = line.strip()
176
+ # Stop when we hit param/return sections
177
+ if line.startswith(':param') or line.startswith(':return'):
178
+ break
179
+ if line:
180
+ description_lines.append(line)
181
+ return ' '.join(description_lines).strip()
182
+ return ""
183
+
184
+ def get_kwargs(arg: ast.Call) -> dict:
185
+ """
186
+ Extracts keyword arguments from an AST Call node.
187
+
188
+ Args:
189
+ arg (ast.Call): The AST Call node to process
190
+
191
+ Returns:
192
+ dict: Dictionary of keyword arguments and their values
193
+ """
194
+ kwargs = {}
195
+ for keyword in arg.keywords:
196
+ if isinstance(keyword.value, ast.Constant):
197
+ kwargs[keyword.arg] = keyword.value.value
198
+ elif isinstance(keyword.value, (ast.List, ast.Tuple)):
199
+ kwargs[keyword.arg] = [
200
+ AgentChain(**get_kwargs(elem)) if isinstance(elem, ast.Call) and isinstance(elem.func, ast.Name) and elem.func.id == "AgentChain"
201
+ else elem.value if isinstance(elem, ast.Constant) else elem
202
+ for elem in keyword.value.elts
203
+ ]
204
+ elif isinstance(keyword.value, ast.Dict):
205
+ kwargs[keyword.arg] = {}
206
+ for k, v in zip(keyword.value.keys, keyword.value.values):
207
+ if isinstance(k, ast.Constant) and isinstance(v, ast.Constant):
208
+ kwargs[keyword.arg][k.value] = v.value
209
+ if isinstance(k, ast.Constant) and isinstance(v, ast.Call):
210
+ kwargs[keyword.arg][k.value] = get_kwargs(v)
211
+ return kwargs
212
+
213
+ def get_runtime(type: str, name: str) -> Runtime:
214
+ settings = get_settings()
215
+ registry_url = settings.registry_url.replace("https://", "").replace("http://", "")
216
+ image = f"{registry_url}/{settings.workspace}/{type}s/{name}"
217
+ return Runtime(image=image)
218
+
219
+ def get_beamlit_deployment_from_resource(resource: Resource) -> AgentDeployment | FunctionDeployment:
220
+ """
221
+ Creates a deployment configuration from a resource.
222
+
223
+ Args:
224
+ resource (Resource): The resource to create a deployment for
225
+
226
+ Returns:
227
+ AgentDeployment | FunctionDeployment: The deployment configuration
228
+ """
229
+ for arg in resource.decorator.args:
230
+ if isinstance(arg, ast.Call):
231
+ if isinstance(arg.func, ast.Name) and arg.func.id == "AgentDeployment":
232
+ kwargs = get_kwargs(arg)
233
+ description = kwargs.pop("description", None)
234
+ return AgentDeployment(
235
+ **kwargs,
236
+ description=get_description(description, resource),
237
+ runtime=get_runtime("agent", kwargs.get("agent", resource.name))
238
+ )
239
+ if isinstance(arg.func, ast.Name) and arg.func.id == "FunctionDeployment":
240
+ kwargs = get_kwargs(arg)
241
+ description = kwargs.pop("description", None)
242
+ return FunctionDeployment(
243
+ **kwargs,
244
+ parameters=get_parameters(resource),
245
+ description=get_description(description, resource),
246
+ runtime=get_runtime("function", kwargs.get("function", resource.name))
247
+ )
248
+ for arg in resource.decorator.keywords:
249
+ if isinstance(arg.value, ast.Call):
250
+ if isinstance(arg.value.func, ast.Name) and arg.value.func.id == "AgentDeployment":
251
+ kwargs = get_kwargs(arg.value)
252
+ description = kwargs.pop("description", None)
253
+ return AgentDeployment(
254
+ **kwargs,
255
+ description=get_description(description, resource),
256
+ runtime=get_runtime("agent", kwargs.get("agent", resource.name))
257
+ )
258
+ if isinstance(arg.value.func, ast.Name) and arg.value.func.id == "FunctionDeployment":
259
+ kwargs = get_kwargs(arg.value)
260
+ description = kwargs.pop("description", None)
261
+ return FunctionDeployment(
262
+ **kwargs,
263
+ parameters=get_parameters(resource),
264
+ description=get_description(description, resource),
265
+ runtime=get_runtime("function", kwargs.get("function", resource.name))
266
+ )
267
+ if resource.type == "agent":
268
+ return AgentDeployment(
269
+ agent=resource.name,
270
+ description=get_description(None,resource),
271
+ runtime=get_runtime("agent", resource.name)
272
+ )
273
+ if resource.type == "function":
274
+ return FunctionDeployment(
275
+ function=resource.name,
276
+ parameters=get_parameters(resource),
277
+ description=get_description(None,resource),
278
+ runtime=get_runtime("function", resource.name)
279
+ )
280
+ return None
281
+
282
+
283
+ def get_flavors(flavors: list[Flavor]) -> str:
284
+ """
285
+ Converts a list of Flavor objects to JSON string.
286
+
287
+ Args:
288
+ flavors (list[Flavor]): List of Flavor objects
289
+
290
+ Returns:
291
+ str: JSON string representation of flavors
292
+ """
293
+ if not flavors:
294
+ return "[]"
295
+ return json.dumps([flavor.to_dict() for flavor in flavors])
296
+
297
+ def format_parameters(parameters: list[StoreFunctionParameter]) -> str:
298
+ """
299
+ Formats function parameters into YAML-compatible string.
300
+
301
+ Args:
302
+ parameters (list[StoreFunctionParameter]): List of parameter objects
303
+
304
+ Returns:
305
+ str: YAML-formatted string of parameters
306
+ """
307
+ if not parameters:
308
+ return "[]"
309
+
310
+ formatted = []
311
+ for param in parameters:
312
+ formatted.append(f"""
313
+ - name: {param.name}
314
+ type: {param.type_}
315
+ required: {str(param.required).lower()}
316
+ description: {param.description}""")
317
+
318
+ return "\n".join(formatted)
319
+
320
+ def format_agent_chain(agent_chain: list[AgentChain]) -> str:
321
+ """
322
+ Formats agent chain configuration into YAML-compatible string.
323
+
324
+ Args:
325
+ agent_chain (list[AgentChain]): List of agent chain configurations
326
+
327
+ Returns:
328
+ str: YAML-formatted string of agent chain
329
+ """
330
+ if not agent_chain:
331
+ return "[]"
332
+ formatted = []
333
+
334
+ for agent in agent_chain:
335
+ formatted.append(f"""
336
+ - agent: {agent.name}
337
+ enabled: {agent.enabled}""")
338
+ if agent.description:
339
+ formatted.append(f" description: {agent.description}")
340
+ return "\n".join(formatted)
341
+
342
+ def get_agent_yaml(agent: AgentDeployment, functions: list[tuple[Resource, FunctionDeployment]], settings: Settings) -> str:
343
+ """
344
+ Generates YAML configuration for an agent deployment.
345
+
346
+ Args:
347
+ agent (AgentDeployment): Agent deployment configuration
348
+ functions (list[tuple[Resource, FunctionDeployment]]): List of associated functions
349
+ settings (Settings): Application settings
350
+
351
+ Returns:
352
+ str: YAML configuration string
353
+ """
354
+ template = f"""
355
+ apiVersion: beamlit.com/v1alpha1
356
+ kind: Agent
357
+ metadata:
358
+ name: {agent.agent}
359
+ spec:
360
+ display_name: {agent.agent}
361
+ deployments:
362
+ - environment: {settings.environment}
363
+ enabled: true
364
+ policies: [{", ".join(agent.policies or [])}]
365
+ functions: [{", ".join([f"{function.function}" for (_, function) in functions])}]
366
+ agent_chain: {format_agent_chain(agent.agent_chain)}
367
+ model: {agent.model}
368
+ runtime:
369
+ image: {agent.runtime.image}
370
+ """
371
+ if agent.description:
372
+ template += f""" description: |
373
+ {agent.description}"""
374
+ return template
375
+
376
+ def get_function_yaml(function: FunctionDeployment, settings: Settings) -> str:
377
+ """
378
+ Generates YAML configuration for a function deployment.
379
+
380
+ Args:
381
+ function (FunctionDeployment): Function deployment configuration
382
+ settings (Settings): Application settings
383
+
384
+ Returns:
385
+ str: YAML configuration string
386
+ """
387
+ return f"""
388
+ apiVersion: beamlit.com/v1alpha1
389
+ kind: Function
390
+ metadata:
391
+ name: {function.function}
392
+ spec:
393
+ display_name: {function.function}
394
+ deployments:
395
+ - environment: {settings.environment}
396
+ enabled: true
397
+ policies: [{", ".join(function.policies or [])}]
398
+ description: |
399
+ {function.description}
400
+ parameters: {format_parameters(function.parameters)}
401
+ runtime:
402
+ image: {function.runtime.image}
403
+ """
404
+
405
+ def dockerfile(type: Literal["agent", "function"], resource: Resource, deployment: AgentDeployment | FunctionDeployment) -> str:
406
+ """
407
+ Generates Dockerfile content for agent or function deployment.
408
+
409
+ Args:
410
+ type (Literal["agent", "function"]): Type of deployment
411
+ resource (Resource): Resource to be deployed
412
+ deployment (AgentDeployment | FunctionDeployment): Deployment configuration
413
+
414
+ Returns:
415
+ str: Dockerfile content
416
+ """
417
+ if type == "agent":
418
+ module = f"{resource.module.__file__.split('/')[-1].replace('.py', '')}.{resource.module.__name__}"
419
+ else:
420
+ module = f"functions.{resource.module.__name__}.{resource.func.__name__}"
421
+ cmd = ["bl", "serve", "--port", "80", "--module", module]
422
+ if type == "agent":
423
+ cmd.append("--remote")
424
+ cmd_str = ','.join([f'"{c}"' for c in cmd])
425
+
426
+ return f"""
427
+ FROM python:3.12-slim
428
+
429
+ ARG UV_VERSION="latest"
430
+ RUN apt update && apt install -y curl
431
+
432
+ # Install uv.
433
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
434
+ RUN curl -fsSL https://raw.githubusercontent.com/beamlit/toolkit/main/install.sh | BINDIR=/bin sh
435
+ WORKDIR /beamlit
436
+
437
+ # Install the application dependencies.
438
+ COPY pyproject.toml /beamlit/pyproject.toml
439
+ COPY uv.lock /beamlit/uv.lock
440
+ RUN uv sync --no-cache
441
+
442
+ COPY README.md /beamlit/README.md
443
+ COPY LICENSE /beamlit/LICENSE
444
+ COPY src /beamlit/src
445
+
446
+ ENV PATH="/beamlit/.venv/bin:$PATH"
447
+
448
+ ENTRYPOINT [{cmd_str}]
449
+ """
450
+
451
+ def generate_beamlit_deployment(directory: str):
452
+ """
453
+ Generates all necessary deployment files for Beamlit agents and functions.
454
+
455
+ Args:
456
+ directory (str): Target directory for generated files
457
+
458
+ Creates:
459
+ - Agent and function YAML configurations
460
+ - Dockerfiles for each deployment
461
+ - Directory structure for agents and functions
462
+ """
463
+ settings = init()
464
+ logger = getLogger(__name__)
465
+ logger.info(f"Importing server module: {settings.server.module}")
466
+ functions: list[tuple[Resource, FunctionDeployment]] = []
467
+ agents: list[tuple[Resource, AgentDeployment]] = []
468
+ for agent in get_resources("agent"):
469
+ agent_deployment = get_beamlit_deployment_from_resource(agent)
470
+ if agent_deployment:
471
+ agents.append((agent, agent_deployment))
472
+ for function in get_resources("function"):
473
+ function_deployment = get_beamlit_deployment_from_resource(function)
474
+ if function_deployment:
475
+ functions.append((function, function_deployment))
476
+
477
+ agents_dir = os.path.join(directory, "agents")
478
+ functions_dir = os.path.join(directory, "functions")
479
+ # Create directory if it doesn't exist
480
+ os.makedirs(agents_dir, exist_ok=True)
481
+ os.makedirs(functions_dir, exist_ok=True)
482
+ for (resource, agent) in agents:
483
+ # write deployment file
484
+ agent_dir = os.path.join(agents_dir, agent.agent)
485
+ os.makedirs(agent_dir, exist_ok=True)
486
+ with open(os.path.join(agent_dir, f"agent.yaml"), "w") as f:
487
+ content = get_agent_yaml(agent, functions, settings)
488
+ f.write(content)
489
+ # write dockerfile for build
490
+ with open(os.path.join(agent_dir, f"Dockerfile"), "w") as f:
491
+ content = dockerfile("agent", resource, agent)
492
+ f.write(content)
493
+ for (resource, function) in functions:
494
+ # write deployment file
495
+ function_dir = os.path.join(functions_dir, function.function)
496
+ os.makedirs(function_dir, exist_ok=True)
497
+ with open(os.path.join(function_dir, f"function.yaml"), "w") as f:
498
+ content = get_function_yaml(function, settings)
499
+ f.write(content)
500
+ # write dockerfile for build
501
+ with open(os.path.join(function_dir, f"Dockerfile"), "w") as f:
502
+ content = dockerfile("function", resource, function)
503
+ f.write(content)
@@ -3,12 +3,11 @@
3
3
  from collections.abc import Callable
4
4
  from logging import getLogger
5
5
 
6
- from langchain_core.tools import create_schema_from_function, tool
7
-
8
6
  from beamlit.authentication import new_client
9
7
  from beamlit.common.settings import get_settings
10
8
  from beamlit.models import FunctionDeployment, FunctionKit
11
9
  from beamlit.run import RunClient
10
+ from langchain_core.tools import create_schema_from_function
12
11
 
13
12
  logger = getLogger(__name__)
14
13
 
@@ -58,7 +57,7 @@ def kit(bl_kit: FunctionKit = None, **kwargs: dict) -> Callable:
58
57
  def wrapper(func: Callable) -> Callable:
59
58
  if bl_kit and not func.__doc__ and bl_kit.description:
60
59
  func.__doc__ = bl_kit.description
61
- return tool(func, **kwargs)
60
+ return func
62
61
 
63
62
  return wrapper
64
63
 
@@ -72,10 +71,7 @@ def function(
72
71
  def wrapper(func: Callable) -> Callable:
73
72
  if bl_function and not func.__doc__ and bl_function.description:
74
73
  func.__doc__ = bl_function.description
75
- if (
76
- settings.environment == "development"
77
- or settings.environment == "production"
78
- ):
74
+ if settings.remote:
79
75
  remote_func = get_remote_function(func, bl_function)
80
76
  if not kwargs.get("args_schema"):
81
77
  kwargs["args_schema"] = create_schema_from_function(
@@ -83,8 +79,7 @@ def function(
83
79
  func,
84
80
  parse_docstring=func.__doc__,
85
81
  )
86
- return tool(remote_func, **kwargs)
87
- return tool(func, **kwargs)
82
+ return remote_func
83
+ return func
88
84
 
89
85
  return wrapper
90
- return wrapper
beamlit/serve/app.py CHANGED
@@ -16,7 +16,6 @@ from .middlewares import AccessLogMiddleware, AddProcessTimeHeader
16
16
  sys.path.insert(0, os.getcwd())
17
17
  sys.path.insert(0, os.path.join(os.getcwd(), "src"))
18
18
 
19
-
20
19
  def import_module():
21
20
  settings = get_settings()
22
21
  main_module = importlib.import_module(".".join(settings.server.module.split(".")[0:-1]))
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: beamlit
3
- Version: 0.0.22rc11
3
+ Version: 0.0.23
4
4
  Summary: Add your description here
5
5
  Author-email: cploujoux <ch.ploujoux@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -1,12 +1,12 @@
1
1
  beamlit/__init__.py,sha256=545gFC-wLLwUktWcOAjUWe_Glha40tBetRTOYSfHnbI,164
2
- beamlit/client.py,sha256=vwvjAkUKHRySnA2tOVzXI8xtm9s1k2sEklCRE4j1Vc8,12543
2
+ beamlit/client.py,sha256=OdRbs5VVHF32HUd5RMcnkhe8YxamnAmgGlxO6pm1Xac,12431
3
3
  beamlit/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
4
4
  beamlit/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6pTVHVXk5hJL79ebTk,25
5
5
  beamlit/run.py,sha256=y61iDBaR0917ihj5q-cJ_r3BFW1Rn5K_kDAISw5O6aU,1339
6
6
  beamlit/types.py,sha256=E1hhDh_zXfsSQ0NCt9-uw90_Mr5iIlsdfnfvxv5HarU,1005
7
7
  beamlit/agents/__init__.py,sha256=nf1iwQwGtCG6nDqyVhxfWoqR6dv6X3bvSpCeqkTCFaM,101
8
- beamlit/agents/chat.py,sha256=8KsUvIB-eaUApfKclT76_4HQu3VBa9nifMqmq_AAvcM,2630
9
- beamlit/agents/decorator.py,sha256=naeOsvfto74TZTcc15Ro98Hl8Bbe6Uhflof_SdyUkwY,6054
8
+ beamlit/agents/chat.py,sha256=aI7pObyywRyg3dBpubzHAUWTbTk1nwtxvpY7iIP1RLY,2704
9
+ beamlit/agents/decorator.py,sha256=XDrWN-Xx4czSy1sIkfQY4t9-UnsM21vMll58CP1TRLw,6468
10
10
  beamlit/api/__init__.py,sha256=zTSiG_ujSjAqWPyc435YXaX9XTlpMjiJWBbV-f-YtdA,45
11
11
  beamlit/api/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  beamlit/api/agents/create_agent.py,sha256=HFExosu02JZqZz7I6U6WjN81TERz6p2i8CzQCyiRYXo,4112
@@ -130,18 +130,20 @@ beamlit/api/workspaces/update_workspace.py,sha256=qa5DV2UJSUYuB_ibALb4E9ghKpT1Ha
130
130
  beamlit/api/workspaces/update_workspace_user_role.py,sha256=Yn9iuJ4tKtauzBiJyU4-wYUMS9g98X2Om8zs7UkzrY8,4917
131
131
  beamlit/authentication/__init__.py,sha256=wiXqRbc7E-ulrH_ueA9duOGFvXeo7-RvhSD1XbFogMo,1020
132
132
  beamlit/authentication/apikey.py,sha256=jnz1FMRauI5qAInqeeDER8aCONx4O8ZPZGedvi3Ap_o,659
133
- beamlit/authentication/authentication.py,sha256=om26AteY2cCV9ctqbOCynX6PgS8YO-aCreNOFSnnWKc,3121
133
+ beamlit/authentication/authentication.py,sha256=tZu8GoVueKDuq1RLXMvtHcV95XLikmQ19PCxLWBn2Ek,3120
134
134
  beamlit/authentication/clientcredentials.py,sha256=6kbfTjwUkXUArJX8XZLe9ZzbEicQc19tSXBvsTpiXMk,3954
135
- beamlit/authentication/credentials.py,sha256=DBw598T6it7EgXKnS_qfsBM0mkC33iRDadWA70bg5X0,5349
135
+ beamlit/authentication/credentials.py,sha256=DlfiF_FfOosPVsRoa39JSR3XoICmhBqTlHXc6b4zWtE,5349
136
136
  beamlit/authentication/device_mode.py,sha256=oQVBCDsq-pdeXF31WSTAAEdaX6eACV7SYcOSyf3ea_Q,3728
137
137
  beamlit/common/__init__.py,sha256=yDoMJDKj-xjTGl7U1YI59KpWxiOV65HSiUulgO8xdTA,277
138
138
  beamlit/common/generate.py,sha256=VJ_MiRDulXdQdnlKdM4_Bod6CO6DOGlFiosGXOLuLGs,7227
139
139
  beamlit/common/logger.py,sha256=ayabnsoHS8ncXm8EpBS01FkvSe0XRcaNdQjKVuPI5z4,1025
140
140
  beamlit/common/secrets.py,sha256=sid81bOe3LflkMKDHwBsBs9nIju8bp5-v9qU9gkyNMc,212
141
- beamlit/common/settings.py,sha256=7PDfLPzTPN5Yeh2NnmAlSzpBi_u-qza2lUIX-i6N_lg,5252
141
+ beamlit/common/settings.py,sha256=N0VzveNQ3vAE6ZJWMnWrIVi2hXidLtkRZkAXQTGo40A,5546
142
142
  beamlit/common/utils.py,sha256=jouz5igBvT37Xn_e94-foCHyQczVim-UzVcoIF6RWJ4,657
143
+ beamlit/deploy/__init__.py,sha256=GS7l7Jtm2yKs7iNLKcfjYO-rAhUzggQ3xiYSf3oxLBY,91
144
+ beamlit/deploy/deploy.py,sha256=bWUXG_5b_XhFcG5t75vel2EbEfZPIdg_YLXtzkfgXUs,18799
143
145
  beamlit/functions/__init__.py,sha256=_RPG1Bfg54JGdIPnViAU6n9zD7E1cDNsdXi8oYGskzE,138
144
- beamlit/functions/decorator.py,sha256=-2newMBztweIgFuh0ABKOdxCfUzWaRxf0ym-YAgggJI,3168
146
+ beamlit/functions/decorator.py,sha256=uYZOVxD-7ZNHORTQfCIn0qdNKPIZupsr7_QdUmWEKu0,2996
145
147
  beamlit/functions/github/__init__.py,sha256=gYnUkeegukOfbymdabuuJkScvH-_ZJygX05BoqkPn0o,49
146
148
  beamlit/functions/github/github.py,sha256=FajzLCNkpXcwfgnC0l9rOGT2eSPLCz8-qrMzK9N_ZNc,598
147
149
  beamlit/functions/github/kit/__init__.py,sha256=jBwPqZv6C23_utukohxqXZwrlicNlI7PYPUj0Den7Cw,136
@@ -292,10 +294,10 @@ beamlit/models/websocket_channel.py,sha256=tyNtsVR0cOwd6BK--ehBCH8bIjxtyPhiAkrxY
292
294
  beamlit/models/workspace.py,sha256=s7wS6ibswosB0FdUb3ry3BnlLa325axBdYPLI3ipe0Q,3986
293
295
  beamlit/models/workspace_labels.py,sha256=WbnUY6eCTkUNdY7hhhSF-KQCl8fWFfkCf7hzCTiNp4A,1246
294
296
  beamlit/models/workspace_user.py,sha256=70CcifQWYbeWG7TDui4pblTzUe5sVK0AS19vNCzKE8g,3423
295
- beamlit/serve/app.py,sha256=-CvUU7pqFDigndHpA01IR4_mxXaT8c0VsnVjMfIw6K8,2399
297
+ beamlit/serve/app.py,sha256=_0ZesKcczd1sYm8vs3ulbXO1M1boO_5DhFf3jSmjM4g,2398
296
298
  beamlit/serve/middlewares/__init__.py,sha256=1dVmnOmhAQWvWktqHkKSIX-YoF6fmMU8xkUQuhg_rJU,148
297
299
  beamlit/serve/middlewares/accesslog.py,sha256=wM52-hcwtO-_hdM1pnsEJzerzJf1MzEyN5m85BdDccE,609
298
300
  beamlit/serve/middlewares/processtime.py,sha256=lDAaIasZ4bwvN-HKHvZpaD9r-yrkVNZYx4abvbjbrCg,411
299
- beamlit-0.0.22rc11.dist-info/METADATA,sha256=AOUr4a-4i_HzlZwKbn12EyaSvGR2BJFEFdzs4WXPqRw,2027
300
- beamlit-0.0.22rc11.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
301
- beamlit-0.0.22rc11.dist-info/RECORD,,
301
+ beamlit-0.0.23.dist-info/METADATA,sha256=3o33Ckt9YG7lMNqHL9niFXXNSeQCLZUWX7BavDh7ZjI,2023
302
+ beamlit-0.0.23.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
303
+ beamlit-0.0.23.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.26.3
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any