Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/Actions/Conversations/ItemObjects.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public static function parse(array $outputItems): array
'program_output' => OutputProgramOutput::from($item),
'apply_patch_call' => OutputApplyPatchToolCall::from($item),
'apply_patch_call_output' => ApplyPatchToolCallOutput::from($item),
default => throw new \UnexpectedValueException('Uh oh! We do not recognize this type. Please submit a bug to openai-php/client on GitHub!'),
},
$outputItems,
);
Expand Down
14 changes: 9 additions & 5 deletions src/Responses/Responses/Output/OutputWebSearchToolCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@

/**
* @phpstan-import-type WebSearchActionType from OutputWebSearchAction
* @phpstan-import-type OutputWebSearchToolCallResultType from OutputWebSearchToolCallResult
* @phpstan-import-type OutputWebSearchToolCallImageResultType from OutputWebSearchToolCallImageResult
* @phpstan-import-type OutputWebSearchToolCallTextResultType from OutputWebSearchToolCallTextResult
*
* @phpstan-type OutputWebSearchToolCallType array{id: string, status: string, type: 'web_search_call', action?: WebSearchActionType, results?: array<int, OutputWebSearchToolCallResultType>}
* @phpstan-type OutputWebSearchToolCallType array{id: string, status: string, type: 'web_search_call', action?: WebSearchActionType, results?: array<int, OutputWebSearchToolCallImageResultType|OutputWebSearchToolCallTextResultType>}
*
* @implements ResponseContract<OutputWebSearchToolCallType>
*/
Expand All @@ -28,7 +29,7 @@ final class OutputWebSearchToolCall implements ResponseContract

/**
* @param 'web_search_call' $type
* @param ?array<int, OutputWebSearchToolCallResult> $results
* @param ?array<int, OutputWebSearchToolCallImageResult|OutputWebSearchToolCallTextResult> $results
*/
private function __construct(
public readonly string $id,
Expand All @@ -52,7 +53,10 @@ public static function from(array $attributes): self
: null,
results: isset($attributes['results'])
? array_map(
static fn (array $result): OutputWebSearchToolCallResult => OutputWebSearchToolCallResult::from($result),
static fn (array $result): OutputWebSearchToolCallImageResult|OutputWebSearchToolCallTextResult => match ($result['type']) {
'image_result' => OutputWebSearchToolCallImageResult::from($result),
'text_result' => OutputWebSearchToolCallTextResult::from($result),
},
$attributes['results'],
)
: null,
Expand All @@ -76,7 +80,7 @@ public function toArray(): array

if ($this->results !== null) {
$data['results'] = array_map(
static fn (OutputWebSearchToolCallResult $result): array => $result->toArray(),
static fn (OutputWebSearchToolCallImageResult|OutputWebSearchToolCallTextResult $result): array => $result->toArray(),
$this->results,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
use OpenAI\Testing\Responses\Concerns\Fakeable;

/**
* @phpstan-type OutputWebSearchToolCallResultType array{type: 'image_result', image_url: string, source_website_url: string, thumbnail_url?: string, caption?: string}
* @phpstan-type OutputWebSearchToolCallImageResultType array{type: 'image_result', image_url: string, source_website_url: string, thumbnail_url?: string, caption?: string}
*
* @implements ResponseContract<OutputWebSearchToolCallResultType>
* @implements ResponseContract<OutputWebSearchToolCallImageResultType>
*/
final class OutputWebSearchToolCallResult implements ResponseContract
final class OutputWebSearchToolCallImageResult implements ResponseContract
{
/**
* @use ArrayAccessible<OutputWebSearchToolCallResultType>
* @use ArrayAccessible<OutputWebSearchToolCallImageResultType>
*/
use ArrayAccessible;

Expand All @@ -34,7 +34,7 @@ private function __construct(
) {}

/**
* @param OutputWebSearchToolCallResultType $attributes
* @param OutputWebSearchToolCallImageResultType $attributes
*/
public static function from(array $attributes): self
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace OpenAI\Responses\Responses\Output;

use OpenAI\Contracts\ResponseContract;
use OpenAI\Responses\Concerns\ArrayAccessible;
use OpenAI\Testing\Responses\Concerns\Fakeable;

/**
* @phpstan-type OutputWebSearchToolCallTextResultType array{type: 'text_result', title?: string, url?: string, snippet?: string}
*
* @implements ResponseContract<OutputWebSearchToolCallTextResultType>
*/
final class OutputWebSearchToolCallTextResult implements ResponseContract
{
/**
* @use ArrayAccessible<OutputWebSearchToolCallTextResultType>
*/
use ArrayAccessible;

use Fakeable;

/**
* @param 'text_result' $type
*/
private function __construct(
public readonly string $type,
public readonly ?string $title,
public readonly ?string $url,
public readonly ?string $snippet,
) {}

/**
* @param OutputWebSearchToolCallTextResultType $attributes
*/
public static function from(array $attributes): self
{
return new self(
type: $attributes['type'],
title: $attributes['title'] ?? null,
url: $attributes['url'] ?? null,
snippet: $attributes['snippet'] ?? null,
);
}

/**
* {@inheritDoc}
*/
public function toArray(): array
{
$data = [
'type' => $this->type,
];

if ($this->title !== null) {
$data['title'] = $this->title;
}

if ($this->url !== null) {
$data['url'] = $this->url;
}

if ($this->snippet !== null) {
$data['snippet'] = $this->snippet;
}

return $data;
}
}
32 changes: 29 additions & 3 deletions tests/Responses/Responses/Output/OutputWebSearchToolCall.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?php

use OpenAI\Responses\Responses\Output\OutputWebSearchToolCall;
use OpenAI\Responses\Responses\Output\OutputWebSearchToolCallResult;
use OpenAI\Responses\Responses\Output\OutputWebSearchToolCallImageResult;
use OpenAI\Responses\Responses\Output\OutputWebSearchToolCallTextResult;
use OpenAI\Responses\Responses\Output\WebSearch\OutputWebSearchAction;

test('from with full action', function () {
Expand All @@ -25,7 +26,7 @@
->url->toBe('https://example.com/news/positive-story');

expect($response->results[0])
->toBeInstanceOf(OutputWebSearchToolCallResult::class)
->toBeInstanceOf(OutputWebSearchToolCallImageResult::class)
->type->toBe('image_result')
->imageUrl->toBe('https://example.com/images/positive-story.jpg')
->thumbnailUrl->toBe('https://example.com/images/positive-story-thumbnail.jpg')
Expand Down Expand Up @@ -89,7 +90,7 @@
$response = OutputWebSearchToolCall::from($payload);

expect($response->results[0])
->toBeInstanceOf(OutputWebSearchToolCallResult::class)
->toBeInstanceOf(OutputWebSearchToolCallImageResult::class)
->thumbnailUrl->toBeNull()
->caption->toBeNull();

Expand All @@ -98,6 +99,31 @@
->toBe($payload);
});

test('from with text search result', function () {
$payload = outputWebSearchToolCall();
$payload['results'] = [
[
'type' => 'text_result',
'title' => 'A positive news story',
'url' => 'https://example.com/news/positive-story',
'snippet' => 'A short summary of the positive news story.',
],
];

$response = OutputWebSearchToolCall::from($payload);

expect($response->results[0])
->toBeInstanceOf(OutputWebSearchToolCallTextResult::class)
->type->toBe('text_result')
->title->toBe('A positive news story')
->url->toBe('https://example.com/news/positive-story')
->snippet->toBe('A short summary of the positive news story.');

expect($response->toArray())
->toBeArray()
->toBe($payload);
});

test('from with action but without query', function () {
$payload = outputWebSearchToolCall();
unset($payload['action']['query']);
Expand Down
Loading