Skip to content

The fork's complete state, v0.101.0 → v0.131.0 - #1028

Open
wishborn wants to merge 245 commits into
prism-php:mainfrom
Particle-Academy:main
Open

wishborn wants to merge 245 commits into
prism-php:mainfrom
Particle-Academy:main

Conversation

@wishborn

@wishborn wishborn commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Upstream has been quiet since March 2026 (v0.100.1), so particle-academy/prism — a drop-in fork, Prism\Prism namespace unchanged — has been absorbing the open backlog and shipping releases (context: discussion #1027). This PR offers all of that work back upstream in one piece: 166 commits, nine releases (v0.101.0–v0.109.0), gated throughout by Pest + PHPStan + Pint/Rector.

If maintainership resumes, merge wholesale or tell us how you'd like it split — we're happy to break it into reviewable chunks. Either way the fork remains active.

Community PRs from this repo merged into the fork (48)

v0.101.0 — correctness fixes (17): #952, #958, #964, #971, #977, #985, #986, #987, #989, #991, #996, #1001, #1004, #1009, #1012, #1013, #1024

v0.103.0 — provider correctness / API drift (16): #949, #954, #961, #965, #975, #976, #980, #992, #993, #995, #997, #1000, #1002, #1008, #1020, #1021

v0.104.0 — features (9): #951 (batches + files APIs), #960 (xAI images), #978 (Vertex AI provider, answers #795), #988 (fine-grained tool streaming), #998 (Anthropic adaptive thinking), #1003 (pause_turn/refusal), #1014 (Mistral FIM), #1018 (provider-agnostic withReasoning()), #1026 (Requesty provider)

v0.105.0 — features + providers (6): #757 (Replicate provider), #810 (async STT interface), #835 (Azure OpenAI provider), #898 (Qwen provider), #907 (OpenAI chat/completions api_format + streaming citations, answers #900), #920 (cost tracking in Usage)

Reimplemented rather than rebased: #932 (client-executed tools + human-in-the-loop approval, answers #921) — clean-room implementation across all providers including streaming; docs at https://ai.particle.academy/docs/core-concepts/human-in-the-loop

Adjudicated, not merged (rationale posted): #950 (duplicate of #977), #937 and #1005 (superseded by an escape-based control-character fix), #999 (superseded), #1025 (rejected — a composer-require-checker CI gate solves the underlying goal properly; analysis in Particle-Academy/prism#3)

Fork-original changes

Full release notes: https://github.com/Particle-Academy/prism/releases

🤖 Generated with Claude Code

cemarta7 and others added 30 commits November 24, 2025 22:18
Add comprehensive Replicate provider implementation supporting all core features:
text generation, streaming (SSE), structured output, embeddings, image generation,
and audio (TTS/STT).

Features:
- Text generation with system prompts and conversation history
- Real-time SSE streaming with automatic fallback to simulated streaming
- Structured output with JSON schema validation
- Image generation (FLUX, Stable Diffusion XL, etc.)
- Text-to-Speech with multiple voices (Kokoro-82m)
- Speech-to-Text with Whisper (WAV, MP3, FLAC, OGG, M4A)
- Embeddings (single and batch, 768-dimensional vectors)

Implementation:
- Async prediction management with configurable polling
- Sync mode (Prefer: wait header) for lower latency
- Comprehensive error handling with typed exceptions
- Full PHPStan level 8 compliance
- 21 tests with 60 assertions (100% feature coverage)
- 455 lines of comprehensive documentation

Files changed: 58 files, 4,444+ lines added
…chronously

This adds the ability to be able to send a request to a provider to create a transcript where the provider will give you an id and then send a webhook to you in the future when the job is done with that id. This is just supplying the interface that a provider can utilize in the future.
Add comprehensive support for Alibaba Cloud's Qwen models via the
DashScope native API (/api/v1), covering text generation, streaming,
structured output, embeddings, image generation, and image editing.

Key features:
- Text generation with multi-step tool calling
- Multi-modal (VL) support with automatic endpoint routing
- Streaming with DashScope SSE protocol and reasoning/thinking tokens
- Structured output with both JSON Object and JSON Schema modes
- Embeddings with configurable dimensions
- Image generation (qwen-image-max/plus) and editing (qwen-image-edit)
- Region-aware configuration (International, China, US deployments)
- 52 tests with real API fixtures (176 assertions)

Co-authored-by: Cursor <cursoragent@cursor.com>
StreamEndEvent.usage can be null when providers don't include usage
data in their final stream chunk, causing a TypeError downstream.
Add `?? new Usage(0, 0)` fallback to emitStreamEndEvent() in all
providers missing it, matching the existing pattern in the OpenAI
stream handler.
Add an `api_format` config option to the OpenAI driver that allows
switching from the default `/responses` endpoint to `/chat/completions`.
This enables using Prism with OpenAI-compatible backends like vLLM,
LiteLLM, and LocalAI that only implement the chat/completions API.

Set `OPENAI_API_FORMAT=chat_completions` in your env to use it. Only
text, structured, and stream methods dispatch conditionally — other
modalities (embeddings, images, moderation, TTS, STT) already use
standard endpoints that work with compatible backends as-is.
…nfigured

Providers that reject unknown parameters (e.g. Perplexity via LiteLLM)
return HTTP 400 when `"tools": []` is sent. Return null instead so
Arr::whereNotNull() filters it out entirely.
Providers with integrated search capabilities (e.g. Perplexity,
You.com) return top-level `citations` and `search_results` fields
in chat/completions responses. These were previously ignored.

Add ChatCompletionsCitationsMapper to map these into Prism's existing
Citation infrastructure, and extract them once per stream in the
ChatCompletions stream handler. Citations are passed through on the
StreamEndEvent, matching the existing pattern used by the Anthropic
handler.
…h job management, result handling, and error mapping
…delete, and metadata retrieval functionalities
…e batch job handling with inputFileId support
…xtRequest

- Use ?? [] on items to avoid passing null to buildAndUploadFile()
- Cast json_encode() result to string to satisfy non-empty-string return type
- Change clientRetry default from [] to [0] to satisfy array{0: int} type constraint

Made-with: Cursor
Introduce image generation support for the XAI provider: add Images handler (sends POST to images/generations, validates response, extracts GeneratedImage objects, and builds a Response via ResponseBuilder) and ImageRequestMap (maps Request to provider payload and forwards supported and additional provider options). Wire the new handler into XAI by adding an images() method. Add comprehensive tests for URL and base64 responses, provider-specific options, multiple images, usage, and meta handling.
…notice

Upstream prism-php#1043 deleted Prism\Prism\Streaming\StreamCollector, and the
fork's v0.132.0 shipped that deletion without declaring it among its
breaking changes. prism-harness 0.13.0 builds every streamed transcript
with it, and its range (>=0.123 <1.0) accepts 0.132, so a routine
`composer update` left any app on the harness failing with
'Class "Prism\Prism\Streaming\StreamCollector" not found' (fancy-labs
run 122, 2026-10-21).

It is restored with the same constructor, collect() and callback
signature, now built on StreamedMessages, so it follows the post-prism-php#1043
stream shape and keeps each step's replay metadata. Deprecated in favour
of StreamedMessages::fromEvents().

Verified against the consumer, not only here: prism-harness's own suite
(373 tests) passes against this tree through a path repository; with
the class deleted, its three streaming tests fail with that same error.
The class's original 13 tests are restored unchanged and pass; a new one
enters exactly as the harness does, over a real multi-step tool stream.
It was the only public class or constructor removed since v0.131.0.
… that relied on the implicit one

The audio guide warned that URLs are not fetched automatically but named
only fetchUrlContent(), the unguarded fetch, never fetchPublicUrlContent(),
the one meant for a URL from user input or model output. And six examples
still sent a URL to something that needs bytes (speech-to-text on OpenAI,
Groq and Mistral, a Gemini video that is not YouTube or a File API URI),
which now throws. Found while preparing the same change for upstream.
wishborn and others added 23 commits October 23, 2026 23:54
…rror, with unknown usage

A body that ended without message_stop (a dropped connection, a proxy
cutting it short) finished as Stop, and StreamEndEvent carried either
`new Usage(0, 0)` (no usage at all) or the message_start usage (input,
no output). Anything billing on the stream end read an interrupted call
as a cheap, complete one.

- No message_stop: a non-recoverable ErrorEvent `incomplete_stream` and
  FinishReason::Error, unless an Anthropic `error` event already ended
  it. A tool_use cut short still never runs.
- StreamEndEvent.usage is null when no usage arrived, or when any step
  of the turn lacked its final message_delta usage. StepFinishEvent
  keeps the step's partial usage.
- StreamCollector no longer turns that null into zeros: the completion
  callback's Response carries the steps' usage, with the Error finish.

Reported by fancy. Reviewed independently; the collector regression was
found in that review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pestphp/pest requires pestphp/pest-plugin-arch itself (^4.0.2 for Pest 4),
so declaring it in require-dev added nothing but a direct dependency the
org's third-party allowlist judges on its own. The plugin last saw
activity 94 days ago, past the policy's 92, which failed every CI job.
The arch tests still run: the plugin arrives with the approved Pest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(openrouter): include BYOK upstream cost with complete billing evidence

* style(openrouter): keep usage guard stable across Pint and Rector
Azure's stream handler ran tool calls through callTools(), the one path
that cannot pause for a human, so a tool marked requiresApproval() or
clientExecuted() was executed without asking whenever Azure streamed.
Every other streaming handler uses the pending-aware path. Azure now
does too: marked calls end the stream on FinishReason::ToolCalls with a
ToolApprovalRequestEvent, and a resumed stream resolves the approvals
(approved runs once, denied never) before going back to the model.

Fixed at the capability as well as the instance: callTools() now
refuses a client-executed or approval-required tool instead of running
it, so no other handler or custom provider can repeat this.
Use shared HTTPS/host checks and credential-free media downloads, refuse
redirects, bound body reads, and restrict SSE credentials to the legacy host.

BREAKING CHANGE: Replicate output downloads require approved HTTPS hosts on
port 443, refuse redirects and embedded credentials, and cap audio at 25 MiB.
Custom SSE gateways are refused; API client options no longer reach media
or modern SSE downloads.
Laravel MCP tools can define shouldRegister() to conditionally register
themselves. Prism wrapped them via Tool::make() and always sent them to
the provider. Ineligible LaravelMcpTool instances are now filtered in
withTools(), so they are neither sent to the provider nor callable.

Fixes prism-php#979

Co-Authored-By: Cursor Agent <cursoragent@cursor.com>
…-should-register

fix(tool): honor shouldRegister on Laravel MCP tools (upstream prism-php#1048)
* ci: pin and verify shared GitHub checks

* ci: harden pinned verifier execution

* ci: isolate verifier environment before shared checks
* feat(telemetry): report tool failures without capturing content

* test(telemetry): exercise native failures across supported transports

* test(telemetry): preserve job data capture in array control
Require laravel/serializable-closure ^1.3.4|^2.0 so process workers can receive readonly ToolCall arrays. Cover all 31 mapped provider surfaces with real transport and tool execution, and require successful array transport in native-failure controls.

BREAKING CHANGE: Applications locked to serializer 1.3.0–1.3.3 must update that dependency with Prism. PHP and Laravel requirements are unchanged.
…104)

* fix(perplexity): repair agent requests and deep research diagnostics

* test: replace redundant Laravel Pest plugin with native time helpers

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.