Bystro Think Python API
The Think SDK is a synchronous, typed client for durable Bystro agent workloads. It intentionally exposes a small surface: authenticate, upload artifacts, compose context, submit work, observe progress, answer pauses, and resume by run ID.
Install
Bystro 2.1 supports CPython 3.11 and 3.12. Activate the environment you want
to use, confirm it with python --version, and install from PyPI:
python -m pip install "bystro>=2.1.0,<2.2"
Production endpoints use publicly trusted HTTPS certificates, so no custom CA bundle or TLS override is required. A private CA bundle is only needed for a local development deployment that uses its own certificate authority.
Authenticate
auth.login uses the same bystro.cloud dashboard account as the browser and
caches its JWT in ~/.bystro/bystro_authentication_token.json. The directory
is mode 0700, the file is atomically replaced at mode 0600, and tokens are
never printed.
from bystro.api import auth
from bystro.think import ThinkClient
auth.login("you@example.com", "your-password")
client = ThinkClient.from_cached_login()
For short scripts, login and construction can be one call:
client = ThinkClient.login("you@example.com", "your-password")
If the deployment keeps Bystro's shared site-access gate enabled, present its code during the same login. The SDK establishes the gate cookie and performs dashboard login in one private session; the code is never written to the auth cache:
import os
client = ThinkClient.login(
"you@example.com",
"your-password",
site_access_code=os.environ["BYSTRO_SITE_ACCESS_CODE"],
)
New accounts must explicitly provide the dashboard's signed legal assertions:
from bystro.api.auth import LegalConsent, signup
signup(
"you@example.com",
"your-password",
"Your Name",
legal_consent=LegalConsent.accepted("Your Name"),
site_access_code=os.environ["BYSTRO_SITE_ACCESS_CODE"],
)
site_access_code is the Bystro application gate, not a Cloudflare credential.
Cloudflare must still allow non-browser traffic to the dashboard authentication
and Think API routes while retaining its challenge on browser pages.
The SDK exchanges that dashboard session through Think's existing cookie-auth admission endpoint. The application credential created by Think remains on the server; it is not copied into local code or exposed as a second API key.
Upload files and submit them with a question
Passing paths to submit uploads each file to personal input artifacts first,
then attaches the resulting artifact records to the same user message:
run = client.submit(
"Find variants associated with the case phenotype.",
files=["cohort.vcf.gz", "phenotypes.tsv"],
)
Uploads use the production resumable protocol: bounded 10 MiB chunks,
per-chunk SHA-256 checksums, idempotent retries with exponential backoff, and
polling for asynchronous server finalization. The chunk size and retry policy
can be configured on ThinkClient. An artifact_path is relative, has at most
64 components, and must end in the local file's exact name; invalid paths fail
locally before authentication or upload begins.
Use upload_artifact when the artifact should be created before the question:
def report_upload(progress):
print(progress.phase.value, f"{progress.fraction:.0%}")
artifact = client.upload_artifact(
"cohort.vcf.gz",
artifact_path="study/cohort.vcf.gz",
on_progress=report_upload,
)
run = client.submit("Run QC on this cohort", files=[artifact])
upload is an equivalent shorter alias.
Compose genetic, conversation, and artifact context
Context helpers accept either a plain string or an immutable
MessageWithContext, so calls compose naturally:
from bystro.think import (
add_artifact_context,
add_genetic_context,
add_previous_conversation_context,
)
message = "Compare the strongest signals"
message = add_genetic_context(
"annotation-job-id",
message,
name="Case cohort",
assembly="hg38",
)
message = add_previous_conversation_context(
"prior-thread-id",
message,
name="Earlier analysis",
)
message = add_artifact_context(artifact, message)
run = client.submit(message)
Reusable higher-order transforms are also available:
from bystro.think import (
artifact_context,
compose_context,
genetic_context,
previous_conversation_context,
)
study_context = compose_context(
genetic_context("annotation-job-id", name="Case cohort", assembly="hg38"),
previous_conversation_context("prior-thread-id"),
artifact_context("existing-artifact-id"),
)
run = client.submit(study_context("Re-evaluate the phenotype association"))
message.to_xml() returns a safely escaped preview of the semantic context.
On the wire, references remain structured metadata. Think resolves artifacts
against the authenticated user before creating canonical input-file context;
dataset and conversation retrieval tools independently enforce ownership
before returning referenced data. Raw user-authored XML is never treated as an
ownership boundary.
Handle needs_input
wait() returns exactly one of two values: RunResult or NeedsInput.
Clarifications and plan review are durable checkpoint states, not transient
socket prompts.
from bystro.think import InputKind, NeedsInput
outcome = run.wait(timeout=3600)
if isinstance(outcome, NeedsInput):
if outcome.kind is InputKind.PLAN_REVIEW:
run.respond("accept")
else:
run.respond("Use case_control as the phenotype column")
outcome = run.wait(timeout=3600)
The first live pause notification can arrive just before its checkpoint is
committed, so checkpoint_id may initially be None. run.respond() requests
the durable replay automatically and will not upload attachments or dispatch
the response until the checkpoint is present. Once answered, replays of that
same or an older checkpoint are ignored, preventing reconnect races from
reopening a stale question. If synchronization fails, the pause remains intact
and RunProtocolError asks you to call run.refresh() and retry. A billing
pause is also represented as NeedsInput, but must be resolved through the
billing action in the dashboard; then call run.refresh().
Progress and reconnects
Pass a callback to the client for all runs, or to wait for one wait cycle:
def progress(event):
print(event.sequence, event.kind.value, event.message or "")
client = ThinkClient(on_event=progress)
run = client.submit("Perform a GWAS", files=["cohort.vcf.gz"])
result = run.wait()
Alternatively, omit the client-level callback and pass on_event=progress to
one wait() call. Do not pass the same callback at both levels unless duplicate
delivery is intentional.
The durable run ID is available immediately after admission:
print(run.id)
Another process can attach to it later:
client = ThinkClient()
run = client.resume("run-or-thread-id")
outcome = run.wait()
run.messages provides the hydrated transcript and run.history provides
bounded SDK progress history. Socket reconnects automatically replay the
current overlay state. When a replayed needs_input overlay arrives before its
transcript, wait() holds the outcome until transcript hydration restores the
clarification or plan-review prompt.
Follow-up turns and errors
After a successful result, start another turn in the same conversation:
run.follow_up("Now stratify the result by ancestry")
next_result = run.wait()
Transport, HTTP, billing, admission, timeout, and protocol failures have typed
exceptions under bystro.think. A ThinkClient owns one foreground run at a
time; use separate clients for concurrently controlled conversations. Closing
a client disconnects local transports but does not cancel durable server work.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bystro-2.1.0.tar.gz.
File metadata
- Download URL: bystro-2.1.0.tar.gz
- Upload date:
- Size: 22.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
682f2e2837b242c990dcaf39deef3444fc4d44ba287c091f6febff0370facc1f
|
|
| MD5 |
ebceeb02030683fc9bf2ef7d6d272c5a
|
|
| BLAKE2b-256 |
f3425d6de1fc207f2c526d35c1f8a592b8d038dffc86d574b240f2813d37e11b
|
File details
Details for the file bystro-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: bystro-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c002317552a438fcfcdd2e3a7b29a2823b4a7f19c79e85b1acc44b9589064e5f
|
|
| MD5 |
69d8d91e9fcbbecfe913be26c6025850
|
|
| BLAKE2b-256 |
1008b491f2dfa1b3b1a89666db1b21484b820a42bb21239d3a9bccdee740d864
|
File details
Details for the file bystro-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: bystro-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5343e2d5b5663755b01f0d9025fbd5a87bfe7e9919a8d789e5da1552d63be71a
|
|
| MD5 |
437296efbd3fa12635148c799c14659b
|
|
| BLAKE2b-256 |
c9b3a05b0d0a4d22a5ebadef0d79c2db0e189302e7ad84792b61ac197bb3d08e
|
File details
Details for the file bystro-2.1.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: bystro-2.1.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce654df6e7d8cfac2c556527276fac5442837614300a6867bf3af0c3a496d24b
|
|
| MD5 |
2f8daa34565adae2e436cadfe9e502eb
|
|
| BLAKE2b-256 |
208033e9f8dd3d5251d122d8c34625928fc21eb703d4c44abf599a83765136d1
|
File details
Details for the file bystro-2.1.0-cp312-cp312-macosx_10_12_x86_64.whl.
File metadata
- Download URL: bystro-2.1.0-cp312-cp312-macosx_10_12_x86_64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.12, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d9d6ac14252181be331a51926f74fe748cb47daac58e363223544733f5e15f99
|
|
| MD5 |
6a76d677f17e32de0aae600dd456bcb1
|
|
| BLAKE2b-256 |
e2c3ba535972fc831f638537dd3abf77eca48b943fdf298d9ba3b34133230cf2
|
File details
Details for the file bystro-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: bystro-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5843aa84fc91d992c5f32b63fda35c331000d0784640470959f8a098ed4f89a
|
|
| MD5 |
f4ec015305060a0816f5e8fa334ea0ff
|
|
| BLAKE2b-256 |
c7eabf6c4d8fda2d88c9e4a785d544428d5c001e5351cc7d489e636e1f288550
|
File details
Details for the file bystro-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: bystro-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d437749549d1bed17610255fe30d2090782f591700e0bd53ccca6a04fd1a6a8
|
|
| MD5 |
237f10c9210797b6d599a595431fa11b
|
|
| BLAKE2b-256 |
eec1955b20f265c37f5fe7cede6e5e8342969d0e89f9ea23dfb607d5cc92e833
|
File details
Details for the file bystro-2.1.0-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: bystro-2.1.0-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c85e6d44f81e3a81bd0918c55b0b1017e54cd052d3ee7ac7964c29054595955
|
|
| MD5 |
8c9f13cc7cc03e4f459ed65b2211854f
|
|
| BLAKE2b-256 |
dfa619f7b6112a19d89e77ef18c887c8e5be25b3e61e1940f1c20a9877a34c3e
|
File details
Details for the file bystro-2.1.0-cp311-cp311-macosx_10_12_x86_64.whl.
File metadata
- Download URL: bystro-2.1.0-cp311-cp311-macosx_10_12_x86_64.whl
- Upload date:
- Size: 22.3 MB
- Tags: CPython 3.11, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8512030982f62aa04b0db68f22c0f4ab25706f0053fba8dc374bdb926ceca2b
|
|
| MD5 |
6c23544bb108a0990d56ed686e176135
|
|
| BLAKE2b-256 |
f7d73a149875ea76124f0ab538bd1468d93a3eba6e707d663e315e18c95444ae
|