unique_web_search 2026.20.0.dev7__tar.gz → 2026.20.0.dev9__tar.gz

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