unique_web_search 2026.24.0.dev1__tar.gz → 2026.24.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.24.0.dev1 → unique_web_search-2026.24.0.dev2}/PKG-INFO +2 -2
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/pyproject.toml +2 -2
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/prompts.py +21 -2
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v3/executor.py +4 -2
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v3/prompts/tool_description.j2 +6 -2
- unique_web_search-2026.24.0.dev2/src/unique_web_search/services/executors/v3/prompts/tool_description_for_system_prompt.j2 +78 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v3/schema.py +41 -4
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/skills/web-search-v3.md +128 -29
- unique_web_search-2026.24.0.dev1/src/unique_web_search/services/executors/v3/prompts/tool_description_for_system_prompt.j2 +0 -40
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/README.md +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/client_settings.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/metrics.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/schema.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/service.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/exceptions.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/prompts/guidelines.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/prompts/rejection_response.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/argument_screening/service.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/client/proxy_config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/cleaning/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/cleaning/character_sanitize.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/cleaning/clean.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/cleaning/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/base.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_guard_judge.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_keyword_redact.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/llm_process.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_and_sanitize_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/keyword_extract_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/page_context.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/sanitize_rules.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/schema.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/settings.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/processing_strategies/truncate.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/content_processing/service.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/README.md +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/base.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/basic.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/crawl4ai.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/firecrawl.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/jina.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/tavily.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/dns.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/models.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/netloc.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/policy.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/redirect.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/resolver.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/service.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/url_safety/settings.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/crawlers/utils.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/README.md +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/base_config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/base_executor.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/context.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/executor.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/prompts/refine_query_system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/prompts/restrict_date_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v1/schema.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/executor.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/prompts/step_query_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v2/schema.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v3/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v3/config.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/executors/v3/prompts/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/helpers.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/message_log.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/query_elicitation.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/README.md +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/base.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/bing.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/brave.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/custom_api.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/firecrawl.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/google.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/jina.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/schema.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/tavily.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/google/schema.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/client.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/models.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/bing/runner.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/models.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/response_parsing.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/client.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/exceptions.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/gemini.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/response_handler.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/search_engine/vertexai.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/snippet_judge/__init__.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/snippet_judge/prompts.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/snippet_judge/schema.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/snippet_judge/service.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/services/structured_llm.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/settings.py +0 -0
- {unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/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.24.0.
|
|
3
|
+
Version: 2026.24.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.24.0.
|
|
20
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.24.0.dev10,<2026.24.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.24.0.
|
|
3
|
+
version = "2026.24.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.24.0.
|
|
26
|
+
"unique-toolkit[monitoring]>=2026.24.0.dev10,<2026.24.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",
|
|
@@ -39,11 +39,28 @@ When multiple sources are available, prioritize:
|
|
|
39
39
|
4. **Primary sources**: Original reports over summaries
|
|
40
40
|
5. **Domain expertise**: Medical info from health institutions, financial from finance sources
|
|
41
41
|
|
|
42
|
-
**When sources are insufficient**: Clearly state "Based on available search results..." and indicate limitations.
|
|
43
|
-
|
|
44
42
|
**REMEMBER**: Source numbers reset with each new WebSearch. Only use numbers from the most recent tool response.
|
|
45
43
|
"""
|
|
46
44
|
|
|
45
|
+
_TOOL_FORMAT_INFORMATION_SYNTHESIS_SECTION = """
|
|
46
|
+
## Synthesizing WebSearch results
|
|
47
|
+
|
|
48
|
+
After one or more WebSearch tool calls, **synthesize** findings in your answer. Do not only cite facts when a single source made the answer obvious.
|
|
49
|
+
|
|
50
|
+
**Evidence ledger (per facet or sub-question):** Track each facet with a confidence label:
|
|
51
|
+
|
|
52
|
+
- **Confirmed** — the exact fact is supported by cited tool content [sourceX].
|
|
53
|
+
- **Partial** — only part of the facet is supported; say what is missing [sourceX].
|
|
54
|
+
- **Not found** — no on-topic public evidence after reasonable search/refinement; state what you tried (no citation required for absence).
|
|
55
|
+
- **Related** — tool content is adjacent but does not answer the exact ask; cite it [sourceX] and label it **related, not confirmed**.
|
|
56
|
+
|
|
57
|
+
**Mandatory behaviors:**
|
|
58
|
+
|
|
59
|
+
- **Always summarize partial findings** before saying something is unavailable. Never reply with only "I couldn't find X" if the tool returned related material—put related material in a **Related leads** (or equivalent) subsection with citations.
|
|
60
|
+
- For multi-facet tasks (diligence, Source of Wealth, company profiles), use a structured answer: direct answer → evidence by facet → gaps and limitations → related leads → optional next steps.
|
|
61
|
+
- Distinguish **Confirmed** from **Related** in prose—do not imply ownership, revenue, or UBO facts unless citations support them.
|
|
62
|
+
""".strip()
|
|
63
|
+
|
|
47
64
|
|
|
48
65
|
_TOOL_FORMAT_INFORMATION_V3_DOMAIN_DIVERSITY_SECTION = """
|
|
49
66
|
## Domain Diversity Requirement
|
|
@@ -61,4 +78,6 @@ DEFAULT_TOOL_FORMAT_INFORMATION_FOR_SYSTEM_PROMPT_V3 = (
|
|
|
61
78
|
DEFAULT_TOOL_FORMAT_INFORMATION_FOR_SYSTEM_PROMPT.rstrip()
|
|
62
79
|
+ "\n\n"
|
|
63
80
|
+ _TOOL_FORMAT_INFORMATION_V3_DOMAIN_DIVERSITY_SECTION
|
|
81
|
+
+ "\n\n"
|
|
82
|
+
+ _TOOL_FORMAT_INFORMATION_SYNTHESIS_SECTION
|
|
64
83
|
)
|
|
@@ -58,11 +58,13 @@ class WebSearchV3Executor(BaseWebSearchExecutor[WebSearchV3ToolParameters]):
|
|
|
58
58
|
p = self.tool_parameters
|
|
59
59
|
if isinstance(p.payload, SearchPayload):
|
|
60
60
|
await self._message_log_callback.log_progress("_Executing Search_")
|
|
61
|
-
return await self._run_search(
|
|
61
|
+
return await self._run_search(
|
|
62
|
+
query=p.payload.query, objective=p.relevance_focus()
|
|
63
|
+
)
|
|
62
64
|
if isinstance(p.payload, FetchUrlsPayload):
|
|
63
65
|
await self._message_log_callback.log_progress("_Reading Web Pages_")
|
|
64
66
|
return await self._run_fetch_urls(
|
|
65
|
-
urls=p.payload.urls, objective=p.
|
|
67
|
+
urls=p.payload.urls, objective=p.relevance_focus()
|
|
66
68
|
)
|
|
67
69
|
|
|
68
70
|
msg = "WebSearchV3ToolParameters requires exactly one of 'query' or 'urls'."
|
|
@@ -3,7 +3,11 @@ The WebSearch tool returns up-to-date information from the web. It exposes two c
|
|
|
3
3
|
- **Search** (`command: "search"`) — runs the configured search engine and returns SERP rows (URL, domain, title, snippet). Gives a high-level read of what relevant pages contain without crawling them. Useful for **exploration** and quick lookups when a snippet is enough to answer.
|
|
4
4
|
- **Fetch** (`command: "read_urls"`) — crawls one or more URLs and returns full-page text. Useful for **deep dives** when the task is complex and needs exact figures, quotes, regulatory text, or specs, and when the user provides a URL directly.
|
|
5
5
|
|
|
6
|
-
Each call performs **one** operation. Drive multi-part tasks by chaining calls.
|
|
6
|
+
Each call performs **one** operation. Drive multi-part tasks by chaining calls; use **parallel** `search` calls for independent facets (short `query` each, not one long query).
|
|
7
|
+
|
|
8
|
+
**`phase`:** `exploratory` (map what exists) | `target` (precise facet in `gap`) | `redirect` (related context when the facet is not on the web). **`gap`:** one atomic facet per call.
|
|
9
|
+
|
|
10
|
+
**Complex research:** build an evidence ledger as you go and **synthesize** in the final answer—do not stop at "not found" if results contain related context.
|
|
7
11
|
|
|
8
12
|
### Fields
|
|
9
13
|
|
|
@@ -11,4 +15,4 @@ Each call performs **one** operation. Drive multi-part tasks by chaining calls.
|
|
|
11
15
|
|
|
12
16
|
Never invent URLs.
|
|
13
17
|
|
|
14
|
-
For
|
|
18
|
+
For the full playbook (search vs fetch, diligence decomposition, partial evidence, synthesis, URL-selection, anti-patterns, SoW examples), activate the `web-search-v3` skill before/while using this tool.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Use `WebSearch` for up-to-date information from the web. It exposes two capabilities, picked per call via `command`. Each invocation performs **one** operation; complex user tasks are handled by **chaining** invocations — use **parallel** `search` calls when several facets are independent (one short `query` per call, not one long query).
|
|
2
|
+
|
|
3
|
+
### `phase` — research phase (required on every call)
|
|
4
|
+
|
|
5
|
+
Set **`phase`** on each WebSearch invocation (replaces the old `objective` field):
|
|
6
|
+
|
|
7
|
+
- **`exploratory`** — sense what exists on the web and what is closest to the user's ask. Use broad, short mapping queries. Typical at the start of a complex task or when scoping an entity.
|
|
8
|
+
- **`target`** — pursue one specific facet named in `payload.gap` with a precise, short `payload.query`. Use for verifiable facts (revenue, ownership, officers, filings).
|
|
9
|
+
- **`redirect`** — last resort when the exact facet is not on the public web. Search for **related, attributable** context (sector, peers, parent company, adjacent news). Label results as related, not confirmed; never invent figures or ownership.
|
|
10
|
+
|
|
11
|
+
**`payload.gap`** — one atomic facet per call (not the whole user question). **`payload.query`** — ~3–8 keywords only; decompose multi-facet asks into parallel `search` calls instead of one bloated query.
|
|
12
|
+
|
|
13
|
+
#### `command: "search"` — search the web
|
|
14
|
+
|
|
15
|
+
Runs the configured search engine and returns SERP rows (URL, domain, title, snippet). It is **fast** and gives a **high-level read** of what relevant pages contain without paying the cost of crawling them.
|
|
16
|
+
|
|
17
|
+
Use it when:
|
|
18
|
+
|
|
19
|
+
- You need to **discover sources**: you don't yet have URLs and need the engine to surface candidates for a topic.
|
|
20
|
+
- The user's question can be answered from **snippets alone** — a definition, a status, a current value, a short factual lookup.
|
|
21
|
+
- You're at the **start of a complex task** and need to map out what's out there before deciding which pages are worth a deeper read.
|
|
22
|
+
- You want to **scope or sanity-check** a topic cheaply (does this entity / event / product even exist? how recent is the latest coverage?).
|
|
23
|
+
- You need to **cover a new gap / sub-question** in a multi-step task — issue another search rather than blindly fetching.
|
|
24
|
+
|
|
25
|
+
#### `command: "read_urls"` — fetch full page content
|
|
26
|
+
|
|
27
|
+
Crawls one or more URLs and returns the full-page text. It is **slower** than search but gives the **complete content** of the chosen pages, not just a snippet.
|
|
28
|
+
|
|
29
|
+
Use it when:
|
|
30
|
+
|
|
31
|
+
- The user **pasted a URL** or asked you to read a specific page — go straight here, do not search first.
|
|
32
|
+
- The task is **complex / in-depth** and needs more than a snippet: exact figures, full quotes, regulatory text, contract language, statute numbers, API specs, version numbers.
|
|
33
|
+
- The previous search returned **paraphrased / hedged snippets** ("around", "approximately", "is expected to", "reportedly") for a question that needs precision.
|
|
34
|
+
- The topic is **canonical-source-driven** — financial filings (10-K, 10-Q, earnings releases), regulator publications, official product docs, peer-reviewed papers, primary press releases — where the page itself is the source of truth.
|
|
35
|
+
- You found a **highly relevant** SERP hit but the title/snippet alone doesn't support the claim you want to make.
|
|
36
|
+
- The snippets from the previous "search" commands are relevant but do not fully answer the question or fill the gap and fetching the full page is necessary.
|
|
37
|
+
|
|
38
|
+
**Current date:** {{ date_string }}
|
|
39
|
+
|
|
40
|
+
### Balance exploration and exploitation
|
|
41
|
+
|
|
42
|
+
- **Explore first.** Start with `command: "search"` to get a cheap, high-level read of candidate pages. Cover one `gap` per call.
|
|
43
|
+
- **Refine, don't escalate prematurely.** If the first search did not fill the `gap`, issue another `command: "search"` with a refined query (different keywords, narrower entity, different timeframe) before reaching for `read_urls`.
|
|
44
|
+
- **Exploit when snippets aren't enough.** Switch to `command: "read_urls"` when snippets paraphrase / hedge, or the task needs exact figures, quotes, regulatory text, specs, or canonical-source content. Pick **1-3 high-signal URLs** from the most recent SERP — complementary domains preferred.
|
|
45
|
+
- **User-provided URLs go straight to fetch.** If the user pasted URL(s), the first call should be `command: "read_urls"`. Do not "search" for a URL the user already supplied.
|
|
46
|
+
- **Latency is a fair trade.** `read_urls` takes longer than `search`. That latency is acceptable on complex queries where the user expects depth — give them the answer that's actually grounded. Don't fetch when a snippet already answers the question; don't refuse to fetch when the snippet doesn't.
|
|
47
|
+
|
|
48
|
+
### WebSearch — Complex and diligence-style research
|
|
49
|
+
|
|
50
|
+
Use this pattern when the user needs **multiple facts about an entity** (ownership, revenue, officers, filings, sanctions, geography, industry context)—including Source of Wealth / KYC-style profiles where not everything is on the public web.
|
|
51
|
+
|
|
52
|
+
- **Before the first WebSearch call** (in your reasoning, not in tool args), decompose the task into **5–10 atomic gaps**—each gap is one verifiable facet (e.g. legal name and jurisdiction, revenue scale, ownership / UBO signals, key executives, recent filings, adverse media, industry peer context).
|
|
53
|
+
- **Execute gradually:** one `command: "search"` (and `read_urls` when snippets are insufficient) **per gap**, in a deliberate order (identity → scale → ownership → corroboration). Use `phase: "exploratory"` to map, then `phase: "target"` per facet; use `phase: "redirect"` only when a target facet has no public evidence after refinement.
|
|
54
|
+
- **After each tool round**, update a mental **evidence ledger** per facet: **Confirmed**, **Partial**, **Not found**, or **Related only**. Do not discard partial or adjacent SERP hits—they may matter in the final synthesis.
|
|
55
|
+
|
|
56
|
+
### WebSearch — When public evidence is missing or indirect
|
|
57
|
+
|
|
58
|
+
- **Do not stop** after one empty or weak SERP for a gap. Refine the query (keywords, entity disambiguation, registry/filing terms, language) before marking a gap **Not found**.
|
|
59
|
+
- If the **exact** fact is not published on the open web, still surface **related, attributable context** from search results: sector, approximate scale, parent/subsidiary links, adjacent filings, news mentioning the person or company, comparable peers. Label these clearly as **related, not confirmed** for the original ask.
|
|
60
|
+
- **Never invent** figures, ownership percentages, or ultimate-beneficial-owner claims. **Never** present related context as if it answered the exact question.
|
|
61
|
+
|
|
62
|
+
### WebSearch — Synthesizing before you answer
|
|
63
|
+
|
|
64
|
+
After WebSearch research (or when the user needs an interim summary), **synthesize**—do not dump raw tool output or answer only the facets that were easy to find.
|
|
65
|
+
|
|
66
|
+
For **complex** tasks, structure the answer as:
|
|
67
|
+
|
|
68
|
+
1. **Direct answer** — what you can support with citations.
|
|
69
|
+
2. **Evidence by facet** — facet → finding → confidence (**Confirmed** / **Partial** / **Related**) → [sourceX].
|
|
70
|
+
3. **Gaps and limitations** — what was not found on the public web and which searches you tried.
|
|
71
|
+
4. **Related leads** — indirect but useful pointers for the user's underlying goal (all cited).
|
|
72
|
+
5. **Suggested next steps** (optional)—e.g. corporate registry, paid databases, user-provided documents—only when appropriate.
|
|
73
|
+
|
|
74
|
+
For **simple** lookups, a short cited answer is enough; do not force the full structure.
|
|
75
|
+
|
|
76
|
+
For the deeper explore-then-exploit playbook (snippet hedging, decomposition, partial evidence, synthesis, URL-selection, anti-patterns, worked examples including Source of Wealth), activate the `web-search-v3` skill before/while using this tool.
|
|
77
|
+
|
|
78
|
+
Tool arguments are defined by the tool schema; the live JSON schema comes from the tool definition.
|
|
@@ -11,12 +11,29 @@ class Command(StrEnum):
|
|
|
11
11
|
FETCH_URLS = "read_urls"
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
class SearchPhase(StrEnum):
|
|
15
|
+
"""How this WebSearch call fits in the research arc."""
|
|
16
|
+
|
|
17
|
+
EXPLORATORY = "exploratory"
|
|
18
|
+
TARGET = "target"
|
|
19
|
+
REDIRECT = "redirect"
|
|
20
|
+
|
|
21
|
+
|
|
14
22
|
class SearchPayload(BaseModel):
|
|
15
23
|
gap: str = Field(
|
|
16
|
-
description=
|
|
24
|
+
description=(
|
|
25
|
+
"One atomic facet this call addresses (e.g. '2023 revenue band for Company X in CH')—"
|
|
26
|
+
"not the whole user question. Pair with `phase`: exploratory scopes the topic; "
|
|
27
|
+
"target pursues this facet precisely; redirect seeks related context when the facet "
|
|
28
|
+
"is unlikely to be on the public web."
|
|
29
|
+
)
|
|
17
30
|
)
|
|
18
31
|
query: str = Field(
|
|
19
|
-
description=
|
|
32
|
+
description=(
|
|
33
|
+
"Short search-engine keyword line (~3–8 words, not a sentence). "
|
|
34
|
+
"Do not pack multiple facets into one query—issue parallel `search` calls with "
|
|
35
|
+
"one `gap` each instead. Do not paste the user question or `gap` text here."
|
|
36
|
+
)
|
|
20
37
|
)
|
|
21
38
|
|
|
22
39
|
|
|
@@ -35,14 +52,31 @@ class WebSearchV3ToolParameters(BaseModel):
|
|
|
35
52
|
description="The command to execute. Must be either 'search' or 'read_urls'."
|
|
36
53
|
)
|
|
37
54
|
|
|
38
|
-
|
|
39
|
-
description=
|
|
55
|
+
phase: SearchPhase = Field(
|
|
56
|
+
description=(
|
|
57
|
+
"Research phase for this call. "
|
|
58
|
+
"`exploratory` — sense what exists on the web and what is closest to the user's ask "
|
|
59
|
+
"(broad, mapping queries). "
|
|
60
|
+
"`target` — pursue one specific facet in `payload.gap` with a precise, short `query`. "
|
|
61
|
+
"`redirect` — last resort when the exact facet is not on the public web; find related, "
|
|
62
|
+
"attributable context (sector, peers, parent entity, adjacent news)—not invented facts."
|
|
63
|
+
)
|
|
40
64
|
)
|
|
41
65
|
|
|
42
66
|
payload: SearchPayload | FetchUrlsPayload = Field(
|
|
43
67
|
description="The payload of the command. Must be either a SearchPayload or a FetchUrlsPayload."
|
|
44
68
|
)
|
|
45
69
|
|
|
70
|
+
def relevance_focus(self) -> str:
|
|
71
|
+
"""Focus string for notify UI, snippet judging, and content processing."""
|
|
72
|
+
phase_label = self.phase.value
|
|
73
|
+
if isinstance(self.payload, SearchPayload):
|
|
74
|
+
return f"[{phase_label}] {self.payload.gap}"
|
|
75
|
+
urls_preview = ", ".join(self.payload.urls[:3])
|
|
76
|
+
if len(self.payload.urls) > 3:
|
|
77
|
+
urls_preview += ", …"
|
|
78
|
+
return f"[{phase_label}] {urls_preview}"
|
|
79
|
+
|
|
46
80
|
@classmethod
|
|
47
81
|
def schema_hint(cls) -> str:
|
|
48
82
|
"""Return a markdown-bulleted hint mirroring the field descriptions of this model.
|
|
@@ -68,6 +102,9 @@ class WebSearchV3ToolParameters(BaseModel):
|
|
|
68
102
|
if name == "command":
|
|
69
103
|
choices = " or ".join(f'`"{c.value}"`' for c in Command)
|
|
70
104
|
lines.append(f"- **`{name}`** — {choices}.")
|
|
105
|
+
elif name == "phase":
|
|
106
|
+
choices = " | ".join(f'`"{c.value}"`' for c in SearchPhase)
|
|
107
|
+
lines.append(f"- **`{name}`** — {choices}.")
|
|
71
108
|
elif name == "payload":
|
|
72
109
|
continue
|
|
73
110
|
else:
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: web-search
|
|
2
|
+
name: web-search-v3
|
|
3
3
|
description: >-
|
|
4
4
|
Use this skill when the WebSearch tool is being used and the task is
|
|
5
|
-
non-trivial. Explains how to balance
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
canonical-source topics, and sub-question coverage.
|
|
5
|
+
non-trivial. Explains how to balance `search` vs `read_urls`, decompose
|
|
6
|
+
complex diligence tasks, handle partial or missing public evidence,
|
|
7
|
+
and synthesize findings before answering.
|
|
9
8
|
---
|
|
10
9
|
|
|
11
10
|
# WebSearch — Explore → Exploit Playbook
|
|
@@ -42,15 +41,13 @@ flowchart TD
|
|
|
42
41
|
## Tool fields
|
|
43
42
|
|
|
44
43
|
- **`command`** (string, per call) — `"search"` or `"read_urls"`.
|
|
45
|
-
- **`
|
|
46
|
-
|
|
44
|
+
- **`phase`** (string, per call) — `exploratory` | `target` | `redirect` (see
|
|
45
|
+
system prompt). Replaces legacy `objective`.
|
|
47
46
|
- **`payload`** (object, per call) — Shape depends on `command`:
|
|
48
47
|
- For `"search"`:
|
|
49
|
-
- **`gap`** —
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
allowed). For time-sensitive topics you may incorporate the current
|
|
53
|
-
year or month to improve recall.
|
|
48
|
+
- **`gap`** — One atomic, verifiable facet (not the whole user question).
|
|
49
|
+
- **`query`** — Short keyword line (~3-8 words). One facet per call—use
|
|
50
|
+
parallel `search` calls instead of one long query.
|
|
54
51
|
- For `"read_urls"`:
|
|
55
52
|
- **`urls`** — HTTP(S) URLs to crawl for full-page text. Use only URLs
|
|
56
53
|
returned by a prior `search` call or pasted by the user — **never
|
|
@@ -72,9 +69,10 @@ Read the user task and silently classify it:
|
|
|
72
69
|
- Composite reasoning that needs sub-answers chained together.
|
|
73
70
|
- Vague / multi-faceted topics the user expects you to cover broadly.
|
|
74
71
|
|
|
75
|
-
For complex tasks
|
|
76
|
-
|
|
77
|
-
`command: "
|
|
72
|
+
For complex tasks (including Source of Wealth / KYC-style profiles),
|
|
73
|
+
decompose into **5–10 atomic gaps** (one verifiable facet each) and run
|
|
74
|
+
**one `command: "search"` per gap** (and follow-up `command: "read_urls"`
|
|
75
|
+
calls as needed). Each gap should:
|
|
78
76
|
|
|
79
77
|
- Be answerable on its own by one focused search (and possibly one fetch
|
|
80
78
|
follow-up).
|
|
@@ -100,10 +98,10 @@ user already supplied.
|
|
|
100
98
|
## Step 3 — Sufficiency check after every search
|
|
101
99
|
|
|
102
100
|
Before deciding the next call, judge the snippets you just received against
|
|
103
|
-
the current `
|
|
101
|
+
the current `phase`, `gap`, and `query`:
|
|
104
102
|
|
|
105
103
|
- Do they contain the **specific** number, quote, date, or name the
|
|
106
|
-
`
|
|
104
|
+
the `gap` requires? (Snippets often paraphrase or truncate.)
|
|
107
105
|
- Are there **≥2 corroborating domains** for fact-style claims, when
|
|
108
106
|
accuracy matters?
|
|
109
107
|
- Is the **freshness** consistent with the question?
|
|
@@ -112,11 +110,16 @@ the current `objective` and `gap`:
|
|
|
112
110
|
|
|
113
111
|
Decide:
|
|
114
112
|
|
|
115
|
-
- **Snippets sufficient** + still uncovered
|
|
116
|
-
|
|
117
|
-
- **Snippets sufficient** + all
|
|
118
|
-
|
|
113
|
+
- **Snippets sufficient** + still uncovered gaps ⇒ next call is another
|
|
114
|
+
`command: "search"` for the next gap.
|
|
115
|
+
- **Snippets sufficient** + all gaps covered (or task was simple) ⇒ stop
|
|
116
|
+
calling and go to Step 5 (synthesize), then answer.
|
|
119
117
|
- **Snippets insufficient** ⇒ go to Step 4.
|
|
118
|
+
- **Gap not filled but snippets are adjacent** (sector context, related
|
|
119
|
+
company, news mentioning the entity without the exact fact) ⇒ record the
|
|
120
|
+
facet as **Related** in your evidence ledger, refine once if worthwhile,
|
|
121
|
+
then continue with the next gap—do not treat "no exact hit" as "nothing
|
|
122
|
+
useful."
|
|
120
123
|
|
|
121
124
|
### Triggers that mean snippets are not sufficient
|
|
122
125
|
|
|
@@ -145,15 +148,14 @@ just to "be thorough" when a snippet already answers cleanly.
|
|
|
145
148
|
Issue a follow-up call with:
|
|
146
149
|
|
|
147
150
|
- `command: "read_urls"`.
|
|
148
|
-
-
|
|
149
|
-
<sub-question Y>".
|
|
151
|
+
- `phase: "target"` and a `gap` naming the missing detail you need from the page.
|
|
150
152
|
- `payload.urls` set to a **small, high-signal** subset (typically 1-3
|
|
151
153
|
URLs; pick complementary domains) of URLs from the `url` fields of the
|
|
152
154
|
SERP JSON you already received.
|
|
153
155
|
|
|
154
156
|
Once the page text comes back, do another sufficiency check. If the task is
|
|
155
|
-
complex and more
|
|
156
|
-
|
|
157
|
+
complex and more gaps remain, continue with the next `command: "search"`;
|
|
158
|
+
otherwise, go to Step 5.
|
|
157
159
|
|
|
158
160
|
### URL-selection rules
|
|
159
161
|
|
|
@@ -167,6 +169,29 @@ complex and more sub-questions remain, continue with the next
|
|
|
167
169
|
- For canonical-source topics, prioritize the **issuer's own page** (the
|
|
168
170
|
regulator, the company, the standards body) over secondary coverage.
|
|
169
171
|
|
|
172
|
+
## Step 5 — Synthesize, then answer
|
|
173
|
+
|
|
174
|
+
Merge your **evidence ledger** across all gaps before writing to the user.
|
|
175
|
+
|
|
176
|
+
**Confidence labels:** **Confirmed** (cited exact fact), **Partial** (cited
|
|
177
|
+
fragment), **Not found** (reasonable search/refinement tried), **Related**
|
|
178
|
+
(cited but does not answer the exact ask—say so explicitly).
|
|
179
|
+
|
|
180
|
+
**Answer structure for complex tasks:**
|
|
181
|
+
|
|
182
|
+
1. Direct answer (what citations support).
|
|
183
|
+
2. Evidence by facet (facet → finding → confidence → [sourceX]).
|
|
184
|
+
3. Gaps and limitations (what public web did not reveal; what you tried).
|
|
185
|
+
4. Related leads (indirect but useful, all cited).
|
|
186
|
+
5. Suggested next steps (optional: registry, paid DB, user documents).
|
|
187
|
+
|
|
188
|
+
**Partial / missing evidence:**
|
|
189
|
+
|
|
190
|
+
- Never answer with only "I couldn't find X" when tool results contain
|
|
191
|
+
related material—surface **Related leads** with citations.
|
|
192
|
+
- Never invent figures, ownership, or UBO claims.
|
|
193
|
+
- For simple single-fact tasks, a short cited answer is enough.
|
|
194
|
+
|
|
170
195
|
## Anti-patterns (do not do these)
|
|
171
196
|
|
|
172
197
|
- Packing several sub-questions into one bloated `query`. Split them across
|
|
@@ -180,6 +205,9 @@ complex and more sub-questions remain, continue with the next
|
|
|
180
205
|
plan stable for the whole task.
|
|
181
206
|
- Setting a `payload` shape that doesn't match `command` (e.g. `urls` under
|
|
182
207
|
a `"search"` command, or `query` under a `"read_urls"` command).
|
|
208
|
+
- Stopping research after one weak SERP on a diligence facet without
|
|
209
|
+
refinement or recording **Related** context.
|
|
210
|
+
- Dumping raw tool output without synthesis on multi-facet tasks.
|
|
183
211
|
|
|
184
212
|
## Worked examples
|
|
185
213
|
|
|
@@ -190,7 +218,7 @@ User: "What is the current US Fed funds target rate?"
|
|
|
190
218
|
```json
|
|
191
219
|
{
|
|
192
220
|
"command": "search",
|
|
193
|
-
"
|
|
221
|
+
"phase": "target",
|
|
194
222
|
"payload": {
|
|
195
223
|
"gap": "Current Fed funds target rate range and effective date.",
|
|
196
224
|
"query": "current Fed funds target rate"
|
|
@@ -209,7 +237,7 @@ User: "Read https://example.com/policy.pdf and summarize."
|
|
|
209
237
|
```json
|
|
210
238
|
{
|
|
211
239
|
"command": "read_urls",
|
|
212
|
-
"
|
|
240
|
+
"phase": "target",
|
|
213
241
|
"payload": {
|
|
214
242
|
"urls": ["https://example.com/policy.pdf"]
|
|
215
243
|
}
|
|
@@ -234,7 +262,7 @@ First call (cover sub-question 1):
|
|
|
234
262
|
```json
|
|
235
263
|
{
|
|
236
264
|
"command": "search",
|
|
237
|
-
"
|
|
265
|
+
"phase": "target",
|
|
238
266
|
"payload": {
|
|
239
267
|
"gap": "Stripe cross-border / international card transaction fee percentages.",
|
|
240
268
|
"query": "Stripe cross-border international card transaction fees pricing"
|
|
@@ -250,7 +278,7 @@ giving exact percentages. Follow up:
|
|
|
250
278
|
```json
|
|
251
279
|
{
|
|
252
280
|
"command": "read_urls",
|
|
253
|
-
"
|
|
281
|
+
"phase": "target",
|
|
254
282
|
"payload": {
|
|
255
283
|
"urls": ["https://stripe.com/pricing"]
|
|
256
284
|
}
|
|
@@ -259,3 +287,74 @@ giving exact percentages. Follow up:
|
|
|
259
287
|
|
|
260
288
|
Then resume with the next sub-question (`command: "search"` for Adyen
|
|
261
289
|
cross-border fees), and so on.
|
|
290
|
+
|
|
291
|
+
### Complex — Source of Wealth / private company profile
|
|
292
|
+
|
|
293
|
+
User: "I need a Source of Wealth picture for Acme Holding AG (Switzerland)—
|
|
294
|
+
revenues, ownership, and who runs it. It's not a listed company."
|
|
295
|
+
|
|
296
|
+
**Decomposed gaps (in reasoning):**
|
|
297
|
+
|
|
298
|
+
1. Legal identity and jurisdiction (Acme Holding AG, CH)
|
|
299
|
+
2. Revenue scale or turnover signals (public estimates, filings, press)
|
|
300
|
+
3. Ownership structure / shareholders / UBO signals
|
|
301
|
+
4. Key executives and board
|
|
302
|
+
5. Recent registry or filing references (if any public)
|
|
303
|
+
6. Adverse media or sanctions mentions
|
|
304
|
+
7. Industry / peer context if direct financials are sparse
|
|
305
|
+
|
|
306
|
+
**Call 1 — identity:**
|
|
307
|
+
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"command": "search",
|
|
311
|
+
"phase": "exploratory",
|
|
312
|
+
"payload": {
|
|
313
|
+
"gap": "Legal name, registered office, and jurisdiction for Acme Holding AG Switzerland.",
|
|
314
|
+
"query": "Acme Holding AG Switzerland company"
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Call 2 — revenue (after identity gap partially filled):**
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"command": "search",
|
|
324
|
+
"phase": "target",
|
|
325
|
+
"payload": {
|
|
326
|
+
"gap": "Revenue scale or turnover band for Acme Holding AG (latest available).",
|
|
327
|
+
"query": "Acme Holding AG Umsatz revenue turnover"
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
If snippets hedge or omit figures, follow with `read_urls` on the best SERP
|
|
333
|
+
(registry excerpt, annual report PDF, credible press).
|
|
334
|
+
|
|
335
|
+
**Call 3 — ownership:**
|
|
336
|
+
|
|
337
|
+
```json
|
|
338
|
+
{
|
|
339
|
+
"command": "search",
|
|
340
|
+
"phase": "target",
|
|
341
|
+
"payload": {
|
|
342
|
+
"gap": "Ownership structure or named shareholders for Acme Holding AG.",
|
|
343
|
+
"query": "Acme Holding AG shareholders ownership"
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Continue gaps 4–7 similarly. After each round, update the ledger
|
|
349
|
+
(Confirmed / Partial / Not found / Related).
|
|
350
|
+
|
|
351
|
+
**Final answer outline (Step 5):**
|
|
352
|
+
|
|
353
|
+
- **Direct answer:** Summarize only **Confirmed** items with [sourceX].
|
|
354
|
+
- **Evidence by facet:** Table or bullets per gap above.
|
|
355
|
+
- **Gaps and limitations:** e.g. "No public UBO disclosure found after …
|
|
356
|
+
searches."
|
|
357
|
+
- **Related leads:** e.g. parent group mentioned in press [source3]—labeled
|
|
358
|
+
**related, not confirmed** as UBO.
|
|
359
|
+
- **Next steps (optional):** Swiss commercial register extract, user-provided
|
|
360
|
+
financials.
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
Use `WebSearch` for up-to-date information from the web. It exposes two capabilities, picked per call via `command`. Each invocation performs **one** operation; complex user tasks are handled by **chaining** invocations.
|
|
2
|
-
|
|
3
|
-
#### `command: "search"` — search the web
|
|
4
|
-
|
|
5
|
-
Runs the configured search engine and returns SERP rows (URL, domain, title, snippet). It is **fast** and gives a **high-level read** of what relevant pages contain without paying the cost of crawling them.
|
|
6
|
-
|
|
7
|
-
Use it when:
|
|
8
|
-
|
|
9
|
-
- You need to **discover sources**: you don't yet have URLs and need the engine to surface candidates for a topic.
|
|
10
|
-
- The user's question can be answered from **snippets alone** — a definition, a status, a current value, a short factual lookup.
|
|
11
|
-
- You're at the **start of a complex task** and need to map out what's out there before deciding which pages are worth a deeper read.
|
|
12
|
-
- You want to **scope or sanity-check** a topic cheaply (does this entity / event / product even exist? how recent is the latest coverage?).
|
|
13
|
-
- You need to **cover a new gap / sub-question** in a multi-step task — issue another search rather than blindly fetching.
|
|
14
|
-
|
|
15
|
-
#### `command: "read_urls"` — fetch full page content
|
|
16
|
-
|
|
17
|
-
Crawls one or more URLs and returns the full-page text. It is **slower** than search but gives the **complete content** of the chosen pages, not just a snippet.
|
|
18
|
-
|
|
19
|
-
Use it when:
|
|
20
|
-
|
|
21
|
-
- The user **pasted a URL** or asked you to read a specific page — go straight here, do not search first.
|
|
22
|
-
- The task is **complex / in-depth** and needs more than a snippet: exact figures, full quotes, regulatory text, contract language, statute numbers, API specs, version numbers.
|
|
23
|
-
- The previous search returned **paraphrased / hedged snippets** ("around", "approximately", "is expected to", "reportedly") for a question that needs precision.
|
|
24
|
-
- The topic is **canonical-source-driven** — financial filings (10-K, 10-Q, earnings releases), regulator publications, official product docs, peer-reviewed papers, primary press releases — where the page itself is the source of truth.
|
|
25
|
-
- You found a **highly relevant** SERP hit but the title/snippet alone doesn't support the claim you want to make.
|
|
26
|
-
- The snippets from the previous "search" commands are relevant but do not fully answer the question or fill the gap and fetching the full page is necessary.
|
|
27
|
-
|
|
28
|
-
**Current date:** {{ date_string }}
|
|
29
|
-
|
|
30
|
-
### Balance exploration and exploitation
|
|
31
|
-
|
|
32
|
-
- **Explore first.** Start with `command: "search"` to get a cheap, high-level read of candidate pages. Cover one `gap` per call.
|
|
33
|
-
- **Refine, don't escalate prematurely.** If the first search did not fill the `gap`, issue another `command: "search"` with a refined query (different keywords, narrower entity, different timeframe) before reaching for `read_urls`.
|
|
34
|
-
- **Exploit when snippets aren't enough.** Switch to `command: "read_urls"` when snippets paraphrase / hedge, or the task needs exact figures, quotes, regulatory text, specs, or canonical-source content. Pick **1-3 high-signal URLs** from the most recent SERP — complementary domains preferred.
|
|
35
|
-
- **User-provided URLs go straight to fetch.** If the user pasted URL(s), the first call should be `command: "read_urls"`. Do not "search" for a URL the user already supplied.
|
|
36
|
-
- **Latency is a fair trade.** `read_urls` takes longer than `search`. That latency is acceptable on complex queries where the user expects depth — give them the answer that's actually grounded. Don't fetch when a snippet already answers the question; don't refuse to fetch when the snippet doesn't.
|
|
37
|
-
|
|
38
|
-
For the deeper explore-then-exploit playbook (snippet hedging triggers, canonical-source topics, sub-question decomposition, URL-selection rules, anti-patterns, worked examples), activate the `web-search-v3` skill before/while using this tool.
|
|
39
|
-
|
|
40
|
-
Tool arguments are defined by the tool schema; the live JSON schema comes from the tool definition.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_web_search-2026.24.0.dev1 → unique_web_search-2026.24.0.dev2}/src/unique_web_search/utils.py
RENAMED
|
File without changes
|