This release is a pre-release and may not be stable for production use.
unique-search-proxy-sdk
Part of Unique Search Proxy · PyPI: unique-search-proxy-sdk
1. What this package is
The SDK is the caller's HTTP client. Platform services (e.g. assistants-core) use it to reach the proxy pod at runtime — search, agent search, and crawl — without hand-crafting httpx calls or duplicating route paths.
It depends on core for request validation and typed errors. It does not include the FastAPI server.
| Package | Question it answers |
|---|---|
| Core | What can be configured and what does a valid request/response look like? |
| Client | How are provider calls executed at runtime? |
| SDK (this) | How do callers reach the proxy over HTTP? |
2. Role in the system
The SDK implements Path B (runtime HTTP) from the system overview. Schema work (Path A) stays in core — the SDK does not expose deployment config or LLM call-schema endpoints.
flowchart LR
Caller["Caller service"]
SDK["unique_search_proxy_sdk"]
Core["unique_search_proxy_core"]
Proxy["unique_search_proxy_client"]
Caller --> SDK
SDK --> Core
SDK -->|"httpx"| Proxy
Before a search call, the caller (or SDK) validates the payload against core request models. Non-2xx responses become the same ProxyError subclasses defined in core.
3. Architecture
Two layers: a hand-written facade over OpenAPI-generated code.
flowchart TB
subgraph sdk_pkg["unique_search_proxy_sdk"]
Facade["UniqueSearchProxyClient"]
SC["SearchClient"]
ASC["AgentSearchClient"]
CC["CrawlClient"]
Transport["OpenapiTransport"]
Gen["_generated/"]
Conv["converters.py"]
Err["errors.py"]
end
Core["unique_search_proxy_core"]
Proxy["Proxy pod"]
Facade --> SC & ASC & CC
SC & ASC & CC --> Transport
Transport --> Gen
SC --> Conv --> Core
Err --> Core
Gen -->|"httpx AsyncClient"| Proxy
| Layer | Path | Responsibility |
|---|---|---|
| Facade | client.py |
UniqueSearchProxyClient — composes sub-clients, health(), ready() |
| Sub-clients | search_client.py, agent_search_client.py, crawl_client.py |
Per-provider typed endpoints + compatibility dispatchers |
| Endpoint factory | _endpoint.py |
async_post_endpoint / async_sse_endpoint (ParamSpec from core request models) |
| Transport | _transport.py, _http.py |
Shared httpx lifecycle, base URL, timeout |
| Generated | _generated/ |
Route functions + attrs models from OpenAPI (do not edit) |
| Converters | converters.py |
Core Pydantic models → generated SDK models |
| Errors | errors.py |
Error envelope → core ProxyError subclasses |
The client package is the source of truth for the HTTP contract. When routes change, regenerate _generated/ from unique_search_proxy_client/openapi.json.
4. Usage
Each provider exposes a typed endpoint whose kwargs mirror the core *Request Pydantic model (via ParamSpec). Snake_case and camelCase aliases both work (fetch_size / fetchSize).
from unique_search_proxy_sdk import UniqueSearchProxyClient
async with UniqueSearchProxyClient("http://unique-search-proxy:2349") as client:
await client.health()
# Typed per-provider endpoints (preferred)
result = await client.search.google(query="unique ag", gl="ch", fetch_size=10)
brave = await client.search.brave(query="news", country="US", safesearch="strict")
agent = await client.agent_search.bing(query="EU AI Act timeline", fetch_size=5)
crawl = await client.crawl.basic(urls=["https://example.com"])
# Compatibility dispatchers (engine/crawler string)
result = await client.search.search("unique ag", engine="google", fetch_size=10)
agent = await client.agent_search.search("query", engine="bing")
crawl = await client.crawl.crawl(["https://example.com"], crawler="Basic")
# Agent SSE streaming
async for event in client.agent_search.bing_stream(query="query"):
...
# Low-level: one generated function per route
raw_client = client.openapi
Search payloads are validated through core's parse_search_request() before serialization. Agent and crawl clients follow the same pattern.
5. API mapping
| Facade method | HTTP |
|---|---|
health() |
GET /health |
ready() |
GET /ready |
search.google(...) / .brave(...) / .perplexity(...) |
POST /v1/search |
search.search(...) |
POST /v1/search (dispatcher) |
agent_search.bing(...) / .vertexai(...) |
POST /v1/agent-search |
agent_search.bing_stream(...) / .vertexai_stream(...) |
POST /v1/agent-search/stream (SSE) |
agent_search.search(...) / .stream(...) |
same routes (dispatchers) |
crawl.basic(...) / .tavily(...) / .jina(...) / .firecrawl(...) |
POST /v1/crawl |
crawl.crawl(...) |
POST /v1/crawl (dispatcher) |
openapi |
Low-level generated client (one function per route) |
Endpoint payloads and provider ids → Client README.
6. Error handling
Non-success responses with a proxy error envelope raise typed exceptions from core:
from unique_search_proxy_core import EngineNotConfiguredError, UpstreamError
ENGINE_NOT_CONFIGURED (503) includes missing_env_vars parsed from the error details list — useful for operators and LLM tool consumers.
Transport failures (non-JSON body, connection errors) raise UniqueSearchProxyClientError.
7. Codegen workflow
Generated via openapi-python-client from the server's OpenAPI spec.
cd ../unique_search_proxy_client
uv sync
uv run python scripts/generate_sdk.py
| Path | Role |
|---|---|
unique_search_proxy_sdk/_generated/ |
Regenerated httpx client + attrs models |
unique_search_proxy_client/openapi.json |
Exported spec (codegen input) |
unique_search_proxy_sdk/client.py |
Hand-written facade (not regenerated) |
Other codegen tools considered: OpenAPI Generator, datamodel-code-generator, Kiota — see git history in the client README if needed.
8. Testing
Pass an injected httpx.AsyncClient with ASGITransport for in-process tests against create_app():
import httpx
from httpx import ASGITransport
from unique_search_proxy_client.web.app import create_app
from unique_search_proxy_sdk import UniqueSearchProxyClient
app = create_app()
async with httpx.AsyncClient(
transport=ASGITransport(app=app),
base_url="http://test",
) as http:
async with UniqueSearchProxyClient("http://test", http_client=http) as client:
...
Run the app lifespan so the in-process HttpClientPool is initialised.
9. Installation & development
cd unique_search_proxy_sdk
uv sync
uv run pytest
uv run ruff check .
uv run basedpyright
Depends on unique-search-proxy-core. Does not depend on unique-search-proxy at runtime (only as a dev dependency for integration tests).
License
Proprietary — Unique AG
Metadata
Release files for unique-search-proxy-sdk 2026.44.0.dev6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| unique_search_proxy_sdk-2026.44.0.dev6.tar.gz | 42.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| unique_search_proxy_sdk-2026.44.0.dev6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 129.0 kB
Release files / unique_search_proxy_sdk-2026.44.0.dev6.tar.gz
| Download URL | unique_search_proxy_sdk-2026.44.0.dev6.tar.gz |
|---|---|
| Size | 42.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a657b7e079a94ddc6d159bf14cb71c4ac40ba9b293bfcfb754e7f28f84db3067
|
|
BLAKE2b-256 checksum How to use checksums |
1e116fc1d9774d503c98403ec89804a6e14103b54ddbfdb17d577b536aca7174
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / unique_search_proxy_sdk-2026.44.0.dev6-py3-none-any.whl
| Download URL | unique_search_proxy_sdk-2026.44.0.dev6-py3-none-any.whl |
|---|---|
| Size | 86.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c8265b79ef666c5503badbd2602cd44de0d7fdbf2dfeab9fc2cafae42f2ef892
|
|
BLAKE2b-256 checksum How to use checksums |
1b0cf3ac11234d3b98e448f18497fb7fb452e5be7d8c26a0f213b759d63f0873
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for unique-search-proxy-sdk 2026.44.0.dev6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.