flowbench (Python SDK)
The Python authoring surface: declarative flows that compile to the canonical
IR (ADR 0002) and execute on the Go engine at full VU scale, or run here
directly (python file.py) as the Python-driven producer, writing to the same
run store (ADR 0012).
Install
pip install flowbench # or: uv add flowbench
Python 3.10+, and httpx is the only dependency. Running a flow at VU scale,
or resolving a named target, also needs the flowbench engine binary — see
installation.
Passing base_url= to flow.run() skips target resolution and needs nothing
but this package.
Prompt observation
FlowBench never makes the LLM call, templates a prompt, or sets a model
parameter (ADR 0009). Your code calls whatever SDK you already use, and
ctx.prompt(...) wraps that call so the exchange is recorded:
client = OpenAI(api_key=flowbench.secret(os.environ["OPENAI_API_KEY"]))
@flow.step
def classify(ctx):
messages = [{"role": "system", "content": SYSTEM},
{"role": "user", "content": str(ctx.user["ticket"])}]
with ctx.prompt("classify", template=SYSTEM, pace="20/m", burst=3) as p:
reply = client.chat.completions.create(model="gpt-4o-mini", messages=messages)
p.record(messages, reply.choices[0].message.content, usage=reply.usage)
expect(p.completion).to_contain("refund")
- The pair is always captured, every iteration, whatever the outcome — a diff needs both sides. Redaction and the size cap still apply.
template=is the prompt's identity. It is hashed, so the diff view can tell "the prompt changed" from "the output changed under the same prompt"; without one the recorded content is hashed instead, which moves whenever a substituted value does.variant="concise"is a label, not machinery: what varies is your code, and the label gives that version its own span identity (classify@concise) so folding, metrics and diffs stay per-variant. Because it is an identity, renaming one splits a flame graph into a before and an after — a clean run warns on stderr when a name earlier runs of the same scenario recorded is no longer there.pace="20/m"is a client-side ceiling keyed to the observation name, so a run over 500 fixture rows doesn't trip the provider's rate limit in the first place.burst=lets the first N calls go unspaced. A wait shows up as its ownpacespan beside the observation.timeout=is measured, not enforced — the call is your SDK's, and FlowBench has no handle to cancel it. An overrun fails the observation after the fact; pass the same bound to your SDK's own timeout to actually cut it short.- The provider's HTTP resolves as child spans of the observation, so the round
trip is never opaque in the flame graph. A provider
429classifies asthrottled, notfailed(ADR 0006). Async clients count: a batch gathered inside one observation lands under it, call by call. Two observations open concurrently do not — gather the calls inside one, or take them in turn.
Observation only runs on the Python-driven path: flowbench run file.py
compiles to IR the Go engine executes, and there is no Python there to wrap, so
compiling a flow that observes a prompt is refused rather than silently
dropped.
Development
The toolchain is uv. It provisions the
interpreter pinned in .python-version and the dev dependencies in the
lockfile, so no manual venv or pip install is needed.
uv sync # create .venv and install the package + dev deps
uv run pytest # unit tests
uv run ruff check . # lint
uv run ruff format . # format
The Go conformance suite (internal/conformance) compiles each tests/flows/*.py
fixture and diffs the resulting IR against the YAML parser's output for the
.flow.yaml of the same name — a flow written twice must compile to one
representation. It picks up sdk-python/.venv automatically, so run uv sync
before go test ./..., or point FLOWBENCH_PYTHON at an interpreter of your
own. Without either it skips rather than fails.
License
Metadata
Release files for flowbench 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| flowbench-0.1.1.tar.gz | 72.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flowbench-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 126.3 kB
Release files / flowbench-0.1.1.tar.gz
| Download URL | flowbench-0.1.1.tar.gz |
|---|---|
| Size | 72.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4c98146f84f13f9247bbb64ef2b2cc61058a85006b73b4c29d2289c6755022b2
|
|
BLAKE2b-256 checksum How to use checksums |
0b1a633cc729d6232701fe585d12700b38d5c7c8b13353f3c8c3c0102c3ab234
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / flowbench-0.1.1-py3-none-any.whl
| Download URL | flowbench-0.1.1-py3-none-any.whl |
|---|---|
| Size | 54.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
38d60c6a0d637d4f7e3f8b35200e7db9e780ad4f9cbaaf83f4817bd63ff95dc7
|
|
BLAKE2b-256 checksum How to use checksums |
6fbee35d68136b72ad055d1c755636b6e1ff02c68579c38fc5900bc0865d21a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for flowbench 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.