Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7871ffb
fix(Mistral): default tool call type to function for Mistral compatib…
ivanmestre Feb 25, 2026
8886359
feat(OpenAI): Add missing fields to `OutputImageGenerationToolCall` (…
Androbin Feb 25, 2026
00e224e
feat(OpenAI): add files missing expiration property (#746)
madskildegaard Mar 9, 2026
0a465f9
fix(OpenAI): add vector store description (#747)
madskildegaard Mar 10, 2026
6a5456d
fix(OpenAI): correct vector store file contract missing updateAttribu…
madskildegaard Mar 10, 2026
0ab6618
chore: format against modern pint defaults (#750)
iBotPeaches Mar 17, 2026
f2b1ce4
release: v0.19.1 (#749)
iBotPeaches Mar 17, 2026
9c0b8cc
fix(VLLM): streaming reasoning content (#751)
L3o-pold Mar 27, 2026
49dceef
feat(OpenAI): Add `phase` property to `OutputMessage` (#754)
Copilot Apr 1, 2026
97ad756
fix(OpenAI): React properly to server and 'high demand' errors (#730)…
leonardfischer Apr 15, 2026
34fda39
fix(OpenAI): VectorStoreResponseFileCounts attribute order (#756)
madskildegaard Apr 15, 2026
b690887
fix(OpenAI): add streaming Ratelimit event (#761)
iBotPeaches Apr 19, 2026
12e3513
release: v0.19.2 (#762)
iBotPeaches Apr 19, 2026
3e6c593
fix(OpenAI): correct missing sequenceNumbers in streaming (#764)
madskildegaard Apr 27, 2026
b9f02a6
fix(Azure): guard missing description for VectorStores (#765)
jesse-bos Apr 29, 2026
40f4cc7
chore: add SECURITY.md
nunomaduro May 13, 2026
c67a4e5
chore: add root-level permissions: read-all to workflow
nunomaduro May 13, 2026
b6dc17a
chore: add root-level permissions: read-all to workflow
nunomaduro May 13, 2026
35efdb7
chore: pin GitHub Actions to SHA
nunomaduro May 13, 2026
d98948a
chore: pin GitHub Actions to SHA
nunomaduro May 13, 2026
08437b7
fix(Gemini): add support for extra_content in chat response tool call…
leonardfischer May 19, 2026
6e93061
Merge remote-tracking branch 'upstream/main' into dev
Fox-Islam May 20, 2026
b230301
Merge branch 'main' into dev
Fox-Islam May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Security Policy

**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).**

## Reporting a Vulnerability

If you discover a security vulnerability, please report it privately using one of the following channels:

1. **GitHub Private Vulnerability Reporting** (preferred) — go to the repository's **Security** tab and click **"Report a vulnerability"**. This creates a private advisory visible only to maintainers and provides a structured workflow for triage, fix coordination, and CVE assignment.

2. **Email** — send the details to Nuno Maduro at **enunomaduro@gmail.com**.

All security vulnerabilities will be promptly addressed.
8 changes: 5 additions & 3 deletions .github/workflows/formats.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Formats

on: ['push', 'pull_request']

permissions: read-all

jobs:
ci:
runs-on: ${{ matrix.os }}
Expand All @@ -18,16 +20,16 @@ jobs:
steps:

- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Cache dependencies
uses: actions/cache@v5
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: ~/.composer/cache/files
key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}

- name: Setup PHP
uses: shivammathur/setup-php@v2
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
with:
php-version: ${{ matrix.php }}
extensions: dom, mbstring, zip
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Tests

on: ['push', 'pull_request']

permissions: read-all

jobs:
ci:
runs-on: ${{ matrix.os }}
Expand All @@ -23,16 +25,16 @@ jobs:
steps:

- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Cache dependencies
uses: actions/cache@v5
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: ~/.composer/cache/files
key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}

- name: Setup PHP
uses: shivammathur/setup-php@v2
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
with:
php-version: ${{ matrix.php }}
extensions: dom, mbstring, zip
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/)
and this project adheres to [Semantic Versioning](https://semver.org/).

# v0.19.2 (2026-04-19)
### Added
* Add `phase` property to `OutputMessage`. ([#754](https://github.com/openai-php/client/pull/754))
* Add streaming Ratelimit event. ([#761](https://github.com/openai-php/client/pull/761))

### Fixed
* Fix reasoning content streaming. ([#751](https://github.com/openai-php/client/pull/751))
* Fix `VectorStoreResponseFileCounts` attribute order. ([#756](https://github.com/openai-php/client/pull/756))
* React properly to server and 'high demand' errors. ([#757](https://github.com/openai-php/client/pull/757))

# v0.19.1 (2026-03-17)
### Added
* Add missing fields for output image generation. ([#742](https://github.com/openai-php/client/pull/742))
* Add missing fields for file properties. ([#746](https://github.com/openai-php/client/pull/746))
* Add missing vector store description. ([#747](https://github.com/openai-php/client/pull/747))
* Add missing contract definition for `updateAttributes`. ([#748](https://github.com/openai-php/client/pull/748))

### Fixed
* Add default call type for functions for Mistral compatibility. ([#744](https://github.com/openai-php/client/pull/744))

# v0.19.0 (2026-02-09)
### Added

Expand Down
9 changes: 9 additions & 0 deletions src/Contracts/Resources/VectorStoresFilesContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ public function list(string $vectorStoreId, array $parameters = []): VectorStore
*/
public function retrieve(string $vectorStoreId, string $fileId): VectorStoreFileResponse;

/**
* Update attributes on a vector store file.
*
* @see https://platform.openai.com/docs/api-reference/vector-stores-files/updateAttributes
*
* @param array<string, mixed> $parameters
*/
public function updateAttributes(string $vectorStoreId, string $fileId, array $parameters): VectorStoreFileResponse;

/**
* Delete a file within a vector store.
*
Expand Down
16 changes: 16 additions & 0 deletions src/Exceptions/ServerException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace OpenAI\Exceptions;

use Exception;
use Psr\Http\Message\ResponseInterface;

final class ServerException extends Exception
{
public function __construct(public ResponseInterface $response)
{
parent::__construct("Server error (HTTP {$response->getStatusCode()}) occurred.");
}
}
6 changes: 3 additions & 3 deletions src/Resources/Files.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function list(array $parameters = []): ListResponse
{
$payload = Payload::list('files', $parameters);

/** @var Response<array{object: string, data: array<int, array{id: string, object: string, created_at: int, bytes: ?int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, first_id: ?string, last_id: ?string, has_more: ?bool}> $response */
/** @var Response<array{object: string, data: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: ?int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, first_id: ?string, last_id: ?string, has_more: ?bool}> $response */
$response = $this->transporter->requestObject($payload);

return ListResponse::from($response->data(), $response->meta());
Expand All @@ -40,7 +40,7 @@ public function retrieve(string $file): RetrieveResponse
{
$payload = Payload::retrieve('files', $file);

/** @var Response<array{id: string, object: string, created_at: int, bytes: ?int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}> $response */
/** @var Response<array{id: string, object: string, created_at: int, expires_at: int|null, bytes: ?int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}> $response */
$response = $this->transporter->requestObject($payload);

return RetrieveResponse::from($response->data(), $response->meta());
Expand Down Expand Up @@ -69,7 +69,7 @@ public function upload(array $parameters): CreateResponse
{
$payload = Payload::upload('files', $parameters);

/** @var Response<array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}> $response */
/** @var Response<array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}> $response */
$response = $this->transporter->requestObject($payload);

return CreateResponse::from($response->data(), $response->meta());
Expand Down
8 changes: 4 additions & 4 deletions src/Resources/FineTunes.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function create(array $parameters): RetrieveResponse
{
$payload = Payload::create('fine-tunes', $parameters);

/** @var Response<array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}> $response */
/** @var Response<array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}> $response */
$response = $this->transporter->requestObject($payload);

return RetrieveResponse::from($response->data(), $response->meta());
Expand All @@ -45,7 +45,7 @@ public function list(): ListResponse
{
$payload = Payload::list('fine-tunes');

/** @var Response<array{object: string, data: array<int, array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}>}> $response */
/** @var Response<array{object: string, data: array<int, array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}>}> $response */
$response = $this->transporter->requestObject($payload);

return ListResponse::from($response->data(), $response->meta());
Expand All @@ -60,7 +60,7 @@ public function retrieve(string $fineTuneId): RetrieveResponse
{
$payload = Payload::retrieve('fine-tunes', $fineTuneId);

/** @var Response<array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}> $response */
/** @var Response<array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}> $response */
$response = $this->transporter->requestObject($payload);

return RetrieveResponse::from($response->data(), $response->meta());
Expand All @@ -75,7 +75,7 @@ public function cancel(string $fineTuneId): RetrieveResponse
{
$payload = Payload::cancel('fine-tunes', $fineTuneId);

/** @var Response<array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}> $response */
/** @var Response<array{id: string, object: string, model: string, created_at: int, events: array<int, array{object: string, created_at: int, level: string, message: string}>, fine_tuned_model: ?string, hyperparams: array{batch_size: ?int, learning_rate_multiplier: ?float, n_epochs: int, prompt_loss_weight: float}, organization_id: string, result_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, status: string, validation_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, training_files: array<int, array{id: string, object: string, created_at: int, expires_at: int|null, bytes: int, filename: string, purpose: string, status: string, status_details: array<array-key, mixed>|string|null}>, updated_at: int}> $response */
$response = $this->transporter->requestObject($payload);

return RetrieveResponse::from($response->data(), $response->meta());
Expand Down
Loading
Loading