futurehouse-client 0.0.1__py3-none-any.whl → 0.0.3__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/__init__.py +6 -6
- futurehouse_client/clients/__init__.py +6 -6
- futurehouse_client/clients/job_client.py +1 -1
- futurehouse_client/clients/rest_client.py +52 -43
- futurehouse_client/models/__init__.py +4 -4
- futurehouse_client/models/app.py +5 -5
- futurehouse_client-0.0.3.dist-info/METADATA +225 -0
- futurehouse_client-0.0.3.dist-info/RECORD +14 -0
- futurehouse_client-0.0.1.dist-info/METADATA +0 -151
- futurehouse_client-0.0.1.dist-info/RECORD +0 -14
- {futurehouse_client-0.0.1.dist-info → futurehouse_client-0.0.3.dist-info}/WHEEL +0 -0
- {futurehouse_client-0.0.1.dist-info → futurehouse_client-0.0.3.dist-info}/top_level.txt +0 -0
futurehouse_client/__init__.py
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
from .clients.job_client import JobClient, JobNames
|
2
|
-
from .clients.rest_client import
|
3
|
-
from .clients.rest_client import RestClient as
|
2
|
+
from .clients.rest_client import PQATaskResponse, TaskResponse, TaskResponseVerbose
|
3
|
+
from .clients.rest_client import RestClient as FutureHouseClient
|
4
4
|
|
5
5
|
__all__ = [
|
6
|
-
"
|
6
|
+
"FutureHouseClient",
|
7
7
|
"JobClient",
|
8
8
|
"JobNames",
|
9
|
-
"
|
10
|
-
"
|
11
|
-
"
|
9
|
+
"PQATaskResponse",
|
10
|
+
"TaskResponse",
|
11
|
+
"TaskResponseVerbose",
|
12
12
|
]
|
@@ -1,12 +1,12 @@
|
|
1
1
|
from .job_client import JobClient, JobNames
|
2
|
-
from .rest_client import
|
3
|
-
from .rest_client import RestClient as
|
2
|
+
from .rest_client import PQATaskResponse, TaskResponse, TaskResponseVerbose
|
3
|
+
from .rest_client import RestClient as FutureHouseClient
|
4
4
|
|
5
5
|
__all__ = [
|
6
|
-
"
|
6
|
+
"FutureHouseClient",
|
7
7
|
"JobClient",
|
8
8
|
"JobNames",
|
9
|
-
"
|
10
|
-
"
|
11
|
-
"
|
9
|
+
"PQATaskResponse",
|
10
|
+
"TaskResponse",
|
11
|
+
"TaskResponseVerbose",
|
12
12
|
]
|
@@ -29,9 +29,9 @@ from futurehouse_client.clients import JobNames
|
|
29
29
|
from futurehouse_client.models.app import (
|
30
30
|
APIKeyPayload,
|
31
31
|
AuthType,
|
32
|
-
|
33
|
-
JobRequest,
|
32
|
+
JobDeploymentConfig,
|
34
33
|
Stage,
|
34
|
+
TaskRequest,
|
35
35
|
)
|
36
36
|
from futurehouse_client.utils.module_utils import (
|
37
37
|
OrganizationSelector,
|
@@ -40,7 +40,7 @@ from futurehouse_client.utils.module_utils import (
|
|
40
40
|
|
41
41
|
logger = logging.getLogger(__name__)
|
42
42
|
|
43
|
-
|
43
|
+
TaskRequest.model_rebuild()
|
44
44
|
|
45
45
|
FILE_UPLOAD_IGNORE_PARTS = {
|
46
46
|
".ruff_cache",
|
@@ -56,6 +56,10 @@ class RestClientError(Exception):
|
|
56
56
|
"""Base exception for REST client errors."""
|
57
57
|
|
58
58
|
|
59
|
+
class TaskFetchError(RestClientError):
|
60
|
+
"""Raised when there's an error fetching a task."""
|
61
|
+
|
62
|
+
|
59
63
|
class JobFetchError(RestClientError):
|
60
64
|
"""Raised when there's an error fetching a job."""
|
61
65
|
|
@@ -72,22 +76,22 @@ class InvalidTaskDescriptionError(Exception):
|
|
72
76
|
JWT_TOKEN_CACHE_EXPIRY: int = 300 # seconds
|
73
77
|
|
74
78
|
|
75
|
-
class
|
76
|
-
"""Base class for
|
79
|
+
class TaskResponse(BaseModel):
|
80
|
+
"""Base class for task responses. This holds attributes shared over all futurehouse jobs."""
|
77
81
|
|
78
82
|
model_config = ConfigDict(extra="ignore")
|
79
83
|
|
80
84
|
status: str
|
81
|
-
|
85
|
+
query: str
|
82
86
|
user: str
|
83
87
|
created_at: datetime
|
84
|
-
|
88
|
+
job_name: str
|
85
89
|
public: bool
|
86
90
|
shared_with: list[str]
|
87
91
|
build_owner: str | None = None
|
88
92
|
environment_name: str | None = None
|
89
93
|
agent_name: str | None = None
|
90
|
-
|
94
|
+
task_id: UUID | None = None
|
91
95
|
|
92
96
|
@model_validator(mode="before")
|
93
97
|
@classmethod
|
@@ -95,10 +99,13 @@ class JobResponse(BaseModel):
|
|
95
99
|
# Extract fields from environment frame state
|
96
100
|
if not isinstance(data, dict):
|
97
101
|
return data
|
102
|
+
# TODO: We probably want to remove these two once we define the final names.
|
103
|
+
data["job_name"] = data.get("crow")
|
104
|
+
data["query"] = data.get("task")
|
98
105
|
if not (env_frame := data.get("environment_frame", {})):
|
99
106
|
return data
|
100
107
|
state = env_frame.get("state", {}).get("state", {})
|
101
|
-
data["
|
108
|
+
data["task_id"] = cast(UUID, state.get("id")) if state.get("id") else None
|
102
109
|
if not (metadata := data.get("metadata", {})):
|
103
110
|
return data
|
104
111
|
data["environment_name"] = metadata.get("environment_name")
|
@@ -106,7 +113,7 @@ class JobResponse(BaseModel):
|
|
106
113
|
return data
|
107
114
|
|
108
115
|
|
109
|
-
class
|
116
|
+
class PQATaskResponse(TaskResponse):
|
110
117
|
model_config = ConfigDict(extra="ignore")
|
111
118
|
|
112
119
|
answer: str | None = None
|
@@ -139,15 +146,15 @@ class PQAJobResponse(JobResponse):
|
|
139
146
|
|
140
147
|
return data
|
141
148
|
|
142
|
-
def clean_verbose(self) -> "
|
149
|
+
def clean_verbose(self) -> "TaskResponse":
|
143
150
|
"""Clean the verbose response from the server."""
|
144
151
|
self.request = None
|
145
152
|
self.response = None
|
146
153
|
return self
|
147
154
|
|
148
155
|
|
149
|
-
class
|
150
|
-
"""Class for responses to include all the fields of a
|
156
|
+
class TaskResponseVerbose(TaskResponse):
|
157
|
+
"""Class for responses to include all the fields of a task response."""
|
151
158
|
|
152
159
|
model_config = ConfigDict(extra="allow")
|
153
160
|
|
@@ -326,66 +333,66 @@ class RestClient:
|
|
326
333
|
path: Path that was searched for files
|
327
334
|
|
328
335
|
Raises:
|
329
|
-
|
336
|
+
TaskFetchError: If no files were found
|
330
337
|
|
331
338
|
"""
|
332
339
|
if not files:
|
333
|
-
raise
|
340
|
+
raise TaskFetchError(f"No files found in {path}")
|
334
341
|
|
335
342
|
@retry(
|
336
343
|
stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
|
337
344
|
wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
|
338
345
|
retry=retry_if_exception_type(Timeout),
|
339
346
|
)
|
340
|
-
def
|
341
|
-
self,
|
342
|
-
) -> "
|
343
|
-
"""Get details for a specific
|
347
|
+
def get_task(
|
348
|
+
self, task_id: str | None = None, history: bool = False, verbose: bool = False
|
349
|
+
) -> "TaskResponse":
|
350
|
+
"""Get details for a specific task."""
|
344
351
|
try:
|
345
|
-
|
352
|
+
task_id = task_id or self.trajectory_id
|
346
353
|
response = self.client.get(
|
347
|
-
f"/v0.1/trajectories/{
|
354
|
+
f"/v0.1/trajectories/{task_id}",
|
348
355
|
params={"history": history},
|
349
356
|
)
|
350
357
|
response.raise_for_status()
|
351
|
-
verbose_response =
|
358
|
+
verbose_response = TaskResponseVerbose(**response.json())
|
352
359
|
if verbose:
|
353
360
|
return verbose_response
|
354
361
|
if any(
|
355
|
-
JobNames.from_string(job_name) in verbose_response.
|
362
|
+
JobNames.from_string(job_name) in verbose_response.job_name
|
356
363
|
for job_name in ["crow", "falcon", "owl", "dummy"]
|
357
364
|
):
|
358
|
-
return
|
359
|
-
return
|
365
|
+
return PQATaskResponse(**response.json())
|
366
|
+
return TaskResponse(**response.json())
|
360
367
|
except ValueError as e:
|
361
|
-
raise ValueError("Invalid
|
368
|
+
raise ValueError("Invalid task ID format. Must be a valid UUID.") from e
|
362
369
|
except Exception as e:
|
363
|
-
raise
|
370
|
+
raise TaskFetchError(f"Error getting task: {e!s}") from e
|
364
371
|
|
365
372
|
@retry(
|
366
373
|
stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
|
367
374
|
wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
|
368
375
|
retry=retry_if_exception_type(Timeout),
|
369
376
|
)
|
370
|
-
def
|
371
|
-
"""Create a new
|
372
|
-
if isinstance(
|
373
|
-
|
374
|
-
|
375
|
-
if isinstance(
|
376
|
-
|
377
|
-
|
377
|
+
def create_task(self, task_data: TaskRequest | dict[str, Any]):
|
378
|
+
"""Create a new futurehouse task."""
|
379
|
+
if isinstance(task_data, dict):
|
380
|
+
task_data = TaskRequest.model_validate(task_data)
|
381
|
+
|
382
|
+
if isinstance(task_data.name, JobNames):
|
383
|
+
task_data.name = task_data.name.from_stage(
|
384
|
+
task_data.name.name,
|
378
385
|
self.stage,
|
379
386
|
)
|
380
387
|
|
381
388
|
try:
|
382
389
|
response = self.client.post(
|
383
|
-
"/v0.1/crows", json=
|
390
|
+
"/v0.1/crows", json=task_data.model_dump(mode="json")
|
384
391
|
)
|
385
392
|
response.raise_for_status()
|
386
393
|
self.trajectory_id = response.json()["trajectory_id"]
|
387
394
|
except Exception as e:
|
388
|
-
raise
|
395
|
+
raise TaskFetchError(f"Error creating task: {e!s}") from e
|
389
396
|
return self.trajectory_id
|
390
397
|
|
391
398
|
@retry(
|
@@ -406,11 +413,11 @@ class RestClient:
|
|
406
413
|
wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
|
407
414
|
retry=retry_if_exception_type(Timeout),
|
408
415
|
)
|
409
|
-
def
|
410
|
-
"""Creates a
|
416
|
+
def create_job(self, config: JobDeploymentConfig) -> dict[str, Any]: # noqa: PLR0915
|
417
|
+
"""Creates a futurehouse job deployment from the environment and environment files.
|
411
418
|
|
412
419
|
Args:
|
413
|
-
config: Configuration object containing all necessary parameters for
|
420
|
+
config: Configuration object containing all necessary parameters for job deployment.
|
414
421
|
|
415
422
|
Returns:
|
416
423
|
A response object containing metadata of the build.
|
@@ -429,7 +436,7 @@ class RestClient:
|
|
429
436
|
raise InvalidTaskDescriptionError(
|
430
437
|
"Task description cannot be None or empty. Ensure your from_task environment function has a valid docstring."
|
431
438
|
" If you are deploying with your Environment as a dependency, "
|
432
|
-
"you must add a `task_description` to your `
|
439
|
+
"you must add a `task_description` to your `JobDeploymentConfig`.",
|
433
440
|
)
|
434
441
|
selected_org = OrganizationSelector.select_organization(self.organizations)
|
435
442
|
if selected_org is None:
|
@@ -578,9 +585,11 @@ class RestClient:
|
|
578
585
|
except HTTPStatusError as e:
|
579
586
|
error_detail = response.json()
|
580
587
|
error_message = error_detail.get("detail", str(e))
|
581
|
-
raise
|
588
|
+
raise JobCreationError(
|
589
|
+
f"Server validation error: {error_message}"
|
590
|
+
) from e
|
582
591
|
except Exception as e:
|
583
|
-
raise
|
592
|
+
raise JobCreationError(f"Error generating docker image: {e!s}") from e
|
584
593
|
return build_context
|
585
594
|
|
586
595
|
|
@@ -1,21 +1,21 @@
|
|
1
1
|
from .app import (
|
2
2
|
AuthType,
|
3
|
-
CrowDeploymentConfig,
|
4
3
|
DockerContainerConfiguration,
|
5
4
|
FramePath,
|
6
|
-
|
5
|
+
JobDeploymentConfig,
|
7
6
|
RuntimeConfig,
|
8
7
|
Stage,
|
9
8
|
Step,
|
9
|
+
TaskRequest,
|
10
10
|
)
|
11
11
|
|
12
12
|
__all__ = [
|
13
13
|
"AuthType",
|
14
|
-
"CrowDeploymentConfig",
|
15
14
|
"DockerContainerConfiguration",
|
16
15
|
"FramePath",
|
17
|
-
"
|
16
|
+
"JobDeploymentConfig",
|
18
17
|
"RuntimeConfig",
|
19
18
|
"Stage",
|
20
19
|
"Step",
|
20
|
+
"TaskRequest",
|
21
21
|
]
|
futurehouse_client/models/app.py
CHANGED
@@ -342,7 +342,7 @@ class DockerContainerConfiguration(BaseModel):
|
|
342
342
|
return self
|
343
343
|
|
344
344
|
|
345
|
-
class
|
345
|
+
class JobDeploymentConfig(BaseModel):
|
346
346
|
model_config = ConfigDict(
|
347
347
|
extra="forbid",
|
348
348
|
arbitrary_types_allowed=True, # Allows for agent: Agent | str
|
@@ -581,7 +581,7 @@ class RuntimeConfig(BaseModel):
|
|
581
581
|
default=None,
|
582
582
|
description=(
|
583
583
|
"Agent configuration to use for this job. If None, it will default to the "
|
584
|
-
"agent selected during Crow deployment in the
|
584
|
+
"agent selected during Crow deployment in the JobDeploymentConfig object."
|
585
585
|
),
|
586
586
|
)
|
587
587
|
continued_job_id: UUID | None = Field(
|
@@ -607,10 +607,10 @@ class RuntimeConfig(BaseModel):
|
|
607
607
|
return value
|
608
608
|
|
609
609
|
|
610
|
-
class
|
611
|
-
|
610
|
+
class TaskRequest(BaseModel):
|
611
|
+
task_id: UUID | None = Field(
|
612
612
|
default=None,
|
613
|
-
description="Optional
|
613
|
+
description="Optional task identifier",
|
614
614
|
alias="id",
|
615
615
|
)
|
616
616
|
name: "str | JobNames" = Field(
|
@@ -0,0 +1,225 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: futurehouse-client
|
3
|
+
Version: 0.0.3
|
4
|
+
Summary: A client for interacting with endpoints of the FutureHouse service.
|
5
|
+
Author-email: FutureHouse technical staff <hello@futurehouse.org>
|
6
|
+
Classifier: Operating System :: OS Independent
|
7
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
8
|
+
Classifier: Programming Language :: Python :: 3.11
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
10
|
+
Classifier: Programming Language :: Python
|
11
|
+
Requires-Python: <3.13,>=3.11
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
Requires-Dist: cloudpickle
|
14
|
+
Requires-Dist: dm-tree<0.1.9
|
15
|
+
Requires-Dist: fhaviary
|
16
|
+
Requires-Dist: httpx
|
17
|
+
Requires-Dist: ldp>=0.22.0
|
18
|
+
Requires-Dist: pydantic
|
19
|
+
Requires-Dist: python-dotenv
|
20
|
+
Requires-Dist: tenacity
|
21
|
+
Provides-Extra: dev
|
22
|
+
Requires-Dist: black; extra == "dev"
|
23
|
+
Requires-Dist: jupyter; extra == "dev"
|
24
|
+
Requires-Dist: jupyterlab; extra == "dev"
|
25
|
+
Requires-Dist: mypy; extra == "dev"
|
26
|
+
Requires-Dist: notebook; extra == "dev"
|
27
|
+
Requires-Dist: pre-commit; extra == "dev"
|
28
|
+
Requires-Dist: pylint; extra == "dev"
|
29
|
+
Requires-Dist: pylint-per-file-ignores; extra == "dev"
|
30
|
+
Requires-Dist: pylint-pydantic; extra == "dev"
|
31
|
+
Requires-Dist: pytest; extra == "dev"
|
32
|
+
Requires-Dist: pytest-rerunfailures; extra == "dev"
|
33
|
+
Requires-Dist: pytest-subtests; extra == "dev"
|
34
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
35
|
+
Requires-Dist: pytest-xdist; extra == "dev"
|
36
|
+
Requires-Dist: ruff; extra == "dev"
|
37
|
+
Requires-Dist: setuptools_scm; extra == "dev"
|
38
|
+
|
39
|
+
# FutureHouse Platform API Documentation
|
40
|
+
|
41
|
+
Documentation and tutorials for crow-client, a client for interacting with endpoints of the FutureHouse crow service.
|
42
|
+
|
43
|
+
> FutureHouse's mascot is the crow. Therefore, some objects are named after the crow as a homage.
|
44
|
+
|
45
|
+
<!--TOC-->
|
46
|
+
|
47
|
+
- [Installation](#installation)
|
48
|
+
- [Quickstart](#quickstart)
|
49
|
+
- [Functionalities](#functionalities)
|
50
|
+
- [Stages](#stages)
|
51
|
+
- [Authentication](#authentication)
|
52
|
+
- [Job submission](#job-submission)
|
53
|
+
- [Job Continuation](#job-continuation)
|
54
|
+
- [Job retrieval](#job-retrieval)
|
55
|
+
|
56
|
+
<!--TOC-->
|
57
|
+
|
58
|
+
## Installation
|
59
|
+
|
60
|
+
```bash
|
61
|
+
uv pip install crow-client
|
62
|
+
```
|
63
|
+
|
64
|
+
## Quickstart
|
65
|
+
|
66
|
+
```python
|
67
|
+
from crow_client import CrowClient, JobNames
|
68
|
+
from pathlib import Path
|
69
|
+
from aviary.core import DummyEnv
|
70
|
+
import ldp
|
71
|
+
|
72
|
+
client = CrowClient(
|
73
|
+
stage=Stage.PROD,
|
74
|
+
auth_type=AuthType.API_KEY,
|
75
|
+
api_key="your_api_key",
|
76
|
+
)
|
77
|
+
|
78
|
+
job_data = {
|
79
|
+
"name": JobNames.CROW,
|
80
|
+
"query": "Has anyone tested therapeutic exerkines in humans or NHPs?",
|
81
|
+
}
|
82
|
+
|
83
|
+
job_run_id = client.create_job(job_data)
|
84
|
+
|
85
|
+
job_status = client.get_job(job_run_id)
|
86
|
+
```
|
87
|
+
|
88
|
+
A quickstart example can be found in the [crow_client_notebook.ipynb](./docs/crow_client_notebook.ipynb) file, where we show how to submit and retrieve a job task, pass runtime configuration to the agent, and ask follow-up questions to the previous job.
|
89
|
+
|
90
|
+
## Functionalities
|
91
|
+
|
92
|
+
Crow-client implements a RestClient (called `CrowClient`) with the following functionalities:
|
93
|
+
|
94
|
+
- [Authentication](#authtype): `auth_client`
|
95
|
+
- [Job submission](#job-submission): `create_job(JobRequest)`
|
96
|
+
- [Job status](#job-status): `get_job(job_id)`
|
97
|
+
|
98
|
+
To create a `CrowClient`, you need to pass the following parameters:
|
99
|
+
| Parameter | Type | Default | Description |
|
100
|
+
| --- | --- | --- | --- |
|
101
|
+
| stage | Stage | Stage.DEV | Where the job will be submitted? |
|
102
|
+
| organization | str \| None | None | Which organization to use? |
|
103
|
+
| auth_type | AuthType | AuthType.API_KEY | Which authentication method to use? |
|
104
|
+
| api_key | str \| None | None | The API key to use for authentication, if using auth_type=AuthType.API_KEY. |
|
105
|
+
|
106
|
+
To instantiate a Client, we can use the following code:
|
107
|
+
|
108
|
+
```python
|
109
|
+
from crow_client import CrowClient
|
110
|
+
from crow_client.models import Stage, AuthType
|
111
|
+
|
112
|
+
client = CrowClient(
|
113
|
+
stage=Stage.PROD,
|
114
|
+
organization="your_organization",
|
115
|
+
auth_type=AuthType.API_KEY,
|
116
|
+
api_key="your_api_key",
|
117
|
+
)
|
118
|
+
```
|
119
|
+
|
120
|
+
### Stages
|
121
|
+
|
122
|
+
The stage is where your job will be submitted. This parameter can be one of the following:
|
123
|
+
| Name | Description |
|
124
|
+
| --- | --- |
|
125
|
+
| Stage.DEV | Development environment at https://dev.api.platform.futurehouse.org |
|
126
|
+
| Stage.PROD | Production environment at https://api.platform.futurehouse.org |
|
127
|
+
|
128
|
+
## Authentication
|
129
|
+
|
130
|
+
In order to use the `CrowClient`, you need to authenticate yourself. Authentication is done by providing an API key, which can be obtained directly from your [profile page in the FutureHouse platform](https://platform.futurehouse.org/profile).
|
131
|
+
|
132
|
+
## Job submission
|
133
|
+
|
134
|
+
`CrowClient` can be used to submit jobs to the FutureHouse platform. Using a `CrowClient` instance, you can submit jobs to the platform by calling the `create_job` method, which receives a `JobRequest` (or a dictionary with `kwargs`) and returns the job id.
|
135
|
+
Aiming to make the submission of jobs as simple as possible, we have created a `JobNames` enum that contains the available job types.
|
136
|
+
|
137
|
+
The available supported jobs are:
|
138
|
+
| Alias | Job Name | Task type | Description |
|
139
|
+
| --- | --- | --- | --- |
|
140
|
+
| `JobNames.CROW` | `job-futurehouse-paperqa2` | Fast Search | Ask a question of scientific data sources, and receive a high-accuracy, cited response. Built with [PaperQA2](https://github.com/Future-House/paper-qa). |
|
141
|
+
| `JobNames.FALCON` | `job-futurehouse-paperqa2-deep` | Deep Search | Use a plethora of sources to deeply research. Receive a detailed, structured report as a response. |
|
142
|
+
| `JobNames.OWL` | `job-futurehouse-hasanyone` | Precedent Search | Formerly known as HasAnyone, query if anyone has ever done something in science. |
|
143
|
+
| `JobNames.DUMMY` | `job-futurehouse-dummy` | Dummy Task | This is a dummy task. Mainly for testing purposes. |
|
144
|
+
|
145
|
+
Using `JobNames`, the client automatically adapts the job name to the current stage.
|
146
|
+
The job submission looks like this:
|
147
|
+
|
148
|
+
```python
|
149
|
+
from crow_client import CrowClient, JobNames
|
150
|
+
from crow_client.models import AuthType, Stage
|
151
|
+
|
152
|
+
client = CrowClient(
|
153
|
+
stage=Stage.PROD,
|
154
|
+
auth_type=AuthType.API_KEY,
|
155
|
+
api_key="your_api_key",
|
156
|
+
)
|
157
|
+
|
158
|
+
job_data = {
|
159
|
+
"name": JobNames.CROW,
|
160
|
+
"query": "Has anyone tested therapeutic exerkines in humans or NHPs?",
|
161
|
+
}
|
162
|
+
|
163
|
+
job_id = client.create_job(job_data)
|
164
|
+
```
|
165
|
+
|
166
|
+
`JobRequest` has the following fields:
|
167
|
+
|
168
|
+
| Field | Type | Description |
|
169
|
+
| -------------- | ------------- | ------------------------------------------------------------------------------------------------------------------- |
|
170
|
+
| id | UUID | Optional job identifier. A UUID will be generated if not provided |
|
171
|
+
| name | str | Name of the job to execute eg. `job-futurehouse-paperqa2`, or using the `JobNames` for convenience: `JobNames.CROW` |
|
172
|
+
| query | str | Query or task to be executed by the job |
|
173
|
+
| runtime_config | RuntimeConfig | Optional runtime parameters for the job |
|
174
|
+
|
175
|
+
`runtime_config` can receive a `AgentConfig` object with the desired kwargs. Check the available `AgentConfig` fields in the [LDP documentation](https://github.com/Future-House/ldp/blob/main/src/ldp/agent/agent.py#L87). Besides the `AgentConfig` object, we can also pass `timeout` and `max_steps` to limit the execution time and the number of steps the agent can take.
|
176
|
+
Other especialised configurations are also available but are outside the scope of this documentation.
|
177
|
+
|
178
|
+
## Job Continuation
|
179
|
+
|
180
|
+
Once a job is submitted and the answer is returned, FutureHouse platform allow you to ask follow-up questions to the previous job.
|
181
|
+
It is also possible through the platform API.
|
182
|
+
To accomplish that, we can use the `runtime_config` we discussed in the [Job submission](#job-submission) section.
|
183
|
+
|
184
|
+
```python
|
185
|
+
from crow_client import CrowClient, JobNames
|
186
|
+
from crow_client.models import AuthType, Stage
|
187
|
+
|
188
|
+
client = CrowClient(
|
189
|
+
stage=Stage.PROD,
|
190
|
+
auth_type=AuthType.API_KEY,
|
191
|
+
api_key="your_api_key",
|
192
|
+
)
|
193
|
+
|
194
|
+
job_data = {"name": JobNames.CROW, "query": "How many species of birds are there?"}
|
195
|
+
|
196
|
+
job_id = client.create_job(job_data)
|
197
|
+
|
198
|
+
continued_job_data = {
|
199
|
+
"name": JobNames.CROW,
|
200
|
+
"query": "From the previous answer, specifically,how many species of crows are there?",
|
201
|
+
"runtime_config": {"continued_job_id": job_id},
|
202
|
+
}
|
203
|
+
|
204
|
+
continued_job_id = client.create_job(continued_job_data)
|
205
|
+
```
|
206
|
+
|
207
|
+
## Job retrieval
|
208
|
+
|
209
|
+
Once a job is submitted, you can retrieve it by calling the `get_job` method, which receives a job id and returns a `JobResponse` object.
|
210
|
+
|
211
|
+
```python
|
212
|
+
from crow_client import CrowClient
|
213
|
+
from crow_client.models import AuthType
|
214
|
+
|
215
|
+
client = CrowClient(
|
216
|
+
auth_type=AuthType.API_KEY,
|
217
|
+
api_key="your_api_key",
|
218
|
+
)
|
219
|
+
|
220
|
+
job_id = "job_id"
|
221
|
+
|
222
|
+
job_status = client.get_job(job_id)
|
223
|
+
```
|
224
|
+
|
225
|
+
`job_status` contains information about the job. For instance, its `status`, `task`, `environment_name` and `agent_name`, and other fields specific to the job.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
futurehouse_client/__init__.py,sha256=ddxO7JE97c6bt7LjNglZZ2Ql8bYCGI9laSFeh9MP6VU,344
|
2
|
+
futurehouse_client/clients/__init__.py,sha256=tFWqwIAY5PvwfOVsCje4imjTpf6xXNRMh_UHIKVI1_0,320
|
3
|
+
futurehouse_client/clients/job_client.py,sha256=RNgdSJVI1vjQSypdfswHX0Gvv_XnKG4bZjklf3WdSuk,8828
|
4
|
+
futurehouse_client/clients/rest_client.py,sha256=xZs4cHVzuKu4X9xOlhqRN0EdEDP99sGp8cgx5gS8McM,25115
|
5
|
+
futurehouse_client/models/__init__.py,sha256=ta3jFLM_LsDz1rKDmx8rja8sT7WtSKoFvMgLF0yFpvA,342
|
6
|
+
futurehouse_client/models/app.py,sha256=G8_-I3aQnRIyxFJT3snTSWsPcZZ2nEvYkRaE5sVdeys,22299
|
7
|
+
futurehouse_client/models/client.py,sha256=n4HD0KStKLm6Ek9nL9ylP-bkK10yzAaD1uIDF83Qp_A,1828
|
8
|
+
futurehouse_client/models/rest.py,sha256=W-wNFTN7HALYFFphw-RQYRMm6_TSa1cl4T-mZ1msk90,393
|
9
|
+
futurehouse_client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
futurehouse_client/utils/module_utils.py,sha256=aFyd-X-pDARXz9GWpn8SSViUVYdSbuy9vSkrzcVIaGI,4955
|
11
|
+
futurehouse_client-0.0.3.dist-info/METADATA,sha256=SWITZXjP7BUoM4Ze6KAIvrcYLx8TCBKyUaJVEFyJgYw,8898
|
12
|
+
futurehouse_client-0.0.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
13
|
+
futurehouse_client-0.0.3.dist-info/top_level.txt,sha256=TRuLUCt_qBnggdFHCX4O_BoCu1j2X43lKfIZC-ElwWY,19
|
14
|
+
futurehouse_client-0.0.3.dist-info/RECORD,,
|
@@ -1,151 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: futurehouse-client
|
3
|
-
Version: 0.0.1
|
4
|
-
Summary: A client for interacting with endpoints of the FutureHouse service.
|
5
|
-
Author-email: FutureHouse technical staff <hello@futurehouse.org>
|
6
|
-
Classifier: Operating System :: OS Independent
|
7
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
8
|
-
Classifier: Programming Language :: Python :: 3.11
|
9
|
-
Classifier: Programming Language :: Python :: 3.12
|
10
|
-
Classifier: Programming Language :: Python
|
11
|
-
Requires-Python: <3.13,>=3.11
|
12
|
-
Description-Content-Type: text/markdown
|
13
|
-
Requires-Dist: cloudpickle
|
14
|
-
Requires-Dist: dm-tree<0.1.9
|
15
|
-
Requires-Dist: fhaviary
|
16
|
-
Requires-Dist: httpx
|
17
|
-
Requires-Dist: ldp>=0.22.0
|
18
|
-
Requires-Dist: pydantic
|
19
|
-
Requires-Dist: python-dotenv
|
20
|
-
Requires-Dist: tenacity
|
21
|
-
Provides-Extra: dev
|
22
|
-
Requires-Dist: black; extra == "dev"
|
23
|
-
Requires-Dist: jupyter; extra == "dev"
|
24
|
-
Requires-Dist: jupyterlab; extra == "dev"
|
25
|
-
Requires-Dist: mypy; extra == "dev"
|
26
|
-
Requires-Dist: notebook; extra == "dev"
|
27
|
-
Requires-Dist: pre-commit; extra == "dev"
|
28
|
-
Requires-Dist: pylint; extra == "dev"
|
29
|
-
Requires-Dist: pylint-per-file-ignores; extra == "dev"
|
30
|
-
Requires-Dist: pylint-pydantic; extra == "dev"
|
31
|
-
Requires-Dist: pytest; extra == "dev"
|
32
|
-
Requires-Dist: pytest-rerunfailures; extra == "dev"
|
33
|
-
Requires-Dist: pytest-subtests; extra == "dev"
|
34
|
-
Requires-Dist: pytest-timeout; extra == "dev"
|
35
|
-
Requires-Dist: pytest-xdist; extra == "dev"
|
36
|
-
Requires-Dist: ruff; extra == "dev"
|
37
|
-
Requires-Dist: setuptools_scm; extra == "dev"
|
38
|
-
|
39
|
-
# crow-client
|
40
|
-
|
41
|
-
A client for interacting with endpoints of the FutureHouse crow service.
|
42
|
-
|
43
|
-
## Installation
|
44
|
-
|
45
|
-
```bash
|
46
|
-
uv pip install crow-client
|
47
|
-
```
|
48
|
-
|
49
|
-
## Usage
|
50
|
-
|
51
|
-
The CrowClient provides simple functions to deploy and monitor your crow.
|
52
|
-
|
53
|
-
In the case of environments the deployment looks like this
|
54
|
-
|
55
|
-
```python
|
56
|
-
from pathlib import Path
|
57
|
-
from crow_client import CrowClient
|
58
|
-
from crow_client.models import CrowDeploymentConfig
|
59
|
-
|
60
|
-
client = CrowClient()
|
61
|
-
|
62
|
-
crow = CrowDeploymentConfig(
|
63
|
-
path=Path("../envs/dummy_env"),
|
64
|
-
environment="dummy_env.env.DummyEnv",
|
65
|
-
requires_aviary_internal=False,
|
66
|
-
environment_variables={"SAMPLE_ENV_VAR": "sample_val"},
|
67
|
-
agent="ldp.agent.SimpleAgent",
|
68
|
-
)
|
69
|
-
|
70
|
-
client.create_crow(crow)
|
71
|
-
|
72
|
-
# checks the status
|
73
|
-
client.get_build_status()
|
74
|
-
```
|
75
|
-
|
76
|
-
For functional environments we don't need to pass the file path and can pass the environment builder instead
|
77
|
-
|
78
|
-
```python
|
79
|
-
from aviary.core import fenv
|
80
|
-
import numpy as np
|
81
|
-
|
82
|
-
|
83
|
-
def function_to_use_here(inpste: str):
|
84
|
-
a = np.array(np.asmatrix("1 2; 3 4"))
|
85
|
-
return inpste
|
86
|
-
|
87
|
-
|
88
|
-
@fenv.start()
|
89
|
-
def my_env(topic: str):
|
90
|
-
"""
|
91
|
-
Here is the doc string describing the task.
|
92
|
-
"""
|
93
|
-
a = np.array(np.asmatrix("1 2; 3 4"))
|
94
|
-
return f"Write a sad story about {topic}", {"chosen_topic": topic}
|
95
|
-
|
96
|
-
|
97
|
-
@my_env.tool()
|
98
|
-
def print_story(story: str, state) -> None:
|
99
|
-
"""Print the story and complete the task"""
|
100
|
-
print(story)
|
101
|
-
print(function_to_use_here(story))
|
102
|
-
state.reward = 1
|
103
|
-
state.done = True
|
104
|
-
|
105
|
-
|
106
|
-
from crow_client import CrowClient
|
107
|
-
from crow_client.models import CrowDeploymentConfig, Stage
|
108
|
-
from crow_client.clients.rest_client import generate_requirements
|
109
|
-
|
110
|
-
client = CrowClient(stage=Stage.LOCAL)
|
111
|
-
|
112
|
-
crow = CrowDeploymentConfig(
|
113
|
-
functional_environment=my_env,
|
114
|
-
environment="my_env",
|
115
|
-
requires_aviary_internal=False,
|
116
|
-
environment_variables={"SAMPLE_ENV_VAR": "sample_val"},
|
117
|
-
agent="ldp.agent.SimpleAgent",
|
118
|
-
requirements=generate_requirements(my_env, globals()),
|
119
|
-
)
|
120
|
-
|
121
|
-
client.create_crow(crow)
|
122
|
-
```
|
123
|
-
|
124
|
-
This client also provides functions that let you send tasks to an existing crow:
|
125
|
-
|
126
|
-
```python
|
127
|
-
from crow_client import CrowJob
|
128
|
-
|
129
|
-
client = CrowClient()
|
130
|
-
|
131
|
-
job_data = {"name": "your-job-name", "query": "your task"}
|
132
|
-
client.create_job(job_data)
|
133
|
-
|
134
|
-
# checks the status
|
135
|
-
client.get_job()
|
136
|
-
```
|
137
|
-
|
138
|
-
The CrowJobClient provides an interface for managing environment states and agent interactions in the FutureHouse crow service.
|
139
|
-
|
140
|
-
```python
|
141
|
-
from crow_client import CrowJobClient
|
142
|
-
from crow_client.models.app import Stage
|
143
|
-
|
144
|
-
client = CrowJobClient(
|
145
|
-
environment="your_environment_name",
|
146
|
-
agent="your_agent_id",
|
147
|
-
auth_token="your_auth_token",
|
148
|
-
base_uri=Stage.DEV,
|
149
|
-
trajectory_id=None,
|
150
|
-
)
|
151
|
-
```
|
@@ -1,14 +0,0 @@
|
|
1
|
-
futurehouse_client/__init__.py,sha256=SaaBeLHh4K81dONiXxowhsgM-Zr12t1g-phDgwi5iWc,316
|
2
|
-
futurehouse_client/clients/__init__.py,sha256=OWJtj6WNJ1GvzA5v-Z8yiKlta47k4dprih-9n7mag40,300
|
3
|
-
futurehouse_client/clients/job_client.py,sha256=M0siUz-5Ffri4_fhXXeBb54qnELwMa1hYzosS8bx3ek,8833
|
4
|
-
futurehouse_client/clients/rest_client.py,sha256=dEes4lP0JOsuRoFgjhU9uXSogBGFOWgSw8ZfopUJ4w8,24734
|
5
|
-
futurehouse_client/models/__init__.py,sha256=VBKYb_2kmxtDwp9LvTL7BEFyioekggQsrQg5I_dhZoI,342
|
6
|
-
futurehouse_client/models/app.py,sha256=_MO31xvKJaAztWz4KrV13ty4POg-RuWrGgqmvS9w2bc,22298
|
7
|
-
futurehouse_client/models/client.py,sha256=n4HD0KStKLm6Ek9nL9ylP-bkK10yzAaD1uIDF83Qp_A,1828
|
8
|
-
futurehouse_client/models/rest.py,sha256=W-wNFTN7HALYFFphw-RQYRMm6_TSa1cl4T-mZ1msk90,393
|
9
|
-
futurehouse_client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
futurehouse_client/utils/module_utils.py,sha256=aFyd-X-pDARXz9GWpn8SSViUVYdSbuy9vSkrzcVIaGI,4955
|
11
|
-
futurehouse_client-0.0.1.dist-info/METADATA,sha256=L7c7KYAcl5HgkRBNmjHS0xnWmZb4QHwmAS3-vrLmtsw,4076
|
12
|
-
futurehouse_client-0.0.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
13
|
-
futurehouse_client-0.0.1.dist-info/top_level.txt,sha256=TRuLUCt_qBnggdFHCX4O_BoCu1j2X43lKfIZC-ElwWY,19
|
14
|
-
futurehouse_client-0.0.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|