Metadata-Version: 2.5
Name: codon-ai
Version: 2026.9.11
Summary: Python client for Codon AI Services: biomedical AI models over one API.
Project-URL: Homepage, https://github.com/linnarsson-lab/codon
Project-URL: Documentation, https://codon.mbb.ki.se/docs/
Author: Karolinska Institutet
License: MIT
Keywords: bioinformatics,codon,protein,structure-prediction
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.10
Description-Content-Type: text/markdown

# codon-ai

Python client for [Codon AI Services](https://codon.mbb.ki.se): around 150
biomedical AI models — structure prediction, embeddings, co-folding, inverse
folding, genomics scoring — behind one API, run on shared GPU hardware.

```bash
pip install codon-ai
```

Python 3.10 or newer, and two dependencies, pydantic and httpx. No model
weights, no ML stack.

You need a Codon account — Codon is Karolinska Institutet's research AI
platform — and an API key from it. Without one you can still build and
validate inputs locally, since the models ship in the package, but nothing
reaches the service, not even the catalog. New tools arrive with new releases, so
`pip install -U codon-ai` from time to time.

## Using it

```python
from codon.ai_services import ESMFold2, ESMFold2Config

fold = ESMFold2(ESMFold2Config(model_checkpoint="esmfold2-fast"))

output, stats = fold.run(complexes=[["MKTAYIAKQRQISFVKSHFSRQ"]])

output.structures[0]
stats.price_usd, stats.runtime_seconds
```

The config goes in the constructor and the input goes to `run`, so one
configured tool serves a whole batch:

```python
for sequence in sequences:
    output, stats = fold.run(complexes=[[sequence]])
```

`run` blocks. To start many jobs at once, submit them and collect later:

```python
jobs = [fold.submit(complexes=[[s]]) for s in sequences]
for job in jobs:
    output, stats = job.result()
```

An input model can be passed positionally instead, for reusing one or
building it from a dict:

```python
from codon.ai_services import ESMFold2Input

data = ESMFold2Input(complexes=[["MKTAYIAKQRQISFVKSHFSRQ"]])
output, stats = fold.run(data)
```

## Pointing it at Codon

Two environment variables, and no credential in your code:

```bash
export CODON_AI_SERVICES_URL="https://codon.mbb.ki.se/ai-services-api"
export CODON_AI_SERVICES_KEY="codon-ais-..."   # API Keys → Codon AI Services
```

Inside a Codon capsule the URL is already set and there is no key to set:
the sandbox holds the credential on your behalf. The same script therefore
runs unchanged on your laptop and inside Codon.

## What a call costs

Tools are priced by the memory a job holds and how long it holds it. `stats`
carries what you were actually charged, alongside `max_price_usd`, the
ceiling reserved when the job was submitted. Failed and timed-out jobs are
never charged.

`timeout_s` is the real cost ceiling, because the charge cannot exceed the
rate times the memory times the deadline:

```python
fold = ESMFold2(config, timeout_s=600)
```

It sits on the tool rather than on the call because `run` and `submit` take
the tool's own field names, and a parameter of the client's own beside them
would share that namespace.

## When something goes wrong

Every failure raises something you can act on, carrying the server's own
message:

| Exception | What to do |
|---|---|
| `BudgetExceeded` | The message names which cap and where to raise it |
| `NoWorkerAvailable` | Retry later; nothing about the request is wrong |
| `TooLargeForAnyWorker` | Choose a smaller checkpoint |
| `ToolTimeout` | Retry with a larger `timeout_s`, not the same one |
| `ToolFailed` | The tool itself raised; the message is its error |
| `TooManyJobs` | Too many in flight; wait for some to finish |

A job whose worker died mid-run is retried once automatically, since nothing
about the request caused it. Nothing else is retried: the same input would
fail the same way and only spend another queue slot.

## Browsing what is available

```python
from codon.ai_services import list_tools, describe

for tool in list_tools():
    print(tool["tool_key"], tool["price_usd_per_gb_hour"])

describe("esmfold2-prediction")["readme"]
```

Entries with `kind == "llm"` are local language models rather than tools.
They have no input or config classes here: call them with the Anthropic SDK
against `<codon>/ai-services-api/llm`, as their catalog page shows.

## Where the models come from

The input, config and output models are generated from the service folders
under `containers/ai_services_worker/services/`, which are what Codon's AI
Services workers actually run. The version is the date of the snapshot.

This package does not run tools locally. It submits jobs to Codon AI Services
and reads the results back; the models are here so mistakes are caught before
a job is submitted.

## Licence

MIT.
