WordPress / WordPress/php-ai-client

WebSearch cannot express max_uses, and lets mutually exclusive domain lists through

Open
#291 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
308
Forks
84
Avg merge
7d 21h
Merged PRs (30d)
2

Description

src/Tools/DTO/WebSearch.php carries exactly two fields, allowedDomains and disallowedDomains. The file is unchanged since the 0.1.0 release. Two consequences, one additive and one that needs a decision.

1. max_uses cannot be expressed, so providers hardcode it

ai-provider-for-anthropic hardcodes it at src/Models/AnthropicTextGenerationModel.php:588-597 (trunk):

if ($webSearch) {
    $tools[] = array_filter([
        'type' => 'web_search_20250305',
        'name' => 'web_search',
        'max_uses' => 1,
        'allowed_domains' => $webSearch->getAllowedDomains(),
        'blocked_domains' => $webSearch->getDisallowedDomains(),
    ]);
}

Every grounded request performs at most one search and a caller cannot change it. Per Anthropic's web search documentation, "Simple factual queries typically use 1-3 searches; comparative or multientity research can use 10 or more", and exceeding the cap yields a max_uses_exceeded error inside the result block rather than a failed request. So a cap of 1 quietly truncates the research a comparative question needs, and the caller sees a thinner answer rather than an error.

This is not a provider oversight: maxUses and userLocation appear nowhere in src/ (case-insensitive grep), so there is nothing for a provider to read.

Suggested: an optional $maxUses constructor parameter with getMaxUses(): ?int, null meaning "provider default", rejecting values below 1. Purely additive — no existing caller changes, and the key is omitted from toArray() when unset so serialisation round-trips unchanged.

2. Mutually exclusive domain lists are not rejected

Anthropic's documentation is explicit: "Provide allowed_domains or blocked_domains, not both. If a request includes both, the API returns a 400 error."

Nothing prevents it. WebSearch::__construct() accepts both lists, and the array_filter above only drops empty arrays — so a WebSearch carrying both populated lists produces a request with both keys and a guaranteed 400.

I am raising this rather than patching it because the fix has a real design question attached. Mutual exclusivity is currently an Anthropic constraint, not a universal one, so enforcing it in a provider-agnostic DTO encodes one vendor's rule into shared code. The options as I see them:

  1. Throw from WebSearch::__construct() when both lists are non-empty. Fails at the point of the mistake, but it is a breaking change: 11 tests in tests/unit/Tools/DTO/WebSearchTest.php construct WebSearch with both lists populated (testCreateWithBothAllowedAndDisallowedDomains, testWithDuplicateDomains, testWithEmptyStringsInArrays, testWithSingleDomainInEachList, testWithManyDomains, testMultipleInstances, testWithCommonDomainPatterns, testToArrayWithBothDomainLists, testFromArrayWithBothDomainLists, testArrayRoundTrip, testArrayRoundTripWithSpecialCharacters). If the test suite does it that freely, callers will too.
  2. Guard in the Anthropic provider, where the constraint actually lives, leaving the DTO permissive.
  3. Document the exclusivity on the DTO and leave enforcement to providers.

I lean towards 2, and towards 1 only if maintainers consider the combination meaningless in general rather than merely unsupported by one vendor.

Offer

I have the maxUses half implemented against trunk with unit tests, PHPCS and PHPStan clean and PHP 7.4 compatible. Happy to open that PR immediately if the shape above is acceptable. I would rather have the domain-list half settled here before writing it.

Related: WordPress/anthropic-ai-provider#41 reaches the same hardcoded max_uses from the usage-reporting angle.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/Tools/DTO/WebSearch.php and tests/unit/Tools/DTO/WebSearchTest.php, then read src/Models/AnthropicTextGenerationModel.php:588-597 to trace how the DTO reaches the provider. Review the documented max_uses and domain-list constraints, including the listed round-trip tests, and establish the agreed provider-versus-DTO behavior before considering implementation. Done means the behavior is decided, covered by tests, and remains compatible with the supported PHP version.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
api, backend-api-design
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.