beamlit 0.0.28rc25__py3-none-any.whl → 0.0.29rc26__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,93 @@
1
+ import asyncio
2
+ from dataclasses import dataclass
3
+ import warnings
4
+ from typing import Any, Callable
5
+
6
+ import pydantic
7
+ import typing_extensions as t
8
+ from beamlit.api.agents import list_agents
9
+ from beamlit.authentication.authentication import AuthenticatedClient
10
+ from beamlit.models import Agent, AgentChain
11
+ from beamlit.run import RunClient
12
+ from beamlit.common.settings import get_settings
13
+ from langchain_core.tools.base import BaseTool, ToolException
14
+
15
+
16
+
17
+ class ChainTool(BaseTool):
18
+ """
19
+ Chain tool
20
+ """
21
+
22
+ client: RunClient
23
+ handle_tool_error: bool | str | Callable[[ToolException], str] | None = True
24
+
25
+ @t.override
26
+ def _run(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
27
+ warnings.warn(
28
+ "Invoke this tool asynchronousely using `ainvoke`. This method exists only to satisfy standard tests.",
29
+ stacklevel=1,
30
+ )
31
+ return asyncio.run(self._arun(*args, **kwargs))
32
+
33
+ @t.override
34
+ async def _arun(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
35
+ settings = get_settings()
36
+ result = self.client.run(
37
+ "agent",
38
+ self.name,
39
+ settings.environment,
40
+ "POST",
41
+ json=kwargs,
42
+ )
43
+ return result.text
44
+
45
+ @t.override
46
+ @property
47
+ def tool_call_schema(self) -> type[pydantic.BaseModel]:
48
+ assert self.args_schema is not None # noqa: S101
49
+ return self.args_schema
50
+
51
+ class ChainInput(pydantic.BaseModel):
52
+ inputs: str
53
+
54
+ @dataclass
55
+ class ChainToolkit:
56
+ """
57
+ Remote toolkit
58
+ """
59
+ client: AuthenticatedClient
60
+ chain: list[AgentChain]
61
+ _chain: list[Agent] | None = None
62
+
63
+ model_config = pydantic.ConfigDict(arbitrary_types_allowed=True)
64
+
65
+ def initialize(self) -> None:
66
+ """Initialize the session and retrieve tools list"""
67
+ if self._chain is None:
68
+ agents = list_agents.sync_detailed(
69
+ client=self.client,
70
+ ).parsed
71
+ chain_enabled = [chain for chain in self.chain if chain.enabled]
72
+ agents_chain = []
73
+ for chain in chain_enabled:
74
+ agent = [agent for agent in agents if agent.metadata.name == chain.name]
75
+ if agent:
76
+ agent[0].spec.description = chain.description or agent[0].spec.description
77
+ agents_chain.append(agent[0])
78
+ self._chain = agents_chain
79
+
80
+ @t.override
81
+ def get_tools(self) -> list[BaseTool]:
82
+ if self._chain is None:
83
+ raise RuntimeError("Must initialize the toolkit first")
84
+
85
+ return [
86
+ ChainTool(
87
+ client=RunClient(self.client),
88
+ name=agent.metadata.name,
89
+ description=agent.spec.description or "",
90
+ args_schema=ChainInput,
91
+ )
92
+ for agent in self._chain
93
+ ]
@@ -18,7 +18,7 @@ from langgraph.checkpoint.memory import MemorySaver
18
18
  from langgraph.prebuilt import create_react_agent
19
19
 
20
20
  from .chat import get_chat_model
21
-
21
+ from .chain import ChainToolkit
22
22
 
23
23
  def get_functions(dir="src/functions", from_decorator="function"):
24
24
  functions = []
@@ -178,7 +178,6 @@ def agent(
178
178
  logger.warn(f"Failed to initialize MCP server {server}: {e!s}")
179
179
 
180
180
  if remote_functions:
181
-
182
181
  for function in remote_functions:
183
182
  try:
184
183
  toolkit = RemoteToolkit(client, function)
@@ -187,6 +186,11 @@ def agent(
187
186
  except Exception as e:
188
187
  logger.warn(f"Failed to initialize remote function {function}: {e!s}")
189
188
 
189
+ if agent.spec.agent_chain:
190
+ toolkit = ChainToolkit(client, agent.spec.agent_chain)
191
+ toolkit.initialize()
192
+ functions.extend(toolkit.get_tools())
193
+
190
194
  if override_agent is None and len(functions) == 0:
191
195
  raise ValueError(
192
196
  "You must define at least one function, you can define this function in directory "
@@ -47,15 +47,15 @@ def new_client_from_settings(settings: Settings):
47
47
 
48
48
 
49
49
  def new_client():
50
+ settings = get_settings()
50
51
  context = current_context()
51
- if context.workspace:
52
+ if context.workspace and not settings.authentication.client.credentials:
52
53
  credentials = load_credentials(context.workspace)
53
54
  client_config = RunClientWithCredentials(
54
55
  credentials=credentials,
55
56
  workspace=context.workspace,
56
57
  )
57
58
  else:
58
- settings = get_settings()
59
59
  credentials = load_credentials_from_settings(settings)
60
60
  client_config = RunClientWithCredentials(
61
61
  credentials=credentials,
@@ -37,7 +37,7 @@ class ClientCredentials(Auth):
37
37
  def refresh_if_needed(self) -> Optional[Exception]:
38
38
  settings = get_settings()
39
39
  if self.credentials.client_credentials and not self.credentials.refresh_token:
40
- headers = {"Authorization": f"Basic {self.credentials.client_credentials}"}
40
+ headers = {"Authorization": f"Basic {self.credentials.client_credentials}", "Content-Type": "application/json"}
41
41
  body = {"grant_type": "client_credentials"}
42
42
  response = requests.post(f"{settings.base_url}/oauth/token", headers=headers, json=body)
43
43
  response.raise_for_status()
@@ -18,11 +18,6 @@ from pydantic_settings import (BaseSettings, PydanticBaseSettingsSource,
18
18
  global SETTINGS
19
19
  SETTINGS = None
20
20
 
21
-
22
- def get_settings():
23
- return SETTINGS
24
-
25
-
26
21
  class SettingsAgent(BaseSettings):
27
22
  agent: Union[None, CompiledGraph, BaseChatModel] = None
28
23
  chain: Union[Unset, list[Agent]] = UNSET
@@ -96,6 +91,9 @@ class Settings(BaseSettings):
96
91
  init_settings,
97
92
  )
98
93
 
94
+ def get_settings() -> Settings:
95
+ return SETTINGS
96
+
99
97
 
100
98
  def init_agent(
101
99
  client: AuthenticatedClient,
@@ -1,20 +1,21 @@
1
1
  import asyncio
2
- import urllib.parse
3
2
  import warnings
4
3
  from typing import Any, Callable
5
4
 
6
5
  import pydantic
7
- import pydantic_core
8
6
  import typing_extensions as t
7
+ from dataclasses import dataclass
9
8
  from beamlit.api.functions import get_function
10
9
  from beamlit.authentication.authentication import AuthenticatedClient
11
- from beamlit.models.function import Function
12
- from langchain_core.tools.base import BaseTool, BaseToolkit, ToolException
10
+ from beamlit.run import RunClient
11
+ from beamlit.common.settings import get_settings
12
+ from beamlit.models import Function, StoreFunctionParameter
13
+ from langchain_core.tools.base import BaseTool, ToolException
13
14
  from pydantic.json_schema import JsonSchemaValue
14
15
  from pydantic_core import core_schema as cs
15
16
 
16
17
 
17
- def create_schema_model(schema: dict[str, t.Any]) -> type[pydantic.BaseModel]:
18
+ def create_schema_model(parameters: list[StoreFunctionParameter]) -> type[pydantic.BaseModel]:
18
19
  # Create a new model class that returns our JSON schema.
19
20
  # LangChain requires a BaseModel class.
20
21
  class Schema(pydantic.BaseModel):
@@ -25,6 +26,18 @@ def create_schema_model(schema: dict[str, t.Any]) -> type[pydantic.BaseModel]:
25
26
  def __get_pydantic_json_schema__(
26
27
  cls, core_schema: cs.CoreSchema, handler: pydantic.GetJsonSchemaHandler
27
28
  ) -> JsonSchemaValue:
29
+ schema = {
30
+ "type": "object",
31
+ "properties": {},
32
+ "required": [],
33
+ }
34
+ for parameter in parameters:
35
+ schema["properties"][parameter.name] = {
36
+ "type": parameter.type_,
37
+ "description": parameter.description,
38
+ }
39
+ if parameter.required:
40
+ schema["required"].append(parameter.name)
28
41
  return schema
29
42
 
30
43
  return Schema
@@ -35,7 +48,7 @@ class RemoteTool(BaseTool):
35
48
  Remote tool
36
49
  """
37
50
 
38
- client: AuthenticatedClient
51
+ client: RunClient
39
52
  handle_tool_error: bool | str | Callable[[ToolException], str] | None = True
40
53
 
41
54
  @t.override
@@ -48,12 +61,15 @@ class RemoteTool(BaseTool):
48
61
 
49
62
  @t.override
50
63
  async def _arun(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
51
- result = self.client.call_tool(self.name, arguments=kwargs)
52
- response = result.json()
53
- content = pydantic_core.to_json(response["content"]).decode()
54
- if response["isError"]:
55
- raise ToolException(content)
56
- return content
64
+ settings = get_settings()
65
+ result = self.client.run(
66
+ "function",
67
+ self.name,
68
+ settings.environment,
69
+ "POST",
70
+ kwargs,
71
+ )
72
+ return result.text
57
73
 
58
74
  @t.override
59
75
  @property
@@ -61,7 +77,8 @@ class RemoteTool(BaseTool):
61
77
  assert self.args_schema is not None # noqa: S101
62
78
  return self.args_schema
63
79
 
64
- class RemoteToolkit(BaseToolkit):
80
+ @dataclass
81
+ class RemoteToolkit:
65
82
  """
66
83
  Remote toolkit
67
84
  """
@@ -75,27 +92,27 @@ class RemoteToolkit(BaseToolkit):
75
92
  def initialize(self) -> None:
76
93
  """Initialize the session and retrieve tools list"""
77
94
  if self._function is None:
78
- self._function = get_function(self.function, client=self.client)
95
+ self._function = get_function.sync_detailed(self.function, client=self.client).parsed
79
96
 
80
97
  @t.override
81
98
  def get_tools(self) -> list[BaseTool]:
82
- if self._tools is None:
99
+ if self._function is None:
83
100
  raise RuntimeError("Must initialize the toolkit first")
84
101
 
85
102
  if self._function.spec.kit:
86
103
  return [
87
104
  RemoteTool(
88
- client=self.client,
89
- name=func.name,
90
- description=func.description or "",
91
- args_schema=create_schema_model(func.parameters),
105
+ client=RunClient(self.client),
106
+ name=func.name,
107
+ description=func.description or "",
108
+ args_schema=create_schema_model(func.parameters),
92
109
  )
93
110
  for func in self._function.spec.kit
94
111
  ]
95
112
 
96
113
  return [
97
114
  RemoteTool(
98
- client=self.client,
115
+ client=RunClient(self.client),
99
116
  name=self._function.metadata.name,
100
117
  description=self._function.spec.description or "",
101
118
  args_schema=create_schema_model(self._function.spec.parameters),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beamlit
3
- Version: 0.0.28rc25
3
+ Version: 0.0.29rc26
4
4
  Summary: Add your description here
5
5
  Author-email: cploujoux <ch.ploujoux@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -5,8 +5,9 @@ beamlit/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6pTVHVXk5hJL79ebTk,25
5
5
  beamlit/run.py,sha256=RLwMv5f_S8lw7Wq7O6DvEcOl0nGYh769qjGl_SmR9Z0,1338
6
6
  beamlit/types.py,sha256=E1hhDh_zXfsSQ0NCt9-uw90_Mr5iIlsdfnfvxv5HarU,1005
7
7
  beamlit/agents/__init__.py,sha256=nf1iwQwGtCG6nDqyVhxfWoqR6dv6X3bvSpCeqkTCFaM,101
8
+ beamlit/agents/chain.py,sha256=HzBs3nI4xaH86I_r-M-HGGp6roXsJxMx-qXl_GrJaY0,2831
8
9
  beamlit/agents/chat.py,sha256=gVyv4FGBdQTDhdutX8l64OUNa6Fdqaw4eCfEDRH0IPQ,3558
9
- beamlit/agents/decorator.py,sha256=WiE6zfRv4Ywf1wH-rUaGjBNGjIDRdgoEH_8Yl26IM6U,9263
10
+ beamlit/agents/decorator.py,sha256=4JFITRjRLuNpaaSTFkj1ZL5B2PQRXY-a5VBoZ_2NSPw,9479
10
11
  beamlit/api/__init__.py,sha256=zTSiG_ujSjAqWPyc435YXaX9XTlpMjiJWBbV-f-YtdA,45
11
12
  beamlit/api/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
13
  beamlit/api/agents/create_agent.py,sha256=t5Pr62My2EhQlcIY71MrI73-0_q5Djr3a_Ybt9MIiQQ,3587
@@ -123,8 +124,8 @@ beamlit/api/workspaces/update_workspace.py,sha256=qa5DV2UJSUYuB_ibALb4E9ghKpT1Ha
123
124
  beamlit/api/workspaces/update_workspace_user_role.py,sha256=Yn9iuJ4tKtauzBiJyU4-wYUMS9g98X2Om8zs7UkzrY8,4917
124
125
  beamlit/authentication/__init__.py,sha256=wiXqRbc7E-ulrH_ueA9duOGFvXeo7-RvhSD1XbFogMo,1020
125
126
  beamlit/authentication/apikey.py,sha256=KNBTgdi0VBzBAAmSwU2X1QoB58vRbg8wkXb8-GTZCQo,657
126
- beamlit/authentication/authentication.py,sha256=a29-iD92T8_q8Kpx25VXEyyASlCaFsSg0s8y-SWPtns,3311
127
- beamlit/authentication/clientcredentials.py,sha256=6kbfTjwUkXUArJX8XZLe9ZzbEicQc19tSXBvsTpiXMk,3954
127
+ beamlit/authentication/authentication.py,sha256=ItVo1olbqHtHmIMz5ILT-T5m4j3AqN7XbQKeUE9-8o8,3358
128
+ beamlit/authentication/clientcredentials.py,sha256=cxZPPu--CgizwqX0pdfFQ91gJt1EFKwyy-aBB_dXX7I,3990
128
129
  beamlit/authentication/credentials.py,sha256=p_1xenabCbQuRz7BiFk7oTK4uCxAt_zoyku5o-jcKGE,5343
129
130
  beamlit/authentication/device_mode.py,sha256=tmr22gllKOZwBRub_QjF5pYa425x-nE8tQNpZ_EGR6g,3644
130
131
  beamlit/common/__init__.py,sha256=yDoMJDKj-xjTGl7U1YI59KpWxiOV65HSiUulgO8xdTA,277
@@ -132,7 +133,7 @@ beamlit/common/generate.py,sha256=LtdCju_QayRS4lZrrb_0VHqWWvTcv4Mbf-iV1TB_Qko,75
132
133
  beamlit/common/instrumentation.py,sha256=MsBDfFcMYqGDiHHj4j5hLHE4EWxZExkhmCeFS3SKzJY,3181
133
134
  beamlit/common/logger.py,sha256=VFRbaZh93n8ZGugeeYKe88IP2nI3g2JNa7XN4j8wVJE,1116
134
135
  beamlit/common/secrets.py,sha256=sid81bOe3LflkMKDHwBsBs9nIju8bp5-v9qU9gkyNMc,212
135
- beamlit/common/settings.py,sha256=Z-UBDQKp_pAusWgwmoIwK5nl_z9xfOYYEeCCuYafr0M,5821
136
+ beamlit/common/settings.py,sha256=uge6-VTioSILA9lgPpKc5V7MaSEMuHYHfCQhwdqHteE,5831
136
137
  beamlit/common/utils.py,sha256=jouz5igBvT37Xn_e94-foCHyQczVim-UzVcoIF6RWJ4,657
137
138
  beamlit/deploy/__init__.py,sha256=GS7l7Jtm2yKs7iNLKcfjYO-rAhUzggQ3xiYSf3oxLBY,91
138
139
  beamlit/deploy/deploy.py,sha256=rXpiAqlO36Ul1eadBEiwiil-6R2DkbaYHzw-qcqZ0g4,9183
@@ -147,7 +148,7 @@ beamlit/functions/github/kit/pull_request.py,sha256=wQVeRBakiqu-2ouflO8p1z7D5u07
147
148
  beamlit/functions/math/__init__.py,sha256=wie4WME8jT-WpFRrtu-lDlHW31Mg6K2cwstjkUdLF3o,43
148
149
  beamlit/functions/math/math.py,sha256=CpoLJGwuvwCPGnVC8k9GYuIyvfUYPDQHKlZg3cx-z-A,1049
149
150
  beamlit/functions/mcp/mcp.py,sha256=uGqNOwEgIKdvtVPmCf9Nf_YI_k7zioLvc6jVOpszrg4,4104
150
- beamlit/functions/remote/remote.py,sha256=W60VNSNfBcVed8HVifOjcWN20StmhDjSV06AT35STaY,3276
151
+ beamlit/functions/remote/remote.py,sha256=Cfmml8yO3tlszLN2rtwp4FpipLabNSjdRN4Q29sDweQ,3836
151
152
  beamlit/functions/search/__init__.py,sha256=5NAthQ9PBwrkNg1FpLRx4flauvv0HyWuwaVS589c1Pw,49
152
153
  beamlit/functions/search/search.py,sha256=8s9ECltq7YE17j6rTxb12uY2EQY4_eTLHmwlIMThI0w,515
153
154
  beamlit/models/__init__.py,sha256=O16oX1-oBJqB5LZEHAfu_hZZZh6_PX2LqZpVl4fNQRs,7730
@@ -253,6 +254,6 @@ beamlit/serve/app.py,sha256=OpwPjRdyHZK6J-ziPwhiRDGGa2mvCrFVcBFE6alJVOM,3071
253
254
  beamlit/serve/middlewares/__init__.py,sha256=1dVmnOmhAQWvWktqHkKSIX-YoF6fmMU8xkUQuhg_rJU,148
254
255
  beamlit/serve/middlewares/accesslog.py,sha256=Mu4T4_9OvHybjA0ApzZFpgi2C8f3X1NbUk-76v634XM,631
255
256
  beamlit/serve/middlewares/processtime.py,sha256=lDAaIasZ4bwvN-HKHvZpaD9r-yrkVNZYx4abvbjbrCg,411
256
- beamlit-0.0.28rc25.dist-info/METADATA,sha256=JLFUlrvUKeIJWwQT1lX7St9EBkt7-xRZwQu_UGKUotg,2405
257
- beamlit-0.0.28rc25.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
258
- beamlit-0.0.28rc25.dist-info/RECORD,,
257
+ beamlit-0.0.29rc26.dist-info/METADATA,sha256=q6aJeKGzSLnVJtuVjAEFGM7wXesSc4-Vre2neU3FPts,2405
258
+ beamlit-0.0.29rc26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
259
+ beamlit-0.0.29rc26.dist-info/RECORD,,