unique-search-proxy-core
Part of Unique Search Proxy · PyPI: unique-search-proxy-core
1. What this package is
Core is the contract layer. It defines every shared type — deployment configs, HTTP request/response shapes, error codes, and LLM tool schemas — without importing FastAPI, httpx pools, or provider SDKs.
Install it anywhere you need to describe or validate proxy behaviour: the proxy server, the HTTP SDK, assistants-core tool manifests, deployment UIs.
| Package | Question it answers |
|---|---|
| Core (this) | What can be configured and what does a valid request/response look like? |
| Client | How are provider calls executed at runtime? |
| SDK | How do callers reach the proxy over HTTP? |
2. Role in the system
Core sits at the centre of Path A (schema & config). It is imported by both the proxy pod and caller services; it never makes HTTP calls itself.
flowchart TB
subgraph consumers["Consumers of core"]
Client["unique_search_proxy_client"]
SDK["unique_search_proxy_sdk"]
AC["assistants-core / deployment UI"]
end
subgraph core["unique_search_proxy_core"]
Contracts["Response & error models"]
Config["*Config deployment models\n(request_model / exposed_params_model / merge)"]
end
AC --> Config
Client --> Contracts
Client --> Config
SDK --> Contracts
Config -->|"flat request body"| SDK
Config -->|"flat request body"| Client
System overview → ../README.md
3. Key concepts
The config class owns its entire parameter lifecycle. Every derived surface is a method on the deployment config — there are no standalone projection or resolver modules.
3.1 Config-owned API (search + agent engines)
Admin JSON → GoogleConfig {expose, value}
├─ GoogleConfig.request_model() → GoogleSearchRequest (HTTP body, query required)
├─ config.exposed_params_model() → GoogleExposedParams (LLM knobs; tool inherits it)
├─ config.merge(llm_args, query=…) → validated GoogleSearchRequest
└─ GoogleConfig.provider_query_params(req) → upstream provider dict
| Method | Kind | Returns |
|---|---|---|
request_model() (classmethod, cached) |
search / agent / crawl | SearchRequestBase (required query) or CrawlRequestBase (required urls) + config fields; ExposableParam knobs unwrapped to optional plain types |
exposed_params_model() (instance) |
search / agent | ExposedParams subclass with exactly the expose=True knobs (camelCase aliases, description-only schema), or None |
merge(overrides, *, query) (instance) |
search / agent | deployment defaults + LLM overrides + query → validated request_model() instance |
provider_query_params(request) (classmethod) |
search only | request serialized for the upstream provider, minus _provider_param_exclude_fields (Google adds search_engine_id) |
ExposableParamsConfig (in param_policy/exposable_config.py) implements the exposable-parameter lifecycle once; BaseSearchEngineConfig and BaseAgentEngineConfig both extend it. Crawlers (BasicConfig, …) only implement request_model(): they have no exposable params and no merge — a crawl request is simply the deployment config fields plus urls.
3.2 ExposableParam
Optional search and agent parameters use ExposableParam[T]:
value— admin default merged into every request (null= deactivated)expose— whentrue, the parameter appears on the LLM-facing exposed-params model
gl: ExposableParam[str | None] = ExposableParam(expose=False, value="de") # admin-fixed
gl: ExposableParam[str | None] = ExposableParam(expose=True, value=None) # LLM-overridable
Bare scalars are not coerced — deployment JSON must use the explicit {"expose": …, "value": …} shape.
3.3 ExposedParams — the LLM tool-schema contract
config.exposed_params_model() returns a plain Pydantic model class. Tool-parameter models graft the knobs on by ordinary inheritance — no field-def plumbing, no stamped attributes:
Exposed = config.exposed_params_model() # GoogleExposedParams | None
class ToolParams(ToolParamsBase, Exposed): ... # or create_model(__base__=(...))
ToolParams.model_json_schema() # camelCase knobs, no title/default noise
Exposed.model_fields # the exposed field names
The shared ExposedParams base owns the single JSON-schema concern: its model_json_schema strips Pydantic's auto-title and default noise, so admin defaults never leak into what the LLM sees.
3.4 merge — deployment defaults + LLM overrides
request = google_config.merge({"gl": "de"}, query="EU AI Act")
# → validated GoogleSearchRequest ready for POST /v1/search
Deactivated knobs (value=None) are dropped, overrides win over admin defaults, engine always comes from the config. The proxy receives a flat body; it does not resolve deployment config over HTTP.
4. Architecture (modules)
flowchart TB
subgraph core_pkg["unique_search_proxy_core"]
Schema["schema.py"]
Errors["errors.py"]
PP["param_policy/\nExposableParam · ExposedParams\nrequest bases · derive"]
Prov["providers/schema.py"]
SE["search_engines/"]
AE["agent_engines/"]
CR["crawlers/"]
end
PP --> SE
PP --> AE
PP --> CR
Prov --> SE
Prov --> CR
SE --> Schema
AE --> Schema
CR --> Schema
Errors --> Schema
| Module | Responsibility |
|---|---|
schema.py |
Shared API models: SearchResponse, AgentSearchResponse, CrawlResponse, WebSearchResult, ErrorResponse, SSE events |
errors.py |
ProxyError hierarchy and stable ProxyErrorCode enum |
param_policy/exposable_param.py |
ExposableParam value object, factory-default merge, type introspection, OpenAPI naming |
param_policy/exposable_config.py |
ExposableParamsConfig — the exposed_params_model() / merge() lifecycle shared by search and agent config bases |
param_policy/exposed_params.py |
ExposedParams base for LLM-facing parameter models (schema noise stripping) |
param_policy/request_base.py |
SearchRequestBase / AgentRequestBase / CrawlRequestBase (required leading fields) |
param_policy/annotations.py |
Annotation unwrapping helpers (private, used by derive) |
param_policy/derive.py |
derive_request_model / derive_exposed_params_model factories called by the config base classes |
providers/schema.py |
JSON Schema + defaults for deployment UIs (provider_config_json_schema, …) |
search_engines/ |
Config models with the config-owned API (request_model / exposed_params_model / merge / provider_query_params), request union |
agent_engines/ |
Agent config/request models (request_model, exposed_params_model, merge), output schema, Bing grounding configuration + agent naming |
crawlers/ |
*Config deployment models + derived *CrawlRequest bodies (request_model()) |
5. Provider contracts
Core registers the discriminator ids and config models. Runtime registration of service classes lives in the client.
| Kind | IDs | Config model |
|---|---|---|
| Search engines | google, brave, perplexity |
GoogleConfig, BraveConfig, PerplexityConfig |
| Agent engines | bing, vertexai |
BingAgentConfig, VertexAIAgentConfig |
| Crawlers | Basic, Tavily, Jina, Firecrawl |
BasicConfig, TavilyConfig, … → BasicCrawlRequest, … |
Search engines share BaseSearchEngineConfig (fetch_size, timeout). Crawlers share BaseCrawlerConfig (timeout only — urls live on derived request models).
6. Key APIs (by use case)
Deployment UI — JSON Schema for a provider
from unique_search_proxy_core.providers.schema import (
provider_config_json_schema,
provider_default_config,
)
schema = provider_config_json_schema("search_engine", "google")
defaults = provider_default_config("search_engine", "google")
Tool manifest — exposed LLM knobs
Exposed = google_config.exposed_params_model() # GoogleExposedParams | None
class ToolParams(ToolParamsBase, Exposed): ... # graft knobs by inheritance
ToolParams.model_json_schema() # camelCase, no title/default noise
Runtime — build flat request before HTTP call
request = google_config.merge(llm_invocation_dict, query="EU AI Act")
body = GoogleConfig.provider_query_params(request) # upstream provider dict
Shared types and errors
from unique_search_proxy_core import (
SearchResponse,
ProxyError,
EngineNotConfiguredError,
WebSearchResult,
)
7. Features summary
- Discriminated provider configs (
engine,crawlerLiteral discriminators) - Search & agent: config-owned
request_model/exposed_params_model/merge(provider_query_paramsis search-only); standard engines put optional provider knobs behind theExposableParampolicy - Agent:
BingAgentConfig.request_model()(injectsquery; excludesoutput_schema); Bing'smarket/freshnessare fixed admin values, never exposed to the LLM, and are baked into the hashed agent name (both areLiterals over Bing's documented values, likeBraveCountry). A blankmarketfalls back to theBING_AGENT_DEFAULT_MARKETenvironment variable - Crawl:
BasicConfig.request_model()(injectsurls); no exposable params / no merge - CamelCase JSON aliases on all models
- Zero server dependencies (import-linter enforced in the client package)
8. Installation & development
cd unique_search_proxy_core
uv sync
uv run pytest
uv run ruff check .
uv run basedpyright
Consumers needing HTTP access should use unique-search-proxy-sdk rather than calling the proxy with raw httpx.
License
Proprietary — Unique AG
Release files for unique-search-proxy-core 2026.40.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| unique_search_proxy_core-2026.40.0.tar.gz | 48.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| unique_search_proxy_core-2026.40.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 128.9 kB
Release files / unique_search_proxy_core-2026.40.0.tar.gz
| Download URL | unique_search_proxy_core-2026.40.0.tar.gz |
|---|---|
| Size | 48.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bab1409ffaeb5ad9b6d8a949f5927212bd51c7c1ec4bb6887a2e652a32f7f5ed
|
|
BLAKE2b-256 checksum How to use checksums |
74fba0180cf2c29a41731d9472cbc16b8d9cc578c40d79681d19346d44e5af6e
|
| 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_core-2026.40.0-py3-none-any.whl
| Download URL | unique_search_proxy_core-2026.40.0-py3-none-any.whl |
|---|---|
| Size | 80.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7fce71ceb30e2e9a97c03d807007ced8dad4e85da4e40ce7729663208c3cd804
|
|
BLAKE2b-256 checksum How to use checksums |
adc79d0fc70d9663790e4d1212f97d8c5ed545c4ba1189ed8a36561b1cc5433f
|
| 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}
|