# Edison Platform API Documentation

[![PyPI version](https://badge.fury.io/py/edison-client.svg)](https://badge.fury.io/py/edison-client) ![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg) ![PyPI Python Versions](https://img.shields.io/pypi/pyversions/edison-client)

Documentation and tutorials for edison-client, a client for interacting with endpoints of the Edison platform.

* [Installation](#installation)
* [Quickstart](#quickstart)
* [Functionalities](#functionalities)
* [Authentication](#authentication)
* [Simple task running](#simple-task-running)
* [Task Continuation](#task-continuation)
* [Asynchronous tasks](#asynchronous-tasks)

## Installation

```bash
uv pip install edison-client
```

## Quickstart

```python
from edison_client import EdisonClient, JobNames

client = EdisonClient(
    api_key="your_api_key",
)

task_data = {
    "name": JobNames.LITERATURE,
    "query": "Which neglected diseases had a treatment developed by artificial intelligence?",
}

task_response = client.run_tasks_until_done(task_data)
```

A quickstart example can be found in the [client\_notebook.ipynb](https://github.com/Future-House/crow-client-docs/blob/main/docs/client_notebook.ipynb) file, where we show how to submit and retrieve a task, pass runtime configuration to the agent, and ask follow-up questions to the previous task.

## Functionalities

Edison client implements a RestClient (called `EdisonClient`) with the following functionalities:

* [Simple task running](#simple-task-running): `run_tasks_until_done(TaskRequest)` or `await arun_tasks_until_done(TaskRequest)`
* [Asynchronous tasks](#asynchronous-tasks): `get_task(task_id)` or `aget_task(task_id)` and `create_task(TaskRequest)` or `acreate_task(TaskRequest)`

To create a `EdisonClient`, you need to pass an Edison Scientific platform api key (see [Authentication](#authentication)):

```python
from edison_client import EdisonClient

client = EdisonClient(
    api_key="your_api_key",
)
```

## Authentication

In order to use the `EdisonClient`, you need to authenticate yourself. Authentication is done by providing an API key, which can be obtained directly from your [profile page in the Edison platform](https://platform.edisonscientific.com/profile).

## Simple task running

In the Edison platform, we define the deployed combination of an agent and an environment as a `job`. To invoke a job, we need to submit a `task` (also called a `query`) to it. `EdisonClient` can be used to submit tasks/queries to available jobs in the Edison platform. Using a `EdisonClient` instance, you can submit tasks to the platform by calling the `create_task` method, which receives a `TaskRequest` (or a dictionary with `kwargs`) and returns the task id. Aiming to make the submission of tasks as simple as possible, we have created a `JobNames` `enum` that contains the available task types.

The available supported jobs are:

| Alias                      | Available Aliases                                         | Task type         | Description                                                                                                                                              |
| -------------------------- | --------------------------------------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `JobNames.LITERATURE`      | `literature-20260216`, `JobNames.CROW`, `JobNames.FALCON` | Literature Search | Ask a question of scientific data sources, and receive a high-accuracy, cited response. Built with [PaperQA3](https://github.com/Future-House/paper-qa). |
| `JobNames.LITERATURE_HIGH` | `literature-high-20260216`                                | Literature Search | Ask a question of scientific data sources, and receive a high-accuracy, cited response. High reasoning mode enabled for SOTA performance.                |
| `JobNames.ANALYSIS`        | `JobNames.FINCH`                                          | Data Analysis     | Turn biological datasets into detailed analyses answering your research questions.                                                                       |
| `JobNames.PRECEDENT`       | `JobNames.OWL`                                            | Precedent Search  | Formerly known as HasAnyone, query if anyone has ever done something in science.                                                                         |
| `JobNames.MOLECULES`       | `JobNames.PHOENIX`                                        | Chemistry Tasks   | A new iteration of ChemCrow, Phoenix uses cheminformatics tools to do chemistry. Good for planning synthesis and designing new molecules.                |

Using `JobNames`, the task submission looks like this:

```python
from edison_client import EdisonClient, JobNames

client = EdisonClient(
    api_key="your_api_key",
)

task_data = {
    "name": JobNames.PRECEDENT,
    "query": "Has anyone tested therapeutic exerkines in humans or NHPs?",
}

task_response = client.run_tasks_until_done(task_data)

print(task_response.answer)
```

Or if running async code:

```python
import asyncio
from edison_client import EdisonClient, JobNames


async def main():
    client = EdisonClient(
        api_key="your_api_key",
    )

    task_data = {
        "name": JobNames.PRECEDENT,
        "query": "Has anyone tested therapeutic exerkines in humans or NHPs?",
    }

    task_response = await client.arun_tasks_until_done(task_data)
    print(task_response.answer)
    return task_id


# For Python 3.7+
if __name__ == "__main__":
    task_id = asyncio.run(main())
```

Note that in either the sync or the async code, collections of tasks can be given to the client to run them in a batch:

```python
import asyncio
from edison_client import EdisonClient, JobNames


async def main():
    client = EdisonClient(
        api_key="your_api_key",
    )

    task_data = [{
        "name": JobNames.PRECEDENT,
        "query": "Has anyone tested therapeutic exerkines in humans or NHPs?",
    },
    {
        "name": JobNames.LITERATURE,
        "query": "Are there any clinically validated therapeutic exerkines for humans?",
    }
    ]

    task_responses = await client.arun_tasks_until_done(task_data)
    print(task_responses[0].answer)
    print(task_responses[1].answer)
    return task_id


# For Python 3.7+
if __name__ == "__main__":
    task_id = asyncio.run(main())
```

`TaskRequest` can also be used to submit jobs and it has the following fields:

| Field           | Type          | Description                                                                                                               |
| --------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------- |
| id              | UUID          | Optional job identifier. A UUID will be generated if not provided                                                         |
| name            | str           | Name of the job to execute eg. `job-futurehouse-paperqa2`, or using the `JobNames` for convenience: `JobNames.LITERATURE` |
| query           | str           | Query or task to be executed by the job                                                                                   |
| runtime\_config | RuntimeConfig | Optional runtime parameters for the job                                                                                   |

`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.

```python
from edison_client import EdisonClient, JobNames
from edison_client.models.app import TaskRequest

client = EdisonClient(
    api_key="your_api_key",
)

task_response = client.run_tasks_until_done(
    TaskRequest(
        name=JobNames.PRECEDENT,
        query="Has anyone tested therapeutic exerkines in humans or NHPs?",
    )
)

print(task_response.answer)
```

A `TaskResponse` will be returned from using our agents. For `LITERATURE` and `PRECEDENT`, we default to a subclass, `PQATaskResponse` which has some key attributes:

| Field                   | Type | Description                                                                     |
| ----------------------- | ---- | ------------------------------------------------------------------------------- |
| answer                  | str  | Answer to your query.                                                           |
| formatted\_answer       | str  | Specially formatted answer with references.                                     |
| has\_successful\_answer | bool | Flag for whether the agent was able to find a good answer to your query or not. |

If using the `verbose` setting, much more data can be pulled down from your `TaskResponse`, which will exist across all agents.

```python
from edison_client import EdisonClient, JobNames
from edison_client.models.app import TaskRequest

client = EdisonClient(
    api_key="your_api_key",
)

task_response = client.run_tasks_until_done(
    TaskRequest(
        name=JobNames.PRECEDENT,
        query="Has anyone tested therapeutic exerkines in humans or NHPs?",
    ),
    verbose=True,
)

print(task_response.environment_frame)
```

In that case, a `TaskResponseVerbose` will have the following fields:

| Field              | Type | Description                                                                                                            |
| ------------------ | ---- | ---------------------------------------------------------------------------------------------------------------------- |
| agent\_state       | dict | Large object with all agent states during the progress of your task.                                                   |
| environment\_frame | dict | Large nested object with all environment data, for PQA environments it includes contexts, paper metadata, and answers. |
| metadata           | dict | Extra metadata about your query.                                                                                       |

## Task Continuation

Once a task is submitted and the answer is returned, Edison platform allow you to ask follow-up questions to the previous task. It is also possible through the platform API. To accomplish that, we can use the `runtime_config` we discussed in the [Simple task running](#simple-task-running) section.

```python
from edison_client import EdisonClient, JobNames

client = EdisonClient(
    api_key="your_api_key",
)

task_data = {"name": JobNames.LITERATURE, "query": "How many species of birds are there?"}

task_id = client.create_task(task_data)

continued_task_data = {
    "name": JobNames.LITERATURE,
    "query": "From the previous answer, specifically, how many species of crows are there?",
    "runtime_config": {"continued_job_id": task_id},
}

task_result = client.run_tasks_until_done(continued_task_data)
```

## Asynchronous tasks

Sometimes you may want to submit many jobs, while querying results at a later time. In this way you can do other things while waiting for a response. The platform API supports this as well rather than waiting for a result.

```python
from edison_client import EdisonClient

client = EdisonClient(
    api_key="your_api_key",
)

task_data = {"name": JobNames.LITERATURE, "query": "How many species of birds are there?"}

task_id = client.create_task(task_data)

# move on to do other things

task_status = client.get_task(task_id)
```

`task_status` contains information about the task. For instance, its `status`, `task`, `environment_name` and `agent_name`, and other fields specific to the job. You can continually query the status until it's `success` before moving on.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.edisonscientific.com/edison-client/readme.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
