Skip to main content

Async HTTP client for the Unique Search Proxy API

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unique_search_proxy_sdk-2026.28.0.tar.gz (36.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unique_search_proxy_sdk-2026.28.0-py3-none-any.whl (72.6 kB view details)

Uploaded Python 3

File details

Details for the file unique_search_proxy_sdk-2026.28.0.tar.gz.

File metadata

  • Download URL: unique_search_proxy_sdk-2026.28.0.tar.gz
  • Upload date:
  • Size: 36.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","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}

File hashes

Hashes for unique_search_proxy_sdk-2026.28.0.tar.gz
Algorithm Hash digest
SHA256 763c30851f584768b976ce4b15d127522c2c0efe24af2e3d966f1556ae02e753
MD5 16ef781532d8ced9fbe639c4d7b8ff97
BLAKE2b-256 20ab228925b54bfbc5448f1ec8eb4396812edd307e814ba2d142c5e2a0c44f80

See more details on using hashes here.

File details

Details for the file unique_search_proxy_sdk-2026.28.0-py3-none-any.whl.

File metadata

  • Download URL: unique_search_proxy_sdk-2026.28.0-py3-none-any.whl
  • Upload date:
  • Size: 72.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","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}

File hashes

Hashes for unique_search_proxy_sdk-2026.28.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f1f87193024ad58273705aabb20da9d2e9605e5b3be8dde655a1d2de81b5278a
MD5 e8e40879d208cfe2843cb46f835fa733
BLAKE2b-256 f29e9121171dcc3c9d10a62bd0d9f7a7ed50847e9033ce63630d39be1fca536a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page