Repository navigation
Releases: Particle-Academy/prism-py
Release list
v0.5.1
OpenAI and Mistral embeddings decode base64 strictly
- Fixed: OpenAI and Mistral embeddings returned as base64 were decoded to an empty vector, so callers silently received
no data. Valid base64 now decodes to the same float32 values as the PHP reference. - Malformed embeddings (non-canonical base64, a byte length that is not a whole number of float32 values, non-finite
values, or a value that is neither a vector nor a string) now raisePrismErrorwith codeinvalid_embedding, instead
of returning an empty or partial vector.
No breaking changes.
v0.5.0
prism 0.5.0: an Anthropic stream that ends early is reported, not passed off as finished
BREAKING CHANGE: an Anthropic stream now always ends with exactly one StreamEndEvent, which reports FinishReason Error if anything went wrong, and its usage is null unless the final usage arrived. Before, a stream cut off before message_stop simply stopped, with no error and no end event; a provider error event was followed by no end event; a later stop could overwrite an earlier error with Stop; and a stream missing its final usage reported the start-of-message counters (the input, no output) as its total. If you treat the end event or its usage as a complete, billable call, check finish_reason and treat a null usage as unknown, not free.
What changed, matching the PHP reference (particle-academy/prism 0.135.0):
- A stream that ends before Anthropic's
message_stop(a dropped connection, a proxy cut) emits anincomplete_streamerror, non-recoverable, then a StreamEndEvent with finish Error. - After a provider
errorevent, the stream still ends with a StreamEndEvent, finish Error, and an unfinished text block is closed with its text. A later stop or final usage never turns Error back into Stop. - The StreamEndEvent usage is null when Anthropic never sent the final usage (
output_tokensinmessage_delta), so a partial count is never reported as the total. - Tool input cut off mid-stream is discarded: it never becomes a completed, executable tool call.
- ErrorEvent gains an optional
recoverableflag.
Verified by a new cross-language streaming suite (prism-parity corpus 0.1.11, ten cases including a truncated tool call and keepalive/unknown events), generated from the published PHP reference and run against both ports. The event vocabulary still differs from the reference (no step events; tracked as G-125); the properties above hold in all three languages.
v0.4.0
prism 0.4.0: replay provider state across turns
No breaking changes.
A stored assistant message can now be sent back exactly as the provider produced it, matching the PHP reference (particle-academy/prism). Before this, the provider state that multi-turn conversations depend on was dropped, so a resumed conversation could lose it.
- Anthropic responses carry
content_blocks,stop_reasonand, when present,thinking_blocksinadditional_content(on the response, each step and the assistant message). When that message is sent back, itscontent_blocksare replayed in order, signatures included, following the reference's rules after a model fallback. The order of preference iscontent_blocks, thenthinking_blocks, then the olderthinkingandthinking_signaturepair. Anthropic requires signed thinking blocks to come back during a tool loop with extended thinking. - OpenAI Responses carry
output_itemsinadditional_content. When the message is sent back, those items are replayed as Responses input, keeping reasoning state across turns. - Thinking signatures and encrypted reasoning are opaque. They are passed through untouched and never logged.
- Checked against the shared cross-language corpus (prism-parity), generated from the published PHP reference 0.135.0, for both the response shape and the replayed request.
v0.3.0
prism-ai-core 0.3.0
BREAKING CHANGE: Media.fetch_public() now refuses an answer over 32 MiB
with media_too_large, where 0.2.0 accepted any size. If you fetch larger
media through the guarded path, pass max_bytes=... to raise the cap.
SECURITY (G-90): the guarded fetch takes a URL the caller does not
trust, and read its answer whole, so a public host could answer with
gigabytes and exhaust the worker's memory.
- HttpRequest.max_body_bytes (new, optional): a transport reads at most
one byte past it, and nothing when a declared Content-Length is
already over it. The default UrllibTransport honours it. A custom
Transport should too; one that does not is still refused, after the
read. - fetch_public(max_bytes=32 * 1024 * 1024) sets it and refuses a body or
a declared length over the cap. 32 MiB is the largest inline document
the providers take, so a larger body could not be sent to a model
anyway.
v0.2.0
prism-ai-core 0.2.0
No breaking changes.
- Guarded media fetch: Media.fetch_public() fetches a URL you do not
trust, after checking the scheme, the literal address and EVERY DNS
answer, and re-checking each redirect hop before requesting it. It
refuses private, loopback, link-local, CGNAT (including Alibaba
Cloud's metadata endpoint 100.100.100.200), documentation,
benchmarking, multicast and reserved ranges, and judges NAT64
(64:ff9b::/96) and 6to4 (2002::/16) addresses by the IPv4 address
they embed, so 64:ff9b::a9fe:a9fe is refused as 169.254.169.254 (G-89).
DNS answers are not pinned to the connection, so DNS rebinding remains
possible; the response body is not size-capped yet (G-90). - Structured output on OpenAI: gpt-6.x (gpt-6-sol, gpt-6-luna,
gpt-6-astra, gpt-6.1-sol) and the o-series (o1, o1-pro, o3, o3-pro,
o4-mini) now get a strict json_schema under the default auto mode.
They previously fell back to json_object, where the schema is not
enforced. Names outside OpenAI's model families keep JSON mode
(Particle-Academy/prism#83).
v0.1.0
v0.1.0 - First release on PyPI
The Python port of Prism, a unified API layer over LLM providers. The distribution is prism-ai-core; the package imports as prism.
pip install prism-ai-core
What it has
- Every capability the PHP reference has:
text,structured,stream,embeddings,images,moderation,audio(text_to_speechandspeech_to_text),files,batchandfim. - Three providers:
anthropic,mistralandopenai. - No runtime dependencies. Python 3.10 or later.
- Every failure carries a stable
code(prism.ErrorCode). Match on the code, not the message. - Every value object has
to_dict()andfrom_dict().
Not in this release
- The tool-execution loop. A response that finishes on tool calls raises
tool_loop_not_supportedinstead of running them. - Fifteen of the reference's eighteen providers.
images,moderation,text_to_speech,filesandbatchwork with OpenAI only.fimworks with Mistral only, as in the reference.
Do not install prism-ai
prism-ai on PyPI is an unrelated package by another author, and it also has a version 0.1.0. Install prism-ai-core.
prism-parity's conformance corpus pins this port's behaviour against the PHP reference and the TypeScript port.