diff --git a/src/Resources/Assistants.php b/src/Resources/Assistants.php index 33a801b0..acbea9cf 100644 --- a/src/Resources/Assistants.php +++ b/src/Resources/Assistants.php @@ -26,7 +26,7 @@ public function create(array $parameters): AssistantResponse { $payload = Payload::create('assistants', $parameters); - /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}> $response */ + /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}> $response */ $response = $this->transporter->requestObject($payload); return AssistantResponse::from($response->data(), $response->meta()); @@ -41,7 +41,7 @@ public function retrieve(string $id): AssistantResponse { $payload = Payload::retrieve('assistants', $id); - /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}> $response */ + /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}> $response */ $response = $this->transporter->requestObject($payload); return AssistantResponse::from($response->data(), $response->meta()); @@ -58,7 +58,7 @@ public function modify(string $id, array $parameters): AssistantResponse { $payload = Payload::modify('assistants', $id, $parameters); - /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}> $response */ + /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}> $response */ $response = $this->transporter->requestObject($payload); return AssistantResponse::from($response->data(), $response->meta()); @@ -90,7 +90,7 @@ public function list(array $parameters = []): AssistantListResponse { $payload = Payload::list('assistants', $parameters); - /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}>, first_id: ?string, last_id: ?string, has_more: bool}> $response */ + /** @var Response}}>, tool_resources: array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}}>, first_id: ?string, last_id: ?string, has_more: bool}> $response */ $response = $this->transporter->requestObject($payload); return AssistantListResponse::from($response->data(), $response->meta()); diff --git a/src/Responses/Assistants/AssistantResponse.php b/src/Responses/Assistants/AssistantResponse.php index 73590655..05f4be65 100644 --- a/src/Responses/Assistants/AssistantResponse.php +++ b/src/Responses/Assistants/AssistantResponse.php @@ -12,12 +12,12 @@ use OpenAI\Testing\Responses\Concerns\Fakeable; /** - * @implements ResponseContract}}>, tool_resources: ?array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: string}}> + * @implements ResponseContract}}>, tool_resources: ?array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: string}}> */ final class AssistantResponse implements ResponseContract, ResponseHasMetaInformationContract { /** - * @use ArrayAccessible}}>, tool_resources: ?array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: string}}> + * @use ArrayAccessible}}>, tool_resources: ?array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: string}}> */ use ArrayAccessible; @@ -33,6 +33,7 @@ private function __construct( public string $object, public int $createdAt, public ?string $name, + public ?string $reasoningEffort, public ?string $description, public string $model, public ?string $instructions, @@ -48,7 +49,7 @@ private function __construct( /** * Acts as static factory, and returns a new Response instance. * - * @param array{id: string, object: string, created_at: int, name: ?string, description: ?string, model: string, instructions: ?string, tools: array}}>, tool_resources: ?array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}} $attributes + * @param array{id: string, object: string, created_at: int, name: ?string, reasoning_effort?: ?string, description: ?string, model: string, instructions: ?string, tools: array}}>, tool_resources: ?array{code_interpreter?: array{file_ids: array}, file_search?: array{vector_store_ids: array}}, metadata: array, temperature: ?float, top_p: ?float, response_format: string|array{type: 'text'|'json_object'}} $attributes */ public static function from(array $attributes, MetaInformation $meta): self { @@ -70,6 +71,7 @@ public static function from(array $attributes, MetaInformation $meta): self $attributes['object'], $attributes['created_at'], $attributes['name'], + $attributes['reasoning_effort'] ?? null, $attributes['description'], $attributes['model'], $attributes['instructions'], @@ -88,11 +90,12 @@ public static function from(array $attributes, MetaInformation $meta): self */ public function toArray(): array { - return [ + $response = [ 'id' => $this->id, 'object' => $this->object, 'created_at' => $this->createdAt, 'name' => $this->name, + 'reasoning_effort' => $this->reasoningEffort, 'description' => $this->description, 'model' => $this->model, 'instructions' => $this->instructions, @@ -103,5 +106,12 @@ public function toArray(): array 'top_p' => $this->topP, 'response_format' => is_string($this->responseFormat) ? $this->responseFormat : $this->responseFormat->toArray(), ]; + + // Only reasoning models will have this property. + if (! $this->reasoningEffort) { + unset($response['reasoning_effort']); + } + + return $response; } } diff --git a/tests/Fixtures/Assistant.php b/tests/Fixtures/Assistant.php index 6d802208..267a4a8b 100644 --- a/tests/Fixtures/Assistant.php +++ b/tests/Fixtures/Assistant.php @@ -26,6 +26,33 @@ function assistantResource(): array ]; } +/** + * @return array + */ +function assistantReasoningModelResource(): array +{ + return [ + 'id' => 'asst_SMzoVX8XmCZEg1EbMHoAm8tc', + 'object' => 'assistant', + 'created_at' => 1699619403, + 'name' => 'Math Tutor', + 'reasoning_effort' => 'high', + 'description' => null, + 'model' => 'gpt-o3', + 'instructions' => 'You are a personal math tutor.', + 'tools' => [ + [ + 'type' => 'code_interpreter', + ], + ], + 'tool_resources' => null, + 'metadata' => [], + 'temperature' => 0.7, + 'top_p' => 1.0, + 'response_format' => 'text', + ]; +} + /** * @return array */ @@ -217,6 +244,23 @@ function assistantListResource(): array ]; } +/** + * @return array + */ +function assistantReasoningListResource(): array +{ + return [ + 'object' => 'list', + 'data' => [ + assistantReasoningModelResource(), + assistantReasoningModelResource(), + ], + 'first_id' => 'asst_SMzoVX8XmCZEg1EbMHoAm8tc', + 'last_id' => 'asst_y49lAdZDiaQUxEBR6zrG846Q', + 'has_more' => true, + ]; +} + /** * @return array */ diff --git a/tests/Responses/Assistants/AssistantListResponse.php b/tests/Responses/Assistants/AssistantListResponse.php index 8df1717f..5becfe17 100644 --- a/tests/Responses/Assistants/AssistantListResponse.php +++ b/tests/Responses/Assistants/AssistantListResponse.php @@ -15,6 +15,14 @@ ->meta()->toBeInstanceOf(MetaInformation::class); }); +test('from reasoning models', function () { + $response = AssistantListResponse::from(assistantReasoningListResource(), meta()); + + expect($response) + ->toBeInstanceOf(AssistantListResponse::class) + ->data->each->toBeInstanceOf(AssistantResponse::class); +}); + test('as array accessible', function () { $response = AssistantListResponse::from(assistantListResource(), meta()); diff --git a/tests/Responses/Assistants/AssistantResponse.php b/tests/Responses/Assistants/AssistantResponse.php index 23fe5f3a..e4a21c7f 100644 --- a/tests/Responses/Assistants/AssistantResponse.php +++ b/tests/Responses/Assistants/AssistantResponse.php @@ -15,6 +15,7 @@ ->object->toBe('assistant') ->createdAt->toBe(1699619403) ->name->toBe('Math Tutor') + ->reasoningEffort->toBeNull() ->description->toBeNull() ->model->toBe('gpt-4') ->instructions->toBe('You are a personal math tutor.') @@ -28,6 +29,14 @@ ->responseFormat->toBe('text'); }); +test('from reasoning model', function () { + $result = AssistantResponse::from(assistantReasoningModelResource(), meta()); + + expect($result) + ->id->toBe('asst_SMzoVX8XmCZEg1EbMHoAm8tc') + ->reasoningEffort->toBe('high'); +}); + test('with file search', function () { $result = AssistantResponse::from(assistantWithToolResources(), meta());