unique-web-search 2026.36.0.dev2__tar.gz → 2026.36.0.dev4__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.36.0.dev2 → unique_web_search-2026.36.0.dev4}/PKG-INFO +3 -3
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/pyproject.toml +3 -3
- unique_web_search-2026.36.0.dev4/src/unique_web_search/invocation_stats.py +31 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/service.py +7 -7
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/llm_guard_judge.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/llm_keyword_redact.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/llm_process.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/base_executor.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/executor.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/README.md +6 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/bing/runner.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/response_parsing.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/snippet_judge/service.py +2 -2
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/structured_llm.py +2 -2
- unique_web_search-2026.36.0.dev2/src/unique_web_search/invocation_stats.py +0 -113
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/README.md +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/client_settings.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/metrics.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/prompts.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/_registry.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/exceptions.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/prompts/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/prompts/guidelines.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/prompts/guidelines_with_keywords.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/prompts/rejection_response.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/argument_screening/service.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/client/proxy_config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/cleaning/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/cleaning/character_sanitize.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/cleaning/clean.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/cleaning/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/base.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_and_sanitize_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/judge_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/keyword_extract_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/page_context.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/sanitize_rules.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/system_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/prompts/user_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/settings.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/processing_strategies/truncate.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/content_processing/service.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/README.md +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/base.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/basic.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/firecrawl.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/jina.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/registry.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/tavily.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/url_safety/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/crawlers/utils.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/README.md +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/base_config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/context.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/modes.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/prompts/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/prompts/refine_query_system_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v1/strategy.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/executor.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/prompts/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/prompts/step_query_description.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v2/strategy.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/config.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/executor.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/prompts/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/prompts/tool_description.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/prompts/tool_description_for_system_prompt.j2 +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/executors/v3/strategy.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/helpers.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/message_log.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/proxy/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/proxy/bridge.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/proxy/mappers.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/query_elicitation.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/base.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/bing.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/brave.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/custom_api.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/google.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/perplexity.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/registry.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/google/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/bing/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/bing/client.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/bing/models.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/models.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/client.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/exceptions.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/gemini.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/utils/grounding/vertexai/response_handler.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/search_engine/vertexai.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/snippet_judge/__init__.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/snippet_judge/prompts.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/services/snippet_judge/schema.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/settings.py +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/skills/web-search-v3.md +0 -0
- {unique_web_search-2026.36.0.dev2 → unique_web_search-2026.36.0.dev4}/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.36.0.
|
|
3
|
+
Version: 2026.36.0.dev4
|
|
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>
|
|
@@ -16,7 +16,7 @@ Requires-Dist: tavily-python>=0.7.11,<1
|
|
|
16
16
|
Requires-Dist: unidecode>=1.4.0,<2
|
|
17
17
|
Requires-Dist: azure-ai-projects>=2.3,<3
|
|
18
18
|
Requires-Dist: azure-identity>=1.25.0,<2
|
|
19
|
-
Requires-Dist: unique-toolkit[monitoring]>=2026.36.0.
|
|
19
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.36.0.dev10,<2026.36.0rc0
|
|
20
20
|
Requires-Dist: azure-core>=1.36.0,<2
|
|
21
21
|
Requires-Dist: google-cloud-aiplatform>=1.128.0,<2
|
|
22
22
|
Requires-Dist: google-auth>=2.43.0,<3
|
|
@@ -25,7 +25,7 @@ Requires-Dist: rapidfuzz>=3.0.0,<4
|
|
|
25
25
|
Requires-Dist: httpx>=0.28.1
|
|
26
26
|
Requires-Dist: certifi>=2025.11.12
|
|
27
27
|
Requires-Dist: jinja2>=3.1.6
|
|
28
|
-
Requires-Dist: unique-search-proxy-core>=2026.36.0.
|
|
28
|
+
Requires-Dist: unique-search-proxy-core>=2026.36.0.dev3,<2026.36.0rc0
|
|
29
29
|
Requires-Dist: unique-search-proxy-sdk>=2026.36.0.dev1,<2026.36.0rc0
|
|
30
30
|
Requires-Dist: openai>=1.105.0,<3
|
|
31
31
|
Requires-Python: >=3.12, <4.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_web_search"
|
|
3
|
-
version = "2026.36.0.
|
|
3
|
+
version = "2026.36.0.dev4"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12,<4.0"
|
|
@@ -22,7 +22,7 @@ dependencies = [
|
|
|
22
22
|
"unidecode>=1.4.0,<2",
|
|
23
23
|
"azure-ai-projects>=2.3,<3",
|
|
24
24
|
"azure-identity>=1.25.0,<2",
|
|
25
|
-
"unique-toolkit[monitoring]>=2026.36.0.
|
|
25
|
+
"unique-toolkit[monitoring]>=2026.36.0.dev10,<2026.36.0rc0",
|
|
26
26
|
"azure-core>=1.36.0,<2",
|
|
27
27
|
"google-cloud-aiplatform>=1.128.0,<2",
|
|
28
28
|
"google-auth>=2.43.0,<3",
|
|
@@ -31,7 +31,7 @@ dependencies = [
|
|
|
31
31
|
"httpx>=0.28.1",
|
|
32
32
|
"certifi>=2025.11.12",
|
|
33
33
|
"jinja2>=3.1.6",
|
|
34
|
-
"unique-search-proxy-core>=2026.36.0.
|
|
34
|
+
"unique-search-proxy-core>=2026.36.0.dev3,<2026.36.0rc0",
|
|
35
35
|
"unique-search-proxy-sdk>=2026.36.0.dev1,<2026.36.0rc0",
|
|
36
36
|
"openai>=1.105.0,<3",
|
|
37
37
|
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Run-scoped collection of language-model invocation usage."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from unique_toolkit.language_model.invocation_stats import InvocationStatsCollector
|
|
6
|
+
|
|
7
|
+
collector = InvocationStatsCollector("web_search")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def record_vertex_response(
|
|
11
|
+
*,
|
|
12
|
+
model_name: str,
|
|
13
|
+
response: Any,
|
|
14
|
+
source: str,
|
|
15
|
+
) -> None:
|
|
16
|
+
"""Record Google GenAI usage metadata using toolkit token names."""
|
|
17
|
+
usage = getattr(response, "usage_metadata", None)
|
|
18
|
+
if usage is None:
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
collector.record_token_usage(
|
|
22
|
+
model_name=model_name,
|
|
23
|
+
usage={
|
|
24
|
+
"prompt_tokens": getattr(usage, "prompt_token_count", None),
|
|
25
|
+
"completion_tokens": getattr(usage, "candidates_token_count", None),
|
|
26
|
+
"total_tokens": getattr(usage, "total_token_count", None),
|
|
27
|
+
"reasoning_tokens": getattr(usage, "thoughts_token_count", None),
|
|
28
|
+
"cached_tokens": getattr(usage, "cached_content_token_count", None),
|
|
29
|
+
},
|
|
30
|
+
source=source,
|
|
31
|
+
)
|
|
@@ -8,14 +8,13 @@ from unique_search_proxy_core.param_policy.exposed_params import ExposedParams
|
|
|
8
8
|
from unique_search_proxy_core.search_engines.base import BaseSearchEngineConfig
|
|
9
9
|
from unique_toolkit._common.chunk_relevancy_sorter.service import ChunkRelevancySorter
|
|
10
10
|
from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
|
|
11
|
-
from unique_toolkit.agentic.feature_flags
|
|
12
|
-
feature_flags,
|
|
13
|
-
)
|
|
11
|
+
from unique_toolkit.agentic.feature_flags import FeatureFlagNames
|
|
14
12
|
from unique_toolkit.agentic.tools.factory import ToolFactory
|
|
15
13
|
from unique_toolkit.agentic.tools.schemas import ToolCallResponse
|
|
16
14
|
from unique_toolkit.agentic.tools.tool import (
|
|
17
15
|
Tool,
|
|
18
16
|
)
|
|
17
|
+
from unique_toolkit.experimental.resources.feature_flags import is_flag_enabled
|
|
19
18
|
from unique_toolkit.language_model.infos import LanguageModelInfo
|
|
20
19
|
from unique_toolkit.language_model.schemas import (
|
|
21
20
|
LanguageModelFunction,
|
|
@@ -24,7 +23,7 @@ from unique_toolkit.language_model.schemas import (
|
|
|
24
23
|
from unique_toolkit.monitoring import metric_scope
|
|
25
24
|
|
|
26
25
|
from unique_web_search.config import WebSearchConfig
|
|
27
|
-
from unique_web_search.invocation_stats import
|
|
26
|
+
from unique_web_search.invocation_stats import collector
|
|
28
27
|
from unique_web_search.metrics import tool_duration, tool_empty_results, tool_errors
|
|
29
28
|
from unique_web_search.schema import WebSearchDebugInfo
|
|
30
29
|
from unique_web_search.services.argument_screening import (
|
|
@@ -152,7 +151,7 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
152
151
|
|
|
153
152
|
@override
|
|
154
153
|
async def run(self, tool_call: LanguageModelFunction) -> ToolCallResponse:
|
|
155
|
-
with
|
|
154
|
+
with collector.scope() as invocation_stats:
|
|
156
155
|
try:
|
|
157
156
|
response = await self._run(tool_call)
|
|
158
157
|
except Exception as e:
|
|
@@ -311,8 +310,9 @@ class WebSearchTool(Tool[WebSearchConfig]):
|
|
|
311
310
|
async def _get_argument_screening_service_if_ff_enabled(
|
|
312
311
|
self,
|
|
313
312
|
) -> ArgumentScreeningService | None:
|
|
314
|
-
if not
|
|
315
|
-
|
|
313
|
+
if not await is_flag_enabled(
|
|
314
|
+
FeatureFlagNames.enable_web_search_argument_screening_un_18741,
|
|
315
|
+
company_id=self.company_id,
|
|
316
316
|
):
|
|
317
317
|
return None
|
|
318
318
|
|
|
@@ -6,7 +6,7 @@ from unique_toolkit._common.utils.jinja.render import render_template
|
|
|
6
6
|
from unique_toolkit.language_model import LanguageModelService
|
|
7
7
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
8
8
|
|
|
9
|
-
from unique_web_search.invocation_stats import
|
|
9
|
+
from unique_web_search.invocation_stats import collector
|
|
10
10
|
from unique_web_search.services.content_processing.processing_strategies.base import (
|
|
11
11
|
ProcessingStrategyKwargs,
|
|
12
12
|
WebSearchResult,
|
|
@@ -317,7 +317,7 @@ class LLMGuardJudge:
|
|
|
317
317
|
"web_search.content_processing.guard_judge_and_sanitize"
|
|
318
318
|
),
|
|
319
319
|
}
|
|
320
|
-
record_language_model_response(
|
|
320
|
+
collector.record_language_model_response(
|
|
321
321
|
model_name=self._config.language_model.name,
|
|
322
322
|
response=response,
|
|
323
323
|
source=source_by_response_model[response_model],
|
|
@@ -8,7 +8,7 @@ from unique_toolkit._common.utils.jinja.render import render_template
|
|
|
8
8
|
from unique_toolkit.language_model import LanguageModelService
|
|
9
9
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
10
10
|
|
|
11
|
-
from unique_web_search.invocation_stats import
|
|
11
|
+
from unique_web_search.invocation_stats import collector
|
|
12
12
|
from unique_web_search.services.content_processing.processing_strategies.base import (
|
|
13
13
|
ProcessingStrategyKwargs,
|
|
14
14
|
WebSearchResult,
|
|
@@ -181,7 +181,7 @@ class LLMKeywordRedact:
|
|
|
181
181
|
structured_output_model=KeywordRedactResponse,
|
|
182
182
|
structured_output_enforce_schema=True,
|
|
183
183
|
)
|
|
184
|
-
record_language_model_response(
|
|
184
|
+
collector.record_language_model_response(
|
|
185
185
|
model_name=self._config.language_model.name,
|
|
186
186
|
response=response,
|
|
187
187
|
source="web_search.content_processing.keyword_redact",
|
|
@@ -13,7 +13,7 @@ from unique_toolkit.language_model import (
|
|
|
13
13
|
)
|
|
14
14
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
15
15
|
|
|
16
|
-
from unique_web_search.invocation_stats import
|
|
16
|
+
from unique_web_search.invocation_stats import collector
|
|
17
17
|
from unique_web_search.services.content_processing.processing_strategies.base import (
|
|
18
18
|
ProcessingStrategyKwargs,
|
|
19
19
|
WebSearchResult,
|
|
@@ -317,7 +317,7 @@ class LLMProcess:
|
|
|
317
317
|
structured_output_model=LLMProcessorResponse,
|
|
318
318
|
structured_output_enforce_schema=True,
|
|
319
319
|
)
|
|
320
|
-
record_language_model_response(
|
|
320
|
+
collector.record_language_model_response(
|
|
321
321
|
model_name=self._config.language_model.name,
|
|
322
322
|
response=response,
|
|
323
323
|
source="web_search.content_processing.llm_process",
|
|
@@ -12,7 +12,7 @@ from unique_toolkit.content import ContentChunk
|
|
|
12
12
|
from unique_toolkit.language_model import LanguageModelFunction
|
|
13
13
|
from unique_toolkit.monitoring import metric_scope
|
|
14
14
|
|
|
15
|
-
from unique_web_search.invocation_stats import
|
|
15
|
+
from unique_web_search.invocation_stats import collector
|
|
16
16
|
from unique_web_search.metrics import llm_duration, llm_errors
|
|
17
17
|
from unique_web_search.schema import (
|
|
18
18
|
StepDebugInfo,
|
|
@@ -165,7 +165,7 @@ class BaseWebSearchExecutor(ABC, Generic[T]):
|
|
|
165
165
|
# usage to each ChunkRelevancy.relevancy.invocation_stats; merge it
|
|
166
166
|
# into the active WebSearch stats scope so it isn't dropped from
|
|
167
167
|
# token analytics (Internal Search does the same after its sort).
|
|
168
|
-
record_invocation_stats(
|
|
168
|
+
collector.record_invocation_stats(
|
|
169
169
|
invocation
|
|
170
170
|
for relevancy in sorted_chunks.relevancies
|
|
171
171
|
if relevancy.relevancy is not None
|
|
@@ -12,7 +12,7 @@ from unique_toolkit.language_model import LanguageModelFunction
|
|
|
12
12
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
13
13
|
from unique_toolkit.monitoring import metric_scope
|
|
14
14
|
|
|
15
|
-
from unique_web_search.invocation_stats import
|
|
15
|
+
from unique_web_search.invocation_stats import collector
|
|
16
16
|
from unique_web_search.metrics import (
|
|
17
17
|
crawl_duration,
|
|
18
18
|
crawl_errors,
|
|
@@ -125,7 +125,7 @@ async def query_generation_agent(
|
|
|
125
125
|
structured_output_model=structured_output_model,
|
|
126
126
|
structured_output_enforce_schema=True,
|
|
127
127
|
)
|
|
128
|
-
record_language_model_response(
|
|
128
|
+
collector.record_language_model_response(
|
|
129
129
|
model_name=language_model.name,
|
|
130
130
|
response=response,
|
|
131
131
|
source="web_search.query_refinement",
|
|
@@ -161,6 +161,12 @@ AZURE_IDENTITY_CREDENTIAL_TYPE=workload # or default
|
|
|
161
161
|
|
|
162
162
|
Requires GCP ADC / workload identity. Fields include `vertexai_model_name`, `generation_instructions`, `enable_entreprise_search`, `enable_redirect_resolution`, `requires_scraping`.
|
|
163
163
|
|
|
164
|
+
```bash
|
|
165
|
+
VERTEXAI_AGENT_DEFAULT_VERTEX_AI_MODEL_NAME=gemini-3-flash-preview
|
|
166
|
+
# ZDR tenants: pin "Enable Enterprise Search" on and disable the checkbox
|
|
167
|
+
VERTEXAI_AGENT_FORCE_ACTIVATE_ENTERPRISE_SEARCH=false
|
|
168
|
+
```
|
|
169
|
+
|
|
164
170
|
---
|
|
165
171
|
|
|
166
172
|
## Factory
|
|
@@ -24,7 +24,7 @@ from openai.types.responses.response_output_text import (
|
|
|
24
24
|
)
|
|
25
25
|
from openai.types.responses.response_text_delta_event import ResponseTextDeltaEvent
|
|
26
26
|
|
|
27
|
-
from unique_web_search.invocation_stats import
|
|
27
|
+
from unique_web_search.invocation_stats import collector
|
|
28
28
|
from unique_web_search.services.search_engine.schema import (
|
|
29
29
|
WebSearchResult,
|
|
30
30
|
)
|
|
@@ -284,7 +284,7 @@ async def _run_responses_agent(
|
|
|
284
284
|
if output_text and not emitted_text:
|
|
285
285
|
emitted_text = True
|
|
286
286
|
answer_parts.append(output_text)
|
|
287
|
-
record_token_usage(
|
|
287
|
+
collector.record_token_usage(
|
|
288
288
|
model_name=model,
|
|
289
289
|
usage=event.response.usage,
|
|
290
290
|
source="web_search.grounding.bing",
|
|
@@ -6,7 +6,7 @@ from unique_toolkit._common.validators import LMI
|
|
|
6
6
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
7
7
|
from unique_toolkit.language_model.service import LanguageModelService
|
|
8
8
|
|
|
9
|
-
from unique_web_search.invocation_stats import
|
|
9
|
+
from unique_web_search.invocation_stats import collector
|
|
10
10
|
from unique_web_search.services.search_engine.schema import WebSearchResult
|
|
11
11
|
from unique_web_search.services.search_engine.utils.grounding.models import (
|
|
12
12
|
GroundingSearchResults,
|
|
@@ -93,7 +93,7 @@ class LLMParserStrategy(ResponseParser):
|
|
|
93
93
|
structured_output_model=GroundingSearchResults,
|
|
94
94
|
structured_output_enforce_schema=True,
|
|
95
95
|
)
|
|
96
|
-
record_language_model_response(
|
|
96
|
+
collector.record_language_model_response(
|
|
97
97
|
model_name=self.llm.name,
|
|
98
98
|
response=llm_response,
|
|
99
99
|
source="web_search.grounding.response_parser",
|
|
@@ -9,7 +9,7 @@ from unique_toolkit._common.validators import LMI
|
|
|
9
9
|
from unique_toolkit.language_model import LanguageModelService
|
|
10
10
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
11
11
|
|
|
12
|
-
from unique_web_search.invocation_stats import
|
|
12
|
+
from unique_web_search.invocation_stats import collector
|
|
13
13
|
from unique_web_search.services.helpers import extract_registered_domain
|
|
14
14
|
from unique_web_search.services.search_engine.schema import (
|
|
15
15
|
WebSearchResult,
|
|
@@ -100,7 +100,7 @@ async def score_and_explain(
|
|
|
100
100
|
structured_output_model=SnippetJudgeResponse,
|
|
101
101
|
structured_output_enforce_schema=True,
|
|
102
102
|
)
|
|
103
|
-
record_language_model_response(
|
|
103
|
+
collector.record_language_model_response(
|
|
104
104
|
model_name=language_model.name,
|
|
105
105
|
response=response,
|
|
106
106
|
source="web_search.snippet_judge",
|
|
@@ -7,7 +7,7 @@ from unique_toolkit._common.validators import LMI
|
|
|
7
7
|
from unique_toolkit.language_model import LanguageModelService
|
|
8
8
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
9
9
|
|
|
10
|
-
from unique_web_search.invocation_stats import
|
|
10
|
+
from unique_web_search.invocation_stats import collector
|
|
11
11
|
|
|
12
12
|
T = TypeVar("T", bound=BaseModel)
|
|
13
13
|
|
|
@@ -40,7 +40,7 @@ async def complete_structured_llm(
|
|
|
40
40
|
structured_output_model=response_model,
|
|
41
41
|
structured_output_enforce_schema=structured_output_enforce_schema,
|
|
42
42
|
)
|
|
43
|
-
record_language_model_response(
|
|
43
|
+
collector.record_language_model_response(
|
|
44
44
|
model_name=language_model.name,
|
|
45
45
|
response=response,
|
|
46
46
|
source=invocation_source,
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
"""Run-scoped collection of language-model invocation usage."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
from collections.abc import Iterable, Iterator
|
|
5
|
-
from contextlib import contextmanager
|
|
6
|
-
from contextvars import ContextVar, Token
|
|
7
|
-
from typing import Any
|
|
8
|
-
|
|
9
|
-
from pydantic import ValidationError
|
|
10
|
-
from unique_toolkit.language_model.invocation_stats import LanguageModelInvocationStats
|
|
11
|
-
from unique_toolkit.language_model.schemas import LanguageModelTokenUsage
|
|
12
|
-
|
|
13
|
-
_LOGGER = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
_CURRENT_INVOCATION_STATS: ContextVar[list[LanguageModelInvocationStats] | None] = (
|
|
16
|
-
ContextVar("web_search_invocation_stats", default=None)
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@contextmanager
|
|
21
|
-
def invocation_stats_scope() -> Iterator[list[LanguageModelInvocationStats]]:
|
|
22
|
-
"""Collect stats for one WebSearch run and isolate concurrent runs."""
|
|
23
|
-
invocation_stats: list[LanguageModelInvocationStats] = []
|
|
24
|
-
token: Token[list[LanguageModelInvocationStats] | None] = (
|
|
25
|
-
_CURRENT_INVOCATION_STATS.set(invocation_stats)
|
|
26
|
-
)
|
|
27
|
-
try:
|
|
28
|
-
yield invocation_stats
|
|
29
|
-
finally:
|
|
30
|
-
_CURRENT_INVOCATION_STATS.reset(token)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def record_invocation_stats(
|
|
34
|
-
invocation_stats: Iterable[LanguageModelInvocationStats],
|
|
35
|
-
) -> None:
|
|
36
|
-
"""Record already-built invocation stats when a run scope is active.
|
|
37
|
-
|
|
38
|
-
Used for usage produced by nested dependencies that hand back
|
|
39
|
-
``LanguageModelInvocationStats`` objects directly (e.g. the chunk relevancy
|
|
40
|
-
sorter attaching per-chunk stats on its result), rather than a raw provider
|
|
41
|
-
usage payload.
|
|
42
|
-
"""
|
|
43
|
-
current_invocation_stats = _CURRENT_INVOCATION_STATS.get()
|
|
44
|
-
if current_invocation_stats is not None:
|
|
45
|
-
current_invocation_stats.extend(invocation_stats)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def record_token_usage(
|
|
49
|
-
*,
|
|
50
|
-
model_name: str,
|
|
51
|
-
usage: Any,
|
|
52
|
-
source: str,
|
|
53
|
-
) -> None:
|
|
54
|
-
"""Record provider usage when both a run scope and usage are available."""
|
|
55
|
-
invocation_stats = _CURRENT_INVOCATION_STATS.get()
|
|
56
|
-
if invocation_stats is None or usage is None:
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
try:
|
|
60
|
-
token_usage = LanguageModelTokenUsage.model_validate(usage)
|
|
61
|
-
except ValidationError:
|
|
62
|
-
_LOGGER.warning(
|
|
63
|
-
"Unable to parse Web Search token usage for %s",
|
|
64
|
-
source,
|
|
65
|
-
exc_info=True,
|
|
66
|
-
)
|
|
67
|
-
return
|
|
68
|
-
|
|
69
|
-
invocation_stats.append(
|
|
70
|
-
LanguageModelInvocationStats.from_usage(
|
|
71
|
-
model_name=model_name,
|
|
72
|
-
token_usage=token_usage,
|
|
73
|
-
source=source,
|
|
74
|
-
)
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def record_language_model_response(
|
|
79
|
-
*,
|
|
80
|
-
model_name: str,
|
|
81
|
-
response: Any,
|
|
82
|
-
source: str,
|
|
83
|
-
) -> None:
|
|
84
|
-
"""Record usage from a Unique Toolkit language-model response."""
|
|
85
|
-
record_token_usage(
|
|
86
|
-
model_name=model_name,
|
|
87
|
-
usage=getattr(response, "usage", None),
|
|
88
|
-
source=source,
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def record_vertex_response(
|
|
93
|
-
*,
|
|
94
|
-
model_name: str,
|
|
95
|
-
response: Any,
|
|
96
|
-
source: str,
|
|
97
|
-
) -> None:
|
|
98
|
-
"""Record Google GenAI usage metadata using toolkit token names."""
|
|
99
|
-
usage = getattr(response, "usage_metadata", None)
|
|
100
|
-
if usage is None:
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
record_token_usage(
|
|
104
|
-
model_name=model_name,
|
|
105
|
-
usage={
|
|
106
|
-
"prompt_tokens": getattr(usage, "prompt_token_count", None),
|
|
107
|
-
"completion_tokens": getattr(usage, "candidates_token_count", None),
|
|
108
|
-
"total_tokens": getattr(usage, "total_token_count", None),
|
|
109
|
-
"reasoning_tokens": getattr(usage, "thoughts_token_count", None),
|
|
110
|
-
"cached_tokens": getattr(usage, "cached_content_token_count", None),
|
|
111
|
-
},
|
|
112
|
-
source=source,
|
|
113
|
-
)
|
|
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.36.0.dev2 → unique_web_search-2026.36.0.dev4}/src/unique_web_search/utils.py
RENAMED
|
File without changes
|