Skip to content

[Bug]: Missing action field in OutputWebSearchToolCall #697

@alxndrmlr

Description

@alxndrmlr

Description

The OutputWebSearchToolCall class does not expose the action field that the OpenAI API returns when using include: ['web_search_call.action.sources']. This prevents developers from accessing the search query and list of sources (URLs) that were consulted.

What the API returns:

{
  "id": "ws_xxx",
  "type": "web_search_call",
  "status": "completed",
  "action": {
    "type": "search",
    "query": "Canada climate policies 2025",
    "sources": [
      {
        "type": "url",
        "url": "https://example.com/article"
      }
    ]
  }
}

What the library exposes:

Currently, OutputWebSearchToolCall only has id, status, and type properties. The action field is silently dropped during deserialization.

Note: The streaming WebSearchCall class already has this field as of v0.17.0, creating an inconsistency.

Steps To Reproduce

  1. Install openai-php/client v0.17.0
  2. Create a response with web search and include parameter:
<?php

require 'vendor/autoload.php';

$client = OpenAI::client(getenv('OPENAI_API_KEY'));

$response = $client->responses()->create([
    'model' => 'gpt-5',
    'tools' => [['type' => 'web_search_preview']],
    'input' => 'What are the latest climate policies?',
    'include' => ['web_search_call.action.sources'],
]);

foreach ($response->output as $item) {
    if ($item->type === 'web_search_call') {
        // This currently fails because $action property doesn't exist
        var_dump($item->action); // ❌ Error: Undefined property
    }
}
  1. Observe that $item->action does not exist, despite the raw API response containing this data

Expected: Access to $item->action['query'] and $item->action['sources']
Actual: Property does not exist; data is silently dropped

OpenAI PHP Client Version

v0.17.0

PHP Version

8.2.20

Notes

Proposed Fix

Add the action property to OutputWebSearchToolCall to match the streaming WebSearchCall class:

<?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 WebSearchSourceType array{type: string, url: string}
 * @phpstan-type WebSearchActionType array{type: string, query?: string, sources?: array<WebSearchSourceType>}
 * @phpstan-type OutputWebSearchToolCallType array{id: string, status: string, type: 'web_search_call', action?: WebSearchActionType}
 *
 * @implements ResponseContract<OutputWebSearchToolCallType>
 */
final class OutputWebSearchToolCall implements ResponseContract
{
    /**
     * @use ArrayAccessible<OutputWebSearchToolCallType>
     */
    use ArrayAccessible;

    use Fakeable;

    /**
     * @param  'web_search_call'  $type
     * @param  array{type: string, query?: string, sources?: array<array{type: string, url: string}>}|null  $action
     */
    private function __construct(
        public readonly string $id,
        public readonly string $status,
        public readonly string $type,
        public readonly ?array $action,
    ) {}

    /**
     * @param  OutputWebSearchToolCallType  $attributes
     */
    public static function from(array $attributes): self
    {
        return new self(
            id: $attributes['id'],
            status: $attributes['status'],
            type: $attributes['type'],
            action: $attributes['action'] ?? null,
        );
    }

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

Why This Matters

Use cases enabled:

  • Build citation systems (show users which sources were consulted)
  • Create audit trails for compliance (log URLs accessed)
  • Debug search behavior (see actual queries executed)
  • Content verification (verify appropriate sources were used)

Compatibility

  • ✅ Backward compatible (field is optional)
  • ✅ Matches existing WebSearchCall streaming class
  • ✅ Tested in production with vendor patch

Related


Additional context: I've implemented this as a vendor patch in my production application and can confirm it works correctly with the OpenAI API.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions