unique_web_search 2026.30.0.dev0__tar.gz → 2026.30.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/PKG-INFO +4 -4
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/pyproject.toml +4 -4
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/service.py +46 -136
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/base_executor.py +14 -0
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/executors/modes.py +164 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v1/__init__.py +3 -5
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v1/config.py +0 -35
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v1/executor.py +17 -17
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v1/prompts/__init__.py +0 -3
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/executors/v1/schema.py +38 -0
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/executors/v1/strategy.py +67 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/config.py +28 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/executor.py +3 -0
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/executors/v2/strategy.py +79 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v3/executor.py +13 -2
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v3/schema.py +67 -17
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/executors/v3/strategy.py +100 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/__init__.py +2 -0
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/search_engine/base.py +194 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/bing.py +7 -25
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/search_engine/brave.py +42 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/custom_api.py +11 -9
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/search_engine/google.py +157 -0
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/search_engine/perplexity.py +43 -0
- unique_web_search-2026.30.0.dev2/src/unique_web_search/services/search_engine/registry.py +110 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/vertexai.py +16 -32
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/utils.py +0 -31
- unique_web_search-2026.30.0.dev0/src/unique_web_search/services/executors/v1/prompts/restrict_date_description.j2 +0 -3
- unique_web_search-2026.30.0.dev0/src/unique_web_search/services/executors/v1/schema.py +0 -26
- unique_web_search-2026.30.0.dev0/src/unique_web_search/services/search_engine/base.py +0 -62
- unique_web_search-2026.30.0.dev0/src/unique_web_search/services/search_engine/brave.py +0 -64
- unique_web_search-2026.30.0.dev0/src/unique_web_search/services/search_engine/google.py +0 -209
- unique_web_search-2026.30.0.dev0/src/unique_web_search/services/search_engine/perplexity.py +0 -62
- unique_web_search-2026.30.0.dev0/src/unique_web_search/services/search_engine/registry.py +0 -62
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/README.md +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/client_settings.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/metrics.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/prompts.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/schema.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/_registry.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/exceptions.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/prompts/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/prompts/guidelines.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/prompts/guidelines_with_keywords.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/prompts/rejection_response.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/argument_screening/service.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/client/proxy_config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/cleaning/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/cleaning/character_sanitize.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/cleaning/clean.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/cleaning/config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/base.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_guard_judge.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_keyword_redact.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_process.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_and_sanitize_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/keyword_extract_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/page_context.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/sanitize_rules.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/schema.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/settings.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/truncate.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/content_processing/service.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/README.md +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/base.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/basic.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/crawl4ai.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/firecrawl.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/jina.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/tavily.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/url_safety/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/crawlers/utils.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/README.md +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/base_config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/context.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v1/prompts/refine_query_system_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v1/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v1/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/prompts/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/prompts/step_query_description.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v2/schema.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v3/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v3/config.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v3/prompts/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v3/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/executors/v3/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/helpers.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/message_log.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/proxy/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/proxy/bridge.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/proxy/mappers.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/query_elicitation.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/README.md +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/schema.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/google/schema.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/client.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/models.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/runner.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/models.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/response_parsing.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/client.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/exceptions.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/gemini.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/response_handler.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/snippet_judge/__init__.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/snippet_judge/prompts.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/snippet_judge/schema.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/snippet_judge/service.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/services/structured_llm.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/settings.py +0 -0
- {unique_web_search-2026.30.0.dev0 → unique_web_search-2026.30.0.dev2}/src/unique_web_search/skills/web-search-v3.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-web-search
|
|
3
|
-
Version: 2026.30.0.
|
|
3
|
+
Version: 2026.30.0.dev2
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Andreas Hauri, Gustav Hartz, Rami Azouz
|
|
6
6
|
Author-email: Andreas Hauri <andreas@unique.ch>, Gustav Hartz <gustav.hartz.ext@unique.ch>, Rami Azouz <rami.ext@unique.ch>
|
|
@@ -17,7 +17,7 @@ Requires-Dist: tavily-python>=0.7.11,<1
|
|
|
17
17
|
Requires-Dist: unidecode>=1.4.0,<2
|
|
18
18
|
Requires-Dist: azure-ai-projects>=1.0.0,<2
|
|
19
19
|
Requires-Dist: azure-identity>=1.25.0,<2
|
|
20
|
-
Requires-Dist: unique-toolkit[monitoring]>=2026.30.0.
|
|
20
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.30.0.dev12,<2026.30.0rc0
|
|
21
21
|
Requires-Dist: azure-core>=1.36.0,<2
|
|
22
22
|
Requires-Dist: google-cloud-aiplatform>=1.128.0,<2
|
|
23
23
|
Requires-Dist: google-auth>=2.43.0,<3
|
|
@@ -27,8 +27,8 @@ Requires-Dist: httpx>=0.28.1
|
|
|
27
27
|
Requires-Dist: certifi>=2025.11.12
|
|
28
28
|
Requires-Dist: jinja2>=3.1.6
|
|
29
29
|
Requires-Dist: playwright>=1.58.0
|
|
30
|
-
Requires-Dist: unique-search-proxy-core>=2026.30.0.
|
|
31
|
-
Requires-Dist: unique-search-proxy-sdk>=2026.30.0.
|
|
30
|
+
Requires-Dist: unique-search-proxy-core>=2026.30.0.dev2,<2026.30.0rc0
|
|
31
|
+
Requires-Dist: unique-search-proxy-sdk>=2026.30.0.dev2,<2026.30.0rc0
|
|
32
32
|
Requires-Python: >=3.12, <4.0
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_web_search"
|
|
3
|
-
version = "2026.30.0.
|
|
3
|
+
version = "2026.30.0.dev2"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12,<4.0"
|
|
@@ -23,7 +23,7 @@ dependencies = [
|
|
|
23
23
|
"unidecode>=1.4.0,<2",
|
|
24
24
|
"azure-ai-projects>=1.0.0,<2",
|
|
25
25
|
"azure-identity>=1.25.0,<2",
|
|
26
|
-
"unique-toolkit[monitoring]>=2026.30.0.
|
|
26
|
+
"unique-toolkit[monitoring]>=2026.30.0.dev12,<2026.30.0rc0",
|
|
27
27
|
"azure-core>=1.36.0,<2",
|
|
28
28
|
"google-cloud-aiplatform>=1.128.0,<2",
|
|
29
29
|
"google-auth>=2.43.0,<3",
|
|
@@ -33,8 +33,8 @@ dependencies = [
|
|
|
33
33
|
"certifi>=2025.11.12",
|
|
34
34
|
"jinja2>=3.1.6",
|
|
35
35
|
"playwright>=1.58.0",
|
|
36
|
-
"unique-search-proxy-core>=2026.30.0.
|
|
37
|
-
"unique-search-proxy-sdk>=2026.30.0.
|
|
36
|
+
"unique-search-proxy-core>=2026.30.0.dev2,<2026.30.0rc0",
|
|
37
|
+
"unique-search-proxy-sdk>=2026.30.0.dev2,<2026.30.0rc0",
|
|
38
38
|
]
|
|
39
39
|
|
|
40
40
|
[build-system]
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import re
|
|
3
2
|
from datetime import datetime
|
|
4
3
|
from time import time
|
|
5
4
|
|
|
6
|
-
from jinja2 import Template
|
|
7
5
|
from typing_extensions import override
|
|
6
|
+
from unique_search_proxy_core.param_policy.exposed_params import ExposedParams
|
|
7
|
+
from unique_search_proxy_core.search_engines.base import BaseSearchEngineConfig
|
|
8
8
|
from unique_toolkit._common.chunk_relevancy_sorter.service import ChunkRelevancySorter
|
|
9
9
|
from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
|
|
10
10
|
from unique_toolkit.agentic.feature_flags.feature_flags import (
|
|
@@ -31,29 +31,22 @@ from unique_web_search.services.argument_screening import (
|
|
|
31
31
|
)
|
|
32
32
|
from unique_web_search.services.content_processing import ContentProcessor
|
|
33
33
|
from unique_web_search.services.crawlers import get_crawler_service
|
|
34
|
-
from unique_web_search.services.executors import (
|
|
35
|
-
WebSearchMode,
|
|
36
|
-
WebSearchV1Executor,
|
|
37
|
-
WebSearchV2Executor,
|
|
38
|
-
WebSearchV3Config,
|
|
39
|
-
WebSearchV3Executor,
|
|
40
|
-
)
|
|
41
34
|
from unique_web_search.services.executors.context import (
|
|
42
35
|
ExecutorCallbacks,
|
|
43
36
|
ExecutorConfiguration,
|
|
44
37
|
ExecutorServiceContext,
|
|
45
38
|
)
|
|
46
|
-
from unique_web_search.services.executors.
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
from unique_web_search.services.executors.modes import (
|
|
40
|
+
WebSearchExecutor,
|
|
41
|
+
WebSearchToolContext,
|
|
42
|
+
WebSearchToolParametersInstance,
|
|
43
|
+
get_mode_strategy,
|
|
44
|
+
)
|
|
49
45
|
from unique_web_search.services.message_log import WebSearchMessageLogger
|
|
50
46
|
from unique_web_search.services.query_elicitation import QueryElicitationService
|
|
51
47
|
from unique_web_search.services.search_engine import (
|
|
52
|
-
SearchEngineMode,
|
|
53
|
-
get_search_engine_mode,
|
|
54
48
|
get_search_engine_service,
|
|
55
49
|
)
|
|
56
|
-
from unique_web_search.services.search_engine.custom_api import CustomAPIConfig
|
|
57
50
|
from unique_web_search.utils import (
|
|
58
51
|
WebPageChunk,
|
|
59
52
|
reduce_sources_to_token_limit,
|
|
@@ -97,6 +90,8 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
97
90
|
)
|
|
98
91
|
self.debug = self.config.debug
|
|
99
92
|
self._display_name = kwargs.get("display_name", "Web Search")
|
|
93
|
+
self.exposed_params_cls = self._resolve_exposed_params_cls()
|
|
94
|
+
self._mode_strategy = get_mode_strategy(self.config.web_search_mode_config)
|
|
100
95
|
|
|
101
96
|
def content_reducer(web_page_chunks: list[WebPageChunk]) -> list[WebPageChunk]:
|
|
102
97
|
|
|
@@ -111,83 +106,37 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
111
106
|
|
|
112
107
|
self.content_reducer = content_reducer
|
|
113
108
|
|
|
114
|
-
def
|
|
115
|
-
"""
|
|
116
|
-
cfg = self.
|
|
117
|
-
|
|
118
|
-
|
|
109
|
+
def _resolve_exposed_params_cls(self) -> type[ExposedParams] | None:
|
|
110
|
+
"""Resolve the exposed-params model from the search-engine config, if any."""
|
|
111
|
+
cfg = self.config.search_engine_config
|
|
112
|
+
if isinstance(cfg, BaseSearchEngineConfig):
|
|
113
|
+
return cfg.exposed_params_model()
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
def _tool_context(self) -> WebSearchToolContext:
|
|
117
|
+
return WebSearchToolContext(
|
|
118
|
+
search_engine_config=self.search_engine_service.config,
|
|
119
|
+
date_string=datetime.now().strftime("%A %B %d, %Y"),
|
|
120
|
+
exposed_params_cls=self.exposed_params_cls,
|
|
121
|
+
)
|
|
119
122
|
|
|
120
123
|
@override
|
|
121
124
|
def tool_description(self) -> LanguageModelToolDescription:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
self.config.web_search_mode_config.tool_parameters_description.query_description,
|
|
125
|
-
self.config.web_search_mode_config.tool_parameters_description.date_restrict_description,
|
|
126
|
-
)
|
|
127
|
-
else:
|
|
128
|
-
if self.config.web_search_mode_config.mode == WebSearchMode.V3:
|
|
129
|
-
self.tool_parameter_calls = WebSearchV3ToolParameters
|
|
130
|
-
else:
|
|
131
|
-
engine_mode = self._resolve_search_engine_mode()
|
|
132
|
-
self.tool_parameter_calls = WebSearchPlan.with_search_engine_mode(
|
|
133
|
-
engine_mode
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
tool_description = self.config.web_search_mode_config.tool_description
|
|
137
|
-
|
|
138
|
-
if self.config.web_search_mode_config.mode == WebSearchMode.V3:
|
|
139
|
-
tool_description = Template(tool_description).render(
|
|
140
|
-
tool_parameters_schema=WebSearchV3ToolParameters.schema_hint(),
|
|
141
|
-
)
|
|
142
|
-
|
|
125
|
+
ctx = self._tool_context()
|
|
126
|
+
self.tool_parameter_calls = self._mode_strategy.build_tool_parameters(ctx)
|
|
143
127
|
return LanguageModelToolDescription(
|
|
144
128
|
name=self.name,
|
|
145
|
-
description=tool_description,
|
|
129
|
+
description=self._mode_strategy.tool_description(ctx),
|
|
146
130
|
parameters=self.tool_parameter_calls,
|
|
147
131
|
)
|
|
148
132
|
|
|
149
133
|
def tool_description_for_system_prompt(self) -> str:
|
|
150
|
-
|
|
151
|
-
if mode_config.mode == WebSearchMode.V1:
|
|
152
|
-
return mode_config.tool_description_for_system_prompt
|
|
153
|
-
|
|
154
|
-
template_str = mode_config.tool_description_for_system_prompt
|
|
155
|
-
|
|
156
|
-
if mode_config.mode == WebSearchMode.V3:
|
|
157
|
-
return Template(template_str).render(
|
|
158
|
-
date_string=datetime.now().strftime("%A %B %d, %Y"),
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
# Backwards compatibility: V2 prompts persisted before the Jinja
|
|
162
|
-
# migration use the legacy ``$max_steps`` placeholder. Jinja would
|
|
163
|
-
# otherwise pass it through verbatim, so rewrite it to the Jinja
|
|
164
|
-
# equivalent before rendering.
|
|
165
|
-
if "$max_steps" in template_str:
|
|
166
|
-
_LOGGER.warning(
|
|
167
|
-
"V2 web-search prompt contains legacy '$max_steps' placeholder; "
|
|
168
|
-
"rewriting to '{{ max_steps }}'. Please update the stored "
|
|
169
|
-
"configuration to use Jinja syntax."
|
|
170
|
-
)
|
|
171
|
-
template_str = template_str.replace("$max_steps", "{{ max_steps }}")
|
|
172
|
-
|
|
173
|
-
engine_mode = self._resolve_search_engine_mode()
|
|
174
|
-
return Template(template_str).render(
|
|
175
|
-
max_steps=mode_config.max_steps,
|
|
176
|
-
date_string=datetime.now().strftime("%A %B %d, %Y"),
|
|
177
|
-
search_engine_mode=engine_mode.value,
|
|
178
|
-
tool_parameters_schema=WebSearchPlan.schema_hint(engine_mode),
|
|
179
|
-
example_simple=WebSearchPlan.build_example_simple(
|
|
180
|
-
engine_mode
|
|
181
|
-
).model_dump_json(indent=2),
|
|
182
|
-
example_complex=WebSearchPlan.build_example_complex(
|
|
183
|
-
engine_mode
|
|
184
|
-
).model_dump_json(indent=2),
|
|
185
|
-
)
|
|
134
|
+
return self._mode_strategy.system_prompt(self._tool_context())
|
|
186
135
|
|
|
187
136
|
def tool_format_information_for_system_prompt(self) -> str:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
137
|
+
return self._mode_strategy.format_information_for_system_prompt(
|
|
138
|
+
default=self.config.tool_format_information_for_system_prompt,
|
|
139
|
+
)
|
|
191
140
|
|
|
192
141
|
def evaluation_check_list(self) -> list[EvaluationMetricName]:
|
|
193
142
|
return self.config.evaluation_check_list
|
|
@@ -202,7 +151,7 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
202
151
|
|
|
203
152
|
screening_service = await self._get_argument_screening_service_if_ff_enabled()
|
|
204
153
|
|
|
205
|
-
parameters_dump = parameters.model_dump()
|
|
154
|
+
parameters_dump = parameters.model_dump(by_alias=True)
|
|
206
155
|
debug_info = WebSearchDebugInfo(parameters=parameters_dump)
|
|
207
156
|
|
|
208
157
|
web_search_message_logger = WebSearchMessageLogger(
|
|
@@ -289,18 +238,16 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
289
238
|
def _get_executor(
|
|
290
239
|
self,
|
|
291
240
|
tool_call: LanguageModelFunction,
|
|
292
|
-
parameters:
|
|
241
|
+
parameters: WebSearchToolParametersInstance,
|
|
293
242
|
debug_info: WebSearchDebugInfo,
|
|
294
243
|
web_search_message_logger: WebSearchMessageLogger,
|
|
295
|
-
) ->
|
|
296
|
-
# Initialize query elicitation service and get callbacks
|
|
244
|
+
) -> WebSearchExecutor:
|
|
297
245
|
elicitation_service = QueryElicitationService(
|
|
298
246
|
chat_service=self._chat_service,
|
|
299
247
|
display_name=self.display_name(),
|
|
300
248
|
config=self.config.query_elicitation_config,
|
|
301
249
|
)
|
|
302
250
|
|
|
303
|
-
# Build context objects
|
|
304
251
|
services = ExecutorServiceContext(
|
|
305
252
|
search_engine_service=self.search_engine_service,
|
|
306
253
|
crawler_service=self.crawler_service,
|
|
@@ -322,43 +269,14 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
322
269
|
tool_progress_reporter=self._ff_tool_progress_reporter(),
|
|
323
270
|
)
|
|
324
271
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
callbacks=callbacks,
|
|
334
|
-
tool_call=tool_call,
|
|
335
|
-
tool_parameters=parameters,
|
|
336
|
-
)
|
|
337
|
-
if isinstance(parameters, WebSearchPlan):
|
|
338
|
-
assert search_config.mode == WebSearchMode.V2
|
|
339
|
-
return WebSearchV2Executor(
|
|
340
|
-
services=services,
|
|
341
|
-
config=config,
|
|
342
|
-
callbacks=callbacks,
|
|
343
|
-
tool_call=tool_call,
|
|
344
|
-
tool_parameters=parameters,
|
|
345
|
-
max_steps=search_config.max_steps,
|
|
346
|
-
)
|
|
347
|
-
elif isinstance(parameters, WebSearchToolParameters):
|
|
348
|
-
assert search_config.mode == WebSearchMode.V1
|
|
349
|
-
return WebSearchV1Executor(
|
|
350
|
-
services=services,
|
|
351
|
-
config=config,
|
|
352
|
-
callbacks=callbacks,
|
|
353
|
-
tool_call=tool_call,
|
|
354
|
-
tool_parameters=parameters,
|
|
355
|
-
refine_query_system_prompt=search_config.refine_query_mode.system_prompt,
|
|
356
|
-
refine_query_language_model=search_config.refine_query_mode.language_model,
|
|
357
|
-
mode=search_config.refine_query_mode.mode,
|
|
358
|
-
max_queries=search_config.max_queries,
|
|
359
|
-
)
|
|
360
|
-
else:
|
|
361
|
-
raise ValueError(f"Invalid parameters: {parameters}")
|
|
272
|
+
return self._mode_strategy.build_executor(
|
|
273
|
+
services=services,
|
|
274
|
+
config=config,
|
|
275
|
+
callbacks=callbacks,
|
|
276
|
+
tool_call=tool_call,
|
|
277
|
+
parameters=parameters,
|
|
278
|
+
exposed_params_cls=self.exposed_params_cls,
|
|
279
|
+
)
|
|
362
280
|
|
|
363
281
|
def get_evaluation_checks_based_on_tool_response(
|
|
364
282
|
self,
|
|
@@ -414,20 +332,12 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
414
332
|
|
|
415
333
|
def _build_display_name(
|
|
416
334
|
self,
|
|
417
|
-
parameters:
|
|
335
|
+
parameters: WebSearchToolParametersInstance,
|
|
418
336
|
) -> str:
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
# Remove "search" from the display name (case-insensitive, all occurrences).
|
|
424
|
-
display_name = re.sub(
|
|
425
|
-
r"\bsearch\b", "", display_name, flags=re.IGNORECASE
|
|
426
|
-
).strip()
|
|
427
|
-
|
|
428
|
-
suffix = parameters.get_display_name_suffix()
|
|
429
|
-
|
|
430
|
-
return display_name + suffix
|
|
337
|
+
return self._mode_strategy.build_display_name(
|
|
338
|
+
base_display_name=self.display_name(),
|
|
339
|
+
parameters=parameters,
|
|
340
|
+
)
|
|
431
341
|
|
|
432
342
|
|
|
433
343
|
ToolFactory.register_tool(WebSearchTool, WebSearchConfig)
|
|
@@ -4,6 +4,7 @@ from time import time
|
|
|
4
4
|
from typing import Generic, TypeVar
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
|
+
from unique_search_proxy_core.param_policy.exposed_params import ExposedParams
|
|
7
8
|
from unique_toolkit.agentic.tools.tool_progress_reporter import (
|
|
8
9
|
ProgressState,
|
|
9
10
|
)
|
|
@@ -39,6 +40,7 @@ class BaseWebSearchExecutor(ABC, Generic[T]):
|
|
|
39
40
|
callbacks: ExecutorCallbacks,
|
|
40
41
|
tool_call: LanguageModelFunction,
|
|
41
42
|
tool_parameters: T,
|
|
43
|
+
exposed_params_cls: type[ExposedParams] | None = None,
|
|
42
44
|
):
|
|
43
45
|
# Extract from service context
|
|
44
46
|
self.search_service = services.search_engine_service
|
|
@@ -61,6 +63,7 @@ class BaseWebSearchExecutor(ABC, Generic[T]):
|
|
|
61
63
|
# Store tool parameters
|
|
62
64
|
self.tool_call = tool_call
|
|
63
65
|
self.tool_parameters = tool_parameters
|
|
66
|
+
self.exposed_params_cls = exposed_params_cls
|
|
64
67
|
|
|
65
68
|
# Initialize notification state
|
|
66
69
|
self._notify_name = ""
|
|
@@ -78,6 +81,17 @@ class BaseWebSearchExecutor(ABC, Generic[T]):
|
|
|
78
81
|
|
|
79
82
|
self.notify_callback = notify_callback
|
|
80
83
|
|
|
84
|
+
def _extract_search_params(self, source: BaseModel) -> ExposedParams | None:
|
|
85
|
+
"""Validate ``source`` against the exposed-params class, dropping tool-only fields.
|
|
86
|
+
|
|
87
|
+
Returns ``None`` when no knobs are exposed for this deployment. Otherwise
|
|
88
|
+
re-validates the source dump through ``exposed_params_cls``
|
|
89
|
+
(``extra="ignore"``) so only admin-exposed engine knobs remain.
|
|
90
|
+
"""
|
|
91
|
+
if self.exposed_params_cls is None:
|
|
92
|
+
return None
|
|
93
|
+
return self.exposed_params_cls.model_validate(source.model_dump(by_alias=True))
|
|
94
|
+
|
|
81
95
|
@property
|
|
82
96
|
def notify_name(self):
|
|
83
97
|
return self._notify_name
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Per-mode strategy objects for the WebSearch tool.
|
|
2
|
+
|
|
3
|
+
Each WebSearch mode (V1/V2/V3) differs only in how it builds its LLM-facing
|
|
4
|
+
surface and which executor runs it. A :class:`WebSearchModeStrategy` owns all of
|
|
5
|
+
that per-mode behaviour in one place:
|
|
6
|
+
|
|
7
|
+
- the tool-call parameter model (``query`` plus any engine-exposed knobs),
|
|
8
|
+
- the tool description shown to the model,
|
|
9
|
+
- the system-prompt text and citation/format-information text,
|
|
10
|
+
- the executor construction, and
|
|
11
|
+
- the runtime display name.
|
|
12
|
+
|
|
13
|
+
``WebSearchTool`` resolves the strategy for the active mode via
|
|
14
|
+
:func:`get_mode_strategy` and delegates to it, staying free of mode branching.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from abc import ABC, abstractmethod
|
|
20
|
+
from collections.abc import Callable
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import cast
|
|
23
|
+
|
|
24
|
+
from pydantic import BaseModel
|
|
25
|
+
from unique_search_proxy_core.param_policy.exposed_params import ExposedParams
|
|
26
|
+
from unique_toolkit.language_model import LanguageModelFunction
|
|
27
|
+
|
|
28
|
+
from unique_web_search.services.executors.base_config import WebSearchMode
|
|
29
|
+
from unique_web_search.services.executors.context import (
|
|
30
|
+
ExecutorCallbacks,
|
|
31
|
+
ExecutorConfiguration,
|
|
32
|
+
ExecutorServiceContext,
|
|
33
|
+
)
|
|
34
|
+
from unique_web_search.services.executors.v1.config import WebSearchV1Config
|
|
35
|
+
from unique_web_search.services.executors.v1.executor import WebSearchV1Executor
|
|
36
|
+
from unique_web_search.services.executors.v1.schema import WebSearchToolParameters
|
|
37
|
+
from unique_web_search.services.executors.v2.config import WebSearchV2Config
|
|
38
|
+
from unique_web_search.services.executors.v2.executor import WebSearchV2Executor
|
|
39
|
+
from unique_web_search.services.executors.v2.schema import WebSearchPlan
|
|
40
|
+
from unique_web_search.services.executors.v3.config import WebSearchV3Config
|
|
41
|
+
from unique_web_search.services.executors.v3.executor import WebSearchV3Executor
|
|
42
|
+
from unique_web_search.services.executors.v3.schema import WebSearchV3ToolParameters
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
"WebSearchExecutor",
|
|
46
|
+
"WebSearchModeConfig",
|
|
47
|
+
"WebSearchModeStrategy",
|
|
48
|
+
"WebSearchToolContext",
|
|
49
|
+
"WebSearchToolParametersInstance",
|
|
50
|
+
"WebSearchToolParametersType",
|
|
51
|
+
"get_mode_strategy",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
WebSearchModeConfig = WebSearchV1Config | WebSearchV2Config | WebSearchV3Config
|
|
55
|
+
|
|
56
|
+
WebSearchToolParametersType = (
|
|
57
|
+
type[WebSearchToolParameters]
|
|
58
|
+
| type[WebSearchPlan]
|
|
59
|
+
| type[WebSearchV3ToolParameters]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
WebSearchToolParametersInstance = (
|
|
63
|
+
WebSearchToolParameters | WebSearchPlan | WebSearchV3ToolParameters
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
WebSearchExecutor = WebSearchV1Executor | WebSearchV2Executor | WebSearchV3Executor
|
|
67
|
+
|
|
68
|
+
_STRATEGY_FACTORIES: (
|
|
69
|
+
dict[WebSearchMode, Callable[[WebSearchModeConfig], WebSearchModeStrategy]] | None
|
|
70
|
+
) = None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(frozen=True)
|
|
74
|
+
class WebSearchToolContext:
|
|
75
|
+
"""Inputs the mode strategy needs to build the LLM-facing tool surface.
|
|
76
|
+
|
|
77
|
+
``exposed_params_cls`` is resolved once by ``WebSearchTool`` at init so
|
|
78
|
+
strategies do not re-call ``exposed_params_model()``. The engine *mode*
|
|
79
|
+
(standard vs agent) is resolved lazily by the one strategy (V2) that needs
|
|
80
|
+
it, so V1/V3 never pay for a resolution they ignore.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
search_engine_config: BaseModel
|
|
84
|
+
date_string: str
|
|
85
|
+
exposed_params_cls: type[ExposedParams] | None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class WebSearchModeStrategy(ABC):
|
|
89
|
+
"""Mode-specific behaviour for building and running the WebSearch tool."""
|
|
90
|
+
|
|
91
|
+
@abstractmethod
|
|
92
|
+
def build_tool_parameters(
|
|
93
|
+
self, ctx: WebSearchToolContext
|
|
94
|
+
) -> WebSearchToolParametersType:
|
|
95
|
+
"""Build the tool-call parameter model (``query`` plus exposed knobs)."""
|
|
96
|
+
|
|
97
|
+
@abstractmethod
|
|
98
|
+
def tool_description(self, ctx: WebSearchToolContext) -> str:
|
|
99
|
+
"""Return the description the model sees when choosing this tool."""
|
|
100
|
+
|
|
101
|
+
@abstractmethod
|
|
102
|
+
def system_prompt(self, ctx: WebSearchToolContext) -> str:
|
|
103
|
+
"""Return the tool's system-prompt instructions."""
|
|
104
|
+
|
|
105
|
+
@abstractmethod
|
|
106
|
+
def build_executor(
|
|
107
|
+
self,
|
|
108
|
+
*,
|
|
109
|
+
services: ExecutorServiceContext,
|
|
110
|
+
config: ExecutorConfiguration,
|
|
111
|
+
callbacks: ExecutorCallbacks,
|
|
112
|
+
tool_call: LanguageModelFunction,
|
|
113
|
+
parameters: WebSearchToolParametersInstance,
|
|
114
|
+
exposed_params_cls: type[ExposedParams] | None,
|
|
115
|
+
) -> WebSearchExecutor:
|
|
116
|
+
"""Construct the executor that runs a validated tool call."""
|
|
117
|
+
|
|
118
|
+
def format_information_for_system_prompt(self, *, default: str) -> str:
|
|
119
|
+
"""Return citation/format instructions; falls back to the tool default."""
|
|
120
|
+
return default
|
|
121
|
+
|
|
122
|
+
def build_display_name(
|
|
123
|
+
self,
|
|
124
|
+
*,
|
|
125
|
+
base_display_name: str,
|
|
126
|
+
parameters: WebSearchToolParametersInstance,
|
|
127
|
+
) -> str:
|
|
128
|
+
"""Return the runtime display name for a tool call."""
|
|
129
|
+
return base_display_name
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _strategy_factories() -> dict[
|
|
133
|
+
WebSearchMode, Callable[[WebSearchModeConfig], WebSearchModeStrategy]
|
|
134
|
+
]:
|
|
135
|
+
global _STRATEGY_FACTORIES
|
|
136
|
+
if _STRATEGY_FACTORIES is None:
|
|
137
|
+
from unique_web_search.services.executors.v1.strategy import (
|
|
138
|
+
WebSearchV1Strategy,
|
|
139
|
+
)
|
|
140
|
+
from unique_web_search.services.executors.v2.strategy import (
|
|
141
|
+
WebSearchV2Strategy,
|
|
142
|
+
)
|
|
143
|
+
from unique_web_search.services.executors.v3.strategy import (
|
|
144
|
+
WebSearchV3Strategy,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
_STRATEGY_FACTORIES = {
|
|
148
|
+
WebSearchMode.V1: lambda cfg: WebSearchV1Strategy(
|
|
149
|
+
cast(WebSearchV1Config, cfg),
|
|
150
|
+
),
|
|
151
|
+
WebSearchMode.V2: lambda cfg: WebSearchV2Strategy(
|
|
152
|
+
cast(WebSearchV2Config, cfg),
|
|
153
|
+
),
|
|
154
|
+
WebSearchMode.V3: lambda cfg: WebSearchV3Strategy(
|
|
155
|
+
cast(WebSearchV3Config, cfg),
|
|
156
|
+
),
|
|
157
|
+
}
|
|
158
|
+
return _STRATEGY_FACTORIES
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def get_mode_strategy(mode_config: WebSearchModeConfig) -> WebSearchModeStrategy:
|
|
162
|
+
"""Resolve the strategy for the configured WebSearch mode."""
|
|
163
|
+
factory = _strategy_factories()[mode_config.mode]
|
|
164
|
+
return factory(mode_config)
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
from unique_web_search.services.executors.v1.config import (
|
|
2
2
|
QueryRefinementConfig,
|
|
3
3
|
RefineQueryMode,
|
|
4
|
-
WebSearchToolParametersDescriptionConfig,
|
|
5
4
|
WebSearchV1Config,
|
|
6
5
|
)
|
|
7
|
-
from unique_web_search.services.executors.v1.executor import
|
|
8
|
-
|
|
9
|
-
)
|
|
6
|
+
from unique_web_search.services.executors.v1.executor import WebSearchV1Executor
|
|
7
|
+
from unique_web_search.services.executors.v1.schema import WebSearchToolParameters
|
|
10
8
|
|
|
11
9
|
__all__ = [
|
|
12
10
|
"QueryRefinementConfig",
|
|
13
11
|
"RefineQueryMode",
|
|
14
|
-
"WebSearchToolParametersDescriptionConfig",
|
|
15
12
|
"WebSearchV1Config",
|
|
16
13
|
"WebSearchV1Executor",
|
|
14
|
+
"WebSearchToolParameters",
|
|
17
15
|
]
|
|
@@ -15,7 +15,6 @@ from unique_web_search.services.executors.v1.prompts import (
|
|
|
15
15
|
DEFAULT_TOOL_DESCRIPTION,
|
|
16
16
|
DEFAULT_TOOL_DESCRIPTION_FOR_SYSTEM_PROMPT,
|
|
17
17
|
REFINE_QUERY_SYSTEM_PROMPT,
|
|
18
|
-
RESTRICT_DATE_DESCRIPTION,
|
|
19
18
|
)
|
|
20
19
|
from unique_web_search.settings import env_settings
|
|
21
20
|
|
|
@@ -26,34 +25,6 @@ class RefineQueryMode(StrEnum):
|
|
|
26
25
|
DEACTIVATED = "Deactivated"
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
_DEFAULT_QUERY_DESCRIPTION = "The search query to issue to the web."
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class WebSearchToolParametersDescriptionConfig(BaseModel):
|
|
33
|
-
model_config = get_configuration_dict()
|
|
34
|
-
|
|
35
|
-
query_description: Annotated[
|
|
36
|
-
str,
|
|
37
|
-
RJSFMetaTag.StringWidget.textarea(
|
|
38
|
-
rows=len(_DEFAULT_QUERY_DESCRIPTION.split("\n"))
|
|
39
|
-
),
|
|
40
|
-
] = Field(
|
|
41
|
-
default=_DEFAULT_QUERY_DESCRIPTION,
|
|
42
|
-
title="Query Parameter Description",
|
|
43
|
-
description="Advanced: Description of the search query parameter shown to the AI model.",
|
|
44
|
-
)
|
|
45
|
-
date_restrict_description: Annotated[
|
|
46
|
-
str,
|
|
47
|
-
RJSFMetaTag.StringWidget.textarea(
|
|
48
|
-
rows=len(RESTRICT_DATE_DESCRIPTION.split("\n"))
|
|
49
|
-
),
|
|
50
|
-
] = Field(
|
|
51
|
-
default=RESTRICT_DATE_DESCRIPTION,
|
|
52
|
-
title="Date Filter Description",
|
|
53
|
-
description="Advanced: Description of the date restriction parameter shown to the AI model.",
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
28
|
class QueryRefinementConfig(BaseModel):
|
|
58
29
|
model_config = get_configuration_dict()
|
|
59
30
|
|
|
@@ -101,12 +72,6 @@ class WebSearchV1Config(BaseWebSearchModeConfig[WebSearchMode.V1]):
|
|
|
101
72
|
description="Maximum number of separate searches to run per user request. Only applies when Query Refinement is set to Advanced.",
|
|
102
73
|
)
|
|
103
74
|
|
|
104
|
-
tool_parameters_description: WebSearchToolParametersDescriptionConfig = Field(
|
|
105
|
-
default_factory=WebSearchToolParametersDescriptionConfig,
|
|
106
|
-
title="Search Parameter Descriptions",
|
|
107
|
-
description="Advanced: Descriptions of each search parameter, shown to the AI model.",
|
|
108
|
-
)
|
|
109
|
-
|
|
110
75
|
tool_description: Annotated[
|
|
111
76
|
str,
|
|
112
77
|
RJSFMetaTag.StringWidget.textarea(
|