feat(web-search): add domain filtering, user location, and structured search actions - #5817
Conversation
Add WebSearchFilters and WebSearchUserLocation models to support OpenAI-compatible domain filtering and location-based search refinement in the web search tool. Change search_context_size from a regex-validated string to a proper Literal type for stronger validation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
…size Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Add support for allowed_domains using Tavily's native include_domains parameter and search_context_size to control max_results via a context size mapping. User location is silently ignored since Tavily has no native location API support. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
…find Add WebSearchSource, WebSearchActionSearch, WebSearchActionOpenPage, and WebSearchActionFind models to represent the discriminated union of actions that a web search tool call can perform. Update OpenAIResponseOutputMessageWebSearchToolCall with an optional action field to carry structured action details. This is a breaking API schema change because the new union-typed field causes Pydantic to generate separate Input/Output schema variants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Add source URL extraction to Brave, Bing, and Tavily search backends so that ToolInvocationResult.metadata contains query and sources fields. This enables downstream consumers like the tool executor to build the action output with proper source attribution. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
When search_context_size was set, the API request count was updated but the result slicing in _clean_brave_response and _extract_sources still used config.max_results, causing a mismatch between requested and returned results. Thread the resolved limit through both methods so results are sliced consistently. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
✱ Stainless preview buildsThis PR will update the
|
| { | ||
| "spec_schema": "WebSearchTool", | ||
| "field": "filters", | ||
| "pydantic_model": "OpenAIResponseInputToolWebSearch" | ||
| }, | ||
| { | ||
| "spec_schema": "WebSearchTool", | ||
| "field": "user_location", | ||
| "pydantic_model": "OpenAIResponseInputToolWebSearch" |
…on check Replace substring check (`url in content`) with exact match against the sources metadata list to resolve CodeQL py/incomplete-url-substring-sanitization high severity alert. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
…n alert CodeQL py/incomplete-url-substring-sanitization fires on any `in` operator with URL strings, including list membership. Switch to set equality which asserts all expected URLs are present without triggering the rule. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
…codex-implementation-of-githu
|
This pull request has merge conflicts that must be resolved before it can be merged. @leseb please rebase it. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork |
…r-codex-implementation-of-githu Signed-off-by: Sébastien Han <seb@redhat.com>
Upstream refactored search providers to use a persistent self._client instead of creating a new httpx.AsyncClient per request. Update test fixtures to set _client directly with a MagicMock instead of patching the httpx.AsyncClient class methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
…r-codex-implementation-of-githu
…ompatibility The search_context_size field defaulted to "medium", which caused the tool executor to always inject it into kwargs even when not explicitly set by the user. This changed the recording hash for web search tool calls, breaking all integration tests in replay mode with "Recording not found" errors surfaced as 500s. Change the default to None so search_context_size is only injected when the user explicitly provides it, preserving backward compatibility with existing integration test recordings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Duplicate existing tavily web search recordings with search_context_size added to kwargs, so integration tests that pass search_context_size: low in the tool config can find matching recordings in replay mode. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
The field names and types are self-documenting. Pydantic Field descriptions are used where needed for provider documentation generation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
…utor Move web_search config injection from nested inside the else catch-all to a proper elif branch, consistent with the MCP and file_search tool handling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
456e1bc to
14b7b8d
Compare
franciscojavierarceo
left a comment
There was a problem hiding this comment.
thanks devin
…r-codex-implementation-of-githu
Move web search filter/location tests from test_openai_responses_tools.py to test_openai_responses_web_search.py to keep the tools test file under the 1000-line limit after upstream merge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Closes #4442
Summary
Implements domain filtering and user location for the web search tool, matching the OpenAI Responses API feature set, and adds structured
WebSearchToolCall.actionmodels to surface search metadata (sources, queries) in responses.API changes
filters(domain include/exclude lists) anduser_location(country, city, region, timezone) fields toOpenAIResponseInputToolWebSearchWebSearchToolCallaction models:search,open_page,findwith source URL metadataProvider changes
search_context_sizecounturl,title) viaToolInvocationResult.metadataResponses layer
filtersanduser_locationfrom the web search tool config through the tool executor to search backendsWebSearchToolCall.actionwith source URLs from search resultsTest plan
test_invoke_with_search_context_size_updates_result_limitverifies brave search result slicing fixuv run pytest tests/unit/providers/tool_runtime/test_brave_search.py -x --tb=shortuv run pre-commit run --all-filesTest script