Skip to content

Add web search provider options, and name unsatisfied options on resolution failure - #295

Open
saarnilauri wants to merge 1 commit into
WordPress:trunkfrom
saarnilauri:websearch-maxuses-and-resolver-errors
Open

saarnilauri wants to merge 1 commit into
WordPress:trunkfrom
saarnilauri:websearch-maxuses-and-resolver-errors

Conversation

@saarnilauri

@saarnilauri saarnilauri commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Two small, independent changes. They touch disjoint files, so I'm happy to split them into separate PRs if you'd rather review them apart.

WebSearch provider options

WebSearch can only express domain lists, so providers hardcode the rest, ai-provider-for-anthropic pins max_uses to 1 and nothing can change it.

This adds an optional bag keyed by provider ID:

new WebSearch(['example.com'], [], ['anthropic' => ['max_uses' => 3]]);

$webSearch->getProviderOptionsFor('anthropic'); // ['max_uses' => 3]

Keyed by provider rather than flat, because a cap on the number of searches turns out to be Anthropic-specific — other vendors cap the number of results, or offer a context-size budget instead, so a flat bag would hand one vendor's keys to every provider. Purely additive, and the key is omitted from toArray() when empty, so existing serialisation round-trips unchanged.

Closes #291

Resolution failures name the option

When an option eliminates every candidate, the error names the capability, which is usually the part that was fine:

No models found for provider "acme" that support text_generation.

Now, on an empty candidate map, the resolver re-checks with the capabilities only. If models exist, it names the options that none of them support; if none exist, the message is exactly as before. ModelRequirements::getUnmetRequirements() already existed for this and wasn't being called.

No models found for provider "acme" that support text_generation. The following requested option is not supported by any of those models: webSearch.

One existing test changes rather than being added to: PromptBuilderTest::testGenerateResultWithProviderNoModelsThrowsException pinned the registry mock to a single lookup, and fromPromptData() always adds inputModalities as a required option, so the diagnostic runs and looks twice. The expectation is widened to exactly(2); the thrown message is unchanged.

Closes #292


Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Researh, Code generation, test running and verification. Code changes reviewd by me.

…lution failure

Two independent changes. They touch disjoint files and split cleanly if
separate PRs are preferred.

WebSearch DTO (WordPress#291):
- Optional providerOptions bag, keyed by provider ID, for web search settings
  that have no portable equivalent (Anthropic's max_uses and user_location).
  Keyed by provider rather than flat, so a config cannot hand one vendor's
  keys to another. Omitted from toArray() when empty, so existing
  serialisation round-trips unchanged.

ModelResolver (WordPress#292):
- On an empty candidate map, re-check with the required capabilities only and
  name the options that no otherwise-suitable model supports, instead of
  naming the capability that was already satisfied. Falls back to the current
  message when the capability genuinely is the cause.
- PromptBuilderTest expectation widened to two registry lookups, since
  fromPromptData() always adds inputModalities as a required option so the
  diagnostic path runs.

1218 unit tests pass; PHPCS and PHPStan clean; PHP 7.4 compatible.

Refs WordPress#291, WordPress#292

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: saarnilauri <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@codecov

codecov Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.63%. Comparing base (a164848) to head (7139f1c).
⚠️ Report is 3 commits behind head on trunk.

Files with missing lines Patch % Lines
src/Providers/ModelResolver.php 85.29% 5 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##              trunk     #295      +/-   ##
============================================
+ Coverage     86.58%   86.63%   +0.05%     
- Complexity     1383     1402      +19     
============================================
  Files            69       69              
  Lines          4449     4504      +55     
============================================
+ Hits           3852     3902      +50     
- Misses          597      602       +5     
Flag Coverage Δ
unit 86.63% <91.66%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant