futurehouse-client 0.3.20.dev411__py3-none-any.whl → 0.4.1__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.
- futurehouse_client/clients/rest_client.py +33 -41
- futurehouse_client/models/app.py +4 -7
- futurehouse_client/utils/general.py +0 -34
- futurehouse_client/utils/world_model_tools.py +3 -2
- futurehouse_client/version.py +3 -16
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.1.dist-info}/METADATA +1 -6
- futurehouse_client-0.4.1.dist-info/RECORD +21 -0
- futurehouse_client/clients/data_storage_methods.py +0 -1867
- futurehouse_client/models/data_storage_methods.py +0 -333
- futurehouse_client-0.3.20.dev411.dist-info/RECORD +0 -23
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.1.dist-info}/WHEEL +0 -0
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.1.dist-info}/top_level.txt +0 -0
@@ -26,14 +26,21 @@ from httpx import (
|
|
26
26
|
AsyncClient,
|
27
27
|
Client,
|
28
28
|
CloseError,
|
29
|
+
ConnectError,
|
30
|
+
ConnectTimeout,
|
29
31
|
HTTPStatusError,
|
32
|
+
NetworkError,
|
33
|
+
ReadError,
|
34
|
+
ReadTimeout,
|
30
35
|
RemoteProtocolError,
|
31
36
|
codes,
|
32
37
|
)
|
33
38
|
from ldp.agent import AgentConfig
|
39
|
+
from requests.exceptions import RequestException, Timeout
|
34
40
|
from tenacity import (
|
35
41
|
before_sleep_log,
|
36
42
|
retry,
|
43
|
+
retry_if_exception_type,
|
37
44
|
stop_after_attempt,
|
38
45
|
wait_exponential,
|
39
46
|
)
|
@@ -41,7 +48,6 @@ from tqdm import tqdm as sync_tqdm
|
|
41
48
|
from tqdm.asyncio import tqdm
|
42
49
|
|
43
50
|
from futurehouse_client.clients import JobNames
|
44
|
-
from futurehouse_client.clients.data_storage_methods import DataStorageMethods
|
45
51
|
from futurehouse_client.models.app import (
|
46
52
|
AuthType,
|
47
53
|
JobDeploymentConfig,
|
@@ -62,10 +68,7 @@ from futurehouse_client.models.rest import (
|
|
62
68
|
WorldModelResponse,
|
63
69
|
)
|
64
70
|
from futurehouse_client.utils.auth import RefreshingJWT
|
65
|
-
from futurehouse_client.utils.general import
|
66
|
-
create_retry_if_connection_error,
|
67
|
-
gather_with_concurrency,
|
68
|
-
)
|
71
|
+
from futurehouse_client.utils.general import gather_with_concurrency
|
69
72
|
from futurehouse_client.utils.module_utils import (
|
70
73
|
OrganizationSelector,
|
71
74
|
fetch_environment_function_docstring,
|
@@ -157,15 +160,28 @@ class FileUploadError(RestClientError):
|
|
157
160
|
"""Raised when there's an error uploading a file."""
|
158
161
|
|
159
162
|
|
160
|
-
retry_if_connection_error =
|
163
|
+
retry_if_connection_error = retry_if_exception_type((
|
164
|
+
# From requests
|
165
|
+
Timeout,
|
166
|
+
ConnectionError,
|
167
|
+
RequestException,
|
168
|
+
# From httpx
|
169
|
+
ConnectError,
|
170
|
+
ConnectTimeout,
|
171
|
+
ReadTimeout,
|
172
|
+
ReadError,
|
173
|
+
NetworkError,
|
174
|
+
RemoteProtocolError,
|
175
|
+
CloseError,
|
176
|
+
FileUploadError,
|
177
|
+
))
|
161
178
|
|
162
179
|
DEFAULT_AGENT_TIMEOUT: int = 2400 # seconds
|
163
180
|
|
164
181
|
|
165
182
|
# pylint: disable=too-many-public-methods
|
166
|
-
class RestClient
|
167
|
-
REQUEST_TIMEOUT: ClassVar[float] = 30.0 # sec
|
168
|
-
FILE_UPLOAD_TIMEOUT: ClassVar[float] = 600.0 # 10 minutes - for file uploads
|
183
|
+
class RestClient:
|
184
|
+
REQUEST_TIMEOUT: ClassVar[float] = 30.0 # sec
|
169
185
|
MAX_RETRY_ATTEMPTS: ClassVar[int] = 3
|
170
186
|
RETRY_MULTIPLIER: ClassVar[int] = 1
|
171
187
|
MAX_RETRY_WAIT: ClassVar[int] = 10
|
@@ -223,35 +239,11 @@ class RestClient(DataStorageMethods):
|
|
223
239
|
"""Authenticated HTTP client for multipart uploads."""
|
224
240
|
return cast(Client, self.get_client(None, authenticated=True))
|
225
241
|
|
226
|
-
@property
|
227
|
-
def file_upload_client(self) -> Client:
|
228
|
-
"""Authenticated HTTP client with extended timeout for file uploads."""
|
229
|
-
return cast(
|
230
|
-
Client,
|
231
|
-
self.get_client(
|
232
|
-
"application/json", authenticated=True, timeout=self.FILE_UPLOAD_TIMEOUT
|
233
|
-
),
|
234
|
-
)
|
235
|
-
|
236
|
-
@property
|
237
|
-
def async_file_upload_client(self) -> AsyncClient:
|
238
|
-
"""Authenticated async HTTP client with extended timeout for file uploads."""
|
239
|
-
return cast(
|
240
|
-
AsyncClient,
|
241
|
-
self.get_client(
|
242
|
-
"application/json",
|
243
|
-
authenticated=True,
|
244
|
-
async_client=True,
|
245
|
-
timeout=self.FILE_UPLOAD_TIMEOUT,
|
246
|
-
),
|
247
|
-
)
|
248
|
-
|
249
242
|
def get_client(
|
250
243
|
self,
|
251
244
|
content_type: str | None = "application/json",
|
252
245
|
authenticated: bool = True,
|
253
246
|
async_client: bool = False,
|
254
|
-
timeout: float | None = None,
|
255
247
|
) -> Client | AsyncClient:
|
256
248
|
"""Return a cached HTTP client or create one if needed.
|
257
249
|
|
@@ -259,13 +251,12 @@ class RestClient(DataStorageMethods):
|
|
259
251
|
content_type: The desired content type header. Use None for multipart uploads.
|
260
252
|
authenticated: Whether the client should include authentication.
|
261
253
|
async_client: Whether to use an async client.
|
262
|
-
timeout: Custom timeout in seconds. Uses REQUEST_TIMEOUT if not provided.
|
263
254
|
|
264
255
|
Returns:
|
265
256
|
An HTTP client configured with the appropriate headers.
|
266
257
|
"""
|
267
|
-
|
268
|
-
key = f"{content_type or 'multipart'}_{authenticated}_{async_client}
|
258
|
+
# Create a composite key based on content type and auth flag
|
259
|
+
key = f"{content_type or 'multipart'}_{authenticated}_{async_client}"
|
269
260
|
|
270
261
|
if key not in self._clients:
|
271
262
|
headers = copy.deepcopy(self.headers)
|
@@ -291,14 +282,14 @@ class RestClient(DataStorageMethods):
|
|
291
282
|
AsyncClient(
|
292
283
|
base_url=self.base_url,
|
293
284
|
headers=headers,
|
294
|
-
timeout=
|
285
|
+
timeout=self.REQUEST_TIMEOUT,
|
295
286
|
auth=auth,
|
296
287
|
)
|
297
288
|
if async_client
|
298
289
|
else Client(
|
299
290
|
base_url=self.base_url,
|
300
291
|
headers=headers,
|
301
|
-
timeout=
|
292
|
+
timeout=self.REQUEST_TIMEOUT,
|
302
293
|
auth=auth,
|
303
294
|
)
|
304
295
|
)
|
@@ -1630,16 +1621,17 @@ class RestClient(DataStorageMethods):
|
|
1630
1621
|
A list of world model names.
|
1631
1622
|
"""
|
1632
1623
|
try:
|
1624
|
+
# Use the consolidated endpoint with search parameters
|
1633
1625
|
response = self.client.get(
|
1634
|
-
"/v0.1/world-models
|
1626
|
+
"/v0.1/world-models",
|
1635
1627
|
params={
|
1636
|
-
"
|
1628
|
+
"q": query,
|
1637
1629
|
"size": size,
|
1638
|
-
"total_search_size": total_search_size,
|
1639
1630
|
"search_all_versions": search_all_versions,
|
1640
1631
|
},
|
1641
1632
|
)
|
1642
1633
|
response.raise_for_status()
|
1634
|
+
# The new endpoint returns a list of models directly
|
1643
1635
|
return response.json()
|
1644
1636
|
except HTTPStatusError as e:
|
1645
1637
|
raise WorldModelFetchError(
|
futurehouse_client/models/app.py
CHANGED
@@ -27,10 +27,7 @@ if TYPE_CHECKING:
|
|
27
27
|
MAX_CROW_JOB_RUN_TIMEOUT = 60 * 60 * 24 # 24 hours in sec
|
28
28
|
MIN_CROW_JOB_RUN_TIMEOUT = 0 # sec
|
29
29
|
|
30
|
-
|
31
|
-
class PythonVersion(StrEnum):
|
32
|
-
V3_11 = "3.11"
|
33
|
-
V3_12 = "3.12"
|
30
|
+
DEFAULT_PYTHON_VERSION_USED_FOR_JOB_BUILDS = "3.13"
|
34
31
|
|
35
32
|
|
36
33
|
class AuthType(StrEnum):
|
@@ -420,9 +417,9 @@ class JobDeploymentConfig(BaseModel):
|
|
420
417
|
description="The configuration for the cloud run container.",
|
421
418
|
)
|
422
419
|
|
423
|
-
python_version:
|
424
|
-
default=
|
425
|
-
description="The python version your docker image should build with.",
|
420
|
+
python_version: str = Field(
|
421
|
+
default=DEFAULT_PYTHON_VERSION_USED_FOR_JOB_BUILDS,
|
422
|
+
description="The python version your docker image should build with (e.g., '3.11', '3.12', '3.13').",
|
426
423
|
)
|
427
424
|
|
428
425
|
agent: Agent | AgentConfig | str = Field(
|
@@ -2,45 +2,11 @@ import asyncio
|
|
2
2
|
from collections.abc import Awaitable, Iterable
|
3
3
|
from typing import TypeVar
|
4
4
|
|
5
|
-
from httpx import (
|
6
|
-
CloseError,
|
7
|
-
ConnectError,
|
8
|
-
ConnectTimeout,
|
9
|
-
NetworkError,
|
10
|
-
ReadError,
|
11
|
-
ReadTimeout,
|
12
|
-
RemoteProtocolError,
|
13
|
-
)
|
14
|
-
from requests.exceptions import RequestException, Timeout
|
15
|
-
from tenacity import retry_if_exception_type
|
16
5
|
from tqdm.asyncio import tqdm
|
17
6
|
|
18
7
|
T = TypeVar("T")
|
19
8
|
|
20
9
|
|
21
|
-
_BASE_CONNECTION_ERRORS = (
|
22
|
-
# From requests
|
23
|
-
Timeout,
|
24
|
-
ConnectionError,
|
25
|
-
RequestException,
|
26
|
-
# From httpx
|
27
|
-
ConnectError,
|
28
|
-
ConnectTimeout,
|
29
|
-
ReadTimeout,
|
30
|
-
ReadError,
|
31
|
-
NetworkError,
|
32
|
-
RemoteProtocolError,
|
33
|
-
CloseError,
|
34
|
-
)
|
35
|
-
|
36
|
-
retry_if_connection_error = retry_if_exception_type(_BASE_CONNECTION_ERRORS)
|
37
|
-
|
38
|
-
|
39
|
-
def create_retry_if_connection_error(*additional_exceptions):
|
40
|
-
"""Create a retry condition with base connection errors plus additional exceptions."""
|
41
|
-
return retry_if_exception_type(_BASE_CONNECTION_ERRORS + additional_exceptions)
|
42
|
-
|
43
|
-
|
44
10
|
async def gather_with_concurrency(
|
45
11
|
n: int | asyncio.Semaphore, coros: Iterable[Awaitable[T]], progress: bool = False
|
46
12
|
) -> list[T]:
|
@@ -46,16 +46,17 @@ class WorldModelTools:
|
|
46
46
|
return WorldModelTools._get_client().create_world_model(world_model)
|
47
47
|
|
48
48
|
@staticmethod
|
49
|
-
def search_world_models(query: str) -> list[str]:
|
49
|
+
def search_world_models(query: str, size: int = 10) -> list[str]:
|
50
50
|
"""Search for world models using a text query.
|
51
51
|
|
52
52
|
Args:
|
53
53
|
query: The search query string to match against world model content.
|
54
|
+
size: The number of results to return (default: 10).
|
54
55
|
|
55
56
|
Returns:
|
56
57
|
list[str]: A list of world model IDs that match the search query.
|
57
58
|
"""
|
58
|
-
return WorldModelTools._get_client().search_world_models(query, size=
|
59
|
+
return WorldModelTools._get_client().search_world_models(query, size=size)
|
59
60
|
|
60
61
|
|
61
62
|
create_world_model_tool = Tool.from_function(WorldModelTools.create_world_model)
|
futurehouse_client/version.py
CHANGED
@@ -1,14 +1,7 @@
|
|
1
1
|
# file generated by setuptools-scm
|
2
2
|
# don't change, don't track in version control
|
3
3
|
|
4
|
-
__all__ = [
|
5
|
-
"__version__",
|
6
|
-
"__version_tuple__",
|
7
|
-
"version",
|
8
|
-
"version_tuple",
|
9
|
-
"__commit_id__",
|
10
|
-
"commit_id",
|
11
|
-
]
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
12
5
|
|
13
6
|
TYPE_CHECKING = False
|
14
7
|
if TYPE_CHECKING:
|
@@ -16,19 +9,13 @@ if TYPE_CHECKING:
|
|
16
9
|
from typing import Union
|
17
10
|
|
18
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
19
|
-
COMMIT_ID = Union[str, None]
|
20
12
|
else:
|
21
13
|
VERSION_TUPLE = object
|
22
|
-
COMMIT_ID = object
|
23
14
|
|
24
15
|
version: str
|
25
16
|
__version__: str
|
26
17
|
__version_tuple__: VERSION_TUPLE
|
27
18
|
version_tuple: VERSION_TUPLE
|
28
|
-
commit_id: COMMIT_ID
|
29
|
-
__commit_id__: COMMIT_ID
|
30
19
|
|
31
|
-
__version__ = version = '0.
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
33
|
-
|
34
|
-
__commit_id__ = commit_id = None
|
20
|
+
__version__ = version = '0.4.1'
|
21
|
+
__version_tuple__ = version_tuple = (0, 4, 1)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: futurehouse-client
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.1
|
4
4
|
Summary: A client for interacting with endpoints of the FutureHouse service.
|
5
5
|
Author-email: FutureHouse technical staff <hello@futurehouse.org>
|
6
6
|
License: Apache License
|
@@ -213,22 +213,18 @@ Classifier: Programming Language :: Python
|
|
213
213
|
Requires-Python: <3.14,>=3.11
|
214
214
|
Description-Content-Type: text/markdown
|
215
215
|
License-File: LICENSE
|
216
|
-
Requires-Dist: aiofiles
|
217
216
|
Requires-Dist: cloudpickle
|
218
217
|
Requires-Dist: fhaviary
|
219
|
-
Requires-Dist: google-resumable-media[aiohttp]
|
220
218
|
Requires-Dist: httpx
|
221
219
|
Requires-Dist: ldp>=0.22.0
|
222
220
|
Requires-Dist: litellm
|
223
221
|
Requires-Dist: pydantic
|
224
222
|
Requires-Dist: python-dotenv
|
225
|
-
Requires-Dist: requests
|
226
223
|
Requires-Dist: tenacity
|
227
224
|
Requires-Dist: tqdm>=4.62
|
228
225
|
Provides-Extra: dev
|
229
226
|
Requires-Dist: black; extra == "dev"
|
230
227
|
Requires-Dist: futurehouse-client[monitoring,typing]; extra == "dev"
|
231
|
-
Requires-Dist: ipykernel; extra == "dev"
|
232
228
|
Requires-Dist: jupyter; extra == "dev"
|
233
229
|
Requires-Dist: jupyterlab; extra == "dev"
|
234
230
|
Requires-Dist: mypy; extra == "dev"
|
@@ -248,7 +244,6 @@ Requires-Dist: setuptools_scm; extra == "dev"
|
|
248
244
|
Provides-Extra: monitoring
|
249
245
|
Requires-Dist: newrelic>=8.8.0; extra == "monitoring"
|
250
246
|
Provides-Extra: typing
|
251
|
-
Requires-Dist: types-PyYAML; extra == "typing"
|
252
247
|
Requires-Dist: types-requests; extra == "typing"
|
253
248
|
Requires-Dist: types-tqdm; extra == "typing"
|
254
249
|
Dynamic: license-file
|
@@ -0,0 +1,21 @@
|
|
1
|
+
futurehouse_client/__init__.py,sha256=PvFTkocA-hobsWoDEBEdrUgLIbuVbDs_0nvMdImJmHk,707
|
2
|
+
futurehouse_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
futurehouse_client/version.py,sha256=yF2DwGUoQKNnLhAbpZX8kCQKjw77EZzhRk7_OTftets,511
|
4
|
+
futurehouse_client/clients/__init__.py,sha256=-HXNj-XJ3LRO5XM6MZ709iPs29YpApss0Q2YYg1qMZw,280
|
5
|
+
futurehouse_client/clients/job_client.py,sha256=D51_qTxya6g5Wfg_ZfJdP031TV_YDJeXkGMiYAJ1qRc,11962
|
6
|
+
futurehouse_client/clients/rest_client.py,sha256=NyK6-YDcvswWcRmvMjUWvvfuE4eYMmI0bWM4Qnkgr8Y,99684
|
7
|
+
futurehouse_client/models/__init__.py,sha256=kQ4R7VEuRxO0IQEW_sk9CndBL7zzl8rUKI24ddyYLM0,647
|
8
|
+
futurehouse_client/models/app.py,sha256=UUg17I3zk6cH_7mrdojHGYvQfm_SeDkuUxsPlRyIYz0,31895
|
9
|
+
futurehouse_client/models/client.py,sha256=n4HD0KStKLm6Ek9nL9ylP-bkK10yzAaD1uIDF83Qp_A,1828
|
10
|
+
futurehouse_client/models/rest.py,sha256=ybelLsyTsKYud7DYUCF0sFF6u81bl8WmS_wWAnbX-0M,3382
|
11
|
+
futurehouse_client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
+
futurehouse_client/utils/auth.py,sha256=tgWELjKfg8eWme_qdcRmc8TjQN9DVZuHHaVXZNHLchk,2960
|
13
|
+
futurehouse_client/utils/general.py,sha256=A_rtTiYW30ELGEZlWCIArO7q1nEmqi8hUlmBRYkMQ_c,767
|
14
|
+
futurehouse_client/utils/module_utils.py,sha256=aFyd-X-pDARXz9GWpn8SSViUVYdSbuy9vSkrzcVIaGI,4955
|
15
|
+
futurehouse_client/utils/monitoring.py,sha256=UjRlufe67kI3VxRHOd5fLtJmlCbVA2Wqwpd4uZhXkQM,8728
|
16
|
+
futurehouse_client/utils/world_model_tools.py,sha256=Ctiy-EfK7EXrjmKO_nI6V5VhOJyHKWc0sKwa8Q0HAAo,2292
|
17
|
+
futurehouse_client-0.4.1.dist-info/licenses/LICENSE,sha256=oQ9ZHjUi-_6GfP3gs14FlPb0OlGwE1QCCKFGnJ4LD2I,11341
|
18
|
+
futurehouse_client-0.4.1.dist-info/METADATA,sha256=ucpuTCGRrKqqgXT8KEhy9XNLT1_e3LQdtPK-IcEKB0g,26797
|
19
|
+
futurehouse_client-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
20
|
+
futurehouse_client-0.4.1.dist-info/top_level.txt,sha256=TRuLUCt_qBnggdFHCX4O_BoCu1j2X43lKfIZC-ElwWY,19
|
21
|
+
futurehouse_client-0.4.1.dist-info/RECORD,,
|