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.dev4.tar.gz (36.8 kB view details)

Uploaded Source

Built Distribution

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

File details

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

File metadata

  • Download URL: unique_search_proxy_sdk-2026.28.0.dev4.tar.gz
  • Upload date:
  • Size: 36.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.5 {"installer":{"name":"uv","version":"0.11.5","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.dev4.tar.gz
Algorithm Hash digest
SHA256 35fd7939c01b792e8141309efca5481dcd906feb93ebc19ddaae69cde9699ef9
MD5 7e79588ca08a413d82daaf73c285c299
BLAKE2b-256 f7462f6f6f63aee4c61555ab19057d861f455b8420549395722de265f1759e42

See more details on using hashes here.

File details

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

File metadata

  • Download URL: unique_search_proxy_sdk-2026.28.0.dev4-py3-none-any.whl
  • Upload date:
  • Size: 72.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.5 {"installer":{"name":"uv","version":"0.11.5","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.dev4-py3-none-any.whl
Algorithm Hash digest
SHA256 24b0b9a670af094d601ad64d84f95752ec3db6090515a41e1092087c5e9978b8
MD5 4703875302a194c008d6f7cb345b307f
BLAKE2b-256 fc195760610fd3f5690b024e291be8c68549b62b4acf6daabe79163e631e5766

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