Metadata-Version: 2.4
Name: nexgenomics
Version: 0.4.1
Summary: Python SDK for fabric guest agents — originate v1.cap.* capability calls.
Project-URL: Homepage, https://github.com/nexgenomics/py-nexgenomics
Author: NexGenomics
License-Expression: Apache-2.0
Keywords: agents,fabric,inference
Requires-Python: >=3.11
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.24; extra == 'test'
Requires-Dist: pytest>=8; extra == 'test'
Description-Content-Type: text/markdown

# nexgenomics

The Python SDK for fabric guest agents. Agent authors originate `v1.cap.*`
capability calls — `model.generate`, `model.stream`, `dataset.search` — without
hand-rolling the wire protocol or ever touching the platform token.

Requires Python **3.11+**. Async-native.

```python
from nexgenomics import connect, PermissionDenied

async with connect() as agent:
    reply = await agent.generate(
        model="mistral-7b-instruct", version="v0.3",
        messages=[{"role": "user", "content": "hello"}],
        max_tokens=64,
    )
    print(reply.content, reply.usage)

    async for chunk in agent.stream(
        model="mistral-7b-instruct", version="v0.3",
        messages=[{"role": "user", "content": "write a haiku"}],
    ):
        print(chunk, end="", flush=True)

    try:
        hits = await agent.search(dataset="papers", space="v1", query="genomics")
    except PermissionDenied:
        ...
```

## How it works

The SDK drives a small Go transport helper (`cap-helper`) as a subprocess over a
length-prefixed-JSON stdio protocol. The helper owns the vsock framing, the
credential handshake, per-call correlation, and the v1.1 stream-frame decode —
one authority shared with the host, so the SDK cannot drift from the wire
contract. The SDK owns the ergonomic surface: the call methods, the exception
hierarchy, and the streaming async iterators.

**Identity is ambient.** The helper reads the credential from env (populated by
the platform at boot); the SDK never sees or accepts the token. Your code does
not change when the platform changes how the token is delivered.

## Errors

Two disjoint branches under `FabricSDKError`:

- **`FabricError`** — the host returned a verdict with a wire code:
  `Unauthenticated`, `PermissionDenied`, `NotFound`, `InvalidArgument`,
  `AlreadyExists`, `FailedPrecondition`, `Unavailable`, `Internal`. A denial on a
  stream is raised from the `async for`.
- **`TransportError`** — the call never reached a verdict: `NoReply` (deadline —
  **never** a denial), `SendFailed`, `ProtocolError`, `Draining`, `HelperExited`.

Catch `FabricError` for "the platform said no", `TransportError` for "no answer".

## Streaming and cancel

`stream(...)` returns an async iterator that yields text deltas; on normal
completion it stops and exposes `.finish_reason` and `.usage`. Breaking out of
the loop, or `await stream.aclose()` / leaving an `async with stream`, sends an
advisory cancel for the in-flight generation.

## The helper binary

At runtime the `cap-helper` binary is delivered by the platform image (it is
version-locked to the deployed host and built in the monorepo), so in-guest the
SDK finds it automatically. For **off-platform development** against the fake
host, point the SDK at a local build:

```bash
export CAP_HELPER_BIN=/path/to/cap-helper
```

## Development

```bash
pip install -e '.[test]'
pytest
```

The tests run the SDK against a fake helper (`tests/_fakehelper.py`) that speaks
the same stdio protocol with an independent codec — no VM, no real host.

## License

Apache-2.0. Releases from 0.4.0 onward are Apache-2.0 licensed; earlier 0.x
releases were BSD-3-Clause.
