From ccfc78dabc7fa9ccf7631fd83e2d7e0721dcff9e Mon Sep 17 00:00:00 2001 From: Zain Ali Date: Thu, 24 Sep 2026 21:31:35 +0100 Subject: [PATCH] feat(OpenAI): add Skills API --- README.md | 163 ++++++++++++++++++ src/Client.php | 11 ++ src/Contracts/ClientContract.php | 8 + .../Resources/SkillVersionsContract.php | 51 ++++++ src/Contracts/Resources/SkillsContract.php | 67 +++++++ src/Resources/SkillVersions.php | 98 +++++++++++ src/Resources/Skills.php | 126 ++++++++++++++ src/Responses/Skills/SkillDeleteResponse.php | 65 +++++++ src/Responses/Skills/SkillListResponse.php | 80 +++++++++ src/Responses/Skills/SkillResponse.php | 77 +++++++++ .../Versions/SkillVersionDeleteResponse.php | 68 ++++++++ .../Versions/SkillVersionListResponse.php | 80 +++++++++ .../Skills/Versions/SkillVersionResponse.php | 77 +++++++++ src/Testing/ClientFake.php | 6 + .../Resources/SkillVersionsTestResource.php | 45 +++++ src/Testing/Resources/SkillsTestResource.php | 56 ++++++ .../Skills/SkillDeleteResponseFixture.php | 12 ++ .../Skills/SkillListResponseFixture.php | 16 ++ .../Fixtures/Skills/SkillResponseFixture.php | 16 ++ .../SkillVersionDeleteResponseFixture.php | 13 ++ .../SkillVersionListResponseFixture.php | 16 ++ .../Versions/SkillVersionResponseFixture.php | 16 ++ tests/Fixtures/Skill.php | 54 ++++++ tests/Fixtures/SkillVersion.php | 55 ++++++ tests/Resources/SkillVersions.php | 92 ++++++++++ tests/Resources/Skills.php | 122 +++++++++++++ .../Responses/Skills/SkillDeleteResponse.php | 33 ++++ tests/Responses/Skills/SkillListResponse.php | 38 ++++ tests/Responses/Skills/SkillResponse.php | 37 ++++ .../Versions/SkillVersionDeleteResponse.php | 34 ++++ .../Versions/SkillVersionListResponse.php | 38 ++++ .../Skills/Versions/SkillVersionResponse.php | 37 ++++ .../Resources/SkillVersionsTestResource.php | 78 +++++++++ .../Testing/Resources/SkillsTestResource.php | 92 ++++++++++ 34 files changed, 1877 insertions(+) create mode 100644 src/Contracts/Resources/SkillVersionsContract.php create mode 100644 src/Contracts/Resources/SkillsContract.php create mode 100644 src/Resources/SkillVersions.php create mode 100644 src/Resources/Skills.php create mode 100644 src/Responses/Skills/SkillDeleteResponse.php create mode 100644 src/Responses/Skills/SkillListResponse.php create mode 100644 src/Responses/Skills/SkillResponse.php create mode 100644 src/Responses/Skills/Versions/SkillVersionDeleteResponse.php create mode 100644 src/Responses/Skills/Versions/SkillVersionListResponse.php create mode 100644 src/Responses/Skills/Versions/SkillVersionResponse.php create mode 100644 src/Testing/Resources/SkillVersionsTestResource.php create mode 100644 src/Testing/Resources/SkillsTestResource.php create mode 100644 src/Testing/Responses/Fixtures/Skills/SkillDeleteResponseFixture.php create mode 100644 src/Testing/Responses/Fixtures/Skills/SkillListResponseFixture.php create mode 100644 src/Testing/Responses/Fixtures/Skills/SkillResponseFixture.php create mode 100644 src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionDeleteResponseFixture.php create mode 100644 src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionListResponseFixture.php create mode 100644 src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionResponseFixture.php create mode 100644 tests/Fixtures/Skill.php create mode 100644 tests/Fixtures/SkillVersion.php create mode 100644 tests/Resources/SkillVersions.php create mode 100644 tests/Resources/Skills.php create mode 100644 tests/Responses/Skills/SkillDeleteResponse.php create mode 100644 tests/Responses/Skills/SkillListResponse.php create mode 100644 tests/Responses/Skills/SkillResponse.php create mode 100644 tests/Responses/Skills/Versions/SkillVersionDeleteResponse.php create mode 100644 tests/Responses/Skills/Versions/SkillVersionListResponse.php create mode 100644 tests/Responses/Skills/Versions/SkillVersionResponse.php create mode 100644 tests/Testing/Resources/SkillVersionsTestResource.php create mode 100644 tests/Testing/Resources/SkillsTestResource.php diff --git a/README.md b/README.md index b0a907ddf..cb478f721 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ If you or your business relies on this package, it's important to support the de - [Conversations Items Resource](#conversations-items-resource) - [Containers Resource](#containers-resource) - [Containers Files Resource](#containers-files-resource) + - [Skills Resource](#skills-resource) + - [Skills Versions Resource](#skills-versions-resource) - [Chat Resource](#chat-resource) - [Audio Resource](#audio-resource) - [Embeddings Resource](#embeddings-resource) @@ -690,6 +692,167 @@ $response->deleted; // true $response->toArray(); // ['id' => 'cfile_...', 'object' => 'container.file.deleted', 'deleted' => true] ``` +### `Skills` Resource + +Skills give an agent reusable instructions and supporting files. Upload a skill either as a zip bundle or as a directory of files, then reference it from the Responses API shell tool via `skill_reference`. + +#### `create` + +Creates a skill from a zip bundle, or from several files that share a single top-level folder. + +```php +// Zip upload +$response = $client->skills()->create([ + 'files' => fopen('basic_math.zip', 'r'), +]); + +// Directory upload +$response = $client->skills()->create([ + 'files' => [ + fopen('basic_math/SKILL.md', 'r'), + fopen('basic_math/calculate.py', 'r'), + ], +]); + +$response->id; // 'skill_abc123' +$response->name; // 'basic-math' +$response->defaultVersion; // '1' +$response->latestVersion; // '1' + +$response->toArray(); // ['id' => 'skill_abc123', ...] +``` + +#### `list` + +Lists the skills in the current project. + +```php +$response = $client->skills()->list([ + 'limit' => 10, +]); + +$response->object; // 'list' +$response->hasMore; // false + +foreach ($response->data as $result) { + $result->id; // 'skill_abc123' + $result->name; // 'basic-math' +} + +$response->toArray(); // ['object' => 'list', 'data' => [...], ...] +``` + +#### `retrieve` + +Retrieves a skill by its ID. + +```php +$response = $client->skills()->retrieve('skill_abc123'); + +$response->id; // 'skill_abc123' +$response->description; // 'Add or multiply numbers.' + +$response->toArray(); // ['id' => 'skill_abc123', ...] +``` + +#### `update` + +Updates the default version pointer for a skill. + +```php +$response = $client->skills()->update('skill_abc123', [ + 'default_version' => '2', +]); + +$response->defaultVersion; // '2' +``` + +#### `content` + +Downloads the zip bundle for a skill's default version. + +```php +$zip = $client->skills()->content('skill_abc123'); + +file_put_contents('basic_math.zip', $zip); +``` + +#### `delete` + +Deletes a skill and all of its versions. + +```php +$response = $client->skills()->delete('skill_abc123'); + +$response->id; // 'skill_abc123' +$response->object; // 'skill.deleted' +$response->deleted; // true + +$response->toArray(); // ['id' => 'skill_abc123', ...] +``` + +### `Skills Versions` Resource + +#### `create` + +Creates a new immutable version of a skill. Pass `default` to make it the default version. + +```php +$response = $client->skills()->versions()->create('skill_abc123', [ + 'files' => fopen('basic_math_v2.zip', 'r'), + 'default' => 'true', +]); + +$response->id; // 'skillver_abc123' +$response->version; // '2' + +$response->toArray(); // ['id' => 'skillver_abc123', ...] +``` + +#### `list` + +Lists the versions of a skill. + +```php +$response = $client->skills()->versions()->list('skill_abc123', [ + 'order' => 'desc', +]); + +foreach ($response->data as $result) { + $result->version; // '2' +} +``` + +#### `retrieve` + +Retrieves a specific version of a skill. + +```php +$response = $client->skills()->versions()->retrieve('skill_abc123', '2'); + +$response->skillId; // 'skill_abc123' +$response->version; // '2' +``` + +#### `content` + +Downloads the zip bundle for a specific skill version. + +```php +$zip = $client->skills()->versions()->content('skill_abc123', '2'); +``` + +#### `delete` + +Deletes a skill version. The default version cannot be deleted; set another default first. + +```php +$response = $client->skills()->versions()->delete('skill_abc123', '1'); + +$response->object; // 'skill.version.deleted' +$response->deleted; // true +``` + ### `Chat` Resource #### `create` diff --git a/src/Client.php b/src/Client.php index 592faa740..eb84b4ecf 100644 --- a/src/Client.php +++ b/src/Client.php @@ -26,6 +26,7 @@ use OpenAI\Resources\Moderations; use OpenAI\Resources\Realtime; use OpenAI\Resources\Responses; +use OpenAI\Resources\Skills; use OpenAI\Resources\Threads; use OpenAI\Resources\VectorStores; @@ -90,6 +91,16 @@ public function containers(): Containers return new Containers($this->transporter); } + /** + * Create and manage skills for use with the Responses API shell tools. + * + * @see https://developers.openai.com/api/reference/resources/skills + */ + public function skills(): Skills + { + return new Skills($this->transporter); + } + /** * Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. * diff --git a/src/Contracts/ClientContract.php b/src/Contracts/ClientContract.php index 61001e483..695f6c96e 100644 --- a/src/Contracts/ClientContract.php +++ b/src/Contracts/ClientContract.php @@ -19,6 +19,7 @@ use OpenAI\Contracts\Resources\ModerationsContract; use OpenAI\Contracts\Resources\RealtimeContract; use OpenAI\Contracts\Resources\ResponsesContract; +use OpenAI\Contracts\Resources\SkillsContract; use OpenAI\Contracts\Resources\ThreadsContract; use OpenAI\Contracts\Resources\VectorStoresContract; @@ -67,6 +68,13 @@ public function chat(): ChatContract; */ public function containers(): ContainersContract; + /** + * Create and manage skills for use with the Responses API shell tools. + * + * @see https://developers.openai.com/api/reference/resources/skills + */ + public function skills(): SkillsContract; + /** * Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. * diff --git a/src/Contracts/Resources/SkillVersionsContract.php b/src/Contracts/Resources/SkillVersionsContract.php new file mode 100644 index 000000000..16c98a117 --- /dev/null +++ b/src/Contracts/Resources/SkillVersionsContract.php @@ -0,0 +1,51 @@ + $parameters + */ + public function create(string $skillId, array $parameters): SkillVersionResponse; + + /** + * List skill versions for a skill. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/methods/list + * + * @param array $parameters + */ + public function list(string $skillId, array $parameters = []): SkillVersionListResponse; + + /** + * Get a specific skill version. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/methods/retrieve + */ + public function retrieve(string $skillId, string $version): SkillVersionResponse; + + /** + * Download a skill version zip bundle. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/subresources/content/methods/retrieve + */ + public function content(string $skillId, string $version): string; + + /** + * Delete a skill version. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/methods/delete + */ + public function delete(string $skillId, string $version): SkillVersionDeleteResponse; +} diff --git a/src/Contracts/Resources/SkillsContract.php b/src/Contracts/Resources/SkillsContract.php new file mode 100644 index 000000000..31c6e92fa --- /dev/null +++ b/src/Contracts/Resources/SkillsContract.php @@ -0,0 +1,67 @@ + $parameters + */ + public function create(array $parameters): SkillResponse; + + /** + * List all skills for the current project. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/list + * + * @param array $parameters + */ + public function list(array $parameters = []): SkillListResponse; + + /** + * Get a skill by its ID. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/retrieve + */ + public function retrieve(string $id): SkillResponse; + + /** + * Update the default version pointer for a skill. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/update + * + * @param array $parameters + */ + public function update(string $id, array $parameters): SkillResponse; + + /** + * Download a skill zip bundle by its ID. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/content/methods/retrieve + */ + public function content(string $id): string; + + /** + * Delete a skill by its ID. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/delete + */ + public function delete(string $id): SkillDeleteResponse; + + /** + * Manage the immutable versions of a skill. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions + */ + public function versions(): SkillVersionsContract; +} diff --git a/src/Resources/SkillVersions.php b/src/Resources/SkillVersions.php new file mode 100644 index 000000000..0aa1f82f9 --- /dev/null +++ b/src/Resources/SkillVersions.php @@ -0,0 +1,98 @@ + $parameters + */ + public function create(string $skillId, array $parameters): SkillVersionResponse + { + $payload = Payload::upload("skills/$skillId/versions", $parameters); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillVersionResponse::from($response->data(), $response->meta()); + } + + /** + * List skill versions for a skill. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/methods/list + * + * @param array $parameters + */ + public function list(string $skillId, array $parameters = []): SkillVersionListResponse + { + $payload = Payload::list("skills/$skillId/versions", $parameters); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillVersionListResponse::from($response->data(), $response->meta()); + } + + /** + * Get a specific skill version. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/methods/retrieve + */ + public function retrieve(string $skillId, string $version): SkillVersionResponse + { + $payload = Payload::retrieve("skills/$skillId/versions", $version); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillVersionResponse::from($response->data(), $response->meta()); + } + + /** + * Download a skill version zip bundle. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/subresources/content/methods/retrieve + */ + public function content(string $skillId, string $version): string + { + $payload = Payload::retrieveContent("skills/$skillId/versions", $version); + + return $this->transporter->requestContent($payload); + } + + /** + * Delete a skill version. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions/methods/delete + */ + public function delete(string $skillId, string $version): SkillVersionDeleteResponse + { + $payload = Payload::delete("skills/$skillId/versions", $version); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillVersionDeleteResponse::from($response->data(), $response->meta()); + } +} diff --git a/src/Resources/Skills.php b/src/Resources/Skills.php new file mode 100644 index 000000000..dc1fc77d5 --- /dev/null +++ b/src/Resources/Skills.php @@ -0,0 +1,126 @@ + $parameters + */ + public function create(array $parameters): SkillResponse + { + $payload = Payload::upload('skills', $parameters); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillResponse::from($response->data(), $response->meta()); + } + + /** + * List all skills for the current project. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/list + * + * @param array $parameters + */ + public function list(array $parameters = []): SkillListResponse + { + $payload = Payload::list('skills', $parameters); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillListResponse::from($response->data(), $response->meta()); + } + + /** + * Get a skill by its ID. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/retrieve + */ + public function retrieve(string $id): SkillResponse + { + $payload = Payload::retrieve('skills', $id); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillResponse::from($response->data(), $response->meta()); + } + + /** + * Update the default version pointer for a skill. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/update + * + * @param array $parameters + */ + public function update(string $id, array $parameters): SkillResponse + { + $payload = Payload::modify('skills', $id, $parameters); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillResponse::from($response->data(), $response->meta()); + } + + /** + * Download a skill zip bundle by its ID. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/content/methods/retrieve + */ + public function content(string $id): string + { + $payload = Payload::retrieveContent('skills', $id); + + return $this->transporter->requestContent($payload); + } + + /** + * Delete a skill by its ID. + * + * @see https://developers.openai.com/api/reference/resources/skills/methods/delete + */ + public function delete(string $id): SkillDeleteResponse + { + $payload = Payload::delete('skills', $id); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return SkillDeleteResponse::from($response->data(), $response->meta()); + } + + /** + * Manage the immutable versions of a skill. + * + * @see https://developers.openai.com/api/reference/resources/skills/subresources/versions + */ + public function versions(): SkillVersionsContract + { + return new SkillVersions($this->transporter); + } +} diff --git a/src/Responses/Skills/SkillDeleteResponse.php b/src/Responses/Skills/SkillDeleteResponse.php new file mode 100644 index 000000000..293335c96 --- /dev/null +++ b/src/Responses/Skills/SkillDeleteResponse.php @@ -0,0 +1,65 @@ + + */ +final class SkillDeleteResponse implements ResponseContract, ResponseHasMetaInformationContract +{ + /** + * @use ArrayAccessible + */ + use ArrayAccessible; + + use Fakeable; + use HasMetaInformation; + + /** + * @param 'skill.deleted' $object + */ + private function __construct( + public readonly string $id, + public readonly string $object, + public readonly bool $deleted, + private readonly MetaInformation $meta, + ) {} + + /** + * Acts as static factory, and returns a new Response instance. + * + * @param SkillDeleteType $attributes + */ + public static function from(array $attributes, MetaInformation $meta): self + { + return new self( + id: $attributes['id'], + object: $attributes['object'], + deleted: $attributes['deleted'], + meta: $meta, + ); + } + + /** + * {@inheritDoc} + */ + public function toArray(): array + { + return [ + 'id' => $this->id, + 'object' => $this->object, + 'deleted' => $this->deleted, + ]; + } +} diff --git a/src/Responses/Skills/SkillListResponse.php b/src/Responses/Skills/SkillListResponse.php new file mode 100644 index 000000000..b501434cf --- /dev/null +++ b/src/Responses/Skills/SkillListResponse.php @@ -0,0 +1,80 @@ + + */ +final class SkillListResponse implements ResponseContract, ResponseHasMetaInformationContract +{ + /** + * @use ArrayAccessible + */ + use ArrayAccessible; + + use Fakeable; + use HasMetaInformation; + + /** + * @param 'list' $object + * @param SkillResponse[] $data + */ + private function __construct( + public readonly string $object, + public readonly array $data, + public readonly ?string $firstId, + public readonly ?string $lastId, + public readonly bool $hasMore, + private readonly MetaInformation $meta, + ) {} + + /** + * Acts as static factory, and returns a new Response instance. + * + * @param SkillListType $attributes + */ + public static function from(array $attributes, MetaInformation $meta): self + { + return new self( + object: $attributes['object'], + data: array_map( + fn (array $result): SkillResponse => SkillResponse::from($result, $meta), + $attributes['data'] + ), + firstId: $attributes['first_id'] ?? null, + lastId: $attributes['last_id'] ?? null, + hasMore: $attributes['has_more'], + meta: $meta, + ); + } + + /** + * {@inheritDoc} + */ + public function toArray(): array + { + return [ + 'object' => $this->object, + 'data' => array_map( + static fn (SkillResponse $result): array => $result->toArray(), + $this->data, + ), + 'first_id' => $this->firstId, + 'last_id' => $this->lastId, + 'has_more' => $this->hasMore, + ]; + } +} diff --git a/src/Responses/Skills/SkillResponse.php b/src/Responses/Skills/SkillResponse.php new file mode 100644 index 000000000..658bea7b7 --- /dev/null +++ b/src/Responses/Skills/SkillResponse.php @@ -0,0 +1,77 @@ + + */ +final class SkillResponse implements ResponseContract, ResponseHasMetaInformationContract +{ + /** + * @use ArrayAccessible + */ + use ArrayAccessible; + + use Fakeable; + use HasMetaInformation; + + /** + * @param 'skill' $object + */ + private function __construct( + public readonly string $id, + public readonly string $object, + public readonly int $createdAt, + public readonly string $name, + public readonly string $description, + public readonly string $defaultVersion, + public readonly string $latestVersion, + private readonly MetaInformation $meta, + ) {} + + /** + * Acts as static factory, and returns a new Response instance. + * + * @param SkillType $attributes + */ + public static function from(array $attributes, MetaInformation $meta): self + { + return new self( + id: $attributes['id'], + object: $attributes['object'], + createdAt: $attributes['created_at'], + name: $attributes['name'], + description: $attributes['description'], + defaultVersion: $attributes['default_version'], + latestVersion: $attributes['latest_version'], + meta: $meta, + ); + } + + /** + * {@inheritDoc} + */ + public function toArray(): array + { + return [ + 'id' => $this->id, + 'object' => $this->object, + 'created_at' => $this->createdAt, + 'name' => $this->name, + 'description' => $this->description, + 'default_version' => $this->defaultVersion, + 'latest_version' => $this->latestVersion, + ]; + } +} diff --git a/src/Responses/Skills/Versions/SkillVersionDeleteResponse.php b/src/Responses/Skills/Versions/SkillVersionDeleteResponse.php new file mode 100644 index 000000000..bbc4d23e5 --- /dev/null +++ b/src/Responses/Skills/Versions/SkillVersionDeleteResponse.php @@ -0,0 +1,68 @@ + + */ +final class SkillVersionDeleteResponse implements ResponseContract, ResponseHasMetaInformationContract +{ + /** + * @use ArrayAccessible + */ + use ArrayAccessible; + + use Fakeable; + use HasMetaInformation; + + /** + * @param 'skill.version.deleted' $object + */ + private function __construct( + public readonly string $id, + public readonly string $object, + public readonly bool $deleted, + public readonly string $version, + private readonly MetaInformation $meta, + ) {} + + /** + * Acts as static factory, and returns a new Response instance. + * + * @param SkillVersionDeleteType $attributes + */ + public static function from(array $attributes, MetaInformation $meta): self + { + return new self( + id: $attributes['id'], + object: $attributes['object'], + deleted: $attributes['deleted'], + version: $attributes['version'], + meta: $meta, + ); + } + + /** + * {@inheritDoc} + */ + public function toArray(): array + { + return [ + 'id' => $this->id, + 'object' => $this->object, + 'deleted' => $this->deleted, + 'version' => $this->version, + ]; + } +} diff --git a/src/Responses/Skills/Versions/SkillVersionListResponse.php b/src/Responses/Skills/Versions/SkillVersionListResponse.php new file mode 100644 index 000000000..9accf27b4 --- /dev/null +++ b/src/Responses/Skills/Versions/SkillVersionListResponse.php @@ -0,0 +1,80 @@ + + */ +final class SkillVersionListResponse implements ResponseContract, ResponseHasMetaInformationContract +{ + /** + * @use ArrayAccessible + */ + use ArrayAccessible; + + use Fakeable; + use HasMetaInformation; + + /** + * @param 'list' $object + * @param SkillVersionResponse[] $data + */ + private function __construct( + public readonly string $object, + public readonly array $data, + public readonly ?string $firstId, + public readonly ?string $lastId, + public readonly bool $hasMore, + private readonly MetaInformation $meta, + ) {} + + /** + * Acts as static factory, and returns a new Response instance. + * + * @param SkillVersionListType $attributes + */ + public static function from(array $attributes, MetaInformation $meta): self + { + return new self( + object: $attributes['object'], + data: array_map( + fn (array $result): SkillVersionResponse => SkillVersionResponse::from($result, $meta), + $attributes['data'] + ), + firstId: $attributes['first_id'] ?? null, + lastId: $attributes['last_id'] ?? null, + hasMore: $attributes['has_more'], + meta: $meta, + ); + } + + /** + * {@inheritDoc} + */ + public function toArray(): array + { + return [ + 'object' => $this->object, + 'data' => array_map( + static fn (SkillVersionResponse $result): array => $result->toArray(), + $this->data, + ), + 'first_id' => $this->firstId, + 'last_id' => $this->lastId, + 'has_more' => $this->hasMore, + ]; + } +} diff --git a/src/Responses/Skills/Versions/SkillVersionResponse.php b/src/Responses/Skills/Versions/SkillVersionResponse.php new file mode 100644 index 000000000..84e489a05 --- /dev/null +++ b/src/Responses/Skills/Versions/SkillVersionResponse.php @@ -0,0 +1,77 @@ + + */ +final class SkillVersionResponse implements ResponseContract, ResponseHasMetaInformationContract +{ + /** + * @use ArrayAccessible + */ + use ArrayAccessible; + + use Fakeable; + use HasMetaInformation; + + /** + * @param 'skill.version' $object + */ + private function __construct( + public readonly string $id, + public readonly string $object, + public readonly int $createdAt, + public readonly string $skillId, + public readonly string $version, + public readonly string $name, + public readonly string $description, + private readonly MetaInformation $meta, + ) {} + + /** + * Acts as static factory, and returns a new Response instance. + * + * @param SkillVersionType $attributes + */ + public static function from(array $attributes, MetaInformation $meta): self + { + return new self( + id: $attributes['id'], + object: $attributes['object'], + createdAt: $attributes['created_at'], + skillId: $attributes['skill_id'], + version: $attributes['version'], + name: $attributes['name'], + description: $attributes['description'], + meta: $meta, + ); + } + + /** + * {@inheritDoc} + */ + public function toArray(): array + { + return [ + 'id' => $this->id, + 'object' => $this->object, + 'created_at' => $this->createdAt, + 'skill_id' => $this->skillId, + 'version' => $this->version, + 'name' => $this->name, + 'description' => $this->description, + ]; + } +} diff --git a/src/Testing/ClientFake.php b/src/Testing/ClientFake.php index 03f1b6053..7b77e5701 100644 --- a/src/Testing/ClientFake.php +++ b/src/Testing/ClientFake.php @@ -25,6 +25,7 @@ use OpenAI\Testing\Resources\ModerationsTestResource; use OpenAI\Testing\Resources\RealtimeTestResource; use OpenAI\Testing\Resources\ResponsesTestResource; +use OpenAI\Testing\Resources\SkillsTestResource; use OpenAI\Testing\Resources\ThreadsTestResource; use OpenAI\Testing\Resources\VectorStoresTestResource; use PHPUnit\Framework\Assert as PHPUnit; @@ -166,6 +167,11 @@ public function containers(): ContainersTestResource return new ContainersTestResource($this); } + public function skills(): SkillsTestResource + { + return new SkillsTestResource($this); + } + public function embeddings(): EmbeddingsTestResource { return new EmbeddingsTestResource($this); diff --git a/src/Testing/Resources/SkillVersionsTestResource.php b/src/Testing/Resources/SkillVersionsTestResource.php new file mode 100644 index 000000000..4660ec3dc --- /dev/null +++ b/src/Testing/Resources/SkillVersionsTestResource.php @@ -0,0 +1,45 @@ +record(__FUNCTION__, func_get_args()); + } + + public function list(string $skillId, array $parameters = []): SkillVersionListResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function retrieve(string $skillId, string $version): SkillVersionResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function content(string $skillId, string $version): string + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function delete(string $skillId, string $version): SkillVersionDeleteResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } +} diff --git a/src/Testing/Resources/SkillsTestResource.php b/src/Testing/Resources/SkillsTestResource.php new file mode 100644 index 000000000..1e92f5ee3 --- /dev/null +++ b/src/Testing/Resources/SkillsTestResource.php @@ -0,0 +1,56 @@ +record(__FUNCTION__, func_get_args()); + } + + public function list(array $parameters = []): SkillListResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function retrieve(string $id): SkillResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function update(string $id, array $parameters): SkillResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function content(string $id): string + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function delete(string $id): SkillDeleteResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } + + public function versions(): SkillVersionsContract + { + return new SkillVersionsTestResource($this->fake); + } +} diff --git a/src/Testing/Responses/Fixtures/Skills/SkillDeleteResponseFixture.php b/src/Testing/Responses/Fixtures/Skills/SkillDeleteResponseFixture.php new file mode 100644 index 000000000..50d545166 --- /dev/null +++ b/src/Testing/Responses/Fixtures/Skills/SkillDeleteResponseFixture.php @@ -0,0 +1,12 @@ + 'skill_abc123', + 'object' => 'skill.deleted', + 'deleted' => true, + ]; +} diff --git a/src/Testing/Responses/Fixtures/Skills/SkillListResponseFixture.php b/src/Testing/Responses/Fixtures/Skills/SkillListResponseFixture.php new file mode 100644 index 000000000..342e5df02 --- /dev/null +++ b/src/Testing/Responses/Fixtures/Skills/SkillListResponseFixture.php @@ -0,0 +1,16 @@ + 'list', + 'data' => [ + SkillResponseFixture::ATTRIBUTES, + ], + 'first_id' => 'skill_abc123', + 'last_id' => 'skill_abc123', + 'has_more' => false, + ]; +} diff --git a/src/Testing/Responses/Fixtures/Skills/SkillResponseFixture.php b/src/Testing/Responses/Fixtures/Skills/SkillResponseFixture.php new file mode 100644 index 000000000..7d415b5a7 --- /dev/null +++ b/src/Testing/Responses/Fixtures/Skills/SkillResponseFixture.php @@ -0,0 +1,16 @@ + 'skill_abc123', + 'object' => 'skill', + 'created_at' => 1710000000, + 'name' => 'basic-math', + 'description' => 'Add or multiply numbers.', + 'default_version' => '1', + 'latest_version' => '2', + ]; +} diff --git a/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionDeleteResponseFixture.php b/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionDeleteResponseFixture.php new file mode 100644 index 000000000..0fa857cf4 --- /dev/null +++ b/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionDeleteResponseFixture.php @@ -0,0 +1,13 @@ + 'skillver_abc123', + 'object' => 'skill.version.deleted', + 'deleted' => true, + 'version' => '1', + ]; +} diff --git a/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionListResponseFixture.php b/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionListResponseFixture.php new file mode 100644 index 000000000..ea0a65838 --- /dev/null +++ b/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionListResponseFixture.php @@ -0,0 +1,16 @@ + 'list', + 'data' => [ + SkillVersionResponseFixture::ATTRIBUTES, + ], + 'first_id' => 'skillver_abc123', + 'last_id' => 'skillver_abc123', + 'has_more' => false, + ]; +} diff --git a/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionResponseFixture.php b/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionResponseFixture.php new file mode 100644 index 000000000..b79b8ea4c --- /dev/null +++ b/src/Testing/Responses/Fixtures/Skills/Versions/SkillVersionResponseFixture.php @@ -0,0 +1,16 @@ + 'skillver_abc123', + 'object' => 'skill.version', + 'created_at' => 1710000000, + 'skill_id' => 'skill_abc123', + 'version' => '1', + 'name' => 'basic-math', + 'description' => 'Add or multiply numbers.', + ]; +} diff --git a/tests/Fixtures/Skill.php b/tests/Fixtures/Skill.php new file mode 100644 index 000000000..ef83ec805 --- /dev/null +++ b/tests/Fixtures/Skill.php @@ -0,0 +1,54 @@ + + */ +function skillResource(): array +{ + return [ + 'id' => 'skill_abc123', + 'object' => 'skill', + 'created_at' => 1710000000, + 'name' => 'basic-math', + 'description' => 'Add or multiply numbers.', + 'default_version' => '1', + 'latest_version' => '2', + ]; +} + +/** + * @return array + */ +function skillListResource(): array +{ + return [ + 'object' => 'list', + 'data' => [ + skillResource(), + [ + 'id' => 'skill_def456', + 'object' => 'skill', + 'created_at' => 1710001000, + 'name' => 'csv-insights', + 'description' => 'Summarize CSV files and produce a markdown report.', + 'default_version' => '1', + 'latest_version' => '1', + ], + ], + 'first_id' => 'skill_abc123', + 'last_id' => 'skill_def456', + 'has_more' => false, + ]; +} + +/** + * @return array + */ +function skillDeleteResource(): array +{ + return [ + 'id' => 'skill_abc123', + 'object' => 'skill.deleted', + 'deleted' => true, + ]; +} diff --git a/tests/Fixtures/SkillVersion.php b/tests/Fixtures/SkillVersion.php new file mode 100644 index 000000000..7fafd691d --- /dev/null +++ b/tests/Fixtures/SkillVersion.php @@ -0,0 +1,55 @@ + + */ +function skillVersionResource(): array +{ + return [ + 'id' => 'skillver_abc123', + 'object' => 'skill.version', + 'created_at' => 1710000000, + 'skill_id' => 'skill_abc123', + 'version' => '1', + 'name' => 'basic-math', + 'description' => 'Add or multiply numbers.', + ]; +} + +/** + * @return array + */ +function skillVersionListResource(): array +{ + return [ + 'object' => 'list', + 'data' => [ + skillVersionResource(), + [ + 'id' => 'skillver_def456', + 'object' => 'skill.version', + 'created_at' => 1710002000, + 'skill_id' => 'skill_abc123', + 'version' => '2', + 'name' => 'basic-math', + 'description' => 'Add, multiply or divide numbers.', + ], + ], + 'first_id' => 'skillver_abc123', + 'last_id' => 'skillver_def456', + 'has_more' => false, + ]; +} + +/** + * @return array + */ +function skillVersionDeleteResource(): array +{ + return [ + 'id' => 'skillver_abc123', + 'object' => 'skill.version.deleted', + 'deleted' => true, + 'version' => '1', + ]; +} diff --git a/tests/Resources/SkillVersions.php b/tests/Resources/SkillVersions.php new file mode 100644 index 000000000..3e35a3046 --- /dev/null +++ b/tests/Resources/SkillVersions.php @@ -0,0 +1,92 @@ + fileResourceResource(), + 'default' => 'true', + ], Response::from(skillVersionResource(), metaHeaders()), validateParams: false); + + $result = $client->skills()->versions()->create('skill_abc123', [ + 'files' => fileResourceResource(), + 'default' => 'true', + ]); + + expect($result) + ->toBeInstanceOf(SkillVersionResponse::class) + ->id->toBe('skillver_abc123') + ->object->toBe('skill.version') + ->createdAt->toBe(1710000000) + ->skillId->toBe('skill_abc123') + ->version->toBe('1') + ->name->toBe('basic-math') + ->description->toBe('Add or multiply numbers.'); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); + +test('list', function () { + $client = mockClient('GET', 'skills/skill_abc123/versions', [ + 'order' => 'desc', + ], Response::from(skillVersionListResource(), metaHeaders())); + + $result = $client->skills()->versions()->list('skill_abc123', [ + 'order' => 'desc', + ]); + + expect($result) + ->toBeInstanceOf(SkillVersionListResponse::class) + ->object->toBe('list') + ->data->toBeArray()->toHaveCount(2) + ->data->each->toBeInstanceOf(SkillVersionResponse::class) + ->firstId->toBe('skillver_abc123') + ->lastId->toBe('skillver_def456') + ->hasMore->toBeFalse(); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); + +test('retrieve', function () { + $client = mockClient('GET', 'skills/skill_abc123/versions/1', [], Response::from(skillVersionResource(), metaHeaders())); + + $result = $client->skills()->versions()->retrieve('skill_abc123', '1'); + + expect($result) + ->toBeInstanceOf(SkillVersionResponse::class) + ->id->toBe('skillver_abc123') + ->version->toBe('1'); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); + +test('content', function () { + $client = mockContentClient('GET', 'skills/skill_abc123/versions/1/content', [], 'zip-bundle'); + + $result = $client->skills()->versions()->content('skill_abc123', '1'); + + expect($result)->toBe('zip-bundle'); +}); + +test('delete', function () { + $client = mockClient('DELETE', 'skills/skill_abc123/versions/1', [], Response::from(skillVersionDeleteResource(), metaHeaders())); + + $result = $client->skills()->versions()->delete('skill_abc123', '1'); + + expect($result) + ->toBeInstanceOf(SkillVersionDeleteResponse::class) + ->id->toBe('skillver_abc123') + ->object->toBe('skill.version.deleted') + ->deleted->toBeTrue() + ->version->toBe('1'); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); diff --git a/tests/Resources/Skills.php b/tests/Resources/Skills.php new file mode 100644 index 000000000..6baaccedb --- /dev/null +++ b/tests/Resources/Skills.php @@ -0,0 +1,122 @@ + fileResourceResource(), + ], Response::from(skillResource(), metaHeaders()), validateParams: false); + + $result = $client->skills()->create([ + 'files' => fileResourceResource(), + ]); + + expect($result) + ->toBeInstanceOf(SkillResponse::class) + ->id->toBe('skill_abc123') + ->object->toBe('skill') + ->createdAt->toBe(1710000000) + ->name->toBe('basic-math') + ->description->toBe('Add or multiply numbers.') + ->defaultVersion->toBe('1') + ->latestVersion->toBe('2'); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); + +test('create with directory upload', function () { + $client = mockClient('POST', 'skills', [ + 'files' => [fileResourceResource(), fileResourceResource()], + ], Response::from(skillResource(), metaHeaders()), validateParams: false); + + $result = $client->skills()->create([ + 'files' => [fileResourceResource(), fileResourceResource()], + ]); + + expect($result) + ->toBeInstanceOf(SkillResponse::class) + ->id->toBe('skill_abc123'); +}); + +test('list', function () { + $client = mockClient('GET', 'skills', [ + 'limit' => 10, + ], Response::from(skillListResource(), metaHeaders())); + + $result = $client->skills()->list([ + 'limit' => 10, + ]); + + expect($result) + ->toBeInstanceOf(SkillListResponse::class) + ->object->toBe('list') + ->data->toBeArray()->toHaveCount(2) + ->data->each->toBeInstanceOf(SkillResponse::class) + ->firstId->toBe('skill_abc123') + ->lastId->toBe('skill_def456') + ->hasMore->toBeFalse(); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); + +test('retrieve', function () { + $client = mockClient('GET', 'skills/skill_abc123', [], Response::from(skillResource(), metaHeaders())); + + $result = $client->skills()->retrieve('skill_abc123'); + + expect($result) + ->toBeInstanceOf(SkillResponse::class) + ->id->toBe('skill_abc123') + ->name->toBe('basic-math') + ->defaultVersion->toBe('1') + ->latestVersion->toBe('2'); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); + +test('update', function () { + $client = mockClient('POST', 'skills/skill_abc123', [ + 'default_version' => '2', + ], Response::from(skillResource(), metaHeaders())); + + $result = $client->skills()->update('skill_abc123', [ + 'default_version' => '2', + ]); + + expect($result) + ->toBeInstanceOf(SkillResponse::class) + ->id->toBe('skill_abc123'); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); + +test('content', function () { + $client = mockContentClient('GET', 'skills/skill_abc123/content', [], 'zip-bundle'); + + $result = $client->skills()->content('skill_abc123'); + + expect($result)->toBe('zip-bundle'); +}); + +test('delete', function () { + $client = mockClient('DELETE', 'skills/skill_abc123', [], Response::from(skillDeleteResource(), metaHeaders())); + + $result = $client->skills()->delete('skill_abc123'); + + expect($result) + ->toBeInstanceOf(SkillDeleteResponse::class) + ->id->toBe('skill_abc123') + ->object->toBe('skill.deleted') + ->deleted->toBeTrue(); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); diff --git a/tests/Responses/Skills/SkillDeleteResponse.php b/tests/Responses/Skills/SkillDeleteResponse.php new file mode 100644 index 000000000..3aab41eea --- /dev/null +++ b/tests/Responses/Skills/SkillDeleteResponse.php @@ -0,0 +1,33 @@ +id->toBe('skill_abc123') + ->object->toBe('skill.deleted') + ->deleted->toBeTrue(); +}); + +test('as array accessible', function () { + $result = SkillDeleteResponse::from(skillDeleteResource(), meta()); + + expect($result['deleted']) + ->toBe(true); +}); + +test('to array', function () { + $result = SkillDeleteResponse::from(skillDeleteResource(), meta()); + + expect($result->toArray()) + ->toBe(skillDeleteResource()); +}); + +test('fake', function () { + $response = SkillDeleteResponse::fake(); + + expect($response) + ->toBeInstanceOf(SkillDeleteResponse::class); +}); diff --git a/tests/Responses/Skills/SkillListResponse.php b/tests/Responses/Skills/SkillListResponse.php new file mode 100644 index 000000000..ad3603f21 --- /dev/null +++ b/tests/Responses/Skills/SkillListResponse.php @@ -0,0 +1,38 @@ +object->toBe('list') + ->data->toBeArray()->toHaveCount(2) + ->data->each->toBeInstanceOf(SkillResponse::class) + ->firstId->toBe('skill_abc123') + ->lastId->toBe('skill_def456') + ->hasMore->toBeFalse(); +}); + +test('as array accessible', function () { + $result = SkillListResponse::from(skillListResource(), meta()); + + expect($result['object']) + ->toBe('list'); +}); + +test('to array', function () { + $result = SkillListResponse::from(skillListResource(), meta()); + + expect($result->toArray()) + ->toBe(skillListResource()); +}); + +test('fake', function () { + $response = SkillListResponse::fake(); + + expect($response) + ->toBeInstanceOf(SkillListResponse::class) + ->data->each->toBeInstanceOf(SkillResponse::class); +}); diff --git a/tests/Responses/Skills/SkillResponse.php b/tests/Responses/Skills/SkillResponse.php new file mode 100644 index 000000000..f0aba893f --- /dev/null +++ b/tests/Responses/Skills/SkillResponse.php @@ -0,0 +1,37 @@ +id->toBe('skill_abc123') + ->object->toBe('skill') + ->createdAt->toBe(1710000000) + ->name->toBe('basic-math') + ->description->toBe('Add or multiply numbers.') + ->defaultVersion->toBe('1') + ->latestVersion->toBe('2'); +}); + +test('as array accessible', function () { + $result = SkillResponse::from(skillResource(), meta()); + + expect($result['default_version']) + ->toBe('1'); +}); + +test('to array', function () { + $result = SkillResponse::from(skillResource(), meta()); + + expect($result->toArray()) + ->toBe(skillResource()); +}); + +test('fake', function () { + $response = SkillResponse::fake(); + + expect($response) + ->toBeInstanceOf(SkillResponse::class); +}); diff --git a/tests/Responses/Skills/Versions/SkillVersionDeleteResponse.php b/tests/Responses/Skills/Versions/SkillVersionDeleteResponse.php new file mode 100644 index 000000000..da31cee89 --- /dev/null +++ b/tests/Responses/Skills/Versions/SkillVersionDeleteResponse.php @@ -0,0 +1,34 @@ +id->toBe('skillver_abc123') + ->object->toBe('skill.version.deleted') + ->deleted->toBeTrue() + ->version->toBe('1'); +}); + +test('as array accessible', function () { + $result = SkillVersionDeleteResponse::from(skillVersionDeleteResource(), meta()); + + expect($result['version']) + ->toBe('1'); +}); + +test('to array', function () { + $result = SkillVersionDeleteResponse::from(skillVersionDeleteResource(), meta()); + + expect($result->toArray()) + ->toBe(skillVersionDeleteResource()); +}); + +test('fake', function () { + $response = SkillVersionDeleteResponse::fake(); + + expect($response) + ->toBeInstanceOf(SkillVersionDeleteResponse::class); +}); diff --git a/tests/Responses/Skills/Versions/SkillVersionListResponse.php b/tests/Responses/Skills/Versions/SkillVersionListResponse.php new file mode 100644 index 000000000..3005f7134 --- /dev/null +++ b/tests/Responses/Skills/Versions/SkillVersionListResponse.php @@ -0,0 +1,38 @@ +object->toBe('list') + ->data->toBeArray()->toHaveCount(2) + ->data->each->toBeInstanceOf(SkillVersionResponse::class) + ->firstId->toBe('skillver_abc123') + ->lastId->toBe('skillver_def456') + ->hasMore->toBeFalse(); +}); + +test('as array accessible', function () { + $result = SkillVersionListResponse::from(skillVersionListResource(), meta()); + + expect($result['object']) + ->toBe('list'); +}); + +test('to array', function () { + $result = SkillVersionListResponse::from(skillVersionListResource(), meta()); + + expect($result->toArray()) + ->toBe(skillVersionListResource()); +}); + +test('fake', function () { + $response = SkillVersionListResponse::fake(); + + expect($response) + ->toBeInstanceOf(SkillVersionListResponse::class) + ->data->each->toBeInstanceOf(SkillVersionResponse::class); +}); diff --git a/tests/Responses/Skills/Versions/SkillVersionResponse.php b/tests/Responses/Skills/Versions/SkillVersionResponse.php new file mode 100644 index 000000000..5018d6523 --- /dev/null +++ b/tests/Responses/Skills/Versions/SkillVersionResponse.php @@ -0,0 +1,37 @@ +id->toBe('skillver_abc123') + ->object->toBe('skill.version') + ->createdAt->toBe(1710000000) + ->skillId->toBe('skill_abc123') + ->version->toBe('1') + ->name->toBe('basic-math') + ->description->toBe('Add or multiply numbers.'); +}); + +test('as array accessible', function () { + $result = SkillVersionResponse::from(skillVersionResource(), meta()); + + expect($result['skill_id']) + ->toBe('skill_abc123'); +}); + +test('to array', function () { + $result = SkillVersionResponse::from(skillVersionResource(), meta()); + + expect($result->toArray()) + ->toBe(skillVersionResource()); +}); + +test('fake', function () { + $response = SkillVersionResponse::fake(); + + expect($response) + ->toBeInstanceOf(SkillVersionResponse::class); +}); diff --git a/tests/Testing/Resources/SkillVersionsTestResource.php b/tests/Testing/Resources/SkillVersionsTestResource.php new file mode 100644 index 000000000..5aa231700 --- /dev/null +++ b/tests/Testing/Resources/SkillVersionsTestResource.php @@ -0,0 +1,78 @@ +skills()->versions()->create('skill_abc123', [ + 'files' => fileResourceResource(), + ]); + + $fake->assertSent(SkillVersions::class, function ($method, $skillId, $parameters) { + return $method === 'create' && + $skillId === 'skill_abc123' && + isset($parameters['files']); + }); +}); + +it('records a skill versions list request', function () { + $fake = new ClientFake([ + SkillVersionListResponse::fake(), + ]); + + $fake->skills()->versions()->list('skill_abc123'); + + $fake->assertSent(SkillVersions::class, function ($method, $skillId) { + return $method === 'list' && + $skillId === 'skill_abc123'; + }); +}); + +it('records a skill versions retrieve request', function () { + $fake = new ClientFake([ + SkillVersionResponse::fake(), + ]); + + $fake->skills()->versions()->retrieve('skill_abc123', '1'); + + $fake->assertSent(SkillVersions::class, function ($method, $skillId, $version) { + return $method === 'retrieve' && + $skillId === 'skill_abc123' && + $version === '1'; + }); +}); + +it('records a skill versions content request', function () { + $fake = new ClientFake([ + 'zip-bundle', + ]); + + $fake->skills()->versions()->content('skill_abc123', '1'); + + $fake->assertSent(SkillVersions::class, function ($method, $skillId, $version) { + return $method === 'content' && + $skillId === 'skill_abc123' && + $version === '1'; + }); +}); + +it('records a skill versions delete request', function () { + $fake = new ClientFake([ + SkillVersionDeleteResponse::fake(), + ]); + + $fake->skills()->versions()->delete('skill_abc123', '1'); + + $fake->assertSent(SkillVersions::class, function ($method, $skillId, $version) { + return $method === 'delete' && + $skillId === 'skill_abc123' && + $version === '1'; + }); +}); diff --git a/tests/Testing/Resources/SkillsTestResource.php b/tests/Testing/Resources/SkillsTestResource.php new file mode 100644 index 000000000..2993699e3 --- /dev/null +++ b/tests/Testing/Resources/SkillsTestResource.php @@ -0,0 +1,92 @@ +skills()->create([ + 'files' => fileResourceResource(), + ]); + + $fake->assertSent(Skills::class, function ($method, $parameters) { + return $method === 'create' && + isset($parameters['files']); + }); +}); + +it('records a skills list request', function () { + $fake = new ClientFake([ + SkillListResponse::fake(), + ]); + + $fake->skills()->list([ + 'limit' => 10, + ]); + + $fake->assertSent(Skills::class, function ($method, $parameters) { + return $method === 'list' && + $parameters['limit'] === 10; + }); +}); + +it('records a skills retrieve request', function () { + $fake = new ClientFake([ + SkillResponse::fake(), + ]); + + $fake->skills()->retrieve('skill_abc123'); + + $fake->assertSent(Skills::class, function ($method, $id) { + return $method === 'retrieve' && + $id === 'skill_abc123'; + }); +}); + +it('records a skills update request', function () { + $fake = new ClientFake([ + SkillResponse::fake(), + ]); + + $fake->skills()->update('skill_abc123', [ + 'default_version' => '2', + ]); + + $fake->assertSent(Skills::class, function ($method, $id, $parameters) { + return $method === 'update' && + $id === 'skill_abc123' && + $parameters['default_version'] === '2'; + }); +}); + +it('records a skills content request', function () { + $fake = new ClientFake([ + 'zip-bundle', + ]); + + $fake->skills()->content('skill_abc123'); + + $fake->assertSent(Skills::class, function ($method, $id) { + return $method === 'content' && + $id === 'skill_abc123'; + }); +}); + +it('records a skills delete request', function () { + $fake = new ClientFake([ + SkillDeleteResponse::fake(), + ]); + + $fake->skills()->delete('skill_abc123'); + + $fake->assertSent(Skills::class, function ($method, $id) { + return $method === 'delete' && + $id === 'skill_abc123'; + }); +});