Metadata-Version: 2.5
Name: syfthub-sdk
Version: 2.0.0a1
Summary: Python SDK for SyftHub: search across Syft Space sources with pre-flight, wallets and budgets
Author: SyftHub Team
License: Apache-2.0
Keywords: rag,sdk,search,syfthub,syftspace
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.7
Provides-Extra: dev
Requires-Dist: h2>=4; extra == 'dev'
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest-xdist>=3.5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Provides-Extra: http2
Requires-Dist: h2>=4; extra == 'http2'
Provides-Extra: testing
Requires-Dist: respx>=0.21; extra == 'testing'
Description-Content-Type: text/markdown

# SyftHub Python SDK

`syfthub` is the Python client for [SyftHub](https://syfthub.org): log in once, pick the sources you
want to search, see what each one will cost and need before anything is sent, then run the search.

This is **v2**. It replaces the earlier `syfthub_sdk` package under the same distribution name,
`syfthub-sdk`. The 0.x line stays on PyPI for existing pins.

## Status

First cut, under construction: headless and search-only. Chat, metadata filters and the Aggregator
come in later cuts.

## Install

```bash
pip install --pre syfthub-sdk      # 2.x is a pre-release until the first stable tag
pip install --pre 'syfthub-sdk[http2]'   # with HTTP/2, for Options(http2=True)
```

## Quick start

```python
import syfthub

async with syfthub.AsyncHub(token="...", budget=1.00) as hub:      # or SYFTHUB_TOKEN; caps 1.00 USD
    plan = hub.search("adverse events in phase 3", ["erin/trials", "carol/papers"])
    pre = await plan.preflight()            # rows + actions; nothing sent, nothing spent
    for action in pre.actions:              # TopUp, OverBudget, AccessDenied, CircuitOpen
        plan = plan.skip(*action.paths)     # the one decision verb
    results = await plan.execute()          # one POST per Space, in parallel
    for path, doc in results.documents:     # best-scored chunks across sources
        print(path, doc.score, doc.content[:80])
```

Budgets are optional and per currency: `budget=1.00` caps USD only, `budget={"USD": 1.00, "IDR": 50000}`
caps both, and a currency with no cap is not budgeted. The SDK never converts money.

The sync twin is the same API without `await`:

```python
with syfthub.Hub(token="...") as hub:
    results = hub.search("adverse events in phase 3", ["erin/trials"]).execute()
```

`syfthub.testing.FakeHub` stands in for a Hub and its Spaces in your own tests, with no extra
dependency. See `examples/` for the reference chat app and `tests/unit/test_testing.py` for the fake.

## Development

```bash
uv sync --all-extras
uv run ruff check src/ tests/
uv run mypy src/
uv run pytest tests/unit
uv run python scripts/gen_sync_stub.py   # after changing a public async method or what it returns
```

`src/syfthub/_sync.pyi` and `src/syfthub/sync.py` are generated: they give the sync `Hub` the
types of the async package. A unit test fails until they are regenerated.
