unique_web_search 2026.20.0.dev7__tar.gz → 2026.20.0.dev9__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.20.0.dev7 → unique_web_search-2026.20.0.dev9}/PKG-INFO +2 -2
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/pyproject.toml +2 -2
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/config.py +1 -9
- unique_web_search-2026.20.0.dev9/src/unique_web_search/schema.py +68 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/service.py +67 -51
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/service.py +26 -20
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/__init__.py +48 -0
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/configs/base.py → unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/base_config.py +0 -2
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/executors/base_executor.py +7 -4
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/__init__.py +17 -0
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/configs/v1_config.py → unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/config.py +6 -8
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/web_search_v1_executor.py → unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/executor.py +4 -6
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/prompts/__init__.py +16 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/prompts/refine_query_system_prompt.j2 +18 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/prompts/restrict_date_description.j2 +3 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/prompts/tool_description.j2 +2 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/prompts/tool_description_for_system_prompt.j2 +12 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v1/schema.py +26 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/__init__.py +7 -0
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/configs/v2_config.py → unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/config.py +9 -13
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/web_search_v2_executor.py → unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/executor.py +8 -15
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/prompts/__init__.py +11 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/prompts/step_query_description.j2 +7 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/prompts/tool_description.j2 +10 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/prompts/tool_description_for_system_prompt.j2 +121 -0
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/executors/v2/schema.py +271 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/message_log.py +5 -5
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/__init__.py +4 -1
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/base.py +39 -5
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/brave.py +7 -2
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/custom_api.py +6 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/bing/runner.py +4 -1
- unique_web_search-2026.20.0.dev9/src/unique_web_search/services/structured_llm.py +47 -0
- unique_web_search-2026.20.0.dev7/src/unique_web_search/schema.py +0 -108
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/__init__.py +0 -23
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/configs/__init__.py +0 -34
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/configs/prompts.py +0 -414
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/configs/v3_config.py +0 -84
- unique_web_search-2026.20.0.dev7/src/unique_web_search/services/executors/web_search_v3_executor.py +0 -259
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/README.md +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/__main__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/cli.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/cli_config.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/commands/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/commands/crawl.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/commands/search.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/cli/formatting.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/client_settings.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/metrics.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/prompts.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/config.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/exceptions.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/prompts/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/prompts/guidelines.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/prompts/rejection_response.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/argument_screening/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/client/proxy_config.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/cleaning/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/cleaning/character_sanitize.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/cleaning/clean.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/cleaning/config.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/config.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/base.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/config.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/llm_guard_judge.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/llm_keyword_redact.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/llm_process.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_and_sanitize_prompt.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_prompt.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/keyword_extract_prompt.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/page_context.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/sanitize_rules.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/schema.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/settings.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/processing_strategies/truncate.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/content_processing/service.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/README.md +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/base.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/basic.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/crawl4ai.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/firecrawl.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/jina.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/tavily.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/crawlers/utils.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/executors/README.md +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/executors/context.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/helpers.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/query_elicitation.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/README.md +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/bing.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/firecrawl.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/google.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/jina.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/schema.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/tavily.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/google/schema.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/bing/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/bing/client.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/bing/models.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/models.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/response_parsing.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/client.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/exceptions.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/gemini.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/response_handler.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/search_engine/vertexai.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/snippet_judge/__init__.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/snippet_judge/prompts.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/snippet_judge/schema.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/services/snippet_judge/service.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/settings.py +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/skills/unique-websearch-cli/SKILL.md +0 -0
- {unique_web_search-2026.20.0.dev7 → unique_web_search-2026.20.0.dev9}/src/unique_web_search/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-web-search
|
|
3
|
-
Version: 2026.20.0.
|
|
3
|
+
Version: 2026.20.0.dev9
|
|
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.20.0.
|
|
20
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.20.0.dev14,<2026.20.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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_web_search"
|
|
3
|
-
version = "2026.20.0.
|
|
3
|
+
version = "2026.20.0.dev9"
|
|
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.20.0.
|
|
26
|
+
"unique-toolkit[monitoring]>=2026.20.0.dev14,<2026.20.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",
|
|
@@ -28,13 +28,12 @@ from unique_web_search.services.crawlers import (
|
|
|
28
28
|
get_crawler_config_types_from_names,
|
|
29
29
|
get_default_crawler_config,
|
|
30
30
|
)
|
|
31
|
-
from unique_web_search.services.executors
|
|
31
|
+
from unique_web_search.services.executors import (
|
|
32
32
|
RefineQueryMode,
|
|
33
33
|
WebSearchMode,
|
|
34
34
|
WebSearchModeConfig,
|
|
35
35
|
WebSearchV1Config,
|
|
36
36
|
WebSearchV2Config,
|
|
37
|
-
WebSearchV3Config,
|
|
38
37
|
get_default_web_search_mode_config,
|
|
39
38
|
)
|
|
40
39
|
from unique_web_search.services.query_elicitation import QueryElicitationConfig
|
|
@@ -173,11 +172,6 @@ class WebSearchConfig(BaseToolConfig):
|
|
|
173
172
|
title="Search Mode V2 Settings",
|
|
174
173
|
description="Settings for the advanced AI-planned search mode (V2), including step limits and tool behavior.",
|
|
175
174
|
)
|
|
176
|
-
web_search_mode_config_v3: WebSearchV3Config = Field(
|
|
177
|
-
default_factory=WebSearchV3Config,
|
|
178
|
-
title="Search Mode V3 Settings (Experimental)",
|
|
179
|
-
description="Settings for V3: pre-filter search results by relevance (snippet judge) before fetching full pages.",
|
|
180
|
-
)
|
|
181
175
|
|
|
182
176
|
# Todo [UN-17655] RJSF Tags don't function properly when using union + dscriminator
|
|
183
177
|
search_engine_config: ActivatedSearchEngine = Field( # type: ignore (This type is computed at runtime so pyright is not able to infer it)
|
|
@@ -259,8 +253,6 @@ class WebSearchConfig(BaseToolConfig):
|
|
|
259
253
|
def web_search_mode_config(self) -> WebSearchModeConfig:
|
|
260
254
|
if self.web_search_active_mode == WebSearchMode.V1:
|
|
261
255
|
return self.web_search_mode_config_v1
|
|
262
|
-
if self.web_search_active_mode == WebSearchMode.V3:
|
|
263
|
-
return self.web_search_mode_config_v3
|
|
264
256
|
return self.web_search_mode_config_v2
|
|
265
257
|
|
|
266
258
|
@field_validator("web_search_active_mode", mode="before")
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Shared web-search runtime models and re-exports for tool parameters.
|
|
2
|
+
|
|
3
|
+
Tool-call Pydantic models live under ``services/executors/vN/schema.py``;
|
|
4
|
+
symbols below are re-exported for backward-compatible imports
|
|
5
|
+
(e.g. ``from unique_web_search.schema import WebSearchPlan``).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
from unidecode import unidecode
|
|
12
|
+
from unique_toolkit.content.schemas import ContentChunk
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class StepDebugInfo(BaseModel):
|
|
16
|
+
step_name: str
|
|
17
|
+
execution_time: float
|
|
18
|
+
config: str | dict
|
|
19
|
+
extra: dict = Field(default_factory=dict)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class WebPageChunk(BaseModel):
|
|
23
|
+
url: str
|
|
24
|
+
display_link: str
|
|
25
|
+
title: str
|
|
26
|
+
snippet: str
|
|
27
|
+
content: str
|
|
28
|
+
order: str
|
|
29
|
+
|
|
30
|
+
def to_content_chunk(self) -> ContentChunk:
|
|
31
|
+
"""Convert WebPageChunk to ContentChunk format."""
|
|
32
|
+
|
|
33
|
+
# Convert to ascii
|
|
34
|
+
title = unidecode(self.title)
|
|
35
|
+
name = f'{self.display_link}: "{title}"'
|
|
36
|
+
|
|
37
|
+
return ContentChunk(
|
|
38
|
+
id=name,
|
|
39
|
+
text=self.content,
|
|
40
|
+
order=int(self.order),
|
|
41
|
+
start_page=None,
|
|
42
|
+
end_page=None,
|
|
43
|
+
key=name,
|
|
44
|
+
chunk_id=self.order,
|
|
45
|
+
url=self.url,
|
|
46
|
+
title=name,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class WebSearchDebugInfo(BaseModel):
|
|
51
|
+
parameters: dict
|
|
52
|
+
steps: list[StepDebugInfo] = []
|
|
53
|
+
web_page_chunks: list[WebPageChunk] = []
|
|
54
|
+
execution_time: float | None = None
|
|
55
|
+
num_chunks_in_final_prompts: int = 0
|
|
56
|
+
|
|
57
|
+
def model_dump(self, *, with_debug_details: bool = True, **kwargs):
|
|
58
|
+
"""
|
|
59
|
+
Dump the model, dropping `additional_info` in steps when debug=False.
|
|
60
|
+
"""
|
|
61
|
+
exclude = kwargs.pop("exclude", {})
|
|
62
|
+
if not with_debug_details:
|
|
63
|
+
# Build an exclude structure that applies to all steps
|
|
64
|
+
exclude = {
|
|
65
|
+
"steps": {i: {"extra"} for i in range(len(self.steps))},
|
|
66
|
+
"web_page_chunks": True,
|
|
67
|
+
} | exclude
|
|
68
|
+
return super().model_dump(exclude=exclude, **kwargs)
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
from time import time
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
from jinja2 import Template
|
|
6
6
|
from typing_extensions import override
|
|
7
7
|
from unique_toolkit._common.chunk_relevancy_sorter.service import ChunkRelevancySorter
|
|
8
8
|
from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
|
|
@@ -24,33 +24,32 @@ from unique_toolkit.monitoring import metric_scope
|
|
|
24
24
|
|
|
25
25
|
from unique_web_search.config import WebSearchConfig
|
|
26
26
|
from unique_web_search.metrics import tool_duration, tool_empty_results, tool_errors
|
|
27
|
-
from unique_web_search.schema import
|
|
28
|
-
WebSearchDebugInfo,
|
|
29
|
-
WebSearchPlan,
|
|
30
|
-
WebSearchToolParameters,
|
|
31
|
-
)
|
|
27
|
+
from unique_web_search.schema import WebSearchDebugInfo
|
|
32
28
|
from unique_web_search.services.argument_screening import (
|
|
33
29
|
ArgumentScreeningService,
|
|
34
30
|
)
|
|
35
31
|
from unique_web_search.services.content_processing import ContentProcessor
|
|
36
32
|
from unique_web_search.services.crawlers import get_crawler_service
|
|
37
33
|
from unique_web_search.services.executors import (
|
|
34
|
+
WebSearchMode,
|
|
38
35
|
WebSearchV1Executor,
|
|
39
36
|
WebSearchV2Executor,
|
|
40
|
-
WebSearchV3Executor,
|
|
41
|
-
)
|
|
42
|
-
from unique_web_search.services.executors.configs import (
|
|
43
|
-
WebSearchMode,
|
|
44
|
-
WebSearchV3Config,
|
|
45
37
|
)
|
|
46
38
|
from unique_web_search.services.executors.context import (
|
|
47
39
|
ExecutorCallbacks,
|
|
48
40
|
ExecutorConfiguration,
|
|
49
41
|
ExecutorServiceContext,
|
|
50
42
|
)
|
|
43
|
+
from unique_web_search.services.executors.v1.schema import WebSearchToolParameters
|
|
44
|
+
from unique_web_search.services.executors.v2.schema import WebSearchPlan
|
|
51
45
|
from unique_web_search.services.message_log import WebSearchMessageLogger
|
|
52
46
|
from unique_web_search.services.query_elicitation import QueryElicitationService
|
|
53
|
-
from unique_web_search.services.search_engine import
|
|
47
|
+
from unique_web_search.services.search_engine import (
|
|
48
|
+
SearchEngineMode,
|
|
49
|
+
get_search_engine_mode,
|
|
50
|
+
get_search_engine_service,
|
|
51
|
+
)
|
|
52
|
+
from unique_web_search.services.search_engine.custom_api import CustomAPIConfig
|
|
54
53
|
from unique_web_search.utils import (
|
|
55
54
|
WebPageChunk,
|
|
56
55
|
reduce_sources_to_token_limit,
|
|
@@ -104,12 +103,18 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
104
103
|
self.config.language_model_max_input_tokens,
|
|
105
104
|
self.config.percentage_of_input_tokens_for_sources,
|
|
106
105
|
self.config.limit_token_sources,
|
|
107
|
-
language_model,
|
|
106
|
+
language_model, # type: ignore
|
|
108
107
|
self.chat_history_token_length,
|
|
109
108
|
)
|
|
110
109
|
|
|
111
110
|
self.content_reducer = content_reducer
|
|
112
111
|
|
|
112
|
+
def _resolve_search_engine_mode(self) -> SearchEngineMode:
|
|
113
|
+
"""Derive the search-engine mode, respecting CustomAPI overrides."""
|
|
114
|
+
cfg = self.search_engine_service.config
|
|
115
|
+
override = cfg.search_engine_mode if isinstance(cfg, CustomAPIConfig) else None
|
|
116
|
+
return get_search_engine_mode(cfg.search_engine_name, override=override)
|
|
117
|
+
|
|
113
118
|
@override
|
|
114
119
|
def tool_description(self) -> LanguageModelToolDescription:
|
|
115
120
|
if self.config.web_search_mode_config.mode == WebSearchMode.V1:
|
|
@@ -118,7 +123,10 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
118
123
|
self.config.web_search_mode_config.tool_parameters_description.date_restrict_description,
|
|
119
124
|
)
|
|
120
125
|
else:
|
|
121
|
-
|
|
126
|
+
engine_mode = self._resolve_search_engine_mode()
|
|
127
|
+
self.tool_parameter_calls = WebSearchPlan.with_search_engine_mode(
|
|
128
|
+
engine_mode
|
|
129
|
+
)
|
|
122
130
|
|
|
123
131
|
tool_description = self.config.web_search_mode_config.tool_description
|
|
124
132
|
|
|
@@ -129,23 +137,39 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
129
137
|
)
|
|
130
138
|
|
|
131
139
|
def tool_description_for_system_prompt(self) -> str:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
mode_config = self.config.web_search_mode_config
|
|
141
|
+
if mode_config.mode == WebSearchMode.V1:
|
|
142
|
+
return mode_config.tool_description_for_system_prompt
|
|
143
|
+
|
|
144
|
+
template_str = mode_config.tool_description_for_system_prompt
|
|
145
|
+
|
|
146
|
+
# Backwards compatibility: V2 prompts persisted before the Jinja
|
|
147
|
+
# migration use the legacy ``$max_steps`` placeholder. Jinja would
|
|
148
|
+
# otherwise pass it through verbatim, so rewrite it to the Jinja
|
|
149
|
+
# equivalent before rendering.
|
|
150
|
+
if "$max_steps" in template_str:
|
|
151
|
+
_LOGGER.warning(
|
|
152
|
+
"V2 web-search prompt contains legacy '$max_steps' placeholder; "
|
|
153
|
+
"rewriting to '{{ max_steps }}'. Please update the stored "
|
|
154
|
+
"configuration to use Jinja syntax."
|
|
138
155
|
)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
156
|
+
template_str = template_str.replace("$max_steps", "{{ max_steps }}")
|
|
157
|
+
|
|
158
|
+
engine_mode = self._resolve_search_engine_mode()
|
|
159
|
+
return Template(template_str).render(
|
|
160
|
+
max_steps=mode_config.max_steps,
|
|
161
|
+
date_string=datetime.now().strftime("%A %B %d, %Y"),
|
|
162
|
+
search_engine_mode=engine_mode.value,
|
|
163
|
+
tool_parameters_schema=WebSearchPlan.schema_hint(engine_mode),
|
|
164
|
+
example_simple=WebSearchPlan.build_example_simple(
|
|
165
|
+
engine_mode
|
|
166
|
+
).model_dump_json(indent=2),
|
|
167
|
+
example_complex=WebSearchPlan.build_example_complex(
|
|
168
|
+
engine_mode
|
|
169
|
+
).model_dump_json(indent=2),
|
|
170
|
+
)
|
|
145
171
|
|
|
146
172
|
def tool_format_information_for_system_prompt(self) -> str:
|
|
147
|
-
if self.config.web_search_active_mode == WebSearchMode.V3:
|
|
148
|
-
return self.config.web_search_mode_config_v3.tool_format_information_for_system_prompt
|
|
149
173
|
return self.config.tool_format_information_for_system_prompt
|
|
150
174
|
|
|
151
175
|
def evaluation_check_list(self) -> list[EvaluationMetricName]:
|
|
@@ -161,7 +185,8 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
161
185
|
|
|
162
186
|
screening_service = await self._get_argument_screening_service_if_ff_enabled()
|
|
163
187
|
|
|
164
|
-
|
|
188
|
+
parameters_dump = parameters.model_dump()
|
|
189
|
+
debug_info = WebSearchDebugInfo(parameters=parameters_dump)
|
|
165
190
|
|
|
166
191
|
web_search_message_logger = WebSearchMessageLogger(
|
|
167
192
|
message_step_logger=self._message_step_logger,
|
|
@@ -176,7 +201,10 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
176
201
|
|
|
177
202
|
try:
|
|
178
203
|
if screening_service is not None:
|
|
179
|
-
screening_result = await screening_service(
|
|
204
|
+
screening_result = await screening_service(
|
|
205
|
+
parameters_dump, web_search_message_logger
|
|
206
|
+
)
|
|
207
|
+
|
|
180
208
|
debug_info.steps.append(
|
|
181
209
|
screening_service.build_step_debug_info_from_result(
|
|
182
210
|
screening_result
|
|
@@ -247,7 +275,7 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
247
275
|
parameters: WebSearchPlan | WebSearchToolParameters,
|
|
248
276
|
debug_info: WebSearchDebugInfo,
|
|
249
277
|
web_search_message_logger: WebSearchMessageLogger,
|
|
250
|
-
) -> WebSearchV1Executor | WebSearchV2Executor
|
|
278
|
+
) -> WebSearchV1Executor | WebSearchV2Executor:
|
|
251
279
|
# Initialize query elicitation service and get callbacks
|
|
252
280
|
elicitation_service = QueryElicitationService(
|
|
253
281
|
chat_service=self._chat_service,
|
|
@@ -278,41 +306,29 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
278
306
|
tool_progress_reporter=self._ff_tool_progress_reporter(),
|
|
279
307
|
)
|
|
280
308
|
|
|
309
|
+
search_config = self.config.web_search_mode_config
|
|
310
|
+
|
|
281
311
|
if isinstance(parameters, WebSearchPlan):
|
|
282
|
-
mode
|
|
283
|
-
if mode == WebSearchMode.V3:
|
|
284
|
-
v3_config = self.config.web_search_mode_config
|
|
285
|
-
assert isinstance(v3_config, WebSearchV3Config)
|
|
286
|
-
|
|
287
|
-
return WebSearchV3Executor(
|
|
288
|
-
services=services,
|
|
289
|
-
config=config,
|
|
290
|
-
callbacks=callbacks,
|
|
291
|
-
tool_call=tool_call,
|
|
292
|
-
tool_parameters=parameters,
|
|
293
|
-
max_steps=v3_config.max_steps,
|
|
294
|
-
snippet_judge_config=v3_config.snippet_judge_config,
|
|
295
|
-
)
|
|
296
|
-
assert mode == WebSearchMode.V2
|
|
312
|
+
assert search_config.mode == WebSearchMode.V2
|
|
297
313
|
return WebSearchV2Executor(
|
|
298
314
|
services=services,
|
|
299
315
|
config=config,
|
|
300
316
|
callbacks=callbacks,
|
|
301
317
|
tool_call=tool_call,
|
|
302
318
|
tool_parameters=parameters,
|
|
303
|
-
max_steps=
|
|
319
|
+
max_steps=search_config.max_steps,
|
|
304
320
|
)
|
|
305
321
|
elif isinstance(parameters, WebSearchToolParameters):
|
|
306
|
-
assert
|
|
322
|
+
assert search_config.mode == WebSearchMode.V1
|
|
307
323
|
return WebSearchV1Executor(
|
|
308
324
|
services=services,
|
|
309
325
|
config=config,
|
|
310
326
|
callbacks=callbacks,
|
|
311
327
|
tool_call=tool_call,
|
|
312
328
|
tool_parameters=parameters,
|
|
313
|
-
refine_query_system_prompt=
|
|
314
|
-
mode=
|
|
315
|
-
max_queries=
|
|
329
|
+
refine_query_system_prompt=search_config.refine_query_mode.system_prompt,
|
|
330
|
+
mode=search_config.refine_query_mode.mode,
|
|
331
|
+
max_queries=search_config.max_queries,
|
|
316
332
|
)
|
|
317
333
|
else:
|
|
318
334
|
raise ValueError(f"Invalid parameters: {parameters}")
|
|
@@ -14,7 +14,6 @@ from pydantic import Field, PrivateAttr
|
|
|
14
14
|
from unique_toolkit._common.utils.structured_output.schema import StructuredOutputModel
|
|
15
15
|
from unique_toolkit._common.validators import LMI
|
|
16
16
|
from unique_toolkit.language_model import LanguageModelService
|
|
17
|
-
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
18
17
|
|
|
19
18
|
from unique_web_search.schema import StepDebugInfo
|
|
20
19
|
from unique_web_search.services.argument_screening.config import (
|
|
@@ -23,6 +22,11 @@ from unique_web_search.services.argument_screening.config import (
|
|
|
23
22
|
from unique_web_search.services.argument_screening.exceptions import (
|
|
24
23
|
ArgumentScreeningUnparseableResponseException,
|
|
25
24
|
)
|
|
25
|
+
from unique_web_search.services.message_log import WebSearchMessageLogger
|
|
26
|
+
from unique_web_search.services.structured_llm import (
|
|
27
|
+
StructuredLlmUnparseableResponseError,
|
|
28
|
+
complete_structured_llm,
|
|
29
|
+
)
|
|
26
30
|
|
|
27
31
|
_LOGGER = logging.getLogger(__name__)
|
|
28
32
|
|
|
@@ -55,7 +59,9 @@ class ArgumentScreeningService:
|
|
|
55
59
|
self._language_model = language_model
|
|
56
60
|
self._config = config
|
|
57
61
|
|
|
58
|
-
async def __call__(
|
|
62
|
+
async def __call__(
|
|
63
|
+
self, arguments: dict, message_log_callback: WebSearchMessageLogger
|
|
64
|
+
) -> ArgumentScreeningResult:
|
|
59
65
|
"""Screen tool call arguments; raises on rejection.
|
|
60
66
|
|
|
61
67
|
Args:
|
|
@@ -69,9 +75,17 @@ class ArgumentScreeningService:
|
|
|
69
75
|
go=True, reason="Argument screening disabled"
|
|
70
76
|
)
|
|
71
77
|
|
|
78
|
+
await message_log_callback.log_progress("PII Detection running...")
|
|
79
|
+
|
|
72
80
|
start_time = time()
|
|
73
81
|
result = await self._screen_arguments(arguments)
|
|
74
82
|
result._execution_time = time() - start_time
|
|
83
|
+
|
|
84
|
+
if not result.go:
|
|
85
|
+
await message_log_callback.log_progress(f"PII Detection: {result.reason}")
|
|
86
|
+
else:
|
|
87
|
+
await message_log_callback.log_progress("PII Detection completed!")
|
|
88
|
+
|
|
75
89
|
return result
|
|
76
90
|
|
|
77
91
|
async def _screen_arguments(self, arguments: dict) -> ArgumentScreeningResult:
|
|
@@ -83,27 +97,19 @@ class ArgumentScreeningService:
|
|
|
83
97
|
guidelines=self._config.guidelines,
|
|
84
98
|
)
|
|
85
99
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
model_name=self._language_model.name,
|
|
96
|
-
structured_output_model=ArgumentScreeningResult,
|
|
97
|
-
structured_output_enforce_schema=True,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
parsed = response.choices[0].message.parsed
|
|
101
|
-
if parsed is None:
|
|
100
|
+
try:
|
|
101
|
+
result = await complete_structured_llm(
|
|
102
|
+
self._language_model_service,
|
|
103
|
+
self._language_model,
|
|
104
|
+
system_message=self._config.system_prompt,
|
|
105
|
+
user_message=user_prompt,
|
|
106
|
+
response_model=ArgumentScreeningResult,
|
|
107
|
+
)
|
|
108
|
+
except StructuredLlmUnparseableResponseError as e:
|
|
102
109
|
raise ArgumentScreeningUnparseableResponseException(
|
|
103
110
|
reason="Argument screening agent failed to return a valid response"
|
|
104
|
-
)
|
|
111
|
+
) from e
|
|
105
112
|
|
|
106
|
-
result = ArgumentScreeningResult.model_validate(parsed)
|
|
107
113
|
_LOGGER.info(f"Argument screening verdict: go={result.go}")
|
|
108
114
|
return result
|
|
109
115
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from logging import getLogger
|
|
2
|
+
|
|
3
|
+
from unique_web_search.services.executors.base_config import WebSearchMode
|
|
4
|
+
from unique_web_search.services.executors.context import (
|
|
5
|
+
ExecutorCallbacks,
|
|
6
|
+
ExecutorConfiguration,
|
|
7
|
+
ExecutorServiceContext,
|
|
8
|
+
)
|
|
9
|
+
from unique_web_search.services.executors.v1.config import (
|
|
10
|
+
RefineQueryMode,
|
|
11
|
+
WebSearchV1Config,
|
|
12
|
+
)
|
|
13
|
+
from unique_web_search.services.executors.v1.executor import (
|
|
14
|
+
WebSearchV1Executor,
|
|
15
|
+
)
|
|
16
|
+
from unique_web_search.services.executors.v2.config import WebSearchV2Config
|
|
17
|
+
from unique_web_search.services.executors.v2.executor import (
|
|
18
|
+
WebSearchV2Executor,
|
|
19
|
+
)
|
|
20
|
+
from unique_web_search.settings import env_settings
|
|
21
|
+
|
|
22
|
+
_LOGGER = getLogger(__name__)
|
|
23
|
+
WebSearchModeConfig = WebSearchV1Config | WebSearchV2Config
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_default_web_search_mode_config() -> WebSearchMode:
|
|
27
|
+
match env_settings.web_search_mode:
|
|
28
|
+
case "v1":
|
|
29
|
+
return WebSearchMode.V1
|
|
30
|
+
case "v2":
|
|
31
|
+
return WebSearchMode.V2
|
|
32
|
+
case _:
|
|
33
|
+
raise ValueError(f"Invalid web search mode: {env_settings.web_search_mode}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"WebSearchModeConfig",
|
|
38
|
+
"WebSearchV1Config",
|
|
39
|
+
"WebSearchV2Config",
|
|
40
|
+
"get_default_web_search_mode_config",
|
|
41
|
+
"WebSearchMode",
|
|
42
|
+
"RefineQueryMode",
|
|
43
|
+
"WebSearchV1Executor",
|
|
44
|
+
"WebSearchV2Executor",
|
|
45
|
+
"ExecutorServiceContext",
|
|
46
|
+
"ExecutorConfiguration",
|
|
47
|
+
"ExecutorCallbacks",
|
|
48
|
+
]
|
|
@@ -12,7 +12,6 @@ from unique_web_search.services.helpers import (
|
|
|
12
12
|
class WebSearchMode(StrEnum):
|
|
13
13
|
V1 = "v1"
|
|
14
14
|
V2 = "v2"
|
|
15
|
-
V3 = "v3"
|
|
16
15
|
|
|
17
16
|
@staticmethod
|
|
18
17
|
def get_enum_names() -> list[str]:
|
|
@@ -23,7 +22,6 @@ class WebSearchMode(StrEnum):
|
|
|
23
22
|
return [
|
|
24
23
|
"V1 — Simple keyword searches with optional query refinement",
|
|
25
24
|
"V2 — AI-planned multi-step research (search and read pages in sequence)",
|
|
26
|
-
"V3 (Experimental) — Like V2, but pre-filters results by relevance (snippet judge) before fetching full pages",
|
|
27
25
|
]
|
|
28
26
|
|
|
29
27
|
@classmethod
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
from time import time
|
|
4
|
+
from typing import Generic, TypeVar
|
|
4
5
|
|
|
6
|
+
from pydantic import BaseModel
|
|
5
7
|
from unique_toolkit.agentic.feature_flags import feature_flags
|
|
6
8
|
from unique_toolkit.agentic.tools.tool_progress_reporter import (
|
|
7
9
|
ProgressState,
|
|
@@ -14,8 +16,6 @@ from unique_web_search.metrics import llm_duration, llm_errors
|
|
|
14
16
|
from unique_web_search.schema import (
|
|
15
17
|
StepDebugInfo,
|
|
16
18
|
WebPageChunk,
|
|
17
|
-
WebSearchPlan,
|
|
18
|
-
WebSearchToolParameters,
|
|
19
19
|
)
|
|
20
20
|
from unique_web_search.services.executors.context import (
|
|
21
21
|
ExecutorCallbacks,
|
|
@@ -29,14 +29,17 @@ from unique_web_search.services.search_engine.schema import (
|
|
|
29
29
|
_LOGGER = logging.getLogger(__name__)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
T = TypeVar("T", bound=BaseModel)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BaseWebSearchExecutor(ABC, Generic[T]):
|
|
33
36
|
def __init__(
|
|
34
37
|
self,
|
|
35
38
|
services: ExecutorServiceContext,
|
|
36
39
|
config: ExecutorConfiguration,
|
|
37
40
|
callbacks: ExecutorCallbacks,
|
|
38
41
|
tool_call: LanguageModelFunction,
|
|
39
|
-
tool_parameters:
|
|
42
|
+
tool_parameters: T,
|
|
40
43
|
):
|
|
41
44
|
# Extract from service context
|
|
42
45
|
self.search_service = services.search_engine_service
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from unique_web_search.services.executors.v1.config import (
|
|
2
|
+
QueryRefinementConfig,
|
|
3
|
+
RefineQueryMode,
|
|
4
|
+
WebSearchToolParametersDescriptionConfig,
|
|
5
|
+
WebSearchV1Config,
|
|
6
|
+
)
|
|
7
|
+
from unique_web_search.services.executors.v1.executor import (
|
|
8
|
+
WebSearchV1Executor,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"QueryRefinementConfig",
|
|
13
|
+
"RefineQueryMode",
|
|
14
|
+
"WebSearchToolParametersDescriptionConfig",
|
|
15
|
+
"WebSearchV1Config",
|
|
16
|
+
"WebSearchV1Executor",
|
|
17
|
+
]
|
|
@@ -6,11 +6,11 @@ from pydantic.json_schema import SkipJsonSchema
|
|
|
6
6
|
from unique_toolkit._common.pydantic.rjsf_tags import RJSFMetaTag
|
|
7
7
|
from unique_toolkit.agentic.tools.config import get_configuration_dict
|
|
8
8
|
|
|
9
|
-
from unique_web_search.services.executors.
|
|
9
|
+
from unique_web_search.services.executors.base_config import (
|
|
10
10
|
BaseWebSearchModeConfig,
|
|
11
11
|
WebSearchMode,
|
|
12
12
|
)
|
|
13
|
-
from unique_web_search.services.executors.
|
|
13
|
+
from unique_web_search.services.executors.v1.prompts import (
|
|
14
14
|
DEFAULT_TOOL_DESCRIPTION,
|
|
15
15
|
DEFAULT_TOOL_DESCRIPTION_FOR_SYSTEM_PROMPT,
|
|
16
16
|
REFINE_QUERY_SYSTEM_PROMPT,
|
|
@@ -97,22 +97,20 @@ class WebSearchV1Config(BaseWebSearchModeConfig[WebSearchMode.V1]):
|
|
|
97
97
|
tool_description: Annotated[
|
|
98
98
|
str,
|
|
99
99
|
RJSFMetaTag.StringWidget.textarea(
|
|
100
|
-
rows=int(len(DEFAULT_TOOL_DESCRIPTION
|
|
100
|
+
rows=int(len(DEFAULT_TOOL_DESCRIPTION.split("\n")))
|
|
101
101
|
),
|
|
102
102
|
] = Field(
|
|
103
|
-
default=DEFAULT_TOOL_DESCRIPTION
|
|
103
|
+
default=DEFAULT_TOOL_DESCRIPTION,
|
|
104
104
|
title="Tool Description",
|
|
105
105
|
description="Advanced: Description that helps the AI model decide when to use web search.",
|
|
106
106
|
)
|
|
107
107
|
tool_description_for_system_prompt: Annotated[
|
|
108
108
|
str,
|
|
109
109
|
RJSFMetaTag.StringWidget.textarea(
|
|
110
|
-
rows=int(
|
|
111
|
-
len(DEFAULT_TOOL_DESCRIPTION_FOR_SYSTEM_PROMPT["v1"].split("\n")) / 2
|
|
112
|
-
)
|
|
110
|
+
rows=int(len(DEFAULT_TOOL_DESCRIPTION_FOR_SYSTEM_PROMPT.split("\n")) / 2)
|
|
113
111
|
),
|
|
114
112
|
] = Field(
|
|
115
|
-
default=DEFAULT_TOOL_DESCRIPTION_FOR_SYSTEM_PROMPT
|
|
113
|
+
default=DEFAULT_TOOL_DESCRIPTION_FOR_SYSTEM_PROMPT,
|
|
116
114
|
title="Tool Description For System Prompt",
|
|
117
115
|
description="Advanced: Detailed instructions for the AI model on how and when to use web search.",
|
|
118
116
|
)
|
|
@@ -20,16 +20,17 @@ from unique_web_search.metrics import (
|
|
|
20
20
|
search_errors,
|
|
21
21
|
search_total,
|
|
22
22
|
)
|
|
23
|
-
from unique_web_search.schema import StepDebugInfo
|
|
23
|
+
from unique_web_search.schema import StepDebugInfo
|
|
24
24
|
from unique_web_search.services.executors.base_executor import (
|
|
25
25
|
BaseWebSearchExecutor,
|
|
26
26
|
)
|
|
27
|
-
from unique_web_search.services.executors.configs import RefineQueryMode
|
|
28
27
|
from unique_web_search.services.executors.context import (
|
|
29
28
|
ExecutorCallbacks,
|
|
30
29
|
ExecutorConfiguration,
|
|
31
30
|
ExecutorServiceContext,
|
|
32
31
|
)
|
|
32
|
+
from unique_web_search.services.executors.v1.config import RefineQueryMode
|
|
33
|
+
from unique_web_search.services.executors.v1.schema import WebSearchToolParameters
|
|
33
34
|
from unique_web_search.services.search_engine.schema import (
|
|
34
35
|
WebSearchResult,
|
|
35
36
|
)
|
|
@@ -99,7 +100,6 @@ async def query_generation_agent(
|
|
|
99
100
|
match mode:
|
|
100
101
|
case RefineQueryMode.DEACTIVATED:
|
|
101
102
|
_LOGGER.info("Query Refinement deactivated")
|
|
102
|
-
### Early return for deactivated mode
|
|
103
103
|
return RefinedQuery(
|
|
104
104
|
objective=query,
|
|
105
105
|
refined_query=query,
|
|
@@ -134,7 +134,7 @@ async def query_generation_agent(
|
|
|
134
134
|
return structured_output_model.model_validate(parsed_response)
|
|
135
135
|
|
|
136
136
|
|
|
137
|
-
class WebSearchV1Executor(BaseWebSearchExecutor):
|
|
137
|
+
class WebSearchV1Executor(BaseWebSearchExecutor[WebSearchToolParameters]):
|
|
138
138
|
"""Executes research plans step by step."""
|
|
139
139
|
|
|
140
140
|
@override
|
|
@@ -157,7 +157,6 @@ class WebSearchV1Executor(BaseWebSearchExecutor):
|
|
|
157
157
|
tool_parameters=tool_parameters,
|
|
158
158
|
)
|
|
159
159
|
self.mode = mode
|
|
160
|
-
self.tool_parameters = tool_parameters
|
|
161
160
|
self.refine_query_system_prompt = refine_query_system_prompt
|
|
162
161
|
self.max_queries = max_queries
|
|
163
162
|
|
|
@@ -177,7 +176,6 @@ class WebSearchV1Executor(BaseWebSearchExecutor):
|
|
|
177
176
|
elicitated_queries = await self._ff_elicitate_queries(refined_queries)
|
|
178
177
|
|
|
179
178
|
web_search_results = []
|
|
180
|
-
# Pass query strings only - callback handles creating WebSearchLogEntry objects
|
|
181
179
|
|
|
182
180
|
queries_wo_results = [
|
|
183
181
|
query_params_to_human_string(refined_query, date_restrict)
|