Skip to content

Releases: Particle-Academy/prism-py

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 30 Oct 03:56

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 raise PrismError with code invalid_embedding, instead
    of returning an empty or partial vector.

No breaking changes.

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 17:36
89394e2

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 an incomplete_stream error, non-recoverable, then a StreamEndEvent with finish Error.
  • After a provider error event, 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_tokens in message_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 recoverable flag.

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

Choose a tag to compare

@github-actions github-actions released this 24 Oct 15:49
5b8d92d

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_reason and, when present, thinking_blocks in additional_content (on the response, each step and the assistant message). When that message is sent back, its content_blocks are replayed in order, signatures included, following the reference's rules after a model fallback. The order of preference is content_blocks, then thinking_blocks, then the older thinking and thinking_signature pair. Anthropic requires signed thinking blocks to come back during a tool loop with extended thinking.
  • OpenAI Responses carry output_items in additional_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

Choose a tag to compare

@github-actions github-actions released this 19 Oct 00:54

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

Choose a tag to compare

@github-actions github-actions released this 15 Oct 18:58

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

Choose a tag to compare

@github-actions github-actions released this 14 Sep 18:33

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_speech and speech_to_text), files, batch and fim.
  • Three providers: anthropic, mistral and openai.
  • 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() and from_dict().

Not in this release

  • The tool-execution loop. A response that finishes on tool calls raises tool_loop_not_supported instead of running them.
  • Fifteen of the reference's eighteen providers.
  • images, moderation, text_to_speech, files and batch work with OpenAI only. fim works 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.