Skill Tracer
Skills › Scientific Agent Skills › esm › forge-api.md

forge-api.md

130 lines · skills/esm/references/forge-api.md at 5f2bc03

Open on GitHub
1# Biohub hosted inference and former Forge clients
2

Biohub hosted inference and former Forge clients

Raw lines 1 to 2
3## Authentication and clients
4
5The current `esm==3.4.1.post1` factories default to `https://biohub.ai` for
6**ESM3, ESMC and ESMFold2**. The old Forge host is historical, not a recommended
7separate ESM3 route. `esm.sdk.forge` names remain for compatibility.
8
9Pass `token=os.environ["ESM_API_KEY"]` explicitly. Factory defaults read the
10environment at module import, so later environment changes are not automatically
11picked up. Keys are managed in the
12[Biohub developer console](https://biohub.ai/developer-console/api-keys).
13Do not send unpublished sequences to hosted inference without authorization for
14that data transfer. Use a fixed trusted host: SDK response paths can deserialize
15binary tensor payloads and must not be directed at an arbitrary server.
17| Factory | Purpose | Example model |
18| --- | --- | --- |
19| `esm.sdk.client` | ESM3 | `esm3-medium-2024-08` |
20| `esm.sdk.esmc_client` | ESMC | `esmc-600m-2024-12` |
21| `esm.sdk.esmfold2_client` | ESMFold2 | `esmfold2-fast-2026-05` |
23The factories accept `model`, `url`, `token`, and `request_timeout` (seconds).
24Their default timeout is `None` (unbounded), while explicit inference-client
25constructors default to 60 seconds. Set a finite timeout deliberately. Explicit
26`ESM3ForgeInferenceClient`, `ESMCForgeInferenceClient`, and
27`SequenceStructureForgeInferenceClient` also accept `min_retry_wait`,
28`max_retry_wait`, and `max_retry_attempts`.

Authentication and clients

The current esm==3.4.1.post1 factories default to https://biohub.ai for ESM3, ESMC and ESMFold2. The old Forge host is historical, not a recommended separate ESM3 route. esm.sdk.forge names remain for compatibility.

Pass token=os.environ["ESM_API_KEY"] explicitly. Factory defaults read the environment at module import, so later environment changes are not automatically picked up. Keys are managed in the Biohub developer console. Do not send unpublished sequences to hosted inference without authorization for that data transfer. Use a fixed trusted host: SDK response paths can deserialize binary tensor payloads and must not be directed at an arbitrary server.

FactoryPurposeExample model
esm.sdk.clientESM3esm3-medium-2024-08
esm.sdk.esmc_clientESMCesmc-600m-2024-12
esm.sdk.esmfold2_clientESMFold2esmfold2-fast-2026-05

The factories accept model, url, token, and request_timeout (seconds). Their default timeout is None (unbounded), while explicit inference-client constructors default to 60 seconds. Set a finite timeout deliberately. Explicit ESM3ForgeInferenceClient, ESMCForgeInferenceClient, and SequenceStructureForgeInferenceClient also accept min_retry_wait, max_retry_wait, and max_retry_attempts.

Raw lines 3 to 29
30## Released HTTP contracts
32All table entries were checked in the released wheel. ESM3 protein generation,
33ESMC encode/logits/decode and the folding failure path were additionally tested
34with `httpx` mock transports; the other routes were source-reviewed only. No
35authenticated request was made. These are single inference requests without
36pagination. Use SDK serialization instead of inventing REST payloads.
38| Method | HTTP route on `https://biohub.ai` | Request / response |
39| --- | --- | --- |
40| ESM3 `generate(ESMProtein, config)` | `POST /api/v1/generate` | JSON `model`, `inputs` tracks, generation settings at the top level; response `outputs` tracks and confidence fields becomes `ESMProtein` |
41| ESM3 `generate(ESMProteinTensor, config)` | `POST /api/v1/generate_tensor` | Token-valued `inputs`; response becomes `ESMProteinTensor` |
42| ESM3/ESMC `encode` | `POST /api/v1/encode` | `model`, `inputs` tracks; `outputs` token arrays and `potential_sequence_of_concern` |
43| ESM3/ESMC `decode` | `POST /api/v1/decode` | `model`, token-valued `inputs`; `outputs` decoded tracks |
44| ESM3/ESMC `logits` | `POST /api/v1/logits` | `model`, token-valued `inputs`, `logits_config`; `LogitsOutput` with per-track logits and optional embeddings |
45| ESM3 `forward_and_sample` | `POST /api/v1/forward_and_sample` | `model`, token-valued `inputs`, `sampling_config`; sampled protein tensor and optional statistics |
46| ESMFold2 `fold_all_atom` | `POST /api/v1/fold_all_atom` | Serialized `all_atom_input`, `model`, folding settings; complex state and confidence values become `MolecularComplexResult` |
48Authorization is `Bearer <token>`. The transport prefixes `/api/v1/`, submits
49JSON, and unwraps a `data` envelope where applicable. Tensor-heavy responses
50may use binary formats; `logits()` defaults to requesting bytes with
51`return-bytes: true` and an SDK-specific `Accept` header. Do not assume all
52responses are ordinary JSON arrays or bypass the SDK decoder.

Released HTTP contracts

All table entries were checked in the released wheel. ESM3 protein generation, ESMC encode/logits/decode and the folding failure path were additionally tested with httpx mock transports; the other routes were source-reviewed only. No authenticated request was made. These are single inference requests without pagination. Use SDK serialization instead of inventing REST payloads.

MethodHTTP route on https://biohub.aiRequest / response
ESM3 generate(ESMProtein, config)POST /api/v1/generateJSON model, inputs tracks, generation settings at the top level; response outputs tracks and confidence fields becomes ESMProtein
ESM3 generate(ESMProteinTensor, config)POST /api/v1/generate_tensorToken-valued inputs; response becomes ESMProteinTensor
ESM3/ESMC encodePOST /api/v1/encodemodel, inputs tracks; outputs token arrays and potential_sequence_of_concern
ESM3/ESMC decodePOST /api/v1/decodemodel, token-valued inputs; outputs decoded tracks
ESM3/ESMC logitsPOST /api/v1/logitsmodel, token-valued inputs, logits_config; LogitsOutput with per-track logits and optional embeddings
ESM3 forward_and_samplePOST /api/v1/forward_and_samplemodel, token-valued inputs, sampling_config; sampled protein tensor and optional statistics
ESMFold2 fold_all_atomPOST /api/v1/fold_all_atomSerialized all_atom_input, model, folding settings; complex state and confidence values become MolecularComplexResult

Authorization is Bearer <token>. The transport prefixes /api/v1/, submits JSON, and unwraps a data envelope where applicable. Tensor-heavy responses may use binary formats; logits() defaults to requesting bytes with return-bytes: true and an SDK-specific Accept header. Do not assume all responses are ordinary JSON arrays or bypass the SDK decoder.

Raw lines 30 to 53
54## Error and retry behavior
56Many SDK methods catch HTTP failures and **return `ESMProteinError`**. Others can
57raise it. Network failures are wrapped as error code 500; deterministic request
58serialization/response-parsing failures become 400. A `requests.HTTPError`
59handler is insufficient: the released transport uses `httpx` and SDK errors.
61```python
62from esm.sdk.api import ESMProteinError
64def require_success(result):
65 if isinstance(result, ESMProteinError):
66 raise result
67 return result
68```
70The SDK retries errors 429, 500, 502, 503 and 504, whether returned or raised,
71using bounded exponential jitter (default five attempts). Do not add unbounded
72outer retries. A timeout does not establish that the server did no work; retrying
73a stochastic inference can produce another result and consume resources. A
74finite per-request timeout is not a global batch deadline. Never use a paid
75inference call merely to claim a token is valid.

Error and retry behavior

Many SDK methods catch HTTP failures and **return ESMProteinError**. Others can raise it. Network failures are wrapped as error code 500; deterministic request serialization/response-parsing failures become 400. A requests.HTTPError handler is insufficient: the released transport uses httpx and SDK errors.

from esm.sdk.api import ESMProteinError

def require_success(result):
    if isinstance(result, ESMProteinError):
        raise result
    return result

The SDK retries errors 429, 500, 502, 503 and 504, whether returned or raised, using bounded exponential jitter (default five attempts). Do not add unbounded outer retries. A timeout does not establish that the server did no work; retrying a stochastic inference can produce another result and consume resources. A finite per-request timeout is not a global batch deadline. Never use a paid inference call merely to claim a token is valid.

Raw lines 54 to 76
77## Bounded concurrent generation
79Illustrative authenticated inference. Each request owns its generation config;
80`asyncio.gather` preserves input order and failures remain linked to IDs.
82```python
83import asyncio
84import os
85from esm.sdk.forge import ESM3ForgeInferenceClient
86from esm.sdk.api import ESMProtein, ESMProteinError, GenerationConfig
88async def generate_many(records, concurrency=4):
89 if concurrency < 1:
90 raise ValueError("concurrency must be positive")
91 semaphore = asyncio.Semaphore(concurrency)
92 async with ESM3ForgeInferenceClient(
93 model="esm3-medium-2024-08", url="https://biohub.ai",
94 token=os.environ["ESM_API_KEY"], request_timeout=120,
95 max_retry_attempts=3,
96 ) as client:
97 async def run_one(record):
98 record_id, prompt = record
99 masks = prompt.count("_")
100 if masks == 0:
101 raise ValueError("Sequence generation needs masked positions")
102 async with semaphore:
103 result = await client.async_generate(
104 ESMProtein(sequence=prompt),
105 GenerationConfig(track="sequence", num_steps=min(20, masks)),
106 )
107 if isinstance(result, ESMProteinError):
108 return record_id, {"error_code": result.error_code}
109 return record_id, {"sequence": result.sequence}
110 return await asyncio.gather(*(run_one(record) for record in records))
111```
113Use bounded chunks for very large iterables rather than creating millions of
114pending tasks. The SDK also supplies `parallel_executor()` with
115`execute_batch(user_func=..., ...)`; `batch_executor` is deprecated. These are
116concurrent on-demand requests, distinct from the newer submitted batch-job API.
117The submitted max-accuracy batch workflow is outside the recipes audited here.
119Save successful records and failures separately with input IDs, model ID and
120complete settings. Cache keys must include every conditioning track, checkpoint
121or hosted revision, SDK version, and config. Do not log keys or sensitive sequence
122payloads. Inspect current account quotas in the console; no fixed RPM, prices,
123SageMaker deployment availability or enterprise data-residency promises are
124asserted here.
126Sources: [factories](https://github.com/Biohub/esm/blob/main/esm/sdk/__init__.py),
127[client serialization](https://github.com/Biohub/esm/blob/main/esm/sdk/forge.py),
128[transport](https://github.com/Biohub/esm/blob/main/esm/sdk/base_forge_client.py),
129[retry rules](https://github.com/Biohub/esm/blob/main/esm/sdk/retry.py),
130[parallel executor](https://github.com/Biohub/esm/blob/main/esm/utils/forge_context_manager.py).

Bounded concurrent generation

Illustrative authenticated inference. Each request owns its generation config; asyncio.gather preserves input order and failures remain linked to IDs.

import asyncio
import os
from esm.sdk.forge import ESM3ForgeInferenceClient
from esm.sdk.api import ESMProtein, ESMProteinError, GenerationConfig

async def generate_many(records, concurrency=4):
    if concurrency < 1:
        raise ValueError("concurrency must be positive")
    semaphore = asyncio.Semaphore(concurrency)
    async with ESM3ForgeInferenceClient(
        model="esm3-medium-2024-08", url="https://biohub.ai",
        token=os.environ["ESM_API_KEY"], request_timeout=120,
        max_retry_attempts=3,
    ) as client:
        async def run_one(record):
            record_id, prompt = record
            masks = prompt.count("_")
            if masks == 0:
                raise ValueError("Sequence generation needs masked positions")
            async with semaphore:
                result = await client.async_generate(
                    ESMProtein(sequence=prompt),
                    GenerationConfig(track="sequence", num_steps=min(20, masks)),
                )
            if isinstance(result, ESMProteinError):
                return record_id, {"error_code": result.error_code}
            return record_id, {"sequence": result.sequence}
        return await asyncio.gather(*(run_one(record) for record in records))

Use bounded chunks for very large iterables rather than creating millions of pending tasks. The SDK also supplies parallel_executor() with execute_batch(user_func=..., ...); batch_executor is deprecated. These are concurrent on-demand requests, distinct from the newer submitted batch-job API. The submitted max-accuracy batch workflow is outside the recipes audited here.

Save successful records and failures separately with input IDs, model ID and complete settings. Cache keys must include every conditioning track, checkpoint or hosted revision, SDK version, and config. Do not log keys or sensitive sequence payloads. Inspect current account quotas in the console; no fixed RPM, prices, SageMaker deployment availability or enterprise data-residency promises are asserted here.

Sources: factories, client serialization, transport, retry rules, parallel executor.

Raw lines 77 to 130