blaxel 0.2.35__py3-none-any.whl → 0.2.37__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. blaxel/__init__.py +2 -2
  2. blaxel/core/client/api/compute/create_sandbox.py +21 -1
  3. blaxel/core/client/api/jobs/create_job_execution.py +12 -12
  4. blaxel/core/client/api/volumes/update_volume.py +187 -0
  5. blaxel/core/client/models/__init__.py +10 -6
  6. blaxel/core/client/models/{create_job_execution_response.py → create_job_execution_output.py} +11 -13
  7. blaxel/core/client/models/{create_job_execution_response_tasks_item.py → create_job_execution_output_tasks_item.py} +5 -5
  8. blaxel/core/client/models/create_job_execution_request.py +31 -0
  9. blaxel/core/client/models/create_job_execution_request_env.py +50 -0
  10. blaxel/core/client/models/function_runtime.py +18 -0
  11. blaxel/core/client/models/{function_spec_transport.py → function_runtime_transport.py} +2 -2
  12. blaxel/core/client/models/function_spec.py +0 -18
  13. blaxel/core/client/models/job_execution_spec.py +35 -0
  14. blaxel/core/client/models/job_execution_spec_env_override.py +50 -0
  15. blaxel/core/client/models/port_protocol.py +1 -0
  16. blaxel/core/client/models/preview.py +48 -1
  17. blaxel/core/client/models/sandbox.py +10 -0
  18. blaxel/core/common/settings.py +5 -0
  19. blaxel/core/jobs/__init__.py +60 -88
  20. blaxel/core/sandbox/__init__.py +12 -0
  21. blaxel/core/{client/api/invitations/list_all_pending_invitations.py → sandbox/client/api/system/get_health.py} +26 -34
  22. blaxel/core/sandbox/client/api/system/post_upgrade.py +196 -0
  23. blaxel/core/sandbox/client/models/__init__.py +8 -0
  24. blaxel/core/sandbox/client/models/content_search_match.py +24 -25
  25. blaxel/core/sandbox/client/models/content_search_response.py +25 -29
  26. blaxel/core/sandbox/client/models/find_match.py +13 -14
  27. blaxel/core/sandbox/client/models/find_response.py +21 -24
  28. blaxel/core/sandbox/client/models/fuzzy_search_match.py +17 -19
  29. blaxel/core/sandbox/client/models/fuzzy_search_response.py +21 -24
  30. blaxel/core/sandbox/client/models/health_response.py +159 -0
  31. blaxel/core/sandbox/client/models/process_upgrade_state.py +20 -0
  32. blaxel/core/sandbox/client/models/upgrade_request.py +71 -0
  33. blaxel/core/sandbox/client/models/upgrade_status.py +125 -0
  34. blaxel/core/sandbox/default/__init__.py +2 -0
  35. blaxel/core/sandbox/default/filesystem.py +20 -6
  36. blaxel/core/sandbox/default/preview.py +48 -1
  37. blaxel/core/sandbox/default/process.py +66 -21
  38. blaxel/core/sandbox/default/sandbox.py +104 -6
  39. blaxel/core/sandbox/default/system.py +71 -0
  40. blaxel/core/sandbox/sync/__init__.py +2 -0
  41. blaxel/core/sandbox/sync/filesystem.py +19 -2
  42. blaxel/core/sandbox/sync/preview.py +50 -3
  43. blaxel/core/sandbox/sync/process.py +38 -15
  44. blaxel/core/sandbox/sync/sandbox.py +97 -5
  45. blaxel/core/sandbox/sync/system.py +71 -0
  46. blaxel/core/sandbox/types.py +212 -5
  47. blaxel/core/volume/volume.py +209 -4
  48. blaxel/langgraph/model.py +25 -14
  49. blaxel/langgraph/tools.py +15 -12
  50. blaxel/llamaindex/model.py +33 -24
  51. blaxel/llamaindex/tools.py +9 -4
  52. blaxel/pydantic/model.py +26 -12
  53. blaxel-0.2.37.dist-info/METADATA +569 -0
  54. {blaxel-0.2.35.dist-info → blaxel-0.2.37.dist-info}/RECORD +57 -47
  55. blaxel-0.2.35.dist-info/METADATA +0 -228
  56. /blaxel/core/{client/api/invitations → sandbox/client/api/system}/__init__.py +0 -0
  57. {blaxel-0.2.35.dist-info → blaxel-0.2.37.dist-info}/WHEEL +0 -0
  58. {blaxel-0.2.35.dist-info → blaxel-0.2.37.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,8 @@
1
- from typing import TYPE_CHECKING, Any, TypeVar, Union
1
+ from typing import TYPE_CHECKING, Any, TypeVar
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
-
8
6
  if TYPE_CHECKING:
9
7
  from ..models.find_match import FindMatch
10
8
 
@@ -16,34 +14,33 @@ T = TypeVar("T", bound="FindResponse")
16
14
  class FindResponse:
17
15
  """
18
16
  Attributes:
19
- matches (Union[Unset, list['FindMatch']]):
20
- total (Union[Unset, int]): Example: 5.
17
+ matches (list['FindMatch']):
18
+ total (int): Example: 5.
21
19
  """
22
20
 
23
- matches: Union[Unset, list["FindMatch"]] = UNSET
24
- total: Union[Unset, int] = UNSET
21
+ matches: list["FindMatch"]
22
+ total: int
25
23
  additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
26
24
 
27
25
  def to_dict(self) -> dict[str, Any]:
28
- matches: Union[Unset, list[dict[str, Any]]] = UNSET
29
- if not isinstance(self.matches, Unset):
30
- matches = []
31
- for matches_item_data in self.matches:
32
- if type(matches_item_data) is dict:
33
- matches_item = matches_item_data
34
- else:
35
- matches_item = matches_item_data.to_dict()
36
- matches.append(matches_item)
26
+ matches = []
27
+ for matches_item_data in self.matches:
28
+ if type(matches_item_data) is dict:
29
+ matches_item = matches_item_data
30
+ else:
31
+ matches_item = matches_item_data.to_dict()
32
+ matches.append(matches_item)
37
33
 
38
34
  total = self.total
39
35
 
40
36
  field_dict: dict[str, Any] = {}
41
37
  field_dict.update(self.additional_properties)
42
- field_dict.update({})
43
- if matches is not UNSET:
44
- field_dict["matches"] = matches
45
- if total is not UNSET:
46
- field_dict["total"] = total
38
+ field_dict.update(
39
+ {
40
+ "matches": matches,
41
+ "total": total,
42
+ }
43
+ )
47
44
 
48
45
  return field_dict
49
46
 
@@ -55,13 +52,13 @@ class FindResponse:
55
52
  return None
56
53
  d = src_dict.copy()
57
54
  matches = []
58
- _matches = d.pop("matches", UNSET)
59
- for matches_item_data in _matches or []:
55
+ _matches = d.pop("matches")
56
+ for matches_item_data in _matches:
60
57
  matches_item = FindMatch.from_dict(matches_item_data)
61
58
 
62
59
  matches.append(matches_item)
63
60
 
64
- total = d.pop("total", UNSET)
61
+ total = d.pop("total")
65
62
 
66
63
  find_response = cls(
67
64
  matches=matches,
@@ -1,10 +1,8 @@
1
- from typing import Any, TypeVar, Union
1
+ from typing import Any, TypeVar
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
-
8
6
  T = TypeVar("T", bound="FuzzySearchMatch")
9
7
 
10
8
 
@@ -12,14 +10,14 @@ T = TypeVar("T", bound="FuzzySearchMatch")
12
10
  class FuzzySearchMatch:
13
11
  """
14
12
  Attributes:
15
- path (Union[Unset, str]): Example: src/main.go.
16
- score (Union[Unset, int]): Example: 100.
17
- type_ (Union[Unset, str]): "file" or "directory" Example: file.
13
+ path (str): Example: src/main.go.
14
+ score (int): Example: 100.
15
+ type_ (str): "file" or "directory" Example: file.
18
16
  """
19
17
 
20
- path: Union[Unset, str] = UNSET
21
- score: Union[Unset, int] = UNSET
22
- type_: Union[Unset, str] = UNSET
18
+ path: str
19
+ score: int
20
+ type_: str
23
21
  additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
24
22
 
25
23
  def to_dict(self) -> dict[str, Any]:
@@ -31,13 +29,13 @@ class FuzzySearchMatch:
31
29
 
32
30
  field_dict: dict[str, Any] = {}
33
31
  field_dict.update(self.additional_properties)
34
- field_dict.update({})
35
- if path is not UNSET:
36
- field_dict["path"] = path
37
- if score is not UNSET:
38
- field_dict["score"] = score
39
- if type_ is not UNSET:
40
- field_dict["type"] = type_
32
+ field_dict.update(
33
+ {
34
+ "path": path,
35
+ "score": score,
36
+ "type": type_,
37
+ }
38
+ )
41
39
 
42
40
  return field_dict
43
41
 
@@ -46,11 +44,11 @@ class FuzzySearchMatch:
46
44
  if not src_dict:
47
45
  return None
48
46
  d = src_dict.copy()
49
- path = d.pop("path", UNSET)
47
+ path = d.pop("path")
50
48
 
51
- score = d.pop("score", UNSET)
49
+ score = d.pop("score")
52
50
 
53
- type_ = d.pop("type", d.pop("type_", UNSET))
51
+ type_ = d.pop("type") if "type" in d else d.pop("type_")
54
52
 
55
53
  fuzzy_search_match = cls(
56
54
  path=path,
@@ -1,10 +1,8 @@
1
- from typing import TYPE_CHECKING, Any, TypeVar, Union
1
+ from typing import TYPE_CHECKING, Any, TypeVar
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
-
8
6
  if TYPE_CHECKING:
9
7
  from ..models.fuzzy_search_match import FuzzySearchMatch
10
8
 
@@ -16,34 +14,33 @@ T = TypeVar("T", bound="FuzzySearchResponse")
16
14
  class FuzzySearchResponse:
17
15
  """
18
16
  Attributes:
19
- matches (Union[Unset, list['FuzzySearchMatch']]):
20
- total (Union[Unset, int]): Example: 5.
17
+ matches (list['FuzzySearchMatch']):
18
+ total (int): Example: 5.
21
19
  """
22
20
 
23
- matches: Union[Unset, list["FuzzySearchMatch"]] = UNSET
24
- total: Union[Unset, int] = UNSET
21
+ matches: list["FuzzySearchMatch"]
22
+ total: int
25
23
  additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
26
24
 
27
25
  def to_dict(self) -> dict[str, Any]:
28
- matches: Union[Unset, list[dict[str, Any]]] = UNSET
29
- if not isinstance(self.matches, Unset):
30
- matches = []
31
- for matches_item_data in self.matches:
32
- if type(matches_item_data) is dict:
33
- matches_item = matches_item_data
34
- else:
35
- matches_item = matches_item_data.to_dict()
36
- matches.append(matches_item)
26
+ matches = []
27
+ for matches_item_data in self.matches:
28
+ if type(matches_item_data) is dict:
29
+ matches_item = matches_item_data
30
+ else:
31
+ matches_item = matches_item_data.to_dict()
32
+ matches.append(matches_item)
37
33
 
38
34
  total = self.total
39
35
 
40
36
  field_dict: dict[str, Any] = {}
41
37
  field_dict.update(self.additional_properties)
42
- field_dict.update({})
43
- if matches is not UNSET:
44
- field_dict["matches"] = matches
45
- if total is not UNSET:
46
- field_dict["total"] = total
38
+ field_dict.update(
39
+ {
40
+ "matches": matches,
41
+ "total": total,
42
+ }
43
+ )
47
44
 
48
45
  return field_dict
49
46
 
@@ -55,13 +52,13 @@ class FuzzySearchResponse:
55
52
  return None
56
53
  d = src_dict.copy()
57
54
  matches = []
58
- _matches = d.pop("matches", UNSET)
59
- for matches_item_data in _matches or []:
55
+ _matches = d.pop("matches")
56
+ for matches_item_data in _matches:
60
57
  matches_item = FuzzySearchMatch.from_dict(matches_item_data)
61
58
 
62
59
  matches.append(matches_item)
63
60
 
64
- total = d.pop("total", UNSET)
61
+ total = d.pop("total")
65
62
 
66
63
  fuzzy_search_response = cls(
67
64
  matches=matches,
@@ -0,0 +1,159 @@
1
+ from typing import TYPE_CHECKING, Any, TypeVar
2
+
3
+ from attrs import define as _attrs_define
4
+ from attrs import field as _attrs_field
5
+
6
+ if TYPE_CHECKING:
7
+ from ..models.upgrade_status import UpgradeStatus
8
+
9
+
10
+ T = TypeVar("T", bound="HealthResponse")
11
+
12
+
13
+ @_attrs_define
14
+ class HealthResponse:
15
+ """
16
+ Attributes:
17
+ arch (str): Example: amd64.
18
+ build_time (str): Example: 2026-01-29 17:36:52+00:00.
19
+ git_commit (str): Example: abc123.
20
+ go_version (str): Example: go1.25.0.
21
+ last_upgrade (UpgradeStatus):
22
+ os (str): Example: linux.
23
+ started_at (str): Example: 2026-01-29 18:45:49+00:00.
24
+ status (str): Example: ok.
25
+ upgrade_count (int):
26
+ uptime (str): Example: 1h30m.
27
+ uptime_seconds (float): Example: 5400.5.
28
+ version (str): Example: v0.1.0.
29
+ """
30
+
31
+ arch: str
32
+ build_time: str
33
+ git_commit: str
34
+ go_version: str
35
+ last_upgrade: "UpgradeStatus"
36
+ os: str
37
+ started_at: str
38
+ status: str
39
+ upgrade_count: int
40
+ uptime: str
41
+ uptime_seconds: float
42
+ version: str
43
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
44
+
45
+ def to_dict(self) -> dict[str, Any]:
46
+ arch = self.arch
47
+
48
+ build_time = self.build_time
49
+
50
+ git_commit = self.git_commit
51
+
52
+ go_version = self.go_version
53
+
54
+ if type(self.last_upgrade) is dict:
55
+ last_upgrade = self.last_upgrade
56
+ else:
57
+ last_upgrade = self.last_upgrade.to_dict()
58
+
59
+ os = self.os
60
+
61
+ started_at = self.started_at
62
+
63
+ status = self.status
64
+
65
+ upgrade_count = self.upgrade_count
66
+
67
+ uptime = self.uptime
68
+
69
+ uptime_seconds = self.uptime_seconds
70
+
71
+ version = self.version
72
+
73
+ field_dict: dict[str, Any] = {}
74
+ field_dict.update(self.additional_properties)
75
+ field_dict.update(
76
+ {
77
+ "arch": arch,
78
+ "buildTime": build_time,
79
+ "gitCommit": git_commit,
80
+ "goVersion": go_version,
81
+ "lastUpgrade": last_upgrade,
82
+ "os": os,
83
+ "startedAt": started_at,
84
+ "status": status,
85
+ "upgradeCount": upgrade_count,
86
+ "uptime": uptime,
87
+ "uptimeSeconds": uptime_seconds,
88
+ "version": version,
89
+ }
90
+ )
91
+
92
+ return field_dict
93
+
94
+ @classmethod
95
+ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None:
96
+ from ..models.upgrade_status import UpgradeStatus
97
+
98
+ if not src_dict:
99
+ return None
100
+ d = src_dict.copy()
101
+ arch = d.pop("arch")
102
+
103
+ build_time = d.pop("buildTime") if "buildTime" in d else d.pop("build_time")
104
+
105
+ git_commit = d.pop("gitCommit") if "gitCommit" in d else d.pop("git_commit")
106
+
107
+ go_version = d.pop("goVersion") if "goVersion" in d else d.pop("go_version")
108
+
109
+ last_upgrade = UpgradeStatus.from_dict(
110
+ d.pop("lastUpgrade") if "lastUpgrade" in d else d.pop("last_upgrade")
111
+ )
112
+
113
+ os = d.pop("os")
114
+
115
+ started_at = d.pop("startedAt") if "startedAt" in d else d.pop("started_at")
116
+
117
+ status = d.pop("status")
118
+
119
+ upgrade_count = d.pop("upgradeCount") if "upgradeCount" in d else d.pop("upgrade_count")
120
+
121
+ uptime = d.pop("uptime")
122
+
123
+ uptime_seconds = d.pop("uptimeSeconds") if "uptimeSeconds" in d else d.pop("uptime_seconds")
124
+
125
+ version = d.pop("version")
126
+
127
+ health_response = cls(
128
+ arch=arch,
129
+ build_time=build_time,
130
+ git_commit=git_commit,
131
+ go_version=go_version,
132
+ last_upgrade=last_upgrade,
133
+ os=os,
134
+ started_at=started_at,
135
+ status=status,
136
+ upgrade_count=upgrade_count,
137
+ uptime=uptime,
138
+ uptime_seconds=uptime_seconds,
139
+ version=version,
140
+ )
141
+
142
+ health_response.additional_properties = d
143
+ return health_response
144
+
145
+ @property
146
+ def additional_keys(self) -> list[str]:
147
+ return list(self.additional_properties.keys())
148
+
149
+ def __getitem__(self, key: str) -> Any:
150
+ return self.additional_properties[key]
151
+
152
+ def __setitem__(self, key: str, value: Any) -> None:
153
+ self.additional_properties[key] = value
154
+
155
+ def __delitem__(self, key: str) -> None:
156
+ del self.additional_properties[key]
157
+
158
+ def __contains__(self, key: str) -> bool:
159
+ return key in self.additional_properties
@@ -0,0 +1,20 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ProcessUpgradeState(str, Enum):
5
+ COMPLETED = "completed"
6
+ FAILED = "failed"
7
+ IDLE = "idle"
8
+ RUNNING = "running"
9
+
10
+ def __str__(self) -> str:
11
+ return str(self.value)
12
+
13
+ @classmethod
14
+ def _missing_(cls, value: object) -> "ProcessUpgradeState | None":
15
+ if isinstance(value, str):
16
+ upper_value = value.upper()
17
+ for member in cls:
18
+ if member.value.upper() == upper_value:
19
+ return member
20
+ return None
@@ -0,0 +1,71 @@
1
+ from typing import Any, TypeVar, Union
2
+
3
+ from attrs import define as _attrs_define
4
+ from attrs import field as _attrs_field
5
+
6
+ from ..types import UNSET, Unset
7
+
8
+ T = TypeVar("T", bound="UpgradeRequest")
9
+
10
+
11
+ @_attrs_define
12
+ class UpgradeRequest:
13
+ """
14
+ Attributes:
15
+ base_url (Union[Unset, str]): Base URL for releases (useful for forks) Example: https://github.com/blaxel-
16
+ ai/sandbox/releases.
17
+ version (Union[Unset, str]): Version to upgrade to: "develop", "main", "latest", or specific tag like "v1.0.0"
18
+ Example: develop.
19
+ """
20
+
21
+ base_url: Union[Unset, str] = UNSET
22
+ version: Union[Unset, str] = UNSET
23
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
24
+
25
+ def to_dict(self) -> dict[str, Any]:
26
+ base_url = self.base_url
27
+
28
+ version = self.version
29
+
30
+ field_dict: dict[str, Any] = {}
31
+ field_dict.update(self.additional_properties)
32
+ field_dict.update({})
33
+ if base_url is not UNSET:
34
+ field_dict["baseUrl"] = base_url
35
+ if version is not UNSET:
36
+ field_dict["version"] = version
37
+
38
+ return field_dict
39
+
40
+ @classmethod
41
+ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None:
42
+ if not src_dict:
43
+ return None
44
+ d = src_dict.copy()
45
+ base_url = d.pop("baseUrl", d.pop("base_url", UNSET))
46
+
47
+ version = d.pop("version", UNSET)
48
+
49
+ upgrade_request = cls(
50
+ base_url=base_url,
51
+ version=version,
52
+ )
53
+
54
+ upgrade_request.additional_properties = d
55
+ return upgrade_request
56
+
57
+ @property
58
+ def additional_keys(self) -> list[str]:
59
+ return list(self.additional_properties.keys())
60
+
61
+ def __getitem__(self, key: str) -> Any:
62
+ return self.additional_properties[key]
63
+
64
+ def __setitem__(self, key: str, value: Any) -> None:
65
+ self.additional_properties[key] = value
66
+
67
+ def __delitem__(self, key: str) -> None:
68
+ del self.additional_properties[key]
69
+
70
+ def __contains__(self, key: str) -> bool:
71
+ return key in self.additional_properties
@@ -0,0 +1,125 @@
1
+ from typing import Any, TypeVar, Union
2
+
3
+ from attrs import define as _attrs_define
4
+ from attrs import field as _attrs_field
5
+
6
+ from ..models.process_upgrade_state import ProcessUpgradeState
7
+ from ..types import UNSET, Unset
8
+
9
+ T = TypeVar("T", bound="UpgradeStatus")
10
+
11
+
12
+ @_attrs_define
13
+ class UpgradeStatus:
14
+ """
15
+ Attributes:
16
+ status (ProcessUpgradeState):
17
+ step (str): Current/last step (none, starting, download, validate, replace, completed, skipped) Example:
18
+ download.
19
+ version (str): Version being upgraded to Example: latest.
20
+ binary_path (Union[Unset, str]): Path to downloaded binary Example: /tmp/sandbox-api-new.
21
+ bytes_downloaded (Union[Unset, int]): Bytes downloaded Example: 25034936.
22
+ download_url (Union[Unset, str]): URL used for download Example: https://github.com/....
23
+ error (Union[Unset, str]): Error message if failed Example: Failed to download binary.
24
+ last_attempt (Union[Unset, str]): When the upgrade was attempted
25
+ """
26
+
27
+ status: ProcessUpgradeState
28
+ step: str
29
+ version: str
30
+ binary_path: Union[Unset, str] = UNSET
31
+ bytes_downloaded: Union[Unset, int] = UNSET
32
+ download_url: Union[Unset, str] = UNSET
33
+ error: Union[Unset, str] = UNSET
34
+ last_attempt: Union[Unset, str] = UNSET
35
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
36
+
37
+ def to_dict(self) -> dict[str, Any]:
38
+ status = self.status.value
39
+
40
+ step = self.step
41
+
42
+ version = self.version
43
+
44
+ binary_path = self.binary_path
45
+
46
+ bytes_downloaded = self.bytes_downloaded
47
+
48
+ download_url = self.download_url
49
+
50
+ error = self.error
51
+
52
+ last_attempt = self.last_attempt
53
+
54
+ field_dict: dict[str, Any] = {}
55
+ field_dict.update(self.additional_properties)
56
+ field_dict.update(
57
+ {
58
+ "status": status,
59
+ "step": step,
60
+ "version": version,
61
+ }
62
+ )
63
+ if binary_path is not UNSET:
64
+ field_dict["binaryPath"] = binary_path
65
+ if bytes_downloaded is not UNSET:
66
+ field_dict["bytesDownloaded"] = bytes_downloaded
67
+ if download_url is not UNSET:
68
+ field_dict["downloadUrl"] = download_url
69
+ if error is not UNSET:
70
+ field_dict["error"] = error
71
+ if last_attempt is not UNSET:
72
+ field_dict["lastAttempt"] = last_attempt
73
+
74
+ return field_dict
75
+
76
+ @classmethod
77
+ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None:
78
+ if not src_dict:
79
+ return None
80
+ d = src_dict.copy()
81
+ status = ProcessUpgradeState(d.pop("status"))
82
+
83
+ step = d.pop("step")
84
+
85
+ version = d.pop("version")
86
+
87
+ binary_path = d.pop("binaryPath", d.pop("binary_path", UNSET))
88
+
89
+ bytes_downloaded = d.pop("bytesDownloaded", d.pop("bytes_downloaded", UNSET))
90
+
91
+ download_url = d.pop("downloadUrl", d.pop("download_url", UNSET))
92
+
93
+ error = d.pop("error", UNSET)
94
+
95
+ last_attempt = d.pop("lastAttempt", d.pop("last_attempt", UNSET))
96
+
97
+ upgrade_status = cls(
98
+ status=status,
99
+ step=step,
100
+ version=version,
101
+ binary_path=binary_path,
102
+ bytes_downloaded=bytes_downloaded,
103
+ download_url=download_url,
104
+ error=error,
105
+ last_attempt=last_attempt,
106
+ )
107
+
108
+ upgrade_status.additional_properties = d
109
+ return upgrade_status
110
+
111
+ @property
112
+ def additional_keys(self) -> list[str]:
113
+ return list(self.additional_properties.keys())
114
+
115
+ def __getitem__(self, key: str) -> Any:
116
+ return self.additional_properties[key]
117
+
118
+ def __setitem__(self, key: str, value: Any) -> None:
119
+ self.additional_properties[key] = value
120
+
121
+ def __delitem__(self, key: str) -> None:
122
+ del self.additional_properties[key]
123
+
124
+ def __contains__(self, key: str) -> bool:
125
+ return key in self.additional_properties
@@ -7,6 +7,7 @@ from .sandbox import (
7
7
  SandboxPreviews,
8
8
  SandboxProcess,
9
9
  )
10
+ from .system import SandboxSystem
10
11
 
11
12
  __all__ = [
12
13
  "SandboxInstance",
@@ -15,5 +16,6 @@ __all__ = [
15
16
  "SandboxPreviews",
16
17
  "SandboxProcess",
17
18
  "SandboxCodegen",
19
+ "SandboxSystem",
18
20
  "CodeInterpreter",
19
21
  ]
@@ -10,6 +10,7 @@ import httpx
10
10
  from ...common.settings import settings
11
11
  from ..client.models import Directory, FileRequest, SuccessResponse
12
12
  from ..types import (
13
+ AsyncWatchHandle,
13
14
  CopyResponse,
14
15
  SandboxConfiguration,
15
16
  SandboxFilesystemFile,
@@ -327,9 +328,7 @@ class SandboxFileSystem(SandboxAction):
327
328
  data = json.loads(await response.aread())
328
329
  self.handle_response_error(response)
329
330
 
330
- from ..client.models.content_search_response import (
331
- ContentSearchResponse,
332
- )
331
+ from ..client.models.content_search_response import ContentSearchResponse
333
332
 
334
333
  return ContentSearchResponse.from_dict(data)
335
334
  finally:
@@ -364,8 +363,23 @@ class SandboxFileSystem(SandboxAction):
364
363
  path: str,
365
364
  callback: Callable[[WatchEvent], None],
366
365
  options: Dict[str, Any] | None = None,
367
- ) -> Dict[str, Callable]:
368
- """Watch for file system changes."""
366
+ ) -> AsyncWatchHandle:
367
+ """Watch for file system changes.
368
+
369
+ Returns an AsyncWatchHandle that can be used as a context manager:
370
+
371
+ async with sandbox.fs.watch(path, callback) as handle:
372
+ # do something
373
+ # handle is automatically closed
374
+
375
+ Or manually:
376
+
377
+ handle = sandbox.fs.watch(path, callback)
378
+ try:
379
+ # do something
380
+ finally:
381
+ handle.close()
382
+ """
369
383
  path = self.format_path(path)
370
384
  closed = False
371
385
 
@@ -444,7 +458,7 @@ class SandboxFileSystem(SandboxAction):
444
458
  closed = True
445
459
  task.cancel()
446
460
 
447
- return {"close": close}
461
+ return AsyncWatchHandle(close)
448
462
 
449
463
  def format_path(self, path: str) -> str:
450
464
  """Format path for filesystem operations.