futurehouse-client 0.3.20.dev63__py3-none-any.whl → 0.3.20.dev112__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.
@@ -8,6 +8,11 @@ from .models.app import (
8
8
  TaskResponse,
9
9
  TaskResponseVerbose,
10
10
  )
11
+ from .utils.world_model_tools import (
12
+ create_world_model_tool,
13
+ search_world_model_tool,
14
+ make_world_model_tools,
15
+ )
11
16
 
12
17
  __all__ = [
13
18
  "FinchTaskResponse",
@@ -19,4 +24,7 @@ __all__ = [
19
24
  "TaskRequest",
20
25
  "TaskResponse",
21
26
  "TaskResponseVerbose",
27
+ "create_world_model_tool",
28
+ "search_world_model_tool",
29
+ "make_world_model_tools",
22
30
  ]
@@ -73,7 +73,7 @@ class JobNames(StrEnum):
73
73
 
74
74
  @staticmethod
75
75
  def get_response_object_from_job(job_name: str) -> type[TaskResponse]:
76
- return JobNames._get_response_mapping()[job_name]
76
+ return JobNames._get_response_mapping().get(job_name, TaskResponse)
77
77
 
78
78
  def get_response_object(self) -> type[TaskResponse]:
79
79
  return self._get_response_mapping()[self.name]
@@ -111,6 +111,8 @@ class WorldModelFetchError(RestClientError):
111
111
  class WorldModelCreationError(RestClientError):
112
112
  """Raised when there's an error creating a world model."""
113
113
 
114
+ class WorldModelDeletionError(RestClientError):
115
+ """Raised when there's an error deleting a world model."""
114
116
 
115
117
  class InvalidTaskDescriptionError(Exception):
116
118
  """Raised when the task description is invalid or empty."""
@@ -139,6 +141,7 @@ retry_if_connection_error = retry_if_exception_type((
139
141
  DEFAULT_AGENT_TIMEOUT: int = 2400 # seconds
140
142
 
141
143
 
144
+ # pylint: disable=too-many-public-methods
142
145
  class RestClient:
143
146
  REQUEST_TIMEOUT: ClassVar[float] = 30.0 # sec
144
147
  MAX_RETRY_ATTEMPTS: ClassVar[int] = 3
@@ -1419,15 +1422,9 @@ class RestClient:
1419
1422
  if not (world_model_id or name) or (world_model_id and name):
1420
1423
  raise ValueError("Provide either 'world_model_id' or 'name', but not both.")
1421
1424
 
1422
- params = {
1423
- "id": str(world_model_id) if world_model_id else None,
1424
- "name": name,
1425
- }
1426
- # Filter out None values before making the request
1427
- params = {k: v for k, v in params.items() if v is not None}
1428
-
1429
1425
  try:
1430
- response = self.client.get("/v0.1/world-model", params=params)
1426
+ identifier = str(world_model_id) if world_model_id else name
1427
+ response = self.client.get(f"/v0.1/world-models/{identifier}")
1431
1428
  response.raise_for_status()
1432
1429
  return WorldModelResponse.model_validate(response.json())
1433
1430
  except HTTPStatusError as e:
@@ -1465,14 +1462,9 @@ class RestClient:
1465
1462
  if not (world_model_id or name) or (world_model_id and name):
1466
1463
  raise ValueError("Provide either 'world_model_id' or 'name', but not both.")
1467
1464
 
1468
- params = {
1469
- "id": str(world_model_id) if world_model_id else None,
1470
- "name": name,
1471
- }
1472
- params = {k: v for k, v in params.items() if v is not None}
1473
-
1474
1465
  try:
1475
- response = await self.async_client.get("/v0.1/world-model", params=params)
1466
+ identifier = str(world_model_id) if world_model_id else name
1467
+ response = await self.async_client.get(f"/v0.1/world-models/{identifier}")
1476
1468
  response.raise_for_status()
1477
1469
  return WorldModelResponse.model_validate(response.json())
1478
1470
  except HTTPStatusError as e:
@@ -1486,6 +1478,25 @@ class RestClient:
1486
1478
  except Exception as e:
1487
1479
  raise WorldModelFetchError(f"An unexpected error occurred: {e}") from e
1488
1480
 
1481
+ @retry(
1482
+ stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
1483
+ wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
1484
+ retry=retry_if_connection_error,
1485
+ )
1486
+ def search_world_models(self, query: str, size: int = 10) -> list[str]:
1487
+ """Search for world models.
1488
+
1489
+ Args:
1490
+ query: The search query.
1491
+ size: The number of results to return.
1492
+
1493
+ Returns:
1494
+ A list of world model names.
1495
+ """
1496
+ response = self.client.get(f"/v0.1/world-models/search/{query}", params={"size": size})
1497
+ response.raise_for_status()
1498
+ return response.json()
1499
+
1489
1500
  @retry(
1490
1501
  stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
1491
1502
  wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
@@ -1559,7 +1570,30 @@ class RestClient:
1559
1570
  f"An unexpected error occurred during world model creation: {e}"
1560
1571
  ) from e
1561
1572
 
1573
+ @retry(
1574
+ stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
1575
+ wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
1576
+ retry=retry_if_connection_error,
1577
+ )
1578
+ async def delete_world_model(self, world_model_id: UUID) -> None:
1579
+ """Delete a world model snapshot by its ID.
1580
+
1581
+ Args:
1582
+ world_model_id: The unique ID of the world model snapshot to delete.
1562
1583
 
1584
+ Raises:
1585
+ WorldModelDeletionError: If the API call fails.
1586
+ """
1587
+ try:
1588
+ response = await self.async_client.delete(f"/v0.1/world-models/{world_model_id}")
1589
+ response.raise_for_status()
1590
+ except HTTPStatusError as e:
1591
+ raise WorldModelDeletionError(
1592
+ f"Error deleting world model: {e.response.status_code} - {e.response.text}"
1593
+ ) from e
1594
+ except Exception as e:
1595
+ raise WorldModelDeletionError(f"An unexpected error occurred: {e}") from e
1596
+
1563
1597
  def get_installed_packages() -> dict[str, str]:
1564
1598
  """Returns a dictionary of installed packages and their versions."""
1565
1599
  return {
@@ -610,7 +610,7 @@ class RuntimeConfig(BaseModel):
610
610
  default=None,
611
611
  description="Optional job identifier for a continued job",
612
612
  )
613
- world_model_id: UUID | None = Field(
613
+ world_model_id: UUID | str | None = Field(
614
614
  default=None,
615
615
  description="Optional world model identifier for the task",
616
616
  )
@@ -46,10 +46,10 @@ class WorldModel(BaseModel):
46
46
  """
47
47
 
48
48
  content: str
49
- prior: UUID | None = None
49
+ prior: UUID | str | None = None
50
50
  name: str | None = None
51
51
  description: str | None = None
52
- trajectory_id: UUID | None = None
52
+ trajectory_id: UUID | str | None = None
53
53
  model_metadata: JsonValue | None = None
54
54
 
55
55
 
@@ -60,12 +60,12 @@ class WorldModelResponse(BaseModel):
60
60
  This model is received from the API.
61
61
  """
62
62
 
63
- id: UUID
64
- prior: UUID | None
63
+ id: UUID | str
64
+ prior: UUID | str | None
65
65
  name: str
66
66
  description: str | None
67
67
  content: str
68
- trajectory_id: UUID | None
68
+ trajectory_id: UUID | str | None
69
69
  email: str | None
70
70
  model_metadata: JsonValue | None
71
71
  enabled: bool
@@ -0,0 +1,52 @@
1
+ from futurehouse_client.clients.rest_client import RestClient
2
+ from futurehouse_client.models.app import Stage
3
+ from futurehouse_client.models.rest import WorldModel
4
+ from uuid import UUID
5
+ from aviary.core import Tool
6
+
7
+
8
+ class WorldModelTools:
9
+ CLIENT = RestClient(
10
+ stage = Stage.DEV,
11
+ api_key="Dk7WJRLpqTFNxp5dYRoj6A.platformv01.eyJqdGkiOiI4ODAyZmZiNy1hNjM2LTRkMWYtYWE4NC1lZTQzYTMzMzRjZGMiLCJzdWIiOiJuN1dJbGU5VDljZ1BkTjd2OUJlM0pEUlpZVTgyIiwiaWF0IjoxNzQ5MDc2NzYzfQ.vThmFNLChP54DZBwB+qeMTB6CvAQ1IVXkTcpB0+efZ0",
12
+ )
13
+
14
+ @staticmethod
15
+ def create_world_model(name: str, description: str, content: str) -> UUID:
16
+ """Create a new world model.
17
+
18
+ Args:
19
+ name: The name of the world model.
20
+ description: A description of the world model.
21
+ content: The content/data of the world model.
22
+
23
+ Returns:
24
+ UUID: The ID of the newly created world model.
25
+ """
26
+ world_model = WorldModel(
27
+ name=name,
28
+ description=description,
29
+ content=content,
30
+ )
31
+ return WorldModelTools.CLIENT.create_world_model(world_model)
32
+
33
+ @staticmethod
34
+ def search_world_models(query: str) -> list[str]:
35
+ """Search for world models using a text query.
36
+
37
+ Args:
38
+ query: The search query string to match against world model content.
39
+
40
+ Returns:
41
+ list[str]: A list of world model IDs that match the search query.
42
+ """
43
+ return WorldModelTools.CLIENT.search_world_models(query, size=1)
44
+
45
+ create_world_model_tool = Tool.from_function(WorldModelTools.create_world_model)
46
+ search_world_model_tool = Tool.from_function(WorldModelTools.search_world_models)
47
+
48
+ def make_world_model_tools() -> list[Tool]:
49
+ return [
50
+ search_world_model_tool,
51
+ create_world_model_tool,
52
+ ]
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.3.20.dev63'
21
- __version_tuple__ = version_tuple = (0, 3, 20, 'dev63')
20
+ __version__ = version = '0.3.20.dev112'
21
+ __version_tuple__ = version_tuple = (0, 3, 20, 'dev112')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: futurehouse-client
3
- Version: 0.3.20.dev63
3
+ Version: 0.3.20.dev112
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
@@ -0,0 +1,21 @@
1
+ futurehouse_client/__init__.py,sha256=rRAJFxDI0nDHiMkyB-d7Q8Y2vVKFVnIFwOuRdjClTPw,707
2
+ futurehouse_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ futurehouse_client/version.py,sha256=nAw6MsWnD67V5v8vArdCA5jF1Rjl2uTamVcuYk2lPQo,530
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=hDV1Pr9gemChBKtklnlZlrwSYVUfHEGNGGmVDhoByIw,63015
7
+ futurehouse_client/models/__init__.py,sha256=5x-f9AoM1hGzJBEHcHAXSt7tPeImST5oZLuMdwp0mXc,554
8
+ futurehouse_client/models/app.py,sha256=TrfSorJlxyuc9ZzJpd2tL1pzKOp3jNBYRqFMfmmUue0,28954
9
+ futurehouse_client/models/client.py,sha256=n4HD0KStKLm6Ek9nL9ylP-bkK10yzAaD1uIDF83Qp_A,1828
10
+ futurehouse_client/models/rest.py,sha256=AwPMcB1ruoqaI8NIhX2ZzN8UuX6XsaQ7uzeSE8EpwKk,1573
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=f-Q1X55HuisYyfTEHhhLMY_VamSMCkdXuHHp_V509bc,1899
17
+ futurehouse_client-0.3.20.dev112.dist-info/licenses/LICENSE,sha256=oQ9ZHjUi-_6GfP3gs14FlPb0OlGwE1QCCKFGnJ4LD2I,11341
18
+ futurehouse_client-0.3.20.dev112.dist-info/METADATA,sha256=a4IX4zQbKP51L71qkqjS8--fvdyIGVQZqneJn7DZuLg,26118
19
+ futurehouse_client-0.3.20.dev112.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
+ futurehouse_client-0.3.20.dev112.dist-info/top_level.txt,sha256=TRuLUCt_qBnggdFHCX4O_BoCu1j2X43lKfIZC-ElwWY,19
21
+ futurehouse_client-0.3.20.dev112.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- futurehouse_client/__init__.py,sha256=BztM_ntbgmIEjzvnBWcvPhvLjM8xGDFCK0Upf3-nIn8,488
2
- futurehouse_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- futurehouse_client/version.py,sha256=isTppsUF5LzE3BUYjhyccnSnZwGsbVa_dNrIiEiEViQ,528
4
- futurehouse_client/clients/__init__.py,sha256=-HXNj-XJ3LRO5XM6MZ709iPs29YpApss0Q2YYg1qMZw,280
5
- futurehouse_client/clients/job_client.py,sha256=JgB5IUAyCmnhGRsYc3bgKldA-lkM1JLwHRwwUeOCdus,11944
6
- futurehouse_client/clients/rest_client.py,sha256=fltCx1kCSZKLD-2QNPmK2PbXPa0q0zW9Q3837xS_6TQ,61554
7
- futurehouse_client/models/__init__.py,sha256=5x-f9AoM1hGzJBEHcHAXSt7tPeImST5oZLuMdwp0mXc,554
8
- futurehouse_client/models/app.py,sha256=fIWATuetex9GuNzGAWQz-9Dc63ifEFl-Mv-UN7nGSfA,28948
9
- futurehouse_client/models/client.py,sha256=n4HD0KStKLm6Ek9nL9ylP-bkK10yzAaD1uIDF83Qp_A,1828
10
- futurehouse_client/models/rest.py,sha256=QqOhRT-qTMfLtNge458qyBv6JFZvoQULnGIjjcDvMy8,1543
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-0.3.20.dev63.dist-info/licenses/LICENSE,sha256=oQ9ZHjUi-_6GfP3gs14FlPb0OlGwE1QCCKFGnJ4LD2I,11341
17
- futurehouse_client-0.3.20.dev63.dist-info/METADATA,sha256=4hmqtHLV-eHTN3l8vXmtIW4L6TFAkBDymbjyg7_rBJQ,26117
18
- futurehouse_client-0.3.20.dev63.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- futurehouse_client-0.3.20.dev63.dist-info/top_level.txt,sha256=TRuLUCt_qBnggdFHCX4O_BoCu1j2X43lKfIZC-ElwWY,19
20
- futurehouse_client-0.3.20.dev63.dist-info/RECORD,,