blaxel 0.2.2rc79__py3-none-any.whl → 0.2.4__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.
- blaxel/core/client/models/job_spec.py +24 -0
- blaxel/core/client/models/trigger.py +1 -1
- blaxel/core/client/models/trigger_configuration.py +46 -3
- blaxel/core/sandbox/client/models/success_response.py +8 -5
- blaxel/core/sandbox/preview.py +29 -8
- blaxel/core/sandbox/sandbox.py +4 -2
- blaxel/core/sandbox/session.py +17 -2
- blaxel/core/sandbox/types.py +20 -0
- blaxel/core/tools/__init__.py +66 -77
- blaxel/crewai/tools.py +1 -1
- blaxel/livekit/tools.py +13 -9
- blaxel/openai/tools.py +3 -3
- {blaxel-0.2.2rc79.dist-info → blaxel-0.2.4.dist-info}/METADATA +3 -3
- {blaxel-0.2.2rc79.dist-info → blaxel-0.2.4.dist-info}/RECORD +16 -16
- {blaxel-0.2.2rc79.dist-info → blaxel-0.2.4.dist-info}/WHEEL +0 -0
- {blaxel-0.2.2rc79.dist-info → blaxel-0.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
|
|
11
11
|
from ..models.model_private_cluster import ModelPrivateCluster
|
12
12
|
from ..models.revision_configuration import RevisionConfiguration
|
13
13
|
from ..models.runtime import Runtime
|
14
|
+
from ..models.trigger import Trigger
|
14
15
|
|
15
16
|
|
16
17
|
T = TypeVar("T", bound="JobSpec")
|
@@ -30,6 +31,7 @@ class JobSpec:
|
|
30
31
|
revision (Union[Unset, RevisionConfiguration]): Revision configuration
|
31
32
|
runtime (Union[Unset, Runtime]): Set of configurations for a deployment
|
32
33
|
sandbox (Union[Unset, bool]): Sandbox mode
|
34
|
+
triggers (Union[Unset, list['Trigger']]): Triggers to use your agent
|
33
35
|
"""
|
34
36
|
|
35
37
|
configurations: Union[Unset, "CoreSpecConfigurations"] = UNSET
|
@@ -41,6 +43,7 @@ class JobSpec:
|
|
41
43
|
revision: Union[Unset, "RevisionConfiguration"] = UNSET
|
42
44
|
runtime: Union[Unset, "Runtime"] = UNSET
|
43
45
|
sandbox: Union[Unset, bool] = UNSET
|
46
|
+
triggers: Union[Unset, list["Trigger"]] = UNSET
|
44
47
|
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
45
48
|
|
46
49
|
def to_dict(self) -> dict[str, Any]:
|
@@ -98,6 +101,16 @@ class JobSpec:
|
|
98
101
|
|
99
102
|
sandbox = self.sandbox
|
100
103
|
|
104
|
+
triggers: Union[Unset, list[dict[str, Any]]] = UNSET
|
105
|
+
if not isinstance(self.triggers, Unset):
|
106
|
+
triggers = []
|
107
|
+
for componentsschemas_triggers_item_data in self.triggers:
|
108
|
+
if type(componentsschemas_triggers_item_data) is dict:
|
109
|
+
componentsschemas_triggers_item = componentsschemas_triggers_item_data
|
110
|
+
else:
|
111
|
+
componentsschemas_triggers_item = componentsschemas_triggers_item_data.to_dict()
|
112
|
+
triggers.append(componentsschemas_triggers_item)
|
113
|
+
|
101
114
|
field_dict: dict[str, Any] = {}
|
102
115
|
field_dict.update(self.additional_properties)
|
103
116
|
field_dict.update({})
|
@@ -119,6 +132,8 @@ class JobSpec:
|
|
119
132
|
field_dict["runtime"] = runtime
|
120
133
|
if sandbox is not UNSET:
|
121
134
|
field_dict["sandbox"] = sandbox
|
135
|
+
if triggers is not UNSET:
|
136
|
+
field_dict["triggers"] = triggers
|
122
137
|
|
123
138
|
return field_dict
|
124
139
|
|
@@ -129,6 +144,7 @@ class JobSpec:
|
|
129
144
|
from ..models.model_private_cluster import ModelPrivateCluster
|
130
145
|
from ..models.revision_configuration import RevisionConfiguration
|
131
146
|
from ..models.runtime import Runtime
|
147
|
+
from ..models.trigger import Trigger
|
132
148
|
|
133
149
|
if not src_dict:
|
134
150
|
return None
|
@@ -176,6 +192,13 @@ class JobSpec:
|
|
176
192
|
|
177
193
|
sandbox = d.pop("sandbox", UNSET)
|
178
194
|
|
195
|
+
triggers = []
|
196
|
+
_triggers = d.pop("triggers", UNSET)
|
197
|
+
for componentsschemas_triggers_item_data in _triggers or []:
|
198
|
+
componentsschemas_triggers_item = Trigger.from_dict(componentsschemas_triggers_item_data)
|
199
|
+
|
200
|
+
triggers.append(componentsschemas_triggers_item)
|
201
|
+
|
179
202
|
job_spec = cls(
|
180
203
|
configurations=configurations,
|
181
204
|
enabled=enabled,
|
@@ -186,6 +209,7 @@ class JobSpec:
|
|
186
209
|
revision=revision,
|
187
210
|
runtime=runtime,
|
188
211
|
sandbox=sandbox,
|
212
|
+
triggers=triggers,
|
189
213
|
)
|
190
214
|
|
191
215
|
job_spec.additional_properties = d
|
@@ -17,7 +17,7 @@ class Trigger:
|
|
17
17
|
"""Trigger configuration
|
18
18
|
|
19
19
|
Attributes:
|
20
|
-
configuration (Union[Unset, TriggerConfiguration]):
|
20
|
+
configuration (Union[Unset, TriggerConfiguration]): Trigger configuration
|
21
21
|
id (Union[Unset, str]): The id of the trigger
|
22
22
|
type_ (Union[Unset, str]): The type of trigger, can be http or http-async
|
23
23
|
"""
|
@@ -1,20 +1,50 @@
|
|
1
|
-
from typing import Any, TypeVar
|
1
|
+
from typing import Any, TypeVar, Union
|
2
2
|
|
3
3
|
from attrs import define as _attrs_define
|
4
4
|
from attrs import field as _attrs_field
|
5
5
|
|
6
|
+
from ..types import UNSET, Unset
|
7
|
+
|
6
8
|
T = TypeVar("T", bound="TriggerConfiguration")
|
7
9
|
|
8
10
|
|
9
11
|
@_attrs_define
|
10
12
|
class TriggerConfiguration:
|
11
|
-
"""
|
13
|
+
"""Trigger configuration
|
14
|
+
|
15
|
+
Attributes:
|
16
|
+
authentication_type (Union[Unset, str]): The authentication type of the trigger
|
17
|
+
path (Union[Unset, str]): The path of the trigger
|
18
|
+
retry (Union[Unset, int]): The retry of the trigger
|
19
|
+
schedule (Union[Unset, str]): The schedule of the trigger, cron expression * * * * *
|
20
|
+
"""
|
12
21
|
|
22
|
+
authentication_type: Union[Unset, str] = UNSET
|
23
|
+
path: Union[Unset, str] = UNSET
|
24
|
+
retry: Union[Unset, int] = UNSET
|
25
|
+
schedule: Union[Unset, str] = UNSET
|
13
26
|
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
14
27
|
|
15
28
|
def to_dict(self) -> dict[str, Any]:
|
29
|
+
authentication_type = self.authentication_type
|
30
|
+
|
31
|
+
path = self.path
|
32
|
+
|
33
|
+
retry = self.retry
|
34
|
+
|
35
|
+
schedule = self.schedule
|
36
|
+
|
16
37
|
field_dict: dict[str, Any] = {}
|
17
38
|
field_dict.update(self.additional_properties)
|
39
|
+
field_dict.update({})
|
40
|
+
if authentication_type is not UNSET:
|
41
|
+
field_dict["authenticationType"] = authentication_type
|
42
|
+
if path is not UNSET:
|
43
|
+
field_dict["path"] = path
|
44
|
+
if retry is not UNSET:
|
45
|
+
field_dict["retry"] = retry
|
46
|
+
if schedule is not UNSET:
|
47
|
+
field_dict["schedule"] = schedule
|
18
48
|
|
19
49
|
return field_dict
|
20
50
|
|
@@ -23,7 +53,20 @@ class TriggerConfiguration:
|
|
23
53
|
if not src_dict:
|
24
54
|
return None
|
25
55
|
d = src_dict.copy()
|
26
|
-
|
56
|
+
authentication_type = d.pop("authenticationType", UNSET)
|
57
|
+
|
58
|
+
path = d.pop("path", UNSET)
|
59
|
+
|
60
|
+
retry = d.pop("retry", UNSET)
|
61
|
+
|
62
|
+
schedule = d.pop("schedule", UNSET)
|
63
|
+
|
64
|
+
trigger_configuration = cls(
|
65
|
+
authentication_type=authentication_type,
|
66
|
+
path=path,
|
67
|
+
retry=retry,
|
68
|
+
schedule=schedule,
|
69
|
+
)
|
27
70
|
|
28
71
|
trigger_configuration.additional_properties = d
|
29
72
|
return trigger_configuration
|
@@ -1,8 +1,10 @@
|
|
1
|
-
from typing import Any, TypeVar
|
1
|
+
from typing import Any, TypeVar, Union
|
2
2
|
|
3
3
|
from attrs import define as _attrs_define
|
4
4
|
from attrs import field as _attrs_field
|
5
5
|
|
6
|
+
from ..types import UNSET, Unset
|
7
|
+
|
6
8
|
T = TypeVar("T", bound="SuccessResponse")
|
7
9
|
|
8
10
|
|
@@ -11,11 +13,11 @@ class SuccessResponse:
|
|
11
13
|
"""
|
12
14
|
Attributes:
|
13
15
|
message (str): Example: File created successfully.
|
14
|
-
path (str): Example: /path/to/file.
|
16
|
+
path (Union[Unset, str]): Example: /path/to/file.
|
15
17
|
"""
|
16
18
|
|
17
19
|
message: str
|
18
|
-
path: str
|
20
|
+
path: Union[Unset, str] = UNSET
|
19
21
|
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
20
22
|
|
21
23
|
def to_dict(self) -> dict[str, Any]:
|
@@ -28,9 +30,10 @@ class SuccessResponse:
|
|
28
30
|
field_dict.update(
|
29
31
|
{
|
30
32
|
"message": message,
|
31
|
-
"path": path,
|
32
33
|
}
|
33
34
|
)
|
35
|
+
if path is not UNSET:
|
36
|
+
field_dict["path"] = path
|
34
37
|
|
35
38
|
return field_dict
|
36
39
|
|
@@ -41,7 +44,7 @@ class SuccessResponse:
|
|
41
44
|
d = src_dict.copy()
|
42
45
|
message = d.pop("message")
|
43
46
|
|
44
|
-
path = d.pop("path")
|
47
|
+
path = d.pop("path", UNSET)
|
45
48
|
|
46
49
|
success_response = cls(
|
47
50
|
message=message,
|
blaxel/core/sandbox/preview.py
CHANGED
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
|
2
2
|
from datetime import datetime
|
3
3
|
from typing import Any, Dict, List, Optional, Union
|
4
4
|
|
5
|
+
from ..client import errors
|
5
6
|
from ..client.api.compute.create_sandbox_preview import (
|
6
7
|
asyncio as create_sandbox_preview,
|
7
8
|
)
|
@@ -47,18 +48,21 @@ class SandboxPreviewToken:
|
|
47
48
|
class SandboxPreviewTokens:
|
48
49
|
"""Manages preview tokens for a sandbox preview."""
|
49
50
|
|
50
|
-
def __init__(self, preview: Preview
|
51
|
+
def __init__(self, preview: Preview):
|
51
52
|
self.preview = preview
|
52
|
-
self.sandbox_name = sandbox_name
|
53
53
|
|
54
54
|
@property
|
55
55
|
def preview_name(self) -> str:
|
56
56
|
return self.preview.metadata.name if self.preview.metadata else ""
|
57
57
|
|
58
|
+
@property
|
59
|
+
def resource_name(self) -> str:
|
60
|
+
return self.preview.metadata.resource_name if self.preview.metadata else ""
|
61
|
+
|
58
62
|
async def create(self, expires_at: datetime) -> SandboxPreviewToken:
|
59
63
|
"""Create a new preview token."""
|
60
64
|
response: PreviewToken = await create_sandbox_preview_token(
|
61
|
-
self.
|
65
|
+
self.resource_name,
|
62
66
|
self.preview_name,
|
63
67
|
body=PreviewToken(
|
64
68
|
spec=PreviewTokenSpec(
|
@@ -72,7 +76,7 @@ class SandboxPreviewTokens:
|
|
72
76
|
async def list(self) -> List[SandboxPreviewToken]:
|
73
77
|
"""List all preview tokens."""
|
74
78
|
response: List[PreviewToken] = await list_sandbox_preview_tokens(
|
75
|
-
self.
|
79
|
+
self.resource_name,
|
76
80
|
self.preview_name,
|
77
81
|
client=client,
|
78
82
|
)
|
@@ -81,7 +85,7 @@ class SandboxPreviewTokens:
|
|
81
85
|
async def delete(self, token_name: str) -> dict:
|
82
86
|
"""Delete a preview token."""
|
83
87
|
response: PreviewToken = await delete_sandbox_preview_token(
|
84
|
-
self.
|
88
|
+
self.resource_name,
|
85
89
|
self.preview_name,
|
86
90
|
token_name,
|
87
91
|
client=client,
|
@@ -92,10 +96,9 @@ class SandboxPreviewTokens:
|
|
92
96
|
class SandboxPreview:
|
93
97
|
"""Represents a sandbox preview with its metadata and tokens."""
|
94
98
|
|
95
|
-
def __init__(self, preview: Preview
|
99
|
+
def __init__(self, preview: Preview):
|
96
100
|
self.preview = preview
|
97
|
-
self.
|
98
|
-
self.tokens = SandboxPreviewTokens(preview, sandbox_name)
|
101
|
+
self.tokens = SandboxPreviewTokens(preview)
|
99
102
|
|
100
103
|
@property
|
101
104
|
def name(self) -> str:
|
@@ -140,6 +143,24 @@ class SandboxPreviews:
|
|
140
143
|
)
|
141
144
|
return SandboxPreview(response)
|
142
145
|
|
146
|
+
async def create_if_not_exists(self, preview: Union[Preview, Dict[str, Any]]) -> SandboxPreview:
|
147
|
+
"""Create a preview if it doesn't exist, otherwise return the existing one."""
|
148
|
+
if isinstance(preview, dict):
|
149
|
+
preview = Preview.from_dict(preview)
|
150
|
+
|
151
|
+
preview_name = preview.metadata.name if preview.metadata else ""
|
152
|
+
|
153
|
+
try:
|
154
|
+
# Try to get existing preview
|
155
|
+
existing_preview = await self.get(preview_name)
|
156
|
+
return existing_preview
|
157
|
+
except errors.UnexpectedStatus as e:
|
158
|
+
# If 404, create the preview
|
159
|
+
if e.status_code == 404:
|
160
|
+
return await self.create(preview)
|
161
|
+
# For any other error, re-raise
|
162
|
+
raise e
|
163
|
+
|
143
164
|
async def get(self, preview_name: str) -> SandboxPreview:
|
144
165
|
"""Get a specific preview by name."""
|
145
166
|
response: Preview = await get_sandbox_preview(
|
blaxel/core/sandbox/sandbox.py
CHANGED
@@ -77,7 +77,7 @@ class SandboxInstance:
|
|
77
77
|
default_image = "blaxel/prod-base:latest"
|
78
78
|
default_memory = 4096
|
79
79
|
|
80
|
-
# Handle SandboxCreateConfiguration or simple dict with name/image/memory/ports keys
|
80
|
+
# Handle SandboxCreateConfiguration or simple dict with name/image/memory/ports/envs keys
|
81
81
|
if (
|
82
82
|
sandbox is None
|
83
83
|
or isinstance(sandbox, SandboxCreateConfiguration | dict)
|
@@ -89,6 +89,7 @@ class SandboxInstance:
|
|
89
89
|
or "image" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
90
90
|
or "memory" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
91
91
|
or "ports" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
92
|
+
or "envs" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
92
93
|
)
|
93
94
|
)
|
94
95
|
):
|
@@ -102,12 +103,13 @@ class SandboxInstance:
|
|
102
103
|
image = sandbox.image or default_image
|
103
104
|
memory = sandbox.memory or default_memory
|
104
105
|
ports = sandbox._normalize_ports() or UNSET
|
106
|
+
envs = sandbox._normalize_envs() or UNSET
|
105
107
|
|
106
108
|
# Create full Sandbox object
|
107
109
|
sandbox = Sandbox(
|
108
110
|
metadata=Metadata(name=name),
|
109
111
|
spec=SandboxSpec(
|
110
|
-
runtime=Runtime(image=image, memory=memory, ports=ports, generation="mk3")
|
112
|
+
runtime=Runtime(image=image, memory=memory, ports=ports, envs=envs, generation="mk3")
|
111
113
|
),
|
112
114
|
)
|
113
115
|
else:
|
blaxel/core/sandbox/session.py
CHANGED
@@ -46,7 +46,7 @@ class SandboxSessions:
|
|
46
46
|
self.sandbox_name, client=client, body=preview_body
|
47
47
|
)
|
48
48
|
|
49
|
-
preview = SandboxPreview(preview_response
|
49
|
+
preview = SandboxPreview(preview_response)
|
50
50
|
token_obj = await preview.tokens.create(expires_at)
|
51
51
|
|
52
52
|
return SessionWithToken(
|
@@ -71,8 +71,23 @@ class SandboxSessions:
|
|
71
71
|
threshold = now + timedelta(seconds=delta_seconds)
|
72
72
|
|
73
73
|
if all_sessions:
|
74
|
+
all_sessions.sort(
|
75
|
+
key=lambda s: datetime.fromisoformat(s.expires_at)
|
76
|
+
if isinstance(s.expires_at, str)
|
77
|
+
else s.expires_at
|
78
|
+
)
|
74
79
|
session_data = all_sessions[0]
|
75
|
-
|
80
|
+
expires_at = datetime.fromisoformat(session_data.expires_at)
|
81
|
+
|
82
|
+
# Make both datetimes timezone-aware or timezone-naive for comparison
|
83
|
+
if expires_at.tzinfo is not None and threshold.tzinfo is None:
|
84
|
+
# expires_at is timezone-aware, make threshold timezone-aware too
|
85
|
+
threshold = threshold.replace(tzinfo=expires_at.tzinfo)
|
86
|
+
elif expires_at.tzinfo is None and threshold.tzinfo is not None:
|
87
|
+
# threshold is timezone-aware, make expires_at timezone-aware too
|
88
|
+
expires_at = expires_at.replace(tzinfo=threshold.tzinfo)
|
89
|
+
|
90
|
+
if expires_at < threshold:
|
76
91
|
await self.delete(session_data.name)
|
77
92
|
session_data = await self.create(options)
|
78
93
|
else:
|
blaxel/core/sandbox/types.py
CHANGED
@@ -113,11 +113,13 @@ class SandboxCreateConfiguration:
|
|
113
113
|
image: Optional[str] = None,
|
114
114
|
memory: Optional[int] = None,
|
115
115
|
ports: Optional[Union[List[Port], List[Dict[str, Any]]]] = None,
|
116
|
+
envs: Optional[List[Dict[str, str]]] = None,
|
116
117
|
):
|
117
118
|
self.name = name
|
118
119
|
self.image = image
|
119
120
|
self.memory = memory
|
120
121
|
self.ports = ports
|
122
|
+
self.envs = envs
|
121
123
|
|
122
124
|
@classmethod
|
123
125
|
def from_dict(cls, data: Dict[str, Any]) -> "SandboxCreateConfiguration":
|
@@ -126,6 +128,7 @@ class SandboxCreateConfiguration:
|
|
126
128
|
image=data.get("image"),
|
127
129
|
memory=data.get("memory"),
|
128
130
|
ports=data.get("ports"),
|
131
|
+
envs=data.get("envs"),
|
129
132
|
)
|
130
133
|
|
131
134
|
def _normalize_ports(self) -> Optional[List[Port]]:
|
@@ -150,3 +153,20 @@ class SandboxCreateConfiguration:
|
|
150
153
|
raise ValueError(f"Invalid port type: {type(port)}. Expected Port object or dict.")
|
151
154
|
|
152
155
|
return port_objects
|
156
|
+
|
157
|
+
def _normalize_envs(self) -> Optional[List[Dict[str, str]]]:
|
158
|
+
"""Convert envs to list of dicts with name and value keys."""
|
159
|
+
if not self.envs:
|
160
|
+
return None
|
161
|
+
|
162
|
+
env_objects = []
|
163
|
+
for env in self.envs:
|
164
|
+
if isinstance(env, dict):
|
165
|
+
# Validate that the dict has the required keys
|
166
|
+
if "name" not in env or "value" not in env:
|
167
|
+
raise ValueError(f"Environment variable dict must have 'name' and 'value' keys: {env}")
|
168
|
+
env_objects.append({"name": env["name"], "value": env["value"]})
|
169
|
+
else:
|
170
|
+
raise ValueError(f"Invalid env type: {type(env)}. Expected dict with 'name' and 'value' keys.")
|
171
|
+
|
172
|
+
return env_objects
|
blaxel/core/tools/__init__.py
CHANGED
@@ -22,12 +22,15 @@ if os.getenv("BL_SERVER_PORT"):
|
|
22
22
|
|
23
23
|
|
24
24
|
class PersistentWebSocket:
|
25
|
-
def __init__(
|
26
|
-
self, url: str, name: str, timeout: int = DEFAULT_TIMEOUT, timeout_enabled: bool = True
|
27
|
-
):
|
28
|
-
self.url = url
|
25
|
+
def __init__(self, name: str, timeout: int = DEFAULT_TIMEOUT, timeout_enabled: bool = True):
|
29
26
|
self.name = name
|
30
27
|
self.timeout = timeout
|
28
|
+
self.type = "function"
|
29
|
+
self.pluralType = "functions"
|
30
|
+
if name.startswith("sandbox/") or name.startswith("sandboxes/"):
|
31
|
+
self.name = name.split("/")[1]
|
32
|
+
self.type = "sandbox"
|
33
|
+
self.pluralType = "sandboxes"
|
31
34
|
self.session_exit_stack = AsyncExitStack()
|
32
35
|
self.client_exit_stack = AsyncExitStack()
|
33
36
|
self.session: ClientSession = None
|
@@ -37,6 +40,42 @@ class PersistentWebSocket:
|
|
37
40
|
self.timeout_enabled = False
|
38
41
|
else:
|
39
42
|
self.timeout_enabled = timeout_enabled
|
43
|
+
self.use_fallback_url = False
|
44
|
+
|
45
|
+
@property
|
46
|
+
def _internal_url(self):
|
47
|
+
"""Get the internal URL for the agent using a hash of workspace and agent name."""
|
48
|
+
hash = get_global_unique_hash(settings.workspace, self.type, self.name)
|
49
|
+
return f"{settings.run_internal_protocol}://bl-{settings.env}-{hash}.{settings.run_internal_hostname}"
|
50
|
+
|
51
|
+
@property
|
52
|
+
def _forced_url(self):
|
53
|
+
"""Get the forced URL from environment variables if set."""
|
54
|
+
return get_forced_url(self.type, self.name)
|
55
|
+
|
56
|
+
@property
|
57
|
+
def _external_url(self):
|
58
|
+
return f"{settings.run_url}/{settings.workspace}/{self.pluralType}/{self.name}"
|
59
|
+
|
60
|
+
@property
|
61
|
+
def _fallback_url(self):
|
62
|
+
if self._external_url != self._url:
|
63
|
+
return self._external_url
|
64
|
+
return None
|
65
|
+
|
66
|
+
@property
|
67
|
+
def _url(self):
|
68
|
+
if self.use_fallback_url:
|
69
|
+
return self._fallback_url
|
70
|
+
logger.debug(f"Getting URL for {self.name}")
|
71
|
+
if self._forced_url:
|
72
|
+
logger.debug(f"Forced URL found for {self.name}: {self._forced_url}")
|
73
|
+
return self._forced_url
|
74
|
+
if settings.run_internal_hostname:
|
75
|
+
logger.debug(f"Internal hostname found for {self.name}: {self._internal_url}")
|
76
|
+
return self._internal_url
|
77
|
+
logger.debug(f"No URL found for {self.name}, using external URL")
|
78
|
+
return self._external_url
|
40
79
|
|
41
80
|
def with_metas(self, metas: dict[str, Any]):
|
42
81
|
self.metas = metas
|
@@ -44,7 +83,7 @@ class PersistentWebSocket:
|
|
44
83
|
|
45
84
|
async def call_tool(self, tool_name: str, arguments: dict[str, Any]) -> CallToolResult:
|
46
85
|
try:
|
47
|
-
await self.
|
86
|
+
await self.initialize()
|
48
87
|
if self.timeout_enabled:
|
49
88
|
self._remove_timer()
|
50
89
|
logger.debug(f"Calling tool {tool_name} with arguments {arguments}")
|
@@ -70,7 +109,7 @@ class PersistentWebSocket:
|
|
70
109
|
|
71
110
|
async def list_tools(self):
|
72
111
|
logger.debug(f"Listing tools for {self.name}")
|
73
|
-
await self.
|
112
|
+
await self.initialize()
|
74
113
|
logger.debug(f"Initialized websocket for {self.name}")
|
75
114
|
if self.timeout_enabled:
|
76
115
|
self._remove_timer()
|
@@ -87,17 +126,23 @@ class PersistentWebSocket:
|
|
87
126
|
def get_tools(self):
|
88
127
|
return self.tools_cache
|
89
128
|
|
90
|
-
async def
|
129
|
+
async def initialize(self, fallback: bool = False):
|
91
130
|
if not self.session:
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
131
|
+
try:
|
132
|
+
logger.debug(f"Initializing websocket client for {self._url}")
|
133
|
+
read, write = await self.client_exit_stack.enter_async_context(
|
134
|
+
websocket_client(self._url, settings.headers)
|
135
|
+
)
|
136
|
+
self.session = cast(
|
137
|
+
ClientSession,
|
138
|
+
await self.session_exit_stack.enter_async_context(ClientSession(read, write)),
|
139
|
+
)
|
140
|
+
await self.session.initialize()
|
141
|
+
except Exception as e:
|
142
|
+
if not fallback:
|
143
|
+
self.use_fallback_url = True
|
144
|
+
return await self.initialize(fallback=True)
|
145
|
+
raise e
|
101
146
|
|
102
147
|
def _reset_timer(self):
|
103
148
|
self._remove_timer()
|
@@ -113,7 +158,7 @@ class PersistentWebSocket:
|
|
113
158
|
self.session = None
|
114
159
|
|
115
160
|
async def _close(self):
|
116
|
-
logger.debug(f"Closing websocket client {self.
|
161
|
+
logger.debug(f"Closing websocket client {self._url}")
|
117
162
|
if self.session:
|
118
163
|
self.session = None
|
119
164
|
try:
|
@@ -129,8 +174,6 @@ class PersistentWebSocket:
|
|
129
174
|
|
130
175
|
def convert_mcp_tool_to_blaxel_tool(
|
131
176
|
websocket_client: PersistentWebSocket,
|
132
|
-
name: str,
|
133
|
-
url: str,
|
134
177
|
tool: MCPTool,
|
135
178
|
) -> Tool:
|
136
179
|
"""Convert an MCP tool to a blaxel tool.
|
@@ -193,34 +236,6 @@ class BlTools:
|
|
193
236
|
self.timeout = timeout
|
194
237
|
self.timeout_enabled = timeout_enabled
|
195
238
|
|
196
|
-
def _internal_url(self, name: str):
|
197
|
-
"""Get the internal URL for the agent using a hash of workspace and agent name."""
|
198
|
-
hash = get_global_unique_hash(settings.workspace, "function", name)
|
199
|
-
return f"{settings.run_internal_protocol}://bl-{settings.env}-{hash}.{settings.run_internal_hostname}"
|
200
|
-
|
201
|
-
def _forced_url(self, name: str):
|
202
|
-
"""Get the forced URL from environment variables if set."""
|
203
|
-
return get_forced_url("function", name)
|
204
|
-
|
205
|
-
def _external_url(self, name: str):
|
206
|
-
return f"{settings.run_url}/{settings.workspace}/functions/{name}"
|
207
|
-
|
208
|
-
def _fallback_url(self, name: str):
|
209
|
-
if self._external_url(name) != self._url(name):
|
210
|
-
return self._external_url(name)
|
211
|
-
return None
|
212
|
-
|
213
|
-
def _url(self, name: str):
|
214
|
-
logger.debug(f"Getting URL for {name}")
|
215
|
-
if self._forced_url(name):
|
216
|
-
logger.debug(f"Forced URL found for {name}: {self._forced_url(name)}")
|
217
|
-
return self._forced_url(name)
|
218
|
-
if settings.run_internal_hostname:
|
219
|
-
logger.debug(f"Internal hostname found for {name}: {self._internal_url(name)}")
|
220
|
-
return self._internal_url(name)
|
221
|
-
logger.debug(f"No URL found for {name}, using external URL")
|
222
|
-
return self._external_url(name)
|
223
|
-
|
224
239
|
def get_tools(self) -> list[Tool]:
|
225
240
|
"""Get a list of all tools from all connected servers."""
|
226
241
|
all_tools: list[Tool] = []
|
@@ -228,47 +243,21 @@ class BlTools:
|
|
228
243
|
toolPersistances.get(name).with_metas(self.metas)
|
229
244
|
websocket = toolPersistances.get(name)
|
230
245
|
tools = websocket.get_tools()
|
231
|
-
converted_tools = [
|
232
|
-
convert_mcp_tool_to_blaxel_tool(websocket, name, self._url(name), tool)
|
233
|
-
for tool in tools
|
234
|
-
]
|
246
|
+
converted_tools = [convert_mcp_tool_to_blaxel_tool(websocket, tool) for tool in tools]
|
235
247
|
all_tools.extend(converted_tools)
|
236
248
|
return all_tools
|
237
249
|
|
238
250
|
async def connect(self, name: str):
|
239
251
|
# Create and store the connection
|
240
|
-
|
241
|
-
url = self._url(name)
|
242
|
-
await self.connect_with_url(name, url)
|
243
|
-
except Exception as e:
|
244
|
-
if not self._fallback_url(name):
|
245
|
-
raise e
|
246
|
-
logger.warning(f"Error connecting to {name}: {e}\n{traceback.format_exc()}")
|
247
|
-
url = self._fallback_url(name)
|
248
|
-
try:
|
249
|
-
await self.connect_with_url(name, url)
|
250
|
-
except Exception as e:
|
251
|
-
logger.error(
|
252
|
-
f"Error connecting to {name} with fallback URL: {e}\n{traceback.format_exc()}"
|
253
|
-
)
|
254
|
-
raise e
|
255
|
-
|
256
|
-
async def connect_with_url(self, name: str, url: str) -> None:
|
257
|
-
"""Initialize a session and load tools from it.
|
258
|
-
|
259
|
-
Args:
|
260
|
-
name: Name to identify this server connection
|
261
|
-
url: The URL to connect to
|
262
|
-
"""
|
263
|
-
logger.debug(f"Initializing session and loading tools from {url}")
|
252
|
+
logger.debug("Initializing session and loading tools")
|
264
253
|
|
265
254
|
if not toolPersistances.get(name):
|
266
255
|
logger.debug(f"Creating new persistent websocket for {name}")
|
267
256
|
toolPersistances[name] = PersistentWebSocket(
|
268
|
-
|
257
|
+
name, timeout=self.timeout, timeout_enabled=self.timeout_enabled
|
269
258
|
)
|
270
259
|
await toolPersistances[name].list_tools()
|
271
|
-
logger.debug(f"Loaded {len(toolPersistances[name].get_tools())} tools
|
260
|
+
logger.debug(f"Loaded {len(toolPersistances[name].get_tools())} tools")
|
272
261
|
return toolPersistances[name].with_metas(self.metas)
|
273
262
|
|
274
263
|
async def initialize(self) -> "BlTools":
|
blaxel/crewai/tools.py
CHANGED
@@ -19,8 +19,8 @@ class CrewAITool(BaseTool):
|
|
19
19
|
def _run(self, *args, **kwargs):
|
20
20
|
return self._tool.sync_coroutine(**kwargs)
|
21
21
|
|
22
|
+
|
22
23
|
async def bl_tools(tools_names: list[str], **kwargs) -> list[BaseTool]:
|
23
24
|
tools = bl_tools_core(tools_names, **kwargs)
|
24
25
|
await tools.initialize()
|
25
26
|
return [CrewAITool(tool) for tool in tools.get_tools()]
|
26
|
-
return [CrewAITool(tool) for tool in tools.get_tools()]
|
blaxel/livekit/tools.py
CHANGED
@@ -8,23 +8,27 @@ def livekit_coroutine(tool: Tool):
|
|
8
8
|
async def livekit_coroutine_wrapper(raw_arguments: dict[str, object]):
|
9
9
|
result = await tool.coroutine(**raw_arguments)
|
10
10
|
return result.model_dump_json()
|
11
|
+
|
11
12
|
return livekit_coroutine_wrapper
|
12
13
|
|
14
|
+
|
13
15
|
def get_livekit_tools(tools: list[Tool]) -> list[llm.FunctionTool]:
|
14
16
|
livekit_tools = []
|
15
17
|
for tool in tools:
|
16
|
-
livekit_tools.append(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
livekit_tools.append(
|
19
|
+
function_tool(
|
20
|
+
livekit_coroutine(tool),
|
21
|
+
raw_schema={
|
22
|
+
"name": tool.name,
|
23
|
+
"description": tool.description,
|
24
|
+
"parameters": tool.input_schema,
|
25
|
+
},
|
26
|
+
)
|
27
|
+
)
|
24
28
|
return livekit_tools
|
25
29
|
|
30
|
+
|
26
31
|
async def bl_tools(tools_names: list[str], **kwargs) -> list[llm.FunctionTool]:
|
27
32
|
tools = bl_tools_core(tools_names, **kwargs)
|
28
33
|
await tools.initialize()
|
29
34
|
return get_livekit_tools(tools.get_tools())
|
30
|
-
return get_livekit_tools(tools.get_tools())
|
blaxel/openai/tools.py
CHANGED
@@ -9,8 +9,8 @@ from blaxel.core.tools.types import Tool
|
|
9
9
|
|
10
10
|
def get_openai_tool(tool: Tool) -> FunctionTool:
|
11
11
|
async def openai_coroutine(
|
12
|
-
|
13
|
-
|
12
|
+
_: RunContextWrapper,
|
13
|
+
arguments: dict[str, Any],
|
14
14
|
) -> Any:
|
15
15
|
result = await tool.coroutine(**json.loads(arguments))
|
16
16
|
return result
|
@@ -22,8 +22,8 @@ def get_openai_tool(tool: Tool) -> FunctionTool:
|
|
22
22
|
on_invoke_tool=openai_coroutine,
|
23
23
|
)
|
24
24
|
|
25
|
+
|
25
26
|
async def bl_tools(tools_names: list[str], **kwargs) -> list[FunctionTool]:
|
26
27
|
tools = bl_tools_core(tools_names, **kwargs)
|
27
28
|
await tools.initialize()
|
28
29
|
return [get_openai_tool(tool) for tool in tools.get_tools()]
|
29
|
-
return [get_openai_tool(tool) for tool in tools.get_tools()]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: blaxel
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.4
|
4
4
|
Summary: Blaxel - AI development platform SDK
|
5
5
|
Project-URL: Homepage, https://blaxel.ai
|
6
6
|
Project-URL: Documentation, https://docs.blaxel.ai
|
@@ -42,7 +42,7 @@ Requires-Dist: llama-index-llms-google-genai>=0.1.13; extra == 'all'
|
|
42
42
|
Requires-Dist: llama-index-llms-groq>=0.3.1; extra == 'all'
|
43
43
|
Requires-Dist: llama-index-llms-mistralai>=0.4.0; extra == 'all'
|
44
44
|
Requires-Dist: llama-index-llms-openai>=0.3.42; extra == 'all'
|
45
|
-
Requires-Dist: llama-index>=0.12.
|
45
|
+
Requires-Dist: llama-index>=0.12.46; extra == 'all'
|
46
46
|
Requires-Dist: openai-agents>=0.0.19; extra == 'all'
|
47
47
|
Requires-Dist: opentelemetry-exporter-otlp>=1.28.0; extra == 'all'
|
48
48
|
Requires-Dist: opentelemetry-instrumentation-anthropic==0.40.6; extra == 'all'
|
@@ -92,7 +92,7 @@ Requires-Dist: llama-index-llms-google-genai>=0.1.13; extra == 'llamaindex'
|
|
92
92
|
Requires-Dist: llama-index-llms-groq>=0.3.1; extra == 'llamaindex'
|
93
93
|
Requires-Dist: llama-index-llms-mistralai>=0.4.0; extra == 'llamaindex'
|
94
94
|
Requires-Dist: llama-index-llms-openai>=0.3.42; extra == 'llamaindex'
|
95
|
-
Requires-Dist: llama-index>=0.12.
|
95
|
+
Requires-Dist: llama-index>=0.12.46; extra == 'llamaindex'
|
96
96
|
Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.40.7; extra == 'llamaindex'
|
97
97
|
Provides-Extra: openai
|
98
98
|
Requires-Dist: openai-agents>=0.0.19; extra == 'openai'
|
@@ -182,7 +182,7 @@ blaxel/core/client/models/job_metrics_executions_chart.py,sha256=OGBEQu-6vvdQJfc
|
|
182
182
|
blaxel/core/client/models/job_metrics_executions_total.py,sha256=YSaxHgDPP4G2y24zFKpz5AfSSZKOqsfphOaNdr0Hxzw,1302
|
183
183
|
blaxel/core/client/models/job_metrics_tasks_chart.py,sha256=fJ-Lr76ZF6L7UIhhU8vpRzlTpJ83XnCpmCXDlvb9204,1272
|
184
184
|
blaxel/core/client/models/job_metrics_tasks_total.py,sha256=MjCKjj81S2LHWrnbNHXLt6LUxdZY-8vmzqbEVQFVlWY,1272
|
185
|
-
blaxel/core/client/models/job_spec.py,sha256=
|
185
|
+
blaxel/core/client/models/job_spec.py,sha256=ZhQ-YlQ53Yqty3qe7qGQxkeYrWupzJx18ehzNxVCl2c,9430
|
186
186
|
blaxel/core/client/models/jobs_chart.py,sha256=XbpoY1WLbP9yRlw7NAY8_XmeQFavP5RQ43OpmvczBdQ,2944
|
187
187
|
blaxel/core/client/models/jobs_chart_value.py,sha256=c-n9y3uc5TC_EBGTDm3_-vzRsEKCUSo7ep5YtxZTQUY,1892
|
188
188
|
blaxel/core/client/models/jobs_executions.py,sha256=e9ryxYNPRPlE9a4ObwdbTMBFPi3gveGbd4QFuxO5lNA,2410
|
@@ -282,8 +282,8 @@ blaxel/core/client/models/token_rate_metric.py,sha256=iucEWvuDrmDBQYu_Q1fyFYN9R8
|
|
282
282
|
blaxel/core/client/models/token_rate_metrics.py,sha256=nvhSYuA9E2Cc73_1gogoWIjtiVzn3u7xXe8iHmKN0aY,4404
|
283
283
|
blaxel/core/client/models/token_total_metric.py,sha256=BPitBM2P79gGL-FkUE89_SPAdhXKeL5yw6lawvdlBnA,3919
|
284
284
|
blaxel/core/client/models/trace_ids_response.py,sha256=0JuhxhKvwEd0qMPBzf3PAGa3eNR547xZ2VveIF0Ztdw,1256
|
285
|
-
blaxel/core/client/models/trigger.py,sha256=
|
286
|
-
blaxel/core/client/models/trigger_configuration.py,sha256=
|
285
|
+
blaxel/core/client/models/trigger.py,sha256=15LJZP4kCIP7U1CGfd0pY9icz2yvUltTndnE0MNTizk,2964
|
286
|
+
blaxel/core/client/models/trigger_configuration.py,sha256=4GzaxybXJ0KSPcLgKg1vIB67MntlchmVgkh-RJez86g,2635
|
287
287
|
blaxel/core/client/models/update_workspace_service_account_body.py,sha256=fz2MGqwRfrYkMmL8PaFHQdsu3RQcRljvP6n6JIru45o,2004
|
288
288
|
blaxel/core/client/models/update_workspace_service_account_response_200.py,sha256=nCLPHFP_iR1MIpicgQMpbiyme97ZMfTFhyQUEbhzkHI,2968
|
289
289
|
blaxel/core/client/models/update_workspace_user_role_body.py,sha256=FyLCWy9oRgUxoFPxxtrDvwzh1kHLkoTZ1pL5w3ayexM,1572
|
@@ -308,11 +308,11 @@ blaxel/core/sandbox/__init__.py,sha256=oF3sX5MbwSqfwhOtF5ODYWwapHffbkp2UI78jPBn7
|
|
308
308
|
blaxel/core/sandbox/action.py,sha256=9Zjkco7YkLzBThD3N2Hr5SpeEiqU_-Ktk8HlKpkpiAg,2802
|
309
309
|
blaxel/core/sandbox/filesystem.py,sha256=dyIvDdlPZO0ijD6mXXX8Yl0t75VijQ6_uMz_9rJd-_4,11317
|
310
310
|
blaxel/core/sandbox/network.py,sha256=P5jLd4AAg1zgyIK4qGWvZaDZ5BzIcxRx2ffz_JLsLMI,357
|
311
|
-
blaxel/core/sandbox/preview.py,sha256=
|
311
|
+
blaxel/core/sandbox/preview.py,sha256=g0uVbMsIi8gRXmmyOfSyqm1qO4Cv6rsq92fs_k884dY,6120
|
312
312
|
blaxel/core/sandbox/process.py,sha256=7zEngDTs2XiNsMm9TZ4lEDUiRpS3af8dw60pEvRuHDY,8357
|
313
|
-
blaxel/core/sandbox/sandbox.py,sha256=
|
314
|
-
blaxel/core/sandbox/session.py,sha256=
|
315
|
-
blaxel/core/sandbox/types.py,sha256=
|
313
|
+
blaxel/core/sandbox/sandbox.py,sha256=y6mV2-i6TsSZGQsvBBGptR514OfgvhV0hXBMEsOBcsY,8648
|
314
|
+
blaxel/core/sandbox/session.py,sha256=3PfoekfdVzLYttsmKeK3MePhuprjqv_FDyVQTQME0OE,5277
|
315
|
+
blaxel/core/sandbox/types.py,sha256=nsbvZLUxvDZkg2oExE3HdXx2qIpPaaoa7_lGYBzQ8Xk,5638
|
316
316
|
blaxel/core/sandbox/client/__init__.py,sha256=N26bD5o1jsTb48oExow6Rgivd8ylaU9jaWZfZsVilP8,128
|
317
317
|
blaxel/core/sandbox/client/client.py,sha256=tcP8cJ4Q3dV9aB3yQ01dDXO-ekfsa3WGGFz4DQAEf8I,7079
|
318
318
|
blaxel/core/sandbox/client/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
|
@@ -354,14 +354,14 @@ blaxel/core/sandbox/client/models/process_request_env.py,sha256=hzVPY4mk4g4bKj_S
|
|
354
354
|
blaxel/core/sandbox/client/models/process_response.py,sha256=vXHK6NBnuf0KYVzpkaApC29KOKwDE-7jBxy_WszApXs,3239
|
355
355
|
blaxel/core/sandbox/client/models/process_response_status.py,sha256=hCE1gCtheV83T6PYURG3k-rPZSauvyTFhsxLEtudgYE,246
|
356
356
|
blaxel/core/sandbox/client/models/subdirectory.py,sha256=obztIgi_XjT4pPoT1-dyOX6O8k0e4ERZUTiI9qgkhJM,1593
|
357
|
-
blaxel/core/sandbox/client/models/success_response.py,sha256=
|
358
|
-
blaxel/core/tools/__init__.py,sha256=
|
357
|
+
blaxel/core/sandbox/client/models/success_response.py,sha256=m8Bj9GJjN4yYQsPszC68izkuTRzEE9DCHjOaDdIYeGg,1825
|
358
|
+
blaxel/core/tools/__init__.py,sha256=OCZExds99o_j_GvAywaWFIGfY12abNZHcaiGOmAyh8o,9793
|
359
359
|
blaxel/core/tools/common.py,sha256=JGK052v_fvwWBFYnIArlBnFFViYyFrqdDn3gdVf53EU,1332
|
360
360
|
blaxel/core/tools/types.py,sha256=YPCGJ4vZDhqR0X2H_TWtc5chQScsC32nGTQdRKJlO8Y,707
|
361
361
|
blaxel/crewai/__init__.py,sha256=HdAZxRDgC2zW-O5xYzb_Xuysb66_fMykNJVPxlTmFnY,123
|
362
362
|
blaxel/crewai/model.py,sha256=VOLUE5tpz9tmYl7KU9L1kNUJ5uTci2rhRfPQ8HyCfWI,1785
|
363
363
|
blaxel/crewai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
364
|
-
blaxel/crewai/tools.py,sha256=
|
364
|
+
blaxel/crewai/tools.py,sha256=HVMSRTVrc0ygiCCNkL6xa3i31IWwFlGKB6oC-6iWrK8,789
|
365
365
|
blaxel/googleadk/__init__.py,sha256=WfYZvtkh5IF042qWLaiWjbDarJZCX9ghHGiTrat8eps,127
|
366
366
|
blaxel/googleadk/model.py,sha256=ZSBGapgcrhRogc1kBFKfuLS36UUkcQL6nZD22yVUEJM,2236
|
367
367
|
blaxel/googleadk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -374,7 +374,7 @@ blaxel/langgraph/custom/gemini.py,sha256=AkhpuVMXnh1CyJ0zR2NMTtxQFPPHtAdHf_cyNzV
|
|
374
374
|
blaxel/livekit/__init__.py,sha256=byUwOJ6MHeSXOYXmaVoHnC3ZUmpkqJ55u5mQglXX-SQ,124
|
375
375
|
blaxel/livekit/model.py,sha256=4HA6Jn4_jQ5QeH5mWMeopWybQDeiJcDRyh5kX5O9LHE,961
|
376
376
|
blaxel/livekit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
377
|
-
blaxel/livekit/tools.py,sha256
|
377
|
+
blaxel/livekit/tools.py,sha256=QipxGDnKqma_ktzTUpKgzdp5x4bvpQnxEVoqSTBesu8,1053
|
378
378
|
blaxel/llamaindex/__init__.py,sha256=iZ3QbZhlwKvP91ChcqSXVkpRrzurMxJoQfKdZFzE2AA,127
|
379
379
|
blaxel/llamaindex/model.py,sha256=FYUCTA80LKC4-UfESh43htoHrsoZjwwVaxXD51T0IuE,2557
|
380
380
|
blaxel/llamaindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -383,7 +383,7 @@ blaxel/llamaindex/custom/cohere.py,sha256=zoUv4NWwMZLZEynYTC3JuOvtinguRgtuRwS31w
|
|
383
383
|
blaxel/openai/__init__.py,sha256=YkizVtcYL2m9v-z5B1EReYVu9n9V-DCxJhSB2mvqOs0,123
|
384
384
|
blaxel/openai/model.py,sha256=lGz4zrV4sURPb6aLtroMRV5-CgfQUq15PeTgjc7QkTI,600
|
385
385
|
blaxel/openai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
386
|
-
blaxel/openai/tools.py,sha256=
|
386
|
+
blaxel/openai/tools.py,sha256=XnbQt8AvvmCHjoQIe3AhylmGi3bwTJIrdmXm--sldLg,834
|
387
387
|
blaxel/pydantic/__init__.py,sha256=-UDZ5VSrlgfqErJuiuphcAFwesijzXxYLeyC7yHEDrE,128
|
388
388
|
blaxel/pydantic/model.py,sha256=1oPf1EH01wvbgBS-w89L73nQrII6VNkZiRIuJYmrMms,3396
|
389
389
|
blaxel/pydantic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -402,7 +402,7 @@ blaxel/telemetry/instrumentation/map.py,sha256=PCzZJj39yiYVYJrxLBNP-NW-tjjYyTijw
|
|
402
402
|
blaxel/telemetry/instrumentation/utils.py,sha256=KInMYZH-mu9_wvetmf0EmgrfN3Sw8IWk2Y95v2u90_U,1901
|
403
403
|
blaxel/telemetry/log/log.py,sha256=RvQByRjZMoP_dRaAZu8oK6DTegsHs-xV4W-UIqis6CA,2461
|
404
404
|
blaxel/telemetry/log/logger.py,sha256=NPAS3g82ryROjvc_DEZaTIfrcehoLEZoP-JkLxADxc0,4113
|
405
|
-
blaxel-0.2.
|
406
|
-
blaxel-0.2.
|
407
|
-
blaxel-0.2.
|
408
|
-
blaxel-0.2.
|
405
|
+
blaxel-0.2.4.dist-info/METADATA,sha256=oh2nI5vCd2gRNp-9jWiQigKLjSeuVwz7ODk1yny-PMM,9875
|
406
|
+
blaxel-0.2.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
407
|
+
blaxel-0.2.4.dist-info/licenses/LICENSE,sha256=p5PNQvpvyDT_0aYBDgmV1fFI_vAD2aSV0wWG7VTgRis,1069
|
408
|
+
blaxel-0.2.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|