Releases: Particle-Academy/prism
Release list
v0.109.1
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: truein the request body but never set the Guzzlestreamtransport 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'sToolCallMapeagerly ranjson_decode()and passed the result straight to theToolCallconstructor; invalid model JSON decoded tonulland threw a rawTypeError. Arguments are now decoded lazily, and a decode failure raises a handledPrismExceptionthat 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
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_completionspath (Text/Structured/Stream) now has cache parity with the Responses path. This also benefits vLLM/LiteLLM-style backends used viaapi_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
cacheReadInputTokensand left insidepromptTokens); 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 vialaravel/framework— no consumer impact).laravel/mcpis now suggested for the optionalLaravelMcpTool. - 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-ignoreddev/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
Fixed
- Cached-token double counting (upstream prism-php#1017): OpenRouter, Vertex, and Gemini reported
cacheReadInputTokenswhile leaving those tokens insidepromptTokens, 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 explicitcachedContentNamecaches. 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
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
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 withFinishReason::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
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 aToolResultMessagewith your results.Tool::requiresApproval(bool|Closure)— execution pauses for an approval decision. Pending calls surface asToolApprovalRequests (server-generated ids) on the assistant message and step; resume withToolApprovalResponses. Deny-by-default: unanswered or denied requests produce denial results, never execution.ToolApprovalRequestEventstream event type + broadcast mapping (ToolApprovalRequestBroadcast) for realtime approval UIs.- Providers not yet wired keep their exact previous behavior (legacy
callToolspath 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.deliverydefault, 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
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
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_turnresume loop;refusalresolves gracefully withFinishReason::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
Absorbs 16 more upstream community PRs (upstream prism-php/prism refs):
Gemini
- prism-php#975 structured output via
response_json_schema+ fork follow-up passing native JSON Schema through (full nullability/enum semantics, closes upstream prism-php#974) - prism-php#976 mix provider tools with custom function tools (new ToolConfigMap, closes upstream prism-php#972)
- prism-php#997 normalize array-type nullable notation for raw schemas
- prism-php#1000 Usage on StepFinishEvent
- prism-php#961 topK parameter · prism-php#1002 service_tier (Flex Inference) · prism-php#1008 rate-limit violations + retry-after extraction
DeepSeek
- prism-php#1020 preserve reasoning_content through thinking-mode tool loops
- prism-php#1021 cache-hit + reasoning token usage extraction
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
- prism-php#965 tool calling in structured mode (tools phase → final json_schema request, closes upstream prism-php#963)
- prism-php#980 reasoning_effort option · prism-php#995 audio diarization
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
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 auditnow 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).