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:
- 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.
- Guard in the Anthropic provider, where the constraint actually lives, leaving the DTO permissive.
- 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/ai-provider-for-anthropic#41 reaches the same hardcoded max_uses from the usage-reporting angle.
src/Tools/DTO/WebSearch.phpcarries exactly two fields,allowedDomainsanddisallowedDomains. The file is unchanged since the 0.1.0 release. Two consequences, one additive and one that needs a decision.1.
max_usescannot be expressed, so providers hardcode itai-provider-for-anthropichardcodes it atsrc/Models/AnthropicTextGenerationModel.php:588-597(trunk):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_exceedederror 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:
maxUsesanduserLocationappear nowhere insrc/(case-insensitive grep), so there is nothing for a provider to read.Suggested: an optional
$maxUsesconstructor parameter withgetMaxUses(): ?int, null meaning "provider default", rejecting values below 1. Purely additive — no existing caller changes, and the key is omitted fromtoArray()when unset so serialisation round-trips unchanged.2. Mutually exclusive domain lists are not rejected
Anthropic's documentation is explicit: "Provide
allowed_domainsorblocked_domains, not both. If a request includes both, the API returns a 400 error."Nothing prevents it.
WebSearch::__construct()accepts both lists, and thearray_filterabove only drops empty arrays — so aWebSearchcarrying 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:
WebSearch::__construct()when both lists are non-empty. Fails at the point of the mistake, but it is a breaking change: 11 tests intests/unit/Tools/DTO/WebSearchTest.phpconstructWebSearchwith 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.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
maxUseshalf 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/ai-provider-for-anthropic#41 reaches the same hardcoded
max_usesfrom the usage-reporting angle.