Repository navigation
Conversation
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.
…ob management and result handling
…h job management, result handling, and error mapping
…-anthropic-and-openai
…lue for data retrieval
… provider methods for batch management
…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
…s from OpenAI responses
…update tests for empty array responses
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.
Co-authored-by: machour <304450+machour@users.noreply.github.com> Agent-Logs-Url: https://github.com/machour/prism/sessions/17f7d150-e3c9-46a7-829b-e671f26cf794
Add images() method override supporting FLUX and other image models. Creates Handlers/Images.php and Maps/ImageRequestMap.php. Handles both v1 and deployment-based Azure endpoints. Updates buildUrl() to recognize /images/generations paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduces a `withReasoning(bool $enabled = true)` fluent setter on the
text and structured pending requests. Calling `->withReasoning(false)`
expresses the semantic intent of "skip reasoning" and is translated to
the right wire-format key by each provider:
| Provider | Wire format when disabled |
|------------|----------------------------------------|
| Ollama | `think: false` |
| OpenAI | `reasoning: { effort: "minimal" }` |
| Anthropic | omits the `thinking` block |
| Gemini | `thinkingConfig: { thinkingBudget: 0 }`|
| OpenRouter | `reasoning: { exclude: true }` |
| Perplexity | `reasoning_effort: "low"` |
Providers that do not support disabling reasoning treat the call as a
graceful no-op. Callers that have set the equivalent key explicitly via
`withProviderOptions()` continue to win, so the change is fully
backward compatible.
The new state lives in a `HasReasoning` concern that mirrors the shape
of `HasProviderOptions` and is composed onto both `PendingRequest` and
`Request` for text and structured generation.
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
…tion in the chunk Groq streams each tool call's deltas in separate chunks and numbers them with the delta's own index. The handler keyed them by the position inside the chunk, which is 0 for a single delta, so parallel tool calls were merged into one with the arguments of both concatenated. Adapted to the maintained fork's existing null-safe buffer access and typed test callback. Retain the legacy chunk-position fallback. Upstream-Commit: ae9432e
* Preserve usage on failed streaming attempts * Preserve native HTTP mapping and unreported stream error sequences * Preserve existing failure listener exception precedence * fix(streaming): preserve generator delegation behavior
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upstream has been quiet since March 2026 (v0.100.1), so particle-academy/prism — a drop-in fork,
Prism\Prismnamespace 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
laravel/framework ^12.61.1|^13.12.0).Tool::requiresApproval(bool|Closure)/Tool::clientExecuted(), deny-by-default resume from message history, streaming approval events — text/structured/stream on all 18 providers.promptTokens= non-cached input everywhere;cacheReadInputTokenspopulated wherever the provider exposes it. Fixed silent double counting in Gemini, Vertex, OpenRouter (v0.108.1) and Z.AI + Requesty streams (v0.109.0); added cache visibility for OpenAI chat/completions, Azure, Groq, Qwen, xAI.anthropic_betaprovider option.src/.Full release notes: https://github.com/Particle-Academy/prism/releases
🤖 Generated with Claude Code