unique-search-proxy-core 2026.44.0.dev0__tar.gz → 2026.44.0.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/PKG-INFO +2 -2
  2. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/pyproject.toml +2 -2
  3. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/http_client/__init__.py +2 -0
  4. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/http_client/client.py +51 -7
  5. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/README.md +0 -0
  6. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/__init__.py +0 -0
  7. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/__init__.py +0 -0
  8. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/base.py +0 -0
  9. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/bing/__init__.py +0 -0
  10. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/bing/enums.py +0 -0
  11. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/bing/grounding.py +0 -0
  12. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/bing/schema.py +0 -0
  13. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/bing/settings.py +0 -0
  14. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/config_types.py +0 -0
  15. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/output_schema.py +0 -0
  16. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/resolve.py +0 -0
  17. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/response_parsing.py +0 -0
  18. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/vertexai/__init__.py +0 -0
  19. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/vertexai/schema.py +0 -0
  20. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/agent_engines/vertexai/settings.py +0 -0
  21. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/context.py +0 -0
  22. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/__init__.py +0 -0
  23. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/base.py +0 -0
  24. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/basic/__init__.py +0 -0
  25. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/basic/content_types.py +0 -0
  26. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/basic/processing/policy.py +0 -0
  27. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/basic/schema.py +0 -0
  28. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/config_types.py +0 -0
  29. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/firecrawl/schema.py +0 -0
  30. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/jina/schema.py +0 -0
  31. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/crawlers/tavily/schema.py +0 -0
  32. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/errors.py +0 -0
  33. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/http_client/credentials.py +0 -0
  34. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/http_client/secrets.py +0 -0
  35. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/http_client/settings.py +0 -0
  36. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/logging.py +0 -0
  37. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/param_policy/__init__.py +0 -0
  38. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/param_policy/annotations.py +0 -0
  39. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/param_policy/derive.py +0 -0
  40. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/param_policy/exposable_config.py +0 -0
  41. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/param_policy/exposable_param.py +0 -0
  42. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/param_policy/exposed_params.py +0 -0
  43. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/param_policy/request_base.py +0 -0
  44. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/providers/schema.py +0 -0
  45. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/schema.py +0 -0
  46. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/__init__.py +0 -0
  47. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/base.py +0 -0
  48. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/brave/__init__.py +0 -0
  49. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/brave/schema.py +0 -0
  50. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/config_types.py +0 -0
  51. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/google/__init__.py +0 -0
  52. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/google/schema.py +0 -0
  53. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/perplexity/__init__.py +0 -0
  54. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/search_engines/perplexity/schema.py +0 -0
  55. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/__init__.py +0 -0
  56. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/dns.py +0 -0
  57. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/egress.py +0 -0
  58. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/models.py +0 -0
  59. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/netloc.py +0 -0
  60. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/policy.py +0 -0
  61. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/redirect.py +0 -0
  62. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/resolver.py +0 -0
  63. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/service.py +0 -0
  64. {unique_search_proxy_core-2026.44.0.dev0 → unique_search_proxy_core-2026.44.0.dev2}/unique_search_proxy_core/url_safety/settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: unique-search-proxy-core
3
- Version: 2026.44.0.dev0
3
+ Version: 2026.44.0.dev2
4
4
  Summary: Shared Pydantic types for the Unique Search Proxy API
5
5
  Author: ThePhilAz
6
6
  Author-email: ThePhilAz <rami.azouz@philico.com>
@@ -8,7 +8,7 @@ Requires-Dist: httpx>=0.28.0,<0.29
8
8
  Requires-Dist: pydantic>=2.12.5,<3.0.0
9
9
  Requires-Dist: pydantic-settings>=2.10.1,<3
10
10
  Requires-Dist: pyhumps>=3.8.0,<4
11
- Requires-Dist: unique-toolkit[monitoring]>=2026.44.0.dev0,<2026.44.0rc0
11
+ Requires-Dist: unique-toolkit[monitoring]>=2026.44.0.dev7,<2026.44.0rc0
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
14
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "unique-search-proxy-core"
3
- version = "2026.44.0.dev0"
3
+ version = "2026.44.0.dev2"
4
4
  description = "Shared Pydantic types for the Unique Search Proxy API"
5
5
  authors = [{ name = "ThePhilAz", email = "rami.azouz@philico.com" }]
6
6
  readme = "README.md"
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "pydantic>=2.12.5,<3.0.0",
11
11
  "pydantic-settings>=2.10.1,<3",
12
12
  "pyhumps>=3.8.0,<4",
13
- "unique-toolkit[monitoring]>=2026.44.0.dev0,<2026.44.0rc0",
13
+ "unique-toolkit[monitoring]>=2026.44.0.dev7,<2026.44.0rc0",
14
14
 
15
15
  ]
16
16
 
@@ -5,6 +5,7 @@ from unique_search_proxy_core.http_client.client import (
5
5
  EgressRoute,
6
6
  HttpClientRegistry,
7
7
  ProxiedRoute,
8
+ ResolvedEgress,
8
9
  async_client_factory,
9
10
  build_async_client,
10
11
  build_route,
@@ -38,6 +39,7 @@ __all__ = [
38
39
  "ProxyProtocol",
39
40
  "ProxySettings",
40
41
  "ProxyUsernameSource",
42
+ "ResolvedEgress",
41
43
  "SettingsProxyCredentials",
42
44
  "UserMetadataProxyCredentials",
43
45
  "async_client_factory",
@@ -57,6 +57,14 @@ class ProxiedRoute:
57
57
  EgressRoute = DirectRoute | ProxiedRoute
58
58
 
59
59
 
60
+ @dataclass(frozen=True)
61
+ class ResolvedEgress:
62
+ """HTTP client and route resolved from one request credential set."""
63
+
64
+ http_client: AsyncClient
65
+ route: EgressRoute
66
+
67
+
60
68
  def _get_proxy_host_and_port(settings: ProxySettings) -> tuple[str, int]:
61
69
  proxy_host = settings.proxy_host
62
70
  proxy_port = settings.proxy_port
@@ -314,20 +322,51 @@ class HttpClientRegistry:
314
322
  fixed_client=client,
315
323
  )
316
324
 
317
- async def client_for(self, context: RequestContext) -> AsyncClient:
318
- """Return the cached client for the request's resolved credentials."""
319
- if self._fixed_client is not None:
320
- return self._fixed_client
325
+ async def egress_for(self, context: RequestContext) -> ResolvedEgress:
326
+ """Return the cached client and route for one credential resolution."""
321
327
  if self._closed:
322
328
  raise RuntimeError("HTTP client registry is closed")
323
-
324
329
  credentials = self._resolver.resolve(context)
330
+ return await self._egress_for_credentials(credentials)
331
+
332
+ async def settings_egress(self) -> ResolvedEgress:
333
+ """Return egress for process-level work using settings credentials."""
334
+ if self._closed:
335
+ raise RuntimeError("HTTP client registry is closed")
336
+ if (
337
+ self._settings.proxy_username_source == "user_metadata"
338
+ and self._settings.proxy_auth_mode == "none"
339
+ ):
340
+ raise ValidationProxyError(
341
+ "Process-level egress cannot use request-scoped proxy credentials; "
342
+ "configure settings-backed username/password or mTLS credentials",
343
+ )
344
+ credentials = SettingsProxyCredentials(self._settings).resolve(
345
+ RequestContext(
346
+ company_id="__settings__",
347
+ user_id="local",
348
+ chat_id="local",
349
+ ),
350
+ )
351
+ return await self._egress_for_credentials(credentials)
352
+
353
+ async def _egress_for_credentials(
354
+ self,
355
+ credentials: ProxyCredentials,
356
+ ) -> ResolvedEgress:
357
+ if self._closed:
358
+ raise RuntimeError("HTTP client registry is closed")
359
+
360
+ route = build_route(self._settings, credentials)
361
+ if self._fixed_client is not None:
362
+ return ResolvedEgress(http_client=self._fixed_client, route=route)
363
+
325
364
  evicted: AsyncClient | None = None
326
365
  async with self._lock:
327
366
  cached = self._clients.get(credentials)
328
367
  if cached is not None:
329
368
  self._clients.move_to_end(credentials)
330
- return cached
369
+ return ResolvedEgress(http_client=cached, route=route)
331
370
 
332
371
  client = build_async_client(
333
372
  self._settings,
@@ -350,7 +389,11 @@ class HttpClientRegistry:
350
389
 
351
390
  if evicted is not None:
352
391
  await evicted.aclose()
353
- return client
392
+ return ResolvedEgress(http_client=client, route=route)
393
+
394
+ async def client_for(self, context: RequestContext) -> AsyncClient:
395
+ """Return the cached client for the request's resolved credentials."""
396
+ return (await self.egress_for(context)).http_client
354
397
 
355
398
  @property
356
399
  def is_open(self) -> bool:
@@ -384,6 +427,7 @@ __all__ = [
384
427
  "EgressRoute",
385
428
  "HttpClientRegistry",
386
429
  "ProxiedRoute",
430
+ "ResolvedEgress",
387
431
  "async_client_factory",
388
432
  "build_async_client",
389
433
  "build_route",