From 728a944eee05d1d78af64c223de3ed4c9f9e2b20 Mon Sep 17 00:00:00 2001 From: Sandro Gehri Date: Thu, 6 Jun 2024 21:02:29 +0200 Subject: [PATCH] Add thread messages delete endpoint --- README.md | 17 ++++++ .../Resources/ThreadsMessagesContract.php | 8 +++ src/Resources/ThreadsMessages.php | 16 +++++ .../Messages/ThreadMessageDeleteResponse.php | 61 +++++++++++++++++++ .../Resources/ThreadsMessagesTestResource.php | 6 ++ tests/Fixtures/ThreadMessage.php | 12 ++++ tests/Resources/ThreadsMessages.php | 16 +++++ .../Messages/ThreadMessageDeleteResponse.php | 47 ++++++++++++++ .../Resources/ThreadsMessagesTestResource.php | 14 +++++ 9 files changed, 197 insertions(+) create mode 100644 src/Responses/Threads/Messages/ThreadMessageDeleteResponse.php create mode 100644 tests/Responses/Threads/Messages/ThreadMessageDeleteResponse.php diff --git a/README.md b/README.md index 146efd23..df1486a3 100644 --- a/README.md +++ b/README.md @@ -1280,6 +1280,23 @@ $response->metadata; // ['name' => 'My new message name'] $response->toArray(); // ['id' => 'msg_SKYwvF3zcigxthfn6F4hnpdU', ...] ``` +#### `delete` + +Deletes a message. + +```php +$response = $client->threads()->messages()->delete( + threadId: 'thread_tKFLqzRN9n7MnyKKvc1Q7868', + messageId: 'msg_SKYwvF3zcigxthfn6F4hnpdU' +); + +$response->id; // 'msg_SKYwvF3zcigxthfn6F4hnpdU' +$response->object; // 'thread.message.deleted' +$response->deleted; // true + +$response->toArray(); // ['id' => 'msg_SKYwvF3zcigxthfn6F4hnpdU', ...] +``` + #### `list` Returns a list of messages for a given thread. diff --git a/src/Contracts/Resources/ThreadsMessagesContract.php b/src/Contracts/Resources/ThreadsMessagesContract.php index 288ecdd9..ea5bcbb6 100644 --- a/src/Contracts/Resources/ThreadsMessagesContract.php +++ b/src/Contracts/Resources/ThreadsMessagesContract.php @@ -2,6 +2,7 @@ namespace OpenAI\Contracts\Resources; +use OpenAI\Responses\Threads\Messages\ThreadMessageDeleteResponse; use OpenAI\Responses\Threads\Messages\ThreadMessageListResponse; use OpenAI\Responses\Threads\Messages\ThreadMessageResponse; @@ -32,6 +33,13 @@ public function retrieve(string $threadId, string $messageId): ThreadMessageResp */ public function modify(string $threadId, string $messageId, array $parameters): ThreadMessageResponse; + /** + * Deletes a message. + * + * @see https://platform.openai.com/docs/api-reference/messages/deleteMessage + */ + public function delete(string $threadId, string $messageId): ThreadMessageDeleteResponse; + /** * Returns a list of messages for a given thread. * diff --git a/src/Resources/ThreadsMessages.php b/src/Resources/ThreadsMessages.php index 9a98514e..da1b1adb 100644 --- a/src/Resources/ThreadsMessages.php +++ b/src/Resources/ThreadsMessages.php @@ -5,6 +5,7 @@ namespace OpenAI\Resources; use OpenAI\Contracts\Resources\ThreadsMessagesContract; +use OpenAI\Responses\Threads\Messages\ThreadMessageDeleteResponse; use OpenAI\Responses\Threads\Messages\ThreadMessageListResponse; use OpenAI\Responses\Threads\Messages\ThreadMessageResponse; use OpenAI\ValueObjects\Transporter\Payload; @@ -63,6 +64,21 @@ public function modify(string $threadId, string $messageId, array $parameters): return ThreadMessageResponse::from($response->data(), $response->meta()); } + /** + * Deletes a message. + * + * @see https://platform.openai.com/docs/api-reference/messages/deleteMessage + */ + public function delete(string $threadId, string $messageId): ThreadMessageDeleteResponse + { + $payload = Payload::delete("threads/$threadId/messages", $messageId); + + /** @var Response $response */ + $response = $this->transporter->requestObject($payload); + + return ThreadMessageDeleteResponse::from($response->data(), $response->meta()); + } + /** * Returns a list of messages for a given thread. * diff --git a/src/Responses/Threads/Messages/ThreadMessageDeleteResponse.php b/src/Responses/Threads/Messages/ThreadMessageDeleteResponse.php new file mode 100644 index 00000000..a9a62385 --- /dev/null +++ b/src/Responses/Threads/Messages/ThreadMessageDeleteResponse.php @@ -0,0 +1,61 @@ + + */ +final class ThreadMessageDeleteResponse implements ResponseContract, ResponseHasMetaInformationContract +{ + /** + * @use ArrayAccessible + */ + use ArrayAccessible; + + use Fakeable; + use HasMetaInformation; + + 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 array{id: string, object: string, deleted: bool} $attributes + */ + public static function from(array $attributes, MetaInformation $meta): self + { + return new self( + $attributes['id'], + $attributes['object'], + $attributes['deleted'], + $meta, + ); + } + + /** + * {@inheritDoc} + */ + public function toArray(): array + { + return [ + 'id' => $this->id, + 'object' => $this->object, + 'deleted' => $this->deleted, + ]; + } +} diff --git a/src/Testing/Resources/ThreadsMessagesTestResource.php b/src/Testing/Resources/ThreadsMessagesTestResource.php index 6556ba17..6c090127 100644 --- a/src/Testing/Resources/ThreadsMessagesTestResource.php +++ b/src/Testing/Resources/ThreadsMessagesTestResource.php @@ -4,6 +4,7 @@ use OpenAI\Contracts\Resources\ThreadsMessagesContract; use OpenAI\Resources\ThreadsMessages; +use OpenAI\Responses\Threads\Messages\ThreadMessageDeleteResponse; use OpenAI\Responses\Threads\Messages\ThreadMessageListResponse; use OpenAI\Responses\Threads\Messages\ThreadMessageResponse; use OpenAI\Testing\Resources\Concerns\Testable; @@ -32,6 +33,11 @@ public function modify(string $threadId, string $messageId, array $parameters): return $this->record(__FUNCTION__, func_get_args()); } + public function delete(string $threadId, string $messageId): ThreadMessageDeleteResponse + { + return $this->record(__FUNCTION__, func_get_args()); + } + public function list(string $threadId, array $parameters = []): ThreadMessageListResponse { return $this->record(__FUNCTION__, func_get_args()); diff --git a/tests/Fixtures/ThreadMessage.php b/tests/Fixtures/ThreadMessage.php index 1f8091fb..d0f47567 100644 --- a/tests/Fixtures/ThreadMessage.php +++ b/tests/Fixtures/ThreadMessage.php @@ -81,3 +81,15 @@ function threadMessageListResource(): array 'has_more' => false, ]; } + +/** + * @return array + */ +function threadMessageDeleteResource(): array +{ + return [ + 'id' => 'msg_KNsDDwE41BUAHhcPNpDkdHWZ', + 'object' => 'thread.message.deleted', + 'deleted' => true, + ]; +} diff --git a/tests/Resources/ThreadsMessages.php b/tests/Resources/ThreadsMessages.php index 924fdd80..ef68732a 100644 --- a/tests/Resources/ThreadsMessages.php +++ b/tests/Resources/ThreadsMessages.php @@ -1,6 +1,7 @@ meta()) ->toBeInstanceOf(MetaInformation::class); }); + +test('delete', function () { + $client = mockClient('DELETE', 'threads/thread_agvtHUGezjTCt4SKgQg0NJ2Y/messages/msg_KNsDDwE41BUAHhcPNpDkdHWZ', [], Response::from(threadMessageDeleteResource(), metaHeaders())); + + $result = $client->threads()->messages()->delete('thread_agvtHUGezjTCt4SKgQg0NJ2Y', 'msg_KNsDDwE41BUAHhcPNpDkdHWZ'); + + expect($result) + ->toBeInstanceOf(ThreadMessageDeleteResponse::class) + ->id->toBe('msg_KNsDDwE41BUAHhcPNpDkdHWZ') + ->object->toBe('thread.message.deleted') + ->deleted->toBe(true); + + expect($result->meta()) + ->toBeInstanceOf(MetaInformation::class); +}); diff --git a/tests/Responses/Threads/Messages/ThreadMessageDeleteResponse.php b/tests/Responses/Threads/Messages/ThreadMessageDeleteResponse.php new file mode 100644 index 00000000..b1cc78a2 --- /dev/null +++ b/tests/Responses/Threads/Messages/ThreadMessageDeleteResponse.php @@ -0,0 +1,47 @@ +id->toBe('msg_KNsDDwE41BUAHhcPNpDkdHWZ') + ->object->toBe('thread.message.deleted') + ->deleted->toBe(true) + ->meta()->toBeInstanceOf(MetaInformation::class); +}); + +test('as array accessible', function () { + $result = ThreadMessageDeleteResponse::from(threadMessageDeleteResource(), meta()); + + expect($result['id']) + ->toBe('msg_KNsDDwE41BUAHhcPNpDkdHWZ'); +}); + +test('to array', function () { + $result = ThreadMessageDeleteResponse::from(threadMessageDeleteResource(), meta()); + + expect($result->toArray()) + ->toBe(threadMessageDeleteResource()); +}); + +test('fake', function () { + $response = ThreadMessageDeleteResponse::fake(); + + expect($response) + ->id->toBe('msg_KNsDDwE41BUAHhcPNpDkdHWZ') + ->deleted->toBe(true); +}); + +test('fake with override', function () { + $response = ThreadMessageDeleteResponse::fake([ + 'id' => 'msg_1234', + 'deleted' => false, + ]); + + expect($response) + ->id->toBe('msg_1234') + ->deleted->toBe(false); +}); diff --git a/tests/Testing/Resources/ThreadsMessagesTestResource.php b/tests/Testing/Resources/ThreadsMessagesTestResource.php index 7a45e37e..43f0482d 100644 --- a/tests/Testing/Resources/ThreadsMessagesTestResource.php +++ b/tests/Testing/Resources/ThreadsMessagesTestResource.php @@ -65,6 +65,20 @@ }); }); +it('records a thread message delete request', function () { + $fake = new ClientFake([ + \OpenAI\Responses\Threads\Messages\ThreadMessageDeleteResponse::fake(), + ]); + + $fake->threads()->messages()->delete('thread_tKFLqzRN9n7MnyKKvc1Q7868', 'msg_KNsDDwE41BUAHhcPNpDkdHWZ'); + + $fake->assertSent(ThreadsMessages::class, function ($method, $threadId, $messageId) { + return $method === 'delete' && + $threadId === 'thread_tKFLqzRN9n7MnyKKvc1Q7868' && + $messageId === 'msg_KNsDDwE41BUAHhcPNpDkdHWZ'; + }); +}); + it('records a thread message list request', function () { $fake = new ClientFake([ ThreadMessageListResponse::fake(),