Skip to content

Commit 9f6d2af

Browse files
committed
feat(OpenAI): add support for actions on web_search_call
1 parent 6fd45a8 commit 9f6d2af

File tree

9 files changed

+174
-3
lines changed

9 files changed

+174
-3
lines changed

src/Responses/Responses/Output/OutputWebSearchToolCall.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66

77
use OpenAI\Contracts\ResponseContract;
88
use OpenAI\Responses\Concerns\ArrayAccessible;
9+
use OpenAI\Responses\Responses\Output\WebSearch\OutputWebSearchAction;
910
use OpenAI\Testing\Responses\Concerns\Fakeable;
1011

1112
/**
12-
* @phpstan-type OutputWebSearchToolCallType array{id: string, status: string, type: 'web_search_call'}
13+
* @phpstan-import-type WebSearchActionType from OutputWebSearchAction
14+
*
15+
* @phpstan-type OutputWebSearchToolCallType array{id: string, status: string, type: 'web_search_call', action: WebSearchActionType}
1316
*
1417
* @implements ResponseContract<OutputWebSearchToolCallType>
1518
*/
@@ -29,6 +32,7 @@ private function __construct(
2932
public readonly string $id,
3033
public readonly string $status,
3134
public readonly string $type,
35+
public readonly OutputWebSearchAction $action,
3236
) {}
3337

3438
/**
@@ -40,6 +44,7 @@ public static function from(array $attributes): self
4044
id: $attributes['id'],
4145
status: $attributes['status'],
4246
type: $attributes['type'],
47+
action: OutputWebSearchAction::from($attributes['action']),
4348
);
4449
}
4550

@@ -52,6 +57,7 @@ public function toArray(): array
5257
'id' => $this->id,
5358
'status' => $this->status,
5459
'type' => $this->type,
60+
'action' => $this->action->toArray(),
5561
];
5662
}
5763
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\Responses\Output\WebSearch;
6+
7+
use OpenAI\Contracts\ResponseContract;
8+
use OpenAI\Responses\Concerns\ArrayAccessible;
9+
use OpenAI\Testing\Responses\Concerns\Fakeable;
10+
11+
/**
12+
* @phpstan-import-type WebSearchActionSourcesType from OutputWebSearchActionSources
13+
*
14+
* @phpstan-type WebSearchActionType array{type: 'search', query?: string, sources: array<int, WebSearchActionSourcesType>}
15+
*
16+
* @implements ResponseContract<WebSearchActionType>
17+
*/
18+
final class OutputWebSearchAction implements ResponseContract
19+
{
20+
/**
21+
* @use ArrayAccessible<WebSearchActionType>
22+
*/
23+
use ArrayAccessible;
24+
25+
use Fakeable;
26+
27+
/**
28+
* @param 'search' $type
29+
* @param array<int, OutputWebSearchActionSources> $sources
30+
*/
31+
private function __construct(
32+
public readonly string $type,
33+
public readonly ?string $query,
34+
public readonly array $sources,
35+
) {}
36+
37+
/**
38+
* @param WebSearchActionType $attributes
39+
*/
40+
public static function from(array $attributes): self
41+
{
42+
return new self(
43+
type: $attributes['type'],
44+
query: $attributes['query'] ?? null,
45+
sources: array_map(
46+
static fn (array $source): OutputWebSearchActionSources => OutputWebSearchActionSources::from($source),
47+
$attributes['sources'],
48+
),
49+
);
50+
}
51+
52+
/**
53+
* {@inheritDoc}
54+
*/
55+
public function toArray(): array
56+
{
57+
$data = [
58+
'type' => $this->type,
59+
'sources' => array_map(
60+
static fn (OutputWebSearchActionSources $source): array => $source->toArray(),
61+
$this->sources,
62+
),
63+
];
64+
65+
if ($this->query !== null) {
66+
$data['query'] = $this->query;
67+
}
68+
69+
return $data;
70+
}
71+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\Responses\Output\WebSearch;
6+
7+
use OpenAI\Contracts\ResponseContract;
8+
use OpenAI\Responses\Concerns\ArrayAccessible;
9+
use OpenAI\Testing\Responses\Concerns\Fakeable;
10+
11+
/**
12+
* @phpstan-type WebSearchActionSourcesType array{type: 'url', url: string}
13+
*
14+
* @implements ResponseContract<WebSearchActionSourcesType>
15+
*/
16+
final class OutputWebSearchActionSources implements ResponseContract
17+
{
18+
/**
19+
* @use ArrayAccessible<WebSearchActionSourcesType>
20+
*/
21+
use ArrayAccessible;
22+
23+
use Fakeable;
24+
25+
/**
26+
* @param 'url' $type
27+
*/
28+
private function __construct(
29+
public readonly string $type,
30+
public readonly string $url
31+
) {}
32+
33+
/**
34+
* @param WebSearchActionSourcesType $attributes
35+
*/
36+
public static function from(array $attributes): self
37+
{
38+
return new self(
39+
type: $attributes['type'],
40+
url: $attributes['url'],
41+
);
42+
}
43+
44+
/**
45+
* {@inheritDoc}
46+
*/
47+
public function toArray(): array
48+
{
49+
return [
50+
'type' => $this->type,
51+
'url' => $this->url,
52+
];
53+
}
54+
}

src/Testing/Responses/Fixtures/Responses/CancelResponseFixture.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ final class CancelResponseFixture
1919
'type' => 'web_search_call',
2020
'id' => 'ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c',
2121
'status' => 'completed',
22+
'action' => [
23+
'type' => 'search',
24+
'query' => 'what was a positive news story from today?',
25+
'sources' => [
26+
['type' => 'url', 'url' => 'https://example.com/news/positive-story'],
27+
['type' => 'url', 'url' => 'https://another.example.com/related-article'],
28+
],
29+
],
2230
],
2331
[
2432
'type' => 'message',

src/Testing/Responses/Fixtures/Responses/CreateResponseFixture.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ final class CreateResponseFixture
1919
'type' => 'web_search_call',
2020
'id' => 'ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c',
2121
'status' => 'completed',
22+
'action' => [
23+
'type' => 'search',
24+
'query' => 'what was a positive news story from today?',
25+
'sources' => [
26+
['type' => 'url', 'url' => 'https://example.com/news/positive-story'],
27+
['type' => 'url', 'url' => 'https://another.example.com/related-article'],
28+
],
29+
],
2230
],
2331
[
2432
'type' => 'message',

src/Testing/Responses/Fixtures/Responses/ResponseObjectFixture.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ final class ResponseObjectFixture
1919
'type' => 'web_search_call',
2020
'id' => 'ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c',
2121
'status' => 'completed',
22+
'action' => [
23+
'type' => 'search',
24+
'query' => 'what was a positive news story from today?',
25+
'sources' => [
26+
['type' => 'url', 'url' => 'https://example.com/news/positive-story'],
27+
['type' => 'url', 'url' => 'https://another.example.com/related-article'],
28+
],
29+
],
2230
],
2331
[
2432
'type' => 'message',

src/Testing/Responses/Fixtures/Responses/RetrieveResponseFixture.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ final class RetrieveResponseFixture
1919
'type' => 'web_search_call',
2020
'id' => 'ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c',
2121
'status' => 'completed',
22+
'action' => [
23+
'type' => 'search',
24+
'query' => 'what was a positive news story from today?',
25+
'sources' => [
26+
['type' => 'url', 'url' => 'https://example.com/news/positive-story'],
27+
['type' => 'url', 'url' => 'https://another.example.com/related-article'],
28+
],
29+
],
2230
],
2331
[
2432
'type' => 'message',

tests/Fixtures/Responses.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,14 @@ function outputWebSearchToolCall(): array
478478
'id' => 'ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c',
479479
'status' => 'completed',
480480
'type' => 'web_search_call',
481+
'action' => [
482+
'type' => 'search',
483+
'sources' => [
484+
['type' => 'url', 'url' => 'https://example.com/news/positive-story'],
485+
['type' => 'url', 'url' => 'https://another.example.com/related-article'],
486+
],
487+
'query' => 'what was a positive news story from today?',
488+
],
481489
];
482490
}
483491

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
data: {"type":"response.created","response":{"id":"resp_67ccf18ef5fc8190b16dbee19bc54e5f087bb177ab789d5c","object":"response","created_at":1741484430,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-2024-08-06","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"generate_summary":null},"store":true,"temperature":1.0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","domains":[],"search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
22
data: {"type":"response.in_progress","response":{"id":"resp_67ccf18ef5fc8190b16dbee19bc54e5f087bb177ab789d5c","object":"response","created_at":1741484430,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-2024-08-06","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"generate_summary":null},"store":true,"temperature":1.0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","domains":[],"search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
33
data: {"type":"response.output_item.added","output_index":0,"item":{"id":"ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c","type":"web_search_call","status":"in_progress"}}
4-
data: {"type":"response.output_item.done","output_index":0,"item":{"id":"ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c","type":"web_search_call","status":"completed"}}
4+
data: {"type":"response.output_item.done","output_index":0,"item":{"id":"ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c","type":"web_search_call","status":"completed","action":{"type":"search","query":"what was a positive news story from today?","sources":[{"type":"url","url":"https://example.com/news/positive-story"},{"type":"url","url":"https://another.example.com/related-article"}]}}}
55
data: {"type":"response.output_item.added","output_index":1,"item":{"id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","type":"message","status":"in_progress","role":"assistant","content":[]}}
66
data: {"type":"response.content_part.added","item_id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","output_index":1,"content_index":0,"part":{"type":"output_text","text":"","annotations":[]}}
77
data: {"type":"response.output_text.delta","item_id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","output_index":1,"content_index":0,"delta":"As of today, March 9, 2025, one notable positive news story..."}
88
data: {"type":"response.output_text.done","item_id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","output_index":1,"content_index":0,"text":"As of today, March 9, 2025, one notable positive news story..."}
99
data: {"type":"response.content_part.done","item_id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","output_index":1,"content_index":0,"part":{"type":"output_text","text":"As of today, March 9, 2025, one notable positive news story...","annotations":[{"type":"url_citation","start_index":442,"end_index":557,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":962,"end_index":1077,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":1336,"end_index":1451,"url":"https://.../?utm_source=chatgpt.com","title":"..."}]}}
1010
data: {"type":"response.output_item.done","output_index":1,"item":{"id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","type":"message","status":"completed","role":"assistant","content":[{"type":"output_text","text":"As of today, March 9, 2025, one notable positive news story...","annotations":[{"type":"url_citation","start_index":442,"end_index":557,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":962,"end_index":1077,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":1336,"end_index":1451,"url":"https://.../?utm_source=chatgpt.com","title":"..."}]}]}}
11-
data: {"type":"response.completed","response":{"id":"resp_67ccf18ef5fc8190b16dbee19bc54e5f087bb177ab789d5c","object":"response","created_at":1741484430,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-2024-08-06","output":[{"type":"web_search_call","id":"ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c","status":"completed"},{"type":"message","id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","status":"completed","role":"assistant","content":[{"type":"output_text","text":"As of today, March 9, 2025, one notable positive news story...","annotations":[{"type":"url_citation","start_index":442,"end_index":557,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":962,"end_index":1077,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":1336,"end_index":1451,"url":"https://.../?utm_source=chatgpt.com","title":"..."}]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"generate_summary":null},"store":true,"temperature":1.0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","domains":[],"search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":328,"input_tokens_details":{"cached_tokens":0},"output_tokens":356,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":684},"user":null,"metadata":{}}}
11+
data: {"type":"response.completed","response":{"id":"resp_67ccf18ef5fc8190b16dbee19bc54e5f087bb177ab789d5c","object":"response","created_at":1741484430,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-2024-08-06","output":[{"type":"web_search_call","id":"ws_67ccf18f64008190a39b619f4c8455ef087bb177ab789d5c","status":"completed","action":{"type":"search","query":"what was a positive news story from today?","sources":[{"type":"url","url":"https://example.com/news/positive-story"},{"type":"url","url":"https://another.example.com/related-article"}]}},{"type":"message","id":"msg_67ccf190ca3881909d433c50b1f6357e087bb177ab789d5c","status":"completed","role":"assistant","content":[{"type":"output_text","text":"As of today, March 9, 2025, one notable positive news story...","annotations":[{"type":"url_citation","start_index":442,"end_index":557,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":962,"end_index":1077,"url":"https://.../?utm_source=chatgpt.com","title":"..."},{"type":"url_citation","start_index":1336,"end_index":1451,"url":"https://.../?utm_source=chatgpt.com","title":"..."}]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"generate_summary":null},"store":true,"temperature":1.0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","domains":[],"search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":328,"input_tokens_details":{"cached_tokens":0},"output_tokens":356,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":684},"user":null,"metadata":{}}}

0 commit comments

Comments
 (0)