unique-search-proxy 2026.44.0.dev12__tar.gz → 2026.44.0.dev13__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 (120) hide show
  1. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/PKG-INFO +4 -4
  2. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/README.md +2 -2
  3. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/pyproject.toml +2 -2
  4. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/app.py +4 -0
  5. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/generator/schema.py +10 -0
  6. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/generator/template.py +66 -7
  7. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/metadata.py +9 -1
  8. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/app.py +1 -0
  9. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/client.py +2 -2
  10. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/__init__.py +0 -0
  11. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/__init__.py +0 -0
  12. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/__init__.py +0 -0
  13. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/health.py +0 -0
  14. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/v1/__init__.py +0 -0
  15. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/v1/agent_search.py +0 -0
  16. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/v1/configuration.py +0 -0
  17. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/v1/context_headers.py +0 -0
  18. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/v1/crawl.py +0 -0
  19. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/v1/openapi_examples.py +0 -0
  20. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/api/v1/search.py +0 -0
  21. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/context.py +0 -0
  22. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/__init__.py +0 -0
  23. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/__init__.py +0 -0
  24. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/bing/cleanup.py +0 -0
  25. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/bing/client.py +0 -0
  26. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/bing/runner.py +0 -0
  27. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/bing/service.py +0 -0
  28. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/factory.py +0 -0
  29. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/service_base.py +0 -0
  30. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/structured_output.py +0 -0
  31. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/vertexai/client.py +0 -0
  32. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/vertexai/gemini.py +0 -0
  33. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/vertexai/redirects.py +0 -0
  34. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/agent_engines/vertexai/service.py +0 -0
  35. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/client/__init__.py +0 -0
  36. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/client/azure_transport.py +0 -0
  37. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/client/credentials.py +0 -0
  38. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/client/service.py +0 -0
  39. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawl_limiter.py +0 -0
  40. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/__init__.py +0 -0
  41. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/__init__.py +0 -0
  42. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/__init__.py +0 -0
  43. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/errors.py +0 -0
  44. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/html_markdown.py +0 -0
  45. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/__init__.py +0 -0
  46. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/html.py +0 -0
  47. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/pdf.py +0 -0
  48. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/plain_text.py +0 -0
  49. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/processing/registry.py +0 -0
  50. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/service.py +0 -0
  51. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/settings.py +0 -0
  52. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/basic/user_agent.py +0 -0
  53. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/factory.py +0 -0
  54. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/firecrawl/polling.py +0 -0
  55. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/firecrawl/request_body.py +0 -0
  56. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/firecrawl/service.py +0 -0
  57. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/jina/request_body.py +0 -0
  58. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/jina/service.py +0 -0
  59. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/pinned_egress.py +0 -0
  60. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/tavily/request_body.py +0 -0
  61. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/crawlers/tavily/service.py +0 -0
  62. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/provider_response.py +0 -0
  63. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/providers.py +0 -0
  64. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/registry.py +0 -0
  65. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/__init__.py +0 -0
  66. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/brave/__init__.py +0 -0
  67. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/brave/pagination.py +0 -0
  68. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/brave/query_params.py +0 -0
  69. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/brave/service.py +0 -0
  70. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/custom_api/__init__.py +0 -0
  71. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/custom_api/service.py +0 -0
  72. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/descriptor.py +0 -0
  73. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/factory.py +0 -0
  74. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/google/__init__.py +0 -0
  75. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/google/pagination.py +0 -0
  76. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/google/query_params.py +0 -0
  77. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/google/service.py +0 -0
  78. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/pagination.py +0 -0
  79. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/perplexity/__init__.py +0 -0
  80. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/perplexity/request_body.py +0 -0
  81. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/perplexity/service.py +0 -0
  82. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/search_engines/service_base.py +0 -0
  83. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/url_safety/__init__.py +0 -0
  84. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/core/url_safety/gate.py +0 -0
  85. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/error_handlers.py +0 -0
  86. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/__init__.py +0 -0
  87. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/generator/__init__.py +0 -0
  88. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/generator/introspect.py +0 -0
  89. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/generator/templates/provider_values_yaml.j2 +0 -0
  90. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/generator/values_yaml.py +0 -0
  91. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/registry.py +0 -0
  92. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/helm/url_safety_registration.py +0 -0
  93. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/logging_config.py +0 -0
  94. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/middleware/context.py +0 -0
  95. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/monitoring/__init__.py +0 -0
  96. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/monitoring/metrics.py +0 -0
  97. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/monitoring/setup.py +0 -0
  98. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/presets/__init__.py +0 -0
  99. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/presets/common.py +0 -0
  100. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/presets/crawl.py +0 -0
  101. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/presets/search.py +0 -0
  102. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/presets/types.py +0 -0
  103. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/__init__.py +0 -0
  104. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/base.py +0 -0
  105. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/monitoring.py +0 -0
  106. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/__init__.py +0 -0
  107. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/base.py +0 -0
  108. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/bing_agent.py +0 -0
  109. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/brave.py +0 -0
  110. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/firecrawl.py +0 -0
  111. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/google.py +0 -0
  112. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/jina.py +0 -0
  113. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/perplexity.py +0 -0
  114. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/tavily.py +0 -0
  115. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/providers/vertexai_agent.py +0 -0
  116. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/request_limits.py +0 -0
  117. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/settings/secret_str.py +0 -0
  118. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/startup_report.py +0 -0
  119. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/utils/__init__.py +0 -0
  120. {unique_search_proxy-2026.44.0.dev12 → unique_search_proxy-2026.44.0.dev13}/unique_search_proxy_client/web/utils/url.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: unique-search-proxy
3
- Version: 2026.44.0.dev12
3
+ Version: 2026.44.0.dev13
4
4
  Summary: Web Search Proxy implementation
5
5
  Author: ThePhilAz
6
6
  Author-email: ThePhilAz <rami.azouz@philico.com>
@@ -20,7 +20,7 @@ Requires-Dist: certifi>=2025.11.12,<2027
20
20
  Requires-Dist: google-genai>=1.73.0,<2
21
21
  Requires-Dist: google-auth>=2.43.0,<3
22
22
  Requires-Dist: jinja2>=3.1.6,<4
23
- Requires-Dist: unique-toolkit[monitoring]>=2026.44.0.dev9,<2026.44.0rc0
23
+ Requires-Dist: unique-toolkit[monitoring]>=2026.44.0.dev10,<2026.44.0rc0
24
24
  Requires-Dist: unique-search-proxy-core>=2026.44.0.dev9,<2026.44.0rc0
25
25
  Requires-Dist: openai>=1.105.0,<3
26
26
  Requires-Python: >=3.12
@@ -120,7 +120,7 @@ Built-in providers register in `register_builtin_providers()` during `create_app
120
120
  | `POST /v1/agent-search/stream` | Same, streamed as SSE (`delta` + `done`) |
121
121
  | `POST /v1/crawl` | Crawl URLs (flat body: `crawler`, `urls`, `timeout`, …) |
122
122
  | `GET /metrics` | Prometheus (when enabled) |
123
- | `/docs` | Swagger UI with preset examples |
123
+ | `/docs` | Swagger UI with preset examples (only when `EXPOSE_DOCS=true`) |
124
124
 
125
125
  OpenAPI spec: `openapi.json` (input for [SDK codegen](../unique_search_proxy_sdk/README.md)).
126
126
 
@@ -310,7 +310,7 @@ uv run python scripts/generate_sdk.py
310
310
  ## 8. Dev testing
311
311
 
312
312
  1. Start the server and configure `.env` (`.env.example` sets `REQUIRE_CONTEXT_HEADERS=false` for local use; production keeps enforcement enabled).
313
- 2. **Swagger** — `/docs` → **Try it out** on `/v1/search` or `/v1/crawl` → pick an **Examples** preset. Context headers default to `local` in the UI.
313
+ 2. **Swagger** (if `EXPOSE_DOCS=true`) — `/docs` → **Try it out** on `/v1/search` or `/v1/crawl` → pick an **Examples** preset. Context headers default to `local` in the UI.
314
314
  3. **CLI** — same presets from the terminal (`scripts/try_presets.py` sends the same local context headers):
315
315
 
316
316
  ```bash
@@ -92,7 +92,7 @@ Built-in providers register in `register_builtin_providers()` during `create_app
92
92
  | `POST /v1/agent-search/stream` | Same, streamed as SSE (`delta` + `done`) |
93
93
  | `POST /v1/crawl` | Crawl URLs (flat body: `crawler`, `urls`, `timeout`, …) |
94
94
  | `GET /metrics` | Prometheus (when enabled) |
95
- | `/docs` | Swagger UI with preset examples |
95
+ | `/docs` | Swagger UI with preset examples (only when `EXPOSE_DOCS=true`) |
96
96
 
97
97
  OpenAPI spec: `openapi.json` (input for [SDK codegen](../unique_search_proxy_sdk/README.md)).
98
98
 
@@ -282,7 +282,7 @@ uv run python scripts/generate_sdk.py
282
282
  ## 8. Dev testing
283
283
 
284
284
  1. Start the server and configure `.env` (`.env.example` sets `REQUIRE_CONTEXT_HEADERS=false` for local use; production keeps enforcement enabled).
285
- 2. **Swagger** — `/docs` → **Try it out** on `/v1/search` or `/v1/crawl` → pick an **Examples** preset. Context headers default to `local` in the UI.
285
+ 2. **Swagger** (if `EXPOSE_DOCS=true`) — `/docs` → **Try it out** on `/v1/search` or `/v1/crawl` → pick an **Examples** preset. Context headers default to `local` in the UI.
286
286
  3. **CLI** — same presets from the terminal (`scripts/try_presets.py` sends the same local context headers):
287
287
 
288
288
  ```bash
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "unique-search-proxy"
3
- version = "2026.44.0.dev12"
3
+ version = "2026.44.0.dev13"
4
4
  description = "Web Search Proxy implementation"
5
5
  authors = [{ name = "ThePhilAz", email = "rami.azouz@philico.com" }]
6
6
  readme = "README.md"
@@ -22,7 +22,7 @@ dependencies = [
22
22
  "google-genai>=1.73.0,<2",
23
23
  "google-auth>=2.43.0,<3",
24
24
  "jinja2>=3.1.6,<4",
25
- "unique-toolkit[monitoring]>=2026.44.0.dev9,<2026.44.0rc0",
25
+ "unique-toolkit[monitoring]>=2026.44.0.dev10,<2026.44.0rc0",
26
26
  "unique-search-proxy-core>=2026.44.0.dev9,<2026.44.0rc0",
27
27
  "openai>=1.105.0,<3",
28
28
  ]
@@ -28,6 +28,7 @@ from unique_search_proxy_client.web.logging_config import (
28
28
  )
29
29
  from unique_search_proxy_client.web.middleware.context import RequestContextMiddleware
30
30
  from unique_search_proxy_client.web.monitoring import setup_prometheus
31
+ from unique_search_proxy_client.web.settings.app import app_settings
31
32
  from unique_search_proxy_client.web.settings.request_limits import (
32
33
  request_limits_settings,
33
34
  )
@@ -92,6 +93,9 @@ def create_app() -> FastAPI:
92
93
  ),
93
94
  version="0.2.0",
94
95
  lifespan=lifespan,
96
+ docs_url="/docs" if app_settings.expose_docs else None,
97
+ redoc_url="/redoc" if app_settings.expose_docs else None,
98
+ openapi_url="/openapi.json" if app_settings.expose_docs else None,
95
99
  swagger_ui_parameters={
96
100
  "defaultModelsExpandDepth": 1,
97
101
  "defaultModelExpandDepth": 2,
@@ -129,6 +129,16 @@ def build_additional_schema(groups: tuple[HelmSettingsGroup, ...]) -> dict[str,
129
129
  for group in groups
130
130
  if group.helm_key is not None
131
131
  }
132
+ properties["networkPolicy"] = {
133
+ "properties": {
134
+ "enabled": {"type": "boolean", "default": True},
135
+ "allowDisabled": {
136
+ "type": "boolean",
137
+ "default": False,
138
+ "description": "Allow networkPolicy.enabled=false. Set only if another control restricts who can reach search-proxy.",
139
+ },
140
+ }
141
+ }
132
142
  return {
133
143
  "$schema": "https://json-schema.org/draft-07/schema#",
134
144
  "properties": properties,
@@ -7,6 +7,7 @@ from unique_search_proxy_client.web.helm.generator.introspect import (
7
7
  from unique_search_proxy_client.web.helm.metadata import (
8
8
  EgressDomainWildcard,
9
9
  EgressEndpointField,
10
+ EgressProxyHost,
10
11
  )
11
12
  from unique_search_proxy_client.web.helm.registry import HelmSettingsGroup
12
13
 
@@ -199,25 +200,83 @@ def _emit_domain_wildcard_egress(
199
200
  ]
200
201
 
201
202
 
203
+ def _proxy_values_paths(
204
+ group: HelmSettingsGroup, egress: EgressProxyHost
205
+ ) -> tuple[str, str] | None:
206
+ host = _find_helm_field(group, egress.host_field)
207
+ port = _find_helm_field(group, egress.port_field)
208
+ if host is None or port is None:
209
+ return None
210
+ root = f".Values.{group.helm_key}"
211
+ return (
212
+ f"{root}.{host.section}.{host.helm_name}",
213
+ f"{root}.{port.section}.{port.helm_name}",
214
+ )
215
+
216
+
217
+ def _emit_proxy_host_egress(
218
+ group: HelmSettingsGroup,
219
+ egress: EgressProxyHost,
220
+ ) -> list[str]:
221
+ paths = _proxy_values_paths(group, egress)
222
+ if paths is None:
223
+ return []
224
+
225
+ host, port = paths
226
+ ipv4_octet = r"(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})"
227
+ return [
228
+ f"{{{{ if and {host} {port} }}}}",
229
+ f"{{{{- $host := {host} -}}}}",
230
+ f"{{{{- $port := {port} -}}}}",
231
+ r'{{- if not (and (kindIs "string" $host) (regexMatch "^[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?$" $host)) -}}',
232
+ '{{- fail "httpClient.connection.proxyHost must be a plain hostname or IPv4 address (no scheme, port, path or IPv6 literal)." -}}',
233
+ "{{- end -}}",
234
+ '{{- if not (regexMatch "^[0-9]+$" (toString $port)) -}}',
235
+ '{{- fail "httpClient.connection.proxyPort must be a number." -}}',
236
+ "{{- else if or (lt (int $port) 1) (gt (int $port) 65535) -}}",
237
+ '{{- fail "httpClient.connection.proxyPort must be between 1 and 65535." -}}',
238
+ "{{- end -}}",
239
+ f'{{{{- if regexMatch "^({ipv4_octet}\\\\.){{3}}{ipv4_octet}$" $host }}}}',
240
+ "- toCIDR:",
241
+ ' - {{ printf "%s/32" $host | quote }}',
242
+ "{{- else }}",
243
+ '{{- if regexMatch "^[0-9.]+$" $host -}}',
244
+ '{{- fail "httpClient.connection.proxyHost is not a valid IPv4 address." -}}',
245
+ "{{- end }}",
246
+ "- toFQDNs:",
247
+ " - matchName: {{ $host | quote }}",
248
+ "{{- end }}",
249
+ " toPorts:",
250
+ " - ports:",
251
+ " - port: {{ $port | quote }}",
252
+ " protocol: TCP",
253
+ "{{- end }}",
254
+ ]
255
+
256
+
202
257
  def _emit_egress_block(group: HelmSettingsGroup) -> list[str]:
203
258
  egress = group.egress
204
259
  if isinstance(egress, EgressEndpointField):
205
260
  return _emit_endpoint_field_egress(group, egress)
206
261
  if isinstance(egress, EgressDomainWildcard):
207
262
  return _emit_domain_wildcard_egress(group, egress)
263
+ if isinstance(egress, EgressProxyHost):
264
+ return _emit_proxy_host_egress(group, egress)
208
265
  return []
209
266
 
210
267
 
268
+ def _egress_active_check(group: HelmSettingsGroup) -> str:
269
+ if isinstance(group.egress, EgressProxyHost):
270
+ paths = _proxy_values_paths(group, group.egress)
271
+ if paths is not None:
272
+ return f"(and {paths[0]} {paths[1]})"
273
+ return f"(and .Values.{group.helm_key} .Values.{group.helm_key}.enabled)"
274
+
275
+
211
276
  def _emit_has_rules_block(groups: tuple[HelmSettingsGroup, ...]) -> list[str]:
212
277
  checks = [
213
- f"(and .Values.{group.helm_key} .Values.{group.helm_key}.enabled)"
214
- for group in groups
215
- if group.egress is not None
278
+ _egress_active_check(group) for group in groups if group.egress is not None
216
279
  ]
217
- if not checks:
218
- return ["{{/* no auto egress rules */}}"]
219
- if len(checks) == 1:
220
- return [f"{{{{- if {checks[0]} -}}}}true{{{{- end -}}}}"]
221
280
  joined = " ".join(checks)
222
281
  return [f"{{{{- if or {joined} -}}}}true{{{{- end -}}}}"]
223
282
 
@@ -43,7 +43,15 @@ class EgressDomainWildcard:
43
43
  port: str = "443"
44
44
 
45
45
 
46
- EgressRule = EgressEndpointField | EgressDomainWildcard
46
+ @dataclass(frozen=True)
47
+ class EgressProxyHost:
48
+ """Proxy egress when host and port are set: /32 ``toCIDR`` for IPv4, else ``toFQDNs``."""
49
+
50
+ host_field: str = "proxy_host"
51
+ port_field: str = "proxy_port"
52
+
53
+
54
+ EgressRule = EgressEndpointField | EgressDomainWildcard | EgressProxyHost
47
55
  """How a settings group's outbound egress hosts are derived from its settings."""
48
56
 
49
57
  _DEFAULT_EGRESS: EgressRule = EgressEndpointField()
@@ -15,6 +15,7 @@ APP_ENV_PREFIX = ""
15
15
  )
16
16
  class AppSettings(BaseSettings):
17
17
  require_context_headers: bool = True
18
+ expose_docs: bool = False
18
19
 
19
20
 
20
21
  def get_app_settings() -> AppSettings:
@@ -7,7 +7,7 @@ from unique_search_proxy_core.http_client import (
7
7
  ProxyUsernameSource,
8
8
  )
9
9
 
10
- from unique_search_proxy_client.web.helm.metadata import helm_settings
10
+ from unique_search_proxy_client.web.helm.metadata import EgressProxyHost, helm_settings
11
11
  from unique_search_proxy_client.web.settings.base import get_settings
12
12
 
13
13
  HTTP_CLIENT_ENV_PREFIX = "HTTP_CLIENT_"
@@ -21,7 +21,7 @@ HTTP_CLIENT_ENV_PREFIX = "HTTP_CLIENT_"
21
21
  # the proxy fields, not by a chart-only toggle. Gating it would silently drop
22
22
  # proxy config from overlays that set it without ``enabled: true``.
23
23
  gated=False,
24
- egress=None,
24
+ egress=EgressProxyHost(),
25
25
  env_prefix=HTTP_CLIENT_ENV_PREFIX,
26
26
  sections={
27
27
  "tuning": [