Releases: fschwar4/saia_python
Release list
v0.9.0 — native async transport
Added
- Native async transport behind a new
[async]extra
(pip install saia-python[async], pullshttpx). Newsaia_python.aio
module:AsyncSAIAClient+AsyncChatService/AsyncArcanaService/
AsyncModelsService, thehttpx.AsyncClienttwins of the sync data plane —
chat completions and ARCANA RAGchat(streaming + non-streaming),
get_rate_limits, andhealth_check. Use it as an async context manager;
from saia_python import AsyncSAIAClientresolves lazily so importing the
package never pullshttpxfor sync-only users. See ADR-0007.- The retry brains are shared, not copied.
aexecute/
apost_chat_completionreuseRetryPolicy/_plan/_jitter/
resolve_retry/parse_rate_limitsverbatim, so the async path honours the
same 429 policy (ADR-0006) as the sync path and the two cannot drift. The
retrykeyword works identically (retry=Falsefails fast; aRetryPolicy
tunes it). AsyncSSEStreamowns thehttpxclient.stream(...)context, retrying
an initial 429 before the body is exposed (never mid-stream). Two
consumption modes:async for chunk in stream(decoded dicts; raises on an
error status) orasync for line in stream.aiter_lines()(raw lines, no
raise — lets a gateway frame upstream errors itself).
- The retry brains are shared, not copied.
- Informative 429 errors (
format_rate_limit_error, exported). When retry is
off or the budget is spent,RateLimitErrornow carries a human-readable
message — which window was hit, when it resets, and how to auto-retry — instead
of only the bare server string. Shared by both transports (raised from
raise_for_status). - Pure request builders (
saia_python._payloads, re-exported at top level):
build_chat_body,apply_arcana_fields,arcana_chat_headers, and the
INFERENCE_SERVICEconstant. Transport-free, so the sync services, the async
services, and external gateways (the AVOR adapter) share one definition of
the three-part ARCANA injection invariant (enable-tools+arcana.idbody
fields + theinference-serviceheader) — defined and unit-tested once.
Changed
- Every
SAIAErrornow carriesstatus_code+response_body(previously
onlyAPIErrordid). Lets a caller reframe the exact upstream response.
RateLimitErrorkeeps itsrate_limitsattribute (unchanged signature). raise_for_statusis transport-agnostic — it accepts arequests.Response
(honouring.ok) or anhttpx.Response(deciding success fromstatus_code),
so one implementation serves both paths. No behaviour change for sync callers.- The
testextra now installs[async]too, so CI exercises the async suite.
Notes
- Async covers the data plane + read-only control-plane calls. File
upload/index/sync, voice, and document conversion stay sync-only on
SAIAClient(batch/admin work, blocking file I/O, no concurrency benefit). See
ADR-0007 for the scope rationale. - Tests: +42 async tests (
test_async_transport/_streaming/_arcana/
_chat/_client,test_payloads,test_rate_limit_message); the suite
grows 198 → 240 and staysmypy- andruff-clean.
v0.8.0
v0.7.0 — Tokenizers
Added — Tokenizers (opt-in [tokenizer] extra)
Download the GWDG open-weight models' tokenizers and measure prompts offline:
chat-template token counts, special/structural-token overhead (absolute + relative),
subword fertility, system-prompt-from-file, and token_distribution for sizing a RAG
corpus (incl. images) against the embedding model qwen3-embedding-4b.
- New
saia_python.tokenizermodule andclient.tokenizersservice. download_tokenizer/download_all_tokenizers(tokenizer files only, never weights),
load_tokenizer,HF_TOKENsupport, and an expressiveGatedRepoAccessError.count_tiktoken_tokensfor the external OpenAI models.- Docs: Extensions guide + quickstart section; runnable
examples/tokenizer_features.ipynb.
Install: pip install saia-python[tokenizer]
Full changelog: https://github.com/fschwar4/saia_python/blob/main/docs/CHANGELOG.md
v0.6.0 — rate-limit handling
Opt-in-by-default 429 retry (RetryPolicy + execute() seam), per-call retry= override, control-plane convergence. Amends ADR-0002 (a 429 on an idempotent call is now retried by default; opt out with SAIAClient(retry=False)). Full notes: docs/CHANGELOG.md.
v0.5.0
Highlights (full notes: docs/CHANGELOG.md → 0.5.0):
- Per-file
on_resulthook on the upload/sync batch helpers (provenance/logging). - Default
(connect, read)timeouts on control-plane calls — fail fast instead of
hanging;generate_index(wait=True)tolerates + diagnoses transient poll timeouts. - New "Extensions" docs section + "ARCANA incremental sync" how-to.
v0.4.1
First release published to PyPI as
saia-python, together with
open-source project tooling and incremental-upload helpers for ARCANA.
Added
ArcanaService.upload_files(name, paths, *, overwrite=True, verbose=False)—
upload an explicit, caller-chosen list of files. The selection of what to
(re)upload is the caller's (e.g. from a checksum/manifest comparison); reuses
the same per-file batch reporting asupload_directory.ArcanaService.sync_directory(name, directory, *, select, pattern="*", recursive=False, prune=False, index=True, index_wait=True, verbose=False)—
sync a local directory under a caller-supplied
select(local_path, remote_or_None) -> "upload" | "replace" | "skip"policy,
then trigger a singlegenerate_indexonly when something changed. Keeps
change-detection (e.g. SHA-256 vs. your own manifest) outside the package,
since the ARCANA API exposes no content hash. Optionalprunedeletes remote
files with no local counterpart.- PyPI packaging metadata in
pyproject.toml:readme,license-files,
keywords, troveclassifiers, and an expanded[project.urls]table
(Homepage, Documentation, Changelog, Issues) so the project page renders the
README and is discoverable. CITATION.cff(Citation File Format 1.2.0) — enables GitHub's "Cite this
repository" button and import into reference managers.saia_python/py.typed— PEP 561 marker so downstream type checkers consume
the package's inline type hints; advertised via theTyping :: Typed
classifier..github/workflows/publish.yml— builds the sdist + wheel, runs
twine check --strict, and publishes to PyPI via OIDC Trusted Publishing
when a GitHub Release is published (no stored API token).- README status badges (PyPI, Python versions, license, CI, docs) and a
commented Zenodo DOI badge placeholder. - Linting and type-checking:
ruff(lint + format) andmypyconfiguration in
pyproject.toml, alintoptional-dependency group, a
.pre-commit-config.yaml, and aQualityCI workflow
(ruff check+ruff format --check+mypy). - Coverage reporting via
pytest-cov; the Tests workflow now runs
pytest --cov.
Changed
ArcanaService.list_files()now documents the full APIFileOutSchema
(name,size,owner_user_name,created_at,updated_at,index_info
with per-fileindex_status/chunks_indexed, andrelated_files).- Corrected the
licensefield from the deprecated SPDX identifierAGPL-3.0
toAGPL-3.0-only. The license terms are unchanged; only the SPDX expression
is now valid for PEP 639 / PyPI. Bumped the build requirement to
setuptools>=77(PEP 639 support). - Applied
ruffautofixes and the formatter across the package and tests
(Optional[X]→X | None, import sorting, consistent formatting) plus minor
mypytype-annotation fixes. No behavior change — all 92 tests pass. Known
typing gaps (tomlkit'sItem | Containerinauth.py; the.listmethod
shadowing the builtin inmodels.py/arcana.py) are scoped via documented
per-modulemypyoverrides.