Skip to content

Releases: Particle-Academy/prism

v0.109.1

Choose a tag to compare

@wishborn wishborn released this 07 Jul 22:50

Bug-fix release addressing three items from the upstream issue tracker plus one found in review.

Fixes

  • DeepSeek & Qwen streaming buffered the whole response (upstream #990). Both handlers sent stream: true in the request body but never set the Guzzle stream transport option, so the entire response was buffered in memory before the first event yielded. Now consistent with the other 14 providers. (The Qwen instance was not reported — found while verifying prism-php#990.)
  • Malformed tool-call JSON crashed with a raw TypeError (upstream #1006). OpenRouter's ToolCallMap eagerly ran json_decode() and passed the result straight to the ToolCall constructor; invalid model JSON decoded to null and threw a raw TypeError. Arguments are now decoded lazily, and a decode failure raises a handled PrismException that the tool-execution loop turns into a tool result the model can see and recover from.

Feature

  • OpenAI text_verbosity (upstream #1015) now works on structured output and both chat/completions paths — previously it was only wired on the Responses text path.

Tests

7 new/updated tests (1,891 total): OpenRouter tool-call mapping and lazy-decode behavior, verbosity pass-through for structured + chat/completions, and the ToolCall value-object test updated to assert the handled exception.

🤖 Generated with Claude Code

v0.109.0

Choose a tag to compare

@wishborn wishborn released this 07 Jul 06:03

Cache-token visibility across seven more providers

Extends the v0.108.1 usage convention — promptTokens = non-cached input tokens, cacheReadInputTokens reported separately — to every remaining provider whose API exposes prompt_tokens_details.cached_tokens:

  • OpenAI chat_completions path (Text/Structured/Stream) now has cache parity with the Responses path. This also benefits vLLM/LiteLLM-style backends used via api_format: chat_completions.
  • Azure, Groq, Qwen, xAI: cached-token visibility wired up — these providers previously ignored the field entirely.
  • Z.AI and Requesty: fixed genuine double counting in their stream paths (cached tokens were reported in cacheReadInputTokens and left inside promptTokens); their Text/Structured paths gain cache visibility.

If you bill or budget on promptTokens for these providers, note the value no longer includes cached input tokens on cache hits.

Dependency hygiene + new CI gate

  • Directly-used dependencies are now declared: ext-mbstring, ext-openssl, psr/http-message, symfony/http-foundation (all were already installed transitively via laravel/framework — no consumer impact). laravel/mcp is now suggested for the optional LaravelMcpTool.
  • A new composer-require-checker CI workflow fails the build if code uses symbols from undeclared packages.
  • The custom Rector rule no longer ships inside src/ (moved to a dev-only, export-ignored dev/ directory).

Tests

10 new tests (1,884 total): cached-token regression coverage for all seven providers, stream-level SSE fixture tests for Z.AI and Requesty, and the first tests for the Azure provider.

🤖 Generated with Claude Code

v0.108.1 — usage accounting fix

Choose a tag to compare

@wishborn wishborn released this 07 Jul 04:18

Fixed

  • Cached-token double counting (upstream prism-php#1017): OpenRouter, Vertex, and Gemini reported cacheReadInputTokens while leaving those tokens inside promptTokens, overstating input for cost math. All three now follow the Anthropic/OpenAI/DeepSeek convention (promptTokens = non-cached portion, guarded at zero); Gemini also now accounts for implicit caching, not just explicit cachedContentName caches. Regression tests for each.

Tests

  • Backfilled Mistral structured tool-loop fixture tests (both request-shape paths) and the OpenRouter parameterless-tool streaming payload test (fork issue #3).

Suite: 1874 passing, PHPStan clean.

v0.108.0 — HITL streaming everywhere

Choose a tag to compare

@wishborn wishborn released this 07 Jul 03:44

Completes the streaming item on fork issue #4: every provider Stream handler now resolves pending approvals at stream start and, on client-executed or approval-required tool calls, yields ToolApprovalRequestEvents and ends the stream with FinishReason::ToolCalls — DeepSeek, Gemini, Groq, Mistral, Ollama, OpenRouter, Qwen, Requesty, Vertex, xAI, Z, and OpenAI ChatCompletions join Anthropic + OpenAI Responses.

Suite: 1868 passing, PHPStan clean.

v0.107.0 — HITL everywhere

Choose a tag to compare

@wishborn wishborn released this 07 Jul 03:33

Human-in-the-loop, phase 2 (fork issue #4)

  • All providers: client-executed tools and approval-required tools now work on every Text and Structured handler with a tool loop — Azure, DeepSeek, Gemini, Groq, Mistral, Ollama, OpenRouter, Qwen, Requesty, Vertex, xAI, Z, and OpenAI ChatCompletions join Anthropic + OpenAI Responses. Each handler resolves pending approvals before sending, stops its loop on marked tool calls, and carries approval requests on the assistant message for resume correlation.
  • Streaming (Anthropic + OpenAI): pending approvals resolve at stream start (yielding their tool result events); marked tool calls yield ToolApprovalRequestEvents and end the stream with FinishReason::ToolCalls. Stream fixtures + tests ported from upstream prism-php#932.
  • Docs: new core-concepts guide — Human-in-the-Loop — covering client tools, static/conditional approvals, the resume flow, deny-by-default semantics, and streaming events. Ships in the package, so the docs site picks it up automatically.

Remaining on issue #4: streaming emission for the other providers' streams, and the Reverb live demo in the docs site app.

Suite: 1868 passing, PHPStan clean.

v0.106.0 — human-in-the-loop tool approval

Choose a tag to compare

@wishborn wishborn released this 07 Jul 01:28

Client-executed tools + human-in-the-loop approval (fork issue #4, phase 1)

Clean-room reimplementation of upstream prism-php#932 (the most-requested upstream feature, prism-php#921), wired end-to-end for Anthropic and OpenAI Text + Structured:

  • Tool::clientExecuted() — the tool is sent to the model but executed by your application: the request loop stops and pending tool calls come back on the response; resume by appending a ToolResultMessage with your results.
  • Tool::requiresApproval(bool|Closure) — execution pauses for an approval decision. Pending calls surface as ToolApprovalRequests (server-generated ids) on the assistant message and step; resume with ToolApprovalResponses. Deny-by-default: unanswered or denied requests produce denial results, never execution.
  • ToolApprovalRequestEvent stream event type + broadcast mapping (ToolApprovalRequestBroadcast) for realtime approval UIs.
  • Providers not yet wired keep their exact previous behavior (legacy callTools path untouched). Streaming emission + remaining providers tracked in fork issue #4.
  • Ports the upstream PR's unit suite (39 tests).

Security

  • Replicate generated-image auto-download hardened (closes #5): https-only, host allowlist (replicate.delivery default, configurable), 30s timeout, 25MB cap — per the v0.105.0 release audit.

Suite: 1866 passing, PHPStan clean.

v0.105.0 — Batch 4: providers, chat/completions, coercion

Choose a tag to compare

@wishborn wishborn released this 06 Jul 05:56

Absorbed upstream PRs

  • prism-php#835 Azure OpenAI provider (text, structured, streaming, embeddings, image generation) — fork fix: arch-conformant visibility
  • prism-php#898 Qwen (Alibaba DashScope) provider — fork fix: null-safe image source resolution
  • prism-php#757 Replicate provider (text, structured, streaming, images, audio, embeddings) — fork fixes: Step signature drift, HTTP response typing
  • prism-php#907 (includes prism-php#902) OpenAI chat/completions api_format with streaming citations — answers upstream prism-php#900 for vLLM / LiteLLM / OpenAI-compatible backends
  • prism-php#920 cost tracking on Usage (populated by OpenRouter, aggregated across steps and streams)
  • prism-php#810 async speech-to-text interface (asTextProviderId / asTextAsync)

Skipped with rationale

  • prism-php#888 (container-resolved broadcast classes) — routes every stream event through the container on the hot path; extensibility belongs in a config map
  • prism-php#772 (ProviderOption value object) — 8-months-stale rewrite of the most-used core trait, conflicts with the batch subsystem; per-provider option scoping tracked for fork-side design

Fork-authored

  • Tool argument coercion: string arguments are coerced to the handler's declared int/float/bool types and converted to BackedEnum instances (closes upstream prism-php#1016, coercion half of prism-php#1007) — Llama-on-Groq stringified arguments now just work
  • Anthropic per-request beta features: withProviderOptions(['anthropic_beta' => …]) merges with config-level flags (upstream prism-php#953)
  • Groq function-name-splitting heuristic now covered end-to-end (issue #3 backfill)

Suite: 1823 passing, PHPStan clean.

v0.104.0 — Batch 3: features

Choose a tag to compare

@wishborn wishborn released this 06 Jul 04:47

Nine upstream feature PRs absorbed (upstream prism-php/prism refs):

Anthropic

  • prism-php#998 adaptive thinking (thinking.type: adaptive) + output effort (output_config.effort)
  • prism-php#1003 pause_turn resume loop; refusal resolves gracefully with FinishReason::Refusal
  • prism-php#988 fine-grained tool streaming (eager_input_streaming)

Cross-provider

  • prism-php#1018 provider-agnostic withReasoning() toggle (Anthropic, Gemini, OpenAI, Ollama, OpenRouter, Perplexity)
  • prism-php#951 Batching + Files APIs for Anthropic and OpenAI (Prism::batch(), Prism::files()) — with a fork fix making the Anthropic payload-size guard config-overridable (prism.anthropic.batch.max_payload_bytes) so it is actually testable

New capabilities & providers

  • prism-php#1014 Mistral FIM (fill-in-the-middle) — Prism::fim()
  • prism-php#960 xAI image generation
  • prism-php#978 Google Vertex AI provider (text, structured, streaming, embeddings) — with a fork fix repairing the GOOGLE_APPLICATION_CREDENTIALS fallback (a no-op ternary meant the env path was never used)
  • prism-php#1026 Requesty provider — with fork fixes: removed the duplicate ToolMap parameters key (the prism-php#1004 bug pattern), graceful unknown finish reasons (prism-php#996 convention), and a backfilled test suite (the PR shipped none)

Deferred

  • prism-php#932 (client-executed tools + human-in-the-loop approval) — touches every provider's handlers and predates three batches of drift; needs a dedicated rebase. Tracked separately.

Suite: 1713 passing, PHPStan clean.

v0.103.0 — Batch 2: provider correctness

Choose a tag to compare

@wishborn wishborn released this 06 Jul 03:25

Absorbs 16 more upstream community PRs (upstream prism-php/prism refs):

Gemini

DeepSeek

OpenRouter

  • prism-php#954 reasoning + reasoning_details extraction, upstream provider error unwrapping (PrismException now carries httpStatus/responseBody)
  • prism-php#992 cache write/read + reasoning usage tokens · prism-php#993 cacheTtl provider option

Mistral

Z.ai

  • prism-php#949 streaming support (full Stream handler + fixtures)

Skipped with rationale

  • prism-php#999 superseded (prefix-based StructuredModeResolver already covers gpt-5.4 models)
  • prism-php#1025 (illuminate/* component split) deferred — would blind Dependabot to laravel/framework advisories and the component list can't be verified by the current test setup; tracked in fork issue #3

Suite: 1580 passing, PHPStan clean.

v0.102.0 — security hardening

Choose a tag to compare

@wishborn wishborn released this 06 Jul 03:02

Resolves all 25 open security alerts:

  • laravel/framework constraint raised to ^12.61.1|^13.12.0, excluding the CRLF-injection (email rule) and temporary-signed-URL advisories. Laravel 11 support is dropped — all 11.x releases fall in the vulnerable ranges and no patched 11.x exists.
  • Docs toolchain moved to VitePress 2 (vite 7 / esbuild ≥0.25) + npm audit fix — clears all 20 npm advisories; npm audit now reports 0 vulnerabilities.
  • Workflows now declare least-privilege permissions: contents: read (code-scanning findings).

No package code changes; full suite green (1542 tests, PHPStan clean).